@agoric/inter-protocol 0.15.0 → 0.16.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.
- package/CHANGELOG.md +45 -0
- package/bundles/bundle-auctioneer-js-meta.json +314 -314
- package/bundles/bundle-auctioneer.js +1 -1
- package/bundles/bundle-econCommitteeCharter-js-meta.json +208 -208
- package/bundles/bundle-econCommitteeCharter.js +1 -1
- package/bundles/bundle-feeDistributor-js-meta.json +189 -189
- package/bundles/bundle-feeDistributor.js +1 -1
- package/bundles/bundle-fluxAggregatorKit-js-meta.json +284 -284
- package/bundles/bundle-fluxAggregatorKit.js +1 -1
- package/bundles/bundle-psm-js-meta.json +302 -302
- package/bundles/bundle-psm.js +1 -1
- package/bundles/bundle-reserve-js-meta.json +293 -293
- package/bundles/bundle-reserve.js +1 -1
- package/bundles/bundle-scaledPriceAuthority-js-meta.json +220 -220
- package/bundles/bundle-scaledPriceAuthority.js +1 -1
- package/bundles/bundle-vaultFactory-js-meta.json +330 -326
- package/bundles/bundle-vaultFactory.js +1 -1
- package/package.json +16 -16
- package/scripts/init-core.js +2 -2
- package/scripts/start-local-chain.sh +1 -1
- package/src/auction/auctionBook.js +10 -2
- package/src/clientSupport.js +79 -7
- package/src/contractSupport.js +16 -45
- package/src/price/fluxAggregatorContract.js +1 -1
- package/src/price/fluxAggregatorKit.js +2 -15
- package/src/price/roundsManager.js +8 -0
- package/src/proposals/core-proposal.js +4 -4
- package/src/proposals/econ-behaviors.js +13 -12
- package/src/reserve/assetReserveKit.js +1 -7
- package/src/reserve/doc.md +4 -4
- package/src/vaultFactory/Liquidation.md +1 -1
- package/src/vaultFactory/liquidation.js +14 -24
- package/src/vaultFactory/params.js +8 -8
- package/src/vaultFactory/proceeds.js +274 -0
- package/src/vaultFactory/types.js +1 -10
- package/src/vaultFactory/vaultDirector.js +3 -42
- package/src/vaultFactory/vaultFactory.js +3 -3
- package/src/vaultFactory/vaultHolder.js +1 -9
- package/src/vaultFactory/vaultManager.js +177 -322
|
@@ -144,7 +144,7 @@ const setWakeups = ({
|
|
|
144
144
|
* @param {TimerWaker} reschedulerWaker
|
|
145
145
|
* @returns {Promise<void>}
|
|
146
146
|
*/
|
|
147
|
-
const setWakeupsForNextAuction = async (
|
|
147
|
+
export const setWakeupsForNextAuction = async (
|
|
148
148
|
auctioneerPublicFacet,
|
|
149
149
|
timer,
|
|
150
150
|
priceLockWaker,
|
|
@@ -157,7 +157,12 @@ const setWakeupsForNextAuction = async (
|
|
|
157
157
|
E(timer).getCurrentTimestamp(),
|
|
158
158
|
]);
|
|
159
159
|
|
|
160
|
-
trace(
|
|
160
|
+
trace(
|
|
161
|
+
'setWakeupsForNextAuction at',
|
|
162
|
+
now.absValue,
|
|
163
|
+
'with',
|
|
164
|
+
nextAuctionSchedule,
|
|
165
|
+
);
|
|
161
166
|
if (!nextAuctionSchedule) {
|
|
162
167
|
// There should always be a nextAuctionSchedule. If there isn't, give up for now.
|
|
163
168
|
cancelWakeups(timer);
|
|
@@ -175,35 +180,25 @@ const setWakeupsForNextAuction = async (
|
|
|
175
180
|
params,
|
|
176
181
|
});
|
|
177
182
|
};
|
|
183
|
+
harden(setWakeupsForNextAuction);
|
|
178
184
|
|
|
179
185
|
/**
|
|
180
186
|
* @param {Amount<'nat'>} debt
|
|
181
187
|
* @param {Amount<'nat'>} minted
|
|
182
|
-
* @returns {{ overage: Amount<'nat'>, shortfall: Amount<'nat'
|
|
188
|
+
* @returns {{ overage: Amount<'nat'>, shortfall: Amount<'nat'>}}
|
|
183
189
|
*/
|
|
184
|
-
const liquidationResults = (debt, minted) => {
|
|
190
|
+
export const liquidationResults = (debt, minted) => {
|
|
185
191
|
if (AmountMath.isEmpty(minted)) {
|
|
186
|
-
return {
|
|
187
|
-
overage: minted,
|
|
188
|
-
toBurn: minted,
|
|
189
|
-
shortfall: debt,
|
|
190
|
-
};
|
|
192
|
+
return { overage: minted, shortfall: debt };
|
|
191
193
|
}
|
|
192
194
|
|
|
193
195
|
const [overage, shortfall] = AmountMath.isGTE(debt, minted)
|
|
194
196
|
? [AmountMath.makeEmptyFromAmount(debt), AmountMath.subtract(debt, minted)]
|
|
195
197
|
: [AmountMath.subtract(minted, debt), AmountMath.makeEmptyFromAmount(debt)];
|
|
196
198
|
|
|
197
|
-
|
|
198
|
-
// debt is fully accounted for, with toBurn and shortfall
|
|
199
|
-
assert(AmountMath.isEqual(debt, AmountMath.add(toBurn, shortfall)));
|
|
200
|
-
|
|
201
|
-
return {
|
|
202
|
-
overage,
|
|
203
|
-
toBurn,
|
|
204
|
-
shortfall,
|
|
205
|
-
};
|
|
199
|
+
return { overage, shortfall };
|
|
206
200
|
};
|
|
201
|
+
harden(liquidationResults);
|
|
207
202
|
|
|
208
203
|
/**
|
|
209
204
|
* Watch governed params for change
|
|
@@ -255,7 +250,7 @@ export const watchForGovernanceChange = (
|
|
|
255
250
|
* totalCollateral: Amount<'nat'>,
|
|
256
251
|
* liqSeat: ZCFSeat}}
|
|
257
252
|
*/
|
|
258
|
-
const getLiquidatableVaults = (
|
|
253
|
+
export const getLiquidatableVaults = (
|
|
259
254
|
zcf,
|
|
260
255
|
collateralizationDetails,
|
|
261
256
|
prioritizedVaults,
|
|
@@ -298,9 +293,4 @@ const getLiquidatableVaults = (
|
|
|
298
293
|
|
|
299
294
|
return { vaultData, totalDebt, totalCollateral, liqSeat };
|
|
300
295
|
};
|
|
301
|
-
|
|
302
|
-
harden(setWakeupsForNextAuction);
|
|
303
|
-
harden(liquidationResults);
|
|
304
296
|
harden(getLiquidatableVaults);
|
|
305
|
-
|
|
306
|
-
export { setWakeupsForNextAuction, liquidationResults, getLiquidatableVaults };
|
|
@@ -25,13 +25,13 @@ export const INTEREST_RATE_KEY = 'InterestRate';
|
|
|
25
25
|
export const MINT_FEE_KEY = 'MintFee';
|
|
26
26
|
export const MIN_INITIAL_DEBT_KEY = 'MinInitialDebt';
|
|
27
27
|
export const SHORTFALL_INVITATION_KEY = 'ShortfallInvitation';
|
|
28
|
-
export const
|
|
28
|
+
export const REFERENCED_UI_KEY = 'ReferencedUI';
|
|
29
29
|
|
|
30
30
|
export const vaultDirectorParamTypes = {
|
|
31
31
|
[MIN_INITIAL_DEBT_KEY]: ParamTypes.AMOUNT,
|
|
32
32
|
[CHARGING_PERIOD_KEY]: ParamTypes.NAT,
|
|
33
33
|
[RECORDING_PERIOD_KEY]: ParamTypes.NAT,
|
|
34
|
-
[
|
|
34
|
+
[REFERENCED_UI_KEY]: ParamTypes.STRING,
|
|
35
35
|
};
|
|
36
36
|
harden(vaultDirectorParamTypes);
|
|
37
37
|
|
|
@@ -39,14 +39,14 @@ harden(vaultDirectorParamTypes);
|
|
|
39
39
|
* @param {Amount<'set'>} electorateInvitationAmount
|
|
40
40
|
* @param {Amount<'nat'>} minInitialDebt
|
|
41
41
|
* @param {Amount<'set'>} shortfallInvitationAmount
|
|
42
|
-
* @param {string}
|
|
42
|
+
* @param {string} referencedUi
|
|
43
43
|
* @param {InterestTiming} interestTiming
|
|
44
44
|
*/
|
|
45
45
|
const makeVaultDirectorParams = (
|
|
46
46
|
electorateInvitationAmount,
|
|
47
47
|
minInitialDebt,
|
|
48
48
|
shortfallInvitationAmount,
|
|
49
|
-
|
|
49
|
+
referencedUi,
|
|
50
50
|
interestTiming,
|
|
51
51
|
) => {
|
|
52
52
|
return harden({
|
|
@@ -62,7 +62,7 @@ const makeVaultDirectorParams = (
|
|
|
62
62
|
type: ParamTypes.INVITATION,
|
|
63
63
|
value: shortfallInvitationAmount,
|
|
64
64
|
},
|
|
65
|
-
[
|
|
65
|
+
[REFERENCED_UI_KEY]: { type: ParamTypes.STRING, value: referencedUi },
|
|
66
66
|
[CHARGING_PERIOD_KEY]: {
|
|
67
67
|
type: ParamTypes.NAT,
|
|
68
68
|
value: TimeMath.relValue(interestTiming.chargingPeriod),
|
|
@@ -131,7 +131,7 @@ export const vaultParamPattern = M.splitRecord(
|
|
|
131
131
|
* reservePublicFacet: AssetReservePublicFacet,
|
|
132
132
|
* interestTiming: InterestTiming,
|
|
133
133
|
* shortfallInvitationAmount: Amount<'set'>,
|
|
134
|
-
*
|
|
134
|
+
* referencedUi?: string,
|
|
135
135
|
* }} opts
|
|
136
136
|
*/
|
|
137
137
|
export const makeGovernedTerms = ({
|
|
@@ -144,7 +144,7 @@ export const makeGovernedTerms = ({
|
|
|
144
144
|
reservePublicFacet,
|
|
145
145
|
timer,
|
|
146
146
|
shortfallInvitationAmount,
|
|
147
|
-
|
|
147
|
+
referencedUi = 'NO REFERENCE',
|
|
148
148
|
}) => {
|
|
149
149
|
return harden({
|
|
150
150
|
auctioneerPublicFacet,
|
|
@@ -155,7 +155,7 @@ export const makeGovernedTerms = ({
|
|
|
155
155
|
electorateInvitationAmount,
|
|
156
156
|
minInitialDebt,
|
|
157
157
|
shortfallInvitationAmount,
|
|
158
|
-
|
|
158
|
+
referencedUi,
|
|
159
159
|
interestTiming,
|
|
160
160
|
),
|
|
161
161
|
bootstrapPaymentValue,
|
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
import { AmountMath } from '@agoric/ertp';
|
|
2
|
+
import {
|
|
3
|
+
ceilDivideBy,
|
|
4
|
+
ceilMultiplyBy,
|
|
5
|
+
floorMultiplyBy,
|
|
6
|
+
makeRatioFromAmounts,
|
|
7
|
+
multiplyRatios,
|
|
8
|
+
} from '@agoric/zoe/src/contractSupport/index.js';
|
|
9
|
+
import { quoteAsRatio, subtractToEmpty } from '../contractSupport.js';
|
|
10
|
+
import { liquidationResults } from './liquidation.js';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* @typedef {{
|
|
14
|
+
* overage: Amount<'nat'>,
|
|
15
|
+
* shortfallToReserve: Amount<'nat'>,
|
|
16
|
+
* collateralForReserve: Amount<'nat'>,
|
|
17
|
+
* actualCollateralSold: Amount<'nat'>,
|
|
18
|
+
* collateralSold: Amount<'nat'>,
|
|
19
|
+
* collatRemaining: Amount<'nat'>,
|
|
20
|
+
* debtToBurn: Amount<'nat'>,
|
|
21
|
+
* mintedForReserve: Amount<'nat'>,
|
|
22
|
+
* mintedProceeds: Amount<'nat'>,
|
|
23
|
+
* phantomDebt: Amount<'nat'>,
|
|
24
|
+
* totalPenalty: Amount<'nat'>,
|
|
25
|
+
* transfersToVault: Array<[number, AmountKeywordRecord]>,
|
|
26
|
+
* vaultsToReinstate: Array<number>
|
|
27
|
+
* }} DistributionPlan
|
|
28
|
+
*
|
|
29
|
+
* The plan to execute for distributing proceeds of a liquidation.
|
|
30
|
+
*
|
|
31
|
+
* Vaults are referenced by index in the list sent to the calculator.
|
|
32
|
+
*/
|
|
33
|
+
|
|
34
|
+
/** @typedef {{ collateral: Amount<'nat'>, presaleDebt: Amount<'nat'>, currentDebt: Amount<'nat'> }} VaultBalances */
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Liquidation.md describes how to process liquidation proceeds.
|
|
38
|
+
*
|
|
39
|
+
* This function is complex and may fail. To defend against this possibility, it
|
|
40
|
+
* starts with a base plan and updates it. The updating is the complex portion
|
|
41
|
+
* and is wrapped in a try/catch. If at any point the plan revising fails, the
|
|
42
|
+
* plan is returned as is.
|
|
43
|
+
*
|
|
44
|
+
* @param {object} inputs
|
|
45
|
+
* @param {AmountKeywordRecord} inputs.proceeds
|
|
46
|
+
* @param {Amount<'nat'>} inputs.totalDebt
|
|
47
|
+
* @param {Amount<'nat'>} inputs.totalCollateral
|
|
48
|
+
* @param {PriceDescription} inputs.oraclePriceAtStart
|
|
49
|
+
* @param {Array<VaultBalances>} inputs.vaultsBalances ordered best to worst collateralized
|
|
50
|
+
* @param {Ratio} inputs.penaltyRate
|
|
51
|
+
* @returns {DistributionPlan}
|
|
52
|
+
*/
|
|
53
|
+
export const calculateDistributionPlan = ({
|
|
54
|
+
proceeds,
|
|
55
|
+
totalDebt,
|
|
56
|
+
totalCollateral,
|
|
57
|
+
oraclePriceAtStart,
|
|
58
|
+
vaultsBalances,
|
|
59
|
+
penaltyRate,
|
|
60
|
+
}) => {
|
|
61
|
+
const emptyCollateral = AmountMath.makeEmptyFromAmount(totalCollateral);
|
|
62
|
+
const emptyMinted = AmountMath.makeEmptyFromAmount(totalDebt);
|
|
63
|
+
|
|
64
|
+
const { Collateral: collateralProceeds } = proceeds;
|
|
65
|
+
/** @type {Amount<'nat'>} */
|
|
66
|
+
const collateralSold = AmountMath.subtract(
|
|
67
|
+
totalCollateral,
|
|
68
|
+
collateralProceeds,
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
const mintedProceeds = proceeds.Minted || emptyMinted;
|
|
72
|
+
const accounting = liquidationResults(totalDebt, mintedProceeds);
|
|
73
|
+
|
|
74
|
+
// charged in collateral
|
|
75
|
+
const totalPenalty = ceilMultiplyBy(
|
|
76
|
+
totalDebt,
|
|
77
|
+
multiplyRatios(penaltyRate, quoteAsRatio(oraclePriceAtStart)),
|
|
78
|
+
);
|
|
79
|
+
|
|
80
|
+
const debtPortion = makeRatioFromAmounts(totalPenalty, totalDebt);
|
|
81
|
+
|
|
82
|
+
// We mutate the plan so that at any point if there's an error the plan can be returned and executed.
|
|
83
|
+
// IOW the plan must always be in a valid state, though perhaps incomplete.
|
|
84
|
+
/** @type {DistributionPlan} */
|
|
85
|
+
const plan = {
|
|
86
|
+
overage: accounting.overage,
|
|
87
|
+
shortfallToReserve: accounting.shortfall,
|
|
88
|
+
collateralForReserve: emptyCollateral,
|
|
89
|
+
actualCollateralSold: emptyCollateral,
|
|
90
|
+
collateralSold,
|
|
91
|
+
collatRemaining: emptyCollateral,
|
|
92
|
+
debtToBurn: emptyMinted,
|
|
93
|
+
mintedForReserve: emptyMinted,
|
|
94
|
+
mintedProceeds,
|
|
95
|
+
phantomDebt: emptyMinted,
|
|
96
|
+
transfersToVault: [],
|
|
97
|
+
vaultsToReinstate: [],
|
|
98
|
+
totalPenalty,
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* If interest was charged between liquidating and liquidated, erase it.
|
|
103
|
+
*
|
|
104
|
+
* @param {VaultBalances} balances
|
|
105
|
+
*/
|
|
106
|
+
const updatePhantomDebt = ({ presaleDebt, currentDebt }) => {
|
|
107
|
+
if (AmountMath.isEqual(presaleDebt, currentDebt)) {
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
const accrued = AmountMath.subtract(currentDebt, presaleDebt);
|
|
111
|
+
plan.phantomDebt = AmountMath.add(plan.phantomDebt, accrued);
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
const runFlow1 = () => {
|
|
115
|
+
// Flow #1: no shortfall
|
|
116
|
+
|
|
117
|
+
const distributableCollateral = subtractToEmpty(
|
|
118
|
+
collateralProceeds,
|
|
119
|
+
totalPenalty,
|
|
120
|
+
);
|
|
121
|
+
|
|
122
|
+
plan.debtToBurn = totalDebt;
|
|
123
|
+
plan.mintedForReserve = accounting.overage;
|
|
124
|
+
|
|
125
|
+
// return remaining funds to vaults before closing
|
|
126
|
+
|
|
127
|
+
let leftToStage = distributableCollateral;
|
|
128
|
+
const price = makeRatioFromAmounts(mintedProceeds, collateralSold);
|
|
129
|
+
|
|
130
|
+
// iterate from best to worst, returning collateral until it has
|
|
131
|
+
// been exhausted. Vaults after that get nothing.
|
|
132
|
+
for (const [vaultIndex, balances] of vaultsBalances.entries()) {
|
|
133
|
+
const { collateral: vCollat, presaleDebt } = balances;
|
|
134
|
+
updatePhantomDebt(balances);
|
|
135
|
+
|
|
136
|
+
// max return is vault value reduced by debt and penalty value
|
|
137
|
+
const debtCollat = ceilDivideBy(presaleDebt, price);
|
|
138
|
+
const penaltyCollat = ceilMultiplyBy(presaleDebt, debtPortion);
|
|
139
|
+
const lessCollat = AmountMath.add(debtCollat, penaltyCollat);
|
|
140
|
+
|
|
141
|
+
const maxCollat = subtractToEmpty(vCollat, lessCollat);
|
|
142
|
+
if (!AmountMath.isEmpty(leftToStage)) {
|
|
143
|
+
const collatReturn = AmountMath.min(leftToStage, maxCollat);
|
|
144
|
+
leftToStage = AmountMath.subtract(leftToStage, collatReturn);
|
|
145
|
+
plan.transfersToVault.push([vaultIndex, { Collateral: collatReturn }]);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
const hasCollateralToDistribute = !AmountMath.isEmpty(
|
|
150
|
+
distributableCollateral,
|
|
151
|
+
);
|
|
152
|
+
plan.collateralForReserve = hasCollateralToDistribute
|
|
153
|
+
? AmountMath.add(leftToStage, totalPenalty)
|
|
154
|
+
: collateralProceeds;
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
// Flow 2a: all collateral was sold but debt was not covered
|
|
158
|
+
const runFlow2a = () => {
|
|
159
|
+
// charge penalty if proceeds are sufficient
|
|
160
|
+
const penaltyInMinted = ceilMultiplyBy(totalDebt, penaltyRate);
|
|
161
|
+
const recoveredDebt = AmountMath.min(
|
|
162
|
+
AmountMath.add(totalDebt, penaltyInMinted),
|
|
163
|
+
mintedProceeds,
|
|
164
|
+
);
|
|
165
|
+
|
|
166
|
+
plan.debtToBurn = recoveredDebt;
|
|
167
|
+
|
|
168
|
+
const distributable = subtractToEmpty(mintedProceeds, recoveredDebt);
|
|
169
|
+
let mintedRemaining = distributable;
|
|
170
|
+
|
|
171
|
+
const vaultPortion = makeRatioFromAmounts(distributable, totalCollateral);
|
|
172
|
+
|
|
173
|
+
// iterate from best to worst returning remaining funds to vaults
|
|
174
|
+
for (const [vaultIndex, balances] of vaultsBalances.entries()) {
|
|
175
|
+
// from best to worst, return minted above penalty if any remains
|
|
176
|
+
const vaultShare = floorMultiplyBy(balances.collateral, vaultPortion);
|
|
177
|
+
updatePhantomDebt(balances);
|
|
178
|
+
|
|
179
|
+
if (!AmountMath.isEmpty(mintedRemaining)) {
|
|
180
|
+
const mintedToReturn = AmountMath.min(mintedRemaining, vaultShare);
|
|
181
|
+
mintedRemaining = AmountMath.subtract(mintedRemaining, mintedToReturn);
|
|
182
|
+
plan.transfersToVault.push([vaultIndex, { Minted: mintedToReturn }]);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
// Flow 2b: collateral remains but debt was not covered
|
|
188
|
+
const runFlow2b = () => {
|
|
189
|
+
plan.debtToBurn = totalDebt;
|
|
190
|
+
plan.mintedForReserve = accounting.overage;
|
|
191
|
+
|
|
192
|
+
// reconstitute vaults until collateral is insufficient
|
|
193
|
+
let reconstituteVaults = AmountMath.isGTE(collateralProceeds, totalPenalty);
|
|
194
|
+
|
|
195
|
+
// charge penalty if proceeds are sufficient
|
|
196
|
+
const distributableCollateral = subtractToEmpty(
|
|
197
|
+
collateralProceeds,
|
|
198
|
+
totalPenalty,
|
|
199
|
+
);
|
|
200
|
+
|
|
201
|
+
plan.collatRemaining = distributableCollateral;
|
|
202
|
+
|
|
203
|
+
let shortfallToReserve = accounting.shortfall;
|
|
204
|
+
const reduceCollateral = amount =>
|
|
205
|
+
(plan.actualCollateralSold = AmountMath.add(
|
|
206
|
+
plan.actualCollateralSold,
|
|
207
|
+
amount,
|
|
208
|
+
));
|
|
209
|
+
|
|
210
|
+
// iterate from best to worst attempting to reconstitute, by
|
|
211
|
+
// returning remaining funds to vaults
|
|
212
|
+
for (const [vaultIndex, balances] of vaultsBalances.entries()) {
|
|
213
|
+
const { collateral: vCollat, presaleDebt } = balances;
|
|
214
|
+
|
|
215
|
+
// according to #7123, Collateral for penalty =
|
|
216
|
+
// total liquidation penalty * vault debt / total debt
|
|
217
|
+
const vaultPenalty = ceilMultiplyBy(presaleDebt, debtPortion);
|
|
218
|
+
const collatPostPenalty = subtractToEmpty(vCollat, vaultPenalty);
|
|
219
|
+
const vaultDebt = floorMultiplyBy(presaleDebt, debtPortion);
|
|
220
|
+
|
|
221
|
+
// Should we continue reconstituting vaults?
|
|
222
|
+
reconstituteVaults =
|
|
223
|
+
reconstituteVaults &&
|
|
224
|
+
!AmountMath.isEmpty(collatPostPenalty) &&
|
|
225
|
+
AmountMath.isGTE(plan.collatRemaining, collatPostPenalty) &&
|
|
226
|
+
AmountMath.isGTE(totalDebt, presaleDebt);
|
|
227
|
+
|
|
228
|
+
if (reconstituteVaults) {
|
|
229
|
+
plan.collatRemaining = AmountMath.subtract(
|
|
230
|
+
plan.collatRemaining,
|
|
231
|
+
collatPostPenalty,
|
|
232
|
+
);
|
|
233
|
+
shortfallToReserve = subtractToEmpty(shortfallToReserve, presaleDebt);
|
|
234
|
+
// must reinstate after atomicRearrange(), so we record them.
|
|
235
|
+
plan.vaultsToReinstate.push(vaultIndex);
|
|
236
|
+
reduceCollateral(vaultDebt);
|
|
237
|
+
plan.transfersToVault.push([
|
|
238
|
+
vaultIndex,
|
|
239
|
+
{ Collateral: collatPostPenalty },
|
|
240
|
+
]);
|
|
241
|
+
} else {
|
|
242
|
+
updatePhantomDebt(balances);
|
|
243
|
+
|
|
244
|
+
reduceCollateral(vCollat);
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
plan.collateralForReserve = AmountMath.add(
|
|
249
|
+
plan.collatRemaining,
|
|
250
|
+
totalPenalty,
|
|
251
|
+
);
|
|
252
|
+
|
|
253
|
+
plan.shortfallToReserve = shortfallToReserve;
|
|
254
|
+
};
|
|
255
|
+
|
|
256
|
+
try {
|
|
257
|
+
if (AmountMath.isEmpty(accounting.shortfall)) {
|
|
258
|
+
// Flow #1: no shortfall
|
|
259
|
+
runFlow1();
|
|
260
|
+
} else if (AmountMath.isEmpty(collateralProceeds)) {
|
|
261
|
+
// Flow 2a: all collateral was sold but debt was not covered
|
|
262
|
+
runFlow2a();
|
|
263
|
+
} else {
|
|
264
|
+
// Flow #2b: There's unsold collateral; some vaults may be reinstated.
|
|
265
|
+
runFlow2b();
|
|
266
|
+
}
|
|
267
|
+
} catch (err) {
|
|
268
|
+
console.error('🚨 Failure running distribution flow:', err);
|
|
269
|
+
// continue to return `plan` in the state that was reached
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
return harden(plan);
|
|
273
|
+
};
|
|
274
|
+
harden(calculateDistributionPlan);
|
|
@@ -21,15 +21,6 @@
|
|
|
21
21
|
* @property {() => Invitation} makeSwapInvitation
|
|
22
22
|
*/
|
|
23
23
|
|
|
24
|
-
/**
|
|
25
|
-
* @typedef {object} Collateral
|
|
26
|
-
* @property {Ratio} liquidationMargin
|
|
27
|
-
* @property {Ratio} stabilityFee
|
|
28
|
-
* @property {Ratio} marketPrice
|
|
29
|
-
* @property {Ratio} interestRate
|
|
30
|
-
* @property {Brand} brand
|
|
31
|
-
*/
|
|
32
|
-
|
|
33
24
|
/**
|
|
34
25
|
* @typedef {object} VaultManagerParamValues
|
|
35
26
|
* @property {Ratio} liquidationMargin - margin below which collateral will be
|
|
@@ -108,7 +99,7 @@
|
|
|
108
99
|
* @typedef {object} LiquidationStrategy
|
|
109
100
|
* @property {() => KeywordKeywordRecord} keywordMapping
|
|
110
101
|
* @property {(collateral: Amount, run: Amount) => Proposal} makeProposal
|
|
111
|
-
* @property {(
|
|
102
|
+
* @property {(debt: Amount) => Promise<Invitation>} makeInvitation
|
|
112
103
|
*/
|
|
113
104
|
|
|
114
105
|
/**
|
|
@@ -15,9 +15,6 @@ import {
|
|
|
15
15
|
import { assertKeywordName } from '@agoric/zoe/src/cleanProposal.js';
|
|
16
16
|
import {
|
|
17
17
|
atomicRearrange,
|
|
18
|
-
getAmountIn,
|
|
19
|
-
getAmountOut,
|
|
20
|
-
makeRatioFromAmounts,
|
|
21
18
|
makeRecorderTopic,
|
|
22
19
|
provideEmptySeat,
|
|
23
20
|
SubscriberShape,
|
|
@@ -87,7 +84,7 @@ const shortfallInvitationKey = 'shortfallInvitation';
|
|
|
87
84
|
* @param {import('@agoric/zoe/src/contractSupport/recorder.js').MakeRecorderKit} makeRecorderKit
|
|
88
85
|
* @param {import('@agoric/zoe/src/contractSupport/recorder.js').MakeERecorderKit} makeERecorderKit
|
|
89
86
|
*/
|
|
90
|
-
|
|
87
|
+
const prepareVaultDirector = (
|
|
91
88
|
baggage,
|
|
92
89
|
zcf,
|
|
93
90
|
directorParamManager,
|
|
@@ -299,9 +296,7 @@ export const prepareVaultDirector = (
|
|
|
299
296
|
}),
|
|
300
297
|
public: M.interface('public', {
|
|
301
298
|
getCollateralManager: M.call(BrandShape).returns(M.remotable()),
|
|
302
|
-
|
|
303
|
-
getMetrics: M.call().returns(SubscriberShape),
|
|
304
|
-
getRunIssuer: M.call().returns(IssuerShape),
|
|
299
|
+
getDebtIssuer: M.call().returns(IssuerShape),
|
|
305
300
|
getSubscription: M.call({ collateralBrand: BrandShape }).returns(
|
|
306
301
|
SubscriberShape,
|
|
307
302
|
),
|
|
@@ -454,44 +449,10 @@ export const prepareVaultDirector = (
|
|
|
454
449
|
/** @type {VaultManager} */
|
|
455
450
|
return managerForCollateral(brandIn).getPublicFacet();
|
|
456
451
|
},
|
|
457
|
-
|
|
458
|
-
* @deprecated get `collaterals` list from metrics
|
|
459
|
-
*/
|
|
460
|
-
async getCollaterals() {
|
|
461
|
-
// should be collateralManagers.map((vm, brand) => ({
|
|
462
|
-
return harden(
|
|
463
|
-
Promise.all(
|
|
464
|
-
[...collateralManagers.entries()].map(
|
|
465
|
-
async ([brand, managerIndex]) => {
|
|
466
|
-
const vm = vaultManagers.get(managerIndex).self;
|
|
467
|
-
const priceQuote = await vm.getCollateralQuote();
|
|
468
|
-
return {
|
|
469
|
-
brand,
|
|
470
|
-
interestRate: vm.getGovernedParams().getInterestRate(),
|
|
471
|
-
liquidationMargin: vm
|
|
472
|
-
.getGovernedParams()
|
|
473
|
-
.getLiquidationMargin(),
|
|
474
|
-
stabilityFee: vm.getGovernedParams().getMintFee(),
|
|
475
|
-
marketPrice: makeRatioFromAmounts(
|
|
476
|
-
getAmountOut(priceQuote),
|
|
477
|
-
getAmountIn(priceQuote),
|
|
478
|
-
),
|
|
479
|
-
};
|
|
480
|
-
},
|
|
481
|
-
),
|
|
482
|
-
),
|
|
483
|
-
);
|
|
484
|
-
},
|
|
485
|
-
/** @deprecated use getPublicTopics */
|
|
486
|
-
getMetrics() {
|
|
487
|
-
return metricsKit.subscriber;
|
|
488
|
-
},
|
|
489
|
-
getRunIssuer() {
|
|
452
|
+
getDebtIssuer() {
|
|
490
453
|
return debtMint.getIssuerRecord().issuer;
|
|
491
454
|
},
|
|
492
455
|
/**
|
|
493
|
-
* @deprecated get from the CollateralManager directly
|
|
494
|
-
*
|
|
495
456
|
* subscription for the paramManager for a particular vaultManager
|
|
496
457
|
*
|
|
497
458
|
* @param {{ collateralBrand: Brand }} selector
|
|
@@ -13,9 +13,9 @@ import '@agoric/zoe/src/contracts/exported.js';
|
|
|
13
13
|
|
|
14
14
|
// This contract wants to be managed by a contractGovernor, but it isn't
|
|
15
15
|
// compatible with contractGovernor, since it has a separate paramManager for
|
|
16
|
-
// each
|
|
17
|
-
// to satisfy contractGovernor. It needs to return a creatorFacet
|
|
18
|
-
// { getParamMgrRetriever, getInvitation, getLimitedCreatorFacet }.
|
|
16
|
+
// each VaultManager. This requires it to manually replicate the API of
|
|
17
|
+
// contractHelper to satisfy contractGovernor. It needs to return a creatorFacet
|
|
18
|
+
// with { getParamMgrRetriever, getInvitation, getLimitedCreatorFacet }.
|
|
19
19
|
|
|
20
20
|
import { CONTRACT_ELECTORATE } from '@agoric/governance';
|
|
21
21
|
import { makeParamManagerFromTerms } from '@agoric/governance/src/contractGovernance/typedParamManager.js';
|
|
@@ -3,10 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import { AmountShape } from '@agoric/ertp';
|
|
5
5
|
import { M, prepareExoClassKit } from '@agoric/vat-data';
|
|
6
|
-
import {
|
|
7
|
-
SubscriberShape,
|
|
8
|
-
TopicsRecordShape,
|
|
9
|
-
} from '@agoric/zoe/src/contractSupport/index.js';
|
|
6
|
+
import { TopicsRecordShape } from '@agoric/zoe/src/contractSupport/index.js';
|
|
10
7
|
import { UnguardedHelperI } from '../typeGuards.js';
|
|
11
8
|
|
|
12
9
|
const { Fail } = assert;
|
|
@@ -22,7 +19,6 @@ const HolderI = M.interface('holder', {
|
|
|
22
19
|
getCollateralAmount: M.call().returns(AmountShape),
|
|
23
20
|
getCurrentDebt: M.call().returns(AmountShape),
|
|
24
21
|
getNormalizedDebt: M.call().returns(AmountShape),
|
|
25
|
-
getSubscriber: M.call().returns(SubscriberShape),
|
|
26
22
|
getPublicTopics: M.call().returns(TopicsRecordShape),
|
|
27
23
|
makeAdjustBalancesInvitation: M.call().returns(M.promise()),
|
|
28
24
|
makeCloseInvitation: M.call().returns(M.promise()),
|
|
@@ -91,10 +87,6 @@ export const prepareVaultHolder = (baggage, makeRecorderKit) => {
|
|
|
91
87
|
},
|
|
92
88
|
},
|
|
93
89
|
holder: {
|
|
94
|
-
/** @deprecated use getPublicTopics */
|
|
95
|
-
getSubscriber() {
|
|
96
|
-
return this.state.topicKit.subscriber;
|
|
97
|
-
},
|
|
98
90
|
getPublicTopics() {
|
|
99
91
|
const { topicKit } = this.state;
|
|
100
92
|
return harden({
|