In the previous article, I explained about how to deploy your own ERC-20 or ERC-721 tokens to Ethereum and Loom Network. (If you haven't read it, click HERE.)  Today, I'll let you know how you can map those two contracts so that your users can transfer your assets between two blockchains.


EVM(Ethereum Virtual Machine)

EVM is a virtual machine that is shipped with every Ethereum node that runs smart contracts that are deployed on the blockchain. It was designed by Vitalik Buterin and open sourced. What's interesting is, Loom Network is interoperable with Ethereum and it also supports EVM. That's why your ERC-20 could have been deployed to Loom Network just like they were to to Ethereum in the last article. These two blockchains share the same virtual machine so if one of your smart contracts is working on Ethereum then it should also work on Loom Network.

Account Mapping

Even though Ethereum and Loom Network share the same computing mechanism for smart contracts, EVM, they are separate blockchains. So first you need to do is to map your accounts on both chains. If you skip this step, you cannot properly setup your ERC-20 asset to work on both blockchains.

Let's add a script named add_account_mapping.js under scripts directory.

const LoomX = require("@web3-guru/loom-x/dist").default;

require("dotenv").config();

module.exports = async () => {
   const loomX = LoomX.fromMnemonic(process.env.MNEMONIC);
   await loomX.loom.mapAccounts(loomX.ethereum);
};

This script maps your Ethereum account address and Loom Network account address.

To execute it:

$ truffle exec scripts/add_account_mapping.js

That's it! Now your addresses were mapped so you can start doing other stuffs with your accounts on both chains.

Contract Mapping

The next thing to do is to map your ERC-20 contract addresses deployed on Ethereum and Loom Network. This is done by interacting with the Transfer Gateway contract officially provided by Loom Network team. That contract is operated by delegated validators who run the nodes to make consensus.

The reason why you need to map your contracts is, Ethereum and Loom Network are separate blockchains so there's no connection between two ERC-20 contracts deployed on them. Let's create the relationship so that they are interoperable.

Add a script named add_contract_mapping.js under scripts directory.

const LoomX = require("@web3-guru/loom-x/dist").default;
const { Address } = require("@web3-guru/loom-x/dist");

require("dotenv").config();

const WEB3_TOKEN_ADDRESS = Address.createEthereumAddress("0x..."); // Your Web3Token address
const WEB3_TOKEN_TX_HASH = "0x..."; // Tx hash used when deploying your Web3Token
const LOOM_WEB3_TOKEN_ADDRESS = Address.createLoomAddress("0x..."); // Your LoomWeb3Token address

module.exports = async () => {
   const loomX = LoomX.fromMnemonic(process.env.MNEMONIC);
   await loomX.loom.mapContracts(loomX.ethereum, WEB3_TOKEN_ADDRESS, WEB3_TOKEN_TX_HASH, LOOM_WEB3_TOKEN_ADDRESS);
};

WEB3_TOKEN_ADDRESS is the contract address of your Web3Token and WEB3_TOKEN_TX_HASH is the transaction hash for deploying your Web3Token. LOOM_WEB3_TOKEN_ADDRESS is the contract address of your LoomWeb3Token. If you didn't deploy your tokens yet, refer to Part 1.

Execute it:

$ truffle exec scripts/add_contract_mapping.js

Now it's all ready to transfer your assets to and from Loom Network. Because your assets were deployed on Ethereum first, balance of your assets must be greater than 0 on Ethereum but is equal to 0 on Loom Network. Balances should only be increased on Ethereum not Loom Network. If you don't follow this rule, your asset could go into chaos.

Transfer Assets To Loom Network

Your ERC-20 assets with positive balance can be transferred to Loom Network. Let's see how.

Add a script named transfer_to_loom.js under scripts directory.

const LoomX = require("@web3-guru/loom-x/dist").default;
const { Address, BigNumberUtils } = require("@web3-guru/loom-x/dist");

require("dotenv").config();

const WEB3_TOKEN_ADDRESS = Address.createEthereumAddress("0x..."); // Your Web3Token address
const AMOUNT = BigNumberUtils.toBigNumber(10**18); // Amount to transfer

module.exports = async () => {
    const loomX = LoomX.fromMnemonic(process.env.MNEMONIC);
    const gatewayAddress = Address.createEthereumAddress(loomX.ethereum.getTransferGateway().address);
    const approveTx = await loomX.ethereum.approveERC20Async(WEB3_TOKEN_ADDRESS, gatewayAddress, AMOUNT);
    await approveTx.wait();
    const depositTx = await loomX.ethereum.depositERC20Async(WEB3_TOKEN_ADDRESS, AMOUNT);
    await depositTx.wait();
};

In this script, it first approves the amount you want to transfer for Transfer Gateway contract by calling approveERC20Async() because that contract is in charge of actual transfer. After that, with depositERC20Async() call, your assets on Ethereum is locked on the gateway and the last step will take place.

Execute it:

$ truffle exec scripts/transfer_to_loom.js

After 10 blocks of confirmation, Transfer Gateway on Loom Network generates the same amount of your assets on Loom Network.

If there's some problem transferring your assets to Loom Network, check if the Account Mapping and Contract Mapping were properly executed. Two mappings have to be setup perfectly prior to transferring assets.

Transfer Assets To Ethereum

Once you've transferred your assets to Loom Network, you can take back some or all the amount to Ethereum.

Add a script named transfer_to_ethereum.js under scripts directory.

const LoomX = require("@web3-guru/loom-x/dist").default;
const { Address, BigNumberUtils } = require("@web3-guru/loom-x/dist");

require("dotenv").config();

const WEB3_TOKEN_ADDRESS = Address.createEthereumAddress("0x..."); // Your Web3Token address
const LOOM_WEB3_TOKEN_ADDRESS = Address.createLoomAddress("0x..."); // Your LoomWeb3Token address
const AMOUNT = BigNumberUtils.toBigNumber(10**18); // Amount to transfer

module.exports = async () => {
    const loomX = LoomX.fromMnemonic(process.env.MNEMONIC);
    // Send tx to Loom Network
    const tx1 = await loomX.loom.withdrawERC20Async(LOOM_WEB3_TOKEN_ADDRESS, AMOUNT);
    await tx1.wait();

    // Listen to the withdrawal signature
    const myEthereumAddress = loomX.ethereum.address;
    const signature = await loomX.loom.listenToTokenWithdrawal(LOOM_WEB3_TOKEN_ADDRESS, myEthereumAddress);

    // Send tx to Ethereum Network
    const tx2 = await loomX.ethereum.withdrawERC20Async(WEB3_TOKEN_ADDRESS, AMOUNT, signature);
    await tx2.wait();
};

Transferring your assets to Ethereum takes 3 steps. First, by calling withdrawERC20Async on Loom Network's Transfer Gateway, balances of your LoomWeb3Token assets are deducted from your account. Secondly, we need to wait for Transfer Gateway on Loom Network to sign your transfer for Ethereum Transfer Gateway to verify it properly. Lastly, calling withdrawERC20Async on Ethereum's Transfer Gateway, AMOUNT of your balances are unlocked from the gateway contract.

Execute it:

$ truffle exec scripts/transfer_to_ethereum.js

Loom.listenToWithdrawal() waits for 120 seconds then it times out if no withdrawal signature is generated.

Handling Pending Withdrawal

If Loom.listenToWithdrawal() times out after 120 seconds or you couldn't properly withdraw your assets, your withdrawal will be in pending state so you need to handle this manually.

Let's create a script named handle_pending_withdrawal.js under scripts directory.

const LoomX = require("@web3-guru/loom-x/dist").default;
const { Address } = require("@web3-guru/loom-x/dist");

require("dotenv").config();

const WEB3_TOKEN_ADDRESS = Address.createEthereumAddress("0x..."); // Your Web3Token address

module.exports = async () => {
    const loomX = LoomX.fromMnemonic(process.env.MNEMONIC);
    // Check if you have a pending receipt
    const nonce = await loomX.ethereum.getWithdrawalNonceAsync();
    if (nonce) {
        // Get pending withdrawal receipt with the nonce
        const receipt = await loomX.getPendingERC20WithdrawalReceipt(nonce);
        // Withdraw pending ERC20
        const tx = await loomX.ethereum.withdrawERC20WithReceiptAsync(WEB3_TOKEN_ADDRESS, receipt);
        if (tx) {
            await tx.wait();
        }
    }
};

If you have a pending withdrawal, execute it:

$ truffle exec scripts/handle_pending_withdrawal.js

Now you'll see that you balance increases on Ethereum.

Conclusion

In this tutorial and Part 1, we've dealt with how to deploy your ERC20 asset to both blockchains and transfer them to Loom Network and vice versa. Even though it wouldn't be easy for you to understand whole the details on how assets are transferred and what Transfer Gateways do, with the help of LoomX you'll easy make your assets going back and forth.

Also, I've pushed the git repository that contains all the example code used in this tutorial. You can check it out at https://github.com/web3-guru/web3token.

I hope this tutorial would help a lot of developers who are interested in Loom Network and Transfer Gateway. Good luck!