Skip to content

Commit

Permalink
Properly handle human readable ABI; add tests.
Browse files Browse the repository at this point in the history
  • Loading branch information
derekpierre committed Oct 15, 2024
1 parent c404a96 commit 441c6b9
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 8 deletions.
12 changes: 7 additions & 5 deletions packages/taco/src/conditions/schemas/contract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ import { AbiParameter } from 'abitype/zod';

import { paramOrContextParamSchema } from './context';
import { rpcConditionSchema } from './rpc';
import { parseAbi, parseAbiItem } from 'abitype';
import { parseAbiItem } from 'abitype';

const functionAbiSchema = z
const verboseAbiSchema = z
.object({
name: z.string(),
type: z.literal('function'),
Expand Down Expand Up @@ -48,8 +48,6 @@ const functionAbiSchema = z
},
);

export type FunctionAbiProps = z.infer<typeof functionAbiSchema>;

export const humanReadableAbiSchema = z
.string().startsWith("function ")
.refine(
Expand All @@ -67,6 +65,10 @@ export const humanReadableAbiSchema = z
)
.transform(parseAbiItem);

const abiSchema = z.union([verboseAbiSchema, humanReadableAbiSchema])

export type FunctionAbiProps = z.infer<typeof abiSchema>;

export const ContractConditionType = 'contract';
export const contractConditionSchema = rpcConditionSchema
.extend({
Expand All @@ -76,7 +78,7 @@ export const contractConditionSchema = rpcConditionSchema
contractAddress: z.string().regex(ETH_ADDRESS_REGEXP).length(42),
standardContractType: z.enum(['ERC20', 'ERC721']).optional(),
method: z.string(),
functionAbi: functionAbiSchema.optional(),
functionAbi: abiSchema.optional(),
parameters: z.array(paramOrContextParamSchema),
})
// Adding this custom logic causes the return type to be ZodEffects instead of ZodObject
Expand Down
34 changes: 31 additions & 3 deletions packages/taco/test/conditions/base/contract.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
CustomContextParam,
} from '../../../src/conditions/context';
import { testContractConditionObj, testFunctionAbi } from '../../test-utils';
import { parseAbiItem } from 'abitype';

describe('validation', () => {
it('accepts on a valid schema', () => {
Expand Down Expand Up @@ -235,18 +236,29 @@ describe('supports custom function abi', async () => {
stateMutability: 'pure',
},
},
])('accepts well-formed functionAbi', ({ method, functionAbi }) => {
{
method: 'balanceOf',
functionAbi: 'function balanceOf(address _owner) view returns (uint256 balance)',
},
])('accepts well-formed functionAbi', ({ method, functionAbi}) => {
const result = ContractCondition.validate(contractConditionSchema, {
...contractConditionObj,
parameters: functionAbi.inputs.map((input) => `fake_parameter_${input}`), //
parameters:
typeof functionAbi === 'string'
? ['fake_parameter']
: functionAbi.inputs.map((input) => `fake_parameter_${input}`),
functionAbi: functionAbi as FunctionAbiProps,
method,
});

expect(result.error).toBeUndefined();
expect(result.data).toBeDefined();
expect(result.data?.method).toEqual(method);
expect(result.data?.functionAbi).toEqual(functionAbi);
if (typeof functionAbi === "string") {
expect(result.data?.functionAbi).toEqual(parseAbiItem(functionAbi));
} else {
expect(result.data?.functionAbi).toEqual(functionAbi);
}
});

it.each([
Expand Down Expand Up @@ -336,6 +348,22 @@ describe('supports custom function abi', async () => {
},
);

it('rejects malformed human-readable functionAbi', () => {
const result = ContractCondition.validate(contractConditionSchema, {
...contractConditionObj,
method: 'invalidMethod',
functionAbi: 'function balance(_owner) invalid human-readable ABI',
});

expect(result.error).toBeDefined();
expect(result.data).toBeUndefined();
expect(result.error?.format()).toMatchObject({
functionAbi: {
_errors: ['Invalid Human-Readable ABI format'],
},
});
});

it.each([
{
contractAddress: '0x123',
Expand Down

0 comments on commit 441c6b9

Please sign in to comment.