Skip to main content

Send ERC20 Tokens by using the SDK

Introduction

This page demonstrates how to use the SDK in order to send ERC20 tokens between two mainnet EVM-compatible chains.

To get started with Nexera SDK, follow the example script provided below. The example uses ethers.js to transfer an ERC20 token from a wallet address on Arbitrum mainnet to the same wallet address on Ethereum mainnet.

⚠️ The current SDK version available, for contracts currently deployed on mainnet, is v4.4.10. This version might be changed in the near future since new versions of contracts will be released soon. Please keep up to date with the latest version.

SDK Installation

To install the SDK in your project, use the following command:

npm install @stichting-allianceblock-foundation/abridge-sdk

Usage example

Next, you will find the sample script for the usage of the SDK. More details about it, including configuration and description of how to use it are below.

  • In your terminal initialize a node project and install the necessary dependencies
npm init
npm install @stichting-allianceblock-foundation/abridge-sdk@4.4.10
npm install ethers@5.6.6
touch index.js
  • In the index.js file paste the following code and update the constants with your preferences
// index.js

import { ethers } from "ethers";
import {
TeleportSDKFactory,
ERC20RouterSDK,
constants,
} from "@stichting-allianceblock-foundation/abridge-sdk";

const PRIVATE_KEY = "YOUR PRIVATE KEY";
const RPC_URL = "RPC URL OF THE SOURCE NETWORK";
const RECEIVER_ADDRESS = "RECEIVER ADDRESS";
const TOKEN_ADDRESS = "TOKEN ADDRESS";
const AMOUNT = ethers.utils.parseEther("AMOUNT");
const TARGET_CHAIN_ID = "TARGET CHAIN ID";
const PROVIDER = new ethers.providers.JsonRpcProvider(RPC_URL);
const SIGNER = new ethers.Wallet(PRIVATE_KEY, PROVIDER);

const main = async () => {
let payableCall;
let contractTransactionResult;
let receiptTx;

console.log("Signer address:", SIGNER.address);
console.log(
"ETH balance:",
ethers.utils.formatUnits(await PROVIDER.getBalance(SIGNER.address), "ether")
);
// The second argument is a reduced version of the ERC20 Token ABI to bridge
const tokenContract = new ethers.Contract(
TOKEN_ADDRESS,
["function balanceOf(address owner) view returns (uint256)"],
PROVIDER
);
console.log(
"Token balance:",
ethers.utils.formatUnits(
await tokenContract.balanceOf(SIGNER.address),
"ether"
)
);

// 1) Initialize the SDK instance
const sdk = await TeleportSDKFactory.create({
chainType: constants.ChainType.EVM,
signerOrProvider: SIGNER,
});

// 2) Check allowed amount granted by the user to the router
const currentAllowance = await sdk
.dapp(ERC20RouterSDK.DAPP_NAME)
.allowance(TOKEN_ADDRESS, SIGNER.address);

console.log(
"Allowance:",
ethers.utils.formatUnits(currentAllowance.allowance, "ether")
);

if (currentAllowance.allowance < AMOUNT) {
console.log("Approving token amount", AMOUNT.toString());

payableCall = await sdk
.dapp(ERC20RouterSDK.DAPP_NAME)
.approve(TOKEN_ADDRESS, AMOUNT);

contractTransactionResult = await payableCall.sendTransaction();
receiptTx = await contractTransactionResult.wait();
if (receiptTx.status === 1) {
console.log("Token amount succesfully approved");
}

const newCurrentAllowance = await sdk
.dapp(ERC20RouterSDK.DAPP_NAME)
.allowance(TOKEN_ADDRESS, SIGNER.address);

console.log(
"new Allowance:",
ethers.utils.formatUnits(newCurrentAllowance.allowance, "ether")
);
}

// 3) Call the sendErc20 method to transfer/bridge tokens between networks
const options = {
targetChainId: Number(TARGET_CHAIN_ID),
tokenAddress: TOKEN_ADDRESS,
amount: AMOUNT,
receiverAddress: RECEIVER_ADDRESS,
feeTokenAddress: ethers.constants.AddressZero,
};

console.log("options): ", options);

payableCall = await sdk.dapp(ERC20RouterSDK.DAPP_NAME).sendErc20(options);

contractTransactionResult = await payableCall.sendTransaction();
console.log("Tx hash:", contractTransactionResult.hash);
receiptTx = await contractTransactionResult.wait();

if (receiptTx.status === 1) {
console.log("Token succesfully sent");
}

console.log("end");
};

await main();
  • Finally in your terminal run node with the flag --en-module-specifier-resolution=node
node --es-module-specifier-resolution=node ./index.js

Initial configuration for the script

In order to be able to use this script accordingly you need to configure the following values at the top of it:

  • privateKey: Replace it with your private key. Do not share it with others, use environment variables instead if you want to share this file.
  • provider: Replace it with any provider built from the RPC url of any supported network.
  • tokenAddress: Replace it with the ERC20 token address you have available in the source network where the transaction will start.
  • targetChainId: A number representing the Nexera Messaging Protocol chainId for the destination network. This value can also be viewed in the supported networks page.

Script description

This is a simple 3-step flow script for transfering/bridging the token from a network to another.

Steps:

  1. In this first step, you initialize the SDK instance by creating it with the EVM compatible chain type, and providing a signerOrProvider:
const sdk = await TeleportSDKFactory.create({
chainType: constants.ChainType.EVM,
signerOrProvider,
});

chainType: The type of blockchain network to connect to. This can be either EVM or SOLANA.

signerOrProvider: The wallet provider to use for signing transactions. This can be either a JsonRpcSigner instance (userWallet) or a JsonRpcProvider instance.

  1. In this second step, you check the allowed amount granted by the user to the ERC20 router. If the granted amount is lower than the amount you want to transfer, the approve command will be executed.
  • Check allowance
const currentAllowance = await sdk
.dapp<ERC20RouterSDK>(ERC20RouterSDK.DAPP_NAME)
.allowance(tokenAddress, signerOrProvider.address);
  • Approve amount to router
await sdk
.dapp<ERC20RouterSDK>(ERC20RouterSDK.DAPP_NAME)
.approve(tokenAddress, amount);
  1. In this final step, you call the sendErc20 method to transfer/bridge tokens from Arbitrum to Ethereum network.
await sdk.dapp<ERC20RouterSDK>(ERC20RouterSDK.DAPP_NAME).sendErc20(options);

Use the Chainlink CCIP explorer in order to find the transactions executed in both networks by inserting the obtained "Tx hash" into the search field of the explorer.