diff --git a/src/actions/public/deployContract.ts b/src/actions/public/deployContract.ts index 8808390237..69f724c7a5 100644 --- a/src/actions/public/deployContract.ts +++ b/src/actions/public/deployContract.ts @@ -1,4 +1,4 @@ -import { Abi } from 'abitype' +import { Abi, Narrow } from 'abitype' import { WalletClient } from '../../clients' import { Chain, ExtractConstructorArgsFromAbi, Hex } from '../../types' @@ -11,18 +11,18 @@ import { export type DeployContractArgs< TChain extends Chain = Chain, - TAbi extends Abi = Abi, + TAbi extends Abi | readonly unknown[] = Abi, > = Omit< SendTransactionArgs, 'accessList' | 'to' | 'data' | 'value' > & { - abi: TAbi + abi: Narrow bytecode: Hex } & ExtractConstructorArgsFromAbi export type DeployContractResponse = SendTransactionResponse -export function deployContract( +export function deployContract( walletClient: WalletClient, { abi, args, bytecode, ...request }: DeployContractArgs, ): Promise { diff --git a/src/actions/public/readContract.ts b/src/actions/public/readContract.ts index f943340486..251d012433 100644 --- a/src/actions/public/readContract.ts +++ b/src/actions/public/readContract.ts @@ -22,21 +22,8 @@ export type FormattedReadContract< export type ReadContractArgs< TAbi extends Abi | readonly unknown[] = Abi, - TFunctionName extends string = any, -> = Omit< - CallArgs, - | 'accessList' - | 'chain' - | 'from' - | 'gas' - | 'gasPrice' - | 'maxFeePerGas' - | 'maxPriorityFeePerGas' - | 'nonce' - | 'to' - | 'data' - | 'value' -> & + TFunctionName extends string = string, +> = Pick & ContractConfig export type ReadContractResponse< @@ -45,8 +32,8 @@ export type ReadContractResponse< > = ExtractResultFromAbi export async function readContract< - TAbi extends Abi = Abi, - TFunctionName extends string = any, + TAbi extends Abi | readonly unknown[], + TFunctionName extends string, >( client: PublicClient, { @@ -76,7 +63,7 @@ export async function readContract< } as DecodeFunctionResultArgs) } catch (err) { throw getContractError(err as BaseError, { - abi, + abi: abi as Abi, address, args, docsPath: '/docs/contract/readContract', diff --git a/src/actions/public/simulateContract.test.ts b/src/actions/public/simulateContract.test.ts index a6c4a314ba..7f3db448ac 100644 --- a/src/actions/public/simulateContract.test.ts +++ b/src/actions/public/simulateContract.test.ts @@ -391,7 +391,6 @@ test('fake contract address', async () => { address: '0x0000000000000000000000000000000000000069', functionName: 'mint', from: accounts[0].address, - args: [], }), ).rejects.toThrowErrorMatchingInlineSnapshot(` "The contract function \\"mint\\" returned no data (\\"0x\\"). diff --git a/src/actions/public/simulateContract.ts b/src/actions/public/simulateContract.ts index 97569e797d..e18677b694 100644 --- a/src/actions/public/simulateContract.ts +++ b/src/actions/public/simulateContract.ts @@ -1,4 +1,4 @@ -import { Abi } from 'abitype' +import { Abi, Narrow } from 'abitype' import type { PublicClient } from '../../clients' import { BaseError } from '../../errors' @@ -36,17 +36,14 @@ export type SimulateContractResponse< TFunctionName extends string = string, > = { result: ExtractResultFromAbi - request: WriteContractArgs & { - address: Address - abi: TAbi - functionName: ExtractFunctionNameFromAbi - } & ExtractArgsFromAbi + request: WriteContractArgs & + ContractConfig } export async function simulateContract< TChain extends Chain, - TAbi extends Abi = Abi, - TFunctionName extends string = any, + TAbi extends Abi | readonly unknown[], + TFunctionName extends string, >( client: PublicClient, { @@ -86,7 +83,7 @@ export async function simulateContract< } as unknown as SimulateContractResponse } catch (err) { throw getContractError(err as BaseError, { - abi, + abi: abi as Abi, address, args, docsPath: '/docs/contract/simulateContract', diff --git a/src/actions/wallet/writeContract.ts b/src/actions/wallet/writeContract.ts index 0670083750..01b3cf40e0 100644 --- a/src/actions/wallet/writeContract.ts +++ b/src/actions/wallet/writeContract.ts @@ -12,7 +12,7 @@ import { export type WriteContractArgs< TChain extends Chain = Chain, TAbi extends Abi | readonly unknown[] = Abi, - TFunctionName extends string = any, + TFunctionName extends string = string, > = Omit, 'to' | 'data' | 'value'> & { value?: GetValue['value']> } & ContractConfig @@ -21,8 +21,8 @@ export type WriteContractResponse = SendTransactionResponse export async function writeContract< TChain extends Chain, - TAbi extends Abi = Abi, - TFunctionName extends string = any, + TAbi extends Abi | readonly unknown[], + TFunctionName extends string, >( client: WalletClient, { diff --git a/src/types/contract.ts b/src/types/contract.ts index a3ba814141..75ee32c4ce 100644 --- a/src/types/contract.ts +++ b/src/types/contract.ts @@ -12,9 +12,10 @@ import type { ExtractAbiFunction, ExtractAbiEvent, ExtractAbiEventNames, - ExtractAbiFunctionNames, ExtractAbiError, ExtractAbiErrorNames, + ExtractAbiFunctionNames, + Narrow, } from 'abitype' import type { Address } from './misc' import type { TransactionRequest } from './transaction' @@ -164,6 +165,18 @@ export type ExtractEventArgsFromAbi< args?: TArgs } +export type ExtractErrorNameFromAbi< + TAbi extends Abi | readonly unknown[] = Abi, + TErrorName extends string = string, +> = TAbi extends Abi + ? ExtractAbiErrorNames extends infer AbiErrorNames + ? + | AbiErrorNames + | (TErrorName extends AbiErrorNames ? TErrorName : never) + | (Abi extends TAbi ? string : never) + : never + : TErrorName + export type ExtractEventNameFromAbi< TAbi extends Abi | readonly unknown[] = Abi, TEventName extends string = string, @@ -355,7 +368,7 @@ export type ContractConfig< TAbiStateMutability extends AbiStateMutability = AbiStateMutability, > = { /** Contract ABI */ - abi: TAbi + abi: Narrow /** Contract address */ address: Address /** Function to invoke on the contract */ diff --git a/src/types/index.ts b/src/types/index.ts index d39e2fbae1..2a8477f2c6 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -18,6 +18,7 @@ export type { ExtractArgsFromFunctionDefinition, ExtractConstructorArgsFromAbi, ExtractErrorArgsFromAbi, + ExtractErrorNameFromAbi, ExtractEventArgsFromAbi, ExtractEventNameFromAbi, ExtractFunctionNameFromAbi, diff --git a/src/utils/abi/decodeAbi.test.ts b/src/utils/abi/decodeAbi.test.ts index 016787c102..028467ab73 100644 --- a/src/utils/abi/decodeAbi.test.ts +++ b/src/utils/abi/decodeAbi.test.ts @@ -1603,7 +1603,7 @@ test('error: zero data', () => { stateMutability: 'pure', type: 'function', }, - ] as const, + ], data: '0x', }), ).toThrowErrorMatchingInlineSnapshot(` diff --git a/src/utils/abi/decodeAbi.ts b/src/utils/abi/decodeAbi.ts index d22832cda8..0ed6fe9097 100644 --- a/src/utils/abi/decodeAbi.ts +++ b/src/utils/abi/decodeAbi.ts @@ -2,6 +2,7 @@ import { AbiParameter, AbiParametersToPrimitiveTypes, AbiParameterToPrimitiveType, + Narrow, } from 'abitype' import { @@ -15,21 +16,24 @@ import { size, slice, trim } from '../data' import { hexToBigInt, hexToBool, hexToNumber, hexToString } from '../encoding' import { getArrayComponents } from './encodeAbi' -export type DecodeAbiArgs = { +export type DecodeAbiArgs< + TParams extends + | readonly AbiParameter[] + | readonly unknown[] = readonly AbiParameter[], +> = { data: Hex - params: TParams + params: Narrow } -export function decodeAbi({ - data, - params, -}: DecodeAbiArgs) { +export function decodeAbi< + TParams extends readonly AbiParameter[] | readonly unknown[], +>({ data, params }: DecodeAbiArgs) { if (data === '0x' && params.length > 0) throw new AbiDecodingZeroDataError() if (size(data) % 32 !== 0) throw new AbiDecodingDataSizeInvalidError(size(data)) const values = decodeParams({ data, - params, + params: params as readonly AbiParameter[], }) if (values.length === 0) return undefined return values diff --git a/src/utils/abi/decodeDeployData.test.ts b/src/utils/abi/decodeDeployData.test.ts index 701060bd8a..34671722e4 100644 --- a/src/utils/abi/decodeDeployData.test.ts +++ b/src/utils/abi/decodeDeployData.test.ts @@ -11,7 +11,7 @@ test('constructor()', () => { stateMutability: 'nonpayable', type: 'constructor', }, - ] as const, + ], bytecode: '0x6080604052348015600f57600080fd5b50603f80601d6000396000f3fe6080604052600080fdfea2646970667358221220116554d4ba29ee08da9e97dc54ff9a2a65d67a648140d616fc225a25ff08c86364736f6c63430008070033', data: '0x6080604052348015600f57600080fd5b50603f80601d6000396000f3fe6080604052600080fdfea2646970667358221220116554d4ba29ee08da9e97dc54ff9a2a65d67a648140d616fc225a25ff08c86364736f6c63430008070033', @@ -22,13 +22,12 @@ test('constructor()', () => { }) expect( decodeDeployData({ - // @ts-expect-error abi: [ { stateMutability: 'nonpayable', type: 'constructor', }, - ] as const, + ], bytecode: '0x6080604052348015600f57600080fd5b50603f80601d6000396000f3fe6080604052600080fdfea2646970667358221220116554d4ba29ee08da9e97dc54ff9a2a65d67a648140d616fc225a25ff08c86364736f6c63430008070033', data: '0x6080604052348015600f57600080fd5b50603f80601d6000396000f3fe6080604052600080fdfea2646970667358221220116554d4ba29ee08da9e97dc54ff9a2a65d67a648140d616fc225a25ff08c86364736f6c63430008070033', @@ -54,7 +53,7 @@ test('constructor(uint256)', () => { stateMutability: 'nonpayable', type: 'constructor', }, - ] as const, + ], bytecode: '0x6080604052348015600f57600080fd5b50603f80601d6000396000f3fe6080604052600080fdfea2646970667358221220116554d4ba29ee08da9e97dc54ff9a2a65d67a648140d616fc225a25ff08c86364736f6c63430008070033', data: '0x6080604052348015600f57600080fd5b50603f80601d6000396000f3fe6080604052600080fdfea2646970667358221220116554d4ba29ee08da9e97dc54ff9a2a65d67a648140d616fc225a25ff08c86364736f6c634300080700330000000000000000000000000000000000000000000000000000000000010f2c', @@ -69,8 +68,7 @@ test('constructor(uint256)', () => { test('error: constructor not found', () => { expect(() => decodeDeployData({ - // @ts-expect-error - abi: [{}] as const, + abi: [{}], bytecode: '0x6080604052348015600f57600080fd5b50603f80601d6000396000f3fe6080604052600080fdfea2646970667358221220116554d4ba29ee08da9e97dc54ff9a2a65d67a648140d616fc225a25ff08c86364736f6c63430008070033', data: '0x6080604052348015600f57600080fd5b50603f80601d6000396000f3fe6080604052600080fdfea2646970667358221220116554d4ba29ee08da9e97dc54ff9a2a65d67a648140d616fc225a25ff08c86364736f6c634300080700330000000000000000000000000000000000000000000000000000000000010f2c', @@ -87,13 +85,12 @@ test('error: constructor not found', () => { test('error: no inputs', () => { expect(() => decodeDeployData({ - // @ts-expect-error abi: [ { stateMutability: 'nonpayable', type: 'constructor', }, - ] as const, + ], bytecode: '0x6080604052348015600f57600080fd5b50603f80601d6000396000f3fe6080604052600080fdfea2646970667358221220116554d4ba29ee08da9e97dc54ff9a2a65d67a648140d616fc225a25ff08c86364736f6c63430008070033', data: '0x6080604052348015600f57600080fd5b50603f80601d6000396000f3fe6080604052600080fdfea2646970667358221220116554d4ba29ee08da9e97dc54ff9a2a65d67a648140d616fc225a25ff08c86364736f6c634300080700330000000000000000000000000000000000000000000000000000000000010f2c', @@ -115,7 +112,7 @@ test('error: no inputs', () => { stateMutability: 'nonpayable', type: 'constructor', }, - ] as const, + ], bytecode: '0x6080604052348015600f57600080fd5b50603f80601d6000396000f3fe6080604052600080fdfea2646970667358221220116554d4ba29ee08da9e97dc54ff9a2a65d67a648140d616fc225a25ff08c86364736f6c63430008070033', data: '0x6080604052348015600f57600080fd5b50603f80601d6000396000f3fe6080604052600080fdfea2646970667358221220116554d4ba29ee08da9e97dc54ff9a2a65d67a648140d616fc225a25ff08c86364736f6c634300080700330000000000000000000000000000000000000000000000000000000000010f2c', @@ -131,14 +128,13 @@ test('error: no inputs', () => { ) expect(() => decodeDeployData({ - // @ts-expect-error abi: [ { inputs: undefined, stateMutability: 'nonpayable', type: 'constructor', }, - ] as const, + ], bytecode: '0x6080604052348015600f57600080fd5b50603f80601d6000396000f3fe6080604052600080fdfea2646970667358221220116554d4ba29ee08da9e97dc54ff9a2a65d67a648140d616fc225a25ff08c86364736f6c63430008070033', data: '0x6080604052348015600f57600080fd5b50603f80601d6000396000f3fe6080604052600080fdfea2646970667358221220116554d4ba29ee08da9e97dc54ff9a2a65d67a648140d616fc225a25ff08c86364736f6c634300080700330000000000000000000000000000000000000000000000000000000000010f2c', diff --git a/src/utils/abi/decodeDeployData.ts b/src/utils/abi/decodeDeployData.ts index c4da910893..0f7c44648e 100644 --- a/src/utils/abi/decodeDeployData.ts +++ b/src/utils/abi/decodeDeployData.ts @@ -9,24 +9,27 @@ import { decodeAbi } from './decodeAbi' const docsPath = '/docs/contract/decodeDeployData' -export type DecodeDeployDataArgs = { - abi: TAbi - bytecode: Hex - data: Hex -} +export type DecodeDeployDataArgs = + { + abi: TAbi + bytecode: Hex + data: Hex + } export type DecodeDeployDataResponse = { args?: readonly unknown[] | undefined bytecode: Hex } -export function decodeDeployData({ +export function decodeDeployData({ abi, bytecode, data, }: DecodeDeployDataArgs): DecodeDeployDataResponse { if (data === bytecode) return { bytecode } - const description = abi.find((x) => 'type' in x && x.type === 'constructor') + const description = (abi as Abi).find( + (x) => 'type' in x && x.type === 'constructor', + ) if (!description) throw new AbiConstructorNotFoundError({ docsPath }) if (!('inputs' in description)) throw new AbiConstructorParamsNotFoundError({ docsPath }) diff --git a/src/utils/abi/decodeFunctionResult.test.ts b/src/utils/abi/decodeFunctionResult.test.ts index df087e15c6..7f255742ce 100644 --- a/src/utils/abi/decodeFunctionResult.test.ts +++ b/src/utils/abi/decodeFunctionResult.test.ts @@ -13,7 +13,7 @@ test('returns ()', () => { stateMutability: 'pure', type: 'function', }, - ] as const, + ], functionName: 'foo', data: '0x', }), @@ -28,7 +28,7 @@ test('returns ()', () => { stateMutability: 'pure', type: 'function', }, - ] as const, + ], functionName: 'foo', // @ts-expect-error data: '', @@ -53,7 +53,7 @@ test('returns (address)', () => { stateMutability: 'pure', type: 'function', }, - ] as const, + ], functionName: 'foo', data: '0x000000000000000000000000a5cc3c03994db5b0d9a5eedd10cabab0813678ac', }), @@ -111,7 +111,7 @@ test('returns (Bar)', () => { stateMutability: 'pure', type: 'function', }, - ] as const, + ], functionName: 'bar', data: '0x000000000000000000000000a5cc3c03994db5b0d9a5eedd10cabab0813678ac0000000000000000000000000000000000000000000000000000000000010f2c0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000a5cc3c03994db5b0d9a5eedd10cabab0813678ac0000000000000000000000000000000000000000000000000000000000000045', }), @@ -182,7 +182,7 @@ test('returns (Bar, string)', () => { stateMutability: 'pure', type: 'function', }, - ] as const, + ], functionName: 'baz', data: '0x000000000000000000000000a5cc3c03994db5b0d9a5eedd10cabab0813678ac0000000000000000000000000000000000000000000000000000000000010f2c0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000a5cc3c03994db5b0d9a5eedd10cabab0813678ac000000000000000000000000000000000000000000000000000000000000004500000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000057761676d69000000000000000000000000000000000000000000000000000000', }), @@ -230,7 +230,7 @@ test('overloads', () => { stateMutability: 'pure', type: 'function', }, - ] as const, + ], functionName: 'foo', data: '0x000000000000000000000000a5cc3c03994db5b0d9a5eedd10cabab0813678ac', }), @@ -265,7 +265,7 @@ test('overloads', () => { stateMutability: 'pure', type: 'function', }, - ] as const, + ], functionName: 'foo', data: '0x0000000000000000000000000000000000000000000000000000000000000069', args: [10n], @@ -290,7 +290,7 @@ test("error: function doesn't exist", () => { stateMutability: 'pure', type: 'function', }, - ] as const, + ], // @ts-expect-error functionName: 'baz', data: '0x000000000000000000000000a5cc3c03994db5b0d9a5eedd10cabab0813678ac', @@ -316,7 +316,7 @@ test("error: function doesn't exist", () => { stateMutability: 'pure', type: 'function', }, - ] as const, + ], functionName: 'foo', data: '0x000000000000000000000000a5cc3c03994db5b0d9a5eedd10cabab0813678ac', }), diff --git a/src/utils/abi/decodeFunctionResult.ts b/src/utils/abi/decodeFunctionResult.ts index bd4c9d040d..5a0711bd59 100644 --- a/src/utils/abi/decodeFunctionResult.ts +++ b/src/utils/abi/decodeFunctionResult.ts @@ -1,4 +1,4 @@ -import { Abi } from 'abitype' +import { Abi, Narrow } from 'abitype' import { AbiFunctionNotFoundError, AbiFunctionOutputsNotFoundError, @@ -16,21 +16,21 @@ const docsPath = '/docs/contract/decodeFunctionResult' export type DecodeFunctionResultArgs< TAbi extends Abi | readonly unknown[] = Abi, - TFunctionName extends string = any, + TFunctionName extends string = string, > = { - abi: TAbi + abi: Narrow functionName: ExtractFunctionNameFromAbi data: Hex } & Partial> export type DecodeFunctionResultResponse< TAbi extends Abi | readonly unknown[] = Abi, - TFunctionName extends string = any, + TFunctionName extends string = string, > = ExtractResultFromAbi export function decodeFunctionResult< - TAbi extends Abi | readonly unknown[] = Abi, - TFunctionName extends string = any, + TAbi extends Abi | readonly unknown[], + TFunctionName extends string, >({ abi, args, diff --git a/src/utils/abi/encodeAbi.test.ts b/src/utils/abi/encodeAbi.test.ts index f9e66c65f0..09b75c6ad0 100644 --- a/src/utils/abi/encodeAbi.test.ts +++ b/src/utils/abi/encodeAbi.test.ts @@ -745,7 +745,7 @@ describe('static', () => { { internalType: 'uint256[2]', name: 'xOut', type: 'uint256[2]' }, { internalType: 'bool', name: 'yOut', type: 'bool' }, { internalType: 'string[3]', name: 'zOut', type: 'string[3]' }, - ] as any, + ], values: [[420n, 69n], true, ['wagmi', 'viem', 'lol']], }), ).toMatchInlineSnapshot( @@ -885,7 +885,7 @@ describe('dynamic', () => { name: 'zIn', type: 'string', }, - ] as const, + ], values: [[420n, 69n], true, 'wagmi'], }), ).toMatchInlineSnapshot( @@ -1202,7 +1202,7 @@ describe('dynamic', () => { name: 'wagmiIn', type: 'tuple', }, - ] as const, + ], values: [ { foo: { diff --git a/src/utils/abi/encodeAbi.ts b/src/utils/abi/encodeAbi.ts index 61c52da0c5..69125b274d 100644 --- a/src/utils/abi/encodeAbi.ts +++ b/src/utils/abi/encodeAbi.ts @@ -2,6 +2,7 @@ import { AbiParameter, AbiParametersToPrimitiveTypes, AbiParameterToPrimitiveType, + Narrow, } from 'abitype' import { @@ -14,25 +15,33 @@ import { Hex } from '../../types' import { concat, padHex, size, slice } from '../data' import { boolToHex, numberToHex, stringToHex } from '../encoding' -export type EncodeAbiArgs = { - params: TParams - values: AbiParametersToPrimitiveTypes +export type EncodeAbiArgs< + TParams extends + | readonly AbiParameter[] + | readonly unknown[] = readonly AbiParameter[], +> = { + params: Narrow + values: TParams extends readonly AbiParameter[] + ? AbiParametersToPrimitiveTypes + : never } /** * @description Encodes a list of primitive values into an ABI-encoded hex value. */ -export function encodeAbi({ - params, - values, -}: EncodeAbiArgs) { +export function encodeAbi< + TParams extends readonly AbiParameter[] | readonly unknown[], +>({ params, values }: EncodeAbiArgs) { if (params.length !== values.length) throw new AbiEncodingLengthMismatchError({ - expectedLength: params.length, + expectedLength: params.length as number, givenLength: values.length, }) // Prepare the parameters to determine dynamic types to encode. - const preparedParams = prepareParams({ params, values }) + const preparedParams = prepareParams({ + params: params as readonly AbiParameter[], + values, + }) const data = encodeParams(preparedParams) if (data.length === 0) return '0x' return data @@ -49,7 +58,7 @@ function prepareParams({ params, values, }: { - params: TParams + params: Narrow values: AbiParametersToPrimitiveTypes }) { let preparedParams: PreparedParam[] = [] diff --git a/src/utils/abi/encodeDeployData.test.ts b/src/utils/abi/encodeDeployData.test.ts index 46ae8d9af4..25c5456394 100644 --- a/src/utils/abi/encodeDeployData.test.ts +++ b/src/utils/abi/encodeDeployData.test.ts @@ -11,7 +11,7 @@ test('constructor()', () => { stateMutability: 'nonpayable', type: 'constructor', }, - ] as const, + ], bytecode: '0x6080604052348015600f57600080fd5b50603f80601d6000396000f3fe6080604052600080fdfea2646970667358221220116554d4ba29ee08da9e97dc54ff9a2a65d67a648140d616fc225a25ff08c86364736f6c63430008070033', }), @@ -20,13 +20,12 @@ test('constructor()', () => { ) expect( encodeDeployData({ - // @ts-expect-error abi: [ { stateMutability: 'nonpayable', type: 'constructor', }, - ] as const, + ], bytecode: '0x6080604052348015600f57600080fd5b50603f80601d6000396000f3fe6080604052600080fdfea2646970667358221220116554d4ba29ee08da9e97dc54ff9a2a65d67a648140d616fc225a25ff08c86364736f6c63430008070033', }), @@ -50,7 +49,7 @@ test('constructor(uint256)', () => { stateMutability: 'nonpayable', type: 'constructor', }, - ] as const, + ], bytecode: '0x6080604052348015600f57600080fd5b50603f80601d6000396000f3fe6080604052600080fdfea2646970667358221220116554d4ba29ee08da9e97dc54ff9a2a65d67a648140d616fc225a25ff08c86364736f6c63430008070033', args: [69420n], @@ -63,8 +62,7 @@ test('constructor(uint256)', () => { test('error: constructor not found', () => { expect(() => encodeDeployData({ - // @ts-expect-error - abi: [{}] as const, + abi: [{}], bytecode: '0x6080604052348015600f57600080fd5b50603f80601d6000396000f3fe6080604052600080fdfea2646970667358221220116554d4ba29ee08da9e97dc54ff9a2a65d67a648140d616fc225a25ff08c86364736f6c63430008070033', args: [69420n], @@ -81,13 +79,12 @@ test('error: constructor not found', () => { test('error: no inputs', () => { expect(() => encodeDeployData({ - // @ts-expect-error abi: [ { stateMutability: 'nonpayable', type: 'constructor', }, - ] as const, + ], bytecode: '0x6080604052348015600f57600080fd5b50603f80601d6000396000f3fe6080604052600080fdfea2646970667358221220116554d4ba29ee08da9e97dc54ff9a2a65d67a648140d616fc225a25ff08c86364736f6c63430008070033', args: [69420n], @@ -104,14 +101,13 @@ test('error: no inputs', () => { expect(() => encodeDeployData({ - // @ts-expect-error abi: [ { inputs: undefined, stateMutability: 'nonpayable', type: 'constructor', }, - ] as const, + ], bytecode: '0x6080604052348015600f57600080fd5b50603f80601d6000396000f3fe6080604052600080fdfea2646970667358221220116554d4ba29ee08da9e97dc54ff9a2a65d67a648140d616fc225a25ff08c86364736f6c63430008070033', args: [69420n], diff --git a/src/utils/abi/encodeDeployData.ts b/src/utils/abi/encodeDeployData.ts index ad823f64b4..a80421e34b 100644 --- a/src/utils/abi/encodeDeployData.ts +++ b/src/utils/abi/encodeDeployData.ts @@ -1,4 +1,4 @@ -import { Abi } from 'abitype' +import { Abi, Narrow } from 'abitype' import { AbiConstructorNotFoundError, @@ -10,19 +10,22 @@ import { encodeAbi } from './encodeAbi' const docsPath = '/docs/contract/encodeDeployData' -export type EncodeDeployDataArgs = { - abi: TAbi - bytecode: Hex -} & ExtractConstructorArgsFromAbi +export type EncodeDeployDataArgs = + { + abi: Narrow + bytecode: Hex + } & ExtractConstructorArgsFromAbi -export function encodeDeployData({ +export function encodeDeployData({ abi, args, bytecode, }: EncodeDeployDataArgs) { if (!args || args.length === 0) return bytecode - const description = abi.find((x) => 'type' in x && x.type === 'constructor') + const description = (abi as Abi).find( + (x) => 'type' in x && x.type === 'constructor', + ) if (!description) throw new AbiConstructorNotFoundError({ docsPath }) if (!('inputs' in description)) throw new AbiConstructorParamsNotFoundError({ docsPath }) diff --git a/src/utils/abi/encodeErrorResult.test.ts b/src/utils/abi/encodeErrorResult.test.ts index 4e543f21a5..22764f91bf 100644 --- a/src/utils/abi/encodeErrorResult.test.ts +++ b/src/utils/abi/encodeErrorResult.test.ts @@ -18,7 +18,6 @@ test('revert SoldOutError()', () => { expect( encodeErrorResult({ abi: [ - // @ts-expect-error { name: 'SoldOutError', type: 'error', @@ -44,7 +43,7 @@ test('revert AccessDeniedError(string)', () => { name: 'AccessDeniedError', type: 'error', }, - ] as const, + ], errorName: 'AccessDeniedError', args: ['you do not have access ser'], }), @@ -116,6 +115,7 @@ test("errors: error doesn't exist", () => { type: 'error', }, ], + // @ts-expect-error errorName: 'AccessDeniedError', args: [ { @@ -139,7 +139,6 @@ test('errors: no inputs', () => { expect(() => encodeErrorResult({ abi: [ - // @ts-expect-error { name: 'AccessDeniedError', type: 'error', @@ -167,7 +166,6 @@ test('errors: no inputs', () => { encodeErrorResult({ abi: [ { - // @ts-expect-error inputs: undefined, name: 'AccessDeniedError', type: 'error', diff --git a/src/utils/abi/encodeErrorResult.ts b/src/utils/abi/encodeErrorResult.ts index 8d47309dc8..9680b2767c 100644 --- a/src/utils/abi/encodeErrorResult.ts +++ b/src/utils/abi/encodeErrorResult.ts @@ -1,10 +1,13 @@ -import { Abi, ExtractAbiErrorNames } from 'abitype' +import { Abi, Narrow } from 'abitype' import { AbiErrorInputsNotFoundError, AbiErrorNotFoundError, } from '../../errors' - -import { ExtractErrorArgsFromAbi, Hex } from '../../types' +import { + ExtractErrorArgsFromAbi, + ExtractErrorNameFromAbi, + Hex, +} from '../../types' import { concatHex } from '../data' import { getFunctionSignature } from '../hash' import { encodeAbi } from './encodeAbi' @@ -14,16 +17,16 @@ import { getAbiItem, GetAbiItemArgs } from './getAbiItem' const docsPath = '/docs/contract/encodeErrorResult' export type EncodeErrorResultArgs< - TAbi extends Abi = Abi, - TErrorName extends ExtractAbiErrorNames = any, + TAbi extends Abi | readonly unknown[] = Abi, + TErrorName extends string = string, > = { - abi: TAbi - errorName: TErrorName + abi: Narrow + errorName: ExtractErrorNameFromAbi } & ExtractErrorArgsFromAbi export function encodeErrorResult< - TAbi extends Abi = Abi, - TErrorName extends ExtractAbiErrorNames = any, + TAbi extends Abi | readonly unknown[], + TErrorName extends string, >({ abi, errorName, args }: EncodeErrorResultArgs) { const description = getAbiItem({ abi, diff --git a/src/utils/abi/encodeEventTopics.test.ts b/src/utils/abi/encodeEventTopics.test.ts index 78714c7d05..b9722b2024 100644 --- a/src/utils/abi/encodeEventTopics.test.ts +++ b/src/utils/abi/encodeEventTopics.test.ts @@ -11,7 +11,7 @@ test('Transfer()', () => { name: 'Transfer', type: 'event', }, - ] as const, + ], eventName: 'Transfer', }), ).toEqual([ @@ -19,13 +19,12 @@ test('Transfer()', () => { ]) expect( encodeEventTopics({ - // @ts-expect-error abi: [ { name: 'Transfer', type: 'event', }, - ] as const, + ], eventName: 'Transfer', }), ).toEqual([ @@ -58,7 +57,7 @@ test('no args: Transfer(address,address,uint256)', () => { name: 'Transfer', type: 'event', }, - ] as const, + ], eventName: 'Transfer', }), ).toEqual([ @@ -91,7 +90,7 @@ test('named args: Transfer(address,address,uint256)', () => { name: 'Transfer', type: 'event', }, - ] as const, + ], eventName: 'Transfer', args: { from: null, @@ -130,7 +129,7 @@ test('named args: Transfer(address,address,uint256)', () => { name: 'Transfer', type: 'event', }, - ] as const, + ], eventName: 'Transfer', args: { from: null, @@ -172,7 +171,7 @@ test('unnamed args: Transfer(address,address,uint256)', () => { name: 'Transfer', type: 'event', }, - ] as const, + ], eventName: 'Transfer', args: [null, '0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC'], }), @@ -205,7 +204,7 @@ test('unnamed args: Transfer(address,address,uint256)', () => { name: 'Transfer', type: 'event', }, - ] as const, + ], eventName: 'Transfer', args: [ null, @@ -240,7 +239,7 @@ test('Foo(string)', () => { name: 'Foo', type: 'event', }, - ] as const, + ], eventName: 'Foo', args: { message: 'hello', @@ -280,7 +279,7 @@ test('Foo((uint,string))', () => { name: 'Bar', type: 'event', }, - ] as const, + ], eventName: 'Bar', args: { x: { @@ -311,7 +310,7 @@ test("errors: event doesn't exist", () => { name: 'Foo', type: 'event', }, - ] as const, + ], // @ts-expect-error eventName: 'Bar', }), @@ -327,14 +326,13 @@ test("errors: event doesn't exist", () => { test("errors: event doesn't exist", () => { expect( encodeEventTopics({ - // @ts-expect-error abi: [ { inputs: undefined, name: 'Foo', type: 'event', }, - ] as const, + ], eventName: 'Foo', // @ts-expect-error args: {}, diff --git a/src/utils/abi/encodeEventTopics.ts b/src/utils/abi/encodeEventTopics.ts index 6c630bf718..60ce04e530 100644 --- a/src/utils/abi/encodeEventTopics.ts +++ b/src/utils/abi/encodeEventTopics.ts @@ -3,13 +3,19 @@ import { AbiParameter, AbiParameterToPrimitiveType, ExtractAbiEventNames, + Narrow, } from 'abitype' import { AbiEventNotFoundError, FilterTypeNotSupportedError, } from '../../errors' -import { EventDefinition, ExtractEventArgsFromAbi, Hex } from '../../types' +import { + EventDefinition, + ExtractEventArgsFromAbi, + ExtractEventNameFromAbi, + Hex, +} from '../../types' import { encodeBytes } from '../encoding' import { keccak256, getEventSignature } from '../hash' import { encodeAbi } from './encodeAbi' @@ -17,16 +23,16 @@ import { formatAbiItem } from './formatAbiItem' import { getAbiItem, GetAbiItemArgs } from './getAbiItem' export type EncodeEventTopicsArgs< - TAbi extends Abi = Abi, - TEventName extends ExtractAbiEventNames = any, + TAbi extends Abi | readonly unknown[] = Abi, + TEventName extends string = string, > = { - abi: TAbi - eventName: TEventName + abi: Narrow + eventName: ExtractEventNameFromAbi } & ExtractEventArgsFromAbi export function encodeEventTopics< - TAbi extends Abi = Abi, - TEventName extends ExtractAbiEventNames = any, + TAbi extends Abi | readonly unknown[], + TEventName extends string, >({ abi, eventName, args }: EncodeEventTopicsArgs) { const abiItem = getAbiItem({ abi, args, name: eventName } as GetAbiItemArgs) if (!abiItem) diff --git a/src/utils/abi/encodeFunctionData.test.ts b/src/utils/abi/encodeFunctionData.test.ts index a859cdaef9..84432e9e6c 100644 --- a/src/utils/abi/encodeFunctionData.test.ts +++ b/src/utils/abi/encodeFunctionData.test.ts @@ -13,13 +13,12 @@ test('foo()', () => { stateMutability: 'nonpayable', type: 'function', }, - ] as const, + ], functionName: 'foo', }), ).toEqual('0xc2985578') expect( encodeFunctionData({ - // @ts-expect-error abi: [ { name: 'foo', @@ -27,7 +26,7 @@ test('foo()', () => { stateMutability: 'nonpayable', type: 'function', }, - ] as const, + ], functionName: 'foo', }), ).toEqual('0xc2985578') @@ -50,7 +49,7 @@ test('bar(uint256)', () => { stateMutability: 'nonpayable', type: 'function', }, - ] as const, + ], functionName: 'bar', args: [1n], }), @@ -98,7 +97,7 @@ test('getVoter((uint256,bool,address,uint256))', () => { stateMutability: 'nonpayable', type: 'function', }, - ] as const, + ], functionName: 'getVoter', args: [ { @@ -125,7 +124,7 @@ test("errors: function doesn't exist", () => { stateMutability: 'nonpayable', type: 'function', }, - ] as const, + ], // @ts-expect-error functionName: 'bar', }), diff --git a/src/utils/abi/encodeFunctionData.ts b/src/utils/abi/encodeFunctionData.ts index 878b289c56..9f3f168b5b 100644 --- a/src/utils/abi/encodeFunctionData.ts +++ b/src/utils/abi/encodeFunctionData.ts @@ -1,4 +1,4 @@ -import { Abi, ExtractAbiFunctionNames } from 'abitype' +import { Abi, Narrow } from 'abitype' import { AbiEncodingLengthMismatchError, @@ -12,16 +12,16 @@ import { formatAbiItem } from './formatAbiItem' import { getAbiItem, GetAbiItemArgs } from './getAbiItem' export type EncodeFunctionDataArgs< - TAbi extends Abi = Abi, - TFunctionName extends string = any, + TAbi extends Abi | readonly unknown[] = Abi, + TFunctionName extends string = string, > = { - abi: TAbi + abi: Narrow functionName: ExtractFunctionNameFromAbi } & ExtractArgsFromAbi export function encodeFunctionData< - TAbi extends Abi = Abi, - TFunctionName extends string = any, + TAbi extends Abi | readonly unknown[], + TFunctionName extends string, >({ abi, args, functionName }: EncodeFunctionDataArgs) { const description = getAbiItem({ abi, diff --git a/src/utils/abi/encodeFunctionResult.test.ts b/src/utils/abi/encodeFunctionResult.test.ts index c876b7d7bb..3925183b50 100644 --- a/src/utils/abi/encodeFunctionResult.test.ts +++ b/src/utils/abi/encodeFunctionResult.test.ts @@ -30,7 +30,7 @@ test('returns ()', () => { }, ], functionName: 'foo', - result: [undefined], + result: undefined, }), ).toEqual('0x') expect( @@ -45,7 +45,6 @@ test('returns ()', () => { }, ], functionName: 'foo', - result: [], }), ).toEqual('0x') }) @@ -67,7 +66,7 @@ test('returns (address)', () => { stateMutability: 'pure', type: 'function', }, - ] as const, + ], functionName: 'foo', result: '0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC', }), @@ -129,17 +128,15 @@ test('returns (Bar)', () => { }, ], functionName: 'bar', - result: [ - { - foo: { - sender: '0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC', - x: 69420n, - y: true, - }, + result: { + foo: { sender: '0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC', - z: 69, + x: 69420n, + y: true, }, - ], + sender: '0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC', + z: 69, + }, }), ).toEqual( '0x000000000000000000000000a5cc3c03994db5b0d9a5eedd10cabab0813678ac0000000000000000000000000000000000000000000000000000000000010f2c0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000a5cc3c03994db5b0d9a5eedd10cabab0813678ac0000000000000000000000000000000000000000000000000000000000000045', @@ -240,6 +237,7 @@ test("error: function doesn't exist", () => { type: 'function', }, ], + // @ts-expect-error functionName: 'baz', result: ['0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC'], }), @@ -258,7 +256,6 @@ test("error: function doesn't exist", () => { expect(() => encodeFunctionResult({ abi: [ - // @ts-expect-error { inputs: [], name: 'foo', diff --git a/src/utils/abi/encodeFunctionResult.ts b/src/utils/abi/encodeFunctionResult.ts index 60c4552846..10010d91b5 100644 --- a/src/utils/abi/encodeFunctionResult.ts +++ b/src/utils/abi/encodeFunctionResult.ts @@ -1,4 +1,4 @@ -import { Abi, ExtractAbiFunctionNames } from 'abitype' +import { Abi, ExtractAbiFunctionNames, Narrow } from 'abitype' import { AbiFunctionNotFoundError, AbiFunctionOutputsNotFoundError, @@ -10,23 +10,25 @@ import { encodeAbi } from './encodeAbi' const docsPath = '/docs/contract/encodeFunctionResult' export type EncodeFunctionResultArgs< - TAbi extends Abi = Abi, - TFunctionName extends string = any, + TAbi extends Abi | readonly unknown[] = Abi, + TFunctionName extends string = string, > = { - abi: TAbi + abi: Narrow functionName: ExtractFunctionNameFromAbi result?: ExtractResultFromAbi } export function encodeFunctionResult< - TAbi extends Abi = Abi, - TFunctionName extends string = any, + TAbi extends Abi | readonly unknown[], + TFunctionName extends string, >({ abi, functionName, result, }: EncodeFunctionResultArgs) { - const description = abi.find((x) => 'name' in x && x.name === functionName) + const description = (abi as Abi).find( + (x) => 'name' in x && x.name === functionName, + ) if (!description) throw new AbiFunctionNotFoundError(functionName, { docsPath }) if (!('outputs' in description)) diff --git a/src/utils/abi/getAbiItem.test.ts b/src/utils/abi/getAbiItem.test.ts index 8d59cce4a0..029cf709b9 100644 --- a/src/utils/abi/getAbiItem.test.ts +++ b/src/utils/abi/getAbiItem.test.ts @@ -47,10 +47,9 @@ test('overloads: no inputs', () => { expect( getAbiItem({ abi: [ - // @ts-expect-error { name: 'balanceOf', - outputs: [{ name: '', type: 'uint256' }], + outputs: [{ name: 'x', type: 'uint256' }], stateMutability: 'view', type: 'function', }, @@ -85,7 +84,6 @@ test('overloads: undefined inputs', () => { getAbiItem({ abi: [ { - // @ts-expect-error inputs: undefined, name: 'balanceOf', outputs: [{ name: '', type: 'uint256' }], @@ -252,7 +250,7 @@ test('overload: different types', () => { stateMutability: 'nonpayable', type: 'function', }, - ] as const + ] expect( getAbiItem({ @@ -366,7 +364,7 @@ test('overloads: tuple', () => { stateMutability: 'nonpayable', type: 'function', }, - ] as const, + ], name: 'foo', args: [ 420n, diff --git a/src/utils/abi/getAbiItem.ts b/src/utils/abi/getAbiItem.ts index fcfa52b621..6aba0bfa26 100644 --- a/src/utils/abi/getAbiItem.ts +++ b/src/utils/abi/getAbiItem.ts @@ -1,20 +1,20 @@ -import type { Abi, AbiParameter, Address } from 'abitype' +import type { Abi, AbiParameter, Address, Narrow } from 'abitype' import type { ExtractArgsFromAbi, ExtractNameFromAbi } from '../../types' import { isAddress } from '../address' export type GetAbiItemArgs< - TAbi extends Abi = Abi, + TAbi extends Abi | readonly unknown[] = Abi, TFunctionName extends string = any, > = { - abi: TAbi + abi: Narrow name: ExtractNameFromAbi } & Partial> export function getAbiItem< - TAbi extends Abi = Abi, - TFunctionName extends string = any, + TAbi extends Abi | readonly unknown[], + TFunctionName extends string, >({ abi, args = [], name }: GetAbiItemArgs) { - const abiItems = abi.filter((x) => 'name' in x && x.name === name) + const abiItems = (abi as Abi).filter((x) => 'name' in x && x.name === name) if (abiItems.length === 0) return undefined if (abiItems.length === 1) return abiItems[0]