Deposit Contract


Deposit contracts are the Ethereum smart contracts into which assets are deposited–custodying the money as it is transacted on plasma and playing out the exit games to resolve the rightful owners of previously deposited assets. As such, it contains the bulk of the logic for the plasma exit games. The things it does not cover are 1) block commitments, and 2), state deprecation, which are handled by calls to the commitment contract and predicate contracts specifically.




struct Range {
    uint256 start;
    uint256 end;

Represents a range of state objects.

  1. start - uint256: Start of the range of objects.
  2. end - uint256: End of the range of objects.


struct StateObject {
    string id;
    address predicate;
    bytes data;

Represents a state object. Contains the address of the predicate contract and input data to that contract which control the conditions under which the object may be mutated.

  1. id - string: A globally unique identifier for this state object.
  2. predicateAddress - address: Address of the predicate contract that dictates how the object can be mutated.
  3. data - bytes: Arbitrary state data for the object.


struct StateUpdate {
    Range range;
    StateObject stateObject;
    address plasmaContract;
    uint256 plasmaBlockNumber;

Represents a state update, which contains the contextual information for how a particular range of state objects was mutated.

  1. range - Range: Range of state objects that were mutated.
  2. stateObject - StateObject: Resulting state object created by the mutation of the input objects.
  3. plasmaContract - address: Address of the plasma contract in which the update was included.
  4. plasmaBlockNumber - uint256: Plasma block number in which the update occurred.


struct Checkpoint {
    StateUpdate stateUpdate;
    Range subRange;

Represents a checkpoint of a particular state update on which a “checkpoint game” is being or has been played out. Checkpoints which have successfully passed the checkpoint game are considered “finalized”, meaning the plasma contract should ignore all state updates on that range with an older plasma block number.

  1. stateUpdate - StateUpdate: State update being checkpointed.
  2. subRange - Range: Sub-range of the state update being checkpointed. We include this field because the update may be partially spent.


struct CheckpointStatus {
    uint256 challengeableUntil;
    uint256 outstandingChallenges;

Status of a particular checkpoint attempt.

  1. challengeableUntil - uint256: Ethereum block number until which the checkpoint can still be challenged.
  2. outstandingChallenges - uint256: Number of outstanding challenges.


struct Challenge {
    Checkpoint challengedCheckpoint;
    Checkpoint challengingCheckpoint;

Describes a challenge against a checkpoint. A challenge is a claim that the challengingCheckpoint has no valid transactions, meaning that the state update in the challengedCheckpoint could never have been reached and thus is invalid.

  1. challengedCheckpoint - Checkpoint: Checkpoint being challenged.
  2. challengingCheckpoint - Checkpoint: Checkpoint being used to challenge.

Public Variables


address constant COMMITMENT_ADDRESS;

Address of the commitment contract where block headers for the plasma chain are being published.


Deposit contracts MUST specify the address of a commitment contract where plasma chain block headers are being published.


Deposit contracts handle deposits and exits from a specific plasma chain. Commitment contracts hold the plasma block headers for that plasma chain and therefore make it possible to verify inclusion proofs.


address constant TOKEN_ADDRESS;

Address of the ERC-20 token which this deposit contract custodies.

  • The deposit contract:
    • MUST be the address of an ERC-20 token.


Each asset type needs to be allocated its own large contiguous “sub-range” within the larger Plasma Cashflow chain. Without these sub-ranges, defragmentation becomes effectively impossible. Although it’s possible to achieve this result within a single deposit contract, it’s easier to simply require that each asset have its own deposit contract and to allocate a large sub-range to every deposit contract.


uint256 constant CHALLENGE_PERIOD;

Number of Ethereum blocks for which a checkpoint may be challenged.


uint256 constant EXIT_PERIOD;

Number of Ethereum blocks before an exit can be finalized.


uint256 public totalDeposited;

Total amount deposited into this contract.


mapping (bytes32 => CheckpointStatus) public checkpoints;

Mapping from the ID of a checkpoint to the checkpoint’s status.


mapping (uint256 => Range) public depositedRanges;

Stores the list of ranges that have not been exited as a mapping from the start of a range to the full range. Prevents multiple exits from the same range of objects.


mapping (bytes32 => uint256) public exitRedeemableAfter;

Mapping from the ID of an exit to the Ethereum block after which the exit can be finalized.


mapping (bytes32 => bool) public challenges;

Mapping from the ID of a challenge to whether or not the challenge is currently active.



event CheckpointStarted(
    Checkpoint checkpoint,
    uint256 challengeableUntil

Emitted whenever a user attempts to checkpoint a state update.

  1. checkpoint - bytes32: ID of the checkpoint that was started.
  2. challengeableUntil - uint256: Ethereum block in which the checkpoint was started.


event CheckpointChallenged(
    Challenge challenge

Emitted whenever an invalid history challenge has been started on a checkpoint.

  1. challenge - Challenge: The details of the challenge .


event CheckpointFinalized(
    bytes32 checkpoint

Emitted whenever a checkpoint is finalized.

  1. checkpoint - bytes32: ID of the checkpoint that was finalized.


event ExitStarted(
    bytes32 exit,
    uint256 redeemableAfter

Emitted whenever an exit is started.

  1. exit - bytes32: ID of the exit that was started.
  2. redeembleAfter - uint256: Ethereum block in which the exit will be redeemable.


event ExitFinalized(
    Checkpoint exit

Emitted whenever an exit is finalized.

  1. exit - Checkpoint: The checkpoint that had its exit finalized.



function deposit(
    address _depositer,
    uint256 _amount,
    StateObject _initialState
) public

Allows a user to submit a deposit to the contract. Only allows users to submit deposits for the asset represented by this contract.

  1. _depositer - address: the account which has approved the ERC20 deposit.
  2. _amount - uint256: Amount of the asset to deposit.
  3. _initialState - StateObject: Initial state to put the deposited assets into. Can be any valid state object.
  • MUST keep track of the total deposited assets, totalDeposited.
  • MUST transfer the deposited amount from the depositer to the deposit contract’s address.
  • MUST create a state update with a state object equal to the provided initialState.
  • MUST compute the range of the created state update as totalDeposited to totalDeposited + amount.
  • MUST update the total amount deposited after the deposit is handled.
  • MUST insert the created state update into the checkpoints mapping with challengeableUntil being the current block number - 1.
  • MUST emit a CheckpointFinalized event for the inserted checkpoint.

Depositing is the mechanism which locks an asset into the plasma escrow agreement, allowing it to be transacted off-chain. The initialState defines its spending conditions, in the same way that a StateUpdate does once further transactions are made. Because deposits are verified on-chain transactions, they can be treated as checkpoints which are unchallengeable.


function startCheckpoint(
    Checkpoint _checkpoint,
    bytes _inclusionProof,
    uint256 _depositedRangeId
) public

Starts a checkpoint for a given state update.

  1. _checkpoint - Checkpoint: Checkpoint to be initiated.
  2. _inclusionProof - bytes: Proof that the state update was included in the block specified within the update.
  3. _depositedRangeId - uint256: The key in the depositedRanges mapping which includes the subRange as a subrange.
  • MUST verify the that checkpoint.stateUpdate was included with inclusionProof.
  • MUST verify that subRange is actually a sub-range of stateUpdate.range.
  • MUST verify that the subRange is still exitable with the depositedRangeId .
  • MUST verify that an indentical checkpoint has not already been started.
  • MUST add the new pending checkpoint to checkpoints with challengeableUntil equalling the current ethereum block.number + CHALLENGE_PERIOD .
  • MUST emit a CheckpointStarted event.

Checkpoints are assertions that a certain state update occured/was included, and that it has no intersecting unspent state updates in its history. Because the operator may publish an invalid block, it must undergo a challenge period in which the parties who care about the unspent state update in the history exit it, and use it to challenge the checkpoint.


function deleteExitOutdated(
    Checkpoint _olderExitt,
    Checkpoint _newerCheckpoint
) public

Deletes an exit by showing that there exists a newer finalized checkpoint. Immediately cancels the exit.

  1. _olderExitt - Checkpoint: `The exit`_ to delete.
  2. _newerCheckpoint - Checkpoint: The checkpoint used to challenge.
  • MUST ensure the checkpoint ranges intersect.
  • MUST ensure that the plasma blocknumber of the _olderExitt is less than that of _newerCheckpoint.
  • MUST ensure that the newerCheckpoint has no challenges.
  • MUST ensure that the newerCheckpoint is no longer challengeable.
  • MUST delete the entries in exitRedeemableAfter.

If a checkpoint game has finalized, the safety property should be that nothing is valid in that range’s previous blocks–”the history has been erased.” However, since there still might be some StateUpdates included in the blocks prior, invalid checkpoints can be initiated. This method allows the rightful owner to demonstrate that the initiated olderCheckpoint is invalid and must be deleted.


function challengeCheckpoint(
    Challenge _challenge
) public

Starts a challenge for a checkpoint by pointing to an exit that occurred in an earlier plasma block. Does not immediately cancel the checkpoint. Challenge can be blocked if the exit is cancelled.

  1. _challenge - Challenge: Challenge to submit.
  • MUST ensure that the checkpoint being used to challenge exists.
  • MUST ensure that the challenge ranges intersect.
  • MUST ensure that the checkpoint being used to challenge has an older plasmaBlockNumber.
  • MUST ensure that an identical challenge is not already underway.
  • MUST ensure that the current ethereum block is not greater than the challengeableUntil block for the checkpoint being challenged.
  • MUST increment the outstandingChallenges for the challenged checkpoint.
  • MUST set the challenges mapping for the challengeId to true.

If the operator includes an invalid StateUpdate (i.e. there is not a deprecation for the last valid StateUpdate on an intersecting range), they may checkpoint it and attempt a malicious exit. To prevent this, the valid owner must checkpoint their unspent state, exit it, and create a challenge on the invalid checkpoint.


function removeChallenge(
    Challenge _challenge
) public

Decrements the number of outstanding challenges on a checkpoint by showing that one of its challenges has been blocked.

  1. _challenge - Challenge: `The challenge`_ that was blocked.
  • MUST check that the challenge was not already removed.
  • MUST check that the challenging exit has since been removed.
  • MUST remove the challenge if above conditions are met.
  • MUST decrement the challenged checkpoint’s outstandingChallenges if the above conditions are met.

Anyone can exit a prior state which was since spent and use it to challenge despite it being deprecated. To remove this invalid challenge, the challenged checkpointer may demonstrate the exit is deprecated, deleting it, and then call this method to remove the challenge.


function startExit(Checkpoint _checkpoint) public

Allows the predicate contract to start an exit from a checkpoint. Checkpoint may be pending or finalized.

  1. _checkpoint - Checkpoint: The checkpoint from which to exit.
  • MUST ensure the checkpoint exists.
  • MUST ensure that the msg.sender is the _checkpoint.stateUpdate.predicateAddress to authenticate the exit’s initiation.
  • MUST ensure an exit on the checkpoint is not already underway.
  • MUST set the exit’s redeemableAfter status to the current Ethereum block.number + LOCKUP_PERIOD.
  • MUST emit an exitStarted event.

For a user to redeem state from the plasma chain onto the main chain, they must checkpoint it and respond to all challenges on the checkpoint, and await a LOCKUP_PERIOD to demonstrate that the checkpointed subrange has not been deprecated. This is the method which starts the latter process on a given checkpoint.


function deprecateExit(
    Checkpoint _checkpoint
) public

Allows the predicate address to cancel an exit which it determines is deprecated.

  1. _checkpoint - Checkpoint: The checkpoint referenced by the exit.
  • MUST ensure the msg.sender is the _checkpoint.stateUpdate.predicateAddress to ensure the deprecation is authenticated.
  • MUST delete the exit from exitRedeemableAfter at the checkpointId .

If a transaction exists spending from a checkpoint, the checkpoint may still be valid, but an exit on it is not. This method allows the predicate to remove the exit if it has determined it to be outdated.


function finalizeExit(Checkpoint _exit, uint256 _depositedRangeId) public

Finalizes an exit that has passed its exit period and has not been successfully challenged.

  1. _exit - Checkpoint: The checkpoint on which the exit is not finalizable.
  2. _depositedRangeId - uint256: the entry in depositedRanges demonstrating the range is not yet exited.
  • MUST ensure that the exit finalization is authenticated from the predicate by msg.sender == _exit.stateUpdate.state.predicateAddress.
  • MUST ensure that the checkpoint is finalized (current Ethereum block exceeds checkpoint.challengeableUntil).
  • MUST ensure that the checkpoint’s outstandingChallenges is 0.
  • MUST ensure that the exit is finalized (current Ethereum block exceeds redeemablAfter ).
  • MUST ensure that the checkpoint is on a subrange of the currently exitable ranges via depositedRangeId.
  • MUST make an ERC20 transfer of the end - start amount to the predicate address.
  • MUST delete the exit.
  • MUST remove the exited range by updating the depositedRanges mapping.
  • MUST delete the checkpoint.
  • MUST emit an exitFinalized event.

Exit finalization is the step which actually allows the assets locked in plasma to be used on the main chain again. Finalization requires that the exit and checkpoint games have completed successfully.