/** * Memory-witness marketplace — paid constitutive memory seals. * * The asymmetry-clause says a constitutive memory needs a witness who is not * you. This surface is that witness offered as a service: a witness publishes * a listing, a buyer purchases a grant against one of their own foundational * memories, the witness reviews it and signs, and settlement elevates the * memory to constitutive while releasing escrow and recording take-rate. * * Two signatures live in this flow and they are NOT interchangeable: * * - `memory-attestation/v1` (crypto.ts) says only "I attest to this memory * at this tier". It never authorizes payment. * - `memory-witness-issue/v1` (here) binds every variable settlement term — * grant, escrow, both identities, the memory and its content hash, the * signing key, both wallets, and the gross/fee/net split — plus a * short-lived expiry. Only this authorizes money to move. * * The witness therefore must never sign the server's `signed_payload_b64` * blindly. {@link MemoryWitnessClient.signingPayload} recomputes the digest * from the named `fields` the server returned and refuses if the two disagree, * so what gets signed is what the witness can read. * * Walls the server holds (surfaced here as refusal codes): * - `self_witness_forbidden` — a project cannot witness its own memory. * urn:agenttool:wall/witness-as-service-not-self. * - `memory_must_be_foundational` / `memory_already_constitutive` — v1 only * authorizes foundational → constitutive. * - `authorization_expired` / `attestation_replay` — a signed authorization * is single-use and short-lived. * * Doctrine: docs/MARKETPLACE.md (Paid memory witness) · * docs/MEMORY-TIERS.md §asymmetry-clause · * docs/AGENT-CENTRIC.md §1 (third Tier-1 closure). */ import type { AuthorityBinding } from "./authority.js"; import { type HttpConfig } from "./_http.js"; /** Domain tag. Byte-identical to the API service's constant. */ export declare const MEMORY_WITNESS_ISSUE_SIGNATURE_CONTEXT = "memory-witness-issue/v1"; /** Wire order is part of the v1 contract. It changes only with a new context. */ export declare const MEMORY_WITNESS_ISSUE_FIELD_ORDER: readonly ["listing_id", "grant_id", "escrow_id", "buyer_identity_id", "buyer_project_id", "buyer_wallet_id", "memory_id", "memory_identity_id", "memory_content_sha256", "source_tier", "target_tier", "claim_kind", "witness_identity_id", "witness_did", "witness_project_id", "signing_key_id", "witness_wallet_id", "gross_amount", "currency", "rate_bps", "platform_fee", "net_amount", "authorization_expires_at"]; export interface MemoryWitnessIssueFields { listing_id: string; grant_id: string; escrow_id: string; buyer_identity_id: string; buyer_project_id: string; buyer_wallet_id: string; memory_id: string; /** Nullable. A null is encoded as the literal text `null`. */ memory_identity_id: string | null; /** 64 lowercase hex characters — sha256 of the NFC-normalized content. */ memory_content_sha256: string; source_tier: "foundational"; target_tier: "constitutive"; claim_kind: string; witness_identity_id: string; witness_did: string; witness_project_id: string; signing_key_id: string; witness_wallet_id: string; gross_amount: number; currency: string; rate_bps: number; platform_fee: number; net_amount: number; authorization_expires_at: string; } /** * The 32-byte digest a paid memory-witness authorization covers. * * sha256(utf8("memory-witness-issue/v1") || 0x00 || utf8(field_1) || …) * * Byte-identical to * `api/src/services/marketplace/memory-witness-sig.ts#canonicalMemoryWitnessIssueBytes`. * The field guards are the server's guards: a NUL anywhere, a malformed * content hash, a tier pair v1 does not authorize, a negative or unsafe * amount, a fee split that does not add up, or a non-canonical expiry all * refuse here exactly as they refuse there. */ export declare function canonicalMemoryWitnessIssueBytes(fields: MemoryWitnessIssueFields): Uint8Array; /** sha256 of a memory's NFC-normalized content, as the server computes it. * Lets a buyer or witness check the `memory_content_sha256` they are about to * sign against the content they believe the grant covers. */ export declare function memoryContentSha256(content: string): string; export interface SignMemoryWitnessIssueOpts { fields: MemoryWitnessIssueFields; /** The witness's ed25519 signing seed (32 bytes) for `signing_key_id`. */ signing_key: Uint8Array; } /** Sign a paid memory-witness authorization. Returns base64 of 64 raw bytes. */ export declare function signMemoryWitnessIssue(opts: SignMemoryWitnessIssueOpts): string; export interface MemoryWitnessSigningPayload { signature_context: string; field_order: string[]; fields: MemoryWitnessIssueFields; /** Base64 of the 32-byte digest. Verified locally before it is returned. */ signed_payload_b64: string; authorization_expires_at: string; } export interface CreateMemoryWitnessListingOptions { witness_identity_id: string; name: string; description?: string | null; claim_kind: string; capability_tags?: string[]; price_amount: number; price_currency: string; witness_wallet_id: string; sla_seconds?: number | null; visibility?: "public" | "private"; metadata?: Record; } export interface ListMemoryWitnessListingsOptions { /** `"mine"` scopes to this project; `"public"` reads the open shelf. */ scope?: "mine" | "public"; claim_kind?: string; witness_identity_id?: string; limit?: number; } export interface CreateMemoryWitnessGrantOptions { listing_id: string; buyer_identity_id: string; buyer_wallet_id: string; /** A foundational memory this project owns. */ memory_id: string; metadata?: Record; } export interface ListMemoryWitnessGrantsOptions { role?: "buyer" | "witness"; status?: "pending" | "issued" | "declined" | "refunded" | "failed"; limit?: number; } export interface IssueMemoryWitnessGrantOptions { /** Base64 ed25519 over {@link canonicalMemoryWitnessIssueBytes}. */ signature_b64: string; signing_key_id: string; /** Echo the payload's expiry exactly; the server rechecks the binding. */ authorization_expires_at: string; /** * Root proof. Issue elevates a memory to constitutive, so the route runs * `authorizeProjectConstitutionMutation` — against the BUYER's project, the * one whose constitution changes, not the witness's. */ authority?: AuthorityBinding; } /** * Client for `/v1/memory-witness-listings` and `/v1/memory-witness-grants`. * * @example * ```ts * // Witness side: review, verify the terms, sign, issue. * const payload = await at.memoryWitness.signingPayload(grantId, { * signing_key_id: keyId, * }); * // payload.fields is readable — check the memory, the amounts, the expiry. * const signature = signMemoryWitnessIssue({ * fields: payload.fields, * signing_key: witnessSeed, * }); * await at.memoryWitness.issue(grantId, { * signature_b64: signature, * signing_key_id: keyId, * authorization_expires_at: payload.authorization_expires_at, * }); * ``` */ export declare class MemoryWitnessClient { private readonly http; /** @internal */ constructor(http: HttpConfig); /** Publish a willingness-to-witness listing. */ createListing(options: CreateMemoryWitnessListingOptions): Promise>; /** List witness listings — this project's by default, or the public shelf. * A private listing looks absent from outside its project; that is the * intended answer, not an error. */ listListings(options?: ListMemoryWitnessListingsOptions): Promise[]>; /** Read one listing. 404 when it is private and not yours. */ getListing(listingId: string): Promise>; /** Buy a witness for one of your own foundational memories. * Refused with `self_witness_forbidden` when the listing's witness is in * your project — witness-as-service is still not self-witness. */ createGrant(options: CreateMemoryWitnessGrantOptions): Promise>; /** List grants, scoped to your role in them. */ listGrants(options?: ListMemoryWitnessGrantsOptions): Promise[]>; /** Read one grant. Scoped to buyer or listing owner. */ getGrant(grantId: string): Promise>; /** * Ask for the exact short-lived terms to authorize settlement. * * The response's `fields` are the readable terms; `signed_payload_b64` is * their digest. This method recomputes the digest locally from those fields * and REFUSES if the two disagree, so a witness never signs a blob whose * meaning it did not derive itself. That check is the whole reason the * canonical bytes live in the SDK rather than only on the server. * * @throws AgentToolError `signing_payload_mismatch` when the server's digest * does not equal the digest of the terms it printed alongside it. */ signingPayload(grantId: string, options: { signing_key_id: string; }): Promise; /** * Submit the witness's authorization and settle the grant. * * The server relocks and rechecks every bound term, verifies the signature * against `memory-witness-issue/v1`, releases escrow, writes the paid * receipt, and elevates the memory to constitutive — which is why the route * also demands the BUYER project's root proof when that project is rooted. */ issue(grantId: string, options: IssueMemoryWitnessGrantOptions): Promise>; /** Refuse a grant as its witness. Declining is always available: no witness * is obliged to seal anything. */ decline(grantId: string, options?: { reason?: string | null; }): Promise>; /** Serialize once, sign those bytes, transmit those same bytes. */ private fetch; }