/** biome-ignore-all lint/style/noNonNullAssertion: testing */ import type { ExtractAbiFunction } from 'abitype' import { decodeFunctionData, encodeAbiParameters, type Hex } from 'viem' import { CONTRACT_ABIS } from '../../../utils/constants.ts' import type { AbiToType, JSONRPCOptions } from './types.ts' export type balanceOf = ExtractAbiFunction export type decimals = ExtractAbiFunction export type allowance = ExtractAbiFunction export type name = ExtractAbiFunction export type approve = ExtractAbiFunction export type nonces = ExtractAbiFunction export type version = ExtractAbiFunction export interface ERC20Options { balanceOf?: (args: AbiToType) => AbiToType decimals?: (args: AbiToType) => AbiToType allowance?: (args: AbiToType) => AbiToType name?: (args: AbiToType) => AbiToType approve?: (args: AbiToType) => AbiToType version?: (args: AbiToType) => AbiToType nonces?: (args: AbiToType) => AbiToType } /** * Handle ERC20 token contract calls */ export function erc20CallHandler(data: Hex, options: JSONRPCOptions): Hex { let functionName: string let args: readonly unknown[] try { const decoded = decodeFunctionData({ abi: CONTRACT_ABIS.ERC20_PERMIT, data: data as Hex, }) functionName = decoded.functionName args = decoded.args } catch { throw new Error(`ERC20: failed to decode function data: ${data}`) } if (options.debug) { console.debug('ERC20: calling function', functionName, 'with args', args) } switch (functionName) { case 'balanceOf': { if (!options.erc20?.balanceOf) { throw new Error('ERC20: balanceOf is not defined') } return encodeAbiParameters( CONTRACT_ABIS.ERC20_PERMIT.find((abi) => abi.type === 'function' && abi.name === 'balanceOf')!.outputs, options.erc20.balanceOf(args as AbiToType) ) } case 'decimals': { if (!options.erc20?.decimals) { throw new Error('ERC20: decimals is not defined') } return encodeAbiParameters( CONTRACT_ABIS.ERC20_PERMIT.find((abi) => abi.type === 'function' && abi.name === 'decimals')!.outputs, options.erc20.decimals(args as AbiToType) ) } case 'allowance': { if (!options.erc20?.allowance) { throw new Error('ERC20: allowance is not defined') } return encodeAbiParameters( CONTRACT_ABIS.ERC20_PERMIT.find((abi) => abi.type === 'function' && abi.name === 'allowance')!.outputs, options.erc20.allowance(args as AbiToType) ) } case 'name': { if (!options.erc20?.name) { throw new Error('ERC20: name is not defined') } return encodeAbiParameters( CONTRACT_ABIS.ERC20_PERMIT.find((abi) => abi.type === 'function' && abi.name === 'name')!.outputs, options.erc20.name(args as AbiToType) ) } case 'approve': { if (!options.erc20?.approve) { throw new Error('ERC20: approve is not defined') } return encodeAbiParameters( CONTRACT_ABIS.ERC20_PERMIT.find((abi) => abi.type === 'function' && abi.name === 'approve')!.outputs, options.erc20.approve(args as AbiToType) ) } case 'version': { if (!options.erc20?.version) { throw new Error('ERC20: version is not defined') } return encodeAbiParameters( CONTRACT_ABIS.ERC20_PERMIT.find((abi) => abi.type === 'function' && abi.name === 'version')!.outputs, options.erc20.version(args as AbiToType) ) } case 'nonces': { if (!options.erc20?.nonces) { throw new Error('ERC20: nonces is not defined') } return encodeAbiParameters( CONTRACT_ABIS.ERC20_PERMIT.find((abi) => abi.type === 'function' && abi.name === 'nonces')!.outputs, options.erc20.nonces(args as AbiToType) ) } default: { throw new Error(`ERC20: unknown function: ${functionName} with args: ${args}`) } } }