Skip to main content

Arbitrum/Ethereum Differences

Arbitrum is designed to be as compatible and consistent with Ethereum as possible, from its high-level RPCs to its low-level bytecode and everything in between. Dapp developers with experience building on Ethereum will likely find that little-to-no new L2-specific knowledge is required to build on Arbitrum.

This document presents an overview of some of the minor differences, perks, and gotchas that devs are advised to be aware of.

Block and Transaction Properties

Blocks and Time

Time in L2 is tricky; the timing assumptions one is used to making about L1 blocks don't exactly carry over into the timing of Arbitrum blocks. For details, see Block Numbers and Time.

Block hashes and randomness

Arbitrum's L2 block hashes should not be relied on as a secure source of randomness (see 'blockhash(x);)

L1 Fees

The L2 fees an Arbitrum transaction pays essentially work identically to gas fees on Ethereum. Arbitrum transactions must also, however, pay an L1-fee component to cover the cost of their calldata. (See L1 pricing.)

L1 to L2 Messages

Arbitrum chains support arbitrary L1 to L2 message passing; developers using this functionality should familiarize themselves with how they work (see L1 to L2 Messaging). Of particular note:

  • The result of a successful initial/"auto"-execution of an L1 to L2 message will be an unsigned L2 transaction receipt.
  • The msg.sender of the L2 side of an L1 to L2 message will be not the initiating L1 address, but rather its address alias.
  • Using the special ethDeposit method will not result in an L2 contract's fallback function getting triggered.

Etc.

Precompiles

Arbitrum chains include a number of special precompiles not present on Ethereum; see Common Precompiles / All Precompiles.

Of particular note is the ArbAddressTable, which allows contracts to map addresses to integers, saving calldata / fees for addresses expected to be reused as parameters; see Arb Address Table tutorial for example usage.

Solidity

You can deploy Solidity contracts onto Arbitrum just like you do Ethereum; there are only a few minor differences in behavior. See Solidity Support for details.

JSON-RPC Comparisons

This section covers the differences in response body fields you'll find when using the Arbitrum JSON-RPC vs Ethereum mainnet.

info

Comprehensive documentation on all generally available JSON-RPC methods for Ethereum can be found at ethereum.org. As Arbitrum has go-ethereum at its core, most of the documented methods there can be used with no modifications.

eth_syncing RPC Method

Calling eth_syncing returns false if not synchronizing (just like on Ethereum). However, if the node is still syncing, eth_syncing returns an object with data about the synchronization status. The returned object is different from what one would get on Ethereum, see here for more details.

Blocks

When calling eth_getBlockByHash or eth_getBlockByNumber, Arbitrum includes a few additional fields and leverages some existing fields in different ways than mainnet Ethereum.

Additional Fields

  • l1BlockNumber: An approximate L1 block number that occurred before this L2 block. See Block Numbers and Time for more info.
  • sendCount: The number of L2-to-L1 messages since Nitro genesis
  • sendRoot: The Merkle root of the Outbox tree state

Existing Fields With Different Behavior

  • extraData: This field is equivalent to sendRoot
  • mixHash: First 8 bytes is equivalent to sendCount, second 8 bytes is equivalent to l1BlockNumber
  • difficulty: Fixed at 0x1
  • gasLimit: Value is fixed at 0x4000000000000, but it's important to note that Arbitrum currently has a 32M gas limit per block

See full list of mainnet block fields for additional reference.

Transactions

Transaction Types

In addition to the three transaction types currently supported on mainnet, Arbitrum adds additional types listed below and documented in full detail here.

On RPC calls that return transactions, such as eth_getTransactionByHash, the type field will reflect the custom codes where applicable.

  • 100 - ArbitrumDepositTxType: A deposit of ETH from L1 to L2 via the Arbitrum bridge.
  • 101 - ArbitrumUnsignedTxType: An L1 user can use to call an L2 contract via the bridge.
  • 102 - ArbitrumContractTxType: Allows an L1 contract to call an L2 contract method via the bridge.
  • 104 - ArbitrumRetryTxType: Used to redeem a retryable ticket on L2, which finalizes a retryable that failed to execute automatically (usually due to low gas).
  • 105 - ArbitrumSubmitRetryableTxType: Retryable tickets are submitted via the L1 bridge and allow arbitrary L1 to L2 messages to be created and executed on L2.
  • 106 - ArbitrumInternalTxType: Internal transactions created by the ArbOS itself for certain state updates, like L1 base fee and block number.

Additional Fields

  • requestId: Added to L1-to-L2 transactions to indicate position in the Inbox queue.

Existing Fields With Different Behavior

  • from: For L1-to-L2 related transactions, will be the aliased version of the L1's msg.sender. See L1 to L2 Messaging for more info.

See full list of mainnet transaction fields for additional reference.

Tx Receipts

Additional Fields

  • l1BlockNumber: The L1 block number that would be used for block.number calls.
  • gasUsedForL1: Amount of gas spent on L1 calldata in units of L2 gas.

See full list of mainnet transaction receipt fields for additional reference.