DEV Community

Cover image for Send tokens between Different Blockchain using Axelar General Message Passing - The Basics
ShatilKhan
ShatilKhan

Posted on

Send tokens between Different Blockchain using Axelar General Message Passing - The Basics

Howdy!

If you are beginning to explore Blockchain Interoperability , you've come to the right place!
Axelar enables you to make cross chain DApps.
And of course they have their own documentations & videos you can watch. But I'm mainly writing this because when I first started searching for a proper place to learn Axelar, I got confused. Because Axelar does A LOT! So it's easy to get overwhelmed by all the jargans thrown around. So I have compiled what I believe is a good starting point for ANYONE. We'll be using the Remix IDE. We'll connect to Meta Mask & actually send a Message from Polygon to Avalanche Blockchain.
Here are the things I will cover accordingly:

  • Basic Definitions & Tips

  • Resource Websites

  • Coding

  • Execution

Basic Definitions

General Message Passing
The first most important service provided by Axelar which allows you to send tokens between blockchains, these tokens can be either messages , nfts etc.
Basically think of it as two banks exchanging cheques between each other for financial purposes. Now of course when you exchange between two banks, you must pay some amount to the bank in order for the transaction to occure. On to the Next Definition!

Gas Service
I think you can kinda guess what the Gas Service is about. Think of the Gas as the fee you pay when sending cheques to another Bank. Now Gas Service serves as the system of payment of that fee. We'll be talking more about this service in the next sections.

Important Arguments:

destinationChain
Think of destinationChain as the Bank you want to send the cheque to. In our case , we are sending a message from Polygon to Avalanche, so our destinationChain will be Avalanche.

destinationAddress
destinationAddress is just the address of your wallet. We'll see more on this later down.

All Right!
Now that those things are out of the way, here's some sites that may come in handy:

Chainlist
Go to Chainlist & connect to testnet of your choice. For this blog I chose Polygon Mumbai & Avalanche Fuji Testnet.

Faucets
Faucets is where you can find Test Gas or in Web2 we call it Fake Money to test your DApp. For our perposes we used the Polygon Faucet & Avalanche Faucet

I used MATIC tokens for Polygon & AVAX for Avalanche.

Coding Begins!

Open up Remix & create a new file. Name it anything you like with the .sol extension. I named mine gmp.sol. You don't have to set up anything else for this. All necessary package imports will be shown in next parts.

So as you may have already understood , we are using Solidity for this task.

Open up gmp.sol & use the code below to use Solidity version:

pragma solidity ^0.8.0;
Enter fullscreen mode Exit fullscreen mode

Imports

Now we'll be exporting some essential packages.
First up is AxelarExecutable . This allows us to execute our contracts through Axelar.
Import Code:

import { AxelarExecutable } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/executable/AxelarExecutable.sol';

Enter fullscreen mode Exit fullscreen mode

Next up is IAxelarGateway , which is basically a gateway plugin that helps you pay the Gas Service charge.
Import Code:

import { IAxelarGateway } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/IAxelarGateway.sol';

Enter fullscreen mode Exit fullscreen mode

Finally we import IAxelarGasService which is the main service that handles the outgoing & incoming Gas.

Import Code:

import { IAxelarGasService } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/IAxelarGasService.sol';

Enter fullscreen mode Exit fullscreen mode

The Contract:

Now we'll initiate a contract. We'll name our contract SenderReceiver. This will allow us to send & receiev messages across blockchains. It's worth mentioning this contract will be an AxelarExecutable which will allow us to execute using Axelar's services.
Now let's look at the contract code & we'll explain further below.

contract SenderReceiver is AxelarExecutable {
    IAxelarGasService public immutable gasService;
    string public message;
    constructor(address gateway_, address gasService_) AxelarExecutable(gateway_) {
        gasService = IAxelarGasService(gasService_);
    }

Enter fullscreen mode Exit fullscreen mode

Here we have defined a state variable gasService which is of type IAxelarGasService. This has to be declared as public and immutable so that it can't be changed and can be accessed externally.
Now we add a constructor function which takes in two arguments gateway_ & gasService_. Now we must initialize the gateway using AxelarExecutable & passing in gateway_ as an argument.
Finally we initialize the gasService using IAxelarGasService & passing in gasService_ as an argument.

And Voila!
Our Contract is ready to go!

Functions:

Now we're gonna be writing some simple functions to send & receive the message between blockchains.
The first function we'll write is will send the message to our destination chain. Let's call sendMessage. We are going to encode our message using this function. We'll need to take in 3 arguments for this function which are destinationChain , destinationAddress which I have already explained before & the third one is message_. All of them are Strings. The message_ arguments stores the text message that we'll be sending.
In order to encode the message we'll be making this function an external payable which will encode our massage & help us pay the Gas Fee.

Function Code:

function sendMessage(
        string calldata destinationChain,
        string calldata destinationAddress,
        string calldata message_
    )external payable{
        bytes memory payload = abi.encode(message_);
        gasService.payNativeGasForContractCall{value: msg.value} (
            address(this),
            destinationChain,
            destinationAddress,
            payload,
            msg.sender
        );

        gateway.callContract(destinationChain, destinationAddress, payload);
    }

Enter fullscreen mode Exit fullscreen mode

We use the payNativeGasForContractCall function from the gasService contract to pay for the gas required to execute the transaction. Finally The gateway.callContract function is used to initiate the transaction to the destinationChain & destinationAddress carrying the messaye payload.

Done!
Now that we can Send a message to our destination Chain , we need a way to receive the message on our destination.

On to The Final Function!

In this function we'll execute our message by decoding it into our destination chain. Let's call it execute function. It will decode the payload & show us the string inside.
Function Code:

    function _execute(
        string calldata sourceChain,
        string calldata sourceAddress,
        bytes calldata payload_
    )internal override{
        message = abi.decode(payload_, (string));
    }
}
Enter fullscreen mode Exit fullscreen mode

message will decode the payload using abi.decode & show you the message.

And That's About It!
Here's the Full Code:

pragma solidity ^0.8.0;

import { AxelarExecutable } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/executable/AxelarExecutable.sol';
import { IAxelarGateway } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/IAxelarGateway.sol';
import { IAxelarGasService } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/IAxelarGasService.sol';


contract SenderReceiver is AxelarExecutable {
    IAxelarGasService public immutable gasService;
    string public message;
    constructor(address gateway_, address gasService_) AxelarExecutable(gateway_) {
        gasService = IAxelarGasService(gasService_);
    }

    function sendMessage(
        string calldata destinationChain,
        string calldata destinationAddress,
        string calldata message_
    )external payable{
        bytes memory payload = abi.encode(message_);
        gasService.payNativeGasForContractCall{value: msg.value} (
            address(this),
            destinationChain,
            destinationAddress,
            payload,
            msg.sender
        );

        gateway.callContract(destinationChain, destinationAddress, payload);
    }

    function _execute(
        string calldata sourceChain,
        string calldata sourceAddress,
        bytes calldata payload_
    )internal override{
        message = abi.decode(payload_, (string));
    }
}
Enter fullscreen mode Exit fullscreen mode

Execution:

On this part you get to see everything happen!
Go over to the side menu & click on Solidity Compiler.
Click on Compile gmp.sol.

Image description

After Compilation you may see some small warnings about not using sourceChain & sourceAddress in the execute function, these arguments are indicating our source blockchain, in our case polygon. No need to worry too much about these at the moment.

Now click on Deploy & Run Transaction button on the side menu.
Choose Injected Provider- MetaMask. You will be prompted to connect your MetaMask wallet. If you don't have one yet, you can just create it now.
Here's a links that'll help:
Download MetaMask for Chrome

Image description

Now after you've connecter MetaMask, check your setting for transaction. Set value to Ether & add 1 Ether.

Image description

Now you get to choose your testnets for transaction
Here are the sites you'll need for this part

Axelar Tesnet Addresses

This site has all the gateway & gas service addresses.
Just Copy & paste them on to here:

Image description

I chose Polygon & Avalanche, Make sure whatever testnet you choose is supported by Axelar.

Image description

First copy the Polygon Addresses & paste them in.

Now you can click on the transact button & your transaction will begin!
Approve your transaction.

Now you have added the Polygon testnet.

For connecting Avalanche, follow the same procedure,
Change your MetaMask profile to Avalanche Fuji.
Got to Avalanche Testnets site. Copy Avalanche chain code & gas service code.
Paste them the same way you pasted Polygon Addresses.
And Click Transact! That's it!
Both Chains are now connected.

Example Image of connecting Polygon:

Image description

After you click confirm, it will take a little time, keep an eye on the Terminal, it'll show you some information.

Now look at bottom left corner, you will have your hash code for the Source testnet, save it somewhere you can see.
It should look like this:

Image description

On the top you can see SENDERRECIEVER. This is the SenderReceiver function we declared in our code. AND you get an ID . Copy it & Paste it in the destinationAddress field & use Polygon as destinationChain.
Click on sendMessage option to send our Old Hello World! Message to Avalanche.
Now click on transact again.

Here we'll see the real magic happen!

Head over to Axelar Gmp Search Site , in here you will see ALL transactions happening LIVE!

Image description

On the very Top we can see our message along with it's status!

Now for another trick!
You can click on it to see EVERY Detail about our transaction!
Which is pretty freaking cool.

Image description
Here we can see that our transaction has been approved & executed.

Now for the final part
Go back to Remix.

Image description

Under deployed contacts, go to Polygons SenderReceiver & Query the message property, Under they when you click the message option , you will see there, beautifully displayed

Hello World!

Top comments (0)