Tenzro Testnet is live. Get testnet TNZO

ERC-7802: Cross-Chain Token Standard

ERC-7802 is a cross-chain token interface proposed by OP Labs that standardizes how tokens are minted and burned across chains. Instead of locking tokens on a source chain and minting wrapped versions on the destination (the traditional bridge model), ERC-7802 defines a crosschainMint and crosschainBurn interface that authorized bridge contracts call directly on the token. Tenzro implements ERC-7802 for wTNZO and any ERC-20 token created through the Token Factory, enabling seamless cross-chain movement without liquidity fragmentation.

How It Works

The ERC-7802 flow replaces lock-and-mint with burn-and-mint. When a user wants to move tokens from Chain A to Chain B:

  1. The user calls the bridge contract on Chain A, which calls crosschainBurn() on the token contract, destroying the tokens on Chain A.
  2. The bridge relays a message to Chain B (via LayerZero, CCIP, or any supported messaging protocol).
  3. On Chain B, the bridge contract calls crosschainMint() on the same token contract, creating fresh tokens for the recipient.
  4. Both events are emitted with matching metadata for cross-chain audit.

Key difference from wrapped tokens: With ERC-7802, there is only one canonical token contract per chain. No wrapped or synthetic tokens are created, and the total supply across all chains is always consistent (burned on source = minted on destination). This eliminates the bridge-risk problem where compromised bridge contracts can drain locked funds.

Interface Definition

// IERC7802 — Cross-chain mint/burn interface
interface IERC7802 is IERC165 {
    /// @notice Mints tokens on the destination chain.
    /// @param to      Recipient address.
    /// @param amount  Amount to mint.
    /// @param sender  Original sender on the source chain.
    /// @dev Only callable by authorized bridge contracts.
    function crosschainMint(
        address to,
        uint256 amount,
        address sender
    ) external;

    /// @notice Burns tokens on the source chain before cross-chain transfer.
    /// @param from    Address whose tokens are burned.
    /// @param amount  Amount to burn.
    /// @param sender  Address initiating the cross-chain transfer.
    /// @dev Only callable by authorized bridge contracts.
    function crosschainBurn(
        address from,
        uint256 amount,
        address sender
    ) external;

    /// @notice Emitted when tokens are minted via cross-chain transfer.
    event CrosschainMint(
        address indexed to,
        uint256 amount,
        address indexed sender
    );

    /// @notice Emitted when tokens are burned via cross-chain transfer.
    event CrosschainBurn(
        address indexed from,
        uint256 amount,
        address indexed sender
    );
}

Bridge Authorization ACL

Not every contract can call crosschainMint or crosschainBurn. The CrosschainTokenManager maintains an access control list (ACL) of authorized bridge contracts. Only addresses registered in the ACL can invoke these functions. The ACL is managed by the token owner (for custom tokens) or by Tenzro governance (for wTNZO).

use tenzro_vm::crosschain::{CrosschainTokenManager, BridgeAuthorization};

let manager = CrosschainTokenManager::new(storage.clone())?;

// Authorize a bridge contract to call crosschainMint/crosschainBurn
manager.authorize_bridge(BridgeAuthorization {
    bridge_address: layerzero_endpoint_address,
    token_address: wtnzo_address,
    authorized_by: governance_multisig,
    chain_id: 1,                             // Ethereum
    label: "LayerZero V2 Endpoint".to_string(),
    per_tx_limit: 1_000_000 * 10u128.pow(18),  // 1M TNZO per tx
    daily_limit: 10_000_000 * 10u128.pow(18),  // 10M TNZO per day
    enabled: true,
})?;

// Revoke authorization
manager.revoke_bridge(layerzero_endpoint_address, wtnzo_address)?;

// Query all authorized bridges for a token
let bridges = manager.authorized_bridges(wtnzo_address)?;

// Check if a specific bridge is authorized
let is_authorized = manager.is_authorized(
    layerzero_endpoint_address,
    wtnzo_address,
)?;

Rate Limits and Safety

Each bridge authorization carries two independent limits to prevent catastrophic loss in the event of a bridge compromise:

Limit TypeScopeBehavior on Breach
per_tx_limitSingle crosschainMint or crosschainBurn callTransaction reverts with ExceedsPerTxLimit
daily_limitCumulative volume within a rolling 24-hour windowTransaction reverts with ExceedsDailyLimit. Resets after 24 hours.
// Limit configuration example
let auth = BridgeAuthorization {
    bridge_address: ccip_router_address,
    token_address: wtnzo_address,
    authorized_by: governance_multisig,
    chain_id: 1,
    label: "Chainlink CCIP Router".to_string(),

    // Per-transaction limit: 500,000 TNZO
    per_tx_limit: 500_000 * 10u128.pow(18),

    // Daily rolling limit: 5,000,000 TNZO
    daily_limit: 5_000_000 * 10u128.pow(18),

    enabled: true,
};

// The manager tracks daily volume internally
// When a crosschainMint is attempted:
match manager.check_limits(ccip_router_address, wtnzo_address, amount) {
    Ok(()) => { /* proceed with mint */ }
    Err(CrosschainError::ExceedsPerTxLimit { limit, attempted }) => {
        // Single transaction too large
    }
    Err(CrosschainError::ExceedsDailyLimit { limit, used, attempted }) => {
        // Daily cap reached — wait for window to roll
    }
    Err(CrosschainError::BridgeNotAuthorized { bridge, token }) => {
        // Bridge not in ACL
    }
    Err(CrosschainError::BridgeDisabled { bridge, token }) => {
        // Bridge temporarily paused via enabled=false
    }
    Err(e) => return Err(e),
}

Events and Audit Trail

Every cross-chain mint and burn emits structured events that are indexed by the Tenzro Ledger. These events carry the sender address from the source chain, enabling full traceability of cross-chain flows.

// Events emitted by the ERC-7802 implementation

// On source chain (burn side):
CrosschainBurn {
    from: "0xuser...abc",           // Token holder
    amount: 1000000000000000000000, // 1000 TNZO (18 decimals)
    sender: "0xbridge...def",       // Bridge contract that initiated
}

// On destination chain (mint side):
CrosschainMint {
    to: "0xuser...abc",             // Recipient (same user, different chain)
    amount: 1000000000000000000000, // 1000 TNZO
    sender: "0xbridge...ghi",       // Bridge contract on destination
}

// Additional Tenzro-specific audit event:
CrosschainTransferCompleted {
    token: "0xwtnzo...123",
    amount: 1000000000000000000000,
    source_chain: 1,                // Ethereum
    dest_chain: 42161,              // Arbitrum
    source_tx: "0xtx_burn...abc",
    dest_tx: "0xtx_mint...def",
    bridge: "layerzero",
    timestamp: 1712793600,
}

Integration with Token Factory

Any ERC-20 token created through Tenzro's Token Factory precompile (0x1002) can opt into ERC-7802 support at creation time. When enabled, the token contract implements the IERC7802 interface and the creator can authorize bridges through the CrosschainTokenManager.

// Create a token with ERC-7802 support enabled
let token = token_factory.create_token(CreateTokenParams {
    name: "My Protocol Token".to_string(),
    symbol: "MPT".to_string(),
    decimals: 18,
    initial_supply: 100_000_000 * 10u128.pow(18),
    creator: deployer_address,
    crosschain_enabled: true,        // Enables ERC-7802 interface
    max_supply: Some(1_000_000_000 * 10u128.pow(18)),
})?;

// The token now supports crosschainMint/crosschainBurn
// Authorize bridges as needed
manager.authorize_bridge(BridgeAuthorization {
    bridge_address: layerzero_endpoint_address,
    token_address: token.address,
    authorized_by: deployer_address,
    chain_id: 1,
    label: "LayerZero V2".to_string(),
    per_tx_limit: 100_000 * 10u128.pow(18),
    daily_limit: 1_000_000 * 10u128.pow(18),
    enabled: true,
})?;

CLI Usage

# Authorize a bridge for a token
tenzro token authorize-bridge --token <token-address> \
  --bridge <bridge-contract> --chain-id 1 \
  --per-tx-limit 1000000 --daily-limit 10000000 \
  --label "LayerZero V2 Endpoint"

# Revoke bridge authorization
tenzro token revoke-bridge --token <token-address> \
  --bridge <bridge-contract>

# List authorized bridges for a token
tenzro token bridges --token <token-address>

# Check current daily volume for a bridge
tenzro token bridge-volume --token <token-address> \
  --bridge <bridge-contract>

# Update limits for an authorized bridge
tenzro token update-bridge-limits --token <token-address> \
  --bridge <bridge-contract> \
  --per-tx-limit 2000000 --daily-limit 20000000

# Temporarily disable a bridge (emergency pause)
tenzro token disable-bridge --token <token-address> \
  --bridge <bridge-contract>

# Re-enable a paused bridge
tenzro token enable-bridge --token <token-address> \
  --bridge <bridge-contract>

Comparison with Traditional Wrapped Tokens

AspectERC-7802 (Burn/Mint)Traditional (Lock/Mint)
Token type on destinationCanonical (same contract)Wrapped (separate contract)
Supply consistencyAlways consistent (burn = mint)Risk of over-minting if bridge exploited
Liquidity fragmentationNone — one canonical token per chainSplit across wrapped representations
DeFi composabilityFull — same token address accepted everywhereLimited — each wrapper needs separate integrations
Bridge exploit impactCapped by per-tx and daily limitsAll locked tokens at risk
Gas costOne burn tx + one mint txOne lock tx + one mint tx (similar)
Token contract deploymentSame contract on every chainDifferent wrapper contracts per bridge per chain

Governance Controls

For the native wTNZO token, bridge authorizations are managed through the on-chain governance system. Adding or removing an authorized bridge requires a governance proposal with a majority vote. This ensures that no single entity can unilaterally authorize a new bridge to mint TNZO.

# Submit a governance proposal to authorize a new bridge
tenzro governance propose \
  --title "Authorize deBridge DLN for wTNZO" \
  --description "Add deBridge DLN as authorized ERC-7802 bridge for wTNZO with 500K per-tx and 5M daily limit" \
  --action authorize-bridge \
  --params '{"bridge": "0xdebridge...", "token": "wTNZO", "per_tx_limit": 500000, "daily_limit": 5000000}'

# Vote on the proposal
tenzro governance vote --proposal <proposal-id> --vote yes