diff --git a/CHANGELOG.md b/CHANGELOG.md index 631e06643e6..4bc198ddda1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -458,6 +458,10 @@ Released with 1.0.0-beta.37 code base. ## [1.6.1] +### Added + +- Support for `eth_createAccessList` as both an rpc call (`web3.eth.createAccessList`) and property of contract method wrappers (`contractInstance.methods.getValue().createAccessList`) (#4332) + ### Changed - Not considering `tx.chainId` if `tx.common.customChain.chainId` is provided for `web3.eth.accounts.signTransaction` function (#4293) @@ -466,3 +470,4 @@ Released with 1.0.0-beta.37 code base. - Emit subscription id with connect event when creating a subscription (#4300) - Introduced new configuration "blockHeaderTimeout" for waiting of block headers for transaction receipt (#3891) - Format `block.baseFeePerGas` to number (#4330) +- Updated README to include Webpack 5 angular support instructions (#4174) diff --git a/docs/web3-eth-contract.rst b/docs/web3-eth-contract.rst index 1ce1adc16e6..47a4c225f62 100644 --- a/docs/web3-eth-contract.rst +++ b/docs/web3-eth-contract.rst @@ -613,6 +613,7 @@ Returns - ``Function`` - :ref:`send `: Will deploy the contract. The promise will resolve with the new contract instance, instead of the receipt! - ``Function`` - :ref:`estimateGas `: Will estimate the gas used for deploying. Note: You must specify a ``from`` address otherwise you may experience odd behavior. - ``Function`` - :ref:`encodeABI `: Encodes the ABI of the deployment, which is contract data + constructor parameters +- ``Function`` - :ref:`createAccessList `: Returns an EIP-2930 access list for specified contract method Note: You must specify a ``from`` address and possible ``gas`` ------- Example @@ -684,7 +685,7 @@ methods myContract.methods.myMethod([param1[, param2[, ...]]]) -Creates a transaction object for that method, which then can be :ref:`called `, :ref:`send `, :ref:`estimated `, or :ref:`ABI encoded `. +Creates a transaction object for that method, which then can be :ref:`called `, :ref:`send `, :ref:`estimated `, :ref:`createAccessList ` , or :ref:`ABI encoded `. The methods of this smart contract are available through: @@ -711,6 +712,7 @@ Returns - ``Function`` - :ref:`send `: Will send a transaction to the smart contract and execute its method (Can alter the smart contract state). - ``Function`` - :ref:`estimateGas `: Will estimate the gas used when the method would be executed on chain. Note: You must specify a ``from`` address otherwise you may experience odd behavior. - ``Function`` - :ref:`encodeABI `: Encodes the ABI for this method. This can be send using a transaction, call the method or passing into another smart contracts method as argument. +- ``Function`` - :ref:`createAccessList `: Returns an EIP-2930 access list for specified contract method Note: You must specify a ``from`` address and ``gas`` if it's not specified in ``options`` when instantiating parent contract object (e.g. ``new web3.eth.Contract(jsonInterface[, address][, options])``). ------- Example @@ -1038,6 +1040,73 @@ Example > '0x58cf5f1000000000000000000000000000000000000000000000000000000000000007B' +------------------------------------------------------------------------------ + +.. _contract-createAccessList: + +methods.myMethod.createAccessList +===================== + +.. code-block:: javascript + + myContract.methods.myMethod([param1[, param2[, ...]]]).createAccessList(options, blockHashOrBlockNumber [, callback]) + +Will call to create an access list a method execution will access when executed in the EVM. +Note: Currently `eth_createAccessList` seems to only be supported by Geth. +Note: You must specify a ``from`` address and ``gas`` if it's not specified in ``options`` when instantiating parent contract object (e.g. ``new web3.eth.Contract(jsonInterface[, address][, options])``). + +---------- +Parameters +---------- + +1. ``options`` - ``Object``: The options used for calling. + * ``from`` - ``String``: The address the call "transaction" should be made from. + * ``gas`` - ``Number`` (optional): The maximum gas provided for this call "transaction" (gas limit). Setting a specific value helps to detect out of gas errors. Access list response will return amount of gas used. +2. ``block`` - ``String|Number|BN|BigNumber`` (optional): The block number or hash. Or the string ``"earliest"``, ``"latest"`` or ``"pending"`` as in the :ref:`default block parameter `. +3. ``callback`` - ``Function`` (optional): This callback will be fired with the result of the access list generation as the second argument, or with an error object as the first argument. + +------- +Returns +------- + +``Promise`` returns ``Object``: The generated access list for transaction. + +.. code-block:: javascript + + { + "accessList": [ + { + "address": "0x00f5f5f3a25f142fafd0af24a754fafa340f32c7", + "storageKeys": [ + "0x0000000000000000000000000000000000000000000000000000000000000000" + ] + } + ], + "gasUsed": "0x644e" + } + + +------- +Example +------- + +.. code-block:: javascript + + // using the callback + myContract.methods.myMethod(123).createAccessList({from: '0xde0B295669a9FD93d5F28D9Ec85E40f4cb697BAe', gas: 5000000}, function(error, accessList){ + ... + }); + + // using the promise + myContract.methods.myMethod(123).createAccessList({from: '0xde0B295669a9FD93d5F28D9Ec85E40f4cb697BAe', gas: 5000000}) + .then(function(accessList){ + ... + }) + .catch(function(error){ + ... + }); + + ------------------------------------------------------------------------------ diff --git a/docs/web3-eth.rst b/docs/web3-eth.rst index 73db060f9cb..3194ef7287d 100644 --- a/docs/web3-eth.rst +++ b/docs/web3-eth.rst @@ -2153,3 +2153,62 @@ Example } ------------------------------------------------------------------------------ + +createAccessList +===================== + +.. code-block:: javascript + + web3.eth.createAccessList(callObject [, callback]) + +Will call to create an access list a method execution will access when executed in the EVM. +Note: Currently `eth_createAccessList` seems to only be supported by Geth. +Note: You must specify a ``from`` address and ``gas`` if it's not specified in ``options`` when instantiating parent contract object (e.g. ``new web3.eth.Contract(jsonInterface[, address][, options])``). + +---------- +Parameters +---------- + +1. A transaction object, see :ref:`web3.eth.sendTransaction ` with the difference that this method is specifically for contract method executions. +2. ``block`` - ``String|Number|BN|BigNumber`` (optional): The block number or hash. Or the string ``"earliest"``, ``"latest"`` or ``"pending"`` as in the :ref:`default block parameter `. +3. ``callback`` - ``Function`` (optional): This callback will be fired with the result of the access list generation as the second argument, or with an error object as the first argument. + + +------- +Returns +------- + +``Promise`` returns ``Object``: The generated access list for transaction. + +.. code-block:: javascript + + { + "accessList": [ + { + "address": "0x00f5f5f3a25f142fafd0af24a754fafa340f32c7", + "storageKeys": [ + "0x0000000000000000000000000000000000000000000000000000000000000000" + ] + } + ], + "gasUsed": "0x644e" + } + +------- +Example +------- + + +.. code-block:: javascript + + web3.eth.createAccessList({ + from: '0x3bc5885c2941c5cda454bdb4a8c88aa7f248e312', + data: '0x20965255', + gasPrice: '0x3b9aca00', + gas: '0x3d0900', + to: '0x00f5f5f3a25f142fafd0af24a754fafa340f32c7' + }) + .then(console.log); + + +------------------------------------------------------------------------------ diff --git a/packages/web3-eth-contract/src/index.js b/packages/web3-eth-contract/src/index.js index a0a2aaa06de..65c028379e5 100644 --- a/packages/web3-eth-contract/src/index.js +++ b/packages/web3-eth-contract/src/index.js @@ -819,6 +819,7 @@ Contract.prototype._createTxObject = function _createTxObject(){ txObject.send.request = this.parent._executeMethod.bind(txObject, 'send', true); // to make batch requests txObject.encodeABI = this.parent._encodeMethodABI.bind(txObject); txObject.estimateGas = this.parent._executeMethod.bind(txObject, 'estimate'); + txObject.createAccessList = this.parent._executeMethod.bind(txObject, 'createAccessList'); if (args && this.method.inputs && args.length !== this.method.inputs.length) { if (this.nextMethod) { @@ -916,6 +917,26 @@ Contract.prototype._executeMethod = function _executeMethod(){ } switch (args.type) { + case 'createAccessList': + + // return error, if no "from" is specified + if(!utils.isAddress(args.options.from)) { + return utils._fireError(errors.ContractNoFromAddressDefinedError(), defer.eventEmitter, defer.reject, args.callback); + } + + var createAccessList = (new Method({ + name: 'createAccessList', + call: 'eth_createAccessList', + params: 2, + inputFormatter: [formatters.inputTransactionFormatter, formatters.inputDefaultBlockNumberFormatter], + requestManager: _this._parent._requestManager, + accounts: ethAccounts, // is eth.accounts (necessary for wallet signing) + defaultAccount: _this._parent.defaultAccount, + defaultBlock: _this._parent.defaultBlock + })).createFunction(); + + return createAccessList(args.options, args.callback); + case 'estimate': var estimateGas = (new Method({ diff --git a/packages/web3-eth/src/index.js b/packages/web3-eth/src/index.js index a977f708c32..7996263419f 100644 --- a/packages/web3-eth/src/index.js +++ b/packages/web3-eth/src/index.js @@ -584,6 +584,12 @@ var Eth = function Eth() { params: 0, outputFormatter: formatter.outputTransactionFormatter }), + new Method({ + name: 'createAccessList', + call: 'eth_createAccessList', + params: 2, + inputFormatter: [formatter.inputTransactionFormatter, formatter.inputDefaultBlockNumberFormatter], + }), // subscriptions new Subscriptions({ diff --git a/test/e2e.eth.createAccessList.js b/test/e2e.eth.createAccessList.js new file mode 100644 index 00000000000..0a329d8b7aa --- /dev/null +++ b/test/e2e.eth.createAccessList.js @@ -0,0 +1,76 @@ +var assert = require('assert'); +var Basic = require('./sources/Basic'); +var Misc = require('./sources/Misc'); +var utils = require('./helpers/test.utils'); +var Web3 = utils.getWeb3(); + +describe('method.call [ @E2E ]', function () { + var web3; + var accounts; + var basic; + var instance; + var options; + + var basicOptions = { + data: Basic.bytecode, + gasPrice: 1000000000, // Default gasPrice set by Geth + gas: 4000000 + }; + + var miscOptions = { + data: Misc.bytecode, + gasPrice: 1000000000, // Default gasPrice set by Geth + gas: 4000000 + }; + + describe('http', function () { + before(async function () { + web3 = new Web3('http://localhost:8545'); + accounts = await web3.eth.getAccounts(); + + basic = new web3.eth.Contract(Basic.abi, basicOptions); + instance = await basic.deploy().send({from: accounts[0]}); + }) + + it('returns expected access list for getValue', async function () { + // Currently only Geth supports eth_createAccessList + if (process.env.GANACHE || global.window ) return + + var expected = { + accessList: [ + { + address: instance.options.address.toLowerCase(), + storageKeys: ["0x0000000000000000000000000000000000000000000000000000000000000000"] + } + ], + gasUsed: '0x644e' + }; + + assert.deepEqual( + await instance.methods.getValue().createAccessList({from: accounts[0]}), + expected + ); + }); + + it('returns expected access list for setValue', async function () { + // Currently only Geth supports eth_createAccessList + if (process.env.GANACHE || global.window ) return + + var expected = { + accessList: [ + { + address: instance.options.address.toLowerCase(), + storageKeys: ["0x0000000000000000000000000000000000000000000000000000000000000000"] + } + ], + gasUsed: '0xb2f5' + } + + + assert.deepEqual( + await instance.methods.setValue(1).createAccessList({from: accounts[0]}), + expected + ); + }); + }); +}); diff --git a/test/eth.createAccessList.js b/test/eth.createAccessList.js new file mode 100644 index 00000000000..8cc3be926c0 --- /dev/null +++ b/test/eth.createAccessList.js @@ -0,0 +1,49 @@ +var testMethod = require('./helpers/test.method.js'); + +var method = 'createAccessList'; + +var tests = [{ + args: [{ + from: '0x3bc5885c2941c5cda454bdb4a8c88aa7f248e312', + data: '0x20965255', + gasPrice: '0x3b9aca00', + gas: '0x3d0900', + to: '0x00f5f5f3a25f142fafd0af24a754fafa340f32c7' + }], + formattedArgs: [ + { + from: '0x3bc5885c2941c5cda454bdb4a8c88aa7f248e312', + data: '0x20965255', + gasPrice: '0x3b9aca00', + gas: '0x3d0900', + to: '0x00f5f5f3a25f142fafd0af24a754fafa340f32c7' + }, + 'latest' + ], + result: { + "accessList": [ + { + "address": "0x00f5f5f3a25f142fafd0af24a754fafa340f32c7", + "storageKeys": [ + "0x0000000000000000000000000000000000000000000000000000000000000000" + ] + } + ], + "gasUsed": "0x644e" + }, + formattedResult: { + "accessList": [ + { + "address": "0x00f5f5f3a25f142fafd0af24a754fafa340f32c7", + "storageKeys": [ + "0x0000000000000000000000000000000000000000000000000000000000000000" + ] + } + ], + "gasUsed": "0x644e" + }, + call: 'eth_'+ method +}]; + +testMethod.runTests('eth', method, tests); +