Skip to main content

Overview

Across Protocol uses a hub-and-spoke model with optimistic verification to enable fast, secure cross-chain token transfers. This architecture centralizes liquidity and governance on Ethereum L1 while deploying lightweight contracts on multiple L2s and sidechains.

Core Components

HubPool (Ethereum L1)

The HubPool is the central contract deployed on Ethereum that:
  • Manages LP Liquidity: Accepts deposits from liquidity providers who earn fees for funding relays
  • Validates Transfers: Uses merkle root bundles to verify cross-chain transfers via optimistic verification
  • Coordinates Rebalancing: Sends tokens to SpokePools across all supported chains to refund relayers
  • Resolves Disputes: Integrates with UMA’s Optimistic Oracle for dispute resolution
  • Owns All SpokePools: Acts as the cross-chain administrator for all deployed SpokePools
/**
 * @notice Contract deployed on Ethereum that houses L1 token liquidity for all SpokePools.
 * @notice This contract is meant to act as the cross chain administrator and owner of all
 * L2 spoke pools, so all governance actions and pool rebalances originate from here.
 */
contract HubPool is HubPoolInterface, Testable, Lockable, MultiCaller, Ownable {
    // Root bundle proposal storage
    RootBundle public rootBundleProposal;
    
    // LP liquidity tracking
    mapping(address => PooledToken) public pooledTokens;
    
    // Cross-chain contract mappings
    mapping(uint256 => CrossChainContract) public crossChainContracts;
    
    // Pool rebalance routes
    mapping(bytes32 => address) private poolRebalanceRoutes;
}
Key Functions:
  • addLiquidity() / removeLiquidity(): LP liquidity management (contracts/HubPool.sol:449, 476)
  • proposeRootBundle(): Data worker submits merkle roots (contracts/HubPool.sol:560)
  • executeRootBundle(): Executes pool rebalances and relays roots to SpokePools (contracts/HubPool.sol:612)
  • disputeRootBundle(): Challenge invalid proposals during liveness period (contracts/HubPool.sol:715)
  • relaySpokePoolAdminFunction(): Send admin messages to SpokePools (contracts/HubPool.sol:249)

SpokePool (Each L2/Sidechain)

SpokePools are deployed on every supported chain and handle:
  • User Deposits: Accept tokens from depositors initiating cross-chain transfers
  • Relayer Fills: Allow relayers to fulfill deposits by sending tokens to recipients
  • Merkle Leaf Execution: Process relayer refunds and slow fills using merkle proofs
  • Cross-Chain Messages: Receive root bundles and admin functions from HubPool
/**
 * @title SpokePool
 * @notice Base contract deployed on source and destination chains enabling depositors
 * to transfer assets from source to destination.
 */
abstract contract SpokePool is
    V3SpokePoolInterface,
    SpokePoolInterface,
    UUPSUpgradeable,
    ReentrancyGuardUpgradeable,
    MultiCallerUpgradeable,
    EIP712CrossChainUpgradeable
{
    // Cross-chain ownership
    address public crossDomainAdmin;
    address public withdrawalRecipient;
    
    // Deposit tracking
    uint32 public numberOfDeposits;
    
    // Root bundles from HubPool
    RootBundle[] public rootBundles;
    
    // Fill status tracking
    mapping(bytes32 => uint256) public fillStatuses;
}
Key Functions:
  • deposit() / depositV3(): User initiates cross-chain transfer (contracts/SpokePool.sol:501, 579)
  • fillRelay(): Relayer fulfills deposit on destination chain
  • relayRootBundle(): Receive merkle roots from HubPool (contracts/SpokePool.sol:343)
  • executeRelayerRefundLeaf(): Relayer claims refund with merkle proof
  • executeSlowRelayLeaf(): Protocol fulfills deposit from reserves
UUPS Upgradeability: All SpokePools are UUPS upgradeable proxies, allowing implementation updates while preserving storage and addresses. The upgrade authority is the HubPool via cross-chain messages.

Chain Adapters

Chain adapters are stateless contracts called via delegatecall from the HubPool to bridge tokens and relay messages to each L2. Located in contracts/chain-adapters/. Purpose:
  • Wrap each chain’s native bridge (Arbitrum Inbox, OP Stack messenger, Polygon FxPortal, etc.)
  • Provide a unified interface for cross-chain communication
  • Support multiple bridge types: native bridges, CCTP, LayerZero OFT, Wormhole
Execution Flow:
// HubPool delegates to adapter to send tokens
(bool success, ) = adapter.delegatecall(
    abi.encodeWithSignature(
        "relayTokens(address,address,uint256,address)",
        l1Token,
        l2Token,
        amount,
        spokePool
    )
);

Supported Chains

Across Protocol supports numerous chains through chain-specific SpokePool implementations:

Arbitrum

Arbitrum_SpokePool.sol

Optimism

Optimism_SpokePool.sol

OP Stack

OP_SpokePool.sol

Polygon

Polygon_SpokePool.sol

Polygon zkEVM

PolygonZkEVM_SpokePool.sol

ZkSync

ZkSync_SpokePool.sol

Base

Uses OP_SpokePool.sol

Linea

Linea_SpokePool.sol

Scroll

Scroll_SpokePool.sol

Blast

Blast_SpokePool.sol

Boba

Boba_SpokePool.sol

Ethereum

Ethereum_SpokePool.sol

Lisk

Lisk_SpokePool.sol

World Chain

WorldChain_SpokePool.sol

Lens

Lens_SpokePool.sol

Ink

Ink_SpokePool.sol

Cher

Cher_SpokePool.sol

Universal

Universal_SpokePool.sol
Each chain-specific SpokePool inherits from the base SpokePool.sol contract and overrides the _requireAdminSender() function to implement chain-specific admin verification logic.

Security Model

The protocol uses optimistic verification with a challenge period (default 2 hours) where proposed root bundles can be disputed. If a dispute occurs, UMA’s Optimistic Oracle resolves it.
All SpokePools use the UUPS (Universal Upgradeable Proxy Standard) pattern, allowing logic upgrades without changing contract addresses or storage. Only the HubPool can authorize upgrades.
The HubPool on Ethereum L1 owns all SpokePool contracts across all chains. Admin functions are relayed cross-chain via chain adapters with proper verification.
Data workers must stake a bond when proposing root bundles. Bonds are slashed if proposals are invalid and returned after successful execution.

Development Frameworks

Foundry

Primary framework for new tests and deployment scripts. Use FOUNDRY_PROFILE=local-test for testing.

Hardhat

Legacy framework for older tests. The codebase is migrating to Foundry.

Project Structure

contracts/
├── HubPool.sol              # Central L1 contract
├── SpokePool.sol            # Base spoke pool contract
├── Arbitrum_SpokePool.sol   # Chain-specific implementations
├── Optimism_SpokePool.sol
├── ...
├── chain-adapters/          # Cross-chain bridge adapters
├── interfaces/              # Contract interfaces
└── libraries/               # Shared libraries (MerkleLib, etc.)

test/evm/
├── foundry/                 # Foundry tests
│   ├── local/              # Unit tests
│   └── fork/               # Fork tests
└── hardhat/                # Legacy Hardhat tests

script/                      # Deployment scripts
└── utils/                  # Deployment utilities

Hub-and-Spoke Model

Learn about the hub-and-spoke architecture in detail

Protocol Flow

Understand the complete flow from deposit to refund

Roles

Explore the different participant roles in the protocol

Build docs developers (and LLMs) love