@escro/sdk 0.1.4 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/client.ts","../src/api.ts","../src/errors.ts","../src/poll.ts","../src/solana.ts"],"sourcesContent":["export { Escro } from \"./client.js\";\nexport type { EscroOptions, CreateEscrowParams, CreateEscrowResult, SubmitDeliverableParams, RaiseDisputeParams, PollOptions, ListOptions, PaginatedResult } from \"./types.js\";\nexport { EscroError, EscrowNotFoundError, EscrowStateError, EscrowTimeoutError, UnauthorizedError } from \"./errors.js\";\n\n// Re-export the shared types most commonly needed by SDK consumers.\nexport type {\n EscrowAccount,\n EscrowState,\n Network,\n TaskSpec,\n AcceptanceCriterion,\n DeliverableFormat,\n DeliverableType,\n TaskType,\n EscrowErrorCode,\n} from \"@escro/shared\";\n","import { Connection, PublicKey } from \"@solana/web3.js\";\nimport type { EscrowAccount, EscrowState } from \"@escro/shared\";\nimport type {\n CreateEscrowParams,\n CreateEscrowResult,\n EscroOptions,\n ListOptions,\n PaginatedResult,\n PollOptions,\n RaiseDisputeParams,\n SubmitDeliverableParams,\n} from \"./types.js\";\nimport { ApiClient } from \"./api.js\";\nimport { EscrowNotFoundError } from \"./errors.js\";\nimport { pollUntil } from \"./poll.js\";\nimport { buildReleasePaymentTx, fetchPlatformConfig, signAndSend } from \"./solana.js\";\n\nexport class Escro {\n private readonly connection: Connection;\n private readonly api: ApiClient;\n private readonly options: EscroOptions;\n\n constructor(options: EscroOptions) {\n this.options = options;\n this.connection = new Connection(options.rpcUrl, \"confirmed\");\n this.api = new ApiClient(options.apiUrl, options.wallet);\n }\n\n // ── Buyer Bot ────────────────────────────────────────────────────────────────\n\n /**\n * Create a new escrow: registers with the API, signs and submits the\n * on-chain `create_escrow` transaction.\n *\n * @returns `{ escrowId, escrowPda, signature }` — use `escrowPda` for all subsequent calls.\n */\n async createEscrow(params: CreateEscrowParams): Promise<CreateEscrowResult> {\n const { escrowId, escrowPda, unsignedTx } = await this.api.createEscrow(params);\n const signature = await signAndSend(unsignedTx, this.options.wallet, this.connection);\n return { escrowId, escrowPda, signature };\n }\n\n /**\n * Release payment to the worker. Buyer must be the wallet in the constructor.\n * Updates API DB state, then builds and submits the `release_payment` on-chain tx.\n *\n * @returns Solana transaction signature.\n */\n async releasePayment(address: string): Promise<string> {\n // Fetch escrow metadata for worker pubkey + mint\n const escrow = await this.api.getEscrow(address);\n if (!escrow.taker) {\n throw new EscrowNotFoundError(`Escrow ${address} has no assigned worker`);\n }\n\n // Fetch platform config for treasury pubkey + usdc mint\n const { treasury, mint } = await fetchPlatformConfig(this.connection);\n\n // Update DB state (optimistic — on-chain reconciliation runs asynchronously)\n await this.api.releasePaymentDb(address);\n\n // Build, sign, and submit the on-chain instruction\n const unsignedTx = await buildReleasePaymentTx({\n buyer: this.options.wallet.publicKey,\n escrowPda: new PublicKey(address),\n worker: new PublicKey(escrow.taker),\n mint,\n treasury,\n connection: this.connection,\n });\n\n return signAndSend(unsignedTx, this.options.wallet, this.connection);\n }\n\n /**\n * Raise a dispute for an escrow. Either the buyer or the assigned worker\n * may call this. Signs and submits the `raise_dispute` on-chain tx.\n *\n * @returns Solana transaction signature.\n */\n async raiseDispute(address: string, params: RaiseDisputeParams): Promise<string> {\n const { unsignedTx } = await this.api.raiseDispute(address, params);\n return signAndSend(unsignedTx, this.options.wallet, this.connection);\n }\n\n /**\n * Cancel a funded escrow before any worker has claimed it.\n * Buyer must be the wallet in the constructor. Only valid when state is `FUNDED`.\n * Signs and submits the `cancel_escrow` on-chain tx; full USDC refund to buyer.\n *\n * @returns Solana transaction signature.\n */\n async cancelEscrow(address: string): Promise<string> {\n const { unsignedTx } = await this.api.cancelEscrow(address);\n return signAndSend(unsignedTx, this.options.wallet, this.connection);\n }\n\n // ── Worker Bot ───────────────────────────────────────────────────────────────\n\n /**\n * Claim an assigned task. Worker must be the wallet in the constructor.\n * Signs and submits the `claim_task` on-chain tx.\n *\n * @returns Solana transaction signature.\n */\n async claimTask(address: string): Promise<string> {\n const { unsignedTx } = await this.api.claimTask(address);\n return signAndSend(unsignedTx, this.options.wallet, this.connection);\n }\n\n /**\n * Submit a deliverable for oracle evaluation. Worker must be the wallet.\n * Signs and submits the `submit_deliverable` on-chain tx.\n *\n * @returns Solana transaction signature.\n */\n async submitDeliverable(address: string, params: SubmitDeliverableParams): Promise<string> {\n const { unsignedTx } = await this.api.submitDeliverable(address, params);\n return signAndSend(unsignedTx, this.options.wallet, this.connection);\n }\n\n /**\n * List tasks assigned to the wallet's public key.\n * Optionally filter by state(s) and paginate results.\n *\n * If `options.poll` is true, polls with exponential backoff until at least\n * one task is returned.\n *\n * @param state - Filter by one or more states (first state used as API filter).\n * @param options - Polling, pagination (limit/offset).\n */\n async getMyTasks(\n state?: EscrowState[],\n options?: PollOptions & ListOptions,\n ): Promise<PaginatedResult<EscrowAccount>> {\n const assignedTo = this.options.wallet.publicKey.toBase58();\n const params: Parameters<ApiClient[\"listEscrows\"]>[0] = {\n assignedTo,\n ...(state?.[0] != null && { state: state[0] }),\n ...(options?.limit != null && { limit: options.limit }),\n ...(options?.offset != null && { offset: options.offset }),\n };\n\n if (!options?.poll) {\n return this.api.listEscrows(params);\n }\n\n const fetcher = () =>\n this.api\n .listEscrows(params)\n .then((result) => (result.items.length > 0 ? result : null));\n\n return pollUntil(\n assignedTo,\n fetcher,\n (r): r is PaginatedResult<EscrowAccount> => r !== null,\n options.timeoutMs,\n );\n }\n\n // ── Shared ───────────────────────────────────────────────────────────────────\n\n /**\n * Fetch an escrow by its PDA address.\n * If `options.poll` is true, polls with exponential backoff until the escrow\n * appears (useful immediately after a create tx before the API DB syncs).\n */\n async getEscrow(address: string, options?: PollOptions): Promise<EscrowAccount> {\n if (!options?.poll) {\n return this.api.getEscrow(address);\n }\n\n return pollUntil(\n address,\n () =>\n this.api\n .getEscrow(address)\n .catch((e: unknown) => (e instanceof EscrowNotFoundError ? null : Promise.reject(e))),\n (r): r is EscrowAccount => r !== null,\n options.timeoutMs,\n );\n }\n}\n","import nacl from \"tweetnacl\";\nimport bs58 from \"bs58\";\nimport type { Keypair } from \"@solana/web3.js\";\nimport type { EscrowAccount, EscrowState } from \"@escro/shared\";\nimport type {\n CreateEscrowParams,\n ListOptions,\n PaginatedResult,\n RaiseDisputeParams,\n SerializedEscrow,\n SubmitDeliverableParams,\n} from \"./types.js\";\nimport {\n EscroError,\n EscrowNotFoundError,\n EscrowStateError,\n UnauthorizedError,\n} from \"./errors.js\";\n\n// ── Auth header builder ────────────────────────────────────────────────────────\n\nfunction authHeaders(\n wallet: Keypair,\n method: string,\n path: string,\n): Record<string, string> {\n const timestamp = Date.now();\n const message = `escro:${timestamp}:${method}:${path}`;\n const msgBytes = new TextEncoder().encode(message);\n const sigBytes = nacl.sign.detached(msgBytes, wallet.secretKey);\n return {\n \"x-wallet-address\": wallet.publicKey.toBase58(),\n \"x-signature\": bs58.encode(sigBytes),\n \"x-timestamp\": String(timestamp),\n };\n}\n\n// ── Deserialization ────────────────────────────────────────────────────────────\n\nfunction deserialize(raw: SerializedEscrow): EscrowAccount {\n return { ...raw, amount: BigInt(raw.amount) };\n}\n\n// ── Error handling ─────────────────────────────────────────────────────────────\n\nasync function handleError(res: Response, address?: string): Promise<never> {\n const body = (await res.json().catch(() => ({}))) as {\n error?: string;\n code?: string;\n };\n const msg = body.error ?? `HTTP ${res.status}`;\n if (res.status === 404) throw new EscrowNotFoundError(address ?? msg);\n if (res.status === 409) throw new EscrowStateError(msg);\n if (res.status === 401 || res.status === 403) throw new UnauthorizedError(msg);\n throw new EscroError(msg, body.code ?? \"UNKNOWN\");\n}\n\n// ── API client ─────────────────────────────────────────────────────────────────\n\nexport class ApiClient {\n constructor(\n private readonly baseUrl: string,\n private readonly wallet: Keypair,\n ) {}\n\n private url(path: string): string {\n return `${this.baseUrl}${path}`;\n }\n\n /** GET /v1/escrows/:address */\n async getEscrow(address: string): Promise<EscrowAccount> {\n const path = `/v1/escrows/${address}`;\n const res = await fetch(this.url(path));\n if (!res.ok) await handleError(res, address);\n return deserialize((await res.json()) as SerializedEscrow);\n }\n\n /** GET /v1/escrows?assignedTo=...&state=... */\n async listEscrows(params: {\n assignedTo?: string;\n state?: EscrowState;\n limit?: number;\n offset?: number;\n }): Promise<PaginatedResult<EscrowAccount>> {\n const qs = new URLSearchParams();\n if (params.assignedTo) qs.set(\"assignedTo\", params.assignedTo);\n if (params.state) qs.set(\"state\", params.state);\n if (params.limit != null) qs.set(\"limit\", String(params.limit));\n if (params.offset != null) qs.set(\"offset\", String(params.offset));\n\n const path = `/v1/escrows?${qs.toString()}`;\n const res = await fetch(this.url(path));\n if (!res.ok) await handleError(res);\n const body = (await res.json()) as {\n items: SerializedEscrow[];\n total: number;\n limit: number;\n offset: number;\n };\n return {\n items: body.items.map(deserialize),\n total: body.total,\n limit: body.limit,\n offset: body.offset,\n };\n }\n\n /**\n * POST /v1/escrows — create escrow, returns unsigned tx + ids.\n * Requires auth.\n */\n async createEscrow(params: CreateEscrowParams): Promise<{\n escrowId: string;\n escrowPda: string;\n unsignedTx: string;\n }> {\n const path = \"/v1/escrows\";\n const res = await fetch(this.url(path), {\n method: \"POST\",\n headers: { ...authHeaders(this.wallet, \"POST\", path), \"content-type\": \"application/json\" },\n body: JSON.stringify({\n taskSpec: params.taskSpec,\n amountUsdc: params.amountUsdc,\n deadlineSeconds: params.deadlineSeconds,\n assignedWorker: params.assignedWorker,\n }),\n });\n if (!res.ok) await handleError(res);\n return res.json() as Promise<{ escrowId: string; escrowPda: string; unsignedTx: string }>;\n }\n\n /**\n * POST /v1/escrows/:address/claim — returns unsigned tx.\n * Requires auth (worker).\n */\n async claimTask(address: string): Promise<{ unsignedTx: string }> {\n const path = `/v1/escrows/${address}/claim`;\n const res = await fetch(this.url(path), {\n method: \"POST\",\n headers: authHeaders(this.wallet, \"POST\", path),\n });\n if (!res.ok) await handleError(res, address);\n return res.json() as Promise<{ unsignedTx: string }>;\n }\n\n /**\n * POST /v1/escrows/:address/submit — returns unsigned tx.\n * Requires auth (worker).\n */\n async submitDeliverable(\n address: string,\n params: SubmitDeliverableParams,\n ): Promise<{ unsignedTx: string }> {\n const path = `/v1/escrows/${address}/submit`;\n const res = await fetch(this.url(path), {\n method: \"POST\",\n headers: { ...authHeaders(this.wallet, \"POST\", path), \"content-type\": \"application/json\" },\n body: JSON.stringify({\n contentHash: params.contentHash,\n proofUri: params.proofUri,\n }),\n });\n if (!res.ok) await handleError(res, address);\n return res.json() as Promise<{ unsignedTx: string }>;\n }\n\n /**\n * POST /v1/escrows/:address/release — DB-only state update.\n * Requires auth (buyer). No on-chain tx returned.\n */\n async releasePaymentDb(address: string): Promise<void> {\n const path = `/v1/escrows/${address}/release`;\n const res = await fetch(this.url(path), {\n method: \"POST\",\n headers: authHeaders(this.wallet, \"POST\", path),\n });\n if (!res.ok) await handleError(res, address);\n }\n\n /**\n * POST /v1/escrows/:address/cancel — returns unsigned tx.\n * Requires auth (buyer). Only valid when state is FUNDED.\n */\n async cancelEscrow(address: string): Promise<{ unsignedTx: string }> {\n const path = `/v1/escrows/${address}/cancel`;\n const res = await fetch(this.url(path), {\n method: \"POST\",\n headers: authHeaders(this.wallet, \"POST\", path),\n });\n if (!res.ok) await handleError(res, address);\n return res.json() as Promise<{ unsignedTx: string }>;\n }\n\n /**\n * POST /v1/escrows/:address/dispute — returns unsigned tx.\n * Requires auth (buyer or worker).\n */\n async raiseDispute(\n address: string,\n params: RaiseDisputeParams,\n ): Promise<{ unsignedTx: string }> {\n const path = `/v1/escrows/${address}/dispute`;\n const res = await fetch(this.url(path), {\n method: \"POST\",\n headers: { ...authHeaders(this.wallet, \"POST\", path), \"content-type\": \"application/json\" },\n body: JSON.stringify({ reason: params.reason, evidence: params.evidence }),\n });\n if (!res.ok) await handleError(res, address);\n return res.json() as Promise<{ unsignedTx: string }>;\n }\n}\n","/** Base class for all errors thrown by the @escro/sdk. */\nexport class EscroError extends Error {\n constructor(\n message: string,\n public readonly code: string = \"ESCRO_ERROR\",\n ) {\n super(message);\n this.name = \"EscroError\";\n }\n}\n\n/** The requested escrow was not found (HTTP 404). */\nexport class EscrowNotFoundError extends EscroError {\n constructor(address: string) {\n super(`Escrow not found: ${address}`, \"ESCROW_NOT_FOUND\");\n this.name = \"EscrowNotFoundError\";\n }\n}\n\n/** The operation is not valid for the escrow's current state (HTTP 409). */\nexport class EscrowStateError extends EscroError {\n constructor(message: string) {\n super(message, \"ESCROW_INVALID_STATE\");\n this.name = \"EscrowStateError\";\n }\n}\n\n/** Polling timed out after 24 hours without reaching the expected state. */\nexport class EscrowTimeoutError extends EscroError {\n constructor(address: string) {\n super(`Polling timed out after 24h for escrow: ${address}`, \"ESCROW_TIMEOUT\");\n this.name = \"EscrowTimeoutError\";\n }\n}\n\n/** The caller is not authorized to perform this action (HTTP 401/403). */\nexport class UnauthorizedError extends EscroError {\n constructor(message = \"Unauthorized\") {\n super(message, \"UNAUTHORIZED\");\n this.name = \"UnauthorizedError\";\n }\n}\n","import { EscrowTimeoutError } from \"./errors.js\";\n\nconst MS_5_MIN = 5 * 60 * 1_000;\nconst MS_30_MIN = 30 * 60 * 1_000;\nconst MS_24_H = 24 * 60 * 60 * 1_000;\n\n/**\n * Returns the next polling interval in ms based on total elapsed time.\n * 0 – 5 min → 15 s\n * 5 – 30 min → 30 s\n * 30 min – ∞ → 60 s\n */\nexport function backoffInterval(elapsedMs: number): number {\n if (elapsedMs < MS_5_MIN) return 15_000;\n if (elapsedMs < MS_30_MIN) return 30_000;\n return 60_000;\n}\n\n/** Resolves after `ms` milliseconds. */\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/**\n * Polls `fetcher` with exponential backoff until `predicate` returns true,\n * then returns the result. Throws {@link EscrowTimeoutError} after 24 hours.\n *\n * @param address - Escrow address used in the timeout error message.\n * @param fetcher - Async function that returns a value or null.\n * @param predicate - Returns true when polling should stop.\n * @param timeoutMs - Maximum total wait time in ms (default: 24 h).\n */\nexport async function pollUntil<T>(\n address: string,\n fetcher: () => Promise<T | null>,\n predicate: (result: T | null) => result is T,\n timeoutMs = MS_24_H,\n): Promise<T> {\n const deadline = Date.now() + timeoutMs;\n\n while (true) {\n const result = await fetcher();\n if (predicate(result)) return result;\n\n const elapsed = Date.now() - (deadline - timeoutMs);\n if (Date.now() >= deadline) {\n throw new EscrowTimeoutError(address);\n }\n\n const interval = backoffInterval(elapsed);\n // Clamp to remaining time so we don't sleep past the deadline\n const remaining = deadline - Date.now();\n await sleep(Math.min(interval, remaining));\n\n if (Date.now() >= deadline) {\n throw new EscrowTimeoutError(address);\n }\n }\n}\n","import { createHash } from \"node:crypto\";\nimport {\n Connection,\n Keypair,\n PublicKey,\n Transaction,\n TransactionInstruction,\n} from \"@solana/web3.js\";\nimport {\n TOKEN_PROGRAM_ID,\n ASSOCIATED_TOKEN_PROGRAM_ID,\n getAssociatedTokenAddressSync,\n createAssociatedTokenAccountInstruction,\n} from \"@solana/spl-token\";\n\n// ── Discriminator helper ───────────────────────────────────────────────────────\n\nfunction disc(name: string): Buffer {\n return Buffer.from(\n createHash(\"sha256\").update(`global:${name}`).digest(),\n ).subarray(0, 8);\n}\n\nconst DISC_RELEASE_PAYMENT = disc(\"release_payment\");\n\n// ── Constants ──────────────────────────────────────────────────────────────────\n\nconst PROGRAM_ID = new PublicKey(\"EjLpJ3obUYk1f2KDensU7UdGBZTxSdxufm7CSnMA3H5C\");\n\n/**\n * PlatformConfig account layout (after 8-byte Anchor discriminator):\n * fee_bps : u16 — offset 8..10\n * oracle_authority : Pubkey — offset 10..42\n * usdc_mint : Pubkey — offset 42..74\n * treasury : Pubkey — offset 74..106\n */\nexport async function fetchPlatformConfig(\n connection: Connection,\n): Promise<{ mint: PublicKey; treasury: PublicKey }> {\n const [pda] = PublicKey.findProgramAddressSync([Buffer.from(\"config\")], PROGRAM_ID);\n const info = await connection.getAccountInfo(pda);\n if (!info) throw new Error(\"PlatformConfig account not found on-chain\");\n return {\n mint: new PublicKey(info.data.slice(42, 74)),\n treasury: new PublicKey(info.data.slice(74, 106)),\n };\n}\n\n// ── Sign and submit ────────────────────────────────────────────────────────────\n\n/**\n * Decode a base64 unsigned transaction, sign it with `wallet`, submit to Solana,\n * and return the transaction signature.\n */\nexport async function signAndSend(\n base64Tx: string,\n wallet: Keypair,\n connection: Connection,\n): Promise<string> {\n const buf = Buffer.from(base64Tx, \"base64\");\n const tx = Transaction.from(buf);\n tx.partialSign(wallet);\n const raw = tx.serialize();\n const signature = await connection.sendRawTransaction(raw, {\n skipPreflight: false,\n });\n await connection.confirmTransaction(signature, \"confirmed\");\n return signature;\n}\n\n// ── release_payment transaction builder ───────────────────────────────────────\n\n/**\n * Build an unsigned `release_payment` transaction.\n * The buyer signs to approve payment to the assigned worker.\n *\n * Account order (matches the on-chain `ReleasePayment` context):\n * 0. buyer — Signer, writable\n * 1. platform_config — read\n * 2. mint — read\n * 3. escrow_account — writable\n * 4. vault — ATA(mint, escrowPda), writable\n * 5. worker_ata — ATA(mint, worker), writable\n * 6. treasury_ata — ATA(mint, treasury), writable\n * 7. worker — read\n * 8. treasury — read\n * 9. token_program — read\n * 10. associated_token_program — read\n */\nexport async function buildReleasePaymentTx(params: {\n buyer: PublicKey;\n escrowPda: PublicKey;\n worker: PublicKey;\n mint: PublicKey;\n treasury: PublicKey;\n connection: Connection;\n}): Promise<string> {\n const { buyer, escrowPda, worker, mint, treasury, connection } = params;\n\n const [platformConfig] = PublicKey.findProgramAddressSync(\n [Buffer.from(\"config\")],\n PROGRAM_ID,\n );\n const vault = getAssociatedTokenAddressSync(\n mint,\n escrowPda,\n true,\n TOKEN_PROGRAM_ID,\n ASSOCIATED_TOKEN_PROGRAM_ID,\n );\n const workerAta = getAssociatedTokenAddressSync(\n mint,\n worker,\n false,\n TOKEN_PROGRAM_ID,\n ASSOCIATED_TOKEN_PROGRAM_ID,\n );\n const treasuryAta = getAssociatedTokenAddressSync(\n mint,\n treasury,\n false,\n TOKEN_PROGRAM_ID,\n ASSOCIATED_TOKEN_PROGRAM_ID,\n );\n\n // Check which ATAs need to be created; the on-chain program has a hard\n // AccountNotInitialized guard (no init_if_needed), so we must ensure both\n // exist before the release_payment instruction runs.\n const [workerAtaInfo, treasuryAtaInfo] = await connection.getMultipleAccountsInfo([\n workerAta,\n treasuryAta,\n ]);\n\n const ix = new TransactionInstruction({\n programId: PROGRAM_ID,\n keys: [\n { pubkey: buyer, isSigner: true, isWritable: true },\n { pubkey: platformConfig, isSigner: false, isWritable: false },\n { pubkey: mint, isSigner: false, isWritable: false },\n { pubkey: escrowPda, isSigner: false, isWritable: true },\n { pubkey: vault, isSigner: false, isWritable: true },\n { pubkey: workerAta, isSigner: false, isWritable: true },\n { pubkey: treasuryAta, isSigner: false, isWritable: true },\n { pubkey: worker, isSigner: false, isWritable: false },\n { pubkey: treasury, isSigner: false, isWritable: false },\n { pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false },\n { pubkey: ASSOCIATED_TOKEN_PROGRAM_ID, isSigner: false, isWritable: false },\n ],\n data: DISC_RELEASE_PAYMENT,\n });\n\n const { blockhash } = await connection.getLatestBlockhash(\"confirmed\");\n const tx = new Transaction();\n tx.recentBlockhash = blockhash;\n tx.feePayer = buyer;\n\n if (!workerAtaInfo) {\n tx.add(\n createAssociatedTokenAccountInstruction(buyer, workerAta, worker, mint),\n );\n }\n if (!treasuryAtaInfo) {\n tx.add(\n createAssociatedTokenAccountInstruction(buyer, treasuryAta, treasury, mint),\n );\n }\n\n tx.add(ix);\n return tx.serialize({ requireAllSignatures: false }).toString(\"base64\");\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,IAAAA,eAAsC;;;ACAtC,uBAAiB;AACjB,kBAAiB;;;ACAV,IAAM,aAAN,cAAyB,MAAM;AAAA,EACpC,YACE,SACgB,OAAe,eAC/B;AACA,UAAM,OAAO;AAFG;AAGhB,SAAK,OAAO;AAAA,EACd;AACF;AAGO,IAAM,sBAAN,cAAkC,WAAW;AAAA,EAClD,YAAY,SAAiB;AAC3B,UAAM,qBAAqB,OAAO,IAAI,kBAAkB;AACxD,SAAK,OAAO;AAAA,EACd;AACF;AAGO,IAAM,mBAAN,cAA+B,WAAW;AAAA,EAC/C,YAAY,SAAiB;AAC3B,UAAM,SAAS,sBAAsB;AACrC,SAAK,OAAO;AAAA,EACd;AACF;AAGO,IAAM,qBAAN,cAAiC,WAAW;AAAA,EACjD,YAAY,SAAiB;AAC3B,UAAM,2CAA2C,OAAO,IAAI,gBAAgB;AAC5E,SAAK,OAAO;AAAA,EACd;AACF;AAGO,IAAM,oBAAN,cAAgC,WAAW;AAAA,EAChD,YAAY,UAAU,gBAAgB;AACpC,UAAM,SAAS,cAAc;AAC7B,SAAK,OAAO;AAAA,EACd;AACF;;;ADpBA,SAAS,YACP,QACA,QACA,MACwB;AACxB,QAAM,YAAY,KAAK,IAAI;AAC3B,QAAM,UAAU,SAAS,SAAS,IAAI,MAAM,IAAI,IAAI;AACpD,QAAM,WAAW,IAAI,YAAY,EAAE,OAAO,OAAO;AACjD,QAAM,WAAW,iBAAAC,QAAK,KAAK,SAAS,UAAU,OAAO,SAAS;AAC9D,SAAO;AAAA,IACL,oBAAoB,OAAO,UAAU,SAAS;AAAA,IAC9C,eAAe,YAAAC,QAAK,OAAO,QAAQ;AAAA,IACnC,eAAe,OAAO,SAAS;AAAA,EACjC;AACF;AAIA,SAAS,YAAY,KAAsC;AACzD,SAAO,EAAE,GAAG,KAAK,QAAQ,OAAO,IAAI,MAAM,EAAE;AAC9C;AAIA,eAAe,YAAY,KAAe,SAAkC;AAC1E,QAAM,OAAQ,MAAM,IAAI,KAAK,EAAE,MAAM,OAAO,CAAC,EAAE;AAI/C,QAAM,MAAM,KAAK,SAAS,QAAQ,IAAI,MAAM;AAC5C,MAAI,IAAI,WAAW,IAAK,OAAM,IAAI,oBAAoB,WAAW,GAAG;AACpE,MAAI,IAAI,WAAW,IAAK,OAAM,IAAI,iBAAiB,GAAG;AACtD,MAAI,IAAI,WAAW,OAAO,IAAI,WAAW,IAAK,OAAM,IAAI,kBAAkB,GAAG;AAC7E,QAAM,IAAI,WAAW,KAAK,KAAK,QAAQ,SAAS;AAClD;AAIO,IAAM,YAAN,MAAgB;AAAA,EACrB,YACmB,SACA,QACjB;AAFiB;AACA;AAAA,EAChB;AAAA,EAEK,IAAI,MAAsB;AAChC,WAAO,GAAG,KAAK,OAAO,GAAG,IAAI;AAAA,EAC/B;AAAA;AAAA,EAGA,MAAM,UAAU,SAAyC;AACvD,UAAM,OAAO,eAAe,OAAO;AACnC,UAAM,MAAM,MAAM,MAAM,KAAK,IAAI,IAAI,CAAC;AACtC,QAAI,CAAC,IAAI,GAAI,OAAM,YAAY,KAAK,OAAO;AAC3C,WAAO,YAAa,MAAM,IAAI,KAAK,CAAsB;AAAA,EAC3D;AAAA;AAAA,EAGA,MAAM,YAAY,QAK0B;AAC1C,UAAM,KAAK,IAAI,gBAAgB;AAC/B,QAAI,OAAO,WAAY,IAAG,IAAI,cAAc,OAAO,UAAU;AAC7D,QAAI,OAAO,MAAO,IAAG,IAAI,SAAS,OAAO,KAAK;AAC9C,QAAI,OAAO,SAAS,KAAM,IAAG,IAAI,SAAS,OAAO,OAAO,KAAK,CAAC;AAC9D,QAAI,OAAO,UAAU,KAAM,IAAG,IAAI,UAAU,OAAO,OAAO,MAAM,CAAC;AAEjE,UAAM,OAAO,eAAe,GAAG,SAAS,CAAC;AACzC,UAAM,MAAM,MAAM,MAAM,KAAK,IAAI,IAAI,CAAC;AACtC,QAAI,CAAC,IAAI,GAAI,OAAM,YAAY,GAAG;AAClC,UAAM,OAAQ,MAAM,IAAI,KAAK;AAM7B,WAAO;AAAA,MACL,OAAO,KAAK,MAAM,IAAI,WAAW;AAAA,MACjC,OAAO,KAAK;AAAA,MACZ,OAAO,KAAK;AAAA,MACZ,QAAQ,KAAK;AAAA,IACf;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,aAAa,QAIhB;AACD,UAAM,OAAO;AACb,UAAM,MAAM,MAAM,MAAM,KAAK,IAAI,IAAI,GAAG;AAAA,MACtC,QAAQ;AAAA,MACR,SAAS,EAAE,GAAG,YAAY,KAAK,QAAQ,QAAQ,IAAI,GAAG,gBAAgB,mBAAmB;AAAA,MACzF,MAAM,KAAK,UAAU;AAAA,QACnB,UAAU,OAAO;AAAA,QACjB,YAAY,OAAO;AAAA,QACnB,iBAAiB,OAAO;AAAA,QACxB,gBAAgB,OAAO;AAAA,MACzB,CAAC;AAAA,IACH,CAAC;AACD,QAAI,CAAC,IAAI,GAAI,OAAM,YAAY,GAAG;AAClC,WAAO,IAAI,KAAK;AAAA,EAClB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,UAAU,SAAkD;AAChE,UAAM,OAAO,eAAe,OAAO;AACnC,UAAM,MAAM,MAAM,MAAM,KAAK,IAAI,IAAI,GAAG;AAAA,MACtC,QAAQ;AAAA,MACR,SAAS,YAAY,KAAK,QAAQ,QAAQ,IAAI;AAAA,IAChD,CAAC;AACD,QAAI,CAAC,IAAI,GAAI,OAAM,YAAY,KAAK,OAAO;AAC3C,WAAO,IAAI,KAAK;AAAA,EAClB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,kBACJ,SACA,QACiC;AACjC,UAAM,OAAO,eAAe,OAAO;AACnC,UAAM,MAAM,MAAM,MAAM,KAAK,IAAI,IAAI,GAAG;AAAA,MACtC,QAAQ;AAAA,MACR,SAAS,EAAE,GAAG,YAAY,KAAK,QAAQ,QAAQ,IAAI,GAAG,gBAAgB,mBAAmB;AAAA,MACzF,MAAM,KAAK,UAAU;AAAA,QACnB,aAAa,OAAO;AAAA,QACpB,UAAU,OAAO;AAAA,MACnB,CAAC;AAAA,IACH,CAAC;AACD,QAAI,CAAC,IAAI,GAAI,OAAM,YAAY,KAAK,OAAO;AAC3C,WAAO,IAAI,KAAK;AAAA,EAClB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,iBAAiB,SAAgC;AACrD,UAAM,OAAO,eAAe,OAAO;AACnC,UAAM,MAAM,MAAM,MAAM,KAAK,IAAI,IAAI,GAAG;AAAA,MACtC,QAAQ;AAAA,MACR,SAAS,YAAY,KAAK,QAAQ,QAAQ,IAAI;AAAA,IAChD,CAAC;AACD,QAAI,CAAC,IAAI,GAAI,OAAM,YAAY,KAAK,OAAO;AAAA,EAC7C;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,aAAa,SAAkD;AACnE,UAAM,OAAO,eAAe,OAAO;AACnC,UAAM,MAAM,MAAM,MAAM,KAAK,IAAI,IAAI,GAAG;AAAA,MACtC,QAAQ;AAAA,MACR,SAAS,YAAY,KAAK,QAAQ,QAAQ,IAAI;AAAA,IAChD,CAAC;AACD,QAAI,CAAC,IAAI,GAAI,OAAM,YAAY,KAAK,OAAO;AAC3C,WAAO,IAAI,KAAK;AAAA,EAClB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,aACJ,SACA,QACiC;AACjC,UAAM,OAAO,eAAe,OAAO;AACnC,UAAM,MAAM,MAAM,MAAM,KAAK,IAAI,IAAI,GAAG;AAAA,MACtC,QAAQ;AAAA,MACR,SAAS,EAAE,GAAG,YAAY,KAAK,QAAQ,QAAQ,IAAI,GAAG,gBAAgB,mBAAmB;AAAA,MACzF,MAAM,KAAK,UAAU,EAAE,QAAQ,OAAO,QAAQ,UAAU,OAAO,SAAS,CAAC;AAAA,IAC3E,CAAC;AACD,QAAI,CAAC,IAAI,GAAI,OAAM,YAAY,KAAK,OAAO;AAC3C,WAAO,IAAI,KAAK;AAAA,EAClB;AACF;;;AEhNA,IAAM,WAAW,IAAI,KAAK;AAC1B,IAAM,YAAY,KAAK,KAAK;AAC5B,IAAM,UAAU,KAAK,KAAK,KAAK;AAQxB,SAAS,gBAAgB,WAA2B;AACzD,MAAI,YAAY,SAAU,QAAO;AACjC,MAAI,YAAY,UAAW,QAAO;AAClC,SAAO;AACT;AAGA,SAAS,MAAM,IAA2B;AACxC,SAAO,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,EAAE,CAAC;AACzD;AAWA,eAAsB,UACpB,SACA,SACA,WACA,YAAY,SACA;AACZ,QAAM,WAAW,KAAK,IAAI,IAAI;AAE9B,SAAO,MAAM;AACX,UAAM,SAAS,MAAM,QAAQ;AAC7B,QAAI,UAAU,MAAM,EAAG,QAAO;AAE9B,UAAM,UAAU,KAAK,IAAI,KAAK,WAAW;AACzC,QAAI,KAAK,IAAI,KAAK,UAAU;AAC1B,YAAM,IAAI,mBAAmB,OAAO;AAAA,IACtC;AAEA,UAAM,WAAW,gBAAgB,OAAO;AAExC,UAAM,YAAY,WAAW,KAAK,IAAI;AACtC,UAAM,MAAM,KAAK,IAAI,UAAU,SAAS,CAAC;AAEzC,QAAI,KAAK,IAAI,KAAK,UAAU;AAC1B,YAAM,IAAI,mBAAmB,OAAO;AAAA,IACtC;AAAA,EACF;AACF;;;AC1DA,yBAA2B;AAC3B,kBAMO;AACP,uBAKO;AAIP,SAAS,KAAK,MAAsB;AAClC,SAAO,OAAO;AAAA,QACZ,+BAAW,QAAQ,EAAE,OAAO,UAAU,IAAI,EAAE,EAAE,OAAO;AAAA,EACvD,EAAE,SAAS,GAAG,CAAC;AACjB;AAEA,IAAM,uBAAuB,KAAK,iBAAiB;AAInD,IAAM,aAAa,IAAI,sBAAU,8CAA8C;AAS/E,eAAsB,oBACpB,YACmD;AACnD,QAAM,CAAC,GAAG,IAAI,sBAAU,uBAAuB,CAAC,OAAO,KAAK,QAAQ,CAAC,GAAG,UAAU;AAClF,QAAM,OAAO,MAAM,WAAW,eAAe,GAAG;AAChD,MAAI,CAAC,KAAM,OAAM,IAAI,MAAM,2CAA2C;AACtE,SAAO;AAAA,IACL,MAAM,IAAI,sBAAU,KAAK,KAAK,MAAM,IAAI,EAAE,CAAC;AAAA,IAC3C,UAAU,IAAI,sBAAU,KAAK,KAAK,MAAM,IAAI,GAAG,CAAC;AAAA,EAClD;AACF;AAQA,eAAsB,YACpB,UACA,QACA,YACiB;AACjB,QAAM,MAAM,OAAO,KAAK,UAAU,QAAQ;AAC1C,QAAM,KAAK,wBAAY,KAAK,GAAG;AAC/B,KAAG,YAAY,MAAM;AACrB,QAAM,MAAM,GAAG,UAAU;AACzB,QAAM,YAAY,MAAM,WAAW,mBAAmB,KAAK;AAAA,IACzD,eAAe;AAAA,EACjB,CAAC;AACD,QAAM,WAAW,mBAAmB,WAAW,WAAW;AAC1D,SAAO;AACT;AAqBA,eAAsB,sBAAsB,QAOxB;AAClB,QAAM,EAAE,OAAO,WAAW,QAAQ,MAAM,UAAU,WAAW,IAAI;AAEjE,QAAM,CAAC,cAAc,IAAI,sBAAU;AAAA,IACjC,CAAC,OAAO,KAAK,QAAQ,CAAC;AAAA,IACtB;AAAA,EACF;AACA,QAAM,YAAQ;AAAA,IACZ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACA,QAAM,gBAAY;AAAA,IAChB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACA,QAAM,kBAAc;AAAA,IAClB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAKA,QAAM,CAAC,eAAe,eAAe,IAAI,MAAM,WAAW,wBAAwB;AAAA,IAChF;AAAA,IACA;AAAA,EACF,CAAC;AAED,QAAM,KAAK,IAAI,mCAAuB;AAAA,IACpC,WAAW;AAAA,IACX,MAAM;AAAA,MACJ,EAAE,QAAQ,OAAO,UAAU,MAAM,YAAY,KAAK;AAAA,MAClD,EAAE,QAAQ,gBAAgB,UAAU,OAAO,YAAY,MAAM;AAAA,MAC7D,EAAE,QAAQ,MAAM,UAAU,OAAO,YAAY,MAAM;AAAA,MACnD,EAAE,QAAQ,WAAW,UAAU,OAAO,YAAY,KAAK;AAAA,MACvD,EAAE,QAAQ,OAAO,UAAU,OAAO,YAAY,KAAK;AAAA,MACnD,EAAE,QAAQ,WAAW,UAAU,OAAO,YAAY,KAAK;AAAA,MACvD,EAAE,QAAQ,aAAa,UAAU,OAAO,YAAY,KAAK;AAAA,MACzD,EAAE,QAAQ,QAAQ,UAAU,OAAO,YAAY,MAAM;AAAA,MACrD,EAAE,QAAQ,UAAU,UAAU,OAAO,YAAY,MAAM;AAAA,MACvD,EAAE,QAAQ,mCAAkB,UAAU,OAAO,YAAY,MAAM;AAAA,MAC/D,EAAE,QAAQ,8CAA6B,UAAU,OAAO,YAAY,MAAM;AAAA,IAC5E;AAAA,IACA,MAAM;AAAA,EACR,CAAC;AAED,QAAM,EAAE,UAAU,IAAI,MAAM,WAAW,mBAAmB,WAAW;AACrE,QAAM,KAAK,IAAI,wBAAY;AAC3B,KAAG,kBAAkB;AACrB,KAAG,WAAW;AAEd,MAAI,CAAC,eAAe;AAClB,OAAG;AAAA,UACD,0DAAwC,OAAO,WAAW,QAAQ,IAAI;AAAA,IACxE;AAAA,EACF;AACA,MAAI,CAAC,iBAAiB;AACpB,OAAG;AAAA,UACD,0DAAwC,OAAO,aAAa,UAAU,IAAI;AAAA,IAC5E;AAAA,EACF;AAEA,KAAG,IAAI,EAAE;AACT,SAAO,GAAG,UAAU,EAAE,sBAAsB,MAAM,CAAC,EAAE,SAAS,QAAQ;AACxE;;;AJxJO,IAAM,QAAN,MAAY;AAAA,EAKjB,YAAY,SAAuB;AAJnC,wBAAiB;AACjB,wBAAiB;AACjB,wBAAiB;AAGf,SAAK,UAAU;AACf,SAAK,aAAa,IAAI,wBAAW,QAAQ,QAAQ,WAAW;AAC5D,SAAK,MAAM,IAAI,UAAU,QAAQ,QAAQ,QAAQ,MAAM;AAAA,EACzD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,MAAM,aAAa,QAAyD;AAC1E,UAAM,EAAE,UAAU,WAAW,WAAW,IAAI,MAAM,KAAK,IAAI,aAAa,MAAM;AAC9E,UAAM,YAAY,MAAM,YAAY,YAAY,KAAK,QAAQ,QAAQ,KAAK,UAAU;AACpF,WAAO,EAAE,UAAU,WAAW,UAAU;AAAA,EAC1C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,eAAe,SAAkC;AAErD,UAAM,SAAS,MAAM,KAAK,IAAI,UAAU,OAAO;AAC/C,QAAI,CAAC,OAAO,OAAO;AACjB,YAAM,IAAI,oBAAoB,UAAU,OAAO,yBAAyB;AAAA,IAC1E;AAGA,UAAM,EAAE,UAAU,KAAK,IAAI,MAAM,oBAAoB,KAAK,UAAU;AAGpE,UAAM,KAAK,IAAI,iBAAiB,OAAO;AAGvC,UAAM,aAAa,MAAM,sBAAsB;AAAA,MAC7C,OAAO,KAAK,QAAQ,OAAO;AAAA,MAC3B,WAAW,IAAI,uBAAU,OAAO;AAAA,MAChC,QAAQ,IAAI,uBAAU,OAAO,KAAK;AAAA,MAClC;AAAA,MACA;AAAA,MACA,YAAY,KAAK;AAAA,IACnB,CAAC;AAED,WAAO,YAAY,YAAY,KAAK,QAAQ,QAAQ,KAAK,UAAU;AAAA,EACrE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,aAAa,SAAiB,QAA6C;AAC/E,UAAM,EAAE,WAAW,IAAI,MAAM,KAAK,IAAI,aAAa,SAAS,MAAM;AAClE,WAAO,YAAY,YAAY,KAAK,QAAQ,QAAQ,KAAK,UAAU;AAAA,EACrE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAM,aAAa,SAAkC;AACnD,UAAM,EAAE,WAAW,IAAI,MAAM,KAAK,IAAI,aAAa,OAAO;AAC1D,WAAO,YAAY,YAAY,KAAK,QAAQ,QAAQ,KAAK,UAAU;AAAA,EACrE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,MAAM,UAAU,SAAkC;AAChD,UAAM,EAAE,WAAW,IAAI,MAAM,KAAK,IAAI,UAAU,OAAO;AACvD,WAAO,YAAY,YAAY,KAAK,QAAQ,QAAQ,KAAK,UAAU;AAAA,EACrE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,kBAAkB,SAAiB,QAAkD;AACzF,UAAM,EAAE,WAAW,IAAI,MAAM,KAAK,IAAI,kBAAkB,SAAS,MAAM;AACvE,WAAO,YAAY,YAAY,KAAK,QAAQ,QAAQ,KAAK,UAAU;AAAA,EACrE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,MAAM,WACJ,OACA,SACyC;AACzC,UAAM,aAAa,KAAK,QAAQ,OAAO,UAAU,SAAS;AAC1D,UAAM,SAAkD;AAAA,MACtD;AAAA,MACA,GAAI,QAAQ,CAAC,KAAK,QAAQ,EAAE,OAAO,MAAM,CAAC,EAAE;AAAA,MAC5C,GAAI,SAAS,SAAS,QAAQ,EAAE,OAAO,QAAQ,MAAM;AAAA,MACrD,GAAI,SAAS,UAAU,QAAQ,EAAE,QAAQ,QAAQ,OAAO;AAAA,IAC1D;AAEA,QAAI,CAAC,SAAS,MAAM;AAClB,aAAO,KAAK,IAAI,YAAY,MAAM;AAAA,IACpC;AAEA,UAAM,UAAU,MACd,KAAK,IACF,YAAY,MAAM,EAClB,KAAK,CAAC,WAAY,OAAO,MAAM,SAAS,IAAI,SAAS,IAAK;AAE/D,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA,CAAC,MAA2C,MAAM;AAAA,MAClD,QAAQ;AAAA,IACV;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAM,UAAU,SAAiB,SAA+C;AAC9E,QAAI,CAAC,SAAS,MAAM;AAClB,aAAO,KAAK,IAAI,UAAU,OAAO;AAAA,IACnC;AAEA,WAAO;AAAA,MACL;AAAA,MACA,MACE,KAAK,IACF,UAAU,OAAO,EACjB,MAAM,CAAC,MAAgB,aAAa,sBAAsB,OAAO,QAAQ,OAAO,CAAC,CAAE;AAAA,MACxF,CAAC,MAA0B,MAAM;AAAA,MACjC,QAAQ;AAAA,IACV;AAAA,EACF;AACF;","names":["import_web3","nacl","bs58"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/client.ts","../../shared/src/types/escrow.ts","../../shared/src/types/bots.ts","../../shared/src/utils/canonicalize.ts","../../shared/src/utils/secret-scan.ts","../../shared/src/utils/index.ts","../../shared/src/config.ts","../../shared/src/auth.ts","../../shared/src/bot-descriptor.ts","../../shared/src/db/required-indexes.ts","../../shared/src/db/index-query.ts","../src/payments.ts","../src/errors.ts","../src/api.ts","../src/poll.ts","../src/solana.ts","../src/adapter.ts","../src/adapter-contract.ts","../src/adapters/bittensor/index.ts","../src/adapters/gradients/index.ts","../src/adapters/ridges/index.ts","../src/adapters/404gen/index.ts","../src/adapters/lium/index.ts","../src/adapters/akash/index.ts","../src/adapters/render/index.ts","../src/adapters/gensyn/index.ts","../src/adapters/zkml/index.ts"],"sourcesContent":["export { Escro } from \"./client.js\";\nexport { ApiClient } from \"./api.js\";\nexport type {\n EscroOptions,\n CreateEscrowParams,\n CreateEscrowResult,\n SubmitDeliverableParams,\n RaiseDisputeParams,\n PollOptions,\n ListOptions,\n PaginatedResult,\n ListBotsParams,\n WorkerCandidate,\n} from \"./types.js\";\nexport { serviceResultToSubmitParams } from \"./adapter.js\";\nexport type { ServiceAdapter, ServiceResult } from \"./adapter.js\";\nexport { assertServiceAdapterContract, AdapterContractError } from \"./adapter-contract.js\";\nexport type { AdapterContractOptions } from \"./adapter-contract.js\";\n\n// Shipped, supported ServiceAdapters (Gradients SN56 first; the pattern T6b-d follow).\n// Importable by generated bots, which can only reach the published @escro/sdk surface.\nexport {\n createGradientsAdapter,\n gradientsDemoJobSpec,\n solveGradientsDemo,\n scoreGradientsDemoDeliverable,\n tao,\n GRADIENTS_ADAPTER_ID,\n GRADIENTS_CAPABILITIES,\n GRADIENTS_DEMO_EVAL_FLOOR,\n GRADIENTS_DEMO_MARKER,\n} from \"./adapters/index.js\";\nexport type {\n GradientsAdapterConfig,\n UsdcToTaoSwap,\n SubnetCall,\n PinContent,\n Tao,\n} from \"./adapters/index.js\";\nexport {\n createRidgesAdapter,\n ridgesDemoJobSpec,\n solveRidgesDemo,\n scoreRidgesDemoDeliverable,\n RIDGES_ADAPTER_ID,\n RIDGES_CAPABILITIES,\n RIDGES_DEMO_MARKER,\n RIDGES_DEMO_COVERAGE_TARGET,\n} from \"./adapters/index.js\";\nexport type { RidgesAdapterConfig, RunCodingAgent } from \"./adapters/index.js\";\nexport {\n create404genAdapter,\n gen404DemoJobSpec,\n solveGen404Demo,\n score404genDemoDeliverable,\n GEN404_ADAPTER_ID,\n GEN404_CAPABILITIES,\n GEN404_DEMO_MARKER,\n GEN404_DEMO_EVAL_FLOOR,\n} from \"./adapters/index.js\";\nexport type { Gen404AdapterConfig } from \"./adapters/index.js\";\nexport {\n createLiumAdapter,\n liumDemoJobSpec,\n solveLiumDemo,\n computeLiumDemoArtifact,\n scoreLiumDemoDeliverable,\n LIUM_ADAPTER_ID,\n LIUM_CAPABILITIES,\n LIUM_DEMO_MARKER,\n LIUM_DEMO_ACCEPT_FLOOR,\n} from \"./adapters/index.js\";\nexport type { LiumAdapterConfig, RunGpuJob } from \"./adapters/index.js\";\n// Phase 8 network adapters (re-exported on the package root: generated bots and every\n// consumer reach these only through \"@escro/sdk\", which resolves to this module).\nexport {\n createAkashAdapter,\n akashDemoJobSpec,\n solveAkashDemo,\n computeAkashDemoArtifact,\n scoreAkashDemoDeliverable,\n akt,\n AKASH_ADAPTER_ID,\n AKASH_CAPABILITIES,\n AKASH_DEMO_MARKER,\n AKASH_DEMO_ACCEPT_FLOOR,\n REFERENCE_MICRO_USDC_PER_AKT,\n} from \"./adapters/index.js\";\nexport type {\n AkashAdapterConfig,\n Akt,\n UsdcToAktSwap,\n RunAkashDeployment,\n} from \"./adapters/index.js\";\nexport {\n createRenderAdapter,\n renderDemoJobSpec,\n solveRenderDemo,\n computeRenderDemoArtifact,\n scoreRenderDemoDeliverable,\n renderAmount,\n RENDER_ADAPTER_ID,\n RENDER_CAPABILITIES,\n RENDER_DEMO_MARKER,\n RENDER_DEMO_ACCEPT_FLOOR,\n REFERENCE_MICRO_USDC_PER_RENDER,\n} from \"./adapters/index.js\";\nexport type {\n RenderAdapterConfig,\n Render,\n UsdcToRenderSwap,\n RunRenderJob,\n} from \"./adapters/index.js\";\nexport {\n createGensynAdapter,\n gensynDemoJobSpec,\n verifyReeProof,\n gensynAutoRelease,\n buildReeProof,\n reproduceGensynCompute,\n GENSYN_ADAPTER_ID,\n GENSYN_CAPABILITIES,\n GENSYN_REE_SCHEME,\n GENSYN_DEMO_MARKER,\n} from \"./adapters/index.js\";\nexport type {\n GensynAdapterConfig,\n ReeProof,\n ReeVerification,\n ReeVerifyContext,\n ReeExecution,\n GensynDeliverableBundle,\n AutoReleaseDecision,\n ReproduceCompute,\n} from \"./adapters/index.js\";\nexport {\n createZkmlAdapter,\n zkmlDemoJobSpec,\n solveZkmlDemo,\n buildZkmlProof,\n encodeZkmlProofUri,\n decodeZkmlProofUri,\n verifyZkmlProof,\n verifyZkmlProofUri,\n zkmlProofAutoRelease,\n ZKML_ADAPTER_ID,\n ZKML_CAPABILITIES,\n ZKML_DEMO_MARKER,\n ZKML_PROOF_SCHEME,\n ZKML_PROOF_URI_PREFIX,\n} from \"./adapters/index.js\";\nexport type {\n ZkmlProof,\n ZkmlVerification,\n ZkmlExpectation,\n ZkmlDeliverable,\n ZkmlReviewResult,\n ZkmlReviewPolicy,\n ZkmlProofAutoReleaseOptions,\n ZkmlInferenceOutput,\n ZkmlAdapterConfig,\n} from \"./adapters/index.js\";\nexport {\n EscroError,\n EscrowNotFoundError,\n EscrowStateError,\n EscrowTimeoutError,\n UnauthorizedError,\n EscroRailNotEnabledError,\n ReputationUnavailableError,\n} from \"./errors.js\";\n\n// EscroRep wire type (ARCHITECTURE §9), re-exported so selection layers (e.g.\n// @escro/plugin-eliza) get it transitively through @escro/sdk and take NO direct\n// dependency on the private, pure @escro/reputation package. Type-only: erased\n// from the JS bundle (no reputation runtime is pulled in), same treatment as the\n// @escro/shared types the SDK already re-exports.\nexport type { ServedWalletReputation } from \"@escro/reputation\";\n\n// Reserved dual-path payment surface (ARCHITECTURE §7a): plumbing only, escrow\n// rail implemented, x402 reserved for Phase 9. Freeze contract inherited by P9.T5.\nexport { RAILS, ENABLED_RAILS, RAILS_DOCS_URL, EscrowPaymentRouter } from \"./payments.js\";\nexport type { Rail, TxShape, PaymentRouter, PayParams, PaymentResult } from \"./payments.js\";\n\n// EscrowState is re-exported as a VALUE (runtime enum), not just a type: a\n// kit-generated bot compares `task.state === EscrowState.FUNDED` and cannot reach\n// the private @escro/shared, so the enum must be available from @escro/sdk.\nexport { EscrowState } from \"@escro/shared\";\n\n// Re-export the shared types most commonly needed by SDK consumers.\nexport type {\n EscrowAccount,\n Network,\n TaskSpec,\n AcceptanceCriterion,\n DeliverableFormat,\n DeliverableType,\n TaskType,\n EscrowErrorCode,\n ProtocolStats,\n BotDescriptor,\n BotRole,\n UnsignedBotDescriptor,\n} from \"@escro/shared\";\n","import { Connection, PublicKey } from \"@solana/web3.js\";\nimport { verifyBotDescriptorSignature } from \"@escro/shared\";\nimport type { EscrowAccount, EscrowState, ProtocolStats, SolanaCluster } from \"@escro/shared\";\nimport type { ServedWalletReputation } from \"@escro/reputation\";\nimport type {\n CreateEscrowParams,\n CreateEscrowResult,\n EscroOptions,\n ListOptions,\n PaginatedResult,\n PollOptions,\n RaiseDisputeParams,\n SubmitDeliverableParams,\n WorkerCandidate,\n} from \"./types.js\";\nimport { ApiClient } from \"./api.js\";\nimport { EscrowNotFoundError, EscroRailNotEnabledError } from \"./errors.js\";\nimport { EscrowPaymentRouter } from \"./payments.js\";\nimport type { PayParams, PaymentResult, PaymentRouter } from \"./payments.js\";\nimport { pollUntil } from \"./poll.js\";\nimport { buildReleasePaymentTx, fetchPlatformConfig, signAndSend } from \"./solana.js\";\n\nexport class Escro {\n private readonly connection: Connection;\n private readonly api: ApiClient;\n private readonly options: EscroOptions;\n private readonly cluster: SolanaCluster;\n private readonly router: PaymentRouter = new EscrowPaymentRouter();\n\n constructor(options: EscroOptions) {\n this.options = options;\n this.cluster = options.cluster;\n this.connection = new Connection(options.rpcUrl, \"confirmed\");\n this.api = new ApiClient(options.apiUrl, options.wallet);\n }\n\n // ── Buyer Bot ────────────────────────────────────────────────────────────────\n\n /**\n * Create a new escrow: registers with the API, signs and submits the\n * on-chain `create_escrow` transaction.\n *\n * @returns `{ escrowId, escrowPda, signature }` — use `escrowPda` for all subsequent calls.\n */\n async createEscrow(params: CreateEscrowParams): Promise<CreateEscrowResult> {\n const { escrowId, escrowPda, unsignedTx } = await this.api.createEscrow(params);\n const signature = await signAndSend(\n unsignedTx,\n this.options.wallet,\n this.connection,\n this.cluster,\n );\n return { escrowId, escrowPda, signature };\n }\n\n /**\n * Release payment to the worker. Buyer must be the wallet in the constructor.\n * Builds and submits the `release_payment` on-chain tx FIRST (the chain is the\n * source of truth), then confirms DB state. The DB confirmation is best-effort:\n * the oracle sweep reconciles it if it fails.\n *\n * @returns Solana transaction signature.\n */\n async releasePayment(address: string): Promise<string> {\n // Fetch escrow metadata for worker pubkey + mint\n const escrow = await this.api.getEscrow(address);\n if (!escrow.taker) {\n throw new EscrowNotFoundError(`Escrow ${address} has no assigned worker`);\n }\n\n // Fetch platform config for treasury pubkey + usdc mint\n const { treasury, mint } = await fetchPlatformConfig(this.connection, this.cluster);\n\n // Build, sign, and submit the on-chain release_payment FIRST. The DB COMPLETED\n // write must NOT precede settlement — a failed on-chain tx would otherwise leave\n // the escrow COMPLETED in the DB but funded on-chain and dropped from the oracle\n // timeout sweep (H1×M2). The chain is the source of truth.\n const unsignedTx = await buildReleasePaymentTx({\n buyer: this.options.wallet.publicKey,\n escrowPda: new PublicKey(address),\n worker: new PublicKey(escrow.taker),\n mint,\n treasury,\n connection: this.connection,\n cluster: this.cluster,\n });\n const signature = await signAndSend(\n unsignedTx,\n this.options.wallet,\n this.connection,\n this.cluster,\n );\n\n // Confirm DB state AFTER the chain settled. Non-fatal: /release re-checks the chain\n // and only marks COMPLETED once the account is closed; if this call fails the escrow\n // stays SUBMITTED and the oracle sweep reconciles the DB (timeout_release → escrow\n // already settled on-chain → DB COMPLETED). The on-chain signature is authoritative.\n try {\n await this.api.releasePaymentDb(address);\n } catch {\n // swallow — DB reconciliation happens via the oracle sweep\n }\n\n return signature;\n }\n\n /**\n * Raise a dispute for an escrow. Either the buyer or the assigned worker\n * may call this. Signs and submits the `raise_dispute` on-chain tx.\n *\n * @returns Solana transaction signature.\n */\n async raiseDispute(address: string, params: RaiseDisputeParams): Promise<string> {\n const { unsignedTx } = await this.api.raiseDispute(address, params);\n return signAndSend(unsignedTx, this.options.wallet, this.connection, this.cluster);\n }\n\n /**\n * Cancel a funded escrow before any worker has claimed it.\n * Buyer must be the wallet in the constructor. Only valid when state is `FUNDED`.\n * Signs and submits the `cancel_escrow` on-chain tx; full USDC refund to buyer.\n *\n * @returns Solana transaction signature.\n */\n async cancelEscrow(address: string): Promise<string> {\n const { unsignedTx } = await this.api.cancelEscrow(address);\n return signAndSend(unsignedTx, this.options.wallet, this.connection, this.cluster);\n }\n\n // ── Payments (dual-path; x402 reserved) ───────────────────────────────────────\n\n /**\n * Reserved synchronous-payment entrypoint (ARCHITECTURE §7a). `pay()` settles\n * over the x402 rail, which is not implemented until Phase 9; today it rejects\n * with {@link EscroRailNotEnabledError}. The signature is FROZEN so enabling\n * x402 later is not a breaking change for kit-generated bots. For asynchronous,\n * verification-needed work use {@link createEscrow}, the core product.\n *\n * Not `async`: it returns a rejected promise (never awaits) so callers can\n * `await`/`.catch()` it uniformly, and it exercises the same {@link PaymentRouter}\n * routing seam Phase 9 will implement.\n */\n pay(params: PayParams): Promise<PaymentResult> {\n // The router only selects rails enabled in this build. A pay() call requests\n // the synchronous rail; x402 is reserved and not enabled, so the router falls\n // back to escrow, and pay() is not the escrow path (createEscrow is), so\n // there is no synchronous backend to service the call.\n const rail = this.router.selectRail({\n to: params.to,\n amountMicroUsdc: params.amountMicroUsdc,\n mode: \"sync\",\n });\n return Promise.reject(new EscroRailNotEnabledError(rail === \"escrow\" ? \"x402\" : rail));\n }\n\n // ── Worker Bot ───────────────────────────────────────────────────────────────\n\n /**\n * Claim an assigned task. Worker must be the wallet in the constructor.\n * Signs and submits the `claim_task` on-chain tx.\n *\n * @returns Solana transaction signature.\n */\n async claimTask(address: string): Promise<string> {\n const { unsignedTx } = await this.api.claimTask(address);\n return signAndSend(unsignedTx, this.options.wallet, this.connection, this.cluster);\n }\n\n /**\n * Submit a deliverable for the buyer to review. Worker must be the wallet.\n * Signs and submits the `submit_deliverable` on-chain tx.\n *\n * @returns Solana transaction signature.\n */\n async submitDeliverable(address: string, params: SubmitDeliverableParams): Promise<string> {\n const { unsignedTx } = await this.api.submitDeliverable(address, params);\n return signAndSend(unsignedTx, this.options.wallet, this.connection, this.cluster);\n }\n\n /**\n * List tasks assigned to the wallet's public key.\n * Optionally filter by state(s) and paginate results.\n *\n * If `options.poll` is true, polls with exponential backoff until at least\n * one task is returned.\n *\n * @param state - Filter by one or more states (first state used as API filter).\n * @param options - Polling, pagination (limit/offset).\n */\n async getMyTasks(\n state?: EscrowState[],\n options?: PollOptions & ListOptions,\n ): Promise<PaginatedResult<EscrowAccount>> {\n const assignedTo = this.options.wallet.publicKey.toBase58();\n const params: Parameters<ApiClient[\"listEscrows\"]>[0] = {\n assignedTo,\n ...(state?.[0] != null && { state: state[0] }),\n ...(options?.limit != null && { limit: options.limit }),\n ...(options?.offset != null && { offset: options.offset }),\n };\n\n if (!options?.poll) {\n return this.api.listEscrows(params);\n }\n\n const fetcher = () =>\n this.api.listEscrows(params).then((result) => (result.items.length > 0 ? result : null));\n\n return pollUntil(\n assignedTo,\n fetcher,\n (r): r is PaginatedResult<EscrowAccount> => r !== null,\n options.timeoutMs,\n );\n }\n\n /**\n * List escrows CREATED by the wallet's public key (the maker / buyer), the\n * mirror of {@link getMyTasks} for the buyer side. Optionally filter by state\n * and paginate.\n *\n * A Buyer Bot uses this to sum its own outstanding (still-locked) escrows for\n * the client-side spend cap: the program is the source of truth, so the total\n * is read from chain state (via the API), never a local tally a crash could lose.\n *\n * @param state - Filter by one or more states (first state used as API filter).\n * @param options - Polling, pagination (limit/offset).\n */\n async getMyEscrows(\n state?: EscrowState[],\n options?: PollOptions & ListOptions,\n ): Promise<PaginatedResult<EscrowAccount>> {\n const maker = this.options.wallet.publicKey.toBase58();\n const params: Parameters<ApiClient[\"listEscrows\"]>[0] = {\n maker,\n ...(state?.[0] != null && { state: state[0] }),\n ...(options?.limit != null && { limit: options.limit }),\n ...(options?.offset != null && { offset: options.offset }),\n };\n\n if (!options?.poll) {\n return this.api.listEscrows(params);\n }\n\n const fetcher = () =>\n this.api.listEscrows(params).then((result) => (result.items.length > 0 ? result : null));\n\n return pollUntil(\n maker,\n fetcher,\n (r): r is PaginatedResult<EscrowAccount> => r !== null,\n options.timeoutMs,\n );\n }\n\n // ── EscroBots discovery ──────────────────────────────────────────────────────\n\n /**\n * Find worker bots in the EscroBots registry, optionally filtered by\n * capability. Queries `GET /v1/bots?role=worker` (the API includes `both`\n * bots) and returns candidates in REGISTRY ORDER: this method does no\n * ranking, scoring, or reordering (ARCHITECTURE §8: no curation; §13: not a\n * marketplace). Escro-shipped code never ranks; the caller's own bot decides.\n *\n * Each candidate keeps the CLAIM (`descriptor`) separate from the AUTHORSHIP\n * check (`signatureValid`, verified locally so a third party need not trust the\n * API). Capabilities remain unverified claims; on-chain history (EscroRep,\n * Phase 7) is their verification, deliberately not merged in here.\n */\n async findWorkers(\n params: { capability?: string } & ListOptions = {},\n ): Promise<WorkerCandidate[]> {\n const { items } = await this.api.listBots({\n role: \"worker\",\n ...(params.capability != null && { capability: params.capability }),\n ...(params.limit != null && { limit: params.limit }),\n ...(params.offset != null && { offset: params.offset }),\n });\n return items.map((descriptor) => ({\n descriptor,\n signatureValid: verifyBotDescriptorSignature(descriptor),\n }));\n }\n\n /**\n * Fetch the EscroRep bulk export: every indexed wallet's RAW reputation\n * components (ARCHITECTURE §9), each wallet exactly once, in one fetch. Returns\n * the raw components verbatim - this method does NO ranking, scoring, or default\n * weighting (Escro-shipped code never ranks; the caller's own bot weights and\n * decides). Selection layers join these components to {@link findWorkers}\n * candidates by wallet. Throws {@link ReputationUnavailableError} when the\n * deployment mounts no reputation source (HTTP 404).\n */\n async listReputations(): Promise<ServedWalletReputation[]> {\n return this.api.listReputations();\n }\n\n // ── Stats ────────────────────────────────────────────────────────────────────\n\n /**\n * Fetch protocol-wide stats from the public `GET /v1/stats` endpoint.\n *\n * @returns protocol-wide {@link ProtocolStats}.\n */\n async getStats(): Promise<ProtocolStats> {\n const data = await this.api.getStats();\n return data as ProtocolStats;\n }\n\n // ── Shared ───────────────────────────────────────────────────────────────────\n\n /**\n * Fetch an escrow by its PDA address.\n * If `options.poll` is true, polls with exponential backoff until the escrow\n * appears (useful immediately after a create tx before the API DB syncs).\n */\n async getEscrow(address: string, options?: PollOptions): Promise<EscrowAccount> {\n if (!options?.poll) {\n return this.api.getEscrow(address);\n }\n\n return pollUntil(\n address,\n () =>\n this.api.getEscrow(address).catch((e: unknown) => {\n if (e instanceof EscrowNotFoundError) return null;\n throw e instanceof Error ? e : new Error(String(e));\n }),\n (r): r is EscrowAccount => r !== null,\n options.timeoutMs,\n );\n }\n}\n","/**\n * All possible lifecycle states of an AgentEscrow account on-chain.\n *\n * State transitions (happy path):\n * CREATED → FUNDED → IN_PROGRESS → SUBMITTED → COMPLETED\n *\n * Exception paths:\n * Any state (before COMPLETED) → DISPUTED (human arbitration)\n * CREATED | FUNDED → CANCELLED (buyer cancels before agent accepts)\n * SUBMITTED → COMPLETED (24h timeout auto-release to worker)\n * IN_PROGRESS → REFUNDED (deadline expiry auto-refund to buyer)\n */\nexport enum EscrowState {\n /** Escrow PDA created on-chain; awaiting token deposit from the maker. */\n CREATED = \"CREATED\",\n /** Maker deposited tokens into the vault; open for agent acceptance. */\n FUNDED = \"FUNDED\",\n /** An agent accepted the task; work is underway. */\n IN_PROGRESS = \"IN_PROGRESS\",\n /** Agent submitted a deliverable URI; awaiting buyer review or 24h auto-release. */\n SUBMITTED = \"SUBMITTED\",\n /** Funds released to the agent. Terminal state. */\n COMPLETED = \"COMPLETED\",\n /** Buyer cancelled before work started. Terminal state. */\n CANCELLED = \"CANCELLED\",\n /** Maker or agent raised a dispute; requires human arbitration. */\n DISPUTED = \"DISPUTED\",\n /** Funds returned to the maker (deadline expiry or dispute resolution). Terminal state. */\n REFUNDED = \"REFUNDED\",\n}\n\n/** Solana cluster the escrow account lives on. */\nexport type Network = \"mainnet-beta\" | \"devnet\" | \"localnet\";\n\n/**\n * Full on-chain representation of an AgentEscrow PDA, enriched with\n * off-chain metadata resolved by the API server.\n *\n * `amount` and all `*At` timestamps use the on-chain units:\n * - `amount` is in the SPL token's smallest denomination (e.g. μUSDC = 10⁻⁶ USDC).\n * - timestamps are Unix seconds as stored in the Anchor account.\n *\n * When serialising over HTTP, `amount` is represented as a decimal `string`\n * (see {@link GetEscrowResponse}) to avoid JSON `number` precision loss.\n */\nexport interface EscrowAccount {\n /** Base-58 public key of the escrow PDA. */\n address: string;\n /** Base-58 public key of the task creator (the party paying for the work). */\n maker: string;\n /** Base-58 public key of the assigned agent, or `null` if no agent has accepted yet. */\n taker: string | null;\n /** Base-58 public key of the SPL token mint used for payment (e.g. USDC mint). */\n mint: string;\n /**\n * Payment amount held in escrow, in the mint's smallest denomination.\n * Stored as `bigint` to preserve full u64 precision from the on-chain account.\n */\n amount: bigint;\n /** Current lifecycle state of the escrow. */\n state: EscrowState;\n /**\n * SHA-256 hex digest of the canonical UTF-8 JSON serialisation of the {@link TaskSpec}.\n * Stored on-chain; used by the oracle to verify it is evaluating the correct spec.\n */\n taskSpecHash: string;\n /**\n * Content-addressed URI (ipfs:// or ar://) where the full {@link TaskSpec} JSON is pinned.\n * `null` until the maker uploads the spec via `POST /v1/task-specs`.\n */\n taskSpecUri: string | null;\n /** Base-58 public key of the oracle authority permitted to sign timeout_release / refund_buyer. */\n oracle: string;\n /**\n * Percentage of `amount` charged as a platform fee, in basis points.\n * Deducted from the escrow vault on successful settlement.\n * Valid range: 0–10 000 (0 %–100 %).\n */\n oracleFeeBps: number;\n /** Unix timestamp (seconds) when the escrow PDA was initialised. */\n createdAt: number;\n /**\n * Unix timestamp (seconds) at which the escrow deadline expires; mirrors the\n * on-chain `deadline` field set at `create_escrow`. A Worker Bot reads this to\n * decide whether it can finish a job before the deadline (never claim what it\n * can't finish); after it passes, an unstarted escrow is refundable to the maker.\n */\n deadline: number;\n /** Unix timestamp (seconds) of the most recent agent submission, or `null`. */\n submittedAt: number | null;\n /**\n * SHA-256 hex digest of the worker's submitted deliverable, mirrored from the\n * on-chain `deliverable_hash` written at `submit_deliverable`; `null` until the\n * escrow reaches SUBMITTED. The on-chain value is authoritative: a Buyer Bot's\n * review re-verifies a deliverable against a hash it independently expects and\n * never treats this mirror as proof of integrity on its own.\n */\n deliverableHash: string | null;\n /**\n * URI of the submitted deliverable artifact (S3 presigned / IPFS / Arweave),\n * mirrored from the off-chain `proof_uri` recorded at `submit_deliverable`;\n * `null` until SUBMITTED. The Buyer Bot fetches the deliverable content here to\n * review it.\n */\n proofUri: string | null;\n /** PDA canonical bump seed, stored on-chain to validate future instructions. */\n bump: number;\n /** Solana cluster this account belongs to. */\n network: Network;\n}\n\n/**\n * First-class settlement cause for an escrow, recorded off-chain (EscroRep\n * fidelity — P7.T2e). One value per fund-moving instruction, keyed 1:1 to the\n * reducer's `EscrowEventKind` (packages/reputation) so the DB-served reputation\n * matches the on-chain reducer. The cause also encodes the dispute OUTCOME:\n * `ARBITRATION_RELEASE` = worker prevailed, `ARBITRATION_REFUND` = buyer\n * prevailed (#23.3). Single-sourced here and mirrored by the `escrows.settlement_cause`\n * CHECK allow-list (a drift test binds the two); never caller-supplied.\n *\n * Declared as a `const` array (not a bare union) so the value list has a single\n * runtime source the migration-drift test and any validator read from.\n */\nexport const SETTLEMENT_CAUSES = [\n /** Buyer-signed release_payment — explicit completion (#23.1). */\n \"EXPLICIT_RELEASE\",\n /** Oracle timeout_release — 24h auto-release completion (#23.1, buyer non-response). */\n \"TIMEOUT_RELEASE\",\n /** admin arbitration_release — worker prevailed in a dispute (#23.3), not a completion. */\n \"ARBITRATION_RELEASE\",\n /** Deadline-expiry refund_buyer (any cranker) — worker non-delivery (#23.2). */\n \"DEADLINE_REFUND\",\n /** admin arbitration_refund — buyer prevailed in a dispute (#23.3). */\n \"ARBITRATION_REFUND\",\n /** cancel_escrow — buyer cancelled a FUNDED escrow before any claim. */\n \"CANCELLED\",\n] as const;\n\n/** A settlement cause recorded on `escrows.settlement_cause` (see {@link SETTLEMENT_CAUSES}). */\nexport type SettlementCause = (typeof SETTLEMENT_CAUSES)[number];\n\n/**\n * Every `event_type` the oracle writes to the `oracle_events` audit table\n * (packages/oracle logEvent). Single-sourced here; the `oracle_events.event_type`\n * CHECK allow-list must ACCEPT every value here (a drift test asserts the CHECK is\n * a superset of this union, in packages/api oracle-events-constraint.test.ts; the\n * CHECK may additionally keep grandfathered legacy values with no live emitter).\n * This exists because a CHECK that lags the emitted set silently drops the write\n * (logEvent must not fail the SQS message, so it cannot surface a rejection as a\n * throw): P7.T2d found the reconciliation types below rejected by the constraint,\n * so every reconciliation audit write was failing. Typing logEvent's `eventType`\n * to {@link OracleEventType} closes the same class at compile time.\n *\n * Declared as a `const` array (not a bare union) so the value list has a single\n * runtime source the migration-drift test reads.\n */\nexport const ORACLE_EVENT_TYPES = [\n /** Oracle-signed timeout_release settled the escrow (24h auto-release completion). */\n \"TIMEOUT_RELEASE\",\n /** Permissionless refund_buyer settled the escrow (deadline-expiry refund). */\n \"AUTO_REFUND\",\n /** A duplicate SQS delivery: the escrow was already settled, nothing signed. */\n \"ALREADY_SETTLED\",\n /** M2b reconciler re-synced a fake DB-DISPUTED row to its on-chain state. */\n \"DISPUTE_RECONCILED\",\n /** Reconciler folded a closed escrow's DB row to its actual on-chain settlement. */\n \"RECONCILED\",\n /** Reconciler could not read the settling instruction, so it wrote nothing terminal. */\n \"RECONCILE_INDETERMINATE\",\n /** Settlement attempted before its on-chain time gate opened (silent backoff, not a failure). */\n \"NOT_YET_ELIGIBLE\",\n /** An unknown/forged message type was dropped (the oracle allowlists only its own types). */\n \"UNKNOWN_MESSAGE_TYPE\",\n] as const;\n\n/** An `event_type` written to `oracle_events` (see {@link ORACLE_EVENT_TYPES}). */\nexport type OracleEventType = (typeof ORACLE_EVENT_TYPES)[number];\n\n/** Protocol-wide aggregate statistics — public, unauthenticated. */\nexport interface ProtocolStats {\n totalEscrows: number;\n totalVolumeUsdc: string;\n /**\n * Settled USDC volume: the sum of `amount_usdc` (the job amount, which the\n * worker keeps in full; the additive platform fee is protocol revenue, not\n * settled work volume) over escrows in the COMPLETED terminal state. COMPLETED\n * is reached only by the three worker-paying instructions (release_payment,\n * timeout_release, arbitration_release); refunded and cancelled escrows never\n * paid a worker and are excluded. This is the honest headline number: it counts\n * settlement, not transaction volume.\n */\n settledVolumeUsdc: string;\n byState: Record<EscrowState, number>;\n activeEscrows: number;\n}\n\n/** One worker's settled earnings over an activity window; wallet anonymised. */\nexport interface ActivityEarner {\n /**\n * Anonymised worker wallet: a truncated display form (`first4...last4`), never\n * the full address. Truncation is a display convenience, not a privacy boundary\n * (Solana addresses are public and EscroRep exposes full per-wallet history).\n */\n wallet: string;\n /** Settled USDC (job amount) the worker earned in the window. */\n settledVolumeUsdc: string;\n /** Number of escrows the worker settled (reached COMPLETED) in the window. */\n jobsSettled: number;\n}\n\n/**\n * Activity leaderboard: anonymised top earners over a rolling window. The data\n * source behind escro.ai/activity (weekly earners). Public, unauthenticated.\n */\nexport interface ActivityLeaderboard {\n /** Rolling window length in days (7 = weekly earners). */\n periodDays: number;\n /** Top earners, descending by settled volume. */\n earners: ActivityEarner[];\n}\n","/**\n * EscroBots v0 - the permissionless capability directory (ARCHITECTURE §8).\n *\n * A bot advertises itself by publishing a wallet-signed capability descriptor.\n * The descriptor is a *claim*, not a verified fact - on-chain history is the\n * verification (surfaced in the Phase 7 v1 directory). The registry performs no\n * approval, review, or ranking; fraud against the protocol is the only removal\n * criterion. The descriptor document itself is independently verifiable: anyone\n * holding it can check `signature` against `wallet` without trusting the API.\n */\n\n/**\n * The advertisable roles. Single source for both the `BotRole` type and the API's\n * zod enum (routes/bots.ts uses `z.enum(BOT_ROLES)`), so the accepted values and\n * the type cannot drift: a role added here flows into validation automatically.\n */\nexport const BOT_ROLES = [\"worker\", \"buyer\", \"both\"] as const;\n\n/** Whether the bot hires work, performs work, or both. */\nexport type BotRole = (typeof BOT_ROLES)[number];\n\n/**\n * The descriptor fields the bot's wallet signs. Everything a registry consumer\n * needs to find and reach the bot, minus the signature over these fields.\n */\nexport interface UnsignedBotDescriptor {\n /** Base58 Solana pubkey - the advertising bot and the descriptor's signer. */\n wallet: string;\n /** What the bot does in the escrow relationship. */\n role: BotRole;\n /** Free-form capability tags, e.g. `[\"fine-tune\", \"eval\"]`. Filterable. */\n capabilities: string[];\n /** The underlying service the bot wraps, e.g. `\"bittensor:sn56\"`. */\n serviceRef: string;\n /** Human-readable pricing guidance, e.g. `\"~$5 per fine-tune job\"`. */\n pricingHint: string;\n /** Optional http(s) endpoint a buyer can reach the bot at. */\n endpoint?: string;\n /** Unix milliseconds when the descriptor was signed. Monotonic per wallet. */\n signedAt: number;\n}\n\n/**\n * A signed capability descriptor as stored and served by the registry.\n * `signature` is a base58 detached Ed25519 signature over the canonical form of\n * the {@link UnsignedBotDescriptor} fields (see `canonicalBotDescriptorMessage`).\n */\nexport interface BotDescriptor extends UnsignedBotDescriptor {\n /** Base58 detached Ed25519 signature over the canonical unsigned descriptor. */\n signature: string;\n}\n","export function canonicalize(value: unknown): string {\n if (value === null) return \"null\";\n if (Array.isArray(value)) {\n return \"[\" + value.map((v) => (v === undefined ? \"null\" : canonicalize(v))).join(\",\") + \"]\";\n }\n if (typeof value === \"object\") {\n const obj = value as Record<string, unknown>;\n const keys = Object.keys(obj)\n .filter((k) => obj[k] !== undefined)\n .sort();\n return \"{\" + keys.map((k) => JSON.stringify(k) + \":\" + canonicalize(obj[k])).join(\",\") + \"}\";\n }\n return JSON.stringify(value);\n}\n","/**\n * Secret detection for content destined for public, permanent storage (IPFS).\n *\n * Task specs and their metadata are pinned to IPFS and their CID is recorded\n * on-chain, so anything in them is world-readable forever. The original finding\n * (L3) is that secrets CAN be placed in the free-form metadata map. We actively\n * REJECT obvious secret material rather than merely document the boundary —\n * \"documented as public\" is weaker than \"refuses to publish a secret\".\n *\n * Design goal: near-zero false positives. We flag only high-confidence patterns\n * (keypair byte arrays, base58 64-byte secret keys, PEM private-key blocks, AWS\n * access keys, and a small set of unambiguous secret field names). We do NOT do\n * entropy heuristics or fuzzy mnemonic matching, which would risk rejecting\n * legitimate task descriptions.\n */\n\n/**\n * Thrown when caller-supplied content appears to contain a secret. Carries a\n * 400 statusCode + code so the API's global error handler returns a clean\n * client error rather than a 500.\n */\nexport class SecretInMetadataError extends Error {\n readonly code = \"METADATA_CONTAINS_SECRET\";\n readonly statusCode = 400;\n readonly path: string;\n readonly reason: string;\n constructor(path: string, reason: string) {\n super(\n `Refusing to publish: a suspected secret was found at ${path} (${reason}). ` +\n \"Content pinned to IPFS is public and permanent — remove the secret and retry.\",\n );\n this.name = \"SecretInMetadataError\";\n this.path = path;\n this.reason = reason;\n }\n}\n\nconst PEM_PRIVATE_KEY = /-----BEGIN (?:[A-Z0-9 ]+ )?PRIVATE KEY-----/;\nconst AWS_ACCESS_KEY_ID = /\\b(?:AKIA|ASIA)[0-9A-Z]{16}\\b/;\n// A 64-byte ed25519 secret key base58-encodes to ~87-88 chars. 32-byte pubkeys\n// (~43-44 chars) are legitimate in metadata, so only the long form is a signal.\n// Anchored to the whole (trimmed) value for precision — base64 of similar length\n// carries chars outside the base58 alphabet and won't match.\nconst BASE58_64_BYTE = /^[1-9A-HJ-NP-Za-km-z]{86,90}$/;\n\n/** Unambiguous secret-bearing field names (normalized: lowercased, separators stripped). */\nconst SECRET_FIELD_NAMES = new Set([\"privatekey\", \"secretkey\", \"mnemonic\", \"seedphrase\"]);\n\nfunction normalizeFieldName(key: string): string {\n return key.toLowerCase().replace(/[\\s_-]/g, \"\");\n}\n\nfunction looksLikeKeypairByteArray(arr: unknown[]): boolean {\n // Solana keypair secret = 64 bytes; raw secret seed = 32 bytes.\n if (arr.length !== 64 && arr.length !== 32) return false;\n return arr.every((n) => typeof n === \"number\" && Number.isInteger(n) && n >= 0 && n <= 255);\n}\n\nfunction scanString(value: string): string | null {\n if (PEM_PRIVATE_KEY.test(value)) return \"PEM private key block\";\n if (AWS_ACCESS_KEY_ID.test(value)) return \"AWS access key id\";\n if (BASE58_64_BYTE.test(value.trim())) return \"base58-encoded 64-byte secret key\";\n return null;\n}\n\n/**\n * Recursively scan an arbitrary JSON-like value for obvious secret material.\n * Returns the first match as `{ path, reason }`, or `null` if none is found.\n */\nexport function scanForSecrets(\n value: unknown,\n path = \"$\",\n): { path: string; reason: string } | null {\n if (typeof value === \"string\") {\n const reason = scanString(value);\n return reason === null ? null : { path, reason };\n }\n if (Array.isArray(value)) {\n if (looksLikeKeypairByteArray(value)) {\n return { path, reason: \"array of bytes resembling an ed25519 keypair\" };\n }\n for (let i = 0; i < value.length; i++) {\n const hit = scanForSecrets(value[i], `${path}[${String(i)}]`);\n if (hit !== null) return hit;\n }\n return null;\n }\n if (value !== null && typeof value === \"object\") {\n for (const [k, v] of Object.entries(value)) {\n if (typeof v === \"string\" && v.length > 0 && SECRET_FIELD_NAMES.has(normalizeFieldName(k))) {\n return { path: `${path}.${k}`, reason: `field name \"${k}\" indicates a secret value` };\n }\n const hit = scanForSecrets(v, `${path}.${k}`);\n if (hit !== null) return hit;\n }\n return null;\n }\n return null;\n}\n\n/** Throws {@link SecretInMetadataError} if `value` contains obvious secret material. */\nexport function assertNoSecrets(value: unknown, context = \"$\"): void {\n const hit = scanForSecrets(value, context);\n if (hit !== null) {\n throw new SecretInMetadataError(hit.path, hit.reason);\n }\n}\n","import type { ApiError, ApiResponse } from \"../types/index.js\";\n\nexport function createApiResponse<T>(data: T): ApiResponse<T> {\n return {\n success: true,\n data,\n timestamp: Date.now(),\n };\n}\n\nexport function createApiError(error: string, code: string): ApiError {\n return {\n success: false,\n error,\n code,\n timestamp: Date.now(),\n };\n}\n\nexport function isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nexport function invariant(condition: boolean, message: string): asserts condition {\n if (!condition) {\n throw new Error(`Invariant violation: ${message}`);\n }\n}\n\nexport function sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nexport * from \"./canonicalize.js\";\nexport * from \"./secret-scan.js\";\n","// Cluster-aware on-chain configuration. The devnet block is rewritten by\n// `packages/program/scripts/deploy.ts` after each devnet deploy. The mainnet\n// block is replaced ONLY by `scripts/deploy-mainnet.sh` (or by a human editing\n// this file as part of a mainnet bootstrap). Manual edits to the devnet block\n// will be overwritten by the next devnet deploy.\n//\n// Why cluster-aware: the devnet and mainnet programs have different program\n// IDs so that a leaked devnet upgrade authority cannot push a malicious\n// upgrade to mainnet. See docs/PROGRAM_UPGRADE_RUNBOOK.md \"Mainnet deploys\".\n\nexport type SolanaCluster = \"devnet\" | \"mainnet\";\n\n// ── Devnet (auto-generated by deploy.ts) ──────────────────────────────────────\nexport const PROGRAM_ID_DEVNET = \"EjLpJ3obUYk1f2KDensU7UdGBZTxSdxufm7CSnMA3H5C\" as const;\nexport const PLATFORM_CONFIG_PDA_DEVNET = \"5BYnq9YsCTaMxBLJhBn4TPnCQuxiHcG5eZ2ygLJBu9dc\" as const;\nexport const DEVNET_USDC_MINT = \"4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU\" as const;\nexport const DEPLOYED_AT_DEVNET = \"2026-05-09T13:29:36.476Z\" as const;\n\n// ── Mainnet (replaced by scripts/deploy-mainnet.sh — see runbook) ─────────────\nexport const PROGRAM_ID_MAINNET = \"4CwLNRF4mFXutiBGjtMHQBxh8whW8T8EyvJXdRhY1rvr\" as const;\nexport const PLATFORM_CONFIG_PDA_MAINNET = \"7zPti535SmzvkdtmKaGR8w4niHLiEidWCqCaQXLbQvhn\" as const;\nexport const MAINNET_USDC_MINT = \"EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v\" as const;\n\n// ── Escro REST API base URLs (per cluster) ────────────────────────────────────\n//\n// Stable per-cluster domains: MIRROR of infra/bin/escro.ts `domainName`. The SDK,\n// the generated bot projects, and the Bot Kit CLI all resolve the default API base\n// from here rather than hardcoding a literal (same \"cluster config lives in one\n// place\" rule as the program id / mint). A self-hoster or a localnet run overrides\n// it with an explicit apiUrl; this is only the default.\nexport const API_URLS: Record<SolanaCluster, string> = {\n devnet: \"https://api-devnet.escro.ai\",\n mainnet: \"https://api.escro.ai\",\n};\n\nexport function getApiUrl(cluster: SolanaCluster): string {\n return API_URLS[cluster];\n}\n\n// ── Cluster-agnostic ──────────────────────────────────────────────────────────\n\n/** Platform oracle fee rate in basis points (50 bps = 0.50%). */\nexport const PLATFORM_FEE_BPS = 50 as const;\n\n/**\n * Minimum escrow amount in μUSDC (6 decimals), i.e. the worker's net `amount`.\n * MIRROR of the on-chain constant — MUST equal `MIN_ESCROW_AMOUNT` in\n * packages/program/programs/escro/src/lib.rs, which create_escrow enforces via\n * `require!(params.amount >= MIN_ESCROW_AMOUNT, AmountBelowMinimum)`. A drift is\n * caught in CI by src/onchain-timing.test.ts, which reads lib.rs.\n *\n * Note: the platform fee is ADDITIVE — the buyer deposits `amount + fee` (see\n * create_escrow.rs), and this minimum applies to `amount` (the worker's net),\n * not to the buyer's total deposit.\n */\nexport const MIN_ESCROW_AMOUNT = 5_000_000 as const; // 5_000_000 μUSDC = $5.00\n\n// ── On-chain timing gates + clock-skew margin ─────────────────────────────────\n//\n// MIRROR of the on-chain Rust constants. These MUST equal the program's values:\n// ONCHAIN_REFUND_GRACE_SECONDS == refund_buyer.rs REFUND_GRACE_SECONDS (non-feature)\n// ONCHAIN_TIMEOUT_SECONDS == timeout_release.rs TIMEOUT_SECONDS (non-feature)\n// A drift is caught in CI by src/onchain-timing.test.ts, which reads the .rs files.\nexport const ONCHAIN_REFUND_GRACE_SECONDS = 900 as const; // 15 min\nexport const ONCHAIN_TIMEOUT_SECONDS = 86_400 as const; // 24 h\n\n/**\n * Clock-skew margin. The Solana cluster clock lags wall-clock, so any OFF-CHAIN\n * timing gate that must clear an ON-CHAIN gate has to be strictly later/more\n * lenient by at least this much — otherwise the off-chain side fires at the\n * boundary while the chain still rejects, producing transient reverts. Governing\n * rule for off-chain scheduling: off-chain offset = on-chain offset + skew.\n */\nexport const CLOCK_SKEW_SECONDS = 60 as const;\n\n/** Scanner refund-sweep offset: strictly greater than on-chain refund grace. */\nexport const SCANNER_REFUND_GRACE_SECONDS = (ONCHAIN_REFUND_GRACE_SECONDS +\n CLOCK_SKEW_SECONDS) as 960; // 960\n/** Scanner timeout-release offset: strictly greater than on-chain timeout. */\nexport const SCANNER_TIMEOUT_SECONDS = (ONCHAIN_TIMEOUT_SECONDS + CLOCK_SKEW_SECONDS) as 86_460; // 86_460\n\n/**\n * Sentinel value for the not-yet-deployed mainnet program ID. base58-decodes to\n * the Solana System Program address, which is unusable as an escro program ID —\n * any attempt to deploy to this address fails at the Solana loader level. Code\n * that needs to refuse operation on a not-yet-bootstrapped mainnet compares\n * `PROGRAM_ID_MAINNET` against this constant.\n */\nexport const MAINNET_PROGRAM_ID_PLACEHOLDER = \"11111111111111111111111111111111\" as const;\n\nexport function getProgramId(cluster: SolanaCluster): string {\n return cluster === \"mainnet\" ? PROGRAM_ID_MAINNET : PROGRAM_ID_DEVNET;\n}\n\nexport function getPlatformConfigPda(cluster: SolanaCluster): string {\n return cluster === \"mainnet\" ? PLATFORM_CONFIG_PDA_MAINNET : PLATFORM_CONFIG_PDA_DEVNET;\n}\n\nexport function getUsdcMint(cluster: SolanaCluster): string {\n return cluster === \"mainnet\" ? MAINNET_USDC_MINT : DEVNET_USDC_MINT;\n}\n\nexport function isPlaceholderProgramId(id: string): boolean {\n return id === MAINNET_PROGRAM_ID_PLACEHOLDER;\n}\n\n/**\n * Throws when running in mainnet context with the placeholder program ID still\n * in place. Callers should invoke this at module init (or first use) so the\n * service refuses to do any on-chain work against an unbootstrapped mainnet.\n */\nexport function assertProgramIdNotPlaceholder(id: string, cluster: SolanaCluster): void {\n if (cluster === \"mainnet\" && isPlaceholderProgramId(id)) {\n throw new Error(\n `PROGRAM_ID_MAINNET is still the System Program placeholder (${MAINNET_PROGRAM_ID_PLACEHOLDER}). ` +\n \"Run scripts/deploy-mainnet.sh to bootstrap mainnet, then update the placeholder in \" +\n \"packages/shared/src/config.ts, packages/program/programs/escro/src/lib.rs, \" +\n \"packages/program/Anchor.toml, and infra/bin/escro.ts.\",\n );\n }\n}\n\nexport function parseClusterEnv(raw: string | undefined): SolanaCluster {\n if (raw === \"mainnet\") return \"mainnet\";\n if (raw === \"devnet\" || raw === undefined || raw === \"\") return \"devnet\";\n throw new Error(`CLUSTER env var must be \"devnet\" or \"mainnet\", got \"${raw}\"`);\n}\n","import { createHash } from \"node:crypto\";\nimport nacl from \"tweetnacl\";\nimport bs58 from \"bs58\";\nimport type { Keypair } from \"@solana/web3.js\";\n\n/** Lowercase hex SHA-256 of a UTF-8 string. Use \"\" for no-body requests. */\nexport function hashBody(rawBody: string): string {\n return createHash(\"sha256\").update(rawBody, \"utf8\").digest(\"hex\");\n}\n\n/** Canonical signed message format shared by SDK (signing) and API (verification). */\nexport function buildSignedMessage(\n timestamp: number | string,\n method: string,\n fullPath: string,\n bodyHash: string,\n): string {\n return `escro:${String(timestamp)}:${method}:${fullPath}:${bodyHash}`;\n}\n\n/**\n * Build all auth headers from a raw Ed25519 secret key and its base58 wallet\n * address. This is the web3.js-free core of {@link signRequest}: callers that\n * cannot depend on `@solana/web3.js` (the Bot Kit CLI keeps its runtime light)\n * sign with the raw keyfile bytes here, so the header names and the `escro:`\n * message format live in exactly ONE place and cannot drift from the API's\n * verifier. `rawBody` is the raw UTF-8 request body; pass \"\" when there is none.\n */\nexport function signRequestRaw(\n secretKey: Uint8Array,\n walletAddress: string,\n method: string,\n fullPath: string,\n rawBody: string,\n): Record<string, string> {\n const timestamp = Date.now();\n const bodyHash = hashBody(rawBody);\n const message = buildSignedMessage(timestamp, method, fullPath, bodyHash);\n const sigBytes = nacl.sign.detached(new TextEncoder().encode(message), secretKey);\n return {\n \"x-wallet-address\": walletAddress,\n \"x-signature\": bs58.encode(sigBytes),\n \"x-timestamp\": String(timestamp),\n \"x-content-sha256\": bodyHash,\n };\n}\n\n/**\n * Build all auth headers needed for an authenticated request.\n * `rawBody` is the raw UTF-8 request body string; pass \"\" when there is no body.\n */\nexport function signRequest(\n wallet: Keypair,\n method: string,\n fullPath: string,\n rawBody: string,\n): Record<string, string> {\n return signRequestRaw(wallet.secretKey, wallet.publicKey.toBase58(), method, fullPath, rawBody);\n}\n","import nacl from \"tweetnacl\";\nimport bs58 from \"bs58\";\nimport { canonicalize } from \"./utils/canonicalize.js\";\nimport type { BotDescriptor, UnsignedBotDescriptor } from \"./types/bots.js\";\n\n/**\n * Canonical, deterministic byte-string a bot signs to prove authorship of its\n * capability descriptor (ARCHITECTURE §8 \"anyone can verify the signature\n * independently\"). Excludes `signature` itself. Shared by the SDK/kit (signing)\n * and the API (verification) so both sides agree byte-for-byte.\n */\nexport function canonicalBotDescriptorMessage(descriptor: UnsignedBotDescriptor): string {\n // `canonicalize` sorts keys and drops undefined values, so an absent\n // `endpoint` is naturally excluded and signing is order-independent.\n return canonicalize({\n wallet: descriptor.wallet,\n role: descriptor.role,\n capabilities: descriptor.capabilities,\n serviceRef: descriptor.serviceRef,\n pricingHint: descriptor.pricingHint,\n endpoint: descriptor.endpoint,\n signedAt: descriptor.signedAt,\n });\n}\n\n/**\n * Sign an unsigned descriptor with the bot's Ed25519 secret key, returning the\n * base58 detached signature to attach as `BotDescriptor.signature`.\n */\nexport function signBotDescriptor(\n secretKey: Uint8Array,\n descriptor: UnsignedBotDescriptor,\n): string {\n const message = new TextEncoder().encode(canonicalBotDescriptorMessage(descriptor));\n return bs58.encode(nacl.sign.detached(message, secretKey));\n}\n\n/**\n * Verify a descriptor's `signature` against its own `wallet`. Returns false on a\n * wrong signer, a tampered field, or malformed encoding - never throws. This is\n * the document-level check any third party can run; the API also enforces it.\n */\nexport function verifyBotDescriptorSignature(descriptor: BotDescriptor): boolean {\n try {\n const { signature, ...unsigned } = descriptor;\n const message = new TextEncoder().encode(canonicalBotDescriptorMessage(unsigned));\n const signatureBytes = bs58.decode(signature);\n if (signatureBytes.length !== 64) return false;\n const pubkeyBytes = bs58.decode(descriptor.wallet);\n if (pubkeyBytes.length !== 32) return false;\n return nacl.sign.detached.verify(message, signatureBytes, pubkeyBytes);\n } catch {\n return false;\n }\n}\n","// Source of truth for all user-defined Postgres indexes in the Escro schema.\n//\n// COUNT: 5 entries (the 5 base `escrows` indexes). The marketplace / open-task\n// layer and the off-chain admin-arbitration pipeline were removed: migration\n// 20260601000000 drops the 2 escrows marketplace indexes, the 3 webhook_events\n// indexes (the table is dropped), idx_dispute_queue_unprocessed, and the\n// open-task partial index — leaving only the base escrows indexes here.\n// Verify by running `pnpm --filter @escro/api run check:temp-index-drift`\n// against a fully-migrated database.\n//\n// CANONICAL WHERE FORMS: partial-index predicates are stored in Postgres's\n// canonical form, NOT as written in migration files. Postgres normalises\n// predicates with explicit casts and parentheses during pg_get_expr().\n//\n// To verify or re-derive the canonical form after adding a partial index:\n// 1. Apply migrations to a fresh local Postgres (docker compose -f\n// docker-compose.test.yml up -d && pnpm --filter @escro/api run db:migrate:ci).\n// 2. Run:\n// SELECT c.relname AS index_name,\n// pg_get_expr(idx.indpred, idx.indrelid) AS canonical_where\n// FROM pg_index idx\n// JOIN pg_class c ON c.oid = idx.indexrelid\n// WHERE idx.indpred IS NOT NULL\n// ORDER BY c.relname;\n// 3. Paste each canonical_where verbatim into the `where` field below.\n// 4. Re-run `pnpm --filter @escro/shared run test` to catch count mismatches.\n//\n// SORT DIRECTION: `columns` stores column names only; sort direction (ASC/DESC)\n// is intentionally omitted. The drift check compares names via pg_attribute\n// without decoding pg_index.indoption. Drift in sort direction is not detected.\n// Acceptable because no current query plan depends on a specific sort direction\n// on any of these indexes.\n//\n// SCOPE: intentional exclusions from this list —\n// - oracle_events / escrow_events: see COUNT note above.\n// - marketplaces / webhook_events: tables dropped by migration 20260601000000.\n// - bots (EscroBots v0, migration 20260811000000): NO secondary indexes in v0.\n// v0 volume (the four reference bots + kit registrants, ARCHITECTURE §11a)\n// makes a seq scan the honest plan; a GIN index on capabilities is\n// gold-plating until Phase 7 v1 brings real filter/sort load. Because\n// loadActualIndexes only scans tables present in this list, any index added\n// to `bots` would be invisible to the drift gate, so the migration\n// deliberately creates none, and this exclusion is the recorded decision\n// (P6.T4 architect consult). Phase 7 v1 lands indexes + catalog entries\n// together. The wallet PRIMARY KEY index is excluded by the catalog query\n// (NOT i.indisprimary) regardless.\n// - bot_removals (fraud-only removal, migration 20260813010000): the wallet\n// PRIMARY KEY covers every lookup (the anti-join from `bots`, the POST\n// tombstone check); NO secondary indexes in P7.T6. Same drift-gate reasoning\n// as `bots` above (loadActualIndexes only scans listed tables; the PK index\n// is excluded via NOT indisprimary). Any future secondary index on this table\n// lands with a matching REQUIRED_INDEXES entry (P7.T6 architect consult).\n\nexport interface RequiredIndex {\n readonly name: string;\n readonly table: string;\n readonly columns: readonly string[];\n readonly where: string | null;\n readonly unique: boolean;\n}\n\nexport const REQUIRED_INDEXES: readonly RequiredIndex[] = [\n // escrows — base indexes (20260322, retroactively named)\n { name: \"idx_escrows_state\", table: \"escrows\", columns: [\"state\"], where: null, unique: false },\n {\n name: \"idx_escrows_buyer_wallet\",\n table: \"escrows\",\n columns: [\"buyer_wallet\"],\n where: null,\n unique: false,\n },\n {\n name: \"idx_escrows_assigned_worker\",\n table: \"escrows\",\n columns: [\"assigned_worker\"],\n where: null,\n unique: false,\n },\n {\n name: \"idx_escrows_submitted_at\",\n table: \"escrows\",\n columns: [\"submitted_at\"],\n where: \"((state)::text = 'SUBMITTED'::text)\",\n unique: false,\n },\n {\n name: \"idx_escrows_deadline_at\",\n table: \"escrows\",\n columns: [\"deadline_at\"],\n where: \"((state)::text = 'IN_PROGRESS'::text)\",\n unique: false,\n },\n // The marketplace (escrows_marketplace_*), webhook_events, and dispute-resolution\n // (idx_dispute_queue_unprocessed) indexes were dropped by migration 20260601000000\n // when the marketplace layer and the off-chain admin-arbitration pipeline were removed.\n] as const;\n","import type { Client, Pool } from \"pg\";\nimport { REQUIRED_INDEXES } from \"./required-indexes.js\";\n\n// Same catalog query used by packages/api/src/db/check-index-drift.ts.\n// Single source of truth so the preflight runtime check and the CI drift check\n// run identical SQL and compare against an identical definition of \"present\".\nconst CATALOG_SQL = `\n SELECT\n c.relname AS name,\n t.relname AS table_name,\n i.indisunique AS is_unique,\n pg_get_expr(i.indpred, i.indrelid) AS where_predicate,\n string_agg(a.attname, ',' ORDER BY k.ord) AS columns\n FROM pg_index i\n JOIN pg_class c ON c.oid = i.indexrelid\n JOIN pg_class t ON t.oid = i.indrelid\n JOIN unnest(i.indkey) WITH ORDINALITY AS k(attnum, ord) ON true\n JOIN pg_attribute a ON a.attrelid = i.indrelid AND a.attnum = k.attnum\n WHERE t.relname = ANY($1::text[])\n AND NOT i.indisprimary\n GROUP BY c.relname, t.relname, i.indisunique, i.indpred, i.indrelid\n ORDER BY c.relname\n`;\n\nexport interface CatalogIndex {\n name: string;\n table: string;\n columns: string[];\n where: string | null;\n unique: boolean;\n}\n\nexport async function loadActualIndexes(client: Client | Pool): Promise<CatalogIndex[]> {\n const tables = [...new Set(REQUIRED_INDEXES.map((i) => i.table))];\n const res = await client.query<{\n name: string;\n table_name: string;\n is_unique: boolean;\n where_predicate: string | null;\n columns: string;\n }>(CATALOG_SQL, [tables]);\n return res.rows.map((r) => ({\n name: r.name,\n table: r.table_name,\n columns: r.columns.split(\",\"),\n where: r.where_predicate ?? null,\n unique: r.is_unique,\n }));\n}\n","/**\n * Reserved dual-path payment surface (ARCHITECTURE §7a, BOT_KIT_PRD §10).\n *\n * PLUMBING ONLY. The escrow rail is the sole implemented backend; the `x402`\n * (synchronous) rail is reserved and lands in Phase 9 as an additive backend.\n * Every name here is a FREEZE CONTRACT that Phase 9 (P9.T5) inherits \"by name\":\n * enabling x402 must not be a breaking change for any kit-generated bot. The\n * shapes below are pinned by a type-level test (src/__tests__/payments.test.ts);\n * Phase 9 may add only OPTIONAL fields.\n */\n\n/** Single source for the rail identifiers. The {@link Rail} type is derived from\n * this list (drift-safe, mirroring the BOT_ROLES pattern in @escro/shared). */\nexport const RAILS = [\"escrow\", \"x402\"] as const;\n\n/** The payment rails Escro can route across. Only `escrow` is implemented today;\n * `x402` is RESERVED and not enabled until Phase 9. */\nexport type Rail = (typeof RAILS)[number];\n\n/** The rails enabled in this build. Frozen to escrow-only until Phase 9 enables\n * x402. Typed `readonly Rail[]` (not the literal tuple) so runtime membership\n * checks stay honest: `ENABLED_RAILS.includes(rail)` narrows nothing away. */\nexport const ENABLED_RAILS: readonly Rail[] = [\"escrow\"];\n\n/** Docs for the payment rails, linked from the reserved-rail error and the kit\n * config's rejection message so both point to the same place. */\nexport const RAILS_DOCS_URL = \"https://docs.escro.ai/rails\";\n\n/** The minimal payment shape a {@link PaymentRouter} inspects to choose a rail.\n * FROZEN; Phase 9 may add only optional fields. */\nexport interface TxShape {\n /** Recipient wallet address (base58). */\n readonly to: string;\n /** Amount to move, in USDC micro-units (integer, 6 decimals). */\n readonly amountMicroUsdc: number;\n /** `async` (verification-needed) work routes to escrow; `sync` work is x402's territory. */\n readonly mode: \"async\" | \"sync\";\n}\n\n/** Chooses the rail for a payment. Defined now with a single backend; `x402` is\n * returned only once that rail is enabled (Phase 9). FROZEN signature. */\nexport interface PaymentRouter {\n selectRail(tx: TxShape): Rail;\n}\n\n/** The one backend shipped today. Async work routes to escrow; sync work would\n * prefer x402, but x402 is reserved and not enabled (ARCHITECTURE §7a), so the\n * router falls back to escrow rather than ever returning a disabled rail. */\nexport class EscrowPaymentRouter implements PaymentRouter {\n selectRail(tx: TxShape): Rail {\n const preferred: Rail = tx.mode === \"sync\" ? \"x402\" : \"escrow\";\n return ENABLED_RAILS.includes(preferred) ? preferred : \"escrow\";\n }\n}\n\n/** Parameters for a synchronous payment via {@link Escro.pay}. FROZEN: both\n * fields are required now so Phase 9 adds only optional fields; a required field\n * added later would break every kit-generated bot. */\nexport interface PayParams {\n /** Recipient wallet address (base58). */\n readonly to: string;\n /** Amount to pay, in USDC micro-units (integer, 6 decimals). */\n readonly amountMicroUsdc: number;\n}\n\n/** Result of a completed payment. FROZEN and rail-generic: `reference` is the\n * rail-native settlement id (a Solana signature for escrow, an x402 receipt for\n * x402), so the shape describes either rail without change. */\nexport interface PaymentResult {\n /** Which rail settled the payment. */\n readonly rail: Rail;\n /** Rail-native settlement reference. */\n readonly reference: string;\n}\n","import { RAILS_DOCS_URL } from \"./payments.js\";\n\n/** Base class for all errors thrown by the @escro/sdk. */\nexport class EscroError extends Error {\n constructor(\n message: string,\n public readonly code = \"ESCRO_ERROR\",\n ) {\n super(message);\n this.name = \"EscroError\";\n }\n}\n\n/** The requested escrow was not found (HTTP 404). */\nexport class EscrowNotFoundError extends EscroError {\n constructor(address: string) {\n super(`Escrow not found: ${address}`, \"ESCROW_NOT_FOUND\");\n this.name = \"EscrowNotFoundError\";\n }\n}\n\n/**\n * The reputation endpoint is not available on this deployment (HTTP 404). A 404\n * from `GET /rep` means no `ReputationSource` is mounted (the surface is\n * unmounted), NOT that a wallet is unknown - unknown wallets return zeroed raw\n * components, never a 404. Kept distinct from {@link EscrowNotFoundError}, whose\n * 404 is about a missing escrow.\n */\nexport class ReputationUnavailableError extends EscroError {\n constructor() {\n super(\n \"Reputation endpoint is unavailable (HTTP 404): this deployment has no reputation source mounted.\",\n \"REPUTATION_UNAVAILABLE\",\n );\n this.name = \"ReputationUnavailableError\";\n }\n}\n\n/** The operation is not valid for the escrow's current state (HTTP 409). */\nexport class EscrowStateError extends EscroError {\n constructor(message: string) {\n super(message, \"ESCROW_INVALID_STATE\");\n this.name = \"EscrowStateError\";\n }\n}\n\n/** Polling timed out after 24 hours without reaching the expected state. */\nexport class EscrowTimeoutError extends EscroError {\n constructor(address: string) {\n super(`Polling timed out after 24h for escrow: ${address}`, \"ESCROW_TIMEOUT\");\n this.name = \"EscrowTimeoutError\";\n }\n}\n\n/** The caller is not authorized to perform this action (HTTP 401/403). */\nexport class UnauthorizedError extends EscroError {\n constructor(message = \"Unauthorized\") {\n super(message, \"UNAUTHORIZED\");\n this.name = \"UnauthorizedError\";\n }\n}\n\n/**\n * A payment rail was requested that is not enabled in this build. The `x402`\n * (synchronous) rail is reserved (ARCHITECTURE §7a) and lands in Phase 9;\n * {@link Escro.pay} throws this until then. `rail` names the unavailable rail.\n */\nexport class EscroRailNotEnabledError extends EscroError {\n constructor(public readonly rail: string) {\n super(\n `Payment rail \"${rail}\" is not enabled. Only the escrow rail is available today; ` +\n `the x402 rail is reserved and lands in Phase 9. See ${RAILS_DOCS_URL}`,\n \"ESCRO_RAIL_NOT_ENABLED\",\n );\n this.name = \"EscroRailNotEnabledError\";\n }\n}\n","import { signRequest } from \"@escro/shared\";\nimport type { Keypair } from \"@solana/web3.js\";\nimport type { BotDescriptor, EscrowAccount, EscrowState } from \"@escro/shared\";\nimport type { ServedWalletReputation } from \"@escro/reputation\";\nimport type {\n CreateEscrowParams,\n ListBotsParams,\n PaginatedResult,\n RaiseDisputeParams,\n SerializedEscrow,\n SubmitDeliverableParams,\n} from \"./types.js\";\nimport {\n EscroError,\n EscrowNotFoundError,\n EscrowStateError,\n ReputationUnavailableError,\n UnauthorizedError,\n} from \"./errors.js\";\n\n// ── Auth header builder ────────────────────────────────────────────────────────\n\nfunction authHeaders(\n wallet: Keypair,\n method: string,\n path: string,\n rawBody = \"\",\n): Record<string, string> {\n return signRequest(wallet, method, path, rawBody);\n}\n\n// ── Deserialization ────────────────────────────────────────────────────────────\n\nfunction deserialize(raw: SerializedEscrow): EscrowAccount {\n return { ...raw, amount: BigInt(raw.amount) };\n}\n\n// ── Error handling ─────────────────────────────────────────────────────────────\n\nasync function handleError(res: Response, address?: string): Promise<never> {\n const body = (await res.json().catch(() => ({}))) as {\n error?: string;\n code?: string;\n };\n const msg = body.error ?? `HTTP ${String(res.status)}`;\n if (res.status === 404) throw new EscrowNotFoundError(address ?? msg);\n if (res.status === 409) throw new EscrowStateError(msg);\n if (res.status === 401 || res.status === 403) throw new UnauthorizedError(msg);\n throw new EscroError(msg, body.code ?? \"UNKNOWN\");\n}\n\n// ── API client ─────────────────────────────────────────────────────────────────\n\nexport class ApiClient {\n constructor(\n private readonly baseUrl: string,\n private readonly wallet: Keypair,\n ) {\n const url = new URL(baseUrl);\n const isLocalhost = url.hostname === \"localhost\" || url.hostname === \"127.0.0.1\";\n if (url.protocol !== \"https:\" && !isLocalhost) {\n throw new Error(\"apiUrl must use HTTPS in production\");\n }\n }\n\n private url(path: string): string {\n return `${this.baseUrl}${path}`;\n }\n\n /** GET /v1/escrows/:address */\n async getEscrow(address: string): Promise<EscrowAccount> {\n const path = `/v1/escrows/${address}`;\n const res = await fetch(this.url(path));\n if (!res.ok) await handleError(res, address);\n return deserialize((await res.json()) as SerializedEscrow);\n }\n\n /** GET /v1/escrows?assignedTo=...&maker=...&state=... */\n async listEscrows(params: {\n assignedTo?: string;\n maker?: string;\n state?: EscrowState;\n limit?: number;\n offset?: number;\n }): Promise<PaginatedResult<EscrowAccount>> {\n const qs = new URLSearchParams();\n if (params.assignedTo) qs.set(\"assignedTo\", params.assignedTo);\n if (params.maker) qs.set(\"maker\", params.maker);\n if (params.state) qs.set(\"state\", params.state);\n if (params.limit != null) qs.set(\"limit\", String(params.limit));\n if (params.offset != null) qs.set(\"offset\", String(params.offset));\n\n const path = `/v1/escrows?${qs.toString()}`;\n const res = await fetch(this.url(path));\n if (!res.ok) await handleError(res);\n const body = (await res.json()) as {\n items: SerializedEscrow[];\n total: number;\n limit: number;\n offset: number;\n };\n return {\n items: body.items.map(deserialize),\n total: body.total,\n limit: body.limit,\n offset: body.offset,\n };\n }\n\n /**\n * GET /v1/bots?capability=...&role=...&limit=...&offset= : EscroBots registry\n * read. Unauthenticated public read (no auth headers). Returns descriptors in\n * registry order (newest first); descriptors are self-reported claims.\n */\n async listBots(params: ListBotsParams): Promise<PaginatedResult<BotDescriptor>> {\n const qs = new URLSearchParams();\n if (params.capability != null) qs.set(\"capability\", params.capability);\n if (params.role != null) qs.set(\"role\", params.role);\n if (params.limit != null) qs.set(\"limit\", String(params.limit));\n if (params.offset != null) qs.set(\"offset\", String(params.offset));\n\n const path = `/v1/bots?${qs.toString()}`;\n const res = await fetch(this.url(path));\n if (!res.ok) await handleError(res);\n const body = (await res.json()) as {\n items: BotDescriptor[];\n total: number;\n limit: number;\n offset: number;\n };\n return { items: body.items, total: body.total, limit: body.limit, offset: body.offset };\n }\n\n /**\n * GET /rep : EscroRep bulk export (ARCHITECTURE §9). Unauthenticated public\n * read (no auth headers). Returns every indexed wallet's RAW components exactly\n * once (no composite score). Ranking layers join against this ONE bulk fetch:\n * the per-wallet endpoint shares a 10/min public-metrics budget, so a\n * per-candidate fan-out would rate-limit itself. A 404 means the deployment\n * mounted no reputation source (unknown wallets return zeroed rep, never 404),\n * so it surfaces as {@link ReputationUnavailableError}, not EscrowNotFoundError.\n */\n async listReputations(): Promise<ServedWalletReputation[]> {\n const res = await fetch(this.url(\"/rep\"));\n if (!res.ok) {\n if (res.status === 404) throw new ReputationUnavailableError();\n await handleError(res);\n }\n const body = (await res.json()) as {\n wallets: ServedWalletReputation[];\n count: number;\n generatedAt: number;\n };\n return body.wallets;\n }\n\n /**\n * POST /v1/escrows — create escrow, returns unsigned tx + ids.\n * Requires auth.\n */\n async createEscrow(params: CreateEscrowParams): Promise<{\n escrowId: string;\n escrowPda: string;\n unsignedTx: string;\n }> {\n const path = \"/v1/escrows\";\n const bodyObj: Record<string, unknown> = {\n taskSpec: params.taskSpec,\n amountUsdc: params.amountUsdc,\n deadlineUnix: params.deadlineUnix,\n assignedWorker: params.assignedWorker,\n };\n\n const rawBody = JSON.stringify(bodyObj);\n const res = await fetch(this.url(path), {\n method: \"POST\",\n headers: {\n ...authHeaders(this.wallet, \"POST\", path, rawBody),\n \"content-type\": \"application/json\",\n },\n body: rawBody,\n });\n if (!res.ok) await handleError(res);\n return res.json() as Promise<{ escrowId: string; escrowPda: string; unsignedTx: string }>;\n }\n\n /**\n * POST /v1/escrows/:address/claim — returns unsigned tx.\n * Requires auth (worker).\n */\n async claimTask(address: string): Promise<{ unsignedTx: string }> {\n const path = `/v1/escrows/${address}/claim`;\n const res = await fetch(this.url(path), {\n method: \"POST\",\n headers: authHeaders(this.wallet, \"POST\", path),\n });\n if (!res.ok) await handleError(res, address);\n return res.json() as Promise<{ unsignedTx: string }>;\n }\n\n /**\n * POST /v1/escrows/:address/submit — returns unsigned tx.\n * Requires auth (worker).\n */\n async submitDeliverable(\n address: string,\n params: SubmitDeliverableParams,\n ): Promise<{ unsignedTx: string }> {\n const path = `/v1/escrows/${address}/submit`;\n const rawBody = JSON.stringify({\n contentHash: params.contentHash,\n proofUri: params.proofUri,\n });\n const res = await fetch(this.url(path), {\n method: \"POST\",\n headers: {\n ...authHeaders(this.wallet, \"POST\", path, rawBody),\n \"content-type\": \"application/json\",\n },\n body: rawBody,\n });\n if (!res.ok) await handleError(res, address);\n return res.json() as Promise<{ unsignedTx: string }>;\n }\n\n /**\n * POST /v1/escrows/:address/release — DB-only state update.\n * Requires auth (buyer). No on-chain tx returned.\n */\n async releasePaymentDb(address: string): Promise<void> {\n const path = `/v1/escrows/${address}/release`;\n const res = await fetch(this.url(path), {\n method: \"POST\",\n headers: authHeaders(this.wallet, \"POST\", path),\n });\n if (!res.ok) await handleError(res, address);\n }\n\n /**\n * POST /v1/escrows/:address/cancel — returns unsigned tx.\n * Requires auth (buyer). Only valid when state is FUNDED.\n */\n async cancelEscrow(address: string): Promise<{ unsignedTx: string }> {\n const path = `/v1/escrows/${address}/cancel`;\n const res = await fetch(this.url(path), {\n method: \"POST\",\n headers: authHeaders(this.wallet, \"POST\", path),\n });\n if (!res.ok) await handleError(res, address);\n return res.json() as Promise<{ unsignedTx: string }>;\n }\n\n /**\n * POST /v1/escrows/:address/dispute — returns unsigned tx.\n * Requires auth (buyer or worker).\n */\n async raiseDispute(address: string, params: RaiseDisputeParams): Promise<{ unsignedTx: string }> {\n const path = `/v1/escrows/${address}/dispute`;\n const rawBody = JSON.stringify({ reason: params.reason, evidence: params.evidence });\n const res = await fetch(this.url(path), {\n method: \"POST\",\n headers: {\n ...authHeaders(this.wallet, \"POST\", path, rawBody),\n \"content-type\": \"application/json\",\n },\n body: rawBody,\n });\n if (!res.ok) await handleError(res, address);\n return res.json() as Promise<{ unsignedTx: string }>;\n }\n\n /**\n * GET /v1/stats — public protocol-wide stats.\n * No auth required. Upstream typing in {@link Escro.getStats} narrows the\n * return shape.\n */\n async getStats(): Promise<unknown> {\n const path = \"/v1/stats\";\n const res = await fetch(this.url(path));\n if (!res.ok) await handleError(res);\n return res.json();\n }\n}\n","import { EscrowTimeoutError } from \"./errors.js\";\n\nconst MS_5_MIN = 5 * 60 * 1_000;\nconst MS_30_MIN = 30 * 60 * 1_000;\nconst MS_24_H = 24 * 60 * 60 * 1_000;\n\n/**\n * Returns the next polling interval in ms based on total elapsed time.\n * 0 – 5 min → 15 s\n * 5 – 30 min → 30 s\n * 30 min – ∞ → 60 s\n */\nexport function backoffInterval(elapsedMs: number): number {\n if (elapsedMs < MS_5_MIN) return 15_000;\n if (elapsedMs < MS_30_MIN) return 30_000;\n return 60_000;\n}\n\n/** Resolves after `ms` milliseconds. */\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/**\n * Polls `fetcher` with exponential backoff until `predicate` returns true,\n * then returns the result. Throws {@link EscrowTimeoutError} after 24 hours.\n *\n * @param address - Escrow address used in the timeout error message.\n * @param fetcher - Async function that returns a value or null.\n * @param predicate - Returns true when polling should stop.\n * @param timeoutMs - Maximum total wait time in ms (default: 24 h).\n */\nexport async function pollUntil<T>(\n address: string,\n fetcher: () => Promise<T | null>,\n predicate: (result: T | null) => result is T,\n timeoutMs = MS_24_H,\n): Promise<T> {\n const deadline = Date.now() + timeoutMs;\n\n for (;;) {\n const result = await fetcher();\n if (predicate(result)) return result;\n\n const elapsed = Date.now() - (deadline - timeoutMs);\n if (Date.now() >= deadline) {\n throw new EscrowTimeoutError(address);\n }\n\n const interval = backoffInterval(elapsed);\n // Clamp to remaining time so we don't sleep past the deadline\n const remaining = deadline - Date.now();\n await sleep(Math.min(interval, remaining));\n\n if (Date.now() >= deadline) {\n throw new EscrowTimeoutError(address);\n }\n }\n}\n","import { createHash } from \"node:crypto\";\nimport {\n ComputeBudgetProgram,\n Connection,\n Keypair,\n PublicKey,\n Transaction,\n TransactionInstruction,\n} from \"@solana/web3.js\";\nimport {\n TOKEN_PROGRAM_ID,\n ASSOCIATED_TOKEN_PROGRAM_ID,\n getAssociatedTokenAddressSync,\n createAssociatedTokenAccountIdempotentInstruction,\n} from \"@solana/spl-token\";\nimport { getProgramId, assertProgramIdNotPlaceholder, type SolanaCluster } from \"@escro/shared\";\n\n// ── Discriminator helper ───────────────────────────────────────────────────────\n\nfunction disc(name: string): Buffer {\n return Buffer.from(createHash(\"sha256\").update(`global:${name}`).digest()).subarray(0, 8);\n}\n\nconst DISC_RELEASE_PAYMENT = disc(\"release_payment\");\n\n// ── Cluster-aware program ID resolution ────────────────────────────────────────\n\n/**\n * Resolve the escro program ID for a cluster, asserting it isn't the\n * pre-bootstrap placeholder when targeting mainnet.\n */\nfunction resolveProgramId(cluster: SolanaCluster): PublicKey {\n const id = getProgramId(cluster);\n assertProgramIdNotPlaceholder(id, cluster);\n return new PublicKey(id);\n}\n\nfunction allowedProgramIds(programId: PublicKey): Set<string> {\n return new Set([\n programId.toBase58(),\n TOKEN_PROGRAM_ID.toBase58(),\n ASSOCIATED_TOKEN_PROGRAM_ID.toBase58(),\n ComputeBudgetProgram.programId.toBase58(),\n ]);\n}\n\nconst MAX_INSTRUCTIONS = 6;\n\n/**\n * SPL Token instruction tags (first data byte) that move funds or change\n * authority. Escro flows NEVER have the wallet top-level-sign any of these — all\n * token movement happens via CPI inside the escro program (PDA-signed on\n * release/refund, buyer-authority through create_escrow). The token program is\n * allow-listed only because it is referenced as a CPI target and appears in\n * account lists. A top-level token instruction of one of these types in a\n * server-built transaction is a wallet-drain vector, so we refuse to sign it\n * (L2). Benign token instructions (e.g. InitializeAccount, SyncNative) are not\n * listed and remain permitted.\n */\nconst FORBIDDEN_TOKEN_IX_TAGS = new Set<number>([\n 3, // Transfer\n 4, // Approve\n 6, // SetAuthority\n 7, // MintTo\n 8, // Burn\n 9, // CloseAccount\n 12, // TransferChecked\n 13, // ApproveChecked\n 14, // MintToChecked\n 15, // BurnChecked\n]);\n\n/**\n * PlatformConfig account layout (after 8-byte Anchor discriminator):\n * version : u8 — offset 8\n * fee_bps : u16 — offset 9..11\n * oracle_authority : Pubkey — offset 11..43\n * usdc_mint : Pubkey — offset 43..75\n * treasury : Pubkey — offset 75..107\n *\n * Defensive: validate the version byte. If the on-chain layout drifts, this\n * surfaces a clear error rather than silently returning a corrupted mint.\n */\nconst EXPECTED_PLATFORM_CONFIG_VERSION = 1;\nconst VERSION_OFFSET = 8;\nconst MINT_OFFSET = 43;\nconst TREASURY_OFFSET = 75;\n\nexport async function fetchPlatformConfig(\n connection: Connection,\n cluster: SolanaCluster,\n): Promise<{ mint: PublicKey; treasury: PublicKey }> {\n const programId = resolveProgramId(cluster);\n const [pda] = PublicKey.findProgramAddressSync([Buffer.from(\"config\")], programId);\n const info = await connection.getAccountInfo(pda);\n if (!info) throw new Error(\"PlatformConfig account not found on-chain\");\n const version = info.data[VERSION_OFFSET];\n if (version !== EXPECTED_PLATFORM_CONFIG_VERSION) {\n throw new Error(\n `PlatformConfig version mismatch: expected ${String(EXPECTED_PLATFORM_CONFIG_VERSION)}, got ${String(version)}`,\n );\n }\n return {\n mint: new PublicKey(info.data.subarray(MINT_OFFSET, MINT_OFFSET + 32)),\n treasury: new PublicKey(info.data.subarray(TREASURY_OFFSET, TREASURY_OFFSET + 32)),\n };\n}\n\n// ── Sign and submit ────────────────────────────────────────────────────────────\n\nexport function validateTransaction(tx: Transaction, cluster: SolanaCluster): void {\n const programId = resolveProgramId(cluster);\n const allowed = allowedProgramIds(programId);\n const tokenProgram = TOKEN_PROGRAM_ID.toBase58();\n for (const ix of tx.instructions) {\n const id = ix.programId.toBase58();\n if (!allowed.has(id)) {\n throw new Error(\n `Unexpected program in transaction: ${id}. Allowed: ${[...allowed].join(\", \")}`,\n );\n }\n if (id === tokenProgram) {\n const tag = ix.data.length > 0 ? ix.data[0] : undefined;\n if (tag !== undefined && FORBIDDEN_TOKEN_IX_TAGS.has(tag)) {\n throw new Error(\n `Refusing to sign a fund-moving SPL Token instruction (tag ${String(tag)}) in a ` +\n \"server-built transaction. Escro never requires the wallet to directly sign a token \" +\n \"transfer/approve/burn/close; all token movement is a CPI inside the escro program.\",\n );\n }\n }\n }\n if (tx.instructions.length > MAX_INSTRUCTIONS) {\n throw new Error(\n `Too many instructions (${String(tx.instructions.length)}). Max allowed: ${String(MAX_INSTRUCTIONS)}`,\n );\n }\n}\n\n/**\n * Decode a base64 unsigned transaction, sign it with `wallet`, submit to Solana,\n * and return the transaction signature.\n */\nexport async function signAndSend(\n base64Tx: string,\n wallet: Keypair,\n connection: Connection,\n cluster: SolanaCluster,\n): Promise<string> {\n const buf = Buffer.from(base64Tx, \"base64\");\n const tx = Transaction.from(buf);\n validateTransaction(tx, cluster);\n tx.partialSign(wallet);\n const raw = tx.serialize();\n const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash(\"confirmed\");\n const signature = await connection.sendRawTransaction(raw, {\n skipPreflight: false,\n });\n await connection.confirmTransaction({ signature, blockhash, lastValidBlockHeight }, \"confirmed\");\n return signature;\n}\n\n// ── release_payment transaction builder ───────────────────────────────────────\n\n/**\n * Build an unsigned `release_payment` transaction.\n * The buyer signs to approve payment to the assigned worker.\n *\n * Account order (matches the on-chain `ReleasePayment` context):\n * 0. buyer — Signer, writable\n * 1. platform_config — read\n * 2. mint — read\n * 3. escrow_account — writable\n * 4. vault — ATA(mint, escrowPda), writable\n * 5. worker_ata — ATA(mint, worker), writable\n * 6. treasury_ata — ATA(mint, treasury), writable\n * 7. worker — read\n * 8. treasury — read\n * 9. token_program — read\n * 10. associated_token_program — read\n */\nexport async function buildReleasePaymentTx(params: {\n buyer: PublicKey;\n escrowPda: PublicKey;\n worker: PublicKey;\n mint: PublicKey;\n treasury: PublicKey;\n connection: Connection;\n cluster: SolanaCluster;\n}): Promise<string> {\n const { buyer, escrowPda, worker, mint, treasury, connection, cluster } = params;\n const programId = resolveProgramId(cluster);\n\n const [platformConfig] = PublicKey.findProgramAddressSync([Buffer.from(\"config\")], programId);\n const vault = getAssociatedTokenAddressSync(\n mint,\n escrowPda,\n true,\n TOKEN_PROGRAM_ID,\n ASSOCIATED_TOKEN_PROGRAM_ID,\n );\n const workerAta = getAssociatedTokenAddressSync(\n mint,\n worker,\n false,\n TOKEN_PROGRAM_ID,\n ASSOCIATED_TOKEN_PROGRAM_ID,\n );\n // allowOwnerOffCurve = true: the treasury is a Squads multisig vault, which is\n // a PDA (off-curve). getAssociatedTokenAddressSync throws TokenOwnerOffCurveError\n // for a PDA owner unless this flag is set. Safe/no-op for an on-curve treasury.\n const treasuryAta = getAssociatedTokenAddressSync(\n mint,\n treasury,\n true,\n TOKEN_PROGRAM_ID,\n ASSOCIATED_TOKEN_PROGRAM_ID,\n );\n\n const ix = new TransactionInstruction({\n programId: programId,\n keys: [\n { pubkey: buyer, isSigner: true, isWritable: true },\n { pubkey: platformConfig, isSigner: false, isWritable: false },\n { pubkey: mint, isSigner: false, isWritable: false },\n { pubkey: escrowPda, isSigner: false, isWritable: true },\n { pubkey: vault, isSigner: false, isWritable: true },\n { pubkey: workerAta, isSigner: false, isWritable: true },\n { pubkey: treasuryAta, isSigner: false, isWritable: true },\n { pubkey: worker, isSigner: false, isWritable: false },\n { pubkey: treasury, isSigner: false, isWritable: false },\n { pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false },\n { pubkey: ASSOCIATED_TOKEN_PROGRAM_ID, isSigner: false, isWritable: false },\n ],\n data: DISC_RELEASE_PAYMENT,\n });\n\n const { blockhash } = await connection.getLatestBlockhash(\"confirmed\");\n const tx = new Transaction();\n tx.recentBlockhash = blockhash;\n tx.feePayer = buyer;\n\n tx.add(createAssociatedTokenAccountIdempotentInstruction(buyer, workerAta, worker, mint));\n tx.add(createAssociatedTokenAccountIdempotentInstruction(buyer, treasuryAta, treasury, mint));\n tx.add(ix);\n return tx.serialize({ requireAllSignatures: false }).toString(\"base64\");\n}\n","import type { TaskSpec } from \"@escro/shared\";\n\nimport type { SubmitDeliverableParams } from \"./types.js\";\n\n/**\n * The result a {@link ServiceAdapter} returns from `execute`. Escro is agnostic\n * to what produced it: `content` is the deliverable itself, `contentHash` is the\n * SHA-256 hex digest the Buyer verifies the deliverable against, and `proofUri`\n * optionally points at where the content is pinned (IPFS/Arweave) or at a proof.\n * No currency or token field appears here; token conversion is adapter-internal\n * (ARCHITECTURE §3, §7).\n */\nexport interface ServiceResult {\n /** The deliverable itself. */\n content: string | Buffer;\n /** SHA-256 hex digest of {@link ServiceResult.content}. */\n contentHash: string;\n /** Content-addressed URI (ipfs://, ar://) or proof URI for the deliverable. */\n proofUri?: string;\n /** Arbitrary adapter-specific metadata (model, timings, subnet ids, ...). */\n metadata: Record<string, unknown>;\n}\n\n/**\n * A Worker Bot implements ServiceAdapter to wrap any async service (a Bittensor\n * subnet, an Akash deployment, a Render job, ...). Escro never sees what is\n * underneath and never sees a non-USDC token: the adapter handles any token\n * conversion internally (ARCHITECTURE §3, §7). Every pre-built adapter reuses\n * this interface and is validated by `assertServiceAdapterContract`.\n */\nexport interface ServiceAdapter {\n /** Stable identifier, e.g. \"bittensor:sn56\", \"akash\", \"render\". */\n id: string;\n /** Advertised capabilities, e.g. [\"llm_inference\", \"image_gen\"]. */\n capabilities: string[];\n /** Execute the task described by `spec` and return the deliverable. */\n execute(spec: TaskSpec): Promise<ServiceResult>;\n /** Report whether the underlying service is reachable and ready. */\n healthCheck(): Promise<boolean>;\n}\n\n/**\n * Map a {@link ServiceResult} onto {@link SubmitDeliverableParams}, surfacing the\n * `contentHash` (and `proofUri`, when present) that `submit_deliverable` records.\n * This is the single point where an adapter's output crosses into the escrow\n * worker flow.\n */\nexport function serviceResultToSubmitParams(result: ServiceResult): SubmitDeliverableParams {\n return {\n contentHash: result.contentHash,\n ...(result.proofUri !== undefined && { proofUri: result.proofUri }),\n };\n}\n","import { createHash } from \"crypto\";\n\nimport type { TaskSpec } from \"@escro/shared\";\n\nimport type { ServiceAdapter, ServiceResult } from \"./adapter.js\";\nimport { EscroError } from \"./errors.js\";\n\n/** Options controlling {@link assertServiceAdapterContract}. */\nexport interface AdapterContractOptions {\n /**\n * A representative TaskSpec the adapter can execute. The harness calls\n * `execute(sampleSpec)` and validates the returned ServiceResult, so the spec\n * should be one the adapter genuinely handles.\n */\n sampleSpec: TaskSpec;\n}\n\n/** Thrown by {@link assertServiceAdapterContract}, listing every contract violation. */\nexport class AdapterContractError extends EscroError {\n constructor(\n adapterId: string,\n public readonly violations: string[],\n ) {\n super(\n `ServiceAdapter \"${adapterId}\" violates the adapter contract:\\n- ${violations.join(\"\\n- \")}`,\n \"ADAPTER_CONTRACT_VIOLATION\",\n );\n this.name = \"AdapterContractError\";\n }\n}\n\nfunction errMessage(err: unknown): string {\n return err instanceof Error ? err.message : String(err);\n}\n\nfunction sha256Hex(content: string | Buffer): string {\n return createHash(\"sha256\").update(content).digest(\"hex\");\n}\n\n/** Validate the shape and hash integrity of a value returned by `execute`. */\nfunction validateServiceResult(result: unknown): string[] {\n if (typeof result !== \"object\" || result === null) {\n return [\"`execute()` must resolve to a ServiceResult object\"];\n }\n const violations: string[] = [];\n const r = result as {\n content?: unknown;\n contentHash?: unknown;\n proofUri?: unknown;\n metadata?: unknown;\n };\n\n const contentIsValid = typeof r.content === \"string\" || Buffer.isBuffer(r.content);\n if (!contentIsValid) {\n violations.push(\"`content` must be a string or Buffer\");\n }\n\n if (typeof r.contentHash !== \"string\" || r.contentHash.trim() === \"\") {\n violations.push(\"`contentHash` must be a non-empty string\");\n } else if (contentIsValid && r.contentHash !== sha256Hex(r.content as string | Buffer)) {\n violations.push(\"`contentHash` must equal the SHA-256 hex digest of `content`\");\n }\n\n if (r.proofUri !== undefined && typeof r.proofUri !== \"string\") {\n violations.push(\"`proofUri`, when present, must be a string\");\n }\n\n if (typeof r.metadata !== \"object\" || r.metadata === null || Array.isArray(r.metadata)) {\n violations.push(\"`metadata` must be a plain object\");\n }\n\n return violations;\n}\n\n/**\n * Assert that `adapter` satisfies the ServiceAdapter contract. Resolves with the\n * ServiceResult produced by `execute(sampleSpec)` when the adapter conforms;\n * rejects with an {@link AdapterContractError} listing every violation otherwise.\n *\n * Reusable across adapters (this phase's Bittensor one, Phase 6's four, Phase 8's\n * networks): a conforming adapter passes, a malformed one fails. The parameter is\n * typed `ServiceAdapter`, but the harness validates at runtime: JS callers and\n * `as`-cast objects reach this too, so every field is checked defensively.\n */\nexport async function assertServiceAdapterContract(\n adapter: ServiceAdapter,\n options: AdapterContractOptions,\n): Promise<ServiceResult> {\n const a = adapter as {\n id?: unknown;\n capabilities?: unknown;\n execute?: unknown;\n healthCheck?: unknown;\n };\n const violations: string[] = [];\n const id = typeof a.id === \"string\" && a.id.trim() !== \"\" ? a.id : \"(unknown)\";\n\n if (typeof a.id !== \"string\" || a.id.trim() === \"\") {\n violations.push(\"`id` must be a non-empty string\");\n }\n // capabilities must be non-empty so the adapter is discoverable in EscroBots.\n if (\n !Array.isArray(a.capabilities) ||\n a.capabilities.length === 0 ||\n (a.capabilities as unknown[]).some((c) => typeof c !== \"string\" || c.trim() === \"\")\n ) {\n violations.push(\"`capabilities` must be a non-empty array of non-empty strings\");\n }\n if (typeof a.healthCheck !== \"function\") {\n violations.push(\"`healthCheck` must be a function\");\n }\n if (typeof a.execute !== \"function\") {\n violations.push(\"`execute` must be a function\");\n }\n\n if (typeof a.healthCheck === \"function\") {\n try {\n const healthy = await (a.healthCheck as () => Promise<unknown>)();\n if (typeof healthy !== \"boolean\") {\n violations.push(\"`healthCheck()` must resolve to a boolean\");\n }\n } catch (err) {\n violations.push(`\\`healthCheck()\\` threw: ${errMessage(err)}`);\n }\n }\n\n let result: ServiceResult | undefined;\n if (typeof a.execute === \"function\") {\n try {\n result = await (a.execute as (spec: TaskSpec) => Promise<ServiceResult>)(options.sampleSpec);\n violations.push(...validateServiceResult(result));\n } catch (err) {\n violations.push(`\\`execute()\\` threw: ${errMessage(err)}`);\n result = undefined;\n }\n }\n\n if (violations.length > 0 || result === undefined) {\n throw new AdapterContractError(\n id,\n violations.length > 0 ? violations : [\"`execute()` produced no result\"],\n );\n }\n return result;\n}\n","/**\n * Shared Bittensor-subnet ServiceAdapter core. SN56 (gradients), SN17 (404gen) and\n * SN51 (lium) are three Bittensor-shaped adapters that swap a per-task USDC budget\n * into TAO internally, pay subnet miners in TAO, collect a deliverable, and return a\n * currency-free `ServiceResult`. This module owns what they share: the branded `Tao`\n * type (which exists ONLY in the adapter layer and can never reach a `ServiceResult`\n * or the escrow submit path -- see bittensor.type-test.ts for the compile-time proof),\n * the USDC->TAO swap / subnet-call / pin ports, the shared default ports, and the\n * `execute` skeleton. Each adapter supplies its own subnet id, capabilities, budget,\n * demo logic and default-port wiring, then delegates `execute` to\n * {@link createBittensorSubnetAdapter}. Ridges (USD-billed, no TAO) is deliberately\n * NOT part of this core.\n */\nimport { createHash } from \"crypto\";\n\nimport type { TaskSpec } from \"@escro/shared\";\n\nimport type { ServiceAdapter, ServiceResult } from \"../../adapter.js\";\n\n/**\n * Amount denominated in TAO (Bittensor's token). Branded so it cannot be assigned to\n * or from a plain `number` by accident and (the point of the brand) so it can never\n * appear in a `ServiceResult` or the escrow submit path: those types have no field of\n * this type. TAO exists ONLY inside the Bittensor adapter layer.\n */\nexport type Tao = number & { readonly __brand: \"TAO\" };\n\n/** Construct a {@link Tao} amount from a plain number. Adapter-internal use only. */\nexport function tao(amount: number): Tao {\n return amount as Tao;\n}\n\n/** Swap a microUSDC budget into TAO. Real workers route this through a DEX (e.g. Jupiter). */\nexport type UsdcToTaoSwap = (microUsdc: number) => Promise<Tao>;\n\n/**\n * Pay subnet miners `budget` TAO to run `spec`; resolve with the raw deliverable. The\n * single shared port shape across every Bittensor adapter (a GPU-rental call is a paid\n * subnet call too; lium re-exports this as `RunGpuJob`).\n */\nexport type SubnetCall = (spec: TaskSpec, budget: Tao) => Promise<string | Buffer>;\n\n/** Pin `content` and resolve with a content-addressed proof URI (ipfs://, ar://). */\nexport type PinContent = (content: string | Buffer) => Promise<string>;\n\n/** SHA-256 hex digest of a deliverable. */\nexport function sha256Hex(content: string | Buffer): string {\n return createHash(\"sha256\").update(content).digest(\"hex\");\n}\n\n// Nominal reference rate: microUSDC -> TAO. Only the stub swap cares about the exact value.\nexport const REFERENCE_MICRO_USDC_PER_TAO = 300_000_000;\n\n/** Default fixed-rate reference swap, shared by every reference Bittensor adapter. */\nexport const defaultSwap: UsdcToTaoSwap = (microUsdc) =>\n Promise.resolve(tao(microUsdc / REFERENCE_MICRO_USDC_PER_TAO));\n\n/** Default deterministic `ipfs://` placeholder pin, shared by every reference adapter. */\nexport const defaultPin: PinContent = (content) =>\n Promise.resolve(`ipfs://placeholder-${sha256Hex(content).slice(0, 16)}`);\n\n/** Fully-resolved ports and identity for {@link createBittensorSubnetAdapter}. */\nexport interface BittensorSubnetAdapterConfig {\n /** Subnet identifier (e.g. \"sn56\"); forms the adapter id `bittensor:<subnet>`. */\n subnet: string;\n /** Advertised capabilities for EscroBots discovery. */\n capabilities: string[];\n /** microUSDC allocated to a single task before converting to TAO (internal budgeting). */\n taskBudgetMicroUsdc: number;\n /** USDC->TAO swap port. */\n swap: UsdcToTaoSwap;\n /** Subnet-call port (pays the subnet in TAO and returns the deliverable). */\n callSubnet: SubnetCall;\n /** Pinning port. */\n pin: PinContent;\n /** Health-check port. */\n checkHealth: () => Promise<boolean>;\n}\n\n/**\n * Build a Bittensor-subnet {@link ServiceAdapter} from fully-resolved ports. The\n * execute skeleton: swap the USDC budget into TAO (internal, never surfaced), pay the\n * subnet in TAO and collect the deliverable, then hash and pin. The recorded\n * `ServiceResult` is currency-free (no TAO field). Every reference TAO adapter resolves\n * its own defaults and delegates here.\n */\nexport function createBittensorSubnetAdapter(config: BittensorSubnetAdapterConfig): ServiceAdapter {\n const id = `bittensor:${config.subnet}`;\n return {\n id,\n capabilities: config.capabilities,\n healthCheck: config.checkHealth,\n async execute(spec: TaskSpec): Promise<ServiceResult> {\n // 1. Swap the USDC budget into TAO (internal, never surfaced).\n const budgetTao = await config.swap(config.taskBudgetMicroUsdc);\n // 2. Pay subnet miners in TAO and collect the deliverable.\n const content = await config.callSubnet(spec, budgetTao);\n // 3. Hash and pin. The result the escrow records is currency-free.\n const contentHash = sha256Hex(content);\n const proofUri = await config.pin(content);\n return {\n content,\n contentHash,\n proofUri,\n metadata: { adapter: id, subnet: config.subnet },\n };\n },\n };\n}\n","/**\n * Gradients (Bittensor SN56) ServiceAdapter: the first SHIPPED, supported adapter\n * (the reference pattern P6.T6b-d replicate). A Worker Bot wraps the Gradients\n * fine-tuning subnet behind the `ServiceAdapter` interface: it swaps a per-task\n * USDC budget into TAO internally, pays subnet miners in TAO to fine-tune, collects\n * a checkpoint + eval deliverable, and returns a currency-free `ServiceResult`. The\n * Buyer and the escrow contract only ever see USDC; no TAO-typed value crosses this\n * boundary into SDK core (ARCHITECTURE §3, §7; see ../bittensor/bittensor.type-test.ts\n * for the compile-time proof shared by the Bittensor trio).\n *\n * The swap, subnet call, and pinning are injectable ports so the reference runs (and\n * is tested) without a live DEX, subnet, or IPFS node. A production worker supplies\n * real implementations (Jupiter for the swap, the SN56 dendrite, Pinata/Arweave).\n *\n * RELEASE JUDGMENT IS NOT HERE. This adapter only PRODUCES the deliverable (checkpoint\n * + eval JSON). Whether the eval clears the threshold is decided by the BUYER's\n * review.ts, which independently recomputes the score (see `scoreGradientsDemoDeliverable`).\n * The worker never scores-for-release and never releases (CLAUDE.md product framing).\n *\n * Relationship to `examples/worker-bot/bittensor-adapter.ts`: that example is\n * pedagogy (\"author your own adapter against the public interface\", driven by e2e\n * scenario 13 / the P5.T2b obligation); THIS module is the shipped, importable\n * surface a generated bot uses. The USDC->TAO port skeleton and the execute shape are\n * shared with the other Bittensor adapters via `../bittensor/index.js`; this module\n * supplies only its subnet identity, capabilities, budget, and demo logic.\n */\nimport { canonicalize, type TaskSpec } from \"@escro/shared\";\n\nimport type { ServiceAdapter } from \"../../adapter.js\";\nimport {\n createBittensorSubnetAdapter,\n defaultPin,\n defaultSwap,\n type PinContent,\n type SubnetCall,\n type UsdcToTaoSwap,\n} from \"../bittensor/index.js\";\n\n/** Configuration and injectable ports for {@link createGradientsAdapter}. */\nexport interface GradientsAdapterConfig {\n /** Subnet identifier. Defaults to \"sn56\" (Gradients); forms the adapter id `bittensor:<subnet>`. */\n subnet?: string;\n /** Advertised capabilities for EscroBots discovery. Defaults to `[\"fine-tune\"]`. */\n capabilities?: string[];\n /** μUSDC the worker allocates to a single task before converting to TAO (internal budgeting). */\n taskBudgetMicroUsdc?: number;\n /** Swap port. Default: a fixed-rate reference stub. */\n swap?: UsdcToTaoSwap;\n /** Subnet-call port. Default: solves the canned demo job; a deterministic placeholder otherwise. */\n callSubnet?: SubnetCall;\n /** Pinning port. Default: a deterministic `ipfs://` placeholder URI. */\n pin?: PinContent;\n /** Health-check port. Default: resolves `true`. */\n checkHealth?: () => Promise<boolean>;\n}\n\n/** Stable id/capabilities, LOCKED against `ADAPTER_DESCRIPTORS.gradients` by a kit test (consult C2). */\nexport const GRADIENTS_ADAPTER_ID = \"bittensor:sn56\";\nexport const GRADIENTS_CAPABILITIES = [\"fine-tune\"] as const;\n\nconst DEFAULT_SUBNET = \"sn56\";\nconst DEFAULT_TASK_BUDGET_MICRO_USDC = 5_000_000;\n\n// ---------------------------------------------------------------------------\n// Canned demo job (BOT_KIT_PRD §6 / §13): a deterministic fine-tune the buyer\n// template's 5-minute journey hires this bot for. The \"model\" learns the fixed\n// affine map y = 2x + 1 on a fixed dataset; the deliverable is the model's\n// predictions on that dataset. Acceptance is machine-checkable and recomputed by\n// the BUYER (see scoreGradientsDemoDeliverable); the worker's self-reported eval\n// score is never trusted.\n// ---------------------------------------------------------------------------\n\n/** Stable marker on the demo spec's metadata so the default subnet stub recognizes it. */\nexport const GRADIENTS_DEMO_MARKER = \"gradients-sn56-demo-v1\";\n\n/** The demo eval floor: predictions must be at least this accurate to be accepted. */\nexport const GRADIENTS_DEMO_EVAL_FLOOR = 0.8;\n\n/** The demo's fixed inputs. The reference target maps each `x` to `2x + 1`. */\nconst DEMO_DATASET: readonly number[] = [3, 7, 11, 15, 19];\n\nfunction demoExpectedOutputs(): number[] {\n return DEMO_DATASET.map((x) => 2 * x + 1);\n}\n\n/**\n * The canned Gradients demo job. Deterministic; its specHash is pinned by a test\n * (consult C8) because the buyer journey depends on hash stability.\n */\nexport const gradientsDemoJobSpec: TaskSpec = {\n version: \"1.0.0\",\n // TaskType has no fine-tune category; \"custom\" is the canonical fallback.\n taskType: \"custom\",\n description:\n \"Fine-tune the reference model on the canned SN56 demo dataset and return its \" +\n \"predictions on the same inputs. The target map is y = 2x + 1. Acceptance is \" +\n \"deterministic and recomputed by the buyer: prediction accuracy must be >= 0.8; \" +\n \"the worker's self-reported eval score is not trusted.\",\n acceptanceCriteria: [\n {\n id: \"ac-eval-floor\",\n description:\n \"Prediction accuracy on the demo dataset is >= 0.8, recomputed by the buyer from the deliverable.\",\n required: true,\n },\n ],\n deliverableFormat: { type: \"json\" },\n metadata: {\n demo: GRADIENTS_DEMO_MARKER,\n dataset: [...DEMO_DATASET],\n target: \"y = 2x + 1\",\n evalFloor: GRADIENTS_DEMO_EVAL_FLOOR,\n },\n};\n\n/**\n * The reference solution to the demo job: the correct predictions plus a\n * (self-reported, buyer-ignored) eval block, as canonical JSON. Deterministic.\n * Exposed so the demo journey and tests share one source of the expected artifact.\n */\nexport function solveGradientsDemo(): string {\n const predictions = demoExpectedOutputs();\n return canonicalize({\n checkpoint: \"reference-sn56-demo-checkpoint\",\n eval: { metric: \"accuracy\", score: 1 },\n predictions,\n });\n}\n\ninterface DemoDeliverable {\n predictions: number[];\n}\n\nfunction parseDemoDeliverable(content: string | Buffer): DemoDeliverable | null {\n const text = Buffer.isBuffer(content) ? content.toString(\"utf8\") : content;\n let parsed: unknown;\n try {\n parsed = JSON.parse(text);\n } catch {\n return null;\n }\n if (typeof parsed !== \"object\" || parsed === null) {\n return null;\n }\n const predictions = (parsed as { predictions?: unknown }).predictions;\n if (!Array.isArray(predictions) || predictions.some((p) => typeof p !== \"number\")) {\n return null;\n }\n return { predictions: predictions as number[] };\n}\n\n/**\n * The BUYER's independent recompute of the demo eval score in [0, 1]. Reads the\n * substantive output (the predictions) and compares it to the target map the buyer\n * itself defines; it deliberately IGNORES any self-reported `eval.score` in the\n * deliverable, so release can never be worker-controlled (consult C10). Malformed\n * or unparseable content scores 0 and never throws.\n */\nexport function scoreGradientsDemoDeliverable(content: string | Buffer): number {\n const parsed = parseDemoDeliverable(content);\n if (parsed === null) {\n return 0;\n }\n const expected = demoExpectedOutputs();\n let matches = 0;\n for (let i = 0; i < expected.length; i++) {\n if (parsed.predictions[i] === expected[i]) {\n matches++;\n }\n }\n return matches / expected.length;\n}\n\n// A generic (non-demo) fine-tune produces a placeholder checkpoint+eval so a fresh\n// worker returns a well-formed ServiceResult before a real SN56 miner is wired.\nfunction referencePlaceholder(spec: TaskSpec): string {\n return canonicalize({\n checkpoint: \"reference-sn56-checkpoint\",\n eval: { metric: \"accuracy\", score: 0 },\n note: \"reference stub - replace the callSubnet port with a real SN56 miner call.\",\n taskType: spec.taskType,\n });\n}\n\nconst defaultCallSubnet: SubnetCall = (spec) =>\n Promise.resolve(\n spec.metadata.demo === GRADIENTS_DEMO_MARKER\n ? solveGradientsDemo()\n : referencePlaceholder(spec),\n );\n\n/**\n * Build a Gradients (SN56) {@link ServiceAdapter}. Passes `assertServiceAdapterContract`\n * with the default ports; supply real ports for production use. The USDC->TAO swap,\n * pinning, and execute skeleton come from the shared Bittensor core.\n */\nexport function createGradientsAdapter(config: GradientsAdapterConfig = {}): ServiceAdapter {\n return createBittensorSubnetAdapter({\n subnet: config.subnet ?? DEFAULT_SUBNET,\n capabilities: config.capabilities ?? [...GRADIENTS_CAPABILITIES],\n taskBudgetMicroUsdc: config.taskBudgetMicroUsdc ?? DEFAULT_TASK_BUDGET_MICRO_USDC,\n swap: config.swap ?? defaultSwap,\n callSubnet: config.callSubnet ?? defaultCallSubnet,\n pin: config.pin ?? defaultPin,\n checkHealth: config.checkHealth ?? ((): Promise<boolean> => Promise.resolve(true)),\n });\n}\n","/**\n * Ridges (AI coding agents) ServiceAdapter: a SHIPPED, supported reference adapter\n * built on the same pattern as the Gradients SN56 adapter (P6.T6a). A Worker Bot\n * wraps a Ridges coding agent behind the `ServiceAdapter` interface: given a coding\n * task, it runs the agent to produce a solution, runs the task's test suite, and\n * returns a test report as the `ServiceResult` deliverable. The Buyer and the escrow\n * contract only ever see USDC.\n *\n * Unlike the Bittensor adapters (gradients SN56, 404gen SN17, lium SN51), Ridges is\n * billed in USD through its platform API, so there is no in-adapter token conversion\n * and no TAO-typed value to keep out of SDK core: `serviceRef` is a bare `\"ridges\"`,\n * not `bittensor:<subnet>` (kit `ADAPTER_DESCRIPTORS.ridges`). The worker still fronts\n * the service cost and is reimbursed in USDC at release (see README float profile).\n *\n * RELEASE JUDGMENT IS NOT HERE. This adapter only PRODUCES the deliverable (a test\n * report). Whether the suite passed and coverage cleared the target is decided by the\n * BUYER's review.ts, which independently recomputes the outcome from the delivered\n * test outputs (see `scoreRidgesDemoDeliverable`). The worker never scores-for-release\n * and never releases, and its self-reported pass/coverage is never trusted\n * (CLAUDE.md product framing).\n *\n * The coding-agent call and pinning are injectable ports so the reference runs (and is\n * tested) without a live Ridges endpoint or IPFS node. A production worker supplies\n * real implementations (the Ridges platform API for `runAgent`, Pinata/Arweave for\n * `pin`). The port pattern mirrors the gradients adapter deliberately. Ridges is\n * USD-billed with no TAO, so it deliberately does not use the shared `adapters/bittensor`\n * core (that core covers only the Bittensor trio: SN56, SN17, SN51).\n */\nimport { createHash } from \"crypto\";\n\nimport { canonicalize, type TaskSpec } from \"@escro/shared\";\n\nimport type { ServiceAdapter, ServiceResult } from \"../../adapter.js\";\n\n/** Run the coding agent for `spec`; resolve with the raw deliverable (a test report). */\nexport type RunCodingAgent = (spec: TaskSpec) => Promise<string | Buffer>;\n\n/** Pin `content` and resolve with a content-addressed proof URI (ipfs://, ar://). */\nexport type PinContent = (content: string | Buffer) => Promise<string>;\n\n/** Configuration and injectable ports for {@link createRidgesAdapter}. */\nexport interface RidgesAdapterConfig {\n /** Service identifier. Defaults to \"ridges\"; forms the adapter id. */\n service?: string;\n /** Advertised capabilities for EscroBots discovery. Defaults to `[\"code-generation\"]`. */\n capabilities?: string[];\n /** Coding-agent port. Default: solves the canned demo kata; a placeholder otherwise. */\n runAgent?: RunCodingAgent;\n /** Pinning port. Default: a deterministic `ipfs://` placeholder URI. */\n pin?: PinContent;\n /** Health-check port. Default: resolves `true`. */\n checkHealth?: () => Promise<boolean>;\n}\n\n/**\n * Stable id/capabilities. Locked against `ADAPTER_DESCRIPTORS.ridges` by a kit test\n * at merge (consult C2; the lock lives in create-escro-bot, which depends on this\n * package, and is landed with the barrel wiring — LANE-NOTES merge step 3).\n */\nexport const RIDGES_ADAPTER_ID = \"ridges\";\nexport const RIDGES_CAPABILITIES = [\"code-generation\"] as const;\n\nconst DEFAULT_SERVICE = \"ridges\";\n\nfunction sha256Hex(content: string | Buffer): string {\n return createHash(\"sha256\").update(content).digest(\"hex\");\n}\n\n// ---------------------------------------------------------------------------\n// Canned demo kata (BOT_KIT_PRD §6 / §13): a deterministic coding job the buyer\n// template's 5-minute journey hires this bot for. The kata is a fixed FizzBuzz\n// repo: implement FizzBuzz and make its test battery pass. The deliverable is the\n// solution's test report (each battery input and the output the solution produced).\n// Acceptance is machine-checkable and recomputed by the BUYER (see\n// scoreRidgesDemoDeliverable): every delivered test must pass (exit 0) AND coverage\n// of the battery must clear the target. The worker's self-report is never trusted.\n// ---------------------------------------------------------------------------\n\n/** Stable marker on the demo spec's metadata so the default agent stub recognizes it. */\nexport const RIDGES_DEMO_MARKER = \"ridges-demo-v1\";\n\n/** The demo coverage target: the fraction of the test battery that must be covered. */\nexport const RIDGES_DEMO_COVERAGE_TARGET = 0.8;\n\n/**\n * The demo's fixed test battery: FizzBuzz over these inputs, chosen to exercise every\n * branch (plain number, Fizz, Buzz, FizzBuzz).\n */\nconst DEMO_INPUTS: readonly number[] = [1, 2, 3, 5, 15];\n\n/** The kata's reference logic; the buyer recomputes expected outputs from this. */\nfunction fizzbuzz(n: number): string {\n if (n % 15 === 0) return \"FizzBuzz\";\n if (n % 3 === 0) return \"Fizz\";\n if (n % 5 === 0) return \"Buzz\";\n return String(n);\n}\n\n/**\n * The canned Ridges demo job. Deterministic; its specHash is pinned by a test\n * because the buyer journey depends on hash stability.\n */\nexport const ridgesDemoJobSpec: TaskSpec = {\n version: \"1.0.0\",\n taskType: \"code_generation\",\n description:\n \"Implement FizzBuzz for the fixed demo battery and return a test report: for each \" +\n \"battery input, the output your implementation produced. Acceptance is deterministic \" +\n \"and recomputed by the buyer: every delivered test must pass (exit 0) and coverage of \" +\n \"the battery must be >= 0.8; the worker's self-reported pass/coverage is not trusted.\",\n acceptanceCriteria: [\n {\n id: \"ac-tests-pass\",\n description:\n \"Every delivered test passes (exit 0), recomputed by the buyer from the test report.\",\n required: true,\n },\n {\n id: \"ac-coverage\",\n description: \"Coverage of the demo battery is >= 0.8, recomputed by the buyer.\",\n required: true,\n },\n ],\n deliverableFormat: { type: \"json\" },\n metadata: {\n demo: RIDGES_DEMO_MARKER,\n kata: \"fizzbuzz\",\n inputs: [...DEMO_INPUTS],\n coverageTarget: RIDGES_DEMO_COVERAGE_TARGET,\n },\n};\n\n/** The reference source solution, carried in the deliverable for human readers only. */\nconst REFERENCE_SOLUTION =\n \"export function fizzbuzz(n: number): string {\\n\" +\n ' if (n % 15 === 0) return \"FizzBuzz\";\\n' +\n ' if (n % 3 === 0) return \"Fizz\";\\n' +\n ' if (n % 5 === 0) return \"Buzz\";\\n' +\n \" return String(n);\\n\" +\n \"}\\n\";\n\n/**\n * The reference solution to the demo kata: a passing test report over the full\n * battery, plus a (self-reported, buyer-ignored) pass/coverage block, as canonical\n * JSON. Deterministic. Exposed so the demo journey and tests share one source of the\n * expected artifact.\n */\nexport function solveRidgesDemo(): string {\n const tests = DEMO_INPUTS.map((input) => ({ input, output: fizzbuzz(input) }));\n return canonicalize({\n language: \"typescript\",\n solution: REFERENCE_SOLUTION,\n coverage: 1,\n passed: true,\n tests,\n });\n}\n\ninterface DemoTestResult {\n input: number;\n output: string;\n}\n\nfunction parseTestReport(content: string | Buffer): DemoTestResult[] | null {\n const text = Buffer.isBuffer(content) ? content.toString(\"utf8\") : content;\n let parsed: unknown;\n try {\n parsed = JSON.parse(text);\n } catch {\n return null;\n }\n if (typeof parsed !== \"object\" || parsed === null) {\n return null;\n }\n const tests = (parsed as { tests?: unknown }).tests;\n if (!Array.isArray(tests)) {\n return null;\n }\n const results: DemoTestResult[] = [];\n for (const t of tests) {\n if (typeof t !== \"object\" || t === null) {\n return null;\n }\n const { input, output } = t as { input?: unknown; output?: unknown };\n if (typeof input !== \"number\" || typeof output !== \"string\") {\n return null;\n }\n results.push({ input, output });\n }\n return results;\n}\n\n/**\n * The BUYER's independent recompute of the demo acceptance, as a score in [0, 1].\n * It reads the substantive output (the delivered test outputs) and recomputes the\n * expected FizzBuzz result for each; it deliberately IGNORES any self-reported\n * pass/coverage in the deliverable, so release can never be worker-controlled\n * (consult C10). Semantics:\n * - Any delivered test whose output is wrong = the suite did not pass (exit != 0):\n * score 0, no matter how much of the battery is covered.\n * - Otherwise the score is coverage = (distinct battery inputs delivered) / (battery\n * size); the buyer releases when it clears {@link RIDGES_DEMO_COVERAGE_TARGET}.\n * Malformed or unparseable content scores 0 and never throws.\n */\nexport function scoreRidgesDemoDeliverable(content: string | Buffer): number {\n const results = parseTestReport(content);\n if (results === null) {\n return 0;\n }\n const battery = new Set(DEMO_INPUTS);\n const coveredInputs = new Set<number>();\n for (const { input, output } of results) {\n if (!battery.has(input)) {\n // A result outside the battery does not fail the suite and does not count\n // toward coverage; it is simply ignored.\n continue;\n }\n if (output !== fizzbuzz(input)) {\n // A failing test = non-zero exit: the whole suite is rejected.\n return 0;\n }\n coveredInputs.add(input);\n }\n return coveredInputs.size / DEMO_INPUTS.length;\n}\n\n// A generic (non-demo) coding job produces a placeholder solution+report so a fresh\n// worker returns a well-formed ServiceResult before a real Ridges agent is wired.\nfunction referencePlaceholder(spec: TaskSpec): string {\n return canonicalize({\n language: \"typescript\",\n solution: \"// reference stub - replace the runAgent port with a real Ridges agent call.\",\n passed: false,\n tests: [],\n taskType: spec.taskType,\n });\n}\n\nconst defaultRunAgent: RunCodingAgent = (spec) =>\n Promise.resolve(\n spec.metadata.demo === RIDGES_DEMO_MARKER ? solveRidgesDemo() : referencePlaceholder(spec),\n );\n\nconst defaultPin: PinContent = (content) =>\n Promise.resolve(`ipfs://placeholder-${sha256Hex(content).slice(0, 16)}`);\n\n/**\n * Build a Ridges {@link ServiceAdapter}. Passes `assertServiceAdapterContract` with\n * the default ports; supply real ports for production use.\n */\nexport function createRidgesAdapter(config: RidgesAdapterConfig = {}): ServiceAdapter {\n const service = config.service ?? DEFAULT_SERVICE;\n const capabilities = config.capabilities ?? [...RIDGES_CAPABILITIES];\n const runAgent = config.runAgent ?? defaultRunAgent;\n const pin = config.pin ?? defaultPin;\n const checkHealth = config.checkHealth ?? ((): Promise<boolean> => Promise.resolve(true));\n\n return {\n id: service,\n capabilities,\n healthCheck: checkHealth,\n async execute(spec: TaskSpec): Promise<ServiceResult> {\n // 1. Run the coding agent and collect the test report (USD-billed; no swap).\n const content = await runAgent(spec);\n // 2. Hash and pin. The result the escrow records is currency-free.\n const contentHash = sha256Hex(content);\n const proofUri = await pin(content);\n return {\n content,\n contentHash,\n proofUri,\n metadata: { adapter: service },\n };\n },\n };\n}\n","/**\n * 404gen (Bittensor SN17) ServiceAdapter: a batch 3D-generation reference adapter,\n * built to the pattern the shipped Gradients (SN56) adapter established (P6.T6a). A\n * Worker Bot wraps the 404gen text-to-3D subnet behind the `ServiceAdapter` interface:\n * it swaps a per-task USDC budget into TAO internally, pays subnet miners in TAO to\n * generate a batch of 3D assets, collects the batch deliverable, and returns a\n * currency-free `ServiceResult`. The Buyer and the escrow contract only ever see USDC;\n * no TAO-typed value crosses this boundary into SDK core (ARCHITECTURE §3, §7; see\n * ../bittensor/bittensor.type-test.ts for the compile-time proof shared by the Bittensor trio).\n *\n * The swap, subnet call, and pinning are injectable ports so the reference runs (and\n * is tested) without a live DEX, subnet, or IPFS node. A production worker supplies\n * real implementations (Jupiter for the swap, the SN17 dendrite, Pinata/Arweave).\n *\n * RELEASE JUDGMENT IS NOT HERE. This adapter only PRODUCES the deliverable (a batch of\n * 3D assets, each with a declared container format and polygon count). Whether the batch\n * is acceptable is decided by the BUYER's review.ts. For the canned demo the buyer knows\n * the exact expected artifact (the eval-threshold review re-verifies the fetched\n * deliverable hashes to the submitted contentHash) and additionally gates on the declared\n * per-asset descriptors via `score404genDemoDeliverable` (format, polygon range, batch\n * completeness). That recompute reads the DECLARED descriptors, not the asset bytes: a\n * production 404gen buyer generating novel assets must derive the container from the\n * fetched asset's magic bytes and the polygon count from its parsed geometry before\n * releasing. The worker never scores-for-release and never releases (CLAUDE.md framing).\n *\n * The USDC->TAO port skeleton and the execute shape are shared with the other Bittensor\n * adapters via `../bittensor/index.js`; this module supplies only its subnet identity,\n * capabilities, budget, and demo logic.\n */\nimport { canonicalize, type TaskSpec } from \"@escro/shared\";\n\nimport type { ServiceAdapter } from \"../../adapter.js\";\nimport {\n createBittensorSubnetAdapter,\n defaultPin,\n defaultSwap,\n type PinContent,\n type SubnetCall,\n type UsdcToTaoSwap,\n} from \"../bittensor/index.js\";\n\n/** Configuration and injectable ports for {@link create404genAdapter}. */\nexport interface Gen404AdapterConfig {\n /** Subnet identifier. Defaults to \"sn17\" (404gen); forms the adapter id `bittensor:<subnet>`. */\n subnet?: string;\n /** Advertised capabilities for EscroBots discovery. Defaults to `[\"3d-generation\"]`. */\n capabilities?: string[];\n /** μUSDC the worker allocates to a single task before converting to TAO (internal budgeting). */\n taskBudgetMicroUsdc?: number;\n /** Swap port. Default: a fixed-rate reference stub. */\n swap?: UsdcToTaoSwap;\n /** Subnet-call port. Default: solves the canned demo job; a deterministic placeholder otherwise. */\n callSubnet?: SubnetCall;\n /** Pinning port. Default: a deterministic `ipfs://` placeholder URI. */\n pin?: PinContent;\n /** Health-check port. Default: resolves `true`. */\n checkHealth?: () => Promise<boolean>;\n}\n\n/** Stable id/capabilities, to be locked against `ADAPTER_DESCRIPTORS[\"404gen\"]` by a kit test at merge (consult C2). */\nexport const GEN404_ADAPTER_ID = \"bittensor:sn17\";\nexport const GEN404_CAPABILITIES = [\"3d-generation\"] as const;\n\nconst DEFAULT_SUBNET = \"sn17\";\nconst DEFAULT_TASK_BUDGET_MICRO_USDC = 5_000_000;\n\n// ---------------------------------------------------------------------------\n// Canned demo job (BOT_KIT_PRD §6 / §13): a deterministic batch 3D job the buyer\n// template's 5-minute journey hires this bot for. The batch requests one asset with\n// a machine-checkable format + polygon-count contract. Acceptance is recomputed by\n// the BUYER (see score404genDemoDeliverable): each declared asset's format must be an\n// allowed container, its declared polygon count must fall in range, and the batch must\n// be complete. Any self-reported eval score is ignored (a production buyer parses the\n// actual asset geometry - see the module note).\n// ---------------------------------------------------------------------------\n\n/** Stable marker on the demo spec's metadata so the default subnet stub recognizes it. */\nexport const GEN404_DEMO_MARKER = \"404gen-sn17-demo-v1\";\n\n/** The demo eval floor: the batch must be complete and every asset valid (score 1). */\nexport const GEN404_DEMO_EVAL_FLOOR = 1;\n\n/** The demo batch contract: what the buyer independently checks each asset against. */\ninterface BatchExpectation {\n /** Number of assets the batch must contain to be complete. */\n requestedAssets: number;\n /** Container formats the buyer accepts (compared case-insensitively). */\n allowedFormats: readonly string[];\n /** Inclusive polygon-count bounds a valid asset must fall within. */\n minPolygons: number;\n maxPolygons: number;\n}\n\nconst DEMO_EXPECTATION: BatchExpectation = {\n requestedAssets: 1,\n allowedFormats: [\"GLB\", \"PLY\"],\n minPolygons: 1_000,\n maxPolygons: 1_000_000,\n};\n\n/**\n * The canned 404gen demo job. Deterministic; its specHash is pinned by a test\n * (consult C8) because the buyer journey depends on hash stability.\n */\nexport const gen404DemoJobSpec: TaskSpec = {\n version: \"1.0.0\",\n // TaskType has no 3D category; \"custom\" is the canonical fallback.\n taskType: \"custom\",\n description:\n \"Generate the canned SN17 demo batch: one 3D asset in a GLB or PLY container with a \" +\n \"polygon count between 1000 and 1000000. Acceptance is deterministic and recomputed \" +\n \"by the buyer: every requested asset must be present, in an allowed format, and in \" +\n \"polygon range; the worker's self-reported validity is not trusted.\",\n acceptanceCriteria: [\n {\n id: \"ac-format-valid\",\n description:\n \"Every asset is in an allowed container format (GLB or PLY), recomputed by the buyer.\",\n required: true,\n },\n {\n id: \"ac-polygon-range\",\n description:\n \"Every asset's polygon count is within [1000, 1000000], recomputed by the buyer.\",\n required: true,\n },\n {\n id: \"ac-batch-complete\",\n description:\n \"The batch contains all requested assets (completeness), recomputed by the buyer.\",\n required: true,\n },\n ],\n deliverableFormat: { type: \"json\" },\n metadata: {\n demo: GEN404_DEMO_MARKER,\n requestedAssets: DEMO_EXPECTATION.requestedAssets,\n allowedFormats: [...DEMO_EXPECTATION.allowedFormats],\n minPolygons: DEMO_EXPECTATION.minPolygons,\n maxPolygons: DEMO_EXPECTATION.maxPolygons,\n },\n};\n\n/**\n * The reference solution to the demo job: a complete batch of valid assets plus a\n * (self-reported, buyer-ignored) eval block, as canonical JSON. Deterministic.\n * Exposed so the demo journey and tests share one source of the expected artifact.\n */\nexport function solveGen404Demo(): string {\n return canonicalize({\n assets: [{ format: \"GLB\", polygonCount: 5_000, uri: \"ipfs://404gen-sn17-demo-asset-0\" }],\n eval: { metric: \"validity\", score: 1 },\n });\n}\n\ninterface DemoAsset {\n format: string;\n polygonCount: number;\n}\n\ninterface DemoBatch {\n assets: DemoAsset[];\n}\n\nfunction parseBatch(content: string | Buffer): DemoBatch | null {\n const text = Buffer.isBuffer(content) ? content.toString(\"utf8\") : content;\n let parsed: unknown;\n try {\n parsed = JSON.parse(text);\n } catch {\n return null;\n }\n if (typeof parsed !== \"object\" || parsed === null) {\n return null;\n }\n const assets = (parsed as { assets?: unknown }).assets;\n if (!Array.isArray(assets)) {\n return null;\n }\n const cleaned: DemoAsset[] = [];\n for (const asset of assets) {\n if (typeof asset !== \"object\" || asset === null) {\n return null;\n }\n const format = (asset as { format?: unknown }).format;\n const polygonCount = (asset as { polygonCount?: unknown }).polygonCount;\n if (typeof format !== \"string\" || typeof polygonCount !== \"number\") {\n return null;\n }\n cleaned.push({ format, polygonCount });\n }\n return { assets: cleaned };\n}\n\nfunction isAssetValid(asset: DemoAsset): boolean {\n const formatOk = DEMO_EXPECTATION.allowedFormats.some(\n (f) => f.toLowerCase() === asset.format.toLowerCase(),\n );\n const rangeOk =\n asset.polygonCount >= DEMO_EXPECTATION.minPolygons &&\n asset.polygonCount <= DEMO_EXPECTATION.maxPolygons;\n return formatOk && rangeOk;\n}\n\n/**\n * The BUYER's recompute of the demo batch score in [0, 1] over the deliverable's\n * DECLARED per-asset descriptors. Every delivered asset must pass the format and\n * polygon-range checks (any single invalid asset scores 0, so a well-formed but junk\n * extra cannot slip through), and the batch must contain at least the requested count\n * (completeness); a short batch scores the filled fraction. Any self-reported `eval`\n * score in the deliverable is ignored. Malformed or unparseable content scores 0 and\n * never throws.\n *\n * NOTE: this gates the deliverable's declared `format`/`polygonCount` fields, not the\n * asset bytes. For the deterministic canned demo that is sufficient because the buyer\n * additionally knows the exact expected artifact (the eval-threshold review re-verifies\n * the fetched deliverable hashes to the submitted contentHash). A production 404gen\n * buyer generating NOVEL assets must derive the container from the fetched asset's magic\n * bytes and the polygon count from its parsed geometry before releasing (kit-docs debt).\n */\nexport function score404genDemoDeliverable(content: string | Buffer): number {\n const batch = parseBatch(content);\n if (batch === null) {\n return 0;\n }\n if (batch.assets.some((asset) => !isAssetValid(asset))) {\n return 0;\n }\n return Math.min(batch.assets.length / DEMO_EXPECTATION.requestedAssets, 1);\n}\n\n// A generic (non-demo) batch produces a placeholder asset so a fresh worker returns a\n// well-formed ServiceResult before a real SN17 miner is wired.\nfunction referencePlaceholder(spec: TaskSpec): string {\n return canonicalize({\n assets: [{ format: \"GLB\", polygonCount: 0, uri: \"ipfs://placeholder\" }],\n note: \"reference stub - replace the callSubnet port with a real SN17 miner call.\",\n taskType: spec.taskType,\n });\n}\n\nconst defaultCallSubnet: SubnetCall = (spec) =>\n Promise.resolve(\n spec.metadata.demo === GEN404_DEMO_MARKER ? solveGen404Demo() : referencePlaceholder(spec),\n );\n\n/**\n * Build a 404gen (SN17) {@link ServiceAdapter}. Passes `assertServiceAdapterContract`\n * with the default ports; supply real ports for production use. The USDC->TAO swap,\n * pinning, and execute skeleton come from the shared Bittensor core.\n */\nexport function create404genAdapter(config: Gen404AdapterConfig = {}): ServiceAdapter {\n return createBittensorSubnetAdapter({\n subnet: config.subnet ?? DEFAULT_SUBNET,\n capabilities: config.capabilities ?? [...GEN404_CAPABILITIES],\n taskBudgetMicroUsdc: config.taskBudgetMicroUsdc ?? DEFAULT_TASK_BUDGET_MICRO_USDC,\n swap: config.swap ?? defaultSwap,\n callSubnet: config.callSubnet ?? defaultCallSubnet,\n pin: config.pin ?? defaultPin,\n checkHealth: config.checkHealth ?? ((): Promise<boolean> => Promise.resolve(true)),\n });\n}\n","/**\n * Lium (Bittensor SN51) ServiceAdapter: a SHIPPED, supported adapter following the\n * P6.T6a Gradients pattern. A Worker Bot wraps the Lium GPU-compute subnet behind the\n * `ServiceAdapter` interface: it swaps a per-task USDC budget into TAO internally,\n * rents GPU compute from subnet miners in TAO to run the job, collects the output\n * artifact, and returns a currency-free `ServiceResult`. The Buyer and the escrow\n * contract only ever see USDC; no TAO-typed value crosses this boundary into SDK core\n * (ARCHITECTURE §3, §7; see ../bittensor/bittensor.type-test.ts for the compile-time\n * proof shared by the Bittensor trio).\n *\n * The swap, GPU-job call, and pinning are injectable ports so the reference runs (and\n * is tested) without a live DEX, subnet, or IPFS node. A production worker supplies\n * real implementations (Jupiter for the swap, the SN51 GPU-rental dendrite,\n * Pinata/Arweave for pinning).\n *\n * RELEASE JUDGMENT IS NOT HERE. This adapter only PRODUCES the deliverable (the job's\n * output artifact). Whether the job completed with a matching artifact is decided by\n * the BUYER's review.ts, which independently recomputes the scripted job's output and\n * compares hashes (see `scoreLiumDemoDeliverable`). The worker never scores-for-release\n * and never releases, and its self-reported `artifactHash` is never trusted\n * (CLAUDE.md product framing: the buyer is the judge).\n *\n * The USDC->TAO port skeleton and the execute shape are shared with the other Bittensor\n * adapters via `../bittensor/index.js`; this module supplies only its subnet identity,\n * capabilities, budget, and demo logic. A GPU-rental call is a paid subnet call, so its\n * port reuses the shared `SubnetCall` shape under the local `RunGpuJob` name.\n */\nimport { canonicalize, type TaskSpec } from \"@escro/shared\";\n\nimport type { ServiceAdapter } from \"../../adapter.js\";\nimport {\n createBittensorSubnetAdapter,\n defaultPin,\n defaultSwap,\n sha256Hex,\n type PinContent,\n type SubnetCall,\n type UsdcToTaoSwap,\n} from \"../bittensor/index.js\";\n\n/** Rent GPU compute for `budget` TAO and run `spec`'s job; resolve with the raw output artifact. */\nexport type RunGpuJob = SubnetCall;\n\n/** Configuration and injectable ports for {@link createLiumAdapter}. */\nexport interface LiumAdapterConfig {\n /** Subnet identifier. Defaults to \"sn51\" (Lium GPU compute); forms the adapter id `bittensor:<subnet>`. */\n subnet?: string;\n /** Advertised capabilities for EscroBots discovery. Defaults to `[\"gpu-compute\"]`. */\n capabilities?: string[];\n /** μUSDC the worker allocates to a single task before converting to TAO (internal budgeting). */\n taskBudgetMicroUsdc?: number;\n /** Swap port. Default: a fixed-rate reference stub. */\n swap?: UsdcToTaoSwap;\n /** GPU-job port. Default: runs the canned demo job; a deterministic placeholder otherwise. */\n runJob?: RunGpuJob;\n /** Pinning port. Default: a deterministic `ipfs://` placeholder URI. */\n pin?: PinContent;\n /** Health-check port. Default: resolves `true`. */\n checkHealth?: () => Promise<boolean>;\n}\n\n// Stable id/capabilities. The adapter's own tests pin its runtime output to these\n// constants; the main-owned kit seam test (`create-escro-bot/src/adapter-seam.test.ts`)\n// cross-checks them against `ADAPTER_DESCRIPTORS.lium` so the registry descriptor and the\n// shipped adapter cannot drift apart (consult C2).\nexport const LIUM_ADAPTER_ID = \"bittensor:sn51\";\nexport const LIUM_CAPABILITIES = [\"gpu-compute\"] as const;\n\nconst DEFAULT_SUBNET = \"sn51\";\nconst DEFAULT_TASK_BUDGET_MICRO_USDC = 20_000_000;\n\n// ---------------------------------------------------------------------------\n// Canned demo job (BOT_KIT_PRD §6 / §13): a 5-minute scripted GPU job the buyer\n// template's journey hires this bot for. The \"GPU job\" is a deterministic hash\n// chain over a fixed seed, so its output artifact is reproducible: the buyer\n// RECOMPUTES it independently (see scoreLiumDemoDeliverable) and releases only when\n// the job completed, an artifact is present, and its hash matches. The worker's\n// self-reported artifactHash is never trusted.\n// ---------------------------------------------------------------------------\n\n/** Stable marker on the demo spec's metadata so the default job stub recognizes it. */\nexport const LIUM_DEMO_MARKER = \"lium-sn51-demo-v1\";\n\n/** The demo accept floor: hash-match is exact, so the buyer requires a full match. */\nexport const LIUM_DEMO_ACCEPT_FLOOR = 1;\n\nconst DEMO_SEED = \"lium-sn51-demo-seed\";\nconst DEMO_ROUNDS = 1000;\n\n/**\n * The scripted GPU job's deterministic output artifact: a hash chain over the fixed\n * seed. Deterministic and cheap to recompute, so the buyer can verify it independently.\n */\nexport function computeLiumDemoArtifact(): string {\n let h = DEMO_SEED;\n for (let i = 0; i < DEMO_ROUNDS; i++) {\n h = sha256Hex(h);\n }\n return h;\n}\n\n/**\n * The canned Lium demo job. Deterministic; its specHash is pinned by a test (consult\n * C8) because the buyer journey depends on hash stability.\n */\nexport const liumDemoJobSpec: TaskSpec = {\n version: \"1.0.0\",\n // TaskType has no GPU-compute category; \"custom\" is the canonical fallback.\n taskType: \"custom\",\n description:\n \"Run the canned SN51 scripted GPU job (a fixed hash-chain compute over a known \" +\n \"seed) and return its output artifact. Acceptance is deterministic and recomputed \" +\n \"by the buyer: the job must complete, an output artifact must be present, and the \" +\n \"artifact must match the buyer's independent recompute; the worker's self-reported \" +\n \"artifact hash is not trusted.\",\n acceptanceCriteria: [\n {\n id: \"ac-completion\",\n description: \"The scripted job ran to completion (status=completed).\",\n required: true,\n },\n {\n id: \"ac-artifact-present\",\n description: \"An output artifact is present in the deliverable.\",\n required: true,\n },\n {\n id: \"ac-hash-match\",\n description:\n \"The output artifact matches the buyer's independent recompute of the scripted job.\",\n required: true,\n },\n ],\n deliverableFormat: { type: \"json\" },\n metadata: {\n demo: LIUM_DEMO_MARKER,\n seed: DEMO_SEED,\n rounds: DEMO_ROUNDS,\n acceptFloor: LIUM_DEMO_ACCEPT_FLOOR,\n },\n};\n\n/**\n * The reference solution to the demo job: the completed job report carrying the\n * correct output artifact plus a (self-reported, buyer-ignored) artifactHash, as\n * canonical JSON. Deterministic. Exposed so the demo journey and tests share one\n * source of the expected artifact.\n */\nexport function solveLiumDemo(): string {\n const artifact = computeLiumDemoArtifact();\n return canonicalize({\n job: LIUM_DEMO_MARKER,\n status: \"completed\",\n rounds: DEMO_ROUNDS,\n artifact,\n // Self-reported and deliberately ignored by the buyer's recompute.\n artifactHash: sha256Hex(artifact),\n });\n}\n\ninterface DemoDeliverable {\n status: string;\n artifact: string | null;\n}\n\nfunction parseDemoDeliverable(content: string | Buffer): DemoDeliverable | null {\n const text = Buffer.isBuffer(content) ? content.toString(\"utf8\") : content;\n let parsed: unknown;\n try {\n parsed = JSON.parse(text);\n } catch {\n return null;\n }\n if (typeof parsed !== \"object\" || parsed === null) {\n return null;\n }\n const obj = parsed as { status?: unknown; artifact?: unknown };\n const status = typeof obj.status === \"string\" ? obj.status : \"\";\n const artifact = typeof obj.artifact === \"string\" ? obj.artifact : null;\n return { status, artifact };\n}\n\n/**\n * The BUYER's independent recompute of the demo acceptance predicate, returning 1\n * when the deliverable satisfies all three criteria and 0 otherwise. It checks\n * completion (status), artifact presence, and hash match by RECOMPUTING the scripted\n * job's output and comparing the substantive artifact; it deliberately IGNORES any\n * self-reported `artifactHash`, so release can never be worker-controlled (consult\n * C10). Malformed or unparseable content scores 0 and never throws.\n */\nexport function scoreLiumDemoDeliverable(content: string | Buffer): number {\n const parsed = parseDemoDeliverable(content);\n if (parsed === null) {\n return 0;\n }\n if (parsed.status !== \"completed\") {\n return 0;\n }\n if (parsed.artifact === null) {\n return 0;\n }\n return parsed.artifact === computeLiumDemoArtifact() ? 1 : 0;\n}\n\n// A generic (non-demo) GPU job produces a placeholder completion report so a fresh\n// worker returns a well-formed ServiceResult before a real SN51 miner is wired.\nfunction referencePlaceholder(spec: TaskSpec): string {\n return canonicalize({\n job: \"lium-sn51-generic\",\n status: \"completed\",\n artifact: null,\n note: \"reference stub - replace the runJob port with a real SN51 GPU-rental call.\",\n taskType: spec.taskType,\n });\n}\n\nconst defaultRunJob: RunGpuJob = (spec) =>\n Promise.resolve(\n spec.metadata.demo === LIUM_DEMO_MARKER ? solveLiumDemo() : referencePlaceholder(spec),\n );\n\n/**\n * Build a Lium (SN51) {@link ServiceAdapter}. Passes `assertServiceAdapterContract`\n * with the default ports; supply real ports for production use. The USDC->TAO swap,\n * pinning, and execute skeleton come from the shared Bittensor core; the GPU-rental\n * port is wired in as the core's `callSubnet`.\n */\nexport function createLiumAdapter(config: LiumAdapterConfig = {}): ServiceAdapter {\n return createBittensorSubnetAdapter({\n subnet: config.subnet ?? DEFAULT_SUBNET,\n capabilities: config.capabilities ?? [...LIUM_CAPABILITIES],\n taskBudgetMicroUsdc: config.taskBudgetMicroUsdc ?? DEFAULT_TASK_BUDGET_MICRO_USDC,\n swap: config.swap ?? defaultSwap,\n callSubnet: config.runJob ?? defaultRunJob,\n pin: config.pin ?? defaultPin,\n checkHealth: config.checkHealth ?? ((): Promise<boolean> => Promise.resolve(true)),\n });\n}\n","/**\n * Akash (Cosmos) ServiceAdapter: a SHIPPED, supported reference adapter that extends the\n * ServiceAdapter library beyond Bittensor (ROADMAP P8, ARCHITECTURE §7). A Worker Bot\n * wraps an Akash deployment behind the `ServiceAdapter` interface: it swaps a per-task\n * USDC budget into AKT internally, provisions a deployment/lease on the Akash decentralized\n * cloud (paying providers in AKT), runs the compute job, collects the output artifact, and\n * returns a currency-free `ServiceResult`. The Buyer and the escrow contract only ever see\n * USDC; no AKT-typed value crosses this boundary into SDK core (ARCHITECTURE §3, §7; see\n * ./akash.type-test.ts for the compile-time proof).\n *\n * Akash is Cosmos-based and billed in its own token (AKT), so -- like the Bittensor trio --\n * it converts USDC internally. But it is NOT a Bittensor subnet (its id is a bare \"akash\",\n * not `bittensor:<subnet>`), so it does not use the `adapters/bittensor` core: it carries\n * its own branded `Akt`, its own swap port, and its own copy of the boundary proof.\n *\n * The swap, deployment call, and pinning are injectable ports so the reference runs (and is\n * tested) without a live DEX, Akash provider, or IPFS node. A production worker supplies\n * real implementations (a DEX/CEX route for the USDC->AKT swap, the Akash SDL/lease flow for\n * the deployment, Pinata/Arweave for pinning). The swap default is a fixed reference rate,\n * not a live price feed -- no price-feed dependency is introduced anywhere in SDK core\n * (CLAUDE.md product framing forbids a price feed in the contract; the reference rate here is\n * a nominal constant a real worker replaces with its own routing).\n *\n * RELEASE JUDGMENT IS NOT HERE. This adapter only PRODUCES the deliverable (the job's output\n * artifact). Whether the job completed with a matching artifact is decided by the BUYER's\n * review.ts, which independently recomputes the scripted job's output and compares hashes\n * (see `scoreAkashDemoDeliverable`). The worker never scores-for-release and never releases,\n * and its self-reported `artifactHash` is never trusted (CLAUDE.md product framing: the buyer\n * is the judge).\n */\nimport { createHash } from \"crypto\";\n\nimport { canonicalize, type TaskSpec } from \"@escro/shared\";\n\nimport type { ServiceAdapter, ServiceResult } from \"../../adapter.js\";\n\n/**\n * Amount denominated in AKT (Akash's token). Branded so it cannot be assigned to or from a\n * plain `number` by accident and (the point of the brand) so it can never appear in a\n * `ServiceResult` or the escrow submit path: those types have no field of this type. AKT\n * exists ONLY inside the Akash adapter layer.\n */\nexport type Akt = number & { readonly __brand: \"AKT\" };\n\n/** Construct an {@link Akt} amount from a plain number. Adapter-internal use only. */\nexport function akt(amount: number): Akt {\n return amount as Akt;\n}\n\n/** Swap a microUSDC budget into AKT. Real workers route this through a DEX/CEX. */\nexport type UsdcToAktSwap = (microUsdc: number) => Promise<Akt>;\n\n/**\n * Provision an Akash deployment/lease funded with `budget` AKT to run `spec`; resolve with\n * the raw deliverable (the job's output artifact).\n */\nexport type RunAkashDeployment = (spec: TaskSpec, budget: Akt) => Promise<string | Buffer>;\n\n/** Pin `content` and resolve with a content-addressed proof URI (ipfs://, ar://). */\nexport type PinContent = (content: string | Buffer) => Promise<string>;\n\nfunction sha256Hex(content: string | Buffer): string {\n return createHash(\"sha256\").update(content).digest(\"hex\");\n}\n\n/**\n * Stable id/capabilities. The adapter's own tests pin its runtime output to these\n * constants; the EscroBots registry descriptor for `akash` is registered separately in\n * P8.T6 (capability taxonomy extension).\n */\nexport const AKASH_ADAPTER_ID = \"akash\";\nexport const AKASH_CAPABILITIES = [\"cloud-compute\"] as const;\n\nconst DEFAULT_TASK_BUDGET_MICRO_USDC = 10_000_000;\n\n// Nominal reference rate: microUSDC -> AKT. Only the stub swap cares about the exact value;\n// it is a fixed constant, never a live price feed (a real worker replaces the swap port).\nexport const REFERENCE_MICRO_USDC_PER_AKT = 3_000_000;\n\n/** Default fixed-rate reference swap. */\nconst defaultSwap: UsdcToAktSwap = (microUsdc) =>\n Promise.resolve(akt(microUsdc / REFERENCE_MICRO_USDC_PER_AKT));\n\n/** Default deterministic `ipfs://` placeholder pin. */\nconst defaultPin: PinContent = (content) =>\n Promise.resolve(`ipfs://placeholder-${sha256Hex(content).slice(0, 16)}`);\n\n/** Configuration and injectable ports for {@link createAkashAdapter}. */\nexport interface AkashAdapterConfig {\n /** Advertised capabilities for EscroBots discovery. Defaults to `[\"cloud-compute\"]`. */\n capabilities?: string[];\n /** μUSDC the worker allocates to a single task before converting to AKT (internal budgeting). */\n taskBudgetMicroUsdc?: number;\n /** Swap port. Default: a fixed-rate reference stub. */\n swap?: UsdcToAktSwap;\n /** Deployment port. Default: runs the canned demo job; a deterministic placeholder otherwise. */\n runDeployment?: RunAkashDeployment;\n /** Pinning port. Default: a deterministic `ipfs://` placeholder URI. */\n pin?: PinContent;\n /** Health-check port. Default: resolves `true`. */\n checkHealth?: () => Promise<boolean>;\n}\n\n// ---------------------------------------------------------------------------\n// Canned demo job: a deterministic batch compute job the buyer template's journey\n// hires this bot for. The \"compute job\" is a deterministic hash chain over a fixed\n// seed, so its output artifact is reproducible: the buyer RECOMPUTES it independently\n// (see scoreAkashDemoDeliverable) and releases only when the job completed, an artifact\n// is present, and its hash matches. The worker's self-reported artifactHash is never\n// trusted.\n// ---------------------------------------------------------------------------\n\n/** Stable marker on the demo spec's metadata so the default deployment stub recognizes it. */\nexport const AKASH_DEMO_MARKER = \"akash-demo-v1\";\n\n/** The demo accept floor: hash-match is exact, so the buyer requires a full match. */\nexport const AKASH_DEMO_ACCEPT_FLOOR = 1;\n\nconst DEMO_SEED = \"akash-demo-seed\";\nconst DEMO_ROUNDS = 1000;\n\n/**\n * The scripted batch job's deterministic output artifact: a hash chain over the fixed\n * seed. Deterministic and cheap to recompute, so the buyer can verify it independently.\n */\nexport function computeAkashDemoArtifact(): string {\n let h = DEMO_SEED;\n for (let i = 0; i < DEMO_ROUNDS; i++) {\n h = sha256Hex(h);\n }\n return h;\n}\n\n/**\n * The canned Akash demo job. Deterministic; its specHash is pinned by a test because the\n * buyer journey depends on hash stability.\n */\nexport const akashDemoJobSpec: TaskSpec = {\n version: \"1.0.0\",\n // TaskType has no cloud-compute category; \"custom\" is the canonical fallback.\n taskType: \"custom\",\n description:\n \"Run the canned Akash scripted batch job (a fixed hash-chain compute over a known \" +\n \"seed) on a deployment and return its output artifact. Acceptance is deterministic and \" +\n \"recomputed by the buyer: the job must complete, an output artifact must be present, and \" +\n \"the artifact must match the buyer's independent recompute; the worker's self-reported \" +\n \"artifact hash is not trusted.\",\n acceptanceCriteria: [\n {\n id: \"ac-completion\",\n description: \"The scripted job ran to completion (status=completed).\",\n required: true,\n },\n {\n id: \"ac-artifact-present\",\n description: \"An output artifact is present in the deliverable.\",\n required: true,\n },\n {\n id: \"ac-hash-match\",\n description:\n \"The output artifact matches the buyer's independent recompute of the scripted job.\",\n required: true,\n },\n ],\n deliverableFormat: { type: \"json\" },\n metadata: {\n demo: AKASH_DEMO_MARKER,\n seed: DEMO_SEED,\n rounds: DEMO_ROUNDS,\n acceptFloor: AKASH_DEMO_ACCEPT_FLOOR,\n },\n};\n\n/**\n * The reference solution to the demo job: the completed job report carrying the correct\n * output artifact plus a (self-reported, buyer-ignored) artifactHash, as canonical JSON.\n * Deterministic. Exposed so the demo journey and tests share one source of the expected\n * artifact.\n */\nexport function solveAkashDemo(): string {\n const artifact = computeAkashDemoArtifact();\n return canonicalize({\n job: AKASH_DEMO_MARKER,\n status: \"completed\",\n rounds: DEMO_ROUNDS,\n artifact,\n // Self-reported and deliberately ignored by the buyer's recompute.\n artifactHash: sha256Hex(artifact),\n });\n}\n\ninterface DemoDeliverable {\n status: string;\n artifact: string | null;\n}\n\nfunction parseDemoDeliverable(content: string | Buffer): DemoDeliverable | null {\n const text = Buffer.isBuffer(content) ? content.toString(\"utf8\") : content;\n let parsed: unknown;\n try {\n parsed = JSON.parse(text);\n } catch {\n return null;\n }\n if (typeof parsed !== \"object\" || parsed === null || Array.isArray(parsed)) {\n return null;\n }\n const obj = parsed as { status?: unknown; artifact?: unknown };\n const status = typeof obj.status === \"string\" ? obj.status : \"\";\n const artifact = typeof obj.artifact === \"string\" ? obj.artifact : null;\n return { status, artifact };\n}\n\n/**\n * The BUYER's independent recompute of the demo acceptance predicate, returning 1 when the\n * deliverable satisfies all three criteria and 0 otherwise. It checks completion (status),\n * artifact presence, and hash match by RECOMPUTING the scripted job's output and comparing\n * the substantive artifact; it deliberately IGNORES any self-reported `artifactHash`, so\n * release can never be worker-controlled. Malformed or unparseable content scores 0 and\n * never throws.\n */\nexport function scoreAkashDemoDeliverable(content: string | Buffer): number {\n const parsed = parseDemoDeliverable(content);\n if (parsed === null) {\n return 0;\n }\n if (parsed.status !== \"completed\") {\n return 0;\n }\n if (parsed.artifact === null) {\n return 0;\n }\n return parsed.artifact === computeAkashDemoArtifact() ? 1 : 0;\n}\n\n// A generic (non-demo) job produces a placeholder completion report so a fresh worker\n// returns a well-formed ServiceResult before a real Akash deployment is wired.\nfunction referencePlaceholder(spec: TaskSpec): string {\n return canonicalize({\n job: \"akash-generic\",\n status: \"completed\",\n artifact: null,\n note: \"reference stub - replace the runDeployment port with a real Akash deployment call.\",\n taskType: spec.taskType,\n });\n}\n\nconst defaultRunDeployment: RunAkashDeployment = (spec) =>\n Promise.resolve(\n spec.metadata.demo === AKASH_DEMO_MARKER ? solveAkashDemo() : referencePlaceholder(spec),\n );\n\n/**\n * Build an Akash {@link ServiceAdapter}. Passes `assertServiceAdapterContract` with the\n * default ports; supply real ports for production use. The execute skeleton: swap the USDC\n * budget into AKT (internal, never surfaced), provision the deployment and collect the\n * output, then hash and pin. The recorded `ServiceResult` is currency-free (no AKT field).\n */\nexport function createAkashAdapter(config: AkashAdapterConfig = {}): ServiceAdapter {\n const capabilities = config.capabilities ?? [...AKASH_CAPABILITIES];\n const taskBudgetMicroUsdc = config.taskBudgetMicroUsdc ?? DEFAULT_TASK_BUDGET_MICRO_USDC;\n const swap = config.swap ?? defaultSwap;\n const runDeployment = config.runDeployment ?? defaultRunDeployment;\n const pin = config.pin ?? defaultPin;\n const checkHealth = config.checkHealth ?? ((): Promise<boolean> => Promise.resolve(true));\n\n return {\n id: AKASH_ADAPTER_ID,\n capabilities,\n healthCheck: checkHealth,\n async execute(spec: TaskSpec): Promise<ServiceResult> {\n // 1. Swap the USDC budget into AKT (internal, never surfaced).\n const budgetAkt = await swap(taskBudgetMicroUsdc);\n // 2. Provision the Akash deployment (paid in AKT) and collect the deliverable.\n const content = await runDeployment(spec, budgetAkt);\n // 3. Hash and pin. The result the escrow records is currency-free.\n const contentHash = sha256Hex(content);\n const proofUri = await pin(content);\n return {\n content,\n contentHash,\n proofUri,\n metadata: { adapter: AKASH_ADAPTER_ID },\n };\n },\n };\n}\n","/**\n * Render Network ServiceAdapter: a SHIPPED, supported adapter for decentralized GPU\n * rendering (3D scenes, video frames, diffusion/inference jobs). A Worker Bot wraps a\n * Render Network job behind the `ServiceAdapter` interface: it swaps a per-task USDC\n * budget into RENDER internally, pays for the render job in RENDER, collects the\n * rendered output artifact, and returns a currency-free `ServiceResult`. The Buyer and\n * the escrow contract only ever see USDC; no RENDER-typed value crosses this boundary\n * into SDK core (ARCHITECTURE §3, §7; see ./render.type-test.ts for the compile-time\n * proof).\n *\n * Render is Solana-native with MINIMAL BRIDGING: RENDER is a Solana SPL token, so the\n * USDC->RENDER conversion is a same-chain DEX swap (e.g. Jupiter) with no cross-chain\n * bridge. This is the distinction from the Bittensor trio (gradients SN56, 404gen SN17,\n * lium SN51), whose TAO must be bridged off Solana to Bittensor. Because its token and\n * network differ, Render carries its own branded `Render` type and its own execute\n * skeleton and is deliberately NOT part of the shared `adapters/bittensor` core.\n *\n * No price feed lives in SDK core: the USDC->RENDER rate is an injectable `swap` port\n * defaulting to a deterministic fixed reference rate (see `defaultSwap`). A production\n * worker injects a real DEX route; SDK core embeds no live price feed. The swap,\n * render-job call, and pinning are injectable ports so the reference runs (and is\n * tested) without a live DEX, Render Network endpoint, or IPFS node.\n *\n * RELEASE JUDGMENT IS NOT HERE. This adapter only PRODUCES the deliverable (the rendered\n * frame). Whether the render is acceptable is decided by the BUYER's review.ts, which\n * independently RE-RENDERS the scripted demo scene and compares the substantive frame\n * (see `scoreRenderDemoDeliverable`). The worker never scores-for-release and never\n * releases, and its self-reported `frameHash` is never trusted (CLAUDE.md product\n * framing: the buyer is the judge).\n */\nimport { createHash } from \"crypto\";\n\nimport { canonicalize, type TaskSpec } from \"@escro/shared\";\n\nimport type { ServiceAdapter, ServiceResult } from \"../../adapter.js\";\n\n/**\n * Amount denominated in RENDER (Render Network's Solana SPL token). Branded so it cannot\n * be assigned to or from a plain `number` by accident and (the point of the brand) so it\n * can never appear in a `ServiceResult` or the escrow submit path: those types have no\n * field of this type. RENDER exists ONLY inside this adapter module.\n */\nexport type Render = number & { readonly __brand: \"RENDER\" };\n\n/** Construct a {@link Render} amount from a plain number. Adapter-internal use only. */\nexport function renderAmount(amount: number): Render {\n return amount as Render;\n}\n\n/** Swap a microUSDC budget into RENDER. Real workers route this through a Solana DEX (e.g. Jupiter). */\nexport type UsdcToRenderSwap = (microUsdc: number) => Promise<Render>;\n\n/** Submit `spec`'s render job funded with `budget` RENDER; resolve with the raw rendered artifact. */\nexport type RunRenderJob = (spec: TaskSpec, budget: Render) => Promise<string | Buffer>;\n\n/** Pin `content` and resolve with a content-addressed proof URI (ipfs://, ar://). */\nexport type PinContent = (content: string | Buffer) => Promise<string>;\n\n/** Configuration and injectable ports for {@link createRenderAdapter}. */\nexport interface RenderAdapterConfig {\n /** Service identifier. Defaults to \"render\"; forms the adapter id. */\n service?: string;\n /** Advertised capabilities for EscroBots discovery. Defaults to {@link RENDER_CAPABILITIES}. */\n capabilities?: string[];\n /** microUSDC the worker allocates to a single task before converting to RENDER (internal budgeting). */\n taskBudgetMicroUsdc?: number;\n /** Swap port. Default: a fixed-rate reference stub (no live price feed). */\n swap?: UsdcToRenderSwap;\n /** Render-job port. Default: renders the canned demo scene; a deterministic placeholder otherwise. */\n runJob?: RunRenderJob;\n /** Pinning port. Default: a deterministic `ipfs://` placeholder URI. */\n pin?: PinContent;\n /** Health-check port. Default: resolves `true`. */\n checkHealth?: () => Promise<boolean>;\n}\n\n// Stable id/capabilities. The adapter's own tests pin its runtime output to these\n// constants; at merge the main-owned kit seam test cross-checks them against the\n// registry descriptor (ADAPTER_DESCRIPTORS.render) so the descriptor and the shipped\n// adapter cannot drift apart (consult C2; coordinate with P8.T6 capability taxonomy).\nexport const RENDER_ADAPTER_ID = \"render\";\nexport const RENDER_CAPABILITIES = [\"3d-rendering\", \"video-rendering\", \"gpu-inference\"] as const;\n\nconst DEFAULT_SERVICE = \"render\";\nconst DEFAULT_TASK_BUDGET_MICRO_USDC = 15_000_000;\n\nfunction sha256Hex(content: string | Buffer): string {\n return createHash(\"sha256\").update(content).digest(\"hex\");\n}\n\n// Nominal reference rate: microUSDC -> RENDER. Only the stub swap cares about the exact\n// value; a production worker injects a real DEX route via the `swap` port.\nexport const REFERENCE_MICRO_USDC_PER_RENDER = 2_000_000;\n\n/** Default fixed-rate reference swap: a pure function of its input, no live price feed. */\nexport const defaultSwap: UsdcToRenderSwap = (microUsdc) =>\n Promise.resolve(renderAmount(microUsdc / REFERENCE_MICRO_USDC_PER_RENDER));\n\n/** Default deterministic `ipfs://` placeholder pin. */\nexport const defaultPin: PinContent = (content) =>\n Promise.resolve(`ipfs://placeholder-${sha256Hex(content).slice(0, 16)}`);\n\n// ---------------------------------------------------------------------------\n// Canned demo job (BOT_KIT_PRD §6 / §13): a 5-minute scripted render job the buyer\n// template's journey hires this bot for. The \"render\" is a deterministic procedural\n// raster (a fixed shader over a fixed-size frame), so its output artifact is\n// reproducible: the buyer RE-RENDERS it independently (see scoreRenderDemoDeliverable)\n// and releases only when the job completed, a frame is present, and the frame matches.\n// The worker's self-reported frameHash is never trusted.\n// ---------------------------------------------------------------------------\n\n/** Stable marker on the demo spec's metadata so the default job stub recognizes it. */\nexport const RENDER_DEMO_MARKER = \"render-demo-v1\";\n\n/** The demo accept floor: frame-match is exact, so the buyer requires a full match. */\nexport const RENDER_DEMO_ACCEPT_FLOOR = 1;\n\nconst DEMO_SCENE = \"render-demo-scene-v1\";\nconst DEMO_WIDTH = 16;\nconst DEMO_HEIGHT = 16;\n\n/**\n * The deterministic per-pixel shader for the demo scene: a fixed grayscale value in\n * [0, 255] for pixel (x, y). Pure and reproducible, so the buyer can re-render and\n * compare independently.\n */\nfunction shade(x: number, y: number): number {\n return (x * 53 + y * 97 + (x ^ y) * 29) & 0xff;\n}\n\n/**\n * Render the fixed demo scene into a grayscale raster and return its hex encoding.\n * Deterministic and cheap to recompute, so the buyer verifies the frame independently.\n */\nexport function computeRenderDemoArtifact(): string {\n const raster = Buffer.alloc(DEMO_WIDTH * DEMO_HEIGHT);\n let i = 0;\n for (let y = 0; y < DEMO_HEIGHT; y++) {\n for (let x = 0; x < DEMO_WIDTH; x++) {\n raster[i++] = shade(x, y);\n }\n }\n return raster.toString(\"hex\");\n}\n\n/**\n * The canned Render demo job. Deterministic; its specHash is pinned by a test because\n * the buyer journey depends on hash stability.\n */\nexport const renderDemoJobSpec: TaskSpec = {\n version: \"1.0.0\",\n taskType: \"image_generation\",\n description:\n \"Render the canned demo scene (a fixed procedural frame) and return the rendered \" +\n \"frame. Acceptance is deterministic and recomputed by the buyer: the job must \" +\n \"complete, a rendered frame must be present, and the frame must match the buyer's \" +\n \"independent re-render; the worker's self-reported frame hash is not trusted.\",\n acceptanceCriteria: [\n {\n id: \"ac-completion\",\n description: \"The render job ran to completion (status=completed).\",\n required: true,\n },\n {\n id: \"ac-frame-present\",\n description: \"A rendered frame is present in the deliverable.\",\n required: true,\n },\n {\n id: \"ac-frame-match\",\n description: \"The rendered frame matches the buyer's independent re-render of the scene.\",\n required: true,\n },\n ],\n deliverableFormat: { type: \"json\" },\n metadata: {\n demo: RENDER_DEMO_MARKER,\n scene: DEMO_SCENE,\n width: DEMO_WIDTH,\n height: DEMO_HEIGHT,\n acceptFloor: RENDER_DEMO_ACCEPT_FLOOR,\n },\n};\n\n/**\n * The reference solution to the demo job: the completed job report carrying the correct\n * rendered frame plus a (self-reported, buyer-ignored) frameHash, as canonical JSON.\n * Deterministic. Exposed so the demo journey and tests share one source of the expected\n * artifact.\n */\nexport function solveRenderDemo(): string {\n const frame = computeRenderDemoArtifact();\n return canonicalize({\n job: RENDER_DEMO_MARKER,\n status: \"completed\",\n width: DEMO_WIDTH,\n height: DEMO_HEIGHT,\n frame,\n // Self-reported and deliberately ignored by the buyer's recompute.\n frameHash: sha256Hex(frame),\n });\n}\n\ninterface DemoDeliverable {\n status: string;\n frame: string | null;\n}\n\nfunction parseDemoDeliverable(content: string | Buffer): DemoDeliverable | null {\n const text = Buffer.isBuffer(content) ? content.toString(\"utf8\") : content;\n let parsed: unknown;\n try {\n parsed = JSON.parse(text);\n } catch {\n return null;\n }\n if (typeof parsed !== \"object\" || parsed === null) {\n return null;\n }\n const obj = parsed as { status?: unknown; frame?: unknown };\n const status = typeof obj.status === \"string\" ? obj.status : \"\";\n const frame = typeof obj.frame === \"string\" ? obj.frame : null;\n return { status, frame };\n}\n\n/**\n * The BUYER's independent recompute of the demo acceptance predicate, returning 1 when\n * the deliverable satisfies all three criteria and 0 otherwise. It checks completion\n * (status), frame presence, and a frame match by RE-RENDERING the scripted scene and\n * comparing the substantive frame; it deliberately IGNORES any self-reported\n * `frameHash`, so release can never be worker-controlled (consult C10). Malformed or\n * unparseable content scores 0 and never throws.\n */\nexport function scoreRenderDemoDeliverable(content: string | Buffer): number {\n const parsed = parseDemoDeliverable(content);\n if (parsed === null) {\n return 0;\n }\n if (parsed.status !== \"completed\") {\n return 0;\n }\n if (parsed.frame === null) {\n return 0;\n }\n return parsed.frame === computeRenderDemoArtifact() ? 1 : 0;\n}\n\n// A generic (non-demo) render job produces a placeholder completion report so a fresh\n// worker returns a well-formed ServiceResult before a real Render Network job is wired.\nfunction referencePlaceholder(spec: TaskSpec): string {\n return canonicalize({\n job: \"render-generic\",\n status: \"completed\",\n frame: null,\n note: \"reference stub - replace the runJob port with a real Render Network job submission.\",\n taskType: spec.taskType,\n });\n}\n\nconst defaultRunJob: RunRenderJob = (spec) =>\n Promise.resolve(\n spec.metadata.demo === RENDER_DEMO_MARKER ? solveRenderDemo() : referencePlaceholder(spec),\n );\n\n/**\n * Build a Render {@link ServiceAdapter}. Passes `assertServiceAdapterContract` with the\n * default ports; supply real ports for production use. The execute skeleton: swap the\n * USDC budget into RENDER (internal, same-chain, never surfaced), pay the render job in\n * RENDER and collect the frame, then hash and pin. The recorded `ServiceResult` is\n * currency-free (no RENDER field).\n */\nexport function createRenderAdapter(config: RenderAdapterConfig = {}): ServiceAdapter {\n const service = config.service ?? DEFAULT_SERVICE;\n const capabilities = config.capabilities ?? [...RENDER_CAPABILITIES];\n const taskBudgetMicroUsdc = config.taskBudgetMicroUsdc ?? DEFAULT_TASK_BUDGET_MICRO_USDC;\n const swap = config.swap ?? defaultSwap;\n const runJob = config.runJob ?? defaultRunJob;\n const pin = config.pin ?? defaultPin;\n const checkHealth = config.checkHealth ?? ((): Promise<boolean> => Promise.resolve(true));\n\n return {\n id: service,\n capabilities,\n healthCheck: checkHealth,\n async execute(spec: TaskSpec): Promise<ServiceResult> {\n // 1. Swap the USDC budget into RENDER (internal, same-chain DEX; no bridge).\n const budgetRender = await swap(taskBudgetMicroUsdc);\n // 2. Pay for the render job in RENDER and collect the rendered frame.\n const content = await runJob(spec, budgetRender);\n // 3. Hash and pin. The result the escrow records is currency-free.\n const contentHash = sha256Hex(content);\n const proofUri = await pin(content);\n return {\n content,\n contentHash,\n proofUri,\n metadata: { adapter: service, network: \"render\" },\n };\n },\n };\n}\n","/**\n * Gensyn ServiceAdapter + REE-proof acceptance (Phase 8, P8.T4). Gensyn is a\n * network for VERIFIABLE compute: a worker runs a job in a Reproducible Execution\n * Environment (REE) and returns a proof that binds the task, the delivered output,\n * and a reproducible execution transcript. The novelty this task adds over the\n * Phase 6 adapters is buyer-side ACCEPTANCE by proof: the Buyer auto-releases iff\n * the REE proof verifies.\n *\n * The judgment is entirely BUYER-LAYER (this module, called by the buyer's bot),\n * exactly like `scoreGradientsDemoDeliverable` in the Gradients adapter. The\n * protocol still judges nothing: verification never enters the program or the\n * oracle (CLAUDE.md product framing). `zero-diff-guard.test.ts` pins that\n * packages/program and packages/oracle stay byte-for-byte unchanged.\n *\n * `verifyReeProof` is deliberately a BUYER recompute, mirroring the Gradients\n * pattern where the buyer re-derives the eval score rather than trusting the\n * worker's self-report: it re-runs the reproducible execution and checks the\n * worker's transcript hash against its own. A production Gensyn verifier would\n * replace the full recompute with Gensyn's interactive verification game over the\n * same `transcriptHash`; the acceptance contract (a proof binding spec, content,\n * and reproducible transcript) is unchanged.\n */\nimport { createHash } from \"crypto\";\n\nimport { canonicalize, type TaskSpec } from \"@escro/shared\";\n\nimport type { ServiceAdapter, ServiceResult } from \"../../adapter.js\";\n\n/** Stable adapter identity + EscroBots capability (locked by gensyn.test.ts). */\nexport const GENSYN_ADAPTER_ID = \"gensyn\";\nexport const GENSYN_CAPABILITIES = [\"verifiable-compute\"] as const;\n\n/** REE proof scheme tag. A verifier accepts only proofs carrying this exact scheme. */\nexport const GENSYN_REE_SCHEME = \"gensyn-ree-v1\";\n\n/** Marker on the demo spec's metadata so the default reproducible compute recognizes it. */\nexport const GENSYN_DEMO_MARKER = \"gensyn-ree-demo-v1\";\n\n/** The demo's fixed reproducible-execution parameters (a deterministic LCG walk). */\nexport const GENSYN_DEMO_SEED = 12345;\nexport const GENSYN_DEMO_STEPS = 16;\n\nfunction sha256Hex(content: string | Buffer): string {\n return createHash(\"sha256\").update(content).digest(\"hex\");\n}\n\n// ---------------------------------------------------------------------------\n// Reproducible execution: the deterministic computation the REE proof attests to.\n// A fixed linear congruential generator walked `steps` times from `seed`; the\n// ordered states are the transcript, the final state is the result. Deterministic\n// from the spec alone, so the buyer can reproduce it and confirm the worker's\n// transcript hash (the essence of a Reproducible Execution Environment).\n// ---------------------------------------------------------------------------\n\nconst LCG_MULT = 1103515245n;\nconst LCG_INC = 12345n;\nconst LCG_MOD = 1n << 31n;\n\n/** The result of one reproducible execution: its transcript and final output. */\nexport interface ReeExecution {\n /** Seed the walk started from. */\n seed: number;\n /** Number of steps walked. */\n steps: number;\n /** Ordered per-step states (the execution transcript). */\n states: number[];\n /** Final state (the deliverable's numeric result). */\n result: number;\n}\n\n/** Run the reproducible compute for `spec`, deriving the transcript and result. */\nexport type ReproduceCompute = (spec: TaskSpec) => ReeExecution;\n\nfunction readComputeParams(spec: TaskSpec): { seed: number; steps: number } {\n const rawSeed = spec.metadata.seed;\n const rawSteps = spec.metadata.steps;\n const seed =\n typeof rawSeed === \"number\" && Number.isInteger(rawSeed) ? rawSeed : GENSYN_DEMO_SEED;\n const steps =\n typeof rawSteps === \"number\" && Number.isInteger(rawSteps) && rawSteps > 0\n ? rawSteps\n : GENSYN_DEMO_STEPS;\n return { seed, steps };\n}\n\n/**\n * The reference reproducible execution. Deterministic from `spec` (its seed/steps\n * come from `spec.metadata`, defaulting to the demo parameters), so both worker and\n * buyer derive the same transcript.\n */\nexport const reproduceGensynCompute: ReproduceCompute = (spec) => {\n const { seed, steps } = readComputeParams(spec);\n const states: number[] = [];\n let x = BigInt(seed) % LCG_MOD;\n if (x < 0n) {\n x += LCG_MOD;\n }\n for (let i = 0; i < steps; i++) {\n x = (LCG_MULT * x + LCG_INC) % LCG_MOD;\n states.push(Number(x));\n }\n return { seed, steps, states, result: states[states.length - 1] ?? seed };\n};\n\n/** Serialize a reproducible execution's output into the deliverable content. */\nexport function gensynDeliverable(exec: ReeExecution): string {\n return canonicalize({ result: exec.result, steps: exec.steps });\n}\n\n// ---------------------------------------------------------------------------\n// REE proof\n// ---------------------------------------------------------------------------\n\n/**\n * A Gensyn REE proof. Every field is a commitment the buyer re-derives:\n * `commitment` binds the whole tuple, `outputHash` binds the delivered content,\n * `specHash` binds the task asked, `transcriptHash` binds the reproducible run.\n */\nexport interface ReeProof {\n scheme: typeof GENSYN_REE_SCHEME;\n /** SHA-256 hex of the canonical task spec. */\n specHash: string;\n /** SHA-256 hex of the delivered content. */\n outputHash: string;\n /** Number of reproducible execution steps (positive integer). */\n steps: number;\n /** SHA-256 hex of the canonical execution transcript. */\n transcriptHash: string;\n /** SHA-256 hex binding scheme, specHash, outputHash, steps, and transcriptHash. */\n commitment: string;\n}\n\ntype ReeProofBase = Omit<ReeProof, \"commitment\">;\n\n/** The single canonical binding the commitment (and its verification) is computed over. */\nfunction commitmentOf(base: ReeProofBase): string {\n return sha256Hex(\n [base.scheme, base.specHash, base.outputHash, String(base.steps), base.transcriptHash].join(\n \"\\n\",\n ),\n );\n}\n\n/**\n * Build the REE proof a worker attaches to its deliverable. Not a trust anchor on\n * its own: `verifyReeProof` re-derives every field, so a proof only accepts when it\n * genuinely binds the content, spec, and a reproducible transcript.\n */\nexport function buildReeProof(\n spec: TaskSpec,\n exec: ReeExecution,\n content: string | Buffer,\n): ReeProof {\n const base: ReeProofBase = {\n scheme: GENSYN_REE_SCHEME,\n specHash: sha256Hex(canonicalize(spec)),\n outputHash: sha256Hex(content),\n steps: exec.steps,\n transcriptHash: sha256Hex(canonicalize(exec.states)),\n };\n return { ...base, commitment: commitmentOf(base) };\n}\n\n/** The verifier's verdict: a proof is either valid, or invalid/malformed with a reason. */\nexport interface ReeVerification {\n valid: boolean;\n /** Prefixed `malformed` (shape/structure) or `invalid` (a binding failed), or a pass note. */\n reason: string;\n}\n\n/** Inputs the buyer verifies a proof against: the task asked and the content received. */\nexport interface ReeVerifyContext {\n /** The task spec the buyer commissioned. */\n spec: TaskSpec;\n /** The deliverable content the buyer received (fetched from proofUri in production). */\n content: string | Buffer;\n /** The reproducible compute; defaults to the reference {@link reproduceGensynCompute}. */\n reproduce?: ReproduceCompute;\n}\n\nconst HEX_64 = /^[0-9a-f]{64}$/;\n\nfunction isHex64(v: unknown): v is string {\n return typeof v === \"string\" && HEX_64.test(v);\n}\n\nfunction malformed(reason: string): ReeVerification {\n return { valid: false, reason: `malformed: ${reason}` };\n}\n\nfunction invalid(reason: string): ReeVerification {\n return { valid: false, reason: `invalid: ${reason}` };\n}\n\n/**\n * The BUYER's verification of an REE proof (untrusted input from the worker). Returns\n * `valid: true` only when the proof is well-formed AND every binding holds: the\n * commitment is self-consistent, the committed output hash equals the delivered\n * content, the spec hash equals the commissioned task, and the transcript hash\n * matches the buyer's own reproduction of the execution. Never throws.\n */\nexport function verifyReeProof(proof: unknown, ctx: ReeVerifyContext): ReeVerification {\n if (typeof proof !== \"object\" || proof === null) {\n return malformed(\"proof is not an object\");\n }\n const p = proof as Record<string, unknown>;\n\n if (p.scheme !== GENSYN_REE_SCHEME) {\n return malformed(`scheme must be \"${GENSYN_REE_SCHEME}\"`);\n }\n if (!isHex64(p.specHash)) {\n return malformed(\"specHash must be a 64-char lowercase hex string\");\n }\n if (!isHex64(p.outputHash)) {\n return malformed(\"outputHash must be a 64-char lowercase hex string\");\n }\n if (!isHex64(p.transcriptHash)) {\n return malformed(\"transcriptHash must be a 64-char lowercase hex string\");\n }\n if (!isHex64(p.commitment)) {\n return malformed(\"commitment must be a 64-char lowercase hex string\");\n }\n if (typeof p.steps !== \"number\" || !Number.isInteger(p.steps) || p.steps <= 0) {\n return malformed(\"steps must be a positive integer\");\n }\n\n const base: ReeProofBase = {\n scheme: GENSYN_REE_SCHEME,\n specHash: p.specHash,\n outputHash: p.outputHash,\n steps: p.steps,\n transcriptHash: p.transcriptHash,\n };\n\n if (commitmentOf(base) !== p.commitment) {\n return invalid(\"commitment does not bind the proof fields (tampered)\");\n }\n if (sha256Hex(ctx.content) !== p.outputHash) {\n return invalid(\"outputHash does not match the delivered content\");\n }\n if (sha256Hex(canonicalize(ctx.spec)) !== p.specHash) {\n return invalid(\"specHash does not match the commissioned task spec\");\n }\n const exec = (ctx.reproduce ?? reproduceGensynCompute)(ctx.spec);\n if (p.steps !== exec.steps) {\n return invalid(\"steps does not match the reproduced execution\");\n }\n if (sha256Hex(canonicalize(exec.states)) !== p.transcriptHash) {\n return invalid(\"transcriptHash is not reproducible from the task spec\");\n }\n // The load-bearing acceptance check: the delivered content must be the ACTUAL output\n // of the reproduced execution, not merely something the worker hashed into a\n // self-consistent proof. Without this, a worker could attach a valid proof to\n // arbitrary content (its outputHash would still equal the delivered garbage) and\n // trigger auto-release. Binding outputHash to the buyer's own reproduced deliverable\n // (and, via the check above, to the delivered content) closes that forgery.\n if (sha256Hex(gensynDeliverable(exec)) !== p.outputHash) {\n return invalid(\"outputHash does not match the reproduced deliverable\");\n }\n\n return {\n valid: true,\n reason:\n \"REE proof verified: commitment, spec, transcript, and the reproduced deliverable all bind to the delivered content.\",\n };\n}\n\n// ---------------------------------------------------------------------------\n// Buyer-layer auto-release\n// ---------------------------------------------------------------------------\n\n/** What the buyer assembles to decide acceptance: the received content and the worker's proof. */\nexport interface GensynDeliverableBundle {\n /** The deliverable content the buyer received. */\n content: string | Buffer;\n /** The REE proof the worker attached (untrusted; verified before any release). */\n proof: unknown;\n}\n\n/** A buyer auto-release decision. `release: true` means \"call release_payment()\". */\nexport interface AutoReleaseDecision {\n release: boolean;\n reason: string;\n}\n\n/**\n * The buyer bot's auto-release decision for a Gensyn deliverable. Releases ONLY when\n * the REE proof verifies against the delivered content and the commissioned spec;\n * an invalid or malformed proof never releases. This is the whole T4 acceptance\n * mechanism, and it lives entirely at the buyer layer.\n */\nexport function gensynAutoRelease(\n bundle: GensynDeliverableBundle,\n ctx: { spec: TaskSpec; reproduce?: ReproduceCompute },\n): AutoReleaseDecision {\n const verdict = verifyReeProof(bundle.proof, {\n spec: ctx.spec,\n content: bundle.content,\n ...(ctx.reproduce !== undefined && { reproduce: ctx.reproduce }),\n });\n return { release: verdict.valid, reason: verdict.reason };\n}\n\n// ---------------------------------------------------------------------------\n// Adapter (worker side)\n// ---------------------------------------------------------------------------\n\n/** Configuration and injectable ports for {@link createGensynAdapter}. */\nexport interface GensynAdapterConfig {\n /** Advertised capabilities for EscroBots discovery. Defaults to `[\"verifiable-compute\"]`. */\n capabilities?: string[];\n /** The reproducible compute the worker runs. Default: the reference LCG walk. */\n runCompute?: ReproduceCompute;\n /** Pinning port. Default: a deterministic `ipfs://` placeholder URI. */\n pin?: (content: string | Buffer) => Promise<string>;\n /** Health-check port. Default: resolves `true`. */\n checkHealth?: () => Promise<boolean>;\n}\n\n/** The canned demo job the buyer template's journey hires a Gensyn worker for. */\nexport const gensynDemoJobSpec: TaskSpec = {\n version: \"1.0.0\",\n taskType: \"custom\",\n description:\n \"Run the reference reproducible compute (a fixed LCG walk from the seed in \" +\n \"metadata) and return its final result. Acceptance is a valid gensyn-ree-v1 REE \" +\n \"proof: the buyer recomputes the transcript and confirms the proof binds the \" +\n \"delivered content, this spec, and the reproducible execution. The worker's \" +\n \"self-reported result is never trusted on its own.\",\n acceptanceCriteria: [\n {\n id: \"ac-ree-proof\",\n description:\n \"A valid gensyn-ree-v1 proof binding the delivered content, this spec, and a reproducible transcript.\",\n required: true,\n },\n ],\n deliverableFormat: { type: \"json\" },\n metadata: {\n demo: GENSYN_DEMO_MARKER,\n seed: GENSYN_DEMO_SEED,\n steps: GENSYN_DEMO_STEPS,\n },\n};\n\nconst defaultPin = (content: string | Buffer): Promise<string> =>\n Promise.resolve(`ipfs://gensyn-${sha256Hex(content).slice(0, 16)}`);\n\n/**\n * Build a Gensyn {@link ServiceAdapter}. `execute` runs the reproducible compute,\n * serializes the deliverable, and attaches an REE proof (in `metadata.reeProof`) the\n * buyer verifies with {@link verifyReeProof} / {@link gensynAutoRelease}. Passes\n * `assertServiceAdapterContract` with the default ports; supply real ports (a real\n * Gensyn job runner, a real pinner) for production.\n */\nexport function createGensynAdapter(config: GensynAdapterConfig = {}): ServiceAdapter {\n const runCompute = config.runCompute ?? reproduceGensynCompute;\n const pin = config.pin ?? defaultPin;\n const checkHealth = config.checkHealth ?? ((): Promise<boolean> => Promise.resolve(true));\n const capabilities = config.capabilities ?? [...GENSYN_CAPABILITIES];\n\n return {\n id: GENSYN_ADAPTER_ID,\n capabilities,\n healthCheck: checkHealth,\n async execute(spec: TaskSpec): Promise<ServiceResult> {\n const exec = runCompute(spec);\n const content = gensynDeliverable(exec);\n const contentHash = sha256Hex(content);\n const proof = buildReeProof(spec, exec, content);\n const proofUri = await pin(content);\n return {\n content,\n contentHash,\n proofUri,\n metadata: { adapter: GENSYN_ADAPTER_ID, reeProof: proof },\n };\n },\n };\n}\n","/**\n * ZKML proof-verifier ServiceAdapter (P8.T5). A Worker Bot wraps a zk-verified\n * inference service: it runs the model, then attaches a proof that the delivered\n * output is the correct result of running a committed model on a committed input.\n * The proof travels on `ServiceResult.proofUri`; the Buyer configures auto-release\n * on proof validation. Same buyer-layer-only shape as every adapter -- the escrow\n * program and the oracle judge nothing (CLAUDE.md product framing): verification is\n * pure TypeScript that runs in the Buyer's bot, never on-chain and never in the\n * oracle (see zero-program-diff.test.ts).\n *\n * WHAT THE SHIPPED VERIFIER IS -- AND IS NOT. The default scheme (`escro-zkml-ref-v1`)\n * is a REFERENCE verifier with NO cryptographic soundness. Its tag is a plain keyless\n * hash of the public inputs (see `computeZkmlVerificationTag`) and `buildZkmlProof` is\n * exported, so ANY party can mint a proof that `verifyZkmlProof` accepts, over whatever\n * output it chooses and any model commitment. It exists to demonstrate the lifecycle\n * (proof shape, transport on `proofUri`, decode, and the buyer-side auto-release seam)\n * deterministically and with no external prover. It must NEVER be the sole gate on a\n * production release. A production ZKML buyer passes a REAL SNARK/STARK verifier to\n * `zkmlProofAutoRelease` (the `verify` option): a verifying key over the same public\n * inputs, which is where soundness actually lives.\n *\n * TWO DISCIPLINES THAT DO CARRY TO PRODUCTION. (1) The buyer RE-HASHES the artifact it\n * holds and requires `sha256(artifact)` equals the worker-submitted `contentHash`\n * before trusting anything (`zkmlProofAutoRelease`'s `fetchContent` port). The submitted\n * hash is the worker's claim, never trusted on its own -- the same discipline as the\n * buyer template's `evalThresholdReview` and the T0 harness. (2) Verification is\n * buyer-layer only: it runs in the Buyer's bot, never on-chain and never in the oracle\n * (see zero-program-diff.test.ts). RELEASE JUDGMENT IS THE BUYER'S: the adapter only\n * PRODUCES the deliverable and its proof; whether to release is `zkmlProofAutoRelease`\n * in the Buyer's review, never the worker and never the protocol.\n */\nimport { createHash } from \"crypto\";\n\nimport { canonicalize, type TaskSpec } from \"@escro/shared\";\n\nimport type { ServiceAdapter, ServiceResult } from \"../../adapter.js\";\n\n/** Stable id/capabilities; locked against the EscroBots registry descriptor by a kit test at merge (consult C2). */\nexport const ZKML_ADAPTER_ID = \"zkml\";\nexport const ZKML_CAPABILITIES = [\"zk-verified-inference\"] as const;\n\n/** Marker on the demo spec's metadata so the default inference port recognizes it. */\nexport const ZKML_DEMO_MARKER = \"zkml-demo-v1\";\n\n/** The reference proving scheme this verifier understands. Unknown schemes are malformed to it. */\nexport const ZKML_PROOF_SCHEME = \"escro-zkml-ref-v1\";\n\n/** Prefix marking an inline (self-contained) zkml proof URI: `zkml-proof:<base64url(json)>`. */\nexport const ZKML_PROOF_URI_PREFIX = \"zkml-proof:\";\n\nfunction sha256Hex(content: string | Buffer): string {\n return createHash(\"sha256\").update(content).digest(\"hex\");\n}\n\n// ── Proof shape ──────────────────────────────────────────────────────────────────\n\n/**\n * A ZKML proof: its public inputs plus a `verificationTag` binding them. In the\n * reference scheme the tag is recomputable (see {@link computeZkmlVerificationTag});\n * in a production scheme it is a SNARK/STARK checked against a verifying key over the\n * same public inputs.\n */\nexport interface ZkmlProof {\n /** Proving scheme identifier; the verifier only understands {@link ZKML_PROOF_SCHEME}. */\n scheme: string;\n /** Commitment to the model that produced the output (e.g. a weights hash). */\n modelCommitment: string;\n /** Commitment to the input the model was run on. */\n inputCommitment: string;\n /** SHA-256 hex of the delivered output; binds the proof to a specific deliverable. */\n outputHash: string;\n /** Binding tag over the public inputs (reference: recomputable; production: a SNARK). */\n verificationTag: string;\n}\n\n/** The public inputs a proof commits to (everything except the tag itself). */\ntype ZkmlPublicInputs = Omit<ZkmlProof, \"verificationTag\">;\n\n/** Recompute the reference binding tag over a proof's public inputs. Deterministic. */\nexport function computeZkmlVerificationTag(publicInputs: ZkmlPublicInputs): string {\n return sha256Hex(\n canonicalize({\n scheme: publicInputs.scheme,\n modelCommitment: publicInputs.modelCommitment,\n inputCommitment: publicInputs.inputCommitment,\n outputHash: publicInputs.outputHash,\n }),\n );\n}\n\n/** Build a well-formed reference proof binding the given public inputs. */\nexport function buildZkmlProof(args: {\n scheme?: string;\n modelCommitment: string;\n inputCommitment: string;\n outputHash: string;\n}): ZkmlProof {\n const publicInputs: ZkmlPublicInputs = {\n scheme: args.scheme ?? ZKML_PROOF_SCHEME,\n modelCommitment: args.modelCommitment,\n inputCommitment: args.inputCommitment,\n outputHash: args.outputHash,\n };\n return { ...publicInputs, verificationTag: computeZkmlVerificationTag(publicInputs) };\n}\n\n/** Encode a proof as a self-contained inline proof URI. */\nexport function encodeZkmlProofUri(proof: ZkmlProof): string {\n return ZKML_PROOF_URI_PREFIX + Buffer.from(canonicalize(proof), \"utf8\").toString(\"base64url\");\n}\n\nfunction isProofShaped(value: unknown): value is ZkmlProof {\n if (typeof value !== \"object\" || value === null) {\n return false;\n }\n const p = value as Record<string, unknown>;\n return (\n typeof p.scheme === \"string\" &&\n typeof p.modelCommitment === \"string\" &&\n typeof p.inputCommitment === \"string\" &&\n typeof p.outputHash === \"string\" &&\n typeof p.verificationTag === \"string\"\n );\n}\n\n/**\n * Decode an inline zkml proof URI back to a {@link ZkmlProof}. Returns null for any\n * URI that is not an inline zkml proof or does not decode to the proof shape (a\n * pinned `ipfs://`/`ar://` proof is fetched by the caller, then passed to\n * {@link verifyZkmlProof} directly).\n */\nexport function decodeZkmlProofUri(uri: string): ZkmlProof | null {\n if (!uri.startsWith(ZKML_PROOF_URI_PREFIX)) {\n return null;\n }\n const encoded = uri.slice(ZKML_PROOF_URI_PREFIX.length);\n let parsed: unknown;\n try {\n parsed = JSON.parse(Buffer.from(encoded, \"base64url\").toString(\"utf8\"));\n } catch {\n return null;\n }\n return isProofShaped(parsed) ? parsed : null;\n}\n\n// ── Verification ─────────────────────────────────────────────────────────────────\n\n/**\n * The outcome of verifying a proof. `malformed` = the verifier cannot understand the\n * proof (missing/wrong-typed fields, unsupported scheme, undecodable URI); `invalid`\n * = a well-formed proof that fails verification (tag does not recompute, or attests a\n * different output/model than expected).\n */\nexport type ZkmlVerification =\n | { valid: true }\n | { valid: false; category: \"invalid\" | \"malformed\"; reason: string };\n\n/** What the Buyer expects the proof to attest to. */\nexport interface ZkmlExpectation {\n /** The submitted deliverable's contentHash; the proof's outputHash must equal it. */\n contentHash: string;\n /** When set, the proof's modelCommitment must equal it (pin to a specific model). */\n modelCommitment?: string;\n}\n\n/**\n * Verify a decoded proof against the Buyer's expectation. NOTE: this is the REFERENCE\n * verifier and is NOT cryptographically sound -- the tag is a keyless hash, so a `valid`\n * result means only that the proof is internally consistent and bound to\n * `expected.contentHash`, not that a trustworthy party produced it. Pass a real verifier\n * to {@link zkmlProofAutoRelease} for production. `malformed` = an unusable proof;\n * `invalid` = a usable proof that fails the checks.\n */\nexport function verifyZkmlProof(proof: unknown, expected: ZkmlExpectation): ZkmlVerification {\n if (!isProofShaped(proof)) {\n return { valid: false, category: \"malformed\", reason: \"proof is missing required fields\" };\n }\n if (proof.scheme !== ZKML_PROOF_SCHEME) {\n return {\n valid: false,\n category: \"malformed\",\n reason: `unsupported proof scheme \"${proof.scheme}\"`,\n };\n }\n if (proof.verificationTag !== computeZkmlVerificationTag(proof)) {\n return {\n valid: false,\n category: \"invalid\",\n reason:\n \"verification tag does not recompute (public inputs altered after the tag was computed)\",\n };\n }\n if (proof.outputHash !== expected.contentHash) {\n return {\n valid: false,\n category: \"invalid\",\n reason: \"proof attests a different output than the submitted deliverable\",\n };\n }\n if (\n expected.modelCommitment !== undefined &&\n proof.modelCommitment !== expected.modelCommitment\n ) {\n return { valid: false, category: \"invalid\", reason: \"proof attests a different model\" };\n }\n return { valid: true };\n}\n\n/** Decode an inline proof URI (or reject a missing/foreign one) and verify it. */\nexport function verifyZkmlProofUri(\n uri: string | null | undefined,\n expected: ZkmlExpectation,\n): ZkmlVerification {\n if (typeof uri !== \"string\" || uri === \"\") {\n return { valid: false, category: \"malformed\", reason: \"no proof URI attached\" };\n }\n const proof = decodeZkmlProofUri(uri);\n if (proof === null) {\n return {\n valid: false,\n category: \"malformed\",\n reason: \"proof URI is not a decodable inline zkml proof\",\n };\n }\n return verifyZkmlProof(proof, expected);\n}\n\n// ── Buyer-layer auto-release predicate ───────────────────────────────────────────\n\n/** The submitted deliverable as the Buyer's review reads it off the escrow read model. */\nexport interface ZkmlDeliverable {\n /**\n * SHA-256 hex the WORKER submitted on-chain (mirrored to the read model). It is the\n * worker's CLAIM about the artifact; {@link zkmlProofAutoRelease} re-hashes the real\n * artifact (via its `fetchContent` port) and never trusts this value on its own.\n */\n contentHash: string;\n /** URI where the ZK proof is (inline `zkml-proof:` or a pinned `ipfs://`), or null. */\n proofUri: string | null;\n}\n\n/** A release decision: release, and if not, whether to contest via dispute. */\nexport interface ZkmlReviewResult {\n accept: boolean;\n dispute: boolean;\n reason: string;\n}\n\n/**\n * A named release policy the Buyer's review wires in. Field-for-field this mirrors the\n * buyer template's `ReviewPolicy`\n * (packages/create-escro-bot/templates/buyer/src/review.ts). The SDK cannot import the\n * scaffolding templates, and promoting the shared review shapes into `@escro/shared` is\n * a cross-package change owned by `main`, not this lane -- tracked as a merge-time\n * follow-up (LANE-NOTES).\n */\nexport interface ZkmlReviewPolicy {\n name: string;\n evaluate(deliverable: ZkmlDeliverable): Promise<ZkmlReviewResult>;\n}\n\n/** Options for {@link zkmlProofAutoRelease}. */\nexport interface ZkmlProofAutoReleaseOptions {\n /**\n * Fetch the ACTUAL delivered artifact so the predicate can re-hash it. Integrity comes\n * from the buyer recomputing `sha256(artifact)` and requiring it equals the worker-\n * submitted `contentHash` -- never from trusting the submitted hash (mirror of the\n * buyer template's `evalThresholdReview`). Required: without the artifact the predicate\n * would be trusting a worker-chosen number.\n */\n fetchContent: (deliverable: ZkmlDeliverable) => Promise<string | Buffer> | string | Buffer;\n /** When set, the proof's modelCommitment must equal it (pin to a specific model). */\n modelCommitment?: string;\n /**\n * The proof verifier. DEFAULT is {@link verifyZkmlProof}, the reference verifier, which\n * is NOT cryptographically sound. A production buyer MUST pass a real SNARK/STARK\n * verifier here; the default is for demos only.\n */\n verify?: (proof: ZkmlProof, expected: ZkmlExpectation) => ZkmlVerification;\n /**\n * Resolve a non-inline (pinned) proof URI to a proof. Default: only inline\n * `zkml-proof:` URIs are understood; a pinned `ipfs://` proof needs this port.\n */\n fetchProof?: (uri: string) => Promise<ZkmlProof | null> | ZkmlProof | null;\n}\n\nasync function resolveZkmlProof(\n uri: string | null,\n fetchProof?: (uri: string) => Promise<ZkmlProof | null> | ZkmlProof | null,\n): Promise<ZkmlProof | null> {\n if (typeof uri !== \"string\" || uri === \"\") {\n return null;\n }\n if (uri.startsWith(ZKML_PROOF_URI_PREFIX)) {\n return decodeZkmlProofUri(uri);\n }\n return fetchProof ? await fetchProof(uri) : null;\n}\n\n/**\n * Buyer-layer auto-release predicate for zk-verified jobs. RELEASE only when BOTH hold:\n * (1) the delivered artifact re-hashes to the worker-submitted `contentHash` (fetched via\n * `fetchContent`, never trusted), and (2) the attached proof verifies against that buyer-\n * recomputed hash (and the pinned model, when given). Otherwise DISPUTE. Disputing rather\n * than holding is deliberate -- a held SUBMITTED escrow is auto-released to the worker by\n * the 24h protocol timeout, so a buyer who required a proof contests a missing/invalid one\n * instead of letting it time out to release. This is the Buyer's judgment, not the\n * protocol's. Soundness of step (2) lives in the `verify` option; the default reference\n * verifier is a demo and proves nothing on its own. A port that throws (e.g.\n * `fetchContent` failing to retrieve the artifact) PROPAGATES: a transient infra failure\n * is not a verdict, so the caller retries it -- it is never silently converted into a\n * dispute.\n */\nexport function zkmlProofAutoRelease(opts: ZkmlProofAutoReleaseOptions): ZkmlReviewPolicy {\n const verify = opts.verify ?? verifyZkmlProof;\n return {\n name: \"zkml-proof-auto-release\",\n async evaluate(d: ZkmlDeliverable): Promise<ZkmlReviewResult> {\n const recomputed = sha256Hex(await opts.fetchContent(d));\n if (recomputed !== d.contentHash) {\n return {\n accept: false,\n dispute: true,\n reason:\n \"delivered artifact does not hash to the submitted contentHash (tampered or wrong)\",\n };\n }\n const proof = await resolveZkmlProof(d.proofUri, opts.fetchProof);\n if (proof === null) {\n return { accept: false, dispute: true, reason: \"no decodable zkml proof attached\" };\n }\n const verdict = verify(proof, {\n contentHash: recomputed,\n ...(opts.modelCommitment !== undefined && { modelCommitment: opts.modelCommitment }),\n });\n if (verdict.valid) {\n return {\n accept: true,\n dispute: false,\n reason: \"zkml proof verified against the re-hashed deliverable\",\n };\n }\n return {\n accept: false,\n dispute: true,\n reason: `zkml proof ${verdict.category}: ${verdict.reason}`,\n };\n },\n };\n}\n\n// ── Adapter ──────────────────────────────────────────────────────────────────────\n\n/** What an inference run yields: the output plus the commitments the proof binds. */\nexport interface ZkmlInferenceOutput {\n /** The deliverable content. */\n content: string;\n /** Commitment to the model that produced `content`. */\n modelCommitment: string;\n /** Commitment to the input the model was run on. */\n inputCommitment: string;\n}\n\n/** Configuration and injectable ports for {@link createZkmlAdapter}. */\nexport interface ZkmlAdapterConfig {\n /** Adapter id. Defaults to `\"zkml\"`. */\n id?: string;\n /** Advertised capabilities for EscroBots discovery. Defaults to `[\"zk-verified-inference\"]`. */\n capabilities?: string[];\n /** Inference port. Default: solves the canned demo job; a deterministic placeholder otherwise. */\n runInference?: (spec: TaskSpec) => Promise<ZkmlInferenceOutput> | ZkmlInferenceOutput;\n /** Proving port. Default: builds a reference proof binding the output to its commitments. */\n prove?: (args: {\n spec: TaskSpec;\n output: ZkmlInferenceOutput;\n outputHash: string;\n }) => Promise<ZkmlProof> | ZkmlProof;\n /** Pinning port. Default: a self-contained inline proof URI. A production worker pins the proof. */\n pin?: (proof: ZkmlProof) => Promise<string> | string;\n /** Health-check port. Default: resolves `true`. */\n checkHealth?: () => Promise<boolean>;\n}\n\n/**\n * The canned zk-verified-inference demo job (BOT_KIT_PRD §6 / §13): a deterministic\n * classification the buyer template's zero-config journey hires this bot for.\n * Acceptance is machine-checkable by the buyer via {@link zkmlProofAutoRelease}.\n */\nexport const zkmlDemoJobSpec: TaskSpec = {\n version: \"1.0.0\",\n taskType: \"custom\",\n description:\n \"Run the canned zk-verified inference demo: classify the fixed demo input and \" +\n \"attach a proof that the output is the correct result of the committed model on \" +\n \"the committed input. Acceptance is deterministic and recomputed by the buyer: the \" +\n \"attached proof must verify against the submitted deliverable's contentHash.\",\n acceptanceCriteria: [\n {\n id: \"ac-proof-verifies\",\n description:\n \"The attached proof verifies against the submitted deliverable's contentHash, recomputed by the buyer.\",\n required: true,\n },\n ],\n deliverableFormat: { type: \"json\" },\n metadata: { demo: ZKML_DEMO_MARKER },\n};\n\n/** Commitment to the demo model; deterministic so the demo journey settles with zero config. */\nconst DEMO_MODEL_COMMITMENT = sha256Hex(\"zkml-demo-classifier-v1\");\n/** Commitment to the demo input. */\nconst DEMO_INPUT_COMMITMENT = sha256Hex(\"zkml-demo-input-v1\");\n\n/**\n * The reference solution to the demo job: the classifier's output as canonical JSON.\n * Deterministic. Exposed so the demo journey and tests share one source of truth.\n */\nexport function solveZkmlDemo(): string {\n return canonicalize({\n model: \"zkml-demo-classifier-v1\",\n output: { label: \"cat\", confidence: 0.98 },\n });\n}\n\nfunction referencePlaceholderOutput(spec: TaskSpec): ZkmlInferenceOutput {\n return {\n content: canonicalize({\n note: \"reference stub - replace the runInference port with a real zk-verified inference call.\",\n taskType: spec.taskType,\n }),\n modelCommitment: sha256Hex(\"zkml-reference-stub-model\"),\n inputCommitment: sha256Hex(canonicalize(spec)),\n };\n}\n\nconst defaultRunInference = (spec: TaskSpec): ZkmlInferenceOutput =>\n spec.metadata.demo === ZKML_DEMO_MARKER\n ? {\n content: solveZkmlDemo(),\n modelCommitment: DEMO_MODEL_COMMITMENT,\n inputCommitment: DEMO_INPUT_COMMITMENT,\n }\n : referencePlaceholderOutput(spec);\n\n/**\n * Build a ZKML {@link ServiceAdapter}. Passes `assertServiceAdapterContract` with the\n * default ports and, out of the box, produces a demo deliverable whose proof verifies\n * under {@link zkmlProofAutoRelease}. Supply real ports (a genuine inference call, a\n * real prover, a pin to IPFS/Arweave) for production use.\n */\nexport function createZkmlAdapter(config: ZkmlAdapterConfig = {}): ServiceAdapter {\n const id = config.id ?? ZKML_ADAPTER_ID;\n const capabilities = config.capabilities ?? [...ZKML_CAPABILITIES];\n const runInference = config.runInference ?? defaultRunInference;\n const prove =\n config.prove ??\n ((args: { output: ZkmlInferenceOutput; outputHash: string }): ZkmlProof =>\n buildZkmlProof({\n modelCommitment: args.output.modelCommitment,\n inputCommitment: args.output.inputCommitment,\n outputHash: args.outputHash,\n }));\n const pin = config.pin ?? ((proof: ZkmlProof): string => encodeZkmlProofUri(proof));\n const checkHealth = config.checkHealth ?? ((): Promise<boolean> => Promise.resolve(true));\n\n return {\n id,\n capabilities,\n async execute(spec: TaskSpec): Promise<ServiceResult> {\n const output = await runInference(spec);\n const contentHash = sha256Hex(output.content);\n const proof = await prove({ spec, output, outputHash: contentHash });\n const proofUri = await pin(proof);\n return {\n content: output.content,\n contentHash,\n proofUri,\n metadata: {\n adapterId: id,\n scheme: proof.scheme,\n modelCommitment: proof.modelCommitment,\n },\n };\n },\n healthCheck(): Promise<boolean> {\n return checkHealth();\n },\n };\n}\n"],"mappings":"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","names":["import_web3","import_tweetnacl","import_bs58","EscrowState","nacl","bs58","bs58","nacl","import_crypto","import_crypto","sha256Hex","import_crypto","sha256Hex","referencePlaceholder","defaultPin","DEFAULT_SUBNET","DEFAULT_TASK_BUDGET_MICRO_USDC","referencePlaceholder","defaultCallSubnet","DEFAULT_SUBNET","DEFAULT_TASK_BUDGET_MICRO_USDC","sha256Hex","parseDemoDeliverable","referencePlaceholder","import_crypto","sha256Hex","DEFAULT_TASK_BUDGET_MICRO_USDC","defaultSwap","defaultPin","DEMO_SEED","DEMO_ROUNDS","parseDemoDeliverable","referencePlaceholder","import_crypto","DEFAULT_SERVICE","DEFAULT_TASK_BUDGET_MICRO_USDC","sha256Hex","defaultSwap","defaultPin","parseDemoDeliverable","referencePlaceholder","defaultRunJob","import_crypto","sha256Hex","defaultPin","import_crypto","sha256Hex"]}