@agoric/inter-protocol 0.13.2-dev-73ca139.0 → 0.13.2-dev-a9d6a3b.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.
@@ -1,225 +0,0 @@
1
- // @jessie-check
2
-
3
- import { AmountMath } from '@agoric/ertp';
4
- import { handleParamGovernance, ParamTypes } from '@agoric/governance';
5
- import { atomicRearrange } from '@agoric/zoe/src/contractSupport/atomicTransfer.js';
6
- import { E, Far } from '@endo/far';
7
- import { makeCollectFeesInvitation } from '../collectFees.js';
8
- import { makeAttestationFacets } from './attestation.js';
9
- import { ManagerKW as KW } from './constants.js';
10
- import { makeStakeFactoryKit } from './stakeFactoryKit.js';
11
- import { makeStakeFactoryManager } from './stakeFactoryManager.js';
12
-
13
- /**
14
- * Lend on the basis of staked assets that earn rewards.
15
- *
16
- * In addition to brands and issuers for `Staked`, `Minted`, and attestation,
17
- * terms of the contract include a periodic `InterestRate`
18
- * plus a `MintFee` proportional to the amount borrowed, as well as
19
- * a `MintingRatio` of funds to (mint and) lend per unit of staked asset.
20
- * These terms are subject to change by the `Electorate`
21
- * and `electionManager` terms.
22
- *
23
- * @typedef {{
24
- * DebtLimit: 'amount',
25
- * MintingRatio: 'ratio',
26
- * InterestRate: 'ratio',
27
- * MintFee: 'ratio',
28
- * }} StakeFactoryParams
29
- *
30
- * As in vaultFactory, `timerService` provides the periodic signal to
31
- * charge interest according to `chargingPeriod` and `recordingPeriod`.
32
- *
33
- * @typedef { GovernanceTerms<StakeFactoryParams> & {
34
- * timerService: import('@agoric/time/src/types').TimerService,
35
- * chargingPeriod: bigint,
36
- * recordingPeriod: bigint,
37
- * lienAttestationName?: string,
38
- * }} StakeFactoryTerms
39
- *
40
- * The public facet provides access to invitations to borrow
41
- * or to return an attestation in order to release a lien on staked assets.
42
- *
43
- * @typedef {{
44
- * createDebtInvitation: () => Promise<Invitation>,
45
- * makeReturnAttInvitation: () => Promise<Invitation>,
46
- * }} StakeFactoryPublic
47
- *
48
- * To create a debt position, get an `AttestationMaker` for your address from
49
- * the creator of this contract, and use
50
- * `E(attMaker).makeAttestation(stakedAmount)` to take out a lien
51
- * and get a payment that attests to the lien. Provide the payment
52
- * in the `Attestation` keyword of an offer,
53
- * using `{ want: { Debt: amountWanted }}`.
54
- *
55
- * Then, using the invitationMakers pattern, use `AdjustBalances` to
56
- * pay down or otherwise adjust the `Debt` and `Attestation`.
57
- *
58
- * Finally, `Close` the debt position, providing `{ give: Debt: debtAmount }}`
59
- *
60
- * To start the contract, authorize minting assets by providing `feeMintAccess`
61
- * and provide access to the underlying staking infrastructure in `lienBridge`.
62
- *
63
- * @typedef {{
64
- * feeMintAccess: FeeMintAccess,
65
- * initialPoserInvitation: Invitation,
66
- * lienBridge: ERef<StakingAuthority>,
67
- * storageNode: StorageNode,
68
- * marshaller: Marshaller,
69
- * }} StakeFactoryPrivateArgs
70
- *
71
- * The creator facet can make an `AttestationMaker` for each account, which
72
- * authorizes placing a lien some of the staked assets in that account.
73
- * @typedef {{
74
- * provideAttestationMaker: (addr: string) => AttestationTool,
75
- * makeCollectFeesInvitation: () => Promise<Invitation<string, never>>,
76
- * }} StakeFactoryCreator
77
- *
78
- */
79
-
80
- /**
81
- * @param {ZCF<StakeFactoryTerms>} zcf
82
- * @param {StakeFactoryPrivateArgs} privateArgs
83
- */
84
- export const start = async (
85
- zcf,
86
- {
87
- feeMintAccess,
88
- initialPoserInvitation,
89
- lienBridge,
90
- storageNode,
91
- marshaller,
92
- },
93
- ) => {
94
- const {
95
- brands: { Stake: stakeBrand },
96
- timerService,
97
- chargingPeriod,
98
- recordingPeriod,
99
- } = zcf.getTerms();
100
- assert.typeof(chargingPeriod, 'bigint', 'chargingPeriod must be a bigint');
101
- assert.typeof(recordingPeriod, 'bigint', 'recordingPeriod must be a bigint');
102
- assert(storageNode && marshaller, 'missing storageNode or marshaller');
103
-
104
- /** @type {ZCFMint<'nat'>} */
105
- const debtMint = await zcf.registerFeeMint(KW.Debt, feeMintAccess);
106
- const { brand: debtBrand } = debtMint.getIssuerRecord();
107
-
108
- const att = await makeAttestationFacets(zcf, stakeBrand, lienBridge);
109
- const attestBrand = await E(att.publicFacet).getBrand();
110
-
111
- const { augmentPublicFacet, makeGovernorFacet, params } =
112
- await handleParamGovernance(
113
- zcf,
114
- initialPoserInvitation,
115
- {
116
- DebtLimit: ParamTypes.AMOUNT,
117
- InterestRate: ParamTypes.RATIO,
118
- MintFee: ParamTypes.RATIO,
119
- MintingRatio: ParamTypes.RATIO,
120
- },
121
- storageNode,
122
- marshaller,
123
- );
124
-
125
- /** For holding newly minted tokens until transferred */
126
- const { zcfSeat: mintSeat } = zcf.makeEmptySeatKit();
127
-
128
- const { zcfSeat: rewardPoolSeat } = zcf.makeEmptySeatKit();
129
-
130
- /**
131
- * Let the manager add rewards to the rewardPoolSeat
132
- * without directly exposing the rewardPoolSeat to them.
133
- *
134
- * @type {MintAndTransfer}
135
- */
136
- const mintAndTransfer = (mintReceiver, toMint, fee, nonMintTransfers) => {
137
- const kept = AmountMath.subtract(toMint, fee);
138
- debtMint.mintGains(harden({ [KW.Debt]: toMint }), mintSeat);
139
- /** @type {import('@agoric/zoe/src/contractSupport/atomicTransfer.js').TransferPart[]} */
140
- const transfers = [
141
- ...nonMintTransfers,
142
- [mintSeat, rewardPoolSeat, { [KW.Debt]: fee }],
143
- [mintSeat, mintReceiver, { [KW.Debt]: kept }],
144
- ];
145
-
146
- try {
147
- atomicRearrange(zcf, harden(transfers));
148
- } catch (e) {
149
- console.error('mintAndTransfer failed to rearrange', e);
150
- // If the rearrange fails, burn the newly minted tokens.
151
- // Assume this won't fail because it relies on the internal mint.
152
- // (Failure would imply much larger problems.)
153
- debtMint.burnLosses(harden({ [KW.Debt]: toMint }), mintSeat);
154
- throw e;
155
- }
156
- // TODO add aggregate debt tracking at the vaultFactory level #4482
157
- // totalDebt = AmountMath.add(totalDebt, toMint);
158
- };
159
-
160
- const burnDebt = (toBurn, seat) => {
161
- debtMint.burnLosses(harden({ [KW.Debt]: toBurn }), seat);
162
- };
163
-
164
- const mintPowers = Far('mintPowers', {
165
- burnDebt,
166
- getGovernedParams: () => params, // XXX until governance support is durable
167
- mintAndTransfer,
168
- });
169
-
170
- const startTimeStamp = await E(timerService).getCurrentTimestamp();
171
- const { manager } = makeStakeFactoryManager(
172
- zcf,
173
- debtMint,
174
- harden({ Attestation: attestBrand, debt: debtBrand, Stake: stakeBrand }),
175
- mintPowers,
176
- { timerService, chargingPeriod, recordingPeriod, startTimeStamp },
177
- );
178
-
179
- /**
180
- * @param {ZCFSeat} seat
181
- */
182
- const offerHandler = seat => {
183
- const { helper, pot } = makeStakeFactoryKit(zcf, seat, manager);
184
-
185
- return harden({
186
- publicSubscribers: {
187
- vault: pot.getSubscriber(),
188
- },
189
- invitationMakers: Far('invitation makers', {
190
- AdjustBalances: () =>
191
- zcf.makeInvitation(
192
- seatx => helper.adjustBalancesHook(seatx),
193
- 'AdjustBalances',
194
- ),
195
- CloseVault: () =>
196
- zcf.makeInvitation(seatx => helper.closeHook(seatx), 'CloseVault'),
197
- }),
198
- vault: pot,
199
- });
200
- };
201
-
202
- const publicFacet = augmentPublicFacet(
203
- harden({
204
- createDebtInvitation: () =>
205
- zcf.makeInvitation(offerHandler, 'make stakeFactory'),
206
- makeReturnAttInvitation: att.publicFacet.makeReturnAttInvitation,
207
- }),
208
- );
209
-
210
- /** @type {ERef<StakeFactoryCreator>} */
211
- const creatorFacet = Far('stakeFactory creator', {
212
- provideAttestationMaker: att.creatorFacet.provideAttestationTool,
213
- makeCollectFeesInvitation: () => {
214
- return makeCollectFeesInvitation(
215
- zcf,
216
- rewardPoolSeat,
217
- debtBrand,
218
- 'Minted',
219
- );
220
- },
221
- });
222
-
223
- return { publicFacet, creatorFacet: makeGovernorFacet(creatorFacet) };
224
- };
225
- harden(start);
@@ -1,465 +0,0 @@
1
- // @jessie-check
2
-
3
- import { AmountMath, AssetKind } from '@agoric/ertp';
4
- import { bindAllMethods, makeTracer } from '@agoric/internal';
5
- import { makePublishKit } from '@agoric/notifier';
6
- import { M, matches } from '@agoric/store';
7
- import { defineKindMulti } from '@agoric/vat-data';
8
- import {
9
- assertProposalShape,
10
- atomicRearrange,
11
- } from '@agoric/zoe/src/contractSupport/index.js';
12
- import { ceilMultiplyBy } from '@agoric/zoe/src/contractSupport/ratio.js';
13
- import { addSubtract, assertOnlyKeys } from '../contractSupport.js';
14
- import { calculateCurrentDebt, reverseInterest } from '../interest-math.js';
15
- import { ManagerKW as KW } from './constants.js';
16
-
17
- const { Fail, quote: q } = assert;
18
-
19
- const trace = makeTracer('R1');
20
-
21
- /**
22
- * Calculate the fee, the amount to mint and the resulting debt.
23
- *
24
- * @param {Ratio} feeCoeff fee coefficient
25
- * @param {Amount<'nat'>} currentDebt
26
- * @param {Amount<'nat'>} giveAmount
27
- * @param {Amount<'nat'>} wantAmount
28
- */
29
- const calculateFee = (feeCoeff, currentDebt, giveAmount, wantAmount) => {
30
- const fee = ceilMultiplyBy(wantAmount, feeCoeff);
31
- const toMint = AmountMath.add(wantAmount, fee);
32
- const newDebt = addSubtract(currentDebt, toMint, giveAmount);
33
- return { newDebt, toMint, fee };
34
- };
35
-
36
- /**
37
- * @typedef {Readonly<{
38
- * collateralBrand: Brand,
39
- * debtBrand: Brand<'nat'>,
40
- * manager: import('./stakeFactoryManager.js').StakeFactoryManager,
41
- * subscriber: Subscriber<unknown>
42
- * vaultSeat: ZCFSeat,
43
- * zcf: ZCF,
44
- * }>} ImmutableState
45
- * @typedef {{
46
- * open: boolean,
47
- * debtSnapshot: Amount<'nat'>,
48
- * interestSnapshot: Ratio,
49
- * publisher: Publisher<unknown> | null,
50
- * }} MutableState
51
- * @typedef {MutableState & ImmutableState} State
52
- * @typedef {{
53
- * state: State,
54
- * facets: {
55
- * helper: import('@agoric/vat-data/src/types').KindFacet<typeof helperBehavior>,
56
- * pot: import('@agoric/vat-data/src/types').KindFacet<typeof potBehavior>,
57
- * },
58
- * }} MethodContext
59
- */
60
-
61
- /**
62
- * Make stakeFactory kit state
63
- *
64
- * @param {ZCF} zcf
65
- * @param {ZCFSeat} startSeat
66
- * @param {import('./stakeFactoryManager.js').StakeFactoryManager} manager
67
- * @returns {State}
68
- */
69
- const initState = (zcf, startSeat, manager) => {
70
- const collateralBrand = manager.getCollateralBrand();
71
- const debtBrand = manager.getDebtBrand();
72
-
73
- const { zcfSeat: vaultSeat } = zcf.makeEmptySeatKit();
74
-
75
- const emptyDebt = AmountMath.makeEmpty(debtBrand);
76
-
77
- const initialDebt = (() => {
78
- assertProposalShape(startSeat, {
79
- give: { [KW.Attestation]: null },
80
- want: { [KW.Debt]: null },
81
- });
82
- const {
83
- give: { [KW.Attestation]: attestationGiven },
84
- want: { [KW.Debt]: runWanted },
85
- } = startSeat.getProposal();
86
-
87
- const { maxDebt } = manager.maxDebtForLien(attestationGiven);
88
- AmountMath.isGTE(maxDebt, runWanted) ||
89
- Fail`wanted ${runWanted}, more than max debt (${maxDebt}) for ${attestationGiven}`;
90
-
91
- const { newDebt, fee, toMint } = calculateFee(
92
- manager.getMintFee(),
93
- emptyDebt,
94
- emptyDebt,
95
- runWanted,
96
- );
97
- !AmountMath.isEmpty(fee) ||
98
- Fail`debt position requested (${runWanted}) is too small; cannot accrue interest`;
99
- AmountMath.isEqual(newDebt, toMint) ||
100
- Fail`mismatch between debt and amount to mint`;
101
- trace('init', { runWanted, fee, attestationGiven });
102
-
103
- manager.mintAndReallocate(
104
- startSeat,
105
- toMint,
106
- fee,
107
- harden([[startSeat, vaultSeat, { [KW.Attestation]: attestationGiven }]]),
108
- );
109
-
110
- startSeat.exit();
111
- return newDebt;
112
- })();
113
- manager.applyDebtDelta(emptyDebt, initialDebt);
114
-
115
- const { publisher, subscriber } = makePublishKit();
116
-
117
- /** @type {ImmutableState} */
118
- const immutable = {
119
- collateralBrand,
120
- debtBrand,
121
- manager,
122
- subscriber,
123
- vaultSeat,
124
- zcf,
125
- };
126
- return {
127
- ...immutable,
128
- open: true,
129
- // Two values from the same moment
130
- interestSnapshot: manager.getCompoundedInterest(),
131
- debtSnapshot: initialDebt,
132
- publisher,
133
- };
134
- };
135
- const helperBehavior = {
136
- /**
137
- * @param {MethodContext} context
138
- * @param {ZCFSeat} seat
139
- */
140
- getCollateralAllocated: ({ state }, seat) =>
141
- seat.getAmountAllocated(KW.Attestation, state.collateralBrand),
142
- /**
143
- * @param {MethodContext} context
144
- * @param {ZCFSeat} seat
145
- */
146
- getMintedAllocated: ({ state }, seat) =>
147
- seat.getAmountAllocated(KW.Debt, state.debtBrand),
148
- /**
149
- * @param {MethodContext} context
150
- */
151
- getCollateralAmount: ({ state, facets }) => {
152
- const { collateralBrand, vaultSeat } = state;
153
- const { helper } = facets;
154
- const emptyCollateral = AmountMath.makeEmpty(
155
- collateralBrand,
156
- AssetKind.COPY_BAG,
157
- );
158
- // getCollateralAllocated would return final allocations
159
- return vaultSeat.hasExited()
160
- ? emptyCollateral
161
- : helper.getCollateralAllocated(vaultSeat);
162
- },
163
-
164
- /**
165
- * @param {MethodContext} context
166
- * @param {boolean} newActive
167
- */
168
- snapshotState: ({ state, facets }, newActive) => {
169
- const { debtSnapshot: debt, interestSnapshot: interest } = state;
170
- const { helper } = facets;
171
- /** @type {VaultNotification} */
172
- const result = harden({
173
- debtSnapshot: { debt, interest },
174
- locked: helper.getCollateralAmount(),
175
- // newPhase param is so that makeTransferInvitation can finish without setting the vault's phase
176
- // TODO refactor https://github.com/Agoric/agoric-sdk/issues/4415
177
- vaultState: newActive ? 'active' : 'closed',
178
- });
179
- return result;
180
- },
181
-
182
- /**
183
- * call this whenever anything changes!
184
- *
185
- * @param {MethodContext} context
186
- */
187
- updateUiState: async ({ state, facets }) => {
188
- const { open: active, publisher } = state;
189
- if (!publisher) {
190
- console.warn('updateUiState called after ui.publisher removed');
191
- return;
192
- }
193
- const uiState = facets.helper.snapshotState(active);
194
- trace('updateUiState', uiState);
195
-
196
- if (active) {
197
- publisher.publish(uiState);
198
- } else {
199
- publisher.finish(uiState);
200
- state.publisher = null;
201
- }
202
- },
203
-
204
- /**
205
- * Called whenever the debt is paid or created through a transaction,
206
- * but not for interest accrual.
207
- *
208
- * @param {MethodContext} context
209
- * @param {Amount<'nat'>} newDebt - principal and all accrued interest
210
- */
211
- updateDebtSnapshot: ({ state }, newDebt) => {
212
- const { manager } = state;
213
- // update local state
214
- state.debtSnapshot = newDebt;
215
- state.interestSnapshot = manager.getCompoundedInterest();
216
- },
217
-
218
- /**
219
- * Update the debt balance and propagate upwards to
220
- * maintain aggregate debt and liquidation order.
221
- *
222
- * @param {MethodContext} context
223
- * @param {Amount<'nat'>} oldDebt - prior principal and all accrued interest
224
- * @param {Amount<'nat'>} newDebt - actual principal and all accrued interest
225
- */
226
- updateDebtAccounting: ({ state, facets }, oldDebt, newDebt) => {
227
- const { manager } = state;
228
- const { helper } = facets;
229
- helper.updateDebtSnapshot(newDebt);
230
- // update vault manager which tracks total debt
231
- manager.applyDebtDelta(oldDebt, newDebt);
232
- },
233
-
234
- /**
235
- * @param {MethodContext} context
236
- */
237
- assertVaultHoldsNoMinted: ({ state, facets }) => {
238
- const { vaultSeat } = state;
239
- const { helper } = facets;
240
- AmountMath.isEmpty(helper.getMintedAllocated(vaultSeat)) ||
241
- Fail`Vault should be empty of debt`;
242
- },
243
-
244
- /**
245
- * Adjust principal and collateral (atomically for offer safety)
246
- *
247
- * @param {MethodContext} context
248
- * @param {ZCFSeat} clientSeat
249
- */
250
- adjustBalancesHook: ({ state, facets }, clientSeat) => {
251
- const { collateralBrand, debtBrand, manager, vaultSeat } = state;
252
- const { helper, pot } = facets;
253
- assert(state.open);
254
-
255
- const proposal = clientSeat.getProposal();
256
- assertOnlyKeys(proposal, [KW.Attestation, KW.Debt]);
257
-
258
- const debt = pot.getCurrentDebt();
259
- const collateral = helper.getCollateralAllocated(vaultSeat);
260
-
261
- const emptyCollateral = AmountMath.makeEmpty(
262
- collateralBrand,
263
- AssetKind.COPY_BAG,
264
- );
265
- const giveColl = proposal.give.Attestation || emptyCollateral;
266
- const wantColl = proposal.want.Attestation || emptyCollateral;
267
-
268
- // new = after the transaction gets applied
269
- const newCollateral = addSubtract(collateral, giveColl, wantColl);
270
- // max debt supported by current Collateral as modified by proposal
271
- const { amountLiened, maxDebt: newMaxDebt } =
272
- manager.maxDebtForLien(newCollateral);
273
-
274
- const emptyDebt = AmountMath.makeEmpty(debtBrand);
275
- const give = AmountMath.min(proposal.give.Debt || emptyDebt, debt);
276
- const want = proposal.want.Debt || emptyDebt;
277
- const giveDebtOnly = matches(
278
- proposal,
279
- harden({ give: { [KW.Debt]: M.record() }, want: {}, exit: M.any() }),
280
- );
281
-
282
- // Calculate the fee, the amount to mint and the resulting debt. We'll
283
- // verify that the target debt doesn't violate the collateralization ratio,
284
- // then mint, reallocate, and burn.
285
- const { newDebt, fee, toMint } = calculateFee(
286
- manager.getMintFee(),
287
- debt,
288
- give,
289
- want,
290
- );
291
- assert(
292
- giveDebtOnly || AmountMath.isGTE(newMaxDebt, newDebt),
293
- `cannot borrow ${q(newDebt)} against ${q(amountLiened)}; max is ${q(
294
- newMaxDebt,
295
- )}`,
296
- );
297
-
298
- trace('adjustBalancesHook', {
299
- targetCollateralAmount: newCollateral,
300
- vaultCollateral: newCollateral,
301
- fee,
302
- toMint,
303
- newDebt,
304
- });
305
-
306
- manager.mintAndReallocate(
307
- clientSeat,
308
- toMint,
309
- fee,
310
- harden([
311
- [clientSeat, vaultSeat, { [KW.Attestation]: giveColl }],
312
- [vaultSeat, clientSeat, { [KW.Attestation]: wantColl }],
313
- [clientSeat, vaultSeat, { [KW.Debt]: give }],
314
- // Minted into vaultSeat requires minting and so is done by mintAndTransfer
315
- ]),
316
- );
317
-
318
- // parent needs to know about the change in debt
319
- helper.updateDebtAccounting(debt, newDebt);
320
-
321
- manager.burnDebt(give, vaultSeat);
322
-
323
- helper.assertVaultHoldsNoMinted();
324
-
325
- void helper.updateUiState();
326
- clientSeat.exit();
327
-
328
- return 'We have adjusted your balances; thank you for your business.';
329
- },
330
-
331
- /**
332
- * Given sufficient Minted payoff, refund the attestation.
333
- *
334
- * @type {import('@agoric/vat-data/src/types').PlusContext<MethodContext, OfferHandler>}
335
- */
336
- closeHook: ({ state, facets }, seat) => {
337
- const { debtBrand, manager, vaultSeat, zcf } = state;
338
- const { helper, pot } = facets;
339
- assert(state.open);
340
- assertProposalShape(seat, {
341
- give: { [KW.Debt]: null },
342
- want: { [KW.Attestation]: null },
343
- });
344
-
345
- const currentDebt = pot.getCurrentDebt();
346
- const {
347
- give: { [KW.Debt]: runOffered },
348
- } = seat.getProposal();
349
- AmountMath.isGTE(runOffered, currentDebt) ||
350
- Fail`Offer ${runOffered} is not sufficient to pay off debt ${currentDebt}`;
351
- atomicRearrange(
352
- zcf,
353
- harden([
354
- [seat, vaultSeat, { [KW.Debt]: currentDebt }],
355
- [
356
- vaultSeat,
357
- seat,
358
- { Attestation: vaultSeat.getAmountAllocated('Attestation') },
359
- ],
360
- ]),
361
- );
362
-
363
- manager.burnDebt(currentDebt, vaultSeat);
364
- state.open = false;
365
- helper.updateDebtSnapshot(AmountMath.makeEmpty(debtBrand));
366
- void helper.updateUiState();
367
- helper.assertVaultHoldsNoMinted();
368
- seat.exit();
369
-
370
- return 'Your stakeFactory is closed; thank you for your business.';
371
- },
372
- };
373
-
374
- const potBehavior = {
375
- /** @param {MethodContext} context */
376
- getSubscriber: ({ state }) => state.subscriber,
377
- /** @param {MethodContext} context */
378
- makeAdjustBalancesInvitation: ({ state, facets }) => {
379
- const { zcf } = state;
380
- const { helper } = facets;
381
- assert(state.open);
382
- return zcf.makeInvitation(
383
- seat => helper.adjustBalancesHook(seat),
384
- 'AdjustBalances',
385
- );
386
- },
387
- /** @param {MethodContext} context */
388
- makeCloseInvitation: ({ state, facets }) => {
389
- const { zcf } = state;
390
- const { helper } = facets;
391
- assert(state.open);
392
- return zcf.makeInvitation(seat => helper.closeHook(seat), 'CloseVault');
393
- },
394
- /**
395
- * The actual current debt, including accrued interest.
396
- *
397
- * This looks like a simple getter but it does a lot of the heavy lifting for
398
- * interest accrual. Rather than updating all records when interest accrues,
399
- * the vault manager updates just its rolling compounded interest. Here we
400
- * calculate what the current debt is given what's recorded in this vault and
401
- * what interest has compounded since this vault record was written.
402
- *
403
- * @see getNormalizedDebt
404
- * @param {MethodContext} context
405
- * @returns {Amount<'nat'>}
406
- */
407
- getCurrentDebt: ({ state }) => {
408
- return calculateCurrentDebt(
409
- state.debtSnapshot,
410
- state.interestSnapshot,
411
- state.manager.getCompoundedInterest(),
412
- );
413
- },
414
- /** @param {MethodContext} context */
415
- getNormalizedDebt: ({ state }) =>
416
- reverseInterest(state.debtSnapshot, state.interestSnapshot),
417
- };
418
-
419
- const behavior = {
420
- helper: helperBehavior,
421
- pot: potBehavior,
422
- };
423
-
424
- /**
425
- * @param {MethodContext} context
426
- */
427
- const finish = ({ facets }) => {
428
- const { helper } = facets;
429
- void helper.updateUiState();
430
- };
431
-
432
- /**
433
- * Make stakeFactory kit, subject to stakeFactory terms.
434
- *
435
- * @param {ZCF} zcf
436
- * @param {ZCFSeat} startSeat
437
- * @param {import('./stakeFactoryManager.js').StakeFactoryManager} manager
438
- * @throws {Error} if startSeat proposal is not consistent with governance parameters in manager
439
- */
440
- const makeStakeFactoryKitInternal = defineKindMulti(
441
- 'stakeFactoryKit',
442
- initState,
443
- behavior,
444
- { finish },
445
- );
446
-
447
- /**
448
- * Make stakeFactory kit, subject to stakeFactory terms.
449
- *
450
- * TODO refactor to remove this wrapper around the kind and to stop using
451
- * `bindAllMethods`.
452
- *
453
- * @param {ZCF} zcf
454
- * @param {ZCFSeat} startSeat
455
- * @param {import('./stakeFactoryManager.js').StakeFactoryManager} manager
456
- * @throws {Error} if startSeat proposal is not consistent with governance parameters in manager
457
- */
458
- export const makeStakeFactoryKit = (zcf, startSeat, manager) => {
459
- const { helper, pot } = makeStakeFactoryKitInternal(zcf, startSeat, manager);
460
- return harden({
461
- // XXX work- around for change from auto - binding
462
- helper: bindAllMethods(helper),
463
- pot,
464
- });
465
- };