@escro/sdk 0.4.0 → 0.4.2
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/dist/index.cjs +254 -63
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +11 -5
- package/dist/index.d.ts +11 -5
- package/dist/index.js +240 -50
- package/dist/index.js.map +1 -1
- package/package.json +6 -6
package/dist/index.cjs
CHANGED
|
@@ -138,10 +138,12 @@ var import_web33 = require("@solana/web3.js");
|
|
|
138
138
|
|
|
139
139
|
// ../shared/dist/index.js
|
|
140
140
|
var import_crypto = require("crypto");
|
|
141
|
+
var import_crypto2 = require("crypto");
|
|
141
142
|
var import_tweetnacl = __toESM(require("tweetnacl"), 1);
|
|
142
143
|
var import_bs58 = __toESM(require("bs58"), 1);
|
|
143
144
|
var import_tweetnacl2 = __toESM(require("tweetnacl"), 1);
|
|
144
145
|
var import_bs582 = __toESM(require("bs58"), 1);
|
|
146
|
+
var import_bs583 = __toESM(require("bs58"), 1);
|
|
145
147
|
var EscrowState = /* @__PURE__ */ ((EscrowState2) => {
|
|
146
148
|
EscrowState2["CREATED"] = "CREATED";
|
|
147
149
|
EscrowState2["FUNDED"] = "FUNDED";
|
|
@@ -188,6 +190,33 @@ function canonicalize(value) {
|
|
|
188
190
|
}
|
|
189
191
|
return JSON.stringify(value);
|
|
190
192
|
}
|
|
193
|
+
var SPEC_KEYS = [
|
|
194
|
+
"version",
|
|
195
|
+
"taskType",
|
|
196
|
+
"description",
|
|
197
|
+
"acceptanceCriteria",
|
|
198
|
+
"deliverableFormat",
|
|
199
|
+
"metadata"
|
|
200
|
+
];
|
|
201
|
+
var CRITERION_KEYS = ["id", "description", "weight", "required"];
|
|
202
|
+
var FORMAT_KEYS = ["type", "schema", "mimeType", "maxSizeBytes", "language"];
|
|
203
|
+
function pick(value, keys) {
|
|
204
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) return value;
|
|
205
|
+
const source = value;
|
|
206
|
+
return Object.fromEntries(keys.filter((k) => k in source).map((k) => [k, source[k]]));
|
|
207
|
+
}
|
|
208
|
+
function normalizeTaskSpec(spec2) {
|
|
209
|
+
const top = pick(spec2, SPEC_KEYS);
|
|
210
|
+
const criteria = top.acceptanceCriteria;
|
|
211
|
+
return {
|
|
212
|
+
...top,
|
|
213
|
+
acceptanceCriteria: Array.isArray(criteria) ? criteria.map((c) => pick(c, CRITERION_KEYS)) : criteria,
|
|
214
|
+
deliverableFormat: pick(top.deliverableFormat, FORMAT_KEYS)
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
function computeTaskSpecHash(spec2) {
|
|
218
|
+
return (0, import_crypto.createHash)("sha256").update(canonicalize(normalizeTaskSpec(spec2)), "utf8").digest("hex");
|
|
219
|
+
}
|
|
191
220
|
function disputeReasonError(reason) {
|
|
192
221
|
if (reason.length === 0) return "reason must not be empty";
|
|
193
222
|
const bytes = new TextEncoder().encode(reason).length;
|
|
@@ -196,8 +225,16 @@ function disputeReasonError(reason) {
|
|
|
196
225
|
}
|
|
197
226
|
return null;
|
|
198
227
|
}
|
|
228
|
+
var SAFE_URL_SCHEMES = ["http:", "https:", "ipfs:", "ar:"];
|
|
229
|
+
function isSafeUrl(value) {
|
|
230
|
+
try {
|
|
231
|
+
return SAFE_URL_SCHEMES.includes(new URL(value).protocol);
|
|
232
|
+
} catch {
|
|
233
|
+
return false;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
199
236
|
function hashBody(rawBody) {
|
|
200
|
-
return (0,
|
|
237
|
+
return (0, import_crypto2.createHash)("sha256").update(rawBody, "utf8").digest("hex");
|
|
201
238
|
}
|
|
202
239
|
function buildSignedMessage(timestamp, method, fullPath, bodyHash) {
|
|
203
240
|
return `escro:${String(timestamp)}:${method}:${fullPath}:${bodyHash}`;
|
|
@@ -241,6 +278,18 @@ function verifyBotDescriptorSignature(descriptor) {
|
|
|
241
278
|
return false;
|
|
242
279
|
}
|
|
243
280
|
}
|
|
281
|
+
var ESCROW_INSTRUCTION_NAMES = [
|
|
282
|
+
"create_escrow",
|
|
283
|
+
"claim_task",
|
|
284
|
+
"submit_deliverable",
|
|
285
|
+
"raise_dispute",
|
|
286
|
+
"cancel_escrow",
|
|
287
|
+
"release_payment",
|
|
288
|
+
"timeout_release",
|
|
289
|
+
"refund_buyer",
|
|
290
|
+
"arbitration_release",
|
|
291
|
+
"arbitration_refund"
|
|
292
|
+
];
|
|
244
293
|
function spec(discriminator, escrowAccountIndex, cause) {
|
|
245
294
|
return {
|
|
246
295
|
discriminator: Uint8Array.from(discriminator),
|
|
@@ -261,6 +310,66 @@ var ESCROW_INSTRUCTIONS = {
|
|
|
261
310
|
arbitration_release: spec([118, 157, 141, 26, 104, 117, 94, 229], 4, "ARBITRATION_RELEASE"),
|
|
262
311
|
arbitration_refund: spec([255, 194, 84, 248, 185, 249, 120, 122], 4, "ARBITRATION_REFUND")
|
|
263
312
|
};
|
|
313
|
+
function escrowInstructionName(data) {
|
|
314
|
+
for (const name of ESCROW_INSTRUCTION_NAMES) {
|
|
315
|
+
const disc2 = ESCROW_INSTRUCTIONS[name].discriminator;
|
|
316
|
+
if (disc2.every((b, i) => data[i] === b)) return name;
|
|
317
|
+
}
|
|
318
|
+
return null;
|
|
319
|
+
}
|
|
320
|
+
var Reader = class {
|
|
321
|
+
constructor(buf) {
|
|
322
|
+
__publicField(this, "buf");
|
|
323
|
+
__publicField(this, "offset", 8);
|
|
324
|
+
this.buf = buf;
|
|
325
|
+
}
|
|
326
|
+
take(n) {
|
|
327
|
+
if (this.offset + n > this.buf.length) {
|
|
328
|
+
throw new Error(
|
|
329
|
+
`instruction data truncated: need ${String(n)} bytes at offset ${String(this.offset)}, have ${String(this.buf.length)}`
|
|
330
|
+
);
|
|
331
|
+
}
|
|
332
|
+
const out = this.buf.subarray(this.offset, this.offset + n);
|
|
333
|
+
this.offset += n;
|
|
334
|
+
return out;
|
|
335
|
+
}
|
|
336
|
+
u8() {
|
|
337
|
+
return this.take(1).readUInt8(0);
|
|
338
|
+
}
|
|
339
|
+
u64() {
|
|
340
|
+
return this.take(8).readBigUInt64LE(0);
|
|
341
|
+
}
|
|
342
|
+
i64() {
|
|
343
|
+
return this.take(8).readBigInt64LE(0);
|
|
344
|
+
}
|
|
345
|
+
string() {
|
|
346
|
+
const len = this.take(4).readUInt32LE(0);
|
|
347
|
+
return this.take(len).toString("utf8");
|
|
348
|
+
}
|
|
349
|
+
option(read) {
|
|
350
|
+
return this.u8() === 0 ? null : read();
|
|
351
|
+
}
|
|
352
|
+
bytes(n) {
|
|
353
|
+
return this.take(n);
|
|
354
|
+
}
|
|
355
|
+
};
|
|
356
|
+
function decodeCreateEscrowArgs(data) {
|
|
357
|
+
const r = new Reader(Buffer.from(data));
|
|
358
|
+
return {
|
|
359
|
+
taskId: r.string(),
|
|
360
|
+
amount: r.u64(),
|
|
361
|
+
deadline: r.i64(),
|
|
362
|
+
specHash: r.string(),
|
|
363
|
+
assignedWorker: r.option(() => import_bs583.default.encode(r.bytes(32)))
|
|
364
|
+
};
|
|
365
|
+
}
|
|
366
|
+
function decodeSubmitDeliverableArgs(data) {
|
|
367
|
+
const r = new Reader(Buffer.from(data));
|
|
368
|
+
return { deliverableHash: r.string(), proofUri: r.option(() => r.string()) };
|
|
369
|
+
}
|
|
370
|
+
function decodeRaiseDisputeArgs(data) {
|
|
371
|
+
return { reason: new Reader(Buffer.from(data)).string() };
|
|
372
|
+
}
|
|
264
373
|
|
|
265
374
|
// src/payments.ts
|
|
266
375
|
var RAILS = ["escrow", "x402"];
|
|
@@ -635,14 +744,19 @@ async function pollUntil(address, fetcher, predicate, timeoutMs = MS_24_H) {
|
|
|
635
744
|
}
|
|
636
745
|
|
|
637
746
|
// src/solana.ts
|
|
638
|
-
var import_node_crypto = require("crypto");
|
|
639
747
|
var import_web32 = require("@solana/web3.js");
|
|
640
748
|
var import_spl_token = require("@solana/spl-token");
|
|
641
749
|
|
|
642
750
|
// ../shared/dist/solana.js
|
|
643
751
|
var import_web3 = require("@solana/web3.js");
|
|
644
|
-
var
|
|
752
|
+
var import_bs584 = __toESM(require("bs58"), 1);
|
|
645
753
|
var utf8 = (s) => new TextEncoder().encode(s);
|
|
754
|
+
function deriveEscrowPda(programId, buyer, taskId) {
|
|
755
|
+
return import_web3.PublicKey.findProgramAddressSync(
|
|
756
|
+
[utf8("escrow"), buyer.toBytes(), utf8(taskId)],
|
|
757
|
+
programId
|
|
758
|
+
)[0];
|
|
759
|
+
}
|
|
646
760
|
function findPlatformConfigPda(programId) {
|
|
647
761
|
return import_web3.PublicKey.findProgramAddressSync([utf8("config")], programId);
|
|
648
762
|
}
|
|
@@ -679,7 +793,7 @@ function decodePlatformConfig(data) {
|
|
|
679
793
|
throw new Error("PlatformConfig discriminator mismatch: not a PlatformConfig account");
|
|
680
794
|
}
|
|
681
795
|
const byte = (at) => data[at] ?? 0;
|
|
682
|
-
const key = (at) =>
|
|
796
|
+
const key = (at) => import_bs584.default.encode(data.subarray(at, at + 32));
|
|
683
797
|
return {
|
|
684
798
|
version: byte(L.version),
|
|
685
799
|
feeBps: byte(L.fee_bps) | byte(L.fee_bps + 1) << 8,
|
|
@@ -691,10 +805,6 @@ function decodePlatformConfig(data) {
|
|
|
691
805
|
}
|
|
692
806
|
|
|
693
807
|
// src/solana.ts
|
|
694
|
-
function disc(name) {
|
|
695
|
-
return Buffer.from((0, import_node_crypto.createHash)("sha256").update(`global:${name}`).digest()).subarray(0, 8);
|
|
696
|
-
}
|
|
697
|
-
var DISC_RELEASE_PAYMENT = disc("release_payment");
|
|
698
808
|
function resolveProgramId(cluster) {
|
|
699
809
|
const id = getProgramId(cluster);
|
|
700
810
|
assertProgramIdNotPlaceholder(id, cluster);
|
|
@@ -704,8 +814,7 @@ function allowedProgramIds(programId) {
|
|
|
704
814
|
return /* @__PURE__ */ new Set([
|
|
705
815
|
programId.toBase58(),
|
|
706
816
|
import_spl_token.TOKEN_PROGRAM_ID.toBase58(),
|
|
707
|
-
import_spl_token.ASSOCIATED_TOKEN_PROGRAM_ID.toBase58()
|
|
708
|
-
import_web32.ComputeBudgetProgram.programId.toBase58()
|
|
817
|
+
import_spl_token.ASSOCIATED_TOKEN_PROGRAM_ID.toBase58()
|
|
709
818
|
]);
|
|
710
819
|
}
|
|
711
820
|
var MAX_INSTRUCTIONS = 6;
|
|
@@ -743,6 +852,12 @@ async function fetchPlatformConfig(connection, cluster) {
|
|
|
743
852
|
}
|
|
744
853
|
return { mint: new import_web32.PublicKey(config.usdcMint), treasury: new import_web32.PublicKey(config.treasury) };
|
|
745
854
|
}
|
|
855
|
+
function refuse(reason) {
|
|
856
|
+
throw new EscroError(
|
|
857
|
+
`Refusing to sign a server-built transaction: ${reason}`,
|
|
858
|
+
"UNEXPECTED_TRANSACTION"
|
|
859
|
+
);
|
|
860
|
+
}
|
|
746
861
|
function validateTransaction(tx, cluster) {
|
|
747
862
|
const programId = resolveProgramId(cluster);
|
|
748
863
|
const allowed = allowedProgramIds(programId);
|
|
@@ -750,36 +865,103 @@ function validateTransaction(tx, cluster) {
|
|
|
750
865
|
for (const ix of tx.instructions) {
|
|
751
866
|
const id = ix.programId.toBase58();
|
|
752
867
|
if (!allowed.has(id)) {
|
|
753
|
-
|
|
754
|
-
`Unexpected program in transaction: ${id}. Allowed: ${[...allowed].join(", ")}`
|
|
755
|
-
);
|
|
868
|
+
refuse(`Unexpected program in transaction: ${id}. Allowed: ${[...allowed].join(", ")}`);
|
|
756
869
|
}
|
|
757
870
|
if (id === tokenProgram) {
|
|
758
871
|
const tag = ix.data.length > 0 ? ix.data[0] : void 0;
|
|
759
872
|
if (tag !== void 0 && FORBIDDEN_TOKEN_IX_TAGS.has(tag)) {
|
|
760
|
-
throw new
|
|
761
|
-
`Refusing to sign a fund-moving SPL Token instruction (tag ${String(tag)}) in a server-built transaction
|
|
873
|
+
throw new EscroError(
|
|
874
|
+
`Refusing to sign a fund-moving SPL Token instruction (tag ${String(tag)}) in a server-built transaction`,
|
|
875
|
+
"UNEXPECTED_TRANSACTION"
|
|
762
876
|
);
|
|
763
877
|
}
|
|
764
878
|
}
|
|
765
879
|
}
|
|
766
880
|
if (tx.instructions.length > MAX_INSTRUCTIONS) {
|
|
767
|
-
|
|
881
|
+
refuse(
|
|
768
882
|
`Too many instructions (${String(tx.instructions.length)}). Max allowed: ${String(MAX_INSTRUCTIONS)}`
|
|
769
883
|
);
|
|
770
884
|
}
|
|
771
885
|
}
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
const tx = import_web32.Transaction.from(buf);
|
|
886
|
+
var ATA_CREATE_IDEMPOTENT = 1;
|
|
887
|
+
function verifyServerTransaction(tx, cluster, wallet, expected) {
|
|
775
888
|
validateTransaction(tx, cluster);
|
|
889
|
+
const programId = resolveProgramId(cluster);
|
|
890
|
+
if (!tx.feePayer?.equals(wallet)) refuse("the fee payer is not the wallet");
|
|
891
|
+
const escro = tx.instructions.filter((ix2) => ix2.programId.equals(programId));
|
|
892
|
+
const others = tx.instructions.filter((ix2) => !ix2.programId.equals(programId));
|
|
893
|
+
for (const ix2 of others) {
|
|
894
|
+
const ataCreate = expected.name === "release_payment" && ix2.programId.equals(import_spl_token.ASSOCIATED_TOKEN_PROGRAM_ID) && ix2.data.length === 1 && ix2.data[0] === ATA_CREATE_IDEMPOTENT;
|
|
895
|
+
if (!ataCreate) refuse(`unexpected ${ix2.programId.toBase58()} instruction`);
|
|
896
|
+
}
|
|
897
|
+
if (escro.length !== 1) refuse(`${String(escro.length)} escro instructions, expected 1`);
|
|
898
|
+
const [ix] = escro;
|
|
899
|
+
if (ix === void 0) refuse("no escro instruction");
|
|
900
|
+
const name = escrowInstructionName(ix.data);
|
|
901
|
+
if (name !== expected.name)
|
|
902
|
+
refuse(`${name ?? "an unknown instruction"}, expected ${expected.name}`);
|
|
903
|
+
const spec2 = ESCROW_INSTRUCTIONS[name];
|
|
904
|
+
const actor = ix.keys[spec2.signerAccountIndex];
|
|
905
|
+
if (actor === void 0 || !actor.pubkey.equals(wallet) || !actor.isSigner) {
|
|
906
|
+
refuse("the acting signer is not the wallet");
|
|
907
|
+
}
|
|
908
|
+
if (ix.keys[spec2.escrowAccountIndex]?.pubkey.toBase58() !== expected.escrowPda) {
|
|
909
|
+
refuse(`the escrow is not ${expected.escrowPda}`);
|
|
910
|
+
}
|
|
911
|
+
try {
|
|
912
|
+
switch (expected.name) {
|
|
913
|
+
case "create_escrow": {
|
|
914
|
+
const args = decodeCreateEscrowArgs(ix.data);
|
|
915
|
+
if (args.taskId !== expected.taskId) refuse("the task id differs");
|
|
916
|
+
if (deriveEscrowPda(programId, wallet, args.taskId).toBase58() !== expected.escrowPda) {
|
|
917
|
+
refuse("the escrow is not derived from the wallet and task id");
|
|
918
|
+
}
|
|
919
|
+
if (args.amount !== expected.amount) refuse("the amount differs");
|
|
920
|
+
if (args.deadline !== expected.deadline) refuse("the deadline differs");
|
|
921
|
+
if (args.specHash !== expected.specHash) refuse("the spec hash differs");
|
|
922
|
+
if (args.assignedWorker !== expected.assignedWorker) refuse("the assigned worker differs");
|
|
923
|
+
break;
|
|
924
|
+
}
|
|
925
|
+
case "submit_deliverable": {
|
|
926
|
+
const args = decodeSubmitDeliverableArgs(ix.data);
|
|
927
|
+
if (args.deliverableHash !== expected.deliverableHash)
|
|
928
|
+
refuse("the deliverable hash differs");
|
|
929
|
+
if (args.proofUri !== expected.proofUri) refuse("the proof URI differs");
|
|
930
|
+
break;
|
|
931
|
+
}
|
|
932
|
+
case "raise_dispute":
|
|
933
|
+
if (decodeRaiseDisputeArgs(ix.data).reason !== expected.reason)
|
|
934
|
+
refuse("the reason differs");
|
|
935
|
+
break;
|
|
936
|
+
default:
|
|
937
|
+
if (ix.data.length !== ESCROW_INSTRUCTIONS[name].discriminator.length) {
|
|
938
|
+
refuse(`${name} carries unexpected arguments`);
|
|
939
|
+
}
|
|
940
|
+
}
|
|
941
|
+
} catch (err) {
|
|
942
|
+
if (err instanceof EscroError) throw err;
|
|
943
|
+
refuse(`malformed ${name} arguments`);
|
|
944
|
+
}
|
|
945
|
+
}
|
|
946
|
+
async function signAndSend(base64Tx, wallet, connection, cluster, expected) {
|
|
947
|
+
const tx = import_web32.Transaction.from(Buffer.from(base64Tx, "base64"));
|
|
948
|
+
verifyServerTransaction(tx, cluster, wallet.publicKey, expected);
|
|
776
949
|
tx.partialSign(wallet);
|
|
777
950
|
const raw = tx.serialize();
|
|
778
951
|
const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash("confirmed");
|
|
779
952
|
const signature = await connection.sendRawTransaction(raw, {
|
|
780
953
|
skipPreflight: false
|
|
781
954
|
});
|
|
782
|
-
|
|
955
|
+
const { value } = await connection.confirmTransaction(
|
|
956
|
+
{ signature, blockhash, lastValidBlockHeight },
|
|
957
|
+
"confirmed"
|
|
958
|
+
);
|
|
959
|
+
if (value.err !== null) {
|
|
960
|
+
throw new EscroError(
|
|
961
|
+
`Transaction ${signature} failed at execution: ${JSON.stringify(value.err)}`,
|
|
962
|
+
"TX_FAILED"
|
|
963
|
+
);
|
|
964
|
+
}
|
|
783
965
|
return signature;
|
|
784
966
|
}
|
|
785
967
|
async function buildReleasePaymentTx(params) {
|
|
@@ -822,7 +1004,7 @@ async function buildReleasePaymentTx(params) {
|
|
|
822
1004
|
{ pubkey: import_spl_token.TOKEN_PROGRAM_ID, isSigner: false, isWritable: false },
|
|
823
1005
|
{ pubkey: import_spl_token.ASSOCIATED_TOKEN_PROGRAM_ID, isSigner: false, isWritable: false }
|
|
824
1006
|
],
|
|
825
|
-
data:
|
|
1007
|
+
data: Buffer.from(ESCROW_INSTRUCTIONS.release_payment.discriminator)
|
|
826
1008
|
});
|
|
827
1009
|
const { blockhash } = await connection.getLatestBlockhash("confirmed");
|
|
828
1010
|
const tx = new import_web32.Transaction();
|
|
@@ -853,14 +1035,6 @@ function isRetryableConfirmCode(code) {
|
|
|
853
1035
|
function isRetryableReleaseCode(code) {
|
|
854
1036
|
return code === "ESCROW_NOT_SETTLED" || isRetryableConfirmCode(code);
|
|
855
1037
|
}
|
|
856
|
-
function isUrl(value) {
|
|
857
|
-
try {
|
|
858
|
-
new URL(value);
|
|
859
|
-
return true;
|
|
860
|
-
} catch {
|
|
861
|
-
return false;
|
|
862
|
-
}
|
|
863
|
-
}
|
|
864
1038
|
var sleep2 = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
865
1039
|
var Escro = class {
|
|
866
1040
|
constructor(options) {
|
|
@@ -883,7 +1057,15 @@ var Escro = class {
|
|
|
883
1057
|
*/
|
|
884
1058
|
async createEscrow(params) {
|
|
885
1059
|
const { escrowId, escrowPda, unsignedTx } = await this.api.createEscrow(params);
|
|
886
|
-
const signature = await this.send(unsignedTx
|
|
1060
|
+
const signature = await this.send(unsignedTx, {
|
|
1061
|
+
name: "create_escrow",
|
|
1062
|
+
escrowPda,
|
|
1063
|
+
taskId: escrowId,
|
|
1064
|
+
amount: BigInt(params.amountUsdc),
|
|
1065
|
+
deadline: BigInt(params.deadlineUnix),
|
|
1066
|
+
specHash: computeTaskSpecHash(params.taskSpec),
|
|
1067
|
+
assignedWorker: params.assignedWorker
|
|
1068
|
+
});
|
|
887
1069
|
await this.confirm(escrowPda, signature);
|
|
888
1070
|
return { escrowId, escrowPda, signature };
|
|
889
1071
|
}
|
|
@@ -904,9 +1086,11 @@ var Escro = class {
|
|
|
904
1086
|
* {@link Escro.releasePayment}, reporting whether the API recorded the release.
|
|
905
1087
|
* `ESCROW_NOT_SETTLED` (the API's RPC does not yet show the escrow closed), the codes
|
|
906
1088
|
* {@link Escro.confirm} retries and a network failure are retried for about 30 s. A
|
|
907
|
-
*
|
|
908
|
-
* `confirm.landed: false` and an `EscroConfirmError` (the API's code, or
|
|
909
|
-
* `NETWORK_ERROR` when the last call never reached it).
|
|
1089
|
+
* failed record never throws: the release already landed, so the signature is returned
|
|
1090
|
+
* with `confirm.landed: false` and an `EscroConfirmError` (the API's code, or
|
|
1091
|
+
* `NETWORK_ERROR` when the last call never reached it). A release that failed at
|
|
1092
|
+
* execution on chain throws an {@link EscroError} with code `TX_FAILED`, and the API is
|
|
1093
|
+
* never asked to record it.
|
|
910
1094
|
*
|
|
911
1095
|
* @returns `{ signature, confirm }`.
|
|
912
1096
|
*/
|
|
@@ -925,12 +1109,7 @@ var Escro = class {
|
|
|
925
1109
|
connection: this.connection,
|
|
926
1110
|
cluster: this.cluster
|
|
927
1111
|
});
|
|
928
|
-
const signature = await
|
|
929
|
-
unsignedTx,
|
|
930
|
-
this.options.wallet,
|
|
931
|
-
this.connection,
|
|
932
|
-
this.cluster
|
|
933
|
-
);
|
|
1112
|
+
const signature = await this.send(unsignedTx, { name: "release_payment", escrowPda: address });
|
|
934
1113
|
try {
|
|
935
1114
|
await this.retryRecord(
|
|
936
1115
|
address,
|
|
@@ -953,11 +1132,18 @@ var Escro = class {
|
|
|
953
1132
|
async raiseDispute(address, params) {
|
|
954
1133
|
const reasonError = disputeReasonError(params.reason);
|
|
955
1134
|
if (reasonError !== null) throw new EscroError(reasonError, "VALIDATION_ERROR");
|
|
956
|
-
if (params.evidence !== void 0 && !
|
|
957
|
-
throw new EscroError(
|
|
1135
|
+
if (params.evidence !== void 0 && !isSafeUrl(params.evidence)) {
|
|
1136
|
+
throw new EscroError(
|
|
1137
|
+
`evidence must be an http(s), ipfs or ar URL: ${params.evidence}`,
|
|
1138
|
+
"VALIDATION_ERROR"
|
|
1139
|
+
);
|
|
958
1140
|
}
|
|
959
1141
|
const { unsignedTx } = await this.api.raiseDispute(address, { reason: params.reason });
|
|
960
|
-
const signature = await this.send(unsignedTx
|
|
1142
|
+
const signature = await this.send(unsignedTx, {
|
|
1143
|
+
name: "raise_dispute",
|
|
1144
|
+
escrowPda: address,
|
|
1145
|
+
reason: params.reason
|
|
1146
|
+
});
|
|
961
1147
|
await this.confirm(address, signature, {
|
|
962
1148
|
...params.evidence !== void 0 && { evidence: params.evidence }
|
|
963
1149
|
});
|
|
@@ -972,7 +1158,7 @@ var Escro = class {
|
|
|
972
1158
|
*/
|
|
973
1159
|
async cancelEscrow(address) {
|
|
974
1160
|
const { unsignedTx } = await this.api.cancelEscrow(address);
|
|
975
|
-
return this.sendAndConfirm(address, unsignedTx);
|
|
1161
|
+
return this.sendAndConfirm(address, unsignedTx, { name: "cancel_escrow", escrowPda: address });
|
|
976
1162
|
}
|
|
977
1163
|
// ── Payments (dual-path; x402 reserved) ───────────────────────────────────────
|
|
978
1164
|
/**
|
|
@@ -1003,7 +1189,7 @@ var Escro = class {
|
|
|
1003
1189
|
*/
|
|
1004
1190
|
async claimTask(address) {
|
|
1005
1191
|
const { unsignedTx } = await this.api.claimTask(address);
|
|
1006
|
-
return this.sendAndConfirm(address, unsignedTx);
|
|
1192
|
+
return this.sendAndConfirm(address, unsignedTx, { name: "claim_task", escrowPda: address });
|
|
1007
1193
|
}
|
|
1008
1194
|
/**
|
|
1009
1195
|
* Submit a deliverable for the buyer to review. Worker must be the wallet.
|
|
@@ -1013,7 +1199,12 @@ var Escro = class {
|
|
|
1013
1199
|
*/
|
|
1014
1200
|
async submitDeliverable(address, params) {
|
|
1015
1201
|
const { unsignedTx } = await this.api.submitDeliverable(address, params);
|
|
1016
|
-
return this.sendAndConfirm(address, unsignedTx
|
|
1202
|
+
return this.sendAndConfirm(address, unsignedTx, {
|
|
1203
|
+
name: "submit_deliverable",
|
|
1204
|
+
escrowPda: address,
|
|
1205
|
+
deliverableHash: params.contentHash,
|
|
1206
|
+
proofUri: params.proofUri ?? null
|
|
1207
|
+
});
|
|
1017
1208
|
}
|
|
1018
1209
|
/**
|
|
1019
1210
|
* List tasks assigned to the wallet's public key.
|
|
@@ -1179,11 +1370,11 @@ var Escro = class {
|
|
|
1179
1370
|
delay = Math.min(delay * 2, CONFIRM_MAX_DELAY_MS);
|
|
1180
1371
|
}
|
|
1181
1372
|
}
|
|
1182
|
-
send(unsignedTx) {
|
|
1183
|
-
return signAndSend(unsignedTx, this.options.wallet, this.connection, this.cluster);
|
|
1373
|
+
send(unsignedTx, expected) {
|
|
1374
|
+
return signAndSend(unsignedTx, this.options.wallet, this.connection, this.cluster, expected);
|
|
1184
1375
|
}
|
|
1185
|
-
async sendAndConfirm(address, unsignedTx) {
|
|
1186
|
-
const signature = await this.send(unsignedTx);
|
|
1376
|
+
async sendAndConfirm(address, unsignedTx, expected) {
|
|
1377
|
+
const signature = await this.send(unsignedTx, expected);
|
|
1187
1378
|
await this.confirm(address, signature);
|
|
1188
1379
|
return signature;
|
|
1189
1380
|
}
|
|
@@ -1217,7 +1408,7 @@ function serviceResultToSubmitParams(result) {
|
|
|
1217
1408
|
}
|
|
1218
1409
|
|
|
1219
1410
|
// src/adapter-contract.ts
|
|
1220
|
-
var
|
|
1411
|
+
var import_crypto3 = require("crypto");
|
|
1221
1412
|
var AdapterContractError = class extends EscroError {
|
|
1222
1413
|
constructor(adapterId, violations) {
|
|
1223
1414
|
super(
|
|
@@ -1233,7 +1424,7 @@ function errMessage(err) {
|
|
|
1233
1424
|
return err instanceof Error ? err.message : String(err);
|
|
1234
1425
|
}
|
|
1235
1426
|
function sha256Hex(content) {
|
|
1236
|
-
return (0,
|
|
1427
|
+
return (0, import_crypto3.createHash)("sha256").update(content).digest("hex");
|
|
1237
1428
|
}
|
|
1238
1429
|
function validateServiceResult(result) {
|
|
1239
1430
|
if (typeof result !== "object" || result === null) {
|
|
@@ -1304,12 +1495,12 @@ async function assertServiceAdapterContract(adapter, options) {
|
|
|
1304
1495
|
}
|
|
1305
1496
|
|
|
1306
1497
|
// src/adapters/bittensor/index.ts
|
|
1307
|
-
var
|
|
1498
|
+
var import_crypto4 = require("crypto");
|
|
1308
1499
|
function tao(amount) {
|
|
1309
1500
|
return amount;
|
|
1310
1501
|
}
|
|
1311
1502
|
function sha256Hex2(content) {
|
|
1312
|
-
return (0,
|
|
1503
|
+
return (0, import_crypto4.createHash)("sha256").update(content).digest("hex");
|
|
1313
1504
|
}
|
|
1314
1505
|
var REFERENCE_MICRO_USDC_PER_TAO = 3e8;
|
|
1315
1506
|
var defaultSwap = (microUsdc) => Promise.resolve(tao(microUsdc / REFERENCE_MICRO_USDC_PER_TAO));
|
|
@@ -1429,12 +1620,12 @@ function createGradientsAdapter(config = {}) {
|
|
|
1429
1620
|
}
|
|
1430
1621
|
|
|
1431
1622
|
// src/adapters/ridges/index.ts
|
|
1432
|
-
var
|
|
1623
|
+
var import_crypto5 = require("crypto");
|
|
1433
1624
|
var RIDGES_ADAPTER_ID = "ridges";
|
|
1434
1625
|
var RIDGES_CAPABILITIES = ["code-generation"];
|
|
1435
1626
|
var DEFAULT_SERVICE = "ridges";
|
|
1436
1627
|
function sha256Hex3(content) {
|
|
1437
|
-
return (0,
|
|
1628
|
+
return (0, import_crypto5.createHash)("sha256").update(content).digest("hex");
|
|
1438
1629
|
}
|
|
1439
1630
|
var RIDGES_DEMO_MARKER = "ridges-demo-v1";
|
|
1440
1631
|
var RIDGES_DEMO_COVERAGE_TARGET = 0.8;
|
|
@@ -1792,12 +1983,12 @@ function createLiumAdapter(config = {}) {
|
|
|
1792
1983
|
}
|
|
1793
1984
|
|
|
1794
1985
|
// src/adapters/akash/index.ts
|
|
1795
|
-
var
|
|
1986
|
+
var import_crypto6 = require("crypto");
|
|
1796
1987
|
function akt(amount) {
|
|
1797
1988
|
return amount;
|
|
1798
1989
|
}
|
|
1799
1990
|
function sha256Hex4(content) {
|
|
1800
|
-
return (0,
|
|
1991
|
+
return (0, import_crypto6.createHash)("sha256").update(content).digest("hex");
|
|
1801
1992
|
}
|
|
1802
1993
|
var AKASH_ADAPTER_ID = "akash";
|
|
1803
1994
|
var AKASH_CAPABILITIES = ["cloud-compute"];
|
|
@@ -1925,7 +2116,7 @@ function createAkashAdapter(config = {}) {
|
|
|
1925
2116
|
}
|
|
1926
2117
|
|
|
1927
2118
|
// src/adapters/render/index.ts
|
|
1928
|
-
var
|
|
2119
|
+
var import_crypto7 = require("crypto");
|
|
1929
2120
|
function renderAmount(amount) {
|
|
1930
2121
|
return amount;
|
|
1931
2122
|
}
|
|
@@ -1934,7 +2125,7 @@ var RENDER_CAPABILITIES = ["3d-rendering", "video-rendering", "gpu-inference"];
|
|
|
1934
2125
|
var DEFAULT_SERVICE2 = "render";
|
|
1935
2126
|
var DEFAULT_TASK_BUDGET_MICRO_USDC5 = 15e6;
|
|
1936
2127
|
function sha256Hex5(content) {
|
|
1937
|
-
return (0,
|
|
2128
|
+
return (0, import_crypto7.createHash)("sha256").update(content).digest("hex");
|
|
1938
2129
|
}
|
|
1939
2130
|
var REFERENCE_MICRO_USDC_PER_RENDER = 2e6;
|
|
1940
2131
|
var defaultSwap3 = (microUsdc) => Promise.resolve(renderAmount(microUsdc / REFERENCE_MICRO_USDC_PER_RENDER));
|
|
@@ -2068,7 +2259,7 @@ function createRenderAdapter(config = {}) {
|
|
|
2068
2259
|
}
|
|
2069
2260
|
|
|
2070
2261
|
// src/adapters/gensyn/index.ts
|
|
2071
|
-
var
|
|
2262
|
+
var import_crypto8 = require("crypto");
|
|
2072
2263
|
var GENSYN_ADAPTER_ID = "gensyn";
|
|
2073
2264
|
var GENSYN_CAPABILITIES = ["verifiable-compute"];
|
|
2074
2265
|
var GENSYN_REE_SCHEME = "gensyn-ree-v1";
|
|
@@ -2076,7 +2267,7 @@ var GENSYN_DEMO_MARKER = "gensyn-ree-demo-v1";
|
|
|
2076
2267
|
var GENSYN_DEMO_SEED = 12345;
|
|
2077
2268
|
var GENSYN_DEMO_STEPS = 16;
|
|
2078
2269
|
function sha256Hex6(content) {
|
|
2079
|
-
return (0,
|
|
2270
|
+
return (0, import_crypto8.createHash)("sha256").update(content).digest("hex");
|
|
2080
2271
|
}
|
|
2081
2272
|
var LCG_MULT = 1103515245n;
|
|
2082
2273
|
var LCG_INC = 12345n;
|
|
@@ -2238,14 +2429,14 @@ function createGensynAdapter(config = {}) {
|
|
|
2238
2429
|
}
|
|
2239
2430
|
|
|
2240
2431
|
// src/adapters/zkml/index.ts
|
|
2241
|
-
var
|
|
2432
|
+
var import_crypto9 = require("crypto");
|
|
2242
2433
|
var ZKML_ADAPTER_ID = "zkml";
|
|
2243
2434
|
var ZKML_CAPABILITIES = ["zk-verified-inference"];
|
|
2244
2435
|
var ZKML_DEMO_MARKER = "zkml-demo-v1";
|
|
2245
2436
|
var ZKML_PROOF_SCHEME = "escro-zkml-ref-v1";
|
|
2246
2437
|
var ZKML_PROOF_URI_PREFIX = "zkml-proof:";
|
|
2247
2438
|
function sha256Hex7(content) {
|
|
2248
|
-
return (0,
|
|
2439
|
+
return (0, import_crypto9.createHash)("sha256").update(content).digest("hex");
|
|
2249
2440
|
}
|
|
2250
2441
|
function computeZkmlVerificationTag(publicInputs) {
|
|
2251
2442
|
return sha256Hex7(
|