Celo L2 Specification

Table of Contents

This document describes the differences between the Celo L2 implementation and Optimism's OP Stack, on which it is based. Refer to the OP Stack specs for details on the unmodified OP Stack.

The L1→L2 migration changes page details the differences compared to the Celo L1 blockchain. The Celo L2 is a continuation of the L1 by using its state and providing a high level of compatibility with it.

Background

Since May 2024, the Celo Community has decided to transition from an L1 blockchain to a L2 solution using the OP Stack. This move, detailed and approved in CGP-133, aims to enhance scalability, security, and interoperability with Ethereum. The proposal aligns with Celo's mission to create a more accessible and inclusive financial system. By leveraging the OP Stack, Celo L2 will retain the benefits of the existing ecosystem while integrating with Ethereum's robust infrastructure, fostering greater innovation and user engagement.

New Features

Technical Differences

Celo core contracts

Table of Contents

To facilitate Celo features and governance, the Celo chain has a set of core contracts.

Contracts List

Dango

ContractProxy Address
Accounts0xed7f51A34B4e71fbE69B3091FcF879cD14bD73A9
Attestations0xAD5E5722427d79DFf28a4Ab30249729d1F8B4cc0
BlockchainParameters0xE5aCbb07b4Eed078e39D50F66bF0c80cF1b93abe
Celo Token (GoldToken)0xF194afDf50B03e69Bd7D057c1Aa9e10c9954E4C9
CeloDistributionSchedule0x78Af211Ad79bCE6BF636640CE8c2C2b29e02365A
DoubleSigningSlasher0x88A4c203C488E8277f583942672E1aF77e2B5040
DowntimeSlasher0xf2224c1d7b447D9A43a98CBD82FCCC0eF1c11CC5
Election0x1c3eDf937CFc2F6F51784D20DEB1af1F9a8655fA
EpochRewards0xB10Ee11244526b94879e1956745bA2E35AE2bA20
Escrow0xb07E10c5837c282209c6B9B3DE0eDBeF16319a37
Exchange0x17bc3304F94c85618c46d0888aA937148007bD3C
ExchangeBRL0xf391DcaF77360d39e566b93c8c0ceb7128fa1A08
ExchangeEUR0x997B494F17D3c49E66Fafb50F37A972d8Db9325B
FeeCurrencyDirectory0x71FFbD48E34bdD5a87c3c683E866dc63b8B2a685
FederatedAttestations0x70F9314aF173c246669cFb0EEe79F9Cfd9C34ee3
FeeHandler0xEAaFf71AB67B5d0eF34ba62Ea06Ac3d3E2dAAA38
Freezer0xfe0Ada6E9a7b782f55750428CC1d8428Cd83C3F1
GasPriceMinimum0xd0Bf87a5936ee17014a057143a494Dc5C5d51E5e
Governance0xAA963FC97281d9632d96700aB62A4D1340F9a28a
GrandaMento0xEcf09FCD57b0C8b1FD3DE92D59E234b88938485B
LockedGold0x6a4CC5693DC5BFA3799C699F3B941bA2Cb00c341
MentoFeeHandlerSeller0xae83C63B5FB50C353c8d23397bcC9dBf3a9837Ac
OdisPayments0x645170cdB6B5c1bc80847bb728dBa56C50a20a49
Random0xdd318EEF001BB0867Cd5c134496D6cF5Aa32311F
Registry0x000000000000000000000000000000000000ce10
Reserve0xa7ed835288Aa4524bB6C73DD23c0bF4315D9Fe3e
SortedOracles0xFdd8bD58115FfBf04e47411c1d228eCC45E93075
StableToken0x874069Fa1Eb16D44d622F2e0Ca25eeA172369bC1
StableTokenBRL0xE4D517785D091D3c54818832dB6094bcc2744545
StableTokenEUR0x10c892A6EC43a53E45D0B916B4b7D383B1b78C0F
TransferWhitelist0x52449A99e3455acB831C0D580dCDAc8B290d5182
UniswapFeeHandlerSeller0xc7b6E77C3702666DDa8EB5b7F30234B020788b21
Validators0x9acF2A99914E083aD0d610672E93d14b0736BBCc

ABIs

JSON ABI descriptions for all core contracts are available in the @celo/abi npm package.

Token Duality

Table of Contents

What is token duality?

Token duality means that the CELO token is both the native currency of the Celo blockchain as well as an ERC20 compatible token. This means CELO tokens can be moved both by doing a native transfer as well as ERC20 transfers and will show up in both in the native account balance and the ERC20 balance, no matter how they were transferred. In contrast to ETH/WETH, no token wrapping or unwrapping is necessary.

Implementation

The native transfers and balances behave exactly as on Ethereum and are stored in the same way. The CELO contract reads native balances and triggers native transfers via its ERC20 interface.

Reading balances via ERC20

The ERC20 token does not store the balances in the contract storage, it uses the native balance as the source of truth. The balanceOf function just passes through the native balance.

Transfers via ERC20

Similarly, the ERC20 transfer and transferFrom functions do not change the contract storage, but initiate a native transfer instead. Since there is no way to trigger native transfers from within a contract in Ethereum, Celo adds a transfer precompile for this purpose. This precompile can only be called by the CELO token.

The transfer precompile

The precompile directly manipulates the account balances in the EVM’s statedb. It checks the caller address to verify that it has been called by the CELO token.

Precompile address: 0xff - 2 == 253
Parameters (abi-encoded): address from, address to, uint256 value
Gas costs: 9000
No return value

Fee Abstraction: Paying Gas With ERC20 Tokens

Table of Contents

Fee Abstraction is a Celo feature that allows users to send transactions without spending any native CELO tokens. Instead, ERC20 tokens are used to pay for the transaction's gas cost.

As a User

Sending Fee Abstraction Transactions

To pay gas via Fee Abstraction, the gas token must be specified in a CIP-64 transaction. This tx type has an additional feeCurrency field that specifies which token is used for the maxFeePerGas and maxPriorityFeePerGas fields. See CIP-64 for details.

Celo will also soon support the CIP-66 tx type in addition to CIP-64.

Client library support is described in docs.celo.org.

JSON-RPC Changes

To make it easier to reliably send Fee Abstraction transactions, the JSON-RPC interface has been extended in two ways:

  • eth_estimateGas takes an optional feeCurrency parameter to get Fee Abstraction specific gas estimates (the gas price for the fee token transfers depends on the token)
  • eth_gasPrice and eth_maxPriorityFeePerGas take an optional feeCurrency parameter for getting CIP-64 gas prices.

The Fee Currency Directory

Only tokens that have been registered in the FeeCurrencyDirectory contract using Celo's governance process can be used for Fee Abstraction. The directory entry shows that the token is trustworthy and contains additional information about the token:

You can run the getCurrencies() method on the FeeCurrencyDirectory contract to get a list of all registered tokens and use getExchangeRate(token address) to fetch the current exchange rate for a token. The IOracle interface is only intended for parties providing Fee Abstraction tokens, not for users or client libraries.

Tokens using FeeCurrencyAdapter

Tokens with a low number of decimals (USDC and USDT) would cause problems during the gas calculation, because the cost per gas can only be accurately given in fractions and not integers. To avoid this issue, the tokens are not directly added to the FeeCurrencyDirectory. Instead, a FeeCurrencyAdapter contracts wraps these tokens, calculates the costs per gas in a higher accuracy and only converts it back to the lower accuracy once the total gas costs for a transaction is determined.

This only really impacts the user in a single way: Instead of using the USDC and USDT token addresses, you have to pass their FeeCurrencyAdapter addresses in the feeCurrency field for CIP-64 txs.

For Token Authors

Requirements for Registering a Fee Abstraction Token

To become registered as a Fee Abstraction currency, the following requirements have to be met:

  • Implement the IFeeCurrency interface
  • Ensure exchange rates are kept up to date in the oracle with the IOracle interface
  • Pass a Celo governance vote for the FeeCurrencyDirectory addition

The fee-currency-example repository contains the interface description and an example Fee Abstraction token implementation with tests.

Inside the Celo Blockchain

Exchange Rate Handling Inside the Blockchain Client

Before each block, the blockchain client reads the list of all registered Fee Abstraction tokens from the FeeCurrencyDirectory and fetches the currency exchange rate for each of them. If the Oracle for a token reverts or returns invalid exchange rates (numerator or denominator are zero), the token is treated as if it was not registered. Token registrations and exchange rates stay the same within a block and are only updated before the next block.

Transactions with unregistered feeCurrency values are not accepted into the tx pool and dropped from the pool if they have been previously accepted. The same is true if the maxFeePerGas falls below the current base fee.

Gas Calculation for Fee Abstraction Transactions

Ethereum transactions pay a fixed fee of 21000 gas ("intrinsic gas") in addition to the cost for executing the transaction. This is meant to cover the operating expenses during tx processing outside the actual tx execution, like debiting the gas cost from the tx sender's account, refunding the unused gas or transferring the base fee and tip to the respective receivers.

When using Fee Abstraction, the fees are transferred by executing functions on the respective token contract, which is computationally more expensive than native token transfers. The exact costs will vary by token and can change over time. Therefore, a token-specific intrinsic gas value is used for Fee Abstraction txs in addition to Ethereum's intrinsic gas. This value is stored in the FeeCurrencyDirectory contract and can be changed by Celo governance. It should be set to at least the maximum gas cost of executing all function calls for debiting and crediting fees for a single transaction.

Block Space Limits Per Fee Abstraction Token

As described above, Celo allows users to pay for gas using ERC20 tokens. There is a governable list of accepted tokens. However, the Celo blockchain client starting with version 1.8.1 implements a protective mechanism that allows validators to control the percentage of available block space used by transactions paid with an alternative fee currency (other than CELO) more precisely.

There are two new flags that control this behavior:

  1. celo.feecurrency.limits with a comma-separated currency_address_hash=limit mappings for currencies listed in the FeeCurrencyWhitelist contract, where limit represents the maximal fraction of the block gas limit as a float point number available for the given fee currency. The addresses are not expected to be checksummed.

    For example, 0x765DE816845861e75A25fCA122bb6898B8B1282a=0.1,0xD8763CBa276a3738E6DE85b4b3bF5FDed6D6cA73=0.05,0xEd6961928066D3238134933ee9cDD510Ff157a6e=0.

  2. celo.feecurrency.default - an overridable default value (initially set to 0.5) for currencies not listed in the limits map, meaning that if not specified otherwise, a transaction with a given fee currency can take up to 50% of the block space. CELO token doesn't have a limit.

Based on historical data, the following default configuration is proposed:

--celo.feecurrency.limits.default=0.5
--celo.feecurrency.limits="0x765DE816845861e75A25fCA122bb6898B8B1282a=0.9,0xD8763CBa276a3738E6DE85b4b3bF5FDed6D6cA73=0.5,0xe8537a3d056DA446677B9E9d6c5dB704EaAb4787=0.5"

It imposes the following limits:

  • cUSD up to 90%
  • cEUR up to 50%
  • cREAL up to 50%
  • any other token except CELO - 50%
  • CELO doesn't have a limit

Transaction Types On Celo L2

Table of Contents

Different categories of transaction types are relevant to Celo. Some are inherited from Ethereum, others were added to support Celo's Fee Abstraction feature, and some older ones have been superseded and are no longer supported. When developing new applications, please use the tx types marked as "recommended" below.

The docs.celo.org page about tx types contains additional information on how to handle different tx types, their differences and tooling support.

Ethereum Compatible Tx Types

To achieve its high level of Ethereum compatibility, Celo supports all Ethereum tx types relevant for an L2. The following transaction types can be used in exactly the same way as on Ethereum and don't require any changes to client libraries or other tooling.

The EIP-4844 tx type 3, which provides blobs for data availability on Ethereum, is not supported.

Celo-Specific Tx Types

The following tx types are an essential part of Celo's Fee Abstraction feature. For more details, read the respective CIPs, linked below, and the Fee Abstraction section.

  • CIP-64 (recommended), type 123
  • CIP-66 (coming soon), type 122

Older, Unsupported Tx Types

These tx types won't be accepted anymore, but transactions in blocks before the L2 migration can still contain transactions of these types.

  • CIP-42, type 124
  • Legacy Celo transaction, type 0, but with different fields than the Ethereum legacy tx

Details on Celo Legacy Transactions

For historic reasons, the Celo legacy txs are not prefixed with a tx type number, just like Ethereum legacy txs. To tell these two legacy tx types apart, you have to look at the tx content, which contains additional feeCurrency, gatewayFeeRecipient, and gatewayFee fields for Celo legacy txs:

RLP([nonce, gasPrice, gasLimit, feeCurrency, gatewayFeeRecipient, gatewayFee, recipient, amount, data, v, r, s])

There is no CIP number for this tx type because it was included in version 1 of the Celo blockchain and CIPs only describe changes introduced after that point in time.

Native Bridge

Table of Contents

With the L2 migration, the Celo blockchain gained a native bridge to Ethereum based on OP Stack's Standard Bridge. Specifically we use Custom Gas Token feature. This page describes the process of bridging assets between L1 and L2.

The Celo token now exists in both L1 and L2 versions. The L1 version is a standard ERC20 token with a total supply of 1 billion, fully minted to the OptimismPortal smart contract, which is part of the bridge (this setup allows any Celo token holder on L2 to bridge their tokens to L1). The L2 version is the native token on the L2 Celo chain, preserving the balances from the Celo L1 chain. Tokens that have not yet been minted on the Celo L1 chain, such as tokens for Community Fund, are now minted to the CeloDistributionSchedule, which manages further distribution.

Bridging CELO from L1 to L2

To deposit ERC20 Celo tokens onto the chain, users should use the OptimismPortalProxy.depositERC20Transaction method. Before depositing tokens with depositERC20Transaction, users must first call approve() on the OptimismPortal. After the deposit is made, L1 tokens are bridged, and an equivalent amount of tokens is minted as native Celo tokens in the user's account on Layer 2 (L2).

Bridging CELO from L2 to L1

To withdraw Celo from the L2 chain, users should use the L2ToL1MessagePasser.initiateWithdrawal method. The process for proving and finalizing withdrawals is the same as it is on OP chains that use ETH as the native token.

Bridging ETH

Native ETH bridging is not supported for now since L1 bridge considers L1 Celo ERC20 as native token for Celo L2 and actively rejects any native ETH sent to the bridge. It is possible to bridge WETH (wrapped ETH) which behaves as standard ERC20 token both on L1 and L2.

Bridged ERC20 Tokens

ERC20 tokens can be bridged the same way as in the unmodified OP Stack, see Bridging ERC-20 Tokens to OP Mainnet With the Optimism SDK for a tutorial on this.

Using Bridged Tokens as Fee Abstraction

The OptimismMintableERC20 (used to represent ERC20 tokens from L1 on L2) supports the IFeeCurrency interface, which is a requirement to use them as a Fee Abstraction token. Before a new OptimismMintableERC20 instance can actually be used as Fee Abstraction, it still has to be added to the FeeCurrencyDirectory (0x71FFbD48E34bdD5a87c3c683E866dc63b8B2a685) by Celo governance. This is currently only the case for WETH.

EigenDA

Table of Contents

In contrast to OP Mainnet sequencer which writes TX batches to Ethereum in the form of calldata or, more recently, EIP-4844 blobs to commit to the transactions included in the canonical L2 chain, Celo uses EigenDA as an alternative data availability layer in order to minimize the TX fees. EigenDA is a data availability store made by EigenLabs and built on top of EigenLayer. With EigenDA, TX data is stored by EigenDA operators off-chain, only DA commitments used for verficiation and subsequent data retrieval are stored On Ethereum which significantly reduces DA costs and L2 TX fees.

The integration is done in accordance with the Optimism's Alt-DA spec which contains a more in-depth description of this interface.

Testnet and Contract Addresses

The Celo Dango testnet uses the EigenDA Holesky testnet. For the current list of deployed contract addresses, please refer to the EigenLayer's Current Testnet Deployment page.

L1→L2 Migration Changes

Table of Contents

The switch from the Celo L1 blockchain to the Celo L2 introduces a variety of changes, most of which are not visible to the majority of developers and even less to the end users. However, tool developers, infrastructure operators and some developers will have to take a few of these changes into account. This page contains all information to check if this is the case for you or not.

Changes for Contracts Developers

  • Removed precompiles (all except the transfer precompile)
  • During the migration the following hardforks are enabled:
  • The following Optimism specific hardforks are enabled:
    • Canyon
    • Delta
    • Ecotone
    • Fjord
      • Notably, this hardfork also enables the P256VERIFY precompile, which performs signature verification for the secp256r1 elliptic curve. This curve has widespread adoption. It's used by Passkeys, Apple Secure Enclave and many other systems.

L2 CELO Distribution Schedule

Following the switch to L2, there will no longer be epoch rewards. The community rewards fund and carbon offsetting funds will continue to receive a CELO distribution according to the CeloDistributionSchedule contract. Since minting will only be allowed on L1, the remaining CELO supply that was set to be minted will be locked into the CeloDistributionSchedule to be distributed accordingly on L2. To distribute CELO to the community and carbon fund, anyone can call the CeloDistributionSchedule.distributeAccordingToSchedule().

The CeloDistributionSchedule contract follows a linear distribution schedule based on the target gold supply previously established by the EpochRewards contract (more here...). Given that the fraction previously allocated to the validators and voters will no longer be minted, the original target schedule for the release of CELO will be pushed back unless the community fraction and/or carbon offsetting fractions are updated.

Since L2 contracts will first be deployed on L1, the CeloDistributionSchedule requires that CeloDistributionSchedule.activate() is called after the L2 transition. This will start the clock on the distribution schedule by setting l2StartTime, totalAllocationAtL2Start, fund fractions, and addresses.

Similarly to the previous linear distribution schedule defined in the EpochRewards contract, the CeloDistributionSchedule contract's linear distribution schedule is only set up to distribute for the first 15 years since the L1 genesis block. Beyond those 15 years, the contract will not allow the distribution of any additional CELO or the modification of distribution percentages until a new schedule is added for the following years.

FeeCurrencyDirectory

We introduced a new contract, FeeCurrencyDirectory, which is responsible for managing the fee currencies used in the Celo network. This contract is replacement for FeeCurrencyWhitelist and keeps track of ERC-20 tokens that can be used as gas currencies on Celo network with additional setup of intrinsic gas cost of transactions for these fee currencies.

FeeCurrencyWhitelist

The FeeCurrencyWhitelist contract has been replaced by the FeeCurrencyDirectory contract.

Deactivated Random Contract

The Random core contract has been deactivated. The EIP-4399 PREVRANDAO opcode provide some pseudo-randomness now. Please be aware of the limitations mentioned in the EIP, as well as the following OP Stack specific limitations:

  • The randao value is read from the L1, it is known a longer time in advance.
  • Since multiple L2 blocks are derived from the same L1 block, the PREVRANDAO value will not change with every L2 block, but only with the L1 block.

Deactivated BlockchainParameters Contract

The BlockchainParameters core contract has been deactivated.

The blockGasLimit can now be found by querying the Optimism L1 SystemConfig contract deployed at 0x43cb8878b4B62D9853452140eFB42CF30672e23a and calling the gasLimit() getter.

The intrinsicGasForAlternativeFeeCurrency can now be found by querying the FeeCurrencyDirectory contract function getCurrencyConfig(token).intrinsicGas.

Updated Governance Hotfix

The Governance Hotfix process has undergone several changes due to the absence of validators on L2, now using a multisig approach. Here’s a detailed explanation of these changes:

Original Hotfix Process

Previously, the hotfix process relied heavily on a set of validators:

  1. Validator Approval: A byzantine quorum of validators was needed to whitelist a hotfix. Validators had financial incentives to act in the network's best interest, ensuring that any approved hotfix had been vetted by a trustworthy group.
  2. Dynamic Validator Set: The list of validators who approved the hotfix changed with each epoch. This dynamic nature made it difficult for validators to collude and approve a malicious hotfix.
  3. Epoch-Dependent: If a hotfix was not executed within the same epoch it was approved, it needed to be reapproved by the new set of validators in the next epoch.
  4. Prepare Step: The hotfix required a "prepare" step, ensuring that the current set of validators had approved the hotfix before it could be executed.

Updated Hotfix Process

Due to the absence of validators on L2, the process now incorporates a multisig approach:

  1. Multisig Approval: The new process requires the approval of an approver multisig, but now also includes the Security Council multisig.
  2. Fixed Signers: Unlike the previous dynamic set of validators, the list of Security Council signers remains fixed. This change simplifies the approval process but also increases the risk of collusion among the fixed set of signers.
  3. Execution Time Limit: If a hotfix is not executed within the specified executionTimeLimit, it must be reset and re-approved. This keeps the time constraint but no longer depends on epoch changes.
  4. Collusion Risk: The fixed list of Security Council signers introduces a new risk factor. Without clear incentives for the signers to act in the network's best interest, there is a higher risk of collusion and the potential for malicious hotfixes being approved.

Changes for JSON-RPC Users

  • Removed tx types, see also the tx types page:
    • Celo legacy tx
    • CIP-42

State Changes During the Migration

The migration is the process of converting the Celo L1 chain into an L2 based on Ethereum. This migration involves different steps and requires the blockchain to shortly pause block production.

During the migration the following things are done:

  • Historic blockchain data such as blocks, headers and transactions are transformed into a version readable by the updated execution client. During this process some data, such as data required for the Istanbul consensus algorithm, is removed as it is no longer required.
  • OP Stack L2 contracts are deployed.
  • The new Celo distribution schedule core contract is initialized.

Historical data migration

Celo started as a fork of go-ethereum but initially some significant changes to the structure of headers and blocks were made because it was operating with a Proof of Stake consensus mechanism.

At the outset Celo blocks lacked the following fields that Ethereum blocks had:

  • sha3Uncles
  • uncles
  • difficulty
  • gasLimit (the gasLimit was defined by a contract and so had to be retrieved from state)
  • mixHash
  • nonce

Later in the Espresso hardfork, dynamic fee transactions were introduced. Instead of relying on the baseFeePerGas field on the block header, the baseFeePerGas was also retrieved from state via a contract call similar to gasLimit.

In the Gingerbread hardfork (block 21616000) all the fields listed above plus baseFeePerGas were added to the internal block representation to bring future blocks into alignment with Ethereum. A constant difficulty field of 0x0 was added to all pre-Gingerbread RPC API block responses.

Celo added the following fields to block bodies:

  • randomness
  • epochSnarkData

As additions they do not damage compatibility at the RPC API level as API clients would generally ignore them. However, in the transition to L2 these fields are planned for removal because they will no longer be needed.

In the transition to L2 as an attempt to improve the situation with RPC API compatibility for historical blocks, all post-Gingerbread fields will be returned for all blocks. Both pre-Gingerbread and post-Gingerbread blocks retrieved from the L2 RPC API would look the same with the exception of baseFeePerGas which for now will not be returned for pre-Gingerbread blocks.

L2 Block Structure

Going forward, blocks occurring after the transition point will gain an extra field, parentBeaconBlockRoot, which will bring our block structure fully up to date with Ethereum’s block structure.

As Ethereum evolves in the time before we make the transition to L2 we could end up with additional fields being added to the L2 Block Structure, and this document will be updated accordingly.

State migration

The OP stack requires a number of contracts to be available on the L2. Those contracts have predefined addresses and cannot be deployed like normal contracts. Instead they are written to the state during the migration.

As this process touches the blockchain state, it is important that it is transparent and can be verified by every node operator and user. Therefore, every node operator can do the migration locally and check the resulting state against Celo L2 state.

OP predeploys

The predeploys to be added to the state are supplied in form of an allocation file which contains a mapping of account addresses to their state. In the state migration tool this file is read and every account copied into the Celo L1 state.

There's a number of checks to make sure this doesn't end up causing problems.

  • If an account to be written to the state already has a balance, this balance is added to the copied account balance. This makes sure the total amount of Celo doesn't change.
  • If an account already contains code, it is checked that the code is the same.

CeloDistributionSchedule set up

The CeloDistributionSchedule is a new contract available on the migrated Celo L2. See the spec for more information.

During the migration it needs to be setup with the remaining unminted Celo.

This is done by first reading the total supply of Celo tokens at the time of the migration. This value is then subtracted from the max supply of Celo tokens, which is 1,000,000,000. This difference is the remaining amount of tokens that gets set as the balance of the distribution schedule contract.

Other Changes

  • No need for validators, since a centralized sequencer is used

CIP-64 Receipts Now Contain the baseFee

For the Celo L1, the effectiveGasPrice for CIP-64 txs is only available until the block state is pruned. Afterwards, the blockchain client is unable to get the baseFee for the relevant feeCurrency, which is required to calculate the effectiveGasPrice. To avoid this and make the effectiveGasPrice available permanently, the baseFee is included as the last field in the RLP-encoded CIP-64 receipt for CIP-64 txs submitted after the L2 migration. The EIP-2718 ReceiptPayload for this transaction type is now rlp([status, cumulativeGasUsed, logsBloom, logs, baseFee]).

Celo Docs: Cel2