@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,296 +0,0 @@
|
|
|
1
|
-
// @ts-check
|
|
2
|
-
// @jessie-check
|
|
3
|
-
import { AmountMath } from '@agoric/ertp';
|
|
4
|
-
import { makePublishKit, observeNotifier } from '@agoric/notifier';
|
|
5
|
-
import { fit, getCopyBagEntries, M } from '@agoric/store';
|
|
6
|
-
import { defineKindMulti } from '@agoric/vat-data';
|
|
7
|
-
import { floorMultiplyBy } from '@agoric/zoe/src/contractSupport/index.js';
|
|
8
|
-
import { makeRatio } from '@agoric/zoe/src/contractSupport/ratio.js';
|
|
9
|
-
import { E } from '@endo/far';
|
|
10
|
-
import { checkDebtLimit } from '../contractSupport.js';
|
|
11
|
-
import { chargeInterest } from '../interest.js';
|
|
12
|
-
import { makeTracer } from '../makeTracer.js';
|
|
13
|
-
import { ManagerKW as KW } from './constants.js';
|
|
14
|
-
|
|
15
|
-
const { details: X } = assert;
|
|
16
|
-
|
|
17
|
-
const trace = makeTracer('RSM', false);
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* @typedef {{
|
|
21
|
-
* getDebtLimit: () => Amount<'nat'>,
|
|
22
|
-
* getInterestRate: () => Ratio,
|
|
23
|
-
* getMintingRatio: () => Ratio,
|
|
24
|
-
* getLoanFee: () => Ratio,
|
|
25
|
-
* }} ParamManager
|
|
26
|
-
* @typedef {{
|
|
27
|
-
* compoundedInterest: Ratio,
|
|
28
|
-
* latestInterestUpdate: Timestamp,
|
|
29
|
-
* totalDebt: Amount<'nat'>,
|
|
30
|
-
* }} AssetState
|
|
31
|
-
* @typedef {Readonly<{
|
|
32
|
-
* assetPublisher: Publisher<AssetState>,
|
|
33
|
-
* assetSubscriber: Subscriber<AssetState>,
|
|
34
|
-
* brands: { debt: Brand<'nat'>, Attestation: Brand<'copyBag'>, Stake: Brand<'nat'> },
|
|
35
|
-
* mintPowers: { burnDebt: BurnDebt, getGovernedParams: () => ParamManager, mintAndReallocate: MintAndReallocate },
|
|
36
|
-
* chargingPeriod: RelativeTime,
|
|
37
|
-
* debtMint: ZCFMint<'nat'>,
|
|
38
|
-
* poolIncrementSeat: ZCFSeat,
|
|
39
|
-
* recordingPeriod: RelativeTime,
|
|
40
|
-
* startTimeStamp: Timestamp,
|
|
41
|
-
* timerService: ERef<TimerService>,
|
|
42
|
-
* zcf: ZCF,
|
|
43
|
-
* }>} ImmutableState
|
|
44
|
-
* @typedef {AssetState & {
|
|
45
|
-
* }} MutableState
|
|
46
|
-
* @typedef {ImmutableState & MutableState} State
|
|
47
|
-
* @typedef {Readonly<{
|
|
48
|
-
* state: State,
|
|
49
|
-
* facets: import('@agoric/vat-data/src/types').KindFacets<typeof behavior>,
|
|
50
|
-
* }>} MethodContext
|
|
51
|
-
*/
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* @param {ZCF} zcf
|
|
55
|
-
* @param {ZCFMint<'nat'>} debtMint
|
|
56
|
-
* @param {{ debt: Brand<'nat'>, Attestation: Brand<'copyBag'>, Stake: Brand<'nat'> }} brands
|
|
57
|
-
* @param {{ burnDebt: BurnDebt, getGovernedParams: () => ParamManager, mintAndReallocate: MintAndReallocate }} mintPowers
|
|
58
|
-
* @param {object} timing
|
|
59
|
-
* @param {ERef<TimerService>} timing.timerService
|
|
60
|
-
* @param {RelativeTime} timing.chargingPeriod
|
|
61
|
-
* @param {RelativeTime} timing.recordingPeriod
|
|
62
|
-
* @param {Timestamp} timing.startTimeStamp
|
|
63
|
-
*
|
|
64
|
-
* @returns {State}
|
|
65
|
-
*/
|
|
66
|
-
const initState = (
|
|
67
|
-
zcf,
|
|
68
|
-
debtMint,
|
|
69
|
-
brands,
|
|
70
|
-
mintPowers,
|
|
71
|
-
{ chargingPeriod, recordingPeriod, startTimeStamp, timerService },
|
|
72
|
-
) => {
|
|
73
|
-
const totalDebt = AmountMath.makeEmpty(brands.debt, 'nat');
|
|
74
|
-
const compoundedInterest = makeRatio(100n, brands.debt); // starts at 1.0, no interest
|
|
75
|
-
const latestInterestUpdate = startTimeStamp;
|
|
76
|
-
|
|
77
|
-
const { publisher: assetPublisher, subscriber: assetSubscriber } =
|
|
78
|
-
makePublishKit();
|
|
79
|
-
assetPublisher.publish(
|
|
80
|
-
harden({
|
|
81
|
-
compoundedInterest,
|
|
82
|
-
interestRate: mintPowers.getGovernedParams().getInterestRate(),
|
|
83
|
-
latestInterestUpdate,
|
|
84
|
-
totalDebt,
|
|
85
|
-
}),
|
|
86
|
-
);
|
|
87
|
-
|
|
88
|
-
const { zcfSeat: poolIncrementSeat } = zcf.makeEmptySeatKit();
|
|
89
|
-
|
|
90
|
-
return {
|
|
91
|
-
assetSubscriber,
|
|
92
|
-
assetPublisher,
|
|
93
|
-
brands,
|
|
94
|
-
chargingPeriod,
|
|
95
|
-
compoundedInterest,
|
|
96
|
-
debtMint,
|
|
97
|
-
latestInterestUpdate,
|
|
98
|
-
mintPowers,
|
|
99
|
-
poolIncrementSeat,
|
|
100
|
-
recordingPeriod,
|
|
101
|
-
startTimeStamp,
|
|
102
|
-
timerService,
|
|
103
|
-
totalDebt,
|
|
104
|
-
zcf,
|
|
105
|
-
};
|
|
106
|
-
};
|
|
107
|
-
|
|
108
|
-
/**
|
|
109
|
-
*
|
|
110
|
-
* @param {MethodContext} context
|
|
111
|
-
*/
|
|
112
|
-
const finish = ({ state, facets }) => {
|
|
113
|
-
const { recordingPeriod, timerService, zcf } = state;
|
|
114
|
-
const { helper } = facets;
|
|
115
|
-
|
|
116
|
-
const periodNotifier = E(timerService).makeNotifier(0n, recordingPeriod);
|
|
117
|
-
|
|
118
|
-
void observeNotifier(periodNotifier, {
|
|
119
|
-
updateState: updateTime =>
|
|
120
|
-
helper
|
|
121
|
-
.chargeAllVaults(updateTime)
|
|
122
|
-
.catch(e =>
|
|
123
|
-
console.error('🚨 stakeFactoryManager failed to charge interest', e),
|
|
124
|
-
),
|
|
125
|
-
fail: reason => {
|
|
126
|
-
zcf.shutdownWithFailure(
|
|
127
|
-
assert.error(X`Unable to continue without a timer: ${reason}`),
|
|
128
|
-
);
|
|
129
|
-
},
|
|
130
|
-
finish: done => {
|
|
131
|
-
zcf.shutdownWithFailure(
|
|
132
|
-
assert.error(X`Unable to continue without a timer: ${done}`),
|
|
133
|
-
);
|
|
134
|
-
},
|
|
135
|
-
});
|
|
136
|
-
};
|
|
137
|
-
|
|
138
|
-
const helper = {
|
|
139
|
-
/**
|
|
140
|
-
* @param {MethodContext} context
|
|
141
|
-
* @param {Timestamp} updateTime
|
|
142
|
-
*/
|
|
143
|
-
chargeAllVaults: async ({ state }, updateTime) => {
|
|
144
|
-
const { debtMint, mintPowers, poolIncrementSeat } = state;
|
|
145
|
-
trace('chargeAllVaults', { updateTime });
|
|
146
|
-
const interestRate = mintPowers.getGovernedParams().getInterestRate();
|
|
147
|
-
|
|
148
|
-
const changes = chargeInterest(
|
|
149
|
-
{
|
|
150
|
-
mint: debtMint,
|
|
151
|
-
mintAndReallocateWithFee: mintPowers.mintAndReallocate,
|
|
152
|
-
poolIncrementSeat,
|
|
153
|
-
seatAllocationKeyword: KW.Debt,
|
|
154
|
-
},
|
|
155
|
-
{
|
|
156
|
-
interestRate,
|
|
157
|
-
chargingPeriod: state.chargingPeriod,
|
|
158
|
-
recordingPeriod: state.recordingPeriod,
|
|
159
|
-
},
|
|
160
|
-
{
|
|
161
|
-
latestInterestUpdate: state.latestInterestUpdate,
|
|
162
|
-
compoundedInterest: state.compoundedInterest,
|
|
163
|
-
totalDebt: state.totalDebt,
|
|
164
|
-
},
|
|
165
|
-
updateTime,
|
|
166
|
-
);
|
|
167
|
-
state.compoundedInterest = changes.compoundedInterest;
|
|
168
|
-
state.latestInterestUpdate = changes.latestInterestUpdate;
|
|
169
|
-
state.totalDebt = changes.totalDebt;
|
|
170
|
-
|
|
171
|
-
const payload = harden({
|
|
172
|
-
compoundedInterest: state.compoundedInterest,
|
|
173
|
-
interestRate,
|
|
174
|
-
latestInterestUpdate: state.latestInterestUpdate,
|
|
175
|
-
totalDebt: state.totalDebt,
|
|
176
|
-
});
|
|
177
|
-
const { assetPublisher: assetUpdater } = state;
|
|
178
|
-
assetUpdater.publish(payload);
|
|
179
|
-
|
|
180
|
-
trace('chargeAllVaults complete', payload);
|
|
181
|
-
},
|
|
182
|
-
};
|
|
183
|
-
|
|
184
|
-
const manager = {
|
|
185
|
-
/**
|
|
186
|
-
* @param {MethodContext} context
|
|
187
|
-
* @param { Amount<'copyBag'>} attestationGiven
|
|
188
|
-
* */
|
|
189
|
-
maxDebtForLien: ({ state }, attestationGiven) => {
|
|
190
|
-
const { brands, mintPowers } = state;
|
|
191
|
-
const mintingRatio = mintPowers.getGovernedParams().getMintingRatio();
|
|
192
|
-
assert.equal(
|
|
193
|
-
mintingRatio.numerator.brand,
|
|
194
|
-
brands.debt,
|
|
195
|
-
X`${mintingRatio} not in Debt / Stake`,
|
|
196
|
-
);
|
|
197
|
-
assert.equal(
|
|
198
|
-
mintingRatio.denominator.brand,
|
|
199
|
-
brands.Stake,
|
|
200
|
-
X`${mintingRatio} not in Debt / Stake`,
|
|
201
|
-
);
|
|
202
|
-
assert.equal(
|
|
203
|
-
attestationGiven.brand,
|
|
204
|
-
brands.Attestation,
|
|
205
|
-
X`Invalid Attestation ${attestationGiven}. Expected brand ${brands.Attestation}`,
|
|
206
|
-
);
|
|
207
|
-
fit(attestationGiven.value, M.bagOf(M.string()), 'attestationGiven');
|
|
208
|
-
const [[_addr, valueLiened]] = getCopyBagEntries(attestationGiven.value);
|
|
209
|
-
const amountLiened = AmountMath.make(brands.Stake, valueLiened);
|
|
210
|
-
const maxDebt = floorMultiplyBy(amountLiened, mintingRatio);
|
|
211
|
-
return { maxDebt, amountLiened };
|
|
212
|
-
},
|
|
213
|
-
|
|
214
|
-
/**
|
|
215
|
-
* Update total debt of this manager given the change in debt on a vault
|
|
216
|
-
*
|
|
217
|
-
* @param {MethodContext} context
|
|
218
|
-
* @param {Amount<'nat'>} oldDebtOnVault
|
|
219
|
-
* @param {Amount<'nat'>} newDebtOnVault
|
|
220
|
-
*/
|
|
221
|
-
// TODO: Add limits for amounts between vault and vault manager
|
|
222
|
-
// https://github.com/Agoric/agoric-sdk/issues/4599
|
|
223
|
-
applyDebtDelta: ({ state }, oldDebtOnVault, newDebtOnVault) => {
|
|
224
|
-
// This does not use AmountMath because it could be validly negative
|
|
225
|
-
const delta = newDebtOnVault.value - oldDebtOnVault.value;
|
|
226
|
-
trace(`updating total debt ${state.totalDebt} by ${delta}`);
|
|
227
|
-
if (delta === 0n) {
|
|
228
|
-
// nothing to do
|
|
229
|
-
return;
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
const { brands } = state;
|
|
233
|
-
// totalDebt += delta (Amount type ensures natural value)
|
|
234
|
-
state.totalDebt = AmountMath.make(
|
|
235
|
-
brands.debt,
|
|
236
|
-
state.totalDebt.value + delta,
|
|
237
|
-
);
|
|
238
|
-
},
|
|
239
|
-
|
|
240
|
-
/**
|
|
241
|
-
* @param {MethodContext} context
|
|
242
|
-
* @param {Amount} toMint
|
|
243
|
-
* @param {Amount} fee
|
|
244
|
-
* @param {ZCFSeat} seat
|
|
245
|
-
* @param {...ZCFSeat} otherSeats
|
|
246
|
-
* @returns {void}
|
|
247
|
-
*/
|
|
248
|
-
mintAndReallocate: ({ state }, toMint, fee, seat, ...otherSeats) => {
|
|
249
|
-
const { mintPowers } = state;
|
|
250
|
-
checkDebtLimit(
|
|
251
|
-
mintPowers.getGovernedParams().getDebtLimit(),
|
|
252
|
-
state.totalDebt,
|
|
253
|
-
toMint,
|
|
254
|
-
);
|
|
255
|
-
mintPowers.mintAndReallocate(toMint, fee, seat, ...otherSeats);
|
|
256
|
-
state.totalDebt = AmountMath.add(state.totalDebt, toMint);
|
|
257
|
-
},
|
|
258
|
-
|
|
259
|
-
/** @param {MethodContext} context */
|
|
260
|
-
getMintingRatio: ({ state }) =>
|
|
261
|
-
state.mintPowers.getGovernedParams().getMintingRatio(),
|
|
262
|
-
/** @param {MethodContext} context */
|
|
263
|
-
getInterestRate: ({ state }) =>
|
|
264
|
-
state.mintPowers.getGovernedParams().getInterestRate(),
|
|
265
|
-
/** @param {MethodContext} context */
|
|
266
|
-
getLoanFee: ({ state }) => state.mintPowers.getGovernedParams().getLoanFee(),
|
|
267
|
-
/**
|
|
268
|
-
* @param {MethodContext} context
|
|
269
|
-
* @param {Amount} toBurn
|
|
270
|
-
* @param {ZCFSeat} seat
|
|
271
|
-
*/
|
|
272
|
-
burnDebt: ({ state }, toBurn, seat) =>
|
|
273
|
-
state.mintPowers.burnDebt(toBurn, seat),
|
|
274
|
-
|
|
275
|
-
/** @param {MethodContext} context */
|
|
276
|
-
getDebtBrand: ({ state }) => state.brands.debt,
|
|
277
|
-
/** @param {MethodContext} context */
|
|
278
|
-
getCollateralBrand: ({ state }) => state.brands.Attestation,
|
|
279
|
-
|
|
280
|
-
/** @param {MethodContext} context */
|
|
281
|
-
getCompoundedInterest: ({ state }) => state.compoundedInterest,
|
|
282
|
-
/** @param {MethodContext} context */
|
|
283
|
-
getAssetSubscriber: ({ state }) => state.assetSubscriber,
|
|
284
|
-
};
|
|
285
|
-
|
|
286
|
-
const behavior = { helper, manager };
|
|
287
|
-
|
|
288
|
-
export const makeStakeFactoryManager = defineKindMulti(
|
|
289
|
-
'StakeFactoryManager',
|
|
290
|
-
initState,
|
|
291
|
-
behavior,
|
|
292
|
-
{ finish },
|
|
293
|
-
);
|
|
294
|
-
/**
|
|
295
|
-
* @typedef {ReturnType<typeof makeStakeFactoryManager>['manager']} StakeFactoryManager
|
|
296
|
-
*/
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* For example, an agoric1... Cosmos address
|
|
3
|
-
*
|
|
4
|
-
* @typedef {string} Address
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* @typedef AttestationTool
|
|
9
|
-
* @property {(amountToLien: Amount<'nat'>) => Promise<Payment>} makeAttestation
|
|
10
|
-
* @property {() => Promise<AccountState>} getAccountState
|
|
11
|
-
* @property {(lienedAmount: Amount<'nat'>) => Amount<'copyBag'>} wrapLienedAmount
|
|
12
|
-
* @property {(attAmount: Amount<'copyBag'>) => Amount<'nat'>} unwrapLienedAmount
|
|
13
|
-
* @property {() => Promise<Invitation>} makeReturnAttInvitation Make an invitation for returning an attestation.
|
|
14
|
-
*/
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* @typedef {CopyBag<Address>} ReturnableAttValue
|
|
18
|
-
*/
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* @typedef {{getTime: () => Timestamp, updateTime: (currentTime:
|
|
22
|
-
* Timestamp) => void}} StoredTime
|
|
23
|
-
*/
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* @typedef {object} StakingAuthority
|
|
27
|
-
* @property {(address: Address, increase: Amount<'nat'>) => Promise<Amount<'nat'>>} increaseLiened
|
|
28
|
-
* @property {(address: Address, decrease: Amount<'nat'>) => Promise<Amount<'nat'>>} decreaseLiened
|
|
29
|
-
* @property {(address: Address, brand: Brand<'nat'>) => ERef<AccountState> } getAccountState
|
|
30
|
-
* @typedef {object} AccountState
|
|
31
|
-
* @property {Amount<'nat'>} bonded
|
|
32
|
-
* @property {Amount<'nat'>} liened
|
|
33
|
-
* @property {Amount<'nat'>} locked
|
|
34
|
-
* @property {Amount<'nat'>} total
|
|
35
|
-
* @property {Amount<'nat'>} unbonding
|
|
36
|
-
* @property {bigint} currentTime
|
|
37
|
-
*
|
|
38
|
-
* Performance note: getAccountState is expensive, as it has to iterate over all
|
|
39
|
-
* delegations.
|
|
40
|
-
*
|
|
41
|
-
* @typedef {(address: Address, brand: Brand<'nat'>) => Amount} GetLiened
|
|
42
|
-
*/
|
|
@@ -1,350 +0,0 @@
|
|
|
1
|
-
/* eslint-disable no-await-in-loop */
|
|
2
|
-
// @ts-check
|
|
3
|
-
|
|
4
|
-
import { E } from '@endo/eventual-send';
|
|
5
|
-
import {
|
|
6
|
-
getAmountOut,
|
|
7
|
-
assertProposalShape,
|
|
8
|
-
offerTo,
|
|
9
|
-
natSafeMath as NatMath,
|
|
10
|
-
ceilMultiplyBy,
|
|
11
|
-
oneMinus,
|
|
12
|
-
} from '@agoric/zoe/src/contractSupport/index.js';
|
|
13
|
-
import { AmountMath } from '@agoric/ertp';
|
|
14
|
-
import { Far } from '@endo/marshal';
|
|
15
|
-
import { makeTracer } from '../makeTracer.js';
|
|
16
|
-
|
|
17
|
-
const { details: X } = assert;
|
|
18
|
-
const trace = makeTracer('LiqI', false);
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* @file
|
|
22
|
-
* This contract liquidates a payment in multiple tranches to limit the
|
|
23
|
-
* price impact on the AMM of any one sale. Each block it will compute
|
|
24
|
-
* a tranche of collateral to sell, where the size is a function of
|
|
25
|
-
* the amount of that collateral in the AMM pool and the desired price impact.
|
|
26
|
-
* It presently consults the AMM and Oracle for whether to sell.
|
|
27
|
-
*
|
|
28
|
-
* The next revision of this will work as follows...
|
|
29
|
-
*
|
|
30
|
-
* It then gets 3 prices for the current tranche:
|
|
31
|
-
* - AMM quote - compute XYK locally based on the pool sizes
|
|
32
|
-
* - Reserve quote - based on a low price at which the Reserve will purchase
|
|
33
|
-
* - Oracle quote - provided by the oracle that triggered liquidation
|
|
34
|
-
* - Oracle limit - a limit that is DIVERGENCE_TOLERANCE below the
|
|
35
|
-
* Oracle quote.
|
|
36
|
-
* Then sell based on the following:
|
|
37
|
-
* - If the AMM quote is *below* the oracle limit, skip this block
|
|
38
|
-
* to wait for oracle and AMM prices to converge.
|
|
39
|
-
* - If the Reserve quote is higher than the AMM quote, sell to the
|
|
40
|
-
* Reserve with a `want` of the Oracle limit
|
|
41
|
-
* - Otherwise, sell to the AMM with a `want` of the Oracle limit
|
|
42
|
-
*
|
|
43
|
-
* Selling uses the `oracleLimit as the `want` as the limit to allowed
|
|
44
|
-
* slippage, and provides the remaining `debt` as the `stopAfter` so
|
|
45
|
-
* that we sell no more than is needed to pay off the debt.
|
|
46
|
-
*
|
|
47
|
-
* TODO integrate the reserve, including the above Reserve strategies.
|
|
48
|
-
*/
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* @typedef {{
|
|
52
|
-
* amm: XYKAMMPublicFacet,
|
|
53
|
-
* priceAuthority: PriceAuthority,
|
|
54
|
-
* reservePublicFacet: AssetReservePublicFacet,
|
|
55
|
-
* timerService: TimerService,
|
|
56
|
-
* debtBrand: Brand,
|
|
57
|
-
* MaxImpactBP: NatValue,
|
|
58
|
-
* OracleTolerance: Ratio,
|
|
59
|
-
* AMMMaxSlippage: Ratio,
|
|
60
|
-
* }} LiquidationContractTerms
|
|
61
|
-
* @param {ZCF<LiquidationContractTerms>} zcf
|
|
62
|
-
*/
|
|
63
|
-
const start = async zcf => {
|
|
64
|
-
const {
|
|
65
|
-
amm,
|
|
66
|
-
priceAuthority,
|
|
67
|
-
reservePublicFacet,
|
|
68
|
-
timerService,
|
|
69
|
-
debtBrand,
|
|
70
|
-
MaxImpactBP,
|
|
71
|
-
OracleTolerance,
|
|
72
|
-
AMMMaxSlippage,
|
|
73
|
-
} = zcf.getTerms();
|
|
74
|
-
|
|
75
|
-
const SCALE = 1_000_000n;
|
|
76
|
-
const BASIS_POINTS = 10_000n * SCALE;
|
|
77
|
-
const BP2 = BASIS_POINTS * BASIS_POINTS;
|
|
78
|
-
const ONE = BASIS_POINTS;
|
|
79
|
-
|
|
80
|
-
const asFloat = (numerator, denominator) =>
|
|
81
|
-
Number(numerator) / Number(denominator);
|
|
82
|
-
|
|
83
|
-
// #region penalty distribution
|
|
84
|
-
const { zcfSeat: penaltyPoolSeat } = zcf.makeEmptySeatKit();
|
|
85
|
-
const drainPenaltyPool = async () => {
|
|
86
|
-
const addCollateral = await E(
|
|
87
|
-
reservePublicFacet,
|
|
88
|
-
).makeAddCollateralInvitation();
|
|
89
|
-
const proposal = harden({
|
|
90
|
-
give: { Collateral: penaltyPoolSeat.getCurrentAllocation().Out },
|
|
91
|
-
});
|
|
92
|
-
const { deposited, userSeatPromise } = await offerTo(
|
|
93
|
-
zcf,
|
|
94
|
-
addCollateral,
|
|
95
|
-
harden({ Out: 'Collateral' }),
|
|
96
|
-
proposal,
|
|
97
|
-
penaltyPoolSeat,
|
|
98
|
-
);
|
|
99
|
-
const [deposits] = await Promise.all([deposited, userSeatPromise]);
|
|
100
|
-
trace('drainPenaltyPool deposited', deposits.Out);
|
|
101
|
-
};
|
|
102
|
-
// #endregion
|
|
103
|
-
|
|
104
|
-
/**
|
|
105
|
-
* Compute the tranche size whose sale on the AMM would have
|
|
106
|
-
* a price impact of MAX_IMPACT_BP.
|
|
107
|
-
* This doesn't use ratios so that it is usable for any brand
|
|
108
|
-
*
|
|
109
|
-
* @param {Amount} poolSize
|
|
110
|
-
* @param {bigint} maxImpactBP
|
|
111
|
-
* @param {bigint} feeBP
|
|
112
|
-
* @returns {Amount}
|
|
113
|
-
*/
|
|
114
|
-
const maxTrancheWithFees = (poolSize, maxImpactBP, feeBP) => {
|
|
115
|
-
trace('maxTrancheWithFees', poolSize, maxImpactBP, feeBP);
|
|
116
|
-
const maxImpactScaled = maxImpactBP * SCALE;
|
|
117
|
-
const ammFeeScaled = feeBP * SCALE;
|
|
118
|
-
// sqrt(impact + 1) - 1
|
|
119
|
-
// Since we take SQRT but want to be BP, multiply in BP
|
|
120
|
-
const impactFactor =
|
|
121
|
-
BigInt(
|
|
122
|
-
Math.ceil(Math.sqrt(Number((maxImpactScaled + ONE) * BASIS_POINTS))),
|
|
123
|
-
) - ONE;
|
|
124
|
-
const impactWithFee = impactFactor * (ONE - ammFeeScaled);
|
|
125
|
-
return AmountMath.make(
|
|
126
|
-
poolSize.brand,
|
|
127
|
-
NatMath.ceilDivide(NatMath.multiply(poolSize.value, impactWithFee), BP2),
|
|
128
|
-
);
|
|
129
|
-
};
|
|
130
|
-
|
|
131
|
-
const computeOracleLimit = (oracleQuote, oracleTolerance) => {
|
|
132
|
-
return ceilMultiplyBy(getAmountOut(oracleQuote), oneMinus(oracleTolerance));
|
|
133
|
-
};
|
|
134
|
-
|
|
135
|
-
const getAMMFeeBP = async () => {
|
|
136
|
-
const zoe = zcf.getZoeService();
|
|
137
|
-
const instance = await E(zoe).getInstance(E(amm).makeSwapInvitation());
|
|
138
|
-
const terms = await E(zoe).getTerms(instance);
|
|
139
|
-
// trace('amm terms', terms);
|
|
140
|
-
const { poolFeeBP, protocolFeeBP } = terms;
|
|
141
|
-
return poolFeeBP + protocolFeeBP;
|
|
142
|
-
};
|
|
143
|
-
|
|
144
|
-
const AMMFeeBP = await getAMMFeeBP();
|
|
145
|
-
|
|
146
|
-
const estimateAMMProceeds = (
|
|
147
|
-
poolCentral,
|
|
148
|
-
poolCollateral,
|
|
149
|
-
tranche,
|
|
150
|
-
debt,
|
|
151
|
-
maxSlip,
|
|
152
|
-
) => {
|
|
153
|
-
const k = NatMath.multiply(poolCentral.value, poolCollateral.value);
|
|
154
|
-
const postSaleCollateral = AmountMath.add(tranche, poolCollateral);
|
|
155
|
-
const estimateCentral = NatMath.subtract(
|
|
156
|
-
poolCentral.value,
|
|
157
|
-
NatMath.floorDivide(k, postSaleCollateral.value),
|
|
158
|
-
);
|
|
159
|
-
const estimateAmount = AmountMath.make(debt.brand, estimateCentral);
|
|
160
|
-
const minAmmProceeds = ceilMultiplyBy(estimateAmount, oneMinus(maxSlip));
|
|
161
|
-
trace('AMM estimate', {
|
|
162
|
-
tranche,
|
|
163
|
-
minAmmProceeds,
|
|
164
|
-
poolCentral,
|
|
165
|
-
poolCollateral,
|
|
166
|
-
});
|
|
167
|
-
return minAmmProceeds;
|
|
168
|
-
};
|
|
169
|
-
|
|
170
|
-
/**
|
|
171
|
-
* A generator that yields once per block, starting in the current block.
|
|
172
|
-
*
|
|
173
|
-
* @yields {void}
|
|
174
|
-
*/
|
|
175
|
-
async function* oncePerBlock() {
|
|
176
|
-
yield;
|
|
177
|
-
while (true) {
|
|
178
|
-
yield E(timerService).delay(1n);
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
/**
|
|
183
|
-
* Generate tranches to sell until the debt is paid off.
|
|
184
|
-
*
|
|
185
|
-
* @param {ZCFSeat} seat
|
|
186
|
-
* @param {Amount} originalDebt
|
|
187
|
-
* @yields {LiquidationStep}
|
|
188
|
-
*/
|
|
189
|
-
async function* processTranches(seat, originalDebt) {
|
|
190
|
-
while (true) {
|
|
191
|
-
const proceedsSoFar = seat.getAmountAllocated('Out');
|
|
192
|
-
const toSell = seat.getAmountAllocated('In');
|
|
193
|
-
if (
|
|
194
|
-
AmountMath.isGTE(proceedsSoFar, originalDebt) ||
|
|
195
|
-
AmountMath.isEmpty(toSell)
|
|
196
|
-
) {
|
|
197
|
-
trace('exiting processTranches loop');
|
|
198
|
-
return;
|
|
199
|
-
}
|
|
200
|
-
await oncePerBlock();
|
|
201
|
-
|
|
202
|
-
// Determine the max allowed tranche size
|
|
203
|
-
const { Secondary: poolCollateral, Central: poolCentral } = await E(
|
|
204
|
-
amm,
|
|
205
|
-
).getPoolAllocation(toSell.brand);
|
|
206
|
-
const maxAllowedTranche = maxTrancheWithFees(
|
|
207
|
-
poolCollateral,
|
|
208
|
-
MaxImpactBP,
|
|
209
|
-
AMMFeeBP,
|
|
210
|
-
);
|
|
211
|
-
trace('Pool', { poolCentral, poolCollateral });
|
|
212
|
-
trace('Max tranche', asFloat(maxAllowedTranche.value, 100000n));
|
|
213
|
-
const tranche = AmountMath.min(maxAllowedTranche, toSell);
|
|
214
|
-
|
|
215
|
-
// compute the expected proceeds from the AMM for tranche
|
|
216
|
-
const debt = AmountMath.subtract(originalDebt, proceedsSoFar);
|
|
217
|
-
const minAmmProceeds = estimateAMMProceeds(
|
|
218
|
-
poolCentral,
|
|
219
|
-
poolCollateral,
|
|
220
|
-
tranche,
|
|
221
|
-
debt,
|
|
222
|
-
AMMMaxSlippage,
|
|
223
|
-
);
|
|
224
|
-
|
|
225
|
-
// this could use a unit rather than the tranche size to run concurrently
|
|
226
|
-
/** @type PriceQuote */
|
|
227
|
-
const oracleQuote = await E(priceAuthority).quoteGiven(
|
|
228
|
-
tranche,
|
|
229
|
-
debtBrand,
|
|
230
|
-
);
|
|
231
|
-
const oracleLimit = computeOracleLimit(oracleQuote, OracleTolerance);
|
|
232
|
-
|
|
233
|
-
trace('Tranche', { debt, tranche, minAmmProceeds, oracleLimit });
|
|
234
|
-
if (AmountMath.isGTE(minAmmProceeds, oracleLimit)) {
|
|
235
|
-
// our prices are within the same range; go ahead and try to sell
|
|
236
|
-
yield {
|
|
237
|
-
collateral: tranche,
|
|
238
|
-
ammProceeds: minAmmProceeds,
|
|
239
|
-
debt,
|
|
240
|
-
oracleLimit,
|
|
241
|
-
};
|
|
242
|
-
} else {
|
|
243
|
-
// prices are too far apart; don't sell this block
|
|
244
|
-
trace('SKIP');
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
async function sellTranche(debtorSeat, collateral, debt, oracleLimit) {
|
|
250
|
-
const swapInvitation = E(amm).makeSwapInvitation();
|
|
251
|
-
const want = AmountMath.min(debt, oracleLimit);
|
|
252
|
-
// TODO if the debt shouldn't require all the collatearal to cover it,
|
|
253
|
-
// this may not provide relevant offer safety
|
|
254
|
-
const proposal = {
|
|
255
|
-
give: { In: collateral },
|
|
256
|
-
want: { Out: want },
|
|
257
|
-
};
|
|
258
|
-
const { deposited, userSeatPromise: liqSeat } = await offerTo(
|
|
259
|
-
zcf,
|
|
260
|
-
swapInvitation,
|
|
261
|
-
undefined, // The keywords were mapped already
|
|
262
|
-
proposal,
|
|
263
|
-
debtorSeat,
|
|
264
|
-
debtorSeat,
|
|
265
|
-
{ stopAfter: debt },
|
|
266
|
-
);
|
|
267
|
-
await Promise.all([E(liqSeat).getOfferResult(), deposited]);
|
|
268
|
-
|
|
269
|
-
// This uses getCurrentAllocationJig only to support testing, so is ok
|
|
270
|
-
const amounts = await E(liqSeat).getCurrentAllocationJig();
|
|
271
|
-
trace('offerResult', { amounts });
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
/**
|
|
275
|
-
* @param {ZCFSeat} debtorSeat
|
|
276
|
-
* @param {object} options
|
|
277
|
-
* @param {Amount<'nat'>} options.debt Debt before penalties
|
|
278
|
-
* @param {Ratio} options.penaltyRate
|
|
279
|
-
*/
|
|
280
|
-
const handleLiquidateOffer = async (
|
|
281
|
-
debtorSeat,
|
|
282
|
-
{ debt: originalDebt, penaltyRate },
|
|
283
|
-
) => {
|
|
284
|
-
assertProposalShape(debtorSeat, {
|
|
285
|
-
give: { In: null },
|
|
286
|
-
});
|
|
287
|
-
originalDebt.brand === debtBrand ||
|
|
288
|
-
assert.fail(X`Cannot liquidate to ${originalDebt.brand}`);
|
|
289
|
-
const penalty = ceilMultiplyBy(originalDebt, penaltyRate);
|
|
290
|
-
const debtWithPenalty = AmountMath.add(originalDebt, penalty);
|
|
291
|
-
trace('LIQ', { originalDebt, debtWithPenalty });
|
|
292
|
-
|
|
293
|
-
for await (const t of processTranches(debtorSeat, debtWithPenalty)) {
|
|
294
|
-
const { collateral, oracleLimit, ammProceeds, debt } = t;
|
|
295
|
-
trace(`OFFER TO DEBT: `, {
|
|
296
|
-
collateral,
|
|
297
|
-
ammProceeds,
|
|
298
|
-
oracleLimit,
|
|
299
|
-
debt,
|
|
300
|
-
});
|
|
301
|
-
const collateralBefore = debtorSeat.getAmountAllocated('In');
|
|
302
|
-
const proceedsBefore = debtorSeat.getAmountAllocated('Out');
|
|
303
|
-
|
|
304
|
-
await sellTranche(debtorSeat, collateral, debt, oracleLimit);
|
|
305
|
-
|
|
306
|
-
const proceedsAfter = debtorSeat.getAmountAllocated('Out');
|
|
307
|
-
if (AmountMath.isEqual(proceedsBefore, proceedsAfter)) {
|
|
308
|
-
// nothing got sold
|
|
309
|
-
const collateralAfter = debtorSeat.getAmountAllocated('In');
|
|
310
|
-
trace('NOSELL', {
|
|
311
|
-
proceedsBefore,
|
|
312
|
-
proceedsAfter,
|
|
313
|
-
collateralBefore,
|
|
314
|
-
collateralAfter,
|
|
315
|
-
});
|
|
316
|
-
}
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
// Now we need to know how much was sold so we can pay off the debt.
|
|
320
|
-
// We can use this seat because only liquidation adds debt brand to it..
|
|
321
|
-
const debtPaid = debtorSeat.getAmountAllocated('Out', debtBrand);
|
|
322
|
-
const penaltyPaid = AmountMath.min(penalty, debtPaid);
|
|
323
|
-
|
|
324
|
-
// Allocate penalty portion of proceeds to a seat that will hold it for transfer to reserve
|
|
325
|
-
penaltyPoolSeat.incrementBy(
|
|
326
|
-
debtorSeat.decrementBy(harden({ Out: penaltyPaid })),
|
|
327
|
-
);
|
|
328
|
-
zcf.reallocate(penaltyPoolSeat, debtorSeat);
|
|
329
|
-
|
|
330
|
-
debtorSeat.exit();
|
|
331
|
-
trace('exit seat');
|
|
332
|
-
// trigger but don't await so it doesn't make liquidation itself fail
|
|
333
|
-
drainPenaltyPool().catch(e =>
|
|
334
|
-
console.error('🚨 error draining penalty pool', e),
|
|
335
|
-
);
|
|
336
|
-
};
|
|
337
|
-
|
|
338
|
-
/**
|
|
339
|
-
* @type {ERef<Liquidator>}
|
|
340
|
-
*/
|
|
341
|
-
const creatorFacet = Far('debtorInvitationCreator (incrementally)', {
|
|
342
|
-
makeLiquidateInvitation: () =>
|
|
343
|
-
zcf.makeInvitation(handleLiquidateOffer, 'Liquidate'),
|
|
344
|
-
});
|
|
345
|
-
|
|
346
|
-
return harden({ creatorFacet });
|
|
347
|
-
};
|
|
348
|
-
|
|
349
|
-
harden(start);
|
|
350
|
-
export { start };
|