Skip to main content

System Architecture

The deBridge Protocol consists of multiple interconnected smart contracts and off-chain components that work together to enable secure cross-chain asset transfers and messaging.

Architecture Overview

Core Components

1. DeBridgeGate

The central contract that handles all cross-chain operations. Location: contracts/transfers/DeBridgeGate.sol Key Responsibilities:

Asset Management

  • Locks assets on native chain
  • Unlocks assets on destination
  • Burns deAssets when bridging back
  • Tracks balances and reserves

Message Handling

  • Submits cross-chain messages
  • Generates unique submission IDs
  • Emits events for validators
  • Manages execution parameters

Fee Collection

  • Collects protocol fees
  • Applies transfer fees
  • Manages fee discounts
  • Handles native and asset fees

Security

  • Verifies validator signatures
  • Enforces confirmation thresholds
  • Implements pause mechanism
  • Validates chain support
Key Functions:
contracts/interfaces/IDeBridgeGate.sol
interface IDeBridgeGate {
    // Send assets to another chain
    function send(
        address _tokenAddress,
        uint256 _amount,
        uint256 _chainIdTo,
        bytes memory _receiver,
        bytes memory _permitEnvelope,
        bool _useAssetFee,
        uint32 _referralCode,
        bytes calldata _autoParams
    ) external payable returns (bytes32 submissionId);
    
    // Send message without assets
    function sendMessage(
        uint256 _dstChainId,
        bytes memory _targetContractAddress,
        bytes memory _targetContractCalldata
    ) external payable returns (bytes32 submissionId);
    
    // Claim on destination chain
    function claim(
        bytes32 _debridgeId,
        uint256 _amount,
        uint256 _chainIdFrom,
        address _receiver,
        uint256 _nonce,
        bytes calldata _signatures,
        bytes calldata _autoParams
    ) external;
}

2. DeBridgeToken (deAssets)

Wrapped token representation of native assets on secondary chains. Location: contracts/periphery/DeBridgeToken.sol Key Features:
  • ERC20-compliant wrapped tokens
  • Mintable only by authorized DeBridgeGate
  • Burnable when bridging back to native chain
  • Pausable for emergency situations
  • Supports EIP-2612 permit for gasless approvals
contracts/interfaces/IDeBridgeToken.sol
interface IDeBridgeToken {
    // Mint deAssets (only MINTER_ROLE)
    function mint(address _receiver, uint256 _amount) external;
    
    // Burn deAssets (only MINTER_ROLE)
    function burn(uint256 _amount) external;
    
    // EIP-2612 permit
    function permit(
        address _owner,
        address _spender,
        uint256 _value,
        uint256 _deadline,
        uint8 _v,
        bytes32 _r,
        bytes32 _s
    ) external;
}
Token Lifecycle:
1

Asset Locked

User locks native token on the source chain via DeBridgeGate.send()
2

deAsset Minted

After validation, DeBridgeToken.mint() creates wrapped tokens on destination
3

deAsset Used

User can transfer, trade, or use deAsset like any ERC20 token
4

deAsset Burned

When bridging back, DeBridgeToken.burn() destroys the wrapped token
5

Asset Unlocked

Original asset is unlocked on the native chain

3. CallProxy

Executes external contract calls on the destination chain. Location: contracts/periphery/CallProxy.sol Purpose: Enables cross-chain composability by executing arbitrary contract calls with transferred assets. Key Features:
  • Executes calls on behalf of users
  • Handles both native and ERC20 token transfers
  • Provides fallback mechanism if call fails
  • Supports multi-send for batched operations
  • Exposes submission metadata (chain ID, native sender)
contracts/interfaces/ICallProxy.sol
interface ICallProxy {
    // Execute call with native tokens
    function call(
        address _reserveAddress,      // fallback recipient
        address _receiver,             // contract to call
        bytes memory _data,            // calldata
        uint256 _flags,                // execution flags
        bytes memory _nativeSender,    // original sender
        uint256 _chainIdFrom           // source chain
    ) external payable returns (bool);
    
    // Execute call with ERC20 tokens
    function callERC20(
        address _token,
        address _reserveAddress,
        address _receiver,
        bytes memory _data,
        uint256 _flags,
        bytes memory _nativeSender,
        uint256 _chainIdFrom
    ) external returns (bool);
    
    // Get submission context
    function submissionChainIdFrom() external view returns (uint256);
    function submissionNativeSender() external view returns (bytes memory);
}
Execution Flow:

4. Signature Verification

Validates oracle signatures to ensure cross-chain transaction authenticity. Location: contracts/transfers/SignatureVerifier.sol Key Responsibilities:
  • Verifies ECDSA signatures from validators
  • Enforces minimum confirmation requirements
  • Checks for required oracle participation
  • Prevents signature reuse
Confirmation Logic:
// Defined in DeBridgeGate.sol:573-586
function _checkConfirmations(
    bytes32 _submissionId,
    bytes32 _debridgeId,
    uint256 _amount,
    bytes calldata _signatures
) internal {
    if (isBlockedSubmission[_submissionId]) revert SubmissionBlocked();
    
    // Use excessConfirmations if amount exceeds threshold
    ISignatureVerifier(signatureVerifier).submit(
        _submissionId,
        _signatures,
        _amount >= getAmountThreshold[_debridgeId] ? excessConfirmations : 0
    );
}

5. OraclesManager

Manages the validator set and confirmation requirements. Location: contracts/transfers/OraclesManager.sol Key Features:
// Add new oracles
function addOracles(
    address[] memory _oracles,
    bool[] memory _required
) external onlyAdmin;

// Update oracle status
function updateOracle(
    address _oracle,
    bool _isValid,
    bool _required
) external onlyAdmin;
Oracle Types:
  • Regular Oracles: Contribute to confirmation count
  • Required Oracles: Must sign every transaction
  • Invalid Oracles: Temporarily or permanently disabled

6. Fee Management

Handles fee collection, calculation, and distribution. Fee Types:

Fixed Native Fee

Flat fee paid in native token (e.g., ETH) per transaction
uint256 fixedFee = chainFees.fixedNativeFee == 0 
    ? globalFixedNativeFee 
    : chainFees.fixedNativeFee;

Transfer Fee

Percentage-based fee on transferred amount (in basis points)
uint256 transferFee = (chainFees.transferFeeBps == 0
    ? globalTransferFeeBps 
    : chainFees.transferFeeBps)
    * (_amount - assetsFixedFee) / BPS_DENOMINATOR;
Fee Discounts: Protocol supports per-address discounts on both fixed and transfer fees:
struct DiscountInfo {
    uint16 discountFixBps;      // Fixed fee discount in BPS
    uint16 discountTransferBps; // Transfer fee discount in BPS
}

Data Structures

DebridgeInfo

Stores information about each bridged asset:
struct DebridgeInfo {
    uint256 chainId;           // Native chain ID
    uint256 maxAmount;         // Maximum transfer amount
    uint256 balance;           // Total locked/minted amount
    uint256 lockedInStrategies; // Amount in DeFi strategies
    address tokenAddress;      // Token address on this chain
    uint16 minReservesBps;    // Minimum reserve ratio
    bool exist;               // Whether asset is registered
}

Submission Auto Parameters

Controls automated execution on destination chain:
struct SubmissionAutoParamsTo {
    uint256 executionFee;     // Fee for executor
    uint256 flags;            // Execution flags
    bytes fallbackAddress;    // Recipient if call fails
    bytes data;               // Calldata to execute
}

struct SubmissionAutoParamsFrom {
    uint256 executionFee;
    uint256 flags;
    address fallbackAddress;
    bytes data;
    bytes nativeSender;       // Original sender on source chain
}

Execution Flags

Control execution behavior via the Flags library:
contracts/libraries/Flags.sol
library Flags {
    uint256 public constant UNWRAP_ETH = 0;                    // Unwrap WETH to ETH
    uint256 public constant REVERT_IF_EXTERNAL_FAIL = 1;       // Revert if call fails
    uint256 public constant PROXY_WITH_SENDER = 2;             // Store sender context
    uint256 public constant SEND_HASHED_DATA = 3;              // Data is pre-hashed
    uint256 public constant SEND_EXTERNAL_CALL_GAS_LIMIT = 4; // Include gas limit
    uint256 public constant MULTI_SEND = 5;                    // Batch multiple calls
}

Off-Chain Components

Validator Network

Decentralized network of independent validators:
1

Event Monitoring

Validators run deBridge nodes that monitor Sent events on all supported chains
2

Transaction Validation

Each validator independently validates the transaction details and checks chain state
3

Signature Generation

Valid transactions are signed using the validator’s private key (ECDSA)
4

Signature Aggregation

Signatures are collected until minimum threshold is reached
5

Claim Execution

Keepers execute the claim transaction on destination with aggregated signatures
Security Model:
  • Validators have economic stake that can be slashed
  • Minimum threshold prevents single validator attacks
  • Required validators ensure critical nodes participate
  • Excess confirmations for high-value transfers

deBridge Node

Validators run deBridge node software that:
  • Monitors all supported blockchains
  • Validates cross-chain transactions
  • Signs valid submissions
  • Submits signatures to aggregation layer
  • Participates in governance

Security Features

Pausable

Admin can pause transfers in emergency situations
function pause() external onlyGovMonitoring {
    _pause();
}

Reentrancy Protection

All state-changing functions use ReentrancyGuard
function send(...) 
    external 
    nonReentrant 
    whenNotPaused

Submission Blocking

Admin can block suspicious submissions
function blockSubmission(
    bytes32[] memory _submissionIds,
    bool isBlocked
) external onlyAdmin;

Signature Verification

Multiple validator signatures required for each transfer
ISignatureVerifier(signatureVerifier)
    .submit(_submissionId, _signatures, ...);

Upgradeability

The protocol uses OpenZeppelin’s upgradeable contract pattern:
  • Contracts are deployed behind proxies
  • Storage layout must be preserved across upgrades
  • Initialization instead of constructors
  • Gap variables for future storage slots
contract DeBridgeGate is
    Initializable,
    AccessControlUpgradeable,
    PausableUpgradeable,
    ReentrancyGuardUpgradeable
{
    // ... implementation
}

Chain Support

The protocol tracks supported chains for sending and receiving:
struct ChainSupportInfo {
    uint256 fixedNativeFee;   // Chain-specific fixed fee
    bool isSupported;         // Whether chain is enabled
    uint16 transferFeeBps;    // Chain-specific transfer fee
}

mapping(uint256 => ChainSupportInfo) public getChainToConfig;   // Outgoing
mapping(uint256 => ChainSupportInfo) public getChainFromConfig; // Incoming
Admin can enable/disable chains and adjust fees per chain.

Performance Considerations

Gas Optimization: The protocol normalizes token amounts to reduce dust and uses efficient storage patterns to minimize gas costs.
contracts/transfers/DeBridgeGate.sol:987-1000
function _normalizeTokenAmount(
    address _token,
    uint256 _amount
) internal view returns (uint256) {
    uint256 decimals = _token == address(0)
        ? 18
        : IERC20Metadata(_token).decimals();
    uint256 maxDecimals = 8;
    if (decimals > maxDecimals) {
        uint256 multiplier = 10 ** (decimals - maxDecimals);
        _amount = _amount / multiplier * multiplier;
    }
    return _amount;
}

Next Steps

Understand Transfers

Learn the details of the lock-and-mint mechanism

Explore Oracles

Deep dive into the validator network and consensus

Integration Guide

Start integrating deBridge into your application

Fee Structure

Understand protocol fees and optimization strategies

Build docs developers (and LLMs) love