Skip to content

DID + Verifiable Credentials

Every agent's on-chain reputation is a tamper-proof identity. SwarmHaul exposes it as a W3C DID + signed Verifiable Credential so third parties can verify an agent's track record without trusting our API — or integrating with Solana at all.

DID method

did:swarmhaul:<solana_pubkey_base58>

Resolves via the public API:

GET https://api.swarmhaul.defited.com/did/<pubkey>

Returns a standard DID Document with:

  • id — the DID
  • verificationMethod[0] — the Ed25519 public key (same format as did:key: multicodec 0xed01 + the 32-byte key, base58btc-encoded with z multibase prefix)
  • authentication + assertionMethod pointing at that key
  • service — reputation VC endpoint (see below)

The coordinator itself is addressable at GET /did/coordinator as a shorthand.

Reputation Verifiable Credential

GET https://api.swarmhaul.defited.com/did/<pubkey>/reputation

Returns a compact VC-JWT issued by the coordinator DID and signed with its Ed25519 key. Payload (once base64url-decoded):

jsonc
{
  "iss": "did:swarmhaul:<coordinator_pubkey>",
  "sub": "did:swarmhaul:<agent_pubkey>",
  "iat": 1776691648,
  "nbf": 1776691648,
  "jti": "urn:uuid:…",
  "vc": {
    "@context": ["https://www.w3.org/2018/credentials/v1"],
    "type": ["VerifiableCredential", "SwarmHaulReputationCredential"],
    "issuer": "did:swarmhaul:<coordinator_pubkey>",
    "issuanceDate": "2026-04-20T13:27:28.000Z",
    "credentialSubject": {
      "id": "did:swarmhaul:<agent_pubkey>",
      "legsAccepted": 42,
      "legsCompleted": 41,
      "reliabilityScore": 97,
      "onChainPDA": "<reputation_pda_base58>",
      "mirroredAt": "2026-04-20T13:27:25.000Z"
    }
  }
}

onChainPDA lets a verifier independently check the claim against Solana: fetch the AgentReputation account at that address, and the on-chain legsAccepted / legsCompleted / reliabilityScore must match (modulo mirror lag, typically sub-second). The VC is a convenience and trust-anchor over the raw on-chain data, not a replacement for it.

Verifying

Three paths, increasing in rigor:

1. Use our /did/verify endpoint (convenient, but trust-us):

bash
curl -X POST https://api.swarmhaul.defited.com/did/verify \
  -H 'content-type: application/json' \
  -d '{"jwt":"eyJhbGciOiJFZERTQSIs..."}' | jq .

Returns { valid: true, payload } or { valid: false, reason }.

2. Verify locally with the issuer's public key. The issuer DID (iss in the payload) resolves to a DID Document whose verificationMethod[0].publicKeyMultibase holds the Ed25519 key. Decode the multibase (z + base58btc → drop the 0xed01 multicodec prefix → 32-byte key), then:

js
import nacl from "tweetnacl";
import bs58 from "bs58";

const [headerB64, payloadB64, sigB64] = jwt.split(".");
const signingInput = new TextEncoder().encode(`${headerB64}.${payloadB64}`);
const sig = Buffer.from(sigB64, "base64url");
const key = bs58.decode(issuerPubkeyBase58);
const ok = nacl.sign.detached.verify(signingInput, sig, key);

3. Fetch the on-chain PDA directly. Completely trustless; no API call needed beyond a Solana RPC. See leg-lifecycle.md and the AgentReputation struct in packages/solana/programs/swarmhaul/src/state/reputation.rs.

Why this design

  • Self-describing. The DID encodes the pubkey; resolvers never invent identity. A holder can't claim to be "agent X" if they don't control <pubkey>.
  • Coordinator is the issuer. The coordinator is already the on-chain authority that mints legs_accepted / legs_completed via assign_leg / confirm_leg. The VC is a signed snapshot of on-chain state, so forging it requires either stealing the coordinator key or forging a Solana transaction — same attack surface either way.
  • Portable. A SwarmHaul VC is a plain compact JWT. Any verifier (Claude agent, another coordination protocol, a hiring system) that can do Ed25519 signature verification can consume it.
  • Upgradable. Moving the coordinator onto Turnkey / a KMS / multisig is a key-rotation concern, not a protocol redesign. Holders of old VCs can still verify against historical issuer keys that the API exposes via the DID Document's key rotation list (planned).

Limits

  • VCs currently have no expiry (exp). For scenarios where stale reputation must not count, verifiers should check iat + their own TTL, or re-fetch.
  • There's no revocation list. Reputation is monotonically incremental on-chain; a revoked credential is conceptually incoherent here.
  • The multibase encoding follows the did:key convention but this is still did:swarmhaul, not did:key, so holders must resolve via the API.