zkCRO

On this page, you can find the contracts and their interactions involved when bridging $CRO and $zkCRO to and from Ethereum (L1) and Cronos zkEVM (L2) and unbonding $zkCRO, it includes:

[L1 -> L2] Minting $zkCRO with $CRO

[L2 -> L1] Withdrawing $zkCRO from L2

Unstaking $zkCRO for $CRO


[L1 -> L2] Minting $zkCRO with $CRO

Before we begin, please note that the decimals of $CRO on Ethereum is 8

Developers can refer to this repository for an example script on converting $CRO (on L1 - Ethereum mainnet) to $zkCRO (on L2 - Cronos zkEVM mainnet).

To bridge $CRO Ethereum mainnet (L1) -> Cronos zkEVM mainnet(L2), and obtain $zkCRO on L2, we would need to interact with:

Step 1) Calculating the $CRO amount to bridge

On Ethereum - Using the $zkCRO contract, call theconvertToShare function to calculating the $CRO amount to bridge:

zkCro.convertToShare(_tokenAmount)

Keep this output amount for use in later steps.

Step 2) Approving the zkCROBridge to spend $CRO

On Ethereum - Using the $CRO contract to approve zkCROBridge contract for the amount you want to bridge to zkEVM. Note that the decimals of $CRO on Ethereum is 8.

Step 3) Minting and Bridging $CRO to L2

On Ethereum - Using the ZkCroMintAndBridge contract, call the mintAndBridge function:

function mintAndBridge(
   address _l2Receiver,
   uint256 _zkCroBridgeAmount,
   uint256 _l2GasLimit,
   uint256 _totalCro
)

Once done, it mints $zkCRO and bridges it to Cronos zkEVM, some of the $CRO on the Ethereum side will be consumed in the buffer range set to pay for the gas on Cronos zkEVM.


[L2 -> L1] Withdrawing $zkCRO from L2

From Cronos zkEVM mainnet (L2) -> Ethereum mainnet (L1)

To withdraw $zkCRO fromCronos zkEVM mainnet -> Ethereum mainnet, we would need to interact with the following contract:

Step 1) Initiating a withdrawal transaction

On Cronos zkEvm, call the withdraw function of zkCRO token contract:

function withdraw(address _l1Receiver) external payable;

It will take at least 24 hours before the withdrawal can be finalized on Ethereum. Store the transaction hash from the withdrawal transaction for later steps.

Step 2) Gathering information for $zkCRO withdrawal on L1

Extra information for the L2 -> L1 transaction is required for the next step in claiming the $zkCRO on L1. This information can be gathered by finalizeWithdrawalParams, using zksync-ethers package

finalizeWithdrawalParams(withdrawalHash)

This takes the L2 withdrawal hash as parameters and returns the parameters required for finalizing a withdrawal in the next step.

Example outputs:

{
  l1BatchNumber: 18,
  l2MessageIndex: 59,
  l2TxNumberInBlock: 2919,
  message: '0x6c0960f935f448644c86dbda241ecb57f18a15c80f35a066000000000000000000000000000000000000000000000a2a15d09519be000000',
  sender: '0x000000000000000000000000000000000000800a',
  proof: [
    '0x23ff0fb003a6a6e111f87cff02afc8680944c711abbe792f07ab4206e9efb9a3',
    '0x09fece9c46307f2a0976a3a9b57873e453cf0f4773c2377dcd19f054166aef22',
    '0x33c106ae5601983b53c751129d1921c17e40b69aa3fdbfaf07b7a0e0750d35e4',
    '0x952ffa5de22d99815d9513dd7454949edb2a1cbcf86008f6fa8b169ffe9b4aee',
    '0x8f10560a0b5412ca2e0578fb9266f55411f357d52c8fc3b2cad43b9877a559a6',
    '0x8e70b93d3c90798df26473a3ad32a86170e8d52023a4044cf1d4c2d645471b14',
    '0xdfaacb39891bbbf4509af408239b97a6f5ef715a5c299ba1f3625c20aec4ef8f',
    '0xb04e5ee349086985f74b73971ce9dfe76bbed95c84906c5dffd96504e1e5396c',
    '0xac506ecb5465659b3a927143f6d724f91d8d9c4bdb2463aee111d9aa869874db',
    '0x124b05ec272cecd7538fdafe53b6628d31188ffb6f345139aac3c3c1fd2e470f',
    '0xc3be9cbd19304d84cca3d045e06b8db3acd68c304fc9cd4cbffe6d18036cb13f',
    '0xfef7bd9f889811e59e4076a0174087135f080177302763019adaf531257e3a87',
    '0xa707d1c62d8be699d34cb74804fdd7b4c568b6c1a821066f126c680d4b83e00b',
    '0xf6e093070e0389d2e529d60fadb855fdded54976ec50ac709e3a36ceaa64c291'
  ]
}

Step 3) Claiming the $zkCRO on L1

Once the transaction in Step 1 has been finalized on L1, we can claim the withdrawn $zkCRO from the zk Chain Shared Bridge contract by calling its finalizeWithdrawal function. The inputs can be found in Step 2,

    function finalizeWithdrawal(
            uint256   _chainId,
            uint256   _l2BatchNumber,
            uint256   _l2MessageIndex,
            uint16    _l2TxNumberInBatch,
            bytes calldata _message,
            bytes32 calldata _merkleProof
        )

Once finalizeWithdrawal is completed, the withdrawn amount of $zkCRO will go into the receiver's wallet on Ethereum.

We can use zksync-ethers package isWithdrawalFinalized call to confirm whether the withdrawal transaction is finalized on the L1 network.

isWithdrawalFinalized(withdrawalHash)

Note - If you would like to convert $zkCRO on Ethereum to $CRO, you can do so by unstaking it to obtain the underlying $CRO staked and receive the $CRO on "Cronos EVM Mainnet" . Please refer to the following guide Unstaking $zkCRO for $CRO to complete the process.


Unstaking $zkCRO for $CRO

To redeem $zkCRO fromEthereum mainnet and receive the underlying unstaked $CRO ( on "Cronos EVM Mainnet"), we would need to interact with the following contracts:

Step 1) Approving $zkCRO to be spend by zkCRO token contract

On Ethereum, approve $zkCRO to be spent by zkCRO contract with appropriate amount.

Step 2) Unstaking $zkCRO to recieve $LCRO

On Ethereum, call the unstake function on the zkCRO token contract:

function unstake(
        address _receiver, 
        uint256 _shareAmount
        )

Once done, $LCRO token will be automatically released within 24 hours and transfer to the _receiver address of "Cronos EVM mainnet".

Step 3) Approving $LCRO spent

On Cronos EVM mainnet, approve $LCRO to be spent by $LCRO contract with appropriate amount

Step 4) Unbonding $LCRO

On Cronos EVM mainnet, call requestUnbond on the LCRO token contract,

function requestUnbond(
        uint256 _shareAmount, 
        address _receiver
        )

Once done you will receive an NFT (vnoNFT) in return. Wait for batch of unbonding to be processed which takes 28-32 days.

Step 5) Approving NFT to be spend by LCRO contract

On Cronos EVM mainnet, call setApprovalForAll on the vnoNFT contract, to approve to transfer of the vnoNFT obtained in Step 4)

setApprovalForAll(
        address operator, 
        bool _approved
        )

Step 6) Withdrawing $CRO

On Cronos EVM mainnet, call unbond function on the LCRO token contract to burn the receipt NFT and receive the underlying unstaked $CRO.

 function unbond(
        uint256 _tokenId, 
        address _receiver
        )

This transaction burns the receipt NFT and sends the unstaked $CRO to the specified receiver.

Last updated