Skip to content

Using Foundry with IOST Layer 2

This guide explains how to use Foundry - a blazing fast, portable Rust-based toolkit for Ethereum application development - to deploy and interact with smart contracts on IOST 3.0 Layer 2.

What is Foundry?

Foundry is a smart contract development toolchain written in Rust that includes:

  • forge: A testing framework for Ethereum contracts
  • cast: A command-line tool for interacting with EVM smart contracts
  • anvil: A local Ethereum node for development purposes
  • chisel: A Solidity REPL for quick experimentation

Compared to other development environments, Foundry offers:

  • Extremely fast compilation and testing
  • Native Solidity testing
  • Advanced debugging and gas profiling tools
  • Strong focus on unit and integration testing

Installation

Install Foundry with the following commands:

bash
# Install Foundry
curl -L https://foundry.paradigm.xyz | bash
foundryup

# Verify installation
forge --version
cast --version
anvil --version

Project Setup

Create a new Foundry project for use with IOST Layer 2:

bash
# Create a new project
forge init my_iost_project
cd my_iost_project

# Install OpenZeppelin contracts (optional but recommended)
forge install OpenZeppelin/openzeppelin-contracts

Configuration for IOST Layer 2

Update your foundry.toml file to include IOST Layer 2 network settings:

toml
[profile.default]
src = "src"
out = "out"
libs = ["lib"]
solc = "0.8.19"
optimizer = true
optimizer_runs = 200

[rpc_endpoints]
iost_mainnet = "https://l2-mainnet.iost.io"

[etherscan]
iost_mainnet = { url = "https://l2-scan.iost.io/" }

Writing Contracts

Create your Solidity contracts in the src directory:

solidity
// src/SimpleStorage.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

contract SimpleStorage {
    uint256 private value;
    
    event ValueChanged(uint256 newValue);
    
    function set(uint256 newValue) public {
        value = newValue;
        emit ValueChanged(newValue);
    }
    
    function get() public view returns (uint256) {
        return value;
    }
}

Writing Tests

Create test files in the test directory using Solidity (one of Foundry's key advantages):

solidity
// test/SimpleStorage.t.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

import "forge-std/Test.sol";
import "../src/SimpleStorage.sol";

contract SimpleStorageTest is Test {
    SimpleStorage public simpleStorage;
    
    function setUp() public {
        simpleStorage = new SimpleStorage();
    }
    
    function testSetValue() public {
        simpleStorage.set(100);
        assertEq(simpleStorage.get(), 100);
    }
    
    function testEmitsEvent() public {
        vm.expectEmit(true, true, true, true);
        emit SimpleStorage.ValueChanged(200);
        simpleStorage.set(200);
    }
}

Run your tests with:

bash
forge test -vv

Creating Deployment Scripts

Foundry uses Solidity scripts for deployment. Create a script file:

solidity
// script/DeploySimpleStorage.s.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

import "forge-std/Script.sol";
import "../src/SimpleStorage.sol";

contract DeploySimpleStorage is Script {
    function run() public {
        // Retrieve private key from environment
        uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY");
        
        // Start broadcasting transactions
        vm.startBroadcast(deployerPrivateKey);
        
        // Deploy the contract
        SimpleStorage simpleStorage = new SimpleStorage();
        
        // Stop broadcasting transactions
        vm.stopBroadcast();
        
        // Log the deployed contract address
        console.log("SimpleStorage deployed to:", address(simpleStorage));
    }
}

Deployment to IOST Layer 2

To deploy your contract to IOST Layer 2:

  1. Set your private key as an environment variable:
bash
export PRIVATE_KEY=your_private_key_here
  1. Deploy using forge:
bash
forge script script/DeploySimpleStorage.s.sol --rpc-url iost_mainnet --broadcast

Contract Verification

Verify your contract on the IOST Layer 2 explorer:

bash
forge verify-contract \
    --chain-id 182 \
    --compiler-version v0.8.19 \
    --watch \
    --verifier-url https://l2-scan.iost.io/ \
    <DEPLOYED_CONTRACT_ADDRESS> \
    src/SimpleStorage.sol:SimpleStorage

Interacting with Deployed Contracts

Foundry's cast command allows you to interact with your deployed contracts:

bash
# Read the current value
cast call <CONTRACT_ADDRESS> "get()" --rpc-url iost_mainnet

# Set a new value
cast send --private-key $PRIVATE_KEY <CONTRACT_ADDRESS> "set(uint256)" 123 --rpc-url iost_mainnet

Advanced Features

Gas Profiling

Analyze gas usage of your contract functions:

bash
forge test --gas-report

Fuzz Testing

Foundry provides powerful property-based testing:

solidity
function testFuzz_SetValue(uint256 x) public {
    simpleStorage.set(x);
    assertEq(simpleStorage.get(), x);
}

Traces

Debug your contract with detailed execution traces:

bash
forge test -vvvv

Fork Testing

Test against a fork of the IOST Layer 2 mainnet:

bash
forge test --fork-url https://l2-mainnet.iost.io

Troubleshooting

RPC Connectivity Issues

Symptom: Unable to connect to IOST Layer 2 network

Solution: Verify RPC URL and network status

Verification Failures

Symptom: Contract verification fails on the explorer

Solution: Ensure compiler version and optimization settings match deployment parameters exactly

Gas Estimation Errors

Symptom: Deployment fails with gas estimation errors

Solution: Add explicit gas limits to your deployment command with --gas-limit

Best Practices

  • Use Consistent Solidity Versions: Keep the same compiler version across your project
  • Leverage Foundry's Testing Features: Use Solidity for tests to benefit from type checking
  • Store Sensitive Data in .env: Never commit private keys to version control
  • Use Script Libraries: Leverage the forge-std Script base for deployments
  • Gas Optimization: Regularly run gas reports to identify optimization opportunities

Released under the MIT License.