@agoric/inter-protocol 0.13.2-dev-c693f8d.0 → 0.13.2-dev-d5b2b97.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/bundles/bundle-amm-meta.js +130 -130
- package/bundles/bundle-econCommitteeCharter-meta.js +75 -75
- package/bundles/bundle-feeDistributor-meta.js +56 -56
- package/bundles/bundle-interchainPool-meta.js +109 -109
- package/bundles/bundle-liquidateIncrementally-meta.js +71 -71
- package/bundles/bundle-liquidateMinimum-meta.js +71 -71
- package/bundles/bundle-priceAggregatorChainlink-meta.js +99 -99
- package/bundles/bundle-psm-meta.js +112 -112
- package/bundles/bundle-reserve-meta.js +112 -112
- package/bundles/bundle-scaledPriceAuthority-meta.js +72 -72
- package/bundles/bundle-stakeFactory-meta.js +118 -118
- package/bundles/bundle-vaultFactory-meta.js +147 -143
- package/bundles/bundle-vaultFactory.js +1 -1
- package/package.json +16 -16
- package/src/proposals/demoIssuers.js +5 -0
- package/src/vaultFactory/math.js +70 -0
- package/src/vaultFactory/params.js +37 -14
- package/src/vaultFactory/types.js +1 -0
- package/src/vaultFactory/vault.js +148 -46
- package/src/vaultFactory/vaultKit.js +1 -1
- package/src/vaultFactory/vaultManager.js +11 -6
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agoric/inter-protocol",
|
|
3
|
-
"version": "0.13.2-dev-
|
|
3
|
+
"version": "0.13.2-dev-d5b2b97.0+d5b2b97",
|
|
4
4
|
"description": "Core cryptoeconomy contracts",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.js",
|
|
@@ -29,18 +29,18 @@
|
|
|
29
29
|
},
|
|
30
30
|
"homepage": "https://github.com/Agoric/agoric-sdk#readme",
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@agoric/assert": "0.5.2-dev-
|
|
33
|
-
"@agoric/ertp": "0.15.4-dev-
|
|
34
|
-
"@agoric/governance": "0.9.2-dev-
|
|
35
|
-
"@agoric/internal": "0.2.2-dev-
|
|
36
|
-
"@agoric/notifier": "0.5.2-dev-
|
|
37
|
-
"@agoric/store": "0.8.4-dev-
|
|
38
|
-
"@agoric/swingset-liveslots": "0.9.1-dev-
|
|
39
|
-
"@agoric/swingset-vat": "0.30.3-dev-
|
|
40
|
-
"@agoric/time": "0.2.2-dev-
|
|
41
|
-
"@agoric/vat-data": "0.4.4-dev-
|
|
42
|
-
"@agoric/vats": "0.13.1-dev-
|
|
43
|
-
"@agoric/zoe": "0.25.4-dev-
|
|
32
|
+
"@agoric/assert": "0.5.2-dev-d5b2b97.0+d5b2b97",
|
|
33
|
+
"@agoric/ertp": "0.15.4-dev-d5b2b97.0+d5b2b97",
|
|
34
|
+
"@agoric/governance": "0.9.2-dev-d5b2b97.0+d5b2b97",
|
|
35
|
+
"@agoric/internal": "0.2.2-dev-d5b2b97.0+d5b2b97",
|
|
36
|
+
"@agoric/notifier": "0.5.2-dev-d5b2b97.0+d5b2b97",
|
|
37
|
+
"@agoric/store": "0.8.4-dev-d5b2b97.0+d5b2b97",
|
|
38
|
+
"@agoric/swingset-liveslots": "0.9.1-dev-d5b2b97.0+d5b2b97",
|
|
39
|
+
"@agoric/swingset-vat": "0.30.3-dev-d5b2b97.0+d5b2b97",
|
|
40
|
+
"@agoric/time": "0.2.2-dev-d5b2b97.0+d5b2b97",
|
|
41
|
+
"@agoric/vat-data": "0.4.4-dev-d5b2b97.0+d5b2b97",
|
|
42
|
+
"@agoric/vats": "0.13.1-dev-d5b2b97.0+d5b2b97",
|
|
43
|
+
"@agoric/zoe": "0.25.4-dev-d5b2b97.0+d5b2b97",
|
|
44
44
|
"@endo/bundle-source": "^2.4.2",
|
|
45
45
|
"@endo/captp": "^2.0.18",
|
|
46
46
|
"@endo/eventual-send": "^0.16.8",
|
|
@@ -50,8 +50,8 @@
|
|
|
50
50
|
"@endo/promise-kit": "^0.2.52"
|
|
51
51
|
},
|
|
52
52
|
"devDependencies": {
|
|
53
|
-
"@agoric/deploy-script-support": "0.9.5-dev-
|
|
54
|
-
"@agoric/smart-wallet": "0.4.3-dev-
|
|
53
|
+
"@agoric/deploy-script-support": "0.9.5-dev-d5b2b97.0+d5b2b97",
|
|
54
|
+
"@agoric/smart-wallet": "0.4.3-dev-d5b2b97.0+d5b2b97",
|
|
55
55
|
"@endo/init": "^0.5.52",
|
|
56
56
|
"@fast-check/ava": "^1.1.3",
|
|
57
57
|
"ava": "^5.1.0",
|
|
@@ -78,5 +78,5 @@
|
|
|
78
78
|
"publishConfig": {
|
|
79
79
|
"access": "public"
|
|
80
80
|
},
|
|
81
|
-
"gitHead": "
|
|
81
|
+
"gitHead": "d5b2b97c7023aec5ec5bbf4b58eada61b28cbd2d"
|
|
82
82
|
}
|
|
@@ -102,6 +102,7 @@ const defaultConfig = /** @type {const} */ ({
|
|
|
102
102
|
* liquidationPenalty: Rational,
|
|
103
103
|
* interestRate: Rational,
|
|
104
104
|
* loanFee: Rational,
|
|
105
|
+
* liquidationPadding?: Rational,
|
|
105
106
|
* },
|
|
106
107
|
* trades: Array<{ central: number, collateral: bigint}>
|
|
107
108
|
* }>}
|
|
@@ -448,6 +449,10 @@ export const poolRates = (issuerName, record, kits, central) => {
|
|
|
448
449
|
liquidationPenalty: toRatio(config.liquidationPenalty, central.brand),
|
|
449
450
|
interestRate: toRatio(config.interestRate, central.brand),
|
|
450
451
|
loanFee: toRatio(config.loanFee, central.brand),
|
|
452
|
+
// XXX not relevant to AMM pools but poolRates is also used for addVaultType
|
|
453
|
+
liquidationPadding:
|
|
454
|
+
config.liquidationPadding &&
|
|
455
|
+
toRatio(config.liquidationPadding, central.brand),
|
|
451
456
|
};
|
|
452
457
|
return { rates, initialValue: inCollateral(config.collateralValue) };
|
|
453
458
|
};
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file calculations specific to the Vault Factory contract
|
|
3
|
+
* See also ../interest-math.js
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { AmountMath } from '@agoric/ertp';
|
|
7
|
+
import { getAmountOut } from '@agoric/zoe/src/contractSupport/priceQuote.js';
|
|
8
|
+
import {
|
|
9
|
+
addRatios,
|
|
10
|
+
ceilMultiplyBy,
|
|
11
|
+
floorDivideBy,
|
|
12
|
+
} from '@agoric/zoe/src/contractSupport/ratio.js';
|
|
13
|
+
import { addSubtract } from '../contractSupport.js';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Calculate the minimum collateralization given the liquidation margin and the "padding"
|
|
17
|
+
* from that liquidation threshold.
|
|
18
|
+
*
|
|
19
|
+
* @param {Ratio} liquidationMargin
|
|
20
|
+
* @param {Ratio} liquidationPadding
|
|
21
|
+
* @returns {Ratio}
|
|
22
|
+
*/
|
|
23
|
+
export const calculateMinimumCollateralization = (
|
|
24
|
+
liquidationMargin,
|
|
25
|
+
liquidationPadding,
|
|
26
|
+
) => addRatios(liquidationMargin, liquidationPadding);
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Calculate the maximum debt allowed based on the price quote and the lesser of
|
|
30
|
+
* the `liquidationMargin` or the `liquidationPadding`.
|
|
31
|
+
*
|
|
32
|
+
* @param {PriceQuote} quoteAmount
|
|
33
|
+
* @param {Ratio} liquidationMargin
|
|
34
|
+
* @param {Ratio} liquidationPadding
|
|
35
|
+
* @returns {Amount<'nat'>}
|
|
36
|
+
*/
|
|
37
|
+
export const maxDebtForVault = (
|
|
38
|
+
quoteAmount,
|
|
39
|
+
liquidationMargin,
|
|
40
|
+
liquidationPadding,
|
|
41
|
+
) => {
|
|
42
|
+
const debtByQuote = getAmountOut(quoteAmount);
|
|
43
|
+
const minimumCollateralization = calculateMinimumCollateralization(
|
|
44
|
+
liquidationMargin,
|
|
45
|
+
liquidationPadding,
|
|
46
|
+
);
|
|
47
|
+
// floorDivide because we want the debt ceiling lower
|
|
48
|
+
return floorDivideBy(debtByQuote, minimumCollateralization);
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Calculate the fee, the amount to mint and the resulting debt.
|
|
53
|
+
* The give and the want together reflect a delta, where typically
|
|
54
|
+
* one is zero because they come from the gave/want of an offer
|
|
55
|
+
* proposal. If the `want` is zero, the `fee` will also be zero,
|
|
56
|
+
* so the simple math works.
|
|
57
|
+
*
|
|
58
|
+
* @param {Amount<'nat'>} currentDebt
|
|
59
|
+
* @param {Amount<'nat'>} give excess of currentDebt is returned in 'surplus'
|
|
60
|
+
* @param {Amount<'nat'>} want
|
|
61
|
+
* @param {Ratio} loanFee
|
|
62
|
+
*/
|
|
63
|
+
export const calculateLoanCosts = (currentDebt, give, want, loanFee) => {
|
|
64
|
+
const maxGive = AmountMath.min(currentDebt, give);
|
|
65
|
+
const surplus = AmountMath.subtract(give, maxGive);
|
|
66
|
+
const fee = ceilMultiplyBy(want, loanFee);
|
|
67
|
+
const toMint = AmountMath.add(want, fee);
|
|
68
|
+
const newDebt = addSubtract(currentDebt, toMint, maxGive);
|
|
69
|
+
return { newDebt, toMint, fee, surplus };
|
|
70
|
+
};
|
|
@@ -2,13 +2,14 @@ import './types.js';
|
|
|
2
2
|
|
|
3
3
|
import {
|
|
4
4
|
CONTRACT_ELECTORATE,
|
|
5
|
-
makeParamManagerSync,
|
|
6
5
|
makeParamManager,
|
|
6
|
+
makeParamManagerSync,
|
|
7
7
|
ParamTypes,
|
|
8
8
|
} from '@agoric/governance';
|
|
9
9
|
import { makeStoredPublisherKit } from '@agoric/notifier';
|
|
10
10
|
import { M } from '@agoric/store';
|
|
11
11
|
import { TimeMath } from '@agoric/time';
|
|
12
|
+
import { subtractRatios } from '@agoric/zoe/src/contractSupport/ratio.js';
|
|
12
13
|
import { amountPattern, ratioPattern } from '../contractSupport.js';
|
|
13
14
|
|
|
14
15
|
export const CHARGING_PERIOD_KEY = 'ChargingPeriod';
|
|
@@ -16,6 +17,7 @@ export const RECORDING_PERIOD_KEY = 'RecordingPeriod';
|
|
|
16
17
|
|
|
17
18
|
export const DEBT_LIMIT_KEY = 'DebtLimit';
|
|
18
19
|
export const LIQUIDATION_MARGIN_KEY = 'LiquidationMargin';
|
|
20
|
+
export const LIQUIDATION_PADDING_KEY = 'LiquidationPadding';
|
|
19
21
|
export const LIQUIDATION_PENALTY_KEY = 'LiquidationPenalty';
|
|
20
22
|
export const INTEREST_RATE_KEY = 'InterestRate';
|
|
21
23
|
export const LOAN_FEE_KEY = 'LoanFee';
|
|
@@ -69,27 +71,48 @@ harden(makeVaultDirectorParams);
|
|
|
69
71
|
|
|
70
72
|
/** @typedef {import('@agoric/governance/src/contractGovernance/typedParamManager').ParamTypesMapFromRecord<ReturnType<typeof makeVaultDirectorParams>>} VaultDirectorParams */
|
|
71
73
|
|
|
74
|
+
/** @type {(liquidationMargin: Ratio) => Ratio} */
|
|
75
|
+
const zeroRatio = liquidationMargin =>
|
|
76
|
+
subtractRatios(liquidationMargin, liquidationMargin);
|
|
77
|
+
|
|
72
78
|
/**
|
|
73
79
|
* @param {import('@agoric/notifier').StoredPublisherKit<GovernanceSubscriptionState>} publisherKit
|
|
74
80
|
* @param {VaultManagerParamValues} initial
|
|
75
81
|
*/
|
|
76
|
-
export const makeVaultParamManager = (
|
|
82
|
+
export const makeVaultParamManager = (
|
|
83
|
+
publisherKit,
|
|
84
|
+
{
|
|
85
|
+
debtLimit,
|
|
86
|
+
interestRate,
|
|
87
|
+
liquidationMargin,
|
|
88
|
+
liquidationPadding = zeroRatio(liquidationMargin),
|
|
89
|
+
liquidationPenalty,
|
|
90
|
+
loanFee,
|
|
91
|
+
},
|
|
92
|
+
) =>
|
|
77
93
|
makeParamManagerSync(publisherKit, {
|
|
78
|
-
[DEBT_LIMIT_KEY]: [ParamTypes.AMOUNT,
|
|
79
|
-
[
|
|
80
|
-
[
|
|
81
|
-
[
|
|
82
|
-
[
|
|
94
|
+
[DEBT_LIMIT_KEY]: [ParamTypes.AMOUNT, debtLimit],
|
|
95
|
+
[INTEREST_RATE_KEY]: [ParamTypes.RATIO, interestRate],
|
|
96
|
+
[LIQUIDATION_PADDING_KEY]: [ParamTypes.RATIO, liquidationPadding],
|
|
97
|
+
[LIQUIDATION_MARGIN_KEY]: [ParamTypes.RATIO, liquidationMargin],
|
|
98
|
+
[LIQUIDATION_PENALTY_KEY]: [ParamTypes.RATIO, liquidationPenalty],
|
|
99
|
+
[LOAN_FEE_KEY]: [ParamTypes.RATIO, loanFee],
|
|
83
100
|
});
|
|
84
101
|
/** @typedef {ReturnType<typeof makeVaultParamManager>} VaultParamManager */
|
|
85
102
|
|
|
86
|
-
export const vaultParamPattern = M.splitRecord(
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
103
|
+
export const vaultParamPattern = M.splitRecord(
|
|
104
|
+
{
|
|
105
|
+
liquidationMargin: ratioPattern,
|
|
106
|
+
liquidationPenalty: ratioPattern,
|
|
107
|
+
interestRate: ratioPattern,
|
|
108
|
+
loanFee: ratioPattern,
|
|
109
|
+
debtLimit: amountPattern,
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
// optional for backwards compatibility, e.g. with loadgen
|
|
113
|
+
liquidationPadding: ratioPattern,
|
|
114
|
+
},
|
|
115
|
+
);
|
|
93
116
|
|
|
94
117
|
/**
|
|
95
118
|
* @param {import('@agoric/notifier').StoredPublisherKit<GovernanceSubscriptionState>} publisherKit
|
|
@@ -35,6 +35,7 @@
|
|
|
35
35
|
* @property {Ratio} loanFee - The fee (in BasisPoints) charged when opening
|
|
36
36
|
* or increasing a loan.
|
|
37
37
|
* @property {Amount<'nat'>} debtLimit
|
|
38
|
+
* @property {Ratio} [liquidationPadding] - vault must maintain this in order to remove collateral or add debt
|
|
38
39
|
*/
|
|
39
40
|
|
|
40
41
|
/**
|
|
@@ -5,7 +5,6 @@ import { M, prepareExoClassKit } from '@agoric/vat-data';
|
|
|
5
5
|
import {
|
|
6
6
|
assertProposalShape,
|
|
7
7
|
atomicTransfer,
|
|
8
|
-
ceilMultiplyBy,
|
|
9
8
|
floorMultiplyBy,
|
|
10
9
|
makeRatioFromAmounts,
|
|
11
10
|
} from '@agoric/zoe/src/contractSupport/index.js';
|
|
@@ -21,6 +20,7 @@ import { UnguardedHelperI } from '../typeGuards.js';
|
|
|
21
20
|
import { prepareVaultKit } from './vaultKit.js';
|
|
22
21
|
|
|
23
22
|
import '@agoric/zoe/exported.js';
|
|
23
|
+
import { calculateLoanCosts } from './math.js';
|
|
24
24
|
|
|
25
25
|
const { quote: q, Fail } = assert;
|
|
26
26
|
|
|
@@ -126,7 +126,18 @@ const validTransitions = {
|
|
|
126
126
|
* @param {Amount<'nat'>} newDebt
|
|
127
127
|
* @returns {boolean}
|
|
128
128
|
*/
|
|
129
|
-
const
|
|
129
|
+
const allocationsChangedSinceQuote = (
|
|
130
|
+
newCollateralPre,
|
|
131
|
+
maxDebtPre,
|
|
132
|
+
newCollateral,
|
|
133
|
+
newDebt,
|
|
134
|
+
) => {
|
|
135
|
+
trace('allocationsChangedSinceQuote', {
|
|
136
|
+
newCollateralPre,
|
|
137
|
+
maxDebtPre,
|
|
138
|
+
newCollateral,
|
|
139
|
+
newDebt,
|
|
140
|
+
});
|
|
130
141
|
if (AmountMath.isGTE(newCollateralPre, newCollateral)) {
|
|
131
142
|
// The collateral did not go up. If the collateral decreased, we pro-rate maxDebt.
|
|
132
143
|
// We can pro-rate maxDebt because the quote is either linear (price is
|
|
@@ -222,6 +233,30 @@ export const prepareVault = (baggage, marshaller, zcf) => {
|
|
|
222
233
|
emptyDebt() {
|
|
223
234
|
return AmountMath.makeEmpty(this.facets.helper.debtBrand());
|
|
224
235
|
},
|
|
236
|
+
/**
|
|
237
|
+
* @typedef {{ give: { Collateral: Amount<'nat'>, Minted: Amount<'nat'> }, want: { Collateral: Amount<'nat'>, Minted: Amount<'nat'> } }} FullProposal
|
|
238
|
+
*/
|
|
239
|
+
/**
|
|
240
|
+
* @param {ProposalRecord} partial
|
|
241
|
+
* @returns {FullProposal}
|
|
242
|
+
*/
|
|
243
|
+
fullProposal(partial) {
|
|
244
|
+
assertOnlyKeys(partial, ['Collateral', 'Minted']);
|
|
245
|
+
return {
|
|
246
|
+
give: {
|
|
247
|
+
Collateral:
|
|
248
|
+
partial.give?.Collateral ||
|
|
249
|
+
this.facets.helper.emptyCollateral(),
|
|
250
|
+
Minted: partial.give?.Minted || this.facets.helper.emptyDebt(),
|
|
251
|
+
},
|
|
252
|
+
want: {
|
|
253
|
+
Collateral:
|
|
254
|
+
partial.want?.Collateral ||
|
|
255
|
+
this.facets.helper.emptyCollateral(),
|
|
256
|
+
Minted: partial.want?.Minted || this.facets.helper.emptyDebt(),
|
|
257
|
+
},
|
|
258
|
+
};
|
|
259
|
+
},
|
|
225
260
|
// #endregion
|
|
226
261
|
|
|
227
262
|
// #region Phase logic
|
|
@@ -459,13 +494,12 @@ export const prepareVault = (baggage, marshaller, zcf) => {
|
|
|
459
494
|
loanFee(currentDebt, giveAmount, wantAmount) {
|
|
460
495
|
const { state } = this;
|
|
461
496
|
|
|
462
|
-
|
|
497
|
+
return calculateLoanCosts(
|
|
498
|
+
currentDebt,
|
|
499
|
+
giveAmount,
|
|
463
500
|
wantAmount,
|
|
464
501
|
state.manager.getGovernedParams().getLoanFee(),
|
|
465
502
|
);
|
|
466
|
-
const toMint = AmountMath.add(wantAmount, fee);
|
|
467
|
-
const newDebt = addSubtract(currentDebt, toMint, giveAmount);
|
|
468
|
-
return { newDebt, toMint, fee };
|
|
469
503
|
},
|
|
470
504
|
|
|
471
505
|
/**
|
|
@@ -480,77 +514,145 @@ export const prepareVault = (baggage, marshaller, zcf) => {
|
|
|
480
514
|
const { self, helper } = facets;
|
|
481
515
|
const { outerUpdater: updaterPre } = state;
|
|
482
516
|
const { vaultSeat } = state;
|
|
483
|
-
const
|
|
484
|
-
|
|
517
|
+
const fp = helper.fullProposal(clientSeat.getProposal());
|
|
518
|
+
|
|
519
|
+
if (
|
|
520
|
+
allEmpty([
|
|
521
|
+
fp.give.Collateral,
|
|
522
|
+
fp.give.Minted,
|
|
523
|
+
fp.want.Collateral,
|
|
524
|
+
fp.want.Minted,
|
|
525
|
+
])
|
|
526
|
+
) {
|
|
527
|
+
clientSeat.exit();
|
|
528
|
+
return 'no transaction, as requested';
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
// Calculate the fee, the amount to mint and the resulting debt. We'll
|
|
532
|
+
// verify that the target debt doesn't violate the collateralization ratio,
|
|
533
|
+
// then mint, reallocate, and burn.
|
|
534
|
+
const { newDebt, fee, surplus, toMint } = helper.loanFee(
|
|
535
|
+
self.getCurrentDebt(),
|
|
536
|
+
fp.give.Minted,
|
|
537
|
+
fp.want.Minted,
|
|
538
|
+
);
|
|
485
539
|
|
|
486
540
|
const normalizedDebtPre = self.getNormalizedDebt();
|
|
487
541
|
const collateralPre = helper.getCollateralAllocated(vaultSeat);
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
542
|
+
const hasWants = !allEmpty([fp.want.Collateral, fp.want.Minted]);
|
|
543
|
+
|
|
544
|
+
if (!hasWants) {
|
|
545
|
+
// allow deposits regardless of max debt allowed
|
|
546
|
+
return helper.commitBalanceAdjustment(
|
|
547
|
+
clientSeat,
|
|
548
|
+
fp,
|
|
549
|
+
{
|
|
550
|
+
newDebt,
|
|
551
|
+
fee,
|
|
552
|
+
surplus,
|
|
553
|
+
toMint,
|
|
554
|
+
},
|
|
555
|
+
{ normalizedDebtPre, collateralPre },
|
|
556
|
+
);
|
|
557
|
+
}
|
|
491
558
|
|
|
492
559
|
const newCollateralPre = addSubtract(
|
|
493
560
|
collateralPre,
|
|
494
|
-
|
|
495
|
-
|
|
561
|
+
fp.give.Collateral,
|
|
562
|
+
fp.want.Collateral,
|
|
496
563
|
);
|
|
497
|
-
// max debt supported by
|
|
564
|
+
// max debt supported by the vault Collateral implied by the proposal
|
|
498
565
|
const maxDebtPre = await state.manager.maxDebtFor(newCollateralPre);
|
|
499
566
|
updaterPre === state.outerUpdater ||
|
|
500
567
|
Fail`Transfer during vault adjustment`;
|
|
501
568
|
helper.assertActive();
|
|
502
569
|
|
|
503
|
-
|
|
504
|
-
// so we can compare to the debt limit based on the new values.
|
|
505
|
-
const collateral = helper.getCollateralAllocated(vaultSeat);
|
|
506
|
-
const newCollateral = addSubtract(collateral, giveColl, wantColl);
|
|
507
|
-
|
|
508
|
-
const debt = self.getCurrentDebt();
|
|
509
|
-
const giveMinted = AmountMath.min(
|
|
510
|
-
proposal.give.Minted || helper.emptyDebt(),
|
|
511
|
-
debt,
|
|
512
|
-
);
|
|
513
|
-
const wantMinted = proposal.want.Minted || helper.emptyDebt();
|
|
514
|
-
if (allEmpty([giveColl, giveMinted, wantColl, wantMinted])) {
|
|
515
|
-
clientSeat.exit();
|
|
516
|
-
return 'no transaction, as requested';
|
|
517
|
-
}
|
|
518
|
-
|
|
519
|
-
// Calculate the fee, the amount to mint and the resulting debt. We'll
|
|
520
|
-
// verify that the target debt doesn't violate the collateralization ratio,
|
|
521
|
-
// then mint, reallocate, and burn.
|
|
522
|
-
const { newDebt, fee, toMint } = helper.loanFee(
|
|
523
|
-
debt,
|
|
524
|
-
giveMinted,
|
|
525
|
-
wantMinted,
|
|
526
|
-
);
|
|
527
|
-
|
|
528
|
-
trace('adjustBalancesHook', state.idInManager, {
|
|
570
|
+
trace('adjustBalancesHook after quote', state.idInManager, {
|
|
529
571
|
newCollateralPre,
|
|
530
|
-
newCollateral,
|
|
531
572
|
fee,
|
|
532
573
|
toMint,
|
|
574
|
+
maxDebtPre,
|
|
533
575
|
newDebt,
|
|
534
576
|
});
|
|
535
577
|
|
|
578
|
+
// While awaiting maxDebtFor, the allocations may have changed.
|
|
579
|
+
// After the `await`, we retrieve the vault's allocations again,
|
|
580
|
+
// so we can compare to the debt limit based on the new values.
|
|
581
|
+
const collateral = helper.getCollateralAllocated(vaultSeat);
|
|
582
|
+
const newCollateral = addSubtract(
|
|
583
|
+
collateral,
|
|
584
|
+
fp.give.Collateral,
|
|
585
|
+
fp.want.Collateral,
|
|
586
|
+
);
|
|
536
587
|
if (
|
|
537
|
-
|
|
588
|
+
allocationsChangedSinceQuote(
|
|
589
|
+
newCollateralPre,
|
|
590
|
+
maxDebtPre,
|
|
591
|
+
newCollateral,
|
|
592
|
+
newDebt,
|
|
593
|
+
)
|
|
538
594
|
) {
|
|
539
595
|
return helper.adjustBalancesHook(clientSeat);
|
|
540
596
|
}
|
|
541
597
|
|
|
542
|
-
|
|
598
|
+
return helper.commitBalanceAdjustment(
|
|
599
|
+
clientSeat,
|
|
600
|
+
fp,
|
|
601
|
+
{
|
|
602
|
+
newDebt,
|
|
603
|
+
fee,
|
|
604
|
+
surplus,
|
|
605
|
+
toMint,
|
|
606
|
+
},
|
|
607
|
+
{ normalizedDebtPre, collateralPre },
|
|
608
|
+
);
|
|
609
|
+
},
|
|
610
|
+
|
|
611
|
+
/**
|
|
612
|
+
*
|
|
613
|
+
* @param {ZCFSeat} clientSeat
|
|
614
|
+
* @param {FullProposal} fp
|
|
615
|
+
* @param {ReturnType<typeof calculateLoanCosts>} costs
|
|
616
|
+
* @param {object} accounting
|
|
617
|
+
* @param {NormalizedDebt} accounting.normalizedDebtPre
|
|
618
|
+
* @param {Amount<'nat'>} accounting.collateralPre
|
|
619
|
+
* @returns {Promise<string>} success message
|
|
620
|
+
*/
|
|
621
|
+
async commitBalanceAdjustment(
|
|
622
|
+
clientSeat,
|
|
623
|
+
fp,
|
|
624
|
+
{ newDebt, fee, surplus, toMint },
|
|
625
|
+
{ normalizedDebtPre, collateralPre },
|
|
626
|
+
) {
|
|
627
|
+
const { state, facets } = this;
|
|
628
|
+
const { helper } = facets;
|
|
629
|
+
const { vaultSeat } = state;
|
|
630
|
+
|
|
631
|
+
const giveMintedTaken = AmountMath.subtract(fp.give.Minted, surplus);
|
|
632
|
+
|
|
633
|
+
// TODO use atomicRearrange https://github.com/Agoric/agoric-sdk/issues/5605
|
|
634
|
+
stageDelta(
|
|
635
|
+
clientSeat,
|
|
636
|
+
vaultSeat,
|
|
637
|
+
fp.give.Collateral,
|
|
638
|
+
fp.want.Collateral,
|
|
639
|
+
'Collateral',
|
|
640
|
+
);
|
|
543
641
|
// `wantMinted` is allocated in the reallocate and mint operation, and so not here
|
|
544
642
|
stageDelta(
|
|
545
643
|
clientSeat,
|
|
546
644
|
vaultSeat,
|
|
547
|
-
|
|
645
|
+
giveMintedTaken,
|
|
548
646
|
helper.emptyDebt(),
|
|
549
647
|
'Minted',
|
|
550
648
|
);
|
|
551
649
|
|
|
552
650
|
/** @type {Array<ZCFSeat>} */
|
|
553
|
-
const vaultSeatOpt = allEmpty([
|
|
651
|
+
const vaultSeatOpt = allEmpty([
|
|
652
|
+
fp.give.Collateral,
|
|
653
|
+
giveMintedTaken,
|
|
654
|
+
fp.want.Collateral,
|
|
655
|
+
])
|
|
554
656
|
? []
|
|
555
657
|
: [vaultSeat];
|
|
556
658
|
state.manager.mintAndReallocate(
|
|
@@ -566,7 +668,7 @@ export const prepareVault = (baggage, marshaller, zcf) => {
|
|
|
566
668
|
collateralPre,
|
|
567
669
|
newDebt,
|
|
568
670
|
);
|
|
569
|
-
state.manager.burnAndRecord(
|
|
671
|
+
state.manager.burnAndRecord(giveMintedTaken, vaultSeat);
|
|
570
672
|
helper.assertVaultHoldsNoMinted();
|
|
571
673
|
|
|
572
674
|
helper.updateUiState();
|
|
@@ -41,7 +41,6 @@ import {
|
|
|
41
41
|
assertProposalShape,
|
|
42
42
|
atomicTransfer,
|
|
43
43
|
ceilDivideBy,
|
|
44
|
-
floorDivideBy,
|
|
45
44
|
getAmountIn,
|
|
46
45
|
getAmountOut,
|
|
47
46
|
makeRatio,
|
|
@@ -53,6 +52,7 @@ import { E } from '@endo/eventual-send';
|
|
|
53
52
|
import { checkDebtLimit } from '../contractSupport.js';
|
|
54
53
|
import { chargeInterest } from '../interest.js';
|
|
55
54
|
import { liquidate, makeQuote, updateQuote } from './liquidation.js';
|
|
55
|
+
import { maxDebtForVault } from './math.js';
|
|
56
56
|
import { makePrioritizedVaults } from './prioritizedVaults.js';
|
|
57
57
|
import { Phase, prepareVault } from './vault.js';
|
|
58
58
|
|
|
@@ -94,6 +94,7 @@ const trace = makeTracer('VM', false);
|
|
|
94
94
|
* getRecordingPeriod: () => RelativeTime,
|
|
95
95
|
* getDebtLimit: () => Amount<'nat'>,
|
|
96
96
|
* getInterestRate: () => Ratio,
|
|
97
|
+
* getLiquidationPadding: () => Ratio,
|
|
97
98
|
* getLiquidationMargin: () => Ratio,
|
|
98
99
|
* getLiquidationPenalty: () => Ratio,
|
|
99
100
|
* getLoanFee: () => Ratio,
|
|
@@ -435,6 +436,7 @@ export const prepareVaultManagerKit = (
|
|
|
435
436
|
const { facets } = this;
|
|
436
437
|
trace('reschedulePriceCheck', collateralBrand, {
|
|
437
438
|
liquidationQueueing,
|
|
439
|
+
outstandingQuote: !!outstandingQuote,
|
|
438
440
|
});
|
|
439
441
|
// INTERLOCK: the first time through, start the activity to wait for
|
|
440
442
|
// and process liquidations over time.
|
|
@@ -622,20 +624,23 @@ export const prepareVaultManagerKit = (
|
|
|
622
624
|
},
|
|
623
625
|
|
|
624
626
|
/**
|
|
627
|
+
* Consults a price authority to determine the max debt this manager
|
|
628
|
+
* config will allow for the collateral.
|
|
629
|
+
*
|
|
625
630
|
* @param {Amount<'nat'>} collateralAmount
|
|
626
631
|
*/
|
|
627
632
|
async maxDebtFor(collateralAmount) {
|
|
628
633
|
trace('maxDebtFor', collateralAmount);
|
|
629
634
|
assert(factoryPowers && priceAuthority);
|
|
630
|
-
const
|
|
635
|
+
const quote = await E(priceAuthority).quoteGiven(
|
|
631
636
|
collateralAmount,
|
|
632
637
|
debtBrand,
|
|
633
638
|
);
|
|
634
|
-
trace('maxDebtFor got quote', quoteAmount);
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
getAmountOut(quoteAmount),
|
|
639
|
+
trace('maxDebtFor got quote', quote.quoteAmount.value[0]);
|
|
640
|
+
return maxDebtForVault(
|
|
641
|
+
quote,
|
|
638
642
|
factoryPowers.getGovernedParams().getLiquidationMargin(),
|
|
643
|
+
factoryPowers.getGovernedParams().getLiquidationPadding(),
|
|
639
644
|
);
|
|
640
645
|
},
|
|
641
646
|
/**
|