/* 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 . */ /** * * @module ABI */ import { AbiError } from 'web3-errors'; import { AbiInput, HexString } from 'web3-types'; import { decodeParameters as decodeParametersInternal } from '../coders/decode.js'; import { encodeParameters } from '../coders/encode.js'; export { encodeParameters, inferTypesAndEncodeParameters } from '../coders/encode.js'; /** * Encodes a parameter based on its type to its ABI representation. * @param abi - The type of the parameter. See the [Solidity documentation](https://docs.soliditylang.org/en/develop/types.html) for a list of types. * @param param - The actual parameter to encode. * @returns - The ABI encoded parameter * @example * ```ts * const res = web3.eth.abi.encodeParameter("uint256", "2345675643"); * console.log(res); * 0x000000000000000000000000000000000000000000000000000000008bd02b7b * * const res = web3.eth.abi.encodeParameter("uint", "2345675643"); * * console.log(res); * >0x000000000000000000000000000000000000000000000000000000008bd02b7b * * const res = web3.eth.abi.encodeParameter("bytes32", "0xdf3234"); * * console.log(res); * >0xdf32340000000000000000000000000000000000000000000000000000000000 * * const res = web3.eth.abi.encodeParameter("bytes", "0xdf3234"); * * console.log(res); * > 0x00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000003df32340000000000000000000000000000000000000000000000000000000000 * * const res = web3.eth.abi.encodeParameter("bytes32[]", ["0xdf3234", "0xfdfd"]); * * console.log(res); * > 0x00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002df32340000000000000000000000000000000000000000000000000000000000fdfd000000000000000000000000000000000000000000000000000000000000 * * const res = web3.eth.abi.encodeParameter( * { * ParentStruct: { * propertyOne: "uint256", * propertyTwo: "uint256", * childStruct: { * propertyOne: "uint256", * propertyTwo: "uint256", * }, * }, * }, * { * propertyOne: 42, * propertyTwo: 56, * childStruct: { * propertyOne: 45, * propertyTwo: 78, * }, * } * ); * * console.log(res); * > 0x000000000000000000000000000000000000000000000000000000000000002a0000000000000000000000000000000000000000000000000000000000000038000000000000000000000000000000000000000000000000000000000000002d000000000000000000000000000000000000000000000000000000000000004e * ``` */ export const encodeParameter = (abi: AbiInput, param: unknown): string => encodeParameters([abi], [param]); /** * Should be used to decode list of params */ export const decodeParametersWith = ( abis: AbiInput[] | ReadonlyArray, bytes: HexString, loose: boolean, ): { [key: string]: unknown; __length__: number } => { try { if (abis.length > 0 && (!bytes || bytes === '0x' || bytes === '0X')) { throw new AbiError( "Returned values aren't valid, did it run Out of Gas? " + 'You might also see this error if you are not using the ' + 'correct ABI for the contract you are retrieving data from, ' + 'requesting data from a block number that does not exist, ' + 'or querying a node which is not fully synced.', ); } return decodeParametersInternal(abis, `0x${bytes.replace(/0x/i, '')}`, loose); } catch (err) { throw new AbiError(`Parameter decoding error: ${(err as Error).message}`, { internalErr: err, }); } }; /** * Should be used to decode list of params */ /** * Decodes ABI encoded parameters to its JavaScript types. * @param abi - An array of {@link AbiInput}. See the [Solidity documentation](https://docs.soliditylang.org/en/develop/types.html) for a list of types. * @param bytes - The ABI byte code to decode * @returns - The result object containing the decoded parameters. * @example * ```ts * let res = web3.eth.abi.decodeParameters( * ["string", "uint256"], * "0x000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000ea000000000000000000000000000000000000000000000000000000000000000848656c6c6f212521000000000000000000000000000000000000000000000000" * ); * console.log(res); * > { '0': 'Hello!%!', '1': 234n, __length__: 2 } * * let res = web3.eth.abi.decodeParameters( * [ * { * type: "string", * name: "myString", * }, * { * type: "uint256", * name: "myNumber", * }, * ], * "0x000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000ea000000000000000000000000000000000000000000000000000000000000000848656c6c6f212521000000000000000000000000000000000000000000000000" * ); * console.log(res); * > { * '0': 'Hello!%!', * '1': 234n, * __length__: 2, * myString: 'Hello!%!', * myNumber: 234n * } * * const res = web3.eth.abi.decodeParameters( * [ * "uint8[]", * { * ParentStruct: { * propertyOne: "uint256", * propertyTwo: "uint256", * childStruct: { * propertyOne: "uint256", * propertyTwo: "uint256", * }, * }, * }, * ], * "0x00000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000002a0000000000000000000000000000000000000000000000000000000000000038000000000000000000000000000000000000000000000000000000000000002d000000000000000000000000000000000000000000000000000000000000004e0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000002a0000000000000000000000000000000000000000000000000000000000000018" * ); * console.log(res); * > * '0': [ 42n, 24n ], * '1': { * '0': 42n, * '1': 56n, * '2': { * '0': 45n, * '1': 78n, * __length__: 2, * propertyOne: 45n, * propertyTwo: 78n * }, * __length__: 3, * propertyOne: 42n, * propertyTwo: 56n, * childStruct: { * '0': 45n, * '1': 78n, * __length__: 2, * propertyOne: 45n, * propertyTwo: 78n * } * }, * __length__: 2, * ParentStruct: { * '0': 42n, * '1': 56n, * '2': { * '0': 45n, * '1': 78n, * __length__: 2, * propertyOne: 45n, * propertyTwo: 78n * }, * __length__: 3, * propertyOne: 42n, * propertyTwo: 56n, * childStruct: { * '0': 45n, * '1': 78n, * __length__: 2, * propertyOne: 45n, * propertyTwo: 78n * } * } *} * ``` */ export const decodeParameters = ( abi: AbiInput[] | ReadonlyArray, bytes: HexString, ): { [key: string]: unknown; __length__: number } => decodeParametersWith(abi, bytes, false); /** * Should be used to decode bytes to plain param */ /** * Decodes an ABI encoded parameter to its JavaScript type. * @param abi - The type of the parameter. See the [Solidity documentation](https://docs.soliditylang.org/en/develop/types.html) for a list of types. * @param bytes - The ABI byte code to decode * @returns - The decoded parameter * @example * ```ts * const res = web3.eth.abi.decodeParameter( * "uint256", * "0x0000000000000000000000000000000000000000000000000000000000000010" * ); * console.log(res); * > 16n * * const res = web3.eth.abi.decodeParameter( * "string", * "0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000848656c6c6f212521000000000000000000000000000000000000000000000000" * ); * * console.log(res); * > Hello!%! * * const res = web3.eth.abi.decodeParameter( * { * ParentStruct: { * propertyOne: "uint256", * propertyTwo: "uint256", * childStruct: { * propertyOne: "uint256", * propertyTwo: "uint256", * }, * }, * }, * "0x000000000000000000000000000000000000000000000000000000000000002a0000000000000000000000000000000000000000000000000000000000000038000000000000000000000000000000000000000000000000000000000000002d000000000000000000000000000000000000000000000000000000000000004e" * ); * * console.log(res); * { * '0': 42n, * '1': 56n, * '2': { * '0': 45n, * '1': 78n, * __length__: 2, * propertyOne: 45n, * propertyTwo: 78n * }, * __length__: 3, * propertyOne: 42n, * propertyTwo: 56n, * childStruct: { * '0': 45n, * '1': 78n, * __length__: 2, * propertyOne: 45n, * propertyTwo: 78n * } *} * ``` */ export const decodeParameter = (abi: AbiInput, bytes: HexString): unknown => decodeParameters([abi], bytes)['0'];