Foundry (EVM example)
Deploy, verify and test a Solidity contract with forge. Reference: smart contract cookbook.
Copied from Futureverse’s
futureversecom/trn-examples, deleted with its GitHub organisation, at commit44c9e16of 2024-10-31. Apache-2.0: license. Before you run it, read Running the examples.
Offline destinations
Some places this page points to did not answer when last checked:
github.com/futureversecom— organisation deleted (HTTP 404) (checked 2026-10-10)porcini.rootnet.app— TLS certificate does not cover the host (checked 2026-10-10), named in code
The node source survives as the mirror https://github.com/marco-fv/trn-seed-public, and the organisation’s code examples are on this site as Code examples; its other repositories have no public copy.
This project showcases the deployment and verification of a basic smart contract on the TRN Porcini network using Foundry's forge CLI. It includes a sample contract, a corresponding test, and a deployment script.
IMPORTANT
Ensure the following ENV vars are available before running the examples
CALLER_PRIVATE_KEY- Private key of an account that submits the transaction. Follow this guide to create and fund an account with some test tokens on Porcini (testnet) if you don't have one yet.- Make sure you have install Foundry, follow the guide here
Examples
bash
# change your working directory to this example first
cd examples/substrate/use-forge
# export all required environments
export CALLER_PRIVATE_KEY=
pnpm forge:install
# deploy contract using `forge create`
pnpm forge:create
# deploy contract using `forge script`
pnpm forge:scriptProcedure:
There are two methods to deploy contracts using Foundry:
Using
forge createUsers can utilize the
forge createcommand to deploy and verify a contract by specifying all the necessary parameters in the command. Here is an example:forge create \ --rpc-url $PORCINI_RPC_URL \ --private-key $DEPLOYER_PRIVATE_KEY \0 --legacy \ --optimize \ --optimizer-runs 200 \ --use <SOLIDITY_VERSION> \ --verify \ --verifier sourcify \ path/to/<CONTRACT_NAME>.sol:<CONTRACT_NAME> \ --constructor-args {if necessary}Note: You can check out the shell script example included in this repo:
examples/evm/use-forge/script/use-forge-create.shIn this example, we set the
--rpc-urlto TRN Porcini and specify the--private-keyusing environment variables (see #5 of Prerequisites section).Pay special attention to the
--legacyflag, as it is necessary for successful contract deployment on the TRN Porcini network. Failure to include this flag may result in errors (refer to the troubleshooting section for more information).Using
forge scriptUsers can also create a deployment script to automate the deployment process without having to provide the parameters each time. For detailed examples and information, refer to this repository (offline, checked 2026-10-10).
However, note that there are known issues (explained further in the following section) when using
forge script. If any errors occur during deployment, it is recommended to revert back to usingforge create.
Testing:
This project includes a test script written in Solidity (see examples/evm/use-forge/test/Counter.t.sol file). To run the test, execute the following command in your terminal:
forge testTroubleshooting:
Deserialization Error: invalid type: null, expected f64 at line 1 column 240.This error occurs when the
--legacyflag is not used during contract deployment. Including this flag will resolve the issue.Failed to get EIP-1559 feesThis error also arises when the
--legacyflag is missing. Adding the flag will resolve the problem.Transaction Failure: 0x9cfe621bac130205088168a30470f0cbfdacb22ebb7ce5869a348a7552b7e8b8When this error occurs, the transaction has been executed on the chain but returns with an error. You can check the error code in the event broadcasted on the blockchain explorer, as shown in the example screenshot below.
Possible errors:
OutOfGas.
One possible reason for this error is that the estimated gas is insufficient for the transaction. Increasing the `--gas-estimate-multiplier`` to 200 or higher may resolve the issue.
(code: -32603, message: submit transaction to pool failed: InvalidTransaction(InvalidTransaction::Custom(3)), data: None)The
InvalidTransaction::Custom(3)meansGasLimitTooLowin frontier. A higher gas limit is required to avoid this error.Note: While using
forge script, sometimes raising gas limit still cannot solve this error. In this case a workaround is to switch toforge create
Source files
contracts/Counter.sol
solidity
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.17;
contract Counter {
int256 count;
constructor(int256 _count) {
count = _count;
}
function increment() public {
count += 1;
}
function decrement() public {
count -= 1;
}
function getCount() public view returns (int256) {
return count;
}
}script/Counter.s.sol
solidity
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.17;
import "../contracts/Counter.sol";
import "forge-std/console.sol";
import "forge-std/Script.sol";
contract CounterScript is Script {
function setUp() public {}
function run() public {
uint256 deployerPrivateKey = vm.envUint("CALLER_PRIVATE_KEY");
vm.startBroadcast(deployerPrivateKey);
new Counter(0);
vm.stopBroadcast();
}
}script/use-forge-create.sh
bash
#!/usr/bin/env bash
forge create \
--rpc-url "https://porcini.rootnet.app" \
--private-key $CALLER_PRIVATE_KEY \
--legacy \
--verify \
--verifier sourcify contracts/Counter.sol:Counter \
--constructor-args 0script/use-forge-script.sh
bash
#!/usr/bin/env bash
forge script \
./script/Counter.s.sol:CounterScript \
--rpc-url "https://porcini.rootnet.app" \
--private-key $CALLER_PRIVATE_KEY \
--legacy \
--broadcast \
--verify \
--verifier sourcify \
-vvvvtest/Counter.t.sol
solidity
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.17;
import "forge-std/Test.sol";
import "../contracts/Counter.sol";
contract CounterTest is Test {
Counter counter;
function setUp() public {
counter = new Counter(0);
}
function testGetCount() public {
int value = counter.getCount();
assertEq(value, 0);
emit log_int(value);
}
function testIncrement() public {
counter.increment();
int value = counter.getCount();
assertEq(value, 1);
emit log_int(value);
}
function testDecrement() public {
counter.decrement();
int value = counter.getCount();
assertEq(value, -1);
emit log_int(value);
}
}foundry.toml
toml
[profile.default]
src = 'contracts'
test = 'test'
out = 'forge-artifacts'
libs = ['lib']
solc = "0.8.17"
optimizer = true
optimizer-runs = 200
verbosity = 2
[rpc_endpoints]
porcini = "https://porcini.rootnet.app"package.json
json
{
"scripts": {
"test": "forge test",
"clean": "forge clean",
"forge:install": "forge install foundry-rs/forge-std --no-commit --shallow",
"forge:create": "./script/use-forge-create.sh",
"forge:script": "./script/use-forge-script.sh",
"forge:test": "forge test"
}
}remappings.txt
text
ds-test/=lib/forge-std/lib/ds-test/src/
forge-std/=lib/forge-std/src/Source:
futureversecom/trn-examples, examples/evm/use-forge (deleted) · commit 44c9e16, 2024-10-31 · Apache-2.0, license · part of Code examples