Transfer a token on L2


Transfer a token on L2

Prerequisites

Setup

1. Create a project folder and cd into it

mkdir transfer-l2
cd transfer-l2

2. Add the libraries

yarn add zksync-ethers@5 ethers@5 typescript @types/node ts-node

Step-by-step

1. Create a script

touch transfer-l2.ts

2. Import the libraries

Open the file and add the following imports:

import * as zksync from "zksync-ethers";
import * as ethers from "ethers";

3. Create a wallet for the sender

Tips

Check the JSON-RPC API doc for the correct RPC endpoint URL.

Create a zkSync Era provider on testnet and use it to build a zkSync Era wallet, replacing <SENDER-PRIVATE-KEY> with your private key.

const zkSyncProvider = new zksync.Provider("https://sepolia.era.zksync.dev");
const zkSyncWallet = new zksync.Wallet("<SENDER-PRIVATE-KEY>", zkSyncProvider);

4. Store the recipient's public key

Save the recipient's wallet address to a variable, replacing <RECIPIENT-PUBLIC-KEY> with their public key.

const receiverWallet = "<RECIPIENT-PUBLIC-KEY>";

5. Store the token information

const l2TokenName = "MCRN";
const l2TokenAddress = "0xAFe4cA0Bbe6215cBdA12857e723134Bc3809F766";

6. Transfer tokens to the recipient

async function l2transfer() {
  // Amount of Token to transfer
  const amount = ethers.BigNumber.from("100000000"); // 0.0000000001
  console.log(`Amount of token to transfer: ${ethers.utils.formatEther(amount)} ${l2TokenName}`);

  // Log the balance of the accounts before transferring
  console.log(`FROM this L2 wallet: "${ethers.utils.formatUnits(await zkSyncProvider.getBalance(zkSyncWallet.address, "latest", l2TokenAddress), 18)}" ${l2TokenName}`);
  console.log(`TO receiver account: "${ethers.utils.formatUnits(await zkSyncProvider.getBalance(receiverWallet, "latest", l2TokenAddress), 18)}" ${l2TokenName}`);

  const transfer = await zkSyncWallet.transfer({
    to: receiverWallet,
    token: l2TokenAddress,
    amount,
  });

  // Await commitment
  const transferReceipt = await transfer.wait();
  console.log(`Tx transfer hash for ${l2TokenName}: ${transferReceipt.blockHash}`);

  // Show the balance of wallets after transfer
  console.log(`FROM this L2 wallet: "${ethers.utils.formatUnits(await zkSyncProvider.getBalance(zkSyncWallet.address, "latest", l2TokenAddress), 18)}" ${l2TokenName}`);
  console.log(`TO receiver wallet: "${ethers.utils.formatUnits(await zkSyncProvider.getBalance(receiverWallet, "latest", l2TokenAddress), 18)}" ${l2TokenName}`);
}

7. Code the call to the transfer function

l2transfer();

Full code

// Import the relevant libraries
import * as zksync from "zksync-ethers";
import * as ethers from "ethers";

// Create zkSync Era provider on testnet
const zkSyncProvider = new zksync.Provider("https://sepolia.era.zksync.dev");

// Create a zkSync wallet for the sender
const zkSyncWallet = new zksync.Wallet("<SENDER-PRIVATE-KEY>", zkSyncProvider);

// Store the recipient public key
const receiverWallet = "<RECIPIENT-PUBLIC-KEY>";

// Store the L2 token address
const l2TokenName = "MCRN";
const l2TokenAddress = "0xAFe4cA0Bbe6215cBdA12857e723134Bc3809F766";

async function l2transfer() {
  // Amount of Token to transfer
  const amount = ethers.BigNumber.from("100000000"); // 0.0000000001
  console.log(`Amount of token to transfer: ${ethers.utils.formatEther(amount)} ${l2TokenName}`);

  // Log the balance of the accounts before transferring
  console.log(`FROM this L2 wallet: "${ethers.utils.formatUnits(await zkSyncProvider.getBalance(zkSyncWallet.address, "latest", l2TokenAddress), 18)}" ${l2TokenName}`);
  console.log(`TO receiver account: "${ethers.utils.formatUnits(await zkSyncProvider.getBalance(receiverWallet, "latest", l2TokenAddress), 18)}" ${l2TokenName}`);

  const transfer = await zkSyncWallet.transfer({
    to: receiverWallet,
    token: l2TokenAddress,
    amount,
  });

  // Await commitment
  const transferReceipt = await transfer.wait();
  console.log(`Tx transfer hash for ${l2TokenName}: ${transferReceipt.blockHash}`);

  // Show the balance of wallets after transfer
  console.log(`FROM this L2 wallet: "${ethers.utils.formatUnits(await zkSyncProvider.getBalance(zkSyncWallet.address, "latest", l2TokenAddress), 18)}" ${l2TokenName}`);
  console.log(`TO receiver wallet: "${ethers.utils.formatUnits(await zkSyncProvider.getBalance(receiverWallet, "latest", l2TokenAddress), 18)}" ${l2TokenName}`);
}

l2transfer();

Run the script

yarn ts-node transfer-l2.ts

Tips

Try running the ts-node transfer-l2.ts command in case you receive an error with yarn ts-node transfer-l2.ts.

Output

You should see output like this:

Amount of token to transfer: 0.0000000001 MCRN
FROM this L2 wallet: "0.00000004530161678" MCRN
TO receiver account: "0.0000000001" MCRN
Tx transfer hash for MCRN: 0x254d63addbf4bfaa3e584e6e9a211d769fc0dd56844ae2caa92a3f305c6c0d04
FROM this L2 wallet: "0.00000004520161678" MCRN
TO receiver wallet: "0.0000000002" MCRN
✨  Done in 4.65s.