diff --git a/src/conditions/base/contract.ts b/src/conditions/base/contract.ts index c7f153f31..522591b74 100644 --- a/src/conditions/base/contract.ts +++ b/src/conditions/base/contract.ts @@ -25,13 +25,13 @@ const functionAbiSchema = Joi.object({ }); } - if (!asInterface.fragments) { + if (!asInterface.functions) { return helper.message({ custom: '"functionAbi" is missing a function fragment', }); } - if (asInterface.fragments.length > 1) { + if (Object.values(asInterface.functions).length !== 1) { return helper.message({ custom: '"functionAbi" must contain exactly one function fragment', }); @@ -40,12 +40,15 @@ const functionAbiSchema = Joi.object({ // Now we just need to validate against the parent schema // Validate method name const method = helper.state.ancestors[0].method; - const functionFragment = asInterface.fragments.filter( - (f) => f.name === method - )[0]; + const abiMethodName = Object.keys(asInterface.functions).find((name) => + name.startsWith(`${method}(`) + ); + const functionFragment = abiMethodName + ? asInterface.functions[abiMethodName] + : null; if (!functionFragment) { return helper.message({ - custom: '"functionAbi" does not contain the method specified as "method"', + custom: `"functionAbi" not valid for method: "${method}"`, }); } diff --git a/test/unit/conditions/base/contract.test.ts b/test/unit/conditions/base/contract.test.ts index 05074ddd1..ee988bbb6 100644 --- a/test/unit/conditions/base/contract.test.ts +++ b/test/unit/conditions/base/contract.test.ts @@ -123,7 +123,7 @@ describe('supports custom function abi', () => { const customParams: Record = {}; customParams[myCustomParam] = 1234; - it('accepts custom function abi', async () => { + it('accepts custom function abi with a custom parameter', async () => { const asJson = await conditionContext .withCustomParams(customParams) .toJson(); @@ -131,4 +131,109 @@ describe('supports custom function abi', () => { expect(asJson).toContain(USER_ADDRESS_PARAM); expect(asJson).toContain(myCustomParam); }); + + it.each([ + { + method: 'balanceOf', + functionAbi: { + name: 'balanceOf', + type: 'function', + inputs: [{ name: '_owner', type: 'address' }], + outputs: [{ name: 'balance', type: 'uint256' }], + stateMutability: 'view', + }, + }, + { + method: 'get', + functionAbi: { + name: 'get', + type: 'function', + inputs: [], + outputs: [], + stateMutability: 'pure', + }, + }, + ])('accepts well-formed functionAbi', ({ method, functionAbi }) => { + expect(() => + new ContractCondition({ + ...contractConditionObj, + parameters: functionAbi.inputs.map( + (input) => `fake_parameter_${input}` + ), // + functionAbi, + method, + }).toObj() + ).not.toThrow(); + }); + + it.each([ + { + method: '1234', + expectedError: '"functionAbi.name" must be a string', + functionAbi: { + name: 1234, // invalid value + type: 'function', + inputs: [{ name: '_owner', type: 'address' }], + outputs: [{ name: 'balance', type: 'uint256' }], + stateMutability: 'view', + }, + }, + { + method: 'transfer', + expectedError: '"functionAbi.inputs" must be an array', + functionAbi: { + name: 'transfer', + type: 'function', + inputs: 'invalid value', // invalid value + outputs: [{ name: '_status', type: 'bool' }], + stateMutability: 'pure', + }, + }, + { + method: 'get', + expectedError: + '"functionAbi.stateMutability" must be one of [view, pure]', + functionAbi: { + name: 'get', + type: 'function', + inputs: [], + outputs: [], + stateMutability: 'invalid', // invalid value + }, + }, + { + method: 'test', + expectedError: '"functionAbi.outputs" must be an array', + functionAbi: { + name: 'test', + type: 'function', + inputs: [], + outputs: 'invalid value', // Invalid value + stateMutability: 'pure', + }, + }, + { + method: 'calculatePow', + expectedError: + 'Invalid condition: "parameters" must have the same length as "functionAbi.inputs"', + functionAbi: { + name: 'calculatePow', + type: 'function', + // 'inputs': [] // Missing inputs array + outputs: [{ name: 'result', type: 'uint256' }], + stateMutability: 'view', + }, + }, + ])( + 'rejects malformed functionAbi', + ({ method, expectedError, functionAbi }) => { + expect(() => + new ContractCondition({ + ...contractConditionObj, + functionAbi, + method, + }).toObj() + ).toThrow(expectedError); + } + ); });