Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.polygon.technology/llms.txt

Use this file to discover all available pages before exploring further.

This guide demonstrates transferring a uint256 value from Polygon PoS to Ethereum. The same approach applies to any data type: encode the data as bytes, emit it from the child contract, then decode it in the root contract after checkpoint verification. For background on the checkpoint and predicate mechanism, see the state sync architecture docs.
The contracts in this guide are simplified illustrations. Do not deploy them to production without a thorough security review and audit appropriate for your use case.

Implementation

1
Deploy contracts
2
Create the child contract on Polygon PoS and the root contract on Ethereum. The function that performs the state change must emit an event whose parameters include the data to transfer.
3
Child.sol
pragma solidity ^0.8.0;

contract Child {
    event Data(address indexed from, bytes bytesData);

    uint256 public data;

    function setData(bytes memory bytesData) public {
        data = abi.decode(bytesData, (uint256));
        emit Data(msg.sender, bytesData);
    }
}
Root.sol
pragma solidity ^0.8.0;

contract Root {
    address public predicate;

    constructor(address _predicate) {
        predicate = _predicate;
    }

    modifier onlyPredicate() {
        require(msg.sender == predicate, "unauthorized");
        _;
    }

    uint256 public data;

    function setData(bytes memory bytesData) public onlyPredicate {
        data = abi.decode(bytesData, (uint256));
    }
}
4
Pass 0x1470E07a6dD1D11eAE439Acaa6971C941C9EF48f as the _predicate value in the Root constructor. The onlyPredicate modifier ensures that only the predicate contract can update state on the root contract. The predicate is invoked by RootChainManager on Ethereum after it verifies the transaction against a Polygon checkpoint, guaranteeing state changes on Ethereum reflect verified Polygon activity.
5
Map your contracts
6
Once both contracts are deployed, submit a mapping request so the PoS bridge recognizes the child/root pair. See the submit a mapping request guide for steps.
7
Already working with a widely used token? The Polygon Portal lists tokens that are already mapped and available for bridging without a new mapping request.
8
Initiate a transfer on Polygon
9
Call setData on the child contract with the encoded value you want to transfer. Wait for the transaction to be included in a Polygon checkpoint. Checkpoints are submitted to Ethereum roughly every 30 minutes.
10
You can verify checkpoint inclusion using the Polygon checkpoint tracker or by polling the RootChainManager on Ethereum.
11
Exit on Ethereum
12
After the checkpoint is confirmed, call exit on RootChainManager on Ethereum to finalize the transfer. You need the transaction hash of the setData call on Polygon and the keccak-256 hash of the Data event signature.
13
The logEventSignature for the Data(address,bytes) event is:
14
0x93f3e547dcb3ce9c356bb293f12e44f70fc24105d675b782bd639333aab70df7
15
Using matic.js:
16
import { POSClient, use } from "@maticnetwork/maticjs";

const client = new POSClient();
await client.init({ network: "mainnet", version: "v1" });

const txHash = "0x<YOUR_POLYGON_TX_HASH>";
const logEventSignature = "0x93f3e547dcb3ce9c356bb293f12e44f70fc24105d675b782bd639333aab70df7";

const tx = await client.exitUtil.buildPayloadForExit(txHash, logEventSignature, false);
17
Alternatively, call exit(bytes calldata inputData) directly on RootChainManager at 0xA0c68C638235ee32657e8f720a23ceC1bfc77C77 on Ethereum mainnet, constructing the proof payload from the burn receipt.
18
Once the exit transaction is confirmed, query the data variable on the root contract to verify the value has been reflected on Ethereum.
The full contract source and exit script for this example are available in the matic-learn-pos repository.