From ebfcd2d9266bd60d5b88d21853dbceef380035f3 Mon Sep 17 00:00:00 2001 From: luu-alex Date: Fri, 18 Aug 2023 12:38:26 -0400 Subject: [PATCH 01/27] update formatsubscriptionResult --- packages/web3-eth/src/web3_subscriptions.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/web3-eth/src/web3_subscriptions.ts b/packages/web3-eth/src/web3_subscriptions.ts index 7167ee1a108..5838aa9ce2d 100644 --- a/packages/web3-eth/src/web3_subscriptions.ts +++ b/packages/web3-eth/src/web3_subscriptions.ts @@ -118,7 +118,7 @@ export class NewHeadsSubscription extends Web3Subscription<{ return ['newHeads']; } - protected formatSubscriptionResult(data: BlockHeaderOutput) { + protected formatSubscriptionResult(data: BlockHeaderOutput): BlockHeaderOutput { return format(blockHeaderSchema, data, super.returnFormat); } } From 48b1f3b9110748b79d8099d9602242e086f0db7e Mon Sep 17 00:00:00 2001 From: luu-alex Date: Fri, 18 Aug 2023 12:41:59 -0400 Subject: [PATCH 02/27] update changelog --- packages/web3-eth/CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/web3-eth/CHANGELOG.md b/packages/web3-eth/CHANGELOG.md index 7db42abe11a..59933ef39ce 100644 --- a/packages/web3-eth/CHANGELOG.md +++ b/packages/web3-eth/CHANGELOG.md @@ -180,3 +180,7 @@ Documentation: - A `signTypedData` method to the `Web3Eth` class (#6286) ## [Unreleased] + +### Fixed + +- Added return type for `formatSubscriptionResult` in class `NewHeadsSubscription` (#6368) From 47fed5cb074e7fd965f1e5377ec2fe8bd37fcd3f Mon Sep 17 00:00:00 2001 From: luu-alex Date: Sat, 19 Aug 2023 13:00:03 -0400 Subject: [PATCH 03/27] data and input typings updated --- packages/web3-eth-contract/src/types.ts | 4 ++++ packages/web3-eth-contract/src/utils.ts | 1 + packages/web3-types/src/eth_contract_types.ts | 2 ++ 3 files changed, 7 insertions(+) diff --git a/packages/web3-eth-contract/src/types.ts b/packages/web3-eth-contract/src/types.ts index e237fb53707..0b62afcc37c 100644 --- a/packages/web3-eth-contract/src/types.ts +++ b/packages/web3-eth-contract/src/types.ts @@ -92,6 +92,10 @@ export interface ContractOptions { * The byte code of the contract. Used when the contract gets {@link Contract.deploy | deployed} */ readonly input?: Bytes; + /** + * The byte code of the contract. Used when the contract gets {@link Contract.deploy | deployed} + */ + readonly data?: Bytes; /** * The {@doclink glossary/json_interface | json interface} object derived from the [ABI](https://github.com/ethereum/wiki/wiki/Ethereum-Contract-ABI) of this contract. * diff --git a/packages/web3-eth-contract/src/utils.ts b/packages/web3-eth-contract/src/utils.ts index 3f46f87d075..af5b5bebb7d 100644 --- a/packages/web3-eth-contract/src/utils.ts +++ b/packages/web3-eth-contract/src/utils.ts @@ -103,6 +103,7 @@ export const getEthTxCallParams = ({ input: contractOptions.input, maxPriorityFeePerGas: contractOptions.maxPriorityFeePerGas, maxFeePerGas: contractOptions.maxFeePerGas, + data: contractOptions.data, }, options as unknown as Record, ) as unknown as TransactionCall; diff --git a/packages/web3-types/src/eth_contract_types.ts b/packages/web3-types/src/eth_contract_types.ts index 5b14b6f0fce..73bb7043cbf 100644 --- a/packages/web3-types/src/eth_contract_types.ts +++ b/packages/web3-types/src/eth_contract_types.ts @@ -65,6 +65,8 @@ export interface NonPayableCallOptions { */ gasPrice?: string; type?: string | number; + data?: HexString; + input?: HexString; } export interface PayableCallOptions extends NonPayableCallOptions { From f5894030d863cbccccdbfd78451c74f9ff01b44c Mon Sep 17 00:00:00 2001 From: luu-alex Date: Mon, 21 Aug 2023 12:39:45 -0400 Subject: [PATCH 04/27] debug contract --- packages/web3-core/CHANGELOG.md | 1 - packages/web3-eth-contract/src/contract.ts | 37 +++++++++++++------ packages/web3-eth-contract/src/utils.ts | 33 +++++++++++++---- .../local_account/contract_erc20.test.ts | 6 ++- .../test/unit/contract.test.ts | 35 +++++++++++++++++- packages/web3-eth/src/rpc_method_wrappers.ts | 1 - .../prepare_transaction_for_signing.test.ts | 2 +- 7 files changed, 90 insertions(+), 25 deletions(-) diff --git a/packages/web3-core/CHANGELOG.md b/packages/web3-core/CHANGELOG.md index e8f5cec1c62..ac218c71641 100644 --- a/packages/web3-core/CHANGELOG.md +++ b/packages/web3-core/CHANGELOG.md @@ -172,4 +172,3 @@ Documentation: ### Added - To fix issue #6190, added the functionality to introduce different timeout value for Web3. (#6336) - diff --git a/packages/web3-eth-contract/src/contract.ts b/packages/web3-eth-contract/src/contract.ts index 65f271c8b38..6f45edfbe8e 100644 --- a/packages/web3-eth-contract/src/contract.ts +++ b/packages/web3-eth-contract/src/contract.ts @@ -480,6 +480,7 @@ export class Contract gasPrice: this.options.gasPrice, from: this.options.from, input: this.options.input, + data: this.options.data, provider: this.currentProvider, syncWithContext: this.syncWithContext, }, @@ -493,6 +494,7 @@ export class Contract gasPrice: this.options.gasPrice, from: this.options.from, input: this.options.input, + data: this.options.data, provider: this.currentProvider, syncWithContext: this.syncWithContext, }, @@ -588,18 +590,25 @@ export class Contract const _input = format( { format: 'bytes' }, - deployOptions?.input ?? deployOptions?.data ?? this.options.input, + deployOptions?.input ?? this.options.input, DEFAULT_RETURN_FORMAT, ); - if (!_input || _input.trim() === '0x') { + const _data = format( + { format: 'bytes' }, + deployOptions?.data ?? this.options.data, + DEFAULT_RETURN_FORMAT, + ); + + if ((!_input || _input.trim() === '0x') && (!_data || _data.trim() === '0x')) { throw new Web3ContractError('contract creation without any data provided.'); } - + // check if data is used properly + // see if deploy data is working as intended. const args = deployOptions?.arguments ?? []; - const contractOptions: ContractOptions = { ...this.options, input: _input }; - + const contractOptions: ContractOptions = { ...this.options, input: _input, data: _data }; + const deployData = _input ?? _data; return { arguments: args, send: ( @@ -636,7 +645,7 @@ export class Contract encodeMethodABI( abi as AbiFunctionFragment, args as unknown[], - format({ format: 'bytes' }, _input as Bytes, DEFAULT_RETURN_FORMAT), + format({ format: 'bytes' }, deployData as Bytes, DEFAULT_RETURN_FORMAT), ), }; } @@ -913,7 +922,7 @@ export class Contract throw new Web3ValidatorError(errors); } } - + console.log("_createContractMethod") const methods = { arguments: abiParams, @@ -930,7 +939,7 @@ export class Contract ), send: (options?: PayableTxOptions | NonPayableTxOptions) => - this._contractMethodSend(methodAbi, abiParams, internalErrorsAbis, options), + this._contractMethodSend(methodAbi, abiParams, internalErrorsAbis, options), // this options does not include data estimateGas: async ( options?: PayableCallOptions | NonPayableCallOptions, @@ -1042,13 +1051,19 @@ export class Contract input: undefined, from: modifiedContractOptions.from ?? this.defaultAccount ?? undefined, }; - + console.log("_contractMethodSend") + console.log("mods") + console.log(modifiedContractOptions) + console.log("options"); + console.log(options); const tx = getSendTxParams({ abi, params, options, contractOptions: modifiedContractOptions, }); + console.log("_contractMethodSend tx") + console.log(tx) const transactionToSend = sendTransaction(this, tx, DEFAULT_RETURN_FORMAT, { // TODO Should make this configurable by the user checkRevertBeforeSending: false, @@ -1061,7 +1076,6 @@ export class Contract decodeContractErrorData(errorsAbi, error.innerError); } }); - return transactionToSend; } @@ -1076,14 +1090,13 @@ export class Contract ...modifiedContractOptions, from: modifiedContractOptions.from ?? this.defaultAccount ?? undefined, }; - + console.log("_contractMethodDeploySend"); const tx = getSendTxParams({ abi, params, options, contractOptions: modifiedContractOptions, }); - return sendTransaction(this, tx, DEFAULT_RETURN_FORMAT, { transactionResolver: receipt => { if (receipt.status === BigInt(0)) { diff --git a/packages/web3-eth-contract/src/utils.ts b/packages/web3-eth-contract/src/utils.ts index af5b5bebb7d..7ebca9e76b6 100644 --- a/packages/web3-eth-contract/src/utils.ts +++ b/packages/web3-eth-contract/src/utils.ts @@ -46,7 +46,11 @@ export const getSendTxParams = ({ }; contractOptions: ContractOptions; }): TransactionCall => { - const deploymentCall = options?.input ?? options?.data ?? contractOptions.input; + console.log("asd contractOptions") + console.log(contractOptions) + console.log("casd options") + console.log(options) + const deploymentCall = options?.input ?? options?.data ?? contractOptions.input ?? contractOptions.data; if (!deploymentCall && !options?.to && !contractOptions.address) { throw new Web3ContractError('Contract address not specified'); @@ -55,7 +59,7 @@ export const getSendTxParams = ({ if (!options?.from && !contractOptions.from) { throw new Web3ContractError('Contract "from" address not specified'); } - + console.log("222") let txParams = mergeDeep( { to: contractOptions.address, @@ -65,17 +69,29 @@ export const getSendTxParams = ({ input: contractOptions.input, maxPriorityFeePerGas: contractOptions.maxPriorityFeePerGas, maxFeePerGas: contractOptions.maxFeePerGas, + data: contractOptions.data }, options as unknown as Record, ) as unknown as TransactionCall; - + // am i supposed to change input? + // doesn't reach + console.log("333") + console.log("txparams") + console.log(txParams); if (!txParams.input || abi.type === 'constructor') { txParams = { ...txParams, input: encodeMethodABI(abi, params, txParams.input as HexString), }; } - + if (!txParams.data || abi.type === 'constructor') { + txParams = { + ...txParams, + data: encodeMethodABI(abi, params, txParams.data as HexString), + }; + } + console.log("tx params") + console.log(txParams) return txParams; }; @@ -111,6 +127,7 @@ export const getEthTxCallParams = ({ txParams = { ...txParams, input: encodeMethodABI(abi, params, txParams.input ? toHex(txParams.input) : undefined), + data: encodeMethodABI(abi, params, txParams.data ? toHex(txParams.data) : undefined), }; return txParams; @@ -134,13 +151,14 @@ export const getEstimateGasParams = ({ gasPrice: contractOptions.gasPrice, from: contractOptions.from, input: contractOptions.input, + data: contractOptions.data }, options as unknown as Record, ) as unknown as TransactionCall; - + const deployData = txParams.input ? toHex(txParams.input) : txParams.data ? toHex(txParams.data) : undefined txParams = { ...txParams, - input: encodeMethodABI(abi, params, txParams.input ? toHex(txParams.input) : undefined), + input: encodeMethodABI(abi, params, deployData), }; return txParams as TransactionWithSenderAPI; @@ -192,6 +210,7 @@ export const getCreateAccessListParams = ({ input: contractOptions.input, maxPriorityFeePerGas: contractOptions.maxPriorityFeePerGas, maxFeePerGas: contractOptions.maxFeePerGas, + data: contractOptions.data, }, options as unknown as Record, ) as unknown as TransactionForAccessList; @@ -200,7 +219,7 @@ export const getCreateAccessListParams = ({ txParams = { ...txParams, input: encodeMethodABI(abi, params, txParams.input as HexString), - }; + }; // need an option for data? } return txParams; diff --git a/packages/web3-eth-contract/test/integration/local_account/contract_erc20.test.ts b/packages/web3-eth-contract/test/integration/local_account/contract_erc20.test.ts index bd379e5f647..b83f46e0a39 100644 --- a/packages/web3-eth-contract/test/integration/local_account/contract_erc20.test.ts +++ b/packages/web3-eth-contract/test/integration/local_account/contract_erc20.test.ts @@ -95,17 +95,18 @@ describe('contract', () => { ).toBe(value - transferFromValue); }); - it.each(['0x1', '0x2'])('should increase allowance %p', async type => { + it.only.each(['0x2'])('should increase allowance %p', async type => { const value = BigInt(10); const extraAmount = BigInt(4); const tempAccount = await createLocalAccount(web3); - + console.log("1") // approve await contractDeployed.methods .approve(tempAccount.address, value) .send({ ...sendOptions, type }); // allowance + console.log("2") expect( await contractDeployed.methods .allowance(localAccount.address, tempAccount.address) @@ -118,6 +119,7 @@ describe('contract', () => { .send({ ...sendOptions, from: localAccount.address, type, gas: '2000000' }); // check allowance + console.log("3") expect( await contractDeployed.methods .allowance(localAccount.address, tempAccount.address) diff --git a/packages/web3-eth-contract/test/unit/contract.test.ts b/packages/web3-eth-contract/test/unit/contract.test.ts index 4ee28bc254f..bae2f97429e 100644 --- a/packages/web3-eth-contract/test/unit/contract.test.ts +++ b/packages/web3-eth-contract/test/unit/contract.test.ts @@ -215,7 +215,7 @@ describe('Contract', () => { }; }); - it('should deploy contract', async () => { + it('should deploy contract with input property', async () => { const input = `${GreeterBytecode}0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000b4d79204772656574696e67000000000000000000000000000000000000000000`; const contract = new Contract(GreeterAbi); @@ -236,6 +236,39 @@ describe('Contract', () => { return Promise.resolve(newContract) as any; }); + const deployedContract = await contract + .deploy({ + input: GreeterBytecode, + arguments: ['My Greeting'], + }) + .send(sendOptions); + + expect(deployedContract).toBeDefined(); + expect(deployedContract.options.address).toStrictEqual(deployedAddr); + sendTransactionSpy.mockClear(); + }); + + it('should deploy contract with data property', async () => { + const data = `${GreeterBytecode}0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000b4d79204772656574696e67000000000000000000000000000000000000000000`; + const contract = new Contract(GreeterAbi); + + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const sendTransactionSpy = jest + .spyOn(eth, 'sendTransaction') + .mockImplementation((_objInstance, tx) => { + expect(tx.to).toBeUndefined(); + expect(tx.gas).toStrictEqual(sendOptions.gas); + expect(tx.gasPrice).toBeUndefined(); + expect(tx.from).toStrictEqual(sendOptions.from); + expect(tx.data).toStrictEqual(data); // padded data + + const newContract = contract.clone(); + newContract.options.address = deployedAddr; + + // eslint-disable-next-line @typescript-eslint/no-unsafe-return + return Promise.resolve(newContract) as any; + }); + const deployedContract = await contract .deploy({ data: GreeterBytecode, diff --git a/packages/web3-eth/src/rpc_method_wrappers.ts b/packages/web3-eth/src/rpc_method_wrappers.ts index e12cc5ed366..88b1379500d 100644 --- a/packages/web3-eth/src/rpc_method_wrappers.ts +++ b/packages/web3-eth/src/rpc_method_wrappers.ts @@ -527,7 +527,6 @@ export function sendTransaction< )), }; } - try { if (options.checkRevertBeforeSending !== false) { const reason = await getRevertReason( diff --git a/packages/web3-eth/test/unit/prepare_transaction_for_signing.test.ts b/packages/web3-eth/test/unit/prepare_transaction_for_signing.test.ts index cf301264407..60d99f0ee7c 100644 --- a/packages/web3-eth/test/unit/prepare_transaction_for_signing.test.ts +++ b/packages/web3-eth/test/unit/prepare_transaction_for_signing.test.ts @@ -31,7 +31,7 @@ import { prepareTransactionForSigning } from '../../src/utils/prepare_transactio import { validTransactions } from '../fixtures/prepare_transaction_for_signing'; describe('prepareTransactionForSigning', () => { - const web3Context = new Web3Context({ +const web3Context = new Web3Context({ provider: new HttpProvider('http://127.0.0.1'), config: { defaultNetworkId: '0x1' }, }); From da552ef1f633d6f85bcb675dc6b0786de770a911 Mon Sep 17 00:00:00 2001 From: luu-alex Date: Tue, 22 Aug 2023 16:54:37 -0400 Subject: [PATCH 05/27] debug --- packages/web3-eth-contract/src/contract.ts | 7 ++----- packages/web3-eth-contract/src/encoding.ts | 1 - packages/web3-eth-contract/src/utils.ts | 21 +++++++++++-------- .../local_account/contract_erc20.test.ts | 1 + 4 files changed, 15 insertions(+), 15 deletions(-) diff --git a/packages/web3-eth-contract/src/contract.ts b/packages/web3-eth-contract/src/contract.ts index 6f45edfbe8e..b25f81591a4 100644 --- a/packages/web3-eth-contract/src/contract.ts +++ b/packages/web3-eth-contract/src/contract.ts @@ -1051,11 +1051,8 @@ export class Contract input: undefined, from: modifiedContractOptions.from ?? this.defaultAccount ?? undefined, }; - console.log("_contractMethodSend") - console.log("mods") - console.log(modifiedContractOptions) - console.log("options"); - console.log(options); + console.log("contractmethodsend") + console.log(contractOptions) const tx = getSendTxParams({ abi, params, diff --git a/packages/web3-eth-contract/src/encoding.ts b/packages/web3-eth-contract/src/encoding.ts index 662b926231c..0f79aac467e 100644 --- a/packages/web3-eth-contract/src/encoding.ts +++ b/packages/web3-eth-contract/src/encoding.ts @@ -187,7 +187,6 @@ export const encodeMethodABI = ( deployData?: HexString, ) => { const inputLength = Array.isArray(abi.inputs) ? abi.inputs.length : 0; - if (inputLength !== args.length) { throw new Web3ContractError( `The number of arguments is not matching the methods required number. You need to pass ${inputLength} arguments.`, diff --git a/packages/web3-eth-contract/src/utils.ts b/packages/web3-eth-contract/src/utils.ts index 7ebca9e76b6..33ad4582b04 100644 --- a/packages/web3-eth-contract/src/utils.ts +++ b/packages/web3-eth-contract/src/utils.ts @@ -46,12 +46,13 @@ export const getSendTxParams = ({ }; contractOptions: ContractOptions; }): TransactionCall => { - console.log("asd contractOptions") - console.log(contractOptions) - console.log("casd options") + console.log("options") console.log(options) + console.log("contractoptions") + console.log(contractOptions) const deploymentCall = options?.input ?? options?.data ?? contractOptions.input ?? contractOptions.data; - + console.log("deploymentcall") + console.log(deploymentCall) if (!deploymentCall && !options?.to && !contractOptions.address) { throw new Web3ContractError('Contract address not specified'); } @@ -59,7 +60,6 @@ export const getSendTxParams = ({ if (!options?.from && !contractOptions.from) { throw new Web3ContractError('Contract "from" address not specified'); } - console.log("222") let txParams = mergeDeep( { to: contractOptions.address, @@ -75,16 +75,19 @@ export const getSendTxParams = ({ ) as unknown as TransactionCall; // am i supposed to change input? // doesn't reach - console.log("333") console.log("txparams") console.log(txParams); - if (!txParams.input || abi.type === 'constructor') { + if (txParams.input && abi.type === 'constructor') { txParams = { ...txParams, input: encodeMethodABI(abi, params, txParams.input as HexString), }; - } - if (!txParams.data || abi.type === 'constructor') { + } else if (txParams.data && abi.type === 'constructor') { + txParams = { + ...txParams, + data: encodeMethodABI(abi, params, txParams.data as HexString), + }; + } else if (abi.type === 'constructor') { txParams = { ...txParams, data: encodeMethodABI(abi, params, txParams.data as HexString), diff --git a/packages/web3-eth-contract/test/integration/local_account/contract_erc20.test.ts b/packages/web3-eth-contract/test/integration/local_account/contract_erc20.test.ts index b83f46e0a39..a335f0cfe11 100644 --- a/packages/web3-eth-contract/test/integration/local_account/contract_erc20.test.ts +++ b/packages/web3-eth-contract/test/integration/local_account/contract_erc20.test.ts @@ -101,6 +101,7 @@ describe('contract', () => { const tempAccount = await createLocalAccount(web3); console.log("1") // approve + console.log("approve") await contractDeployed.methods .approve(tempAccount.address, value) .send({ ...sendOptions, type }); From a4b280f88cf892a3de02d77dc2cda0a633bda926 Mon Sep 17 00:00:00 2001 From: luu-alex Date: Wed, 23 Aug 2023 14:18:23 -0400 Subject: [PATCH 06/27] update debug --- packages/web3-eth-contract/src/contract.ts | 8 ---- packages/web3-eth-contract/src/utils.ts | 38 ++++++++++--------- .../test/integration/contract_deploy.test.ts | 2 + .../local_account/contract_erc20.test.ts | 6 +-- packages/web3-eth/src/rpc_method_wrappers.ts | 1 - .../web3-eth/src/utils/format_transaction.ts | 2 - 6 files changed, 24 insertions(+), 33 deletions(-) diff --git a/packages/web3-eth-contract/src/contract.ts b/packages/web3-eth-contract/src/contract.ts index b25f81591a4..a6f51302e93 100644 --- a/packages/web3-eth-contract/src/contract.ts +++ b/packages/web3-eth-contract/src/contract.ts @@ -632,7 +632,6 @@ export class Contract returnFormat: ReturnFormat = DEFAULT_RETURN_FORMAT as ReturnFormat, ) => { const modifiedOptions = { ...options }; - return this._contractMethodEstimateGas({ abi: abi as AbiFunctionFragment, params: args as unknown[], @@ -922,7 +921,6 @@ export class Contract throw new Web3ValidatorError(errors); } } - console.log("_createContractMethod") const methods = { arguments: abiParams, @@ -1051,16 +1049,12 @@ export class Contract input: undefined, from: modifiedContractOptions.from ?? this.defaultAccount ?? undefined, }; - console.log("contractmethodsend") - console.log(contractOptions) const tx = getSendTxParams({ abi, params, options, contractOptions: modifiedContractOptions, }); - console.log("_contractMethodSend tx") - console.log(tx) const transactionToSend = sendTransaction(this, tx, DEFAULT_RETURN_FORMAT, { // TODO Should make this configurable by the user checkRevertBeforeSending: false, @@ -1087,7 +1081,6 @@ export class Contract ...modifiedContractOptions, from: modifiedContractOptions.from ?? this.defaultAccount ?? undefined, }; - console.log("_contractMethodDeploySend"); const tx = getSendTxParams({ abi, params, @@ -1133,7 +1126,6 @@ export class Contract options, contractOptions: contractOptions ?? this.options, }); - return estimateGas(this, tx, BlockTags.LATEST, returnFormat); } diff --git a/packages/web3-eth-contract/src/utils.ts b/packages/web3-eth-contract/src/utils.ts index 33ad4582b04..7872fa84c49 100644 --- a/packages/web3-eth-contract/src/utils.ts +++ b/packages/web3-eth-contract/src/utils.ts @@ -46,13 +46,7 @@ export const getSendTxParams = ({ }; contractOptions: ContractOptions; }): TransactionCall => { - console.log("options") - console.log(options) - console.log("contractoptions") - console.log(contractOptions) const deploymentCall = options?.input ?? options?.data ?? contractOptions.input ?? contractOptions.data; - console.log("deploymentcall") - console.log(deploymentCall) if (!deploymentCall && !options?.to && !contractOptions.address) { throw new Web3ContractError('Contract address not specified'); } @@ -73,10 +67,6 @@ export const getSendTxParams = ({ }, options as unknown as Record, ) as unknown as TransactionCall; - // am i supposed to change input? - // doesn't reach - console.log("txparams") - console.log(txParams); if (txParams.input && abi.type === 'constructor') { txParams = { ...txParams, @@ -92,9 +82,12 @@ export const getSendTxParams = ({ ...txParams, data: encodeMethodABI(abi, params, txParams.data as HexString), }; + } else { + txParams = { + ...txParams, + data: encodeMethodABI(abi, params, txParams.data as HexString), + }; } - console.log("tx params") - console.log(txParams) return txParams; }; @@ -159,11 +152,22 @@ export const getEstimateGasParams = ({ options as unknown as Record, ) as unknown as TransactionCall; const deployData = txParams.input ? toHex(txParams.input) : txParams.data ? toHex(txParams.data) : undefined - txParams = { - ...txParams, - input: encodeMethodABI(abi, params, deployData), - }; - + if (txParams.input) { + txParams = { + ...txParams, + input: encodeMethodABI(abi, params, deployData), + }; + } else if (txParams.data) { + txParams = { + ...txParams, + data: encodeMethodABI(abi, params, deployData), + }; + } else { + txParams = { + ...txParams, + input: encodeMethodABI(abi, params, deployData), + } + } return txParams as TransactionWithSenderAPI; }; diff --git a/packages/web3-eth-contract/test/integration/contract_deploy.test.ts b/packages/web3-eth-contract/test/integration/contract_deploy.test.ts index 5c6c666212c..1f0a926346c 100644 --- a/packages/web3-eth-contract/test/integration/contract_deploy.test.ts +++ b/packages/web3-eth-contract/test/integration/contract_deploy.test.ts @@ -96,6 +96,7 @@ describe('contract', () => { ); it('should return estimated gas of contract constructor %p', async () => { + console.log("estimate gas") const estimatedGas = await new Contract(GreeterAbi, undefined, { provider: getSystemTestProvider(), }) @@ -108,6 +109,7 @@ describe('contract', () => { gas: '1000000', }); expect(Number(estimatedGas)).toBeGreaterThan(0); + console.log("after estimate") }); it('should return estimated gas of contract constructor without arguments', async () => { const estimatedGas = await new Contract(ERC721TokenAbi, undefined, { diff --git a/packages/web3-eth-contract/test/integration/local_account/contract_erc20.test.ts b/packages/web3-eth-contract/test/integration/local_account/contract_erc20.test.ts index a335f0cfe11..39c32ca5322 100644 --- a/packages/web3-eth-contract/test/integration/local_account/contract_erc20.test.ts +++ b/packages/web3-eth-contract/test/integration/local_account/contract_erc20.test.ts @@ -95,19 +95,16 @@ describe('contract', () => { ).toBe(value - transferFromValue); }); - it.only.each(['0x2'])('should increase allowance %p', async type => { + it.each(['0x1','0x2'])('should increase allowance %p', async type => { const value = BigInt(10); const extraAmount = BigInt(4); const tempAccount = await createLocalAccount(web3); - console.log("1") // approve - console.log("approve") await contractDeployed.methods .approve(tempAccount.address, value) .send({ ...sendOptions, type }); // allowance - console.log("2") expect( await contractDeployed.methods .allowance(localAccount.address, tempAccount.address) @@ -120,7 +117,6 @@ describe('contract', () => { .send({ ...sendOptions, from: localAccount.address, type, gas: '2000000' }); // check allowance - console.log("3") expect( await contractDeployed.methods .allowance(localAccount.address, tempAccount.address) diff --git a/packages/web3-eth/src/rpc_method_wrappers.ts b/packages/web3-eth/src/rpc_method_wrappers.ts index 88b1379500d..866ca7aab6c 100644 --- a/packages/web3-eth/src/rpc_method_wrappers.ts +++ b/packages/web3-eth/src/rpc_method_wrappers.ts @@ -969,7 +969,6 @@ export async function estimateGas( returnFormat: ReturnFormat, ) { const transactionFormatted = formatTransaction(transaction, ETH_DATA_FORMAT); - const blockNumberFormatted = isBlockTag(blockNumber as string) ? (blockNumber as BlockTag) : format({ format: 'uint' }, blockNumber as Numbers, ETH_DATA_FORMAT); diff --git a/packages/web3-eth/src/utils/format_transaction.ts b/packages/web3-eth/src/utils/format_transaction.ts index 44f153cee85..5333254db60 100644 --- a/packages/web3-eth/src/utils/format_transaction.ts +++ b/packages/web3-eth/src/utils/format_transaction.ts @@ -42,13 +42,11 @@ export function formatTransaction< if (!isNullish(transaction.common?.customChain)) formattedTransaction.common.customChain = { ...transaction.common.customChain }; } - formattedTransaction = format( options.transactionSchema ?? transactionInfoSchema, formattedTransaction, returnFormat, ); - if ( !isNullish(formattedTransaction.data) && !isNullish(formattedTransaction.input) && From 1fb6068b62660023a312b3e633e0ac7066bc0518 Mon Sep 17 00:00:00 2001 From: moshmage Date: Thu, 24 Aug 2023 14:51:20 +0100 Subject: [PATCH 07/27] add `{fillInputAndData: true,}` to `eth_call` on method_wrappers --- packages/web3-eth/src/rpc_method_wrappers.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/web3-eth/src/rpc_method_wrappers.ts b/packages/web3-eth/src/rpc_method_wrappers.ts index e12cc5ed366..4c952946643 100644 --- a/packages/web3-eth/src/rpc_method_wrappers.ts +++ b/packages/web3-eth/src/rpc_method_wrappers.ts @@ -951,7 +951,7 @@ export async function call( const response = await ethRpcMethods.call( web3Context.requestManager, - formatTransaction(transaction, ETH_DATA_FORMAT), + formatTransaction(transaction, ETH_DATA_FORMAT, {fillInputAndData: true,}), blockNumberFormatted, ); From 4eeccbbcc8e2b87a64acb1593987b4758b517edc Mon Sep 17 00:00:00 2001 From: luu-alex Date: Thu, 24 Aug 2023 15:28:16 -0400 Subject: [PATCH 08/27] fixing tests --- packages/web3-eth-contract/src/contract.ts | 4 +- .../local_account/contract_erc20.test.ts | 2 +- .../test/unit/contract.test.ts | 43 +++++++++++++++++-- 3 files changed, 43 insertions(+), 6 deletions(-) diff --git a/packages/web3-eth-contract/src/contract.ts b/packages/web3-eth-contract/src/contract.ts index a6f51302e93..9d2b071a6c6 100644 --- a/packages/web3-eth-contract/src/contract.ts +++ b/packages/web3-eth-contract/src/contract.ts @@ -937,7 +937,7 @@ export class Contract ), send: (options?: PayableTxOptions | NonPayableTxOptions) => - this._contractMethodSend(methodAbi, abiParams, internalErrorsAbis, options), // this options does not include data + this._contractMethodSend(methodAbi, abiParams, internalErrorsAbis, options), estimateGas: async ( options?: PayableCallOptions | NonPayableCallOptions, @@ -1059,7 +1059,7 @@ export class Contract // TODO Should make this configurable by the user checkRevertBeforeSending: false, }); - + // eslint-disable-next-line no-void void transactionToSend.on('error', (error: unknown) => { if (error instanceof ContractExecutionError) { diff --git a/packages/web3-eth-contract/test/integration/local_account/contract_erc20.test.ts b/packages/web3-eth-contract/test/integration/local_account/contract_erc20.test.ts index 39c32ca5322..878f4ad7dd4 100644 --- a/packages/web3-eth-contract/test/integration/local_account/contract_erc20.test.ts +++ b/packages/web3-eth-contract/test/integration/local_account/contract_erc20.test.ts @@ -95,7 +95,7 @@ describe('contract', () => { ).toBe(value - transferFromValue); }); - it.each(['0x1','0x2'])('should increase allowance %p', async type => { + it.each(['0x1', '0x2'])('should increase allowance %p', async type => { const value = BigInt(10); const extraAmount = BigInt(4); const tempAccount = await createLocalAccount(web3); diff --git a/packages/web3-eth-contract/test/unit/contract.test.ts b/packages/web3-eth-contract/test/unit/contract.test.ts index bae2f97429e..fde353b21ee 100644 --- a/packages/web3-eth-contract/test/unit/contract.test.ts +++ b/packages/web3-eth-contract/test/unit/contract.test.ts @@ -291,7 +291,7 @@ describe('Contract', () => { }); // eslint-disable-next-line @typescript-eslint/require-await - it('send method on deployed contract should work', async () => { + it.only('send method on deployed contract should work', async () => { const arg = 'Hello'; const contract = new Contract(GreeterAbi); @@ -873,7 +873,7 @@ describe('Contract', () => { spyGetLogs.mockClear(); }); - it('encodeABI should work for the deploy function', () => { + it('encodeABI should work for the deploy function using data', () => { const contract = new Contract(GreeterAbi); const spyTx = jest.spyOn(eth, 'sendTransaction').mockImplementation(() => { @@ -896,7 +896,7 @@ describe('Contract', () => { spyTx.mockClear(); }); - it('estimateGas should work for the deploy function', async () => { + it('estimateGas should work for the deploy function using input', async () => { const contract = new Contract(GreeterAbi); const spyTx = jest.spyOn(eth, 'sendTransaction').mockImplementation(() => { @@ -921,6 +921,43 @@ describe('Contract', () => { return Promise.resolve(BigInt(36916)) as any; }); + const deploy = contract.deploy({ + input: GreeterBytecode, + arguments: ['My Greeting'], + }); + + const result = await deploy.estimateGas(sendOptions, ETH_DATA_FORMAT); + expect(result).toStrictEqual(BigInt(36916)); + + spyTx.mockClear(); + spyEstimateGas.mockClear(); + }); + + it('estimateGas should work for the deploy function', async () => { + const contract = new Contract(GreeterAbi); + + const spyTx = jest.spyOn(eth, 'sendTransaction').mockImplementation(() => { + const newContract = contract.clone(); + newContract.options.address = deployedAddr; + // eslint-disable-next-line @typescript-eslint/no-unsafe-return + return Promise.resolve(newContract) as any; + }); + + const spyEstimateGas = jest + .spyOn(eth, 'estimateGas') + .mockImplementationOnce((_objInstance, _tx, _block, returnFormat) => { + expect(_block).toBe('latest'); + expect(_tx.to).toBeUndefined(); + expect(_tx.from).toStrictEqual(sendOptions.from); + expect(_tx.data).toBe( + '0x60806040523480156200001157600080fd5b5060405162000ed038038062000ed08339818101604052810190620000379190620001ea565b806001908162000048919062000486565b5060008081905550506200056d565b6000604051905090565b600080fd5b600080fd5b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b620000c08262000075565b810181811067ffffffffffffffff82111715620000e257620000e162000086565b5b80604052505050565b6000620000f762000057565b9050620001058282620000b5565b919050565b600067ffffffffffffffff82111562000128576200012762000086565b5b620001338262000075565b9050602081019050919050565b60005b838110156200016057808201518184015260208101905062000143565b60008484015250505050565b6000620001836200017d846200010a565b620000eb565b905082815260208101848484011115620001a257620001a162000070565b5b620001af84828562000140565b509392505050565b600082601f830112620001cf57620001ce6200006b565b5b8151620001e18482602086016200016c565b91505092915050565b60006020828403121562000203576200020262000061565b5b600082015167ffffffffffffffff81111562000224576200022362000066565b5b6200023284828501620001b7565b91505092915050565b600081519050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b600060028204905060018216806200028e57607f821691505b602082108103620002a457620002a362000246565b5b50919050565b60008190508160005260206000209050919050565b60006020601f8301049050919050565b600082821b905092915050565b6000600883026200030e7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82620002cf565b6200031a8683620002cf565b95508019841693508086168417925050509392505050565b6000819050919050565b6000819050919050565b600062000367620003616200035b8462000332565b6200033c565b62000332565b9050919050565b6000819050919050565b620003838362000346565b6200039b62000392826200036e565b848454620002dc565b825550505050565b600090565b620003b2620003a3565b620003bf81848462000378565b505050565b5b81811015620003e757620003db600082620003a8565b600181019050620003c5565b5050565b601f82111562000436576200040081620002aa565b6200040b84620002bf565b810160208510156200041b578190505b620004336200042a85620002bf565b830182620003c4565b50505b505050565b600082821c905092915050565b60006200045b600019846008026200043b565b1980831691505092915050565b600062000476838362000448565b9150826002028217905092915050565b62000491826200023b565b67ffffffffffffffff811115620004ad57620004ac62000086565b5b620004b9825462000275565b620004c6828285620003eb565b600060209050601f831160018114620004fe5760008415620004e9578287015190505b620004f5858262000468565b86555062000565565b601f1984166200050e86620002aa565b60005b82811015620005385784890151825560018201915060208501945060208101905062000511565b8683101562000558578489015162000554601f89168262000448565b8355505b6001600288020188555050505b505050505050565b610953806200057d6000396000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c8063a413686214610046578063cfae321714610077578063d09de08a14610095575b600080fd5b610060600480360381019061005b91906103c0565b61009f565b60405161006e9291906104a3565b60405180910390f35b61007f6101bd565b60405161008c91906104d3565b60405180910390f35b61009d61024f565b005b600060607f0d363f2fba46ab11b6db8da0125b0d5484787c44e265b48810735998bab12b756001846040516100d59291906105ee565b60405180910390a182600190816100ec91906107c6565b507f7d7846723bda52976e0286c6efffee937ee9f76817a867ec70531ad29fb1fc0e600160405161011d9190610898565b60405180910390a160018080805461013490610524565b80601f016020809104026020016040519081016040528092919081815260200182805461016090610524565b80156101ad5780601f10610182576101008083540402835291602001916101ad565b820191906000526020600020905b81548152906001019060200180831161019057829003601f168201915b5050505050905091509150915091565b6060600180546101cc90610524565b80601f01602080910402602001604051908101604052809291908181526020018280546101f890610524565b80156102455780601f1061021a57610100808354040283529160200191610245565b820191906000526020600020905b81548152906001019060200180831161022857829003601f168201915b5050505050905090565b600160005461025e91906108e9565b600081905550565b6000604051905090565b600080fd5b600080fd5b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6102cd82610284565b810181811067ffffffffffffffff821117156102ec576102eb610295565b5b80604052505050565b60006102ff610266565b905061030b82826102c4565b919050565b600067ffffffffffffffff82111561032b5761032a610295565b5b61033482610284565b9050602081019050919050565b82818337600083830152505050565b600061036361035e84610310565b6102f5565b90508281526020810184848401111561037f5761037e61027f565b5b61038a848285610341565b509392505050565b600082601f8301126103a7576103a661027a565b5b81356103b7848260208601610350565b91505092915050565b6000602082840312156103d6576103d5610270565b5b600082013567ffffffffffffffff8111156103f4576103f3610275565b5b61040084828501610392565b91505092915050565b60008115159050919050565b61041e81610409565b82525050565b600081519050919050565b600082825260208201905092915050565b60005b8381101561045e578082015181840152602081019050610443565b60008484015250505050565b600061047582610424565b61047f818561042f565b935061048f818560208601610440565b61049881610284565b840191505092915050565b60006040820190506104b86000830185610415565b81810360208301526104ca818461046a565b90509392505050565b600060208201905081810360008301526104ed818461046a565b905092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b6000600282049050600182168061053c57607f821691505b60208210810361054f5761054e6104f5565b5b50919050565b60008190508160005260206000209050919050565b6000815461057781610524565b610581818661042f565b9450600182166000811461059c57600181146105b2576105e5565b60ff1983168652811515602002860193506105e5565b6105bb85610555565b60005b838110156105dd578154818901526001820191506020810190506105be565b808801955050505b50505092915050565b60006040820190508181036000830152610608818561056a565b9050818103602083015261061c818461046a565b90509392505050565b60006020601f8301049050919050565b600082821b905092915050565b6000600883026106727fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82610635565b61067c8683610635565b95508019841693508086168417925050509392505050565b6000819050919050565b6000819050919050565b60006106c36106be6106b984610694565b61069e565b610694565b9050919050565b6000819050919050565b6106dd836106a8565b6106f16106e9826106ca565b848454610642565b825550505050565b600090565b6107066106f9565b6107118184846106d4565b505050565b5b818110156107355761072a6000826106fe565b600181019050610717565b5050565b601f82111561077a5761074b81610555565b61075484610625565b81016020851015610763578190505b61077761076f85610625565b830182610716565b50505b505050565b600082821c905092915050565b600061079d6000198460080261077f565b1980831691505092915050565b60006107b6838361078c565b9150826002028217905092915050565b6107cf82610424565b67ffffffffffffffff8111156107e8576107e7610295565b5b6107f28254610524565b6107fd828285610739565b600060209050601f831160018114610830576000841561081e578287015190505b61082885826107aa565b865550610890565b601f19841661083e86610555565b60005b8281101561086657848901518255600182019150602085019450602081019050610841565b86831015610883578489015161087f601f89168261078c565b8355505b6001600288020188555050505b505050505050565b600060208201905081810360008301526108b2818461056a565b905092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60006108f482610694565b91506108ff83610694565b9250828201905080821115610917576109166108ba565b5b9291505056fea26469706673582212207e5ba44159ffb37af8e8a9e7c5b6fb5ce81ea195b62ae3ac36288f2cf72c18a764736f6c634300081000330000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000b4d79204772656574696e67000000000000000000000000000000000000000000', + ); + expect(returnFormat).toBe(ETH_DATA_FORMAT); + + // eslint-disable-next-line @typescript-eslint/no-unsafe-return + return Promise.resolve(BigInt(36916)) as any; + }); + const deploy = contract.deploy({ data: GreeterBytecode, arguments: ['My Greeting'], From 0d574908115161b50a3ad2cc93bc6b16954dbaa4 Mon Sep 17 00:00:00 2001 From: luu-alex Date: Thu, 24 Aug 2023 15:52:05 -0400 Subject: [PATCH 09/27] fix unit tests --- packages/web3-eth-contract/test/unit/contract.test.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/web3-eth-contract/test/unit/contract.test.ts b/packages/web3-eth-contract/test/unit/contract.test.ts index fde353b21ee..f45ed66591d 100644 --- a/packages/web3-eth-contract/test/unit/contract.test.ts +++ b/packages/web3-eth-contract/test/unit/contract.test.ts @@ -291,7 +291,7 @@ describe('Contract', () => { }); // eslint-disable-next-line @typescript-eslint/require-await - it.only('send method on deployed contract should work', async () => { + it('send method on deployed contract should work', async () => { const arg = 'Hello'; const contract = new Contract(GreeterAbi); @@ -321,7 +321,9 @@ describe('Contract', () => { if ( _tx.input === - '0xa41368620000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000548656c6c6f000000000000000000000000000000000000000000000000000000' + '0xa41368620000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000548656c6c6f000000000000000000000000000000000000000000000000000000' || + _tx.data === + '0xa41368620000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000548656c6c6f000000000000000000000000000000000000000000000000000000' ) { // eslint-disable-next-line expect(_tx.to).toStrictEqual(deployedAddr); From 2760c634f5bc3b4e27c28c5ad330112b239e55fe Mon Sep 17 00:00:00 2001 From: luu-alex Date: Mon, 28 Aug 2023 15:59:59 -0400 Subject: [PATCH 10/27] update tests --- packages/web3-eth-contract/src/contract.ts | 6 +- packages/web3-eth-contract/src/utils.ts | 28 ++++-- .../local_account/contract_erc20.test.ts | 1 + .../test/unit/contract.test.ts | 85 +++++++++++-------- 4 files changed, 72 insertions(+), 48 deletions(-) diff --git a/packages/web3-eth-contract/src/contract.ts b/packages/web3-eth-contract/src/contract.ts index 9d2b071a6c6..b3fe75e905a 100644 --- a/packages/web3-eth-contract/src/contract.ts +++ b/packages/web3-eth-contract/src/contract.ts @@ -212,6 +212,7 @@ export class Contract * myContract.options.gas = 5000000; // provide as fallback always 5M gas * ``` */ + public readonly options: ContractOptions; /** @@ -373,7 +374,8 @@ export class Contract gas: options?.gas ?? options?.gasLimit, gasPrice: options?.gasPrice, from: options?.from, - input: options?.input ?? options?.data, + input: options?.input, + data: options?.data, }; this.syncWithContext = (options as ContractInitOptions)?.syncWithContext ?? false; @@ -1059,7 +1061,7 @@ export class Contract // TODO Should make this configurable by the user checkRevertBeforeSending: false, }); - + // eslint-disable-next-line no-void void transactionToSend.on('error', (error: unknown) => { if (error instanceof ContractExecutionError) { diff --git a/packages/web3-eth-contract/src/utils.ts b/packages/web3-eth-contract/src/utils.ts index 7872fa84c49..f8b24131814 100644 --- a/packages/web3-eth-contract/src/utils.ts +++ b/packages/web3-eth-contract/src/utils.ts @@ -46,7 +46,8 @@ export const getSendTxParams = ({ }; contractOptions: ContractOptions; }): TransactionCall => { - const deploymentCall = options?.input ?? options?.data ?? contractOptions.input ?? contractOptions.data; + const deploymentCall = + options?.input ?? options?.data ?? contractOptions.input ?? contractOptions.data; if (!deploymentCall && !options?.to && !contractOptions.address) { throw new Web3ContractError('Contract address not specified'); } @@ -63,16 +64,16 @@ export const getSendTxParams = ({ input: contractOptions.input, maxPriorityFeePerGas: contractOptions.maxPriorityFeePerGas, maxFeePerGas: contractOptions.maxFeePerGas, - data: contractOptions.data + data: contractOptions.data, }, options as unknown as Record, ) as unknown as TransactionCall; - if (txParams.input && abi.type === 'constructor') { + if (txParams.input) { txParams = { ...txParams, input: encodeMethodABI(abi, params, txParams.input as HexString), }; - } else if (txParams.data && abi.type === 'constructor') { + } else if (txParams.data) { txParams = { ...txParams, data: encodeMethodABI(abi, params, txParams.data as HexString), @@ -80,12 +81,13 @@ export const getSendTxParams = ({ } else if (abi.type === 'constructor') { txParams = { ...txParams, - data: encodeMethodABI(abi, params, txParams.data as HexString), + input: encodeMethodABI(abi, params, txParams.data as HexString), }; } else { + // if no data is specified, default to input txParams = { ...txParams, - data: encodeMethodABI(abi, params, txParams.data as HexString), + input: encodeMethodABI(abi, params, txParams.data as HexString), }; } return txParams; @@ -147,11 +149,19 @@ export const getEstimateGasParams = ({ gasPrice: contractOptions.gasPrice, from: contractOptions.from, input: contractOptions.input, - data: contractOptions.data + data: contractOptions.data, }, options as unknown as Record, ) as unknown as TransactionCall; - const deployData = txParams.input ? toHex(txParams.input) : txParams.data ? toHex(txParams.data) : undefined + let deployData; + + if (txParams.input) { + deployData = toHex(txParams.input); + } else if (txParams.data) { + deployData = toHex(txParams.data); + } else { + deployData = undefined; + } if (txParams.input) { txParams = { ...txParams, @@ -166,7 +176,7 @@ export const getEstimateGasParams = ({ txParams = { ...txParams, input: encodeMethodABI(abi, params, deployData), - } + }; } return txParams as TransactionWithSenderAPI; }; diff --git a/packages/web3-eth-contract/test/integration/local_account/contract_erc20.test.ts b/packages/web3-eth-contract/test/integration/local_account/contract_erc20.test.ts index 878f4ad7dd4..bd379e5f647 100644 --- a/packages/web3-eth-contract/test/integration/local_account/contract_erc20.test.ts +++ b/packages/web3-eth-contract/test/integration/local_account/contract_erc20.test.ts @@ -99,6 +99,7 @@ describe('contract', () => { const value = BigInt(10); const extraAmount = BigInt(4); const tempAccount = await createLocalAccount(web3); + // approve await contractDeployed.methods .approve(tempAccount.address, value) diff --git a/packages/web3-eth-contract/test/unit/contract.test.ts b/packages/web3-eth-contract/test/unit/contract.test.ts index f45ed66591d..3666a26fb1f 100644 --- a/packages/web3-eth-contract/test/unit/contract.test.ts +++ b/packages/web3-eth-contract/test/unit/contract.test.ts @@ -208,7 +208,7 @@ describe('Contract', () => { let sendOptions: Record; const deployedAddr = '0x20bc23D0598b12c34cBDEf1fae439Ba8744DB426'; - beforeAll(() => { + beforeEach(() => { sendOptions = { from: '0x12364916b10Ae90076dDa6dE756EE1395BB69ec2', gas: '1000000', @@ -291,39 +291,22 @@ describe('Contract', () => { }); // eslint-disable-next-line @typescript-eslint/require-await - it('send method on deployed contract should work', async () => { + it('send method on deployed contract should work using input', async () => { const arg = 'Hello'; const contract = new Contract(GreeterAbi); - - // eslint-disable-next-line @typescript-eslint/no-empty-function - // const send = jest.spyOn( - // { - // send: () => { - // return { on: () => {} }; - // }, - // }, - // 'send', - // ); - - // const setResolverMock = jest.spyOn(ens['_registry'], 'setResolver').mockReturnValue({ - // send, - // } as unknown as Web3PromiEvent); + sendOptions = { + from: '0x12364916b10Ae90076dDa6dE756EE1395BB69ec2', + gas: '1000000', + }; const spyTx = jest .spyOn(eth, 'sendTransaction') .mockImplementation((_objInstance, _tx) => { const newContract = contract.clone(); newContract.options.address = deployedAddr; - - // jest.spyOn(newContract.methods.setGreeting(arg), 'send').mockReturnValue({ - // send, - // status: '0x1', - // } as unknown as Web3PromiEvent); - + expect(_tx.input).toBeDefined(); if ( _tx.input === - '0xa41368620000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000548656c6c6f000000000000000000000000000000000000000000000000000000' || - _tx.data === - '0xa41368620000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000548656c6c6f000000000000000000000000000000000000000000000000000000' + '0xa41368620000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000548656c6c6f000000000000000000000000000000000000000000000000000000' ) { // eslint-disable-next-line expect(_tx.to).toStrictEqual(deployedAddr); @@ -334,24 +317,52 @@ describe('Contract', () => { // eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-empty-function return Promise.resolve(Object.assign(newContract, { on: () => {} })) as any; }); - // const spyTx = jest.spyOn(eth, 'sendTransaction').mockImplementation((...args) => { - // // const actualEth = jest.requireActual('web3-eth'); - - // // eslint-disable-next-line @typescript-eslint/no-unsafe-call - // // const transactionToSend = actualEth.sendTransaction(args); - // // Object.assign(transactionToSend, { on: () => {} }); - // // return transactionToSend; - // // eslint-disable-next-line @typescript-eslint/no-unsafe-return - // // eslint-disable-next-line @typescript-eslint/no-empty-function - // return { on: () => {} } as unknown as Web3PromiEvent; - // }); + const deployedContract = await contract .deploy({ input: GreeterBytecode, arguments: ['My Greeting'], }) .send(sendOptions); + const receipt = await deployedContract.methods.setGreeting(arg).send(sendOptions); + expect(receipt.status).toBe('0x1'); + + spyTx.mockClear(); + }); + + it('send method on deployed contract should work using data', async () => { + const arg = 'Hello'; + const contract = new Contract(GreeterAbi); + sendOptions = { + from: '0x12364916b10Ae90076dDa6dE756EE1395BB69ec2', + gas: '1000000', + data: '0xa41368620000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000548656c6c6f000000000000000000000000000000000000000000000000000000', + }; + const spyTx = jest + .spyOn(eth, 'sendTransaction') + .mockImplementation((_objInstance, _tx) => { + const newContract = contract.clone(); + newContract.options.address = deployedAddr; + if ( + _tx.data === + '0xa41368620000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000548656c6c6f000000000000000000000000000000000000000000000000000000' + ) { + // eslint-disable-next-line + expect(_tx.to).toStrictEqual(deployedAddr); + // eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-empty-function + return { status: '0x1', on: () => {} } as any; + } + // eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-empty-function + return Promise.resolve(Object.assign(newContract, { on: () => {} })) as any; + }); + + const deployedContract = await contract + .deploy({ + data: GreeterBytecode, + arguments: ['My Greeting'], + }) + .send(sendOptions); const receipt = await deployedContract.methods.setGreeting(arg).send(sendOptions); expect(receipt.status).toBe('0x1'); @@ -990,7 +1001,7 @@ describe('Contract', () => { expect(_block).toBe('latest'); expect(_tx.to).toStrictEqual(deployedAddr); expect(_tx.from).toStrictEqual(sendOptions.from); - expect(_tx.input).toBe( + expect(_tx.data).toBe( '0xa41368620000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000548656c6c6f000000000000000000000000000000000000000000000000000000', ); From 8b77a372f0132f4f543f797f8b7f4e5c8b04b7a6 Mon Sep 17 00:00:00 2001 From: luu-alex Date: Mon, 28 Aug 2023 16:34:38 -0400 Subject: [PATCH 11/27] remove console log --- .../web3-eth-contract/test/integration/contract_deploy.test.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/web3-eth-contract/test/integration/contract_deploy.test.ts b/packages/web3-eth-contract/test/integration/contract_deploy.test.ts index 1f0a926346c..5c6c666212c 100644 --- a/packages/web3-eth-contract/test/integration/contract_deploy.test.ts +++ b/packages/web3-eth-contract/test/integration/contract_deploy.test.ts @@ -96,7 +96,6 @@ describe('contract', () => { ); it('should return estimated gas of contract constructor %p', async () => { - console.log("estimate gas") const estimatedGas = await new Contract(GreeterAbi, undefined, { provider: getSystemTestProvider(), }) @@ -109,7 +108,6 @@ describe('contract', () => { gas: '1000000', }); expect(Number(estimatedGas)).toBeGreaterThan(0); - console.log("after estimate") }); it('should return estimated gas of contract constructor without arguments', async () => { const estimatedGas = await new Contract(ERC721TokenAbi, undefined, { From e2a6a9d7d915fcbe3660ab782ed9a1417646fea6 Mon Sep 17 00:00:00 2001 From: luu-alex Date: Mon, 28 Aug 2023 17:03:40 -0400 Subject: [PATCH 12/27] clean up --- packages/web3-eth-contract/src/contract.ts | 3 +-- packages/web3-eth-contract/src/utils.ts | 20 +++++++++++++++++-- .../prepare_transaction_for_signing.test.ts | 2 +- 3 files changed, 20 insertions(+), 5 deletions(-) diff --git a/packages/web3-eth-contract/src/contract.ts b/packages/web3-eth-contract/src/contract.ts index b3fe75e905a..90e4bbb99a6 100644 --- a/packages/web3-eth-contract/src/contract.ts +++ b/packages/web3-eth-contract/src/contract.ts @@ -605,8 +605,7 @@ export class Contract if ((!_input || _input.trim() === '0x') && (!_data || _data.trim() === '0x')) { throw new Web3ContractError('contract creation without any data provided.'); } - // check if data is used properly - // see if deploy data is working as intended. + const args = deployOptions?.arguments ?? []; const contractOptions: ContractOptions = { ...this.options, input: _input, data: _data }; diff --git a/packages/web3-eth-contract/src/utils.ts b/packages/web3-eth-contract/src/utils.ts index f8b24131814..3ecfdeb8d17 100644 --- a/packages/web3-eth-contract/src/utils.ts +++ b/packages/web3-eth-contract/src/utils.ts @@ -232,11 +232,27 @@ export const getCreateAccessListParams = ({ options as unknown as Record, ) as unknown as TransactionForAccessList; - if (!txParams.input || abi.type === 'constructor') { + if (txParams.input) { txParams = { ...txParams, input: encodeMethodABI(abi, params, txParams.input as HexString), - }; // need an option for data? + }; + } else if (txParams.data) { + txParams = { + ...txParams, + data: encodeMethodABI(abi, params, txParams.data as HexString), + }; + } else if (abi.type === 'constructor') { + txParams = { + ...txParams, + input: encodeMethodABI(abi, params, txParams.data as HexString), + }; + } else { + // if no data is specified, default to input + txParams = { + ...txParams, + input: encodeMethodABI(abi, params, txParams.data as HexString), + }; } return txParams; diff --git a/packages/web3-eth/test/unit/prepare_transaction_for_signing.test.ts b/packages/web3-eth/test/unit/prepare_transaction_for_signing.test.ts index 60d99f0ee7c..cf301264407 100644 --- a/packages/web3-eth/test/unit/prepare_transaction_for_signing.test.ts +++ b/packages/web3-eth/test/unit/prepare_transaction_for_signing.test.ts @@ -31,7 +31,7 @@ import { prepareTransactionForSigning } from '../../src/utils/prepare_transactio import { validTransactions } from '../fixtures/prepare_transaction_for_signing'; describe('prepareTransactionForSigning', () => { -const web3Context = new Web3Context({ + const web3Context = new Web3Context({ provider: new HttpProvider('http://127.0.0.1'), config: { defaultNetworkId: '0x1' }, }); From c4acb78243317e23b5d66df5c7b0070bd5e15362 Mon Sep 17 00:00:00 2001 From: luu-alex Date: Mon, 28 Aug 2023 21:27:54 -0400 Subject: [PATCH 13/27] update test case and reformat --- packages/web3-eth-contract/src/utils.ts | 81 +++++++++---------- .../unit/rpc_method_wrappers/fixtures/call.ts | 1 + 2 files changed, 39 insertions(+), 43 deletions(-) diff --git a/packages/web3-eth-contract/src/utils.ts b/packages/web3-eth-contract/src/utils.ts index 3ecfdeb8d17..30895404bd5 100644 --- a/packages/web3-eth-contract/src/utils.ts +++ b/packages/web3-eth-contract/src/utils.ts @@ -31,6 +31,37 @@ import { isNullish, mergeDeep, toHex } from 'web3-utils'; import { encodeMethodABI } from './encoding.js'; import { ContractOptions, Web3ContractContext } from './types.js'; +const dataInputEncodeMethodHelper = ( + txParams: TransactionCall, + abi: AbiFunctionFragment, + params: unknown[], +): TransactionCall => { + let tx = txParams; + if (tx.input) { + tx = { + ...txParams, + input: encodeMethodABI(abi, params, txParams.input as HexString), + }; + } else if (tx.data) { + tx = { + ...txParams, + data: encodeMethodABI(abi, params, txParams.data as HexString), + }; + } else if (abi.type === 'constructor') { + tx = { + ...txParams, + input: encodeMethodABI(abi, params, txParams.data as HexString), + }; + } else { + // if no data is specified, default to input + tx = { + ...txParams, + input: encodeMethodABI(abi, params, txParams.data as HexString), + }; + } + return tx; +}; + export const getSendTxParams = ({ abi, params, @@ -68,28 +99,7 @@ export const getSendTxParams = ({ }, options as unknown as Record, ) as unknown as TransactionCall; - if (txParams.input) { - txParams = { - ...txParams, - input: encodeMethodABI(abi, params, txParams.input as HexString), - }; - } else if (txParams.data) { - txParams = { - ...txParams, - data: encodeMethodABI(abi, params, txParams.data as HexString), - }; - } else if (abi.type === 'constructor') { - txParams = { - ...txParams, - input: encodeMethodABI(abi, params, txParams.data as HexString), - }; - } else { - // if no data is specified, default to input - txParams = { - ...txParams, - input: encodeMethodABI(abi, params, txParams.data as HexString), - }; - } + txParams = dataInputEncodeMethodHelper(txParams, abi, params); return txParams; }; @@ -153,31 +163,16 @@ export const getEstimateGasParams = ({ }, options as unknown as Record, ) as unknown as TransactionCall; - let deployData; if (txParams.input) { - deployData = toHex(txParams.input); - } else if (txParams.data) { - deployData = toHex(txParams.data); - } else { - deployData = undefined; + txParams.input = toHex(txParams.input); } - if (txParams.input) { - txParams = { - ...txParams, - input: encodeMethodABI(abi, params, deployData), - }; - } else if (txParams.data) { - txParams = { - ...txParams, - data: encodeMethodABI(abi, params, deployData), - }; - } else { - txParams = { - ...txParams, - input: encodeMethodABI(abi, params, deployData), - }; + if (txParams.data) { + txParams.data = toHex(txParams.data); } + + txParams = dataInputEncodeMethodHelper(txParams, abi, params); + return txParams as TransactionWithSenderAPI; }; diff --git a/packages/web3-eth/test/unit/rpc_method_wrappers/fixtures/call.ts b/packages/web3-eth/test/unit/rpc_method_wrappers/fixtures/call.ts index e8949e97eab..a65a4107f00 100644 --- a/packages/web3-eth/test/unit/rpc_method_wrappers/fixtures/call.ts +++ b/packages/web3-eth/test/unit/rpc_method_wrappers/fixtures/call.ts @@ -28,6 +28,7 @@ const transaction: TransactionCall = { maxFeePerGas: '0x1229298c00', maxPriorityFeePerGas: '0x49504f80', data: '0x', + input: '0x', nonce: '0x4', chain: 'mainnet', hardfork: 'berlin', From d66fd67d54788cd80e1b516235af35cc35cf5dca Mon Sep 17 00:00:00 2001 From: luu-alex Date: Tue, 29 Aug 2023 14:21:46 -0400 Subject: [PATCH 14/27] address feedback --- packages/web3-eth-contract/src/utils.ts | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/packages/web3-eth-contract/src/utils.ts b/packages/web3-eth-contract/src/utils.ts index 30895404bd5..bc5133c3c79 100644 --- a/packages/web3-eth-contract/src/utils.ts +++ b/packages/web3-eth-contract/src/utils.ts @@ -48,15 +48,10 @@ const dataInputEncodeMethodHelper = ( data: encodeMethodABI(abi, params, txParams.data as HexString), }; } else if (abi.type === 'constructor') { + // default to using input tx = { ...txParams, - input: encodeMethodABI(abi, params, txParams.data as HexString), - }; - } else { - // if no data is specified, default to input - tx = { - ...txParams, - input: encodeMethodABI(abi, params, txParams.data as HexString), + input: encodeMethodABI(abi, params, txParams.input as HexString), }; } return tx; @@ -240,13 +235,7 @@ export const getCreateAccessListParams = ({ } else if (abi.type === 'constructor') { txParams = { ...txParams, - input: encodeMethodABI(abi, params, txParams.data as HexString), - }; - } else { - // if no data is specified, default to input - txParams = { - ...txParams, - input: encodeMethodABI(abi, params, txParams.data as HexString), + input: encodeMethodABI(abi, params, txParams.input as HexString), }; } From bd2d9c16206b9a23a7a139acccfd14e72c6d80e1 Mon Sep 17 00:00:00 2001 From: luu-alex Date: Tue, 29 Aug 2023 15:35:31 -0400 Subject: [PATCH 15/27] update else statement --- packages/web3-eth-contract/src/utils.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/web3-eth-contract/src/utils.ts b/packages/web3-eth-contract/src/utils.ts index bc5133c3c79..060f31f70ce 100644 --- a/packages/web3-eth-contract/src/utils.ts +++ b/packages/web3-eth-contract/src/utils.ts @@ -47,7 +47,7 @@ const dataInputEncodeMethodHelper = ( ...txParams, data: encodeMethodABI(abi, params, txParams.data as HexString), }; - } else if (abi.type === 'constructor') { + } else { // default to using input tx = { ...txParams, @@ -232,7 +232,7 @@ export const getCreateAccessListParams = ({ ...txParams, data: encodeMethodABI(abi, params, txParams.data as HexString), }; - } else if (abi.type === 'constructor') { + } else { txParams = { ...txParams, input: encodeMethodABI(abi, params, txParams.input as HexString), From b06aa2e04834769ba25921b9f663005c7017e43f Mon Sep 17 00:00:00 2001 From: luu-alex Date: Sat, 2 Sep 2023 10:23:45 -0400 Subject: [PATCH 16/27] adding tests and refactoring --- packages/web3-eth-contract/src/utils.ts | 31 ++++--------------- .../test/unit/contract.test.ts | 25 +++++++++++++++ 2 files changed, 31 insertions(+), 25 deletions(-) diff --git a/packages/web3-eth-contract/src/utils.ts b/packages/web3-eth-contract/src/utils.ts index 060f31f70ce..c564b9c41d6 100644 --- a/packages/web3-eth-contract/src/utils.ts +++ b/packages/web3-eth-contract/src/utils.ts @@ -37,12 +37,12 @@ const dataInputEncodeMethodHelper = ( params: unknown[], ): TransactionCall => { let tx = txParams; - if (tx.input) { + if (isNullish(tx.input)) { tx = { ...txParams, input: encodeMethodABI(abi, params, txParams.input as HexString), }; - } else if (tx.data) { + } else if (!isNullish(tx.data)) { tx = { ...txParams, data: encodeMethodABI(abi, params, txParams.data as HexString), @@ -127,11 +127,7 @@ export const getEthTxCallParams = ({ options as unknown as Record, ) as unknown as TransactionCall; - txParams = { - ...txParams, - input: encodeMethodABI(abi, params, txParams.input ? toHex(txParams.input) : undefined), - data: encodeMethodABI(abi, params, txParams.data ? toHex(txParams.data) : undefined), - }; + txParams = dataInputEncodeMethodHelper(txParams, abi, params); return txParams; }; @@ -159,10 +155,10 @@ export const getEstimateGasParams = ({ options as unknown as Record, ) as unknown as TransactionCall; - if (txParams.input) { + if (!isNullish(txParams.input)) { txParams.input = toHex(txParams.input); } - if (txParams.data) { + if (!isNullish(txParams.data)) { txParams.data = toHex(txParams.data); } @@ -222,22 +218,7 @@ export const getCreateAccessListParams = ({ options as unknown as Record, ) as unknown as TransactionForAccessList; - if (txParams.input) { - txParams = { - ...txParams, - input: encodeMethodABI(abi, params, txParams.input as HexString), - }; - } else if (txParams.data) { - txParams = { - ...txParams, - data: encodeMethodABI(abi, params, txParams.data as HexString), - }; - } else { - txParams = { - ...txParams, - input: encodeMethodABI(abi, params, txParams.input as HexString), - }; - } + txParams = dataInputEncodeMethodHelper(txParams, abi, params); return txParams; }; diff --git a/packages/web3-eth-contract/test/unit/contract.test.ts b/packages/web3-eth-contract/test/unit/contract.test.ts index 3666a26fb1f..85996cd2ef2 100644 --- a/packages/web3-eth-contract/test/unit/contract.test.ts +++ b/packages/web3-eth-contract/test/unit/contract.test.ts @@ -623,6 +623,31 @@ describe('Contract', () => { spyEthCall.mockClear(); }); + it('should be able call a payable method with data as an option', async () => { + const contract = new Contract( + erc721Abi, + '0x1230B93ffd14F2F022039675fA3fc3A46eE4C701', + { gas: '123' }, + { config: { defaultAccount: '0x00000000219ab540356cBB839Cbe05303d7705Fa' } }, + ); + + const spyEthCall = jest + .spyOn(eth, 'call') + .mockImplementation(async (_objInstance, _tx) => { + expect(_tx.to).toBe('0x1230B93ffd14F2F022039675fA3fc3A46eE4C701'); + expect(_tx.input).toBe( + '0x095ea7b300000000000000000000000000000000219ab540356cbb839cbe05303d7705fa0000000000000000000000000000000000000000000000000000000000000001', + ); + return '0x00'; + }); + + await expect( + contract.methods.approve('0x00000000219ab540356cBB839Cbe05303d7705Fa', 1).call(), + ).resolves.toBeTruthy(); + + spyEthCall.mockClear(); + }); + it('getPastEvents with filter should work', async () => { const contract = new Contract(GreeterAbi); From e2c2569259b398e476c653affeb392307ab80f69 Mon Sep 17 00:00:00 2001 From: luu-alex Date: Sun, 3 Sep 2023 11:17:28 -0400 Subject: [PATCH 17/27] fix builds --- packages/web3-eth-contract/src/utils.ts | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/packages/web3-eth-contract/src/utils.ts b/packages/web3-eth-contract/src/utils.ts index c564b9c41d6..877fc48d16c 100644 --- a/packages/web3-eth-contract/src/utils.ts +++ b/packages/web3-eth-contract/src/utils.ts @@ -37,7 +37,7 @@ const dataInputEncodeMethodHelper = ( params: unknown[], ): TransactionCall => { let tx = txParams; - if (isNullish(tx.input)) { + if (!isNullish(tx.input)) { tx = { ...txParams, input: encodeMethodABI(abi, params, txParams.input as HexString), @@ -218,7 +218,22 @@ export const getCreateAccessListParams = ({ options as unknown as Record, ) as unknown as TransactionForAccessList; - txParams = dataInputEncodeMethodHelper(txParams, abi, params); - + if (!isNullish(txParams.input)) { + txParams = { + ...txParams, + input: encodeMethodABI(abi, params, txParams.input as HexString), + }; + } else if (!isNullish(txParams.data)) { + txParams = { + ...txParams, + data: encodeMethodABI(abi, params, txParams.data as HexString), + }; + } else { + // default to using input + txParams = { + ...txParams, + input: encodeMethodABI(abi, params, txParams.input), + }; + } return txParams; }; From 9ea72a4341af76564b44c2da940f5b3c3a3f0046 Mon Sep 17 00:00:00 2001 From: luu-alex Date: Tue, 5 Sep 2023 00:48:39 -0400 Subject: [PATCH 18/27] address feedback --- packages/web3-eth-contract/src/utils.ts | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/packages/web3-eth-contract/src/utils.ts b/packages/web3-eth-contract/src/utils.ts index 877fc48d16c..42411403dc3 100644 --- a/packages/web3-eth-contract/src/utils.ts +++ b/packages/web3-eth-contract/src/utils.ts @@ -37,12 +37,7 @@ const dataInputEncodeMethodHelper = ( params: unknown[], ): TransactionCall => { let tx = txParams; - if (!isNullish(tx.input)) { - tx = { - ...txParams, - input: encodeMethodABI(abi, params, txParams.input as HexString), - }; - } else if (!isNullish(tx.data)) { + if (!isNullish(tx.data)) { tx = { ...txParams, data: encodeMethodABI(abi, params, txParams.data as HexString), From b4e00585462d48fe784434a22cb71a5d033f0597 Mon Sep 17 00:00:00 2001 From: luu-alex Date: Tue, 5 Sep 2023 10:57:44 -0400 Subject: [PATCH 19/27] address feedback --- packages/web3-eth-contract/src/utils.ts | 56 +++++++++++-------------- 1 file changed, 24 insertions(+), 32 deletions(-) diff --git a/packages/web3-eth-contract/src/utils.ts b/packages/web3-eth-contract/src/utils.ts index 42411403dc3..b552e1d22a8 100644 --- a/packages/web3-eth-contract/src/utils.ts +++ b/packages/web3-eth-contract/src/utils.ts @@ -27,29 +27,38 @@ import { PayableCallOptions, ContractInitOptions, } from 'web3-types'; -import { isNullish, mergeDeep, toHex } from 'web3-utils'; +import { isNullish, mergeDeep } from 'web3-utils'; import { encodeMethodABI } from './encoding.js'; import { ContractOptions, Web3ContractContext } from './types.js'; const dataInputEncodeMethodHelper = ( - txParams: TransactionCall, + txParams: TransactionCall | TransactionForAccessList, abi: AbiFunctionFragment, params: unknown[], -): TransactionCall => { +): {data?: HexString, input?: HexString} => { let tx = txParams; if (!isNullish(tx.data)) { tx = { ...txParams, data: encodeMethodABI(abi, params, txParams.data as HexString), }; - } else { + } + if (!isNullish(tx.input)){ + tx = { + ...txParams, + input: encodeMethodABI(abi, params, txParams.input as HexString), + }; + } + // if input and data is empty, use input as default + if (isNullish(tx.input) && isNullish(tx.data)) { // default to using input tx = { ...txParams, input: encodeMethodABI(abi, params, txParams.input as HexString), }; } - return tx; + + return {data: tx.data as HexString, input: tx.input as HexString}; }; export const getSendTxParams = ({ @@ -89,7 +98,9 @@ export const getSendTxParams = ({ }, options as unknown as Record, ) as unknown as TransactionCall; - txParams = dataInputEncodeMethodHelper(txParams, abi, params); + const dataInput = dataInputEncodeMethodHelper(txParams, abi, params); + txParams = {...txParams, data: dataInput.data, input: dataInput.input} + return txParams; }; @@ -122,7 +133,8 @@ export const getEthTxCallParams = ({ options as unknown as Record, ) as unknown as TransactionCall; - txParams = dataInputEncodeMethodHelper(txParams, abi, params); + const dataInput = dataInputEncodeMethodHelper(txParams, abi, params); + txParams = {...txParams, data: dataInput.data, input: dataInput.input} return txParams; }; @@ -150,14 +162,8 @@ export const getEstimateGasParams = ({ options as unknown as Record, ) as unknown as TransactionCall; - if (!isNullish(txParams.input)) { - txParams.input = toHex(txParams.input); - } - if (!isNullish(txParams.data)) { - txParams.data = toHex(txParams.data); - } - - txParams = dataInputEncodeMethodHelper(txParams, abi, params); + const dataInput = dataInputEncodeMethodHelper(txParams, abi, params); + txParams = {...txParams, data: dataInput.data, input: dataInput.input} return txParams as TransactionWithSenderAPI; }; @@ -213,22 +219,8 @@ export const getCreateAccessListParams = ({ options as unknown as Record, ) as unknown as TransactionForAccessList; - if (!isNullish(txParams.input)) { - txParams = { - ...txParams, - input: encodeMethodABI(abi, params, txParams.input as HexString), - }; - } else if (!isNullish(txParams.data)) { - txParams = { - ...txParams, - data: encodeMethodABI(abi, params, txParams.data as HexString), - }; - } else { - // default to using input - txParams = { - ...txParams, - input: encodeMethodABI(abi, params, txParams.input), - }; - } + const dataInput = dataInputEncodeMethodHelper(txParams, abi, params); + txParams = {...txParams, data: dataInput.data, input: dataInput.input} + return txParams; }; From 7f5d08b250a56e6a09eaea5d5bb07c81a5cb3db4 Mon Sep 17 00:00:00 2001 From: luu-alex Date: Wed, 6 Sep 2023 00:06:06 -0400 Subject: [PATCH 20/27] add dataInputFill flag --- packages/web3-core/src/web3_config.ts | 21 +++++++++++ .../__snapshots__/web3_context.test.ts.snap | 1 + .../web3-core/test/unit/web3_config.test.ts | 1 + packages/web3-eth-contract/src/contract.ts | 24 ++++++++----- packages/web3-eth-contract/src/utils.ts | 28 ++++++--------- .../test/unit/contract.test.ts | 35 +++++++++++++++---- packages/web3-types/src/eth_contract_types.ts | 5 +++ 7 files changed, 83 insertions(+), 32 deletions(-) diff --git a/packages/web3-core/src/web3_config.ts b/packages/web3-core/src/web3_config.ts index 11436841b2d..c58023b46d3 100644 --- a/packages/web3-core/src/web3_config.ts +++ b/packages/web3-core/src/web3_config.ts @@ -37,6 +37,7 @@ export interface Web3ConfigOptions { transactionConfirmationPollingInterval?: number; blockHeaderTimeout: number; maxListenersWarningThreshold: number; + contractDataInputFill: 'data' | 'input' | 'both' defaultNetworkId?: Numbers; defaultChain: string; defaultHardfork: string; @@ -78,6 +79,7 @@ export abstract class Web3Config transactionConfirmationPollingInterval: undefined, blockHeaderTimeout: 10, maxListenersWarningThreshold: 100, + contractDataInputFill: 'input', defaultNetworkId: undefined, defaultChain: 'mainnet', defaultHardfork: 'london', @@ -126,6 +128,25 @@ export abstract class Web3Config this.config.handleRevert = val; } + /** + * The `contractDataInputFill` options property will allow you to set the hash of the method signature and encoded parameters to the property either `data`, `input` or both within your contract. This will affect: + * - myContract.deploy() + * - myContract.methods.myMethod().call() + * - myContract.methods.myMethod().send() + * Default is `input`. + */ + public get contractDataInputFill() { + return this.config.contractDataInputFill; + } + + /** + * Will set the contractDataInputFill + */ + public set contractDataInputFill(val) { + this._triggerConfigChange('contractDataInputFill', val); + this.config.contractDataInputFill = val; + } + /** * This default address is used as the default `from` property, if no `from` property is specified in for the following methods: * - web3.eth.sendTransaction() diff --git a/packages/web3-core/test/unit/__snapshots__/web3_context.test.ts.snap b/packages/web3-core/test/unit/__snapshots__/web3_context.test.ts.snap index 8053e771302..775594827c9 100644 --- a/packages/web3-core/test/unit/__snapshots__/web3_context.test.ts.snap +++ b/packages/web3-core/test/unit/__snapshots__/web3_context.test.ts.snap @@ -5,6 +5,7 @@ Object { "accountProvider": undefined, "config": Object { "blockHeaderTimeout": 10, + "contractDataInputFill": "input", "defaultAccount": undefined, "defaultBlock": "latest", "defaultChain": "mainnet", diff --git a/packages/web3-core/test/unit/web3_config.test.ts b/packages/web3-core/test/unit/web3_config.test.ts index ceab871a0c2..435ac9b8806 100644 --- a/packages/web3-core/test/unit/web3_config.test.ts +++ b/packages/web3-core/test/unit/web3_config.test.ts @@ -33,6 +33,7 @@ const defaultConfig = { useRpcCallSpecification: false, }, handleRevert: false, + contractDataInputFill: 'input', maxListenersWarningThreshold: 100, transactionBlockTimeout: 50, transactionConfirmationBlocks: 24, diff --git a/packages/web3-eth-contract/src/contract.ts b/packages/web3-eth-contract/src/contract.ts index 90e4bbb99a6..2b029e3d901 100644 --- a/packages/web3-eth-contract/src/contract.ts +++ b/packages/web3-eth-contract/src/contract.ts @@ -234,6 +234,7 @@ export class Contract private readonly _overloadedMethodAbis: Map; private _methods!: ContractMethodsInterface; private _events!: ContractEventsInterface; + private _dataInputFill?: 'data' | 'input' | 'both' private context?: Web3Context; /** @@ -349,7 +350,6 @@ export class Contract provider, registeredSubscriptions: contractSubscriptions, }); - this._overloadedMethodAbis = new Map(); // eslint-disable-next-line no-nested-ternary @@ -362,6 +362,10 @@ export class Contract const address = typeof addressOrOptionsOrContext === 'string' ? addressOrOptionsOrContext : undefined; + this._dataInputFill = (options as ContractInitOptions)?.dataInputFill ?? 'input'; + if (contractContext instanceof Web3Context){ + this._dataInputFill = contractContext.config.contractDataInputFill; + } this._parseAndSetJsonInterface(jsonInterface, returnDataFormat); if (!isNullish(address)) { @@ -378,11 +382,12 @@ export class Contract data: options?.data, }; + + this.syncWithContext = (options as ContractInitOptions)?.syncWithContext ?? false; if (contractContext instanceof Web3Context) { this.subscribeToContextEvents(contractContext); } - Object.defineProperty(this.options, 'address', { set: (value: Address) => this._parseAndSetAddress(value, returnDataFormat), get: () => this._address, @@ -472,7 +477,6 @@ export class Contract */ public clone() { let newContract: Contract; - if (this.options.address) { newContract = new Contract( [...this._jsonInterface, ...this._errorsInterface] as unknown as Abi, @@ -485,6 +489,7 @@ export class Contract data: this.options.data, provider: this.currentProvider, syncWithContext: this.syncWithContext, + dataInputFill: this._dataInputFill }, this.getContextObject(), ); @@ -499,6 +504,7 @@ export class Contract data: this.options.data, provider: this.currentProvider, syncWithContext: this.syncWithContext, + dataInputFill: this._dataInputFill }, this.getContextObject(), ); @@ -581,7 +587,6 @@ export class Contract arguments?: ContractConstructorArgs; }) { let abi = this._jsonInterface.find(j => j.type === 'constructor') as AbiConstructorFragment; - if (!abi) { abi = { type: 'constructor', @@ -792,7 +797,6 @@ export class Contract returnFormat: DataFormat = DEFAULT_RETURN_FORMAT, ) { this._functions = {}; - this._methods = {} as ContractMethodsInterface; this._events = {} as ContractEventsInterface; @@ -829,7 +833,7 @@ export class Contract const contractMethod = this._createContractMethod< typeof abiFragment, AbiErrorFragment - >(abiFragment, errorsAbi); + >(abiFragment, errorsAbi, this._dataInputFill); this._functions[methodName] = { signature: methodSignature, @@ -887,8 +891,10 @@ export class Contract private _createContractMethod( abiArr: T, errorsAbis: E[], + dataInputFill?: string ): ContractBoundMethod { const abi = abiArr[abiArr.length - 1]; + console.log(dataInputFill) return (...params: unknown[]) => { let abiParams!: Array; const abis = this._overloadedMethodAbis.get(abi.name) ?? []; @@ -933,7 +939,8 @@ export class Contract methodAbi, abiParams, internalErrorsAbis, - options, + {...options, + dataInputFill}, block, ), @@ -983,9 +990,10 @@ export class Contract abi: AbiFunctionFragment, params: unknown[], errorsAbi: AbiErrorFragment[], - options?: Options, + options?: Options & {dataInputFill?: string}, block?: BlockNumberOrTag, ) { + console.log(options?.dataInputFill) const tx = getEthTxCallParams({ abi, params, diff --git a/packages/web3-eth-contract/src/utils.ts b/packages/web3-eth-contract/src/utils.ts index b552e1d22a8..c1b779b1f46 100644 --- a/packages/web3-eth-contract/src/utils.ts +++ b/packages/web3-eth-contract/src/utils.ts @@ -35,27 +35,18 @@ const dataInputEncodeMethodHelper = ( txParams: TransactionCall | TransactionForAccessList, abi: AbiFunctionFragment, params: unknown[], + dataInputFill?: string, ): {data?: HexString, input?: HexString} => { let tx = txParams; - if (!isNullish(tx.data)) { - tx = { - ...txParams, - data: encodeMethodABI(abi, params, txParams.data as HexString), - }; + if (!isNullish(tx.data) || dataInputFill === 'data' || dataInputFill === 'both') { + tx.data = encodeMethodABI(abi, params, txParams.data as HexString) } - if (!isNullish(tx.input)){ - tx = { - ...txParams, - input: encodeMethodABI(abi, params, txParams.input as HexString), - }; + if (!isNullish(tx.input) || dataInputFill === 'input' || dataInputFill === 'both'){ + tx.input = encodeMethodABI(abi, params, txParams.input as HexString) } // if input and data is empty, use input as default if (isNullish(tx.input) && isNullish(tx.data)) { - // default to using input - tx = { - ...txParams, - input: encodeMethodABI(abi, params, txParams.input as HexString), - }; + tx.input = encodeMethodABI(abi, params, txParams.input as HexString) } return {data: tx.data as HexString, input: tx.input as HexString}; @@ -112,13 +103,13 @@ export const getEthTxCallParams = ({ }: { abi: AbiFunctionFragment; params: unknown[]; - options?: (PayableCallOptions | NonPayableCallOptions) & { to?: Address }; + options?: (PayableCallOptions | NonPayableCallOptions) & { to?: Address, dataInputFill?: string }; contractOptions: ContractOptions; }): TransactionCall => { if (!options?.to && !contractOptions.address) { throw new Web3ContractError('Contract address not specified'); } - + console.log(options) let txParams = mergeDeep( { to: contractOptions.address, @@ -133,7 +124,7 @@ export const getEthTxCallParams = ({ options as unknown as Record, ) as unknown as TransactionCall; - const dataInput = dataInputEncodeMethodHelper(txParams, abi, params); + const dataInput = dataInputEncodeMethodHelper(txParams, abi, params, options?.dataInputFill); txParams = {...txParams, data: dataInput.data, input: dataInput.input} return txParams; @@ -181,6 +172,7 @@ export const isContractInitOptions = (options: unknown): options is ContractInit 'address', 'jsonInterface', 'syncWithContext', + 'dataInputFill' ].some(key => key in options); export const isWeb3ContractContext = (options: unknown): options is Web3ContractContext => diff --git a/packages/web3-eth-contract/test/unit/contract.test.ts b/packages/web3-eth-contract/test/unit/contract.test.ts index 85996cd2ef2..dd50e40c329 100644 --- a/packages/web3-eth-contract/test/unit/contract.test.ts +++ b/packages/web3-eth-contract/test/unit/contract.test.ts @@ -370,10 +370,10 @@ describe('Contract', () => { }); it('call on deployed contract should decode result', async () => { + const arg = 'Hello'; const encodedArg = '0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000548656c6c6f000000000000000000000000000000000000000000000000000000'; - const contract = new Contract(GreeterAbi); const spyTx = jest.spyOn(eth, 'sendTransaction').mockImplementation(() => { @@ -389,14 +389,12 @@ describe('Contract', () => { // eslint-disable-next-line @typescript-eslint/no-unsafe-return return Promise.resolve(encodedArg) as any; // contract class should decode encodedArg }); - const deployedContract = await contract .deploy({ input: GreeterBytecode, arguments: ['My Greeting'], }) .send(sendOptions); - const res = await deployedContract.methods.greet().call(); expect(res).toStrictEqual(arg); @@ -623,19 +621,44 @@ describe('Contract', () => { spyEthCall.mockClear(); }); - it('should be able call a payable method with data as an option', async () => { + it('should be able call a payable method with data as a contract init option', async () => { + const contract = new Contract( + erc721Abi, + '0x1230B93ffd14F2F022039675fA3fc3A46eE4C701', + { gas: '123', dataInputFill: "data" }, + { config: { defaultAccount: '0x00000000219ab540356cBB839Cbe05303d7705Fa'} }, + ); + + const spyEthCall = jest + .spyOn(eth, 'call') + .mockImplementation(async (_objInstance, _tx) => { + expect(_tx.to).toBe('0x1230B93ffd14F2F022039675fA3fc3A46eE4C701'); + expect(_tx.data).toBe( + '0x095ea7b300000000000000000000000000000000219ab540356cbb839cbe05303d7705fa0000000000000000000000000000000000000000000000000000000000000001', + ); + return '0x00'; + }); + + await expect( + contract.methods.approve('0x00000000219ab540356cBB839Cbe05303d7705Fa', 1).call(), + ).resolves.toBeTruthy(); + + spyEthCall.mockClear(); + }); + + it('should be able call a payable method with data as a web3config option', async () => { const contract = new Contract( erc721Abi, '0x1230B93ffd14F2F022039675fA3fc3A46eE4C701', { gas: '123' }, - { config: { defaultAccount: '0x00000000219ab540356cBB839Cbe05303d7705Fa' } }, + { config: { defaultAccount: '0x00000000219ab540356cBB839Cbe05303d7705Fa'} }, ); const spyEthCall = jest .spyOn(eth, 'call') .mockImplementation(async (_objInstance, _tx) => { expect(_tx.to).toBe('0x1230B93ffd14F2F022039675fA3fc3A46eE4C701'); - expect(_tx.input).toBe( + expect(_tx.data).toBe( '0x095ea7b300000000000000000000000000000000219ab540356cbb839cbe05303d7705fa0000000000000000000000000000000000000000000000000000000000000001', ); return '0x00'; diff --git a/packages/web3-types/src/eth_contract_types.ts b/packages/web3-types/src/eth_contract_types.ts index 73bb7043cbf..46dac5c70f8 100644 --- a/packages/web3-types/src/eth_contract_types.ts +++ b/packages/web3-types/src/eth_contract_types.ts @@ -45,6 +45,11 @@ export interface ContractInitOptions { * If `true`, the defaults of the contract instance will be updated automatically based on the changes of the context used to instantiate the contract. */ readonly syncWithContext?: boolean; + + readonly dataInputFill?: 'data' | 'input' | 'both' + /** + * this will make calls default to `data`, `input` or `both` + */ } export interface NonPayableCallOptions { From 5f5b14ee01e7a2537565ca2645a5b52dfca9fd3a Mon Sep 17 00:00:00 2001 From: luu-alex Date: Wed, 6 Sep 2023 23:44:56 -0400 Subject: [PATCH 21/27] add datafillinput config --- packages/web3-eth-contract/src/contract.ts | 33 +- packages/web3-eth-contract/src/utils.ts | 30 +- .../test/unit/contract.test.ts | 368 +++++++++++++++++- 3 files changed, 393 insertions(+), 38 deletions(-) diff --git a/packages/web3-eth-contract/src/contract.ts b/packages/web3-eth-contract/src/contract.ts index 2b029e3d901..34280625dbb 100644 --- a/packages/web3-eth-contract/src/contract.ts +++ b/packages/web3-eth-contract/src/contract.ts @@ -234,7 +234,7 @@ export class Contract private readonly _overloadedMethodAbis: Map; private _methods!: ContractMethodsInterface; private _events!: ContractEventsInterface; - private _dataInputFill?: 'data' | 'input' | 'both' + private readonly _dataInputFill?: 'data' | 'input' | 'both' private context?: Web3Context; /** @@ -362,9 +362,10 @@ export class Contract const address = typeof addressOrOptionsOrContext === 'string' ? addressOrOptionsOrContext : undefined; - this._dataInputFill = (options as ContractInitOptions)?.dataInputFill ?? 'input'; - if (contractContext instanceof Web3Context){ - this._dataInputFill = contractContext.config.contractDataInputFill; + if (this.config.contractDataInputFill === 'both') { + this._dataInputFill = this.config.contractDataInputFill; + } else { + this._dataInputFill = (options as ContractInitOptions)?.dataInputFill ?? this.config.contractDataInputFill; } this._parseAndSetJsonInterface(jsonInterface, returnDataFormat); @@ -833,7 +834,7 @@ export class Contract const contractMethod = this._createContractMethod< typeof abiFragment, AbiErrorFragment - >(abiFragment, errorsAbi, this._dataInputFill); + >(abiFragment, errorsAbi); this._functions[methodName] = { signature: methodSignature, @@ -891,10 +892,8 @@ export class Contract private _createContractMethod( abiArr: T, errorsAbis: E[], - dataInputFill?: string ): ContractBoundMethod { const abi = abiArr[abiArr.length - 1]; - console.log(dataInputFill) return (...params: unknown[]) => { let abiParams!: Array; const abis = this._overloadedMethodAbis.get(abi.name) ?? []; @@ -939,8 +938,7 @@ export class Contract methodAbi, abiParams, internalErrorsAbis, - {...options, - dataInputFill}, + options, block, ), @@ -990,14 +988,15 @@ export class Contract abi: AbiFunctionFragment, params: unknown[], errorsAbi: AbiErrorFragment[], - options?: Options & {dataInputFill?: string}, + options?: Options, block?: BlockNumberOrTag, ) { - console.log(options?.dataInputFill) const tx = getEthTxCallParams({ abi, params, - options, + options: { + ...options, dataInputFill: this._dataInputFill + }, contractOptions: { ...this.options, from: this.options.from ?? this.config.defaultAccount, @@ -1027,8 +1026,8 @@ export class Contract const tx = getCreateAccessListParams({ abi, params, - options, - contractOptions: { + options: {...options, dataInputFill: this.config.contractDataInputFill}, + contractOptions: { ...this.options, from: this.options.from ?? this.config.defaultAccount, }, @@ -1061,7 +1060,7 @@ export class Contract const tx = getSendTxParams({ abi, params, - options, + options: {...options, dataInputFill: this.config.contractDataInputFill}, contractOptions: modifiedContractOptions, }); const transactionToSend = sendTransaction(this, tx, DEFAULT_RETURN_FORMAT, { @@ -1093,7 +1092,7 @@ export class Contract const tx = getSendTxParams({ abi, params, - options, + options: {...options, dataInputFill: this.config.contractDataInputFill}, contractOptions: modifiedContractOptions, }); return sendTransaction(this, tx, DEFAULT_RETURN_FORMAT, { @@ -1132,7 +1131,7 @@ export class Contract const tx = getEstimateGasParams({ abi, params, - options, + options:{...options, dataInputFill: this.config.contractDataInputFill}, contractOptions: contractOptions ?? this.options, }); return estimateGas(this, tx, BlockTags.LATEST, returnFormat); diff --git a/packages/web3-eth-contract/src/utils.ts b/packages/web3-eth-contract/src/utils.ts index c1b779b1f46..acfd52c30fa 100644 --- a/packages/web3-eth-contract/src/utils.ts +++ b/packages/web3-eth-contract/src/utils.ts @@ -35,18 +35,18 @@ const dataInputEncodeMethodHelper = ( txParams: TransactionCall | TransactionForAccessList, abi: AbiFunctionFragment, params: unknown[], - dataInputFill?: string, + dataInputFill?: 'data' | 'input' | 'both', ): {data?: HexString, input?: HexString} => { - let tx = txParams; - if (!isNullish(tx.data) || dataInputFill === 'data' || dataInputFill === 'both') { - tx.data = encodeMethodABI(abi, params, txParams.data as HexString) + let tx: {data?: HexString, input?: HexString} = {}; + if (!isNullish(txParams.data) || dataInputFill === 'both') { + tx.data = encodeMethodABI(abi, params, (txParams.data ?? txParams.input) as HexString) } - if (!isNullish(tx.input) || dataInputFill === 'input' || dataInputFill === 'both'){ - tx.input = encodeMethodABI(abi, params, txParams.input as HexString) + if (!isNullish(txParams.input) || dataInputFill === 'both'){ + tx.input = encodeMethodABI(abi, params, (txParams.input ?? txParams.data) as HexString) } - // if input and data is empty, use input as default + // if input and data is empty, use web3config default if (isNullish(tx.input) && isNullish(tx.data)) { - tx.input = encodeMethodABI(abi, params, txParams.input as HexString) + tx[dataInputFill as 'data' | 'input'] = encodeMethodABI(abi, params) } return {data: tx.data as HexString, input: tx.input as HexString}; @@ -64,6 +64,7 @@ export const getSendTxParams = ({ input?: HexString; data?: HexString; to?: Address; + dataInputFill?: 'input' | 'data' | 'both'; }; contractOptions: ContractOptions; }): TransactionCall => { @@ -89,7 +90,7 @@ export const getSendTxParams = ({ }, options as unknown as Record, ) as unknown as TransactionCall; - const dataInput = dataInputEncodeMethodHelper(txParams, abi, params); + const dataInput = dataInputEncodeMethodHelper(txParams, abi, params, options?.dataInputFill); txParams = {...txParams, data: dataInput.data, input: dataInput.input} return txParams; @@ -103,13 +104,12 @@ export const getEthTxCallParams = ({ }: { abi: AbiFunctionFragment; params: unknown[]; - options?: (PayableCallOptions | NonPayableCallOptions) & { to?: Address, dataInputFill?: string }; + options?: (PayableCallOptions | NonPayableCallOptions) & { to?: Address, dataInputFill?: 'input' | 'data' | 'both' }; contractOptions: ContractOptions; }): TransactionCall => { if (!options?.to && !contractOptions.address) { throw new Web3ContractError('Contract address not specified'); } - console.log(options) let txParams = mergeDeep( { to: contractOptions.address, @@ -138,7 +138,7 @@ export const getEstimateGasParams = ({ }: { abi: AbiFunctionFragment; params: unknown[]; - options?: PayableCallOptions | NonPayableCallOptions; + options?: (PayableCallOptions | NonPayableCallOptions) & { dataInputFill?: 'input' | 'data' | 'both' }; contractOptions: ContractOptions; }): Partial => { let txParams = mergeDeep( @@ -153,7 +153,7 @@ export const getEstimateGasParams = ({ options as unknown as Record, ) as unknown as TransactionCall; - const dataInput = dataInputEncodeMethodHelper(txParams, abi, params); + const dataInput = dataInputEncodeMethodHelper(txParams, abi, params, options?.dataInputFill); txParams = {...txParams, data: dataInput.data, input: dataInput.input} return txParams as TransactionWithSenderAPI; @@ -186,7 +186,7 @@ export const getCreateAccessListParams = ({ }: { abi: AbiFunctionFragment; params: unknown[]; - options?: (PayableCallOptions | NonPayableCallOptions) & { to?: Address }; + options?: (PayableCallOptions | NonPayableCallOptions) & { to?: Address, dataInputFill?: 'input' | 'data' | 'both' }; contractOptions: ContractOptions; }): TransactionForAccessList => { if (!options?.to && !contractOptions.address) { @@ -211,7 +211,7 @@ export const getCreateAccessListParams = ({ options as unknown as Record, ) as unknown as TransactionForAccessList; - const dataInput = dataInputEncodeMethodHelper(txParams, abi, params); + const dataInput = dataInputEncodeMethodHelper(txParams, abi, params, options?.dataInputFill); txParams = {...txParams, data: dataInput.data, input: dataInput.input} return txParams; diff --git a/packages/web3-eth-contract/test/unit/contract.test.ts b/packages/web3-eth-contract/test/unit/contract.test.ts index dd50e40c329..d12a088ed42 100644 --- a/packages/web3-eth-contract/test/unit/contract.test.ts +++ b/packages/web3-eth-contract/test/unit/contract.test.ts @@ -336,13 +336,14 @@ describe('Contract', () => { sendOptions = { from: '0x12364916b10Ae90076dDa6dE756EE1395BB69ec2', gas: '1000000', - data: '0xa41368620000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000548656c6c6f000000000000000000000000000000000000000000000000000000', + data: '0xa41368620000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000548656c6c6f000000000000000000000000000000000000000000000000000000' }; const spyTx = jest .spyOn(eth, 'sendTransaction') .mockImplementation((_objInstance, _tx) => { const newContract = contract.clone(); newContract.options.address = deployedAddr; + expect(_tx.data).toBeDefined(); if ( _tx.data === '0xa41368620000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000548656c6c6f000000000000000000000000000000000000000000000000000000' @@ -369,6 +370,136 @@ describe('Contract', () => { spyTx.mockClear(); }); + it('should send method on deployed contract should work with data using web3config', async () => { + const expectedProvider = 'http://127.0.0.1:8545'; + const web3Context = new Web3Context({ + provider: expectedProvider, + config: { contractDataInputFill: 'data', defaultAccount: '0x00000000219ab540356cBB839Cbe05303d7705Fa' }, + }); + const arg = 'Hello'; + const contract = new Contract(GreeterAbi, web3Context); + sendOptions = { + from: '0x12364916b10Ae90076dDa6dE756EE1395BB69ec2', + gas: '1000000', + }; + const spyTx = jest + .spyOn(eth, 'sendTransaction') + .mockImplementation((_objInstance, _tx) => { + const newContract = contract.clone(); + newContract.options.address = deployedAddr; + if ( + _tx.data === + '0xa41368620000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000548656c6c6f000000000000000000000000000000000000000000000000000000' + ) { + // eslint-disable-next-line + expect(_tx.to).toStrictEqual(deployedAddr); + // eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-empty-function + return { status: '0x1', on: () => {} } as any; + } + + // eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-empty-function + return Promise.resolve(Object.assign(newContract, { on: () => {} })) as any; + }); + + const deployedContract = await contract + .deploy({ + data: GreeterBytecode, + arguments: ['My Greeting'], + }) + .send(sendOptions); + const receipt = await deployedContract.methods.setGreeting(arg).send(sendOptions); + expect(receipt.status).toBe('0x1'); + + spyTx.mockClear(); + }); + + it('send method on deployed contract should work with both input and data using web3config', async () => { + const expectedProvider = 'http://127.0.0.1:8545'; + const web3Context = new Web3Context({ + provider: expectedProvider, + config: { contractDataInputFill: 'both', defaultAccount: '0x00000000219ab540356cBB839Cbe05303d7705Fa' }, + }); + const arg = 'Hello'; + const contract = new Contract(GreeterAbi, web3Context); + sendOptions = { + from: '0x12364916b10Ae90076dDa6dE756EE1395BB69ec2', + gas: '1000000', + }; + const spyTx = jest + .spyOn(eth, 'sendTransaction') + .mockImplementation((_objInstance, _tx) => { + const newContract = contract.clone(); + newContract.options.address = deployedAddr; + if ( + _tx.data === + '0xa41368620000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000548656c6c6f000000000000000000000000000000000000000000000000000000' + ) { + expect(_tx.input).toStrictEqual("0xa41368620000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000548656c6c6f000000000000000000000000000000000000000000000000000000") + // eslint-disable-next-line + expect(_tx.to).toStrictEqual(deployedAddr); + // eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-empty-function + return { status: '0x1', on: () => {} } as any; + } + + // eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-empty-function + return Promise.resolve(Object.assign(newContract, { on: () => {} })) as any; + }); + + const deployedContract = await contract + .deploy({ + data: GreeterBytecode, + arguments: ['My Greeting'], + }) + .send(sendOptions); + const receipt = await deployedContract.methods.setGreeting(arg).send(sendOptions); + expect(receipt.status).toBe('0x1'); + + spyTx.mockClear(); + }); + + it('should send method on deployed contract should work with input using web3config', async () => { + const expectedProvider = 'http://127.0.0.1:8545'; + const web3Context = new Web3Context({ + provider: expectedProvider, + config: { contractDataInputFill: 'input', defaultAccount: '0x00000000219ab540356cBB839Cbe05303d7705Fa' }, + }); + const arg = 'Hello'; + const contract = new Contract(GreeterAbi, web3Context); + sendOptions = { + from: '0x12364916b10Ae90076dDa6dE756EE1395BB69ec2', + gas: '1000000', + }; + const spyTx = jest + .spyOn(eth, 'sendTransaction') + .mockImplementation((_objInstance, _tx) => { + const newContract = contract.clone(); + newContract.options.address = deployedAddr; + if ( + _tx.input === + '0xa41368620000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000548656c6c6f000000000000000000000000000000000000000000000000000000' + ) { + // eslint-disable-next-line + expect(_tx.to).toStrictEqual(deployedAddr); + // eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-empty-function + return { status: '0x1', on: () => {} } as any; + } + + // eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-empty-function + return Promise.resolve(Object.assign(newContract, { on: () => {} })) as any; + }); + + const deployedContract = await contract + .deploy({ + input: GreeterBytecode, + arguments: ['My Greeting'], + }) + .send(sendOptions); + const receipt = await deployedContract.methods.setGreeting(arg).send(sendOptions); + expect(receipt.status).toBe('0x1'); + + spyTx.mockClear(); + }); + it('call on deployed contract should decode result', async () => { const arg = 'Hello'; @@ -596,7 +727,7 @@ describe('Contract', () => { expect(contract.options.jsonInterface).toMatchObject(ERC20TokenAbi); }); - it('should be able call a payable method', async () => { + it('should be able to call a payable method', async () => { const contract = new Contract( erc721Abi, '0x1230B93ffd14F2F022039675fA3fc3A46eE4C701', @@ -621,7 +752,7 @@ describe('Contract', () => { spyEthCall.mockClear(); }); - it('should be able call a payable method with data as a contract init option', async () => { + it('should be able to call a payable method with data as a contract init option', async () => { const contract = new Contract( erc721Abi, '0x1230B93ffd14F2F022039675fA3fc3A46eE4C701', @@ -646,14 +777,44 @@ describe('Contract', () => { spyEthCall.mockClear(); }); - it('should be able call a payable method with data as a web3config option', async () => { + it('should be able to call a payable method with input as a contract init option', async () => { const contract = new Contract( erc721Abi, '0x1230B93ffd14F2F022039675fA3fc3A46eE4C701', - { gas: '123' }, + { gas: '123', dataInputFill: "input" }, { config: { defaultAccount: '0x00000000219ab540356cBB839Cbe05303d7705Fa'} }, ); + const spyEthCall = jest + .spyOn(eth, 'call') + .mockImplementation(async (_objInstance, _tx) => { + expect(_tx.to).toBe('0x1230B93ffd14F2F022039675fA3fc3A46eE4C701'); + expect(_tx.input).toBe( + '0x095ea7b300000000000000000000000000000000219ab540356cbb839cbe05303d7705fa0000000000000000000000000000000000000000000000000000000000000001', + ); + return '0x00'; + }); + + await expect( + contract.methods.approve('0x00000000219ab540356cBB839Cbe05303d7705Fa', 1).call(), + ).resolves.toBeTruthy(); + + spyEthCall.mockClear(); + }); + + it('should be able to call a payable method with data as a web3Context option', async () => { + const expectedProvider = 'http://127.0.0.1:8545'; + const web3Context = new Web3Context({ + provider: expectedProvider, + config: { contractDataInputFill: 'data', defaultAccount: '0x00000000219ab540356cBB839Cbe05303d7705Fa' }, + }); + const contract = new Contract( + erc721Abi, + '0x1230B93ffd14F2F022039675fA3fc3A46eE4C701', + { gas: '123' }, + web3Context, + ); + const spyEthCall = jest .spyOn(eth, 'call') .mockImplementation(async (_objInstance, _tx) => { @@ -671,6 +832,39 @@ describe('Contract', () => { spyEthCall.mockClear(); }); + it('should be able to call a payable method with both data and input as a web3Context option', async () => { + const expectedProvider = 'http://127.0.0.1:8545'; + const web3Context = new Web3Context({ + provider: expectedProvider, + config: { contractDataInputFill: 'both', defaultAccount: '0x00000000219ab540356cBB839Cbe05303d7705Fa' }, + }); + const contract = new Contract( + erc721Abi, + '0x1230B93ffd14F2F022039675fA3fc3A46eE4C701', + { gas: '123' }, + web3Context, + ); + + const spyEthCall = jest + .spyOn(eth, 'call') + .mockImplementation(async (_objInstance, _tx) => { + expect(_tx.to).toBe('0x1230B93ffd14F2F022039675fA3fc3A46eE4C701'); + expect(_tx.data).toBe( + '0x095ea7b300000000000000000000000000000000219ab540356cbb839cbe05303d7705fa0000000000000000000000000000000000000000000000000000000000000001', + ); + expect(_tx.input).toBe( + '0x095ea7b300000000000000000000000000000000219ab540356cbb839cbe05303d7705fa0000000000000000000000000000000000000000000000000000000000000001', + ); + return '0x00'; + }); + + await expect( + contract.methods.approve('0x00000000219ab540356cBB839Cbe05303d7705Fa', 1).call(), + ).resolves.toBeTruthy(); + + spyEthCall.mockClear(); + }); + it('getPastEvents with filter should work', async () => { const contract = new Contract(GreeterAbi); @@ -994,7 +1188,7 @@ describe('Contract', () => { spyEstimateGas.mockClear(); }); - it('estimateGas should work for the deploy function', async () => { + it('estimateGas should work for the deploy function using data', async () => { const contract = new Contract(GreeterAbi); const spyTx = jest.spyOn(eth, 'sendTransaction').mockImplementation(() => { @@ -1031,6 +1225,94 @@ describe('Contract', () => { spyEstimateGas.mockClear(); }); + it('estimateGas should work for the deploy function using both data and input web3config', async () => { + const expectedProvider = 'http://127.0.0.1:8545'; + const web3Context = new Web3Context({ + provider: expectedProvider, + config: {contractDataInputFill: 'both'} + }); + + const contract = new Contract(GreeterAbi, web3Context); + + const spyTx = jest.spyOn(eth, 'sendTransaction').mockImplementation(() => { + const newContract = contract.clone(); + newContract.options.address = deployedAddr; + // eslint-disable-next-line @typescript-eslint/no-unsafe-return + return Promise.resolve(newContract) as any; + }); + + const spyEstimateGas = jest + .spyOn(eth, 'estimateGas') + .mockImplementationOnce((_objInstance, _tx, _block, returnFormat) => { + expect(_block).toBe('latest'); + expect(_tx.to).toBeUndefined(); + expect(_tx.from).toStrictEqual(sendOptions.from); + expect(_tx.data).toBe( + '0x60806040523480156200001157600080fd5b5060405162000ed038038062000ed08339818101604052810190620000379190620001ea565b806001908162000048919062000486565b5060008081905550506200056d565b6000604051905090565b600080fd5b600080fd5b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b620000c08262000075565b810181811067ffffffffffffffff82111715620000e257620000e162000086565b5b80604052505050565b6000620000f762000057565b9050620001058282620000b5565b919050565b600067ffffffffffffffff82111562000128576200012762000086565b5b620001338262000075565b9050602081019050919050565b60005b838110156200016057808201518184015260208101905062000143565b60008484015250505050565b6000620001836200017d846200010a565b620000eb565b905082815260208101848484011115620001a257620001a162000070565b5b620001af84828562000140565b509392505050565b600082601f830112620001cf57620001ce6200006b565b5b8151620001e18482602086016200016c565b91505092915050565b60006020828403121562000203576200020262000061565b5b600082015167ffffffffffffffff81111562000224576200022362000066565b5b6200023284828501620001b7565b91505092915050565b600081519050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b600060028204905060018216806200028e57607f821691505b602082108103620002a457620002a362000246565b5b50919050565b60008190508160005260206000209050919050565b60006020601f8301049050919050565b600082821b905092915050565b6000600883026200030e7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82620002cf565b6200031a8683620002cf565b95508019841693508086168417925050509392505050565b6000819050919050565b6000819050919050565b600062000367620003616200035b8462000332565b6200033c565b62000332565b9050919050565b6000819050919050565b620003838362000346565b6200039b62000392826200036e565b848454620002dc565b825550505050565b600090565b620003b2620003a3565b620003bf81848462000378565b505050565b5b81811015620003e757620003db600082620003a8565b600181019050620003c5565b5050565b601f82111562000436576200040081620002aa565b6200040b84620002bf565b810160208510156200041b578190505b620004336200042a85620002bf565b830182620003c4565b50505b505050565b600082821c905092915050565b60006200045b600019846008026200043b565b1980831691505092915050565b600062000476838362000448565b9150826002028217905092915050565b62000491826200023b565b67ffffffffffffffff811115620004ad57620004ac62000086565b5b620004b9825462000275565b620004c6828285620003eb565b600060209050601f831160018114620004fe5760008415620004e9578287015190505b620004f5858262000468565b86555062000565565b601f1984166200050e86620002aa565b60005b82811015620005385784890151825560018201915060208501945060208101905062000511565b8683101562000558578489015162000554601f89168262000448565b8355505b6001600288020188555050505b505050505050565b610953806200057d6000396000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c8063a413686214610046578063cfae321714610077578063d09de08a14610095575b600080fd5b610060600480360381019061005b91906103c0565b61009f565b60405161006e9291906104a3565b60405180910390f35b61007f6101bd565b60405161008c91906104d3565b60405180910390f35b61009d61024f565b005b600060607f0d363f2fba46ab11b6db8da0125b0d5484787c44e265b48810735998bab12b756001846040516100d59291906105ee565b60405180910390a182600190816100ec91906107c6565b507f7d7846723bda52976e0286c6efffee937ee9f76817a867ec70531ad29fb1fc0e600160405161011d9190610898565b60405180910390a160018080805461013490610524565b80601f016020809104026020016040519081016040528092919081815260200182805461016090610524565b80156101ad5780601f10610182576101008083540402835291602001916101ad565b820191906000526020600020905b81548152906001019060200180831161019057829003601f168201915b5050505050905091509150915091565b6060600180546101cc90610524565b80601f01602080910402602001604051908101604052809291908181526020018280546101f890610524565b80156102455780601f1061021a57610100808354040283529160200191610245565b820191906000526020600020905b81548152906001019060200180831161022857829003601f168201915b5050505050905090565b600160005461025e91906108e9565b600081905550565b6000604051905090565b600080fd5b600080fd5b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6102cd82610284565b810181811067ffffffffffffffff821117156102ec576102eb610295565b5b80604052505050565b60006102ff610266565b905061030b82826102c4565b919050565b600067ffffffffffffffff82111561032b5761032a610295565b5b61033482610284565b9050602081019050919050565b82818337600083830152505050565b600061036361035e84610310565b6102f5565b90508281526020810184848401111561037f5761037e61027f565b5b61038a848285610341565b509392505050565b600082601f8301126103a7576103a661027a565b5b81356103b7848260208601610350565b91505092915050565b6000602082840312156103d6576103d5610270565b5b600082013567ffffffffffffffff8111156103f4576103f3610275565b5b61040084828501610392565b91505092915050565b60008115159050919050565b61041e81610409565b82525050565b600081519050919050565b600082825260208201905092915050565b60005b8381101561045e578082015181840152602081019050610443565b60008484015250505050565b600061047582610424565b61047f818561042f565b935061048f818560208601610440565b61049881610284565b840191505092915050565b60006040820190506104b86000830185610415565b81810360208301526104ca818461046a565b90509392505050565b600060208201905081810360008301526104ed818461046a565b905092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b6000600282049050600182168061053c57607f821691505b60208210810361054f5761054e6104f5565b5b50919050565b60008190508160005260206000209050919050565b6000815461057781610524565b610581818661042f565b9450600182166000811461059c57600181146105b2576105e5565b60ff1983168652811515602002860193506105e5565b6105bb85610555565b60005b838110156105dd578154818901526001820191506020810190506105be565b808801955050505b50505092915050565b60006040820190508181036000830152610608818561056a565b9050818103602083015261061c818461046a565b90509392505050565b60006020601f8301049050919050565b600082821b905092915050565b6000600883026106727fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82610635565b61067c8683610635565b95508019841693508086168417925050509392505050565b6000819050919050565b6000819050919050565b60006106c36106be6106b984610694565b61069e565b610694565b9050919050565b6000819050919050565b6106dd836106a8565b6106f16106e9826106ca565b848454610642565b825550505050565b600090565b6107066106f9565b6107118184846106d4565b505050565b5b818110156107355761072a6000826106fe565b600181019050610717565b5050565b601f82111561077a5761074b81610555565b61075484610625565b81016020851015610763578190505b61077761076f85610625565b830182610716565b50505b505050565b600082821c905092915050565b600061079d6000198460080261077f565b1980831691505092915050565b60006107b6838361078c565b9150826002028217905092915050565b6107cf82610424565b67ffffffffffffffff8111156107e8576107e7610295565b5b6107f28254610524565b6107fd828285610739565b600060209050601f831160018114610830576000841561081e578287015190505b61082885826107aa565b865550610890565b601f19841661083e86610555565b60005b8281101561086657848901518255600182019150602085019450602081019050610841565b86831015610883578489015161087f601f89168261078c565b8355505b6001600288020188555050505b505050505050565b600060208201905081810360008301526108b2818461056a565b905092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60006108f482610694565b91506108ff83610694565b9250828201905080821115610917576109166108ba565b5b9291505056fea26469706673582212207e5ba44159ffb37af8e8a9e7c5b6fb5ce81ea195b62ae3ac36288f2cf72c18a764736f6c634300081000330000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000b4d79204772656574696e67000000000000000000000000000000000000000000', + ); + expect(_tx.input).toBe( + '0x60806040523480156200001157600080fd5b5060405162000ed038038062000ed08339818101604052810190620000379190620001ea565b806001908162000048919062000486565b5060008081905550506200056d565b6000604051905090565b600080fd5b600080fd5b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b620000c08262000075565b810181811067ffffffffffffffff82111715620000e257620000e162000086565b5b80604052505050565b6000620000f762000057565b9050620001058282620000b5565b919050565b600067ffffffffffffffff82111562000128576200012762000086565b5b620001338262000075565b9050602081019050919050565b60005b838110156200016057808201518184015260208101905062000143565b60008484015250505050565b6000620001836200017d846200010a565b620000eb565b905082815260208101848484011115620001a257620001a162000070565b5b620001af84828562000140565b509392505050565b600082601f830112620001cf57620001ce6200006b565b5b8151620001e18482602086016200016c565b91505092915050565b60006020828403121562000203576200020262000061565b5b600082015167ffffffffffffffff81111562000224576200022362000066565b5b6200023284828501620001b7565b91505092915050565b600081519050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b600060028204905060018216806200028e57607f821691505b602082108103620002a457620002a362000246565b5b50919050565b60008190508160005260206000209050919050565b60006020601f8301049050919050565b600082821b905092915050565b6000600883026200030e7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82620002cf565b6200031a8683620002cf565b95508019841693508086168417925050509392505050565b6000819050919050565b6000819050919050565b600062000367620003616200035b8462000332565b6200033c565b62000332565b9050919050565b6000819050919050565b620003838362000346565b6200039b62000392826200036e565b848454620002dc565b825550505050565b600090565b620003b2620003a3565b620003bf81848462000378565b505050565b5b81811015620003e757620003db600082620003a8565b600181019050620003c5565b5050565b601f82111562000436576200040081620002aa565b6200040b84620002bf565b810160208510156200041b578190505b620004336200042a85620002bf565b830182620003c4565b50505b505050565b600082821c905092915050565b60006200045b600019846008026200043b565b1980831691505092915050565b600062000476838362000448565b9150826002028217905092915050565b62000491826200023b565b67ffffffffffffffff811115620004ad57620004ac62000086565b5b620004b9825462000275565b620004c6828285620003eb565b600060209050601f831160018114620004fe5760008415620004e9578287015190505b620004f5858262000468565b86555062000565565b601f1984166200050e86620002aa565b60005b82811015620005385784890151825560018201915060208501945060208101905062000511565b8683101562000558578489015162000554601f89168262000448565b8355505b6001600288020188555050505b505050505050565b610953806200057d6000396000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c8063a413686214610046578063cfae321714610077578063d09de08a14610095575b600080fd5b610060600480360381019061005b91906103c0565b61009f565b60405161006e9291906104a3565b60405180910390f35b61007f6101bd565b60405161008c91906104d3565b60405180910390f35b61009d61024f565b005b600060607f0d363f2fba46ab11b6db8da0125b0d5484787c44e265b48810735998bab12b756001846040516100d59291906105ee565b60405180910390a182600190816100ec91906107c6565b507f7d7846723bda52976e0286c6efffee937ee9f76817a867ec70531ad29fb1fc0e600160405161011d9190610898565b60405180910390a160018080805461013490610524565b80601f016020809104026020016040519081016040528092919081815260200182805461016090610524565b80156101ad5780601f10610182576101008083540402835291602001916101ad565b820191906000526020600020905b81548152906001019060200180831161019057829003601f168201915b5050505050905091509150915091565b6060600180546101cc90610524565b80601f01602080910402602001604051908101604052809291908181526020018280546101f890610524565b80156102455780601f1061021a57610100808354040283529160200191610245565b820191906000526020600020905b81548152906001019060200180831161022857829003601f168201915b5050505050905090565b600160005461025e91906108e9565b600081905550565b6000604051905090565b600080fd5b600080fd5b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6102cd82610284565b810181811067ffffffffffffffff821117156102ec576102eb610295565b5b80604052505050565b60006102ff610266565b905061030b82826102c4565b919050565b600067ffffffffffffffff82111561032b5761032a610295565b5b61033482610284565b9050602081019050919050565b82818337600083830152505050565b600061036361035e84610310565b6102f5565b90508281526020810184848401111561037f5761037e61027f565b5b61038a848285610341565b509392505050565b600082601f8301126103a7576103a661027a565b5b81356103b7848260208601610350565b91505092915050565b6000602082840312156103d6576103d5610270565b5b600082013567ffffffffffffffff8111156103f4576103f3610275565b5b61040084828501610392565b91505092915050565b60008115159050919050565b61041e81610409565b82525050565b600081519050919050565b600082825260208201905092915050565b60005b8381101561045e578082015181840152602081019050610443565b60008484015250505050565b600061047582610424565b61047f818561042f565b935061048f818560208601610440565b61049881610284565b840191505092915050565b60006040820190506104b86000830185610415565b81810360208301526104ca818461046a565b90509392505050565b600060208201905081810360008301526104ed818461046a565b905092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b6000600282049050600182168061053c57607f821691505b60208210810361054f5761054e6104f5565b5b50919050565b60008190508160005260206000209050919050565b6000815461057781610524565b610581818661042f565b9450600182166000811461059c57600181146105b2576105e5565b60ff1983168652811515602002860193506105e5565b6105bb85610555565b60005b838110156105dd578154818901526001820191506020810190506105be565b808801955050505b50505092915050565b60006040820190508181036000830152610608818561056a565b9050818103602083015261061c818461046a565b90509392505050565b60006020601f8301049050919050565b600082821b905092915050565b6000600883026106727fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82610635565b61067c8683610635565b95508019841693508086168417925050509392505050565b6000819050919050565b6000819050919050565b60006106c36106be6106b984610694565b61069e565b610694565b9050919050565b6000819050919050565b6106dd836106a8565b6106f16106e9826106ca565b848454610642565b825550505050565b600090565b6107066106f9565b6107118184846106d4565b505050565b5b818110156107355761072a6000826106fe565b600181019050610717565b5050565b601f82111561077a5761074b81610555565b61075484610625565b81016020851015610763578190505b61077761076f85610625565b830182610716565b50505b505050565b600082821c905092915050565b600061079d6000198460080261077f565b1980831691505092915050565b60006107b6838361078c565b9150826002028217905092915050565b6107cf82610424565b67ffffffffffffffff8111156107e8576107e7610295565b5b6107f28254610524565b6107fd828285610739565b600060209050601f831160018114610830576000841561081e578287015190505b61082885826107aa565b865550610890565b601f19841661083e86610555565b60005b8281101561086657848901518255600182019150602085019450602081019050610841565b86831015610883578489015161087f601f89168261078c565b8355505b6001600288020188555050505b505050505050565b600060208201905081810360008301526108b2818461056a565b905092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60006108f482610694565b91506108ff83610694565b9250828201905080821115610917576109166108ba565b5b9291505056fea26469706673582212207e5ba44159ffb37af8e8a9e7c5b6fb5ce81ea195b62ae3ac36288f2cf72c18a764736f6c634300081000330000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000b4d79204772656574696e67000000000000000000000000000000000000000000', + ); + expect(returnFormat).toBe(ETH_DATA_FORMAT); + + // eslint-disable-next-line @typescript-eslint/no-unsafe-return + return Promise.resolve(BigInt(36916)) as any; + }); + + const deploy = contract.deploy({ + data: GreeterBytecode, + arguments: ['My Greeting'], + }); + + const result = await deploy.estimateGas(sendOptions, ETH_DATA_FORMAT); + expect(result).toStrictEqual(BigInt(36916)); + + spyTx.mockClear(); + spyEstimateGas.mockClear(); + }); + it('estimateGas should work for the deploy function using data web3config', async () => { + const expectedProvider = 'http://127.0.0.1:8545'; + const web3Context = new Web3Context({ + provider: expectedProvider, + config: {contractDataInputFill: 'data'} + }); + + const contract = new Contract(GreeterAbi, web3Context); + + const spyTx = jest.spyOn(eth, 'sendTransaction').mockImplementation(() => { + const newContract = contract.clone(); + newContract.options.address = deployedAddr; + // eslint-disable-next-line @typescript-eslint/no-unsafe-return + return Promise.resolve(newContract) as any; + }); + + const spyEstimateGas = jest + .spyOn(eth, 'estimateGas') + .mockImplementationOnce((_objInstance, _tx, _block, returnFormat) => { + expect(_block).toBe('latest'); + expect(_tx.to).toBeUndefined(); + expect(_tx.from).toStrictEqual(sendOptions.from); + expect(_tx.data).toBe( + '0x60806040523480156200001157600080fd5b5060405162000ed038038062000ed08339818101604052810190620000379190620001ea565b806001908162000048919062000486565b5060008081905550506200056d565b6000604051905090565b600080fd5b600080fd5b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b620000c08262000075565b810181811067ffffffffffffffff82111715620000e257620000e162000086565b5b80604052505050565b6000620000f762000057565b9050620001058282620000b5565b919050565b600067ffffffffffffffff82111562000128576200012762000086565b5b620001338262000075565b9050602081019050919050565b60005b838110156200016057808201518184015260208101905062000143565b60008484015250505050565b6000620001836200017d846200010a565b620000eb565b905082815260208101848484011115620001a257620001a162000070565b5b620001af84828562000140565b509392505050565b600082601f830112620001cf57620001ce6200006b565b5b8151620001e18482602086016200016c565b91505092915050565b60006020828403121562000203576200020262000061565b5b600082015167ffffffffffffffff81111562000224576200022362000066565b5b6200023284828501620001b7565b91505092915050565b600081519050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b600060028204905060018216806200028e57607f821691505b602082108103620002a457620002a362000246565b5b50919050565b60008190508160005260206000209050919050565b60006020601f8301049050919050565b600082821b905092915050565b6000600883026200030e7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82620002cf565b6200031a8683620002cf565b95508019841693508086168417925050509392505050565b6000819050919050565b6000819050919050565b600062000367620003616200035b8462000332565b6200033c565b62000332565b9050919050565b6000819050919050565b620003838362000346565b6200039b62000392826200036e565b848454620002dc565b825550505050565b600090565b620003b2620003a3565b620003bf81848462000378565b505050565b5b81811015620003e757620003db600082620003a8565b600181019050620003c5565b5050565b601f82111562000436576200040081620002aa565b6200040b84620002bf565b810160208510156200041b578190505b620004336200042a85620002bf565b830182620003c4565b50505b505050565b600082821c905092915050565b60006200045b600019846008026200043b565b1980831691505092915050565b600062000476838362000448565b9150826002028217905092915050565b62000491826200023b565b67ffffffffffffffff811115620004ad57620004ac62000086565b5b620004b9825462000275565b620004c6828285620003eb565b600060209050601f831160018114620004fe5760008415620004e9578287015190505b620004f5858262000468565b86555062000565565b601f1984166200050e86620002aa565b60005b82811015620005385784890151825560018201915060208501945060208101905062000511565b8683101562000558578489015162000554601f89168262000448565b8355505b6001600288020188555050505b505050505050565b610953806200057d6000396000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c8063a413686214610046578063cfae321714610077578063d09de08a14610095575b600080fd5b610060600480360381019061005b91906103c0565b61009f565b60405161006e9291906104a3565b60405180910390f35b61007f6101bd565b60405161008c91906104d3565b60405180910390f35b61009d61024f565b005b600060607f0d363f2fba46ab11b6db8da0125b0d5484787c44e265b48810735998bab12b756001846040516100d59291906105ee565b60405180910390a182600190816100ec91906107c6565b507f7d7846723bda52976e0286c6efffee937ee9f76817a867ec70531ad29fb1fc0e600160405161011d9190610898565b60405180910390a160018080805461013490610524565b80601f016020809104026020016040519081016040528092919081815260200182805461016090610524565b80156101ad5780601f10610182576101008083540402835291602001916101ad565b820191906000526020600020905b81548152906001019060200180831161019057829003601f168201915b5050505050905091509150915091565b6060600180546101cc90610524565b80601f01602080910402602001604051908101604052809291908181526020018280546101f890610524565b80156102455780601f1061021a57610100808354040283529160200191610245565b820191906000526020600020905b81548152906001019060200180831161022857829003601f168201915b5050505050905090565b600160005461025e91906108e9565b600081905550565b6000604051905090565b600080fd5b600080fd5b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6102cd82610284565b810181811067ffffffffffffffff821117156102ec576102eb610295565b5b80604052505050565b60006102ff610266565b905061030b82826102c4565b919050565b600067ffffffffffffffff82111561032b5761032a610295565b5b61033482610284565b9050602081019050919050565b82818337600083830152505050565b600061036361035e84610310565b6102f5565b90508281526020810184848401111561037f5761037e61027f565b5b61038a848285610341565b509392505050565b600082601f8301126103a7576103a661027a565b5b81356103b7848260208601610350565b91505092915050565b6000602082840312156103d6576103d5610270565b5b600082013567ffffffffffffffff8111156103f4576103f3610275565b5b61040084828501610392565b91505092915050565b60008115159050919050565b61041e81610409565b82525050565b600081519050919050565b600082825260208201905092915050565b60005b8381101561045e578082015181840152602081019050610443565b60008484015250505050565b600061047582610424565b61047f818561042f565b935061048f818560208601610440565b61049881610284565b840191505092915050565b60006040820190506104b86000830185610415565b81810360208301526104ca818461046a565b90509392505050565b600060208201905081810360008301526104ed818461046a565b905092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b6000600282049050600182168061053c57607f821691505b60208210810361054f5761054e6104f5565b5b50919050565b60008190508160005260206000209050919050565b6000815461057781610524565b610581818661042f565b9450600182166000811461059c57600181146105b2576105e5565b60ff1983168652811515602002860193506105e5565b6105bb85610555565b60005b838110156105dd578154818901526001820191506020810190506105be565b808801955050505b50505092915050565b60006040820190508181036000830152610608818561056a565b9050818103602083015261061c818461046a565b90509392505050565b60006020601f8301049050919050565b600082821b905092915050565b6000600883026106727fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82610635565b61067c8683610635565b95508019841693508086168417925050509392505050565b6000819050919050565b6000819050919050565b60006106c36106be6106b984610694565b61069e565b610694565b9050919050565b6000819050919050565b6106dd836106a8565b6106f16106e9826106ca565b848454610642565b825550505050565b600090565b6107066106f9565b6107118184846106d4565b505050565b5b818110156107355761072a6000826106fe565b600181019050610717565b5050565b601f82111561077a5761074b81610555565b61075484610625565b81016020851015610763578190505b61077761076f85610625565b830182610716565b50505b505050565b600082821c905092915050565b600061079d6000198460080261077f565b1980831691505092915050565b60006107b6838361078c565b9150826002028217905092915050565b6107cf82610424565b67ffffffffffffffff8111156107e8576107e7610295565b5b6107f28254610524565b6107fd828285610739565b600060209050601f831160018114610830576000841561081e578287015190505b61082885826107aa565b865550610890565b601f19841661083e86610555565b60005b8281101561086657848901518255600182019150602085019450602081019050610841565b86831015610883578489015161087f601f89168261078c565b8355505b6001600288020188555050505b505050505050565b600060208201905081810360008301526108b2818461056a565b905092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60006108f482610694565b91506108ff83610694565b9250828201905080821115610917576109166108ba565b5b9291505056fea26469706673582212207e5ba44159ffb37af8e8a9e7c5b6fb5ce81ea195b62ae3ac36288f2cf72c18a764736f6c634300081000330000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000b4d79204772656574696e67000000000000000000000000000000000000000000', + ); + expect(returnFormat).toBe(ETH_DATA_FORMAT); + + // eslint-disable-next-line @typescript-eslint/no-unsafe-return + return Promise.resolve(BigInt(36916)) as any; + }); + + const deploy = contract.deploy({ + data: GreeterBytecode, + arguments: ['My Greeting'], + }); + + const result = await deploy.estimateGas(sendOptions, ETH_DATA_FORMAT); + expect(result).toStrictEqual(BigInt(36916)); + + spyTx.mockClear(); + spyEstimateGas.mockClear(); + }); + it('estimateGas should work for contract method', async () => { const arg = 'Hello'; @@ -1153,6 +1435,80 @@ describe('Contract', () => { spyEthCall.mockClear(); }); + it('contract method createAccessList should work using data with web3config', async () => { + const expectedProvider = 'http://127.0.0.1:8545'; + const web3Context = new Web3Context({ + provider: expectedProvider, + config: { contractDataInputFill: 'data' }, + }); + const fromAddr: Address = '0x20bc23D0598b12c34cBDEf1fae439Ba8744DB426'; + const result: AccessListResult = { + accessList: [ + { + address: deployedAddr, + storageKeys: [ + '0x0000000000000000000000000000000000000000000000000000000000000001', + ], + }, + ], + gasUsed: '0x644e', + }; + + const contract = new Contract(GreeterAbi, deployedAddr, web3Context); + + const spyEthCall = jest + .spyOn(eth, 'createAccessList') + .mockImplementation((_objInstance, _tx) => { + expect(_tx.to).toStrictEqual(deployedAddr); + expect(_tx.data).toBe('0xcfae3217'); + expect(_tx.from).toBe(fromAddr); + // eslint-disable-next-line @typescript-eslint/no-unsafe-return + return Promise.resolve(result) as any; // contract class should decode encodedArg + }); + + const res = await contract.methods.greet().createAccessList({ from: fromAddr }); + expect(res).toStrictEqual(result); + + spyEthCall.mockClear(); + }); + it('contract method createAccessList should work using data with web3config', async () => { + const expectedProvider = 'http://127.0.0.1:8545'; + const web3Context = new Web3Context({ + provider: expectedProvider, + config: { contractDataInputFill: 'both' }, + }); + const fromAddr: Address = '0x20bc23D0598b12c34cBDEf1fae439Ba8744DB426'; + const result: AccessListResult = { + accessList: [ + { + address: deployedAddr, + storageKeys: [ + '0x0000000000000000000000000000000000000000000000000000000000000001', + ], + }, + ], + gasUsed: '0x644e', + }; + + const contract = new Contract(GreeterAbi, deployedAddr, web3Context); + + const spyEthCall = jest + .spyOn(eth, 'createAccessList') + .mockImplementation((_objInstance, _tx) => { + expect(_tx.to).toStrictEqual(deployedAddr); + expect(_tx.data).toBe('0xcfae3217'); + expect(_tx.input).toBe('0xcfae3217'); + expect(_tx.from).toBe(fromAddr); + // eslint-disable-next-line @typescript-eslint/no-unsafe-return + return Promise.resolve(result) as any; // contract class should decode encodedArg + }); + + const res = await contract.methods.greet().createAccessList({ from: fromAddr }); + expect(res).toStrictEqual(result); + + spyEthCall.mockClear(); + }); + it('should correctly apply provided Web3Context to new Contract instance', () => { const expectedProvider = 'http://127.0.0.1:8545'; const web3Context = new Web3Context({ From 01e71b88a6ecfbb5bef190b51082ef538bb73371 Mon Sep 17 00:00:00 2001 From: luu-alex Date: Thu, 7 Sep 2023 12:19:08 -0400 Subject: [PATCH 22/27] update changelogs --- packages/web3-eth-contract/CHANGELOG.md | 7 ++++ packages/web3-eth-contract/src/contract.ts | 41 +++++++++++-------- packages/web3-eth/CHANGELOG.md | 5 +++ packages/web3-eth/src/rpc_method_wrappers.ts | 2 +- .../unit/rpc_method_wrappers/fixtures/call.ts | 1 - 5 files changed, 36 insertions(+), 20 deletions(-) diff --git a/packages/web3-eth-contract/CHANGELOG.md b/packages/web3-eth-contract/CHANGELOG.md index 7043d980d7d..87736b34188 100644 --- a/packages/web3-eth-contract/CHANGELOG.md +++ b/packages/web3-eth-contract/CHANGELOG.md @@ -301,3 +301,10 @@ Documentation: - In case of error events there will be inner error also available for details ## [Unreleased] + +### Fixed + +### Added + +- Added `dataInputFill` as a ContractInitOption, allowing users to have the choice using property `data`, `input` or `both` for contract methods to be sent to the RPC provider. (#6355) +- Added to `Web3Config` property `contractDataInputFill` allowing users to have the choice using property `data`, `input` or `both` for contract methods to be sent to the RPC provider when creating contracts. (#6377) diff --git a/packages/web3-eth-contract/src/contract.ts b/packages/web3-eth-contract/src/contract.ts index 34280625dbb..ad8a6924eb2 100644 --- a/packages/web3-eth-contract/src/contract.ts +++ b/packages/web3-eth-contract/src/contract.ts @@ -234,7 +234,7 @@ export class Contract private readonly _overloadedMethodAbis: Map; private _methods!: ContractMethodsInterface; private _events!: ContractEventsInterface; - private readonly _dataInputFill?: 'data' | 'input' | 'both' + private readonly _dataInputFill?: 'data' | 'input' | 'both'; private context?: Web3Context; /** @@ -310,12 +310,6 @@ export class Contract ? optionsOrContextOrReturnFormat : undefined; - if (!isNullish(options) && !isNullish(options.data) && !isNullish(options.input)) - throw new ContractTransactionDataAndInputError({ - data: options.data as HexString, - input: options.input as HexString, - }); - let contractContext; if (isWeb3ContractContext(addressOrOptionsOrContext)) { contractContext = addressOrOptionsOrContext; @@ -350,6 +344,16 @@ export class Contract provider, registeredSubscriptions: contractSubscriptions, }); + if ( + !isNullish(options) && + !isNullish(options.data) && + !isNullish(options.input) && + this.config.contractDataInputFill !== 'both' + ) + throw new ContractTransactionDataAndInputError({ + data: options.data as HexString, + input: options.input as HexString, + }); this._overloadedMethodAbis = new Map(); // eslint-disable-next-line no-nested-ternary @@ -365,7 +369,9 @@ export class Contract if (this.config.contractDataInputFill === 'both') { this._dataInputFill = this.config.contractDataInputFill; } else { - this._dataInputFill = (options as ContractInitOptions)?.dataInputFill ?? this.config.contractDataInputFill; + this._dataInputFill = + (options as ContractInitOptions)?.dataInputFill ?? + this.config.contractDataInputFill; } this._parseAndSetJsonInterface(jsonInterface, returnDataFormat); @@ -383,8 +389,6 @@ export class Contract data: options?.data, }; - - this.syncWithContext = (options as ContractInitOptions)?.syncWithContext ?? false; if (contractContext instanceof Web3Context) { this.subscribeToContextEvents(contractContext); @@ -490,7 +494,7 @@ export class Contract data: this.options.data, provider: this.currentProvider, syncWithContext: this.syncWithContext, - dataInputFill: this._dataInputFill + dataInputFill: this._dataInputFill, }, this.getContextObject(), ); @@ -505,7 +509,7 @@ export class Contract data: this.options.data, provider: this.currentProvider, syncWithContext: this.syncWithContext, - dataInputFill: this._dataInputFill + dataInputFill: this._dataInputFill, }, this.getContextObject(), ); @@ -995,7 +999,8 @@ export class Contract abi, params, options: { - ...options, dataInputFill: this._dataInputFill + ...options, + dataInputFill: this._dataInputFill, }, contractOptions: { ...this.options, @@ -1026,8 +1031,8 @@ export class Contract const tx = getCreateAccessListParams({ abi, params, - options: {...options, dataInputFill: this.config.contractDataInputFill}, - contractOptions: { + options: { ...options, dataInputFill: this.config.contractDataInputFill }, + contractOptions: { ...this.options, from: this.options.from ?? this.config.defaultAccount, }, @@ -1060,7 +1065,7 @@ export class Contract const tx = getSendTxParams({ abi, params, - options: {...options, dataInputFill: this.config.contractDataInputFill}, + options: { ...options, dataInputFill: this.config.contractDataInputFill }, contractOptions: modifiedContractOptions, }); const transactionToSend = sendTransaction(this, tx, DEFAULT_RETURN_FORMAT, { @@ -1092,7 +1097,7 @@ export class Contract const tx = getSendTxParams({ abi, params, - options: {...options, dataInputFill: this.config.contractDataInputFill}, + options: { ...options, dataInputFill: this.config.contractDataInputFill }, contractOptions: modifiedContractOptions, }); return sendTransaction(this, tx, DEFAULT_RETURN_FORMAT, { @@ -1131,7 +1136,7 @@ export class Contract const tx = getEstimateGasParams({ abi, params, - options:{...options, dataInputFill: this.config.contractDataInputFill}, + options: { ...options, dataInputFill: this.config.contractDataInputFill }, contractOptions: contractOptions ?? this.options, }); return estimateGas(this, tx, BlockTags.LATEST, returnFormat); diff --git a/packages/web3-eth/CHANGELOG.md b/packages/web3-eth/CHANGELOG.md index 3b29e582cc9..9a0a97a8642 100644 --- a/packages/web3-eth/CHANGELOG.md +++ b/packages/web3-eth/CHANGELOG.md @@ -186,3 +186,8 @@ Documentation: - Added return type for `formatSubscriptionResult` in class `NewHeadsSubscription` (#6368) ## [Unreleased] + +### Added + +- +- Added to `Web3Config` property `contractDataInputFill` allowing users to have the choice using property `data`, `input` or `both` for contract methods to be sent to the RPC provider when creating contracts. (#6377) (#6400) diff --git a/packages/web3-eth/src/rpc_method_wrappers.ts b/packages/web3-eth/src/rpc_method_wrappers.ts index b5fce03689b..866ca7aab6c 100644 --- a/packages/web3-eth/src/rpc_method_wrappers.ts +++ b/packages/web3-eth/src/rpc_method_wrappers.ts @@ -950,7 +950,7 @@ export async function call( const response = await ethRpcMethods.call( web3Context.requestManager, - formatTransaction(transaction, ETH_DATA_FORMAT, {fillInputAndData: true,}), + formatTransaction(transaction, ETH_DATA_FORMAT), blockNumberFormatted, ); diff --git a/packages/web3-eth/test/unit/rpc_method_wrappers/fixtures/call.ts b/packages/web3-eth/test/unit/rpc_method_wrappers/fixtures/call.ts index a65a4107f00..e8949e97eab 100644 --- a/packages/web3-eth/test/unit/rpc_method_wrappers/fixtures/call.ts +++ b/packages/web3-eth/test/unit/rpc_method_wrappers/fixtures/call.ts @@ -28,7 +28,6 @@ const transaction: TransactionCall = { maxFeePerGas: '0x1229298c00', maxPriorityFeePerGas: '0x49504f80', data: '0x', - input: '0x', nonce: '0x4', chain: 'mainnet', hardfork: 'berlin', From 96ee281872b9a4927d2415f4d5c5dd0244a5660b Mon Sep 17 00:00:00 2001 From: luu-alex Date: Thu, 7 Sep 2023 19:25:42 -0400 Subject: [PATCH 23/27] updating docs --- ...ng_and_interacting_with_smart_contracts.md | 50 +++++++++++++++++++ packages/web3-core/src/web3_config.ts | 11 ++-- packages/web3-eth-contract/src/contract.ts | 5 ++ packages/web3-eth/CHANGELOG.md | 1 - packages/web3-types/src/eth_contract_types.ts | 10 ++-- 5 files changed, 65 insertions(+), 12 deletions(-) diff --git a/docs/docs/guides/smart_contracts/deploying_and_interacting_with_smart_contracts.md b/docs/docs/guides/smart_contracts/deploying_and_interacting_with_smart_contracts.md index 5da74ab75a2..5054e2950fc 100644 --- a/docs/docs/guides/smart_contracts/deploying_and_interacting_with_smart_contracts.md +++ b/docs/docs/guides/smart_contracts/deploying_and_interacting_with_smart_contracts.md @@ -353,6 +353,56 @@ Transaction Hash: 0x9825e2a2115896728d0c9c04c2deaf08dfe1f1ff634c4b0e6eeb2f504372 my number updated value: 2 ``` +## Troubleshooting and errors + +If you are running into errors when executing contract methods such as `myContract.methods.call` or `myContract.deploy.estimateGas()` you might be see a contract execution revert error such as: `value transfer did not complete from a contract execution reverted`. + +This could be due to the node you are connected to and is expecting the `data` property to be populated in your contract instead of `input`. Web3 version >4.03 will always populate `input` when sending transactions. +To fix this, configure the `contractDataInputFill` in `Web3Config` or when initializing your contract to specify `data` in `dataInputFill` to be filled. +Another way to fix this is to provide `data` when using the send or call method. +If you want both `data` and `input` filled, set the property to `both`. + +Here are examples: + +```typescript + +// Configuring Web3Context with `contractDataInputFill` +const expectedProvider = 'http://127.0.0.1:8545'; +const web3Context = new Web3Context({ + provider: expectedProvider, + config: {contractDataInputFill: 'data'} // all new contracts created to populate `data` field +}); + +const contract = new Contract(GreeterAbi, web3Context); + +// data will now be populated when using the call method +const res = await contract.methods.greet().call(); + +// Another way to do this is to set it within the contract using `dataInputFill` + +const contract = new Contract( + erc721Abi, + '0x1230B93ffd14F2F022039675fA3fc3A46eE4C701', + { gas: '123', dataInputFill: "data" }, // methods will now be populating `data` field +); + +// `data` will now be populated instead of `input` +contract.methods.approve('0x00000000219ab540356cBB839Cbe05303d7705Fa', 1).call(), + +// Another way to do this is to set `data` when calling methods + +const contract = new Contract( + erc721Abi, + '0x1230B93ffd14F2F022039675fA3fc3A46eE4C701', +); + +contract.methods.approve('0x00000000219ab540356cBB839Cbe05303d7705Fa', 1).call( + {data: contract.methods.approve('0x00000000219ab540356cBB839Cbe05303d7705Fa', 1).encodeABI()} +) + + +``` + ## Conclusion In this tutorial, we learned how to generate the ABI and the Bytecode of a smart contract, deploy it to the Ethereum network, and interact with it using web3.js version 4.x. diff --git a/packages/web3-core/src/web3_config.ts b/packages/web3-core/src/web3_config.ts index c58023b46d3..46ceb357b9f 100644 --- a/packages/web3-core/src/web3_config.ts +++ b/packages/web3-core/src/web3_config.ts @@ -37,7 +37,7 @@ export interface Web3ConfigOptions { transactionConfirmationPollingInterval?: number; blockHeaderTimeout: number; maxListenersWarningThreshold: number; - contractDataInputFill: 'data' | 'input' | 'both' + contractDataInputFill: 'data' | 'input' | 'both'; defaultNetworkId?: Numbers; defaultChain: string; defaultHardfork: string; @@ -129,13 +129,12 @@ export abstract class Web3Config } /** - * The `contractDataInputFill` options property will allow you to set the hash of the method signature and encoded parameters to the property either `data`, `input` or both within your contract. This will affect: - * - myContract.deploy() - * - myContract.methods.myMethod().call() - * - myContract.methods.myMethod().send() + * The `contractDataInputFill` options property will allow you to set the hash of the method signature and encoded parameters to the property + * either `data`, `input` or both within your contract. + * This will affect the contracts send, call and estimateGas methods * Default is `input`. */ - public get contractDataInputFill() { + public get contractDataInputFill() { return this.config.contractDataInputFill; } diff --git a/packages/web3-eth-contract/src/contract.ts b/packages/web3-eth-contract/src/contract.ts index ad8a6924eb2..01c757b3946 100644 --- a/packages/web3-eth-contract/src/contract.ts +++ b/packages/web3-eth-contract/src/contract.ts @@ -234,6 +234,11 @@ export class Contract private readonly _overloadedMethodAbis: Map; private _methods!: ContractMethodsInterface; private _events!: ContractEventsInterface; + /** + * Set property to `data`, `input`, or `both` to change the property of the contract being sent to the + * RPC provider when using contract methods. + * Default is `input` + */ private readonly _dataInputFill?: 'data' | 'input' | 'both'; private context?: Web3Context; diff --git a/packages/web3-eth/CHANGELOG.md b/packages/web3-eth/CHANGELOG.md index 9a0a97a8642..b30e008202c 100644 --- a/packages/web3-eth/CHANGELOG.md +++ b/packages/web3-eth/CHANGELOG.md @@ -189,5 +189,4 @@ Documentation: ### Added -- - Added to `Web3Config` property `contractDataInputFill` allowing users to have the choice using property `data`, `input` or `both` for contract methods to be sent to the RPC provider when creating contracts. (#6377) (#6400) diff --git a/packages/web3-types/src/eth_contract_types.ts b/packages/web3-types/src/eth_contract_types.ts index 46dac5c70f8..6c4dd374869 100644 --- a/packages/web3-types/src/eth_contract_types.ts +++ b/packages/web3-types/src/eth_contract_types.ts @@ -45,11 +45,11 @@ export interface ContractInitOptions { * If `true`, the defaults of the contract instance will be updated automatically based on the changes of the context used to instantiate the contract. */ readonly syncWithContext?: boolean; - - readonly dataInputFill?: 'data' | 'input' | 'both' - /** - * this will make calls default to `data`, `input` or `both` - */ + + readonly dataInputFill?: 'data' | 'input' | 'both'; + /** + * this will make calls default to `data`, `input` or `both` + */ } export interface NonPayableCallOptions { From 0df6e8b05ecc272448deef313ede102a5c84bca4 Mon Sep 17 00:00:00 2001 From: luu-alex Date: Thu, 7 Sep 2023 22:29:07 -0400 Subject: [PATCH 24/27] fixing linter --- packages/web3-eth-contract/src/utils.ts | 42 ++++++++++------- .../test/unit/contract.test.ts | 47 +++++++++++++------ 2 files changed, 57 insertions(+), 32 deletions(-) diff --git a/packages/web3-eth-contract/src/utils.ts b/packages/web3-eth-contract/src/utils.ts index acfd52c30fa..ca3fd7f9c34 100644 --- a/packages/web3-eth-contract/src/utils.ts +++ b/packages/web3-eth-contract/src/utils.ts @@ -36,20 +36,20 @@ const dataInputEncodeMethodHelper = ( abi: AbiFunctionFragment, params: unknown[], dataInputFill?: 'data' | 'input' | 'both', -): {data?: HexString, input?: HexString} => { - let tx: {data?: HexString, input?: HexString} = {}; +): { data?: HexString; input?: HexString } => { + const tx: { data?: HexString; input?: HexString } = {}; if (!isNullish(txParams.data) || dataInputFill === 'both') { - tx.data = encodeMethodABI(abi, params, (txParams.data ?? txParams.input) as HexString) - } - if (!isNullish(txParams.input) || dataInputFill === 'both'){ - tx.input = encodeMethodABI(abi, params, (txParams.input ?? txParams.data) as HexString) + tx.data = encodeMethodABI(abi, params, (txParams.data ?? txParams.input) as HexString); + } + if (!isNullish(txParams.input) || dataInputFill === 'both') { + tx.input = encodeMethodABI(abi, params, (txParams.input ?? txParams.data) as HexString); } // if input and data is empty, use web3config default if (isNullish(tx.input) && isNullish(tx.data)) { - tx[dataInputFill as 'data' | 'input'] = encodeMethodABI(abi, params) + tx[dataInputFill as 'data' | 'input'] = encodeMethodABI(abi, params); } - return {data: tx.data as HexString, input: tx.input as HexString}; + return { data: tx.data as HexString, input: tx.input as HexString }; }; export const getSendTxParams = ({ @@ -91,8 +91,8 @@ export const getSendTxParams = ({ options as unknown as Record, ) as unknown as TransactionCall; const dataInput = dataInputEncodeMethodHelper(txParams, abi, params, options?.dataInputFill); - txParams = {...txParams, data: dataInput.data, input: dataInput.input} - + txParams = { ...txParams, data: dataInput.data, input: dataInput.input }; + return txParams; }; @@ -104,7 +104,10 @@ export const getEthTxCallParams = ({ }: { abi: AbiFunctionFragment; params: unknown[]; - options?: (PayableCallOptions | NonPayableCallOptions) & { to?: Address, dataInputFill?: 'input' | 'data' | 'both' }; + options?: (PayableCallOptions | NonPayableCallOptions) & { + to?: Address; + dataInputFill?: 'input' | 'data' | 'both'; + }; contractOptions: ContractOptions; }): TransactionCall => { if (!options?.to && !contractOptions.address) { @@ -125,7 +128,7 @@ export const getEthTxCallParams = ({ ) as unknown as TransactionCall; const dataInput = dataInputEncodeMethodHelper(txParams, abi, params, options?.dataInputFill); - txParams = {...txParams, data: dataInput.data, input: dataInput.input} + txParams = { ...txParams, data: dataInput.data, input: dataInput.input }; return txParams; }; @@ -138,7 +141,9 @@ export const getEstimateGasParams = ({ }: { abi: AbiFunctionFragment; params: unknown[]; - options?: (PayableCallOptions | NonPayableCallOptions) & { dataInputFill?: 'input' | 'data' | 'both' }; + options?: (PayableCallOptions | NonPayableCallOptions) & { + dataInputFill?: 'input' | 'data' | 'both'; + }; contractOptions: ContractOptions; }): Partial => { let txParams = mergeDeep( @@ -154,7 +159,7 @@ export const getEstimateGasParams = ({ ) as unknown as TransactionCall; const dataInput = dataInputEncodeMethodHelper(txParams, abi, params, options?.dataInputFill); - txParams = {...txParams, data: dataInput.data, input: dataInput.input} + txParams = { ...txParams, data: dataInput.data, input: dataInput.input }; return txParams as TransactionWithSenderAPI; }; @@ -172,7 +177,7 @@ export const isContractInitOptions = (options: unknown): options is ContractInit 'address', 'jsonInterface', 'syncWithContext', - 'dataInputFill' + 'dataInputFill', ].some(key => key in options); export const isWeb3ContractContext = (options: unknown): options is Web3ContractContext => @@ -186,7 +191,10 @@ export const getCreateAccessListParams = ({ }: { abi: AbiFunctionFragment; params: unknown[]; - options?: (PayableCallOptions | NonPayableCallOptions) & { to?: Address, dataInputFill?: 'input' | 'data' | 'both' }; + options?: (PayableCallOptions | NonPayableCallOptions) & { + to?: Address; + dataInputFill?: 'input' | 'data' | 'both'; + }; contractOptions: ContractOptions; }): TransactionForAccessList => { if (!options?.to && !contractOptions.address) { @@ -212,7 +220,7 @@ export const getCreateAccessListParams = ({ ) as unknown as TransactionForAccessList; const dataInput = dataInputEncodeMethodHelper(txParams, abi, params, options?.dataInputFill); - txParams = {...txParams, data: dataInput.data, input: dataInput.input} + txParams = { ...txParams, data: dataInput.data, input: dataInput.input }; return txParams; }; diff --git a/packages/web3-eth-contract/test/unit/contract.test.ts b/packages/web3-eth-contract/test/unit/contract.test.ts index d12a088ed42..19f7a768f40 100644 --- a/packages/web3-eth-contract/test/unit/contract.test.ts +++ b/packages/web3-eth-contract/test/unit/contract.test.ts @@ -336,7 +336,7 @@ describe('Contract', () => { sendOptions = { from: '0x12364916b10Ae90076dDa6dE756EE1395BB69ec2', gas: '1000000', - data: '0xa41368620000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000548656c6c6f000000000000000000000000000000000000000000000000000000' + data: '0xa41368620000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000548656c6c6f000000000000000000000000000000000000000000000000000000', }; const spyTx = jest .spyOn(eth, 'sendTransaction') @@ -374,7 +374,10 @@ describe('Contract', () => { const expectedProvider = 'http://127.0.0.1:8545'; const web3Context = new Web3Context({ provider: expectedProvider, - config: { contractDataInputFill: 'data', defaultAccount: '0x00000000219ab540356cBB839Cbe05303d7705Fa' }, + config: { + contractDataInputFill: 'data', + defaultAccount: '0x00000000219ab540356cBB839Cbe05303d7705Fa', + }, }); const arg = 'Hello'; const contract = new Contract(GreeterAbi, web3Context); @@ -417,7 +420,10 @@ describe('Contract', () => { const expectedProvider = 'http://127.0.0.1:8545'; const web3Context = new Web3Context({ provider: expectedProvider, - config: { contractDataInputFill: 'both', defaultAccount: '0x00000000219ab540356cBB839Cbe05303d7705Fa' }, + config: { + contractDataInputFill: 'both', + defaultAccount: '0x00000000219ab540356cBB839Cbe05303d7705Fa', + }, }); const arg = 'Hello'; const contract = new Contract(GreeterAbi, web3Context); @@ -434,7 +440,10 @@ describe('Contract', () => { _tx.data === '0xa41368620000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000548656c6c6f000000000000000000000000000000000000000000000000000000' ) { - expect(_tx.input).toStrictEqual("0xa41368620000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000548656c6c6f000000000000000000000000000000000000000000000000000000") + // eslint-disable-next-line + expect(_tx.input).toStrictEqual( + '0xa41368620000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000548656c6c6f000000000000000000000000000000000000000000000000000000', + ); // eslint-disable-next-line expect(_tx.to).toStrictEqual(deployedAddr); // eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-empty-function @@ -461,7 +470,10 @@ describe('Contract', () => { const expectedProvider = 'http://127.0.0.1:8545'; const web3Context = new Web3Context({ provider: expectedProvider, - config: { contractDataInputFill: 'input', defaultAccount: '0x00000000219ab540356cBB839Cbe05303d7705Fa' }, + config: { + contractDataInputFill: 'input', + defaultAccount: '0x00000000219ab540356cBB839Cbe05303d7705Fa', + }, }); const arg = 'Hello'; const contract = new Contract(GreeterAbi, web3Context); @@ -501,7 +513,6 @@ describe('Contract', () => { }); it('call on deployed contract should decode result', async () => { - const arg = 'Hello'; const encodedArg = '0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000548656c6c6f000000000000000000000000000000000000000000000000000000'; @@ -756,8 +767,8 @@ describe('Contract', () => { const contract = new Contract( erc721Abi, '0x1230B93ffd14F2F022039675fA3fc3A46eE4C701', - { gas: '123', dataInputFill: "data" }, - { config: { defaultAccount: '0x00000000219ab540356cBB839Cbe05303d7705Fa'} }, + { gas: '123', dataInputFill: 'data' }, + { config: { defaultAccount: '0x00000000219ab540356cBB839Cbe05303d7705Fa' } }, ); const spyEthCall = jest @@ -781,8 +792,8 @@ describe('Contract', () => { const contract = new Contract( erc721Abi, '0x1230B93ffd14F2F022039675fA3fc3A46eE4C701', - { gas: '123', dataInputFill: "input" }, - { config: { defaultAccount: '0x00000000219ab540356cBB839Cbe05303d7705Fa'} }, + { gas: '123', dataInputFill: 'input' }, + { config: { defaultAccount: '0x00000000219ab540356cBB839Cbe05303d7705Fa' } }, ); const spyEthCall = jest @@ -806,7 +817,10 @@ describe('Contract', () => { const expectedProvider = 'http://127.0.0.1:8545'; const web3Context = new Web3Context({ provider: expectedProvider, - config: { contractDataInputFill: 'data', defaultAccount: '0x00000000219ab540356cBB839Cbe05303d7705Fa' }, + config: { + contractDataInputFill: 'data', + defaultAccount: '0x00000000219ab540356cBB839Cbe05303d7705Fa', + }, }); const contract = new Contract( erc721Abi, @@ -836,7 +850,10 @@ describe('Contract', () => { const expectedProvider = 'http://127.0.0.1:8545'; const web3Context = new Web3Context({ provider: expectedProvider, - config: { contractDataInputFill: 'both', defaultAccount: '0x00000000219ab540356cBB839Cbe05303d7705Fa' }, + config: { + contractDataInputFill: 'both', + defaultAccount: '0x00000000219ab540356cBB839Cbe05303d7705Fa', + }, }); const contract = new Contract( erc721Abi, @@ -1229,7 +1246,7 @@ describe('Contract', () => { const expectedProvider = 'http://127.0.0.1:8545'; const web3Context = new Web3Context({ provider: expectedProvider, - config: {contractDataInputFill: 'both'} + config: { contractDataInputFill: 'both' }, }); const contract = new Contract(GreeterAbi, web3Context); @@ -1274,7 +1291,7 @@ describe('Contract', () => { const expectedProvider = 'http://127.0.0.1:8545'; const web3Context = new Web3Context({ provider: expectedProvider, - config: {contractDataInputFill: 'data'} + config: { contractDataInputFill: 'data' }, }); const contract = new Contract(GreeterAbi, web3Context); @@ -1471,7 +1488,7 @@ describe('Contract', () => { spyEthCall.mockClear(); }); - it('contract method createAccessList should work using data with web3config', async () => { + it('contract method createAccessList should work using data with web3config with both input and data', async () => { const expectedProvider = 'http://127.0.0.1:8545'; const web3Context = new Web3Context({ provider: expectedProvider, From 4c1d30c20f3c41a41078632e01642232f28ef88c Mon Sep 17 00:00:00 2001 From: luu-alex Date: Fri, 8 Sep 2023 13:27:55 -0400 Subject: [PATCH 25/27] add provider example --- .../deploying_and_interacting_with_smart_contracts.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/guides/smart_contracts/deploying_and_interacting_with_smart_contracts.md b/docs/docs/guides/smart_contracts/deploying_and_interacting_with_smart_contracts.md index 5054e2950fc..44cb791c8f2 100644 --- a/docs/docs/guides/smart_contracts/deploying_and_interacting_with_smart_contracts.md +++ b/docs/docs/guides/smart_contracts/deploying_and_interacting_with_smart_contracts.md @@ -357,7 +357,7 @@ my number updated value: 2 If you are running into errors when executing contract methods such as `myContract.methods.call` or `myContract.deploy.estimateGas()` you might be see a contract execution revert error such as: `value transfer did not complete from a contract execution reverted`. -This could be due to the node you are connected to and is expecting the `data` property to be populated in your contract instead of `input`. Web3 version >4.03 will always populate `input` when sending transactions. +This could be due to the node you are connected to and is expecting the `data` property to be populated in your contract instead of `input`, for example this issue will happen with an Anvil node from Foundry. Web3 version >4.0.3 will always populate `input` when sending transactions. To fix this, configure the `contractDataInputFill` in `Web3Config` or when initializing your contract to specify `data` in `dataInputFill` to be filled. Another way to fix this is to provide `data` when using the send or call method. If you want both `data` and `input` filled, set the property to `both`. From 21782780db5d99adb531ba62e8c68e80614e5938 Mon Sep 17 00:00:00 2001 From: luu-alex Date: Sun, 10 Sep 2023 13:11:00 -0400 Subject: [PATCH 26/27] updating docs --- .../deploying_and_interacting_with_smart_contracts.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/docs/guides/smart_contracts/deploying_and_interacting_with_smart_contracts.md b/docs/docs/guides/smart_contracts/deploying_and_interacting_with_smart_contracts.md index 44cb791c8f2..3f5db7264d8 100644 --- a/docs/docs/guides/smart_contracts/deploying_and_interacting_with_smart_contracts.md +++ b/docs/docs/guides/smart_contracts/deploying_and_interacting_with_smart_contracts.md @@ -367,6 +367,8 @@ Here are examples: ```typescript // Configuring Web3Context with `contractDataInputFill` +import { Web3Context } from 'web3-core'; + const expectedProvider = 'http://127.0.0.1:8545'; const web3Context = new Web3Context({ provider: expectedProvider, From 5aa72ec5504c72c1cde3d3decba09cacfe34cada Mon Sep 17 00:00:00 2001 From: luu-alex Date: Sun, 10 Sep 2023 20:45:26 -0400 Subject: [PATCH 27/27] updating docs --- .../deploying_and_interacting_with_smart_contracts.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/docs/docs/guides/smart_contracts/deploying_and_interacting_with_smart_contracts.md b/docs/docs/guides/smart_contracts/deploying_and_interacting_with_smart_contracts.md index 3f5db7264d8..f6c1353cd37 100644 --- a/docs/docs/guides/smart_contracts/deploying_and_interacting_with_smart_contracts.md +++ b/docs/docs/guides/smart_contracts/deploying_and_interacting_with_smart_contracts.md @@ -205,7 +205,7 @@ node index.js If everything is working correctly, you should see the current block number logged to the console. However, if you got an error with the reason `connect ECONNREFUSED 127.0.0.1:7545` then double check that you are running Ganache locally on port `7545`. -## Step 5: Deploy the smart contract to the Ganache network using web3.js +## Step 6: Deploy the smart contract to the Ganache network using web3.js In this step, we will use web3.js to deploy the smart contract to the Ganache network. @@ -282,7 +282,7 @@ Estimated gas: 142748n Contract deployed at address: 0x16447837D4A572d0a8b419201bdcD91E6e428Df1 ``` -## Step 6: Interact with the smart contract using web3.js +## Step 7: Interact with the smart contract using web3.js In this step, we will use web3.js to interact with the smart contract on the Ganache network. @@ -355,7 +355,9 @@ my number updated value: 2 ## Troubleshooting and errors -If you are running into errors when executing contract methods such as `myContract.methods.call` or `myContract.deploy.estimateGas()` you might be see a contract execution revert error such as: `value transfer did not complete from a contract execution reverted`. +If you are running into errors when executing contract methods such as `myContract.methods.call` or `myContract.deploy.estimateGas()` you might be seeing a contract execution revert error such as: `value transfer did not complete from a contract execution reverted` + +or response error: ResponseError: Returned error: unknown field `input`, expected one of `from`, `to`, `gasPrice`, `maxFeePerGas`, `maxPriorityFeePerGas`, `gas`, `value`, `data`, `nonce`, `chainId`, `accessList`, `type`. This could be due to the node you are connected to and is expecting the `data` property to be populated in your contract instead of `input`, for example this issue will happen with an Anvil node from Foundry. Web3 version >4.0.3 will always populate `input` when sending transactions. To fix this, configure the `contractDataInputFill` in `Web3Config` or when initializing your contract to specify `data` in `dataInputFill` to be filled.