Overview
Deposited transactions, also known as deposits are transactions which are initiated on L1, and executed on L2. This document outlines a new transaction type for deposits. It also describes how deposits are initiated on L1, along with the authorization and validation conditions on L2. Vocabulary note: deposited transaction refers specifically to an L2 transaction, while deposit can refer to the transaction at various stages (for instance when it is deposited on L1).The Deposited Transaction Type
Deposited transactions have the following notable distinctions from existing transaction types:- They are derived from Layer 1 blocks, and must be included as part of the protocol.
- They do not include signature validation (see User-Deposited Transactions for the rationale).
- They buy their L2 gas on L1 and, as such, the L2 gas is not refundable.
0x7E to represent a deposit transaction.
A deposit has the following fields
(rlp encoded in the order they appear here):
bytes32 sourceHash: the source-hash, uniquely identifies the origin of the deposit.address from: The address of the sender account.address to: The address of the recipient account, or the null (zero-length) address if the deposited transaction is a contract creation.uint256 mint: The ETH value to mint on L2.uint256 value: The ETH value to send to the recipient account.uint64 gas: The gas limit for the L2 transaction.bool isSystemTx: If true, the transaction does not interact with the L2 block gas pool.- This value is disabled and MUST be
false.
- This value is disabled and MUST be
bytes data: The calldata.
- Does not include a
nonce, since it is identified by thesourceHash. API responses still include anonceattribute, set to thedepositNoncevalue from the corresponding transaction receipt. - Does not include signature information, and makes the
fromaddress explicit. API responses contain zeroed signaturev,r,svalues for backwards compatibility. - Includes new
sourceHash,from,mint, andisSystemTxattributes. API responses contain these as additional fields.
0x7E because transaction type identifiers are currently allowed to go up to 0x7F.
Picking a high identifier minimizes the risk that the identifier will be used by another
transaction type on the L1 chain in the future. We don’t pick 0x7F itself in case it becomes used
for a variable-length encoding scheme.
Source hash computation
ThesourceHash of a deposit transaction is computed based on the origin:
- User-deposited:
keccak256(bytes32(uint256(0)), keccak256(l1BlockHash, bytes32(uint256(l1LogIndex)))). Where thel1BlockHash, andl1LogIndexall refer to the inclusion of the deposit log event on L1.l1LogIndexis the index of the deposit event log in the combined list of log events of the block. - L1 attributes deposited:
keccak256(bytes32(uint256(1)), keccak256(l1BlockHash, bytes32(uint256(seqNumber)))). Wherel1BlockHashrefers to the L1 block hash of which the info attributes are deposited. AndseqNumber = l2BlockNum - l2EpochStartBlockNum, wherel2BlockNumis the L2 block number of the inclusion of the deposit tx in L2, andl2EpochStartBlockNumis the L2 block number of the first L2 block in the epoch. - Upgrade-deposited:
keccak256(bytes32(uint256(2)), keccak256(intent)). Whereintentis a UTF-8 byte string, identifying the upgrade intent.
sourceHash in a deposit, two different deposited transactions could have the same exact hash.
The outer keccak256 hashes the actual uniquely identifying information with a domain,
to avoid collisions between different types of sources.
The Interop derivation spec introduces two additional kinds of system deposits,
with domains 3 and 4.
We do not use the sender’s nonce to ensure uniqueness because this would require an extra L2 EVM state read from the
execution engine during block-derivation.
Kinds of Deposited Transactions
Although we define only one new transaction type, we can distinguish between two kinds of deposited transactions, based on their positioning in the L2 block:- The first transaction MUST be a L1 attributes deposited transaction, followed by
- an array of zero-or-more user-deposited transactions
submitted to the deposit feed contract on L1 (called
OptimismPortal). User-deposited transactions are only present in the first block of a L2 epoch.
Validation and Authorization of Deposited Transactions
As noted above, the deposited transaction type does not include a signature for validation. Rather, authorization is handled by the L2 chain derivation process, which when correctly applied will only derive transactions with afrom address attested to by the logs of the L1
deposit contract.
Execution
In order to execute a deposited transaction: First, the balance of thefrom account MUST be increased by the amount of mint.
This is unconditional, and does not revert on deposit failure.
Then, the execution environment for a deposited transaction is initialized based on the
transaction’s attributes, in exactly the same manner as it would be for an EIP-155 transaction.
The deposit transaction is processed exactly like a type-2 (EIP-1559) transaction, with the exception of:
- No fee fields are verified: the deposit does not have any, as it pays for gas on L1.
- No
noncefield is verified: the deposit does not have any, it’s uniquely identified by itssourceHash. - No access-list is processed: the deposit has no access-list, and it is thus processed as if the access-list is empty.
- No check if
fromis an Externally Owner Account (EOA): the deposit is ensured not to be an EOA through L1 address masking, this may change in future L1 contract-deployments to e.g. enable an account-abstraction like mechanism. - No gas is refunded as ETH. (either by not refunding or utilizing the fact the gas-price of the deposit is
0) - No transaction priority fee is charged. No payment is made to the block fee-recipient.
- No L1-cost fee is charged, as deposits are derived from L1 and do not have to be submitted as data back to it.
- No base fee is charged. The total base fee accounting does not change.
- It is transformed into an EVM-error:
i.e. the deposit will always be included, but its receipt will indicate a failure
if it runs into a non-EVM state-transition error, e.g. failure to transfer the specified
valueamount of ETH due to insufficient account-balance. - The world state is rolled back to the start of the EVM processing, after the minting part of the deposit.
- The
nonceoffromin the world state is incremented by 1, making the error equivalent to a native EVM failure. Note that a previousnonceincrement may have happened during EVM processing, but this would be rolled back first.
depositNonce value, storing the nonce value of the from sender as registered before the EVM processing.
Note that the gas used as stated by the execution output is subtracted from the gas pool.
Note for application developers: because CALLER and ORIGIN are set to from, the
semantics of using the tx.origin == msg.sender check will not work to determine whether
or not a caller is an EOA during a deposit transaction. Instead, the check could only be useful for
identifying the first call in the L2 deposit transaction. However this check does still satisfy
the common case in which developers are using this check to ensure that the CALLER is unable to
execute code before and after the call.
Nonce Handling
Despite the lack of signature validation, we still increment the nonce of thefrom account when a
deposit transaction is executed. In the context of a deposit-only roll up, this is not necessary
for transaction ordering or replay prevention, however it maintains consistency with the use of
nonces during contract creation. It may also simplify integration with downstream
tooling (such as wallets and block explorers).
Deposit Receipt
Transaction receipts use standard typing as per EIP-2718. The Deposit transaction receipt type is equal to a regular receipt, but extended with an optionaldepositNonce field.
The RLP-encoded consensus-enforced fields are:
postStateOrStatus(standard): this contains the transaction status, see EIP-658.cumulativeGasUsed(standard): gas used in the block thus far, including this transaction.- The actual gas used is derived from the difference in
CumulativeGasUsedwith the previous transaction. - This accounts for the actual gas usage by the deposit, like regular transactions.
- The actual gas used is derived from the difference in
bloom(standard): bloom filter of the transaction logs.logs(standard): log events emitted by the EVM processing.depositNonce(unique extension): Optional field. The deposit transaction persists the nonce used during execution.depositNonceVersion(unique extension): Optional field. The value must be 1 if the field is present- Before Canyon, these
depositNonce&depositNonceVersionfields must always be omitted. - With Canyon, these
depositNonce&depositNonceVersionfields must always be included.
- Before Canyon, these
- The
depositNonceis included in the receipt JSON data in API responses - For contract-deployments (when
to == null), thedepositNoncehelps derive the correctcontractAddressmeta-data, instead of assuming the nonce was zero. - The
cumulativeGasUsedaccounts for the actual gas usage, as metered in the EVM processing.
L1 Attributes Deposited Transaction
An L1 attributes deposited transaction is a deposit transaction sent to the L1 attributes predeployed contract. This transaction MUST have the following values:fromis0xdeaddeaddeaddeaddeaddeaddeaddeaddead0001(the address of the L1 Attributes depositor account)tois0x4200000000000000000000000000000000000015(the address of the L1 attributes predeployed contract).mintis0valueis0gasLimitis set to1,000,000.isSystemTxis set tofalse.datais an encoded call to the L1 attributes predeployed contract that depends on the upgrades that are active (see below).
gasLimit, as it is considered part of state-transition processing.
L1 Attributes Deposited Transaction Calldata
L1 Attributes - Bedrock, Canyon, Delta
Thedata field of the L1 attributes deposited transaction is an ABI encoded call to the
setL1BlockValues() function with correct values associated with the corresponding L1 block
(cf. reference implementation).
Special Accounts on L2
The L1 attributes deposit transaction involves two special purpose accounts:- The L1 attributes depositor account
- The L1 attributes predeployed contract
L1 Attributes Depositor Account
The depositor account is an EOA with no known private key. It has the address0xdeaddeaddeaddeaddeaddeaddeaddeaddead0001. Its value is returned by the CALLER and ORIGIN
opcodes during execution of the L1 attributes deposited transaction.
L1 Attributes Predeployed Contract
A predeployed contract on L2 at address0x4200000000000000000000000000000000000015, which holds
certain block variables from the corresponding L1 block in storage, so that they may be accessed
during the execution of the subsequent deposited transactions.
The predeploy stores the following values:
- L1 block attributes:
number(uint64)timestamp(uint64)basefee(uint256)hash(bytes32)
sequenceNumber(uint64): This equals the L2 block number relative to the start of the epoch, i.e. the L2 block distance to the L2 block height that the L1 attributes last changed, and reset to 0 at the start of a new epoch.- System configurables tied to the L1 block, see System configuration specification:
batcherHash(bytes32): A versioned commitment to the batch-submitter(s) currently operating.overhead(uint256): The L1 fee overhead to apply to L1 cost computation of transactions in this L2 block.scalar(uint256): The L1 fee scalar to apply to L1 cost computation of transactions in this L2 block.
L1 Attributes Predeployed Contract: Reference Implementation
A reference implementation of the L1 Attributes predeploy contract can be found in L1Block.sol.User-Deposited Transactions
User-deposited transactions are deposited transactions generated by the L2 Chain Derivation process. The content of each user-deposited transaction are determined by the correspondingTransactionDeposited event emitted by the
deposit contract on L1.
fromis unchanged from the emitted value (though it may have been transformed to an alias inOptimismPortal, the deposit feed contract).tois any 20-byte address (including the zero address)- In case of a contract creation (cf.
isCreation), this address is set tonull.
- In case of a contract creation (cf.
mintis set to the emitted value.valueis set to the emitted value.gaslimitis unchanged from the emitted value. It must be at least 21000.isCreationis set totrueif the transaction is a contract creation,falseotherwise.datais unchanged from the emitted value. Depending on the value ofisCreationit is handled as either calldata or contract initialization code.isSystemTxis set by the rollup node for certain transactions that have unmetered execution. It isfalsefor user deposited transactions
Deposit Contract
The deposit contract is deployed to L1. Deposited transactions are derived from the values in theTransactionDeposited event(s) emitted by the deposit contract.
The deposit contract is responsible for maintaining the guaranteed gas market,
charging deposits for gas to be used on L2, and ensuring that the total amount of guaranteed
gas in a single L1 block does not exceed the L2 block gas limit.
The deposit contract handles two special cases:
- A contract creation deposit, which is indicated by setting the
isCreationflag totrue. In the event that thetoaddress is non-zero, the contract will revert. - A call from a contract account, in which case the
fromvalue is transformed to its L2 alias.
Address Aliasing
If the caller is a contract, the address will be transformed by adding0x1111000000000000000000000000000000001111 to it. The math is unchecked and done on a
Solidity uint160 so the value will overflow. This prevents attacks in which a
contract on L1 has the same address as a contract on L2 but doesn’t have the same code. We can safely ignore this
for EOAs because they’re guaranteed to have the same “code” (i.e. no code at all). This also makes
it possible for users to interact with contracts on L2 even when the Sequencer is down.
Deposit Contract Implementation: Optimism Portal
A reference implementation of the deposit contract can be found in OptimismPortal.sol.Guaranteed Gas Fee Market
Deposited transactions are transactions on L2 that are initiated on L1. The gas that they use on L2 is bought on L1 via a gas burn (or a direct payment in the future). We maintain a fee market and hard cap on the amount of gas provided to all deposits in a single L1 block. The gas provided to deposited transactions is sometimes called “guaranteed gas”. The gas provided to deposited transactions is unique in the regard that it is not refundable. It cannot be refunded as it is sometimes paid for with a gas burn and there may not be any ETH left to refund. The guaranteed gas is composed of a gas stipend, and of any guaranteed gas the user would like to purchase (on L1) on top of that. Guaranteed gas on L2 is bought in the following manner. An L2 gas price is calculated via an EIP-1559-style algorithm. The total amount of ETH required to buy that gas is then calculated as (guaranteed gas * L2 deposit base fee). The contract then accepts that amount of ETH (in a future
upgrade) or (only method right now), burns an amount of L1 gas that corresponds to the L2 cost (L2 cost / L1 base fee). The L2 gas price for guaranteed gas is not synchronized with the base fee on
L2 and will likely be different.
Gas Stipend
To offset the gas spent on the deposit event, we creditgas spent * L1 base fee ETH to the cost
of the L2 gas, where gas spent is the amount of L1 gas spent processing the deposit. If the ETH
value of this credit is greater than the ETH value of the requested guaranteed gas (requested guaranteed gas * L2 gas price), no L1 gas is burnt.
Default Values
| Variable | Value |
|---|---|
MAX_RESOURCE_LIMIT | 20,000,000 |
ELASTICITY_MULTIPLIER | 10 |
BASE_FEE_MAX_CHANGE_DENOMINATOR | 8 |
MINIMUM_BASE_FEE | 1 gwei |
MAXIMUM_BASE_FEE | type(uint128).max |
SYSTEM_TX_MAX_GAS | 1,000,000 |
TARGET_RESOURCE_LIMIT | MAX_RESOURCE_LIMIT / ELASTICITY_MULTIPLIER |
Limiting Guaranteed Gas
The total amount of guaranteed gas that can be bought in a single L1 block must be limited to prevent a denial of service attack against L2 as well as ensure the total amount of guaranteed gas stays below the L2 block gas limit. We set a guaranteed gas limit ofMAX_RESOURCE_LIMIT gas per L1 block and a target of
MAX_RESOURCE_LIMIT / ELASTICITY_MULTIPLIER gas per L1 block. These numbers enabled
occasional large transactions while staying within our target and maximum gas usage on L2.
Because the amount of guaranteed L2 gas that can be purchased in a single block is now limited,
we implement an EIP-1559-style fee market to reduce congestion on deposits. By setting the limit
at a multiple of the target, we enable deposits to temporarily use more L2 gas at a greater cost.
Rationale for burning L1 Gas
There must be a sybil resistance mechanism for usage of the network. If it is very cheap to get guaranteed gas on L2, then it would be possible to spam the network. Burning a dynamic amount of gas on L1 acts as a sybil resistance mechanism as it becomes more expensive with more demand. If we collect ETH directly to pay for L2 gas, every (indirect) caller of the deposit function will need to be marked with the payable selector. This won’t be possible for many existing projects. Unfortunately this is quite wasteful. As such, we will provide two options to buy L2 gas:- Burn L1 Gas
- Send ETH to the Optimism Portal (Not yet supported)