Using the Ethereum Web3 Library to Send Transactions on Moonbeam
By: Alberto Viera
Tags: Solidity, Smart Contracts, Ethereum, Substrate, Polkadot

Using the Ethereum Web3 Library to Send Transactions on Moonbeam

The Web3 JavaScript library is one of the many ways we can interact with the Ethereum blockchain. The great thing about using the Web3 library is that you have full control not only of your private key, but also of every interaction you make with Ethereum.

This guide walks through the process of using Web3 to manually sign and send a transaction to a Moonbeam dev node. For this example, we will use Node.js and straightforward JavaScript code. The Web3 library is very extensive (link here), so we will only go through the methods needed for this tutorial.

The examples in this guide are based on a Ubuntu 18.04 environment and assume that you have a local Moonbeam node running in — dev mode. You can find instructions to setup a local Moonbeam node here.

Note: This tutorial was created using the pre-alpha release of Moonbeam. The Moonbeam platform, and the Frontier components it relies on for Substrate-based Ethereum compatibility, are still under very active development. We have created this tutorial so you can test out Moonbeam’s Ethereum compatibility features. Even though we are still in development, we believe it’s important that interested community members and developers have the opportunity to start to try things with Moonbeam and provide feedback.

We’ve also created a video of this tutorial, which you can view below. It will cover the same steps we are about to outline.

Checking Prerequisites

If you followed the tutorial, you should have a local Moonbeam node producing blocks that looks like this:

In addition, for this tutorial, we need to install Node.js (we’ll go for v14.x) and the npm package manager. You can do this by running in your terminal:

curl -sL https://deb.nodesource.com/setup_14.x | sudo -E bash -

sudo apt install -y nodejs

We can verify that everything installed correctly by querying the version for each package:

node -v

npm -v

As of the writing of this guide, versions used were 14.6.0 and 6.14.6, respectively.

Next, we can create a directory to store all our relevant files (in a separate path from the local Moonbeam node files), and create a simple package.json file by running:

mkdir transaction && cd transaction/

npm init --yes

With the package.json file created, we can then install the Web3 package by executing:

npm install --save web3

To verify the installed version of Web3, you can use the ls command:

npm ls web3

As of the writing of this guide, the version used was 1.2.9. Remember you can fix a version of a package by using the @ symbol, this is useful to install specific versions, for example:

npm install --save web3@1.2.9

The Transaction File

Now that everything it’s installed, let’s get to the cool part and start coding!

For our example, we only need a single JavaScript file (arbitrarily named transaction.js, which you can find here) to create the transaction, which we will run using the node command in the terminal. The script will transfer 100 “ETH” from the genesis account to another address. For simplicity, the file is divided into three sections: variable definition, create transaction, and deploy transaction.

We need to set a couple of values in the variable definitions:

Create our Web3 constructor ( Web3 ). Define the privKey variable as the private key of our genesis account, which is where all the funds are stored when deploying your local Moonbeam node, and what is used to sign the transactions. Set the “from” and “to” addresses. Here we will send funds from our genesis account to the address MetaMask creates by default when setting up a wallet, make sure you use your address. Create a local Web3 instance and set the provider to connect to our local Moonbeam node.

Note: Remember to change the addressTo variable to another address provided by your MetaMask wallet.

const Web3 = require('web3');



// Variables definition

const privKey =

'99B3C12287537E38C90A9219D4CB074A89A16E9CDB20BF85728EBD97C343E342'; // Genesis private key

const addressFrom = '0x6Be02d1d3665660d22FF9624b7BE0551ee1Ac91b';

const addressTo = '0xB90168C8CBcd351D069ffFdA7B71cd846924d551';

const web3 = new Web3('http://localhost:9933');

Both the “create transaction” and “deploy transaction” sections are wrapped in an asynchronous function that handles the promises from our Web3 instance. To create the transaction, we need to invoke a sign transaction method web3.eth.accounts.signTransaction(tx, privKey) , where we have to define the transaction object with some parameters such as: addressFrom , addressTo , number of tokens to send, and the gas limit.

Note: the number of tokens needs to be given in Wei, but we can use the Web3 toWei utility to convert units. The private key must be provided as well to sign the transaction.

// Create transaction

const deploy = async () => {

console.log(

`Attempting to make transaction from ${addressFrom} to ${addressTo}`

);



const createTransaction = await web3.eth.accounts.signTransaction(

{

from: addressFrom,

to: addressTo,

value: web3.utils.toWei('100', 'ether'),

gas: '4294967295',

},

privKey

);

Note: currently, the value “4294967295” for gas (referred to as the gas limit) needs to be manually set. As of the writing of this guide, we are working through some issues related to gas estimation in Moonbeam. Once these are fixed, this manual setting of the gas limit shouldn’t be necessary.

Since the transaction message has been created and signed (you can console.log(createTransaction) to see the v-r-s values), we can now deploy it using the web3.eth.sendSignedTransaction(signedTx) by providing the rawTransaction from the createTransaction object.

Lastly, we run our deploy function.

// Deploy transaction

const createReceipt = await web3.eth.sendSignedTransaction(

createTransaction.rawTransaction

);

console.log(

`Transaction successful with hash: ${createReceipt.transactionHash}`

);

};



deploy();

So our completes transaction.js script looks like this:

const Web3 = require('web3');



// Variables definition

const privKey =

'99B3C12287537E38C90A9219D4CB074A89A16E9CDB20BF85728EBD97C343E342'; // Genesis private key

const addressFrom = '0x6Be02d1d3665660d22FF9624b7BE0551ee1Ac91b';

const addressTo = '0xB90168C8CBcd351D069ffFdA7B71cd846924d551';

const web3 = new Web3('http://localhost:9933');



// Create transaction

const deploy = async () => {

console.log(

`Attempting to make transaction from ${addressFrom} to ${addressTo}`

);



const createTransaction = await web3.eth.accounts.signTransaction(

{

from: addressFrom,

to: addressTo,

value: web3.utils.toWei('100', 'ether'),

gas: '4294967295',

},

privKey

);



// Deploy transaction

const createReceipt = await web3.eth.sendSignedTransaction(

createTransaction.rawTransaction

);

console.log(

`Transaction successful with hash: ${createReceipt.transactionHash}`

);

};



deploy();

The Balance File

Before running the script, we need another file to check the balances of both addresses before and after the transaction is executed. We can easily do this by leveraging the Ethereum compatibility features of Moonbeam.

For simplicity, the balance file (named arbitrarily balances.js, which you can find here), is composed of two sections: the variables definition and the balance call. The variables definition is nearly the same as for the previous transaction file; the only difference is that we do not need the private key, as this is only a call function (reading data from the local Moonbeam node).

To get the balances of our addresses, we need to make an asynchronous function that uses the web3.eth.getBalance(address) command. We can take advantage of the web3.utils.fromWei() function to transform the balance into a more readable number in ETH.

So basically, our balances.js script looks like this (make sure to change the addressTo to the same value provided in the transaction file:

const Web3 = require('web3');



// Variables definition

const addressFrom = '0x6Be02d1d3665660d22FF9624b7BE0551ee1Ac91b';

const addressTo = '0xB90168C8CBcd351D069ffFdA7B71cd846924d551';

const web3 = new Web3('http://localhost:9933');



// Balance call

const balances = async () => {

const balanceFrom = web3.utils.fromWei(

await web3.eth.getBalance(addressFrom),

'ether'

);

const balanceTo = await web3.utils.fromWei(

await web3.eth.getBalance(addressTo),

'ether'

);



console.log(`The balance of ${addressFrom} is: ${balanceFrom} ETH.`);

console.log(`The balance of ${addressTo} is: ${balanceTo} ETH.`);

};



balances();

Running the Scripts

First, let’s check the balances of both of our addresses before the transaction by running:

node balances.js

The output of the execution is the following:

We can run our transaction.js script from the terminal window:

node transaction.js

The output of the execution is the following:

And we can check the new balances:

Next, learn to deploy your Solidity smart contract to Moonbeam.

We Want to Hear From You

This is a relatively simple example, but it provides context for how you can start working with Moonbeam and how you can try out its Ethereum compatibility features. We are interested in hearing about your experience following the steps in this guide or your experience trying other Ethereum-based tools with Moonbeam. Feel free to join us in the Moonbeam Riot room here. We would love to hear your feedback on Moonbeam and answer any questions that you have.