Skip to main content

Set up mass exit

This guide helps you enable the mass exit mechanism by configuring your bridge contracts and Chromia chains for snapshot-based withdrawals. Remember that you must prepare for mass exit in advance; you cannot retrofit it after deployment. If your bridge isn't set to snapshot mode, you won't be able to trigger a mass exit.

Prerequisites

Before you start, make sure that:

  • You have an EVM-compatible bridge set up or in progress.
  • You are using a bridge contract that supports snapshot-based withdrawals, such as TokenBridgeWithSnapshotWithdraw.
  • Your Chromia Bridge Chain registers tokens in foreign mode with use_snapshots: true.

Token modes and mass exit implications

Foreign mode (EVM-originated tokens):

  • The token originates on EVM.
  • FT4 tokens are minted when moving from EVM to Chromia.
  • FT4 tokens are burned when moving from Chromia to EVM.
  • Snapshot-based mass exit is supported and required to ensure asset recovery in case of bridge failure.
  • Simpler and preferred mode for enabling mass exits.

Native mode (Chromia-originated tokens):

  • The token originates on Chromia.
  • FT4 tokens are locked in a special blockchain account when moving from Chromia to EVM.
  • FT4 tokens are released from that account when moving from EVM to Chromia.
  • This ensures total supply is protected against faulty EVM contracts.
  • Mass exit is not supported in this mode. If Chromia is compromised, the demand to exit native assets to EVM is expected to be low.

Step 1: Deploy snapshot-ready EVM bridge

To deploy the EVM bridge contract with snapshot support, run the following command:

npx hardhat deploy:snapshots \
--network <NETWORK> \
--verify \
--validator-address <VALIDATOR_CONTRACT_ADDRESS> \
--offset 2
  • Use one of the supported networks: Ethereum (ethereum, sepolia), BSC (bsc, bsc_testnet), Base (base, base_sepolia).
  • Replace <VALIDATOR_CONTRACT_ADDRESS> with the address of your validator or directory validator contract.
  • The --offset parameter sets the dispute period (lockup interval) in blocks, and a 72-hour equivalent is recommended.

Step 2: Register FT4 asset on the Bridge Chain

In your Rell deployment on the Chromia Bridge Chain, register the asset using the following code:

val asset = ft4.assets.Unsafe.register_asset(
name, // the name of the asset
symbol, // the symbol of the asset
decimals, // the decimals of the asset
blockchain_rid, // the RID of the asset issuing blockchain
icon_url, // the URL of the asset icon
type // the type of the asset, defaults to `ASSET_TYPE_FT4`
);

Step 3: Register ERC-20 token with snapshot support

Next, register your ERC-20 token on the Bridge Chain with this operation:

val erc20_asset = hbridge.register_erc20_asset(
network_id, // EVM network ID (e.g., 97 for BSC testnet)
token_address, // Address of the deployed ERC-20 contract
asset, // FT4 asset returned from the previous step
bridge_mode.foreign, // ERC-20 token must be registered as a `foreign` asset.
true // Set `use_snapshots` to `true` to enable mass exit functionality
);
note

Setting use_snapshots = true is essential for enabling mass exit support.

Step 4: Create a bridge contract

While still in the initialization phase, create a bridge contract:

val bridge_contract = hbridge.get_or_create_bridge(
network_id, // EVM network ID
bridge_address // Address where the bridge contract is deployed
);

Step 5: Bind ERC-20 to the bridge contract

While still in the initialization phase, bind the ERC-20 asset to the bridge contract using this code:

create bridge_erc20_asset(
bridge_contract, // The bridge contract
erc20_asset // The ERC-20 token to bind to the bridge contract
);

Step 6: Cross-chain mass exit (recovery contract)

If your blockchain does not support bridge functionality but receives bridged tokens from the Bridge Chain via cross-chain transfers, you must register a recovery contract on the Bridge Chain to ensure that users on your chain can recover their assets in the event of a mass exit. Chains that receive tokens from the Bridge Chain are referred to as downstream chains.

To deploy a recovery contract use the following command:

npx hardhat deploy:recovery \
--network <NETWORK> \
--verify \
--validator-address <BRIDGE_VALIDATOR_CONTRACT_ADDRESS>

To obtain the bridge validator contract address, execute the inspect:bridge script:

$ npx hardhat inspect:bridge --network <NETWORK> --bridge-address <BRIDGE_CONTRACT_ADDRESS>

Set the RID for the downstream chain on the recovery contract

npx hardhat setBlockchainRid:recovery \
--network <NETWORK> \
--address <RECOVERY_CONTRACT_ADDRESS> \
--blockchain-rid <DOWNSTREAM_CHAIN_RID>

Register the cross-chain FT4 asset on the downstream chain

val asset = crosschain.Unsafe.register_crosschain_asset(
id, // The ID of the asset to be registered
name, // The name of the asset to be registered
symbol, // The symbol of the asset to be registered
decimals, // The decimals of the asset to be registered
issuing_blockchain_rid, // The blockchain RID of the issuing chain
icon_url, // The URL of the icon for the asset
type, // The type of the asset to be registered (see FT4 docs)
uniqueness_resolver, // The uniqueness resolver for the asset (see FT4 docs)
origin_blockchain_rid // The blockchain we'll receive this asset from
// (might not be the same as issuing_blockchain_rid)
);

Register the ERC-20 token with snapshot support

Lastly, to register ERC-20 token with snapshot support on the downstream chain, register steps 3-5 on the downstream chain.

Register recovery contract

Registering a recovery contract on the Bridge Chain requires ICCF authentication, so the recovery contract must first be registered on the downstream chain.

To register the recovery contract on the downstream chain, use the following command:

chr tx -brid $DOWNSTREAM_CHAIN_RID register_recovery_contract \
-- $NETWORK_ID x"'$RECOVERY_CONTRACT_ADDRESS'"

Next, register it on the bridge chain (or upstream chain) using ICCF authentication:

chr tx -brid $BRIDGE --iccf-tx $ICCF_TX_RID \
--iccf-source $DOWNSTREAM_CHAIN_RID \
register_recovery_contract -- 0

With all of these steps completed, mass exit functionality is now enabled.