2

For the below Arbitrum transaction, Tenderly shows a "Total Gas" of ~205k and an "Actual Gas Used" of ~8000k. How can this difference be explained? How can the actual gas used be higher than the total gas?

https://dashboard.tenderly.co/tx/arbitrum-sepolia/0xc98beb10bbfa1d088e401f2136b88a2431871711f7556e7388f8074f579eda1e/gas-usage

enter image description here

2 Answers 2

2

It's calling "Total Gas" the gas spent by executing the transaction (opcode by opcode, same as mainnet), while "Actual Gas Used" includes also the gas spent to publish the calldata on L1.

Using the notation from here:

Gas Limit (G) = Gas used on L2 (L2G) + Extra Buffer for L1 cost (B)

G can be "Actual Gas Used" and L2G "Total Gas".

You can look at this page on the explorer to confirm it (look at "L1 Gas Used" and "L2 Gas Used"): https://sepolia.arbiscan.io/tx/0xc98beb10bbfa1d088e401f2136b88a2431871711f7556e7388f8074f579eda1e#txninfo

1
  • ideally, ternderly maybe should display it a bit more clearly
    – matorus
    Commented Oct 17 at 19:17
0

It seems like you are doing normal 1559 fee estimation for an L2 which doesn't really work. Here is a proof of concept on Arbitrum fee estimation:

import { NODE_INTERFACE_ADDRESS } from '@arbitrum/sdk/dist/lib/dataEntities/constants';
import { NodeInterface__factory } from '@arbitrum/sdk/dist/lib/abi/factories/NodeInterface__factory';
import { utils } from 'ethers';

// Instantiation of the NodeInterface object
    const nodeInterface = NodeInterface__factory.connect(NODE_INTERFACE_ADDRESS, this.rpc);

    const gasEstimateComponents = await nodeInterface.callStatic.gasEstimateComponents(to, false, utils.hexlify(data), {
      blockTag: 'latest'
    });

    // Getting useful values for calculating the formula
    const l1GasEstimated = gasEstimateComponents.gasEstimateForL1;
    const l2GasUsed = gasEstimateComponents.gasEstimate.sub(gasEstimateComponents.gasEstimateForL1);
    const l2EstimatedPrice = gasEstimateComponents.baseFee;
    const l1EstimatedPrice = gasEstimateComponents.l1BaseFeeEstimate.mul(16);

    console.log('gasEstimateComponents', gasEstimateComponents);
    console.log('l1GasEstimated', l1GasEstimated.toNumber());
    console.log('l2GasUsed', l2GasUsed.toNumber());
    console.log('l2EstimatedPrice', l2EstimatedPrice.toNumber());
    console.log('l1EstimatedPrice', l1EstimatedPrice.toNumber());
    // Calculating some extra values to be able to apply all variables of the formula
    // -------------------------------------------------------------------------------
    // NOTE: This one might be a bit confusing, but l1GasEstimated (B in the formula) is calculated based on l2 gas fees
    // const l1Cost = l1GasEstimated.mul(l2EstimatedPrice);
    // NOTE: This is similar to 140 + utils.hexDataLength(txData);
    // const l1Size = l1Cost.div(l1EstimatedPrice);

    // Getting the result of the formula
    // ---------------------------------
    // Setting the basic variables of the formula
    const P = l2EstimatedPrice;
    const L2G = l2GasUsed;
    const L1P = l1EstimatedPrice;
    const L1S = 0;

    // L1C (L1 Cost) = L1P * L1S
    const L1C = L1P.mul(L1S);

    // B (Extra Buffer) = L1C / P
    const B = L1C.div(P);

    // G (Gas Limit) = L2G + B
    const G = L2G.add(B);

    // TXFEES (Transaction fees) = P * G
    const TXFEES = P.mul(G);

    console.log('Gas estimation components');
    console.log('-------------------');
    console.log(`Full gas estimation = ${gasEstimateComponents.gasEstimate.toNumber()} units`);
    console.log(`L2 Gas (L2G) = ${L2G.toNumber()} units`);
    console.log(`L1 estimated Gas (L1G) = ${l1GasEstimated.toNumber()} units`);

    console.log(`P (L2 Gas Price) = ${utils.formatUnits(P, 'gwei')} gwei`);
    console.log(`L1P (L1 estimated calldata price per byte) = ${utils.formatUnits(L1P, 'gwei')} gwei`);
    console.log(`L1S (L1 Calldata size in bytes) = ${L1S} bytes`);

    console.log('-------------------');
    console.log(`Transaction estimated fees to pay == ${this.network.tokenToWei(utils.formatEther(TXFEES), 18)} ETH`);
    console.log(`Transaction estimated fees to pay unformatted = ${utils.formatEther(TXFEES)} ETH`);

    return { fee: `${utils.formatEther(TXFEES)}`, raw: { baseFee: l2EstimatedPrice, maxPriorityFee: 1 } };

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.