Deposit and Checkpoint Event Tracking - PoS

Quick Summary:

This section of the docs deal with tracking and monitoring the pace and speed of transactions done within the Polygon ecosystem. Depositing into the network (when done with the PoS bridge) typically takes an average of 5-7 minutes but we've seen instances where users seek to see real time progress reports. As a developer, you may also want to augment the UX of your app with instant feedback to the user. In all these cases, look into this section, we have exactly what you need.

Deposit Events

When a user deposits a token from Ethereum to Polygon, the State Sync Mechanism is triggered. If you didn't click on that link, the state sync mechanism is simply the native mechanism that reads Ethereum data from Polygon EVM chain and establishes a balance between the two chains. Over a process that lasts for 5-7 minutes, the mechanism mints the equivalent value of the Ethereum tokens deposits on the Polygon chain for the user. As this takes a small amount of time, it is sometimes good UX to listen to the event stream and track it to see when it starts and ends.

Realtime deposit event tracking using a web socket connection

The fastest route to seeing the stream of the connection and intermittently checking to see its process is via a WebSocket protocol. This is what your sample script should look like

const WebSocket = require("ws");
const Web3 = require("web3");
// For Mumbai
const ws = new WebSocket("wss://");
// For Matic mainnet: wss://
const web3 = new Web3();
const abiCoder = web3.eth.abi;
async function checkDepositStatus(
) {
return new Promise((resolve, reject) => {
ws.on("open", () => {
`{"id": 1, "method": "eth_subscribe", "params": ["newDeposits", {"Contract": ${childChainManagerProxy}}]}`
ws.on("message", (msg) => {
const parsedMsg = JSON.parse(msg);
if (
parsedMsg &&
parsedMsg.params &&
parsedMsg.params.result &&
) {
const fullData = parsedMsg.params.result.Data;
const { 0: syncType, 1: syncData } = abiCoder.decodeParameters(
["bytes32", "bytes"],
// check if sync is of deposit type (keccak256("DEPOSIT"))
const depositType =
if (syncType.toLowerCase() === depositType.toLowerCase()) {
const {
0: userAddress,
1: rootTokenAddress,
2: depositData,
} = abiCoder.decodeParameters(
["address", "address", "bytes"],
// depositData can be further decoded to get amount, tokenId etc. based on token type
// For ERC20 tokens
const { 0: amount } = abiCoder.decodeParameters(
if (
userAddress.toLowerCase() === userAccount.toLowerCase() &&
rootToken.toLowerCase() === rootTokenAddress.toLowerCase() &&
depositAmount === amount
) {
ws.on("error", () => {
ws.on("close", () => {
// Param1 - user address
// Param2 - contract address on main chain
// Param3 - amount deposited on main chain
// Param4 - child chain manager proxy address (0xA6FA4fB5f76172d178d61B04b0ecd319C5d1C0aa for mainnet)
.then((res) => {
.catch((err) => {

Historical Checkpoint Inclusion Check by querying the blockchain

This can be checked using the following API. The block number of the burn transaction on the child chain has to be given as a param to this GET API.

// Testnet
// Mainnet