@agoric/ertp 0.16.3-u14.0 → 0.16.3-u16.1
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/exported.d.ts +37 -0
- package/exported.js +2 -1
- package/package.json +35 -26
- package/src/amountMath.d.ts +44 -31
- package/src/amountMath.d.ts.map +1 -1
- package/src/amountMath.js +130 -120
- package/src/amountStore.d.ts +9 -0
- package/src/amountStore.d.ts.map +1 -0
- package/src/amountStore.js +34 -0
- package/src/displayInfo.d.ts +3 -0
- package/src/displayInfo.d.ts.map +1 -1
- package/src/displayInfo.js +2 -0
- package/src/index.js +8 -0
- package/src/issuerKit.d.ts +30 -6
- package/src/issuerKit.d.ts.map +1 -1
- package/src/issuerKit.js +218 -76
- package/src/legacy-payment-helpers.d.ts +6 -1
- package/src/legacy-payment-helpers.d.ts.map +1 -1
- package/src/legacy-payment-helpers.js +33 -32
- package/src/mathHelpers/copyBagMathHelpers.d.ts +3 -4
- package/src/mathHelpers/copyBagMathHelpers.d.ts.map +1 -1
- package/src/mathHelpers/copyBagMathHelpers.js +4 -5
- package/src/mathHelpers/copySetMathHelpers.d.ts +3 -3
- package/src/mathHelpers/copySetMathHelpers.d.ts.map +1 -1
- package/src/mathHelpers/copySetMathHelpers.js +6 -4
- package/src/mathHelpers/natMathHelpers.d.ts +8 -7
- package/src/mathHelpers/natMathHelpers.d.ts.map +1 -1
- package/src/mathHelpers/natMathHelpers.js +7 -8
- package/src/mathHelpers/setMathHelpers.d.ts +2 -0
- package/src/mathHelpers/setMathHelpers.d.ts.map +1 -1
- package/src/mathHelpers/setMathHelpers.js +2 -1
- package/src/payment.d.ts +4 -2
- package/src/payment.d.ts.map +1 -1
- package/src/payment.js +6 -7
- package/src/paymentLedger.d.ts +6 -2
- package/src/paymentLedger.d.ts.map +1 -1
- package/src/paymentLedger.js +71 -90
- package/src/purse.d.ts +19 -9
- package/src/purse.d.ts.map +1 -1
- package/src/purse.js +86 -25
- package/src/transientNotifier.d.ts +1 -1
- package/src/transientNotifier.d.ts.map +1 -1
- package/src/transientNotifier.js +5 -0
- package/src/typeGuards.d.ts +41 -9
- package/src/typeGuards.d.ts.map +1 -1
- package/src/typeGuards.js +38 -43
- package/src/types.d.ts +250 -215
- package/src/types.d.ts.map +1 -1
- package/src/types.js +305 -326
- package/CHANGELOG.md +0 -775
- package/src/types-ambient.d.ts +0 -376
- package/src/types-ambient.d.ts.map +0 -1
- 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
|
|
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
|
-
*
|
|
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
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
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
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"setMathHelpers.d.ts","sourceRoot":"","sources":["setMathHelpers.js"],"names":[],"mappings":"
|
|
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
|
-
|
|
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>(
|
|
2
|
-
|
|
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
|
package/src/payment.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"payment.d.ts","sourceRoot":"","sources":["payment.js"],"names":[],"mappings":"AAeO,
|
|
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
|
-
/** @
|
|
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 {
|
|
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 = (
|
|
17
|
-
const makePayment =
|
|
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,
|
package/src/paymentLedger.d.ts
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
-
export function preparePaymentLedger<K extends AssetKind>(
|
|
2
|
-
|
|
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":"
|
|
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"}
|
package/src/paymentLedger.js
CHANGED
|
@@ -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
|
-
/**
|
|
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
|
-
*
|
|
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 {
|
|
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
|
-
|
|
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 =
|
|
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(
|
|
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 =
|
|
143
|
-
|
|
144
|
-
|
|
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
|
-
*
|
|
152
|
-
*
|
|
153
|
-
*
|
|
154
|
-
*
|
|
155
|
-
*
|
|
156
|
-
*
|
|
157
|
-
*
|
|
158
|
-
*
|
|
159
|
-
*
|
|
160
|
-
*
|
|
161
|
-
*
|
|
162
|
-
*
|
|
163
|
-
*
|
|
164
|
-
*
|
|
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 =
|
|
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 (
|
|
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
|
-
*
|
|
217
|
-
*
|
|
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 {
|
|
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
|
-
|
|
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
|
-
|
|
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 {
|
|
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
|
-
|
|
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
|
|
331
|
-
const issuer =
|
|
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
|
-
*
|
|
383
|
-
*
|
|
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 =
|
|
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 =
|
|
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(
|
|
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():
|
|
5
|
-
getCurrentAmountNotifier(): Notifier<any>;
|
|
6
|
-
getAllegedBrand():
|
|
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<
|
|
11
|
-
recoverAll():
|
|
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
|
package/src/purse.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"purse.d.ts","sourceRoot":"","sources":["purse.js"],"names":[],"mappings":"
|
|
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
|
-
|
|
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
|
-
|
|
23
|
-
|
|
24
|
-
|
|
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 =
|
|
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 =
|
|
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
|
-
|
|
59
|
-
|
|
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
|
-
|
|
70
|
-
|
|
71
|
-
newPurseBalance =>
|
|
72
|
-
updatePurseBalance(state, newPurseBalance, this.facets.purse),
|
|
119
|
+
const payment = withdrawInternal(
|
|
120
|
+
balanceStore,
|
|
73
121
|
amount,
|
|
74
|
-
|
|
122
|
+
optRecoverySet,
|
|
75
123
|
);
|
|
124
|
+
updateBalance(purse, balanceStore.getAmount());
|
|
125
|
+
return payment;
|
|
76
126
|
},
|
|
77
127
|
getCurrentAmount() {
|
|
78
|
-
|
|
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
|
-
|
|
138
|
+
|
|
87
139
|
getDepositFacet() {
|
|
88
140
|
return this.facets.depositFacet;
|
|
89
141
|
},
|
|
90
142
|
|
|
91
143
|
getRecoverySet() {
|
|
92
|
-
|
|
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
|
-
|
|
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
|
-
|
|
164
|
+
optRecoverySet.getSize() === 0 ||
|
|
104
165
|
Fail`internal: Remaining unrecovered payments: ${facets.purse.getRecoverySet()}`;
|
|
105
166
|
return amount;
|
|
106
167
|
},
|