Technical Documentation

Portal V2

Technical deep dive into M0's unified cross-chain bridge and messaging system, featuring modular bridge adapters, token bridging, and protocol metadata propagation.

Portal V2 is M0's cross-chain infrastructure for bridging tokens and propagating protocol metadata across multiple blockchains. It replaces the previous dual-implementation model (Portal Standard + Portal Lite) with a unified, modular architecture that supports pluggable bridge adapters.

Overview

Portal V2 serves two core functions in the M0 ecosystem:

  1. Token Bridging - Enables seamless transfer of M0 extension tokens between L1 chains like Ethereum, Solana, and BNB, and supported L2 chains like Arbitrum, Base, and others
  2. Metadata Propagation - Synchronizes critical protocol data (earning index, governance registrar values, earner lists) from L1 to all connected L2s. Also supports notification messages when a cross-chain order is filled or cancelled

Why V2?

The previous portal system offered two separate implementations: Portal Standard (built on Wormhole NTT) and Portal Lite (built on Hyperlane). Each was tightly coupled to its underlying bridge provider.

Portal V2 introduces a bridge adapter abstraction layer that decouples the portal logic from any specific messaging protocol. This enables:

  • Multiple bridge providers - Both Hyperlane and Wormhole are supported simultaneously, with the ability to add more
  • Per-chain bridge selection - Each destination chain can have a different default bridge adapter
  • Unified codebase - A single Portal implementation replaces two separate codebases
  • Configurable cross-spoke transfers - Spoke-to-spoke transfers can be enabled on a per-chain basis (isolated by default)

For background on the previous portal architecture, see M Portals (V1).

Architecture

Portal V2 follows a hub-and-spoke model with Ethereum as the hub chain.

Hub Chain (Ethereum)

The HubPortal contract is deployed on Ethereum - the single source of truth for native issuance and governance. It:

  • Locks tokens when bridging to spoke chains
  • Releases locked tokens when bridged back
  • Tracks bridged principal per spoke chain (for isolated spokes) to ensure it never releases more than was locked
  • Broadcasts the earning index, registrar key/value pairs, and earner list updates to spoke chains
  • Controls earning - can enable/disable earning for the portal, affecting which index is propagated

Spoke Chains (L1s & L2s)

SpokePortal contracts are deployed on each supported chain (Optimism, Arbitrum, Base, Solana, and others). They:

  • Mint token representations when tokens are bridged from the hub
  • Burn representations when tokens are bridged back to the hub
  • Apply index and registrar updates received from the hub
  • Optionally support cross-spoke transfers when enabled by the hub

Bridge Adapter Layer

Bridge adapters are modular contracts that handle the actual cross-chain message delivery. Each adapter:

  • Implements a standard IBridgeAdapter interface
  • Maps internal chain IDs to provider-specific chain IDs
  • Handles quoting, sending, and receiving messages

Current adapters:

AdapterProtocolDelivery Model
HyperlaneBridgeAdapterHyperlaneMailbox dispatch with ISM validation
WormholeBridgeAdapterWormholeCore Bridge publish with Executor-based delivery
LayerZeroBridgeAdapterLayerZeroEndpoint dispatch with DVN validation

Operators can configure a default adapter per destination chain, and users can optionally specify an explicit adapter when sending tokens.

Token Transfer Flow

Hub to Spoke

  1. User calls sendToken() on the HubPortal, specifying amount, destination chain, and recipient
  2. If sending an extension token, the portal unwraps it first
  3. Tokens are locked in the HubPortal; bridged principal is incremented for the destination spoke
  4. A TokenTransfer payload is encoded with the amount, current index, and recipient
  5. The payload is sent via the selected bridge adapter
  6. On the spoke chain, the bridge adapter delivers the message to the SpokePortal
  7. The SpokePortal mints tokens to the recipient (wrapping to an extension if specified)

Spoke to Hub

  1. User calls sendToken() on the SpokePortal
  2. Tokens are burned on the spoke chain
  3. Message is sent back to the Hub via the bridge adapter
  4. The HubPortal verifies that the release amount does not exceed the bridged principal for that spoke
  5. Tokens are released (unlocked) and delivered to the recipient on Ethereum

Spoke to Spoke

Cross-spoke transfers are disabled by default. Each spoke starts in isolated mode, where it can only communicate with the hub.

To enable spoke-to-spoke transfers:

  1. The hub operator calls enableCrossSpokeTokenTransfer() on the HubPortal for the spoke chain
  2. The spoke operator calls enableCrossSpokeTokenTransfer() on the SpokePortal for each peer spoke

Once enabled, tokens are burned on the source spoke and minted on the destination spoke, with a message relayed through the bridge adapter.

Once cross-spoke transfers are enabled for a spoke, the hub stops tracking per-spoke bridged principal for that chain, since tokens can now flow freely between spokes.

Metadata Propagation

Beyond token transfers, Portal V2 propagates critical protocol state from Ethereum to all spoke chains.

Earning Index

The HubPortal broadcasts the current earning index to spoke chains via sendMTokenIndex(). Spoke chains use this index to correctly calculate yield accrual.

  • When earning is enabled on the HubPortal, the live index from the token contract is used
  • When earning is disabled, a frozen index (captured at disable time) is propagated instead
  • Earning can only be enabled once - after being disabled, it cannot be re-enabled

Registrar Data

Governance parameters from M0's TTG (Two Token Governance) system are propagated to spoke chains:

  • Key-value pairs via sendRegistrarKey() - configuration values that govern protocol behavior
  • List membership via sendRegistrarListStatus() - whether accounts are on specific governance lists (e.g., approved earners)

Earner Merkle Roots (SVM)

For Solana spoke chains, the HubPortal can send earner Merkle roots via sendEarnersMerkleRoot(), enabling Solana-based holders to prove their earner status.

OrderBook Integration

Portal V2 integrates with M0's Limit Order Protocol to relay cross-chain fill and cancel reports:

  • Fill Reports - When a solver fills an order on a destination chain, the OrderBook calls sendFillReport() on the portal to relay the fill details back to the origin chain
  • Cancel Reports - When an order is cancelled on the destination chain, sendCancelReport() relays the cancellation back to the origin chain for refund processing

These functions are restricted to the OrderBook contract address.

Message Types

All cross-chain messages share a common header and are differentiated by payload type:

TypeNameDirectionPurpose
0TokenTransferHub ↔ Spoke, Spoke ↔ SpokeBridge tokens between chains
1IndexHub → SpokeBroadcast earning index update
2RegistrarKeyHub → SpokePropagate governance key-value pair
3RegistrarListHub → SpokePropagate governance list membership
4FillReportHub ↔ Spoke, Spoke ↔ SpokeRelay OrderBook fill details
5EarnerMerkleRootHub → Spoke (SVM)Broadcast SVM earners merkle root
6CancelReportHub ↔ Spoke, Spoke ↔ SpokeRelay OrderBook cancel details

Roles and Permissions

Portal V2 uses role-based access control:

RoleCapabilities
Admin (DEFAULT_ADMIN_ROLE)Authorize contract upgrades
Pauser (PAUSER_ROLE)Pause/unpause send and receive operations independently
Operator (OPERATOR_ROLE)Configure bridge adapters, bridging paths, gas limits, cross-spoke transfers

Additionally:

  • Only the OrderBook contract can call sendFillReport() and sendCancelReport()
  • Only registered bridge adapters can call receiveMessage()

Security Features

  • Reentrancy protection - Uses transient storage-based locking to prevent recursive calls
  • Message deduplication - Each message has a unique ID; processed messages are tracked to prevent replay
  • Independent pause controls - Send and receive can be paused separately, allowing partial operation during incidents
  • Per-spoke principal tracking - For isolated spokes, the HubPortal ensures it never releases more tokens than were locked for that specific spoke
  • Earning freeze - The hub can freeze the earning index to manage token supply during transitions
  • Wrap failure fallback - If wrapping to an extension fails on the destination, the recipient receives the underlying token instead of the transaction reverting

Migration from V1

Portal V2 includes migration logic for transitioning from the previous portal system:

  1. Storage from V1 is cleaned using dedicated StorageCleaner contracts
  2. The proxy is upgraded to the V2 implementation
  3. migrateBridgedPrincipal() is called for each existing spoke to set the correct locked amounts
  4. completeMigration() finalizes the process, disabling further migration operations
Copyright © M0 Foundation 2026