HelloERC20

HelloERC20 is an example ERC20 token implemented in Solidity, designed for cross-chain operations without relying on traditional bridge mechanisms. Utilizing the Via Labs Solidity package and MessageClient extension, it demonstrates a bridgeless approach to native token minting and burning across different blockchain networks.

Prerequisites

Node.js and npm

Linux (Ubuntu/Debian)
# Install using APT
sudo apt update
sudo apt install nodejs npm
Windows
# Download and install from:
https://nodejs.org/en/download/
macOS
# Install using Homebrew
brew install node

Git

Linux (Ubuntu/Debian)
# Install using APT
sudo apt install git
Windows
# Download and install from:
https://gitforwindows.org/
macOS
# Install using Homebrew (if not pre-installed)
brew install git

Testnet Tokens

Installation

Open a terminal to run the following commands. You can use any terminal of your choice, including the built in terminal in (vscode) (Terminal -> New Terminal)

  1. Clone the Repository:
    git clone https://github.com/VIALabs-io/hello-erc20.git
    
  2. Change into Project Directory:
    cd hello-erc20
    
  3. Install Dependencies:
    npm install
    
  4. Set Up Environment Variables:
    Create a new .env file to set your EVM private key for contract deployment or copy and edit the existing .env.example to .env
    PRIVATE_KEY=0000000000000000000000000000
    

Deployment

Deploy the HelloERC20 contract to your desired networks. This must be done for each network you wish to operate on. You can see a list of our networks in the Package documentation

  1. Ethereum Sepolia Testnet:
    npx hardhat --network ethereum-sepolia deploy
    
  2. Polygon Testnet:
    npx hardhat --network polygon-amoy deploy
    

Configuration

Once all contracts are deployed across the desired networks and listed in networks-testnet.json, configure them using the provided script. Remember, if a new network is added later, all contracts must be reconfigured.

  1. Ethereum Sepolia Testnet:
    npx hardhat --network ethereum-sepolia configure
    
  2. Polygon Testnet:
    npx hardhat --network polygon-amoy configure
    

Usage

Checking Token Balance

To check the balance of tokens on a particular chain:

npx hardhat --network ethereum-sepolia get-token-balance

Bridging Tokens to Another Chain

To send tokens to another chain it is required to set the --dest parameter to the destination chain id. The example below uses the id for the Polygon Testnet. Chain IDs can be looked up in the Package documentation.

npx hardhat --network ethereum-sepolia bridge-token --dest 80002 --amount 5

Check Tokens on Destination Chain

You can now check the balance on the destination chain. Please give the transaction some time to process. You should see your balance increase on the destination chain:

npx hardhat --network polygon-amoy get-token-balance

Contract Breakdown of HelloERC20

This contract is an ERC20 token with additional functionalities for cross-chain operations. It inherits from ERC20Burnable for standard ERC20 functionality with burn capabilities and from MessageClient for handling cross-chain messages.

pragma solidity 0.8.17;

import "@vialabs-io/contracts/message/MessageClient.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol";

contract HelloERC20 is ERC20Burnable, MessageClient {
    constructor() ERC20("HelloERC20", "HELLO") {
        _mint(msg.sender, 1_000_000 ether);
    }

    function bridge(uint _destChainId, address _recipient, uint _amount) external onlyActiveChain(_destChainId) {
        // burn tokens
        _burn(msg.sender, _amount);

        // send cross chain message
        _sendMessage(_destChainId, abi.encode(_recipient, _amount));
    }

    function messageProcess(uint, uint _sourceChainId, address _sender, address, uint, bytes calldata _data) external override  onlySelf(_sender, _sourceChainId)  {
        // decode message
        (address _recipient, uint _amount) = abi.decode(_data, (address, uint));

        // mint tokens
        _mint(_recipient, _amount);
    }
}

Constructor

constructor() ERC20("HelloERC20", "HELLO") {
    _mint(msg.sender, 1_000_000 ether);
}
  • Initializes the token with the name "HelloERC20" and symbol "HELLO".
  • Mints 1,000,000 tokens to the address deploying the contract.

Function: bridge

function bridge(
    uint _destChainId, 
    address _recipient, 
    uint _amount
) external onlyActiveChain(_destChainId) {
    // burn tokens
    _burn(msg.sender, _amount);

    // send cross chain message
    _sendMessage(_destChainId, abi.encode(_recipient, _amount));
}
  • Allows a user to send tokens to another chain.
  • Parameters:
    • _destChainId: The ID of the destination chain.
    • _recipient: The recipient's address on the destination chain.
    • _amount: The amount of tokens to send.
  • Process:
    • Burns the specified _amount of tokens from the sender's balance.
    • Encodes the _recipient address and _amount into bytes (_data).
    • Calls _sendMessage, a function from MessageClient, to send this encoded data to the destination chain.
  • Modifiers:
    • onlyActiveChain: A modifier restricts this function to be called only if the destination chain is active.

Function: messageProcess

function messageProcess(
    uint, 
    uint _sourceChainId, 
    address _sender, 
    address, 
    uint, 
    bytes calldata _data
) external override  onlySelf(_sender, _sourceChainId)  {
    // decode message
    (address _recipient, uint _amount) = abi.decode(_data, (address, uint));

    // mint tokens
    _mint(_recipient, _amount);
}
  • Handles incoming messages from other chains.
  • Parameters:
    • _sourceChainId: The ID of the source chain from where the message is sent.
    • _data: Encoded data containing the recipient's address and the amount.
  • Process:
    • Decodes _data to extract _recipient and _amount.
    • Mints _amount of tokens to _recipient's address on the current chain.
  • Modifiers:
    • onlySelf: A modifier restricts this function to be called only if the message was sent from the corresponding deployments of this contract on the source chain.