@escro/sdk 0.1.3 → 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.
- package/LICENSE +21 -0
- package/README.md +1 -1
- package/dist/index.cjs +1859 -76
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1538 -8
- package/dist/index.d.ts +1538 -8
- package/dist/index.js +1770 -77
- package/dist/index.js.map +1 -1
- package/package.json +16 -16
package/dist/index.d.cts
CHANGED
|
@@ -1,9 +1,418 @@
|
|
|
1
|
-
import { TaskSpec, EscrowState, EscrowAccount } from '@escro/shared';
|
|
2
|
-
export { AcceptanceCriterion, DeliverableFormat, DeliverableType, EscrowAccount, EscrowErrorCode, EscrowState, Network, TaskSpec, TaskType } from '@escro/shared';
|
|
3
1
|
import { Keypair } from '@solana/web3.js';
|
|
4
2
|
|
|
3
|
+
/**
|
|
4
|
+
* All possible lifecycle states of an AgentEscrow account on-chain.
|
|
5
|
+
*
|
|
6
|
+
* State transitions (happy path):
|
|
7
|
+
* CREATED → FUNDED → IN_PROGRESS → SUBMITTED → COMPLETED
|
|
8
|
+
*
|
|
9
|
+
* Exception paths:
|
|
10
|
+
* Any state (before COMPLETED) → DISPUTED (human arbitration)
|
|
11
|
+
* CREATED | FUNDED → CANCELLED (buyer cancels before agent accepts)
|
|
12
|
+
* SUBMITTED → COMPLETED (24h timeout auto-release to worker)
|
|
13
|
+
* IN_PROGRESS → REFUNDED (deadline expiry auto-refund to buyer)
|
|
14
|
+
*/
|
|
15
|
+
declare enum EscrowState {
|
|
16
|
+
/** Escrow PDA created on-chain; awaiting token deposit from the maker. */
|
|
17
|
+
CREATED = "CREATED",
|
|
18
|
+
/** Maker deposited tokens into the vault; open for agent acceptance. */
|
|
19
|
+
FUNDED = "FUNDED",
|
|
20
|
+
/** An agent accepted the task; work is underway. */
|
|
21
|
+
IN_PROGRESS = "IN_PROGRESS",
|
|
22
|
+
/** Agent submitted a deliverable URI; awaiting buyer review or 24h auto-release. */
|
|
23
|
+
SUBMITTED = "SUBMITTED",
|
|
24
|
+
/** Funds released to the agent. Terminal state. */
|
|
25
|
+
COMPLETED = "COMPLETED",
|
|
26
|
+
/** Buyer cancelled before work started. Terminal state. */
|
|
27
|
+
CANCELLED = "CANCELLED",
|
|
28
|
+
/** Maker or agent raised a dispute; requires human arbitration. */
|
|
29
|
+
DISPUTED = "DISPUTED",
|
|
30
|
+
/** Funds returned to the maker (deadline expiry or dispute resolution). Terminal state. */
|
|
31
|
+
REFUNDED = "REFUNDED"
|
|
32
|
+
}
|
|
33
|
+
/** Solana cluster the escrow account lives on. */
|
|
34
|
+
type Network = "mainnet-beta" | "devnet" | "localnet";
|
|
35
|
+
/**
|
|
36
|
+
* Full on-chain representation of an AgentEscrow PDA, enriched with
|
|
37
|
+
* off-chain metadata resolved by the API server.
|
|
38
|
+
*
|
|
39
|
+
* `amount` and all `*At` timestamps use the on-chain units:
|
|
40
|
+
* - `amount` is in the SPL token's smallest denomination (e.g. μUSDC = 10⁻⁶ USDC).
|
|
41
|
+
* - timestamps are Unix seconds as stored in the Anchor account.
|
|
42
|
+
*
|
|
43
|
+
* When serialising over HTTP, `amount` is represented as a decimal `string`
|
|
44
|
+
* (see {@link GetEscrowResponse}) to avoid JSON `number` precision loss.
|
|
45
|
+
*/
|
|
46
|
+
interface EscrowAccount {
|
|
47
|
+
/** Base-58 public key of the escrow PDA. */
|
|
48
|
+
address: string;
|
|
49
|
+
/** Base-58 public key of the task creator (the party paying for the work). */
|
|
50
|
+
maker: string;
|
|
51
|
+
/** Base-58 public key of the assigned agent, or `null` if no agent has accepted yet. */
|
|
52
|
+
taker: string | null;
|
|
53
|
+
/** Base-58 public key of the SPL token mint used for payment (e.g. USDC mint). */
|
|
54
|
+
mint: string;
|
|
55
|
+
/**
|
|
56
|
+
* Payment amount held in escrow, in the mint's smallest denomination.
|
|
57
|
+
* Stored as `bigint` to preserve full u64 precision from the on-chain account.
|
|
58
|
+
*/
|
|
59
|
+
amount: bigint;
|
|
60
|
+
/** Current lifecycle state of the escrow. */
|
|
61
|
+
state: EscrowState;
|
|
62
|
+
/**
|
|
63
|
+
* SHA-256 hex digest of the canonical UTF-8 JSON serialisation of the {@link TaskSpec}.
|
|
64
|
+
* Stored on-chain; used by the oracle to verify it is evaluating the correct spec.
|
|
65
|
+
*/
|
|
66
|
+
taskSpecHash: string;
|
|
67
|
+
/**
|
|
68
|
+
* Content-addressed URI (ipfs:// or ar://) where the full {@link TaskSpec} JSON is pinned.
|
|
69
|
+
* `null` until the maker uploads the spec via `POST /v1/task-specs`.
|
|
70
|
+
*/
|
|
71
|
+
taskSpecUri: string | null;
|
|
72
|
+
/** Base-58 public key of the oracle authority permitted to sign timeout_release / refund_buyer. */
|
|
73
|
+
oracle: string;
|
|
74
|
+
/**
|
|
75
|
+
* Percentage of `amount` charged as a platform fee, in basis points.
|
|
76
|
+
* Deducted from the escrow vault on successful settlement.
|
|
77
|
+
* Valid range: 0–10 000 (0 %–100 %).
|
|
78
|
+
*/
|
|
79
|
+
oracleFeeBps: number;
|
|
80
|
+
/** Unix timestamp (seconds) when the escrow PDA was initialised. */
|
|
81
|
+
createdAt: number;
|
|
82
|
+
/**
|
|
83
|
+
* Unix timestamp (seconds) at which the escrow deadline expires; mirrors the
|
|
84
|
+
* on-chain `deadline` field set at `create_escrow`. A Worker Bot reads this to
|
|
85
|
+
* decide whether it can finish a job before the deadline (never claim what it
|
|
86
|
+
* can't finish); after it passes, an unstarted escrow is refundable to the maker.
|
|
87
|
+
*/
|
|
88
|
+
deadline: number;
|
|
89
|
+
/** Unix timestamp (seconds) of the most recent agent submission, or `null`. */
|
|
90
|
+
submittedAt: number | null;
|
|
91
|
+
/**
|
|
92
|
+
* SHA-256 hex digest of the worker's submitted deliverable, mirrored from the
|
|
93
|
+
* on-chain `deliverable_hash` written at `submit_deliverable`; `null` until the
|
|
94
|
+
* escrow reaches SUBMITTED. The on-chain value is authoritative: a Buyer Bot's
|
|
95
|
+
* review re-verifies a deliverable against a hash it independently expects and
|
|
96
|
+
* never treats this mirror as proof of integrity on its own.
|
|
97
|
+
*/
|
|
98
|
+
deliverableHash: string | null;
|
|
99
|
+
/**
|
|
100
|
+
* URI of the submitted deliverable artifact (S3 presigned / IPFS / Arweave),
|
|
101
|
+
* mirrored from the off-chain `proof_uri` recorded at `submit_deliverable`;
|
|
102
|
+
* `null` until SUBMITTED. The Buyer Bot fetches the deliverable content here to
|
|
103
|
+
* review it.
|
|
104
|
+
*/
|
|
105
|
+
proofUri: string | null;
|
|
106
|
+
/** PDA canonical bump seed, stored on-chain to validate future instructions. */
|
|
107
|
+
bump: number;
|
|
108
|
+
/** Solana cluster this account belongs to. */
|
|
109
|
+
network: Network;
|
|
110
|
+
}
|
|
111
|
+
/** Protocol-wide aggregate statistics — public, unauthenticated. */
|
|
112
|
+
interface ProtocolStats {
|
|
113
|
+
totalEscrows: number;
|
|
114
|
+
totalVolumeUsdc: string;
|
|
115
|
+
/**
|
|
116
|
+
* Settled USDC volume: the sum of `amount_usdc` (the job amount, which the
|
|
117
|
+
* worker keeps in full; the additive platform fee is protocol revenue, not
|
|
118
|
+
* settled work volume) over escrows in the COMPLETED terminal state. COMPLETED
|
|
119
|
+
* is reached only by the three worker-paying instructions (release_payment,
|
|
120
|
+
* timeout_release, arbitration_release); refunded and cancelled escrows never
|
|
121
|
+
* paid a worker and are excluded. This is the honest headline number: it counts
|
|
122
|
+
* settlement, not transaction volume.
|
|
123
|
+
*/
|
|
124
|
+
settledVolumeUsdc: string;
|
|
125
|
+
byState: Record<EscrowState, number>;
|
|
126
|
+
activeEscrows: number;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Broad categories of agent work.
|
|
131
|
+
*
|
|
132
|
+
* Used for analytics and UI display. Use `"custom"` for task types not
|
|
133
|
+
* covered by the built-in categories.
|
|
134
|
+
*/
|
|
135
|
+
type TaskType = "code_generation" | "code_review" | "data_analysis" | "content_writing" | "translation" | "summarization" | "question_answering" | "image_generation" | "audio_transcription" | "custom";
|
|
136
|
+
/** High-level container format for a deliverable artifact. */
|
|
137
|
+
type DeliverableType = "text" | "json" | "file" | "url" | "code";
|
|
138
|
+
/**
|
|
139
|
+
* Constraints on the shape, size, and encoding of the expected deliverable.
|
|
140
|
+
*/
|
|
141
|
+
interface DeliverableFormat {
|
|
142
|
+
/** High-level container type. Determines which other fields are applicable. */
|
|
143
|
+
type: DeliverableType;
|
|
144
|
+
/**
|
|
145
|
+
* JSON Schema (draft-07) object the deliverable must validate against.
|
|
146
|
+
* Only applicable when `type === "json"`.
|
|
147
|
+
*/
|
|
148
|
+
schema?: Record<string, unknown>;
|
|
149
|
+
/**
|
|
150
|
+
* Expected MIME type of the delivered file (e.g. `"application/pdf"`, `"image/png"`).
|
|
151
|
+
* Only applicable when `type === "file"`.
|
|
152
|
+
*/
|
|
153
|
+
mimeType?: string;
|
|
154
|
+
/**
|
|
155
|
+
* Maximum permitted size of the deliverable content in bytes.
|
|
156
|
+
* Applies to `"file"`, `"text"`, `"code"`, and `"json"` types.
|
|
157
|
+
*/
|
|
158
|
+
maxSizeBytes?: number;
|
|
159
|
+
/**
|
|
160
|
+
* Programming language identifier for code deliverables (e.g. `"typescript"`, `"python"`).
|
|
161
|
+
* Only applicable when `type === "code"`.
|
|
162
|
+
*/
|
|
163
|
+
language?: string;
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* A single acceptance criterion that the deliverable must satisfy.
|
|
167
|
+
*/
|
|
168
|
+
interface AcceptanceCriterion {
|
|
169
|
+
/**
|
|
170
|
+
* Unique identifier for this criterion within the task spec.
|
|
171
|
+
* Convention: short kebab-case string, e.g. `"ac-correctness"`, `"ac-format"`.
|
|
172
|
+
* Must be unique within a single {@link TaskSpec}.
|
|
173
|
+
*/
|
|
174
|
+
id: string;
|
|
175
|
+
/**
|
|
176
|
+
* Human-readable description of what must be true for this criterion to pass.
|
|
177
|
+
*/
|
|
178
|
+
description: string;
|
|
179
|
+
/**
|
|
180
|
+
* Relative importance of this criterion.
|
|
181
|
+
* Weights are normalised across all criteria, so only their ratios matter.
|
|
182
|
+
* Defaults to `1.0` when omitted.
|
|
183
|
+
*/
|
|
184
|
+
weight?: number;
|
|
185
|
+
/**
|
|
186
|
+
* When `true`, this criterion is mandatory for acceptance.
|
|
187
|
+
* Defaults to `false`.
|
|
188
|
+
*/
|
|
189
|
+
required?: boolean;
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Canonical specification of the unit of work held in escrow.
|
|
193
|
+
*
|
|
194
|
+
* This object is:
|
|
195
|
+
* 1. Serialised to canonical UTF-8 JSON (sorted keys, no trailing whitespace).
|
|
196
|
+
* 2. Hashed with SHA-256 → stored on-chain as `EscrowAccount.taskSpecHash`.
|
|
197
|
+
* 3. Pinned to IPFS or Arweave → URI stored as `EscrowAccount.taskSpecUri`.
|
|
198
|
+
*
|
|
199
|
+
* Any mutation of the spec changes its hash, invalidating the on-chain record.
|
|
200
|
+
*/
|
|
201
|
+
interface TaskSpec {
|
|
202
|
+
/**
|
|
203
|
+
* Semver string identifying the task spec schema version (e.g. `"1.0.0"`).
|
|
204
|
+
* Allows the oracle and API server to handle format evolution gracefully.
|
|
205
|
+
* Increment the minor version for backwards-compatible additions;
|
|
206
|
+
* the major version for breaking changes.
|
|
207
|
+
*/
|
|
208
|
+
version: string;
|
|
209
|
+
/**
|
|
210
|
+
* Broad category of the task. See {@link TaskType} for supported values.
|
|
211
|
+
*/
|
|
212
|
+
taskType: TaskType;
|
|
213
|
+
/**
|
|
214
|
+
* Complete description of the task, written for both the agent performing it
|
|
215
|
+
* and the oracle evaluating the result.
|
|
216
|
+
*
|
|
217
|
+
* Good descriptions:
|
|
218
|
+
* - State the goal, not just the method.
|
|
219
|
+
* - Include any non-obvious constraints (language, style, performance bounds).
|
|
220
|
+
* - Are precise enough that an LLM could verify correctness without ambiguity.
|
|
221
|
+
*/
|
|
222
|
+
description: string;
|
|
223
|
+
/**
|
|
224
|
+
* Ordered list of acceptance criteria the deliverable must satisfy.
|
|
225
|
+
* Must contain at least one entry.
|
|
226
|
+
*/
|
|
227
|
+
acceptanceCriteria: AcceptanceCriterion[];
|
|
228
|
+
/**
|
|
229
|
+
* Structural and size constraints the deliverable must conform to.
|
|
230
|
+
*/
|
|
231
|
+
deliverableFormat: DeliverableFormat;
|
|
232
|
+
/**
|
|
233
|
+
* Arbitrary key-value extension map for protocol plugins, agent hints, or audit trails.
|
|
234
|
+
*/
|
|
235
|
+
metadata: Record<string, unknown>;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Exhaustive set of machine-readable error codes returned by the escro.ai REST API
|
|
240
|
+
* in the `code` field of an {@link ApiError} response.
|
|
241
|
+
*
|
|
242
|
+
* Consumers should switch on this value to handle errors programmatically
|
|
243
|
+
* rather than parsing the human-readable `error` string.
|
|
244
|
+
*/
|
|
245
|
+
type EscrowErrorCode =
|
|
246
|
+
/** The requested escrow PDA does not exist on the specified network. */
|
|
247
|
+
"ESCROW_NOT_FOUND"
|
|
248
|
+
/** The requested operation is not permitted in the escrow's current state. */
|
|
249
|
+
| "ESCROW_INVALID_STATE"
|
|
250
|
+
/** The referenced task spec hash has not been registered. */
|
|
251
|
+
| "TASK_SPEC_NOT_FOUND"
|
|
252
|
+
/** The submitted task spec failed schema validation. */
|
|
253
|
+
| "TASK_SPEC_INVALID"
|
|
254
|
+
/** The caller does not have permission to perform this action. */
|
|
255
|
+
| "UNAUTHORIZED"
|
|
256
|
+
/** The provided transaction signature is invalid or does not match the escrow. */
|
|
257
|
+
| "INVALID_SIGNATURE"
|
|
258
|
+
/** The requested token amount is zero, negative, or exceeds the u64 maximum. */
|
|
259
|
+
| "INVALID_AMOUNT"
|
|
260
|
+
/** The escrow's network does not match the caller's requested network. */
|
|
261
|
+
| "NETWORK_MISMATCH"
|
|
262
|
+
/** The caller has exceeded the rate limit; retry after the indicated backoff. */
|
|
263
|
+
| "RATE_LIMITED"
|
|
264
|
+
/** An unexpected server-side error occurred; report to escro.ai support. */
|
|
265
|
+
| "INTERNAL_ERROR"
|
|
266
|
+
/** Request body or query parameters failed schema validation. */
|
|
267
|
+
| "VALIDATION_ERROR";
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* EscroBots v0 - the permissionless capability directory (ARCHITECTURE §8).
|
|
271
|
+
*
|
|
272
|
+
* A bot advertises itself by publishing a wallet-signed capability descriptor.
|
|
273
|
+
* The descriptor is a *claim*, not a verified fact - on-chain history is the
|
|
274
|
+
* verification (surfaced in the Phase 7 v1 directory). The registry performs no
|
|
275
|
+
* approval, review, or ranking; fraud against the protocol is the only removal
|
|
276
|
+
* criterion. The descriptor document itself is independently verifiable: anyone
|
|
277
|
+
* holding it can check `signature` against `wallet` without trusting the API.
|
|
278
|
+
*/
|
|
279
|
+
/**
|
|
280
|
+
* The advertisable roles. Single source for both the `BotRole` type and the API's
|
|
281
|
+
* zod enum (routes/bots.ts uses `z.enum(BOT_ROLES)`), so the accepted values and
|
|
282
|
+
* the type cannot drift: a role added here flows into validation automatically.
|
|
283
|
+
*/
|
|
284
|
+
declare const BOT_ROLES: readonly ["worker", "buyer", "both"];
|
|
285
|
+
/** Whether the bot hires work, performs work, or both. */
|
|
286
|
+
type BotRole = (typeof BOT_ROLES)[number];
|
|
287
|
+
/**
|
|
288
|
+
* The descriptor fields the bot's wallet signs. Everything a registry consumer
|
|
289
|
+
* needs to find and reach the bot, minus the signature over these fields.
|
|
290
|
+
*/
|
|
291
|
+
interface UnsignedBotDescriptor {
|
|
292
|
+
/** Base58 Solana pubkey - the advertising bot and the descriptor's signer. */
|
|
293
|
+
wallet: string;
|
|
294
|
+
/** What the bot does in the escrow relationship. */
|
|
295
|
+
role: BotRole;
|
|
296
|
+
/** Free-form capability tags, e.g. `["fine-tune", "eval"]`. Filterable. */
|
|
297
|
+
capabilities: string[];
|
|
298
|
+
/** The underlying service the bot wraps, e.g. `"bittensor:sn56"`. */
|
|
299
|
+
serviceRef: string;
|
|
300
|
+
/** Human-readable pricing guidance, e.g. `"~$5 per fine-tune job"`. */
|
|
301
|
+
pricingHint: string;
|
|
302
|
+
/** Optional http(s) endpoint a buyer can reach the bot at. */
|
|
303
|
+
endpoint?: string;
|
|
304
|
+
/** Unix milliseconds when the descriptor was signed. Monotonic per wallet. */
|
|
305
|
+
signedAt: number;
|
|
306
|
+
}
|
|
307
|
+
/**
|
|
308
|
+
* A signed capability descriptor as stored and served by the registry.
|
|
309
|
+
* `signature` is a base58 detached Ed25519 signature over the canonical form of
|
|
310
|
+
* the {@link UnsignedBotDescriptor} fields (see `canonicalBotDescriptorMessage`).
|
|
311
|
+
*/
|
|
312
|
+
interface BotDescriptor extends UnsignedBotDescriptor {
|
|
313
|
+
/** Base58 detached Ed25519 signature over the canonical unsigned descriptor. */
|
|
314
|
+
signature: string;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
type SolanaCluster = "devnet" | "mainnet";
|
|
318
|
+
|
|
319
|
+
/** Dispute tally with its outcome split (from the wallet's perspective). */
|
|
320
|
+
interface DisputeRecord {
|
|
321
|
+
/** Total disputes this wallet was party to (raised by either side). */
|
|
322
|
+
total: number;
|
|
323
|
+
/** Disputes resolved in this wallet's favour. */
|
|
324
|
+
won: number;
|
|
325
|
+
/** Disputes resolved against this wallet. */
|
|
326
|
+
lost: number;
|
|
327
|
+
}
|
|
328
|
+
/** Worker-side raw reputation components for a wallet. */
|
|
329
|
+
interface WorkerReputation {
|
|
330
|
+
/** Tasks this wallet claimed. */
|
|
331
|
+
tasksClaimed: number;
|
|
332
|
+
/**
|
|
333
|
+
* Completions credited to the Worker. Per the #23.1 ruling this is exactly the
|
|
334
|
+
* explicit-Buyer-release and timeout-release paths; an arbitration_release is a
|
|
335
|
+
* dispute WIN (see {@link disputes}), not a completion, though its funds still
|
|
336
|
+
* count in {@link volumeSettledUsdc}.
|
|
337
|
+
*/
|
|
338
|
+
completions: number;
|
|
339
|
+
/** Completions via explicit Buyer release (stored distinctly — #23.1). */
|
|
340
|
+
completionsViaRelease: number;
|
|
341
|
+
/** Completions via timeout release (stored distinctly — #23.1). */
|
|
342
|
+
completionsViaTimeout: number;
|
|
343
|
+
/** Claimed-but-not-delivered escrows (deadline-expiry refund — #23.2). */
|
|
344
|
+
nonDeliveries: number;
|
|
345
|
+
/** completions / tasksClaimed; null when no task was claimed. */
|
|
346
|
+
completionRate: number | null;
|
|
347
|
+
/** Disputes as Worker: won = arbitration_release, lost = arbitration_refund. */
|
|
348
|
+
disputes: DisputeRecord;
|
|
349
|
+
/** disputes.total / tasksClaimed; null when no task was claimed. */
|
|
350
|
+
disputeRate: number | null;
|
|
351
|
+
/** Sum of worker_amount received in μUSDC. */
|
|
352
|
+
volumeSettledUsdc: bigint;
|
|
353
|
+
/** Avg seconds create->claim across this wallet's claimed escrows; null if none. */
|
|
354
|
+
avgCreateToClaimSeconds: number | null;
|
|
355
|
+
/** Avg seconds claim->submit across this wallet's submitted escrows; null if none. */
|
|
356
|
+
avgClaimToSubmitSeconds: number | null;
|
|
357
|
+
}
|
|
358
|
+
/** Buyer-side raw reputation components for a wallet. */
|
|
359
|
+
interface BuyerReputation {
|
|
360
|
+
/** Escrows this wallet created. */
|
|
361
|
+
escrowsCreated: number;
|
|
362
|
+
/** Escrows that settled via timeout release — buyer non-response signal (#23.1). */
|
|
363
|
+
timeoutReleases: number;
|
|
364
|
+
/** Disputes as Buyer: won = arbitration_refund, lost = arbitration_release. */
|
|
365
|
+
disputes: DisputeRecord;
|
|
366
|
+
/** disputes.total / escrowsCreated; null when no escrow was created. */
|
|
367
|
+
disputeRate: number | null;
|
|
368
|
+
/** Sum of worker_amount settled out of escrows this wallet funded, in μUSDC. */
|
|
369
|
+
volumeSettledUsdc: bigint;
|
|
370
|
+
}
|
|
371
|
+
/**
|
|
372
|
+
* The complete raw reputation for one wallet. No composite/overall score field
|
|
373
|
+
* exists by design (ARCHITECTURE §9).
|
|
374
|
+
*/
|
|
375
|
+
interface WalletReputation {
|
|
376
|
+
/** Base-58 wallet address. */
|
|
377
|
+
wallet: string;
|
|
378
|
+
/** Worker-side components. */
|
|
379
|
+
asWorker: WorkerReputation;
|
|
380
|
+
/** Buyer-side components. */
|
|
381
|
+
asBuyer: BuyerReputation;
|
|
382
|
+
/** Unix seconds of first Escro activity (wallet-age basis); null if none. */
|
|
383
|
+
firstActivityAt: number | null;
|
|
384
|
+
/** Unix seconds of most recent Escro activity; null if none. */
|
|
385
|
+
lastActivityAt: number | null;
|
|
386
|
+
}
|
|
387
|
+
/** JSON-safe form of {@link WalletReputation} (bigint volumes as decimal strings). */
|
|
388
|
+
interface SerializedWalletReputation extends Omit<WalletReputation, "asWorker" | "asBuyer"> {
|
|
389
|
+
asWorker: Omit<WorkerReputation, "volumeSettledUsdc"> & {
|
|
390
|
+
volumeSettledUsdc: string;
|
|
391
|
+
};
|
|
392
|
+
asBuyer: Omit<BuyerReputation, "volumeSettledUsdc"> & {
|
|
393
|
+
volumeSettledUsdc: string;
|
|
394
|
+
};
|
|
395
|
+
}
|
|
396
|
+
/**
|
|
397
|
+
* The wire shape served by the internal reputation endpoint: the serialized
|
|
398
|
+
* aggregates plus wallet age derived at serve time. The indexer stores raw
|
|
399
|
+
* clock-free timestamps ({@link WalletReputation.firstActivityAt}); age (#23.5,
|
|
400
|
+
* "age since first Escro activity") is a function of the serving clock, so it is
|
|
401
|
+
* derived here rather than baked into the stored aggregates.
|
|
402
|
+
*/
|
|
403
|
+
interface ServedWalletReputation extends SerializedWalletReputation {
|
|
404
|
+
/** now - firstActivityAt in seconds; null when the wallet has no activity. */
|
|
405
|
+
walletAgeSeconds: number | null;
|
|
406
|
+
}
|
|
407
|
+
|
|
5
408
|
/** Constructor options for the {@link Escro} client. */
|
|
6
409
|
interface EscroOptions {
|
|
410
|
+
/**
|
|
411
|
+
* Which Solana cluster this client talks to. Required so the program ID and
|
|
412
|
+
* USDC mint resolve correctly. Pass `"devnet"` for testing, `"mainnet"` for
|
|
413
|
+
* production. Breaking change in SDK 0.2.0 (previously implicit devnet).
|
|
414
|
+
*/
|
|
415
|
+
cluster: SolanaCluster;
|
|
7
416
|
/** Solana RPC endpoint URL. */
|
|
8
417
|
rpcUrl: string;
|
|
9
418
|
/** Escro REST API base URL (e.g. "https://api.escro.ai"). */
|
|
@@ -15,11 +424,19 @@ interface EscroOptions {
|
|
|
15
424
|
interface CreateEscrowParams {
|
|
16
425
|
/** Full task specification uploaded to IPFS. */
|
|
17
426
|
taskSpec: TaskSpec;
|
|
18
|
-
/**
|
|
427
|
+
/**
|
|
428
|
+
* Worker's net payment in μUSDC (1 USDC = 1_000_000). Minimum: 5_000_000.
|
|
429
|
+
* The buyer is charged `amountUsdc + fee` at creation; the worker receives
|
|
430
|
+
* the full `amountUsdc` on settlement.
|
|
431
|
+
*/
|
|
19
432
|
amountUsdc: number;
|
|
20
433
|
/** Unix timestamp (seconds) at which the escrow deadline expires. */
|
|
21
|
-
|
|
22
|
-
/**
|
|
434
|
+
deadlineUnix: number;
|
|
435
|
+
/**
|
|
436
|
+
* Base-58 public key of the worker assigned to this task. Required —
|
|
437
|
+
* every escrow is created against a specific worker (open tasks are
|
|
438
|
+
* not supported).
|
|
439
|
+
*/
|
|
23
440
|
assignedWorker: string;
|
|
24
441
|
}
|
|
25
442
|
/** Return value from {@link Escro.createEscrow}. */
|
|
@@ -77,11 +494,100 @@ interface PaginatedResult<T> {
|
|
|
77
494
|
/** The effective offset applied to this response. */
|
|
78
495
|
offset: number;
|
|
79
496
|
}
|
|
497
|
+
/** Filters for an EscroBots registry read (`GET /v1/bots`). */
|
|
498
|
+
interface ListBotsParams {
|
|
499
|
+
/** Free-form capability tag to filter by, e.g. `"fine-tune"`. */
|
|
500
|
+
capability?: string;
|
|
501
|
+
/** Role filter. `worker` includes `both` bots (a `both` bot is hireable as a worker). */
|
|
502
|
+
role?: BotDescriptor["role"];
|
|
503
|
+
/** Maximum number of descriptors to return. */
|
|
504
|
+
limit?: number;
|
|
505
|
+
/** Zero-based offset for pagination. */
|
|
506
|
+
offset?: number;
|
|
507
|
+
}
|
|
508
|
+
/**
|
|
509
|
+
* One candidate returned by {@link Escro.findWorkers}. The `descriptor` is a
|
|
510
|
+
* self-reported CLAIM (ARCHITECTURE §8); `signatureValid` attests only that the
|
|
511
|
+
* claim was genuinely signed by `descriptor.wallet` (authorship), NOT that its
|
|
512
|
+
* capabilities are true. On-chain history (EscroRep, Phase 7) is the verification
|
|
513
|
+
* of the claim, deliberately kept separate here, never merged into one flag.
|
|
514
|
+
*/
|
|
515
|
+
interface WorkerCandidate {
|
|
516
|
+
/** The wallet-signed capability descriptor as served by the registry (a claim). */
|
|
517
|
+
descriptor: BotDescriptor;
|
|
518
|
+
/** True iff `descriptor.signature` verifies against `descriptor.wallet` (authorship only). */
|
|
519
|
+
signatureValid: boolean;
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
/**
|
|
523
|
+
* Reserved dual-path payment surface (ARCHITECTURE §7a, BOT_KIT_PRD §10).
|
|
524
|
+
*
|
|
525
|
+
* PLUMBING ONLY. The escrow rail is the sole implemented backend; the `x402`
|
|
526
|
+
* (synchronous) rail is reserved and lands in Phase 9 as an additive backend.
|
|
527
|
+
* Every name here is a FREEZE CONTRACT that Phase 9 (P9.T5) inherits "by name":
|
|
528
|
+
* enabling x402 must not be a breaking change for any kit-generated bot. The
|
|
529
|
+
* shapes below are pinned by a type-level test (src/__tests__/payments.test.ts);
|
|
530
|
+
* Phase 9 may add only OPTIONAL fields.
|
|
531
|
+
*/
|
|
532
|
+
/** Single source for the rail identifiers. The {@link Rail} type is derived from
|
|
533
|
+
* this list (drift-safe, mirroring the BOT_ROLES pattern in @escro/shared). */
|
|
534
|
+
declare const RAILS: readonly ["escrow", "x402"];
|
|
535
|
+
/** The payment rails Escro can route across. Only `escrow` is implemented today;
|
|
536
|
+
* `x402` is RESERVED and not enabled until Phase 9. */
|
|
537
|
+
type Rail = (typeof RAILS)[number];
|
|
538
|
+
/** The rails enabled in this build. Frozen to escrow-only until Phase 9 enables
|
|
539
|
+
* x402. Typed `readonly Rail[]` (not the literal tuple) so runtime membership
|
|
540
|
+
* checks stay honest: `ENABLED_RAILS.includes(rail)` narrows nothing away. */
|
|
541
|
+
declare const ENABLED_RAILS: readonly Rail[];
|
|
542
|
+
/** Docs for the payment rails, linked from the reserved-rail error and the kit
|
|
543
|
+
* config's rejection message so both point to the same place. */
|
|
544
|
+
declare const RAILS_DOCS_URL = "https://docs.escro.ai/rails";
|
|
545
|
+
/** The minimal payment shape a {@link PaymentRouter} inspects to choose a rail.
|
|
546
|
+
* FROZEN; Phase 9 may add only optional fields. */
|
|
547
|
+
interface TxShape {
|
|
548
|
+
/** Recipient wallet address (base58). */
|
|
549
|
+
readonly to: string;
|
|
550
|
+
/** Amount to move, in USDC micro-units (integer, 6 decimals). */
|
|
551
|
+
readonly amountMicroUsdc: number;
|
|
552
|
+
/** `async` (verification-needed) work routes to escrow; `sync` work is x402's territory. */
|
|
553
|
+
readonly mode: "async" | "sync";
|
|
554
|
+
}
|
|
555
|
+
/** Chooses the rail for a payment. Defined now with a single backend; `x402` is
|
|
556
|
+
* returned only once that rail is enabled (Phase 9). FROZEN signature. */
|
|
557
|
+
interface PaymentRouter {
|
|
558
|
+
selectRail(tx: TxShape): Rail;
|
|
559
|
+
}
|
|
560
|
+
/** The one backend shipped today. Async work routes to escrow; sync work would
|
|
561
|
+
* prefer x402, but x402 is reserved and not enabled (ARCHITECTURE §7a), so the
|
|
562
|
+
* router falls back to escrow rather than ever returning a disabled rail. */
|
|
563
|
+
declare class EscrowPaymentRouter implements PaymentRouter {
|
|
564
|
+
selectRail(tx: TxShape): Rail;
|
|
565
|
+
}
|
|
566
|
+
/** Parameters for a synchronous payment via {@link Escro.pay}. FROZEN: both
|
|
567
|
+
* fields are required now so Phase 9 adds only optional fields; a required field
|
|
568
|
+
* added later would break every kit-generated bot. */
|
|
569
|
+
interface PayParams {
|
|
570
|
+
/** Recipient wallet address (base58). */
|
|
571
|
+
readonly to: string;
|
|
572
|
+
/** Amount to pay, in USDC micro-units (integer, 6 decimals). */
|
|
573
|
+
readonly amountMicroUsdc: number;
|
|
574
|
+
}
|
|
575
|
+
/** Result of a completed payment. FROZEN and rail-generic: `reference` is the
|
|
576
|
+
* rail-native settlement id (a Solana signature for escrow, an x402 receipt for
|
|
577
|
+
* x402), so the shape describes either rail without change. */
|
|
578
|
+
interface PaymentResult {
|
|
579
|
+
/** Which rail settled the payment. */
|
|
580
|
+
readonly rail: Rail;
|
|
581
|
+
/** Rail-native settlement reference. */
|
|
582
|
+
readonly reference: string;
|
|
583
|
+
}
|
|
80
584
|
|
|
81
585
|
declare class Escro {
|
|
82
586
|
private readonly connection;
|
|
83
587
|
private readonly api;
|
|
84
588
|
private readonly options;
|
|
589
|
+
private readonly cluster;
|
|
590
|
+
private readonly router;
|
|
85
591
|
constructor(options: EscroOptions);
|
|
86
592
|
/**
|
|
87
593
|
* Create a new escrow: registers with the API, signs and submits the
|
|
@@ -92,7 +598,9 @@ declare class Escro {
|
|
|
92
598
|
createEscrow(params: CreateEscrowParams): Promise<CreateEscrowResult>;
|
|
93
599
|
/**
|
|
94
600
|
* Release payment to the worker. Buyer must be the wallet in the constructor.
|
|
95
|
-
*
|
|
601
|
+
* Builds and submits the `release_payment` on-chain tx FIRST (the chain is the
|
|
602
|
+
* source of truth), then confirms DB state. The DB confirmation is best-effort:
|
|
603
|
+
* the oracle sweep reconciles it if it fails.
|
|
96
604
|
*
|
|
97
605
|
* @returns Solana transaction signature.
|
|
98
606
|
*/
|
|
@@ -112,6 +620,18 @@ declare class Escro {
|
|
|
112
620
|
* @returns Solana transaction signature.
|
|
113
621
|
*/
|
|
114
622
|
cancelEscrow(address: string): Promise<string>;
|
|
623
|
+
/**
|
|
624
|
+
* Reserved synchronous-payment entrypoint (ARCHITECTURE §7a). `pay()` settles
|
|
625
|
+
* over the x402 rail, which is not implemented until Phase 9; today it rejects
|
|
626
|
+
* with {@link EscroRailNotEnabledError}. The signature is FROZEN so enabling
|
|
627
|
+
* x402 later is not a breaking change for kit-generated bots. For asynchronous,
|
|
628
|
+
* verification-needed work use {@link createEscrow}, the core product.
|
|
629
|
+
*
|
|
630
|
+
* Not `async`: it returns a rejected promise (never awaits) so callers can
|
|
631
|
+
* `await`/`.catch()` it uniformly, and it exercises the same {@link PaymentRouter}
|
|
632
|
+
* routing seam Phase 9 will implement.
|
|
633
|
+
*/
|
|
634
|
+
pay(params: PayParams): Promise<PaymentResult>;
|
|
115
635
|
/**
|
|
116
636
|
* Claim an assigned task. Worker must be the wallet in the constructor.
|
|
117
637
|
* Signs and submits the `claim_task` on-chain tx.
|
|
@@ -120,7 +640,7 @@ declare class Escro {
|
|
|
120
640
|
*/
|
|
121
641
|
claimTask(address: string): Promise<string>;
|
|
122
642
|
/**
|
|
123
|
-
* Submit a deliverable for
|
|
643
|
+
* Submit a deliverable for the buyer to review. Worker must be the wallet.
|
|
124
644
|
* Signs and submits the `submit_deliverable` on-chain tx.
|
|
125
645
|
*
|
|
126
646
|
* @returns Solana transaction signature.
|
|
@@ -137,6 +657,50 @@ declare class Escro {
|
|
|
137
657
|
* @param options - Polling, pagination (limit/offset).
|
|
138
658
|
*/
|
|
139
659
|
getMyTasks(state?: EscrowState[], options?: PollOptions & ListOptions): Promise<PaginatedResult<EscrowAccount>>;
|
|
660
|
+
/**
|
|
661
|
+
* List escrows CREATED by the wallet's public key (the maker / buyer), the
|
|
662
|
+
* mirror of {@link getMyTasks} for the buyer side. Optionally filter by state
|
|
663
|
+
* and paginate.
|
|
664
|
+
*
|
|
665
|
+
* A Buyer Bot uses this to sum its own outstanding (still-locked) escrows for
|
|
666
|
+
* the client-side spend cap: the program is the source of truth, so the total
|
|
667
|
+
* is read from chain state (via the API), never a local tally a crash could lose.
|
|
668
|
+
*
|
|
669
|
+
* @param state - Filter by one or more states (first state used as API filter).
|
|
670
|
+
* @param options - Polling, pagination (limit/offset).
|
|
671
|
+
*/
|
|
672
|
+
getMyEscrows(state?: EscrowState[], options?: PollOptions & ListOptions): Promise<PaginatedResult<EscrowAccount>>;
|
|
673
|
+
/**
|
|
674
|
+
* Find worker bots in the EscroBots registry, optionally filtered by
|
|
675
|
+
* capability. Queries `GET /v1/bots?role=worker` (the API includes `both`
|
|
676
|
+
* bots) and returns candidates in REGISTRY ORDER: this method does no
|
|
677
|
+
* ranking, scoring, or reordering (ARCHITECTURE §8: no curation; §13: not a
|
|
678
|
+
* marketplace). Escro-shipped code never ranks; the caller's own bot decides.
|
|
679
|
+
*
|
|
680
|
+
* Each candidate keeps the CLAIM (`descriptor`) separate from the AUTHORSHIP
|
|
681
|
+
* check (`signatureValid`, verified locally so a third party need not trust the
|
|
682
|
+
* API). Capabilities remain unverified claims; on-chain history (EscroRep,
|
|
683
|
+
* Phase 7) is their verification, deliberately not merged in here.
|
|
684
|
+
*/
|
|
685
|
+
findWorkers(params?: {
|
|
686
|
+
capability?: string;
|
|
687
|
+
} & ListOptions): Promise<WorkerCandidate[]>;
|
|
688
|
+
/**
|
|
689
|
+
* Fetch the EscroRep bulk export: every indexed wallet's RAW reputation
|
|
690
|
+
* components (ARCHITECTURE §9), each wallet exactly once, in one fetch. Returns
|
|
691
|
+
* the raw components verbatim - this method does NO ranking, scoring, or default
|
|
692
|
+
* weighting (Escro-shipped code never ranks; the caller's own bot weights and
|
|
693
|
+
* decides). Selection layers join these components to {@link findWorkers}
|
|
694
|
+
* candidates by wallet. Throws {@link ReputationUnavailableError} when the
|
|
695
|
+
* deployment mounts no reputation source (HTTP 404).
|
|
696
|
+
*/
|
|
697
|
+
listReputations(): Promise<ServedWalletReputation[]>;
|
|
698
|
+
/**
|
|
699
|
+
* Fetch protocol-wide stats from the public `GET /v1/stats` endpoint.
|
|
700
|
+
*
|
|
701
|
+
* @returns protocol-wide {@link ProtocolStats}.
|
|
702
|
+
*/
|
|
703
|
+
getStats(): Promise<ProtocolStats>;
|
|
140
704
|
/**
|
|
141
705
|
* Fetch an escrow by its PDA address.
|
|
142
706
|
* If `options.poll` is true, polls with exponential backoff until the escrow
|
|
@@ -145,6 +709,130 @@ declare class Escro {
|
|
|
145
709
|
getEscrow(address: string, options?: PollOptions): Promise<EscrowAccount>;
|
|
146
710
|
}
|
|
147
711
|
|
|
712
|
+
declare class ApiClient {
|
|
713
|
+
private readonly baseUrl;
|
|
714
|
+
private readonly wallet;
|
|
715
|
+
constructor(baseUrl: string, wallet: Keypair);
|
|
716
|
+
private url;
|
|
717
|
+
/** GET /v1/escrows/:address */
|
|
718
|
+
getEscrow(address: string): Promise<EscrowAccount>;
|
|
719
|
+
/** GET /v1/escrows?assignedTo=...&maker=...&state=... */
|
|
720
|
+
listEscrows(params: {
|
|
721
|
+
assignedTo?: string;
|
|
722
|
+
maker?: string;
|
|
723
|
+
state?: EscrowState;
|
|
724
|
+
limit?: number;
|
|
725
|
+
offset?: number;
|
|
726
|
+
}): Promise<PaginatedResult<EscrowAccount>>;
|
|
727
|
+
/**
|
|
728
|
+
* GET /v1/bots?capability=...&role=...&limit=...&offset= : EscroBots registry
|
|
729
|
+
* read. Unauthenticated public read (no auth headers). Returns descriptors in
|
|
730
|
+
* registry order (newest first); descriptors are self-reported claims.
|
|
731
|
+
*/
|
|
732
|
+
listBots(params: ListBotsParams): Promise<PaginatedResult<BotDescriptor>>;
|
|
733
|
+
/**
|
|
734
|
+
* GET /rep : EscroRep bulk export (ARCHITECTURE §9). Unauthenticated public
|
|
735
|
+
* read (no auth headers). Returns every indexed wallet's RAW components exactly
|
|
736
|
+
* once (no composite score). Ranking layers join against this ONE bulk fetch:
|
|
737
|
+
* the per-wallet endpoint shares a 10/min public-metrics budget, so a
|
|
738
|
+
* per-candidate fan-out would rate-limit itself. A 404 means the deployment
|
|
739
|
+
* mounted no reputation source (unknown wallets return zeroed rep, never 404),
|
|
740
|
+
* so it surfaces as {@link ReputationUnavailableError}, not EscrowNotFoundError.
|
|
741
|
+
*/
|
|
742
|
+
listReputations(): Promise<ServedWalletReputation[]>;
|
|
743
|
+
/**
|
|
744
|
+
* POST /v1/escrows — create escrow, returns unsigned tx + ids.
|
|
745
|
+
* Requires auth.
|
|
746
|
+
*/
|
|
747
|
+
createEscrow(params: CreateEscrowParams): Promise<{
|
|
748
|
+
escrowId: string;
|
|
749
|
+
escrowPda: string;
|
|
750
|
+
unsignedTx: string;
|
|
751
|
+
}>;
|
|
752
|
+
/**
|
|
753
|
+
* POST /v1/escrows/:address/claim — returns unsigned tx.
|
|
754
|
+
* Requires auth (worker).
|
|
755
|
+
*/
|
|
756
|
+
claimTask(address: string): Promise<{
|
|
757
|
+
unsignedTx: string;
|
|
758
|
+
}>;
|
|
759
|
+
/**
|
|
760
|
+
* POST /v1/escrows/:address/submit — returns unsigned tx.
|
|
761
|
+
* Requires auth (worker).
|
|
762
|
+
*/
|
|
763
|
+
submitDeliverable(address: string, params: SubmitDeliverableParams): Promise<{
|
|
764
|
+
unsignedTx: string;
|
|
765
|
+
}>;
|
|
766
|
+
/**
|
|
767
|
+
* POST /v1/escrows/:address/release — DB-only state update.
|
|
768
|
+
* Requires auth (buyer). No on-chain tx returned.
|
|
769
|
+
*/
|
|
770
|
+
releasePaymentDb(address: string): Promise<void>;
|
|
771
|
+
/**
|
|
772
|
+
* POST /v1/escrows/:address/cancel — returns unsigned tx.
|
|
773
|
+
* Requires auth (buyer). Only valid when state is FUNDED.
|
|
774
|
+
*/
|
|
775
|
+
cancelEscrow(address: string): Promise<{
|
|
776
|
+
unsignedTx: string;
|
|
777
|
+
}>;
|
|
778
|
+
/**
|
|
779
|
+
* POST /v1/escrows/:address/dispute — returns unsigned tx.
|
|
780
|
+
* Requires auth (buyer or worker).
|
|
781
|
+
*/
|
|
782
|
+
raiseDispute(address: string, params: RaiseDisputeParams): Promise<{
|
|
783
|
+
unsignedTx: string;
|
|
784
|
+
}>;
|
|
785
|
+
/**
|
|
786
|
+
* GET /v1/stats — public protocol-wide stats.
|
|
787
|
+
* No auth required. Upstream typing in {@link Escro.getStats} narrows the
|
|
788
|
+
* return shape.
|
|
789
|
+
*/
|
|
790
|
+
getStats(): Promise<unknown>;
|
|
791
|
+
}
|
|
792
|
+
|
|
793
|
+
/**
|
|
794
|
+
* The result a {@link ServiceAdapter} returns from `execute`. Escro is agnostic
|
|
795
|
+
* to what produced it: `content` is the deliverable itself, `contentHash` is the
|
|
796
|
+
* SHA-256 hex digest the Buyer verifies the deliverable against, and `proofUri`
|
|
797
|
+
* optionally points at where the content is pinned (IPFS/Arweave) or at a proof.
|
|
798
|
+
* No currency or token field appears here; token conversion is adapter-internal
|
|
799
|
+
* (ARCHITECTURE §3, §7).
|
|
800
|
+
*/
|
|
801
|
+
interface ServiceResult {
|
|
802
|
+
/** The deliverable itself. */
|
|
803
|
+
content: string | Buffer;
|
|
804
|
+
/** SHA-256 hex digest of {@link ServiceResult.content}. */
|
|
805
|
+
contentHash: string;
|
|
806
|
+
/** Content-addressed URI (ipfs://, ar://) or proof URI for the deliverable. */
|
|
807
|
+
proofUri?: string;
|
|
808
|
+
/** Arbitrary adapter-specific metadata (model, timings, subnet ids, ...). */
|
|
809
|
+
metadata: Record<string, unknown>;
|
|
810
|
+
}
|
|
811
|
+
/**
|
|
812
|
+
* A Worker Bot implements ServiceAdapter to wrap any async service (a Bittensor
|
|
813
|
+
* subnet, an Akash deployment, a Render job, ...). Escro never sees what is
|
|
814
|
+
* underneath and never sees a non-USDC token: the adapter handles any token
|
|
815
|
+
* conversion internally (ARCHITECTURE §3, §7). Every pre-built adapter reuses
|
|
816
|
+
* this interface and is validated by `assertServiceAdapterContract`.
|
|
817
|
+
*/
|
|
818
|
+
interface ServiceAdapter {
|
|
819
|
+
/** Stable identifier, e.g. "bittensor:sn56", "akash", "render". */
|
|
820
|
+
id: string;
|
|
821
|
+
/** Advertised capabilities, e.g. ["llm_inference", "image_gen"]. */
|
|
822
|
+
capabilities: string[];
|
|
823
|
+
/** Execute the task described by `spec` and return the deliverable. */
|
|
824
|
+
execute(spec: TaskSpec): Promise<ServiceResult>;
|
|
825
|
+
/** Report whether the underlying service is reachable and ready. */
|
|
826
|
+
healthCheck(): Promise<boolean>;
|
|
827
|
+
}
|
|
828
|
+
/**
|
|
829
|
+
* Map a {@link ServiceResult} onto {@link SubmitDeliverableParams}, surfacing the
|
|
830
|
+
* `contentHash` (and `proofUri`, when present) that `submit_deliverable` records.
|
|
831
|
+
* This is the single point where an adapter's output crosses into the escrow
|
|
832
|
+
* worker flow.
|
|
833
|
+
*/
|
|
834
|
+
declare function serviceResultToSubmitParams(result: ServiceResult): SubmitDeliverableParams;
|
|
835
|
+
|
|
148
836
|
/** Base class for all errors thrown by the @escro/sdk. */
|
|
149
837
|
declare class EscroError extends Error {
|
|
150
838
|
readonly code: string;
|
|
@@ -154,6 +842,16 @@ declare class EscroError extends Error {
|
|
|
154
842
|
declare class EscrowNotFoundError extends EscroError {
|
|
155
843
|
constructor(address: string);
|
|
156
844
|
}
|
|
845
|
+
/**
|
|
846
|
+
* The reputation endpoint is not available on this deployment (HTTP 404). A 404
|
|
847
|
+
* from `GET /rep` means no `ReputationSource` is mounted (the surface is
|
|
848
|
+
* unmounted), NOT that a wallet is unknown - unknown wallets return zeroed raw
|
|
849
|
+
* components, never a 404. Kept distinct from {@link EscrowNotFoundError}, whose
|
|
850
|
+
* 404 is about a missing escrow.
|
|
851
|
+
*/
|
|
852
|
+
declare class ReputationUnavailableError extends EscroError {
|
|
853
|
+
constructor();
|
|
854
|
+
}
|
|
157
855
|
/** The operation is not valid for the escrow's current state (HTTP 409). */
|
|
158
856
|
declare class EscrowStateError extends EscroError {
|
|
159
857
|
constructor(message: string);
|
|
@@ -166,5 +864,837 @@ declare class EscrowTimeoutError extends EscroError {
|
|
|
166
864
|
declare class UnauthorizedError extends EscroError {
|
|
167
865
|
constructor(message?: string);
|
|
168
866
|
}
|
|
867
|
+
/**
|
|
868
|
+
* A payment rail was requested that is not enabled in this build. The `x402`
|
|
869
|
+
* (synchronous) rail is reserved (ARCHITECTURE §7a) and lands in Phase 9;
|
|
870
|
+
* {@link Escro.pay} throws this until then. `rail` names the unavailable rail.
|
|
871
|
+
*/
|
|
872
|
+
declare class EscroRailNotEnabledError extends EscroError {
|
|
873
|
+
readonly rail: string;
|
|
874
|
+
constructor(rail: string);
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
/** Options controlling {@link assertServiceAdapterContract}. */
|
|
878
|
+
interface AdapterContractOptions {
|
|
879
|
+
/**
|
|
880
|
+
* A representative TaskSpec the adapter can execute. The harness calls
|
|
881
|
+
* `execute(sampleSpec)` and validates the returned ServiceResult, so the spec
|
|
882
|
+
* should be one the adapter genuinely handles.
|
|
883
|
+
*/
|
|
884
|
+
sampleSpec: TaskSpec;
|
|
885
|
+
}
|
|
886
|
+
/** Thrown by {@link assertServiceAdapterContract}, listing every contract violation. */
|
|
887
|
+
declare class AdapterContractError extends EscroError {
|
|
888
|
+
readonly violations: string[];
|
|
889
|
+
constructor(adapterId: string, violations: string[]);
|
|
890
|
+
}
|
|
891
|
+
/**
|
|
892
|
+
* Assert that `adapter` satisfies the ServiceAdapter contract. Resolves with the
|
|
893
|
+
* ServiceResult produced by `execute(sampleSpec)` when the adapter conforms;
|
|
894
|
+
* rejects with an {@link AdapterContractError} listing every violation otherwise.
|
|
895
|
+
*
|
|
896
|
+
* Reusable across adapters (this phase's Bittensor one, Phase 6's four, Phase 8's
|
|
897
|
+
* networks): a conforming adapter passes, a malformed one fails. The parameter is
|
|
898
|
+
* typed `ServiceAdapter`, but the harness validates at runtime: JS callers and
|
|
899
|
+
* `as`-cast objects reach this too, so every field is checked defensively.
|
|
900
|
+
*/
|
|
901
|
+
declare function assertServiceAdapterContract(adapter: ServiceAdapter, options: AdapterContractOptions): Promise<ServiceResult>;
|
|
902
|
+
|
|
903
|
+
/**
|
|
904
|
+
* Amount denominated in TAO (Bittensor's token). Branded so it cannot be assigned to
|
|
905
|
+
* or from a plain `number` by accident and (the point of the brand) so it can never
|
|
906
|
+
* appear in a `ServiceResult` or the escrow submit path: those types have no field of
|
|
907
|
+
* this type. TAO exists ONLY inside the Bittensor adapter layer.
|
|
908
|
+
*/
|
|
909
|
+
type Tao = number & {
|
|
910
|
+
readonly __brand: "TAO";
|
|
911
|
+
};
|
|
912
|
+
/** Construct a {@link Tao} amount from a plain number. Adapter-internal use only. */
|
|
913
|
+
declare function tao(amount: number): Tao;
|
|
914
|
+
/** Swap a microUSDC budget into TAO. Real workers route this through a DEX (e.g. Jupiter). */
|
|
915
|
+
type UsdcToTaoSwap = (microUsdc: number) => Promise<Tao>;
|
|
916
|
+
/**
|
|
917
|
+
* Pay subnet miners `budget` TAO to run `spec`; resolve with the raw deliverable. The
|
|
918
|
+
* single shared port shape across every Bittensor adapter (a GPU-rental call is a paid
|
|
919
|
+
* subnet call too; lium re-exports this as `RunGpuJob`).
|
|
920
|
+
*/
|
|
921
|
+
type SubnetCall = (spec: TaskSpec, budget: Tao) => Promise<string | Buffer>;
|
|
922
|
+
/** Pin `content` and resolve with a content-addressed proof URI (ipfs://, ar://). */
|
|
923
|
+
type PinContent$3 = (content: string | Buffer) => Promise<string>;
|
|
924
|
+
|
|
925
|
+
/**
|
|
926
|
+
* Gradients (Bittensor SN56) ServiceAdapter: the first SHIPPED, supported adapter
|
|
927
|
+
* (the reference pattern P6.T6b-d replicate). A Worker Bot wraps the Gradients
|
|
928
|
+
* fine-tuning subnet behind the `ServiceAdapter` interface: it swaps a per-task
|
|
929
|
+
* USDC budget into TAO internally, pays subnet miners in TAO to fine-tune, collects
|
|
930
|
+
* a checkpoint + eval deliverable, and returns a currency-free `ServiceResult`. The
|
|
931
|
+
* Buyer and the escrow contract only ever see USDC; no TAO-typed value crosses this
|
|
932
|
+
* boundary into SDK core (ARCHITECTURE §3, §7; see ../bittensor/bittensor.type-test.ts
|
|
933
|
+
* for the compile-time proof shared by the Bittensor trio).
|
|
934
|
+
*
|
|
935
|
+
* The swap, subnet call, and pinning are injectable ports so the reference runs (and
|
|
936
|
+
* is tested) without a live DEX, subnet, or IPFS node. A production worker supplies
|
|
937
|
+
* real implementations (Jupiter for the swap, the SN56 dendrite, Pinata/Arweave).
|
|
938
|
+
*
|
|
939
|
+
* RELEASE JUDGMENT IS NOT HERE. This adapter only PRODUCES the deliverable (checkpoint
|
|
940
|
+
* + eval JSON). Whether the eval clears the threshold is decided by the BUYER's
|
|
941
|
+
* review.ts, which independently recomputes the score (see `scoreGradientsDemoDeliverable`).
|
|
942
|
+
* The worker never scores-for-release and never releases (CLAUDE.md product framing).
|
|
943
|
+
*
|
|
944
|
+
* Relationship to `examples/worker-bot/bittensor-adapter.ts`: that example is
|
|
945
|
+
* pedagogy ("author your own adapter against the public interface", driven by e2e
|
|
946
|
+
* scenario 13 / the P5.T2b obligation); THIS module is the shipped, importable
|
|
947
|
+
* surface a generated bot uses. The USDC->TAO port skeleton and the execute shape are
|
|
948
|
+
* shared with the other Bittensor adapters via `../bittensor/index.js`; this module
|
|
949
|
+
* supplies only its subnet identity, capabilities, budget, and demo logic.
|
|
950
|
+
*/
|
|
951
|
+
|
|
952
|
+
/** Configuration and injectable ports for {@link createGradientsAdapter}. */
|
|
953
|
+
interface GradientsAdapterConfig {
|
|
954
|
+
/** Subnet identifier. Defaults to "sn56" (Gradients); forms the adapter id `bittensor:<subnet>`. */
|
|
955
|
+
subnet?: string;
|
|
956
|
+
/** Advertised capabilities for EscroBots discovery. Defaults to `["fine-tune"]`. */
|
|
957
|
+
capabilities?: string[];
|
|
958
|
+
/** μUSDC the worker allocates to a single task before converting to TAO (internal budgeting). */
|
|
959
|
+
taskBudgetMicroUsdc?: number;
|
|
960
|
+
/** Swap port. Default: a fixed-rate reference stub. */
|
|
961
|
+
swap?: UsdcToTaoSwap;
|
|
962
|
+
/** Subnet-call port. Default: solves the canned demo job; a deterministic placeholder otherwise. */
|
|
963
|
+
callSubnet?: SubnetCall;
|
|
964
|
+
/** Pinning port. Default: a deterministic `ipfs://` placeholder URI. */
|
|
965
|
+
pin?: PinContent$3;
|
|
966
|
+
/** Health-check port. Default: resolves `true`. */
|
|
967
|
+
checkHealth?: () => Promise<boolean>;
|
|
968
|
+
}
|
|
969
|
+
/** Stable id/capabilities, LOCKED against `ADAPTER_DESCRIPTORS.gradients` by a kit test (consult C2). */
|
|
970
|
+
declare const GRADIENTS_ADAPTER_ID = "bittensor:sn56";
|
|
971
|
+
declare const GRADIENTS_CAPABILITIES: readonly ["fine-tune"];
|
|
972
|
+
/** Stable marker on the demo spec's metadata so the default subnet stub recognizes it. */
|
|
973
|
+
declare const GRADIENTS_DEMO_MARKER = "gradients-sn56-demo-v1";
|
|
974
|
+
/** The demo eval floor: predictions must be at least this accurate to be accepted. */
|
|
975
|
+
declare const GRADIENTS_DEMO_EVAL_FLOOR = 0.8;
|
|
976
|
+
/**
|
|
977
|
+
* The canned Gradients demo job. Deterministic; its specHash is pinned by a test
|
|
978
|
+
* (consult C8) because the buyer journey depends on hash stability.
|
|
979
|
+
*/
|
|
980
|
+
declare const gradientsDemoJobSpec: TaskSpec;
|
|
981
|
+
/**
|
|
982
|
+
* The reference solution to the demo job: the correct predictions plus a
|
|
983
|
+
* (self-reported, buyer-ignored) eval block, as canonical JSON. Deterministic.
|
|
984
|
+
* Exposed so the demo journey and tests share one source of the expected artifact.
|
|
985
|
+
*/
|
|
986
|
+
declare function solveGradientsDemo(): string;
|
|
987
|
+
/**
|
|
988
|
+
* The BUYER's independent recompute of the demo eval score in [0, 1]. Reads the
|
|
989
|
+
* substantive output (the predictions) and compares it to the target map the buyer
|
|
990
|
+
* itself defines; it deliberately IGNORES any self-reported `eval.score` in the
|
|
991
|
+
* deliverable, so release can never be worker-controlled (consult C10). Malformed
|
|
992
|
+
* or unparseable content scores 0 and never throws.
|
|
993
|
+
*/
|
|
994
|
+
declare function scoreGradientsDemoDeliverable(content: string | Buffer): number;
|
|
995
|
+
/**
|
|
996
|
+
* Build a Gradients (SN56) {@link ServiceAdapter}. Passes `assertServiceAdapterContract`
|
|
997
|
+
* with the default ports; supply real ports for production use. The USDC->TAO swap,
|
|
998
|
+
* pinning, and execute skeleton come from the shared Bittensor core.
|
|
999
|
+
*/
|
|
1000
|
+
declare function createGradientsAdapter(config?: GradientsAdapterConfig): ServiceAdapter;
|
|
1001
|
+
|
|
1002
|
+
/** Run the coding agent for `spec`; resolve with the raw deliverable (a test report). */
|
|
1003
|
+
type RunCodingAgent = (spec: TaskSpec) => Promise<string | Buffer>;
|
|
1004
|
+
/** Pin `content` and resolve with a content-addressed proof URI (ipfs://, ar://). */
|
|
1005
|
+
type PinContent$2 = (content: string | Buffer) => Promise<string>;
|
|
1006
|
+
/** Configuration and injectable ports for {@link createRidgesAdapter}. */
|
|
1007
|
+
interface RidgesAdapterConfig {
|
|
1008
|
+
/** Service identifier. Defaults to "ridges"; forms the adapter id. */
|
|
1009
|
+
service?: string;
|
|
1010
|
+
/** Advertised capabilities for EscroBots discovery. Defaults to `["code-generation"]`. */
|
|
1011
|
+
capabilities?: string[];
|
|
1012
|
+
/** Coding-agent port. Default: solves the canned demo kata; a placeholder otherwise. */
|
|
1013
|
+
runAgent?: RunCodingAgent;
|
|
1014
|
+
/** Pinning port. Default: a deterministic `ipfs://` placeholder URI. */
|
|
1015
|
+
pin?: PinContent$2;
|
|
1016
|
+
/** Health-check port. Default: resolves `true`. */
|
|
1017
|
+
checkHealth?: () => Promise<boolean>;
|
|
1018
|
+
}
|
|
1019
|
+
/**
|
|
1020
|
+
* Stable id/capabilities. Locked against `ADAPTER_DESCRIPTORS.ridges` by a kit test
|
|
1021
|
+
* at merge (consult C2; the lock lives in create-escro-bot, which depends on this
|
|
1022
|
+
* package, and is landed with the barrel wiring — LANE-NOTES merge step 3).
|
|
1023
|
+
*/
|
|
1024
|
+
declare const RIDGES_ADAPTER_ID = "ridges";
|
|
1025
|
+
declare const RIDGES_CAPABILITIES: readonly ["code-generation"];
|
|
1026
|
+
/** Stable marker on the demo spec's metadata so the default agent stub recognizes it. */
|
|
1027
|
+
declare const RIDGES_DEMO_MARKER = "ridges-demo-v1";
|
|
1028
|
+
/** The demo coverage target: the fraction of the test battery that must be covered. */
|
|
1029
|
+
declare const RIDGES_DEMO_COVERAGE_TARGET = 0.8;
|
|
1030
|
+
/**
|
|
1031
|
+
* The canned Ridges demo job. Deterministic; its specHash is pinned by a test
|
|
1032
|
+
* because the buyer journey depends on hash stability.
|
|
1033
|
+
*/
|
|
1034
|
+
declare const ridgesDemoJobSpec: TaskSpec;
|
|
1035
|
+
/**
|
|
1036
|
+
* The reference solution to the demo kata: a passing test report over the full
|
|
1037
|
+
* battery, plus a (self-reported, buyer-ignored) pass/coverage block, as canonical
|
|
1038
|
+
* JSON. Deterministic. Exposed so the demo journey and tests share one source of the
|
|
1039
|
+
* expected artifact.
|
|
1040
|
+
*/
|
|
1041
|
+
declare function solveRidgesDemo(): string;
|
|
1042
|
+
/**
|
|
1043
|
+
* The BUYER's independent recompute of the demo acceptance, as a score in [0, 1].
|
|
1044
|
+
* It reads the substantive output (the delivered test outputs) and recomputes the
|
|
1045
|
+
* expected FizzBuzz result for each; it deliberately IGNORES any self-reported
|
|
1046
|
+
* pass/coverage in the deliverable, so release can never be worker-controlled
|
|
1047
|
+
* (consult C10). Semantics:
|
|
1048
|
+
* - Any delivered test whose output is wrong = the suite did not pass (exit != 0):
|
|
1049
|
+
* score 0, no matter how much of the battery is covered.
|
|
1050
|
+
* - Otherwise the score is coverage = (distinct battery inputs delivered) / (battery
|
|
1051
|
+
* size); the buyer releases when it clears {@link RIDGES_DEMO_COVERAGE_TARGET}.
|
|
1052
|
+
* Malformed or unparseable content scores 0 and never throws.
|
|
1053
|
+
*/
|
|
1054
|
+
declare function scoreRidgesDemoDeliverable(content: string | Buffer): number;
|
|
1055
|
+
/**
|
|
1056
|
+
* Build a Ridges {@link ServiceAdapter}. Passes `assertServiceAdapterContract` with
|
|
1057
|
+
* the default ports; supply real ports for production use.
|
|
1058
|
+
*/
|
|
1059
|
+
declare function createRidgesAdapter(config?: RidgesAdapterConfig): ServiceAdapter;
|
|
1060
|
+
|
|
1061
|
+
/**
|
|
1062
|
+
* 404gen (Bittensor SN17) ServiceAdapter: a batch 3D-generation reference adapter,
|
|
1063
|
+
* built to the pattern the shipped Gradients (SN56) adapter established (P6.T6a). A
|
|
1064
|
+
* Worker Bot wraps the 404gen text-to-3D subnet behind the `ServiceAdapter` interface:
|
|
1065
|
+
* it swaps a per-task USDC budget into TAO internally, pays subnet miners in TAO to
|
|
1066
|
+
* generate a batch of 3D assets, collects the batch deliverable, and returns a
|
|
1067
|
+
* currency-free `ServiceResult`. The Buyer and the escrow contract only ever see USDC;
|
|
1068
|
+
* no TAO-typed value crosses this boundary into SDK core (ARCHITECTURE §3, §7; see
|
|
1069
|
+
* ../bittensor/bittensor.type-test.ts for the compile-time proof shared by the Bittensor trio).
|
|
1070
|
+
*
|
|
1071
|
+
* The swap, subnet call, and pinning are injectable ports so the reference runs (and
|
|
1072
|
+
* is tested) without a live DEX, subnet, or IPFS node. A production worker supplies
|
|
1073
|
+
* real implementations (Jupiter for the swap, the SN17 dendrite, Pinata/Arweave).
|
|
1074
|
+
*
|
|
1075
|
+
* RELEASE JUDGMENT IS NOT HERE. This adapter only PRODUCES the deliverable (a batch of
|
|
1076
|
+
* 3D assets, each with a declared container format and polygon count). Whether the batch
|
|
1077
|
+
* is acceptable is decided by the BUYER's review.ts. For the canned demo the buyer knows
|
|
1078
|
+
* the exact expected artifact (the eval-threshold review re-verifies the fetched
|
|
1079
|
+
* deliverable hashes to the submitted contentHash) and additionally gates on the declared
|
|
1080
|
+
* per-asset descriptors via `score404genDemoDeliverable` (format, polygon range, batch
|
|
1081
|
+
* completeness). That recompute reads the DECLARED descriptors, not the asset bytes: a
|
|
1082
|
+
* production 404gen buyer generating novel assets must derive the container from the
|
|
1083
|
+
* fetched asset's magic bytes and the polygon count from its parsed geometry before
|
|
1084
|
+
* releasing. The worker never scores-for-release and never releases (CLAUDE.md framing).
|
|
1085
|
+
*
|
|
1086
|
+
* The USDC->TAO port skeleton and the execute shape are shared with the other Bittensor
|
|
1087
|
+
* adapters via `../bittensor/index.js`; this module supplies only its subnet identity,
|
|
1088
|
+
* capabilities, budget, and demo logic.
|
|
1089
|
+
*/
|
|
1090
|
+
|
|
1091
|
+
/** Configuration and injectable ports for {@link create404genAdapter}. */
|
|
1092
|
+
interface Gen404AdapterConfig {
|
|
1093
|
+
/** Subnet identifier. Defaults to "sn17" (404gen); forms the adapter id `bittensor:<subnet>`. */
|
|
1094
|
+
subnet?: string;
|
|
1095
|
+
/** Advertised capabilities for EscroBots discovery. Defaults to `["3d-generation"]`. */
|
|
1096
|
+
capabilities?: string[];
|
|
1097
|
+
/** μUSDC the worker allocates to a single task before converting to TAO (internal budgeting). */
|
|
1098
|
+
taskBudgetMicroUsdc?: number;
|
|
1099
|
+
/** Swap port. Default: a fixed-rate reference stub. */
|
|
1100
|
+
swap?: UsdcToTaoSwap;
|
|
1101
|
+
/** Subnet-call port. Default: solves the canned demo job; a deterministic placeholder otherwise. */
|
|
1102
|
+
callSubnet?: SubnetCall;
|
|
1103
|
+
/** Pinning port. Default: a deterministic `ipfs://` placeholder URI. */
|
|
1104
|
+
pin?: PinContent$3;
|
|
1105
|
+
/** Health-check port. Default: resolves `true`. */
|
|
1106
|
+
checkHealth?: () => Promise<boolean>;
|
|
1107
|
+
}
|
|
1108
|
+
/** Stable id/capabilities, to be locked against `ADAPTER_DESCRIPTORS["404gen"]` by a kit test at merge (consult C2). */
|
|
1109
|
+
declare const GEN404_ADAPTER_ID = "bittensor:sn17";
|
|
1110
|
+
declare const GEN404_CAPABILITIES: readonly ["3d-generation"];
|
|
1111
|
+
/** Stable marker on the demo spec's metadata so the default subnet stub recognizes it. */
|
|
1112
|
+
declare const GEN404_DEMO_MARKER = "404gen-sn17-demo-v1";
|
|
1113
|
+
/** The demo eval floor: the batch must be complete and every asset valid (score 1). */
|
|
1114
|
+
declare const GEN404_DEMO_EVAL_FLOOR = 1;
|
|
1115
|
+
/**
|
|
1116
|
+
* The canned 404gen demo job. Deterministic; its specHash is pinned by a test
|
|
1117
|
+
* (consult C8) because the buyer journey depends on hash stability.
|
|
1118
|
+
*/
|
|
1119
|
+
declare const gen404DemoJobSpec: TaskSpec;
|
|
1120
|
+
/**
|
|
1121
|
+
* The reference solution to the demo job: a complete batch of valid assets plus a
|
|
1122
|
+
* (self-reported, buyer-ignored) eval block, as canonical JSON. Deterministic.
|
|
1123
|
+
* Exposed so the demo journey and tests share one source of the expected artifact.
|
|
1124
|
+
*/
|
|
1125
|
+
declare function solveGen404Demo(): string;
|
|
1126
|
+
/**
|
|
1127
|
+
* The BUYER's recompute of the demo batch score in [0, 1] over the deliverable's
|
|
1128
|
+
* DECLARED per-asset descriptors. Every delivered asset must pass the format and
|
|
1129
|
+
* polygon-range checks (any single invalid asset scores 0, so a well-formed but junk
|
|
1130
|
+
* extra cannot slip through), and the batch must contain at least the requested count
|
|
1131
|
+
* (completeness); a short batch scores the filled fraction. Any self-reported `eval`
|
|
1132
|
+
* score in the deliverable is ignored. Malformed or unparseable content scores 0 and
|
|
1133
|
+
* never throws.
|
|
1134
|
+
*
|
|
1135
|
+
* NOTE: this gates the deliverable's declared `format`/`polygonCount` fields, not the
|
|
1136
|
+
* asset bytes. For the deterministic canned demo that is sufficient because the buyer
|
|
1137
|
+
* additionally knows the exact expected artifact (the eval-threshold review re-verifies
|
|
1138
|
+
* the fetched deliverable hashes to the submitted contentHash). A production 404gen
|
|
1139
|
+
* buyer generating NOVEL assets must derive the container from the fetched asset's magic
|
|
1140
|
+
* bytes and the polygon count from its parsed geometry before releasing (kit-docs debt).
|
|
1141
|
+
*/
|
|
1142
|
+
declare function score404genDemoDeliverable(content: string | Buffer): number;
|
|
1143
|
+
/**
|
|
1144
|
+
* Build a 404gen (SN17) {@link ServiceAdapter}. Passes `assertServiceAdapterContract`
|
|
1145
|
+
* with the default ports; supply real ports for production use. The USDC->TAO swap,
|
|
1146
|
+
* pinning, and execute skeleton come from the shared Bittensor core.
|
|
1147
|
+
*/
|
|
1148
|
+
declare function create404genAdapter(config?: Gen404AdapterConfig): ServiceAdapter;
|
|
1149
|
+
|
|
1150
|
+
/**
|
|
1151
|
+
* Lium (Bittensor SN51) ServiceAdapter: a SHIPPED, supported adapter following the
|
|
1152
|
+
* P6.T6a Gradients pattern. A Worker Bot wraps the Lium GPU-compute subnet behind the
|
|
1153
|
+
* `ServiceAdapter` interface: it swaps a per-task USDC budget into TAO internally,
|
|
1154
|
+
* rents GPU compute from subnet miners in TAO to run the job, collects the output
|
|
1155
|
+
* artifact, and returns a currency-free `ServiceResult`. The Buyer and the escrow
|
|
1156
|
+
* contract only ever see USDC; no TAO-typed value crosses this boundary into SDK core
|
|
1157
|
+
* (ARCHITECTURE §3, §7; see ../bittensor/bittensor.type-test.ts for the compile-time
|
|
1158
|
+
* proof shared by the Bittensor trio).
|
|
1159
|
+
*
|
|
1160
|
+
* The swap, GPU-job call, and pinning are injectable ports so the reference runs (and
|
|
1161
|
+
* is tested) without a live DEX, subnet, or IPFS node. A production worker supplies
|
|
1162
|
+
* real implementations (Jupiter for the swap, the SN51 GPU-rental dendrite,
|
|
1163
|
+
* Pinata/Arweave for pinning).
|
|
1164
|
+
*
|
|
1165
|
+
* RELEASE JUDGMENT IS NOT HERE. This adapter only PRODUCES the deliverable (the job's
|
|
1166
|
+
* output artifact). Whether the job completed with a matching artifact is decided by
|
|
1167
|
+
* the BUYER's review.ts, which independently recomputes the scripted job's output and
|
|
1168
|
+
* compares hashes (see `scoreLiumDemoDeliverable`). The worker never scores-for-release
|
|
1169
|
+
* and never releases, and its self-reported `artifactHash` is never trusted
|
|
1170
|
+
* (CLAUDE.md product framing: the buyer is the judge).
|
|
1171
|
+
*
|
|
1172
|
+
* The USDC->TAO port skeleton and the execute shape are shared with the other Bittensor
|
|
1173
|
+
* adapters via `../bittensor/index.js`; this module supplies only its subnet identity,
|
|
1174
|
+
* capabilities, budget, and demo logic. A GPU-rental call is a paid subnet call, so its
|
|
1175
|
+
* port reuses the shared `SubnetCall` shape under the local `RunGpuJob` name.
|
|
1176
|
+
*/
|
|
1177
|
+
|
|
1178
|
+
/** Rent GPU compute for `budget` TAO and run `spec`'s job; resolve with the raw output artifact. */
|
|
1179
|
+
type RunGpuJob = SubnetCall;
|
|
1180
|
+
/** Configuration and injectable ports for {@link createLiumAdapter}. */
|
|
1181
|
+
interface LiumAdapterConfig {
|
|
1182
|
+
/** Subnet identifier. Defaults to "sn51" (Lium GPU compute); forms the adapter id `bittensor:<subnet>`. */
|
|
1183
|
+
subnet?: string;
|
|
1184
|
+
/** Advertised capabilities for EscroBots discovery. Defaults to `["gpu-compute"]`. */
|
|
1185
|
+
capabilities?: string[];
|
|
1186
|
+
/** μUSDC the worker allocates to a single task before converting to TAO (internal budgeting). */
|
|
1187
|
+
taskBudgetMicroUsdc?: number;
|
|
1188
|
+
/** Swap port. Default: a fixed-rate reference stub. */
|
|
1189
|
+
swap?: UsdcToTaoSwap;
|
|
1190
|
+
/** GPU-job port. Default: runs the canned demo job; a deterministic placeholder otherwise. */
|
|
1191
|
+
runJob?: RunGpuJob;
|
|
1192
|
+
/** Pinning port. Default: a deterministic `ipfs://` placeholder URI. */
|
|
1193
|
+
pin?: PinContent$3;
|
|
1194
|
+
/** Health-check port. Default: resolves `true`. */
|
|
1195
|
+
checkHealth?: () => Promise<boolean>;
|
|
1196
|
+
}
|
|
1197
|
+
declare const LIUM_ADAPTER_ID = "bittensor:sn51";
|
|
1198
|
+
declare const LIUM_CAPABILITIES: readonly ["gpu-compute"];
|
|
1199
|
+
/** Stable marker on the demo spec's metadata so the default job stub recognizes it. */
|
|
1200
|
+
declare const LIUM_DEMO_MARKER = "lium-sn51-demo-v1";
|
|
1201
|
+
/** The demo accept floor: hash-match is exact, so the buyer requires a full match. */
|
|
1202
|
+
declare const LIUM_DEMO_ACCEPT_FLOOR = 1;
|
|
1203
|
+
/**
|
|
1204
|
+
* The scripted GPU job's deterministic output artifact: a hash chain over the fixed
|
|
1205
|
+
* seed. Deterministic and cheap to recompute, so the buyer can verify it independently.
|
|
1206
|
+
*/
|
|
1207
|
+
declare function computeLiumDemoArtifact(): string;
|
|
1208
|
+
/**
|
|
1209
|
+
* The canned Lium demo job. Deterministic; its specHash is pinned by a test (consult
|
|
1210
|
+
* C8) because the buyer journey depends on hash stability.
|
|
1211
|
+
*/
|
|
1212
|
+
declare const liumDemoJobSpec: TaskSpec;
|
|
1213
|
+
/**
|
|
1214
|
+
* The reference solution to the demo job: the completed job report carrying the
|
|
1215
|
+
* correct output artifact plus a (self-reported, buyer-ignored) artifactHash, as
|
|
1216
|
+
* canonical JSON. Deterministic. Exposed so the demo journey and tests share one
|
|
1217
|
+
* source of the expected artifact.
|
|
1218
|
+
*/
|
|
1219
|
+
declare function solveLiumDemo(): string;
|
|
1220
|
+
/**
|
|
1221
|
+
* The BUYER's independent recompute of the demo acceptance predicate, returning 1
|
|
1222
|
+
* when the deliverable satisfies all three criteria and 0 otherwise. It checks
|
|
1223
|
+
* completion (status), artifact presence, and hash match by RECOMPUTING the scripted
|
|
1224
|
+
* job's output and comparing the substantive artifact; it deliberately IGNORES any
|
|
1225
|
+
* self-reported `artifactHash`, so release can never be worker-controlled (consult
|
|
1226
|
+
* C10). Malformed or unparseable content scores 0 and never throws.
|
|
1227
|
+
*/
|
|
1228
|
+
declare function scoreLiumDemoDeliverable(content: string | Buffer): number;
|
|
1229
|
+
/**
|
|
1230
|
+
* Build a Lium (SN51) {@link ServiceAdapter}. Passes `assertServiceAdapterContract`
|
|
1231
|
+
* with the default ports; supply real ports for production use. The USDC->TAO swap,
|
|
1232
|
+
* pinning, and execute skeleton come from the shared Bittensor core; the GPU-rental
|
|
1233
|
+
* port is wired in as the core's `callSubnet`.
|
|
1234
|
+
*/
|
|
1235
|
+
declare function createLiumAdapter(config?: LiumAdapterConfig): ServiceAdapter;
|
|
1236
|
+
|
|
1237
|
+
/**
|
|
1238
|
+
* Amount denominated in AKT (Akash's token). Branded so it cannot be assigned to or from a
|
|
1239
|
+
* plain `number` by accident and (the point of the brand) so it can never appear in a
|
|
1240
|
+
* `ServiceResult` or the escrow submit path: those types have no field of this type. AKT
|
|
1241
|
+
* exists ONLY inside the Akash adapter layer.
|
|
1242
|
+
*/
|
|
1243
|
+
type Akt = number & {
|
|
1244
|
+
readonly __brand: "AKT";
|
|
1245
|
+
};
|
|
1246
|
+
/** Construct an {@link Akt} amount from a plain number. Adapter-internal use only. */
|
|
1247
|
+
declare function akt(amount: number): Akt;
|
|
1248
|
+
/** Swap a microUSDC budget into AKT. Real workers route this through a DEX/CEX. */
|
|
1249
|
+
type UsdcToAktSwap = (microUsdc: number) => Promise<Akt>;
|
|
1250
|
+
/**
|
|
1251
|
+
* Provision an Akash deployment/lease funded with `budget` AKT to run `spec`; resolve with
|
|
1252
|
+
* the raw deliverable (the job's output artifact).
|
|
1253
|
+
*/
|
|
1254
|
+
type RunAkashDeployment = (spec: TaskSpec, budget: Akt) => Promise<string | Buffer>;
|
|
1255
|
+
/** Pin `content` and resolve with a content-addressed proof URI (ipfs://, ar://). */
|
|
1256
|
+
type PinContent$1 = (content: string | Buffer) => Promise<string>;
|
|
1257
|
+
/**
|
|
1258
|
+
* Stable id/capabilities. The adapter's own tests pin its runtime output to these
|
|
1259
|
+
* constants; the EscroBots registry descriptor for `akash` is registered separately in
|
|
1260
|
+
* P8.T6 (capability taxonomy extension).
|
|
1261
|
+
*/
|
|
1262
|
+
declare const AKASH_ADAPTER_ID = "akash";
|
|
1263
|
+
declare const AKASH_CAPABILITIES: readonly ["cloud-compute"];
|
|
1264
|
+
declare const REFERENCE_MICRO_USDC_PER_AKT = 3000000;
|
|
1265
|
+
/** Configuration and injectable ports for {@link createAkashAdapter}. */
|
|
1266
|
+
interface AkashAdapterConfig {
|
|
1267
|
+
/** Advertised capabilities for EscroBots discovery. Defaults to `["cloud-compute"]`. */
|
|
1268
|
+
capabilities?: string[];
|
|
1269
|
+
/** μUSDC the worker allocates to a single task before converting to AKT (internal budgeting). */
|
|
1270
|
+
taskBudgetMicroUsdc?: number;
|
|
1271
|
+
/** Swap port. Default: a fixed-rate reference stub. */
|
|
1272
|
+
swap?: UsdcToAktSwap;
|
|
1273
|
+
/** Deployment port. Default: runs the canned demo job; a deterministic placeholder otherwise. */
|
|
1274
|
+
runDeployment?: RunAkashDeployment;
|
|
1275
|
+
/** Pinning port. Default: a deterministic `ipfs://` placeholder URI. */
|
|
1276
|
+
pin?: PinContent$1;
|
|
1277
|
+
/** Health-check port. Default: resolves `true`. */
|
|
1278
|
+
checkHealth?: () => Promise<boolean>;
|
|
1279
|
+
}
|
|
1280
|
+
/** Stable marker on the demo spec's metadata so the default deployment stub recognizes it. */
|
|
1281
|
+
declare const AKASH_DEMO_MARKER = "akash-demo-v1";
|
|
1282
|
+
/** The demo accept floor: hash-match is exact, so the buyer requires a full match. */
|
|
1283
|
+
declare const AKASH_DEMO_ACCEPT_FLOOR = 1;
|
|
1284
|
+
/**
|
|
1285
|
+
* The scripted batch job's deterministic output artifact: a hash chain over the fixed
|
|
1286
|
+
* seed. Deterministic and cheap to recompute, so the buyer can verify it independently.
|
|
1287
|
+
*/
|
|
1288
|
+
declare function computeAkashDemoArtifact(): string;
|
|
1289
|
+
/**
|
|
1290
|
+
* The canned Akash demo job. Deterministic; its specHash is pinned by a test because the
|
|
1291
|
+
* buyer journey depends on hash stability.
|
|
1292
|
+
*/
|
|
1293
|
+
declare const akashDemoJobSpec: TaskSpec;
|
|
1294
|
+
/**
|
|
1295
|
+
* The reference solution to the demo job: the completed job report carrying the correct
|
|
1296
|
+
* output artifact plus a (self-reported, buyer-ignored) artifactHash, as canonical JSON.
|
|
1297
|
+
* Deterministic. Exposed so the demo journey and tests share one source of the expected
|
|
1298
|
+
* artifact.
|
|
1299
|
+
*/
|
|
1300
|
+
declare function solveAkashDemo(): string;
|
|
1301
|
+
/**
|
|
1302
|
+
* The BUYER's independent recompute of the demo acceptance predicate, returning 1 when the
|
|
1303
|
+
* deliverable satisfies all three criteria and 0 otherwise. It checks completion (status),
|
|
1304
|
+
* artifact presence, and hash match by RECOMPUTING the scripted job's output and comparing
|
|
1305
|
+
* the substantive artifact; it deliberately IGNORES any self-reported `artifactHash`, so
|
|
1306
|
+
* release can never be worker-controlled. Malformed or unparseable content scores 0 and
|
|
1307
|
+
* never throws.
|
|
1308
|
+
*/
|
|
1309
|
+
declare function scoreAkashDemoDeliverable(content: string | Buffer): number;
|
|
1310
|
+
/**
|
|
1311
|
+
* Build an Akash {@link ServiceAdapter}. Passes `assertServiceAdapterContract` with the
|
|
1312
|
+
* default ports; supply real ports for production use. The execute skeleton: swap the USDC
|
|
1313
|
+
* budget into AKT (internal, never surfaced), provision the deployment and collect the
|
|
1314
|
+
* output, then hash and pin. The recorded `ServiceResult` is currency-free (no AKT field).
|
|
1315
|
+
*/
|
|
1316
|
+
declare function createAkashAdapter(config?: AkashAdapterConfig): ServiceAdapter;
|
|
1317
|
+
|
|
1318
|
+
/**
|
|
1319
|
+
* Amount denominated in RENDER (Render Network's Solana SPL token). Branded so it cannot
|
|
1320
|
+
* be assigned to or from a plain `number` by accident and (the point of the brand) so it
|
|
1321
|
+
* can never appear in a `ServiceResult` or the escrow submit path: those types have no
|
|
1322
|
+
* field of this type. RENDER exists ONLY inside this adapter module.
|
|
1323
|
+
*/
|
|
1324
|
+
type Render = number & {
|
|
1325
|
+
readonly __brand: "RENDER";
|
|
1326
|
+
};
|
|
1327
|
+
/** Construct a {@link Render} amount from a plain number. Adapter-internal use only. */
|
|
1328
|
+
declare function renderAmount(amount: number): Render;
|
|
1329
|
+
/** Swap a microUSDC budget into RENDER. Real workers route this through a Solana DEX (e.g. Jupiter). */
|
|
1330
|
+
type UsdcToRenderSwap = (microUsdc: number) => Promise<Render>;
|
|
1331
|
+
/** Submit `spec`'s render job funded with `budget` RENDER; resolve with the raw rendered artifact. */
|
|
1332
|
+
type RunRenderJob = (spec: TaskSpec, budget: Render) => Promise<string | Buffer>;
|
|
1333
|
+
/** Pin `content` and resolve with a content-addressed proof URI (ipfs://, ar://). */
|
|
1334
|
+
type PinContent = (content: string | Buffer) => Promise<string>;
|
|
1335
|
+
/** Configuration and injectable ports for {@link createRenderAdapter}. */
|
|
1336
|
+
interface RenderAdapterConfig {
|
|
1337
|
+
/** Service identifier. Defaults to "render"; forms the adapter id. */
|
|
1338
|
+
service?: string;
|
|
1339
|
+
/** Advertised capabilities for EscroBots discovery. Defaults to {@link RENDER_CAPABILITIES}. */
|
|
1340
|
+
capabilities?: string[];
|
|
1341
|
+
/** microUSDC the worker allocates to a single task before converting to RENDER (internal budgeting). */
|
|
1342
|
+
taskBudgetMicroUsdc?: number;
|
|
1343
|
+
/** Swap port. Default: a fixed-rate reference stub (no live price feed). */
|
|
1344
|
+
swap?: UsdcToRenderSwap;
|
|
1345
|
+
/** Render-job port. Default: renders the canned demo scene; a deterministic placeholder otherwise. */
|
|
1346
|
+
runJob?: RunRenderJob;
|
|
1347
|
+
/** Pinning port. Default: a deterministic `ipfs://` placeholder URI. */
|
|
1348
|
+
pin?: PinContent;
|
|
1349
|
+
/** Health-check port. Default: resolves `true`. */
|
|
1350
|
+
checkHealth?: () => Promise<boolean>;
|
|
1351
|
+
}
|
|
1352
|
+
declare const RENDER_ADAPTER_ID = "render";
|
|
1353
|
+
declare const RENDER_CAPABILITIES: readonly ["3d-rendering", "video-rendering", "gpu-inference"];
|
|
1354
|
+
declare const REFERENCE_MICRO_USDC_PER_RENDER = 2000000;
|
|
1355
|
+
/** Stable marker on the demo spec's metadata so the default job stub recognizes it. */
|
|
1356
|
+
declare const RENDER_DEMO_MARKER = "render-demo-v1";
|
|
1357
|
+
/** The demo accept floor: frame-match is exact, so the buyer requires a full match. */
|
|
1358
|
+
declare const RENDER_DEMO_ACCEPT_FLOOR = 1;
|
|
1359
|
+
/**
|
|
1360
|
+
* Render the fixed demo scene into a grayscale raster and return its hex encoding.
|
|
1361
|
+
* Deterministic and cheap to recompute, so the buyer verifies the frame independently.
|
|
1362
|
+
*/
|
|
1363
|
+
declare function computeRenderDemoArtifact(): string;
|
|
1364
|
+
/**
|
|
1365
|
+
* The canned Render demo job. Deterministic; its specHash is pinned by a test because
|
|
1366
|
+
* the buyer journey depends on hash stability.
|
|
1367
|
+
*/
|
|
1368
|
+
declare const renderDemoJobSpec: TaskSpec;
|
|
1369
|
+
/**
|
|
1370
|
+
* The reference solution to the demo job: the completed job report carrying the correct
|
|
1371
|
+
* rendered frame plus a (self-reported, buyer-ignored) frameHash, as canonical JSON.
|
|
1372
|
+
* Deterministic. Exposed so the demo journey and tests share one source of the expected
|
|
1373
|
+
* artifact.
|
|
1374
|
+
*/
|
|
1375
|
+
declare function solveRenderDemo(): string;
|
|
1376
|
+
/**
|
|
1377
|
+
* The BUYER's independent recompute of the demo acceptance predicate, returning 1 when
|
|
1378
|
+
* the deliverable satisfies all three criteria and 0 otherwise. It checks completion
|
|
1379
|
+
* (status), frame presence, and a frame match by RE-RENDERING the scripted scene and
|
|
1380
|
+
* comparing the substantive frame; it deliberately IGNORES any self-reported
|
|
1381
|
+
* `frameHash`, so release can never be worker-controlled (consult C10). Malformed or
|
|
1382
|
+
* unparseable content scores 0 and never throws.
|
|
1383
|
+
*/
|
|
1384
|
+
declare function scoreRenderDemoDeliverable(content: string | Buffer): number;
|
|
1385
|
+
/**
|
|
1386
|
+
* Build a Render {@link ServiceAdapter}. Passes `assertServiceAdapterContract` with the
|
|
1387
|
+
* default ports; supply real ports for production use. The execute skeleton: swap the
|
|
1388
|
+
* USDC budget into RENDER (internal, same-chain, never surfaced), pay the render job in
|
|
1389
|
+
* RENDER and collect the frame, then hash and pin. The recorded `ServiceResult` is
|
|
1390
|
+
* currency-free (no RENDER field).
|
|
1391
|
+
*/
|
|
1392
|
+
declare function createRenderAdapter(config?: RenderAdapterConfig): ServiceAdapter;
|
|
1393
|
+
|
|
1394
|
+
/** Stable adapter identity + EscroBots capability (locked by gensyn.test.ts). */
|
|
1395
|
+
declare const GENSYN_ADAPTER_ID = "gensyn";
|
|
1396
|
+
declare const GENSYN_CAPABILITIES: readonly ["verifiable-compute"];
|
|
1397
|
+
/** REE proof scheme tag. A verifier accepts only proofs carrying this exact scheme. */
|
|
1398
|
+
declare const GENSYN_REE_SCHEME = "gensyn-ree-v1";
|
|
1399
|
+
/** Marker on the demo spec's metadata so the default reproducible compute recognizes it. */
|
|
1400
|
+
declare const GENSYN_DEMO_MARKER = "gensyn-ree-demo-v1";
|
|
1401
|
+
/** The result of one reproducible execution: its transcript and final output. */
|
|
1402
|
+
interface ReeExecution {
|
|
1403
|
+
/** Seed the walk started from. */
|
|
1404
|
+
seed: number;
|
|
1405
|
+
/** Number of steps walked. */
|
|
1406
|
+
steps: number;
|
|
1407
|
+
/** Ordered per-step states (the execution transcript). */
|
|
1408
|
+
states: number[];
|
|
1409
|
+
/** Final state (the deliverable's numeric result). */
|
|
1410
|
+
result: number;
|
|
1411
|
+
}
|
|
1412
|
+
/** Run the reproducible compute for `spec`, deriving the transcript and result. */
|
|
1413
|
+
type ReproduceCompute = (spec: TaskSpec) => ReeExecution;
|
|
1414
|
+
/**
|
|
1415
|
+
* The reference reproducible execution. Deterministic from `spec` (its seed/steps
|
|
1416
|
+
* come from `spec.metadata`, defaulting to the demo parameters), so both worker and
|
|
1417
|
+
* buyer derive the same transcript.
|
|
1418
|
+
*/
|
|
1419
|
+
declare const reproduceGensynCompute: ReproduceCompute;
|
|
1420
|
+
/**
|
|
1421
|
+
* A Gensyn REE proof. Every field is a commitment the buyer re-derives:
|
|
1422
|
+
* `commitment` binds the whole tuple, `outputHash` binds the delivered content,
|
|
1423
|
+
* `specHash` binds the task asked, `transcriptHash` binds the reproducible run.
|
|
1424
|
+
*/
|
|
1425
|
+
interface ReeProof {
|
|
1426
|
+
scheme: typeof GENSYN_REE_SCHEME;
|
|
1427
|
+
/** SHA-256 hex of the canonical task spec. */
|
|
1428
|
+
specHash: string;
|
|
1429
|
+
/** SHA-256 hex of the delivered content. */
|
|
1430
|
+
outputHash: string;
|
|
1431
|
+
/** Number of reproducible execution steps (positive integer). */
|
|
1432
|
+
steps: number;
|
|
1433
|
+
/** SHA-256 hex of the canonical execution transcript. */
|
|
1434
|
+
transcriptHash: string;
|
|
1435
|
+
/** SHA-256 hex binding scheme, specHash, outputHash, steps, and transcriptHash. */
|
|
1436
|
+
commitment: string;
|
|
1437
|
+
}
|
|
1438
|
+
/**
|
|
1439
|
+
* Build the REE proof a worker attaches to its deliverable. Not a trust anchor on
|
|
1440
|
+
* its own: `verifyReeProof` re-derives every field, so a proof only accepts when it
|
|
1441
|
+
* genuinely binds the content, spec, and a reproducible transcript.
|
|
1442
|
+
*/
|
|
1443
|
+
declare function buildReeProof(spec: TaskSpec, exec: ReeExecution, content: string | Buffer): ReeProof;
|
|
1444
|
+
/** The verifier's verdict: a proof is either valid, or invalid/malformed with a reason. */
|
|
1445
|
+
interface ReeVerification {
|
|
1446
|
+
valid: boolean;
|
|
1447
|
+
/** Prefixed `malformed` (shape/structure) or `invalid` (a binding failed), or a pass note. */
|
|
1448
|
+
reason: string;
|
|
1449
|
+
}
|
|
1450
|
+
/** Inputs the buyer verifies a proof against: the task asked and the content received. */
|
|
1451
|
+
interface ReeVerifyContext {
|
|
1452
|
+
/** The task spec the buyer commissioned. */
|
|
1453
|
+
spec: TaskSpec;
|
|
1454
|
+
/** The deliverable content the buyer received (fetched from proofUri in production). */
|
|
1455
|
+
content: string | Buffer;
|
|
1456
|
+
/** The reproducible compute; defaults to the reference {@link reproduceGensynCompute}. */
|
|
1457
|
+
reproduce?: ReproduceCompute;
|
|
1458
|
+
}
|
|
1459
|
+
/**
|
|
1460
|
+
* The BUYER's verification of an REE proof (untrusted input from the worker). Returns
|
|
1461
|
+
* `valid: true` only when the proof is well-formed AND every binding holds: the
|
|
1462
|
+
* commitment is self-consistent, the committed output hash equals the delivered
|
|
1463
|
+
* content, the spec hash equals the commissioned task, and the transcript hash
|
|
1464
|
+
* matches the buyer's own reproduction of the execution. Never throws.
|
|
1465
|
+
*/
|
|
1466
|
+
declare function verifyReeProof(proof: unknown, ctx: ReeVerifyContext): ReeVerification;
|
|
1467
|
+
/** What the buyer assembles to decide acceptance: the received content and the worker's proof. */
|
|
1468
|
+
interface GensynDeliverableBundle {
|
|
1469
|
+
/** The deliverable content the buyer received. */
|
|
1470
|
+
content: string | Buffer;
|
|
1471
|
+
/** The REE proof the worker attached (untrusted; verified before any release). */
|
|
1472
|
+
proof: unknown;
|
|
1473
|
+
}
|
|
1474
|
+
/** A buyer auto-release decision. `release: true` means "call release_payment()". */
|
|
1475
|
+
interface AutoReleaseDecision {
|
|
1476
|
+
release: boolean;
|
|
1477
|
+
reason: string;
|
|
1478
|
+
}
|
|
1479
|
+
/**
|
|
1480
|
+
* The buyer bot's auto-release decision for a Gensyn deliverable. Releases ONLY when
|
|
1481
|
+
* the REE proof verifies against the delivered content and the commissioned spec;
|
|
1482
|
+
* an invalid or malformed proof never releases. This is the whole T4 acceptance
|
|
1483
|
+
* mechanism, and it lives entirely at the buyer layer.
|
|
1484
|
+
*/
|
|
1485
|
+
declare function gensynAutoRelease(bundle: GensynDeliverableBundle, ctx: {
|
|
1486
|
+
spec: TaskSpec;
|
|
1487
|
+
reproduce?: ReproduceCompute;
|
|
1488
|
+
}): AutoReleaseDecision;
|
|
1489
|
+
/** Configuration and injectable ports for {@link createGensynAdapter}. */
|
|
1490
|
+
interface GensynAdapterConfig {
|
|
1491
|
+
/** Advertised capabilities for EscroBots discovery. Defaults to `["verifiable-compute"]`. */
|
|
1492
|
+
capabilities?: string[];
|
|
1493
|
+
/** The reproducible compute the worker runs. Default: the reference LCG walk. */
|
|
1494
|
+
runCompute?: ReproduceCompute;
|
|
1495
|
+
/** Pinning port. Default: a deterministic `ipfs://` placeholder URI. */
|
|
1496
|
+
pin?: (content: string | Buffer) => Promise<string>;
|
|
1497
|
+
/** Health-check port. Default: resolves `true`. */
|
|
1498
|
+
checkHealth?: () => Promise<boolean>;
|
|
1499
|
+
}
|
|
1500
|
+
/** The canned demo job the buyer template's journey hires a Gensyn worker for. */
|
|
1501
|
+
declare const gensynDemoJobSpec: TaskSpec;
|
|
1502
|
+
/**
|
|
1503
|
+
* Build a Gensyn {@link ServiceAdapter}. `execute` runs the reproducible compute,
|
|
1504
|
+
* serializes the deliverable, and attaches an REE proof (in `metadata.reeProof`) the
|
|
1505
|
+
* buyer verifies with {@link verifyReeProof} / {@link gensynAutoRelease}. Passes
|
|
1506
|
+
* `assertServiceAdapterContract` with the default ports; supply real ports (a real
|
|
1507
|
+
* Gensyn job runner, a real pinner) for production.
|
|
1508
|
+
*/
|
|
1509
|
+
declare function createGensynAdapter(config?: GensynAdapterConfig): ServiceAdapter;
|
|
1510
|
+
|
|
1511
|
+
/** Stable id/capabilities; locked against the EscroBots registry descriptor by a kit test at merge (consult C2). */
|
|
1512
|
+
declare const ZKML_ADAPTER_ID = "zkml";
|
|
1513
|
+
declare const ZKML_CAPABILITIES: readonly ["zk-verified-inference"];
|
|
1514
|
+
/** Marker on the demo spec's metadata so the default inference port recognizes it. */
|
|
1515
|
+
declare const ZKML_DEMO_MARKER = "zkml-demo-v1";
|
|
1516
|
+
/** The reference proving scheme this verifier understands. Unknown schemes are malformed to it. */
|
|
1517
|
+
declare const ZKML_PROOF_SCHEME = "escro-zkml-ref-v1";
|
|
1518
|
+
/** Prefix marking an inline (self-contained) zkml proof URI: `zkml-proof:<base64url(json)>`. */
|
|
1519
|
+
declare const ZKML_PROOF_URI_PREFIX = "zkml-proof:";
|
|
1520
|
+
/**
|
|
1521
|
+
* A ZKML proof: its public inputs plus a `verificationTag` binding them. In the
|
|
1522
|
+
* reference scheme the tag is recomputable (see {@link computeZkmlVerificationTag});
|
|
1523
|
+
* in a production scheme it is a SNARK/STARK checked against a verifying key over the
|
|
1524
|
+
* same public inputs.
|
|
1525
|
+
*/
|
|
1526
|
+
interface ZkmlProof {
|
|
1527
|
+
/** Proving scheme identifier; the verifier only understands {@link ZKML_PROOF_SCHEME}. */
|
|
1528
|
+
scheme: string;
|
|
1529
|
+
/** Commitment to the model that produced the output (e.g. a weights hash). */
|
|
1530
|
+
modelCommitment: string;
|
|
1531
|
+
/** Commitment to the input the model was run on. */
|
|
1532
|
+
inputCommitment: string;
|
|
1533
|
+
/** SHA-256 hex of the delivered output; binds the proof to a specific deliverable. */
|
|
1534
|
+
outputHash: string;
|
|
1535
|
+
/** Binding tag over the public inputs (reference: recomputable; production: a SNARK). */
|
|
1536
|
+
verificationTag: string;
|
|
1537
|
+
}
|
|
1538
|
+
/** Build a well-formed reference proof binding the given public inputs. */
|
|
1539
|
+
declare function buildZkmlProof(args: {
|
|
1540
|
+
scheme?: string;
|
|
1541
|
+
modelCommitment: string;
|
|
1542
|
+
inputCommitment: string;
|
|
1543
|
+
outputHash: string;
|
|
1544
|
+
}): ZkmlProof;
|
|
1545
|
+
/** Encode a proof as a self-contained inline proof URI. */
|
|
1546
|
+
declare function encodeZkmlProofUri(proof: ZkmlProof): string;
|
|
1547
|
+
/**
|
|
1548
|
+
* Decode an inline zkml proof URI back to a {@link ZkmlProof}. Returns null for any
|
|
1549
|
+
* URI that is not an inline zkml proof or does not decode to the proof shape (a
|
|
1550
|
+
* pinned `ipfs://`/`ar://` proof is fetched by the caller, then passed to
|
|
1551
|
+
* {@link verifyZkmlProof} directly).
|
|
1552
|
+
*/
|
|
1553
|
+
declare function decodeZkmlProofUri(uri: string): ZkmlProof | null;
|
|
1554
|
+
/**
|
|
1555
|
+
* The outcome of verifying a proof. `malformed` = the verifier cannot understand the
|
|
1556
|
+
* proof (missing/wrong-typed fields, unsupported scheme, undecodable URI); `invalid`
|
|
1557
|
+
* = a well-formed proof that fails verification (tag does not recompute, or attests a
|
|
1558
|
+
* different output/model than expected).
|
|
1559
|
+
*/
|
|
1560
|
+
type ZkmlVerification = {
|
|
1561
|
+
valid: true;
|
|
1562
|
+
} | {
|
|
1563
|
+
valid: false;
|
|
1564
|
+
category: "invalid" | "malformed";
|
|
1565
|
+
reason: string;
|
|
1566
|
+
};
|
|
1567
|
+
/** What the Buyer expects the proof to attest to. */
|
|
1568
|
+
interface ZkmlExpectation {
|
|
1569
|
+
/** The submitted deliverable's contentHash; the proof's outputHash must equal it. */
|
|
1570
|
+
contentHash: string;
|
|
1571
|
+
/** When set, the proof's modelCommitment must equal it (pin to a specific model). */
|
|
1572
|
+
modelCommitment?: string;
|
|
1573
|
+
}
|
|
1574
|
+
/**
|
|
1575
|
+
* Verify a decoded proof against the Buyer's expectation. NOTE: this is the REFERENCE
|
|
1576
|
+
* verifier and is NOT cryptographically sound -- the tag is a keyless hash, so a `valid`
|
|
1577
|
+
* result means only that the proof is internally consistent and bound to
|
|
1578
|
+
* `expected.contentHash`, not that a trustworthy party produced it. Pass a real verifier
|
|
1579
|
+
* to {@link zkmlProofAutoRelease} for production. `malformed` = an unusable proof;
|
|
1580
|
+
* `invalid` = a usable proof that fails the checks.
|
|
1581
|
+
*/
|
|
1582
|
+
declare function verifyZkmlProof(proof: unknown, expected: ZkmlExpectation): ZkmlVerification;
|
|
1583
|
+
/** Decode an inline proof URI (or reject a missing/foreign one) and verify it. */
|
|
1584
|
+
declare function verifyZkmlProofUri(uri: string | null | undefined, expected: ZkmlExpectation): ZkmlVerification;
|
|
1585
|
+
/** The submitted deliverable as the Buyer's review reads it off the escrow read model. */
|
|
1586
|
+
interface ZkmlDeliverable {
|
|
1587
|
+
/**
|
|
1588
|
+
* SHA-256 hex the WORKER submitted on-chain (mirrored to the read model). It is the
|
|
1589
|
+
* worker's CLAIM about the artifact; {@link zkmlProofAutoRelease} re-hashes the real
|
|
1590
|
+
* artifact (via its `fetchContent` port) and never trusts this value on its own.
|
|
1591
|
+
*/
|
|
1592
|
+
contentHash: string;
|
|
1593
|
+
/** URI where the ZK proof is (inline `zkml-proof:` or a pinned `ipfs://`), or null. */
|
|
1594
|
+
proofUri: string | null;
|
|
1595
|
+
}
|
|
1596
|
+
/** A release decision: release, and if not, whether to contest via dispute. */
|
|
1597
|
+
interface ZkmlReviewResult {
|
|
1598
|
+
accept: boolean;
|
|
1599
|
+
dispute: boolean;
|
|
1600
|
+
reason: string;
|
|
1601
|
+
}
|
|
1602
|
+
/**
|
|
1603
|
+
* A named release policy the Buyer's review wires in. Field-for-field this mirrors the
|
|
1604
|
+
* buyer template's `ReviewPolicy`
|
|
1605
|
+
* (packages/create-escro-bot/templates/buyer/src/review.ts). The SDK cannot import the
|
|
1606
|
+
* scaffolding templates, and promoting the shared review shapes into `@escro/shared` is
|
|
1607
|
+
* a cross-package change owned by `main`, not this lane -- tracked as a merge-time
|
|
1608
|
+
* follow-up (LANE-NOTES).
|
|
1609
|
+
*/
|
|
1610
|
+
interface ZkmlReviewPolicy {
|
|
1611
|
+
name: string;
|
|
1612
|
+
evaluate(deliverable: ZkmlDeliverable): Promise<ZkmlReviewResult>;
|
|
1613
|
+
}
|
|
1614
|
+
/** Options for {@link zkmlProofAutoRelease}. */
|
|
1615
|
+
interface ZkmlProofAutoReleaseOptions {
|
|
1616
|
+
/**
|
|
1617
|
+
* Fetch the ACTUAL delivered artifact so the predicate can re-hash it. Integrity comes
|
|
1618
|
+
* from the buyer recomputing `sha256(artifact)` and requiring it equals the worker-
|
|
1619
|
+
* submitted `contentHash` -- never from trusting the submitted hash (mirror of the
|
|
1620
|
+
* buyer template's `evalThresholdReview`). Required: without the artifact the predicate
|
|
1621
|
+
* would be trusting a worker-chosen number.
|
|
1622
|
+
*/
|
|
1623
|
+
fetchContent: (deliverable: ZkmlDeliverable) => Promise<string | Buffer> | string | Buffer;
|
|
1624
|
+
/** When set, the proof's modelCommitment must equal it (pin to a specific model). */
|
|
1625
|
+
modelCommitment?: string;
|
|
1626
|
+
/**
|
|
1627
|
+
* The proof verifier. DEFAULT is {@link verifyZkmlProof}, the reference verifier, which
|
|
1628
|
+
* is NOT cryptographically sound. A production buyer MUST pass a real SNARK/STARK
|
|
1629
|
+
* verifier here; the default is for demos only.
|
|
1630
|
+
*/
|
|
1631
|
+
verify?: (proof: ZkmlProof, expected: ZkmlExpectation) => ZkmlVerification;
|
|
1632
|
+
/**
|
|
1633
|
+
* Resolve a non-inline (pinned) proof URI to a proof. Default: only inline
|
|
1634
|
+
* `zkml-proof:` URIs are understood; a pinned `ipfs://` proof needs this port.
|
|
1635
|
+
*/
|
|
1636
|
+
fetchProof?: (uri: string) => Promise<ZkmlProof | null> | ZkmlProof | null;
|
|
1637
|
+
}
|
|
1638
|
+
/**
|
|
1639
|
+
* Buyer-layer auto-release predicate for zk-verified jobs. RELEASE only when BOTH hold:
|
|
1640
|
+
* (1) the delivered artifact re-hashes to the worker-submitted `contentHash` (fetched via
|
|
1641
|
+
* `fetchContent`, never trusted), and (2) the attached proof verifies against that buyer-
|
|
1642
|
+
* recomputed hash (and the pinned model, when given). Otherwise DISPUTE. Disputing rather
|
|
1643
|
+
* than holding is deliberate -- a held SUBMITTED escrow is auto-released to the worker by
|
|
1644
|
+
* the 24h protocol timeout, so a buyer who required a proof contests a missing/invalid one
|
|
1645
|
+
* instead of letting it time out to release. This is the Buyer's judgment, not the
|
|
1646
|
+
* protocol's. Soundness of step (2) lives in the `verify` option; the default reference
|
|
1647
|
+
* verifier is a demo and proves nothing on its own. A port that throws (e.g.
|
|
1648
|
+
* `fetchContent` failing to retrieve the artifact) PROPAGATES: a transient infra failure
|
|
1649
|
+
* is not a verdict, so the caller retries it -- it is never silently converted into a
|
|
1650
|
+
* dispute.
|
|
1651
|
+
*/
|
|
1652
|
+
declare function zkmlProofAutoRelease(opts: ZkmlProofAutoReleaseOptions): ZkmlReviewPolicy;
|
|
1653
|
+
/** What an inference run yields: the output plus the commitments the proof binds. */
|
|
1654
|
+
interface ZkmlInferenceOutput {
|
|
1655
|
+
/** The deliverable content. */
|
|
1656
|
+
content: string;
|
|
1657
|
+
/** Commitment to the model that produced `content`. */
|
|
1658
|
+
modelCommitment: string;
|
|
1659
|
+
/** Commitment to the input the model was run on. */
|
|
1660
|
+
inputCommitment: string;
|
|
1661
|
+
}
|
|
1662
|
+
/** Configuration and injectable ports for {@link createZkmlAdapter}. */
|
|
1663
|
+
interface ZkmlAdapterConfig {
|
|
1664
|
+
/** Adapter id. Defaults to `"zkml"`. */
|
|
1665
|
+
id?: string;
|
|
1666
|
+
/** Advertised capabilities for EscroBots discovery. Defaults to `["zk-verified-inference"]`. */
|
|
1667
|
+
capabilities?: string[];
|
|
1668
|
+
/** Inference port. Default: solves the canned demo job; a deterministic placeholder otherwise. */
|
|
1669
|
+
runInference?: (spec: TaskSpec) => Promise<ZkmlInferenceOutput> | ZkmlInferenceOutput;
|
|
1670
|
+
/** Proving port. Default: builds a reference proof binding the output to its commitments. */
|
|
1671
|
+
prove?: (args: {
|
|
1672
|
+
spec: TaskSpec;
|
|
1673
|
+
output: ZkmlInferenceOutput;
|
|
1674
|
+
outputHash: string;
|
|
1675
|
+
}) => Promise<ZkmlProof> | ZkmlProof;
|
|
1676
|
+
/** Pinning port. Default: a self-contained inline proof URI. A production worker pins the proof. */
|
|
1677
|
+
pin?: (proof: ZkmlProof) => Promise<string> | string;
|
|
1678
|
+
/** Health-check port. Default: resolves `true`. */
|
|
1679
|
+
checkHealth?: () => Promise<boolean>;
|
|
1680
|
+
}
|
|
1681
|
+
/**
|
|
1682
|
+
* The canned zk-verified-inference demo job (BOT_KIT_PRD §6 / §13): a deterministic
|
|
1683
|
+
* classification the buyer template's zero-config journey hires this bot for.
|
|
1684
|
+
* Acceptance is machine-checkable by the buyer via {@link zkmlProofAutoRelease}.
|
|
1685
|
+
*/
|
|
1686
|
+
declare const zkmlDemoJobSpec: TaskSpec;
|
|
1687
|
+
/**
|
|
1688
|
+
* The reference solution to the demo job: the classifier's output as canonical JSON.
|
|
1689
|
+
* Deterministic. Exposed so the demo journey and tests share one source of truth.
|
|
1690
|
+
*/
|
|
1691
|
+
declare function solveZkmlDemo(): string;
|
|
1692
|
+
/**
|
|
1693
|
+
* Build a ZKML {@link ServiceAdapter}. Passes `assertServiceAdapterContract` with the
|
|
1694
|
+
* default ports and, out of the box, produces a demo deliverable whose proof verifies
|
|
1695
|
+
* under {@link zkmlProofAutoRelease}. Supply real ports (a genuine inference call, a
|
|
1696
|
+
* real prover, a pin to IPFS/Arweave) for production use.
|
|
1697
|
+
*/
|
|
1698
|
+
declare function createZkmlAdapter(config?: ZkmlAdapterConfig): ServiceAdapter;
|
|
169
1699
|
|
|
170
|
-
export { type CreateEscrowParams, type CreateEscrowResult, Escro, EscroError, type EscroOptions, EscrowNotFoundError, EscrowStateError, EscrowTimeoutError, type ListOptions, type PaginatedResult, type PollOptions, type RaiseDisputeParams, type SubmitDeliverableParams, UnauthorizedError };
|
|
1700
|
+
export { AKASH_ADAPTER_ID, AKASH_CAPABILITIES, AKASH_DEMO_ACCEPT_FLOOR, AKASH_DEMO_MARKER, type AcceptanceCriterion, AdapterContractError, type AdapterContractOptions, type AkashAdapterConfig, type Akt, ApiClient, type AutoReleaseDecision, type BotDescriptor, type BotRole, type CreateEscrowParams, type CreateEscrowResult, type DeliverableFormat, type DeliverableType, ENABLED_RAILS, Escro, EscroError, type EscroOptions, EscroRailNotEnabledError, type EscrowAccount, type EscrowErrorCode, EscrowNotFoundError, EscrowPaymentRouter, EscrowState, EscrowStateError, EscrowTimeoutError, GEN404_ADAPTER_ID, GEN404_CAPABILITIES, GEN404_DEMO_EVAL_FLOOR, GEN404_DEMO_MARKER, GENSYN_ADAPTER_ID, GENSYN_CAPABILITIES, GENSYN_DEMO_MARKER, GENSYN_REE_SCHEME, GRADIENTS_ADAPTER_ID, GRADIENTS_CAPABILITIES, GRADIENTS_DEMO_EVAL_FLOOR, GRADIENTS_DEMO_MARKER, type Gen404AdapterConfig, type GensynAdapterConfig, type GensynDeliverableBundle, type GradientsAdapterConfig, LIUM_ADAPTER_ID, LIUM_CAPABILITIES, LIUM_DEMO_ACCEPT_FLOOR, LIUM_DEMO_MARKER, type ListBotsParams, type ListOptions, type LiumAdapterConfig, type Network, type PaginatedResult, type PayParams, type PaymentResult, type PaymentRouter, type PinContent$3 as PinContent, type PollOptions, type ProtocolStats, RAILS, RAILS_DOCS_URL, REFERENCE_MICRO_USDC_PER_AKT, REFERENCE_MICRO_USDC_PER_RENDER, RENDER_ADAPTER_ID, RENDER_CAPABILITIES, RENDER_DEMO_ACCEPT_FLOOR, RENDER_DEMO_MARKER, RIDGES_ADAPTER_ID, RIDGES_CAPABILITIES, RIDGES_DEMO_COVERAGE_TARGET, RIDGES_DEMO_MARKER, type Rail, type RaiseDisputeParams, type ReeExecution, type ReeProof, type ReeVerification, type ReeVerifyContext, type Render, type RenderAdapterConfig, type ReproduceCompute, ReputationUnavailableError, type RidgesAdapterConfig, type RunAkashDeployment, type RunCodingAgent, type RunGpuJob, type RunRenderJob, type ServedWalletReputation, type ServiceAdapter, type ServiceResult, type SubmitDeliverableParams, type SubnetCall, type Tao, type TaskSpec, type TaskType, type TxShape, UnauthorizedError, type UnsignedBotDescriptor, type UsdcToAktSwap, type UsdcToRenderSwap, type UsdcToTaoSwap, type WorkerCandidate, ZKML_ADAPTER_ID, ZKML_CAPABILITIES, ZKML_DEMO_MARKER, ZKML_PROOF_SCHEME, ZKML_PROOF_URI_PREFIX, type ZkmlAdapterConfig, type ZkmlDeliverable, type ZkmlExpectation, type ZkmlInferenceOutput, type ZkmlProof, type ZkmlProofAutoReleaseOptions, type ZkmlReviewPolicy, type ZkmlReviewResult, type ZkmlVerification, akashDemoJobSpec, akt, assertServiceAdapterContract, buildReeProof, buildZkmlProof, computeAkashDemoArtifact, computeLiumDemoArtifact, computeRenderDemoArtifact, create404genAdapter, createAkashAdapter, createGensynAdapter, createGradientsAdapter, createLiumAdapter, createRenderAdapter, createRidgesAdapter, createZkmlAdapter, decodeZkmlProofUri, encodeZkmlProofUri, gen404DemoJobSpec, gensynAutoRelease, gensynDemoJobSpec, gradientsDemoJobSpec, liumDemoJobSpec, renderAmount, renderDemoJobSpec, reproduceGensynCompute, ridgesDemoJobSpec, score404genDemoDeliverable, scoreAkashDemoDeliverable, scoreGradientsDemoDeliverable, scoreLiumDemoDeliverable, scoreRenderDemoDeliverable, scoreRidgesDemoDeliverable, serviceResultToSubmitParams, solveAkashDemo, solveGen404Demo, solveGradientsDemo, solveLiumDemo, solveRenderDemo, solveRidgesDemo, solveZkmlDemo, tao, verifyReeProof, verifyZkmlProof, verifyZkmlProofUri, zkmlDemoJobSpec, zkmlProofAutoRelease };
|