Skip to content
This repository was archived by the owner on May 24, 2024. It is now read-only.

Commit 7325ec4

Browse files
committed
liquidate self-collateral like override
1 parent 12bf69d commit 7325ec4

File tree

5 files changed

+198
-124
lines changed

5 files changed

+198
-124
lines changed

contracts/modules/Liquidation.sol

Lines changed: 44 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -124,55 +124,64 @@ contract Liquidation is BaseLogic {
124124
OverrideConfig memory overrideConfig;
125125
AssetConfig memory collateralConfig;
126126
AssetConfig memory underlyingConfig;
127-
if (liqLocs.underlying == liqLocs.collateral) {
128-
liqOpp.repay = type(uint).max;
129-
} else {
130-
collateralConfig = resolveAssetConfig(liqLocs.collateral);
131-
underlyingConfig = resolveAssetConfig(liqLocs.underlying);
132-
133-
uint collateralFactor = collateralConfig.collateralFactor;
134-
uint borrowFactor = underlyingConfig.borrowFactor;
135-
136-
if (liqLocs.overrideCollateralValue > 0) {
137-
overrideConfig = overrideLookup[liqLocs.underlying][liqLocs.collateral];
138-
}
139127

140-
// If override is active, assume the resulting liability will be fully covered by override collateral
141-
if (overrideConfig.enabled) { // the liquidated collateral is an override
142-
collateralFactor = overrideConfig.collateralFactor;
143-
borrowFactor = CONFIG_FACTOR_SCALE;
128+
collateralConfig = resolveAssetConfig(liqLocs.collateral);
129+
underlyingConfig = liqLocs.underlying == liqLocs.collateral
130+
? collateralConfig
131+
: resolveAssetConfig(liqLocs.underlying);
144132

133+
uint collateralFactor = collateralConfig.collateralFactor;
134+
uint borrowFactor = underlyingConfig.borrowFactor;
135+
136+
// If override is active for the liquidated pair, assume the resulting liability will be fully covered by override collateral, and adjust inputs
137+
if (liqLocs.overrideCollateralValue > 0) {
138+
if (liqLocs.underlying == liqLocs.collateral) { // liquidating self-collateral
139+
collateralFactor = SELF_COLLATERAL_FACTOR;
140+
borrowFactor = CONFIG_FACTOR_SCALE;
145141
// adjust the whole liability for override BF = 1
146142
liqLocs.liabilityValue = liqLocs.currentOwed * liqLocs.underlyingPrice / 1e18;
147-
}
143+
} else {
144+
overrideConfig = overrideLookup[liqLocs.underlying][liqLocs.collateral];
148145

149-
// Calculate for no overrides or resulting liability fully covered by override
150-
// or if liquidating non-override collateral assume result will be partially covered by override
151-
calculateRepayCommon(liqOpp, liqLocs, collateralFactor, borrowFactor);
146+
if (overrideConfig.enabled) { // the liquidated collateral has active override with liability
147+
collateralFactor = overrideConfig.collateralFactor;
148+
borrowFactor = CONFIG_FACTOR_SCALE;
149+
// adjust the whole liability for override BF = 1
150+
liqLocs.liabilityValue = liqLocs.currentOwed * liqLocs.underlyingPrice / 1e18;
151+
}
152+
}
152153
}
153154

155+
// Calculate for no overrides or resulting liability fully covered by override
156+
// or if liquidating non-override collateral assume result will be partially covered by override
157+
calculateRepayCommon(liqOpp, liqLocs, collateralFactor, borrowFactor);
158+
154159
// Limit repay and yield to current debt and available collateral
155160
boundRepayAndYield(liqOpp, liqLocs);
156161

157162
// Test the assumptions and adjust if needed
158163

159164
// Correction when liquidating override collateral
160165
if (
161-
// Override and regular collateral, liquidating collateral
162-
overrideConfig.enabled && liqLocs.overrideCollateralValue != liqLocs.collateralValue &&
166+
// override and regular collateral present
167+
liqLocs.overrideCollateralValue != liqLocs.collateralValue &&
168+
// liquidating collateral with override or self-collateral
169+
(overrideConfig.enabled || liqLocs.underlying == liqLocs.collateral) &&
163170
// not already maxed out
164171
liqOpp.yield != liqLocs.collateralBalance &&
165172
// result is not fully covered by override collateral as expected
166173
(liqOpp.repay == 0 || // numerator in equation was negative
167174
(liqLocs.currentOwed - liqOpp.repay) * liqLocs.underlyingPrice / 1e18 >
168-
liqLocs.overrideCollateralValue - liqOpp.yield * overrideConfig.collateralFactor / CONFIG_FACTOR_SCALE * liqLocs.collateralPrice / 1e18)
175+
liqLocs.overrideCollateralValue - liqOpp.yield * collateralFactor / CONFIG_FACTOR_SCALE * liqLocs.collateralPrice / 1e18)
169176
) {
170-
uint auxAdj = 1e18 * CONFIG_FACTOR_SCALE / underlyingConfig.borrowFactor - 1e18;
171-
uint borrowAdj = underlyingConfig.borrowFactor != 0 ? TARGET_HEALTH * CONFIG_FACTOR_SCALE / underlyingConfig.borrowFactor : MAX_SANE_DEBT_AMOUNT;
172-
uint collateralAdj = 1e18 * uint(overrideConfig.collateralFactor) / CONFIG_FACTOR_SCALE * (TARGET_HEALTH * auxAdj / 1e18 + 1e18) / (1e18 - liqOpp.discount);
177+
borrowFactor = underlyingConfig.borrowFactor;
178+
179+
uint auxAdj = 1e18 * CONFIG_FACTOR_SCALE / borrowFactor - 1e18;
180+
uint borrowAdj = borrowFactor != 0 ? TARGET_HEALTH * CONFIG_FACTOR_SCALE / borrowFactor : MAX_SANE_DEBT_AMOUNT;
181+
uint collateralAdj = 1e18 * collateralFactor / CONFIG_FACTOR_SCALE * (TARGET_HEALTH * auxAdj / 1e18 + 1e18) / (1e18 - liqOpp.discount);
173182

174183
uint overrideCollateralValueAdj = liqLocs.overrideCollateralValue * auxAdj / 1e18;
175-
uint liabilityValueAdj = liqLocs.currentOwed * liqLocs.underlyingPrice / 1e18 * CONFIG_FACTOR_SCALE / underlyingConfig.borrowFactor;
184+
uint liabilityValueAdj = liqLocs.currentOwed * liqLocs.underlyingPrice / 1e18 * CONFIG_FACTOR_SCALE / borrowFactor;
176185

177186
if (liabilityValueAdj < overrideCollateralValueAdj || borrowAdj <= collateralAdj) {
178187
liqOpp.repay = type(uint).max;
@@ -190,16 +199,20 @@ contract Liquidation is BaseLogic {
190199

191200
// Correction when liquidating regular collateral with overrides present
192201
if (
193-
// liquidating regular collateral, override present
194-
!overrideConfig.enabled && liqLocs.overrideCollateralValue > 0 &&
202+
// liquidating regular collateral
203+
!(overrideConfig.enabled || liqLocs.underlying == liqLocs.collateral) &&
204+
// override present
205+
liqLocs.overrideCollateralValue > 0 &&
195206
// not already maxed out
196207
liqOpp.yield != liqLocs.collateralBalance &&
197208
// result is not partially collateralised as expected
198209
(liqLocs.currentOwed - liqOpp.repay) * liqLocs.underlyingPrice / 1e18 < liqLocs.overrideCollateralValue
199210
) {
200211
// adjust the whole liability for override BF = 1
201212
liqLocs.liabilityValue = liqLocs.currentOwed * liqLocs.underlyingPrice / 1e18;
202-
calculateRepayCommon(liqOpp, liqLocs, collateralConfig.collateralFactor, CONFIG_FACTOR_SCALE);
213+
214+
collateralFactor = collateralConfig.collateralFactor;
215+
calculateRepayCommon(liqOpp, liqLocs, collateralFactor, CONFIG_FACTOR_SCALE);
203216

204217
liqOpp.repay = liqOpp.repay == 0 ? type(uint).max : liqOpp.repay;
205218

@@ -218,7 +231,7 @@ contract Liquidation is BaseLogic {
218231
uint collateralAdj = 1e18 * collateralFactor / CONFIG_FACTOR_SCALE * 1e18 / (1e18 - liqOpp.discount);
219232
uint liabilityValue = liqLocs.liabilityValue * TARGET_HEALTH / 1e18;
220233

221-
if (liabilityValue > liqLocs.collateralValue) { // TODO L < 0
234+
if (liabilityValue > liqLocs.collateralValue) {
222235
if (borrowAdj <= collateralAdj) {
223236
liqOpp.repay = type(uint).max;
224237
} else {

contracts/modules/RiskManager.sol

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -299,14 +299,14 @@ contract RiskManager is IRiskManager, BaseLogic {
299299
uint borrowFactorCache;
300300

301301
for (uint i = 0; i < underlyings.length; ++i) {
302-
config = resolveAssetConfig(underlyings[i]);
302+
address underlying = underlyings[i];
303+
config = resolveAssetConfig(underlying);
303304
assetStorage = eTokenLookup[config.eTokenAddress];
304305

305306
uint balance = assetStorage.users[account].balance;
306-
uint owed = assetStorage.users[account].owed;
307307

308-
if (owed != 0) {
309-
initAssetCache(underlyings[i], assetStorage, assetCache);
308+
if (assetStorage.users[account].owed != 0) {
309+
initAssetCache(underlying, assetStorage, assetCache);
310310
(uint price,) = getPriceInternal(assetCache, config);
311311

312312
status.numBorrows++;
@@ -339,10 +339,10 @@ contract RiskManager is IRiskManager, BaseLogic {
339339
overrideConfig.enabled = false;
340340

341341
if (singleLiability != address(0)) {
342-
overrideConfig = overrideLookup[singleLiability][underlyings[i]];
342+
overrideConfig = overrideLookup[singleLiability][underlying];
343343
}
344344
if(config.collateralFactor != 0 || overrideConfig.enabled) {
345-
initAssetCache(underlyings[i], assetStorage, assetCache);
345+
initAssetCache(underlying, assetStorage, assetCache);
346346
(uint price,) = getPriceInternal(assetCache, config);
347347

348348
uint balanceInUnderlying = balanceToUnderlyingAmount(assetCache, balance);
@@ -386,10 +386,10 @@ contract RiskManager is IRiskManager, BaseLogic {
386386

387387
for (uint i = 0; i < underlyings.length; ++i) {
388388
output[i].underlying = singleUnderlying[0] = underlyings[i];
389-
output[i].status = computeLiquidityRaw(account, singleUnderlying, address(0));
389+
output[i].status = computeLiquidityRaw(account, singleUnderlying, singleLiability);
390390

391391
// the override liability is only possible to calculate with all underlyings
392-
if (singleLiability != address(0)) {
392+
if (singleLiability == underlyings[i]) {
393393
LiquidityStatus memory status = computeLiquidityRaw(account, underlyings, singleLiability);
394394
output[i].status.liabilityValue = status.liabilityValue;
395395
}
@@ -398,11 +398,12 @@ contract RiskManager is IRiskManager, BaseLogic {
398398
return output;
399399
}
400400

401-
function findSingleLiability(address account, address[] memory underlyings) private view returns (address singleLiabilityAddress){
401+
function findSingleLiability(address account, address[] memory underlyings) private view returns (address singleLiabilityAddress) {
402402
for (uint i = 0; i < underlyings.length; ++i) {
403-
if (eTokenLookup[underlyingLookup[underlyings[i]].eTokenAddress].users[account].owed > 0) {
403+
address underlying = underlyings[i];
404+
if (eTokenLookup[underlyingLookup[underlying].eTokenAddress].users[account].owed > 0) {
404405
if (singleLiabilityAddress == address(0)) {
405-
singleLiabilityAddress = underlyings[i];
406+
singleLiabilityAddress = underlying;
406407
} else {
407408
singleLiabilityAddress = address(0);
408409
break;

test/batch.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,6 @@ et.testSet({
196196

197197
.test({
198198
desc: "simulate a batch execution without liquidity checks",
199-
dev: 1,
200199
actions: ctx => [
201200
{ action: 'updateUniswapPrice', pair: 'TST/WETH', price: '1'},
202201
{ action: 'updateUniswapPrice', pair: 'TST2/WETH', price: '0.4'},

0 commit comments

Comments
 (0)