Skip to content

joepegler/statecraft

Statecraft

npm version License: MIT CI: Build (PR to main) @st8craft/core line coverage Docs

Statecraft is a TypeScript-first testing primitive for Ethereum integration tests that replaces ad hoc beforeEach setup and brittle helper stacks with one explicit scenario pipeline. You compose deterministic fixtures like withChain, withFork, and withFundedWallet into a single test function, so setup order is visible, repeatable, and easy to reason about. If your Vitest integration tests are getting flaky or hard to maintain, Statecraft gives you a cleaner path without replacing viem, Anvil, or your test runner.

First Success in 60 Seconds

Requirements

Statecraft relies on Anvil from Foundry for local and forked runtimes.

For local development:

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

Ensure anvil is available on your PATH.

For GitHub Actions, set up Foundry before running tests:

- name: Setup Foundry
  uses: foundry-rs/foundry-toolchain@v1

- name: Run SDK Tests
  run: bun run test:ci

Install

bun add -D @st8craft/core @pimlico/alto viem

Create a local chain scenario (quick win)

import { test, expect } from "vitest";
import { scenario, withChain, withFundedWallet } from "@st8craft/core";

test(
  "runs a funded wallet scenario in one test",
  scenario(
    withChain(),
    withFundedWallet({
      balance: 1_000_000_000_000_000_000n, // 1 ETH in wei
    }),
    async ({ wallet, publicClient }) => {
      const balance = await publicClient.getBalance({ address: wallet });
      expect(balance).toBe(1_000_000_000_000_000_000n);
    },
  ),
);

Why Switch from Raw Hooks and Helper Stacks

Most suites start clean, then degrade into hidden setup, flaky fork state, and copy-pasted helper stacks. Statecraft keeps setup as explicit middleware in one place:

  • Deterministic by default, pin fork blocks and keep state setup explicit.
  • Composable setup, add only the withX fixtures a test needs.
  • Honest context flow, each fixture extends context and passes it forward in order.
  • Runner-friendly design, scenario(...) returns an async function for Vitest, Jest, or node:test.

Before vs After (Real Forked State)

Without Statecraft, setup usually lives in custom helpers plus beforeEach, and ordering guarantees are easy to break.

With Statecraft, setup is explicit middleware:

import { test, expect } from "vitest";
import { erc20Abi, parseEther } from "viem";
import {
  scenario,
  withFork,
  withFundedWallet,
  withErc20Balance,
} from "@st8craft/core";

const USDC_MAINNET = "0xA0b86991c6218b36c1d19D4a2e9Eb0ce3606eB48" as const;

test(
  "fork + funded wallet + USDC balance",
  scenario(
    withFork({
      rpcUrl: process.env.VITE_RPC_URL!,
      blockNumber: 22_000_000n,
    }),
    withFundedWallet({
      balance: parseEther("1"),
    }),
    withErc20Balance({
      token: USDC_MAINNET,
      amount: 1_000_000n, // 1 USDC (6 decimals)
    }),
    async ({ walletClient, publicClient }) => {
      const usdc = await publicClient.readContract({
        address: USDC_MAINNET,
        abi: erc20Abi,
        functionName: "balanceOf",
        args: [walletClient.account.address],
      });

      expect(usdc).toBe(1_000_000n);
    },
  ),
);

Core Primitives

  • scenario(...steps, testFn): composes setup steps into one async test function (examples wrap it with Vitest test).
  • withChain(): starts a fresh local Anvil runtime.
  • withFork({ rpcUrl, blockNumber }): starts a pinned local fork for deterministic mainnet state.
  • withFundedWallet({ balance, erc20? }): creates and funds a test wallet.
  • withErc20Balance({ token, amount }): seeds ERC-20 balance on compatible local or forked nodes.
  • withSnapshot(): snapshots before inner steps and reverts in finally.
  • withContracts(...): injects runtime bytecode at known addresses.
  • withDeployments(...): performs real deployments with constructor semantics.

Use It When / Skip It When

Use Statecraft when:

  • your tests need repeatable fork state
  • setup is spread across helper files and hooks
  • fixture ordering bugs are common

Skip Statecraft when:

  • plain unit tests already cover your behavior
  • your integration setup is trivial and stable
  • you need a full Ethereum framework (Statecraft is not that)

Limits and Caveats

  • withErc20Balance is test-only balance mutation, not a mint path.
  • Forks should use pinned blockNumber values for reproducibility.
  • Some tokens and node configurations may require alternative setup strategies.

Examples

Run examples:

bun install
bun run test

Included examples in packages/examples/examples/scenarios.test.ts:

  • fresh local chain plus funded wallet
  • forked mainnet plus funded wallet plus real contract call
  • forked mainnet plus funded wallet plus USDC via withFundedWallet.erc20 or withErc20Balance
  • runtime bytecode injection with withContracts
  • real deployment flow with withDeployments

Package Layout

  • packages/core: published SDK (@st8craft/core): runtime, viem clients, scenario engine, and withX fixtures
  • packages/examples: runnable scenario examples (private workspace package)

Documentation

This repo uses Vocs for docs.

Suggested reading order:

  1. Overview
  2. Quickstart
  3. Core Concepts
  4. Migration (only when upgrading)

For contributor and agent-assisted workflows, see AGENTS.md.

Run docs locally:

bun run docs:dev

Project Status

Current maturity

Statecraft is an early-stage, 0.x SDK. Public APIs and behaviors may change between minor versions, so review the changelog before upgrading.

Security and support

Release verification

Releases to npm are published via Changesets and include CI build and test verification. Additionally, the publish step validates the packed tarball to ensure it contains the expected dist/ output.

Key checks:

  • bun run build and vitest run as part of CI (see sdk-tests.yml).
  • scripts/validate-publish-manifests.mjs runs during the publish workflow to validate the final npm package contents (see publish-npm.yml).

About

Composable scenario runtime for testing Ethereum apps and ERC-4337 flows in Vitest.

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Packages

 
 
 

Contributors