@agoric/ertp 0.16.3-u13.0 → 0.16.3-u16.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 (53) hide show
  1. package/exported.d.ts +37 -0
  2. package/exported.js +2 -1
  3. package/package.json +35 -26
  4. package/src/amountMath.d.ts +44 -31
  5. package/src/amountMath.d.ts.map +1 -1
  6. package/src/amountMath.js +130 -120
  7. package/src/amountStore.d.ts +9 -0
  8. package/src/amountStore.d.ts.map +1 -0
  9. package/src/amountStore.js +34 -0
  10. package/src/displayInfo.d.ts +3 -0
  11. package/src/displayInfo.d.ts.map +1 -1
  12. package/src/displayInfo.js +2 -0
  13. package/src/index.js +8 -0
  14. package/src/issuerKit.d.ts +30 -6
  15. package/src/issuerKit.d.ts.map +1 -1
  16. package/src/issuerKit.js +218 -76
  17. package/src/legacy-payment-helpers.d.ts +6 -1
  18. package/src/legacy-payment-helpers.d.ts.map +1 -1
  19. package/src/legacy-payment-helpers.js +33 -32
  20. package/src/mathHelpers/copyBagMathHelpers.d.ts +3 -4
  21. package/src/mathHelpers/copyBagMathHelpers.d.ts.map +1 -1
  22. package/src/mathHelpers/copyBagMathHelpers.js +4 -5
  23. package/src/mathHelpers/copySetMathHelpers.d.ts +3 -3
  24. package/src/mathHelpers/copySetMathHelpers.d.ts.map +1 -1
  25. package/src/mathHelpers/copySetMathHelpers.js +6 -4
  26. package/src/mathHelpers/natMathHelpers.d.ts +8 -7
  27. package/src/mathHelpers/natMathHelpers.d.ts.map +1 -1
  28. package/src/mathHelpers/natMathHelpers.js +7 -8
  29. package/src/mathHelpers/setMathHelpers.d.ts +2 -0
  30. package/src/mathHelpers/setMathHelpers.d.ts.map +1 -1
  31. package/src/mathHelpers/setMathHelpers.js +2 -1
  32. package/src/payment.d.ts +4 -2
  33. package/src/payment.d.ts.map +1 -1
  34. package/src/payment.js +6 -7
  35. package/src/paymentLedger.d.ts +6 -2
  36. package/src/paymentLedger.d.ts.map +1 -1
  37. package/src/paymentLedger.js +71 -90
  38. package/src/purse.d.ts +19 -9
  39. package/src/purse.d.ts.map +1 -1
  40. package/src/purse.js +86 -25
  41. package/src/transientNotifier.d.ts +1 -1
  42. package/src/transientNotifier.d.ts.map +1 -1
  43. package/src/transientNotifier.js +5 -0
  44. package/src/typeGuards.d.ts +41 -9
  45. package/src/typeGuards.d.ts.map +1 -1
  46. package/src/typeGuards.js +38 -43
  47. package/src/types.d.ts +250 -215
  48. package/src/types.d.ts.map +1 -1
  49. package/src/types.js +305 -326
  50. package/CHANGELOG.md +0 -767
  51. package/src/types-ambient.d.ts +0 -376
  52. package/src/types-ambient.d.ts.map +0 -1
  53. package/src/types-ambient.js +0 -440
@@ -2,20 +2,19 @@
2
2
 
3
3
  import { Nat, isNat } from '@endo/nat';
4
4
 
5
- import '../types-ambient.js';
5
+ /** @import {MathHelpers, NatValue} from '../types.js' */
6
6
 
7
7
  const { Fail } = assert;
8
8
  const empty = 0n;
9
9
 
10
10
  /**
11
- * Fungible digital assets use the natMathHelpers to manage balances -
12
- * the operations are merely arithmetic on natural, non-negative
13
- * numbers.
11
+ * Fungible digital assets use the natMathHelpers to manage balances - the
12
+ * operations are merely arithmetic on natural, non-negative numbers.
14
13
  *
15
- * Natural numbers are used for fungible erights such as money because
16
- * rounding issues make floats problematic. All operations should be
17
- * done with the smallest whole unit such that the `natMathHelpers` never
18
- * deals with fractional parts.
14
+ * Natural numbers are used for fungible erights such as money because rounding
15
+ * issues make floats problematic. All operations should be done with the
16
+ * smallest whole unit such that the `natMathHelpers` never deals with
17
+ * fractional parts.
19
18
  *
20
19
  * @type {MathHelpers<NatValue>}
21
20
  */
@@ -3,4 +3,6 @@
3
3
  * @type {MathHelpers<SetValue>}
4
4
  */
5
5
  export const setMathHelpers: MathHelpers<SetValue>;
6
+ import type { SetValue } from '../types.js';
7
+ import type { MathHelpers } from '../types.js';
6
8
  //# sourceMappingURL=setMathHelpers.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"setMathHelpers.d.ts","sourceRoot":"","sources":["setMathHelpers.js"],"names":[],"mappings":"AAkBA;;;GAGG;AACH,6BAFU,qBAAqB,CAkB5B"}
1
+ {"version":3,"file":"setMathHelpers.d.ts","sourceRoot":"","sources":["setMathHelpers.js"],"names":[],"mappings":"AAmBA;;;GAGG;AACH,6BAFU,YAAY,QAAQ,CAAC,CAkB5B;8BA3BsC,aAAa;iCAAb,aAAa"}
@@ -9,7 +9,8 @@ import {
9
9
  coerceToElements,
10
10
  elementsCompare,
11
11
  } from '@agoric/store';
12
- import '../types-ambient.js';
12
+
13
+ /** @import {MathHelpers, SetValue} from '../types.js' */
13
14
 
14
15
  // Operations for arrays with unique objects identifying and providing
15
16
  // information about digital assets. Used for Zoe invites.
package/src/payment.d.ts CHANGED
@@ -1,3 +1,5 @@
1
- export function preparePaymentKind<K extends AssetKind>(issuerBaggage: MapStore<string, unknown>, name: string, brand: Brand<K>, PaymentI: InterfaceGuard): () => Payment<K>;
2
- export type Baggage = import('@agoric/vat-data').Baggage;
1
+ export function preparePaymentKind<K extends AssetKind>(issuerZone: import("@agoric/zone").Zone, name: string, brand: Brand<K>, PaymentI: import("@endo/patterns").InterfaceGuard<any>): () => Payment<K>;
2
+ import type { AssetKind } from './types.js';
3
+ import type { Brand } from './types.js';
4
+ import type { Payment } from './types.js';
3
5
  //# sourceMappingURL=payment.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"payment.d.ts","sourceRoot":"","sources":["payment.js"],"names":[],"mappings":"AAeO,wGALI,MAAM,6BAEN,cAAc,oBAgBxB;sBAvBa,OAAO,kBAAkB,EAAE,OAAO"}
1
+ {"version":3,"file":"payment.d.ts","sourceRoot":"","sources":["payment.js"],"names":[],"mappings":"AAeO,mCAPkB,CAAC,SAAb,SAAW,cACb,OAAO,cAAc,EAAE,IAAI,QAC3B,MAAM,SACN,MAAM,CAAC,CAAC,YACR,OAAO,gBAAgB,EAAE,cAAc,CAAC,GAAG,CAAC,GAC1C,MAAM,QAAQ,CAAC,CAAC,CAc5B;+BAvB4C,YAAY;2BAAZ,YAAY;6BAAZ,YAAY"}
package/src/payment.js CHANGED
@@ -1,21 +1,20 @@
1
1
  // @jessie-check
2
2
 
3
3
  import { initEmpty } from '@agoric/store';
4
- import { prepareExoClass } from '@agoric/vat-data';
5
4
 
6
- /** @typedef {import('@agoric/vat-data').Baggage} Baggage */
5
+ /** @import {AssetKind, Brand, Payment} from './types.js' */
7
6
 
7
+ // TODO Type InterfaceGuard better than InterfaceGuard<any>
8
8
  /**
9
9
  * @template {AssetKind} K
10
- * @param {Baggage} issuerBaggage
10
+ * @param {import('@agoric/zone').Zone} issuerZone
11
11
  * @param {string} name
12
12
  * @param {Brand<K>} brand
13
- * @param {InterfaceGuard} PaymentI
13
+ * @param {import('@endo/patterns').InterfaceGuard<any>} PaymentI
14
14
  * @returns {() => Payment<K>}
15
15
  */
16
- export const preparePaymentKind = (issuerBaggage, name, brand, PaymentI) => {
17
- const makePayment = prepareExoClass(
18
- issuerBaggage,
16
+ export const preparePaymentKind = (issuerZone, name, brand, PaymentI) => {
17
+ const makePayment = issuerZone.exoClass(
19
18
  `${name} payment`,
20
19
  PaymentI,
21
20
  initEmpty,
@@ -1,3 +1,7 @@
1
- export function preparePaymentLedger<K extends AssetKind>(issuerBaggage: MapStore<string, unknown>, name: string, assetKind: K, displayInfo: DisplayInfo<K>, elementShape: Pattern, optShutdownWithFailure?: import("@agoric/swingset-vat").ShutdownWithFailure | undefined): PaymentLedger<K>;
2
- export type Baggage = import('@agoric/vat-data').Baggage;
1
+ export function preparePaymentLedger<K extends AssetKind>(issuerZone: import("@agoric/zone").Zone, name: string, assetKind: K, displayInfo: DisplayInfo<K>, elementShape: Pattern, recoverySetsState: RecoverySetsOption, optShutdownWithFailure?: ShutdownWithFailure | undefined): PaymentLedger<K>;
2
+ import type { AssetKind } from './types.js';
3
+ import type { DisplayInfo } from './types.js';
4
+ import type { RecoverySetsOption } from './types.js';
5
+ import type { ShutdownWithFailure } from '@agoric/swingset-vat';
6
+ import type { PaymentLedger } from './types.js';
3
7
  //# sourceMappingURL=paymentLedger.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"paymentLedger.d.ts","sourceRoot":"","sources":["paymentLedger.js"],"names":[],"mappings":"AAoFO,0GAPI,MAAM,2DAGN,OAAO,6GA+UjB;sBA9Ya,OAAO,kBAAkB,EAAE,OAAO"}
1
+ {"version":3,"file":"paymentLedger.d.ts","sourceRoot":"","sources":["paymentLedger.js"],"names":[],"mappings":"AAqFO,qCAVkB,CAAC,SAAb,SAAW,cACb,OAAO,cAAc,EAAE,IAAI,QAC3B,MAAM,aACN,CAAC,eACD,YAAY,CAAC,CAAC,gBACd,OAAO,qBACP,kBAAkB,6DAEhB,cAAc,CAAC,CAAC,CAyT5B;+BA9XwH,YAAY;iCAAZ,YAAY;wCAAZ,YAAY;yCAC/F,sBAAsB;mCAD6D,YAAY"}
@@ -1,21 +1,21 @@
1
1
  // @jessie-check
2
2
 
3
+ /// <reference types="@agoric/store/exported.js" />
4
+
3
5
  /* eslint-disable no-use-before-define */
4
6
  import { isPromise } from '@endo/promise-kit';
5
7
  import { mustMatch, M, keyEQ } from '@agoric/store';
6
- import {
7
- provideDurableWeakMapStore,
8
- prepareExo,
9
- provide,
10
- } from '@agoric/vat-data';
11
8
  import { AmountMath } from './amountMath.js';
12
9
  import { preparePaymentKind } from './payment.js';
13
10
  import { preparePurseKind } from './purse.js';
14
11
 
15
- import '@agoric/store/exported.js';
16
12
  import { BrandI, makeIssuerInterfaces } from './typeGuards.js';
17
13
 
18
- /** @typedef {import('@agoric/vat-data').Baggage} Baggage */
14
+ /**
15
+ * @import {Amount, AssetKind, DisplayInfo, PaymentLedger, Payment, Brand, RecoverySetsOption, Purse, Issuer, Mint} from './types.js'
16
+ * @import {ShutdownWithFailure} from '@agoric/swingset-vat'
17
+ * @import {Key} from '@endo/patterns';
18
+ */
19
19
 
20
20
  const { details: X, quote: q, Fail } = assert;
21
21
 
@@ -70,29 +70,31 @@ const amountShapeFromElementShape = (brand, assetKind, elementShape) => {
70
70
  };
71
71
 
72
72
  /**
73
- * Make the paymentLedger, the source of truth for the balances of
74
- * payments. All minting and transfer authority originates here.
73
+ * Make the paymentLedger, the source of truth for the balances of payments. All
74
+ * minting and transfer authority originates here.
75
75
  *
76
76
  * @template {AssetKind} K
77
- * @param {Baggage} issuerBaggage
77
+ * @param {import('@agoric/zone').Zone} issuerZone
78
78
  * @param {string} name
79
79
  * @param {K} assetKind
80
80
  * @param {DisplayInfo<K>} displayInfo
81
81
  * @param {Pattern} elementShape
82
+ * @param {RecoverySetsOption} recoverySetsState
82
83
  * @param {ShutdownWithFailure} [optShutdownWithFailure]
83
84
  * @returns {PaymentLedger<K>}
84
85
  */
85
86
  export const preparePaymentLedger = (
86
- issuerBaggage,
87
+ issuerZone,
87
88
  name,
88
89
  assetKind,
89
90
  displayInfo,
90
91
  elementShape,
92
+ recoverySetsState,
91
93
  optShutdownWithFailure = undefined,
92
94
  ) => {
93
95
  /** @type {Brand<K>} */
94
96
  // @ts-expect-error XXX callWhen
95
- const brand = prepareExo(issuerBaggage, `${name} brand`, BrandI, {
97
+ const brand = issuerZone.exo(`${name} brand`, BrandI, {
96
98
  isMyIssuer(allegedIssuer) {
97
99
  // BrandI delays calling this method until `allegedIssuer` is a Remotable
98
100
  return allegedIssuer === issuer;
@@ -121,7 +123,7 @@ export const preparePaymentLedger = (
121
123
  amountShape,
122
124
  );
123
125
 
124
- const makePayment = preparePaymentKind(issuerBaggage, name, brand, PaymentI);
126
+ const makePayment = preparePaymentKind(issuerZone, name, brand, PaymentI);
125
127
 
126
128
  /** @type {ShutdownWithFailure} */
127
129
  const shutdownLedgerWithFailure = reason => {
@@ -139,48 +141,48 @@ export const preparePaymentLedger = (
139
141
  };
140
142
 
141
143
  /** @type {WeakMapStore<Payment, Amount>} */
142
- const paymentLedger = provideDurableWeakMapStore(
143
- issuerBaggage,
144
- 'paymentLedger',
145
- { valueShape: amountShape },
146
- );
144
+ const paymentLedger = issuerZone.weakMapStore('paymentLedger', {
145
+ valueShape: amountShape,
146
+ });
147
147
 
148
148
  /**
149
- * A withdrawn live payment is associated with the recovery set of
150
- * the purse it was withdrawn from. Let's call these "recoverable"
151
- * payments. All recoverable payments are live, but not all live
152
- * payments are recoverable. We do the bookkeeping for payment recovery
153
- * with this weakmap from recoverable payments to the recovery set they are
154
- * in.
155
- * A bunch of interesting invariants here:
156
- * * Every payment that is a key in the outer `paymentRecoverySets`
157
- * weakMap is also in the recovery set indexed by that payment.
158
- * * Implied by the above but worth stating: the payment is only
159
- * in at most one recovery set.
160
- * * A recovery set only contains such payments.
161
- * * Every purse is associated with exactly one recovery set unique to
162
- * it.
163
- * * A purse's recovery set only contains payments withdrawn from
164
- * that purse and not yet consumed.
149
+ * A (non-empty) withdrawn live payment is associated with the recovery set of
150
+ * the purse it was withdrawn from. Let's call these "recoverable" payments.
151
+ * All recoverable payments are live, but not all live payments are
152
+ * recoverable. We do the bookkeeping for payment recovery with this weakmap
153
+ * from recoverable payments to the recovery set they are in. A bunch of
154
+ * interesting invariants here:
155
+ *
156
+ * - Every payment that is a key in the outer `paymentRecoverySets` weakMap is
157
+ * also in the recovery set indexed by that payment.
158
+ * - Implied by the above but worth stating: the payment is only in at most one
159
+ * recovery set.
160
+ * - A recovery set only contains such payments.
161
+ * - Every purse is associated with exactly one recovery set unique to it.
162
+ * - A purse's recovery set only contains payments withdrawn from that purse and
163
+ * not yet consumed.
164
+ *
165
+ * If `recoverySetsState === 'noRecoverySets'`, then nothing should ever be
166
+ * added to this WeakStore.
165
167
  *
166
168
  * @type {WeakMapStore<Payment, SetStore<Payment>>}
167
169
  */
168
- const paymentRecoverySets = provideDurableWeakMapStore(
169
- issuerBaggage,
170
- 'paymentRecoverySets',
171
- );
170
+ const paymentRecoverySets = issuerZone.weakMapStore('paymentRecoverySets');
172
171
 
173
172
  /**
174
173
  * To maintain the invariants listed in the `paymentRecoverySets` comment,
175
- * `initPayment` should contain the only
176
- * call to `paymentLedger.init`.
174
+ * `initPayment` should contain the only call to `paymentLedger.init`.
177
175
  *
178
176
  * @param {Payment} payment
179
177
  * @param {Amount} amount
180
178
  * @param {SetStore<Payment>} [optRecoverySet]
181
179
  */
182
180
  const initPayment = (payment, amount, optRecoverySet = undefined) => {
183
- if (optRecoverySet !== undefined) {
181
+ if (recoverySetsState === 'noRecoverySets') {
182
+ optRecoverySet === undefined ||
183
+ Fail`when recoverSetsState === 'noRecoverySets', optRecoverySet must be empty`;
184
+ }
185
+ if (optRecoverySet !== undefined && !AmountMath.isEmpty(amount)) {
184
186
  optRecoverySet.add(payment);
185
187
  paymentRecoverySets.init(payment, optRecoverySet);
186
188
  }
@@ -189,8 +191,7 @@ export const preparePaymentLedger = (
189
191
 
190
192
  /**
191
193
  * To maintain the invariants listed in the `paymentRecoverySets` comment,
192
- * `deletePayment` should contain the only
193
- * call to `paymentLedger.delete`.
194
+ * `deletePayment` should contain the only call to `paymentLedger.delete`.
194
195
  *
195
196
  * @param {Payment} payment
196
197
  */
@@ -203,19 +204,14 @@ export const preparePaymentLedger = (
203
204
  }
204
205
  };
205
206
 
206
- /** @type {(left: Amount, right: Amount) => Amount } */
207
- const add = (left, right) => AmountMath.add(left, right, brand);
208
- /** @type {(left: Amount, right: Amount) => Amount } */
209
- const subtract = (left, right) => AmountMath.subtract(left, right, brand);
210
207
  /** @type {(allegedAmount: Amount) => Amount} */
211
208
  const coerce = allegedAmount => AmountMath.coerce(brand, allegedAmount);
212
- /** @type {(left: Amount, right: Amount) => boolean } */
209
+ /** @type {(left: Amount, right: Amount) => boolean} */
213
210
 
214
211
  /**
215
- * Methods like deposit() have an optional second parameter
216
- * `optAmountShape`
217
- * which, if present, is supposed to match the balance of the
218
- * payment. This helper function does that check.
212
+ * Methods like deposit() have an optional second parameter `optAmountShape`
213
+ * which, if present, is supposed to match the balance of the payment. This
214
+ * helper function does that check.
219
215
  *
220
216
  * Note: `optAmountShape` is user-supplied with no previous validation.
221
217
  *
@@ -243,17 +239,13 @@ export const preparePaymentLedger = (
243
239
  /**
244
240
  * Used by the purse code to implement purse.deposit
245
241
  *
246
- * @param {Amount} currentBalance - the current balance of the purse
247
- * before a deposit
248
- * @param {(newPurseBalance: Amount) => void} updatePurseBalance -
249
- * commit the purse balance
242
+ * @param {import('./amountStore.js').AmountStore} balanceStore
250
243
  * @param {Payment} srcPayment
251
244
  * @param {Pattern} [optAmountShape]
252
245
  * @returns {Amount}
253
246
  */
254
247
  const depositInternal = (
255
- currentBalance,
256
- updatePurseBalance,
248
+ balanceStore,
257
249
  srcPayment,
258
250
  optAmountShape = undefined,
259
251
  ) => {
@@ -265,13 +257,12 @@ export const preparePaymentLedger = (
265
257
  assertLivePayment(srcPayment);
266
258
  const srcPaymentBalance = paymentLedger.get(srcPayment);
267
259
  assertAmountConsistent(srcPaymentBalance, optAmountShape);
268
- const newPurseBalance = add(srcPaymentBalance, currentBalance);
269
260
  try {
270
261
  // COMMIT POINT
271
262
  // Move the assets in `srcPayment` into this purse, using up the
272
263
  // source payment, such that total assets are conserved.
273
264
  deletePayment(srcPayment);
274
- updatePurseBalance(newPurseBalance);
265
+ balanceStore.increment(srcPaymentBalance);
275
266
  } catch (err) {
276
267
  shutdownLedgerWithFailure(err);
277
268
  throw err;
@@ -282,30 +273,19 @@ export const preparePaymentLedger = (
282
273
  /**
283
274
  * Used by the purse code to implement purse.withdraw
284
275
  *
285
- * @param {Amount} currentBalance - the current balance of the purse
286
- * before a withdrawal
287
- * @param {(newPurseBalance: Amount) => void} updatePurseBalance -
288
- * commit the purse balance
276
+ * @param {import('./amountStore.js').AmountStore} balanceStore
289
277
  * @param {Amount} amount - the amount to be withdrawn
290
- * @param {SetStore<Payment>} recoverySet
278
+ * @param {SetStore<Payment>} [recoverySet]
291
279
  * @returns {Payment}
292
280
  */
293
- const withdrawInternal = (
294
- currentBalance,
295
- updatePurseBalance,
296
- amount,
297
- recoverySet,
298
- ) => {
281
+ const withdrawInternal = (balanceStore, amount, recoverySet = undefined) => {
299
282
  amount = coerce(amount);
300
- AmountMath.isGTE(currentBalance, amount) ||
301
- Fail`Withdrawal of ${amount} failed because the purse only contained ${currentBalance}`;
302
- const newPurseBalance = subtract(currentBalance, amount);
303
-
304
283
  const payment = makePayment();
284
+ // COMMIT POINT Move the withdrawn assets from this purse into
285
+ // payment. Total assets must remain conserved.
286
+ balanceStore.decrement(amount) ||
287
+ Fail`Withdrawal of ${amount} failed because the purse only contained ${balanceStore.getAmount()}`;
305
288
  try {
306
- // COMMIT POINT Move the withdrawn assets from this purse into
307
- // payment. Total assets must remain conserved.
308
- updatePurseBalance(newPurseBalance);
309
289
  initPayment(payment, amount, recoverySet);
310
290
  } catch (err) {
311
291
  shutdownLedgerWithFailure(err);
@@ -314,8 +294,10 @@ export const preparePaymentLedger = (
314
294
  return payment;
315
295
  };
316
296
 
297
+ /** @type {() => Purse<K>} */
298
+ // @ts-expect-error XXX amount kinds
317
299
  const makeEmptyPurse = preparePurseKind(
318
- issuerBaggage,
300
+ issuerZone,
319
301
  name,
320
302
  assetKind,
321
303
  brand,
@@ -324,11 +306,13 @@ export const preparePaymentLedger = (
324
306
  depositInternal,
325
307
  withdrawInternal,
326
308
  }),
309
+ recoverySetsState,
310
+ paymentRecoverySets,
327
311
  );
328
312
 
329
313
  /** @type {Issuer<K>} */
330
- // @ts-expect-error cast due to callWhen discrepancy
331
- const issuer = prepareExo(issuerBaggage, `${name} issuer`, IssuerI, {
314
+ // @ts-expect-error XXX callWhen
315
+ const issuer = issuerZone.exo(`${name} issuer`, IssuerI, {
332
316
  getBrand() {
333
317
  return brand;
334
318
  },
@@ -378,23 +362,20 @@ export const preparePaymentLedger = (
378
362
  /**
379
363
  * Provides for the recovery of newly minted but not-yet-deposited payments.
380
364
  *
381
- * Because the `mintRecoveryPurse` is placed in baggage, even if the
382
- * caller of `makeIssuerKit` drops it on the floor, it can still be
383
- * recovered in an emergency upgrade.
384
- *
385
- * @type {Purse<K>}
365
+ * Because the `mintRecoveryPurse` is placed in baggage, even if the caller of
366
+ * `makeIssuerKit` drops it on the floor, it can still be recovered in an
367
+ * emergency upgrade.
386
368
  */
387
- const mintRecoveryPurse = provide(issuerBaggage, 'mintRecoveryPurse', () =>
388
- makeEmptyPurse(),
369
+ const mintRecoveryPurse = /** @type {Purse<K>} */ (
370
+ issuerZone.makeOnce('mintRecoveryPurse', () => makeEmptyPurse())
389
371
  );
390
372
 
391
373
  /** @type {Mint<K>} */
392
- const mint = prepareExo(issuerBaggage, `${name} mint`, MintI, {
374
+ const mint = issuerZone.exo(`${name} mint`, MintI, {
393
375
  getIssuer() {
394
376
  return issuer;
395
377
  },
396
378
  mintPayment(newAmount) {
397
- // @ts-expect-error checked cast
398
379
  newAmount = coerce(newAmount);
399
380
  mustMatch(newAmount, amountShape, 'minted amount');
400
381
  // `rawPayment` is not associated with any recovery set, and
package/src/purse.d.ts CHANGED
@@ -1,13 +1,23 @@
1
- export function preparePurseKind(issuerBaggage: any, name: any, assetKind: any, brand: any, PurseIKit: any, purseMethods: any): () => {
1
+ export function preparePurseKind(issuerZone: import("@agoric/zone").Zone, name: string, assetKind: AssetKind, brand: Brand, PurseIKit: {
2
+ purse: import("@endo/patterns").InterfaceGuard<any>;
3
+ depositFacet: import("@endo/patterns").InterfaceGuard<any>;
4
+ }, purseMethods: {
5
+ depositInternal: any;
6
+ withdrawInternal: any;
7
+ }, recoverySetsState: RecoverySetsOption, paymentRecoverySets: WeakMapStore<Payment, SetStore<Payment>>): () => import("@endo/exo").Guarded<{
2
8
  deposit(srcPayment: any, optAmountShape?: undefined): any;
3
9
  withdraw(amount: any): any;
4
- getCurrentAmount(): Amount<any>;
5
- getCurrentAmountNotifier(): Notifier<any>;
6
- getAllegedBrand(): any;
7
- getDepositFacet(): {
10
+ getCurrentAmount(): import("./types.js").NatAmount | import("./types.js").CopySetAmount<import("@endo/patterns").Key> | import("./types.js").SetAmount<import("@endo/patterns").Key> | import("./types.js").CopyBagAmount<import("@endo/patterns").Key>;
11
+ getCurrentAmountNotifier(): import("@agoric/notifier").Notifier<any>;
12
+ getAllegedBrand(): Brand;
13
+ getDepositFacet(): import("@endo/exo").Guarded<{
8
14
  receive(...args: any[]): any;
9
- };
10
- getRecoverySet(): CopySet<Payment<AssetKind>>;
11
- recoverAll(): Amount<any>;
12
- };
15
+ }>;
16
+ getRecoverySet(): import("@endo/patterns").CopySet<any>;
17
+ recoverAll(): import("./types.js").NatAmount | import("./types.js").CopySetAmount<import("@endo/patterns").Key> | import("./types.js").SetAmount<import("@endo/patterns").Key> | import("./types.js").CopyBagAmount<import("@endo/patterns").Key>;
18
+ }>;
19
+ import type { AssetKind } from './types.js';
20
+ import type { Brand } from './types.js';
21
+ import type { RecoverySetsOption } from './types.js';
22
+ import type { Payment } from './types.js';
13
23
  //# sourceMappingURL=purse.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"purse.d.ts","sourceRoot":"","sources":["purse.js"],"names":[],"mappings":"AAOO;;;;;;;;;;;EAkHN"}
1
+ {"version":3,"file":"purse.d.ts","sourceRoot":"","sources":["purse.js"],"names":[],"mappings":"AA4BO,6CAfI,OAAO,cAAc,EAAE,IAAI,QAC3B,MAAM,aACN,SAAS,SACT,KAAK,aACL;IACV,KAAS,EAAE,OAAO,gBAAgB,EAAE,cAAc,CAAC,GAAG,CAAC,CAAC;IACxD,YAAgB,EAAE,OAAO,gBAAgB,EAAE,cAAc,CAAC,GAAG,CAAC,CAAC;CAC5D,gBACO;IACV,eAAmB,EAAE,GAAG,CAAC;IACzB,gBAAoB,EAAE,GAAG,CAAC;CACvB,qBACO,kBAAkB,uBAClB,YAAY,CAAC,OAAO,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAC;;;;;;;;;;;GA4JlD;+BAjLwG,YAAY;2BAAZ,YAAY;wCAAZ,YAAY;6BAAZ,YAAY"}
package/src/purse.js CHANGED
@@ -1,27 +1,74 @@
1
- import { M } from '@agoric/store';
2
- import { prepareExoClassKit, makeScalarBigSetStore } from '@agoric/vat-data';
1
+ import { M, makeCopySet } from '@agoric/store';
3
2
  import { AmountMath } from './amountMath.js';
4
3
  import { makeTransientNotifierKit } from './transientNotifier.js';
4
+ import { makeAmountStore } from './amountStore.js';
5
+
6
+ /** @import {Amount, AssetKind, AmountValue, AssetKindForValue, RecoverySetsOption, Brand, Payment} from './types.js' */
5
7
 
6
8
  const { Fail } = assert;
7
9
 
10
+ const EMPTY_COPY_SET = makeCopySet([]);
11
+
12
+ // TODO Type InterfaceGuard better than InterfaceGuard<any>
13
+ /**
14
+ * @param {import('@agoric/zone').Zone} issuerZone
15
+ * @param {string} name
16
+ * @param {AssetKind} assetKind
17
+ * @param {Brand} brand
18
+ * @param {{
19
+ * purse: import('@endo/patterns').InterfaceGuard<any>;
20
+ * depositFacet: import('@endo/patterns').InterfaceGuard<any>;
21
+ * }} PurseIKit
22
+ * @param {{
23
+ * depositInternal: any;
24
+ * withdrawInternal: any;
25
+ * }} purseMethods
26
+ * @param {RecoverySetsOption} recoverySetsState
27
+ * @param {WeakMapStore<Payment, SetStore<Payment>>} paymentRecoverySets
28
+ */
8
29
  export const preparePurseKind = (
9
- issuerBaggage,
30
+ issuerZone,
10
31
  name,
11
32
  assetKind,
12
33
  brand,
13
34
  PurseIKit,
14
35
  purseMethods,
36
+ recoverySetsState,
37
+ paymentRecoverySets,
15
38
  ) => {
16
39
  const amountShape = brand.getAmountShape();
17
40
 
18
41
  // Note: Virtual for high cardinality, but *not* durable, and so
19
42
  // broken across an upgrade.
43
+ // TODO propagate zonifying to notifiers, maybe?
20
44
  const { provideNotifier, update: updateBalance } = makeTransientNotifierKit();
21
45
 
22
- const updatePurseBalance = (state, newPurseBalance, purse) => {
23
- state.currentBalance = newPurseBalance;
24
- updateBalance(purse, purse.getCurrentAmount());
46
+ /**
47
+ * If `recoverySetsState === 'hasRecoverySets'` (the normal state), then just
48
+ * return `state.recoverySet`.
49
+ *
50
+ * If `recoverySetsState === 'noRecoverySets'`, return `undefined`. Callers
51
+ * must be aware that the `undefined` return happens iff `recoverySetsState
52
+ * === 'noRecoverySets'`, and to avoid storing or retrieving anything from the
53
+ * actual recovery set.
54
+ *
55
+ * @param {{ recoverySet: SetStore<Payment> }} state
56
+ * @returns {SetStore<Payment> | undefined}
57
+ */
58
+ const maybeRecoverySet = state => {
59
+ const { recoverySet } = state;
60
+ if (recoverySetsState === 'hasRecoverySets') {
61
+ return recoverySet;
62
+ } else {
63
+ recoverySetsState === 'noRecoverySets' ||
64
+ Fail`recoverSetsState must be noRecoverySets if it isn't hasRecoverSets`;
65
+ paymentRecoverySets !== undefined ||
66
+ Fail`paymentRecoverySets must always be defined`;
67
+ recoverySet.getSize() === 0 ||
68
+ Fail`With noRecoverySets, recoverySet must be empty`;
69
+
70
+ return undefined;
71
+ }
25
72
  };
26
73
 
27
74
  // - This kind is a pair of purse and depositFacet that have a 1:1
@@ -31,17 +78,14 @@ export const preparePurseKind = (
31
78
  // that created depositFacet as needed. But this approach ensures a constant
32
79
  // identity for the facet and exercises the multi-faceted object style.
33
80
  const { depositInternal, withdrawInternal } = purseMethods;
34
- const makePurseKit = prepareExoClassKit(
35
- issuerBaggage,
81
+ const makePurseKit = issuerZone.exoClassKit(
36
82
  `${name} Purse`,
37
83
  PurseIKit,
38
84
  () => {
39
85
  const currentBalance = AmountMath.makeEmpty(brand, assetKind);
40
86
 
41
87
  /** @type {SetStore<Payment>} */
42
- const recoverySet = makeScalarBigSetStore('recovery set', {
43
- durable: true,
44
- });
88
+ const recoverySet = issuerZone.detached().setStore('recovery set');
45
89
 
46
90
  return {
47
91
  currentBalance,
@@ -54,28 +98,36 @@ export const preparePurseKind = (
54
98
  // PurseI does *not* delay `deposit` until `srcPayment` is fulfulled.
55
99
  // See the comments on PurseI.deposit in typeGuards.js
56
100
  const { state } = this;
101
+ const { purse } = this.facets;
102
+ const balanceStore = makeAmountStore(state, 'currentBalance');
57
103
  // Note COMMIT POINT within deposit.
58
- return depositInternal(
59
- state.currentBalance,
60
- newPurseBalance =>
61
- updatePurseBalance(state, newPurseBalance, this.facets.purse),
104
+ const srcPaymentBalance = depositInternal(
105
+ balanceStore,
62
106
  srcPayment,
63
107
  optAmountShape,
64
108
  );
109
+ updateBalance(purse, balanceStore.getAmount());
110
+ return srcPaymentBalance;
65
111
  },
66
112
  withdraw(amount) {
67
113
  const { state } = this;
114
+ const { purse } = this.facets;
115
+
116
+ const optRecoverySet = maybeRecoverySet(state);
117
+ const balanceStore = makeAmountStore(state, 'currentBalance');
68
118
  // Note COMMIT POINT within withdraw.
69
- return withdrawInternal(
70
- state.currentBalance,
71
- newPurseBalance =>
72
- updatePurseBalance(state, newPurseBalance, this.facets.purse),
119
+ const payment = withdrawInternal(
120
+ balanceStore,
73
121
  amount,
74
- state.recoverySet,
122
+ optRecoverySet,
75
123
  );
124
+ updateBalance(purse, balanceStore.getAmount());
125
+ return payment;
76
126
  },
77
127
  getCurrentAmount() {
78
- return this.state.currentBalance;
128
+ const { state } = this;
129
+ const balanceStore = makeAmountStore(state, 'currentBalance');
130
+ return balanceStore.getAmount();
79
131
  },
80
132
  getCurrentAmountNotifier() {
81
133
  return provideNotifier(this.facets.purse);
@@ -83,24 +135,33 @@ export const preparePurseKind = (
83
135
  getAllegedBrand() {
84
136
  return brand;
85
137
  },
86
- // eslint-disable-next-line no-use-before-define
138
+
87
139
  getDepositFacet() {
88
140
  return this.facets.depositFacet;
89
141
  },
90
142
 
91
143
  getRecoverySet() {
92
- return this.state.recoverySet.snapshot();
144
+ const { state } = this;
145
+ const optRecoverySet = maybeRecoverySet(state);
146
+ if (optRecoverySet === undefined) {
147
+ return EMPTY_COPY_SET;
148
+ }
149
+ return optRecoverySet.snapshot();
93
150
  },
94
151
  recoverAll() {
95
152
  const { state, facets } = this;
96
153
  let amount = AmountMath.makeEmpty(brand, assetKind);
97
- for (const payment of state.recoverySet.keys()) {
154
+ const optRecoverySet = maybeRecoverySet(state);
155
+ if (optRecoverySet === undefined) {
156
+ return amount; // empty at this time
157
+ }
158
+ for (const payment of optRecoverySet.keys()) {
98
159
  // This does cause deletions from the set while iterating,
99
160
  // but this special case is allowed.
100
161
  const delta = facets.purse.deposit(payment);
101
162
  amount = AmountMath.add(amount, delta, brand);
102
163
  }
103
- state.recoverySet.getSize() === 0 ||
164
+ optRecoverySet.getSize() === 0 ||
104
165
  Fail`internal: Remaining unrecovered payments: ${facets.purse.getRecoverySet()}`;
105
166
  return amount;
106
167
  },
@@ -1,5 +1,5 @@
1
1
  export function makeTransientNotifierKit(): {
2
- provideNotifier: (key: any) => Notifier<any>;
2
+ provideNotifier: (key: any) => import("@agoric/notifier").Notifier<any>;
3
3
  update: (key: any, newValue: any) => void;
4
4
  };
5
5
  //# sourceMappingURL=transientNotifier.d.ts.map