Skip to content

Using Ape to Deploy To Moonbeam

Introduction

Ape is an Ethereum development environment that helps Python developers manage and automate the recurring tasks inherent to building smart contracts and DApps. Ape can directly interact with Moonbeam's Ethereum API, so you can also use Ape to deploy smart contracts on Moonbeam.

This guide will walk you through using Ape to compile, deploy, and interact with Ethereum smart contracts on the Moonbase Alpha TestNet. You can adapt this guide for Moonbeam, Moonriver, or a Moonbeam development node.

Checking Prerequisites

To get started, ensure you have the following:

  • MetaMask installed and connected to Moonbase Alpha
  • 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

Creating an Ape Project

If you don't already have an Ape project, you must install Ape and create a new one. You can follow the steps below to get started and create an empty project:

  1. Create a directory for your project

    mkdir ape && cd ape
    
  2. If you don't have pipx installed, install it

    python3 -m pip install --user pipx
    python3 -m pipx ensurepath
    
  3. Install Ape using pipx

    pipx install eth-ape
    
  4. Create a project

    ape init
    
  5. Enter a name for your project

    ape init Please enter project name: ape-demo
    SUCCESS: ape-demo is written in ape-config.yaml
    ls ape-config.yaml contracts scripts tests

Your Ape project contains a bare-bones ape-config.yaml file for customizing specific settings and the following empty directories:

  • contracts - an empty directory for storing smart contracts
  • scripts - an empty directory for storing Python scripts, such as deployment scripts and scripts to interact with your deployed contracts
  • tests - an empty directory for pytest testing scripts

Configure Accounts

You'll need to import an account before you can deploy smart contracts or interact with previously deployed contracts from your Ape project. You can run the following command, which will import your account and give it a name:

ape accounts import INSERT_ACCOUNT_NAME

You'll then be prompted to enter your private key and add a password to encrypt your account.

ape accounts import alice Enter Private Key: Create Passphrase to encrypt account: Repeat for confirmation: SUCCESS: A new account '0x097D9Eea23DE2D3081169e0225173d0C55768338' has been added with the id 'alice'

Note

If you wish to use a mnemonic instead, you can append the --use-mnemonic option to the import command.

Create Smart Contracts

Now that you have set up your account, you can start writing smart contracts. As a basic example, you can use the following Box contract to store a value you can retrieve later.

Start by creating a file named Box.sol inside the contracts directory:

touch contracts/Box.sol

Open the file and add the following contract to it:

// SPDX-License-Identifier: MIT 
pragma solidity ^0.8.1;

contract Box {
    uint256 private value;

    event ValueChanged(uint256 newValue);

    function store(uint256 newValue) public {
        value = newValue;
        emit ValueChanged(newValue);
    }

    function retrieve() public view returns (uint256) {
        return value;
    }
}

You can store any additional contracts in the contracts directory.

Compile the Solidity Contract

Before compiling the Solidity, you must install the Solidity compiler plugin. Running the following command will install the latest version of the plugin:

ape plugins install solidity

To use a specific version of Solidity or a specific EVM version, you can modify your ape-config.yaml file as follows:

solidity:
  version: INSERT_VERSION
  evm_version: INSERT_VERSION

For more information on the Solidity plugin, please refer to the README of the ape-solidity repository on GitHub.

With the Solidity plugin installed, the next step is to compile the smart contract:

ape compile
ape compile INFO: Compiling 'Box.sol'. INFO: Compiling using Solidity compiler '0.8.23+commit.f704f362'.

After compilation, you can find the bytecode and ABI for your contracts in the .build directory.

Test the Contract

Before you deploy your contract, you can test it out directly inside your Ape project using the pytest framework to make sure it works as you expect.

You should already have a tests directory where you'll create your tests, but if not, please create one, as all tests must be located in a directory named tests. Additionally, each test file name must start with test_ and end with .py. So, first, you can create a test file for the Box.sol contract:

touch tests/test_box.py

In addition to the test file, you can create a conftest.py file that will define a couple of essential fixtures. Fixtures allow you to define functions that set up the necessary environment or resources to run your tests. Note that while the Box.sol contract is simple, incorporating fixtures into your testing process is good practice.

To create the file, you can run the following command:

touch tests/conftest.py

Since your tests will rely on the injection of the fixtures, you must define the fixtures first. When defining fixtures, you need to apply the pytest.fixture decorator above each function. For this example, you'll create two fixtures: one that defines the owner of the contract and one that deploys the contract from the owner's account.

The owner fixture will use the built-in accounts fixture to take the first account in the list of test accounts provided by Ape and return it. The box fixture will deploy the Box contract type using the built-in project fixture, you simply have to provide the name of the contract and use the owner fixture to deploy it.

tests/conftest.py
import pytest


@pytest.fixture
def owner(accounts):
    return accounts[0]


@pytest.fixture
def box(owner, project):
    return owner.deploy(project.Box)

Now that you've created the fixtures, you can start creating your tests. Each test function name must start with test_ and describe what the test does. For this example, you can use test_store_value, as you'll create a test for the store function. The test will store a value and then retrieve it, asserting that the retrieved value is equal to the value passed into the store function.

To use the owner and box fixtures, you must pass them into your test function, which will inject the fixtures automatically for you to use. The owner account will be used to call the store function of the box contract instance.

tests/test_box.py
def test_store_value(box, owner):
    new_value = 5
    box.store(new_value, sender=owner)
    assert box.retrieve() == new_value

And that's it! That's all you'll need inside your test file. You can use the following command to run the test:

ape test

The results of running the test will be printed to the terminal.

ape test ===================== test session starts ====================== platform darwin -- Python 3.10.4, pytest-7.2.1, pluggy-1.4.0 rootdir: /Users/moonbeam/ape plugins: eth-ape-0.7.7, web3-6.15.1 collected 1 item
tests/test_box.py . [100%]
====================== 1 passed in 0.70s =======================

Now that you have confidence in your contract, the next step is to deploy it.

Deploy the Contract

To deploy your contracts, create a deployment script named deploy.py inside of the scripts directory:

touch scripts/deploy.py

Next, you'll need to write the deployment script. You'll need to load the account you will use to deploy the contract and access it by its name using the project manager.

scripts/deploy.py
from ape import project, accounts


def main():
    # Load your account by its name
    account = accounts.load("alice")
    # Deploy the contract using your account
    return account.deploy(project.Box)

Now you're ready to deploy the Box contract! 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.

Take the following steps to initiate and send the deployment transaction:

  1. Run the deployment script using the ape run deploy command

    ape run deploy --network INSERT_RPC_API_ENDPOINT
    
    ape run deploy --network INSERT_RPC_API_ENDPOINT
    
    ape run deploy --network https://rpc.api.moonbase.moonbeam.network
    
    ape run deploy --network http://127.0.0.1:9944
    

    Note

    For the ape run deploy command to work as intended, the deployment script must be named deploy.py and stored in the scripts directory, and the script must define a main() method.

  2. Review the transaction details and enter y to sign the transaction

  3. Enter your passphrase for your account
  4. Enter y to leave your account unlocked or n to lock it

After you follow the prompts and submit the transaction, the transaction hash, total fees paid, and contract address will be displayed in the terminal.

ape run deploy --network https://rpc.api.moonbase.moonbeam.network INFO: Connecting to a 'moonbase' node.
DynamicFeeTransaction: chainId: 1287 from: 0x097D9Eea23DE2D3081169e0225173d0C55768338 gas: 123964 nonce: 372 value: 0 data: 0x307836...303333 type: 2 maxFeePerGas: 125000000 maxPriorityFeePerGas: 0 accessList: []
Sign: [y/N]: y Enter passphrase to unlock 'alice' []: Leave 'alice' unlocked? [y/N]: n INFO: Confirmed 0x365cd903e7fac5ad1f815d7a6f211b1aa32bd7d78630c2e81d67514cfb9e55bb (total fees paid = 15326250000000) SUCCESS: Contract 'Box' deployed to: 0x68039277300E8B104dDf848029dCA04C2EFe8610

Congratulations! Your contract is live! Save the address to interact with your contract in the following section.

Interact with the Contract

You can interact with contracts using the Ape console for quick debugging and testing, or write a script.

Using The Ape Console

To interact with your newly deployed contract, you can launch the Ape console by running:

ape console --network INSERT_RPC_API_ENDPOINT
ape console --network INSERT_RPC_API_ENDPOINT
ape console --network https://rpc.api.moonbase.moonbeam.network
ape console --network http://127.0.0.1:9944

Next, you'll need to create a contract instance using the contract's address:

box = Contract("INSERT_CONTRACT_ADDRESS")
ape console --network https://rpc.api.moonbase.moonbeam.network INFO: Connecting to a 'moonbase' node.
alice = accounts.load("alice") box = Contract("0x68039277300E8B104dDf848029dCA04C2EFe8610")

Now, you can interact with your contract instance! For example, you can set the variable to be stored in the Box contract using the following commands:

  1. Call the store method by passing in a value to store and the account you want to use to send the transaction:

    box.store(4, sender=alice)
    
  2. Review the transaction details and enter y to sign the transaction

  3. If you previously locked your account, you must enter your passphrase to unlock it. Otherwise, Ape will use the cached key for your account
  4. If you unlocked your account in the previous step, you'll be asked if you want to leave your account unlocked. You can enter y to leave it unlocked or n to lock it

After you follow the prompts and submit the transaction, the transaction hash and total fees paid will be displayed in the terminal.

box.store(4, sender=alice) DynamicFeeTransaction: chainId: 1287 to: 0x68039277300E8B104dDf848029dCA04C2EFe8610 from: 0x097D9Eea23DE2D3081169e0225173d0C55768338 gas: 45668 nonce: 373 value: 0 data: 0x307836...303034 type: 2 maxFeePerGas: 125000000 maxPriorityFeePerGas: 0 accessList: []
Sign: [y/N]: y Enter passphrase to unlock 'alice' []: Leave 'alice' unlocked? [y/N]: n INFO: Confirmed 0xd2e8305f22f33c1ab8ccaaef94252a93ff0f69c9bf98503fc2744bf257f1ef67 (total fees paid = 5573750000000) Receipt 0xd2e8305f22f33c1ab8ccaaef94252a93ff0f69c9bf98503fc2744bf257f1ef67

Then, you can retrieve the stored value by calling the retrieve method:

box.retrieve()

The number you just stored in the previous steps will be printed to the console.

contract.retrieve() 4

Using a Script

You can also write a script to interact with your newly deployed contract. To get started, you can create a new file in the scripts directory:

touch scripts/store-and-retrieve.py

Next, you can write a script that stores and retrieves a value. Note that when creating a contract instance to interact with, you must pass in the address of the deployed contract.

scripts/store-and-retrieve.py
from ape import Contract, accounts


def main():
    account = accounts.load("alice")
    box = Contract("INSERT_CONTRACT_ADDRESS")
    store = box.store(4, sender=account)
    print("Transaction hash for updating the stored value:", store.txn_hash)

    retrieve = box.retrieve()
    print("Stored value:", retrieve)

Now, you can run the script to set the stored value and retrieve it:

  1. Run the script

    ape run store-and-retrieve --network INSERT_RPC_API_ENDPOINT
    
    ape run store-and-retrieve --network INSERT_RPC_API_ENDPOINT
    
    ape run store-and-retrieve --network https://rpc.api.moonbase.moonbeam.network
    
    ape run store-and-retrieve --network http://127.0.0.1:9944
    
  2. Review the transaction details and enter y to sign the transaction

  3. If you previously locked your account, you must enter your passphrase to unlock it. Otherwise, Ape will use the cached key for your account
  4. If you unlocked your account in the previous step, you'll be asked if you want to leave your account unlocked. You can enter y to leave it unlocked or n to lock it

Once completed, you should see a transaction hash and a value of 4 printed to the console.

ape run store-and-retrieve --network https://rpc.api.moonbase.moonbeam.network DynamicFeeTransaction: chainId: 1287 to: 0x68039277300E8B104dDf848029dCA04C2EFe8610 from: 0x097D9Eea23DE2D3081169e0225173d0C55768338 gas: 25974 nonce: 374 value: 0 data: 0x307836...303035 type: 2 maxFeePerGas: 125000000 maxPriorityFeePerGas: 0 accessList: []
Sign: [y/N]: y Enter passphrase to unlock 'alice' []: Leave 'alice' unlocked? [y/N]: n INFO: Confirmed 0x6d74e48c23fd48438bf48baad34e235693c737bd880ef0077c0fb996f3896f5f (total fees paid = 3086250000000) Transaction hash for updating the stored value: 0x6d74e48c23fd48438bf48baad34e235693c737bd880ef0077c0fb996f3896f5f Stored value: 5

Congratulations! You have successfully deployed and interacted with a contract using Ape!

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: March 13, 2024
| Created: February 7, 2024