Skip to content

Commit

Permalink
Fix Contract methods input param type any[] (#7340)
Browse files Browse the repository at this point in the history
* fix types

* fix

* Update type.test.ts

* fix tests

* fix test
  • Loading branch information
avkos authored and MRLab12 committed Oct 30, 2024
1 parent c446cd8 commit 12d7e18
Show file tree
Hide file tree
Showing 6 changed files with 96 additions and 6 deletions.
6 changes: 5 additions & 1 deletion packages/web3-eth-contract/src/contract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,11 @@ type ContractBoundMethod<
Abi extends AbiFunctionFragment,
Method extends ContractMethod<Abi> = ContractMethod<Abi>,
> = (
...args: Method['Inputs'] extends undefined | unknown ? any[] : Method['Inputs']
...args: Abi extends undefined
? any[]
: Method['Inputs'] extends never
? any[]
: Method['Inputs']
) => Method['Abi']['stateMutability'] extends 'payable' | 'pure'
? PayableMethodObject<Method['Inputs'], Method['Outputs']>
: NonPayableMethodObject<Method['Inputs'], Method['Outputs']>;
Expand Down
2 changes: 1 addition & 1 deletion packages/web3-eth-contract/test/fixtures/erc20.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import { ContractEventOptions, PayableMethodObject, NonPayableMethodObject } fro
export interface Erc20Interface {
methods: {
[key: string]: (
...args: ReadonlyArray<any>
...args: any[]
) =>
| PayableMethodObject<ReadonlyArray<unknown>, ReadonlyArray<unknown>>
| NonPayableMethodObject<ReadonlyArray<unknown>, ReadonlyArray<unknown>>;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,11 +102,14 @@ describe('contract ERC721 overloaded functions', () => {
});

it('transferFrom with 3 invalid arguments', () => {
expect(() => contractDeployed.methods.safeTransferFrom(1, 2, 3)).toThrow('Web3 validator');
expect(() => contractDeployed.methods.safeTransferFrom('1', '2', 3)).toThrow(
'Web3 validator',
);
});

it('transferFrom with 2 arguments', () => {
expect(() =>
// @ts-expect-error invalid arguments so ts will throw an error
contractDeployed.methods.safeTransferFrom(localAccount.address, localAccount.address),
).toThrow('Web3 validator');
});
Expand Down
6 changes: 4 additions & 2 deletions packages/web3-eth-contract/test/unit/contract_typing.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,10 @@ describe('contract typing', () => {
]);

typecheck('should allow any input params', () => [
expectTypeOf<Parameters<typeof defaultContractInstance.methods.test>>().toBe<any[]>(),
expectTypeOf<Parameters<typeof web3ContractInstance.methods.test>>().toBe<any[]>(),
expectTypeOf<Parameters<typeof defaultContractInstance.methods.test>>().toBe<
any[] | []
>(),
expectTypeOf<Parameters<typeof web3ContractInstance.methods.test>>().toBe<any[] | []>(),
]);
});
describe('custom abi', () => {
Expand Down
79 changes: 79 additions & 0 deletions packages/web3-eth-contract/test/unit/type.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/*
This file is part of web3.js.
web3.js is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
web3.js is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with web3.js. If not, see <http://www.gnu.org/licenses/>.
*/

import { Contract } from '../../src';

describe('Contract method types', () => {
it('contract method params types test', () => {
const abiAsConst = [
{
inputs: [
{ internalType: 'uint256', name: 'testArg1', type: 'uint256' },
{ internalType: 'uint256', name: 'testArg2', type: 'uint256' },
],
name: 'testWithParams',
outputs: [{ internalType: 'uint256', name: 'testRes1', type: 'uint256' }],
stateMutability: 'nonpayable',
type: 'function',
},
{
inputs: [],
name: 'testWithoutParams',
outputs: [{ internalType: 'uint256', name: 'testRes1', type: 'uint256' }],
stateMutability: 'nonpayable',
type: 'function',
},
] as const;

const abiAsArray = [
{
inputs: [
{ internalType: 'uint256', name: 'testArg1', type: 'uint256' },
{ internalType: 'uint256', name: 'testArg2', type: 'uint256' },
],
name: 'testWithParams',
outputs: [{ internalType: 'uint256', name: 'testRes1', type: 'uint256' }],
stateMutability: 'nonpayable',
type: 'function',
},
{
inputs: [],
name: 'testWithoutParams',
outputs: [{ internalType: 'uint256', name: 'testRes1', type: 'uint256' }],
stateMutability: 'nonpayable',
type: 'function',
},
];

// abi as const
const contract = new Contract<typeof abiAsConst>(abiAsConst);
contract.methods.testWithParams(1, 2); // no ts error - works as expected
// @ts-expect-error ts compiler error
expect(() => contract.methods.testWithParams()).toThrow(); // ts error - works as expected
// @ts-expect-error ts compiler error
contract.methods.testWithoutParams(1, 2); // ts error - works as expected
contract.methods.testWithoutParams(); // no ts error - works as expected

// abi as usual array type
const contract2 = new Contract<typeof abiAsArray>(abiAsArray);
// because we do not know exact type without const or provided type
contract2.methods.testWithParams(1, 2); // no ts error - works as expected
contract2.methods.testWithoutParams(); // no ts error - works as expected
contract2.methods.testWithoutParams(1, 2); // no ts error - works as expected
expect(() => contract2.methods.testWithParams()).toThrow(); // no ts error - works as expected
});
});
4 changes: 3 additions & 1 deletion packages/web3-types/src/eth_abi_types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,9 @@ export type ContractMethodOutputParameters<Params extends ReadonlyArray<unknown>
: [];

export type ContractMethodInputParameters<Params extends ReadonlyArray<unknown> | undefined> =
Params extends readonly []
Params extends undefined
? any[]
: Params extends readonly []
? []
: Params extends readonly [infer H, ...infer R]
? H extends AbiParameter
Expand Down

0 comments on commit 12d7e18

Please sign in to comment.