Ethereum to Polygon (L1 to L2)
Data flows from Ethereum to Polygon via the state sync mechanism. A contract on Ethereum callssyncState on the StateSender contract, which emits a StateSynced event. Heimdall validators relay this event to Bor, which calls onStateReceive on the target contract on Polygon within a single sprint (approximately 16 blocks, or a few minutes).
This mechanism is used internally by both the PoS token bridge and FxPortal. You can also use it directly for arbitrary data, subject to the registration requirement described below.
For a step-by-step implementation, see Ethereum to PoS.
Registration requirement
Sender/receiver pairs must be registered withStateSender before state sync will relay events between them. This registration authorizes the pair: Heimdall only processes StateSynced events from registered sender contracts targeting registered receiver contracts.
Registration is managed by the Polygon team. Contact the team on Discord or via the mapping request form to register a new pair.
Security in receiver contracts
TheonStateReceive function on Polygon is called by the StateReceiver system contract at address 0x0000000000000000000000000000000000001001. Always verify msg.sender against this address in your receiver implementation. Without this check, any address on Polygon can call onStateReceive directly and inject arbitrary data.
See the state sync architecture docs for a full description of how state sync works.
Polygon to Ethereum (L2 to L1)
Data flows from Polygon back to Ethereum via the checkpoint and exit mechanism. There is no continuous message relay in this direction. Instead:- A transaction on Polygon emits an event containing the data to transfer.
- The transaction is included in a Polygon checkpoint, which is committed to Ethereum roughly every 30 minutes.
- After the checkpoint is finalized on Ethereum, anyone can submit an exit proof to
RootChainManageron Ethereum to trigger the corresponding state change on the root contract.
Choosing the right approach
| Need | Recommended approach |
|---|---|
| Bridge a standard ERC-20, ERC-721, or ERC-1155 token | Submit a mapping request and use the PoS bridge contracts |
| Send arbitrary data from Ethereum to Polygon without custom registration | Use FxPortal (FxRoot / FxChild) |
| Send arbitrary data from Ethereum to Polygon with a custom registered pair | Raw state sync via StateSender |
| Send data from Polygon back to Ethereum | Checkpoint and exit via RootChainManager |
withdraw on the child ERC-20 contract on Polygon to burn tokens, then after checkpoint, call exit on RootChainManager on Ethereum to release the funds to your target address.
Contract reference
The following contracts are used for L1-L2 messaging on mainnet. Source addresses are from the canonical network config.State sync
These are the low-level contracts that underpin all L1-to-L2 messaging on Polygon PoS.| Contract | Network | Address | Purpose |
|---|---|---|---|
StateSender | Ethereum | 0x28e4F3a7f651294B9564800b2D01f35189A5bFbE | Entry point for L1→L2 messages. Registered sender contracts call syncState here. |
StateReceiver | Polygon | 0x0000000000000000000000000000000000001001 | Genesis contract that delivers state sync messages on Polygon by calling onStateReceive on the target contract. |
FxPortal
FxPortal is Polygon’s pre-registered messaging layer built on top of state sync.FxRoot is already registered as a sender in StateSender, and FxChild is its registered receiver on Polygon. You can inherit from FxBaseRootTunnel and FxBaseChildTunnel to build bidirectional messaging without needing custom registration.
| Contract | Network | Address | Purpose |
|---|---|---|---|
FxRoot | Ethereum | 0xfe5e5D361b2ad62c541bAb87C45a0B9B018389a2 | Ethereum-side entry point for FxPortal. Calls syncState on StateSender. |
FxChild | Polygon | 0x8397259c983751DAf40400790063935a11afa28a | Polygon-side receiver for FxPortal. Called by StateReceiver and routes messages to child tunnel contracts. |
FxERC20RootTunnel | Ethereum | 0x0cc2caed31490b546c741bd93dbba8ab387f7f2c | FxPortal tunnel for bridging ERC-20 tokens via FxRoot. |
FxERC721RootTunnel | Ethereum | 0xca1f5ec720eCdA31bE3d80BD3ef4686cBb07eb4D | FxPortal tunnel for bridging ERC-721 tokens via FxRoot. |
FxERC20ChildTunnel | Polygon | 0xd531Cf2142D9b9Dc8b077dF3c4E93B46E7Cf879a | Polygon-side counterpart to FxERC20RootTunnel. |
FxERC721ChildTunnel | Polygon | 0x2b4732e448b3023131a7b25046b3A5EF50CfCf71 | Polygon-side counterpart to FxERC721RootTunnel. |
PoS token bridge
These contracts handle token deposits and withdrawals through the official PoS bridge. Use these when bridging mapped ERC-20, ERC-721, or ERC-1155 tokens rather than arbitrary data.| Contract | Network | Address | Purpose |
|---|---|---|---|
RootChainManagerProxy | Ethereum | 0xA0c68C638235ee32657e8f720a23ceC1bFc77C77 | Main entry point for PoS token bridge on Ethereum. Call depositFor to deposit tokens and exit to finalize withdrawals after checkpoint. |
ChildChainManagerProxy | Polygon | 0xA6FA4fB5f76172d178d61B04b0ecd319C5d1C0aa | Polygon-side manager. Mints tokens on deposit and processes burns on withdrawal. |
ERC20PredicateProxy | Ethereum | 0x40ec5B33f54e0E8A33A975908C5BA1c14e5BbbDf | Locks ERC-20 tokens on Ethereum on deposit; releases them on exit. |
ERC721PredicateProxy | Ethereum | 0xE6F45376f64e1F568BD1404C155e5fFD2F80F7AD | Locks ERC-721 tokens on Ethereum on deposit; releases them on exit. |
ERC1155PredicateProxy | Ethereum | 0x0B9020d4E32990D67559b1317c7BF0C15D6EB88f | Locks ERC-1155 tokens on Ethereum on deposit; releases them on exit. |