> ## Documentation Index
> Fetch the complete documentation index at: https://docs.hedera.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Deploy and Verify a Smart Contract with Foundry

## Deploying a Contract Using Foundry

This tutorial will walk you through writing and compiling an ERC-20 Solidity smart contract. You'll then deploy and interact with it on the Hedera network using the [Hedera Smart Contract Service (HSCS)](/support/glossary#hedera-smart-contract-service-hscs) and [Foundry](https://getfoundry.sh/), connecting via the [JSON-RPC relay](/evm/development/json-rpc).

<Tip>
  **Developing or running CI?** [Solo](https://solo.hiero.org/docs/) runs a full Hedera network locally, no testnet rate limits, faucet, or resets, and works with the same EVM tooling. See the [Solo quickstart](https://solo.hiero.org/docs/simple-solo-setup/quickstart/) and [Using Solo with EVM tools](https://solo.hiero.org/docs/using-solo/using-solo-with-evm-tools/).
</Tip>

#### What you will accomplish

By the end of this tutorial, you will be able to:

* Compile and deploy a smart contract using Foundry
* Interact with a smart contract using Foundry's `cast` command
* Verify your smart contract programmatically with `forge verify-contract`

***

## Prerequisites

Before you begin, you should have **completed** the following tutorial:

* [x] [Create and Fund a Testnet Account via the Hedera Faucet](/evm/quickstart/get-test-hbar)
* [x] [Install Foundry](https://getfoundry.sh/)

```bash theme={null}
curl -L https://foundry.paradigm.xyz | bash
foundryup
```

This will install `forge`, `cast`, `anvil`, and `chisel`.

***

## Table of Contents

1. [Step 1: Project Setup](#step-1%3A-project-setup)
2. [Step 2: Creating the ERC20 Contract](#step-2%3A-creating-the-erc20-contract)
3. [Step 3: Create a Deployment Script](#step-3%3A-create-a-deployment-script)
4. [Step 4: Deploy your ERC20 Smart Contract](#step-4%3A-deploy-your-erc20-smart-contract)
5. [Step 5: Interacting with the Contract](#step-5%3A-interacting-with-the-contract)
6. [Step 6: Verify Your Smart Contract with Foundry](#step-6%3A-verify-your-smart-contract-with-foundry)

***

## Step 1: Project Setup

#### Initialize Project

Set up your Foundry project:

```bash theme={null}
forge init hedera-foundry-erc20-tutorial
cd hedera-foundry-erc20-tutorial
```

This creates a new directory with a standard Foundry project structure, including `src`, `test`, and `script` folders.

#### Install Dependencies

Foundry uses git submodules to manage dependencies. We'll install the OpenZeppelin Contracts library, which provides a standard and secure implementation of the ERC20 token.

```bash theme={null}
forge install OpenZeppelin/openzeppelin-contracts
```

This command will download the contracts and add them to your `lib` folder.

#### Create `.env` File

Create a `.env` file in your project's root directory to securely store your private key and the RPC URL for the Hedera Testnet.

```bash theme={null}
touch .env
```

Securely store your sensitive data like the `OPERATOR_KEY` in a `.env` file. For the JSON `RPC_URL`, we'll use the [Hashio RPC endpoint for testnet](https://www.hashgraph.com/hashio/).

```bash .env theme={null}
HEDERA_RPC_URL=https://testnet.hashio.io/api
HEDERA_PRIVATE_KEY=0x-your-private-key
```

<Warning>
  Replace the `0x-your-private-key` environment variable with the **HEX Encoded
  Private Key** for your **ECDSA** **account** from the [Hedera
  Portal](https://portal.hedera.com/).
</Warning>

<Danger>
  ***Please note**:* *that Hashio is intended for development and testing
  purposes only. For production use cases, it's recommended to use
  commercial-grade JSON-RPC Relay or host your own instance of the* [*Hiero
  JSON-RPC Relay*](https://github.com/hiero-ledger/hiero-json-rpc-relay)*.*
</Danger>

#### Configure Foundry

Foundry uses the `foundry.toml` file for configuration. Open it and add profiles for the Hedera Testnet RPC endpoint.

```toml foundry.toml theme={null}
[profile.default]
src = "src"
out = "out"
libs = ["lib"]
remappings = [
  "@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
  "forge-std/=lib/forge-std/src/"
]

# Add this section for Hedera testnet
[rpc_endpoints]
testnet = "${HEDERA_RPC_URL}"
```

Note the values in `remappings` field. We need this to import prefix to a filesystem path so both Foundry(forge) and our editor can resolve short, package-like imports instead of long relative paths.

***

## Step 2: Creating the ERC20 Contract

Create a new Solidity file (`HederaToken.sol` ) inside the `src` directory:

```solidity src/HederaToken.sol theme={null}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";

contract HederaToken is ERC20, Ownable {
    constructor(address initialOwner)
        ERC20("HederaToken", "HEDT")
        Ownable(initialOwner)
    {
        _mint(msg.sender, 1000 * 10 ** decimals());
    }

    function mint(address to, uint256 amount) public onlyOwner {
        _mint(to, amount);
    }
}
```

The contract uses the OpenZeppelin ERC20 and Ownable implementations.

* The token is named "HederaToken" with the symbol "HEDT"
* The `constructor` mints an initial supply of 1,000 tokens to the deployer of the contract
* An `onlyOwner` `mint` function is included to allow the contract owner to mint more tokens in the future.

Now, compile the contract:

```bash theme={null}
forge build
```

This command compiles your contracts and places the artifacts(including the [ABI](/evm/development/compiling) and bytecode) into the `out` directory. We are now ready to deploy the smart contract.

***

## Step 3: Create a Deployment Script

Using a script is the standard and most reliable way to handle deployments in Foundry. Create a new file named `HederaToken.s.sol` inside the `script` directory.

```solidity script/HederaToken.s.sol theme={null}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

import {Script, console} from "forge-std/Script.sol";
import {HederaToken} from "../src/HederaToken.sol";

contract HederaTokenScript is Script {
    function run() external returns (address) {
        // Load the private key from the .env file
        uint256 deployerPrivateKey = vm.envUint("HEDERA_PRIVATE_KEY");

        // Start broadcasting transactions with the loaded private key
        vm.startBroadcast(deployerPrivateKey);

        // Get the deployer's address to use as the initial owner
        address deployerAddress = vm.addr(deployerPrivateKey);

        // Deploy the contract
        HederaToken hederaToken = new HederaToken(deployerAddress);

        // Stop broadcasting
        vm.stopBroadcast();

        console.log("HederaToken deployed to:", address(hederaToken));

        return address(hederaToken);
    }
}
```

***

## Step 4: Deploy Your ERC20 Smart Contract

Now, execute the script to deploy your contract. Foundry will automatically load the variables from your `.env` file.

```bash theme={null}
forge script script/HederaToken.s.sol:HederaTokenScript --rpc-url testnet --broadcast
```

After a few moments, you will see the address of your newly deployed contract:

```
[⠒] Compiling...
[⠒] Sending transaction...
[⠒] Waiting for receipt...
== Logs ==
  HederaToken deployed to: 0x047f8c7569b9beecab790902ba29daad143041d7
```

<Check>
  Copy the deployed contract address. You'll need this in subsequent steps.
</Check>

***

## Step 5: Interacting with the Contract

Now that the contract is deployed, you can interact with it using `cast`, Foundry's command-line tool for making RPC calls.

To use `cast` and other command-line tools, you need to load the variables from your `.env` file into your current terminal session.

**Load Environment Variables**

Run the following command to load the `HEDERA_PRIVATE_KEY` and `HEDERA_RPC_URL` into your shell:

```bash theme={null}
source .env
```

Now your shell knows the value of `$HEDERA_PRIVATE_KEY` and `$HEDERA_RPC_URL`.

**Set Up Shell Variables**

Next, set up variables for your contract address and public address to make the next commands easier to read. Please export these variables in your shell.

```bash theme={null}
# Replace with the contract address from the previous step
export CONTRACT_ADDRESS=<your-contract-address>

# Derive your public address from the private key
export MY_ADDRESS=$(cast wallet address $HEDERA_PRIVATE_KEY)
```

**Check Your Balance**

Let's call the `balanceOf` function to check the token balance of your account.

```bash theme={null}
cast call $CONTRACT_ADDRESS "balanceOf(address)" $MY_ADDRESS --rpc-url $HEDERA_RPC_URL
```

The output will be the balance in its raw form (with 18 decimals):

```
0x00000000000000000000000000000000000000000000003635c9adc5dea00000
```

You can use the following to convert the hexadecimal to a decimal number so it's human readable.

```bash theme={null}
cast --to-dec 0x00000000000000000000000000000000000000000000003635c9adc5dea00000
```

You should see the value `1000000000000000000000`.

**Transfer Tokens**

Next, let's transfer 100 tokens to a new account. For this example, we'll generate a new random private key.

```bash theme={null}
# Generate a new random private key and get its address
export RECIPIENT_ADDRESS=$(cast wallet address $(openssl rand -hex 32))
echo "Recipient Address: $RECIPIENT_ADDRESS"
```

Now, send 100 tokens to this new address. Note that `100e18` is a convenient way to write `100 * 10^18`.

```bash theme={null}
cast send $CONTRACT_ADDRESS "transfer(address,uint256)" $RECIPIENT_ADDRESS 100e18 \
    --private-key $HEDERA_PRIVATE_KEY \
    --rpc-url $HEDERA_RPC_URL
```

After the transaction confirms, check the recipient's balance:

```bash theme={null}
cast call $CONTRACT_ADDRESS "balanceOf(address)" $RECIPIENT_ADDRESS --rpc-url testnet
```

The output will show the 100 tokens you sent:

```
0x0000000000000000000000000000000000000000000000056bc75e2d63100000
```

***

## Step 6: Verify Your Smart Contract with Foundry

Foundry can verify your contract programmatically straight from the command line via `forge verify-contract`. Programmatic verification is the most reliable and efficient method, especially for complex or upgradeable contracts, because Foundry already knows your exact compilation settings, dependency graph, and deployment artifacts.

`forge verify-contract` submits the verification request to [Sourcify](https://sourcify.dev), which natively supports Hedera Mainnet (chain ID `295`) and Testnet (chain ID `296`). Once Sourcify accepts the match, the verified status surfaces automatically on [HashScan](https://hashscan.io/) and any other explorer that reads from Sourcify.

The constructor for this contract takes one argument (`initialOwner`), which we must provide for successful verification. Run the following command, using the variables you set earlier.

```bash theme={null}
forge verify-contract $CONTRACT_ADDRESS src/HederaToken.sol:HederaToken \
    --chain-id 296 \
    --verifier sourcify \
    --verifier-url "https://sourcify.dev/server" \
    --constructor-args $(cast abi-encode "constructor(address)" $MY_ADDRESS)
```

After running the command, you should see a success message.

```
Submitting verification for [HederaToken] "0x047F8c7569B9beECaB790902BA29DaAD143041d7".
Contract successfully verified
```

**Congratulations! 🎉 You have successfully deployed, interacted with, and verified an ERC20 smart contract on the Hedera Testnet using Foundry. Feel free to reach out in** [**Discord**](https://hedera.com/discord)**!**

***

## Next Steps

* Check out [OpenZeppelin ERC-20 Documentation](https://docs.openzeppelin.com/contracts/5.x/erc20)
* See the full code in the [Hedera-Code-Snippets Repository](https://github.com/hedera-dev/hedera-code-snippets/tree/main/foundry-erc20)
* Follow more [Foundry guides with Hedera](/evm/tools/foundry).

<Columns cols={2}>
  <Card title="Writer: Kiran, Developer Advocate" arrow>
    [Github](https://github.com/kpachhai) | [Linkedin](https://www.linkedin.com/in/kiranpachhai/)
  </Card>

  <Card title="Editor: Luke, DevRel Engineer" arrow>
    [GitHub](https://github.com/LukeForrest-Hashgraph) | [X](https://x.com/_LukeForrest)
  </Card>
</Columns>
