From 0fb6b18b16f0d2f608059b15303ad3f10bbd351c Mon Sep 17 00:00:00 2001 From: Kevin Weaver Date: Wed, 5 Jan 2022 16:54:04 -0500 Subject: [PATCH 1/4] Add support for Arbitrum gas fee calculations --- packages/interface-adapter/lib/adapter/web3/index.ts | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/packages/interface-adapter/lib/adapter/web3/index.ts b/packages/interface-adapter/lib/adapter/web3/index.ts index 6ce0fa34934..1daac2e9305 100644 --- a/packages/interface-adapter/lib/adapter/web3/index.ts +++ b/packages/interface-adapter/lib/adapter/web3/index.ts @@ -79,7 +79,17 @@ export class Web3InterfaceAdapter implements InterfaceAdapter { const gasPrice = new BN(tx.gasPrice); const gas = new BN(receipt.gasUsed); const value = new BN(tx.value); - const cost = gasPrice.mul(gas).add(value); + + // Arbitrum fees exist in their "feeStats" attribute: https://developer.offchainlabs.com/docs/differences_overview#transaction-receipts + var cost = new BN(0); + if("feeStats" in receipt && "paid" in receipt["feeStats"]){ + // If the receipt includes Arbitrum's "feeStats", cost == the sum of its values. + cost = new BN(Object.values(receipt["feeStats"]["paid"]).reduce((sum, value) => sum + value)); + } else { + cost = new BN(gasPrice.mul(gas).add(value)); + } + // TODO - ^this new cost calculation complexity seems a bit much for an "InterfaceAdapter". + // I'm leaning toward creating a new CostCalculator object for this. return { timestamp: block.timestamp, From 7368423e11729cc98ed4eeb36d90b5fcd23126e4 Mon Sep 17 00:00:00 2001 From: Kevin Weaver Date: Thu, 6 Jan 2022 13:39:13 -0500 Subject: [PATCH 2/4] Check effectiveGasPrice and if it doesn't exist, fall back to gasPrice --- .../interface-adapter/lib/adapter/web3/index.ts | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/packages/interface-adapter/lib/adapter/web3/index.ts b/packages/interface-adapter/lib/adapter/web3/index.ts index 1daac2e9305..aff870f45bf 100644 --- a/packages/interface-adapter/lib/adapter/web3/index.ts +++ b/packages/interface-adapter/lib/adapter/web3/index.ts @@ -76,20 +76,13 @@ export class Web3InterfaceAdapter implements InterfaceAdapter { if (!block) return null; const balance = await this.getBalance(tx.from); - const gasPrice = new BN(tx.gasPrice); + // gasPrice has been deprecated in favor of effectiveGasPrice + // via https://github.com/ethereum/execution-specs/pull/251 + const gasPrice = new BN(receipt.effectiveGasPrice || tx.gasPrice); const gas = new BN(receipt.gasUsed); const value = new BN(tx.value); - // Arbitrum fees exist in their "feeStats" attribute: https://developer.offchainlabs.com/docs/differences_overview#transaction-receipts - var cost = new BN(0); - if("feeStats" in receipt && "paid" in receipt["feeStats"]){ - // If the receipt includes Arbitrum's "feeStats", cost == the sum of its values. - cost = new BN(Object.values(receipt["feeStats"]["paid"]).reduce((sum, value) => sum + value)); - } else { - cost = new BN(gasPrice.mul(gas).add(value)); - } - // TODO - ^this new cost calculation complexity seems a bit much for an "InterfaceAdapter". - // I'm leaning toward creating a new CostCalculator object for this. + const cost = gasPrice.mul(gas).add(value); return { timestamp: block.timestamp, From 03179897d29832627db14fef167b20c5dfefcb66 Mon Sep 17 00:00:00 2001 From: Kevin Weaver Date: Mon, 10 Jan 2022 19:06:46 -0500 Subject: [PATCH 3/4] Add spec comparing report.gasPrice to effectiveGasPrice --- .../test/getTransactionReport.test.ts | 60 +++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 packages/interface-adapter/test/getTransactionReport.test.ts diff --git a/packages/interface-adapter/test/getTransactionReport.test.ts b/packages/interface-adapter/test/getTransactionReport.test.ts new file mode 100644 index 00000000000..676ddddee9b --- /dev/null +++ b/packages/interface-adapter/test/getTransactionReport.test.ts @@ -0,0 +1,60 @@ +import { describe, it } from "mocha"; +import assert from "assert"; + +import { Server } from "http"; +import BN from "bn.js"; + +import Web3 from "web3"; +import Ganache from "ganache-core"; + +import { createInterfaceAdapter } from "../lib"; +import { + InterfaceAdapter, + Provider, + TransactionReceipt +} from "../lib/adapter/types"; + +const port = 12345; + +async function prepareGanache(): Promise<{ + server: Server; + interfaceAdapter: InterfaceAdapter; +}> { + return new Promise((resolve, reject) => { + const server = Ganache.server(); + server.listen(port, () => { + const interfaceAdapter = createInterfaceAdapter({ + provider: new Web3.providers.HttpProvider(`http://127.0.0.1:${port}`) + }); + resolve({ + server, + interfaceAdapter + }); + }); + }); +} + +describe("getTransactionReport", function () { + let provider: any; + let web3: Web3; + + before("Create Provider", async function () { + provider = Ganache.provider({ seed: "decoder", gasLimit: 7000000 }); + web3 = new Web3(provider); + }); + + it("calculates cost given an effectiveGasPrice", async function () { + const preparedGanache = await prepareGanache(); + const accounts = await web3.eth.getAccounts(); + const receipt = await web3.eth.sendTransaction({ + from: accounts[0], + to: accounts[1] + }); + const report = await preparedGanache.interfaceAdapter.getTransactionCostReport( + receipt + ); + console.log("report", report); + assert.strictEqual(report.gasPrice, receipt.effectiveGasPrice); + await preparedGanache.server.close(); + }); +}); From 73e6269f16214708869d29fe5c397472e7e4af18 Mon Sep 17 00:00:00 2001 From: Kevin Weaver Date: Tue, 10 May 2022 13:56:03 -0700 Subject: [PATCH 4/4] Add note about Arbitrum effectiveGasPrice support --- packages/interface-adapter/lib/adapter/web3/index.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/interface-adapter/lib/adapter/web3/index.ts b/packages/interface-adapter/lib/adapter/web3/index.ts index aff870f45bf..7f756c507f7 100644 --- a/packages/interface-adapter/lib/adapter/web3/index.ts +++ b/packages/interface-adapter/lib/adapter/web3/index.ts @@ -69,7 +69,9 @@ export class Web3InterfaceAdapter implements InterfaceAdapter { return this.web3.eth.getBlockNumber(); } - public async getTransactionCostReport(receipt: TransactionReceipt): Promise { + public async getTransactionCostReport( + receipt: TransactionReceipt + ): Promise { const tx = await this.getTransaction(receipt.transactionHash); const block = await this.getBlock(receipt.blockNumber); @@ -78,6 +80,8 @@ export class Web3InterfaceAdapter implements InterfaceAdapter { const balance = await this.getBalance(tx.from); // gasPrice has been deprecated in favor of effectiveGasPrice // via https://github.com/ethereum/execution-specs/pull/251 + // Note: this incidentally conforms to Arbitrum as well + // via https://github.com/trufflesuite/truffle/issues/4559 const gasPrice = new BN(receipt.effectiveGasPrice || tx.gasPrice); const gas = new BN(receipt.gasUsed); const value = new BN(tx.value);