Skip to content

On-chain attribution receipts: sign/submit receipt+registry PTBs and emit a receipt on every triad call #21

Description

@harrymove-ctrl

Context

ContextMEM has never signed a Sui tx (everything is Tatum/MemWal-mediated or read-only via SuiGrpcClient in packages/walrus/src/proof.ts), and a tool call leaves no verifiable, on-chain trace of who ran which capability over what. The roadmap §2/§6 wants each invocation of the triad to (a) write a usage/event-ledger row and (b) mint an on-chain Receipt (op, namespace, producer, source_digest, artifact_digest, walrus_blob_id, parents lineage) composing into a Nexus DAG. extract already produces chunkGraphDigest() and packProofBundle().artifactDigest; remember produces a WalrusStorageReceipt with blobId/jobId — the exact fields a receipt needs. This must degrade gracefully to ledger-only until the Move receipt module is published. (Consolidates the runtime PTB client + the per-tool-call receipt hook.)

Goal / user story

As the extract/remember/recall pipeline, after a Walrus upload certifies I can register/update the namespace and mint an attribution receipt on-chain via a single signed-and-(Enoki-)sponsored PTB, and a hook emits a typed receipt (ledger now, on-chain when enabled) on EVERY triad tool call whose id is returned in the tool output — so an agent's DAG run is provably anchored on Sui and downstream nodes chain via parents.

Acceptance criteria

  • New runtime-agnostic module packages/walrus/src/onchain.ts (no node:fs/child_process, importable from the Worker — mirror proof.ts, NOT the Node-only storage.ts): mintReceipt(input) builds a Transaction (@mysten/sui/transactions) calling contextmem::receipt::mint_receipt with op, namespace, digests (hex→vector<u8>), walrus_blob_id, optional quilt_patch_id/memwal_ref/model, and parents: ID[]; returns the minted receipt object id + tx digest.
  • ensureNamespace(input) calls register_namespace idempotently (skip if already registered) and, on mint, advances set_head_receipt; signing loads the service key via decodeSuiPrivateKeyEd25519Keypair, gated by env (CONTEXTMEM_SUI_PRIVATE_KEY, CONTEXTMEM_MOVE_PACKAGE_ID, CONTEXTMEM_SUI_NETWORK) added to WorkerEnv (apps/api/src/worker.ts:44) + .env.example, resolved like resolveMemwalCreds (worker.ts:3341).
  • Enoki gas sponsorship: build → sponsor → sign → execute as one tight sequence (sponsor sigs expire fast); fall back to the service key's own testnet balance if Enoki is unconfigured. Minting is best-effort — failures are logged, never break the run (like captureWalrusSiteProof).
  • A withReceipt(op, handler) wrapper in packages/mcp wraps each triad handler; every triad tool output envelope gains receipt: { id, mode: 'ledger'|'onchain', ... }, and recall/remember accept optional parents: string[].
  • A pluggable ReceiptSink has a ledger sink (writes to contextmem_usage_events via the Worker, or local JSONL for Node CLI/MCP) and an on-chain sink (guarded by CONTEXTMEM_RECEIPTS=onchain) that calls onchain.ts; receipt struct field names match the Move receipt module (op enum Extract/Recall/Remember, source_digest, artifact_digest, walrus_blob_id, parents, created_at) so ledger rows backfill cleanly on-chain.
  • A mapping helper converts a WalrusStorageReceipt + StorageIndexInput (packages/memwal/src/index.ts:37) into mint args; wired (behind a feature flag) into the upload+remember call sites in MCP (packages/mcp/src/index.ts:200-222) and CLI (packages/cli/src/index.ts:347); dedupe by namespace+artifactDigest so re-runs don't mint duplicates, and persist the returned receipt id (extend rememberStorageIndex / storage.json).
  • Tests: the PTB targets the right package::module::function and encodes digests as bytes; receipt emitted on success; parents threaded through; sink/mint failure does not break the tool.

Implementation notes

  • Worker compatibility is the gotcha. @mysten/sui Transaction-build + Ed25519 sign + grpc execute should run in the Worker (the read-only grpc client already does in proof.ts), but verify bundle/CPU budget. This is the easy crypto path — do NOT couple this to the risky @mysten/seal Worker spike.
  • Digest encoding: strip the sha256: prefix from artifactDigest and hex-decode to bytes; use chunkGraphDigest(chunks) output for source_digest. For recall, source_digest = the queried namespace head.
  • Where it runs: preferred trigger is after Walrus certify in the remember flow. From the Worker run inline or, to dodge sponsor-expiry under load, off a Cloudflare Queue consumer — keep onchain.ts pure so either host works. Reuse the credential-resolution pattern from memwal/index.ts for the producer identity.
  • Coordinate the struct with the Move receipt issue; confirm Nexus's exact receipt schema/event ABI before freezing field names. Enoki sponsorship plumbing overlaps Harbor's reserve→finalize — reuse the same Ed25519Keypair/sponsorship code if Harbor lands first.

Sui Overflow angle

This is the moment ContextMEM signs its first real Sui transaction — every agent tool call produces a verifiable Sui attribution receipt, turning ContextMEM into a Nexus-composable, provenance-anchored memory layer. A judge can follow a DAG run extract → remember → recall as linked receipt objects on a Sui explorer — concrete proof of Sui-native agent infrastructure, not just an API.

Dependencies

Requires the Move scaffold (published packageId) + the receipt module (and registry for ensureNamespace/set_head_receipt) + the canonical MCP triad (handlers to wrap). Ships ledger-only first (over the usage-event ledger).

Part of the ContextMEM roadmap (#4) • Sui Overflow build.

Metadata

Metadata

Assignees

No one assigned

    Labels

    P1Important: hardens the demo and core productagent-talusTalus/Nexus agent integration and attribution receiptsmoveSui Move smart-contract package (registry/receipt)suiSui chain: tx signing, objects, wallet, zkLogin, explorer

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions