---
description: Smart contracts for bridging from Agoric to Ethereum & Avalanche
---

# Axelar Transfer

{% hint style="warning" %}
**Limited Developer Support**

All assets represented in this library are community built, which means limited support from the Agoric OpCo development team. Please use components, APIs, and front-ends with caution. &#x20;
{% endhint %}

## **Summary**

Sending cross-chain messages from Agoric

## **Details**

The Axelar protocol enables decentralised cross-chain communication between different networks, allowing to send arbitrary data and/or tokens.

Axelar decentralisation is achieved by its own proof-of-stake blockchain network built using Cosmos SDK with permissionless set of validators, which constantly produce blocks containing cross-chain transactions info.

This component relies on [Pegasus package](https://github.com/Agoric/dapp-pegasus) that enables pegging of [Agoric](https://agoric.com/) ERTP assets to or from remote assets. This is achieved by using the IBC (Inter-Blockchain Communication) protocol supported by Agoric.

This component allows tokens and/or arbitrary data to EVM chains. This enables a lot of use cases, like token/information bridging, response to Agoric on-chain events on EVM chain and etc.

Check the list of supported EVM chains [here](https://github.com/axelarnetwork/evm-cosmos-gmp-sample/blob/main/native-integration/onboard-devnet.md#supported-chains).

## Dependencies

There are some previous considerations to have before instantiating the Axelar transfer contract.

The first one is related to the agoric-sdk version used, you should use [this](https://github.com/schnetzlerjoe/agoric-sdk/tree/community-dev) version of Agoric SDK.

In order to start an instance of the Axelar-Transfer contract it is not required any issuerKeywordRecord, terms, or privateArgs. Only the installation reference. Although, there is a need to establish an IBC and Pegasus transfer channel between the Agoric and Axelar, prior to the execution of the contract methods.

## Contract Facets

The `publicFacet` of the contract contains only `setupAxelar` method that runs the Axelar setup process and returns a function `sendGMP` that can be used to send arbitrary data to EVM chains. The creator facet is empty and has no methods.

`setupAxelar` requires `pegaus` parameter, which is pegasus service instance.

```javascript
const publicFacet = Far('publicFacet', {
  // Public faucet for anyone to call
  /**
   * This is a contract to interact with Axelar and send messages and tokens from Agoric to EVM's with Axelar
   *
   * @param {import('@agoric/pegasus').Pegasus} pegasus Pegasus public facet
   */
  setupAxelar: async (
    pegasus
  ) => {
    const ret = await setupAxelar(
      pegasus
    );
    return ret;
  },
});
```

## Functionalities

### sendGMP

This function will trigger cross-chain call to EVM chain with specified target address, value and payload. Metadata object should contain information about destination chain, address and payload that will be passed to EVM contract as calldata.

`sendGMP` function creates an invitation to transfer assets over network with all cross-chain info included. The Pegasus package is modified in the required version of Agoric SDK so that it could accept additional `sender` parameter for the Axelar protocol. The offer then is issued and then `sendGMP` returns an offer result.

```javascript
export const setupAxelar = async (
  pegasus,
) => {
  // ...
  return Far('axelar', {
    /**
     * Sends a GMP message to an EVM chain from Agoric.
     *
     * @param {ZoeService} zoe - Zoe service instance
     * @param {Purse} purse - Purse for `amount` payment
     * @param {Peg} peg - Pegasus connection instance
     * @param {string} receiver - Pegasus receceiver address
     * @param {string} sender - Pegasus sender address
     * @param {NatValue} amount - Amount of tokens to be sent (0 if only data is sent)
     * @param {Metadata} metadata - object containing destination chain, address and payload info
     * @returns {Promise<any>}
     */
    sendGMP: async (zoe, purse, peg, receiver, sender, amount, metadata) => {
			/** @type {import('@agoric/pegasus').Pegasus} */
      const pegasus = await storeConnection.get("pegasus");

      const memo = JSON.stringify(metadata);

			// Create a Zoe invitation with cross-chain message info
      // to transfer assets over network to a deposit address
      const [invitation, brand] = await Promise.all([
        E(pegasus).makeInvitationToTransfer(peg, receiver, memo, sender),
        E(peg).getLocalBrand()
      ]);

      const amt = harden({ brand, value: amount });
      const pmt = await E(purse).withdraw(amt);

      const seat = E(zoe).offer(
        invitation,
        harden({ give: { Transfer: amt } }),
        harden({ Transfer: pmt }),
      );

      const result = await E(seat).getOfferResult();

      return result
		}
}
```

For sending only messages without tokens to the remote chain, use `"type": 1` in metadata:

```javascript
// create metadata (note you have to abi encode payload)
let payload = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,185,77,138,47,92,174,154,148,168,212,54,75,162,212,199,126,135,33,159,249]

/** @type {Metadata} */
const metadata = {
    payload,
    "type": 1,
    "destination_chain": "avalanche",
    "destination_address": "0xF4799D77Cc7280fd3Bd9186A7e86B0540243E32d"
}

// Lets send a GMP message
await E(axelar).sendGMP(
    home.zoe,
    localPurseP,
    peg,
    'axelar1dv4u5k73pzqrxlzujxg3qp8kvc3pje7jtdvu72npnt5zhq05ejcsn5qme5',
    'agoric1m26r7lnp422hftlspza6e8pkun3nvddacmu8ta',
    0n,
    metadata
);
```

For sending tokens and the payload to the remote chain, use `"type": 2` in metadata:

```javascript
// create metadata (note you have to abi encode payload)
let payload = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,185,77,138,47,92,174,154,148,168,212,54,75,162,212,199,126,135,33,159,249]

/** @type {Metadata} */
const metadata = {
    payload,
    "type": 2,
    "destination_chain": "avalanche",
    "destination_address": "0xF4799D77Cc7280fd3Bd9186A7e86B0540243E32d"
}

// Lets send a GMP message
await E(axelar).sendGMP(
    home.zoe,
    localPurseP,
    peg,
    'axelar1dv4u5k73pzqrxlzujxg3qp8kvc3pje7jtdvu72npnt5zhq05ejcsn5qme5',
    'agoric1m26r7lnp422hftlspza6e8pkun3nvddacmu8ta',
    1000000n / 4n,
    metadata
);
```

For sending only tokens without payload, use `"type": 3` in metadata and set `"payload": null`:

## Usage and Integration

The initialisation and setup guide can be found in [README.md](https://github.com/pitalco/axelar-transfer/blob/main/README.md) file in project repository. Also check the unit test for the contract to find the testing setup process for `sendGMP` function.

Be aware of specifics of calling EVM contracts - the payload that will be passed to the contract must be decodable by recipient contract. If you are attempting to call a specific function of the contract, make sure to correctly encode the function selector and the function arguments. Otherwise, your payload has to be handled and decoded manually by the `fallback()`function. Check the [official Solidity](https://docs.soliditylang.org/en/v0.8.21/internals/layout_in_calldata.html) documentation for more info about the encoding:

````solidity
```solidity
// function selector: 0x40c10f19
// e.g. if you want to mint 100 tokens (6 decimals) to 
// 0x1234567890123456789012345678901234567890, the payload encoding would be:

// 0x40c10f19 + 0000000000000000000000001234567890123456789012345678901234567890 + 0000000000000000000000000000000000000000000000000000000005f5e100
// ^            ^                                                                  ^
// selector     address argument `to`, padded to 32 bytes                          uint256 argument `amount`, padded to 32 bytes (100000000 converted to hex)
function mint(address to, uint256 amount) public {
    // TODO: check msg.sender
    _mint(to, amount);
}

// for manual data handling
fallback() external payable {
    // TODO: check msg.sender
    (
        // declare variables to store decoded arguments
    ) = abi.decode(msg.data, (/* specify argument types */));
}
```
````

## **Explore on GitHub**

[https://github.com/pitalco/axelar-transfer](https://github.com/pitalco/axelar-transfer)
