Skip to content

Commit fdbe957

Browse files
authored
Merge pull request #1174 from JoinColony/maint/gas-prices
Type 2 transactions for miner / mtx broadcaster
2 parents 93b9573 + 100937e commit fdbe957

10 files changed

Lines changed: 189 additions & 126 deletions

File tree

package-lock.json

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/metatransaction-broadcaster/Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ COPY ./packages ./packages
33
COPY ./package.json ./
44
COPY ./package-lock.json ./
55
COPY ./build ./build
6-
RUN npm i
6+
RUN npm ci
77
RUN cd ./packages/metatransaction-broadcaster/ && npm i
88
RUN cd ./packages/package-utils/ && npm i
99
EXPOSE 3000

packages/metatransaction-broadcaster/MetatransactionBroadcaster.js

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ const sqlite = require("sqlite");
44
const sqlite3 = require("sqlite3");
55
const queue = require("express-queue");
66
const NonceManager = require("./ExtendedNonceManager");
7-
const { colonyIOCors, ConsoleAdapter, updateGasEstimate } = require("../package-utils");
7+
const { colonyIOCors, ConsoleAdapter, getFeeData } = require("../package-utils");
88

99
const ETHEREUM_BRIDGE_ADDRESS = "0x75Df5AF045d91108662D8080fD1FEFAd6aA0bb59";
1010
const BINANCE_BRIDGE_ADDRESS = "0x162E898bD0aacB578C8D5F8d6ca588c13d2A383F";
@@ -81,7 +81,7 @@ class MetatransactionBroadcaster {
8181
const colonyNetworkDef = await this.loader.load({ contractName: "IColonyNetwork" }, { abi: true, address: false });
8282
this.colonyNetwork = new ethers.Contract(colonyNetworkAddress, colonyNetworkDef.abi, this.wallet);
8383

84-
this.gasPrice = await updateGasEstimate("safeLow", this.chainId, this.adapter);
84+
this.feeData = await getFeeData("safeLow", this.chainId, this.adapter, this.provider);
8585
this.tokenLockingAddress = await this.colonyNetwork.getTokenLocking();
8686

8787
this.metaTxDef = await this.loader.load({ contractName: "IBasicMetaTransaction" }, { abi: true, address: false });
@@ -336,6 +336,10 @@ class MetatransactionBroadcaster {
336336

337337
try {
338338
gasEstimate = await estimateGas(...args);
339+
if (ethers.BigNumber.from(args[args.length - 1].gasLimit).gt(gasEstimate.mul(11).div(10))) {
340+
// eslint-disable-next-line
341+
args[args.length - 1].gasLimit = gasEstimate.mul(11).div(10);
342+
}
339343
} catch (err) {
340344
let reason;
341345
try {
@@ -441,14 +445,14 @@ class MetatransactionBroadcaster {
441445
try {
442446
const { target, userAddress, payload, r, s, v } = req.body;
443447
const contract = new ethers.Contract(target, this.metaTxDef.abi, this.nonceManager);
444-
this.gasPrice = await updateGasEstimate("safeLow", this.chainId, this.adapter);
448+
this.feeData = await getFeeData("safeLow", this.chainId, this.adapter, this.provider);
445449
return this.processTransactionLogic(req, res, contract.estimateGas.executeMetaTransaction, contract.executeMetaTransaction, [
446450
userAddress,
447451
payload,
448452
r,
449453
s,
450454
v,
451-
{ gasPrice: this.gasPrice, gasLimit: this.gasLimit },
455+
{ ...this.feeData, gasLimit: this.gasLimit },
452456
]);
453457
} catch (err) {
454458
return res.status(500).send({
@@ -462,7 +466,7 @@ class MetatransactionBroadcaster {
462466
try {
463467
const { target, owner, spender, value, deadline, r, s, v } = req.body;
464468
const contract = new ethers.Contract(target, this.metaTxTokenDef.abi, this.nonceManager);
465-
this.gasPrice = await updateGasEstimate("safeLow", this.chainId, this.adapter);
469+
this.feeData = await getFeeData("safeLow", this.chainId, this.adapter, this.provider);
466470
return this.processTransactionLogic(req, res, contract.estimateGas.permit, contract.permit, [
467471
owner,
468472
spender,
@@ -471,7 +475,7 @@ class MetatransactionBroadcaster {
471475
v,
472476
r,
473477
s,
474-
{ gasPrice: this.gasPrice, gasLimit: this.gasLimit },
478+
{ ...this.feeData, gasLimit: this.gasLimit },
475479
]);
476480
} catch (err) {
477481
return res.status(500).send({
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
const ethers = require("ethers");
2+
const axios = require("axios");
3+
4+
/**
5+
* Update the gas estimate
6+
* @param {string} Transaction speed (fastest, fast, safeLow)
7+
* @param {number} Chain ID
8+
* @param {object} Adapter
9+
* @param {object} Provider
10+
* @return {Promise}
11+
*/
12+
const getFeeData = async function (_type, chainId, adapter, provider) {
13+
let defaultGasPrice;
14+
let factor;
15+
let feeData;
16+
17+
let type = _type;
18+
const options = {
19+
headers: {
20+
"User-Agent": "Request-Promise",
21+
},
22+
json: true, // Automatically parses the JSON string in the response
23+
};
24+
25+
if (chainId === 100) {
26+
options.url = "https://blockscout.com/xdai/mainnet/api/v1/gas-price-oracle";
27+
defaultGasPrice = ethers.BigNumber.from(10000000000);
28+
factor = 1;
29+
// This oracle presents the information slightly differently from ethgasstation.
30+
if (_type === "safeLow") {
31+
type = "slow";
32+
}
33+
} else if (chainId === 1) {
34+
options.url = "https://ethgasstation.info/json/ethgasAPI.json";
35+
defaultGasPrice = ethers.BigNumber.from(10000000000);
36+
factor = 10;
37+
} else {
38+
// We don't have an oracle, so just use the provided fee data
39+
adapter.log(`During gas estimation: unknown chainid ${chainId}`);
40+
feeData = await provider.getFeeData();
41+
delete feeData.lastBaseFeePerGas;
42+
if (feeData.maxFeePerGas) {
43+
delete feeData.gasPrice;
44+
}
45+
return feeData;
46+
}
47+
48+
try {
49+
feeData = await provider.getFeeData();
50+
delete feeData.lastBaseFeePerGas;
51+
if (feeData.maxFeePerGas) {
52+
delete feeData.gasPrice;
53+
}
54+
// Update gas prices from whichever oracle
55+
try {
56+
const request = await axios.request(options);
57+
const gasEstimates = request.data;
58+
59+
if (feeData.maxFeePerGas) {
60+
// Update the EIP1559 fee data based on the type
61+
const ratio = gasEstimates[type] / gasEstimates.average;
62+
// Increase the priority fee by this ratio
63+
const newMaxPriorityFeePerGas = ethers.BigNumber.from(Math.floor(feeData.maxPriorityFeePerGas * 1000))
64+
.mul(Math.floor(ratio * 1000))
65+
.div(1000 * 1000);
66+
// Increase the max fee per gas by the same amount (not the same ratio)
67+
feeData.maxFeePerGas = feeData.maxFeePerGas.add(newMaxPriorityFeePerGas).sub(feeData.maxPriorityFeePerGas);
68+
feeData.maxPriorityFeePerGas = newMaxPriorityFeePerGas;
69+
return feeData;
70+
}
71+
72+
// If we get here, chain is not EIP1559, so just update gasPrice
73+
if (gasEstimates[type]) {
74+
feeData.gasPrice = ethers.BigNumber.from(gasEstimates[type] * 1e9).div(factor);
75+
} else {
76+
feeData.gasPrice = defaultGasPrice;
77+
}
78+
} catch (err) {
79+
adapter.error(`Error during gas estimation: ${err}`);
80+
adapter.error(`Using default fee data from node`);
81+
}
82+
} catch (err) {
83+
adapter.error(`Error getting fee data from provider: ${err}`);
84+
adapter.error(`Using default static gas fee. Hopefully it's not too low...`);
85+
feeData = { gasPrice: defaultGasPrice };
86+
}
87+
return feeData;
88+
};
89+
90+
module.exports = getFeeData;

packages/package-utils/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
exports.colonyIOCors = require("./colonyIOCors");
2-
exports.updateGasEstimate = require("./updateGasEstimate");
2+
exports.getFeeData = require("./getFeeData");
33
exports.DiscordAdapter = require("./adapters/discord");
44
exports.SlackAdapter = require("./adapters/slack");
55
exports.ConsoleAdapter = require("./adapters/console");

packages/package-utils/updateGasEstimate.js

Lines changed: 0 additions & 55 deletions
This file was deleted.

0 commit comments

Comments
 (0)