@agoric/inter-protocol 0.13.3 → 0.13.4-dev-d32a66a.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/README.md +26 -20
- package/bundles/bundle-auctioneer-js-meta.json +722 -0
- package/bundles/bundle-auctioneer.js +1 -0
- package/bundles/bundle-econCommitteeCharter-js-meta.json +514 -0
- package/bundles/bundle-econCommitteeCharter.js +1 -0
- package/bundles/bundle-feeDistributor-js-meta.json +458 -0
- package/bundles/bundle-feeDistributor.js +1 -1
- package/bundles/bundle-fluxAggregatorKit-js-meta.json +674 -0
- package/bundles/bundle-fluxAggregatorKit.js +1 -0
- package/bundles/bundle-psm-js-meta.json +666 -0
- package/bundles/bundle-psm.js +1 -1
- package/bundles/bundle-reserve-js-meta.json +662 -0
- package/bundles/bundle-reserve.js +1 -1
- package/bundles/bundle-scaledPriceAuthority-js-meta.json +542 -0
- package/bundles/bundle-scaledPriceAuthority.js +1 -1
- package/bundles/bundle-vaultFactory-js-meta.json +786 -0
- package/bundles/bundle-vaultFactory.js +1 -1
- package/exported.js +0 -2
- package/package.json +34 -31
- package/scripts/add-collateral-core.js +14 -4
- package/scripts/build-bundles.js +9 -2
- package/scripts/deploy-contracts.js +1 -4
- package/scripts/init-core.js +20 -38
- package/scripts/invite-committee-core.js +1 -1
- package/scripts/manual-price-feed.js +2 -2
- package/scripts/price-feed-core.js +7 -6
- package/scripts/start-local-chain.sh +84 -0
- package/src/auction/auctionBook.js +755 -0
- package/src/auction/auctioneer.js +720 -0
- package/src/auction/offerBook.js +221 -0
- package/src/auction/params.js +174 -0
- package/src/auction/scheduleMath.js +167 -0
- package/src/auction/scheduler.js +370 -0
- package/src/auction/sortedOffers.js +136 -0
- package/src/auction/util.js +55 -0
- package/src/clientSupport.js +324 -0
- package/src/collectFees.js +8 -14
- package/src/contractSupport.js +24 -68
- package/src/econCommitteeCharter.js +161 -77
- package/src/feeDistributor.js +60 -20
- package/src/index.js +2 -0
- package/src/interest-math.js +1 -4
- package/src/interest.js +20 -13
- package/src/price/README.md +57 -0
- package/src/price/fluxAggregatorContract.js +190 -0
- package/src/price/fluxAggregatorKit.js +375 -0
- package/src/price/priceOracleKit.js +127 -0
- package/src/price/roundsManager.js +726 -0
- package/src/proposals/addAssetToVault.js +89 -94
- package/src/proposals/committee-proposal.js +141 -40
- package/src/proposals/core-proposal.js +100 -167
- package/src/proposals/econ-behaviors.js +320 -564
- package/src/proposals/price-feed-proposal.js +175 -78
- package/src/proposals/startEconCommittee.js +25 -12
- package/src/proposals/startPSM.js +231 -211
- package/src/proposals/utils.js +31 -17
- package/src/psm/README.md +71 -0
- package/src/psm/psm.js +272 -160
- package/src/psm/types.js +2 -0
- package/src/reserve/assetReserve.js +56 -413
- package/src/reserve/assetReserveKit.js +303 -0
- package/src/reserve/doc.md +1 -3
- package/src/reserve/params.js +2 -5
- package/src/typeGuards.js +13 -0
- package/src/vaultFactory/Liquidation.md +100 -0
- package/src/vaultFactory/burn.js +2 -1
- package/src/vaultFactory/liquidation.js +270 -108
- package/src/vaultFactory/math.js +95 -0
- package/src/vaultFactory/orderedVaultStore.js +0 -1
- package/src/vaultFactory/params.js +133 -112
- package/src/vaultFactory/prioritizedVaults.js +36 -79
- package/src/vaultFactory/storeUtils.js +67 -9
- package/src/vaultFactory/type-imports.js +2 -0
- package/src/vaultFactory/types.js +22 -26
- package/src/vaultFactory/vault.js +772 -709
- package/src/vaultFactory/vaultDirector.js +480 -483
- package/src/vaultFactory/vaultFactory.js +99 -60
- package/src/vaultFactory/vaultHolder.js +121 -95
- package/src/vaultFactory/vaultKit.js +39 -31
- package/src/vaultFactory/vaultManager.js +1249 -868
- package/bundles/bundle-amm-meta.js +0 -618
- package/bundles/bundle-amm.js +0 -1
- package/bundles/bundle-feeDistributor-meta.js +0 -346
- package/bundles/bundle-interchainPool-meta.js +0 -534
- package/bundles/bundle-interchainPool.js +0 -1
- package/bundles/bundle-liquidateIncrementally-meta.js +0 -442
- package/bundles/bundle-liquidateIncrementally.js +0 -1
- package/bundles/bundle-liquidateMinimum-meta.js +0 -442
- package/bundles/bundle-liquidateMinimum.js +0 -1
- package/bundles/bundle-psm-meta.js +0 -538
- package/bundles/bundle-psmCharter-meta.js +0 -418
- package/bundles/bundle-psmCharter.js +0 -1
- package/bundles/bundle-reserve-meta.js +0 -542
- package/bundles/bundle-scaledPriceAuthority-meta.js +0 -442
- package/bundles/bundle-stakeFactory-meta.js +0 -574
- package/bundles/bundle-stakeFactory.js +0 -1
- package/bundles/bundle-vaultFactory-meta.js +0 -598
- package/scripts/add-initial-liquidity.js +0 -180
- package/src/collect.js +0 -13
- package/src/interchainPool.js +0 -135
- package/src/makeTracer.js +0 -36
- package/src/my-lien.js +0 -85
- package/src/proposals/demoIssuers.js +0 -685
- package/src/proposals/sim-behaviors.js +0 -40
- package/src/psm/psmCharter.js +0 -139
- package/src/stakeFactory/README.md +0 -62
- package/src/stakeFactory/attestation.js +0 -267
- package/src/stakeFactory/attestationTool.js +0 -66
- package/src/stakeFactory/constants.js +0 -16
- package/src/stakeFactory/params.js +0 -31
- package/src/stakeFactory/stakeFactory.js +0 -236
- package/src/stakeFactory/stakeFactoryKit.js +0 -455
- package/src/stakeFactory/stakeFactoryManager.js +0 -296
- package/src/stakeFactory/types.js +0 -42
- package/src/vaultFactory/liquidateIncrementally.js +0 -350
- package/src/vaultFactory/liquidateMinimum.js +0 -100
- package/src/vpool-xyk-amm/AttackersGuide.md +0 -89
- package/src/vpool-xyk-amm/addLiquidity.js +0 -222
- package/src/vpool-xyk-amm/addPool.js +0 -197
- package/src/vpool-xyk-amm/constantProduct/AMM-Trade.jpeg +0 -0
- package/src/vpool-xyk-amm/constantProduct/README.md +0 -204
- package/src/vpool-xyk-amm/constantProduct/calcFees.js +0 -99
- package/src/vpool-xyk-amm/constantProduct/calcSwapPrices.js +0 -85
- package/src/vpool-xyk-amm/constantProduct/core.js +0 -153
- package/src/vpool-xyk-amm/constantProduct/defaults.js +0 -5
- package/src/vpool-xyk-amm/constantProduct/getXY.js +0 -52
- package/src/vpool-xyk-amm/constantProduct/internal-types.js +0 -116
- package/src/vpool-xyk-amm/constantProduct/invariants.js +0 -43
- package/src/vpool-xyk-amm/constantProduct/swap.js +0 -272
- package/src/vpool-xyk-amm/constantProduct/types.js +0 -32
- package/src/vpool-xyk-amm/doublePool.js +0 -194
- package/src/vpool-xyk-amm/estimate.js +0 -155
- package/src/vpool-xyk-amm/multipoolMarketMaker.js +0 -520
- package/src/vpool-xyk-amm/params.js +0 -61
- package/src/vpool-xyk-amm/pool.js +0 -396
- package/src/vpool-xyk-amm/priceAuthority.js +0 -94
- package/src/vpool-xyk-amm/removeLiquidity.js +0 -31
- package/src/vpool-xyk-amm/singlePool.js +0 -73
- package/src/vpool-xyk-amm/swap.js +0 -69
- package/src/vpool-xyk-amm/types.js +0 -154
|
@@ -1,144 +1,306 @@
|
|
|
1
|
-
// @ts-check
|
|
2
1
|
// @jessie-check
|
|
3
2
|
|
|
4
|
-
import { E } from '@endo/eventual-send';
|
|
5
3
|
import { AmountMath } from '@agoric/ertp';
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
} from '@agoric/zoe/src/contractSupport/index.js';
|
|
11
|
-
import {
|
|
4
|
+
import { makeTracer } from '@agoric/internal';
|
|
5
|
+
import { observeIteration, subscribeEach } from '@agoric/notifier';
|
|
6
|
+
import { makeScalarMapStore } from '@agoric/store';
|
|
7
|
+
import { TimeMath } from '@agoric/time';
|
|
8
|
+
import { atomicRearrange } from '@agoric/zoe/src/contractSupport/index.js';
|
|
9
|
+
import { E } from '@endo/eventual-send';
|
|
10
|
+
|
|
11
|
+
import { AUCTION_START_DELAY, PRICE_LOCK_PERIOD } from '../auction/params.js';
|
|
12
|
+
import { makeCancelTokenMaker } from '../auction/util.js';
|
|
13
|
+
|
|
14
|
+
const trace = makeTracer('LIQ');
|
|
12
15
|
|
|
13
|
-
|
|
16
|
+
/** @typedef {import('@agoric/time/src/types').TimerService} TimerService */
|
|
17
|
+
/** @typedef {import('@agoric/time/src/types').TimerWaker} TimerWaker */
|
|
18
|
+
/** @typedef {import('@agoric/time/src/types').CancelToken} CancelToken */
|
|
19
|
+
/** @typedef {import('@agoric/time/src/types').RelativeTimeRecord} RelativeTimeRecord */
|
|
20
|
+
|
|
21
|
+
const makeCancelToken = makeCancelTokenMaker('liq');
|
|
14
22
|
|
|
15
23
|
/**
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
* liquidationMargin above its debt.
|
|
24
|
+
* This will normally be set. If the schedule goes sideways, we'll unschedule
|
|
25
|
+
* all events and unset it. When auction params are changed, we'll restart the schedule
|
|
19
26
|
*
|
|
20
|
-
* @
|
|
21
|
-
* @param {Ratio} liquidationMargin
|
|
27
|
+
* @type {object | undefined}
|
|
22
28
|
*/
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
29
|
+
let cancelToken = makeCancelToken();
|
|
30
|
+
|
|
31
|
+
const waitForRepair = () => {
|
|
32
|
+
// the params observer will setWakeup to resume.
|
|
33
|
+
console.warn(
|
|
34
|
+
'🛠️ No wake for reschedule. Repair by resetting auction params.',
|
|
27
35
|
);
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
// Generally, canceling wakups has to be followed by setting up new ones but
|
|
39
|
+
// not in the case of pausing wakeups. We do that in the event of invalid
|
|
40
|
+
// schedule params. When they are repaired by governance, the wakers resume.
|
|
41
|
+
/** @param {ERef<TimerService>} timer */
|
|
42
|
+
const cancelWakeups = timer => {
|
|
43
|
+
if (cancelToken) {
|
|
44
|
+
void E(timer).cancel(cancelToken);
|
|
45
|
+
}
|
|
46
|
+
cancelToken = undefined;
|
|
47
|
+
};
|
|
28
48
|
|
|
29
49
|
/**
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
50
|
+
* Schedule wakeups for the *next* auction round.
|
|
51
|
+
*
|
|
52
|
+
* In practice, there are these cases to handle (with N as "live" and N+1 is "next"):
|
|
53
|
+
*
|
|
54
|
+
* | when (now within the range) | what |
|
|
55
|
+
* | -------------------------------- | --------------------------------------- |
|
|
56
|
+
* | [start N, nominalStart N+1] | good: schedule normally the three wakers|
|
|
57
|
+
* | (nominalStart N+1, endTime N+1] | recover: skip round N+1 and schedule N+2|
|
|
58
|
+
* | (endTime N+1, ∞) | give up: wait for repair by governance |
|
|
59
|
+
*
|
|
60
|
+
* @param {object} opts
|
|
61
|
+
* @param {ERef<TimerService>} opts.timer
|
|
62
|
+
* @param {TimerWaker} opts.priceLockWaker
|
|
63
|
+
* @param {TimerWaker} opts.liquidationWaker
|
|
64
|
+
* @param {TimerWaker} opts.reschedulerWaker
|
|
65
|
+
* @param {import('../auction/scheduler.js').Schedule} opts.nextAuctionSchedule
|
|
66
|
+
* @param {import('@agoric/time/src/types').TimestampRecord} opts.now
|
|
67
|
+
* @param {ParamStateRecord} opts.params
|
|
68
|
+
* @returns {void}
|
|
33
69
|
*/
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
70
|
+
const setWakeups = ({
|
|
71
|
+
nextAuctionSchedule,
|
|
72
|
+
now,
|
|
73
|
+
timer,
|
|
74
|
+
reschedulerWaker,
|
|
75
|
+
liquidationWaker,
|
|
76
|
+
priceLockWaker,
|
|
77
|
+
params,
|
|
78
|
+
}) => {
|
|
79
|
+
const { startTime, endTime } = nextAuctionSchedule;
|
|
80
|
+
|
|
81
|
+
/** @type {RelativeTimeRecord} */
|
|
82
|
+
// @ts-expect-error Casting
|
|
83
|
+
// eslint-disable-next-line no-restricted-syntax -- https://github.com/Agoric/eslint-config-jessie/issues/33
|
|
84
|
+
const priceLockPeriod = params[PRICE_LOCK_PERIOD].value;
|
|
85
|
+
/** @type {RelativeTimeRecord} */
|
|
86
|
+
// @ts-expect-error Casting
|
|
87
|
+
// eslint-disable-next-line no-restricted-syntax -- https://github.com/Agoric/eslint-config-jessie/issues/33
|
|
88
|
+
const auctionStartDelay = params[AUCTION_START_DELAY].value;
|
|
89
|
+
|
|
90
|
+
// nominal is the declared start time, but the actual auctioning begins after auctionStartDelay
|
|
91
|
+
const nominalStart = TimeMath.subtractAbsRel(startTime, auctionStartDelay);
|
|
92
|
+
|
|
93
|
+
// Is there a problem (case 2 or 3)?
|
|
94
|
+
// setWakeupsForNextAuction is supposed to be called just after an auction
|
|
95
|
+
// started. If we're late but there's still time for the nominal start, then
|
|
96
|
+
// we'll proceed. Reschedule for the next round if that's still in the future.
|
|
97
|
+
// Otherwise, wait for governance params to change.
|
|
98
|
+
if (TimeMath.compareAbs(now, nominalStart) > 0) {
|
|
99
|
+
// nominalStart is past, so cancel timers and plan to recover
|
|
100
|
+
cancelWakeups(timer);
|
|
101
|
+
|
|
102
|
+
if (TimeMath.compareAbs(now, endTime) < 0) {
|
|
103
|
+
// We're currently scheduling the N+1 (where N is live), but we need to skip it.
|
|
104
|
+
// So wake up for the N+2 round's startTime
|
|
105
|
+
const afterNextStartTime = TimeMath.addAbsRel(endTime, 1n);
|
|
106
|
+
trace(
|
|
107
|
+
'CASE 2: endTime is in the future or now so reschedule waking to startTime of the following round',
|
|
108
|
+
afterNextStartTime,
|
|
109
|
+
);
|
|
110
|
+
void E(timer).setWakeup(afterNextStartTime, reschedulerWaker);
|
|
111
|
+
} else {
|
|
112
|
+
trace('CASE 3: endTime is past; wait for repair');
|
|
113
|
+
waitForRepair();
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
trace('CASE 1: nominalStart is now or in the future');
|
|
119
|
+
|
|
120
|
+
cancelToken = cancelToken || makeCancelToken();
|
|
121
|
+
const priceLockWakeTime = TimeMath.subtractAbsRel(
|
|
122
|
+
nominalStart,
|
|
123
|
+
priceLockPeriod,
|
|
38
124
|
);
|
|
125
|
+
const a = t => TimeMath.absValue(t);
|
|
126
|
+
trace('scheduling ', a(priceLockWakeTime), a(nominalStart), a(startTime));
|
|
127
|
+
void E(timer).setWakeup(priceLockWakeTime, priceLockWaker, cancelToken);
|
|
128
|
+
void E(timer).setWakeup(nominalStart, liquidationWaker, cancelToken);
|
|
129
|
+
// Call setWakeupsForNextAuction again one tick after nominalStart
|
|
130
|
+
const afterStart = TimeMath.addAbsRel(startTime, 1n);
|
|
131
|
+
void E(timer).setWakeup(afterStart, reschedulerWaker, cancelToken);
|
|
39
132
|
};
|
|
40
133
|
|
|
41
134
|
/**
|
|
135
|
+
* Schedule wakeups for the *next* auction round.
|
|
136
|
+
*
|
|
137
|
+
* Called by vaultDirector's resetWakeupsForNextAuction at start() and every
|
|
138
|
+
* time there's a "reschedule" wakeup.
|
|
42
139
|
*
|
|
43
|
-
* @param {
|
|
44
|
-
* @param {
|
|
45
|
-
* @param {
|
|
140
|
+
* @param {ERef<import('../auction/auctioneer.js').AuctioneerPublicFacet>} auctioneerPublicFacet
|
|
141
|
+
* @param {ERef<TimerService>} timer
|
|
142
|
+
* @param {TimerWaker} priceLockWaker
|
|
143
|
+
* @param {TimerWaker} liquidationWaker
|
|
144
|
+
* @param {TimerWaker} reschedulerWaker
|
|
145
|
+
* @returns {Promise<void>}
|
|
46
146
|
*/
|
|
47
|
-
const
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
147
|
+
const setWakeupsForNextAuction = async (
|
|
148
|
+
auctioneerPublicFacet,
|
|
149
|
+
timer,
|
|
150
|
+
priceLockWaker,
|
|
151
|
+
liquidationWaker,
|
|
152
|
+
reschedulerWaker,
|
|
153
|
+
) => {
|
|
154
|
+
const [{ nextAuctionSchedule }, params, now] = await Promise.all([
|
|
155
|
+
E(auctioneerPublicFacet).getSchedules(),
|
|
156
|
+
E(auctioneerPublicFacet).getGovernedParams(),
|
|
157
|
+
E(timer).getCurrentTimestamp(),
|
|
158
|
+
]);
|
|
159
|
+
|
|
160
|
+
trace('SCHEDULE', now.absValue, nextAuctionSchedule);
|
|
161
|
+
if (!nextAuctionSchedule) {
|
|
162
|
+
// There should always be a nextAuctionSchedule. If there isn't, give up for now.
|
|
163
|
+
cancelWakeups(timer);
|
|
164
|
+
waitForRepair();
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
setWakeups({
|
|
169
|
+
nextAuctionSchedule,
|
|
170
|
+
now,
|
|
171
|
+
timer,
|
|
172
|
+
reschedulerWaker,
|
|
173
|
+
liquidationWaker,
|
|
174
|
+
priceLockWaker,
|
|
175
|
+
params,
|
|
176
|
+
});
|
|
52
177
|
};
|
|
53
178
|
|
|
54
179
|
/**
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
180
|
+
* @param {Amount<'nat'>} debt
|
|
181
|
+
* @param {Amount<'nat'>} minted
|
|
182
|
+
* @returns {{ overage: Amount<'nat'>, shortfall: Amount<'nat'>, toBurn: Amount<'nat'>}}
|
|
183
|
+
*/
|
|
184
|
+
const liquidationResults = (debt, minted) => {
|
|
185
|
+
if (AmountMath.isEmpty(minted)) {
|
|
186
|
+
return {
|
|
187
|
+
overage: minted,
|
|
188
|
+
toBurn: minted,
|
|
189
|
+
shortfall: debt,
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
const [overage, shortfall] = AmountMath.isGTE(debt, minted)
|
|
194
|
+
? [AmountMath.makeEmptyFromAmount(debt), AmountMath.subtract(debt, minted)]
|
|
195
|
+
: [AmountMath.subtract(minted, debt), AmountMath.makeEmptyFromAmount(debt)];
|
|
196
|
+
|
|
197
|
+
const toBurn = AmountMath.min(minted, debt);
|
|
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
|
+
};
|
|
206
|
+
};
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Watch governed params for change
|
|
61
210
|
*
|
|
211
|
+
* @param {ERef<import('../auction/auctioneer.js').AuctioneerPublicFacet>} auctioneerPublicFacet
|
|
212
|
+
* @param {ERef<TimerService>} timer
|
|
213
|
+
* @param {TimerWaker} reschedulerWaker
|
|
214
|
+
* @returns {void}
|
|
215
|
+
*/
|
|
216
|
+
export const watchForGovernanceChange = (
|
|
217
|
+
auctioneerPublicFacet,
|
|
218
|
+
timer,
|
|
219
|
+
reschedulerWaker,
|
|
220
|
+
) => {
|
|
221
|
+
void E.when(E(timer).getCurrentTimestamp(), now =>
|
|
222
|
+
// make one observer that will usually ignore the update.
|
|
223
|
+
observeIteration(
|
|
224
|
+
subscribeEach(E(auctioneerPublicFacet).getSubscription()),
|
|
225
|
+
harden({
|
|
226
|
+
async updateState(_newState) {
|
|
227
|
+
if (!cancelToken) {
|
|
228
|
+
cancelToken = makeCancelToken();
|
|
229
|
+
void E(timer).setWakeup(
|
|
230
|
+
// bump one tick to prevent an infinite loop
|
|
231
|
+
TimeMath.addAbsRel(now, 1n),
|
|
232
|
+
reschedulerWaker,
|
|
233
|
+
cancelToken,
|
|
234
|
+
);
|
|
235
|
+
}
|
|
236
|
+
},
|
|
237
|
+
}),
|
|
238
|
+
),
|
|
239
|
+
);
|
|
240
|
+
};
|
|
241
|
+
|
|
242
|
+
/**
|
|
62
243
|
* @param {ZCF} zcf
|
|
63
|
-
* @param {
|
|
64
|
-
* @param {
|
|
65
|
-
* @param {
|
|
66
|
-
* @param {Ratio}
|
|
244
|
+
* @param {object} collateralizationDetails
|
|
245
|
+
* @param {PriceQuote} collateralizationDetails.quote
|
|
246
|
+
* @param {Ratio} collateralizationDetails.interest
|
|
247
|
+
* @param {Ratio} collateralizationDetails.margin
|
|
248
|
+
* @param {ReturnType<typeof import('./prioritizedVaults.js').makePrioritizedVaults>} prioritizedVaults
|
|
249
|
+
* @param {SetStore<Vault>} liquidatingVaults
|
|
250
|
+
* @param {Brand<'nat'>} debtBrand
|
|
251
|
+
* @param {Brand<'nat'>} collateralBrand
|
|
252
|
+
* @returns {{
|
|
253
|
+
* vaultData: MapStore<Vault, { collateralAmount: Amount<'nat'>, debtAmount: Amount<'nat'>}>,
|
|
254
|
+
* totalDebt: Amount<'nat'>,
|
|
255
|
+
* totalCollateral: Amount<'nat'>,
|
|
256
|
+
* liqSeat: ZCFSeat}}
|
|
67
257
|
*/
|
|
68
|
-
const
|
|
258
|
+
const getLiquidatableVaults = (
|
|
69
259
|
zcf,
|
|
70
|
-
|
|
71
|
-
|
|
260
|
+
collateralizationDetails,
|
|
261
|
+
prioritizedVaults,
|
|
262
|
+
liquidatingVaults,
|
|
263
|
+
debtBrand,
|
|
72
264
|
collateralBrand,
|
|
73
|
-
penaltyRate,
|
|
74
265
|
) => {
|
|
75
|
-
|
|
76
|
-
|
|
266
|
+
const vaultsToLiquidate = prioritizedVaults.removeVaultsBelow(
|
|
267
|
+
collateralizationDetails,
|
|
268
|
+
);
|
|
269
|
+
/** @type {MapStore<Vault, { collateralAmount: Amount<'nat'>, debtAmount: Amount<'nat'>}>} */
|
|
270
|
+
const vaultData = makeScalarMapStore();
|
|
77
271
|
|
|
78
|
-
const
|
|
272
|
+
const { zcfSeat: liqSeat } = zcf.makeEmptySeatKit();
|
|
273
|
+
let totalDebt = AmountMath.makeEmpty(debtBrand);
|
|
274
|
+
let totalCollateral = AmountMath.makeEmpty(collateralBrand);
|
|
275
|
+
/** @type {import('@agoric/zoe/src/contractSupport/atomicTransfer.js').TransferPart[]} */
|
|
276
|
+
const transfers = [];
|
|
79
277
|
|
|
80
|
-
const
|
|
278
|
+
for (const vault of vaultsToLiquidate.values()) {
|
|
279
|
+
vault.liquidating();
|
|
280
|
+
liquidatingVaults.add(vault);
|
|
81
281
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
collateralBrand,
|
|
85
|
-
);
|
|
86
|
-
trace(`liq prep`, { collateralToSell, debt, liquidator });
|
|
87
|
-
|
|
88
|
-
const { deposited, userSeatPromise: liqSeat } = await offerTo(
|
|
89
|
-
zcf,
|
|
90
|
-
E(liquidator).makeLiquidateInvitation(),
|
|
91
|
-
harden({ Collateral: 'In', Minted: 'Out' }),
|
|
92
|
-
harden({
|
|
93
|
-
give: { In: collateralToSell },
|
|
94
|
-
want: { Out: AmountMath.makeEmpty(debt.brand) },
|
|
95
|
-
}),
|
|
96
|
-
vaultZcfSeat,
|
|
97
|
-
vaultZcfSeat,
|
|
98
|
-
harden({ debt, penaltyRate }),
|
|
99
|
-
);
|
|
100
|
-
trace(` offeredTo`, { collateralToSell, debt });
|
|
282
|
+
const collateralAmount = vault.getCollateralAmount();
|
|
283
|
+
totalCollateral = AmountMath.add(totalCollateral, collateralAmount);
|
|
101
284
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
AmountMath.makeEmptyFromAmount(debt),
|
|
112
|
-
AmountMath.subtract(debt, proceeds.Minted),
|
|
113
|
-
]
|
|
114
|
-
: [
|
|
115
|
-
AmountMath.subtract(proceeds.Minted, debt),
|
|
116
|
-
AmountMath.makeEmptyFromAmount(debt),
|
|
117
|
-
];
|
|
118
|
-
|
|
119
|
-
const toBurn = AmountMath.min(proceeds.Minted, debt);
|
|
120
|
-
// debt is fully accounted for, with toBurn and shortfall
|
|
121
|
-
assert(AmountMath.isEqual(debt, AmountMath.add(toBurn, shortfall)));
|
|
285
|
+
const debtAmount = vault.getCurrentDebt();
|
|
286
|
+
totalDebt = AmountMath.add(totalDebt, debtAmount);
|
|
287
|
+
transfers.push([
|
|
288
|
+
vault.getVaultSeat(),
|
|
289
|
+
liqSeat,
|
|
290
|
+
{ Collateral: collateralAmount },
|
|
291
|
+
]);
|
|
292
|
+
vaultData.init(vault, { collateralAmount, debtAmount });
|
|
293
|
+
}
|
|
122
294
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
295
|
+
if (transfers.length > 0) {
|
|
296
|
+
atomicRearrange(zcf, harden(transfers));
|
|
297
|
+
}
|
|
126
298
|
|
|
127
|
-
|
|
128
|
-
return { proceeds: proceeds.Minted, overage, toBurn, shortfall };
|
|
299
|
+
return { vaultData, totalDebt, totalCollateral, liqSeat };
|
|
129
300
|
};
|
|
130
301
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
OracleTolerance: makeRatio(30n, debtBrand),
|
|
135
|
-
AMMMaxSlippage: makeRatio(30n, debtBrand),
|
|
136
|
-
});
|
|
137
|
-
/** @typedef {ReturnType<typeof liquidationDetailTerms>} LiquidationTerms */
|
|
138
|
-
|
|
139
|
-
harden(liquidate);
|
|
140
|
-
harden(liquidationDetailTerms);
|
|
141
|
-
harden(makeQuote);
|
|
142
|
-
harden(updateQuote);
|
|
302
|
+
harden(setWakeupsForNextAuction);
|
|
303
|
+
harden(liquidationResults);
|
|
304
|
+
harden(getLiquidatableVaults);
|
|
143
305
|
|
|
144
|
-
export {
|
|
306
|
+
export { setWakeupsForNextAuction, liquidationResults, getLiquidatableVaults };
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
// @jessie-check
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file calculations specific to the Vault Factory contract
|
|
5
|
+
* See also ../interest-math.js
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { AmountMath } from '@agoric/ertp';
|
|
9
|
+
import { getAmountOut } from '@agoric/zoe/src/contractSupport/priceQuote.js';
|
|
10
|
+
import {
|
|
11
|
+
addRatios,
|
|
12
|
+
ceilMultiplyBy,
|
|
13
|
+
floorDivideBy,
|
|
14
|
+
ratioGTE,
|
|
15
|
+
} from '@agoric/zoe/src/contractSupport/ratio.js';
|
|
16
|
+
import { priceFrom } from '../auction/util.js';
|
|
17
|
+
import { addSubtract } from '../contractSupport.js';
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Calculate the minimum collateralization given the liquidation margin and the "padding"
|
|
21
|
+
* from that liquidation threshold.
|
|
22
|
+
*
|
|
23
|
+
* @param {Ratio} liquidationMargin
|
|
24
|
+
* @param {Ratio} liquidationPadding
|
|
25
|
+
* @returns {Ratio}
|
|
26
|
+
*/
|
|
27
|
+
export const calculateMinimumCollateralization = (
|
|
28
|
+
liquidationMargin,
|
|
29
|
+
liquidationPadding,
|
|
30
|
+
) => addRatios(liquidationMargin, liquidationPadding);
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Calculate the lesser price of the given quotes.
|
|
34
|
+
*
|
|
35
|
+
* @param {PriceQuote} quoteA
|
|
36
|
+
* @param {PriceQuote} [quoteB]
|
|
37
|
+
* @returns {Ratio}
|
|
38
|
+
*/
|
|
39
|
+
export const minimumPrice = (quoteA, quoteB) => {
|
|
40
|
+
const priceA = priceFrom(quoteA);
|
|
41
|
+
if (quoteB === undefined) {
|
|
42
|
+
return priceA;
|
|
43
|
+
}
|
|
44
|
+
const priceB = priceFrom(quoteB);
|
|
45
|
+
if (ratioGTE(priceA, priceB)) {
|
|
46
|
+
return priceB;
|
|
47
|
+
} else {
|
|
48
|
+
return priceA;
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
harden(minimumPrice);
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Calculate the maximum debt allowed based on the price quote and the lesser of
|
|
55
|
+
* the `liquidationMargin` or the `liquidationPadding`.
|
|
56
|
+
*
|
|
57
|
+
* @param {PriceQuote} quoteAmount
|
|
58
|
+
* @param {Ratio} liquidationMargin
|
|
59
|
+
* @param {Ratio} liquidationPadding
|
|
60
|
+
* @returns {Amount<'nat'>}
|
|
61
|
+
*/
|
|
62
|
+
export const maxDebtForVault = (
|
|
63
|
+
quoteAmount,
|
|
64
|
+
liquidationMargin,
|
|
65
|
+
liquidationPadding,
|
|
66
|
+
) => {
|
|
67
|
+
const debtByQuote = getAmountOut(quoteAmount);
|
|
68
|
+
const minimumCollateralization = calculateMinimumCollateralization(
|
|
69
|
+
liquidationMargin,
|
|
70
|
+
liquidationPadding,
|
|
71
|
+
);
|
|
72
|
+
// floorDivide because we want the debt ceiling lower
|
|
73
|
+
return floorDivideBy(debtByQuote, minimumCollateralization);
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Calculate the fee, the amount to mint and the resulting debt.
|
|
78
|
+
* The give and the want together reflect a delta, where typically
|
|
79
|
+
* one is zero because they come from the gave/want of an offer
|
|
80
|
+
* proposal. If the `want` is zero, the `fee` will also be zero,
|
|
81
|
+
* so the simple math works.
|
|
82
|
+
*
|
|
83
|
+
* @param {Amount<'nat'>} currentDebt
|
|
84
|
+
* @param {Amount<'nat'>} give excess of currentDebt is returned in 'surplus'
|
|
85
|
+
* @param {Amount<'nat'>} want
|
|
86
|
+
* @param {Ratio} debtFee
|
|
87
|
+
*/
|
|
88
|
+
export const calculateDebtCosts = (currentDebt, give, want, debtFee) => {
|
|
89
|
+
const maxGive = AmountMath.min(currentDebt, give);
|
|
90
|
+
const surplus = AmountMath.subtract(give, maxGive);
|
|
91
|
+
const fee = ceilMultiplyBy(want, debtFee);
|
|
92
|
+
const toMint = AmountMath.add(want, fee);
|
|
93
|
+
const newDebt = addSubtract(currentDebt, toMint, maxGive);
|
|
94
|
+
return { newDebt, toMint, fee, surplus };
|
|
95
|
+
};
|