During last week’s Arbitrum Odyssey, Arbitrum One experienced record levels of traffic. Some discerning users noticed something curious: as the price of L2 gas increased, the amount of L2gas that a given transaction would use would actually decrease.
This, it turns out, is the system working as it’s supposed to, but to the uninitiated, can look a bit confusing.
If you understand what was said so far well enough to be properly confused, this post attempts to clear things up; if you’re too confused to even know what you should be confused about, you’re welcome to read on anyway! — though you might find useful these primers on Ethereum and Arbitrum gas. (And if you can already see exactly where this is going, you should probably apply for a position: https://offchainlabs.com/careers/)
The thing about paying fees on layer 2 is that in an economically designed system (like Arbitrum), you’re actually paying for two things at once: L1-native resources and L2-native resources. Arbitrum One being a Rollup, the L1 resources you’re paying for are essentially just Ethereum calldata; i.e., you pay the size in raw data of your transaction times the L2’s view of the L1 calldata price (roughly speaking). The L2 resources you need to pay for are whatever computation your transaction is doing in Arbitrum’s general-purpose VM — execution, writing to storage, etc. This value is the L2 gas price multiplied by the amount of ArbGas — Arbitrum’s base unit of computation — your transaction uses.The total L2 fee a transaction needs to pay to succeed is the sum of these two components.
…In a One-Dimensional World
The tricky bit is, although L2s like Arbitrum have fees that are inherently two dimensional, the current Ethereum ecosystem was built out primarily for an L1 whose fees can be represented one-dimensionally. This means that current infrastructure — wallets, developer libraries, etc. — assume transaction formats in which fees are the product of a single gas unit and a single gas price; when transacting on Arbitrum, we’re forced to cram both L1 and L2 dimensions into this restrictive format. So how do we do it?
How We Do It
So to recap, our restriction is that the total fee — which has to include both L1 and L2 costs — needs to be represented as the product of two values we’ll call “something like gas price” (P) and “something like gas limit” (G).
The value we use for P (as returned by Arbitrum’s estimate gas price RPC) is, in fact, just the L2 gas price (the estimate gas RPC adds a small percentage increase buffer; any excess gets refunded). G is where we account for the L1 dimension; calling Arbitrum’s estimate gas price RPC gives a value that represents the ArbGas used for L2 computation plus an additional buffer (B) such that P*G ends up being sufficient to cover the full transaction cost. In other words, we increase the “gas limit”-ish field such that the total amount paid at the given gas price is enough to cover both the L1 and L2 dimensions of the fee.
With a bit of algebra, we find this buffer B must equal (L1 calldata cost) / P.
So in sum, G, unpacks to:
L2 gas used + ( L1 calldata price * L1 calldata size) / (L2 gas price)
…of which the “L2 gas price” denominator (to return to the initial confusion) shows why all other values being equal, an increase in L2 gas price actually decreases the value of G.
Towards A 2-D Fee Standard
If this all seems inelegant and unlovely, we agree; we’re currently stuck working within the 1-D-fee infrastructure the ecosystem currently supports, but ideally, a multidimensional fee standard would be agreed upon and widely adapted; several proposals exist, and we have thoughts of our own. If you’re interested in helping coordinate around a new standard, do reach out / get involved in our research forum.