|
| 1 | +--- |
| 2 | +title: Estimating the cost of interop messages |
| 3 | +description: Estimate the gas cost of Superchain interop messages. |
| 4 | +lang: en-US |
| 5 | +content_type: guide |
| 6 | +topic: interop-gas-estimate |
| 7 | +personas: |
| 8 | + - protocol-developer |
| 9 | + - app-developer |
| 10 | +categories: |
| 11 | + - interoperability |
| 12 | + - cross-chain-messaging |
| 13 | + - superchain |
| 14 | + - message-passing |
| 15 | + - gas-cost |
| 16 | +is_imported_content: 'false' |
| 17 | +--- |
| 18 | + |
| 19 | +import { Callout } from 'nextra/components' |
| 20 | +import { InteropCallout } from '@/components/WipCallout' |
| 21 | + |
| 22 | +<InteropCallout /> |
| 23 | + |
| 24 | +# Estimating the cost of interop messages |
| 25 | + |
| 26 | +<Callout type="info"> |
| 27 | +As of May 2025, the cost of 100 interop messages is just a few cents. |
| 28 | +Unless OP Stack transaction costs increase significantly, interop costs should not be a primary consideration in your implementation decisions. |
| 29 | + |
| 30 | +To see the current cost of gas, go to a [block explorer](https://optimism.blockscout.com/) and look at a recent transaction. |
| 31 | +</Callout> |
| 32 | + |
| 33 | +There are several factors that determine the cost of an [interop transaction](/interop/message-passing): |
| 34 | + |
| 35 | +* How you pass the message. |
| 36 | + You can either use [`CrossL2Inbox`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L2/CrossL2Inbox.sol) directly, or use the cross domain messenger, [`L2ToL2CrossDomainMessenger`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L2/L2ToL2CrossDomainMessenger.sol), which uses `CrossL2Inbox` internally. |
| 37 | +* The transaction type. |
| 38 | + Every interop message has two transactions, an [initiating message](/interop/message-passing#initiating-message) in a transaction to the source chain, and an [executing message](/interop/message-passing#executing-message) in the destination chain. |
| 39 | + |
| 40 | +## CrossL2Inbox |
| 41 | + |
| 42 | +This is the low level protocol used by all interop protocols, including `L2ToL2CrossDomainMessenger`. |
| 43 | + |
| 44 | +### Initiating message |
| 45 | + |
| 46 | +The initiating message is any log entry. |
| 47 | +A log entry emitted by Solidity code contains 1-4 topics (t) and unlimited unstructured data bytes (n). |
| 48 | +The gas cost is calculated as [375(t+1)+8n](https://www.evm.codes/?fork=cancun#a1). |
| 49 | + |
| 50 | +### Executing message |
| 51 | + |
| 52 | +The executing message cost has several components: |
| 53 | + |
| 54 | +1. The cost of posting the transaction. |
| 55 | +2. The cost of hashing the message. |
| 56 | +3. The cost of `CrossL2Inbox.validateMessage`. |
| 57 | +4. The cost of using the message. |
| 58 | + |
| 59 | +The first and second components depend on the log entry. |
| 60 | +`CrossL2Inbox.validateMessage` only requires a 32 byte hash of the log entry, but actually using it typically requires the information that has been hashed. |
| 61 | + |
| 62 | +Additionally, you must provide the `CrossL2Inbox` with the information needed to locate the log entry. |
| 63 | +This information is encoded in a [five-member structure](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L2/CrossL2Inbox.sol#L7-L19) that requires 160 bytes (32 bytes × 5 members). |
| 64 | +Lastly, you need to call a function which requires a 4-byte selector. |
| 65 | + |
| 66 | +Therefore, the total bytes required is: **164 + 32t + n** |
| 67 | + |
| 68 | +Where: |
| 69 | +* `164` = base overhead (160 bytes for the structure + 4 bytes for the function selector) |
| 70 | +* `t` = number of topics in the log entry |
| 71 | +* `n` = number of data bytes in the log entry |
| 72 | + |
| 73 | +Every transaction posted costs at least *21,000* gas. |
| 74 | +The hashing operation costs approximately [*30+0.2×\<number of bytes>*](https://www.evm.codes/?fork=cancun#20), which is negligible by comparison. |
| 75 | +We can usually ignore the [memory expansion cost](https://www.evm.codes/about#memoryexpansion), unless the validating contract uses a really large amount of memory. |
| 76 | + |
| 77 | +The cost of using the message is beyond the scope here, because it depends on your application. |
| 78 | + |
| 79 | +The main cost drivers are the 21,000 gas transaction cost plus the cost of posting a *164+32t+n* byte transaction. |
| 80 | + |
| 81 | +## Cross domain messenger |
| 82 | + |
| 83 | +This higher level protocol adds some expenses, mostly because replay protection requires storage, and [writing to storage](https://www.evm.codes/?fork=cancun#55) is a relatively expensive operation. |
| 84 | + |
| 85 | +### Initiating message |
| 86 | + |
| 87 | +The initiating message is sent by [`L2ToL2CrossDomainMessenger.sendMessage`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L2/L2ToL2CrossDomainMessenger.sol#L128-L161). This function writes to storage twice. |
| 88 | + |
| 89 | +It writes to [specify that the hash has a sent message](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L2/L2ToL2CrossDomainMessenger.sol#L157). |
| 90 | +This would typically be written to previously empty storage, so the cost is *22,100* gas. |
| 91 | + |
| 92 | +Then it [increments the nonce value](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L2/L2ToL2CrossDomainMessenger.sol#L158). |
| 93 | +Overwriting previously used storage (which means storage where the present value is *not* zero) only costs *5,000* gas. |
| 94 | + |
| 95 | +Hence, the gas cost for creating an initiating message is approximately *27,100* gas, plus minor overhead for log emission and contract operations. |
| 96 | +Note that this estimate excludes the 21,000 gas base transaction cost, which applies to all transactions. |
| 97 | + |
| 98 | +### Executing message |
| 99 | + |
| 100 | +If autorelay is turned on in a blockchain, then you don't care about the cost of the executing message. |
| 101 | +The chain operator will bear the cost. |
| 102 | + |
| 103 | +If autorelay is not turned on, the executing message is a call to [`L2ToL2CrossDomainMessenger.relayMessage`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L2/L2ToL2CrossDomainMessenger.sol#L197-L256). |
| 104 | +The only storage operation here is [noting the hash has been used for a message already](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L2/L2ToL2CrossDomainMessenger.sol#L241). |
| 105 | +This is previously unwritten storage, so we can expect to pay the full *22,100* in gas. |
| 106 | +Plus, of course, the *21,000* that any transaction costs. |
| 107 | +All the other gas costs are negligible. |
| 108 | + |
| 109 | +## Conclusion |
| 110 | + |
| 111 | +Unless the message is *extremely* long, the cost of an interop message, taking both sides together, is unlikely to exceed *100,000* gas. |
| 112 | +At the time of writing, each gas unit costs approximately `$3×10^-9`, so it would take about thirty messages to add up to a full cent. |
| 113 | + |
| 114 | +## Next steps |
| 115 | + |
| 116 | +* Build a [revolutionary app](/app-developers/get-started) that uses multiple blockchains within the Superchain |
| 117 | +* Deploy a [SuperchainERC20](/interop/tutorials/deploy-superchain-erc20) to the Superchain |
| 118 | +* Learn [how messages get from one chain to another chain](/interop/message-passing) |
| 119 | +* Watch [this video](https://www.youtube.com/watch?v=FKc5RgjtGes), which gives an overview of Superchain interoperability. |
0 commit comments