@escro/sdk 0.2.0 → 0.4.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/README.md +6 -14
- package/dist/index.cjs +384 -113
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +239 -119
- package/dist/index.d.ts +239 -119
- package/dist/index.js +378 -108
- package/dist/index.js.map +1 -1
- package/package.json +4 -5
package/dist/index.js
CHANGED
|
@@ -3,7 +3,7 @@ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { en
|
|
|
3
3
|
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
4
4
|
|
|
5
5
|
// src/client.ts
|
|
6
|
-
import { Connection as Connection2, PublicKey as
|
|
6
|
+
import { Connection as Connection2, PublicKey as PublicKey3 } from "@solana/web3.js";
|
|
7
7
|
|
|
8
8
|
// ../shared/dist/index.js
|
|
9
9
|
import { createHash } from "crypto";
|
|
@@ -22,20 +22,10 @@ var EscrowState = /* @__PURE__ */ ((EscrowState2) => {
|
|
|
22
22
|
EscrowState2["REFUNDED"] = "REFUNDED";
|
|
23
23
|
return EscrowState2;
|
|
24
24
|
})(EscrowState || {});
|
|
25
|
-
function canonicalize(value) {
|
|
26
|
-
if (value === null) return "null";
|
|
27
|
-
if (Array.isArray(value)) {
|
|
28
|
-
return "[" + value.map((v) => v === void 0 ? "null" : canonicalize(v)).join(",") + "]";
|
|
29
|
-
}
|
|
30
|
-
if (typeof value === "object") {
|
|
31
|
-
const obj = value;
|
|
32
|
-
const keys = Object.keys(obj).filter((k) => obj[k] !== void 0).sort();
|
|
33
|
-
return "{" + keys.map((k) => JSON.stringify(k) + ":" + canonicalize(obj[k])).join(",") + "}";
|
|
34
|
-
}
|
|
35
|
-
return JSON.stringify(value);
|
|
36
|
-
}
|
|
37
25
|
var PROGRAM_ID_DEVNET = "EjLpJ3obUYk1f2KDensU7UdGBZTxSdxufm7CSnMA3H5C";
|
|
38
26
|
var PROGRAM_ID_MAINNET = "4CwLNRF4mFXutiBGjtMHQBxh8whW8T8EyvJXdRhY1rvr";
|
|
27
|
+
var CURRENT_ACCOUNT_VERSION = 1;
|
|
28
|
+
var MAX_DISPUTE_REASON_BYTES = 200;
|
|
39
29
|
var ONCHAIN_REFUND_GRACE_SECONDS = 900;
|
|
40
30
|
var ONCHAIN_TIMEOUT_SECONDS = 86400;
|
|
41
31
|
var CLOCK_SKEW_SECONDS = 60;
|
|
@@ -55,6 +45,26 @@ function assertProgramIdNotPlaceholder(id, cluster) {
|
|
|
55
45
|
);
|
|
56
46
|
}
|
|
57
47
|
}
|
|
48
|
+
function canonicalize(value) {
|
|
49
|
+
if (value === null) return "null";
|
|
50
|
+
if (Array.isArray(value)) {
|
|
51
|
+
return "[" + value.map((v) => v === void 0 ? "null" : canonicalize(v)).join(",") + "]";
|
|
52
|
+
}
|
|
53
|
+
if (typeof value === "object") {
|
|
54
|
+
const obj = value;
|
|
55
|
+
const keys = Object.keys(obj).filter((k) => obj[k] !== void 0).sort();
|
|
56
|
+
return "{" + keys.map((k) => JSON.stringify(k) + ":" + canonicalize(obj[k])).join(",") + "}";
|
|
57
|
+
}
|
|
58
|
+
return JSON.stringify(value);
|
|
59
|
+
}
|
|
60
|
+
function disputeReasonError(reason) {
|
|
61
|
+
if (reason.length === 0) return "reason must not be empty";
|
|
62
|
+
const bytes = new TextEncoder().encode(reason).length;
|
|
63
|
+
if (bytes > MAX_DISPUTE_REASON_BYTES) {
|
|
64
|
+
return `reason is ${String(bytes)} bytes in UTF-8; the program accepts at most ${String(MAX_DISPUTE_REASON_BYTES)}`;
|
|
65
|
+
}
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
58
68
|
function hashBody(rawBody) {
|
|
59
69
|
return createHash("sha256").update(rawBody, "utf8").digest("hex");
|
|
60
70
|
}
|
|
@@ -100,6 +110,26 @@ function verifyBotDescriptorSignature(descriptor) {
|
|
|
100
110
|
return false;
|
|
101
111
|
}
|
|
102
112
|
}
|
|
113
|
+
function spec(discriminator, escrowAccountIndex, cause) {
|
|
114
|
+
return {
|
|
115
|
+
discriminator: Uint8Array.from(discriminator),
|
|
116
|
+
escrowAccountIndex,
|
|
117
|
+
signerAccountIndex: 0,
|
|
118
|
+
cause
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
var ESCROW_INSTRUCTIONS = {
|
|
122
|
+
create_escrow: spec([253, 215, 165, 116, 36, 108, 68, 80], 4, null),
|
|
123
|
+
claim_task: spec([49, 222, 219, 238, 155, 68, 221, 136], 1, null),
|
|
124
|
+
submit_deliverable: spec([38, 137, 64, 44, 237, 11, 125, 101], 1, null),
|
|
125
|
+
raise_dispute: spec([41, 243, 1, 51, 150, 95, 246, 73], 1, null),
|
|
126
|
+
cancel_escrow: spec([156, 203, 54, 179, 38, 72, 33, 21], 3, "CANCELLED"),
|
|
127
|
+
release_payment: spec([24, 34, 191, 86, 145, 160, 183, 233], 3, "EXPLICIT_RELEASE"),
|
|
128
|
+
timeout_release: spec([98, 176, 26, 12, 83, 105, 154, 68], 3, "TIMEOUT_RELEASE"),
|
|
129
|
+
refund_buyer: spec([199, 139, 203, 146, 192, 150, 53, 218], 3, "DEADLINE_REFUND"),
|
|
130
|
+
arbitration_release: spec([118, 157, 141, 26, 104, 117, 94, 229], 4, "ARBITRATION_RELEASE"),
|
|
131
|
+
arbitration_refund: spec([255, 194, 84, 248, 185, 249, 120, 122], 4, "ARBITRATION_REFUND")
|
|
132
|
+
};
|
|
103
133
|
|
|
104
134
|
// src/payments.ts
|
|
105
135
|
var RAILS = ["escrow", "x402"];
|
|
@@ -114,9 +144,10 @@ var EscrowPaymentRouter = class {
|
|
|
114
144
|
|
|
115
145
|
// src/errors.ts
|
|
116
146
|
var EscroError = class extends Error {
|
|
117
|
-
constructor(message, code = "ESCRO_ERROR") {
|
|
147
|
+
constructor(message, code = "ESCRO_ERROR", retryAfterMs2) {
|
|
118
148
|
super(message);
|
|
119
149
|
__publicField(this, "code", code);
|
|
150
|
+
__publicField(this, "retryAfterMs", retryAfterMs2);
|
|
120
151
|
this.name = "EscroError";
|
|
121
152
|
}
|
|
122
153
|
};
|
|
@@ -147,6 +178,18 @@ var EscrowTimeoutError = class extends EscroError {
|
|
|
147
178
|
this.name = "EscrowTimeoutError";
|
|
148
179
|
}
|
|
149
180
|
};
|
|
181
|
+
var EscroConfirmError = class extends EscroError {
|
|
182
|
+
constructor(address, signature, code, message, retryAfterMs2) {
|
|
183
|
+
super(
|
|
184
|
+
`Confirm failed for escrow ${address} (signature ${signature}): ${message}`,
|
|
185
|
+
code,
|
|
186
|
+
retryAfterMs2
|
|
187
|
+
);
|
|
188
|
+
__publicField(this, "address", address);
|
|
189
|
+
__publicField(this, "signature", signature);
|
|
190
|
+
this.name = "EscroConfirmError";
|
|
191
|
+
}
|
|
192
|
+
};
|
|
150
193
|
var UnauthorizedError = class extends EscroError {
|
|
151
194
|
constructor(message = "Unauthorized") {
|
|
152
195
|
super(message, "UNAUTHORIZED");
|
|
@@ -177,7 +220,10 @@ async function handleError(res, address) {
|
|
|
177
220
|
if (res.status === 404) throw new EscrowNotFoundError(address ?? msg);
|
|
178
221
|
if (res.status === 409) throw new EscrowStateError(msg);
|
|
179
222
|
if (res.status === 401 || res.status === 403) throw new UnauthorizedError(msg);
|
|
180
|
-
throw new EscroError(msg, body.code ?? "UNKNOWN");
|
|
223
|
+
throw new EscroError(msg, body.code ?? "UNKNOWN", retryAfterMs(res.headers.get("retry-after")));
|
|
224
|
+
}
|
|
225
|
+
function retryAfterMs(header) {
|
|
226
|
+
return header !== null && /^\d+$/.test(header.trim()) ? Number(header.trim()) * 1e3 : void 0;
|
|
181
227
|
}
|
|
182
228
|
var ApiClient = class {
|
|
183
229
|
constructor(baseUrl, wallet) {
|
|
@@ -253,6 +299,22 @@ var ApiClient = class {
|
|
|
253
299
|
const body = await res.json();
|
|
254
300
|
return body.wallets;
|
|
255
301
|
}
|
|
302
|
+
/**
|
|
303
|
+
* GET /rep/:wallet : one wallet's EscroRep RAW components (ARCHITECTURE §9).
|
|
304
|
+
* Unauthenticated public read (no auth headers). Unknown wallets return zeroed
|
|
305
|
+
* components, never 404; a 404 means the deployment mounted no reputation
|
|
306
|
+
* source and surfaces as {@link ReputationUnavailableError}. Shares the public
|
|
307
|
+
* per-wallet rate budget with every other caller, so fan-outs should use
|
|
308
|
+
* {@link listReputations} instead.
|
|
309
|
+
*/
|
|
310
|
+
async getReputation(wallet) {
|
|
311
|
+
const res = await fetch(this.url(`/rep/${encodeURIComponent(wallet)}`));
|
|
312
|
+
if (!res.ok) {
|
|
313
|
+
if (res.status === 404) throw new ReputationUnavailableError();
|
|
314
|
+
await handleError(res);
|
|
315
|
+
}
|
|
316
|
+
return await res.json();
|
|
317
|
+
}
|
|
256
318
|
/**
|
|
257
319
|
* POST /v1/escrows — create escrow, returns unsigned tx + ids.
|
|
258
320
|
* Requires auth.
|
|
@@ -312,8 +374,11 @@ var ApiClient = class {
|
|
|
312
374
|
return res.json();
|
|
313
375
|
}
|
|
314
376
|
/**
|
|
315
|
-
* POST /v1/escrows/:address/release
|
|
316
|
-
* Requires auth (buyer). No on-chain tx returned.
|
|
377
|
+
* POST /v1/escrows/:address/release: records the landed release once the API's RPC shows
|
|
378
|
+
* the escrow closed. Requires auth (buyer). No on-chain tx returned. A 409
|
|
379
|
+
* `ESCROW_NOT_SETTLED`, a 5xx or a 429 throws an {@link EscroError} with the server's code,
|
|
380
|
+
* or `HTTP_<status>` when the answer carries none; {@link Escro.releasePaymentWithOutcome}
|
|
381
|
+
* decides which to retry. Other refusals throw as every route does.
|
|
317
382
|
*/
|
|
318
383
|
async releasePaymentDb(address) {
|
|
319
384
|
const path = `/v1/escrows/${address}/release`;
|
|
@@ -321,7 +386,19 @@ var ApiClient = class {
|
|
|
321
386
|
method: "POST",
|
|
322
387
|
headers: authHeaders(this.wallet, "POST", path)
|
|
323
388
|
});
|
|
324
|
-
if (
|
|
389
|
+
if (res.ok) return;
|
|
390
|
+
if (res.status !== 409 && res.status !== 429 && res.status < 500) {
|
|
391
|
+
await handleError(res, address);
|
|
392
|
+
}
|
|
393
|
+
const body = await res.json().catch(() => ({}));
|
|
394
|
+
if (res.status === 409 && body.code !== "ESCROW_NOT_SETTLED") {
|
|
395
|
+
throw new EscrowStateError(body.error ?? `HTTP ${String(res.status)}`);
|
|
396
|
+
}
|
|
397
|
+
throw new EscroError(
|
|
398
|
+
body.error ?? `HTTP ${String(res.status)}`,
|
|
399
|
+
body.code ?? `HTTP_${String(res.status)}`,
|
|
400
|
+
retryAfterMs(res.headers.get("retry-after"))
|
|
401
|
+
);
|
|
325
402
|
}
|
|
326
403
|
/**
|
|
327
404
|
* POST /v1/escrows/:address/cancel — returns unsigned tx.
|
|
@@ -342,7 +419,7 @@ var ApiClient = class {
|
|
|
342
419
|
*/
|
|
343
420
|
async raiseDispute(address, params) {
|
|
344
421
|
const path = `/v1/escrows/${address}/dispute`;
|
|
345
|
-
const rawBody = JSON.stringify({ reason: params.reason
|
|
422
|
+
const rawBody = JSON.stringify({ reason: params.reason });
|
|
346
423
|
const res = await fetch(this.url(path), {
|
|
347
424
|
method: "POST",
|
|
348
425
|
headers: {
|
|
@@ -354,6 +431,35 @@ var ApiClient = class {
|
|
|
354
431
|
if (!res.ok) await handleError(res, address);
|
|
355
432
|
return res.json();
|
|
356
433
|
}
|
|
434
|
+
/**
|
|
435
|
+
* POST /v1/escrows/:address/confirm: the API records the create, claim, submit,
|
|
436
|
+
* cancel or dispute the landed `signature` carries, after verifying it on chain.
|
|
437
|
+
* A non-2xx answer throws an {@link EscroError} with the server's code, or
|
|
438
|
+
* `HTTP_<status>` when the answer carries none; a network failure rejects with
|
|
439
|
+
* fetch's own error. {@link Escro.confirm} decides which to retry.
|
|
440
|
+
*/
|
|
441
|
+
async confirm(address, signature, evidence) {
|
|
442
|
+
const path = `/v1/escrows/${address}/confirm`;
|
|
443
|
+
const rawBody = JSON.stringify({ signature, evidence });
|
|
444
|
+
const res = await fetch(this.url(path), {
|
|
445
|
+
method: "POST",
|
|
446
|
+
headers: {
|
|
447
|
+
...authHeaders(this.wallet, "POST", path, rawBody),
|
|
448
|
+
"content-type": "application/json"
|
|
449
|
+
},
|
|
450
|
+
body: rawBody
|
|
451
|
+
});
|
|
452
|
+
if (!res.ok) {
|
|
453
|
+
const body2 = await res.json().catch(() => ({}));
|
|
454
|
+
throw new EscroError(
|
|
455
|
+
body2.error ?? `HTTP ${String(res.status)}`,
|
|
456
|
+
body2.code ?? `HTTP_${String(res.status)}`,
|
|
457
|
+
retryAfterMs(res.headers.get("retry-after"))
|
|
458
|
+
);
|
|
459
|
+
}
|
|
460
|
+
const body = await res.json();
|
|
461
|
+
return deserialize(body.escrow);
|
|
462
|
+
}
|
|
357
463
|
/**
|
|
358
464
|
* GET /v1/stats — public protocol-wide stats.
|
|
359
465
|
* No auth required. Upstream typing in {@link Escro.getStats} narrows the
|
|
@@ -401,7 +507,7 @@ async function pollUntil(address, fetcher, predicate, timeoutMs = MS_24_H) {
|
|
|
401
507
|
import { createHash as createHash2 } from "crypto";
|
|
402
508
|
import {
|
|
403
509
|
ComputeBudgetProgram,
|
|
404
|
-
PublicKey,
|
|
510
|
+
PublicKey as PublicKey2,
|
|
405
511
|
Transaction,
|
|
406
512
|
TransactionInstruction
|
|
407
513
|
} from "@solana/web3.js";
|
|
@@ -411,6 +517,59 @@ import {
|
|
|
411
517
|
getAssociatedTokenAddressSync,
|
|
412
518
|
createAssociatedTokenAccountIdempotentInstruction
|
|
413
519
|
} from "@solana/spl-token";
|
|
520
|
+
|
|
521
|
+
// ../shared/dist/solana.js
|
|
522
|
+
import { PublicKey } from "@solana/web3.js";
|
|
523
|
+
import bs583 from "bs58";
|
|
524
|
+
var utf8 = (s) => new TextEncoder().encode(s);
|
|
525
|
+
function findPlatformConfigPda(programId) {
|
|
526
|
+
return PublicKey.findProgramAddressSync([utf8("config")], programId);
|
|
527
|
+
}
|
|
528
|
+
function derivePlatformConfigPda(programId) {
|
|
529
|
+
return findPlatformConfigPda(programId)[0];
|
|
530
|
+
}
|
|
531
|
+
var PLATFORM_CONFIG_LAYOUT = {
|
|
532
|
+
version: 8,
|
|
533
|
+
fee_bps: 9,
|
|
534
|
+
oracle_authority: 11,
|
|
535
|
+
usdc_mint: 43,
|
|
536
|
+
treasury: 75,
|
|
537
|
+
bump: 107,
|
|
538
|
+
length: 108
|
|
539
|
+
};
|
|
540
|
+
var PLATFORM_CONFIG_DISCRIMINATOR = [
|
|
541
|
+
160,
|
|
542
|
+
78,
|
|
543
|
+
128,
|
|
544
|
+
0,
|
|
545
|
+
248,
|
|
546
|
+
83,
|
|
547
|
+
230,
|
|
548
|
+
160
|
|
549
|
+
];
|
|
550
|
+
function decodePlatformConfig(data) {
|
|
551
|
+
const L = PLATFORM_CONFIG_LAYOUT;
|
|
552
|
+
if (data.length !== L.length) {
|
|
553
|
+
throw new Error(
|
|
554
|
+
`PlatformConfig account is ${String(data.length)} bytes, expected ${String(L.length)}`
|
|
555
|
+
);
|
|
556
|
+
}
|
|
557
|
+
if (PLATFORM_CONFIG_DISCRIMINATOR.some((byte2, i) => data[i] !== byte2)) {
|
|
558
|
+
throw new Error("PlatformConfig discriminator mismatch: not a PlatformConfig account");
|
|
559
|
+
}
|
|
560
|
+
const byte = (at) => data[at] ?? 0;
|
|
561
|
+
const key = (at) => bs583.encode(data.subarray(at, at + 32));
|
|
562
|
+
return {
|
|
563
|
+
version: byte(L.version),
|
|
564
|
+
feeBps: byte(L.fee_bps) | byte(L.fee_bps + 1) << 8,
|
|
565
|
+
oracleAuthority: key(L.oracle_authority),
|
|
566
|
+
usdcMint: key(L.usdc_mint),
|
|
567
|
+
treasury: key(L.treasury),
|
|
568
|
+
bump: byte(L.bump)
|
|
569
|
+
};
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
// src/solana.ts
|
|
414
573
|
function disc(name) {
|
|
415
574
|
return Buffer.from(createHash2("sha256").update(`global:${name}`).digest()).subarray(0, 8);
|
|
416
575
|
}
|
|
@@ -418,7 +577,7 @@ var DISC_RELEASE_PAYMENT = disc("release_payment");
|
|
|
418
577
|
function resolveProgramId(cluster) {
|
|
419
578
|
const id = getProgramId(cluster);
|
|
420
579
|
assertProgramIdNotPlaceholder(id, cluster);
|
|
421
|
-
return new
|
|
580
|
+
return new PublicKey2(id);
|
|
422
581
|
}
|
|
423
582
|
function allowedProgramIds(programId) {
|
|
424
583
|
return /* @__PURE__ */ new Set([
|
|
@@ -451,25 +610,17 @@ var FORBIDDEN_TOKEN_IX_TAGS = /* @__PURE__ */ new Set([
|
|
|
451
610
|
15
|
|
452
611
|
// BurnChecked
|
|
453
612
|
]);
|
|
454
|
-
var EXPECTED_PLATFORM_CONFIG_VERSION = 1;
|
|
455
|
-
var VERSION_OFFSET = 8;
|
|
456
|
-
var MINT_OFFSET = 43;
|
|
457
|
-
var TREASURY_OFFSET = 75;
|
|
458
613
|
async function fetchPlatformConfig(connection, cluster) {
|
|
459
|
-
const
|
|
460
|
-
const [pda] = PublicKey.findProgramAddressSync([Buffer.from("config")], programId);
|
|
614
|
+
const pda = derivePlatformConfigPda(resolveProgramId(cluster));
|
|
461
615
|
const info = await connection.getAccountInfo(pda);
|
|
462
616
|
if (!info) throw new Error("PlatformConfig account not found on-chain");
|
|
463
|
-
const
|
|
464
|
-
if (version !==
|
|
617
|
+
const config = decodePlatformConfig(info.data);
|
|
618
|
+
if (config.version !== CURRENT_ACCOUNT_VERSION) {
|
|
465
619
|
throw new Error(
|
|
466
|
-
`PlatformConfig version mismatch: expected ${String(
|
|
620
|
+
`PlatformConfig version mismatch: expected ${String(CURRENT_ACCOUNT_VERSION)}, got ${String(config.version)}`
|
|
467
621
|
);
|
|
468
622
|
}
|
|
469
|
-
return {
|
|
470
|
-
mint: new PublicKey(info.data.subarray(MINT_OFFSET, MINT_OFFSET + 32)),
|
|
471
|
-
treasury: new PublicKey(info.data.subarray(TREASURY_OFFSET, TREASURY_OFFSET + 32))
|
|
472
|
-
};
|
|
623
|
+
return { mint: new PublicKey2(config.usdcMint), treasury: new PublicKey2(config.treasury) };
|
|
473
624
|
}
|
|
474
625
|
function validateTransaction(tx, cluster) {
|
|
475
626
|
const programId = resolveProgramId(cluster);
|
|
@@ -513,7 +664,7 @@ async function signAndSend(base64Tx, wallet, connection, cluster) {
|
|
|
513
664
|
async function buildReleasePaymentTx(params) {
|
|
514
665
|
const { buyer, escrowPda, worker, mint, treasury, connection, cluster } = params;
|
|
515
666
|
const programId = resolveProgramId(cluster);
|
|
516
|
-
const
|
|
667
|
+
const platformConfig = derivePlatformConfigPda(programId);
|
|
517
668
|
const vault = getAssociatedTokenAddressSync(
|
|
518
669
|
mint,
|
|
519
670
|
escrowPda,
|
|
@@ -563,6 +714,33 @@ async function buildReleasePaymentTx(params) {
|
|
|
563
714
|
}
|
|
564
715
|
|
|
565
716
|
// src/client.ts
|
|
717
|
+
var CONFIRM_WINDOW_MS = 3e4;
|
|
718
|
+
var CONFIRM_FIRST_DELAY_MS = 500;
|
|
719
|
+
var CONFIRM_MAX_DELAY_MS = 4e3;
|
|
720
|
+
var RETRYABLE_CONFIRM_CODES = [
|
|
721
|
+
"TX_NOT_FOUND",
|
|
722
|
+
"RPC_UNAVAILABLE",
|
|
723
|
+
"HTTP_502",
|
|
724
|
+
"HTTP_503",
|
|
725
|
+
"HTTP_504",
|
|
726
|
+
"RATE_LIMITED",
|
|
727
|
+
"HTTP_429"
|
|
728
|
+
];
|
|
729
|
+
function isRetryableConfirmCode(code) {
|
|
730
|
+
return RETRYABLE_CONFIRM_CODES.includes(code);
|
|
731
|
+
}
|
|
732
|
+
function isRetryableReleaseCode(code) {
|
|
733
|
+
return code === "ESCROW_NOT_SETTLED" || isRetryableConfirmCode(code);
|
|
734
|
+
}
|
|
735
|
+
function isUrl(value) {
|
|
736
|
+
try {
|
|
737
|
+
new URL(value);
|
|
738
|
+
return true;
|
|
739
|
+
} catch {
|
|
740
|
+
return false;
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
var sleep2 = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
566
744
|
var Escro = class {
|
|
567
745
|
constructor(options) {
|
|
568
746
|
__publicField(this, "connection");
|
|
@@ -578,29 +756,40 @@ var Escro = class {
|
|
|
578
756
|
// ── Buyer Bot ────────────────────────────────────────────────────────────────
|
|
579
757
|
/**
|
|
580
758
|
* Create a new escrow: registers with the API, signs and submits the
|
|
581
|
-
* on-chain `create_escrow` transaction.
|
|
759
|
+
* on-chain `create_escrow` transaction, then confirms it with the API.
|
|
582
760
|
*
|
|
583
761
|
* @returns `{ escrowId, escrowPda, signature }` — use `escrowPda` for all subsequent calls.
|
|
584
762
|
*/
|
|
585
763
|
async createEscrow(params) {
|
|
586
764
|
const { escrowId, escrowPda, unsignedTx } = await this.api.createEscrow(params);
|
|
587
|
-
const signature = await
|
|
588
|
-
|
|
589
|
-
this.options.wallet,
|
|
590
|
-
this.connection,
|
|
591
|
-
this.cluster
|
|
592
|
-
);
|
|
765
|
+
const signature = await this.send(unsignedTx);
|
|
766
|
+
await this.confirm(escrowPda, signature);
|
|
593
767
|
return { escrowId, escrowPda, signature };
|
|
594
768
|
}
|
|
595
769
|
/**
|
|
596
770
|
* Release payment to the worker. Buyer must be the wallet in the constructor.
|
|
597
771
|
* Builds and submits the `release_payment` on-chain tx FIRST (the chain is the
|
|
598
|
-
* source of truth), then
|
|
599
|
-
*
|
|
772
|
+
* source of truth), then has the API record it, retrying as
|
|
773
|
+
* {@link Escro.releasePaymentWithOutcome} does. Use that method to see whether the
|
|
774
|
+
* API recorded the release.
|
|
600
775
|
*
|
|
601
776
|
* @returns Solana transaction signature.
|
|
602
777
|
*/
|
|
603
778
|
async releasePayment(address) {
|
|
779
|
+
const { signature } = await this.releasePaymentWithOutcome(address);
|
|
780
|
+
return signature;
|
|
781
|
+
}
|
|
782
|
+
/**
|
|
783
|
+
* {@link Escro.releasePayment}, reporting whether the API recorded the release.
|
|
784
|
+
* `ESCROW_NOT_SETTLED` (the API's RPC does not yet show the escrow closed), the codes
|
|
785
|
+
* {@link Escro.confirm} retries and a network failure are retried for about 30 s. A
|
|
786
|
+
* failure never throws: the release already landed, so the signature is returned with
|
|
787
|
+
* `confirm.landed: false` and an `EscroConfirmError` (the API's code, or
|
|
788
|
+
* `NETWORK_ERROR` when the last call never reached it).
|
|
789
|
+
*
|
|
790
|
+
* @returns `{ signature, confirm }`.
|
|
791
|
+
*/
|
|
792
|
+
async releasePaymentWithOutcome(address) {
|
|
604
793
|
const escrow = await this.api.getEscrow(address);
|
|
605
794
|
if (!escrow.taker) {
|
|
606
795
|
throw new EscrowNotFoundError(`Escrow ${address} has no assigned worker`);
|
|
@@ -608,8 +797,8 @@ var Escro = class {
|
|
|
608
797
|
const { treasury, mint } = await fetchPlatformConfig(this.connection, this.cluster);
|
|
609
798
|
const unsignedTx = await buildReleasePaymentTx({
|
|
610
799
|
buyer: this.options.wallet.publicKey,
|
|
611
|
-
escrowPda: new
|
|
612
|
-
worker: new
|
|
800
|
+
escrowPda: new PublicKey3(address),
|
|
801
|
+
worker: new PublicKey3(escrow.taker),
|
|
613
802
|
mint,
|
|
614
803
|
treasury,
|
|
615
804
|
connection: this.connection,
|
|
@@ -622,31 +811,47 @@ var Escro = class {
|
|
|
622
811
|
this.cluster
|
|
623
812
|
);
|
|
624
813
|
try {
|
|
625
|
-
await this.
|
|
626
|
-
|
|
814
|
+
await this.retryRecord(
|
|
815
|
+
address,
|
|
816
|
+
signature,
|
|
817
|
+
() => this.api.releasePaymentDb(address),
|
|
818
|
+
isRetryableReleaseCode
|
|
819
|
+
);
|
|
820
|
+
} catch (err) {
|
|
821
|
+
if (!(err instanceof EscroConfirmError)) throw err;
|
|
822
|
+
return { signature, confirm: { landed: false, error: err } };
|
|
627
823
|
}
|
|
628
|
-
return signature;
|
|
824
|
+
return { signature, confirm: { landed: true } };
|
|
629
825
|
}
|
|
630
826
|
/**
|
|
631
827
|
* Raise a dispute for an escrow. Either the buyer or the assigned worker
|
|
632
|
-
* may call this. Signs and submits the `raise_dispute` on-chain tx.
|
|
828
|
+
* may call this. Signs and submits the `raise_dispute` on-chain tx, then confirms it with the API.
|
|
633
829
|
*
|
|
634
830
|
* @returns Solana transaction signature.
|
|
635
831
|
*/
|
|
636
832
|
async raiseDispute(address, params) {
|
|
637
|
-
const
|
|
638
|
-
|
|
833
|
+
const reasonError = disputeReasonError(params.reason);
|
|
834
|
+
if (reasonError !== null) throw new EscroError(reasonError, "VALIDATION_ERROR");
|
|
835
|
+
if (params.evidence !== void 0 && !isUrl(params.evidence)) {
|
|
836
|
+
throw new EscroError(`evidence must be a URL: ${params.evidence}`, "VALIDATION_ERROR");
|
|
837
|
+
}
|
|
838
|
+
const { unsignedTx } = await this.api.raiseDispute(address, { reason: params.reason });
|
|
839
|
+
const signature = await this.send(unsignedTx);
|
|
840
|
+
await this.confirm(address, signature, {
|
|
841
|
+
...params.evidence !== void 0 && { evidence: params.evidence }
|
|
842
|
+
});
|
|
843
|
+
return signature;
|
|
639
844
|
}
|
|
640
845
|
/**
|
|
641
846
|
* Cancel a funded escrow before any worker has claimed it.
|
|
642
847
|
* Buyer must be the wallet in the constructor. Only valid when state is `FUNDED`.
|
|
643
|
-
* Signs and submits the `cancel_escrow` on-chain tx; full USDC refund to buyer.
|
|
848
|
+
* Signs and submits the `cancel_escrow` on-chain tx, then confirms it with the API; full USDC refund to buyer.
|
|
644
849
|
*
|
|
645
850
|
* @returns Solana transaction signature.
|
|
646
851
|
*/
|
|
647
852
|
async cancelEscrow(address) {
|
|
648
853
|
const { unsignedTx } = await this.api.cancelEscrow(address);
|
|
649
|
-
return
|
|
854
|
+
return this.sendAndConfirm(address, unsignedTx);
|
|
650
855
|
}
|
|
651
856
|
// ── Payments (dual-path; x402 reserved) ───────────────────────────────────────
|
|
652
857
|
/**
|
|
@@ -671,23 +876,23 @@ var Escro = class {
|
|
|
671
876
|
// ── Worker Bot ───────────────────────────────────────────────────────────────
|
|
672
877
|
/**
|
|
673
878
|
* Claim an assigned task. Worker must be the wallet in the constructor.
|
|
674
|
-
* Signs and submits the `claim_task` on-chain tx.
|
|
879
|
+
* Signs and submits the `claim_task` on-chain tx, then confirms it with the API.
|
|
675
880
|
*
|
|
676
881
|
* @returns Solana transaction signature.
|
|
677
882
|
*/
|
|
678
883
|
async claimTask(address) {
|
|
679
884
|
const { unsignedTx } = await this.api.claimTask(address);
|
|
680
|
-
return
|
|
885
|
+
return this.sendAndConfirm(address, unsignedTx);
|
|
681
886
|
}
|
|
682
887
|
/**
|
|
683
888
|
* Submit a deliverable for the buyer to review. Worker must be the wallet.
|
|
684
|
-
* Signs and submits the `submit_deliverable` on-chain tx.
|
|
889
|
+
* Signs and submits the `submit_deliverable` on-chain tx, then confirms it with the API.
|
|
685
890
|
*
|
|
686
891
|
* @returns Solana transaction signature.
|
|
687
892
|
*/
|
|
688
893
|
async submitDeliverable(address, params) {
|
|
689
894
|
const { unsignedTx } = await this.api.submitDeliverable(address, params);
|
|
690
|
-
return
|
|
895
|
+
return this.sendAndConfirm(address, unsignedTx);
|
|
691
896
|
}
|
|
692
897
|
/**
|
|
693
898
|
* List tasks assigned to the wallet's public key.
|
|
@@ -797,6 +1002,70 @@ var Escro = class {
|
|
|
797
1002
|
return data;
|
|
798
1003
|
}
|
|
799
1004
|
// ── Shared ───────────────────────────────────────────────────────────────────
|
|
1005
|
+
/**
|
|
1006
|
+
* Ask the API to record the create, claim, submit, cancel or dispute that the
|
|
1007
|
+
* landed `signature` carries; the API verifies it on chain first. Retries a
|
|
1008
|
+
* not-yet-visible transaction, an RPC failure, a gateway error or a rate limit
|
|
1009
|
+
* for about 30 s (waiting at least a sent Retry-After), never a rejection. Throws
|
|
1010
|
+
* {@link EscroConfirmError}; calling again is safe (a replay of a recorded
|
|
1011
|
+
* transition succeeds).
|
|
1012
|
+
*/
|
|
1013
|
+
async confirm(address, signature, opts = {}) {
|
|
1014
|
+
return this.retryRecord(
|
|
1015
|
+
address,
|
|
1016
|
+
signature,
|
|
1017
|
+
() => this.api.confirm(address, signature, opts.evidence),
|
|
1018
|
+
isRetryableConfirmCode
|
|
1019
|
+
);
|
|
1020
|
+
}
|
|
1021
|
+
// Calls `record` until the API records the landed `signature`: a code `retryable` accepts or
|
|
1022
|
+
// a network failure is retried for about 30 s (waiting at least a sent Retry-After), any
|
|
1023
|
+
// other refusal is not. Throws EscroConfirmError.
|
|
1024
|
+
async retryRecord(address, signature, record, retryable) {
|
|
1025
|
+
const deadline = Date.now() + CONFIRM_WINDOW_MS;
|
|
1026
|
+
let delay = CONFIRM_FIRST_DELAY_MS;
|
|
1027
|
+
for (; ; ) {
|
|
1028
|
+
let code;
|
|
1029
|
+
let message;
|
|
1030
|
+
let retryAfterMs2;
|
|
1031
|
+
let wait = delay;
|
|
1032
|
+
try {
|
|
1033
|
+
return await record();
|
|
1034
|
+
} catch (err) {
|
|
1035
|
+
if (err instanceof EscroError) {
|
|
1036
|
+
if (!retryable(err.code)) {
|
|
1037
|
+
throw new EscroConfirmError(
|
|
1038
|
+
address,
|
|
1039
|
+
signature,
|
|
1040
|
+
err.code,
|
|
1041
|
+
err.message,
|
|
1042
|
+
err.retryAfterMs
|
|
1043
|
+
);
|
|
1044
|
+
}
|
|
1045
|
+
code = err.code;
|
|
1046
|
+
message = err.message;
|
|
1047
|
+
retryAfterMs2 = err.retryAfterMs;
|
|
1048
|
+
wait = Math.max(delay, err.retryAfterMs ?? 0);
|
|
1049
|
+
} else {
|
|
1050
|
+
code = "NETWORK_ERROR";
|
|
1051
|
+
message = err instanceof Error ? err.message : String(err);
|
|
1052
|
+
}
|
|
1053
|
+
}
|
|
1054
|
+
if (Date.now() + wait > deadline) {
|
|
1055
|
+
throw new EscroConfirmError(address, signature, code, message, retryAfterMs2);
|
|
1056
|
+
}
|
|
1057
|
+
await sleep2(wait);
|
|
1058
|
+
delay = Math.min(delay * 2, CONFIRM_MAX_DELAY_MS);
|
|
1059
|
+
}
|
|
1060
|
+
}
|
|
1061
|
+
send(unsignedTx) {
|
|
1062
|
+
return signAndSend(unsignedTx, this.options.wallet, this.connection, this.cluster);
|
|
1063
|
+
}
|
|
1064
|
+
async sendAndConfirm(address, unsignedTx) {
|
|
1065
|
+
const signature = await this.send(unsignedTx);
|
|
1066
|
+
await this.confirm(address, signature);
|
|
1067
|
+
return signature;
|
|
1068
|
+
}
|
|
800
1069
|
/**
|
|
801
1070
|
* Fetch an escrow by its PDA address.
|
|
802
1071
|
* If `options.poll` is true, polls with exponential backoff until the escrow
|
|
@@ -930,9 +1199,9 @@ function createBittensorSubnetAdapter(config) {
|
|
|
930
1199
|
id,
|
|
931
1200
|
capabilities: config.capabilities,
|
|
932
1201
|
healthCheck: config.checkHealth,
|
|
933
|
-
async execute(
|
|
1202
|
+
async execute(spec2) {
|
|
934
1203
|
const budgetTao = await config.swap(config.taskBudgetMicroUsdc);
|
|
935
|
-
const content = await config.callSubnet(
|
|
1204
|
+
const content = await config.callSubnet(spec2, budgetTao);
|
|
936
1205
|
const contentHash = sha256Hex2(content);
|
|
937
1206
|
const proofUri = await config.pin(content);
|
|
938
1207
|
return {
|
|
@@ -1015,16 +1284,16 @@ function scoreGradientsDemoDeliverable(content) {
|
|
|
1015
1284
|
}
|
|
1016
1285
|
return matches / expected.length;
|
|
1017
1286
|
}
|
|
1018
|
-
function referencePlaceholder(
|
|
1287
|
+
function referencePlaceholder(spec2) {
|
|
1019
1288
|
return canonicalize({
|
|
1020
1289
|
checkpoint: "reference-sn56-checkpoint",
|
|
1021
1290
|
eval: { metric: "accuracy", score: 0 },
|
|
1022
1291
|
note: "reference stub - replace the callSubnet port with a real SN56 miner call.",
|
|
1023
|
-
taskType:
|
|
1292
|
+
taskType: spec2.taskType
|
|
1024
1293
|
});
|
|
1025
1294
|
}
|
|
1026
|
-
var defaultCallSubnet = (
|
|
1027
|
-
|
|
1295
|
+
var defaultCallSubnet = (spec2) => Promise.resolve(
|
|
1296
|
+
spec2.metadata.demo === GRADIENTS_DEMO_MARKER ? solveGradientsDemo() : referencePlaceholder(spec2)
|
|
1028
1297
|
);
|
|
1029
1298
|
function createGradientsAdapter(config = {}) {
|
|
1030
1299
|
return createBittensorSubnetAdapter({
|
|
@@ -1136,17 +1405,17 @@ function scoreRidgesDemoDeliverable(content) {
|
|
|
1136
1405
|
}
|
|
1137
1406
|
return coveredInputs.size / DEMO_INPUTS.length;
|
|
1138
1407
|
}
|
|
1139
|
-
function referencePlaceholder2(
|
|
1408
|
+
function referencePlaceholder2(spec2) {
|
|
1140
1409
|
return canonicalize({
|
|
1141
1410
|
language: "typescript",
|
|
1142
1411
|
solution: "// reference stub - replace the runAgent port with a real Ridges agent call.",
|
|
1143
1412
|
passed: false,
|
|
1144
1413
|
tests: [],
|
|
1145
|
-
taskType:
|
|
1414
|
+
taskType: spec2.taskType
|
|
1146
1415
|
});
|
|
1147
1416
|
}
|
|
1148
|
-
var defaultRunAgent = (
|
|
1149
|
-
|
|
1417
|
+
var defaultRunAgent = (spec2) => Promise.resolve(
|
|
1418
|
+
spec2.metadata.demo === RIDGES_DEMO_MARKER ? solveRidgesDemo() : referencePlaceholder2(spec2)
|
|
1150
1419
|
);
|
|
1151
1420
|
var defaultPin2 = (content) => Promise.resolve(`ipfs://placeholder-${sha256Hex3(content).slice(0, 16)}`);
|
|
1152
1421
|
function createRidgesAdapter(config = {}) {
|
|
@@ -1159,8 +1428,8 @@ function createRidgesAdapter(config = {}) {
|
|
|
1159
1428
|
id: service,
|
|
1160
1429
|
capabilities,
|
|
1161
1430
|
healthCheck: checkHealth,
|
|
1162
|
-
async execute(
|
|
1163
|
-
const content = await runAgent(
|
|
1431
|
+
async execute(spec2) {
|
|
1432
|
+
const content = await runAgent(spec2);
|
|
1164
1433
|
const contentHash = sha256Hex3(content);
|
|
1165
1434
|
const proofUri = await pin(content);
|
|
1166
1435
|
return {
|
|
@@ -1269,15 +1538,15 @@ function score404genDemoDeliverable(content) {
|
|
|
1269
1538
|
}
|
|
1270
1539
|
return Math.min(batch.assets.length / DEMO_EXPECTATION.requestedAssets, 1);
|
|
1271
1540
|
}
|
|
1272
|
-
function referencePlaceholder3(
|
|
1541
|
+
function referencePlaceholder3(spec2) {
|
|
1273
1542
|
return canonicalize({
|
|
1274
1543
|
assets: [{ format: "GLB", polygonCount: 0, uri: "ipfs://placeholder" }],
|
|
1275
1544
|
note: "reference stub - replace the callSubnet port with a real SN17 miner call.",
|
|
1276
|
-
taskType:
|
|
1545
|
+
taskType: spec2.taskType
|
|
1277
1546
|
});
|
|
1278
1547
|
}
|
|
1279
|
-
var defaultCallSubnet2 = (
|
|
1280
|
-
|
|
1548
|
+
var defaultCallSubnet2 = (spec2) => Promise.resolve(
|
|
1549
|
+
spec2.metadata.demo === GEN404_DEMO_MARKER ? solveGen404Demo() : referencePlaceholder3(spec2)
|
|
1281
1550
|
);
|
|
1282
1551
|
function create404genAdapter(config = {}) {
|
|
1283
1552
|
return createBittensorSubnetAdapter({
|
|
@@ -1377,17 +1646,17 @@ function scoreLiumDemoDeliverable(content) {
|
|
|
1377
1646
|
}
|
|
1378
1647
|
return parsed.artifact === computeLiumDemoArtifact() ? 1 : 0;
|
|
1379
1648
|
}
|
|
1380
|
-
function referencePlaceholder4(
|
|
1649
|
+
function referencePlaceholder4(spec2) {
|
|
1381
1650
|
return canonicalize({
|
|
1382
1651
|
job: "lium-sn51-generic",
|
|
1383
1652
|
status: "completed",
|
|
1384
1653
|
artifact: null,
|
|
1385
1654
|
note: "reference stub - replace the runJob port with a real SN51 GPU-rental call.",
|
|
1386
|
-
taskType:
|
|
1655
|
+
taskType: spec2.taskType
|
|
1387
1656
|
});
|
|
1388
1657
|
}
|
|
1389
|
-
var defaultRunJob = (
|
|
1390
|
-
|
|
1658
|
+
var defaultRunJob = (spec2) => Promise.resolve(
|
|
1659
|
+
spec2.metadata.demo === LIUM_DEMO_MARKER ? solveLiumDemo() : referencePlaceholder4(spec2)
|
|
1391
1660
|
);
|
|
1392
1661
|
function createLiumAdapter(config = {}) {
|
|
1393
1662
|
return createBittensorSubnetAdapter({
|
|
@@ -1496,17 +1765,17 @@ function scoreAkashDemoDeliverable(content) {
|
|
|
1496
1765
|
}
|
|
1497
1766
|
return parsed.artifact === computeAkashDemoArtifact() ? 1 : 0;
|
|
1498
1767
|
}
|
|
1499
|
-
function referencePlaceholder5(
|
|
1768
|
+
function referencePlaceholder5(spec2) {
|
|
1500
1769
|
return canonicalize({
|
|
1501
1770
|
job: "akash-generic",
|
|
1502
1771
|
status: "completed",
|
|
1503
1772
|
artifact: null,
|
|
1504
1773
|
note: "reference stub - replace the runDeployment port with a real Akash deployment call.",
|
|
1505
|
-
taskType:
|
|
1774
|
+
taskType: spec2.taskType
|
|
1506
1775
|
});
|
|
1507
1776
|
}
|
|
1508
|
-
var defaultRunDeployment = (
|
|
1509
|
-
|
|
1777
|
+
var defaultRunDeployment = (spec2) => Promise.resolve(
|
|
1778
|
+
spec2.metadata.demo === AKASH_DEMO_MARKER ? solveAkashDemo() : referencePlaceholder5(spec2)
|
|
1510
1779
|
);
|
|
1511
1780
|
function createAkashAdapter(config = {}) {
|
|
1512
1781
|
const capabilities = config.capabilities ?? [...AKASH_CAPABILITIES];
|
|
@@ -1519,9 +1788,9 @@ function createAkashAdapter(config = {}) {
|
|
|
1519
1788
|
id: AKASH_ADAPTER_ID,
|
|
1520
1789
|
capabilities,
|
|
1521
1790
|
healthCheck: checkHealth,
|
|
1522
|
-
async execute(
|
|
1791
|
+
async execute(spec2) {
|
|
1523
1792
|
const budgetAkt = await swap(taskBudgetMicroUsdc);
|
|
1524
|
-
const content = await runDeployment(
|
|
1793
|
+
const content = await runDeployment(spec2, budgetAkt);
|
|
1525
1794
|
const contentHash = sha256Hex4(content);
|
|
1526
1795
|
const proofUri = await pin(content);
|
|
1527
1796
|
return {
|
|
@@ -1638,17 +1907,17 @@ function scoreRenderDemoDeliverable(content) {
|
|
|
1638
1907
|
}
|
|
1639
1908
|
return parsed.frame === computeRenderDemoArtifact() ? 1 : 0;
|
|
1640
1909
|
}
|
|
1641
|
-
function referencePlaceholder6(
|
|
1910
|
+
function referencePlaceholder6(spec2) {
|
|
1642
1911
|
return canonicalize({
|
|
1643
1912
|
job: "render-generic",
|
|
1644
1913
|
status: "completed",
|
|
1645
1914
|
frame: null,
|
|
1646
1915
|
note: "reference stub - replace the runJob port with a real Render Network job submission.",
|
|
1647
|
-
taskType:
|
|
1916
|
+
taskType: spec2.taskType
|
|
1648
1917
|
});
|
|
1649
1918
|
}
|
|
1650
|
-
var defaultRunJob2 = (
|
|
1651
|
-
|
|
1919
|
+
var defaultRunJob2 = (spec2) => Promise.resolve(
|
|
1920
|
+
spec2.metadata.demo === RENDER_DEMO_MARKER ? solveRenderDemo() : referencePlaceholder6(spec2)
|
|
1652
1921
|
);
|
|
1653
1922
|
function createRenderAdapter(config = {}) {
|
|
1654
1923
|
const service = config.service ?? DEFAULT_SERVICE2;
|
|
@@ -1662,9 +1931,9 @@ function createRenderAdapter(config = {}) {
|
|
|
1662
1931
|
id: service,
|
|
1663
1932
|
capabilities,
|
|
1664
1933
|
healthCheck: checkHealth,
|
|
1665
|
-
async execute(
|
|
1934
|
+
async execute(spec2) {
|
|
1666
1935
|
const budgetRender = await swap(taskBudgetMicroUsdc);
|
|
1667
|
-
const content = await runJob(
|
|
1936
|
+
const content = await runJob(spec2, budgetRender);
|
|
1668
1937
|
const contentHash = sha256Hex5(content);
|
|
1669
1938
|
const proofUri = await pin(content);
|
|
1670
1939
|
return {
|
|
@@ -1691,15 +1960,15 @@ function sha256Hex6(content) {
|
|
|
1691
1960
|
var LCG_MULT = 1103515245n;
|
|
1692
1961
|
var LCG_INC = 12345n;
|
|
1693
1962
|
var LCG_MOD = 1n << 31n;
|
|
1694
|
-
function readComputeParams(
|
|
1695
|
-
const rawSeed =
|
|
1696
|
-
const rawSteps =
|
|
1963
|
+
function readComputeParams(spec2) {
|
|
1964
|
+
const rawSeed = spec2.metadata.seed;
|
|
1965
|
+
const rawSteps = spec2.metadata.steps;
|
|
1697
1966
|
const seed = typeof rawSeed === "number" && Number.isInteger(rawSeed) ? rawSeed : GENSYN_DEMO_SEED;
|
|
1698
1967
|
const steps = typeof rawSteps === "number" && Number.isInteger(rawSteps) && rawSteps > 0 ? rawSteps : GENSYN_DEMO_STEPS;
|
|
1699
1968
|
return { seed, steps };
|
|
1700
1969
|
}
|
|
1701
|
-
var reproduceGensynCompute = (
|
|
1702
|
-
const { seed, steps } = readComputeParams(
|
|
1970
|
+
var reproduceGensynCompute = (spec2) => {
|
|
1971
|
+
const { seed, steps } = readComputeParams(spec2);
|
|
1703
1972
|
const states = [];
|
|
1704
1973
|
let x = BigInt(seed) % LCG_MOD;
|
|
1705
1974
|
if (x < 0n) {
|
|
@@ -1721,10 +1990,10 @@ function commitmentOf(base) {
|
|
|
1721
1990
|
)
|
|
1722
1991
|
);
|
|
1723
1992
|
}
|
|
1724
|
-
function buildReeProof(
|
|
1993
|
+
function buildReeProof(spec2, exec, content) {
|
|
1725
1994
|
const base = {
|
|
1726
1995
|
scheme: GENSYN_REE_SCHEME,
|
|
1727
|
-
specHash: sha256Hex6(canonicalize(
|
|
1996
|
+
specHash: sha256Hex6(canonicalize(spec2)),
|
|
1728
1997
|
outputHash: sha256Hex6(content),
|
|
1729
1998
|
steps: exec.steps,
|
|
1730
1999
|
transcriptHash: sha256Hex6(canonicalize(exec.states))
|
|
@@ -1831,11 +2100,11 @@ function createGensynAdapter(config = {}) {
|
|
|
1831
2100
|
id: GENSYN_ADAPTER_ID,
|
|
1832
2101
|
capabilities,
|
|
1833
2102
|
healthCheck: checkHealth,
|
|
1834
|
-
async execute(
|
|
1835
|
-
const exec = runCompute(
|
|
2103
|
+
async execute(spec2) {
|
|
2104
|
+
const exec = runCompute(spec2);
|
|
1836
2105
|
const content = gensynDeliverable(exec);
|
|
1837
2106
|
const contentHash = sha256Hex6(content);
|
|
1838
|
-
const proof = buildReeProof(
|
|
2107
|
+
const proof = buildReeProof(spec2, exec, content);
|
|
1839
2108
|
const proofUri = await pin(content);
|
|
1840
2109
|
return {
|
|
1841
2110
|
content,
|
|
@@ -2010,21 +2279,21 @@ function solveZkmlDemo() {
|
|
|
2010
2279
|
output: { label: "cat", confidence: 0.98 }
|
|
2011
2280
|
});
|
|
2012
2281
|
}
|
|
2013
|
-
function referencePlaceholderOutput(
|
|
2282
|
+
function referencePlaceholderOutput(spec2) {
|
|
2014
2283
|
return {
|
|
2015
2284
|
content: canonicalize({
|
|
2016
2285
|
note: "reference stub - replace the runInference port with a real zk-verified inference call.",
|
|
2017
|
-
taskType:
|
|
2286
|
+
taskType: spec2.taskType
|
|
2018
2287
|
}),
|
|
2019
2288
|
modelCommitment: sha256Hex7("zkml-reference-stub-model"),
|
|
2020
|
-
inputCommitment: sha256Hex7(canonicalize(
|
|
2289
|
+
inputCommitment: sha256Hex7(canonicalize(spec2))
|
|
2021
2290
|
};
|
|
2022
2291
|
}
|
|
2023
|
-
var defaultRunInference = (
|
|
2292
|
+
var defaultRunInference = (spec2) => spec2.metadata.demo === ZKML_DEMO_MARKER ? {
|
|
2024
2293
|
content: solveZkmlDemo(),
|
|
2025
2294
|
modelCommitment: DEMO_MODEL_COMMITMENT,
|
|
2026
2295
|
inputCommitment: DEMO_INPUT_COMMITMENT
|
|
2027
|
-
} : referencePlaceholderOutput(
|
|
2296
|
+
} : referencePlaceholderOutput(spec2);
|
|
2028
2297
|
function createZkmlAdapter(config = {}) {
|
|
2029
2298
|
const id = config.id ?? ZKML_ADAPTER_ID;
|
|
2030
2299
|
const capabilities = config.capabilities ?? [...ZKML_CAPABILITIES];
|
|
@@ -2039,10 +2308,10 @@ function createZkmlAdapter(config = {}) {
|
|
|
2039
2308
|
return {
|
|
2040
2309
|
id,
|
|
2041
2310
|
capabilities,
|
|
2042
|
-
async execute(
|
|
2043
|
-
const output = await runInference(
|
|
2311
|
+
async execute(spec2) {
|
|
2312
|
+
const output = await runInference(spec2);
|
|
2044
2313
|
const contentHash = sha256Hex7(output.content);
|
|
2045
|
-
const proof = await prove({ spec, output, outputHash: contentHash });
|
|
2314
|
+
const proof = await prove({ spec: spec2, output, outputHash: contentHash });
|
|
2046
2315
|
const proofUri = await pin(proof);
|
|
2047
2316
|
return {
|
|
2048
2317
|
content: output.content,
|
|
@@ -2069,6 +2338,7 @@ export {
|
|
|
2069
2338
|
ApiClient,
|
|
2070
2339
|
ENABLED_RAILS,
|
|
2071
2340
|
Escro,
|
|
2341
|
+
EscroConfirmError,
|
|
2072
2342
|
EscroError,
|
|
2073
2343
|
EscroRailNotEnabledError,
|
|
2074
2344
|
EscrowNotFoundError,
|