This section is intended for Custodians, Exchanges, and other services that intend to custody Celo assets such as Celo Dollar and CELO on behalf of a user. Generally speaking, custodying CELO, the native token on the Celo network, requires understanding the various states that CELO can exist in at any time. This is to provide useful services beyond custody such as allowing users to lock up their CELO and vote with it. Many of these "states" are implemented as smart contracts, and involve sending CELO from a user owned account to a contract address. Thus, in order to be able to show a user's true balance, services need to be able to observe every balance changing operation and reconcile CELO balances from all the various contracts and states CELO can be in.

Balance Model

As a fork of Ethereum, Celo retains the account model to keep track of users' balances. Celo Dollar and CELO implement the ERC20 interface. As mentioned previously, it is common for smart contracts to hold balances on behalf of other addresses. One example is the LockedGold smart contract that holds the "locked portion of a user's CELO balance". Another one is the ReleaseGold smart contract that holds CELO that is being released to a beneficiary address over time according to some schedule.

Celo assets assets exist on an independent blockchain, and although they implement the ERC20 interface, they cannot be accessed through wallets that connect to the Ethereum network. Wallets and other integrations must connect to the Celo network to transfer tokens on Celo.

Applications that display balances may need to be written to be aware of this possibility.


CELO and Celo Dollars implement the ERC20 interface, as will any future core stable Celo currencies. CELO, as the native currency of the network, can also be transferred by specifying the value field of a transaction, in the same way that ETH can be transferred in Ethereum. Therefore, for CELO, application developers should be aware that transactions can be specified in both ways.

CELO State Machine

CELO as described previously can also exist in various states that represent a specific user behavior. For example, if a user wants to lock CELO to either participate in consensus directly or vote, that CELO will be sent to the LockedGold smart contract. To understand the high level flow, please read this description of the various states CELO can exist in.

Smart Contracts

The following smart contracts are helpful to understand in order to map the conceptual states to actual accounts and function calls.


Accounts.sol allows the mapping of an address to an account in storage, after which all further functionality (locking, voting, etc.) can be accessed.

The createAccount function indexes the address as an account in storage, and is required to differentiate an arbitrary key-pair from a user-owned account in the Celo network.

The Accounts contract also allows for the authorization of various signer keys, such as a vote signer key. This allows for the user who owns the primary account key to authorize a separate key that can only vote on behalf of the account. This allows for the ability to custody keys in a manner corresponding to their exposure or "warmth". Eg. the primary account private key can be kept in cold storage after authorizing the signer keys, which can be in warmer environments, and potentially more exposed to the network. See the key management guide for more details.


LockedGold.sol, which references Celo Gold, the deprecated name for the native token, is used as part of Celo's proof-of-stake mechanism. Users can lock CELO by sending it to the LockedGold contract after creating an account via the Accounts contract as described above. This allows users to vote in validator elections, receive epoch rewards, and participate in on-chain governance.

There are two ways in which users can vote:

  • Directly, by sending voting transactions with the same key used to lock up CELO

  • Via an authorized vote signer, which can submit voting transactions on behalf of the account with locked CELO

LockedGold has a mapping of addresses to balances which is a type that contains both the nonvoting amount of CELO as well as pendingWithdrawals, which contain values corresponding to timestamps at which they can be withdrawn. The reason for the latter is because all locked CELO has an unlocking period that is set at time of contract initialization, which is 3 days in the Celo network's deployed LockedGold contract. Hence, if users unlock CELO in tranches, multiple pending withdrawals could exist at once. Once the timestamp has eclipsed, CELO can be withdrawn back to the user's address.


Once CELO has been locked via LockedGold, it can then be used to vote for validator groups. Election.sol is the contract that manages this functionality.

The votes in this contract are tracked by a Votes type which has pending, active, and total votes. Pending votes are those that have been cast for a validator group, and active votes are those that have been activated after an epoch, meaning that these votes generate voter rewards.

Votes are cast for a validator group using the vote function. This increments the pending and total votes in the Election contract, and decrements the equivalent amount of CELO from the nonvoting balance in the LockedGold contract, for the associated account.

The activate function can then be called to shift pending votes into active votes in a following epoch. Votes in either state can then be revoked, which decrements votes from the Election contract and returns them to the LockedGold balance for the associated account. Users can revoke votes at any time and this takes effect instantly.


A common problem in other proof-of-stake protocols is the tension between wanting early token holders' balances to release over time to ensure long-term alignment, while also wanting them to be able to participate in consensus to increase the security of the network. To bridge both goals, many early token balances in the Celo network are released via the ReleaseGold contract. Beneficiaries of these contracts can then participate in the proof-of-stake system by staking and voting with CELO that has not yet been "released" for transfers. Please find more high level information about the ReleaseGold contract here.

From a technical perspective, ReleaseGold can be thought of as a "puppet" account controlled by the "puppeteer", or the beneficiary private key corresponding to the beneficiary address in the contract. This beneficiary key can then authorize validator signer and vote signer keys that can then call respective functions associated with validating or voting. Most of the required function calls described above can be made by the signer keys directly to the LockedGold or Election contracts associated with the ReleaseGold account. However, some functions in the ReleaseGold contract are proxied to the underlying LockedGold or Election contracts, and have a separate function signature that can be called by the beneficiary address. Notably:

Notice that all these functions have corresponding functions that are called on the underlying contract. The ReleaseGold contract can then just be thought of as brokering the transaction to the correct place, when necessary.

Other Balance Changing Operations

In addition to transfers (both native and ERC-20) and locking / voting flows affecting user balances, there are also several additional Celo network features that may cause user balances to change:

  • Gas fee payments: the fee paid by transaction senders to use the network

  • Tobin tax: a tax on CELO transfers when the reserve balance is low and needs to be repleted

  • Epoch rewards distribution: reward payments to voters, validators, and validator groups

Some of these may occur as events rather than transactions on the network, and therefore when updating balances, special attention should be paid to them.

Useful Tools

Since monitoring balance changing operations is important to be able to display user balances properly, it can be helpful to use a tracing or reconciling system. Celo Rosetta is an RPC server that exposes an API to query the Celo blockchain, obtain balance changing operations, and construct airgapped transactions. With a special focus on getting balance change operations, Celo Rosetta provides an easy way to obtain changes that are not easily queryable using the celo-blockchain RPC.