Examples
Two ways to drive a running localnet: from the CLI with the bundled recipe scripts, or from application code with your usual client library pointed at the manifest’s endpoints. Boot the network first:
wharfnet up # or: wharfnet up --bareFrom the CLI
Task-oriented shell recipes live in examples/.
Each reads endpoints, accounts, and token addresses straight from
.wharfnet/wharfnet.json (via jq), so nothing is hard-coded.
| Recipe | What it shows |
|---|---|
| evm/fund-and-transfer.sh | Faucet an address, send an ERC-20 transfer, read balances |
| evm/snapshot-revert.sh | Snapshot state, mutate it, roll back — the test-isolation pattern |
| evm/fork-and-impersonate.sh | Fork mainnet, impersonate a whale, move real USDC with no key |
| solana/airdrop-and-tokens.sh | Airdrop SOL, top up SPL tokens, read balances over JSON-RPC |
| starknet/fund-and-read.sh | Fund the Cairo test tokens, read an ERC-20 balance |
| ci/github-actions.yml | Boot the localnet in CI, run tests, tear down |
From application code
Point your usual client at the endpoints from wharfnet status (or read them
from .wharfnet/wharfnet.json). The chains behave like the real thing, so no
wharfnet-specific SDK is needed.
EVM — viem
import { createPublicClient, http } from 'viem'
import { anvil } from 'viem/chains'
// anvil-1's RPC, from `wharfnet status`
const client = createPublicClient({ chain: anvil, transport: http('http://127.0.0.1:8545') })
// USDC is pre-deployed at a fixed address on every EVM chain
const USDC = '0x5FbDB2315678afecb367f032d93F642f64180aa3'
const abi = [{
name: 'balanceOf', type: 'function', stateMutability: 'view',
inputs: [{ name: 'account', type: 'address' }], outputs: [{ type: 'uint256' }],
}] as const
const balance = await client.readContract({
address: USDC, abi, functionName: 'balanceOf',
args: ['0x70997970C51812dc3A010C7d01b50e0d17dc79C8'],
})
console.log('USDC balance (base units):', balance)The dev accounts use Anvil’s standard test mnemonic, so their private keys are
well-known — sign with them via createWalletClient for writes.
Need funded accounts or tokens at a specific address first? Use the
faucet — wharfnet faucet <chain> <address> <amount> tops
up the native coin and every test token, with no private key.
In Rust tests — wharfnet::testkit
wharfnet is also a library. Add it as a dev-dependency and connect to a
running localnet from an integration test — no hard-coded URLs or token
addresses, all read from the manifest wharfnet up writes:
[dev-dependencies]
wharfnet = "0.1.0" # pre-1.0 — pin the version you tested againstuse wharfnet::testkit::Localnet;
#[test]
fn usdc_is_seeded_on_solana() {
// Reads .wharfnet/wharfnet.json (run `wharfnet up` first, or in a CI step).
let net = Localnet::connect().unwrap();
let sol = net.solana();
let rpc = sol.rpc_url(); // e.g. http://127.0.0.1:8899
let ws = sol.ws_url(); // Some("ws://127.0.0.1:8900")
let usdc = sol.token("USDC"); // mint address + decimals
let dev0 = sol.account(0); // funded dev account: address + private key
assert_eq!(usdc.decimals, 6);
// ... point solana-client / a signer built from dev0.private_key at `rpc`.
let _ = (rpc, ws);
}net.evm(), net.starknet(), net.chain("anvil-2"), and net.chains() give
the same typed handles for every chain. Missing chains/tokens panic with a clear
message (a setup error in tests), or use the try_*/of_kind variants to handle
them yourself.
The contract ABIs for the bundled test tokens are embedded too, so you can instantiate a token without fetching or hand-writing one — feed the JSON straight to viem/ethers/alloy (EVM) or starknet.js/starknet-rust (Starknet):
let evm = net.evm();
let abi_json = evm.token_abi("USDC"); // Some(&str) — the ERC-20 + mint ABI
// net.starknet().token_abi("REB") → the rebasing-token Cairo ABI
// Solana SPL tokens use the standard SPL Token program, so this is None.The raw ABI constants are also available under wharfnet::abi
(e.g. wharfnet::abi::evm::TEST_TOKEN, wharfnet::abi::starknet::REBASING_TOKEN).