Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ contract SpokeLiquidationCallScenariosTest is SpokeLiquidationCallBaseTest {

address public user = makeAddr('user');
address public liquidator = makeAddr('liquidator');
address public charlie = makeAddr('charlie');

ISpoke public spoke;

Expand Down Expand Up @@ -49,12 +50,19 @@ contract SpokeLiquidationCallScenariosTest is SpokeLiquidationCallBaseTest {

for (uint256 reserveId = 0; reserveId < spoke.getReserveCount(); reserveId++) {
_deal(spoke, reserveId, liquidator, MAX_SUPPLY_AMOUNT);
_deal(spoke, reserveId, charlie, MAX_SUPPLY_AMOUNT);
SpokeActions.approve({
spoke: spoke,
reserveId: reserveId,
owner: liquidator,
amount: MAX_SUPPLY_AMOUNT
});
SpokeActions.approve({
spoke: spoke,
reserveId: reserveId,
owner: charlie,
amount: MAX_SUPPLY_AMOUNT
});
}
}

Expand Down Expand Up @@ -448,6 +456,96 @@ contract SpokeLiquidationCallScenariosTest is SpokeLiquidationCallBaseTest {
);
}

/// @dev receiving shares can improve an unhealthy liquidator's position.
function test_liquidationCall_liquidatorReceivesSharesAndImprovesHealthFactor() public {
uint256 collateralReserveId = _wethReserveId(spoke);
uint256 debtReserveId = _daiReserveId(spoke);

_increaseCollateralSupply(
spoke,
collateralReserveId,
_convertValueToAmount(spoke, collateralReserveId, 1_000e26),
liquidator
);
_openSupplyPosition(
spoke,
debtReserveId,
_convertValueToAmount(spoke, debtReserveId, 10_000e26)
);
_borrowToBeAtHf(spoke, liquidator, debtReserveId, 0.99e18);

uint256 liquidatorHealthFactorBefore = spoke.getUserAccountData(liquidator).healthFactor;
assertLt(liquidatorHealthFactorBefore, HEALTH_FACTOR_LIQUIDATION_THRESHOLD);

_increaseCollateralSupply(
spoke,
collateralReserveId,
_convertValueToAmount(spoke, collateralReserveId, 5_000e26),
user
);
_makeUserLiquidatable(spoke, user, debtReserveId, 0.95e18);

_checkedLiquidationCall(
CheckedLiquidationCallParams({
spoke: spoke,
collateralReserveId: collateralReserveId,
debtReserveId: debtReserveId,
user: user,
debtToCover: UINT256_MAX,
liquidator: liquidator,
isSolvent: true,
receiveShares: true
})
);

uint256 liquidatorHealthFactorAfter = spoke.getUserAccountData(liquidator).healthFactor;
assertGt(liquidatorHealthFactorAfter, liquidatorHealthFactorBefore);
assertGt(liquidatorHealthFactorAfter, HEALTH_FACTOR_LIQUIDATION_THRESHOLD);
}

/// @dev an unhealthy liquidator can be liquidated before receiving shares from another liquidation.
function test_liquidationCall_liquidatorCanBeLiquidatedBeforeReceivingShares() public {
uint256 collateralReserveId = _wethReserveId(spoke);
uint256 debtReserveId = _daiReserveId(spoke);

_increaseCollateralSupply(
spoke,
collateralReserveId,
_convertValueToAmount(spoke, collateralReserveId, 1_000e26),
liquidator
);
_openSupplyPosition(
spoke,
debtReserveId,
_convertValueToAmount(spoke, debtReserveId, 10_000e26)
);
_borrowToBeAtHf(spoke, liquidator, debtReserveId, 0.99e18);

uint256 liquidatorHealthFactorBefore = spoke.getUserAccountData(liquidator).healthFactor;
uint256 liquidatorCollateralBefore = spoke.getUserSuppliedAssets(
collateralReserveId,
liquidator
);
uint256 liquidatorDebtBefore = spoke.getUserTotalDebt(debtReserveId, liquidator);

assertLt(liquidatorHealthFactorBefore, HEALTH_FACTOR_LIQUIDATION_THRESHOLD);

vm.prank(charlie);
spoke.liquidationCall({
collateralReserveId: collateralReserveId,
debtReserveId: debtReserveId,
user: liquidator,
debtToCover: UINT256_MAX,
receiveShares: false
});

assertLt(
spoke.getUserSuppliedAssets(collateralReserveId, liquidator),
liquidatorCollateralBefore
);
assertLt(spoke.getUserTotalDebt(debtReserveId, liquidator), liquidatorDebtBefore);
}

// When liquidation bonus is 0, effective collateral liquidated must be less than effective debt liquidated.
// Full debt is liquidated, and amount of collateral liquidated must be computed based on the effective debt liquidated.
function test_liquidationCall_scenario5() public {
Expand Down
Loading