Portal V2
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:
- 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
- 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
IBridgeAdapterinterface - Maps internal chain IDs to provider-specific chain IDs
- Handles quoting, sending, and receiving messages
Current adapters:
| Adapter | Protocol | Delivery Model |
|---|---|---|
HyperlaneBridgeAdapter | Hyperlane | Mailbox dispatch with ISM validation |
WormholeBridgeAdapter | Wormhole | Core Bridge publish with Executor-based delivery |
LayerZeroBridgeAdapter | LayerZero | Endpoint 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
- User calls
sendToken()on theHubPortal, specifying amount, destination chain, and recipient - If sending an extension token, the portal unwraps it first
- Tokens are locked in the
HubPortal; bridged principal is incremented for the destination spoke - A
TokenTransferpayload is encoded with the amount, current index, and recipient - The payload is sent via the selected bridge adapter
- On the spoke chain, the bridge adapter delivers the message to the
SpokePortal - The
SpokePortalmints tokens to the recipient (wrapping to an extension if specified)
Spoke to Hub
- User calls
sendToken()on theSpokePortal - Tokens are burned on the spoke chain
- Message is sent back to the Hub via the bridge adapter
- The
HubPortalverifies that the release amount does not exceed the bridged principal for that spoke - 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:
- The hub operator calls
enableCrossSpokeTokenTransfer()on theHubPortalfor the spoke chain - The spoke operator calls
enableCrossSpokeTokenTransfer()on theSpokePortalfor 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.
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
OrderBookcallssendFillReport()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:
| Type | Name | Direction | Purpose |
|---|---|---|---|
| 0 | TokenTransfer | Hub ↔ Spoke, Spoke ↔ Spoke | Bridge tokens between chains |
| 1 | Index | Hub → Spoke | Broadcast earning index update |
| 2 | RegistrarKey | Hub → Spoke | Propagate governance key-value pair |
| 3 | RegistrarList | Hub → Spoke | Propagate governance list membership |
| 4 | FillReport | Hub ↔ Spoke, Spoke ↔ Spoke | Relay OrderBook fill details |
| 5 | EarnerMerkleRoot | Hub → Spoke (SVM) | Broadcast SVM earners merkle root |
| 6 | CancelReport | Hub ↔ Spoke, Spoke ↔ Spoke | Relay OrderBook cancel details |
Roles and Permissions
Portal V2 uses role-based access control:
| Role | Capabilities |
|---|---|
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()andsendCancelReport() - 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
HubPortalensures 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:
- Storage from V1 is cleaned using dedicated
StorageCleanercontracts - The proxy is upgraded to the V2 implementation
migrateBridgedPrincipal()is called for each existing spoke to set the correct locked amountscompleteMigration()finalizes the process, disabling further migration operations
Related
- Accessing Liquidity - Overview of M0's liquidity infrastructure
- Limit Order Protocol - Onchain settlement layer for cross-chain swaps
- M Portals (V1) - Previous portal architecture reference
- Cross-Chain - Guide to deploying and bridging stablecoins across networks
- Source Code - Smart contract repository
Minting & Burning (MinterGateway)
Complete documentation of the MinterGateway contract, the central hub for minting and burning, managing minter collateral, and tracking debt obligations.
Rate Models & Yield
Detailed documentation of the interest rate models that govern minter obligations and earner yield within the M0 Protocol.