Skip to content

Transfers API

Moonbeam v Ethereum - Transfers API Banner

Introduction

While Moonbeam strives to be compatible with Ethereum's Web3 API and EVM, there are some important Moonbeam differences that developers should know and understand in terms of balance transfers.

Token holders have two ways of initiating a balance transfer on Moonbeam. On one side, users can use the Ethereum API via apps like MetaMask, MathWallet, or any other tools that use the Ethereum JSON-RPC. On the other side, users can use the Substrate API, via the Polkadot.js Apps website.

Developers need to be aware that token holders can leverage both APIs to transfer tokens. This guide will outline some of these main differences around both APIs for balance transfers and what to expect when using Moonbeam for the first time.

Ethereum Transfers

A simple balance transfer using the Ethereum API relies on the eth_sendRawTransaction JSON RPC. This can be directly from one account to another or via a smart contract.

There are different strategies to listen for transfers or balance changes on Ethereum, which are not covered in this documentation. But they are all focused on different strategies using the Ethereum JSON RPC.

Moonbeam Transfers

As stated before, Moonbeam enables token holders to execute transfers via both the Ethereum and Substrate API. There are multiple scenarios to trigger token transfer on Moonbeam. Consequently, to monitor all transfers, you should use the Polkadot.js SDK (Substrate API).

Before going over the different scenarios, there are two different elements associated with a block:

  • Extrinsic — refers to state changes that originated outside of the system itself. The most common form of extrinsic is a transaction. They are ordered by execution
  • Events — refers to logs generated from the extrinsic. There can be multiple events per extrinsic. They are ordered by execution

The different transfer scenarios are:

  • Substrate transfer — it will create an extrinsic, either balances.transfer or balances.transferKeepAlive. It will trigger one balances.Transfer event
  • Substrate feature — some native Substrate features can create extrinsic that would send tokens to an address. For example, Treasury can create an extrinsic such as treasury.proposeSend, which will trigger one or multiple balances.Transfer events
  • Ethereum transfer — it will create an ethereum.transact extrinsic, with an empty input. It will trigger one balances.Transfer event
  • Ethereum transfers via smart contracts — it will create an ethereum.transact extrinsic, with some data as input. It will trigger one or multiple balances.Transfer events

All the scenarios described above will effectively transfer tokens. The easiest way to monitor them all is to rely on the balances.Transfer event.

Monitor All Balance Transfers with the Substrate API

The Polkadot.js API package provides developers a way to interact with Substrate chains using Javascript.

The following code snippet uses Polkadot.js to loop through each event fetched from the provider. Then, it checks it corresponds to a balances.Transfer event. If so, it will extract the from, to and amount of the transfer and display it on the console. Note that the amount is shown in the smallest unit (Wei). You can find all the available information about Polkadot.js and the Substrate JSON RPC in their official documentation site.

import { typesBundle } from "moonbeam-types-bundle";
import { ApiPromise, WsProvider } from "@polkadot/api";


// This script will listen to all MOVRs transfers (Substrate & Ethereum)

const main = async () => {
  // Define the provider
  const wsProvider = new WsProvider("wss://wss.moonriver.moonbeam.network");

  // Create the provider using Moonbeam types
  const polkadotApi = await ApiPromise.create({
    provider: wsProvider,
    typesBundle: typesBundle,
  });


  polkadotApi.query.system.events((events) => {
    // Loop through the Vec<EventRecord>
    events.forEach(({ event }) => {

      // Check if the event is related to balances.Transfer
      if (event.section == "balances" && event.method == "Transfer") {

        // Extract the relevant information
        const from = event.data[0].toString();
        const to = event.data[1].toString();
        const balance = event.data[2].toBigInt();

        // Balance is shown in the min unit
        console.log(`Transfer from ${from} to ${to} of ${balance}`);
      }
    });
  });
};

main();

In addition, you can find more code snippets related to more specific cases around balance transfers in this script.