Skip to main content

Using Foundry with the Metal C-Chain


This guide shows how to deploy and interact with smart contracts using foundry on a local Metal Blockchain Network and the Tahoe C-Chain, which is an instance of the EVM.

Foundry toolchain is a smart contract development toolchain written in Rust. It manages your dependencies, compiles your project, runs tests, deploys, and lets you interact with the chain from the command-line.


  • You have installed Foundry. This installation includes the forge and cast binaries used in this walk-through.

MetalGo and Metal Network Runner

MetalGo is an Metal node implementation written in Go.

Metal Network Runner is a tool to quickly deploy local test networks. Together, you can deploy local test networks and run tests on them.

Start a local five node Metal network:

cd /path/to/metal-network-runner
# start a five node staking network
./go run examples/local/fivenodenetwork/main.go

A five node Metal Blockchain network is running on your machine. Network will run until you Ctrl + C to exit.

Getting Started

This section will walk you through creating an ERC721.

Clone Metal Smart Contract Quick Start

Clone the quickstart repository and install the necessary packages via yarn.

git clone
cd metal-smart-contract-quickstart

In order to deploy contracts, you need to have some METAL. You can get testnet METAL from the Metal Faucet, which is an easy way to get to play around with Metal Blockchain. After getting comfortable with your code, you can run it on Mainnet after making the necessary changes to your workflow.

Write Contracts

We will use our example ERC721 smart contract, NFT.sol found in ./contracts of our project.

//SPDX-License-Identifier: MIT
// contracts/ERC721.sol

pragma solidity >=0.6.2;

import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/utils/Counters.sol";

contract NFT is ERC721 {
using Counters for Counters.Counter;
Counters.Counter private _tokenIds;

constructor() ERC721("GameItem", "ITM") {}

// commented out unused variable
// function awardItem(address player, string memory tokenURI)
function awardItem(address player)
returns (uint256)

uint256 newItemId = _tokenIds.current();
_mint(player, newItemId);
// _setTokenURI(newItemId, tokenURI);

return newItemId;

Let's examine this implementation of an NFT as a Game Item. We start by importing to contracts from our node modules. We import OpenZeppelin's open source implementation of the ERC721 standard which our NFT contract will inherit from. Our constructor takes the _name and _symbol arguments for our NFT and passes them on to the constructor of the parent ERC721 implementation. Lastly we implement the awardItem function which allows anyone to mint an NFT to a player's wallet address. This function increments the currentTokenId and makes use of the _mint function of our parent contract.

Compile & Deploy with Forge

Forge is a command-line tool that ships with Foundry. Forge tests, builds, and deploys your smart contracts.

To compile the NFT contract run:

forge build

By default the compiler output will be in the out directory. To deploy our compiled contract with Forge we have to set environment variables for the RPC endpoint and the private key we want to use to deploy.

Set your environment variables by running:


Since we are deploying to Tahoe testnet, our RPC_URL export should be:

export RPC_URL=

Once set, you can deploy your NFT with Forge by running the command below while adding the values for _name and _symbol, the relevant constructor arguments of the NFT contract:

forge create NFT --rpc-url=$RPC_URL --private-key=$PRIVATE_KEY --constructor-args GameItem ITM

Upon successful deployment, you will see the deploying wallet's address, the contract's address as well as the transaction hash printed to your terminal.

Here's an example output from an NFT deployment.

[⠔] Compiling...
No files changed, compilation skipped
Deployer: 0x8db97c7cece249c2b98bdc0226cc4c2a57bf52fc
Deployed to: 0x52c84043cd9c865236f11d9fc9f56aa003c1f922
Transaction hash: 0xf35c40dbbdc9e4298698ad1cb9937195e5a5e74e557bab1970a5dfd42a32f533

Note: Please store your Deployed to address for use in the next section.

Using Cast to Interact with the Smart Contract

We can call functions on our NFT contract with Cast, Foundry's command-line tool for interacting with smart contracts, sending transactions, and getting chain data. In this scenario, we will mint a Game Item to a player's wallet using the awardItem function in our smart contract.

Mint an NFT from your contract by replacing <NFT-CONTRACT-ADDRESS> with your Deployed to address and <NFT-RECIPIENT-ADDRESS> with an address of your choice.

Note: This section assumes that you have already set your RPC and private key env variables during deployment

cast send --rpc-url=$RPC_URL  <NFT-CONTRACT-ADDRESS> "awardItem(address)" <NFT-RECIPIENT-ADDRESS> --private-key=$PRIVATE_KEY

Upon success, the command line will display the transaction data.

blockHash               0x1d9b0364fe002eeddd0e32be0c27d6797c63dffb51fe555ea446357759e6a6f8
blockNumber 10714448
cumulativeGasUsed 90837
effectiveGasPrice 28000000000
gasUsed 90837
logs [{"address":"0x45857b942723fff8ee7acd2b1d6515d9965c16e5","topics":["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0x0000000000000000000000000000000000000000000000000000000000000000","0x000000000000000000000000845095a03a6686e24b90fed55e11f4ec808b1ab3","0x0000000000000000000000000000000000000000000000000000000000000001"],"data":"0x","blockHash":"0x1d9b0364fe002eeddd0e32be0c27d6797c63dffb51fe555ea446357759e6a6f8","blockNumber":"0xa37d50","transactionHash":"0x4651ae041a481a6eeb852e5300e9be48e66a1d2332733df22d8e75cf460b0c2c","transactionIndex":"0x0","logIndex":"0x0","removed":false}]
logsBloom 0x00000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000040000000000000000000000000008010000000000000000040000000000000000000000000000020000040000000000000800000000002000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000060080000000000000000000000000000000000000000000000000000000000000000
status 1
transactionHash 0x4651ae041a481a6eeb852e5300e9be48e66a1d2332733df22d8e75cf460b0c2c
transactionIndex 0
type 2

Well done! You just minted your first NFT from your contract. You can check the owner of tokenId 1 by running the cast call command below:

cast call --rpc-url=$RPC_URL --private-key=$PRIVATE_KEY <NFT-CONTRACT-ADDRESS> "ownerOf(uint256)" 1

The address you provided above should be returned as the owner.


Mainnet Workflow

The Tahoe testnet workflow above can be adapted to Mainnet with the following modifications to the environment variables:

export RPC_URL=

Local Workflow

The Tahoe testnet workflow above can be adapted to a Local Network by doing following:

In a new terminal navigate to your Metal Network Runner directory.

cd /path/to/Metal-Network-Runner

Next, deploy a new Metal Network with five nodes (a Cluster) locally.

go run examples/local/fivenodenetwork/main.go

Next, modify the environment variables in your Foundry project:

export RPC_URL=http://localhost:9650/ext/bc/C/rpc
export PRIVATE_KEY=56289e99c94b6912bfc12adc093c9b51124f0dc54ac7a766b2bc5ccf558d8027

The example PRIVATE_KEY variable above provides a pre-funded account on Metal Network Runner and should be used for LOCAL DEVELOPMENT ONLY.


Now you have the tools you need to launch a local Metal network, create a Foundry project, as well as create, compile, deploy and interact with Solidity contracts.

If you have questions, problems, or just want to chat with us, you can reach us on our public Telegram chat. We'd love to hear from you and find out what you're building on Metal Blockchain!