Ephemeral and deterministic wallets for testing — that clean up after themselves and that your whole team and CI can trust.
Anyone can generate a keypair in one line. Ghostki's value isn't key generation — it's the lifecycle and the guarantees around it:
- 🔥 Burners that self-clean — spawn a throwaway wallet, fund it, use it, then sweep its funds home and destroy the key in one step. Ghostki remembers every burner it ever made so nothing leaks and no test ETH is lost.
- 🧬 Deterministic sets — one seed → the same named wallets (
alice,bob,deployer) on every machine and every CI run. Reproducible fixtures, enforced in CI. - 🛡️ Zero-knowledge seed ownership — prove you hold the project seed without revealing it, via the Ziren zkVM (experimental).
All standards-compliant: keys derive along m/44'/60'/0'/0/index (BIP-44), so every mnemonic imports cleanly into MetaMask, Rabby, Ledger, Anvil, and Hardhat.
go build -o ghostki . # or: go build -o ghostki.exe . on WindowsRun with no arguments for the interactive TUI, or with a subcommand for scripts/CI:
./ghostki # interactive menu
./ghostki sync --check # non-interactive (CI)A throwaway wallet you never have to think about. Full lifecycle:
| Step | TUI | CLI | What it does |
|---|---|---|---|
| Spawn | Spawn a burner | — | Forge a correct wallet, track it, optionally inject into .env |
| Fund | Fund a burner | — | Send test ETH from your home wallet |
| List | List burners | — | Show every burner + live balances |
| Sweep | Sweep a burner | — | Return remaining funds to your home wallet |
| Burn | Burn a burner | — | Destroy the key and scrub it from .env (irreversible) |
| Vanish | Vanish a burner | ghostki vanish <ref> --yes |
Sweep then burn, in one shot |
vanish sweeps before it burns and only burns if the sweep succeeds — so a destroyed key can never strand funds.
Add to .env:
GHOSTKI_RPC_URL=http://localhost:8545
GHOSTKI_HOME_PRIVATE_KEY=0x... # funds burners and receives sweepsSpawn, list, and burn work fully offline without these.
The problem: everyone's local test wallets differ, so tests behave differently per machine and break in CI.
The fix: one secret seed → the same named wallets everywhere, forever.
-
Declare the accounts you want in
ghostki.json:{ "accounts": [ { "label": "deployer" }, { "label": "alice" }, { "label": "bob" } ] }(
ghostki initscaffolds this for you.) -
Derive them:
ghostki sync
This writes two files:
ghostki.lock.json— public addresses only. Commit this so the whole team agrees on the set..env— the private keys. Secret, gitignored.
-
The seed comes from
$GHOSTKI_PROJECT_SEED(a CI secret) or a local.ghostki/seedfile that is auto-created and never committed.
--manifest PATH accounts manifest (default ghostki.json)
--lock PATH expected addresses (default ghostki.lock.json)
--env PATH .env to inject into (default .env)
--no-env do not write private keys to .env
--check verify only; exit non-zero on drift, write nothing
ghostki sync --check re-derives the set and fails if it doesn't match the committed ghostki.lock.json — so an accidental seed or manifest change is caught before it reaches anyone.
A reusable GitHub Action is included (action.yml):
# .github/workflows/wallets.yml
name: Wallets
on: [pull_request, push]
jobs:
verify-wallets:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: ./ # or your-org/ghostki@v1
with:
seed: ${{ secrets.GHOSTKI_PROJECT_SEED }}
check: 'true'Add a repository secret named GHOSTKI_PROJECT_SEED (a BIP-39 mnemonic).
Prove the statement "I know the project seed behind fingerprint F" without revealing the seed — using the Ziren zkVM.
-
The guest program (
zkguest/) runs inside the zkVM. It reads the seed as a private input, computes its fingerprint with the SHA-256 precompile, and commits only the public fingerprint (the same one inghostki.lock.json). -
The host stages the job:
ghostki prove
This serializes the seed into the guest's exact input format, writes the expected public values to
.ghostki/zk/, and sanity-checks the witness against your lockfile. -
The SNARK itself is produced by the external Ziren toolchain (not bundled):
GOOS=linux GOARCH=mipsle GOMIPS=softfloat go build -o ghostki-guest ./zkguest # then run the Ziren prover on ghostki-guest with .ghostki/zk/input.bin
A valid proof convinces anyone that you hold the real seed behind a committed wallet set — useful for proving membership/authority without ever exposing the seed.
The guest compiles and links for the MIPS target today. Proving/verifying requires installing Ziren.
.env,.ghostki/, and.claude/are gitignored. Private keys and the seed never enter git. Only public addresses (ghostki.lock.json) are meant to be committed.- Burner keys use independent entropy, so
burn/vanishare truly irreversible — the key cannot be re-derived. - The project seed (deterministic mode) is shared via a secret, never written to a tracked file. Its fingerprint is a one-way hash — committing it reveals nothing.
- For real test networks, treat
GHOSTKI_HOME_PRIVATE_KEYas a low-value, testnet-only key.
| Package | Responsibility |
|---|---|
wallet/ |
Standards-compliant BIP-44 HD derivation (with a test against the Anvil vector) |
ledger/ |
On-disk source of truth for every burner's lifecycle |
chain/ |
Balance / fund / sweep over go-ethereum |
envfile/ |
Labeled inject + scrub of .env |
fixtures/ |
Deterministic sets, lockfile, drift detection |
config/ |
Loads RPC + home key from .env |
zk/ + zkguest/ |
Host staging + zkVM guest for seed-ownership proofs |
main.go / cli.go |
Interactive TUI / non-interactive CLI |
Build everything: go build ./... · test: go test ./...
Use
go run .(the package), notgo run main.go— the code spans multiple files.
ghostki Interactive TUI
ghostki init Create a starter ghostki.json
ghostki sync Derive the deterministic set
ghostki sync --check Verify against ghostki.lock.json (CI)
ghostki vanish <ref> --yes Sweep a burner home, then destroy it
ghostki prove Stage a zkVM proof of seed ownership
ghostki version Print version
ghostki help Show usage