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 5 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)
130 changes: 116 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,19 +771,15 @@ Method.prototype.buildCall = function () {
};

// Send the actual transaction
if (isSendTx && !!payload.params[0] && typeof payload.params[0] === 'object' && typeof payload.params[0].gasPrice === 'undefined') {
if (isSendTx
&& !!payload.params[0]
&& typeof payload.params[0] === 'object'
spacesailor24 marked this conversation as resolved.
Show resolved Hide resolved
) {
if (typeof payload.params[0].type === 'undefined')
payload.params[0].type = _handleTxType(payload.params[0]);

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;
}
_handleTxPricing(method, payload.params[0]).then(txPricing => {
payload.params[0] = {...payload.params[0], ...txPricing};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it make more sense to move all this logic outside of the blocks?

Regardless of how its being sent, we should just update the TX accordingly

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think in this case, we only want to add gas pricing info to the payload object if the info is not already provided for specifically sendTxs, otherwise the code shouldn't be executed


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

sendRequest(payload, method);
});

})
} else {
if (isSendTx) {
setTimeout(() => {
Expand All @@ -819,6 +815,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
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