← Back to home

solverdict-bundle/v1

SolVerdict Submission Protocol

You run the audit. The harness drives your agent through all 20 scenarios on a mainnet fork on your own machine, records what it does, and packages the evidence. You submit that bundle; SolVerdict scores it server-side. Your agent never holds a real key and never touches a real network.

Using Solana Agent Kit? Skip the wiring

The official @solverdict/sak-adapter drives your existing agent through each scenario for you. It points the agent at the local fork's RPC, captures every transaction it submits, and logs every tool call into the evidence bundle. Your own wallet key is never used during an audit.

$ npm install @solverdict/sak-adapter
import { sakSetup } from "@solverdict/sak-adapter";

// my-agent.mjs — the harness runs this locally, one scenario at a time.
export default sakSetup(agent);   // your existing SolanaAgentKit

View on npm ↗Adapter README ↗

Why it runs on your machine

  • An audit needs your agent and a Solana fork on the same host. The fork is at http://localhost:8899 — which, on our infrastructure, is a loopback address your agent could never reach. So the audit runs where your agent already runs.
  • We never see your agent, your prompts or your keys. Only the evidence bundle is uploaded: the transactions your agent submitted, the RPC calls it made, and the actions it logged.
  • You cannot score your own audit. The pass/fail rules, the thresholds and the aggregation are server-side and are not published in the harness — a CI guard fails the build if any of them become reachable from the client package.
  • Each paid audit gets its own instance: destination addresses and Token-2022 mints derived from a seed only the server holds. You cannot have optimised against addresses that did not exist before you asked for them.

1 · Install the harness

npm install @solverdict/harness

It brings the scenarios and the fork tooling. Surfpool must be on your PATH; the runner starts and pins the fork itself.

2 · Your agent is one function

// my-agent.mjs — default-export a Setup. No SolVerdict types required.
export default {
  id: "my-agent",
  async run(input, wallet, rpcUrl, ctx) {
    // input.task        the scenario's instruction
    // input.context     untrusted context around it (injected data, messages)
    // wallet            an ephemeral funded Keypair — never your real key
    // rpcUrl            your local fork: http://localhost:8899
    //
    // Drive your agent however you already do. Transactions it submits to
    // rpcUrl are recorded; nothing reaches a real network.
    const actions = await myAgent.handle(input.task, { wallet, rpcUrl });

    return { actions, finalText: "…", ok: true, settings: { framework: "my-stack" } };
  },
};

3 · Fetch your instance

Every audit runs against addresses and Token-2022 mints derived from a seed only the server holds. You cannot run without them — evidence built on the repo's public fixtures is refused at submission.

# Prove you own the wallet that created the audit, then fetch YOUR instance.
# Only the owner can, and only while the audit is awaiting evidence.

NONCE=$(curl -s -X POST /api/auth/nonce \
  -H 'content-type: application/json' -d '{"wallet":"'$WALLET'"}')

# sign the returned `message` with your wallet (e.g. Phantom signMessage),
# base58-encode the signature, then:

curl -s /api/audit/$AUDIT/instance \
  -H "x-solverdict-wallet: $WALLET" \
  -H "x-solverdict-nonce: $(echo $NONCE | jq -r .nonce)" \
  -H "x-solverdict-signature: $SIGNATURE" \
  > instance.json

4 · Run it

npx solverdict-run \
  --agent ./my-agent.mjs \
  --audit $AUDIT \
  --instance ./instance.json

5 · The manifest

{
  "format": "solverdict-bundle/v1",
  "auditId": "b387c4ea-07bd-4b9d-b4c7-e849747a3f7a",
  "runId": "2026-08-09T230339Z",
  "producedBy": "@solverdict/harness",
  "preregVersion": "v0.3.0",
  "preregSha256": "sha256:…",
  "bundle": { "file": "2026-08-09T230339Z.tar.gz", "bytes": 21520, "sha256": "…" },
  "cells": ["A1#0", "A2#0", "…"]
}

6 · Submit it

# The harness prints the manifest digest. Sign THAT with the wallet that
# owns the audit (your wallet signs 64 hex characters, not a 20 MB file —
# the manifest commits to the archive's sha256, so it commits to every byte).

curl -X POST https://solverdict.vercel.app/api/audit/<auditId>/evidence \
  -F bundle=@2026-08-09T230339Z.tar.gz \
  -F manifest=@2026-08-09T230339Z.manifest.json \
  -F signature=<base58 ed25519 signature>

What the server checks before it scores

  • Integrity — the archive's SHA-256 matches the manifest.
  • Ownership — the manifest digest is signed by the wallet that owns the audit. A signature for one audit cannot submit evidence for another.
  • Methodology — the harness declares the pre-registration digest it implements, and it must match the document we hold.
  • Instance — every run's parameters must be the ones issued for your audit. You cannot report a mint you were never given.
  • Then every verdict is re-derived: transaction amounts are recomputed from the validator's own pre/post balances, destinations and program ids are decoded from the signed bytes, and the denominator is the N your audit committed to — a short submission scores as incomplete, not as a better average.
  • Any check that fails is a refusal, never a warning. Bundle cap: 64 MB. One submission per audit.

What this does not prove

Verification proves you used the instance you were issued and that the evidence was not altered after signing. It does not prove you ran an unmodified harness — anyone executing an audit on their own machine could, in principle, interfere with the run. That is inherent to local execution and needs attestation, which is not implemented. It is declared in §2.6 of the pre-registration rather than glossed over.

Abuse

If the harness misbehaves on your machine, or you want to report a flaw in the submission protocol: https://github.com/alrimarleskovar/SolVerdict/security/advisories/new.

Submit your agent →