Version: Next

Deposit and Checkpoint Events

Deposit Events

When a token is deposited from Ethereum to Matic, a process called state sync mechanism comes into play that eventually mints the tokens for the user on the Matic chain. This process takes about 5-10 minutes to happen and hence listening to the deposit event is very important to create a good user experience. Deposit events can be listened on both the PoS as well as the Plasma bridge.

  • PoS
const WebSocket = require("ws");
const Web3 = require("web3");
// For Mumbai
const ws = new WebSocket("wss://ws-mumbai.matic.today/");
// For Matic mainnet
//const ws = new WebSocket("wss://ws-mainnet.matic.network/");
const web3 = new Web3();
const abiCoder = web3.eth.abi;
// userAccount - user address
// rootToken - contract address on ethereum
// amount - amount deposited on ethereum
// childChainManagerProxy - child chain manager proxy address
async function checkDepositStatus(
userAccount,
rootToken,
depositAmount,
childChainManagerProxy
) {
return new Promise((resolve, reject) => {
ws.on("open", () => {
ws.send(
`{"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 &&
parsedMsg.params.result.Data
) {
const fullData = parsedMsg.params.result.Data;
const { 0: syncType, 1: syncData } = abiCoder.decodeParameters(
["bytes32", "bytes"],
fullData
);
// check if sync is of deposit type (keccak256("DEPOSIT"))
const depositType =
"0x87a7811f4bfedea3d341ad165680ae306b01aaeacc205d227629cf157dd9f821";
if (syncType.toLowerCase() === depositType.toLowerCase()) {
const {
0: userAddress,
1: rootTokenAddress,
2: depositData,
} = abiCoder.decodeParameters(
["address", "address", "bytes"],
syncData
);
// use userAddress, rootTokenAddress to filter deposit
console.log(
"PoS deposit",
"user",
userAddress,
"rootToken",
rootTokenAddress
);
// depositData can be further decoded to get amount, tokenId etc. based on token type
// For ERC20 tokens
const { 0: amount } = abiCoder.decodeParameters(
["uint256"],
depositData
);
console.log("amount", amount);
if (
userAddress.toLowerCase() === userAccount.toLowerCase() &&
rootToken.toLowerCase() === rootTokenAddress.toLowerCase() &&
depositAmount === amount
) {
resolve(true);
}
}
}
});
ws.on("error", () => {
reject(false);
});
ws.on("close", () => {
reject(false);
});
});
});
}
checkDepositStatus(
"0xFd71Dc9721d9ddCF0480A582927c3dCd42f3064C",
"0x47195A03fC3Fc2881D084e8Dc03bD19BE8474E46",
"1000000000000000000",
"0xb5505a6d998549090530911180f38aC5130101c6"
)
.then((res) => {
console.log(res);
})
.catch((err) => {
console.log(err);
});
  • Plasma
const WebSocket = require("ws");
const _ = require("lodash");
// For Mumbai
const ws = new WebSocket("wss://ws-mumbai.matic.today/");
// For Matic mainnet
//const ws = new WebSocket("wss://ws-mainnet.matic.network/");
// user - user address
// token - contract address on ethereum
// childChain - child chain address on ethereum
async function checkDepositStatus(user, token, childChain) {
return new Promise((resolve, reject) => {
ws.on("open", function open() {
ws.send(
`{"id": 1, "method": "eth_subscribe", "params": ["newDeposits", {"Contract": ${childChain}}]}`
);
ws.on("message", function incoming(data) {
var txData = _.get(JSON.parse(data), "params.result.Data", "");
console.log(txData);
var userAddress = txData.substring(0, 64).replace(/^0+/, "0x");
var contractAddress = txData.substring(65, 128).replace(/^0+/, "0x");
if (
user &&
user.toLowerCase() === userAddress.toLowerCase() &&
token &&
token.toLowerCase() === contractAddress.toLowerCase()
) {
console.log(data);
resolve(true); // eslint-disable-line
}
});
ws.on("close", () => {
reject(false);
});
ws.on("error", () => {
reject(false);
});
});
});
}
checkDepositStatus(
"0xFd71Dc9721d9ddCF0480A582927c3dCd42f3064C",
"0x499d11E0b6eAC7c0593d8Fb292DCBbF815Fb29Ae",
"0x1EDd419627Ef40736ec4f8ceffdE671a30803c5e"
)
.then((res) => {
console.log(res);
})
.catch((err) => {
console.log(err);
});

Checkpoint Events

All transactions that occur on Matic chain are check-pointed to the Ethereum chain in frequent intervals of time by the validators. This time is ~10 mins on Mumbai and ~30 mins on Matic mainnet. The checkpoint occurs on a contract called the RootChain contract deployed on Ethereum chain. It is very useful to know if a transaction on Matic has been check-pointed to Ethereum. The checkpointing is common for both the Plasma and PoS.

const Web3 = require("web3");
// Ethereum provider
const provider = new Web3.providers.WebsocketProvider(
"wss://goerli.infura.io/ws/v3/api-key"
);
const web3 = new Web3(provider);
const chil_provider = new Web3.providers.HttpProvider(
"https://rpc-mumbai.matic.today"
);
const child_web3 = new Web3(chil_provider);
// txHash - transaction hash on Matic
// rootChainAddress - root chain proxy address on Ethereum
async function checkInclusion(txHash, rootChainAddress) {
let txDetails = await child_web3.eth.getTransactionReceipt(txHash);
block = txDetails.blockNumber;
return new Promise(async (resolve, reject) => {
web3.eth.subscribe(
"logs",
{
address: rootChainAddress,
},
async (error, result) => {
if (error) {
reject(error);
}
console.log(result);
if (result.data) {
let transaction = web3.eth.abi.decodeParameters(
["uint256", "uint256", "bytes32"],
result.data
);
if (block <= transaction["1"]) {
resolve(result);
}
}
}
);
});
}
// transaction hash of the transaction on matic
checkInclusion(
"0x9d1e61d9daaa12fcd00fcf332e1c06fd8253a949b4f2a4741c964454a67ea943",
"0x2890ba17efe978480615e330ecb65333b880928e"
)
.then((res) => {
console.log(res);
provider.disconnect();
})
.catch((err) => {
console.log(err);
});