Skip to main content

ERC20 Deposit and Withdraw Guide

Check out the latest Matic.js Documentation on ERC20.

This tutorial uses the Polygon Testnet ( Mumbai ) which is mapped to the Goerli Network to demonstrate the asset transfer to and fro the two blockchains. An important thing to be noted while following this tutorial is that you should always use a Proxy address whenever it is available. For example, the RootChainManagerProxy address has to be used for interaction instead of the RootChainManager address. The PoS contract addresses, ABI, Test Token Addresses and other deployment details of the PoS bridge contracts can be found here.

Mapping your assets is necessary to integrate the PoS bridge on your application. You can submit a mapping request here. But for the purpose of this tutorial, we have already deployed the Test tokens and mapped them on the PoS bridge. You may need it for trying out the tutorial on your own. You can request the desired Asset from the faucet. If the test tokens are unavailable on the faucet, do reach us on discord.

In the upcoming tutorial, every step will be explained in detail along with a few code snippets. However, you can always refer to this repository which will have all the example source code that can help you to integrate and understand the working of PoS bridge.

High Level Flow

Deposit ERC20 -

  1. Approve ERC20Predicate contract to spend the tokens that have to be deposited.
  2. Make depositFor call on RootChainManager.

Withdraw ERC20 -

  1. Burn tokens on the Polygon chain.
  2. Call the exit() function on RootChainManager to submit proof of burn transaction. This call can be made after the checkpoint is submitted for the block containing the burn transaction.

Steps Details

Approve

This is a normal ERC20 approval so that ERC20Predicate can call transferFrom function. Polygon POS client exposes approve method to make this call.

const execute = async () => {
const client = await getPOSClient();
const erc20RootToken = posClient.erc20(<root token address>,true);
const approveResult = await erc20Token.approve(100);
const txHash = await approveResult.getTransactionHash();
const txReceipt = await approveResult.getReceipt();
}

Deposit

Note that the token needs to be mapped and approved for transfer beforehand. Polygon PoS client exposes the deposit() method to make this call.

const execute = async () => {
const client = await getPOSClient();
const erc20RootToken = posClient.erc20(<root token address>, true);

//deposit 100 to user address
const result = await erc20Token.deposit(100, <user address>);
const txHash = await result.getTransactionHash();
const txReceipt = await result.getReceipt();

}
note

Deposits from Ethereum to Polygon happen using a State Sync mechanism and take about 22-30 minutes. After waiting for this time interval, it is recommended to check the balance using the web3.js/matic.js library or using Metamask. The explorer will show the balance only if at least one asset transfer has happened on the child chain. This link explains how to track deposit events.

WithdrawStart method to Burn

The withdrawStart() method can be used to initiate the withdrawal process which will burn the specified amount on the Polygon chain.

const execute = async () => {
const client = await getPOSClient();
const erc20Token = posClient.erc20(<child token address>);

// start withdraw process for 100 amount
const result = await erc20Token.withdrawStart(100);
const txHash = await result.getTransactionHash();
const txReceipt = await result.getReceipt();
}

Store the transaction hash for this call and use it while generating burn proof.

Exit

Once the checkpoint has been submitted for the block containing the burn transaction, the user should call the exit() function of the RootChainManager contract and submit the proof of burn. Upon submitting valid proof, tokens are transferred to the user. Polygon PoS client exposes the withdrawExit method to make this call. This function can be called only after the checkpoint is included in the main chain. The checkpoint inclusion can be tracked by following this guide.

withdrawExit method can be used to exit the withdraw process by using the txHash from withdrawStart method.

note

The withdrawStart transaction must be checkpointed in order to exit the withdraw.

const execute = async () => {
const client = await getPOSClient();
const erc20RootToken = posClient.erc20(<root token address>, true);
const result = await erc20Token.withdrawExit(<burn tx hash>);
const txHash = await result.getTransactionHash();
const txReceipt = await result.getReceipt();
}