Using Foundry with Flow
Foundry is a suite of development tools that simplifies the process of developing and deploying Solidity contracts to EVM networks. This guide will walk you through the process of deploying a Solidity contract to Flow EVM using the Foundry development toolchain. You can check out the official Foundry docs here.
In this guide, we'll deploy an ERC-20 token contract to Flow EVM using Foundry. We'll cover:
- Developing and testing a basic ERC-20 contract
- Deploying the contract to Flow EVM using Foundry tools
- Querying Testnet state
- Mutating Testnet state by sending transactions
Overview
To use Flow across all Foundry tools you need to:
-
Provide the Flow EVM RPC URL to the command you are using:
-
Use the
--legacy
flag to disable EIP-1559 style transactions. Flow will support EIP-1559 soon and this flag won't be needed.
As an example, we'll show you how to deploy a fungible token contract to Flow EVM using Foundry. You will see how the above flags are used in practice.
Example: Deploying an ERC-20 Token Contract to Flow EVM
ERC-20 tokens are the most common type of tokens on Ethereum. We'll use OpenZeppelin starter templates with Foundry on Flow Testnet to deploy our own token called MyToken
.
Installation
The best way to install Foundry, is to use the foundryup
CLI tool. You can get it using the following command:
Install the tools:
This will install the Foundry tool suite: forge
, cast
, anvil
, and chisel
.
You may need to reload your shell after foundryup
installation.
Check out the official Installation guide for more information about different platforms or installing specific versions.
Wallet Setup
We first need to generate a key pair for our EVM account. We can do this using the cast
tool:
cast
will print the private key and address of the new account. We can then paste the account address into the Faucet to fund it with some Testnet FLOW tokens.
You can verify the balance of the account after funding. Replace $YOUR_ADDRESS
with the address of the account you funded:
Project Setup
First, create a new directory for your project:
We can use init
to initialize a new project:
This will create a contract called Counter
in the contracts
directory with associated tests and deployment scripts. We can replace this with our own ERC-20 contract. To verify the initial setup, you can run the tests for Counter
:
The tests should pass.
Writing the ERC-20 Token Contract
We'll use the OpenZeppelin ERC-20 contract template. We can start by adding OpenZeppelin to our project:
Rename src/Counter.sol
to src/MyToken.sol
and replace the contents with the following:
The above is a basic ERC-20 token with the name MyToken
and symbol MyT
. It also mints the specified amount of tokens to the contract deployer. The amount is passed as a constructor argument during deployment.
Before compiling, we also need to update the test file.
Testing
Rename test/Counter.t.sol
to test/MyToken.t.sol
and replace the contents with the following:
You can now make sure everything is okay by compiling the contracts:
Run the tests:
They should all succeed.
Deploying to Flow Testnet
We can now deploy MyToken
using the forge create
command. We need to provide the RPC URL, private key from a funded account using the faucet, and constructor arguments that is the initial mint amount in this case. We need to use the --legacy
flag to disable EIP-1559 style transactions. Replace $DEPLOYER_PRIVATE_KEY
with the private key of the account you created earlier:
The above will print the deployed contract address. We'll use it in the next section to interact with the contract.
Verifying a Smart Contract
Once deployed, you can verify the contract so that others can see the source code and interact with it from Flow's block explorer. You can use the forge verify-contract
command:
When verifying a Mainnet contract, be sure to use the Mainnet RPC and block explorer URLs.
Querying Testnet State
Based on the given constructor arguments, the deployer should own 42,000,000 MyT
. We can check the MyToken
balance of the contract owner. Replace $DEPLOYED_MYTOKEN_ADDRESS
with the address of the deployed contract and $DEPLOYER_ADDRESS
with the address of the account you funded earlier:
This should return the amount specified during deployment. We can also call the associated function directly in the contract:
We can query other data like the token symbol:
Sending Transactions
Let's create a second account and move some tokens using a transaction. You can use cast wallet new
to create a new test account. You don't need to fund it to receive tokens. Replace $NEW_ADDRESS
with the address of the new account:
We can check the balance of the new account:
The deployer should also own less tokens now: