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..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. @@ -353,6 +353,60 @@ 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 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. +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` +import { Web3Context } from 'web3-core'; + +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 11436841b2d..46ceb357b9f 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,24 @@ 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 the contracts send, call and estimateGas methods + * 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/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 65f271c8b38..01c757b3946 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; /** @@ -233,6 +234,12 @@ 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; /** @@ -308,12 +315,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; @@ -348,7 +349,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 @@ -361,6 +371,13 @@ export class Contract const address = typeof addressOrOptionsOrContext === 'string' ? addressOrOptionsOrContext : undefined; + if (this.config.contractDataInputFill === 'both') { + this._dataInputFill = this.config.contractDataInputFill; + } else { + this._dataInputFill = + (options as ContractInitOptions)?.dataInputFill ?? + this.config.contractDataInputFill; + } this._parseAndSetJsonInterface(jsonInterface, returnDataFormat); if (!isNullish(address)) { @@ -373,14 +390,14 @@ 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; if (contractContext instanceof Web3Context) { this.subscribeToContextEvents(contractContext); } - Object.defineProperty(this.options, 'address', { set: (value: Address) => this._parseAndSetAddress(value, returnDataFormat), get: () => this._address, @@ -470,7 +487,6 @@ export class Contract */ public clone() { let newContract: Contract; - if (this.options.address) { newContract = new Contract( [...this._jsonInterface, ...this._errorsInterface] as unknown as Abi, @@ -480,8 +496,10 @@ 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, + dataInputFill: this._dataInputFill, }, this.getContextObject(), ); @@ -493,8 +511,10 @@ 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, + dataInputFill: this._dataInputFill, }, this.getContextObject(), ); @@ -577,7 +597,6 @@ export class Contract arguments?: ContractConstructorArgs; }) { let abi = this._jsonInterface.find(j => j.type === 'constructor') as AbiConstructorFragment; - if (!abi) { abi = { type: 'constructor', @@ -588,18 +607,24 @@ export class Contract const _input = format( { format: 'bytes' }, - deployOptions?.input ?? deployOptions?.data ?? this.options.input, + deployOptions?.input ?? this.options.input, + DEFAULT_RETURN_FORMAT, + ); + + const _data = format( + { format: 'bytes' }, + deployOptions?.data ?? this.options.data, DEFAULT_RETURN_FORMAT, ); - if (!_input || _input.trim() === '0x') { + if ((!_input || _input.trim() === '0x') && (!_data || _data.trim() === '0x')) { throw new Web3ContractError('contract creation without any data provided.'); } 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: ( @@ -623,7 +648,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[], @@ -636,7 +660,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), ), }; } @@ -783,7 +807,6 @@ export class Contract returnFormat: DataFormat = DEFAULT_RETURN_FORMAT, ) { this._functions = {}; - this._methods = {} as ContractMethodsInterface; this._events = {} as ContractEventsInterface; @@ -913,7 +936,6 @@ export class Contract throw new Web3ValidatorError(errors); } } - const methods = { arguments: abiParams, @@ -981,7 +1003,10 @@ export class Contract const tx = getEthTxCallParams({ abi, params, - options, + options: { + ...options, + dataInputFill: this._dataInputFill, + }, contractOptions: { ...this.options, from: this.options.from ?? this.config.defaultAccount, @@ -1011,7 +1036,7 @@ export class Contract const tx = getCreateAccessListParams({ abi, params, - options, + options: { ...options, dataInputFill: this.config.contractDataInputFill }, contractOptions: { ...this.options, from: this.options.from ?? this.config.defaultAccount, @@ -1042,11 +1067,10 @@ export class Contract input: undefined, from: modifiedContractOptions.from ?? this.defaultAccount ?? undefined, }; - const tx = getSendTxParams({ abi, params, - options, + options: { ...options, dataInputFill: this.config.contractDataInputFill }, contractOptions: modifiedContractOptions, }); const transactionToSend = sendTransaction(this, tx, DEFAULT_RETURN_FORMAT, { @@ -1061,7 +1085,6 @@ export class Contract decodeContractErrorData(errorsAbi, error.innerError); } }); - return transactionToSend; } @@ -1076,14 +1099,12 @@ export class Contract ...modifiedContractOptions, from: modifiedContractOptions.from ?? this.defaultAccount ?? undefined, }; - const tx = getSendTxParams({ abi, params, - options, + options: { ...options, dataInputFill: this.config.contractDataInputFill }, contractOptions: modifiedContractOptions, }); - return sendTransaction(this, tx, DEFAULT_RETURN_FORMAT, { transactionResolver: receipt => { if (receipt.status === BigInt(0)) { @@ -1120,10 +1141,9 @@ 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/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/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..ca3fd7f9c34 100644 --- a/packages/web3-eth-contract/src/utils.ts +++ b/packages/web3-eth-contract/src/utils.ts @@ -27,10 +27,31 @@ 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 | TransactionForAccessList, + abi: AbiFunctionFragment, + params: unknown[], + dataInputFill?: 'data' | 'input' | 'both', +): { 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); + } + // if input and data is empty, use web3config default + if (isNullish(tx.input) && isNullish(tx.data)) { + tx[dataInputFill as 'data' | 'input'] = encodeMethodABI(abi, params); + } + + return { data: tx.data as HexString, input: tx.input as HexString }; +}; + export const getSendTxParams = ({ abi, params, @@ -43,11 +64,12 @@ export const getSendTxParams = ({ input?: HexString; data?: HexString; to?: Address; + dataInputFill?: 'input' | 'data' | 'both'; }; contractOptions: ContractOptions; }): TransactionCall => { - const deploymentCall = options?.input ?? options?.data ?? contractOptions.input; - + 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 +77,6 @@ export const getSendTxParams = ({ if (!options?.from && !contractOptions.from) { throw new Web3ContractError('Contract "from" address not specified'); } - let txParams = mergeDeep( { to: contractOptions.address, @@ -65,16 +86,12 @@ export const getSendTxParams = ({ input: contractOptions.input, maxPriorityFeePerGas: contractOptions.maxPriorityFeePerGas, maxFeePerGas: contractOptions.maxFeePerGas, + data: contractOptions.data, }, options as unknown as Record, ) as unknown as TransactionCall; - - if (!txParams.input || abi.type === 'constructor') { - txParams = { - ...txParams, - input: encodeMethodABI(abi, params, txParams.input as HexString), - }; - } + const dataInput = dataInputEncodeMethodHelper(txParams, abi, params, options?.dataInputFill); + txParams = { ...txParams, data: dataInput.data, input: dataInput.input }; return txParams; }; @@ -87,13 +104,15 @@ export const getEthTxCallParams = ({ }: { abi: AbiFunctionFragment; params: unknown[]; - options?: (PayableCallOptions | NonPayableCallOptions) & { to?: Address }; + options?: (PayableCallOptions | NonPayableCallOptions) & { + to?: Address; + dataInputFill?: 'input' | 'data' | 'both'; + }; contractOptions: ContractOptions; }): TransactionCall => { if (!options?.to && !contractOptions.address) { throw new Web3ContractError('Contract address not specified'); } - let txParams = mergeDeep( { to: contractOptions.address, @@ -103,14 +122,13 @@ export const getEthTxCallParams = ({ input: contractOptions.input, maxPriorityFeePerGas: contractOptions.maxPriorityFeePerGas, maxFeePerGas: contractOptions.maxFeePerGas, + data: contractOptions.data, }, options as unknown as Record, ) as unknown as TransactionCall; - txParams = { - ...txParams, - input: encodeMethodABI(abi, params, txParams.input ? toHex(txParams.input) : undefined), - }; + const dataInput = dataInputEncodeMethodHelper(txParams, abi, params, options?.dataInputFill); + txParams = { ...txParams, data: dataInput.data, input: dataInput.input }; return txParams; }; @@ -123,7 +141,9 @@ export const getEstimateGasParams = ({ }: { abi: AbiFunctionFragment; params: unknown[]; - options?: PayableCallOptions | NonPayableCallOptions; + options?: (PayableCallOptions | NonPayableCallOptions) & { + dataInputFill?: 'input' | 'data' | 'both'; + }; contractOptions: ContractOptions; }): Partial => { let txParams = mergeDeep( @@ -133,14 +153,13 @@ export const getEstimateGasParams = ({ gasPrice: contractOptions.gasPrice, from: contractOptions.from, input: contractOptions.input, + data: contractOptions.data, }, options as unknown as Record, ) as unknown as TransactionCall; - txParams = { - ...txParams, - input: encodeMethodABI(abi, params, txParams.input ? toHex(txParams.input) : undefined), - }; + const dataInput = dataInputEncodeMethodHelper(txParams, abi, params, options?.dataInputFill); + txParams = { ...txParams, data: dataInput.data, input: dataInput.input }; return txParams as TransactionWithSenderAPI; }; @@ -158,6 +177,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 => @@ -171,7 +191,10 @@ 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) { @@ -191,16 +214,13 @@ export const getCreateAccessListParams = ({ input: contractOptions.input, maxPriorityFeePerGas: contractOptions.maxPriorityFeePerGas, maxFeePerGas: contractOptions.maxFeePerGas, + data: contractOptions.data, }, options as unknown as Record, ) as unknown as TransactionForAccessList; - if (!txParams.input || abi.type === 'constructor') { - txParams = { - ...txParams, - input: encodeMethodABI(abi, params, txParams.input as HexString), - }; - } + 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 4ee28bc254f..19f7a768f40 100644 --- a/packages/web3-eth-contract/test/unit/contract.test.ts +++ b/packages/web3-eth-contract/test/unit/contract.test.ts @@ -208,14 +208,14 @@ describe('Contract', () => { let sendOptions: Record; const deployedAddr = '0x20bc23D0598b12c34cBDEf1fae439Ba8744DB426'; - beforeAll(() => { + beforeEach(() => { sendOptions = { from: '0x12364916b10Ae90076dDa6dE756EE1395BB69ec2', gas: '1000000', }; }); - 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, @@ -258,34 +291,201 @@ 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); + sendOptions = { + from: '0x12364916b10Ae90076dDa6dE756EE1395BB69ec2', + gas: '1000000', + }; + const spyTx = jest + .spyOn(eth, 'sendTransaction') + .mockImplementation((_objInstance, _tx) => { + const newContract = contract.clone(); + newContract.options.address = deployedAddr; + expect(_tx.input).toBeDefined(); + 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'); - // 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); + 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; + expect(_tx.data).toBeDefined(); + 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'); - // jest.spyOn(newContract.methods.setGreeting(arg), 'send').mockReturnValue({ - // send, - // status: '0x1', - // } as unknown as Web3PromiEvent); + 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' + ) { + // 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 + 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' @@ -299,24 +499,13 @@ 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'); @@ -327,7 +516,6 @@ describe('Contract', () => { const arg = 'Hello'; const encodedArg = '0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000548656c6c6f000000000000000000000000000000000000000000000000000000'; - const contract = new Contract(GreeterAbi); const spyTx = jest.spyOn(eth, 'sendTransaction').mockImplementation(() => { @@ -343,14 +531,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); @@ -552,7 +738,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', @@ -577,6 +763,125 @@ describe('Contract', () => { spyEthCall.mockClear(); }); + it('should be able to 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 to call a payable method with input as a contract init option', async () => { + const contract = new Contract( + erc721Abi, + '0x1230B93ffd14F2F022039675fA3fc3A46eE4C701', + { 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) => { + 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 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); @@ -840,7 +1145,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(() => { @@ -863,7 +1168,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(() => { @@ -888,6 +1193,131 @@ 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 using data', 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'], + }); + + 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 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'], @@ -918,7 +1348,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', ); @@ -1022,6 +1452,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 with both input and data', 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({ diff --git a/packages/web3-eth/CHANGELOG.md b/packages/web3-eth/CHANGELOG.md index 3b29e582cc9..b30e008202c 100644 --- a/packages/web3-eth/CHANGELOG.md +++ b/packages/web3-eth/CHANGELOG.md @@ -186,3 +186,7 @@ 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 e12cc5ed366..866ca7aab6c 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( @@ -970,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) && diff --git a/packages/web3-types/src/eth_contract_types.ts b/packages/web3-types/src/eth_contract_types.ts index 5b14b6f0fce..6c4dd374869 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 { @@ -65,6 +70,8 @@ export interface NonPayableCallOptions { */ gasPrice?: string; type?: string | number; + data?: HexString; + input?: HexString; } export interface PayableCallOptions extends NonPayableCallOptions {