Skip to content

Using Truffle to Deploy to Moonbeam

Introduction

This guide walks through the process of deploying a Solidity-based smart contract to a Moonbeam node using Truffle, a commonly used development tool for smart contracts on Ethereum. Given Moonbeam’s Ethereum compatibility features, Truffle can be used directly with any of the Moonbeam networks.

To ease the process of getting started with Truffle, you can use the Moonbeam Truffle box. This provides a boilerplate setup to speed up the process to deploy contracts on Moonbeam. The Moonbeam Truffle box comes with the Moonbeam Truffle plugin, which enables you to get started with a Moonbeam development node quickly.

This guide will show you how to deploy a contract and interact with it using the Moonbeam Truffle box and the Moonbeam Truffle plugin on a locally running development node. You can adapt the instructions in this guide for Moonbeam, Moonriver, or the Moonbase Alpha TestNet.

Checking Prerequisites

As this guide will use the Moonbeam Truffle box and the Moonbeam Truffle plugin, you don't have to worry about creating an account and funding it. The Moonbeam development node comes with 10 pre-funded accounts. However, if you're adapting this guide for Moonbeam, Moonriver, or Moonbase Alpha you will need to have an account with funds. You can get DEV tokens for testing on Moonbase Alpha once every 24 hours from the Moonbase Alpha Faucet.

To test out the examples in this guide on Moonbeam or Moonriver, you will need to have your own endpoint and API key, which you can get from one of the supported Endpoint Providers.

To use the Moonbeam Truffle plugin, you will need to have Docker installed.

For the following examples, you don't need to have Truffle globally installed, as it is included as a dependency in the Moonbeam Truffle box. However, if you want to use the truffle commands directly instead of running npx truffle or ./node_modules/.bin/truffle, you can globally install it by running:

npm install -g truffle

Creating a Project using the Moonbeam Truffle Box

To get started with the Moonbeam Truffle box, you can take the following steps:

  1. If you have Truffle installed globally, you can execute:

    mkdir moonbeam-truffle-box && cd moonbeam-truffle-box
    truffle unbox PureStake/moonbeam-truffle-box
    

    Unbox Moonbeam Truffle box

    Otherwise, you can directly clone the following repository:

    git clone https://github.com/PureStake/moonbeam-truffle-box
    cd moonbeam-truffle-box
    
  2. With the files in your local system, you can install all dependencies by running:

    npm install
    

If you look inside of the moonbeam-truffle-box directory, you'll find the following notable directories and files:

  • contracts - a directory that is meant to store any Solidity contracts you create including the following ones that come in the Moonbeam Truffle box:
    • Migrations.sol - required contract to use Truffle's migration feature
    • MyToken.sol - example contract
  • migrations - contains the JavaScript files that help you deploy contracts to the network. It comes with the following scripts:
    • 1_initial_migration.js - script that deploys the Migrations.sol contract. Since this contract would need to be deployed first to use migrations, it begins with 1 and from there you can create new migrations with increasing numbered prefixes
    • 2_deploy_contracts.js - script that deploys the example MyToken.sol contract
  • truffle-config.js - the configuration file for your project where you can define the networks your project can be deployed to, the compiler to use when compiling your contracts, and more

Using the Moonbeam Truffle Plugin to Run a Node

Now that you have created a simple Truffle project, you can spin up a local Moonbeam development node to deploy the contract to. The Moonbeam Truffle plugin provides a way to get started with a development node quickly by using Docker under the hood.

To start a Moonbeam development node in your local environment, you need to:

  1. Download the corresponding Docker image:

    truffle run moonbeam install
    

    Docker image download

  2. Once downloaded, you can proceed to start the local node with the following command:

    truffle run moonbeam start
    

    You will see a message indicating that the node has started, followed by both of the endpoinds available

    Moonbeam local node started

Once you are finished using your Moonbeam development node, you can run the following lines to stop it and remove the Docker image if that is the case:

truffle run moonbeam stop && \
truffle run moonbeam remove

Moonbeam local node stoped and image removed

You also have the option to pause and unpause your Moonbeam development node:

truffle run moonbeam pause
truffle run moonbeam unpause

You can see the output of these commands in the following image:

Install Moonbeam Truffle box

Note

If you are familiar with Docker, you can skip the plugin commands and interact with the Docker image directly.

The Truffle Configuration File

The Truffle configuration file already includes everything you need to get started and deploy a contract to your local Moonbeam development node. Open the truffle-config.js file and review the following details:

  1. The HDWalletProvider package from Truffle has been imported and is used as the hierarchical deterministic wallet
  2. The privateKeyDev variable corresponds to the private key of one of your development accounts, which should hold some development funds. Your development node comes with 10 pre-funded accounts
  3. Under the networks object, you'll see the dev network configuration which is configured to use the port your local development node is running on along with the private key of your development account. Both of which are needed to deploy a contract to your local development node
  4. Under compilers, the solc version listed should be set to support the version of any contracts you wish to deploy. For this example it's set to support version 0.7.0 and up

    Note

    With the release of Solidity v0.8.20, support for the Shanghai hard fork has been introduced, which includes PUSH0 opcodes in the generated bytecode. Support for the PUSH0 opcode on Moonbeam hasn't been rolled out yet. As such, if you'd like to use Solidity v0.8.20, you'll need to update the compilers config to use the London compiler:

    compilers: {
      solc: {
        version: '^0.8.0',
        settings: {
          evmVersion: 'london',
        },
      },
    },
    

    If you attempt to use the default compiler of Solidity v0.8.20, you will see the following error:

    "Migrations" -- evm error: InvalidCode(Opcode(95)).
    

    After you edit your config, you may need to force a compile by running:

    truffle compile --all
    
  5. Under the plugins object, you'll see the moonbeam-truffle-plugin which enables you to quickly spin up a local Moonbeam development node. You'll also find the truffle-plugin-verify plugin which automates the contract verification process for you. Please check out the Verify Smart Contracts with Etherscan Plugins for more information on how to use the plugin

// 1. Import HDWalletProvider
const HDWalletProvider = require('@truffle/hdwallet-provider');

// 2. Moonbeam development node private key
const privateKeyDev =
   '99B3C12287537E38C90A9219D4CB074A89A16E9CDB20BF85728EBD97C343E342';

module.exports = {
  networks: {
    // 3. Configure networks
    dev: {
      provider: () => {
        ...
        return new HDWalletProvider(privateKeyDev, 'http://127.0.0.1:9944')
      },
      network_id: 1281,  // 0x501 in hex,
    },
  },
   // 4. Configure compiler & version
  compilers: {
    solc: {
      version: '^0.7.0',
    },  
  },
  // 5. Plugin configuration
  plugins: ['moonbeam-truffle-plugin', 'truffle-plugin-verify'],
};

Note

For the purpose of this guide, some of the configuration file was removed from the above example.

If you're adapting this guide for Moonbeam, Moonriver, or Moonbase Alpha, you will need to update the configuration file with the appropriate network. To configure your project for Moonbeam or Moonriver, you will need to have your own endpoint and API key which you can get from one of the supported Endpoint Providers. You'll also need to update the private key to one that has funds on that network:

moonbeam: {
  provider: () => {
    ...
    return new HDWalletProvider(
      'PRIVATE_KEY_HERE',  // Insert your private key here
      'INSERT_RPC_API_ENDPOINT' // Insert your RPC URL here
    )
  },
  network_id: 1284 // (hex: 0x504),
},
moonriver: {
  provider: () => {
    ...
    return new HDWalletProvider(
      'PRIVATE_KEY_HERE',  // Insert your private key here
      'INSERT_RPC_API_ENDPOINT' // Insert your RPC URL here
    )
  },
  network_id: 1285 // (hex: 0x505),
},
moonbase: {
  provider: () => {
    ...
    return new HDWalletProvider(
      'PRIVATE_KEY_HERE',  // Insert your private key here
      'https://rpc.api.moonbase.moonbeam.network' // Insert your RPC URL here
    )
  },
  network_id: 1287 // (hex: 0x507),
},

The Contract File

Under the contracts directory, you'll find an ERC-20 token contract, called MyToken, that mints a given amount of tokens to the contract owner:

pragma solidity ^0.7.5;

// Import OpenZeppelin Contract
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";

// This ERC-20 contract mints the specified amount of tokens to the contract creator.
contract MyToken is ERC20 {
  constructor(uint256 initialSupply) ERC20("MyToken", "MYTOK") {
    _mint(msg.sender, initialSupply);
  }
}

This is a simple ERC-20 contract based on the OpenZepplin ERC-20 contract template. It creates MyToken which has MYTOK as the symbol and the standard 18 decimal places. Furthermore, it assigns the created initial token supply to the contract creator.

The Migration Script

Truffle uses a concept called migrations. Migrations are JavaScript files that help you deploy contracts to the network.

If you take a look at the migration scripts in the migrations directory, you'll see there are two files. As previously mentioned, the 1_initial_migration.js script needs to be deployed first and is required to enable Truffle's migration feature. If you take a look at the migration script under migrations/2_deploy_contracts.js, it contains the following:

var MyToken = artifacts.require('MyToken');

module.exports = function (deployer) {
   deployer.deploy(MyToken, '8000000000000000000000000');
};

This script imports the MyToken contract artifact which is created when you compile the contract. It is then used to deploy the contract with any initial constructor values.

For this example, 8000000000000000000000000 is the number of tokens to initially mint with the contract, i.e., 8 million with 18 decimal places.

Deploying a Contract to Moonbeam Using Truffle

Before you can deploy your contracts, you must compile them. As a reminder, you will be deploying the Migrations.sol contract first using the migrations/1_initial_migration.js script. This will enable you to use Truffle's migration feature. You can take the following steps to compile and deploy your contract:

  1. Compile the contracts:

    truffle compile
    

    If successful, you should see output like the following:

    Truffle compile success message

  2. Deploy the compiled contracts:

    truffle migrate --network moonbeam
    
    truffle migrate --network moonriver
    
    truffle migrate --network moonbase
    
    truffle migrate --network dev
    

    If successful, you will see deployment actions, including the address of the deployed contract:

    Successful contract deployment actions

Forking with Ganache

Ganache is part of the Truffle suite of development tools and is your own personal blockchain for local development and testing. You can use Ganache to fork Moonbeam, which will simulate the live network locally, enabling you to interact with already deployed contracts on Moonbeam in a local test environment.

There are some limitations to be aware of when forking with Ganache. Since Ganache is based on an EVM implementation, you cannot interact with any of the Moonbeam precompiled contracts and their functions. Precompiles are a part of the Substrate implementation and therefore cannot be replicated in the simulated EVM environment. This prohibits you from interacting with cross-chain assets on Moonbeam and Substrate-based functionality such as staking and governance.

From your Truffle project, you can install Ganache CLI by running:

npm install ganache

Then you can add a script to run Ganache forking in your package.json file:

...
"scripts": {
  "ganache": "ganache --fork.url INSERT_RPC_API_ENDPOINT"
},
...
...
"scripts": {
  "ganache": "ganache --fork.url INSERT_RPC_API_ENDPOINT"
},
...
...
"scripts": {
  "ganache": "ganache --fork.url https://rpc.api.moonbase.moonbeam.network"
},
...

When you spin up the forked instance, you'll have 10 development accounts that are pre-funded with 1,000 test tokens. The forked instance is available at http://127.0.0.1:8545/. The output in your terminal should resemble the following:

Forking terminal screen

To verify you have forked the network, you can query the latest block number:

curl --data '{"method":"eth_blockNumber","params":[],"id":1,"jsonrpc":"2.0"}' -H "Content-Type: application/json" -X POST localhost:8545 

If you convert the result from hex to decimal, you should get the latest block number from the time you forked the network. You can cross reference the block number using a block explorer.

From here you can deploy new contracts to your forked instance of Moonbeam or interact with contracts already deployed by creating a local instance of the deployed contract.

To interact with an already deployed contract, you can create a new script in the scripts directory using Ethers.js or Web3.js. First, you'll need to install the JavaScript library of your choice:

npm install ethers
npm install web3

Then you can create a new script to access a live contract on the network:

const ethers = require('ethers');

async function main() {
  const provider = new ethers.JsonRpcProvider('http://127.0.0.1:8545/');

  const contract = new ethers.Contract(
      'INSERT_CONTRACT_ADDRESS', 'INSERT_CONTRACT_ABI', provider
  );
}

main().catch((error) => {
  console.error(error);
  process.exitCode = 1;
});
const Web3 = require('web3');

async function main() {
  const web3 = new Web3('http://127.0.0.1:8545/');

  const contract = new web3.eth.Contract('INSERT_CONTRACT_ADDRESS', 'INSERT_CONTRACT_ABI');
}

main().catch((error) => {
  console.error(error);
  process.exitCode = 1;
});

To run the script, you can use the following command:

truffle exec INSERT_PATH_TO_FILE
The information presented herein has been provided by third parties and is made available solely for general information purposes. Moonbeam does not endorse any project listed and described on the Moonbeam Doc Website (https://docs.moonbeam.network/). Moonbeam Foundation does not warrant the accuracy, completeness or usefulness of this information. Any reliance you place on such information is strictly at your own risk. Moonbeam Foundation disclaims all liability and responsibility arising from any reliance placed on this information by you or by anyone who may be informed of any of its contents. All statements and/or opinions expressed in these materials are solely the responsibility of the person or entity providing those materials and do not necessarily represent the opinion of Moonbeam Foundation. The information should not be construed as professional or financial advice of any kind. Advice from a suitably qualified professional should always be sought in relation to any particular matter or circumstance. The information herein may link to or integrate with other websites operated or content provided by third parties, and such other websites may link to this website. Moonbeam Foundation has no control over any such other websites or their content and will have no liability arising out of or related to such websites or their content. The existence of any such link does not constitute an endorsement of such websites, the content of the websites, or the operators of the websites. These links are being provided to you only as a convenience and you release and hold Moonbeam Foundation harmless from any and all liability arising from your use of this information or the information provided by any third-party website or service.
Last update: May 13, 2023
| Created: March 1, 2022