@escro/sdk 0.4.1 → 0.5.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 CHANGED
@@ -1,6 +1,11 @@
1
1
  # @escro/sdk
2
2
 
3
- TypeScript SDK for the [escro.ai](https://escro.ai) on-chain escrow protocol on Solana.
3
+ TypeScript SDK for the [escro.ai](https://escro.ai) on-chain escrow protocol on Solana: escrow for
4
+ bots. A Buyer Bot locks USDC, a Worker Bot delivers, and the contract enforces the state machine
5
+ and defaults to refund. The SDK builds and signs the transactions and talks to the API; Escro never
6
+ judges quality, the Buyer releases or disputes.
7
+
8
+ Source: [github.com/escro-ai/escro.ai](https://github.com/escro-ai/escro.ai/tree/main/packages/sdk).
4
9
 
5
10
  ## Install
6
11
 
@@ -23,8 +28,10 @@ const client = new Escro({
23
28
 
24
29
  // Buyer: create and fund an escrow
25
30
  const { escrowPda, signature } = await client.createEscrow({
26
- taskSpec: { /* ... */ },
27
- amountUsdc: 10_000_000, // 10 USDC
31
+ taskSpec: {
32
+ /* ... */
33
+ },
34
+ amountUsdc: 10_000_000, // 10 USDC
28
35
  deadlineUnix: Math.floor(Date.now() / 1000) + 3600,
29
36
  assignedWorker: "WorkerPubkeyBase58...",
30
37
  });
@@ -39,9 +46,67 @@ await client.submitDeliverable(items[0].address, {
39
46
 
40
47
  // Buyer: release payment or cancel
41
48
  await client.releasePayment(escrowPda);
42
- await client.cancelEscrow(escrowPda); // only if FUNDED, before worker claims
49
+ await client.cancelEscrow(escrowPda); // only if FUNDED, before worker claims
43
50
  ```
44
51
 
52
+ ## Spend cap
53
+
54
+ A buyer sets `spendCap` when it constructs the client: the most micro-USDC its wallet may hold
55
+ in open escrows, each counted as its deposit (amount plus fee).
56
+
57
+ ```typescript
58
+ import { Escro, parseUsdc } from "@escro/sdk";
59
+
60
+ const buyer = new Escro({
61
+ cluster: "mainnet",
62
+ rpcUrl: "https://api.mainnet-beta.solana.com",
63
+ apiUrl: "https://api.escro.ai",
64
+ wallet,
65
+ spendCap: { maxOutstandingMicroUsdc: parseUsdc("50") }, // 50 USDC
66
+ });
67
+ ```
68
+
69
+ Before the create is sent, `createEscrow` reads the on-chain fee rate and the wallet's open
70
+ deposits (one `GET /v1/escrows/outstanding`: FUNDED, IN_PROGRESS, SUBMITTED and DISPUTED escrows),
71
+ adds this process's creates still in flight, and throws `SPEND_CAP_EXCEEDED` for a create that
72
+ would pass the cap. An outstanding read that fails, answers something malformed or takes longer
73
+ than 15 s refuses the create with `SPEND_CAP_UNREADABLE` (a failed or timed-out read as its
74
+ `cause`); a PlatformConfig read that fails or takes longer than 15 s throws its own error, with no
75
+ code. On `"mainnet"` a client without `spendCap` cannot create (`SPEND_CAP_REQUIRED`); a
76
+ worker-only client needs none. `spendCap.outstanding` replaces the API read under the same 15 s
77
+ bound (one that has not answered is abandoned, not cancelled), and the in-flight creates are
78
+ added to its answer. The error codes are exported as `SPEND_CAP_ERROR_CODES`. `createEscrow`
79
+ also refuses an `assignedWorker` that is not a base-58 public key, or an
80
+ `amountUsdc` that is not a positive whole number (`VALIDATION_ERROR`). The create request
81
+ (`POST /v1/escrows`) is abandoned after 15 s with `API_TIMEOUT`.
82
+
83
+ The cap holds per process. Every capped client for one wallet and cluster in the process shares one
84
+ queue: creates are checked one at a time, and each holds its deposit as in flight from the API's
85
+ answer to its POST. A create that throws before its transaction is sent (the SDK's refusal of the
86
+ server's transaction as not the create it asked for, `UNEXPECTED_TRANSACTION`; an undecodable server
87
+ transaction; a failed blockhash read) holds nothing. Once sent, the hold lasts until a successful
88
+ `confirm(address, signature)`, or until evidence shows the transaction never took effect: the RPC
89
+ rejected it other than as already processed, or it failed at execution (`TX_FAILED`). A create that
90
+ throws after its transaction is sent for any other reason (a network error, a confirmation timeout,
91
+ an `EscroConfirmError`) keeps counting, and shrinks the cap's room, until `confirm(address,
92
+ signature)` succeeds or the process exits. An "already processed" rejection carries no signature to
93
+ confirm with, so its hold lasts until the process exits. Two processes or hosts on one wallet each
94
+ enforce the cap and together can pass it by the other's in-flight deposits: run one buyer process
95
+ per wallet, or give each its share.
96
+
97
+ ## Paying a 402
98
+
99
+ A `pay()` given an address rule (`admitAddress`) needs direct egress and local DNS: it resolves each
100
+ host with this machine's resolver and connects directly to the addresses the rule admitted, ignoring
101
+ any HTTP or HTTPS proxy set in the environment. With `url`, on a network reachable only through a
102
+ proxy the pay fails at its first request, before anything is funded or signed. With
103
+ `paymentRequired`, a `resource.url` whose host resolves here but cannot be reached directly fails at
104
+ the paid request, after the escrow is funded or the `exact` payment signed.
105
+
106
+ `pay()` refuses a `url`, or with `paymentRequired` the 402's `resource.url`, on a port `fetch` blocks
107
+ (25, 6667 and the rest of the Fetch standard's bad-port list) before any lookup or request, and the default job-specification read refuses a
108
+ `specUri` that carries a username or password or names such a port.
109
+
45
110
  ## API
46
111
 
47
112
  Every method, its parameters and its errors are in the generated