ER1155 Deposit and Withdraw Guide

Quick summary

This section of the docs deal with depositing and withdrawing ERC1155 tokens. Just like the Using SDK section of the docs, the bare skeleton of this page is very much the same as depositing and withdrawing ETH. What stands as a difference are the contracts that are instantiated, and the difference in the methods used. In this section, we'll learn how to instantiate the contracts, deposit, burn, and exit. Let's go.

High Level Flow

Depositing ERC1155

  • Provide approval for the ERC1155PredicateProxy contract to spend the tokens that will be deposited
  • Go on to deposit the tokens by making the depositFor call on RootChainManager.

Withdrawing ERC1155

  • Burn tokens on Polygon chain.
  • Call the exit function and make sure to submit the transaction proof of burn hash. This call is to be made after the checkpoint is submitted for the block containing burn transaction

Details

Let's see what the steps to using the contracts look like

Instantiate the contracts

const mainWeb3 = new Web3(mainProvider)
const maticWeb3 = new Web3(maticProvider)
const rootTokenContract = new mainWeb3.eth.Contract(rootTokenABI, rootTokenAddress)
const rootChainManagerContract = new mainWeb3.eth.Contract(rootChainManagerABI, rootChainManagerAddress)
const childTokenContract = new maticWeb3(childTokenABI, childTokenAddress)

Approve

Provide approval for the ERC1155Predicate to spend tokens by calling the setApprovalForAll method of token contract. This function takes two arguments operator and approved. Operator is the address that is being approved to spend user's tokens. Approved is a boolean indicating if tokens can be spent.

This is what the setApprovalForAll method looks like

await rootTokenContract.methods
.setApprovalForAll(erc1155Predicate, true)
.send({ from: userAddress })

Deposit

Deposit is initiated by calling depositFor on the RootChainManager contract. As always, the token needs to be mapped and approved for transfer before hand. This function takes 3 arguments: user, rootToken and depositData. User is the address of user that will receive the deposit on the Polygon chain, rootToken is the address of token on the main chain while depositData is the abi encoded list of ids, list of tokens and bytes data.

const depositData = mainWeb3.eth.abi.encodeParameters(
['uint256[]', 'uint256[]', 'bytes'],
idList, amountList, data
)
await rootChainManagerContract.methods
.depositFor(userAddress, rootToken, depositData)
.send({ from: userAddress })

Burn

Burning an ERC1155 token involves destroying the token on the Polygon chain by calling the withdrawSingle or withdrawBatch function on the child token contract and making the proof of burn available in the exit step. The withdrawBatch takes 2 arguments, list of ids and list of amounts.

// For single burn
const burnTx = await childTokenContract.methods
.withdrawSingle(id, amount)
.send({ from: userAddress })
const burnTxHash = burnTx.transactionHash
// For batch burn
const burnTx = await childTokenContract.methods
.withdrawBatch(idList, amountList)
.send({ from: userAddress })
const burnTxHash = burnTx.transactionHash

Exit

Exit function on RootChainManager contract has to be called to unlock and receive the tokens back from ERC1155PredicateProxy contract. This function takes a single bytes argument that proves the burn transaction. Wait for the checkpoint containing burn transaction to be submitted before calling this function. The Proof is generated by RLP encoding the following fields -

  • headerNumber - Checkpoint header block number containing the burn transaction
  • blockProof - Proof that the block header (in the child chain) is a leaf in the submitted merkle root
  • blockNumber - Block number containing the burn transaction on child chain
  • blockTime - Burn transaction block time
  • txRoot - Transactions root of block
  • receiptRoot - Receipts root of block
  • receipt - Receipt of the burn transaction
  • receiptProof - Merkle proof of the burn receipt
  • branchMask - 32 bits denoting the path of receipt in merkle patricia tree
  • receiptLogIndex - Log Index to read from the receipt

Generating proof manually can be tricky so it is advisable to use the matic SDK. If you want to send the transaction manually, you can pass encodeAbi as true in the options object to get raw calldata.

const exitCalldata = await maticPOSClient
.exitSingleERC1155(burnTxHash, { from, encodeAbi: true })

Send this calldata to RootChainManager.

await mainWeb3.eth.sendTransaction({
from: userAddress,
to: rootChainManagerAddress,
data: exitCalldata.data
})