@zerc20/wallet-sdk 0.4.0 → 0.6.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.
Files changed (73) hide show
  1. package/LICENSE +17 -20
  2. package/README.md +2 -2
  3. package/dist/accountId.d.ts +5 -0
  4. package/dist/accountId.js +19 -0
  5. package/dist/accountId.js.map +1 -0
  6. package/dist/chain.d.ts +86 -9
  7. package/dist/chain.js +61 -33
  8. package/dist/chain.js.map +1 -1
  9. package/dist/context.d.ts +8 -2
  10. package/dist/context.js +15 -2
  11. package/dist/context.js.map +1 -1
  12. package/dist/core.d.ts +35 -5
  13. package/dist/core.js +98 -25
  14. package/dist/core.js.map +1 -1
  15. package/dist/errors.d.ts +20 -3
  16. package/dist/errors.js +7 -1
  17. package/dist/errors.js.map +1 -1
  18. package/dist/index.d.ts +4 -2
  19. package/dist/index.js +4 -2
  20. package/dist/index.js.map +1 -1
  21. package/dist/network.d.ts +4 -2
  22. package/dist/network.js +3 -1
  23. package/dist/network.js.map +1 -1
  24. package/dist/pos.d.ts +10 -1
  25. package/dist/pos.js +219 -55
  26. package/dist/pos.js.map +1 -1
  27. package/dist/prove.d.ts +3 -0
  28. package/dist/prove.js +9 -0
  29. package/dist/prove.js.map +1 -1
  30. package/dist/rageExit.d.ts +27 -4
  31. package/dist/rageExit.js +160 -49
  32. package/dist/rageExit.js.map +1 -1
  33. package/dist/seed.d.ts +4 -0
  34. package/dist/seed.js +13 -1
  35. package/dist/seed.js.map +1 -1
  36. package/dist/servers.d.ts +5 -0
  37. package/dist/servers.js +2 -0
  38. package/dist/servers.js.map +1 -1
  39. package/dist/services.d.ts +14 -6
  40. package/dist/services.js +35 -14
  41. package/dist/services.js.map +1 -1
  42. package/dist/spend.d.ts +53 -11
  43. package/dist/spend.js +171 -65
  44. package/dist/spend.js.map +1 -1
  45. package/dist/state.d.ts +21 -0
  46. package/dist/state.js.map +1 -1
  47. package/dist/sync.d.ts +10 -5
  48. package/dist/sync.js +49 -18
  49. package/dist/sync.js.map +1 -1
  50. package/dist/wallet.d.ts +132 -21
  51. package/dist/wallet.js +342 -91
  52. package/dist/wallet.js.map +1 -1
  53. package/package.json +3 -3
  54. package/src/accountId.ts +22 -0
  55. package/src/chain.ts +101 -49
  56. package/src/context.ts +27 -3
  57. package/src/core.ts +112 -26
  58. package/src/errors.ts +15 -2
  59. package/src/index.ts +15 -2
  60. package/src/network.ts +6 -3
  61. package/src/pos.ts +247 -61
  62. package/src/prove.ts +10 -0
  63. package/src/rageExit.ts +237 -61
  64. package/src/seed.ts +24 -1
  65. package/src/servers.ts +9 -1
  66. package/src/services.ts +36 -22
  67. package/src/spend.ts +188 -75
  68. package/src/state.ts +25 -1
  69. package/src/sync.ts +54 -19
  70. package/src/wallet.ts +437 -109
  71. package/wasm/zerc20_wallet_core.d.ts +1 -1
  72. package/wasm/zerc20_wallet_core.js +1 -1
  73. package/wasm/zerc20_wallet_core_bg.wasm +0 -0
package/dist/wallet.d.ts CHANGED
@@ -28,6 +28,9 @@ export interface OpenOptions {
28
28
  birthday?: bigint | Date;
29
29
  /** The app opening the wallet, when it takes a share of what reaches the deposit addresses it hands out. */
30
30
  referrer?: Referrer;
31
+ /** Takes the wallet from another tab or window that holds it open, whose `taken` aborts, rather than failing with
32
+ * `wallet-in-use`: for a user who opens it here, where the other may be a tab the browser keeps in the background. */
33
+ take?: boolean;
31
34
  }
32
35
  export interface WatchOptions extends Pick<OpenOptions, 'network' | 'persist' | 'birthday'> {
33
36
  /** The account's view key, from its wallet's `viewKey()`. */
@@ -78,7 +81,8 @@ export interface Activity {
78
81
  * paid none. */
79
82
  fee: bigint | null;
80
83
  /** The other side, where known: a payer's claimed address (unverified), where a payment or withdrawal went, or whom a
81
- * returned deposit went back to. */
84
+ * returned deposit went back to. A payment's other side, `sent`'s or that of a `received` with no `burnAddress`, is a
85
+ * zERC20 account, which an app shows by its zERC20 ID (`accountId`); any other is a public address. */
82
86
  counterparty: Address | null;
83
87
  /** What the counterparty alone does not say: the receive code a payment went to (it has no counterparty), or the
84
88
  * deposit address a deposit came through (its counterparty, which forwarded what was sent to it). */
@@ -115,9 +119,21 @@ export interface CoinInfo {
115
119
  state: 'spendable' | Exclude<PendingReason, 'incoming'> | 'spending' | 'blocked';
116
120
  /** A note's payer (as claimed, unverified) or a deposit's sender, where known. */
117
121
  from: Address | null;
118
- /** For a deposit in `screening`, when the ASP should decide it: an estimate, null until there is one. */
119
- screenedBy: Date | null;
122
+ /** The deposit address of this wallet's that a deposit came through (its `from`), as `Activity.via` names it: its
123
+ * `rageExit` goes where `to` says. */
124
+ via: {
125
+ depositAddress: Address;
126
+ } | null;
127
+ /** While `screening` or `awaiting-root`, when it should be spendable: the later of its AML check's deadline and when a
128
+ * root should cover it, by how long commitments on its chain usually wait for one. An estimate: null until there is
129
+ * one, and in other states. */
130
+ readyBy: Date | null;
131
+ /** When it landed: its block's time, null until read. */
132
+ at: Date | null;
120
133
  }
134
+ /** Of `coins`, the one whose turning spendable makes them `need`, the soonest first; null where they never do, or the
135
+ * one it takes has no estimate. */
136
+ export declare function waitsOn(coins: CoinInfo[], need: bigint): CoinInfo | null;
121
137
  export interface DepositInfo {
122
138
  id: string;
123
139
  /** The burn address it was sent to. */
@@ -130,18 +146,39 @@ export interface DepositInfo {
130
146
  sender: Address | null;
131
147
  state: 'screening' | 'approved' | 'rejected' | 'spent';
132
148
  }
149
+ export interface DepositAddressInfo {
150
+ address: Address;
151
+ token: Token;
152
+ /** What the relayer takes out of each payment through it. Null where its receipt in storage does not say what it was
153
+ * registered with: `flushDepositAddress` needs that, so only the relayer flushes such an address. */
154
+ fee: bigint | null;
155
+ /** When it was handed out, or watched again (`rewatchDepositAddress`), from which the deposit relayer watches it for
156
+ * 7 days: when storage took its receipt. */
157
+ at: Date;
158
+ }
133
159
  /** A send's or withdrawal's recipient gets all of its amount, and the private balance pays `fee` on top. */
134
160
  export interface FeeQuote {
135
161
  /** To the relayer. */
136
162
  relayer: bigint;
137
163
  /** The protocol's cut of the public withdrawal: a withdrawal's, or the one that pays the relayer. */
138
164
  protocol: bigint;
165
+ /** `protocol` as a rate of that withdrawal, in basis points (35 is 0.35%): lower in tiers as the withdrawal grows. */
166
+ protocolBps: number;
139
167
  /** `relayer + protocol`: the `maxFee` this quote passes. */
140
168
  fee: bigint;
141
169
  /** Transactions needed: one JoinSplit for a send or a withdrawal, a consolidation's merges (each pays the relayer's
142
170
  * fee again). */
143
171
  steps: number;
144
172
  }
173
+ /** The most a send or withdrawal can pay now, and what its fees keep back of what is spendable. */
174
+ export interface MaxAmount {
175
+ /** What the recipient would get: 0 where the fees take everything. */
176
+ amount: bigint;
177
+ /** The fees: the payment's, and those of the merges it needs first. Where they take everything, what they would be. */
178
+ fee: bigint;
179
+ /** Merges first, when one JoinSplit cannot spend all of it: each pays the relayer again. */
180
+ merges: number;
181
+ }
145
182
  export type OperationKind = OperationRecord['kind'];
146
183
  export type OperationStatus = OperationRecord['status'];
147
184
  export type CoinState = CoinInfo['state'];
@@ -167,18 +204,31 @@ export interface Operation {
167
204
  /** How far a send, withdrawal or consolidation round has come, for an app to show; null for a deposit, or between
168
205
  * rounds. It moves during a sync: read it while one runs. */
169
206
  readonly stage: Step['stage'] | MergeStep['stage'] | null;
170
- /** Whom a deposit pays, when it goes into their burn address (`deposit({ to })`); null otherwise. */
207
+ /** Whom a deposit pays, when `deposit({ to })` named an address; null otherwise. One to a receive code shows its code
208
+ * as `via` in `activity()`. */
171
209
  readonly to: Address | null;
210
+ /** Whether `cancel()` can still end it: a send, withdrawal or consolidation that has paid nothing and has no request
211
+ * out to the relayer. It moves during a sync: read it while one runs. */
212
+ readonly cancellable: boolean;
172
213
  /** Syncs until the operation is done; throws if it fails. */
173
214
  wait(): Promise<void>;
215
+ /** Ends it while `cancellable`, and does nothing once it is cancelled: it paid nothing, its notes and deposits are free
216
+ * again, it leaves `operations()` and `activity()`, and `wait()` throws `cancelled`. Throws otherwise, and when the
217
+ * wallet cannot save it, which leaves it under way. */
218
+ cancel(): Promise<void>;
174
219
  }
175
220
  export declare class Wallet {
176
221
  #private;
222
+ /** A wallet over `ctx`, held by `lock`: by default held nowhere, as where there are no Web Locks. */
177
223
  private constructor();
178
- /** Lets this wallet open again: in another tab, or here for another account. This object is done with: what is
224
+ /** Lets this wallet go, for another tab or another account here. This object is done with: what is
179
225
  * queued fails with `wallet-closed`, a burn address search stops, and the wallet is let go once the task under way
180
226
  * ends, so that two never write its state at once. */
181
227
  close(): Promise<void>;
228
+ /** Aborts once another tab or window takes this wallet (`take`), which closes it here: what is queued fails with
229
+ * `wallet-taken`, a burn address search stops, and the task under way saves nothing more, as the other tab reads the
230
+ * state and writes it now. */
231
+ get taken(): AbortSignal;
182
232
  get address(): Address;
183
233
  /** The account's view key, for `watch` to follow it with on another device: whoever holds it sees what this wallet
184
234
  * shows, except the private payments to receive codes, and can spend none of it. Checksummed text (bech32m,
@@ -216,6 +266,20 @@ export declare class Wallet {
216
266
  } | null>;
217
267
  /** Every deposit found, with the id `rageExit` takes. */
218
268
  deposits(): DepositInfo[];
269
+ /** The deposit addresses this wallet handed out (`depositAddress`), on any of its devices, newest first: for an app to
270
+ * show each while what is sent to it is on its way, which `activity()` shows once deposited. Each is dated, and its
271
+ * fee told, by its receipt in storage, alike on every device. */
272
+ depositAddresses(): DepositAddressInfo[];
273
+ /** What `address` is to this wallet on `chainId`: one of its own burn addresses (`deposit`), one it paid someone
274
+ * into (`payment`, `deposit({ to })` to an address), or neither (null), as is a receive code's that it paid. On chain
275
+ * either is a plain transfer to an address that names no one: this tells an app listing the account's public
276
+ * transfers which they were. Both are recorded before the transfer is sent. */
277
+ burnAddressOf(chainId: bigint, address: Address): {
278
+ kind: 'deposit';
279
+ } | {
280
+ kind: 'payment';
281
+ to: Address;
282
+ } | null;
219
283
  /** The payments to the burn addresses this wallet's points of sale handed out. Spent ones are, normally, in a
220
284
  * merged note. */
221
285
  payments(): DepositInfo[];
@@ -225,17 +289,32 @@ export declare class Wallet {
225
289
  * addresses. */
226
290
  posKey(): Promise<Hex>;
227
291
  /** Refunds deposit `id` to its sender without the ASP, the attester or a proved root: for a deposit the ASP
228
- * rejected, or when those services stop. The account's wallet sends the transactions and pays their gas. */
229
- rageExit(id: string): Promise<Hex[]>;
292
+ * rejected, or when those services stop. The account's wallet sends the transactions and pays their gas, or with
293
+ * `from` another wallet of the user's does, as `deposit({ from })` pays. One through a deposit address of this
294
+ * wallet's (`CoinInfo.via`) goes to `to`, by default `from`'s account, else this account; any other goes back to its
295
+ * sender, and one through a point of sale's deposit address to the refund address its payer named. */
296
+ rageExit(id: string, opts?: {
297
+ from?: WalletClient;
298
+ to?: Address;
299
+ }): Promise<Hex[]>;
300
+ /** Sends what deposit address `address` of this wallet's holds of `asset` (NATIVE for the chain's own currency) to
301
+ * `to`: another token sent to it, which it cannot wrap. What it can wrap is wrapped instead, as a payment to it is.
302
+ * It deploys on its first flush, and refunds nothing before. `from` and `to` as for `rageExit`. */
303
+ refundDepositAddress(address: Address, asset: Address, opts?: {
304
+ from?: WalletClient;
305
+ to?: Address;
306
+ }): Promise<Hex>;
230
307
  operations(): Operation[];
231
308
  /** Moves `amount` of the account's public tokens into the private balance: wraps the underlying asset into a fresh
232
309
  * burn address (approving it first if needed). The deposit is spendable once the ASP has screened it. More than the
233
310
  * account holds fails at once (`insufficient-funds`), before anything is asked of the wallet.
234
311
  *
235
- * With `to`, an address that registered, it pays them instead, privately: into a fresh burn address of theirs,
236
- * under the public key they registered, told to them in storage first as a note is (`planDeposit`). They
237
- * receive it as a deposit of their own, screened like any; the burn address names no one. It shows in `activity()`
238
- * as sent. Finding the address takes about 2^16 hashes (`burn-address`).
312
+ * With `to`, an account that registered, by its address or its zERC20 ID, it pays them instead, privately: into a
313
+ * fresh burn address of theirs, under the public key they registered, told to them in storage first as a note is
314
+ * (`planDeposit`). They receive it as a deposit of their own, screened like any; the burn address names no one. It
315
+ * shows in `activity()` as sent. Finding the address takes about 2^16 hashes (`burn-address`). Or `to` is a receive
316
+ * code (`receiveCode`), paid into its burn address, which its owner already watches: storage is told nothing, so
317
+ * only this device's `activity()` shows it as sent.
239
318
  *
240
319
  * With `wrapped`, it pays from the account's zERC20 itself, as a withdrawal pays out, rather than its underlying
241
320
  * asset: a plain transfer into the burn address, with no wrap and no approval.
@@ -248,7 +327,7 @@ export declare class Wallet {
248
327
  deposit(opts: {
249
328
  token: Token;
250
329
  amount: bigint;
251
- to?: Address;
330
+ to?: string;
252
331
  wrapped?: boolean;
253
332
  from?: WalletClient;
254
333
  onStep?: (step: DepositStep) => void;
@@ -256,13 +335,31 @@ export declare class Wallet {
256
335
  /** An address that takes `token`'s underlying asset from anywhere (an exchange withdrawal, another wallet) and
257
336
  * deposits it privately, less `fee` (in the underlying's base units) to the deposit relayer each time: what arrives
258
337
  * must exceed it. A wallet opened with a `referrer` also pays it its `bps` of the rest. Watched for 7 days by the
259
- * deposit relayer; refunds go back to this account. `onStep` hears what it waits on (`queued`, `burn-address`). */
338
+ * deposit relayer. It names no account: its refunds go where a key of its own signs for (`rageExit`'s `to`,
339
+ * `refundDepositAddress`). `depositAddresses()` lists it. `onStep` hears what it waits on (`queued`,
340
+ * `burn-address`). */
260
341
  depositAddress(token: Token, opts?: {
261
342
  onStep?: (step: DepositStep) => void;
262
343
  }): Promise<{
263
344
  address: Address;
264
345
  fee: bigint;
265
346
  }>;
347
+ /** Has the deposit relayer watch deposit address `address` of this wallet's for another 7 days, at the fee it was
348
+ * handed out with: what reached it after its 7 days is deposited then, and so is what reaches it within the next.
349
+ * `depositAddresses()` dates it from now, on every device. */
350
+ rewatchDepositAddress(address: Address): Promise<{
351
+ address: Address;
352
+ fee: bigint;
353
+ }>;
354
+ /** Deposits what deposit address `address` of this wallet's holds, as the deposit relayer would, for when it does
355
+ * not: down, or no longer watching the address. Its receipt says all the address was registered with, wherever its
356
+ * `fee` is known (`depositAddresses()`), so no relayer is asked. `from`, another wallet of the user's, sends the
357
+ * flush and pays its gas, and shows on chain as the depositor: never the account's own, which the address does not
358
+ * name. What it holds must exceed the fee (`insufficient-funds`). It shows in `activity()` as any deposit through
359
+ * the address. */
360
+ flushDepositAddress(address: Address, opts: {
361
+ from: WalletClient;
362
+ }): Promise<Hex>;
266
363
  /** A receive code for `token`, to hand to one payer: it pays any amount, as often as it likes, publicly by a transfer
267
364
  * of the token to the code's burn address (a deposit, like a point of sale's payment addresses), or privately by
268
365
  * `send`. It is one of this wallet's burn addresses, recorded in storage ahead of need, so handing it out writes
@@ -283,13 +380,17 @@ export declare class Wallet {
283
380
  maxAmount(opts: {
284
381
  kind: 'send' | 'withdraw';
285
382
  token: Token;
286
- }): Promise<bigint>;
383
+ }): Promise<MaxAmount>;
287
384
  /** What the next merge of a consolidation of everything would spend, as `coins()` ids: up to 100, the largest first,
288
385
  * for `consolidate({ coins })`. Null when nothing spendable is worth merging. */
289
386
  nextMerge(token: Token): Promise<string[] | null>;
290
- /** Pays `amount` privately: to an address that has registered (any wallet that ever opened), or to a receive code
291
- * (`receiveCode`). An address that never registered fails with `recipient-not-registered`. One JoinSplit from
292
- * what is spendable now, or it fails here: `needs-consolidation`, `funds-settling` or `insufficient-funds`.
387
+ /** Fetches what a send or withdrawal proves with, some 25 MB, once a page: an app calls it as a payment form opens,
388
+ * so that the payment's proof does not wait for the download. Outside the queue of calls: a sync goes on meanwhile. */
389
+ preloadProver(): Promise<void>;
390
+ /** Pays `amount` privately: to an account that has registered (any wallet that ever opened), by its address or its
391
+ * zERC20 ID (`accountId`), or to a receive code (`receiveCode`). An account that never registered fails with
392
+ * `recipient-not-registered`. One JoinSplit from what is spendable now, or it fails here: `needs-consolidation`,
393
+ * `funds-settling` or `insufficient-funds`.
293
394
  * `amount` is what the recipient gets, and `maxFee` caps what it pays on top, `fees({ kind: 'send' }).fee`: the
294
395
  * relayer names its fee, so a quote the user saw is the cap. */
295
396
  send(opts: {
@@ -324,7 +425,17 @@ export declare class Wallet {
324
425
  unwrap?: boolean;
325
426
  }): Promise<Operation>;
326
427
  }
327
- /** Holds `address`'s wallet until the returned function is called: two tabs on one wallet would each overwrite the
328
- * other's state and spend the same notes. A wallet that watches it (`view`) is held apart, as its state is its own.
329
- * Nothing where there are no Web Locks. */
330
- export declare function lockWallet(address: Address, kind?: 'wallet' | 'view'): Promise<() => void>;
428
+ /** A wallet held open here (`lockWallet`): until `release`, or until another tab or window takes it, which aborts
429
+ * `taken`. */
430
+ export interface Hold {
431
+ release: () => void;
432
+ taken: AbortSignal;
433
+ /** Runs `f`, a read or a write of the wallet's saved state, with no other tab in one, and only while this one holds the
434
+ * wallet: asked of the browser's lock manager, which knows of a take before this tab is told, so that a write lands
435
+ * either before the tab that took the wallet reads the state, or not at all. */
436
+ guard: <T>(f: () => Promise<T>) => Promise<T>;
437
+ }
438
+ /** Holds `address`'s wallet: two tabs on one wallet would each overwrite the other's state and spend the same notes. It
439
+ * fails with `wallet-in-use` while another tab or window holds it, unless it `take`s it from that one. A wallet that
440
+ * watches it (`view`) is held apart, as its state is its own. Neither where there are no Web Locks. */
441
+ export declare function lockWallet(address: Address, kind?: 'wallet' | 'view', take?: boolean): Promise<Hold>;