Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

EIP-1559 support for web3.eth.sendTransaction #4220

Merged
merged 27 commits into from
Aug 5, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
c437549
Add txType and pricing helper methods. Refactor logic for sendTransac…
spacesailor24 Aug 3, 2021
adf7705
Add esModuleInterop: true
spacesailor24 Aug 3, 2021
a24e07c
Add EIP-1559 test
spacesailor24 Aug 3, 2021
496017c
Update CHANGELOG
spacesailor24 Aug 3, 2021
b5dadf9
Add check for ganache network
spacesailor24 Aug 3, 2021
0299df8
add @ethereumjs/common dependency
spacesailor24 Aug 3, 2021
1ad553e
Correct if statement conditions
spacesailor24 Aug 4, 2021
8b8224d
Update tests
spacesailor24 Aug 4, 2021
a9e1556
Debugging ganache tests
spacesailor24 Aug 4, 2021
136d690
Debugging ganache tests - toHex gasPrice
spacesailor24 Aug 4, 2021
460b0af
Revert debugs
spacesailor24 Aug 4, 2021
2f7418a
Debugging e2e_ganache - txPricing all to hex
spacesailor24 Aug 4, 2021
1b0db3b
Debugging e2e_ganache - revert and console.log
spacesailor24 Aug 4, 2021
8ad5052
Remove debugging console.log
spacesailor24 Aug 4, 2021
5f44175
Debugging - console.log
spacesailor24 Aug 4, 2021
6635a18
Debugging - move console logs
spacesailor24 Aug 4, 2021
e77f37a
Debug - delete type if 0x0
spacesailor24 Aug 4, 2021
7e1d338
Debug - move deletion of type
spacesailor24 Aug 4, 2021
ee2d0b8
Remove debugs
spacesailor24 Aug 5, 2021
2d2ee63
Debug - add check for method !== eth_sendRawTransaction
spacesailor24 Aug 5, 2021
2c88d26
Debug- sanity check
spacesailor24 Aug 5, 2021
8ca0b72
Debug - minimal code changes
spacesailor24 Aug 5, 2021
431aa81
Debug - forgot to comment old code
spacesailor24 Aug 5, 2021
146b096
Debug - old code
spacesailor24 Aug 5, 2021
fbfbbca
Debug - minimal code refactor
spacesailor24 Aug 5, 2021
3ef9420
Debug - new code refactored
spacesailor24 Aug 5, 2021
b4a52d6
Didn't uncomment curly brace
spacesailor24 Aug 5, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -424,3 +424,4 @@ Released with 1.0.0-beta.37 code base.

- `maxPriorityFeePerGas` and `maxFeePerGas` now included in `_txInputFormatter` (#4217)
- If `maxPriorityFeePerGas` of `maxFeePerGas` present `_txInputFormatter` deletes `tx.gasPrice` (fixes #4211) (#4217)
- Support for EIP-1559 to `web3.eth.sendTransaction` (#4220)
5,598 changes: 5,561 additions & 37 deletions packages/web3-core-method/package-lock.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions packages/web3-core-method/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
},
"main": "lib/index.js",
"dependencies": {
"@ethereumjs/common": "^2.4.0",
"@ethersproject/transactions": "^5.0.0-beta.135",
"web3-core-helpers": "1.5.0",
"web3-core-promievent": "1.5.0",
Expand Down
145 changes: 131 additions & 14 deletions packages/web3-core-method/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ var formatters = require('web3-core-helpers').formatters;
var utils = require('web3-utils');
var promiEvent = require('web3-core-promievent');
var Subscriptions = require('web3-core-subscriptions').subscriptions;
var HardForks = require('@ethereumjs/common').Hardfork;

var EthersTransactionUtils = require('@ethersproject/transactions');

Expand Down Expand Up @@ -770,18 +771,29 @@ Method.prototype.buildCall = function () {
};

// Send the actual transaction
if (isSendTx && !!payload.params[0] && typeof payload.params[0] === 'object' && typeof payload.params[0].gasPrice === 'undefined') {

var getGasPrice = (new Method({
name: 'getGasPrice',
call: 'eth_gasPrice',
params: 0
})).createFunction(method.requestManager);

getGasPrice(function (err, gasPrice) {

if (gasPrice) {
payload.params[0].gasPrice = gasPrice;
if (isSendTx
&& !!payload.params[0]
&& typeof payload.params[0] === 'object'
spacesailor24 marked this conversation as resolved.
Show resolved Hide resolved
&& (
typeof payload.params[0].gasPrice === 'undefined'
&& (
typeof payload.params[0].maxPriorityFeePerGas === 'undefined'
|| typeof payload.params[0].maxFeePerGas === 'undefined'
)
)
) {
if (typeof payload.params[0].type === 'undefined')
payload.params[0].type = _handleTxType(payload.params[0]);

_handleTxPricing(method, payload.params[0]).then(txPricing => {
if (txPricing.gasPrice !== undefined) {
payload.params[0].gasPrice = txPricing.gasPrice;
} else if (
txPricing.maxPriorityFeePerGas !== undefined
&& txPricing.maxFeePerGas !== undefined
) {
payload.params[0].maxPriorityFeePerGas = txPricing.maxPriorityFeePerGas;
payload.params[0].maxFeePerGas = txPricing.maxFeePerGas;
}

if (isSendTx) {
Expand All @@ -791,8 +803,7 @@ Method.prototype.buildCall = function () {
}

sendRequest(payload, method);
});

})
} else {
if (isSendTx) {
setTimeout(() => {
Expand All @@ -819,6 +830,112 @@ Method.prototype.buildCall = function () {
return send;
};

function _handleTxType(tx) {
GregTheGreek marked this conversation as resolved.
Show resolved Hide resolved
// Taken from https://github.com/ethers-io/ethers.js/blob/2a7ce0e72a1e0c9469e10392b0329e75e341cf18/packages/abstract-signer/src.ts/index.ts#L215
const hasEip1559 = (tx.maxFeePerGas !== undefined || tx.maxPriorityFeePerGas !== undefined);

let txType;

if (tx.type !== undefined) {
txType = utils.toHex(tx.type)
} else if (tx.type === undefined && hasEip1559) {
txType = '0x2'
} else {
txType = '0x0'
}

if (tx.gasPrice !== undefined && (txType === '0x2' || hasEip1559))
throw Error("eip-1559 transactions don't support gasPrice");
if ((txType === '0x1' || txType === '0x0') && hasEip1559)
throw Error("pre-eip-1559 transaction don't support maxFeePerGas/maxPriorityFeePerGas");

if (
hasEip1559 ||
(
(tx.common && tx.common.hardfork && tx.common.hardfork.toLowerCase() === HardForks.London) ||
(tx.hardfork && tx.hardfork.toLowerCase() === HardForks.London)
)
) {
txType = '0x2';
} else if (
tx.accessList ||
(
(tx.common && tx.common.hardfork && tx.common.hardfork.toLowerCase() === HardForks.Berlin) ||
(tx.hardfork && tx.hardfork.toLowerCase() === HardForks.Berlin)
)
) {
txType = '0x1';
}

return txType
}

function _handleTxPricing(method, tx) {
return new Promise((resolve, reject) => {
try {
var getBlockByNumber = (new Method({
name: 'getBlockByNumber',
call: 'eth_getBlockByNumber',
params: 2,
inputFormatter: [function(blockNumber) {
return blockNumber ? utils.toHex(blockNumber) : 'latest'
}, function() {
return false
}]
})).createFunction(method.requestManager);
var getGasPrice = (new Method({
name: 'getGasPrice',
call: 'eth_gasPrice',
params: 0
})).createFunction(method.requestManager);

if (tx.type < '0x2' && tx.gasPrice !== undefined) {
// Legacy transaction, return provided gasPrice
resolve({ gasPrice: tx.gasPrice })
} else {
Promise.all([
getBlockByNumber(),
getGasPrice()
]).then(responses => {
const [block, gasPrice] = responses;
if (
(tx.type === '0x2') &&
block && block.baseFeePerGas
) {
// The network supports EIP-1559

// Taken from https://github.com/ethers-io/ethers.js/blob/ba6854bdd5a912fe873d5da494cb5c62c190adde/packages/abstract-provider/src.ts/index.ts#L230
let maxPriorityFeePerGas, maxFeePerGas;

if (tx.gasPrice) {
// Using legacy gasPrice property on an eip-1559 network,
// so use gasPrice as both fee properties
maxPriorityFeePerGas = tx.gasPrice;
maxFeePerGas = tx.gasPrice;
delete tx.gasPrice;
} else {
maxPriorityFeePerGas = tx.maxPriorityFeePerGas || '0x3B9ACA00'; // 1 Gwei
maxFeePerGas = tx.maxFeePerGas ||
utils.toHex(
utils.toBN(block.baseFeePerGas)
.mul(utils.toBN(2))
.add(utils.toBN(maxPriorityFeePerGas))
);
}
resolve({ maxFeePerGas, maxPriorityFeePerGas });
} else {
if (tx.maxPriorityFeePerGas || tx.maxFeePerGas)
throw Error("Network doesn't support eip-1559")
resolve({ gasPrice });
}
})
}
} catch (error) {
reject(error)
}
})
}

/**
* Returns the revert reason string if existing or otherwise false.
*
Expand Down
3 changes: 2 additions & 1 deletion packages/web3-core-method/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"outDir": "./lib"
"outDir": "./lib",
"esModuleInterop": true
},
"include": [
"./src"
Expand Down
31 changes: 30 additions & 1 deletion test/contract.js
Original file line number Diff line number Diff line change
Expand Up @@ -2634,6 +2634,34 @@ var runTests = function(contractFactory) {
var provider = new FakeIpcProvider();
var signature = 'mySend(address,uint256)';

provider.injectResult({
baseFeePerGas: "0x7",
difficulty: "0x6cd6be3a",
extraData: "0x796f75747562652e636f6d2f77617463683f763d6451773477395767586351",
gasLimit: "0x1c9c381",
gasUsed: "0x8dc073",
hash: "0x846880b1158f434884f3637802ed09bac77eafc35b5f03b881ac88ce38a54907",
logsBloom: "0x4020001000000000000000008000010000000000400200000001002140000008000000010000810020000840000204304000081000000b00400010000822200004200020020140000001000882000064000021303200020000400008800000000002202102000084010000090020a8000800002000000010000030300000000000000006001005000040080001010000010040018100004c0050004000000000420000000021000200000010020008100000004000080000000000000040000900080102004002000080210201081014004030200148101000002020108025000018020020102040000204240500010000002200048000401300080088000002",
miner: "0x86864f1edf10eaf105b1bdc6e9aa8232b4c6aa00",
mixHash: "0xa29afb1fa1aea9eeac72ff435a8fc420bbc1fa1be08223eb61f294ee32250bde",
nonce: "0x122af1a5ccd78f3b",
number: "0xa0d600",
parentHash: "0x28f49150e1fe6f245655925b290f59e707d1e5c646dadaa22937169433b30294",
receiptsRoot: "0xc97d4f9980d680053606318a5820261a1dccb556d1056b70f0d48fb384986be5",
sha3Uncles: "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
size: "0x2042",
stateRoot: "0x116981b10423133ade5bd44f03c54cc3c57f4467a1c3d4b0c6d8d33a76c361ad",
timestamp: "0x60dc24ec",
totalDifficulty: "0x78828f2d886cbb",
transactions: [],
transactionsRoot: "0x738f53f745d58169da93ebbd52cc49e0c979d6ca68a6513007b546b19ab78ba4",
uncles: []
});
provider.injectValidation(function (payload) {
assert.equal(payload.method, 'eth_getBlockByNumber');
assert.deepEqual(payload.params, ['latest', false]);
});

provider.injectValidation(function (payload) {
assert.equal(payload.method, 'eth_gasPrice');
assert.deepEqual(payload.params, []);
Expand All @@ -2650,7 +2678,8 @@ var runTests = function(contractFactory) {
'0000000000000000000000000000000000000000000000000000000000000011' ,
to: addressLowercase,
from: addressLowercase,
gasPrice: '0x45656456456456'
gasPrice: '0x45656456456456',
type: '0x0'
}]);

done();
Expand Down
40 changes: 40 additions & 0 deletions test/e2e.method.send.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,26 @@ describe('method.send [ @E2E ]', function () {
assert(web3.utils.isHexStrict(receipt.transactionHash));
});

it('returns a receipt (EIP-1559, maxFeePerGas and maxPriorityFeePerGas specified)', async function () {
// ganache does not support eth_signTransaction
if (process.env.GANACHE || global.window ) return

var nonceVal = await web3.eth.getTransactionCount(accounts[0]);
var receipt = await web3.eth.sendTransaction({
to: accounts[1],
from: accounts[0],
nonce: nonceVal,
value: web3.utils.toHex(web3.utils.toWei('0.1', 'ether')),
gas: web3.utils.toHex(21000),
maxFeePerGas: '0x59682F00', // 1.5 Gwei
maxPriorityFeePerGas: '0x1DCD6500', // .5 Gwei
type: '0x2'
})

assert(receipt.status === true);
assert(web3.utils.isHexStrict(receipt.transactionHash));
});

it('errors on OOG', async function () {
try {
var nonceVal = await web3.eth.getTransactionCount(accounts[0]);
Expand Down Expand Up @@ -137,6 +157,26 @@ describe('method.send [ @E2E ]', function () {
assert(web3.utils.isHexStrict(receipt.transactionHash));
});

it('returns a receipt (EIP-1559, maxFeePerGas and maxPriorityFeePerGas specified)', async function () {
// ganache does not support eth_signTransaction
if (process.env.GANACHE || global.window ) return

var nonceVal = await web3.eth.getTransactionCount(accounts[0]);
var receipt = await web3.eth.sendTransaction({
to: accounts[1],
from: accounts[0],
nonce: nonceVal,
value: web3.utils.toHex(web3.utils.toWei('0.1', 'ether')),
gas: web3.utils.toHex(21000),
maxFeePerGas: '0x59682F00', // 1.5 Gwei
maxPriorityFeePerGas: '0x1DCD6500', // .5 Gwei
type: '0x2'
})

assert(receipt.status === true);
assert(web3.utils.isHexStrict(receipt.transactionHash));
});

it('errors on OOG', async function () {
try {
var nonceVal = await web3.eth.getTransactionCount(accounts[0]);
Expand Down
38 changes: 31 additions & 7 deletions test/eth.sendTransaction.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,19 +52,26 @@ var tests = [{
}
}
},
call: 'eth_gasPrice',
formattedArgs: [],
result: '0x1234567',
formattedResult: '0x1234567',

call2: 'eth_'+ method,
formattedArgs2: [{
call: 'eth_getBlockByNumber',
formattedArgs: ['latest', false],

call2: 'eth_gasPrice',
formattedArgs2: [],
result2: '0x1234567',
formattedResult2: '0x1234567',

call3: 'eth_'+ method,
formattedArgs3: [{
from: "0xdbdbdb2cbd23b783741e8d7fcf51e459b497e4a6",
to: "0xdbdbdb2cbd23b783741e8d7fcf51e459b497e4a6",
value: "0x11f71f76bb1",
gasPrice: "0x1234567"
gasPrice: "0x1234567",
type: "0x0"
}],
result2: '0x1234567'
result3: '0x1234567'
},{
args: [{
from: '0XDBDBDB2CBD23B783741E8D7FCF51E459B497E4A6',
Expand Down Expand Up @@ -249,6 +256,15 @@ describe(method, function () {
});
}

if (test.call3) {
provider.injectResult(clone(test.result3));
provider.injectValidation(function (payload) {
assert.equal(payload.jsonrpc, '2.0');
assert.equal(payload.method, test.call3);
assert.deepEqual(payload.params, test.formattedArgs3 || []);
});
}

provider.injectResult(null);
provider.injectValidation(function (payload) {
assert.equal(payload.method, 'eth_getTransactionReceipt');
Expand Down Expand Up @@ -331,7 +347,15 @@ describe(method, function () {
assert.deepEqual(payload.params, test.formattedArgs2 || []);
});
}


if (test.call3) {
provider.injectResult(clone(test.result3));
provider.injectValidation(function (payload) {
assert.equal(payload.jsonrpc, '2.0');
assert.equal(payload.method, test.call3);
assert.deepEqual(payload.params, test.formattedArgs3 || []);
});
}

provider.injectResult(null);
provider.injectValidation(function (payload) {
Expand Down
16 changes: 16 additions & 0 deletions test/helpers/test.method.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,14 @@ var runTests = function (obj, method, tests) {
});
}

if (test.call3) {
provider.injectResult(clone(test.result3));
provider.injectValidation(function (payload) {
assert.equal(payload.jsonrpc, '2.0');
assert.equal(payload.method, test.call3);
assert.deepEqual(payload.params, test.formattedArgs3 || []);
});
}

// if notification its sendTransaction, which needs two more results, subscription and receipt
if(test.notification) {
Expand Down Expand Up @@ -198,6 +206,14 @@ var runTests = function (obj, method, tests) {
});
}

if (test.call3) {
provider.injectResult(clone(test.result3));
provider.injectValidation(function (payload) {
assert.equal(payload.jsonrpc, '2.0');
assert.equal(payload.method, test.call3);
assert.deepEqual(payload.params, test.formattedArgs3 || []);
});
}

var args = clone(test.args);

Expand Down
Loading