web3-eth-contract
Advanced tools
Comparing version 4.3.0 to 4.3.1-dev.1c03666.0
import { Web3Context, Web3EventEmitter, Web3PromiEvent } from 'web3-core'; | ||
import { NewHeadsSubscription, SendTransactionEvents } from 'web3-eth'; | ||
import { AbiFunctionFragment, ContractAbi, ContractConstructorArgs, ContractEvent, ContractEvents, ContractMethod, ContractMethodInputParameters, ContractMethodOutputParameters, Address, EthExecutionAPI, Filter, FilterAbis, HexString, ContractInitOptions, PayableCallOptions, DataFormat, DEFAULT_RETURN_FORMAT, EventLog, ContractOptions, TransactionReceipt, FormatType } from 'web3-types'; | ||
import { AbiFunctionFragment, ContractAbi, ContractConstructorArgs, ContractEvent, ContractEvents, ContractMethod, ContractMethodInputParameters, ContractMethodOutputParameters, Address, EthExecutionAPI, Filter, FilterAbis, HexString, ContractInitOptions, PayableCallOptions, DataFormat, DEFAULT_RETURN_FORMAT, EventLog, ContractOptions, TransactionReceipt, FormatType, DecodedParams } from 'web3-types'; | ||
import { LogsSubscription } from './log_subscription.js'; | ||
@@ -163,2 +163,63 @@ import { ContractEventOptions, NonPayableMethodObject, PayableMethodObject, PayableTxOptions, Web3ContractContext } from './types.js'; | ||
* | ||
* ### decodeMethodData | ||
* Decodes the given ABI-encoded data, revealing both the method name and the parameters used in the smart contract call. | ||
* This function reverses the encoding process happens at the method `encodeABI`. | ||
* It's particularly useful for debugging and understanding the interactions with and between smart contracts. | ||
* | ||
* #### Parameters | ||
* | ||
* - `data` **HexString**: The string of ABI-encoded data that needs to be decoded. This should include the method signature and the encoded parameters. | ||
* | ||
* #### Returns | ||
* | ||
* - **Object**: This object combines both the decoded parameters and the method name in a readable format. Specifically, the returned object contains: | ||
* - `__method__` **String**: The name of the contract method, reconstructed from the ABI. | ||
* - `__length__` **Number**: The number of parameters decoded. | ||
* - Additional properties representing each parameter by name, as well as their position and values. | ||
* | ||
* #### Example | ||
* | ||
* Given an ABI-encoded string from a transaction, you can decode this data to identify the method called and the parameters passed. | ||
* Here's a simplified example: | ||
* | ||
* | ||
* ```typescript | ||
* const GreeterAbi = [ | ||
* { | ||
* inputs: [ | ||
* { | ||
* internalType: 'string', | ||
* name: '_greeting', | ||
* type: 'string', | ||
* }, | ||
* ], | ||
* name: 'setGreeting', | ||
* outputs: [], | ||
* type: 'function', | ||
* }, | ||
* ]; | ||
* const contract = new Contract(GreeterAbi); // Initialize with your contract's ABI | ||
* | ||
* // The ABI-encoded data string for "setGreeting('Hello World')" | ||
* const encodedData = | ||
* '0xa41368620000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000b48656c6c6f20576f726c64000000000000000000000000000000000000000000'; | ||
* | ||
* try { | ||
* const decoded = contract.decodeMethodData(encodedData); | ||
* console.log(decoded.__method__); // Outputs: "setGreeting(string)" | ||
* console.log(decoded); // Outputs the detailed parameter data | ||
* // This tells that the method called was `setGreeting` with a single string parameter "Hello World": | ||
* // { | ||
* // __method__: 'setGreeting(string)', | ||
* // __length__: 1, | ||
* // '0': 'Hello World', | ||
* // _greeting: 'Hello World' | ||
* // } | ||
* } catch (error) { | ||
* console.error(error); | ||
* } | ||
* ``` | ||
* | ||
* ### createAccessList | ||
@@ -371,2 +432,18 @@ * This will create an access list a method execution will access when executed in the EVM. | ||
* | ||
* // decoding | ||
* myContract.deploy({ | ||
* input: '0x12345...', | ||
* // arguments: [123, 'My Greeting'] if you just need to decode the data, you can skip the arguments | ||
* }) | ||
* .decodeData('0x12345...0000012345678765432'); | ||
* > { | ||
* __method__: 'constructor', | ||
* __length__: 2, | ||
* '0': '123', | ||
* _id: '123', | ||
* '1': 'My Greeting', | ||
* _greeting: 'My Greeting', | ||
* } | ||
* | ||
* | ||
* // Gas estimation | ||
@@ -402,2 +479,6 @@ * myContract.deploy({ | ||
encodeABI: () => string; | ||
decodeData: (data: HexString) => { | ||
__method__: string; | ||
__length__: number; | ||
}; | ||
}; | ||
@@ -447,2 +528,5 @@ /** | ||
private _parseAndSetAddress; | ||
decodeMethodData(data: HexString): DecodedParams & { | ||
__method__: string; | ||
}; | ||
private _parseAndSetJsonInterface; | ||
@@ -449,0 +533,0 @@ private _getAbiParams; |
@@ -160,2 +160,63 @@ "use strict"; | ||
* | ||
* ### decodeMethodData | ||
* Decodes the given ABI-encoded data, revealing both the method name and the parameters used in the smart contract call. | ||
* This function reverses the encoding process happens at the method `encodeABI`. | ||
* It's particularly useful for debugging and understanding the interactions with and between smart contracts. | ||
* | ||
* #### Parameters | ||
* | ||
* - `data` **HexString**: The string of ABI-encoded data that needs to be decoded. This should include the method signature and the encoded parameters. | ||
* | ||
* #### Returns | ||
* | ||
* - **Object**: This object combines both the decoded parameters and the method name in a readable format. Specifically, the returned object contains: | ||
* - `__method__` **String**: The name of the contract method, reconstructed from the ABI. | ||
* - `__length__` **Number**: The number of parameters decoded. | ||
* - Additional properties representing each parameter by name, as well as their position and values. | ||
* | ||
* #### Example | ||
* | ||
* Given an ABI-encoded string from a transaction, you can decode this data to identify the method called and the parameters passed. | ||
* Here's a simplified example: | ||
* | ||
* | ||
* ```typescript | ||
* const GreeterAbi = [ | ||
* { | ||
* inputs: [ | ||
* { | ||
* internalType: 'string', | ||
* name: '_greeting', | ||
* type: 'string', | ||
* }, | ||
* ], | ||
* name: 'setGreeting', | ||
* outputs: [], | ||
* type: 'function', | ||
* }, | ||
* ]; | ||
* const contract = new Contract(GreeterAbi); // Initialize with your contract's ABI | ||
* | ||
* // The ABI-encoded data string for "setGreeting('Hello World')" | ||
* const encodedData = | ||
* '0xa41368620000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000b48656c6c6f20576f726c64000000000000000000000000000000000000000000'; | ||
* | ||
* try { | ||
* const decoded = contract.decodeMethodData(encodedData); | ||
* console.log(decoded.__method__); // Outputs: "setGreeting(string)" | ||
* console.log(decoded); // Outputs the detailed parameter data | ||
* // This tells that the method called was `setGreeting` with a single string parameter "Hello World": | ||
* // { | ||
* // __method__: 'setGreeting(string)', | ||
* // __length__: 1, | ||
* // '0': 'Hello World', | ||
* // _greeting: 'Hello World' | ||
* // } | ||
* } catch (error) { | ||
* console.error(error); | ||
* } | ||
* ``` | ||
* | ||
* ### createAccessList | ||
@@ -200,4 +261,3 @@ * This will create an access list a method execution will access when executed in the EVM. | ||
let provider; | ||
if (typeof addressOrOptionsOrContext === 'object' && | ||
'provider' in addressOrOptionsOrContext) { | ||
if (typeof addressOrOptionsOrContext === 'object' && 'provider' in addressOrOptionsOrContext) { | ||
provider = addressOrOptionsOrContext.provider; | ||
@@ -209,4 +269,3 @@ } | ||
} | ||
else if (typeof contextOrReturnFormat === 'object' && | ||
'provider' in contextOrReturnFormat) { | ||
else if (typeof contextOrReturnFormat === 'object' && 'provider' in contextOrReturnFormat) { | ||
provider = contextOrReturnFormat.provider; | ||
@@ -433,2 +492,18 @@ } | ||
* | ||
* // decoding | ||
* myContract.deploy({ | ||
* input: '0x12345...', | ||
* // arguments: [123, 'My Greeting'] if you just need to decode the data, you can skip the arguments | ||
* }) | ||
* .decodeData('0x12345...0000012345678765432'); | ||
* > { | ||
* __method__: 'constructor', | ||
* __length__: 2, | ||
* '0': '123', | ||
* _id: '123', | ||
* '1': 'My Greeting', | ||
* _greeting: 'My Greeting', | ||
* } | ||
* | ||
* | ||
* // Gas estimation | ||
@@ -481,2 +556,3 @@ * myContract.deploy({ | ||
encodeABI: () => (0, encoding_js_1.encodeMethodABI)(abi, args, (0, web3_utils_1.format)({ format: 'bytes' }, deployData, web3_types_1.DEFAULT_RETURN_FORMAT)), | ||
decodeData: (data) => (Object.assign(Object.assign({}, (0, encoding_js_1.decodeMethodParams)(abi, data.replace(deployData, ''), false)), { __method__: abi.type })), | ||
}; | ||
@@ -523,4 +599,3 @@ } | ||
if (Array.isArray(filter[key])) { | ||
return filter[key].some((v) => String(log.returnValues[key]).toUpperCase() === | ||
String(v).toUpperCase()); | ||
return filter[key].some((v) => String(log.returnValues[key]).toUpperCase() === String(v).toUpperCase()); | ||
} | ||
@@ -533,4 +608,3 @@ const inputAbi = (_a = abi.inputs) === null || _a === void 0 ? void 0 : _a.filter(input => input.name === key)[0]; | ||
} | ||
return (String(log.returnValues[key]).toUpperCase() === | ||
String(filter[key]).toUpperCase()); | ||
return String(log.returnValues[key]).toUpperCase() === String(filter[key]).toUpperCase(); | ||
}); | ||
@@ -547,2 +621,11 @@ }); | ||
} | ||
decodeMethodData(data) { | ||
const methodSignature = data.slice(0, 10); | ||
const functionsAbis = this._jsonInterface.filter(j => j.type !== 'error'); | ||
const abi = functionsAbis.find(a => methodSignature === (0, web3_eth_abi_1.encodeFunctionSignature)((0, web3_eth_abi_1.jsonInterfaceMethodToString)(a))); | ||
if (!abi) { | ||
throw new web3_errors_1.Web3ContractError(`The ABI for the provided method signature ${methodSignature} was not found.`); | ||
} | ||
return Object.assign(Object.assign({}, (0, encoding_js_1.decodeMethodParams)(abi, data)), { __method__: (0, web3_eth_abi_1.jsonInterfaceMethodToString)(abi) }); | ||
} | ||
_parseAndSetJsonInterface(abis, returnFormat = web3_types_1.DEFAULT_RETURN_FORMAT) { | ||
@@ -561,2 +644,3 @@ var _a, _b, _c, _d, _e; | ||
const methodSignature = (0, web3_eth_abi_1.encodeFunctionSignature)(methodName); | ||
abi.methodNameWithInputs = methodName; | ||
abi.signature = methodSignature; | ||
@@ -573,13 +657,15 @@ // make constant and payable backwards compatible | ||
const contractMethod = this._createContractMethod(abiFragment, errorsAbi); | ||
const exactContractMethod = this._createContractMethod(abiFragment, errorsAbi, true); | ||
this._functions[methodName] = { | ||
signature: methodSignature, | ||
method: contractMethod, | ||
method: exactContractMethod, | ||
}; | ||
// We don't know a particular type of the Abi method so can't type check | ||
this._methods[abi.name] = this._functions[methodName].method; | ||
this._methods[abi.name] = contractMethod; | ||
// We don't know a particular type of the Abi method so can't type check | ||
this._methods[methodName] = this._functions[methodName].method; | ||
this._methods[methodName] = | ||
exactContractMethod; | ||
// We don't know a particular type of the Abi method so can't type check | ||
this._methods[methodSignature] = this | ||
._functions[methodName].method; | ||
this._methods[methodSignature] = | ||
exactContractMethod; | ||
} | ||
@@ -616,8 +702,11 @@ else if ((0, web3_eth_abi_1.isAbiEventFragment)(abi)) { | ||
} | ||
_createContractMethod(abiArr, errorsAbis) { | ||
_createContractMethod(abiArr, errorsAbis, exact = false) { | ||
const abi = abiArr[abiArr.length - 1]; | ||
return (...params) => { | ||
var _a, _b; | ||
var _a, _b, _c; | ||
let abiParams; | ||
const abis = (_a = this._overloadedMethodAbis.get(abi.name)) !== null && _a !== void 0 ? _a : []; | ||
const abis = (_b = (exact | ||
? (_a = this._overloadedMethodAbis | ||
.get(abi.name)) === null || _a === void 0 ? void 0 : _a.filter(_abi => _abi.signature === abi.signature) | ||
: this._overloadedMethodAbis.get(abi.name))) !== null && _b !== void 0 ? _b : []; | ||
let methodAbi = abis[0]; | ||
@@ -628,6 +717,8 @@ const internalErrorsAbis = errorsAbis; | ||
abiParams = this._getAbiParams(methodAbi, params); | ||
web3_validator_1.validator.validate((_b = abi.inputs) !== null && _b !== void 0 ? _b : [], abiParams); | ||
web3_validator_1.validator.validate((_c = abi.inputs) !== null && _c !== void 0 ? _c : [], abiParams); | ||
} | ||
else { | ||
const errors = []; | ||
// all the methods that have is valid for the given inputs | ||
const applicableMethodAbi = []; | ||
for (const _abi of arrayOfAbis) { | ||
@@ -637,4 +728,3 @@ try { | ||
web3_validator_1.validator.validate(_abi.inputs, abiParams); | ||
methodAbi = _abi; | ||
break; | ||
applicableMethodAbi.push(_abi); | ||
} | ||
@@ -645,2 +735,14 @@ catch (e) { | ||
} | ||
if (applicableMethodAbi.length === 1) { | ||
[methodAbi] = applicableMethodAbi; // take the first item that is the only item in the array | ||
} | ||
else if (applicableMethodAbi.length > 1) { | ||
[methodAbi] = applicableMethodAbi; // take the first item in the array | ||
console.warn(`Multiple methods found that is compatible with the given inputs.\n\tFound ${applicableMethodAbi.length} compatible methods: ${JSON.stringify(applicableMethodAbi.map(m => `${m.methodNameWithInputs} (signature: ${m.signature})`))} \n\tThe first one will be used: ${methodAbi.methodNameWithInputs}`); | ||
// TODO: 5.x Should throw a new error with the list of methods found. | ||
// Related issue: https://github.com/web3/web3.js/issues/6923 | ||
// This is in order to provide an error message when there is more than one method found that fits the inputs. | ||
// To do that, replace the pervious line of code with something like the following line: | ||
// throw new Web3ValidatorError({ message: 'Multiple methods found', ... list of applicable methods })); | ||
} | ||
if (errors.length === arrayOfAbis.length) { | ||
@@ -652,5 +754,3 @@ throw new web3_validator_1.Web3ValidatorError(errors); | ||
arguments: abiParams, | ||
call: (options, block) => __awaiter(this, void 0, void 0, function* () { | ||
return this._contractMethodCall(methodAbi, abiParams, internalErrorsAbis, options, block); | ||
}), | ||
call: (options, block) => __awaiter(this, void 0, void 0, function* () { return this._contractMethodCall(methodAbi, abiParams, internalErrorsAbis, options, block); }), | ||
send: (options) => this._contractMethodSend(methodAbi, abiParams, internalErrorsAbis, options), | ||
@@ -666,2 +766,3 @@ estimateGas: (options, returnFormat = web3_types_1.DEFAULT_RETURN_FORMAT) => __awaiter(this, void 0, void 0, function* () { | ||
encodeABI: () => (0, encoding_js_1.encodeMethodABI)(methodAbi, abiParams), | ||
decodeData: (data) => (0, encoding_js_1.decodeMethodParams)(methodAbi, data), | ||
createAccessList: (options, block) => __awaiter(this, void 0, void 0, function* () { | ||
@@ -668,0 +769,0 @@ return this._contractMethodCreateAccessList(methodAbi, abiParams, internalErrorsAbis, options, block); |
@@ -10,2 +10,6 @@ import { AbiConstructorFragment, AbiEventFragment, AbiFunctionFragment, Filter, HexString, ContractOptions } from 'web3-types'; | ||
export declare const encodeMethodABI: (abi: AbiFunctionFragment | AbiConstructorFragment, args: unknown[], deployData?: HexString) => string; | ||
export declare const decodeMethodParams: (abi: AbiFunctionFragment | AbiConstructorFragment, data: HexString, methodSignatureProvided?: boolean) => { | ||
[key: string]: unknown; | ||
__length__: number; | ||
}; | ||
export declare const decodeMethodReturn: (abi: AbiFunctionFragment, returnValues?: HexString) => unknown; |
@@ -19,3 +19,3 @@ "use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.decodeMethodReturn = exports.encodeMethodABI = exports.encodeEventABI = exports.decodeEventABI = void 0; | ||
exports.decodeMethodReturn = exports.decodeMethodParams = exports.encodeMethodABI = exports.encodeEventABI = exports.decodeEventABI = void 0; | ||
const web3_utils_1 = require("web3-utils"); | ||
@@ -111,2 +111,13 @@ const web3_types_1 = require("web3-types"); | ||
exports.encodeMethodABI = encodeMethodABI; | ||
const decodeMethodParams = (abi, data, methodSignatureProvided = true) => { | ||
const value = methodSignatureProvided && data && data.length >= 10 && data.startsWith('0x') | ||
? data.slice(10) | ||
: data; | ||
if (!abi.inputs) { | ||
throw new web3_errors_1.Web3ContractError('No inputs found in the ABI'); | ||
} | ||
const result = (0, web3_eth_abi_1.decodeParameters)([...abi.inputs], value); | ||
return result; | ||
}; | ||
exports.decodeMethodParams = decodeMethodParams; | ||
const decodeMethodReturn = (abi, returnValues) => { | ||
@@ -113,0 +124,0 @@ // If it was constructor then we need to return contract address |
@@ -167,2 +167,9 @@ import { Web3ContextInitOptions, Web3PromiEvent } from 'web3-core'; | ||
/** | ||
* Decode raw result of method call into readable value(s). | ||
* | ||
* @param data - The data to decode. | ||
* @returns - The decoded data. | ||
*/ | ||
decodeData<SpecialInputs = Inputs>(data: HexString): SpecialInputs; | ||
/** | ||
* This method generates an access list for a transaction. You must specify a `from` address and `gas` if it’s not specified in options. | ||
@@ -338,2 +345,9 @@ * | ||
/** | ||
* Decode raw result of method call into readable value(s). | ||
* | ||
* @param data - The data to decode. | ||
* @returns - The decoded data. | ||
*/ | ||
decodeData<SpecialInputs = Inputs>(data: HexString): SpecialInputs; | ||
/** | ||
* This method generates an access list for a transaction. You must specify a `from` address and `gas` if it’s not specified in options. | ||
@@ -340,0 +354,0 @@ * |
@@ -33,3 +33,3 @@ /* | ||
import { isNullish, validator, utils as validatorUtils, Web3ValidatorError, } from 'web3-validator'; | ||
import { decodeMethodReturn, encodeEventABI, encodeMethodABI } from './encoding.js'; | ||
import { decodeMethodReturn, decodeMethodParams, encodeEventABI, encodeMethodABI, } from './encoding.js'; | ||
import { LogsSubscription } from './log_subscription.js'; | ||
@@ -158,2 +158,63 @@ import { getCreateAccessListParams, getEstimateGasParams, getEthTxCallParams, getSendTxParams, isWeb3ContractContext, } from './utils.js'; | ||
* | ||
* ### decodeMethodData | ||
* Decodes the given ABI-encoded data, revealing both the method name and the parameters used in the smart contract call. | ||
* This function reverses the encoding process happens at the method `encodeABI`. | ||
* It's particularly useful for debugging and understanding the interactions with and between smart contracts. | ||
* | ||
* #### Parameters | ||
* | ||
* - `data` **HexString**: The string of ABI-encoded data that needs to be decoded. This should include the method signature and the encoded parameters. | ||
* | ||
* #### Returns | ||
* | ||
* - **Object**: This object combines both the decoded parameters and the method name in a readable format. Specifically, the returned object contains: | ||
* - `__method__` **String**: The name of the contract method, reconstructed from the ABI. | ||
* - `__length__` **Number**: The number of parameters decoded. | ||
* - Additional properties representing each parameter by name, as well as their position and values. | ||
* | ||
* #### Example | ||
* | ||
* Given an ABI-encoded string from a transaction, you can decode this data to identify the method called and the parameters passed. | ||
* Here's a simplified example: | ||
* | ||
* | ||
* ```typescript | ||
* const GreeterAbi = [ | ||
* { | ||
* inputs: [ | ||
* { | ||
* internalType: 'string', | ||
* name: '_greeting', | ||
* type: 'string', | ||
* }, | ||
* ], | ||
* name: 'setGreeting', | ||
* outputs: [], | ||
* type: 'function', | ||
* }, | ||
* ]; | ||
* const contract = new Contract(GreeterAbi); // Initialize with your contract's ABI | ||
* | ||
* // The ABI-encoded data string for "setGreeting('Hello World')" | ||
* const encodedData = | ||
* '0xa41368620000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000b48656c6c6f20576f726c64000000000000000000000000000000000000000000'; | ||
* | ||
* try { | ||
* const decoded = contract.decodeMethodData(encodedData); | ||
* console.log(decoded.__method__); // Outputs: "setGreeting(string)" | ||
* console.log(decoded); // Outputs the detailed parameter data | ||
* // This tells that the method called was `setGreeting` with a single string parameter "Hello World": | ||
* // { | ||
* // __method__: 'setGreeting(string)', | ||
* // __length__: 1, | ||
* // '0': 'Hello World', | ||
* // _greeting: 'Hello World' | ||
* // } | ||
* } catch (error) { | ||
* console.error(error); | ||
* } | ||
* ``` | ||
* | ||
* ### createAccessList | ||
@@ -198,4 +259,3 @@ * This will create an access list a method execution will access when executed in the EVM. | ||
let provider; | ||
if (typeof addressOrOptionsOrContext === 'object' && | ||
'provider' in addressOrOptionsOrContext) { | ||
if (typeof addressOrOptionsOrContext === 'object' && 'provider' in addressOrOptionsOrContext) { | ||
provider = addressOrOptionsOrContext.provider; | ||
@@ -207,4 +267,3 @@ } | ||
} | ||
else if (typeof contextOrReturnFormat === 'object' && | ||
'provider' in contextOrReturnFormat) { | ||
else if (typeof contextOrReturnFormat === 'object' && 'provider' in contextOrReturnFormat) { | ||
provider = contextOrReturnFormat.provider; | ||
@@ -431,2 +490,18 @@ } | ||
* | ||
* // decoding | ||
* myContract.deploy({ | ||
* input: '0x12345...', | ||
* // arguments: [123, 'My Greeting'] if you just need to decode the data, you can skip the arguments | ||
* }) | ||
* .decodeData('0x12345...0000012345678765432'); | ||
* > { | ||
* __method__: 'constructor', | ||
* __length__: 2, | ||
* '0': '123', | ||
* _id: '123', | ||
* '1': 'My Greeting', | ||
* _greeting: 'My Greeting', | ||
* } | ||
* | ||
* | ||
* // Gas estimation | ||
@@ -479,2 +554,3 @@ * myContract.deploy({ | ||
encodeABI: () => encodeMethodABI(abi, args, format({ format: 'bytes' }, deployData, DEFAULT_RETURN_FORMAT)), | ||
decodeData: (data) => (Object.assign(Object.assign({}, decodeMethodParams(abi, data.replace(deployData, ''), false)), { __method__: abi.type })), | ||
}; | ||
@@ -521,4 +597,3 @@ } | ||
if (Array.isArray(filter[key])) { | ||
return filter[key].some((v) => String(log.returnValues[key]).toUpperCase() === | ||
String(v).toUpperCase()); | ||
return filter[key].some((v) => String(log.returnValues[key]).toUpperCase() === String(v).toUpperCase()); | ||
} | ||
@@ -531,4 +606,3 @@ const inputAbi = (_a = abi.inputs) === null || _a === void 0 ? void 0 : _a.filter(input => input.name === key)[0]; | ||
} | ||
return (String(log.returnValues[key]).toUpperCase() === | ||
String(filter[key]).toUpperCase()); | ||
return String(log.returnValues[key]).toUpperCase() === String(filter[key]).toUpperCase(); | ||
}); | ||
@@ -545,2 +619,11 @@ }); | ||
} | ||
decodeMethodData(data) { | ||
const methodSignature = data.slice(0, 10); | ||
const functionsAbis = this._jsonInterface.filter(j => j.type !== 'error'); | ||
const abi = functionsAbis.find(a => methodSignature === encodeFunctionSignature(jsonInterfaceMethodToString(a))); | ||
if (!abi) { | ||
throw new Web3ContractError(`The ABI for the provided method signature ${methodSignature} was not found.`); | ||
} | ||
return Object.assign(Object.assign({}, decodeMethodParams(abi, data)), { __method__: jsonInterfaceMethodToString(abi) }); | ||
} | ||
_parseAndSetJsonInterface(abis, returnFormat = DEFAULT_RETURN_FORMAT) { | ||
@@ -559,2 +642,3 @@ var _a, _b, _c, _d, _e; | ||
const methodSignature = encodeFunctionSignature(methodName); | ||
abi.methodNameWithInputs = methodName; | ||
abi.signature = methodSignature; | ||
@@ -571,13 +655,15 @@ // make constant and payable backwards compatible | ||
const contractMethod = this._createContractMethod(abiFragment, errorsAbi); | ||
const exactContractMethod = this._createContractMethod(abiFragment, errorsAbi, true); | ||
this._functions[methodName] = { | ||
signature: methodSignature, | ||
method: contractMethod, | ||
method: exactContractMethod, | ||
}; | ||
// We don't know a particular type of the Abi method so can't type check | ||
this._methods[abi.name] = this._functions[methodName].method; | ||
this._methods[abi.name] = contractMethod; | ||
// We don't know a particular type of the Abi method so can't type check | ||
this._methods[methodName] = this._functions[methodName].method; | ||
this._methods[methodName] = | ||
exactContractMethod; | ||
// We don't know a particular type of the Abi method so can't type check | ||
this._methods[methodSignature] = this | ||
._functions[methodName].method; | ||
this._methods[methodSignature] = | ||
exactContractMethod; | ||
} | ||
@@ -614,8 +700,11 @@ else if (isAbiEventFragment(abi)) { | ||
} | ||
_createContractMethod(abiArr, errorsAbis) { | ||
_createContractMethod(abiArr, errorsAbis, exact = false) { | ||
const abi = abiArr[abiArr.length - 1]; | ||
return (...params) => { | ||
var _a, _b; | ||
var _a, _b, _c; | ||
let abiParams; | ||
const abis = (_a = this._overloadedMethodAbis.get(abi.name)) !== null && _a !== void 0 ? _a : []; | ||
const abis = (_b = (exact | ||
? (_a = this._overloadedMethodAbis | ||
.get(abi.name)) === null || _a === void 0 ? void 0 : _a.filter(_abi => _abi.signature === abi.signature) | ||
: this._overloadedMethodAbis.get(abi.name))) !== null && _b !== void 0 ? _b : []; | ||
let methodAbi = abis[0]; | ||
@@ -626,6 +715,8 @@ const internalErrorsAbis = errorsAbis; | ||
abiParams = this._getAbiParams(methodAbi, params); | ||
validator.validate((_b = abi.inputs) !== null && _b !== void 0 ? _b : [], abiParams); | ||
validator.validate((_c = abi.inputs) !== null && _c !== void 0 ? _c : [], abiParams); | ||
} | ||
else { | ||
const errors = []; | ||
// all the methods that have is valid for the given inputs | ||
const applicableMethodAbi = []; | ||
for (const _abi of arrayOfAbis) { | ||
@@ -635,4 +726,3 @@ try { | ||
validator.validate(_abi.inputs, abiParams); | ||
methodAbi = _abi; | ||
break; | ||
applicableMethodAbi.push(_abi); | ||
} | ||
@@ -643,2 +733,14 @@ catch (e) { | ||
} | ||
if (applicableMethodAbi.length === 1) { | ||
[methodAbi] = applicableMethodAbi; // take the first item that is the only item in the array | ||
} | ||
else if (applicableMethodAbi.length > 1) { | ||
[methodAbi] = applicableMethodAbi; // take the first item in the array | ||
console.warn(`Multiple methods found that is compatible with the given inputs.\n\tFound ${applicableMethodAbi.length} compatible methods: ${JSON.stringify(applicableMethodAbi.map(m => `${m.methodNameWithInputs} (signature: ${m.signature})`))} \n\tThe first one will be used: ${methodAbi.methodNameWithInputs}`); | ||
// TODO: 5.x Should throw a new error with the list of methods found. | ||
// Related issue: https://github.com/web3/web3.js/issues/6923 | ||
// This is in order to provide an error message when there is more than one method found that fits the inputs. | ||
// To do that, replace the pervious line of code with something like the following line: | ||
// throw new Web3ValidatorError({ message: 'Multiple methods found', ... list of applicable methods })); | ||
} | ||
if (errors.length === arrayOfAbis.length) { | ||
@@ -650,5 +752,3 @@ throw new Web3ValidatorError(errors); | ||
arguments: abiParams, | ||
call: (options, block) => __awaiter(this, void 0, void 0, function* () { | ||
return this._contractMethodCall(methodAbi, abiParams, internalErrorsAbis, options, block); | ||
}), | ||
call: (options, block) => __awaiter(this, void 0, void 0, function* () { return this._contractMethodCall(methodAbi, abiParams, internalErrorsAbis, options, block); }), | ||
send: (options) => this._contractMethodSend(methodAbi, abiParams, internalErrorsAbis, options), | ||
@@ -664,2 +764,3 @@ estimateGas: (options, returnFormat = DEFAULT_RETURN_FORMAT) => __awaiter(this, void 0, void 0, function* () { | ||
encodeABI: () => encodeMethodABI(methodAbi, abiParams), | ||
decodeData: (data) => decodeMethodParams(methodAbi, data), | ||
createAccessList: (options, block) => __awaiter(this, void 0, void 0, function* () { | ||
@@ -666,0 +767,0 @@ return this._contractMethodCreateAccessList(methodAbi, abiParams, internalErrorsAbis, options, block); |
@@ -104,2 +104,12 @@ /* | ||
}; | ||
export const decodeMethodParams = (abi, data, methodSignatureProvided = true) => { | ||
const value = methodSignatureProvided && data && data.length >= 10 && data.startsWith('0x') | ||
? data.slice(10) | ||
: data; | ||
if (!abi.inputs) { | ||
throw new Web3ContractError('No inputs found in the ABI'); | ||
} | ||
const result = decodeParameters([...abi.inputs], value); | ||
return result; | ||
}; | ||
export const decodeMethodReturn = (abi, returnValues) => { | ||
@@ -106,0 +116,0 @@ // If it was constructor then we need to return contract address |
import { Web3Context, Web3EventEmitter, Web3PromiEvent } from 'web3-core'; | ||
import { NewHeadsSubscription, SendTransactionEvents } from 'web3-eth'; | ||
import { AbiFunctionFragment, ContractAbi, ContractConstructorArgs, ContractEvent, ContractEvents, ContractMethod, ContractMethodInputParameters, ContractMethodOutputParameters, Address, EthExecutionAPI, Filter, FilterAbis, HexString, ContractInitOptions, PayableCallOptions, DataFormat, DEFAULT_RETURN_FORMAT, EventLog, ContractOptions, TransactionReceipt, FormatType } from 'web3-types'; | ||
import { AbiFunctionFragment, ContractAbi, ContractConstructorArgs, ContractEvent, ContractEvents, ContractMethod, ContractMethodInputParameters, ContractMethodOutputParameters, Address, EthExecutionAPI, Filter, FilterAbis, HexString, ContractInitOptions, PayableCallOptions, DataFormat, DEFAULT_RETURN_FORMAT, EventLog, ContractOptions, TransactionReceipt, FormatType, DecodedParams } from 'web3-types'; | ||
import { LogsSubscription } from './log_subscription.js'; | ||
@@ -163,2 +163,63 @@ import { ContractEventOptions, NonPayableMethodObject, PayableMethodObject, PayableTxOptions, Web3ContractContext } from './types.js'; | ||
* | ||
* ### decodeMethodData | ||
* Decodes the given ABI-encoded data, revealing both the method name and the parameters used in the smart contract call. | ||
* This function reverses the encoding process happens at the method `encodeABI`. | ||
* It's particularly useful for debugging and understanding the interactions with and between smart contracts. | ||
* | ||
* #### Parameters | ||
* | ||
* - `data` **HexString**: The string of ABI-encoded data that needs to be decoded. This should include the method signature and the encoded parameters. | ||
* | ||
* #### Returns | ||
* | ||
* - **Object**: This object combines both the decoded parameters and the method name in a readable format. Specifically, the returned object contains: | ||
* - `__method__` **String**: The name of the contract method, reconstructed from the ABI. | ||
* - `__length__` **Number**: The number of parameters decoded. | ||
* - Additional properties representing each parameter by name, as well as their position and values. | ||
* | ||
* #### Example | ||
* | ||
* Given an ABI-encoded string from a transaction, you can decode this data to identify the method called and the parameters passed. | ||
* Here's a simplified example: | ||
* | ||
* | ||
* ```typescript | ||
* const GreeterAbi = [ | ||
* { | ||
* inputs: [ | ||
* { | ||
* internalType: 'string', | ||
* name: '_greeting', | ||
* type: 'string', | ||
* }, | ||
* ], | ||
* name: 'setGreeting', | ||
* outputs: [], | ||
* type: 'function', | ||
* }, | ||
* ]; | ||
* const contract = new Contract(GreeterAbi); // Initialize with your contract's ABI | ||
* | ||
* // The ABI-encoded data string for "setGreeting('Hello World')" | ||
* const encodedData = | ||
* '0xa41368620000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000b48656c6c6f20576f726c64000000000000000000000000000000000000000000'; | ||
* | ||
* try { | ||
* const decoded = contract.decodeMethodData(encodedData); | ||
* console.log(decoded.__method__); // Outputs: "setGreeting(string)" | ||
* console.log(decoded); // Outputs the detailed parameter data | ||
* // This tells that the method called was `setGreeting` with a single string parameter "Hello World": | ||
* // { | ||
* // __method__: 'setGreeting(string)', | ||
* // __length__: 1, | ||
* // '0': 'Hello World', | ||
* // _greeting: 'Hello World' | ||
* // } | ||
* } catch (error) { | ||
* console.error(error); | ||
* } | ||
* ``` | ||
* | ||
* ### createAccessList | ||
@@ -371,2 +432,18 @@ * This will create an access list a method execution will access when executed in the EVM. | ||
* | ||
* // decoding | ||
* myContract.deploy({ | ||
* input: '0x12345...', | ||
* // arguments: [123, 'My Greeting'] if you just need to decode the data, you can skip the arguments | ||
* }) | ||
* .decodeData('0x12345...0000012345678765432'); | ||
* > { | ||
* __method__: 'constructor', | ||
* __length__: 2, | ||
* '0': '123', | ||
* _id: '123', | ||
* '1': 'My Greeting', | ||
* _greeting: 'My Greeting', | ||
* } | ||
* | ||
* | ||
* // Gas estimation | ||
@@ -402,2 +479,6 @@ * myContract.deploy({ | ||
encodeABI: () => string; | ||
decodeData: (data: HexString) => { | ||
__method__: string; | ||
__length__: number; | ||
}; | ||
}; | ||
@@ -447,2 +528,5 @@ /** | ||
private _parseAndSetAddress; | ||
decodeMethodData(data: HexString): DecodedParams & { | ||
__method__: string; | ||
}; | ||
private _parseAndSetJsonInterface; | ||
@@ -449,0 +533,0 @@ private _getAbiParams; |
@@ -10,3 +10,7 @@ import { AbiConstructorFragment, AbiEventFragment, AbiFunctionFragment, Filter, HexString, ContractOptions } from 'web3-types'; | ||
export declare const encodeMethodABI: (abi: AbiFunctionFragment | AbiConstructorFragment, args: unknown[], deployData?: HexString) => string; | ||
export declare const decodeMethodParams: (abi: AbiFunctionFragment | AbiConstructorFragment, data: HexString, methodSignatureProvided?: boolean) => { | ||
[key: string]: unknown; | ||
__length__: number; | ||
}; | ||
export declare const decodeMethodReturn: (abi: AbiFunctionFragment, returnValues?: HexString) => unknown; | ||
//# sourceMappingURL=encoding.d.ts.map |
@@ -167,2 +167,9 @@ import { Web3ContextInitOptions, Web3PromiEvent } from 'web3-core'; | ||
/** | ||
* Decode raw result of method call into readable value(s). | ||
* | ||
* @param data - The data to decode. | ||
* @returns - The decoded data. | ||
*/ | ||
decodeData<SpecialInputs = Inputs>(data: HexString): SpecialInputs; | ||
/** | ||
* This method generates an access list for a transaction. You must specify a `from` address and `gas` if it’s not specified in options. | ||
@@ -338,2 +345,9 @@ * | ||
/** | ||
* Decode raw result of method call into readable value(s). | ||
* | ||
* @param data - The data to decode. | ||
* @returns - The decoded data. | ||
*/ | ||
decodeData<SpecialInputs = Inputs>(data: HexString): SpecialInputs; | ||
/** | ||
* This method generates an access list for a transaction. You must specify a `from` address and `gas` if it’s not specified in options. | ||
@@ -340,0 +354,0 @@ * |
{ | ||
"name": "web3-eth-contract", | ||
"version": "4.3.0", | ||
"version": "4.3.1-dev.1c03666.0+1c03666", | ||
"description": "Web3 module to interact with Ethereum smart contracts.", | ||
@@ -48,9 +48,9 @@ "main": "./lib/commonjs/index.js", | ||
"dependencies": { | ||
"web3-core": "^4.3.2", | ||
"web3-errors": "^1.1.4", | ||
"web3-eth": "^4.5.0", | ||
"web3-eth-abi": "^4.2.0", | ||
"web3-types": "^1.5.0", | ||
"web3-utils": "^4.2.2", | ||
"web3-validator": "^2.0.5" | ||
"web3-core": "4.3.3-dev.1c03666.0+1c03666", | ||
"web3-errors": "1.1.5-dev.1c03666.0+1c03666", | ||
"web3-eth": "4.5.1-dev.1c03666.0+1c03666", | ||
"web3-eth-abi": "4.2.1-dev.1c03666.0+1c03666", | ||
"web3-types": "1.5.1-dev.1c03666.0+1c03666", | ||
"web3-utils": "4.2.3-dev.1c03666.0+1c03666", | ||
"web3-validator": "2.0.6-dev.1c03666.0+1c03666" | ||
}, | ||
@@ -72,6 +72,6 @@ "devDependencies": { | ||
"typescript": "^4.7.4", | ||
"web3-eth-accounts": "^4.1.1", | ||
"web3-providers-ws": "^4.0.7" | ||
"web3-eth-accounts": "4.1.2-dev.1c03666.0+1c03666", | ||
"web3-providers-ws": "4.0.8-dev.1c03666.0+1c03666" | ||
}, | ||
"gitHead": "7379a3bb3c274eff76c64b2447e95c34282e04fd" | ||
"gitHead": "1c036667a5815731eb470fb56da8da5365bdd6db" | ||
} |
@@ -87,2 +87,3 @@ /* | ||
FormatType, | ||
DecodedParams, | ||
} from 'web3-types'; | ||
@@ -103,3 +104,8 @@ import { | ||
} from 'web3-validator'; | ||
import { decodeMethodReturn, encodeEventABI, encodeMethodABI } from './encoding.js'; | ||
import { | ||
decodeMethodReturn, | ||
decodeMethodParams, | ||
encodeEventABI, | ||
encodeMethodABI, | ||
} from './encoding.js'; | ||
import { LogsSubscription } from './log_subscription.js'; | ||
@@ -328,2 +334,63 @@ import { | ||
* | ||
* ### decodeMethodData | ||
* Decodes the given ABI-encoded data, revealing both the method name and the parameters used in the smart contract call. | ||
* This function reverses the encoding process happens at the method `encodeABI`. | ||
* It's particularly useful for debugging and understanding the interactions with and between smart contracts. | ||
* | ||
* #### Parameters | ||
* | ||
* - `data` **HexString**: The string of ABI-encoded data that needs to be decoded. This should include the method signature and the encoded parameters. | ||
* | ||
* #### Returns | ||
* | ||
* - **Object**: This object combines both the decoded parameters and the method name in a readable format. Specifically, the returned object contains: | ||
* - `__method__` **String**: The name of the contract method, reconstructed from the ABI. | ||
* - `__length__` **Number**: The number of parameters decoded. | ||
* - Additional properties representing each parameter by name, as well as their position and values. | ||
* | ||
* #### Example | ||
* | ||
* Given an ABI-encoded string from a transaction, you can decode this data to identify the method called and the parameters passed. | ||
* Here's a simplified example: | ||
* | ||
* | ||
* ```typescript | ||
* const GreeterAbi = [ | ||
* { | ||
* inputs: [ | ||
* { | ||
* internalType: 'string', | ||
* name: '_greeting', | ||
* type: 'string', | ||
* }, | ||
* ], | ||
* name: 'setGreeting', | ||
* outputs: [], | ||
* type: 'function', | ||
* }, | ||
* ]; | ||
* const contract = new Contract(GreeterAbi); // Initialize with your contract's ABI | ||
* | ||
* // The ABI-encoded data string for "setGreeting('Hello World')" | ||
* const encodedData = | ||
* '0xa41368620000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000b48656c6c6f20576f726c64000000000000000000000000000000000000000000'; | ||
* | ||
* try { | ||
* const decoded = contract.decodeMethodData(encodedData); | ||
* console.log(decoded.__method__); // Outputs: "setGreeting(string)" | ||
* console.log(decoded); // Outputs the detailed parameter data | ||
* // This tells that the method called was `setGreeting` with a single string parameter "Hello World": | ||
* // { | ||
* // __method__: 'setGreeting(string)', | ||
* // __length__: 1, | ||
* // '0': 'Hello World', | ||
* // _greeting: 'Hello World' | ||
* // } | ||
* } catch (error) { | ||
* console.error(error); | ||
* } | ||
* ``` | ||
* | ||
* ### createAccessList | ||
@@ -452,7 +519,3 @@ * This will create an access list a method execution will access when executed in the EVM. | ||
jsonInterface: Abi, | ||
addressOrOptionsOrContext?: | ||
| Address | ||
| ContractInitOptions | ||
| Web3ContractContext | ||
| Web3Context, | ||
addressOrOptionsOrContext?: Address | ContractInitOptions | Web3ContractContext | Web3Context, | ||
optionsOrContextOrReturnFormat?: | ||
@@ -483,6 +546,3 @@ | ContractInitOptions | ||
let provider; | ||
if ( | ||
typeof addressOrOptionsOrContext === 'object' && | ||
'provider' in addressOrOptionsOrContext | ||
) { | ||
if (typeof addressOrOptionsOrContext === 'object' && 'provider' in addressOrOptionsOrContext) { | ||
provider = addressOrOptionsOrContext.provider; | ||
@@ -494,6 +554,3 @@ } else if ( | ||
provider = optionsOrContextOrReturnFormat.provider; | ||
} else if ( | ||
typeof contextOrReturnFormat === 'object' && | ||
'provider' in contextOrReturnFormat | ||
) { | ||
} else if (typeof contextOrReturnFormat === 'object' && 'provider' in contextOrReturnFormat) { | ||
provider = contextOrReturnFormat.provider; | ||
@@ -742,2 +799,18 @@ } else { | ||
* | ||
* // decoding | ||
* myContract.deploy({ | ||
* input: '0x12345...', | ||
* // arguments: [123, 'My Greeting'] if you just need to decode the data, you can skip the arguments | ||
* }) | ||
* .decodeData('0x12345...0000012345678765432'); | ||
* > { | ||
* __method__: 'constructor', | ||
* __length__: 2, | ||
* '0': '123', | ||
* _id: '123', | ||
* '1': 'My Greeting', | ||
* _greeting: 'My Greeting', | ||
* } | ||
* | ||
* | ||
* // Gas estimation | ||
@@ -826,2 +899,10 @@ * myContract.deploy({ | ||
), | ||
decodeData: (data: HexString) => ({ | ||
...decodeMethodParams( | ||
abi as AbiFunctionFragment, | ||
data.replace(deployData as string, ''), | ||
false, | ||
), | ||
__method__: abi.type, // abi.type is constructor | ||
}), | ||
}; | ||
@@ -948,4 +1029,3 @@ } | ||
(v: Numbers) => | ||
String(log.returnValues[key]).toUpperCase() === | ||
String(v).toUpperCase(), | ||
String(log.returnValues[key]).toUpperCase() === String(v).toUpperCase(), | ||
); | ||
@@ -960,6 +1040,3 @@ } | ||
return ( | ||
String(log.returnValues[key]).toUpperCase() === | ||
String(filter[key]).toUpperCase() | ||
); | ||
return String(log.returnValues[key]).toUpperCase() === String(filter[key]).toUpperCase(); | ||
}); | ||
@@ -978,2 +1055,17 @@ }); | ||
public decodeMethodData(data: HexString): DecodedParams & { __method__: string } { | ||
const methodSignature = data.slice(0, 10); | ||
const functionsAbis = this._jsonInterface.filter(j => j.type !== 'error'); | ||
const abi = functionsAbis.find( | ||
a => methodSignature === encodeFunctionSignature(jsonInterfaceMethodToString(a)), | ||
); | ||
if (!abi) { | ||
throw new Web3ContractError( | ||
`The ABI for the provided method signature ${methodSignature} was not found.`, | ||
); | ||
} | ||
return { ...decodeMethodParams(abi, data), __method__: jsonInterfaceMethodToString(abi) }; | ||
} | ||
private _parseAndSetJsonInterface( | ||
@@ -990,5 +1082,3 @@ abis: ContractAbi, | ||
const functionsAbi = abis.filter(abi => abi.type !== 'error'); | ||
const errorsAbi = abis.filter(abi => | ||
isAbiErrorFragment(abi), | ||
) as unknown as AbiErrorFragment[]; | ||
const errorsAbi = abis.filter(abi => isAbiErrorFragment(abi)) as unknown as AbiErrorFragment[]; | ||
@@ -1004,2 +1094,3 @@ for (const a of functionsAbi) { | ||
const methodSignature = encodeFunctionSignature(methodName); | ||
abi.methodNameWithInputs = methodName; | ||
abi.signature = methodSignature; | ||
@@ -1009,5 +1100,3 @@ | ||
abi.constant = | ||
abi.stateMutability === 'view' ?? | ||
abi.stateMutability === 'pure' ?? | ||
abi.constant; | ||
abi.stateMutability === 'view' ?? abi.stateMutability === 'pure' ?? abi.constant; | ||
@@ -1020,25 +1109,27 @@ abi.payable = abi.stateMutability === 'payable' ?? abi.payable; | ||
const abiFragment = this._overloadedMethodAbis.get(abi.name) ?? []; | ||
const contractMethod = this._createContractMethod< | ||
const contractMethod = this._createContractMethod<typeof abiFragment, AbiErrorFragment>( | ||
abiFragment, | ||
errorsAbi, | ||
); | ||
const exactContractMethod = this._createContractMethod< | ||
typeof abiFragment, | ||
AbiErrorFragment | ||
>(abiFragment, errorsAbi); | ||
>(abiFragment, errorsAbi, true); | ||
this._functions[methodName] = { | ||
signature: methodSignature, | ||
method: contractMethod, | ||
method: exactContractMethod, | ||
}; | ||
// We don't know a particular type of the Abi method so can't type check | ||
this._methods[abi.name as keyof ContractMethodsInterface<Abi>] = this._functions[ | ||
methodName | ||
].method as never; | ||
this._methods[abi.name as keyof ContractMethodsInterface<Abi>] = contractMethod as never; | ||
// We don't know a particular type of the Abi method so can't type check | ||
this._methods[methodName as keyof ContractMethodsInterface<Abi>] = this._functions[ | ||
methodName | ||
].method as never; | ||
this._methods[methodName as keyof ContractMethodsInterface<Abi>] = | ||
exactContractMethod as never; | ||
// We don't know a particular type of the Abi method so can't type check | ||
this._methods[methodSignature as keyof ContractMethodsInterface<Abi>] = this | ||
._functions[methodName].method as never; | ||
this._methods[methodSignature as keyof ContractMethodsInterface<Abi>] = | ||
exactContractMethod as never; | ||
} else if (isAbiEventFragment(abi)) { | ||
@@ -1082,2 +1173,3 @@ const eventName = jsonInterfaceMethodToString(abi); | ||
errorsAbis: E[], | ||
exact = false, // when true, it will only match the exact method signature | ||
): ContractBoundMethod<T[0]> { | ||
@@ -1087,3 +1179,8 @@ const abi = abiArr[abiArr.length - 1]; | ||
let abiParams!: Array<unknown>; | ||
const abis = this._overloadedMethodAbis.get(abi.name) ?? []; | ||
const abis = | ||
(exact | ||
? this._overloadedMethodAbis | ||
.get(abi.name) | ||
?.filter(_abi => _abi.signature === abi.signature) | ||
: this._overloadedMethodAbis.get(abi.name)) ?? []; | ||
let methodAbi: AbiFunctionFragment = abis[0]; | ||
@@ -1102,11 +1199,9 @@ const internalErrorsAbis = errorsAbis; | ||
// all the methods that have is valid for the given inputs | ||
const applicableMethodAbi: AbiFunctionFragment[] = []; | ||
for (const _abi of arrayOfAbis) { | ||
try { | ||
abiParams = this._getAbiParams(_abi, params); | ||
validator.validate( | ||
_abi.inputs as unknown as ValidationSchemaInput, | ||
abiParams, | ||
); | ||
methodAbi = _abi; | ||
break; | ||
validator.validate(_abi.inputs as unknown as ValidationSchemaInput, abiParams); | ||
applicableMethodAbi.push(_abi); | ||
} catch (e) { | ||
@@ -1116,2 +1211,26 @@ errors.push(e as Web3ValidationErrorObject); | ||
} | ||
if (applicableMethodAbi.length === 1) { | ||
[methodAbi] = applicableMethodAbi; // take the first item that is the only item in the array | ||
} else if (applicableMethodAbi.length > 1) { | ||
[methodAbi] = applicableMethodAbi; // take the first item in the array | ||
console.warn( | ||
`Multiple methods found that is compatible with the given inputs.\n\tFound ${ | ||
applicableMethodAbi.length | ||
} compatible methods: ${JSON.stringify( | ||
applicableMethodAbi.map( | ||
m => | ||
`${(m as { methodNameWithInputs: string }).methodNameWithInputs} (signature: ${ | ||
(m as { signature: string }).signature | ||
})`, | ||
), | ||
)} \n\tThe first one will be used: ${ | ||
(methodAbi as { methodNameWithInputs: string }).methodNameWithInputs | ||
}`, | ||
); | ||
// TODO: 5.x Should throw a new error with the list of methods found. | ||
// Related issue: https://github.com/web3/web3.js/issues/6923 | ||
// This is in order to provide an error message when there is more than one method found that fits the inputs. | ||
// To do that, replace the pervious line of code with something like the following line: | ||
// throw new Web3ValidatorError({ message: 'Multiple methods found', ... list of applicable methods })); | ||
} | ||
if (errors.length === arrayOfAbis.length) { | ||
@@ -1127,10 +1246,3 @@ throw new Web3ValidatorError(errors); | ||
block?: BlockNumberOrTag, | ||
) => | ||
this._contractMethodCall( | ||
methodAbi, | ||
abiParams, | ||
internalErrorsAbis, | ||
options, | ||
block, | ||
), | ||
) => this._contractMethodCall(methodAbi, abiParams, internalErrorsAbis, options, block), | ||
@@ -1152,2 +1264,3 @@ send: (options?: PayableTxOptions | NonPayableTxOptions): ContractMethodSend => | ||
encodeABI: () => encodeMethodABI(methodAbi, abiParams), | ||
decodeData: (data: HexString) => decodeMethodParams(methodAbi, data), | ||
@@ -1343,7 +1456,3 @@ createAccessList: async ( | ||
return (...params: unknown[]) => { | ||
const { topics, fromBlock } = encodeEventABI( | ||
this.options, | ||
abi, | ||
params[0] as EventParameters, | ||
); | ||
const { topics, fromBlock } = encodeEventABI(this.options, abi, params[0] as EventParameters); | ||
const sub = new LogsSubscription( | ||
@@ -1358,6 +1467,3 @@ { | ||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment | ||
subscriptionManager: this.subscriptionManager as Web3SubscriptionManager< | ||
unknown, | ||
any | ||
>, | ||
subscriptionManager: this.subscriptionManager as Web3SubscriptionManager<unknown, any>, | ||
returnFormat, | ||
@@ -1375,6 +1481,3 @@ }, | ||
.catch((error: Error) => { | ||
sub.emit( | ||
'error', | ||
new SubscriptionError('Failed to get past events.', error), | ||
); | ||
sub.emit('error', new SubscriptionError('Failed to get past events.', error)); | ||
}); | ||
@@ -1381,0 +1484,0 @@ } |
@@ -157,2 +157,18 @@ /* | ||
export const decodeMethodParams = ( | ||
abi: AbiFunctionFragment | AbiConstructorFragment, | ||
data: HexString, | ||
methodSignatureProvided = true, | ||
) => { | ||
const value = | ||
methodSignatureProvided && data && data.length >= 10 && data.startsWith('0x') | ||
? data.slice(10) | ||
: data; | ||
if (!abi.inputs) { | ||
throw new Web3ContractError('No inputs found in the ABI'); | ||
} | ||
const result = decodeParameters([...abi.inputs], value); | ||
return result; | ||
}; | ||
export const decodeMethodReturn = (abi: AbiFunctionFragment, returnValues?: HexString) => { | ||
@@ -159,0 +175,0 @@ // If it was constructor then we need to return contract address |
@@ -215,2 +215,10 @@ /* | ||
/** | ||
* Decode raw result of method call into readable value(s). | ||
* | ||
* @param data - The data to decode. | ||
* @returns - The decoded data. | ||
*/ | ||
decodeData<SpecialInputs = Inputs>(data: HexString): SpecialInputs; | ||
/** | ||
* This method generates an access list for a transaction. You must specify a `from` address and `gas` if it’s not specified in options. | ||
@@ -405,2 +413,10 @@ * | ||
/** | ||
* Decode raw result of method call into readable value(s). | ||
* | ||
* @param data - The data to decode. | ||
* @returns - The decoded data. | ||
*/ | ||
decodeData<SpecialInputs = Inputs>(data: HexString): SpecialInputs; | ||
/** | ||
* This method generates an access list for a transaction. You must specify a `from` address and `gas` if it’s not specified in options. | ||
@@ -407,0 +423,0 @@ * |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Manifest confusion
Supply chain riskThis package has inconsistent metadata. This could be malicious or caused by an error when publishing the package.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
397762
7288
2
1
- Removed@ethereumjs/rlp@4.0.1(transitive)
- Removed@noble/curves@1.4.2(transitive)
- Removed@noble/hashes@1.4.0(transitive)
- Removed@scure/base@1.1.9(transitive)
- Removed@scure/bip32@1.4.0(transitive)
- Removed@scure/bip39@1.3.0(transitive)
- Removed@types/node@22.7.4(transitive)
- Removed@types/ws@8.5.3(transitive)
- Removedabitype@0.7.1(transitive)
- Removedavailable-typed-arrays@1.0.7(transitive)
- Removedcall-bind@1.0.7(transitive)
- Removedcrc-32@1.2.2(transitive)
- Removedcross-fetch@4.0.0(transitive)
- Removeddefine-data-property@1.1.4(transitive)
- Removedes-define-property@1.0.0(transitive)
- Removedes-errors@1.3.0(transitive)
- Removedethereum-cryptography@2.2.1(transitive)
- Removedeventemitter3@5.0.1(transitive)
- Removedfor-each@0.3.3(transitive)
- Removedfunction-bind@1.1.2(transitive)
- Removedget-intrinsic@1.2.4(transitive)
- Removedgopd@1.0.1(transitive)
- Removedhas-property-descriptors@1.0.2(transitive)
- Removedhas-proto@1.0.3(transitive)
- Removedhas-symbols@1.0.3(transitive)
- Removedhas-tostringtag@1.0.2(transitive)
- Removedhasown@2.0.2(transitive)
- Removedinherits@2.0.4(transitive)
- Removedis-arguments@1.1.1(transitive)
- Removedis-callable@1.2.7(transitive)
- Removedis-generator-function@1.0.10(transitive)
- Removedis-typed-array@1.1.13(transitive)
- Removedisomorphic-ws@5.0.0(transitive)
- Removednode-fetch@2.7.0(transitive)
- Removedpossible-typed-array-names@1.0.0(transitive)
- Removedset-function-length@1.2.2(transitive)
- Removedsetimmediate@1.0.5(transitive)
- Removedtr46@0.0.3(transitive)
- Removedtypescript@5.6.2(transitive)
- Removedundici-types@6.19.8(transitive)
- Removedutil@0.12.5(transitive)
- Removedweb3-core@4.6.0(transitive)
- Removedweb3-errors@1.3.0(transitive)
- Removedweb3-eth@4.9.0(transitive)
- Removedweb3-eth-abi@4.2.4(transitive)
- Removedweb3-eth-accounts@4.2.1(transitive)
- Removedweb3-eth-iban@4.0.7(transitive)
- Removedweb3-net@4.1.0(transitive)
- Removedweb3-providers-http@4.2.0(transitive)
- Removedweb3-providers-ipc@4.0.7(transitive)
- Removedweb3-providers-ws@4.0.8(transitive)
- Removedweb3-rpc-methods@1.3.0(transitive)
- Removedweb3-types@1.8.0(transitive)
- Removedweb3-utils@4.3.1(transitive)
- Removedweb3-validator@2.0.6(transitive)
- Removedwebidl-conversions@3.0.1(transitive)
- Removedwhatwg-url@5.0.0(transitive)
- Removedwhich-typed-array@1.1.15(transitive)
- Removedws@8.18.0(transitive)
- Removedzod@3.23.8(transitive)