DEVELOPER GUIDES

Bridging M and wM Tokens

How to manually bridge M and Wrapped M (wM) tokens across chains with Portal V2 using a block explorer's Write as Proxy interface.

This guide explains how to manually bridge $M and Wrapped $M (w$M) tokens across chains using Portal V2 and a block explorer's "Write as Proxy" interface.

Portal V2 is M0's unified cross-chain bridge. It replaces the previous two-portal system (Portal Standard on Wormhole NTT and Portal Lite on Hyperlane) with a single contract on every chain. The same three-step flow (quote, approve, sendToken) works in every direction: from the hub to a spoke, from a spoke back to the hub, and between spokes where cross-spoke transfers are enabled.

Portal V2 also bridges M0 extension tokens. The steps below use $M and w$M, but the same flow applies when the source or destination token is an extension. If wrapping to an extension fails on the destination chain, the recipient receives the underlying $M token instead.

Prerequisites

  • A Web3 wallet (for example, MetaMask) connected to the source chain.
  • The wallet funded with the token you want to bridge.
  • Native currency on the source chain to pay for gas and the messaging fee (for example, ETH on Ethereum).

How Portal V2 addressing works

Every chain runs one Portal contract:

  • HubPortal on Ethereum locks tokens when you bridge out and releases them when you bridge back.
  • SpokePortal on every other chain mints tokens when they arrive and burns them when you bridge away.

You always interact with the Portal on the chain you are sending from. A few things differ from the old system:

  • Standard EVM chain IDs. The destinationChainId is the destination chain's standard EVM chain ID (for example, Ethereum is 1), not a Wormhole chain ID. The Portal's bridge adapter maps it to the underlying provider internally.
  • bytes32 addresses. The recipient, destinationToken, and refundAddress fields are bytes32, not address. Left-pad a 20-byte EVM address to 32 bytes by prefixing it with 0x followed by 24 zeros (12 bytes), then the 40 hex characters of the address. For example, address 0xABCD...1234 becomes 0x000000000000000000000000ABCD...1234.
  • A messaging fee. Cross-chain delivery costs a fee that you pass as native value on the sendToken call. Read it from quote first.

Supported chains

Portal V2 is live on the chains below. Ethereum is the hub; the rest are spokes. When a step asks for a destinationChainId, use the destination's EVM chain ID from this table.

ChainEVM chain ID
Ethereum (hub)1
Arbitrum42161
Base8453
Linea59144
BNB56
HyperEVM999
Plume98866
Mantra5888
Soneium1868
Plasma9745
Citrea4114
0G16661
Fluent25363
Moca2288
Monad143
Rise4153

Look up each chain's HubPortal / SpokePortal and token addresses on the Deployments page.

Solana is a non-EVM (SVM) chain. It is supported as a spoke, but the addressing and tooling differ. See the Solana docs for Solana-specific steps.

Addresses

Do not hard-code addresses from this guide. Look up the current HubPortal, SpokePortal, $M, and w$M addresses for each chain on the Deployments page.

$M and w$M use 6 decimal places. When entering an amount in a contract call, add 6 zeros. To transfer 10 tokens, enter 10000000.

Bridging with Write as Proxy

The flow below is identical whether you are bridging from Ethereum to a spoke, from a spoke to Ethereum, or between two spokes. Perform every step on the source chain's block explorer (for example, Etherscan for Ethereum, Arbiscan for Arbitrum).

Step 1: Open the source-chain Portal in Write as Proxy

Look up the Portal address for your source chain on the Deployments page. On Ethereum this is the HubPortal; on every other chain it is the SpokePortal.

Open that address on the source chain's block explorer, go to the Contract tab, then Write as Proxy, and connect your wallet.

Step 2: Read the fee with quote

On the Read as Proxy tab, call quote:

  • destinationChainId: the destination chain's standard EVM chain ID (for example, 1 for Ethereum, 42161 for Arbitrum).
  • payloadType: 0 (TokenTransfer).

Note the returned value. This is the messaging fee in the source chain's native currency (in wei). You will pass it as the payable value in Step 4.

Step 3: Approve the Portal to spend your tokens

Open the token you are bridging ($M or w$M) on the source chain's block explorer, go to Write (or Write as Proxy), and call approve:

  • spender: the Portal address from Step 1.
  • amount: the amount to bridge, in base units (6 decimals; see the note above).

Confirm the transaction and wait for it to be mined.

Step 4: Call sendToken

Return to the Portal's Write as Proxy tab and call sendToken:

  • payableAmount (the native value sent with the call): the fee returned by quote in Step 2.
  • amount: the amount to bridge, in base units.
  • sourceToken: the address of the token on the source chain ($M or w$M).
  • destinationChainId: the destination chain's standard EVM chain ID.
  • destinationToken: the bytes32 address of the token you want to receive on the destination chain.
  • recipient: the bytes32 address that receives the tokens on the destination chain.
  • refundAddress: the bytes32 address that receives any leftover native fee on the source chain.
  • bridgeAdapterArgs: leave empty (0x) to use the default bridge adapter for the destination chain.

Confirm the transaction. The Portal locks or burns your tokens on the source chain and emits a TokenSent event with a messageId.

Step 5: Wait for delivery

The selected bridge adapter relays the message to the destination chain, where the Portal mints or releases the tokens to your recipient. Delivery time depends on the underlying bridge provider. You can track the destination Portal for a matching TokenReceived event.

Any native fee you overpay is returned to the refundAddress you provided, so a slightly high quote value is safe.
Copyright © M0 Foundation 2026