@escro/sdk 0.4.1 → 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 +239 -59
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +225 -46
- package/dist/index.js.map +1 -1
- package/package.json +6 -6
package/dist/index.js
CHANGED
|
@@ -7,10 +7,12 @@ import { Connection as Connection2, PublicKey as PublicKey3 } from "@solana/web3
|
|
|
7
7
|
|
|
8
8
|
// ../shared/dist/index.js
|
|
9
9
|
import { createHash } from "crypto";
|
|
10
|
+
import { createHash as createHash2 } from "crypto";
|
|
10
11
|
import nacl from "tweetnacl";
|
|
11
12
|
import bs58 from "bs58";
|
|
12
13
|
import nacl2 from "tweetnacl";
|
|
13
14
|
import bs582 from "bs58";
|
|
15
|
+
import bs583 from "bs58";
|
|
14
16
|
var EscrowState = /* @__PURE__ */ ((EscrowState2) => {
|
|
15
17
|
EscrowState2["CREATED"] = "CREATED";
|
|
16
18
|
EscrowState2["FUNDED"] = "FUNDED";
|
|
@@ -57,6 +59,33 @@ function canonicalize(value) {
|
|
|
57
59
|
}
|
|
58
60
|
return JSON.stringify(value);
|
|
59
61
|
}
|
|
62
|
+
var SPEC_KEYS = [
|
|
63
|
+
"version",
|
|
64
|
+
"taskType",
|
|
65
|
+
"description",
|
|
66
|
+
"acceptanceCriteria",
|
|
67
|
+
"deliverableFormat",
|
|
68
|
+
"metadata"
|
|
69
|
+
];
|
|
70
|
+
var CRITERION_KEYS = ["id", "description", "weight", "required"];
|
|
71
|
+
var FORMAT_KEYS = ["type", "schema", "mimeType", "maxSizeBytes", "language"];
|
|
72
|
+
function pick(value, keys) {
|
|
73
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) return value;
|
|
74
|
+
const source = value;
|
|
75
|
+
return Object.fromEntries(keys.filter((k) => k in source).map((k) => [k, source[k]]));
|
|
76
|
+
}
|
|
77
|
+
function normalizeTaskSpec(spec2) {
|
|
78
|
+
const top = pick(spec2, SPEC_KEYS);
|
|
79
|
+
const criteria = top.acceptanceCriteria;
|
|
80
|
+
return {
|
|
81
|
+
...top,
|
|
82
|
+
acceptanceCriteria: Array.isArray(criteria) ? criteria.map((c) => pick(c, CRITERION_KEYS)) : criteria,
|
|
83
|
+
deliverableFormat: pick(top.deliverableFormat, FORMAT_KEYS)
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
function computeTaskSpecHash(spec2) {
|
|
87
|
+
return createHash("sha256").update(canonicalize(normalizeTaskSpec(spec2)), "utf8").digest("hex");
|
|
88
|
+
}
|
|
60
89
|
function disputeReasonError(reason) {
|
|
61
90
|
if (reason.length === 0) return "reason must not be empty";
|
|
62
91
|
const bytes = new TextEncoder().encode(reason).length;
|
|
@@ -65,8 +94,16 @@ function disputeReasonError(reason) {
|
|
|
65
94
|
}
|
|
66
95
|
return null;
|
|
67
96
|
}
|
|
97
|
+
var SAFE_URL_SCHEMES = ["http:", "https:", "ipfs:", "ar:"];
|
|
98
|
+
function isSafeUrl(value) {
|
|
99
|
+
try {
|
|
100
|
+
return SAFE_URL_SCHEMES.includes(new URL(value).protocol);
|
|
101
|
+
} catch {
|
|
102
|
+
return false;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
68
105
|
function hashBody(rawBody) {
|
|
69
|
-
return
|
|
106
|
+
return createHash2("sha256").update(rawBody, "utf8").digest("hex");
|
|
70
107
|
}
|
|
71
108
|
function buildSignedMessage(timestamp, method, fullPath, bodyHash) {
|
|
72
109
|
return `escro:${String(timestamp)}:${method}:${fullPath}:${bodyHash}`;
|
|
@@ -110,6 +147,18 @@ function verifyBotDescriptorSignature(descriptor) {
|
|
|
110
147
|
return false;
|
|
111
148
|
}
|
|
112
149
|
}
|
|
150
|
+
var ESCROW_INSTRUCTION_NAMES = [
|
|
151
|
+
"create_escrow",
|
|
152
|
+
"claim_task",
|
|
153
|
+
"submit_deliverable",
|
|
154
|
+
"raise_dispute",
|
|
155
|
+
"cancel_escrow",
|
|
156
|
+
"release_payment",
|
|
157
|
+
"timeout_release",
|
|
158
|
+
"refund_buyer",
|
|
159
|
+
"arbitration_release",
|
|
160
|
+
"arbitration_refund"
|
|
161
|
+
];
|
|
113
162
|
function spec(discriminator, escrowAccountIndex, cause) {
|
|
114
163
|
return {
|
|
115
164
|
discriminator: Uint8Array.from(discriminator),
|
|
@@ -130,6 +179,66 @@ var ESCROW_INSTRUCTIONS = {
|
|
|
130
179
|
arbitration_release: spec([118, 157, 141, 26, 104, 117, 94, 229], 4, "ARBITRATION_RELEASE"),
|
|
131
180
|
arbitration_refund: spec([255, 194, 84, 248, 185, 249, 120, 122], 4, "ARBITRATION_REFUND")
|
|
132
181
|
};
|
|
182
|
+
function escrowInstructionName(data) {
|
|
183
|
+
for (const name of ESCROW_INSTRUCTION_NAMES) {
|
|
184
|
+
const disc2 = ESCROW_INSTRUCTIONS[name].discriminator;
|
|
185
|
+
if (disc2.every((b, i) => data[i] === b)) return name;
|
|
186
|
+
}
|
|
187
|
+
return null;
|
|
188
|
+
}
|
|
189
|
+
var Reader = class {
|
|
190
|
+
constructor(buf) {
|
|
191
|
+
__publicField(this, "buf");
|
|
192
|
+
__publicField(this, "offset", 8);
|
|
193
|
+
this.buf = buf;
|
|
194
|
+
}
|
|
195
|
+
take(n) {
|
|
196
|
+
if (this.offset + n > this.buf.length) {
|
|
197
|
+
throw new Error(
|
|
198
|
+
`instruction data truncated: need ${String(n)} bytes at offset ${String(this.offset)}, have ${String(this.buf.length)}`
|
|
199
|
+
);
|
|
200
|
+
}
|
|
201
|
+
const out = this.buf.subarray(this.offset, this.offset + n);
|
|
202
|
+
this.offset += n;
|
|
203
|
+
return out;
|
|
204
|
+
}
|
|
205
|
+
u8() {
|
|
206
|
+
return this.take(1).readUInt8(0);
|
|
207
|
+
}
|
|
208
|
+
u64() {
|
|
209
|
+
return this.take(8).readBigUInt64LE(0);
|
|
210
|
+
}
|
|
211
|
+
i64() {
|
|
212
|
+
return this.take(8).readBigInt64LE(0);
|
|
213
|
+
}
|
|
214
|
+
string() {
|
|
215
|
+
const len = this.take(4).readUInt32LE(0);
|
|
216
|
+
return this.take(len).toString("utf8");
|
|
217
|
+
}
|
|
218
|
+
option(read) {
|
|
219
|
+
return this.u8() === 0 ? null : read();
|
|
220
|
+
}
|
|
221
|
+
bytes(n) {
|
|
222
|
+
return this.take(n);
|
|
223
|
+
}
|
|
224
|
+
};
|
|
225
|
+
function decodeCreateEscrowArgs(data) {
|
|
226
|
+
const r = new Reader(Buffer.from(data));
|
|
227
|
+
return {
|
|
228
|
+
taskId: r.string(),
|
|
229
|
+
amount: r.u64(),
|
|
230
|
+
deadline: r.i64(),
|
|
231
|
+
specHash: r.string(),
|
|
232
|
+
assignedWorker: r.option(() => bs583.encode(r.bytes(32)))
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
function decodeSubmitDeliverableArgs(data) {
|
|
236
|
+
const r = new Reader(Buffer.from(data));
|
|
237
|
+
return { deliverableHash: r.string(), proofUri: r.option(() => r.string()) };
|
|
238
|
+
}
|
|
239
|
+
function decodeRaiseDisputeArgs(data) {
|
|
240
|
+
return { reason: new Reader(Buffer.from(data)).string() };
|
|
241
|
+
}
|
|
133
242
|
|
|
134
243
|
// src/payments.ts
|
|
135
244
|
var RAILS = ["escrow", "x402"];
|
|
@@ -504,9 +613,7 @@ async function pollUntil(address, fetcher, predicate, timeoutMs = MS_24_H) {
|
|
|
504
613
|
}
|
|
505
614
|
|
|
506
615
|
// src/solana.ts
|
|
507
|
-
import { createHash as createHash2 } from "crypto";
|
|
508
616
|
import {
|
|
509
|
-
ComputeBudgetProgram,
|
|
510
617
|
PublicKey as PublicKey2,
|
|
511
618
|
Transaction,
|
|
512
619
|
TransactionInstruction
|
|
@@ -520,8 +627,14 @@ import {
|
|
|
520
627
|
|
|
521
628
|
// ../shared/dist/solana.js
|
|
522
629
|
import { PublicKey } from "@solana/web3.js";
|
|
523
|
-
import
|
|
630
|
+
import bs584 from "bs58";
|
|
524
631
|
var utf8 = (s) => new TextEncoder().encode(s);
|
|
632
|
+
function deriveEscrowPda(programId, buyer, taskId) {
|
|
633
|
+
return PublicKey.findProgramAddressSync(
|
|
634
|
+
[utf8("escrow"), buyer.toBytes(), utf8(taskId)],
|
|
635
|
+
programId
|
|
636
|
+
)[0];
|
|
637
|
+
}
|
|
525
638
|
function findPlatformConfigPda(programId) {
|
|
526
639
|
return PublicKey.findProgramAddressSync([utf8("config")], programId);
|
|
527
640
|
}
|
|
@@ -558,7 +671,7 @@ function decodePlatformConfig(data) {
|
|
|
558
671
|
throw new Error("PlatformConfig discriminator mismatch: not a PlatformConfig account");
|
|
559
672
|
}
|
|
560
673
|
const byte = (at) => data[at] ?? 0;
|
|
561
|
-
const key = (at) =>
|
|
674
|
+
const key = (at) => bs584.encode(data.subarray(at, at + 32));
|
|
562
675
|
return {
|
|
563
676
|
version: byte(L.version),
|
|
564
677
|
feeBps: byte(L.fee_bps) | byte(L.fee_bps + 1) << 8,
|
|
@@ -570,10 +683,6 @@ function decodePlatformConfig(data) {
|
|
|
570
683
|
}
|
|
571
684
|
|
|
572
685
|
// src/solana.ts
|
|
573
|
-
function disc(name) {
|
|
574
|
-
return Buffer.from(createHash2("sha256").update(`global:${name}`).digest()).subarray(0, 8);
|
|
575
|
-
}
|
|
576
|
-
var DISC_RELEASE_PAYMENT = disc("release_payment");
|
|
577
686
|
function resolveProgramId(cluster) {
|
|
578
687
|
const id = getProgramId(cluster);
|
|
579
688
|
assertProgramIdNotPlaceholder(id, cluster);
|
|
@@ -583,8 +692,7 @@ function allowedProgramIds(programId) {
|
|
|
583
692
|
return /* @__PURE__ */ new Set([
|
|
584
693
|
programId.toBase58(),
|
|
585
694
|
TOKEN_PROGRAM_ID.toBase58(),
|
|
586
|
-
ASSOCIATED_TOKEN_PROGRAM_ID.toBase58()
|
|
587
|
-
ComputeBudgetProgram.programId.toBase58()
|
|
695
|
+
ASSOCIATED_TOKEN_PROGRAM_ID.toBase58()
|
|
588
696
|
]);
|
|
589
697
|
}
|
|
590
698
|
var MAX_INSTRUCTIONS = 6;
|
|
@@ -622,6 +730,12 @@ async function fetchPlatformConfig(connection, cluster) {
|
|
|
622
730
|
}
|
|
623
731
|
return { mint: new PublicKey2(config.usdcMint), treasury: new PublicKey2(config.treasury) };
|
|
624
732
|
}
|
|
733
|
+
function refuse(reason) {
|
|
734
|
+
throw new EscroError(
|
|
735
|
+
`Refusing to sign a server-built transaction: ${reason}`,
|
|
736
|
+
"UNEXPECTED_TRANSACTION"
|
|
737
|
+
);
|
|
738
|
+
}
|
|
625
739
|
function validateTransaction(tx, cluster) {
|
|
626
740
|
const programId = resolveProgramId(cluster);
|
|
627
741
|
const allowed = allowedProgramIds(programId);
|
|
@@ -629,29 +743,87 @@ function validateTransaction(tx, cluster) {
|
|
|
629
743
|
for (const ix of tx.instructions) {
|
|
630
744
|
const id = ix.programId.toBase58();
|
|
631
745
|
if (!allowed.has(id)) {
|
|
632
|
-
|
|
633
|
-
`Unexpected program in transaction: ${id}. Allowed: ${[...allowed].join(", ")}`
|
|
634
|
-
);
|
|
746
|
+
refuse(`Unexpected program in transaction: ${id}. Allowed: ${[...allowed].join(", ")}`);
|
|
635
747
|
}
|
|
636
748
|
if (id === tokenProgram) {
|
|
637
749
|
const tag = ix.data.length > 0 ? ix.data[0] : void 0;
|
|
638
750
|
if (tag !== void 0 && FORBIDDEN_TOKEN_IX_TAGS.has(tag)) {
|
|
639
|
-
throw new
|
|
640
|
-
`Refusing to sign a fund-moving SPL Token instruction (tag ${String(tag)}) in a server-built transaction
|
|
751
|
+
throw new EscroError(
|
|
752
|
+
`Refusing to sign a fund-moving SPL Token instruction (tag ${String(tag)}) in a server-built transaction`,
|
|
753
|
+
"UNEXPECTED_TRANSACTION"
|
|
641
754
|
);
|
|
642
755
|
}
|
|
643
756
|
}
|
|
644
757
|
}
|
|
645
758
|
if (tx.instructions.length > MAX_INSTRUCTIONS) {
|
|
646
|
-
|
|
759
|
+
refuse(
|
|
647
760
|
`Too many instructions (${String(tx.instructions.length)}). Max allowed: ${String(MAX_INSTRUCTIONS)}`
|
|
648
761
|
);
|
|
649
762
|
}
|
|
650
763
|
}
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
const tx = Transaction.from(buf);
|
|
764
|
+
var ATA_CREATE_IDEMPOTENT = 1;
|
|
765
|
+
function verifyServerTransaction(tx, cluster, wallet, expected) {
|
|
654
766
|
validateTransaction(tx, cluster);
|
|
767
|
+
const programId = resolveProgramId(cluster);
|
|
768
|
+
if (!tx.feePayer?.equals(wallet)) refuse("the fee payer is not the wallet");
|
|
769
|
+
const escro = tx.instructions.filter((ix2) => ix2.programId.equals(programId));
|
|
770
|
+
const others = tx.instructions.filter((ix2) => !ix2.programId.equals(programId));
|
|
771
|
+
for (const ix2 of others) {
|
|
772
|
+
const ataCreate = expected.name === "release_payment" && ix2.programId.equals(ASSOCIATED_TOKEN_PROGRAM_ID) && ix2.data.length === 1 && ix2.data[0] === ATA_CREATE_IDEMPOTENT;
|
|
773
|
+
if (!ataCreate) refuse(`unexpected ${ix2.programId.toBase58()} instruction`);
|
|
774
|
+
}
|
|
775
|
+
if (escro.length !== 1) refuse(`${String(escro.length)} escro instructions, expected 1`);
|
|
776
|
+
const [ix] = escro;
|
|
777
|
+
if (ix === void 0) refuse("no escro instruction");
|
|
778
|
+
const name = escrowInstructionName(ix.data);
|
|
779
|
+
if (name !== expected.name)
|
|
780
|
+
refuse(`${name ?? "an unknown instruction"}, expected ${expected.name}`);
|
|
781
|
+
const spec2 = ESCROW_INSTRUCTIONS[name];
|
|
782
|
+
const actor = ix.keys[spec2.signerAccountIndex];
|
|
783
|
+
if (actor === void 0 || !actor.pubkey.equals(wallet) || !actor.isSigner) {
|
|
784
|
+
refuse("the acting signer is not the wallet");
|
|
785
|
+
}
|
|
786
|
+
if (ix.keys[spec2.escrowAccountIndex]?.pubkey.toBase58() !== expected.escrowPda) {
|
|
787
|
+
refuse(`the escrow is not ${expected.escrowPda}`);
|
|
788
|
+
}
|
|
789
|
+
try {
|
|
790
|
+
switch (expected.name) {
|
|
791
|
+
case "create_escrow": {
|
|
792
|
+
const args = decodeCreateEscrowArgs(ix.data);
|
|
793
|
+
if (args.taskId !== expected.taskId) refuse("the task id differs");
|
|
794
|
+
if (deriveEscrowPda(programId, wallet, args.taskId).toBase58() !== expected.escrowPda) {
|
|
795
|
+
refuse("the escrow is not derived from the wallet and task id");
|
|
796
|
+
}
|
|
797
|
+
if (args.amount !== expected.amount) refuse("the amount differs");
|
|
798
|
+
if (args.deadline !== expected.deadline) refuse("the deadline differs");
|
|
799
|
+
if (args.specHash !== expected.specHash) refuse("the spec hash differs");
|
|
800
|
+
if (args.assignedWorker !== expected.assignedWorker) refuse("the assigned worker differs");
|
|
801
|
+
break;
|
|
802
|
+
}
|
|
803
|
+
case "submit_deliverable": {
|
|
804
|
+
const args = decodeSubmitDeliverableArgs(ix.data);
|
|
805
|
+
if (args.deliverableHash !== expected.deliverableHash)
|
|
806
|
+
refuse("the deliverable hash differs");
|
|
807
|
+
if (args.proofUri !== expected.proofUri) refuse("the proof URI differs");
|
|
808
|
+
break;
|
|
809
|
+
}
|
|
810
|
+
case "raise_dispute":
|
|
811
|
+
if (decodeRaiseDisputeArgs(ix.data).reason !== expected.reason)
|
|
812
|
+
refuse("the reason differs");
|
|
813
|
+
break;
|
|
814
|
+
default:
|
|
815
|
+
if (ix.data.length !== ESCROW_INSTRUCTIONS[name].discriminator.length) {
|
|
816
|
+
refuse(`${name} carries unexpected arguments`);
|
|
817
|
+
}
|
|
818
|
+
}
|
|
819
|
+
} catch (err) {
|
|
820
|
+
if (err instanceof EscroError) throw err;
|
|
821
|
+
refuse(`malformed ${name} arguments`);
|
|
822
|
+
}
|
|
823
|
+
}
|
|
824
|
+
async function signAndSend(base64Tx, wallet, connection, cluster, expected) {
|
|
825
|
+
const tx = Transaction.from(Buffer.from(base64Tx, "base64"));
|
|
826
|
+
verifyServerTransaction(tx, cluster, wallet.publicKey, expected);
|
|
655
827
|
tx.partialSign(wallet);
|
|
656
828
|
const raw = tx.serialize();
|
|
657
829
|
const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash("confirmed");
|
|
@@ -710,7 +882,7 @@ async function buildReleasePaymentTx(params) {
|
|
|
710
882
|
{ pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false },
|
|
711
883
|
{ pubkey: ASSOCIATED_TOKEN_PROGRAM_ID, isSigner: false, isWritable: false }
|
|
712
884
|
],
|
|
713
|
-
data:
|
|
885
|
+
data: Buffer.from(ESCROW_INSTRUCTIONS.release_payment.discriminator)
|
|
714
886
|
});
|
|
715
887
|
const { blockhash } = await connection.getLatestBlockhash("confirmed");
|
|
716
888
|
const tx = new Transaction();
|
|
@@ -741,14 +913,6 @@ function isRetryableConfirmCode(code) {
|
|
|
741
913
|
function isRetryableReleaseCode(code) {
|
|
742
914
|
return code === "ESCROW_NOT_SETTLED" || isRetryableConfirmCode(code);
|
|
743
915
|
}
|
|
744
|
-
function isUrl(value) {
|
|
745
|
-
try {
|
|
746
|
-
new URL(value);
|
|
747
|
-
return true;
|
|
748
|
-
} catch {
|
|
749
|
-
return false;
|
|
750
|
-
}
|
|
751
|
-
}
|
|
752
916
|
var sleep2 = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
753
917
|
var Escro = class {
|
|
754
918
|
constructor(options) {
|
|
@@ -771,7 +935,15 @@ var Escro = class {
|
|
|
771
935
|
*/
|
|
772
936
|
async createEscrow(params) {
|
|
773
937
|
const { escrowId, escrowPda, unsignedTx } = await this.api.createEscrow(params);
|
|
774
|
-
const signature = await this.send(unsignedTx
|
|
938
|
+
const signature = await this.send(unsignedTx, {
|
|
939
|
+
name: "create_escrow",
|
|
940
|
+
escrowPda,
|
|
941
|
+
taskId: escrowId,
|
|
942
|
+
amount: BigInt(params.amountUsdc),
|
|
943
|
+
deadline: BigInt(params.deadlineUnix),
|
|
944
|
+
specHash: computeTaskSpecHash(params.taskSpec),
|
|
945
|
+
assignedWorker: params.assignedWorker
|
|
946
|
+
});
|
|
775
947
|
await this.confirm(escrowPda, signature);
|
|
776
948
|
return { escrowId, escrowPda, signature };
|
|
777
949
|
}
|
|
@@ -815,12 +987,7 @@ var Escro = class {
|
|
|
815
987
|
connection: this.connection,
|
|
816
988
|
cluster: this.cluster
|
|
817
989
|
});
|
|
818
|
-
const signature = await
|
|
819
|
-
unsignedTx,
|
|
820
|
-
this.options.wallet,
|
|
821
|
-
this.connection,
|
|
822
|
-
this.cluster
|
|
823
|
-
);
|
|
990
|
+
const signature = await this.send(unsignedTx, { name: "release_payment", escrowPda: address });
|
|
824
991
|
try {
|
|
825
992
|
await this.retryRecord(
|
|
826
993
|
address,
|
|
@@ -843,11 +1010,18 @@ var Escro = class {
|
|
|
843
1010
|
async raiseDispute(address, params) {
|
|
844
1011
|
const reasonError = disputeReasonError(params.reason);
|
|
845
1012
|
if (reasonError !== null) throw new EscroError(reasonError, "VALIDATION_ERROR");
|
|
846
|
-
if (params.evidence !== void 0 && !
|
|
847
|
-
throw new EscroError(
|
|
1013
|
+
if (params.evidence !== void 0 && !isSafeUrl(params.evidence)) {
|
|
1014
|
+
throw new EscroError(
|
|
1015
|
+
`evidence must be an http(s), ipfs or ar URL: ${params.evidence}`,
|
|
1016
|
+
"VALIDATION_ERROR"
|
|
1017
|
+
);
|
|
848
1018
|
}
|
|
849
1019
|
const { unsignedTx } = await this.api.raiseDispute(address, { reason: params.reason });
|
|
850
|
-
const signature = await this.send(unsignedTx
|
|
1020
|
+
const signature = await this.send(unsignedTx, {
|
|
1021
|
+
name: "raise_dispute",
|
|
1022
|
+
escrowPda: address,
|
|
1023
|
+
reason: params.reason
|
|
1024
|
+
});
|
|
851
1025
|
await this.confirm(address, signature, {
|
|
852
1026
|
...params.evidence !== void 0 && { evidence: params.evidence }
|
|
853
1027
|
});
|
|
@@ -862,7 +1036,7 @@ var Escro = class {
|
|
|
862
1036
|
*/
|
|
863
1037
|
async cancelEscrow(address) {
|
|
864
1038
|
const { unsignedTx } = await this.api.cancelEscrow(address);
|
|
865
|
-
return this.sendAndConfirm(address, unsignedTx);
|
|
1039
|
+
return this.sendAndConfirm(address, unsignedTx, { name: "cancel_escrow", escrowPda: address });
|
|
866
1040
|
}
|
|
867
1041
|
// ── Payments (dual-path; x402 reserved) ───────────────────────────────────────
|
|
868
1042
|
/**
|
|
@@ -893,7 +1067,7 @@ var Escro = class {
|
|
|
893
1067
|
*/
|
|
894
1068
|
async claimTask(address) {
|
|
895
1069
|
const { unsignedTx } = await this.api.claimTask(address);
|
|
896
|
-
return this.sendAndConfirm(address, unsignedTx);
|
|
1070
|
+
return this.sendAndConfirm(address, unsignedTx, { name: "claim_task", escrowPda: address });
|
|
897
1071
|
}
|
|
898
1072
|
/**
|
|
899
1073
|
* Submit a deliverable for the buyer to review. Worker must be the wallet.
|
|
@@ -903,7 +1077,12 @@ var Escro = class {
|
|
|
903
1077
|
*/
|
|
904
1078
|
async submitDeliverable(address, params) {
|
|
905
1079
|
const { unsignedTx } = await this.api.submitDeliverable(address, params);
|
|
906
|
-
return this.sendAndConfirm(address, unsignedTx
|
|
1080
|
+
return this.sendAndConfirm(address, unsignedTx, {
|
|
1081
|
+
name: "submit_deliverable",
|
|
1082
|
+
escrowPda: address,
|
|
1083
|
+
deliverableHash: params.contentHash,
|
|
1084
|
+
proofUri: params.proofUri ?? null
|
|
1085
|
+
});
|
|
907
1086
|
}
|
|
908
1087
|
/**
|
|
909
1088
|
* List tasks assigned to the wallet's public key.
|
|
@@ -1069,11 +1248,11 @@ var Escro = class {
|
|
|
1069
1248
|
delay = Math.min(delay * 2, CONFIRM_MAX_DELAY_MS);
|
|
1070
1249
|
}
|
|
1071
1250
|
}
|
|
1072
|
-
send(unsignedTx) {
|
|
1073
|
-
return signAndSend(unsignedTx, this.options.wallet, this.connection, this.cluster);
|
|
1251
|
+
send(unsignedTx, expected) {
|
|
1252
|
+
return signAndSend(unsignedTx, this.options.wallet, this.connection, this.cluster, expected);
|
|
1074
1253
|
}
|
|
1075
|
-
async sendAndConfirm(address, unsignedTx) {
|
|
1076
|
-
const signature = await this.send(unsignedTx);
|
|
1254
|
+
async sendAndConfirm(address, unsignedTx, expected) {
|
|
1255
|
+
const signature = await this.send(unsignedTx, expected);
|
|
1077
1256
|
await this.confirm(address, signature);
|
|
1078
1257
|
return signature;
|
|
1079
1258
|
}
|