@escro/sdk 0.1.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/dist/index.js ADDED
@@ -0,0 +1,455 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
3
+ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
4
+
5
+ // src/client.ts
6
+ import { Connection as Connection2, PublicKey as PublicKey2 } from "@solana/web3.js";
7
+
8
+ // src/api.ts
9
+ import nacl from "tweetnacl";
10
+ import bs58 from "bs58";
11
+
12
+ // src/errors.ts
13
+ var EscroError = class extends Error {
14
+ constructor(message, code = "ESCRO_ERROR") {
15
+ super(message);
16
+ this.code = code;
17
+ this.name = "EscroError";
18
+ }
19
+ };
20
+ var EscrowNotFoundError = class extends EscroError {
21
+ constructor(address) {
22
+ super(`Escrow not found: ${address}`, "ESCROW_NOT_FOUND");
23
+ this.name = "EscrowNotFoundError";
24
+ }
25
+ };
26
+ var EscrowStateError = class extends EscroError {
27
+ constructor(message) {
28
+ super(message, "ESCROW_INVALID_STATE");
29
+ this.name = "EscrowStateError";
30
+ }
31
+ };
32
+ var EscrowTimeoutError = class extends EscroError {
33
+ constructor(address) {
34
+ super(`Polling timed out after 24h for escrow: ${address}`, "ESCROW_TIMEOUT");
35
+ this.name = "EscrowTimeoutError";
36
+ }
37
+ };
38
+ var UnauthorizedError = class extends EscroError {
39
+ constructor(message = "Unauthorized") {
40
+ super(message, "UNAUTHORIZED");
41
+ this.name = "UnauthorizedError";
42
+ }
43
+ };
44
+
45
+ // src/api.ts
46
+ function authHeaders(wallet, method, path) {
47
+ const timestamp = Date.now();
48
+ const message = `escro:${timestamp}:${method}:${path}`;
49
+ const msgBytes = new TextEncoder().encode(message);
50
+ const sigBytes = nacl.sign.detached(msgBytes, wallet.secretKey);
51
+ return {
52
+ "x-wallet-address": wallet.publicKey.toBase58(),
53
+ "x-signature": bs58.encode(sigBytes),
54
+ "x-timestamp": String(timestamp),
55
+ "content-type": "application/json"
56
+ };
57
+ }
58
+ function deserialize(raw) {
59
+ return { ...raw, amount: BigInt(raw.amount) };
60
+ }
61
+ async function handleError(res, address) {
62
+ const body = await res.json().catch(() => ({}));
63
+ const msg = body.error ?? `HTTP ${res.status}`;
64
+ if (res.status === 404) throw new EscrowNotFoundError(address ?? msg);
65
+ if (res.status === 409) throw new EscrowStateError(msg);
66
+ if (res.status === 401 || res.status === 403) throw new UnauthorizedError(msg);
67
+ throw new EscroError(msg, body.code ?? "UNKNOWN");
68
+ }
69
+ var ApiClient = class {
70
+ constructor(baseUrl, wallet) {
71
+ this.baseUrl = baseUrl;
72
+ this.wallet = wallet;
73
+ }
74
+ url(path) {
75
+ return `${this.baseUrl}${path}`;
76
+ }
77
+ /** GET /v1/escrows/:address */
78
+ async getEscrow(address) {
79
+ const path = `/v1/escrows/${address}`;
80
+ const res = await fetch(this.url(path));
81
+ if (!res.ok) await handleError(res, address);
82
+ return deserialize(await res.json());
83
+ }
84
+ /** GET /v1/escrows?assignedTo=...&state=... */
85
+ async listEscrows(params) {
86
+ const qs = new URLSearchParams();
87
+ if (params.assignedTo) qs.set("assignedTo", params.assignedTo);
88
+ if (params.state) qs.set("state", params.state);
89
+ if (params.limit != null) qs.set("limit", String(params.limit));
90
+ if (params.offset != null) qs.set("offset", String(params.offset));
91
+ const path = `/v1/escrows?${qs.toString()}`;
92
+ const res = await fetch(this.url(path));
93
+ if (!res.ok) await handleError(res);
94
+ const body = await res.json();
95
+ return {
96
+ items: body.items.map(deserialize),
97
+ total: body.total,
98
+ limit: body.limit,
99
+ offset: body.offset
100
+ };
101
+ }
102
+ /**
103
+ * POST /v1/escrows — create escrow, returns unsigned tx + ids.
104
+ * Requires auth.
105
+ */
106
+ async createEscrow(params) {
107
+ const path = "/v1/escrows";
108
+ const res = await fetch(this.url(path), {
109
+ method: "POST",
110
+ headers: authHeaders(this.wallet, "POST", path),
111
+ body: JSON.stringify({
112
+ taskSpec: params.taskSpec,
113
+ amountUsdc: params.amountUsdc,
114
+ deadlineSeconds: params.deadlineSeconds,
115
+ assignedWorker: params.assignedWorker
116
+ })
117
+ });
118
+ if (!res.ok) await handleError(res);
119
+ return res.json();
120
+ }
121
+ /**
122
+ * POST /v1/escrows/:address/claim — returns unsigned tx.
123
+ * Requires auth (worker).
124
+ */
125
+ async claimTask(address) {
126
+ const path = `/v1/escrows/${address}/claim`;
127
+ const res = await fetch(this.url(path), {
128
+ method: "POST",
129
+ headers: authHeaders(this.wallet, "POST", path)
130
+ });
131
+ if (!res.ok) await handleError(res, address);
132
+ return res.json();
133
+ }
134
+ /**
135
+ * POST /v1/escrows/:address/submit — returns unsigned tx.
136
+ * Requires auth (worker).
137
+ */
138
+ async submitDeliverable(address, params) {
139
+ const path = `/v1/escrows/${address}/submit`;
140
+ const res = await fetch(this.url(path), {
141
+ method: "POST",
142
+ headers: authHeaders(this.wallet, "POST", path),
143
+ body: JSON.stringify({
144
+ contentHash: params.contentHash,
145
+ proofUri: params.proofUri
146
+ })
147
+ });
148
+ if (!res.ok) await handleError(res, address);
149
+ return res.json();
150
+ }
151
+ /**
152
+ * POST /v1/escrows/:address/release — DB-only state update.
153
+ * Requires auth (buyer). No on-chain tx returned.
154
+ */
155
+ async releasePaymentDb(address) {
156
+ const path = `/v1/escrows/${address}/release`;
157
+ const res = await fetch(this.url(path), {
158
+ method: "POST",
159
+ headers: authHeaders(this.wallet, "POST", path)
160
+ });
161
+ if (!res.ok) await handleError(res, address);
162
+ }
163
+ /**
164
+ * POST /v1/escrows/:address/cancel — returns unsigned tx.
165
+ * Requires auth (buyer). Only valid when state is FUNDED.
166
+ */
167
+ async cancelEscrow(address) {
168
+ const path = `/v1/escrows/${address}/cancel`;
169
+ const res = await fetch(this.url(path), {
170
+ method: "POST",
171
+ headers: authHeaders(this.wallet, "POST", path)
172
+ });
173
+ if (!res.ok) await handleError(res, address);
174
+ return res.json();
175
+ }
176
+ /**
177
+ * POST /v1/escrows/:address/dispute — returns unsigned tx.
178
+ * Requires auth (buyer or worker).
179
+ */
180
+ async raiseDispute(address, params) {
181
+ const path = `/v1/escrows/${address}/dispute`;
182
+ const res = await fetch(this.url(path), {
183
+ method: "POST",
184
+ headers: authHeaders(this.wallet, "POST", path),
185
+ body: JSON.stringify({ reason: params.reason, evidence: params.evidence })
186
+ });
187
+ if (!res.ok) await handleError(res, address);
188
+ return res.json();
189
+ }
190
+ };
191
+
192
+ // src/poll.ts
193
+ var MS_5_MIN = 5 * 60 * 1e3;
194
+ var MS_30_MIN = 30 * 60 * 1e3;
195
+ var MS_24_H = 24 * 60 * 60 * 1e3;
196
+ function backoffInterval(elapsedMs) {
197
+ if (elapsedMs < MS_5_MIN) return 15e3;
198
+ if (elapsedMs < MS_30_MIN) return 3e4;
199
+ return 6e4;
200
+ }
201
+ function sleep(ms) {
202
+ return new Promise((resolve) => setTimeout(resolve, ms));
203
+ }
204
+ async function pollUntil(address, fetcher, predicate, timeoutMs = MS_24_H) {
205
+ const deadline = Date.now() + timeoutMs;
206
+ while (true) {
207
+ const result = await fetcher();
208
+ if (predicate(result)) return result;
209
+ const elapsed = Date.now() - (deadline - timeoutMs);
210
+ if (Date.now() >= deadline) {
211
+ throw new EscrowTimeoutError(address);
212
+ }
213
+ const interval = backoffInterval(elapsed);
214
+ const remaining = deadline - Date.now();
215
+ await sleep(Math.min(interval, remaining));
216
+ if (Date.now() >= deadline) {
217
+ throw new EscrowTimeoutError(address);
218
+ }
219
+ }
220
+ }
221
+
222
+ // src/solana.ts
223
+ import { createHash } from "crypto";
224
+ import {
225
+ PublicKey,
226
+ Transaction,
227
+ TransactionInstruction
228
+ } from "@solana/web3.js";
229
+ import {
230
+ TOKEN_PROGRAM_ID,
231
+ ASSOCIATED_TOKEN_PROGRAM_ID,
232
+ getAssociatedTokenAddressSync
233
+ } from "@solana/spl-token";
234
+ function disc(name) {
235
+ return Buffer.from(
236
+ createHash("sha256").update(`global:${name}`).digest()
237
+ ).subarray(0, 8);
238
+ }
239
+ var DISC_RELEASE_PAYMENT = disc("release_payment");
240
+ var PROGRAM_ID = new PublicKey("EjLpJ3obUYk1f2KDensU7UdGBZTxSdxufm7CSnMA3H5C");
241
+ async function fetchPlatformConfig(connection) {
242
+ const [pda] = PublicKey.findProgramAddressSync([Buffer.from("config")], PROGRAM_ID);
243
+ const info = await connection.getAccountInfo(pda);
244
+ if (!info) throw new Error("PlatformConfig account not found on-chain");
245
+ return {
246
+ mint: new PublicKey(info.data.slice(42, 74)),
247
+ treasury: new PublicKey(info.data.slice(74, 106))
248
+ };
249
+ }
250
+ async function signAndSend(base64Tx, wallet, connection) {
251
+ const buf = Buffer.from(base64Tx, "base64");
252
+ const tx = Transaction.from(buf);
253
+ tx.partialSign(wallet);
254
+ const raw = tx.serialize();
255
+ const signature = await connection.sendRawTransaction(raw, {
256
+ skipPreflight: false
257
+ });
258
+ await connection.confirmTransaction(signature, "confirmed");
259
+ return signature;
260
+ }
261
+ async function buildReleasePaymentTx(params) {
262
+ const { buyer, escrowPda, worker, mint, treasury, connection } = params;
263
+ const [platformConfig] = PublicKey.findProgramAddressSync(
264
+ [Buffer.from("config")],
265
+ PROGRAM_ID
266
+ );
267
+ const vault = getAssociatedTokenAddressSync(
268
+ mint,
269
+ escrowPda,
270
+ true,
271
+ TOKEN_PROGRAM_ID,
272
+ ASSOCIATED_TOKEN_PROGRAM_ID
273
+ );
274
+ const workerAta = getAssociatedTokenAddressSync(
275
+ mint,
276
+ worker,
277
+ false,
278
+ TOKEN_PROGRAM_ID,
279
+ ASSOCIATED_TOKEN_PROGRAM_ID
280
+ );
281
+ const treasuryAta = getAssociatedTokenAddressSync(
282
+ mint,
283
+ treasury,
284
+ false,
285
+ TOKEN_PROGRAM_ID,
286
+ ASSOCIATED_TOKEN_PROGRAM_ID
287
+ );
288
+ const ix = new TransactionInstruction({
289
+ programId: PROGRAM_ID,
290
+ keys: [
291
+ { pubkey: buyer, isSigner: true, isWritable: true },
292
+ { pubkey: platformConfig, isSigner: false, isWritable: false },
293
+ { pubkey: mint, isSigner: false, isWritable: false },
294
+ { pubkey: escrowPda, isSigner: false, isWritable: true },
295
+ { pubkey: vault, isSigner: false, isWritable: true },
296
+ { pubkey: workerAta, isSigner: false, isWritable: true },
297
+ { pubkey: treasuryAta, isSigner: false, isWritable: true },
298
+ { pubkey: worker, isSigner: false, isWritable: false },
299
+ { pubkey: treasury, isSigner: false, isWritable: false },
300
+ { pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false },
301
+ { pubkey: ASSOCIATED_TOKEN_PROGRAM_ID, isSigner: false, isWritable: false }
302
+ ],
303
+ data: DISC_RELEASE_PAYMENT
304
+ });
305
+ const { blockhash } = await connection.getLatestBlockhash("confirmed");
306
+ const tx = new Transaction();
307
+ tx.recentBlockhash = blockhash;
308
+ tx.feePayer = buyer;
309
+ tx.add(ix);
310
+ return tx.serialize({ requireAllSignatures: false }).toString("base64");
311
+ }
312
+
313
+ // src/client.ts
314
+ var Escro = class {
315
+ constructor(options) {
316
+ __publicField(this, "connection");
317
+ __publicField(this, "api");
318
+ __publicField(this, "options");
319
+ this.options = options;
320
+ this.connection = new Connection2(options.rpcUrl, "confirmed");
321
+ this.api = new ApiClient(options.apiUrl, options.wallet);
322
+ }
323
+ // ── Buyer Bot ────────────────────────────────────────────────────────────────
324
+ /**
325
+ * Create a new escrow: registers with the API, signs and submits the
326
+ * on-chain `create_escrow` transaction.
327
+ *
328
+ * @returns `{ escrowId, escrowPda, signature }` — use `escrowPda` for all subsequent calls.
329
+ */
330
+ async createEscrow(params) {
331
+ const { escrowId, escrowPda, unsignedTx } = await this.api.createEscrow(params);
332
+ const signature = await signAndSend(unsignedTx, this.options.wallet, this.connection);
333
+ return { escrowId, escrowPda, signature };
334
+ }
335
+ /**
336
+ * Release payment to the worker. Buyer must be the wallet in the constructor.
337
+ * Updates API DB state, then builds and submits the `release_payment` on-chain tx.
338
+ *
339
+ * @returns Solana transaction signature.
340
+ */
341
+ async releasePayment(address) {
342
+ const escrow = await this.api.getEscrow(address);
343
+ if (!escrow.taker) {
344
+ throw new EscrowNotFoundError(`Escrow ${address} has no assigned worker`);
345
+ }
346
+ const { treasury, mint } = await fetchPlatformConfig(this.connection);
347
+ await this.api.releasePaymentDb(address);
348
+ const unsignedTx = await buildReleasePaymentTx({
349
+ buyer: this.options.wallet.publicKey,
350
+ escrowPda: new PublicKey2(address),
351
+ worker: new PublicKey2(escrow.taker),
352
+ mint,
353
+ treasury,
354
+ connection: this.connection
355
+ });
356
+ return signAndSend(unsignedTx, this.options.wallet, this.connection);
357
+ }
358
+ /**
359
+ * Raise a dispute for an escrow. Either the buyer or the assigned worker
360
+ * may call this. Signs and submits the `raise_dispute` on-chain tx.
361
+ *
362
+ * @returns Solana transaction signature.
363
+ */
364
+ async raiseDispute(address, params) {
365
+ const { unsignedTx } = await this.api.raiseDispute(address, params);
366
+ return signAndSend(unsignedTx, this.options.wallet, this.connection);
367
+ }
368
+ /**
369
+ * Cancel a funded escrow before any worker has claimed it.
370
+ * Buyer must be the wallet in the constructor. Only valid when state is `FUNDED`.
371
+ * Signs and submits the `cancel_escrow` on-chain tx; full USDC refund to buyer.
372
+ *
373
+ * @returns Solana transaction signature.
374
+ */
375
+ async cancelEscrow(address) {
376
+ const { unsignedTx } = await this.api.cancelEscrow(address);
377
+ return signAndSend(unsignedTx, this.options.wallet, this.connection);
378
+ }
379
+ // ── Worker Bot ───────────────────────────────────────────────────────────────
380
+ /**
381
+ * Claim an assigned task. Worker must be the wallet in the constructor.
382
+ * Signs and submits the `claim_task` on-chain tx.
383
+ *
384
+ * @returns Solana transaction signature.
385
+ */
386
+ async claimTask(address) {
387
+ const { unsignedTx } = await this.api.claimTask(address);
388
+ return signAndSend(unsignedTx, this.options.wallet, this.connection);
389
+ }
390
+ /**
391
+ * Submit a deliverable for oracle evaluation. Worker must be the wallet.
392
+ * Signs and submits the `submit_deliverable` on-chain tx.
393
+ *
394
+ * @returns Solana transaction signature.
395
+ */
396
+ async submitDeliverable(address, params) {
397
+ const { unsignedTx } = await this.api.submitDeliverable(address, params);
398
+ return signAndSend(unsignedTx, this.options.wallet, this.connection);
399
+ }
400
+ /**
401
+ * List tasks assigned to the wallet's public key.
402
+ * Optionally filter by state(s) and paginate results.
403
+ *
404
+ * If `options.poll` is true, polls with exponential backoff until at least
405
+ * one task is returned.
406
+ *
407
+ * @param state - Filter by one or more states (first state used as API filter).
408
+ * @param options - Polling, pagination (limit/offset).
409
+ */
410
+ async getMyTasks(state, options) {
411
+ const assignedTo = this.options.wallet.publicKey.toBase58();
412
+ const params = {
413
+ assignedTo,
414
+ ...state?.[0] != null && { state: state[0] },
415
+ ...options?.limit != null && { limit: options.limit },
416
+ ...options?.offset != null && { offset: options.offset }
417
+ };
418
+ if (!options?.poll) {
419
+ return this.api.listEscrows(params);
420
+ }
421
+ const fetcher = () => this.api.listEscrows(params).then((result) => result.items.length > 0 ? result : null);
422
+ return pollUntil(
423
+ assignedTo,
424
+ fetcher,
425
+ (r) => r !== null,
426
+ options.timeoutMs
427
+ );
428
+ }
429
+ // ── Shared ───────────────────────────────────────────────────────────────────
430
+ /**
431
+ * Fetch an escrow by its PDA address.
432
+ * If `options.poll` is true, polls with exponential backoff until the escrow
433
+ * appears (useful immediately after a create tx before the API DB syncs).
434
+ */
435
+ async getEscrow(address, options) {
436
+ if (!options?.poll) {
437
+ return this.api.getEscrow(address);
438
+ }
439
+ return pollUntil(
440
+ address,
441
+ () => this.api.getEscrow(address).catch((e) => e instanceof EscrowNotFoundError ? null : Promise.reject(e)),
442
+ (r) => r !== null,
443
+ options.timeoutMs
444
+ );
445
+ }
446
+ };
447
+ export {
448
+ Escro,
449
+ EscroError,
450
+ EscrowNotFoundError,
451
+ EscrowStateError,
452
+ EscrowTimeoutError,
453
+ UnauthorizedError
454
+ };
455
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/client.ts","../src/api.ts","../src/errors.ts","../src/poll.ts","../src/solana.ts"],"sourcesContent":["import { Connection, PublicKey } from \"@solana/web3.js\";\nimport type { EscrowAccount, EscrowState } from \"@escro/shared\";\nimport type {\n CreateEscrowParams,\n CreateEscrowResult,\n EscroOptions,\n ListOptions,\n PaginatedResult,\n PollOptions,\n RaiseDisputeParams,\n SubmitDeliverableParams,\n} from \"./types.js\";\nimport { ApiClient } from \"./api.js\";\nimport { EscrowNotFoundError } from \"./errors.js\";\nimport { pollUntil } from \"./poll.js\";\nimport { buildReleasePaymentTx, fetchPlatformConfig, signAndSend } from \"./solana.js\";\n\nexport class Escro {\n private readonly connection: Connection;\n private readonly api: ApiClient;\n private readonly options: EscroOptions;\n\n constructor(options: EscroOptions) {\n this.options = options;\n this.connection = new Connection(options.rpcUrl, \"confirmed\");\n this.api = new ApiClient(options.apiUrl, options.wallet);\n }\n\n // ── Buyer Bot ────────────────────────────────────────────────────────────────\n\n /**\n * Create a new escrow: registers with the API, signs and submits the\n * on-chain `create_escrow` transaction.\n *\n * @returns `{ escrowId, escrowPda, signature }` — use `escrowPda` for all subsequent calls.\n */\n async createEscrow(params: CreateEscrowParams): Promise<CreateEscrowResult> {\n const { escrowId, escrowPda, unsignedTx } = await this.api.createEscrow(params);\n const signature = await signAndSend(unsignedTx, this.options.wallet, this.connection);\n return { escrowId, escrowPda, signature };\n }\n\n /**\n * Release payment to the worker. Buyer must be the wallet in the constructor.\n * Updates API DB state, then builds and submits the `release_payment` on-chain tx.\n *\n * @returns Solana transaction signature.\n */\n async releasePayment(address: string): Promise<string> {\n // Fetch escrow metadata for worker pubkey + mint\n const escrow = await this.api.getEscrow(address);\n if (!escrow.taker) {\n throw new EscrowNotFoundError(`Escrow ${address} has no assigned worker`);\n }\n\n // Fetch platform config for treasury pubkey + usdc mint\n const { treasury, mint } = await fetchPlatformConfig(this.connection);\n\n // Update DB state (optimistic — on-chain reconciliation runs asynchronously)\n await this.api.releasePaymentDb(address);\n\n // Build, sign, and submit the on-chain instruction\n const unsignedTx = await buildReleasePaymentTx({\n buyer: this.options.wallet.publicKey,\n escrowPda: new PublicKey(address),\n worker: new PublicKey(escrow.taker),\n mint,\n treasury,\n connection: this.connection,\n });\n\n return signAndSend(unsignedTx, this.options.wallet, this.connection);\n }\n\n /**\n * Raise a dispute for an escrow. Either the buyer or the assigned worker\n * may call this. Signs and submits the `raise_dispute` on-chain tx.\n *\n * @returns Solana transaction signature.\n */\n async raiseDispute(address: string, params: RaiseDisputeParams): Promise<string> {\n const { unsignedTx } = await this.api.raiseDispute(address, params);\n return signAndSend(unsignedTx, this.options.wallet, this.connection);\n }\n\n /**\n * Cancel a funded escrow before any worker has claimed it.\n * Buyer must be the wallet in the constructor. Only valid when state is `FUNDED`.\n * Signs and submits the `cancel_escrow` on-chain tx; full USDC refund to buyer.\n *\n * @returns Solana transaction signature.\n */\n async cancelEscrow(address: string): Promise<string> {\n const { unsignedTx } = await this.api.cancelEscrow(address);\n return signAndSend(unsignedTx, this.options.wallet, this.connection);\n }\n\n // ── Worker Bot ───────────────────────────────────────────────────────────────\n\n /**\n * Claim an assigned task. Worker must be the wallet in the constructor.\n * Signs and submits the `claim_task` on-chain tx.\n *\n * @returns Solana transaction signature.\n */\n async claimTask(address: string): Promise<string> {\n const { unsignedTx } = await this.api.claimTask(address);\n return signAndSend(unsignedTx, this.options.wallet, this.connection);\n }\n\n /**\n * Submit a deliverable for oracle evaluation. Worker must be the wallet.\n * Signs and submits the `submit_deliverable` on-chain tx.\n *\n * @returns Solana transaction signature.\n */\n async submitDeliverable(address: string, params: SubmitDeliverableParams): Promise<string> {\n const { unsignedTx } = await this.api.submitDeliverable(address, params);\n return signAndSend(unsignedTx, this.options.wallet, this.connection);\n }\n\n /**\n * List tasks assigned to the wallet's public key.\n * Optionally filter by state(s) and paginate results.\n *\n * If `options.poll` is true, polls with exponential backoff until at least\n * one task is returned.\n *\n * @param state - Filter by one or more states (first state used as API filter).\n * @param options - Polling, pagination (limit/offset).\n */\n async getMyTasks(\n state?: EscrowState[],\n options?: PollOptions & ListOptions,\n ): Promise<PaginatedResult<EscrowAccount>> {\n const assignedTo = this.options.wallet.publicKey.toBase58();\n const params: Parameters<ApiClient[\"listEscrows\"]>[0] = {\n assignedTo,\n ...(state?.[0] != null && { state: state[0] }),\n ...(options?.limit != null && { limit: options.limit }),\n ...(options?.offset != null && { offset: options.offset }),\n };\n\n if (!options?.poll) {\n return this.api.listEscrows(params);\n }\n\n const fetcher = () =>\n this.api\n .listEscrows(params)\n .then((result) => (result.items.length > 0 ? result : null));\n\n return pollUntil(\n assignedTo,\n fetcher,\n (r): r is PaginatedResult<EscrowAccount> => r !== null,\n options.timeoutMs,\n );\n }\n\n // ── Shared ───────────────────────────────────────────────────────────────────\n\n /**\n * Fetch an escrow by its PDA address.\n * If `options.poll` is true, polls with exponential backoff until the escrow\n * appears (useful immediately after a create tx before the API DB syncs).\n */\n async getEscrow(address: string, options?: PollOptions): Promise<EscrowAccount> {\n if (!options?.poll) {\n return this.api.getEscrow(address);\n }\n\n return pollUntil(\n address,\n () =>\n this.api\n .getEscrow(address)\n .catch((e: unknown) => (e instanceof EscrowNotFoundError ? null : Promise.reject(e))),\n (r): r is EscrowAccount => r !== null,\n options.timeoutMs,\n );\n }\n}\n","import nacl from \"tweetnacl\";\nimport bs58 from \"bs58\";\nimport type { Keypair } from \"@solana/web3.js\";\nimport type { EscrowAccount, EscrowState } from \"@escro/shared\";\nimport type {\n CreateEscrowParams,\n ListOptions,\n PaginatedResult,\n RaiseDisputeParams,\n SerializedEscrow,\n SubmitDeliverableParams,\n} from \"./types.js\";\nimport {\n EscroError,\n EscrowNotFoundError,\n EscrowStateError,\n UnauthorizedError,\n} from \"./errors.js\";\n\n// ── Auth header builder ────────────────────────────────────────────────────────\n\nfunction authHeaders(\n wallet: Keypair,\n method: string,\n path: string,\n): Record<string, string> {\n const timestamp = Date.now();\n const message = `escro:${timestamp}:${method}:${path}`;\n const msgBytes = new TextEncoder().encode(message);\n const sigBytes = nacl.sign.detached(msgBytes, wallet.secretKey);\n return {\n \"x-wallet-address\": wallet.publicKey.toBase58(),\n \"x-signature\": bs58.encode(sigBytes),\n \"x-timestamp\": String(timestamp),\n \"content-type\": \"application/json\",\n };\n}\n\n// ── Deserialization ────────────────────────────────────────────────────────────\n\nfunction deserialize(raw: SerializedEscrow): EscrowAccount {\n return { ...raw, amount: BigInt(raw.amount) };\n}\n\n// ── Error handling ─────────────────────────────────────────────────────────────\n\nasync function handleError(res: Response, address?: string): Promise<never> {\n const body = (await res.json().catch(() => ({}))) as {\n error?: string;\n code?: string;\n };\n const msg = body.error ?? `HTTP ${res.status}`;\n if (res.status === 404) throw new EscrowNotFoundError(address ?? msg);\n if (res.status === 409) throw new EscrowStateError(msg);\n if (res.status === 401 || res.status === 403) throw new UnauthorizedError(msg);\n throw new EscroError(msg, body.code ?? \"UNKNOWN\");\n}\n\n// ── API client ─────────────────────────────────────────────────────────────────\n\nexport class ApiClient {\n constructor(\n private readonly baseUrl: string,\n private readonly wallet: Keypair,\n ) {}\n\n private url(path: string): string {\n return `${this.baseUrl}${path}`;\n }\n\n /** GET /v1/escrows/:address */\n async getEscrow(address: string): Promise<EscrowAccount> {\n const path = `/v1/escrows/${address}`;\n const res = await fetch(this.url(path));\n if (!res.ok) await handleError(res, address);\n return deserialize((await res.json()) as SerializedEscrow);\n }\n\n /** GET /v1/escrows?assignedTo=...&state=... */\n async listEscrows(params: {\n assignedTo?: string;\n state?: EscrowState;\n limit?: number;\n offset?: number;\n }): Promise<PaginatedResult<EscrowAccount>> {\n const qs = new URLSearchParams();\n if (params.assignedTo) qs.set(\"assignedTo\", params.assignedTo);\n if (params.state) qs.set(\"state\", params.state);\n if (params.limit != null) qs.set(\"limit\", String(params.limit));\n if (params.offset != null) qs.set(\"offset\", String(params.offset));\n\n const path = `/v1/escrows?${qs.toString()}`;\n const res = await fetch(this.url(path));\n if (!res.ok) await handleError(res);\n const body = (await res.json()) as {\n items: SerializedEscrow[];\n total: number;\n limit: number;\n offset: number;\n };\n return {\n items: body.items.map(deserialize),\n total: body.total,\n limit: body.limit,\n offset: body.offset,\n };\n }\n\n /**\n * POST /v1/escrows — create escrow, returns unsigned tx + ids.\n * Requires auth.\n */\n async createEscrow(params: CreateEscrowParams): Promise<{\n escrowId: string;\n escrowPda: string;\n unsignedTx: string;\n }> {\n const path = \"/v1/escrows\";\n const res = await fetch(this.url(path), {\n method: \"POST\",\n headers: authHeaders(this.wallet, \"POST\", path),\n body: JSON.stringify({\n taskSpec: params.taskSpec,\n amountUsdc: params.amountUsdc,\n deadlineSeconds: params.deadlineSeconds,\n assignedWorker: params.assignedWorker,\n }),\n });\n if (!res.ok) await handleError(res);\n return res.json() as Promise<{ escrowId: string; escrowPda: string; unsignedTx: string }>;\n }\n\n /**\n * POST /v1/escrows/:address/claim — returns unsigned tx.\n * Requires auth (worker).\n */\n async claimTask(address: string): Promise<{ unsignedTx: string }> {\n const path = `/v1/escrows/${address}/claim`;\n const res = await fetch(this.url(path), {\n method: \"POST\",\n headers: authHeaders(this.wallet, \"POST\", path),\n });\n if (!res.ok) await handleError(res, address);\n return res.json() as Promise<{ unsignedTx: string }>;\n }\n\n /**\n * POST /v1/escrows/:address/submit — returns unsigned tx.\n * Requires auth (worker).\n */\n async submitDeliverable(\n address: string,\n params: SubmitDeliverableParams,\n ): Promise<{ unsignedTx: string }> {\n const path = `/v1/escrows/${address}/submit`;\n const res = await fetch(this.url(path), {\n method: \"POST\",\n headers: authHeaders(this.wallet, \"POST\", path),\n body: JSON.stringify({\n contentHash: params.contentHash,\n proofUri: params.proofUri,\n }),\n });\n if (!res.ok) await handleError(res, address);\n return res.json() as Promise<{ unsignedTx: string }>;\n }\n\n /**\n * POST /v1/escrows/:address/release — DB-only state update.\n * Requires auth (buyer). No on-chain tx returned.\n */\n async releasePaymentDb(address: string): Promise<void> {\n const path = `/v1/escrows/${address}/release`;\n const res = await fetch(this.url(path), {\n method: \"POST\",\n headers: authHeaders(this.wallet, \"POST\", path),\n });\n if (!res.ok) await handleError(res, address);\n }\n\n /**\n * POST /v1/escrows/:address/cancel — returns unsigned tx.\n * Requires auth (buyer). Only valid when state is FUNDED.\n */\n async cancelEscrow(address: string): Promise<{ unsignedTx: string }> {\n const path = `/v1/escrows/${address}/cancel`;\n const res = await fetch(this.url(path), {\n method: \"POST\",\n headers: authHeaders(this.wallet, \"POST\", path),\n });\n if (!res.ok) await handleError(res, address);\n return res.json() as Promise<{ unsignedTx: string }>;\n }\n\n /**\n * POST /v1/escrows/:address/dispute — returns unsigned tx.\n * Requires auth (buyer or worker).\n */\n async raiseDispute(\n address: string,\n params: RaiseDisputeParams,\n ): Promise<{ unsignedTx: string }> {\n const path = `/v1/escrows/${address}/dispute`;\n const res = await fetch(this.url(path), {\n method: \"POST\",\n headers: authHeaders(this.wallet, \"POST\", path),\n body: JSON.stringify({ reason: params.reason, evidence: params.evidence }),\n });\n if (!res.ok) await handleError(res, address);\n return res.json() as Promise<{ unsignedTx: string }>;\n }\n}\n","/** Base class for all errors thrown by the @escro/sdk. */\nexport class EscroError extends Error {\n constructor(\n message: string,\n public readonly code: string = \"ESCRO_ERROR\",\n ) {\n super(message);\n this.name = \"EscroError\";\n }\n}\n\n/** The requested escrow was not found (HTTP 404). */\nexport class EscrowNotFoundError extends EscroError {\n constructor(address: string) {\n super(`Escrow not found: ${address}`, \"ESCROW_NOT_FOUND\");\n this.name = \"EscrowNotFoundError\";\n }\n}\n\n/** The operation is not valid for the escrow's current state (HTTP 409). */\nexport class EscrowStateError extends EscroError {\n constructor(message: string) {\n super(message, \"ESCROW_INVALID_STATE\");\n this.name = \"EscrowStateError\";\n }\n}\n\n/** Polling timed out after 24 hours without reaching the expected state. */\nexport class EscrowTimeoutError extends EscroError {\n constructor(address: string) {\n super(`Polling timed out after 24h for escrow: ${address}`, \"ESCROW_TIMEOUT\");\n this.name = \"EscrowTimeoutError\";\n }\n}\n\n/** The caller is not authorized to perform this action (HTTP 401/403). */\nexport class UnauthorizedError extends EscroError {\n constructor(message = \"Unauthorized\") {\n super(message, \"UNAUTHORIZED\");\n this.name = \"UnauthorizedError\";\n }\n}\n","import { EscrowTimeoutError } from \"./errors.js\";\n\nconst MS_5_MIN = 5 * 60 * 1_000;\nconst MS_30_MIN = 30 * 60 * 1_000;\nconst MS_24_H = 24 * 60 * 60 * 1_000;\n\n/**\n * Returns the next polling interval in ms based on total elapsed time.\n * 0 – 5 min → 15 s\n * 5 – 30 min → 30 s\n * 30 min – ∞ → 60 s\n */\nexport function backoffInterval(elapsedMs: number): number {\n if (elapsedMs < MS_5_MIN) return 15_000;\n if (elapsedMs < MS_30_MIN) return 30_000;\n return 60_000;\n}\n\n/** Resolves after `ms` milliseconds. */\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/**\n * Polls `fetcher` with exponential backoff until `predicate` returns true,\n * then returns the result. Throws {@link EscrowTimeoutError} after 24 hours.\n *\n * @param address - Escrow address used in the timeout error message.\n * @param fetcher - Async function that returns a value or null.\n * @param predicate - Returns true when polling should stop.\n * @param timeoutMs - Maximum total wait time in ms (default: 24 h).\n */\nexport async function pollUntil<T>(\n address: string,\n fetcher: () => Promise<T | null>,\n predicate: (result: T | null) => result is T,\n timeoutMs = MS_24_H,\n): Promise<T> {\n const deadline = Date.now() + timeoutMs;\n\n while (true) {\n const result = await fetcher();\n if (predicate(result)) return result;\n\n const elapsed = Date.now() - (deadline - timeoutMs);\n if (Date.now() >= deadline) {\n throw new EscrowTimeoutError(address);\n }\n\n const interval = backoffInterval(elapsed);\n // Clamp to remaining time so we don't sleep past the deadline\n const remaining = deadline - Date.now();\n await sleep(Math.min(interval, remaining));\n\n if (Date.now() >= deadline) {\n throw new EscrowTimeoutError(address);\n }\n }\n}\n","import { createHash } from \"node:crypto\";\nimport {\n Connection,\n Keypair,\n PublicKey,\n Transaction,\n TransactionInstruction,\n} from \"@solana/web3.js\";\nimport {\n TOKEN_PROGRAM_ID,\n ASSOCIATED_TOKEN_PROGRAM_ID,\n getAssociatedTokenAddressSync,\n} from \"@solana/spl-token\";\n\n// ── Discriminator helper ───────────────────────────────────────────────────────\n\nfunction disc(name: string): Buffer {\n return Buffer.from(\n createHash(\"sha256\").update(`global:${name}`).digest(),\n ).subarray(0, 8);\n}\n\nconst DISC_RELEASE_PAYMENT = disc(\"release_payment\");\n\n// ── Constants ──────────────────────────────────────────────────────────────────\n\nconst PROGRAM_ID = new PublicKey(\"EjLpJ3obUYk1f2KDensU7UdGBZTxSdxufm7CSnMA3H5C\");\n\n/**\n * PlatformConfig account layout (after 8-byte Anchor discriminator):\n * fee_bps : u16 — offset 8..10\n * oracle_authority : Pubkey — offset 10..42\n * usdc_mint : Pubkey — offset 42..74\n * treasury : Pubkey — offset 74..106\n */\nexport async function fetchPlatformConfig(\n connection: Connection,\n): Promise<{ mint: PublicKey; treasury: PublicKey }> {\n const [pda] = PublicKey.findProgramAddressSync([Buffer.from(\"config\")], PROGRAM_ID);\n const info = await connection.getAccountInfo(pda);\n if (!info) throw new Error(\"PlatformConfig account not found on-chain\");\n return {\n mint: new PublicKey(info.data.slice(42, 74)),\n treasury: new PublicKey(info.data.slice(74, 106)),\n };\n}\n\n// ── Sign and submit ────────────────────────────────────────────────────────────\n\n/**\n * Decode a base64 unsigned transaction, sign it with `wallet`, submit to Solana,\n * and return the transaction signature.\n */\nexport async function signAndSend(\n base64Tx: string,\n wallet: Keypair,\n connection: Connection,\n): Promise<string> {\n const buf = Buffer.from(base64Tx, \"base64\");\n const tx = Transaction.from(buf);\n tx.partialSign(wallet);\n const raw = tx.serialize();\n const signature = await connection.sendRawTransaction(raw, {\n skipPreflight: false,\n });\n await connection.confirmTransaction(signature, \"confirmed\");\n return signature;\n}\n\n// ── release_payment transaction builder ───────────────────────────────────────\n\n/**\n * Build an unsigned `release_payment` transaction.\n * The buyer signs to approve payment to the assigned worker.\n *\n * Account order (matches the on-chain `ReleasePayment` context):\n * 0. buyer — Signer, writable\n * 1. platform_config — read\n * 2. mint — read\n * 3. escrow_account — writable\n * 4. vault — ATA(mint, escrowPda), writable\n * 5. worker_ata — ATA(mint, worker), writable\n * 6. treasury_ata — ATA(mint, treasury), writable\n * 7. worker — read\n * 8. treasury — read\n * 9. token_program — read\n * 10. associated_token_program — read\n */\nexport async function buildReleasePaymentTx(params: {\n buyer: PublicKey;\n escrowPda: PublicKey;\n worker: PublicKey;\n mint: PublicKey;\n treasury: PublicKey;\n connection: Connection;\n}): Promise<string> {\n const { buyer, escrowPda, worker, mint, treasury, connection } = params;\n\n const [platformConfig] = PublicKey.findProgramAddressSync(\n [Buffer.from(\"config\")],\n PROGRAM_ID,\n );\n const vault = getAssociatedTokenAddressSync(\n mint,\n escrowPda,\n true,\n TOKEN_PROGRAM_ID,\n ASSOCIATED_TOKEN_PROGRAM_ID,\n );\n const workerAta = getAssociatedTokenAddressSync(\n mint,\n worker,\n false,\n TOKEN_PROGRAM_ID,\n ASSOCIATED_TOKEN_PROGRAM_ID,\n );\n const treasuryAta = getAssociatedTokenAddressSync(\n mint,\n treasury,\n false,\n TOKEN_PROGRAM_ID,\n ASSOCIATED_TOKEN_PROGRAM_ID,\n );\n\n const ix = new TransactionInstruction({\n programId: PROGRAM_ID,\n keys: [\n { pubkey: buyer, isSigner: true, isWritable: true },\n { pubkey: platformConfig, isSigner: false, isWritable: false },\n { pubkey: mint, isSigner: false, isWritable: false },\n { pubkey: escrowPda, isSigner: false, isWritable: true },\n { pubkey: vault, isSigner: false, isWritable: true },\n { pubkey: workerAta, isSigner: false, isWritable: true },\n { pubkey: treasuryAta, isSigner: false, isWritable: true },\n { pubkey: worker, isSigner: false, isWritable: false },\n { pubkey: treasury, isSigner: false, isWritable: false },\n { pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false },\n { pubkey: ASSOCIATED_TOKEN_PROGRAM_ID, isSigner: false, isWritable: false },\n ],\n data: DISC_RELEASE_PAYMENT,\n });\n\n const { blockhash } = await connection.getLatestBlockhash(\"confirmed\");\n const tx = new Transaction();\n tx.recentBlockhash = blockhash;\n tx.feePayer = buyer;\n tx.add(ix);\n return tx.serialize({ requireAllSignatures: false }).toString(\"base64\");\n}\n"],"mappings":"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","names":["Connection","PublicKey","Connection","PublicKey"]}
package/package.json ADDED
@@ -0,0 +1,49 @@
1
+ {
2
+ "name": "@escro/sdk",
3
+ "version": "0.1.0",
4
+ "description": "TypeScript SDK for the escro.ai on-chain escrow protocol",
5
+ "license": "MIT",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "https://github.com/escro-ai/escro.ai",
9
+ "directory": "packages/sdk"
10
+ },
11
+ "keywords": ["solana", "escrow", "sdk", "ai-agents", "spl-token"],
12
+ "type": "module",
13
+ "exports": {
14
+ ".": {
15
+ "import": "./dist/index.js",
16
+ "require": "./dist/index.cjs"
17
+ }
18
+ },
19
+ "main": "./dist/index.cjs",
20
+ "module": "./dist/index.js",
21
+ "types": "./dist/index.d.ts",
22
+ "scripts": {
23
+ "build": "tsup",
24
+ "typecheck": "tsc --noEmit",
25
+ "test": "vitest run",
26
+ "lint": "eslint src",
27
+ "lint:fix": "eslint src --fix",
28
+ "format": "prettier --write src",
29
+ "format:check": "prettier --check src",
30
+ "clean": "rm -rf dist *.tsbuildinfo",
31
+ "prepublishOnly": "npm run build && npm run typecheck"
32
+ },
33
+ "dependencies": {
34
+ "@solana/spl-token": "^0.4.9",
35
+ "@solana/web3.js": "^1.95.8",
36
+ "bs58": "^5.0.0",
37
+ "tweetnacl": "^1.0.3"
38
+ },
39
+ "peerDependencies": {
40
+ "@solana/web3.js": "^1.95.0"
41
+ },
42
+ "devDependencies": {
43
+ "@escro/shared": "*",
44
+ "@vitest/coverage-v8": "^4.0.0",
45
+ "tsup": "^8.0.0",
46
+ "vitest": "^4.0.0"
47
+ },
48
+ "files": ["dist", "README.md"]
49
+ }