Shardeum Documentation

Using Foundry

Foundry is a fast, Rust-based toolkit for developing, testing, and deploying EVM-compatible smart contracts. It includes:

  • forge — for building, testing, and deploying contracts
  • cast — for interacting with deployed contracts
  • anvil — for running a local Ethereum-compatible node

Foundry is well-suited for advanced developers who prefer Solidity-based tests and fast iteration.

Official Foundry repository: https://github.com/foundry-rs/foundry

Deployment Guide

Prerequisites

Before you begin, ensure you have:

  • A Unix-like terminal (Linux, macOS, or WSL on Windows)
  • A funded wallet private key (testnet or mainnet SHM)
  • Access to a Shardeum RPC endpoint

Install Foundry

Install Foundry using the official installer:

Deployment Guide

Prerequisites

Before you begin, ensure you have:

  • A Unix-like terminal (Linux, macOS, or WSL on Windows)
  • A funded wallet private key (testnet or mainnet SHM)
  • Access to a Shardeum RPC endpoint

Install Foundry

Install Foundry using the official installer:

curl -L https://foundry.paradigm.xyz | bash

Restart your terminal (or reload your shell), then run:

Restart your terminal (or reload your shell), then run:

foundryup


Verify installation:

```shell
forge --version

Verify installation:

forge --version

If this installation method does not work, or you would like to install Foundry a different way, see other installation methods in Foundry's README:

Create a Foundry Project

Create a Foundry Project

Initialize a new Foundry project: Initialize a new Foundry project:

forge init shardeum-foundry
cd shardeum-foundry
forge init shardeum-foundry
cd shardeum-foundry

This creates the following structure: This creates the following structure:

  • src/ — smart contracts
  • test/ — Solidity test contracts
  • foundry.toml — project configuration
  • src/ — smart contracts
  • test/ — Solidity test contracts
  • foundry.toml — project configuration

Write a Simple Storage Contract

Write a Simple Storage Contract

Create a new file at src/Contract.sol: Create a new file at src/Contract.sol:

// SPDX-License-Identifier: MIT
pragma solidity 0.8.7;
 
error sameStorageValue();
error notOwner();
error msgValueZero();
 
contract SimpleStorage {
    uint public storedData;
    uint public ownerUnixTimeContract;
    uint public storedData;
    uint public ownerUnixTimeContract;
    address public immutable owner;
 
    constructor() {
        owner = msg.sender;
    }
 
    event setOpenDataEvent(address indexed user, uint newValue);
    event setOpenDataEvent(address indexed user, uint newValue);
    event setOwnerDataEvent(uint newOwnerUnixTime);
    event donateToOwnerEvent();
 
    function set(uint x) public {
        if (storedData == x) revert sameStorageValue();
        if (storedData == x) revert sameStorageValue();
        storedData = x;
        emit setOpenDataEvent(msg.sender, x);
        emit setOpenDataEvent(msg.sender, x);
    }
 
    function setOwnerData() public {
        if (msg.sender != owner) revert notOwner();
        if (msg.sender != owner) revert notOwner();
        ownerUnixTimeContract = block.timestamp;
        emit setOwnerDataEvent(block.timestamp);
    }
 
    function donateToOwner() public payable {
        if (msg.value == 0) revert msgValueZero();
        if (msg.value == 0) revert msgValueZero();
        payable(owner).transfer(address(this).balance);
        emit donateToOwnerEvent();
    }
}

Add a Test Contract

Add a Test Contract

Create test/Contract.t.sol: Create test/Contract.t.sol:

// SPDX-License-Identifier: Unlicense
pragma solidity 0.8.7;
 
import "forge-std/Test.sol";
import "src/Contract.sol";
 
contract TestContract is Test {
    receive() external payable {}
    fallback() external payable {}
 
    receive() external payable {}
    fallback() external payable {}
 
    event setOpenDataEvent(address indexed user, uint newValue);
    event setOwnerDataEvent(uint newOwnerUnixTime);
    event donateToOwnerEvent();
 
    SimpleStorage storageContract;
    SimpleStorage storageContract;
 
    function setUp() public {
        storageContract = new SimpleStorage();
        storageContract = new SimpleStorage();
    }
 
    function testInitialState() public {
        assertEq(storageContract.storedData(), 0);
        assertEq(storageContract.ownerUnixTimeContract(), 0);
        assertEq(storageContract.owner(), address(this));
    function testInitialState() public {
        assertEq(storageContract.storedData(), 0);
        assertEq(storageContract.ownerUnixTimeContract(), 0);
        assertEq(storageContract.owner(), address(this));
    }
 
    function testSetValue() public {
        vm.expectEmit(true, false, false, true);
        emit setOpenDataEvent(address(this), 1);
 
        storageContract.set(1);
        assertEq(storageContract.storedData(), 1);
    function testSetValue() public {
        vm.expectEmit(true, false, false, true);
        emit setOpenDataEvent(address(this), 1);
 
        storageContract.set(1);
        assertEq(storageContract.storedData(), 1);
    }
 
    function testSetSameValueReverts() public {
        vm.expectRevert(sameStorageValue.selector);
        storageContract.set(0);
    function testSetSameValueReverts() public {
        vm.expectRevert(sameStorageValue.selector);
        storageContract.set(0);
    }
 
    function testOwnerOnlyFunction() public {
        vm.warp(10);
        storageContract.setOwnerData();
        assertEq(storageContract.ownerUnixTimeContract(), 10);
    function testOwnerOnlyFunction() public {
        vm.warp(10);
        storageContract.setOwnerData();
        assertEq(storageContract.ownerUnixTimeContract(), 10);
    }
 
    function testDonateRevertsOnZeroValue() public {
        vm.expectRevert(msgValueZero.selector);
        storageContract.donateToOwner();
    function testDonateRevertsOnZeroValue() public {
        vm.expectRevert(msgValueZero.selector);
        storageContract.donateToOwner();
    }
}

Run all tests: Run all tests:

forge test

Run a specific test with verbose output: Run a specific test with verbose output:

forge test -vvvv --match-test testSetValue

Set Environment Variables

Create a .env file in the project root (or export variables in your shell):

SHARDEUM_RPC=https://api-mezame.shardeum.org PRIVATE_KEY=YOUR_PRIVATE_KEY

Security note:

  • Never commit private keys to version control
  • Add .env to .gitignore

Deploy to Shardeum Using Foundry

Foundry uses EIP-1559 transactions by default. Shardeum currently requires legacy-style gas parameters, so deployments should include the --legacy flag.

Deploy to Testnet (Mezame)

forge test -vvvv --match-test testSetValue


### Set Environment Variables

Create a `.env` file in the project root (or export variables in your shell):

SHARDEUM_RPC=https://api-mezame.shardeum.org
PRIVATE_KEY=YOUR_PRIVATE_KEY

**Security note**:
- Never commit private keys to version control
- Add `.env` to `.gitignore`

### Deploy to Shardeum Using Foundry

Foundry uses EIP-1559 transactions by default. Shardeum currently requires legacy-style gas parameters, so deployments should include the --legacy flag.

#### Deploy to Testnet (Mezame)

```shell
forge create \
  --legacy \
  --rpc-url $SHARDEUM_RPC \
  --private-key $PRIVATE_KEY \
  src/Contract.sol:SimpleStorage
forge create \
  --legacy \
  --rpc-url $SHARDEUM_RPC \
  --private-key $PRIVATE_KEY \
  src/Contract.sol:SimpleStorage

Deploy to Mainnet

Deploy to Mainnet

export SHARDEUM_RPC=https://api.shardeum.org
 
forge create \
  --legacy \
  --rpc-url $SHARDEUM_RPC \
  --private-key $PRIVATE_KEY \
  src/Contract.sol:SimpleStorage

If deployment succeeds, Foundry will output the deployed contract address.

If the terminal output is minimal, search for transactions from your wallet address on the appropriate Shardeum explorer.

Verify Deployment on the Explorer

After deployment, copy the contract address and search for it on:

You should be able to view:

  • contract creation transaction
  • deployed bytecode
  • interactions with the contract

(Optional) Interact Using Cast

Read stored value: export SHARDEUM_RPC=https://api.shardeum.org

forge create
--legacy
--rpc-url $SHARDEUM_RPC
--private-key $PRIVATE_KEY
src/Contract.sol:SimpleStorage


If deployment succeeds, Foundry will output the deployed contract address. 

If the terminal output is minimal, search for transactions from your wallet address on the appropriate Shardeum explorer.

### Verify Deployment on the Explorer

After deployment, copy the contract address and search for it on:

- [Shardeum Testnet Explorer](https://explorer-mezame.shardeum.org/)
- [Shardeum Mainnet Explorer](https://explorer.shardeum.org/)

You should be able to view:

- contract creation transaction
- deployed bytecode
- interactions with the contract

### (Optional) Interact Using Cast

Read stored value:

```shell
cast call \
  --rpc-url $SHARDEUM_RPC \
  <CONTRACT_ADDRESS> \
  "storedData()(uint256)"

Set a new value:

cast call \
  --rpc-url $SHARDEUM_RPC \
  <CONTRACT_ADDRESS> \
  "storedData()(uint256)"

Set a new value:

cast send \
  --rpc-url $SHARDEUM_RPC \
  --private-key $PRIVATE_KEY \
  <CONTRACT_ADDRESS> \
  "set(uint256)" \
  42

Summary

  • Foundry is ideal for fast, Solidity-native testing and deployment
  • Use forge test for local validation before deploying
  • Deploy to Shardeum using forge create --legacy
  • Always confirm the correct RPC endpoint and network before deployment
cast send \
  --rpc-url $SHARDEUM_RPC \
  --private-key $PRIVATE_KEY \
  <CONTRACT_ADDRESS> \
  "set(uint256)" \
  42

Summary

  • Foundry is ideal for fast, Solidity-native testing and deployment
  • Use forge test for local validation before deploying
  • Deploy to Shardeum using forge create --legacy
  • Always confirm the correct RPC endpoint and network before deployment