@agoric/inter-protocol 0.16.2-other-dev-8f8782b.0 → 0.16.2-other-dev-fbe72e7.0.fbe72e7

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 (166) hide show
  1. package/README.md +6 -6
  2. package/package.json +46 -39
  3. package/scripts/build-bundles.js +5 -21
  4. package/src/auction/auctionBook.d.ts +147 -0
  5. package/src/auction/auctionBook.d.ts.map +1 -0
  6. package/src/auction/auctionBook.js +182 -151
  7. package/src/auction/auctionMath.d.ts +17 -0
  8. package/src/auction/auctionMath.d.ts.map +1 -0
  9. package/src/auction/auctionMath.js +81 -0
  10. package/src/auction/auctioneer.d.ts +70 -0
  11. package/src/auction/auctioneer.d.ts.map +1 -0
  12. package/src/auction/auctioneer.js +72 -59
  13. package/src/auction/offerBook.d.ts +46 -0
  14. package/src/auction/offerBook.d.ts.map +1 -0
  15. package/src/auction/offerBook.js +17 -12
  16. package/src/auction/params.d.ts +145 -0
  17. package/src/auction/params.d.ts.map +1 -0
  18. package/src/auction/params.js +11 -9
  19. package/src/auction/scheduleMath.d.ts +5 -0
  20. package/src/auction/scheduleMath.d.ts.map +1 -0
  21. package/src/auction/scheduleMath.js +18 -16
  22. package/src/auction/scheduler.d.ts +50 -0
  23. package/src/auction/scheduler.d.ts.map +1 -0
  24. package/src/auction/scheduler.js +53 -47
  25. package/src/auction/sortedOffers.d.ts +8 -0
  26. package/src/auction/sortedOffers.d.ts.map +1 -0
  27. package/src/auction/sortedOffers.js +10 -9
  28. package/src/auction/util.d.ts +31 -0
  29. package/src/auction/util.d.ts.map +1 -0
  30. package/src/auction/util.js +12 -6
  31. package/src/clientSupport.d.ts +168 -0
  32. package/src/clientSupport.d.ts.map +1 -0
  33. package/src/clientSupport.js +161 -98
  34. package/src/collectFees.d.ts +2 -0
  35. package/src/collectFees.d.ts.map +1 -0
  36. package/src/contractSupport.d.ts +28 -0
  37. package/src/contractSupport.d.ts.map +1 -0
  38. package/src/contractSupport.js +19 -13
  39. package/src/econCommitteeCharter.d.ts +43 -0
  40. package/src/econCommitteeCharter.d.ts.map +1 -0
  41. package/src/econCommitteeCharter.js +25 -20
  42. package/src/feeDistributor.d.ts +224 -0
  43. package/src/feeDistributor.d.ts.map +1 -0
  44. package/src/feeDistributor.js +41 -33
  45. package/src/index.d.ts +2 -0
  46. package/src/index.d.ts.map +1 -0
  47. package/src/index.js +1 -0
  48. package/src/interest-math.d.ts +4 -0
  49. package/src/interest-math.d.ts.map +1 -0
  50. package/src/interest-math.js +5 -1
  51. package/src/interest.d.ts +30 -0
  52. package/src/interest.d.ts.map +1 -0
  53. package/src/interest.js +25 -23
  54. package/src/price/README.md +14 -1
  55. package/src/price/fluxAggregatorContract.d.ts +71 -0
  56. package/src/price/fluxAggregatorContract.d.ts.map +1 -0
  57. package/src/price/fluxAggregatorContract.js +64 -55
  58. package/src/price/fluxAggregatorKit.d.ts +104 -0
  59. package/src/price/fluxAggregatorKit.d.ts.map +1 -0
  60. package/src/price/fluxAggregatorKit.js +55 -42
  61. package/src/price/priceOracleKit.d.ts +39 -0
  62. package/src/price/priceOracleKit.d.ts.map +1 -0
  63. package/src/price/priceOracleKit.js +17 -15
  64. package/src/price/roundsManager.d.ts +204 -0
  65. package/src/price/roundsManager.d.ts.map +1 -0
  66. package/src/price/roundsManager.js +132 -85
  67. package/src/proposals/README.md +2 -3
  68. package/src/proposals/add-auction.js +285 -0
  69. package/src/proposals/addAssetToVault.js +192 -40
  70. package/src/proposals/committee-proposal.js +25 -31
  71. package/src/proposals/core-proposal.js +9 -11
  72. package/src/proposals/deploy-price-feeds.js +341 -0
  73. package/src/proposals/econ-behaviors.js +84 -49
  74. package/src/proposals/price-feed-proposal.js +109 -51
  75. package/src/proposals/replace-fee-distributor.js +198 -0
  76. package/src/proposals/replace-scaledPriceAuthorities.js +124 -0
  77. package/src/proposals/replaceElectorate.js +610 -0
  78. package/src/proposals/startEconCommittee.js +2 -2
  79. package/src/proposals/startPSM.js +44 -29
  80. package/src/proposals/upgrade-scaledPriceAuthorities.js +78 -0
  81. package/src/proposals/upgrade-vaults.js +207 -0
  82. package/src/proposals/utils.d.ts +21 -0
  83. package/src/proposals/utils.d.ts.map +1 -0
  84. package/src/proposals/utils.js +66 -9
  85. package/src/proposals/withdraw-reserve-proposal.js +63 -0
  86. package/src/provisionPool.d.ts +69 -0
  87. package/src/provisionPool.d.ts.map +1 -0
  88. package/src/provisionPool.js +138 -0
  89. package/src/provisionPoolKit.d.ts +129 -0
  90. package/src/provisionPoolKit.d.ts.map +1 -0
  91. package/src/provisionPoolKit.js +608 -0
  92. package/src/psm/psm.d.ts +133 -0
  93. package/src/psm/psm.d.ts.map +1 -0
  94. package/src/psm/psm.js +85 -79
  95. package/src/psm/types-ambient.d.ts +2 -0
  96. package/src/psm/types-ambient.d.ts.map +1 -0
  97. package/src/psm/types-ambient.js +3 -0
  98. package/src/reserve/assetReserve.d.ts +58 -0
  99. package/src/reserve/assetReserve.d.ts.map +1 -0
  100. package/src/reserve/assetReserve.js +42 -34
  101. package/src/reserve/assetReserveKit.d.ts +103 -0
  102. package/src/reserve/assetReserveKit.d.ts.map +1 -0
  103. package/src/reserve/assetReserveKit.js +134 -32
  104. package/src/reserve/params.d.ts +16 -0
  105. package/src/reserve/params.d.ts.map +1 -0
  106. package/src/reserve/params.js +8 -2
  107. package/src/tokens.d.ts +3 -0
  108. package/src/tokens.d.ts.map +1 -0
  109. package/src/tokens.js +5 -0
  110. package/src/vaultFactory/burn.d.ts +2 -0
  111. package/src/vaultFactory/burn.d.ts.map +1 -0
  112. package/src/vaultFactory/burn.js +1 -1
  113. package/src/vaultFactory/liquidation.d.ts +25 -0
  114. package/src/vaultFactory/liquidation.d.ts.map +1 -0
  115. package/src/vaultFactory/liquidation.js +37 -24
  116. package/src/vaultFactory/math.d.ts +11 -0
  117. package/src/vaultFactory/math.d.ts.map +1 -0
  118. package/src/vaultFactory/math.js +11 -10
  119. package/src/vaultFactory/orderedVaultStore.d.ts +94 -0
  120. package/src/vaultFactory/orderedVaultStore.d.ts.map +1 -0
  121. package/src/vaultFactory/orderedVaultStore.js +9 -10
  122. package/src/vaultFactory/params.d.ts +143 -0
  123. package/src/vaultFactory/params.d.ts.map +1 -0
  124. package/src/vaultFactory/params.js +56 -25
  125. package/src/vaultFactory/prioritizedVaults.d.ts +280 -0
  126. package/src/vaultFactory/prioritizedVaults.d.ts.map +1 -0
  127. package/src/vaultFactory/prioritizedVaults.js +7 -4
  128. package/src/vaultFactory/proceeds.d.ts +35 -0
  129. package/src/vaultFactory/proceeds.d.ts.map +1 -0
  130. package/src/vaultFactory/proceeds.js +26 -18
  131. package/src/vaultFactory/storeUtils.d.ts +25 -0
  132. package/src/vaultFactory/storeUtils.d.ts.map +1 -0
  133. package/src/vaultFactory/storeUtils.js +10 -12
  134. package/src/vaultFactory/types-ambient.d.ts +137 -0
  135. package/src/vaultFactory/types-ambient.d.ts.map +1 -0
  136. package/src/vaultFactory/{types.js → types-ambient.js} +47 -44
  137. package/src/vaultFactory/vault.d.ts +344 -0
  138. package/src/vaultFactory/vault.d.ts.map +1 -0
  139. package/src/vaultFactory/vault.js +107 -100
  140. package/src/vaultFactory/vaultDirector.d.ts +347 -0
  141. package/src/vaultFactory/vaultDirector.d.ts.map +1 -0
  142. package/src/vaultFactory/vaultDirector.js +94 -64
  143. package/src/vaultFactory/vaultFactory.d.ts +250 -0
  144. package/src/vaultFactory/vaultFactory.d.ts.map +1 -0
  145. package/src/vaultFactory/vaultFactory.js +56 -33
  146. package/src/vaultFactory/vaultHolder.d.ts +170 -0
  147. package/src/vaultFactory/vaultHolder.d.ts.map +1 -0
  148. package/src/vaultFactory/vaultHolder.js +14 -15
  149. package/src/vaultFactory/vaultKit.d.ts +33 -0
  150. package/src/vaultFactory/vaultKit.d.ts.map +1 -0
  151. package/src/vaultFactory/vaultKit.js +9 -4
  152. package/src/vaultFactory/vaultManager.d.ts +676 -0
  153. package/src/vaultFactory/vaultManager.d.ts.map +1 -0
  154. package/src/vaultFactory/vaultManager.js +286 -167
  155. package/CHANGELOG.md +0 -1041
  156. package/exported.js +0 -2
  157. package/scripts/add-collateral-core.js +0 -112
  158. package/scripts/deploy-contracts.js +0 -100
  159. package/scripts/init-core.js +0 -198
  160. package/scripts/invite-committee-core.js +0 -42
  161. package/scripts/manual-price-feed.js +0 -117
  162. package/scripts/price-feed-core.js +0 -104
  163. package/scripts/start-local-chain.sh +0 -84
  164. package/src/psm/types.js +0 -3
  165. package/src/typeGuards.js +0 -13
  166. package/src/vaultFactory/type-imports.js +0 -4
@@ -0,0 +1,608 @@
1
+ // @ts-check
2
+ import { X, q, Fail } from '@endo/errors';
3
+ import { E } from '@endo/far';
4
+
5
+ import { AmountMath, BrandShape } from '@agoric/ertp';
6
+ import { deeplyFulfilledObject, makeTracer } from '@agoric/internal';
7
+ import { UnguardedHelperI } from '@agoric/internal/src/typeGuards.js';
8
+ import {
9
+ observeIteration,
10
+ observeNotifier,
11
+ subscribeEach,
12
+ } from '@agoric/notifier';
13
+ import {
14
+ M,
15
+ makeScalarBigMapStore,
16
+ makeScalarBigSetStore,
17
+ } from '@agoric/vat-data';
18
+ import { makeAtomicProvider, makeScalarMapStore } from '@agoric/store';
19
+ import { PowerFlags } from '@agoric/vats/src/walletFlags.js';
20
+ import {
21
+ PublicTopicShape,
22
+ makeRecorderTopic,
23
+ } from '@agoric/zoe/src/contractSupport/topics.js';
24
+ import { InstanceHandleShape } from '@agoric/zoe/src/typeGuards.js';
25
+ import { isUpgradeDisconnection } from '@agoric/internal/src/upgrade-api.js';
26
+
27
+ /**
28
+ * @import {EReturn} from '@endo/far';
29
+ * @import {BridgeMessage} from '@agoric/cosmic-swingset/src/types.js';
30
+ * @import {Amount, Brand, Payment, Purse} from '@agoric/ertp';
31
+ * @import {StorageNode} from '@agoric/internal/src/lib-chainStorage.js';
32
+ * @import {ZCF} from '@agoric/zoe';
33
+ * @import {ERef} from '@endo/far'
34
+ * @import {Bank, BankManager} from '@agoric/vats/src/vat-bank.js'
35
+ * @import {MapStore, SetStore} from '@agoric/store';
36
+ */
37
+
38
+ const trace = makeTracer('ProvPool');
39
+
40
+ const FIRST_UPPER_KEYWORD = /^[A-Z][a-zA-Z0-9_$]*$/;
41
+ // see https://github.com/Agoric/agoric-sdk/issues/8238
42
+ const FIRST_LOWER_NEAR_KEYWORD = /^[a-z][a-zA-Z0-9_$]*$/;
43
+
44
+ // XXX when inferred, error TS2742: cannot be named without a reference to '../../../node_modules/@endo/exo/src/get-interface.js'. This is likely not portable. A type annotation is necessary.
45
+ /**
46
+ * @typedef {{
47
+ * machine: any;
48
+ * helper: any;
49
+ * forHandler: any;
50
+ * public: any;
51
+ * }} ProvisionPoolKit
52
+ */
53
+
54
+ /**
55
+ * @typedef {import('@agoric/zoe/src/zoeService/utils.js').Instance<
56
+ * import('@agoric/inter-protocol/src/psm/psm.js').start
57
+ * >} PsmInstance
58
+ */
59
+
60
+ /**
61
+ * @typedef {object} ProvisionPoolKitReferences
62
+ * @property {ERef<BankManager>} bankManager
63
+ * @property {ERef<import('@agoric/vats').NameAdmin>} namesByAddressAdmin
64
+ * @property {ERef<
65
+ * import('@agoric/vats/src/core/startWalletFactory.js').WalletFactoryStartResult['creatorFacet']
66
+ * >} walletFactory
67
+ */
68
+
69
+ /**
70
+ * @typedef {object} MetricsNotification Metrics naming scheme is that nouns are
71
+ * present values and past-participles are accumulative.
72
+ * @property {bigint} walletsProvisioned count of new wallets provisioned
73
+ * @property {Amount<'nat'>} totalMintedProvided running sum of Minted provided
74
+ * to new wallets
75
+ * @property {Amount<'nat'>} totalMintedConverted running sum of Minted ever
76
+ * received by the contract from PSM
77
+ */
78
+
79
+ /**
80
+ * Given attenuated access to the funding purse, handle requests to provision
81
+ * smart wallets.
82
+ *
83
+ * @param {import('@agoric/zone').Zone} zone
84
+ */
85
+ export const prepareBridgeProvisionTool = zone =>
86
+ zone.exoClass(
87
+ 'smartWalletProvisioningHandler',
88
+ M.interface('ProvisionBridgeHandlerMaker', {
89
+ fromBridge: M.callWhen(M.record()).returns(),
90
+ }),
91
+ /**
92
+ * @param {ERef<BankManager>} bankManager
93
+ * @param {ERef<
94
+ * EReturn<
95
+ * import('@agoric/smart-wallet/src/walletFactory.js').start
96
+ * >['creatorFacet']
97
+ * >} walletFactory
98
+ * @param {ERef<import('@agoric/vats').NameAdmin>} namesByAddressAdmin
99
+ * @param {ProvisionPoolKit['forHandler']} forHandler
100
+ */
101
+ (bankManager, walletFactory, namesByAddressAdmin, forHandler) => ({
102
+ bankManager,
103
+ walletFactory,
104
+ namesByAddressAdmin,
105
+ forHandler,
106
+ }),
107
+ {
108
+ /** @param {BridgeMessage} obj */
109
+ async fromBridge(obj) {
110
+ if (obj.type !== 'PLEASE_PROVISION')
111
+ throw Fail`Unrecognized request ${obj.type}`;
112
+ trace('PLEASE_PROVISION', obj);
113
+ const { address, powerFlags } = obj;
114
+ // XXX expects powerFlags to be an array, but if it's a string then
115
+ // this allows a string that has 'SMART_WALLET' in it.
116
+ powerFlags.includes(PowerFlags.SMART_WALLET) ||
117
+ Fail`missing SMART_WALLET in powerFlags`;
118
+
119
+ const { bankManager, walletFactory, namesByAddressAdmin, forHandler } =
120
+ this.state;
121
+
122
+ const bank = E(bankManager).getBankForAddress(address);
123
+ // only proceed if we can provide funds
124
+ await forHandler.sendInitialPayment(bank);
125
+
126
+ const [_, created] = await E(walletFactory).provideSmartWallet(
127
+ address,
128
+ bank,
129
+ namesByAddressAdmin,
130
+ );
131
+ if (created) {
132
+ forHandler.onProvisioned();
133
+ }
134
+ trace(created ? 'provisioned' : 're-provisioned', address);
135
+ },
136
+ },
137
+ );
138
+
139
+ /**
140
+ * @param {import('@agoric/zone').Zone} zone
141
+ * @param {{
142
+ * makeRecorderKit: import('@agoric/zoe/src/contractSupport/recorder.js').MakeRecorderKit;
143
+ * params: any;
144
+ * poolBank: import('@endo/far').ERef<Bank>;
145
+ * zcf: ZCF;
146
+ * makeBridgeProvisionTool: ReturnType<typeof prepareBridgeProvisionTool>;
147
+ * }} powers
148
+ */
149
+ export const prepareProvisionPoolKit = (
150
+ zone,
151
+ { makeRecorderKit, params, poolBank, zcf, makeBridgeProvisionTool },
152
+ ) => {
153
+ const zoe = zcf.getZoeService();
154
+ const ephemeralPurses = makeScalarMapStore('fundingPurseForBrand');
155
+ const purseProvider = makeAtomicProvider(ephemeralPurses);
156
+ const getFundingPurseForBrand = async poolBrand => {
157
+ await null;
158
+ try {
159
+ const purse = await purseProvider.provideAsync(poolBrand, brand =>
160
+ E(poolBank).getPurse(brand),
161
+ );
162
+ return purse;
163
+ } catch (err) {
164
+ trace(`🚨 could not get purse for brand ${poolBrand}`, err);
165
+ throw err;
166
+ }
167
+ };
168
+
169
+ const makeProvisionPoolKitInternal = zone.exoClassKit(
170
+ 'ProvisionPoolKit',
171
+ {
172
+ machine: M.interface('ProvisionPoolKit machine', {
173
+ addRevivableAddresses: M.call(M.arrayOf(M.string())).returns(),
174
+ getWalletReviver: M.call().returns(
175
+ M.remotable('ProvisionPoolKit wallet reviver'),
176
+ ),
177
+ setReferences: M.callWhen({
178
+ bankManager: M.eref(M.remotable('bankManager')),
179
+ namesByAddressAdmin: M.eref(M.remotable('nameAdmin')),
180
+ walletFactory: M.eref(M.remotable('walletFactory')),
181
+ }).returns(),
182
+ makeHandler: M.call().returns(M.remotable('BridgeHandler')),
183
+ initPSM: M.call(BrandShape, InstanceHandleShape).returns(),
184
+ }),
185
+ walletReviver: M.interface('ProvisionPoolKit wallet reviver', {
186
+ reviveWallet: M.callWhen(M.string()).returns(
187
+ M.remotable('SmartWallet'),
188
+ ),
189
+ ackWallet: M.call(M.string()).returns(M.boolean()),
190
+ }),
191
+ helper: UnguardedHelperI,
192
+ forHandler: UnguardedHelperI,
193
+ public: M.interface('ProvisionPoolKit public', {
194
+ getPublicTopics: M.call().returns({ metrics: PublicTopicShape }),
195
+ }),
196
+ },
197
+ /**
198
+ * @param {object} opts
199
+ * @param {Purse<'nat'>} [opts.fundPurse]
200
+ * @param {Brand<'nat'>} opts.poolBrand
201
+ * @param {StorageNode} opts.metricsNode
202
+ */
203
+ ({ fundPurse, poolBrand, metricsNode }) => {
204
+ /** @type {import('@agoric/zoe/src/contractSupport/recorder.js').RecorderKit<MetricsNotification>} */
205
+ const metricsRecorderKit = makeRecorderKit(metricsNode);
206
+
207
+ /** @type {MapStore<ERef<Brand>, PsmInstance>} */
208
+ const brandToPSM = makeScalarBigMapStore('brandToPSM', { durable: true });
209
+ const revivableAddresses = makeScalarBigSetStore('revivableAddresses', {
210
+ durable: true,
211
+ keyShape: M.string(),
212
+ });
213
+
214
+ /**
215
+ * to be set by `setReferences`
216
+ *
217
+ * @type {Partial<ProvisionPoolKitReferences>}
218
+ */
219
+ const references = {
220
+ bankManager: undefined,
221
+ namesByAddressAdmin: undefined,
222
+ walletFactory: undefined,
223
+ };
224
+
225
+ return {
226
+ brandToPSM,
227
+ fundPurse,
228
+ metricsRecorderKit,
229
+ poolBrand,
230
+ walletsProvisioned: 0n,
231
+ totalMintedProvided: AmountMath.makeEmpty(poolBrand),
232
+ totalMintedConverted: AmountMath.makeEmpty(poolBrand),
233
+ revivableAddresses,
234
+ ...references,
235
+ };
236
+ },
237
+ {
238
+ // aka "limitedCreatorFacet"
239
+ machine: {
240
+ /** @param {string[]} oldAddresses */
241
+ addRevivableAddresses(oldAddresses) {
242
+ trace('revivableAddresses count', oldAddresses.length);
243
+ this.state.revivableAddresses.addAll(oldAddresses);
244
+ },
245
+ getWalletReviver() {
246
+ return this.facets.walletReviver;
247
+ },
248
+ /** @param {ProvisionPoolKitReferences} erefs */
249
+ async setReferences(erefs) {
250
+ const { bankManager, namesByAddressAdmin, walletFactory } = erefs;
251
+ const obj = harden({
252
+ bankManager,
253
+ namesByAddressAdmin,
254
+ walletFactory,
255
+ });
256
+ const refs = await deeplyFulfilledObject(obj);
257
+ Object.assign(this.state, refs);
258
+ },
259
+ /** @returns {import('@agoric/vats').BridgeHandler} */
260
+ makeHandler() {
261
+ const { bankManager, namesByAddressAdmin, walletFactory } =
262
+ this.state;
263
+ if (!bankManager || !namesByAddressAdmin || !walletFactory) {
264
+ throw Fail`must set references before handling requests`;
265
+ }
266
+
267
+ const { forHandler } = this.facets;
268
+
269
+ const provisionHandler = makeBridgeProvisionTool(
270
+ bankManager,
271
+ walletFactory,
272
+ namesByAddressAdmin,
273
+ forHandler,
274
+ );
275
+
276
+ return provisionHandler;
277
+ },
278
+ /**
279
+ * @param {Brand} brand
280
+ * @param {PsmInstance} instance
281
+ */
282
+ initPSM(brand, instance) {
283
+ const { brandToPSM } = this.state;
284
+ brandToPSM.init(brand, instance);
285
+ },
286
+ },
287
+ walletReviver: {
288
+ /** @param {string} address */
289
+ async reviveWallet(address) {
290
+ const {
291
+ revivableAddresses,
292
+ bankManager,
293
+ namesByAddressAdmin,
294
+ walletFactory,
295
+ } = this.state;
296
+ if (!bankManager || !namesByAddressAdmin || !walletFactory) {
297
+ throw Fail`must set references before handling requests`;
298
+ }
299
+ revivableAddresses.has(address) ||
300
+ Fail`non-revivable address ${address}`;
301
+ const bank = E(bankManager).getBankForAddress(address);
302
+ const [wallet, _created] = await E(walletFactory).provideSmartWallet(
303
+ address,
304
+ bank,
305
+ namesByAddressAdmin,
306
+ );
307
+ return wallet;
308
+ },
309
+ /**
310
+ * @param {string} address
311
+ * @returns {boolean} isRevive
312
+ */
313
+ ackWallet(address) {
314
+ const { revivableAddresses } = this.state;
315
+ if (!revivableAddresses.has(address)) {
316
+ return false;
317
+ }
318
+ revivableAddresses.delete(address);
319
+ return true;
320
+ },
321
+ },
322
+ helper: {
323
+ publishMetrics() {
324
+ const {
325
+ metricsRecorderKit,
326
+ walletsProvisioned,
327
+ totalMintedConverted,
328
+ totalMintedProvided,
329
+ } = this.state;
330
+ void metricsRecorderKit.recorder.write(
331
+ harden({
332
+ walletsProvisioned,
333
+ totalMintedProvided,
334
+ totalMintedConverted,
335
+ }),
336
+ );
337
+ },
338
+ onTrade(converted) {
339
+ const { state, facets } = this;
340
+ state.totalMintedConverted = AmountMath.add(
341
+ state.totalMintedConverted,
342
+ converted,
343
+ );
344
+ facets.helper.publishMetrics();
345
+ },
346
+ onSendFunds(provided) {
347
+ const { state, facets } = this;
348
+ state.totalMintedProvided = AmountMath.add(
349
+ state.totalMintedProvided,
350
+ provided,
351
+ );
352
+ facets.helper.publishMetrics();
353
+ },
354
+ /**
355
+ * @param {Amount} amount
356
+ * @param {ERef<Purse>} srcPurse
357
+ */
358
+ async onPoolDeposit(amount, srcPurse) {
359
+ const { helper } = this.facets;
360
+ const { brandToPSM, poolBrand } = this.state;
361
+
362
+ const { brand } = amount;
363
+ if (AmountMath.isEmpty(amount) || brand === poolBrand) {
364
+ return;
365
+ }
366
+
367
+ // `amount` doesn't match the current `poolBrand`, so we need to swap
368
+ // it.
369
+ if (!brandToPSM.has(brand)) {
370
+ console.error('funds arrived but no PSM instance', brand);
371
+ return;
372
+ }
373
+ const instance = brandToPSM.get(brand);
374
+ const payment = E(srcPurse).withdraw(amount);
375
+ await helper.swap(payment, amount, instance).catch(async reason => {
376
+ console.error(X`swap failed: ${reason}`);
377
+ const resolvedPayment = await payment;
378
+ return E(srcPurse).deposit(resolvedPayment);
379
+ });
380
+ },
381
+ /**
382
+ * @param {ERef<Purse>} exchangePurse
383
+ * @param {ERef<Brand>} brand
384
+ */
385
+ watchCurrentAmount(exchangePurse, brand) {
386
+ const { helper } = this.facets;
387
+ void observeNotifier(E(exchangePurse).getCurrentAmountNotifier(), {
388
+ updateState: async amount => {
389
+ trace('provisionPool balance update', amount);
390
+ await helper.onPoolDeposit(amount, exchangePurse);
391
+ },
392
+ fail: reason => {
393
+ if (isUpgradeDisconnection(reason)) {
394
+ void helper.watchCurrentAmount(exchangePurse, brand);
395
+ } else {
396
+ console.error(reason);
397
+ }
398
+ },
399
+ });
400
+ },
401
+ watchAssetSubscription() {
402
+ const { facets } = this;
403
+ const { helper } = facets;
404
+
405
+ /** @param {import('@agoric/vats/src/vat-bank.js').AssetDescriptor} desc */
406
+ const repairDesc = desc => {
407
+ if (desc.issuerName.match(FIRST_UPPER_KEYWORD)) {
408
+ trace(`Saving Issuer ${desc.issuerName}`);
409
+ return desc;
410
+ } else if (desc.issuerName.match(FIRST_LOWER_NEAR_KEYWORD)) {
411
+ const bad = desc.issuerName;
412
+ const goodName = bad.replace(bad[0], bad[0].toUpperCase());
413
+
414
+ trace(
415
+ `Saving Issuer ${desc.issuerName} with repaired keyword ${goodName}`,
416
+ );
417
+ return { ...desc, issuerName: goodName };
418
+ } else {
419
+ console.error(
420
+ `unable to save issuer with illegal keyword: ${desc.issuerName}`,
421
+ );
422
+ return undefined;
423
+ }
424
+ };
425
+
426
+ return observeIteration(
427
+ subscribeEach(E(poolBank).getAssetSubscription()),
428
+ {
429
+ updateState: async desc => {
430
+ await null;
431
+ const issuer = zcf.getTerms().issuers[desc.issuerName];
432
+ if (issuer === desc.issuer) {
433
+ trace('provisionPool re-notified of known asset', desc.brand);
434
+ } else {
435
+ const goodDesc = repairDesc(desc);
436
+ if (goodDesc) {
437
+ await zcf.saveIssuer(goodDesc.issuer, goodDesc.issuerName);
438
+ } else {
439
+ console.error(
440
+ `unable to save issuer with illegal keyword: ${desc.issuerName}`,
441
+ );
442
+ }
443
+ }
444
+
445
+ /** @type {ERef<Purse>} */
446
+ const exchangePurse = E(poolBank).getPurse(desc.brand);
447
+ helper.watchCurrentAmount(exchangePurse, desc.brand);
448
+ },
449
+ fail: _reason => {
450
+ void helper.watchAssetSubscription();
451
+ },
452
+ },
453
+ );
454
+ },
455
+ /**
456
+ * @param {Brand<'nat'>} poolBrand
457
+ * @param {object} [options]
458
+ * @param {MetricsNotification} [options.metrics]
459
+ */
460
+ start(poolBrand, { metrics } = {}) {
461
+ const { facets, state } = this;
462
+ const { helper } = facets;
463
+ const lastPoolBrand = state.poolBrand;
464
+
465
+ // The PerAccountInitialAmount param must use the correct brand for
466
+ // this incarnation.
467
+ AmountMath.coerce(poolBrand, params.getPerAccountInitialAmount());
468
+
469
+ // Restore old metrics.
470
+ if (metrics) {
471
+ const {
472
+ walletsProvisioned,
473
+ totalMintedProvided,
474
+ totalMintedConverted,
475
+ } = metrics;
476
+ assert.typeof(walletsProvisioned, 'bigint');
477
+ AmountMath.coerce(lastPoolBrand, totalMintedProvided);
478
+ AmountMath.coerce(lastPoolBrand, totalMintedConverted);
479
+ Object.assign(state, {
480
+ walletsProvisioned,
481
+ totalMintedProvided,
482
+ totalMintedConverted,
483
+ });
484
+ helper.publishMetrics();
485
+ }
486
+
487
+ // Update as needed when `poolBrand` changes.
488
+ if (poolBrand !== lastPoolBrand) {
489
+ state.poolBrand = poolBrand;
490
+ state.fundPurse = undefined;
491
+ void getFundingPurseForBrand(poolBrand).then(purse =>
492
+ helper.updateFundPurse(purse, poolBrand),
493
+ );
494
+ state.totalMintedProvided = AmountMath.makeEmpty(poolBrand);
495
+ state.totalMintedConverted = AmountMath.makeEmpty(poolBrand);
496
+ helper.publishMetrics();
497
+ }
498
+
499
+ void helper.watchAssetSubscription();
500
+ },
501
+ /**
502
+ * @param {ERef<Payment>} payIn
503
+ * @param {Amount} amount
504
+ * @param {PsmInstance} instance
505
+ */
506
+ async swap(payIn, amount, instance) {
507
+ await null;
508
+ const { facets, state } = this;
509
+ const { helper } = facets;
510
+ const {
511
+ poolBrand,
512
+ fundPurse = await getFundingPurseForBrand(poolBrand),
513
+ } = state;
514
+ const psmPub = E(zoe).getPublicFacet(instance);
515
+ const proposal = harden({ give: { In: amount } });
516
+ const invitation = E(psmPub).makeWantMintedInvitation();
517
+ const seat = E(zoe).offer(invitation, proposal, { In: payIn });
518
+ const payout = await E(seat).getPayout('Out');
519
+ const rxd = await E(fundPurse).deposit(payout);
520
+ helper.onTrade(rxd);
521
+ return rxd;
522
+ },
523
+ /**
524
+ * @param {Purse<'nat'>} purse
525
+ * @param {Brand<'nat'>} brand
526
+ */
527
+ updateFundPurse(purse, brand) {
528
+ const { state } = this;
529
+ if (brand !== state.poolBrand || state.fundPurse) return;
530
+ state.fundPurse = purse;
531
+ },
532
+ },
533
+ forHandler: {
534
+ onProvisioned() {
535
+ const { facets, state } = this;
536
+ state.walletsProvisioned += 1n;
537
+ facets.helper.publishMetrics();
538
+ },
539
+ /** @param {ERef<Bank>} destBank */
540
+ async sendInitialPayment(destBank) {
541
+ await null;
542
+ const { facets, state } = this;
543
+ const { helper } = facets;
544
+ const {
545
+ poolBrand,
546
+ fundPurse = await getFundingPurseForBrand(poolBrand),
547
+ } = state;
548
+ const perAccountInitialAmount = /** @type {Amount<'nat'>} */ (
549
+ params.getPerAccountInitialAmount()
550
+ );
551
+ trace('sendInitialPayment withdrawing', perAccountInitialAmount);
552
+ const initialPmt = await E(fundPurse).withdraw(
553
+ perAccountInitialAmount,
554
+ );
555
+
556
+ const destPurse = E(destBank).getPurse(poolBrand);
557
+ return E(destPurse)
558
+ .deposit(initialPmt)
559
+ .then(amt => {
560
+ helper.onSendFunds(perAccountInitialAmount);
561
+ trace('provisionPool sent', amt);
562
+ })
563
+ .catch(reason => {
564
+ console.error(X`initial deposit failed: ${q(reason)}`);
565
+ void E(fundPurse).deposit(initialPmt);
566
+ throw reason;
567
+ });
568
+ },
569
+ },
570
+ public: {
571
+ getPublicTopics() {
572
+ return {
573
+ metrics: makeRecorderTopic(
574
+ 'Provision Pool metrics',
575
+ this.state.metricsRecorderKit,
576
+ ),
577
+ };
578
+ },
579
+ },
580
+ },
581
+ {
582
+ finish: ({ facets }) => {
583
+ facets.helper.publishMetrics();
584
+ },
585
+ },
586
+ );
587
+
588
+ /**
589
+ * Prepare synchronous values before passing to real Exo maker
590
+ *
591
+ * @param {object} opts
592
+ * @param {Brand<'nat'>} opts.poolBrand
593
+ * @param {ERef<StorageNode>} opts.storageNode
594
+ * @returns {Promise<ProvisionPoolKit>}
595
+ */
596
+ const makeProvisionPoolKit = async ({ poolBrand, storageNode }) => {
597
+ const fundPurse = await getFundingPurseForBrand(poolBrand);
598
+ const metricsNode = await E(storageNode).makeChildNode('metrics');
599
+
600
+ return makeProvisionPoolKitInternal({
601
+ fundPurse,
602
+ poolBrand,
603
+ metricsNode,
604
+ });
605
+ };
606
+
607
+ return makeProvisionPoolKit;
608
+ };