Created
June 22, 2023 19:27
-
-
Save aviggiano/f5f22404e0bbd314fd217642b1deed2b to your computer and use it in GitHub Desktop.
Test that liquidating a position does not leave the protocol with less collateral than minimum debt value
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// SPDX-License-Identifier: MIT | |
pragma solidity 0.8.19; | |
import { Fixed256x18 } from "@tempusfinance/tempus-utils/contracts/math/Fixed256x18.sol"; | |
import { PositionManager } from "../contracts/PositionManager.sol"; | |
import { IERC20Indexable } from "../contracts/Interfaces/IERC20Indexable.sol"; | |
import { IRToken } from "../contracts/Interfaces/IRToken.sol"; | |
import { PriceFeedTestnet } from "./mocks/PriceFeedTestnet.sol"; | |
import { TestSetup } from "./utils/TestSetup.t.sol"; | |
import { FlashMintLiquidator } from "../contracts/FlashMintLiquidator.sol"; | |
import { MockAMM } from "./mocks/MockAMM.sol"; | |
contract PositionManagerLiquidationTotalCollateralCannotBeLowerThanMinCollateralTest is TestSetup { | |
using Fixed256x18 for uint256; | |
uint256 public constant DEFAULT_PRICE = 200 * 1e18; | |
PriceFeedTestnet public priceFeed; | |
PriceFeedTestnet public priceFeed2; | |
IRToken public rToken; | |
IERC20Indexable public raftDebtToken; | |
IERC20Indexable public raftDebtToken2; | |
MockAMM public mockAmm; | |
FlashMintLiquidator public liquidator; | |
function setUp() public override { | |
super.setUp(); | |
priceFeed = new PriceFeedTestnet(); | |
priceFeed2 = new PriceFeedTestnet(); | |
rToken = positionManager.rToken(); | |
positionManager.addCollateralToken(collateralToken, priceFeed, splitLiquidationCollateral); | |
positionManager.addCollateralToken(collateralToken2, priceFeed2, splitLiquidationCollateral2); | |
mockAmm = new MockAMM(collateralToken2, rToken, DEFAULT_PRICE); | |
liquidator = new FlashMintLiquidator(positionManager, mockAmm, collateralToken2); | |
(,raftDebtToken, ,,,,,,,) = positionManager.collateralInfo(collateralToken); | |
(,raftDebtToken2, ,,,,,,,) = positionManager.collateralInfo(collateralToken2); | |
collateralToken.mint(ALICE, 10e36); | |
collateralToken.mint(BOB, 10e36); | |
collateralToken.mint(CAROL, 10e36); | |
collateralToken.mint(DAVE, 10e36); | |
collateralToken.mint(EVE, 10e36); | |
collateralToken.mint(FRANK, 10e36); | |
collateralToken2.mint(ALICE, 10e36); | |
collateralToken2.mint(BOB, 10e36); | |
collateralToken2.mint(CAROL, 10e36); | |
collateralToken2.mint(DAVE, 10e36); | |
collateralToken2.mint(EVE, 10e36); | |
collateralToken2.mint(FRANK, 10e36); | |
priceFeed.setPrice(DEFAULT_PRICE); | |
} | |
event Debug(string name, uint256 value); | |
function testLiquidateCollateralWhenOnlyOnePositionActive() public { | |
// 1. Deposit high TVL on collateral 1 | |
// 2. Deposit min on collateral 2 | |
// 3. Deposit high on collateral 2 | |
// 4. Liquidate high collateral 2 | |
// 5. Deposit new high collateral 2 | |
// 6. See what happens to you and them | |
// 1. Deposit high TVL on collateral 1 | |
uint256 initialCR = 1.11e18; | |
uint256 rToMint = 55.6 * 1e6 * 1e18; // 55.6m TVL according to defillama | |
uint256 collateralAmount = rToMint.divUp(DEFAULT_PRICE).mulUp(initialCR); | |
vm.startPrank(ALICE); | |
collateralToken.approve(address(positionManager), collateralAmount); | |
positionManager.managePosition( | |
collateralToken, | |
ALICE, | |
collateralAmount, | |
true, // collateral increase | |
rToMint, | |
true, // debt increase | |
1e17, | |
emptySignature | |
); | |
emit Debug("b4 raftDebtToken.balanceOf(ALICE)", raftDebtToken.balanceOf(ALICE)); | |
emit Debug("b4 rToken.balanceOf(ALICE)", rToken.balanceOf(ALICE)); | |
// 2. Deposit min on collateral 2 | |
vm.stopPrank(); | |
vm.startPrank(BOB); | |
rToMint = splitLiquidationCollateral2.LOW_TOTAL_DEBT(); // mint minimum debt value (3000 R) using collateral 2 | |
collateralAmount = rToMint.divUp(DEFAULT_PRICE).mulUp(initialCR); // assuming collateral 2 price == collateral 1 price | |
collateralToken2.approve(address(positionManager), collateralAmount); | |
positionManager.managePosition( | |
collateralToken2, | |
BOB, | |
collateralAmount, | |
true, // collateral increase | |
rToMint, | |
true, // debt increase | |
1e17, | |
emptySignature | |
); | |
emit Debug("b4 raftDebtToken2.balanceOf(BOB)", raftDebtToken2.balanceOf(BOB)); | |
emit Debug("b4 rToken.balanceOf(BOB)", rToken.balanceOf(BOB)); | |
vm.stopPrank(); | |
// 3. Deposit high on collateral 2 | |
// last position cannot be liquidated, so we need a new one | |
vm.startPrank(CAROL); | |
rToMint = 10_000 * splitLiquidationCollateral2.LOW_TOTAL_DEBT(); // whale | |
collateralAmount = rToMint.divUp(DEFAULT_PRICE).mulUp(initialCR); // assuming collateral 2 price == collateral 1 price | |
collateralToken2.approve(address(positionManager), collateralAmount); | |
positionManager.managePosition( | |
collateralToken2, | |
CAROL, | |
collateralAmount, | |
true, // collateral increase | |
rToMint, | |
true, // debt increase | |
1e17, | |
emptySignature | |
); | |
vm.stopPrank(); | |
emit Debug("b4 raftDebtToken2.balanceOf(CAROL)", raftDebtToken2.balanceOf(CAROL)); | |
emit Debug("b4 rToken.balanceOf(CAROL)", rToken.balanceOf(CAROL)); | |
// 4. Liquidate high collateral 2 | |
// price drops to 1ETH:198R, reducing CAROL's ICR between 100% and 110% | |
uint256 price = 198e18; | |
priceFeed2.setPrice(price); | |
vm.startPrank(ALICE); | |
positionManager.liquidate(CAROL); // liquidate whale, greatly reducing collateral2 from protocol | |
emit Debug("raftDebtToken.balanceOf(ALICE)", raftDebtToken.balanceOf(ALICE)); | |
emit Debug("rToken.balanceOf(ALICE)", rToken.balanceOf(ALICE)); | |
emit Debug("raftDebtToken2.balanceOf(BOB)", raftDebtToken2.balanceOf(BOB)); | |
emit Debug("rToken.balanceOf(BOB)", rToken.balanceOf(BOB)); | |
emit Debug("raftDebtToken2.balanceOf(CAROL)", raftDebtToken2.balanceOf(CAROL)); | |
emit Debug("rToken.balanceOf(CAROL)", rToken.balanceOf(CAROL)); | |
assertEq(raftDebtToken.balanceOf(CAROL), 0); | |
vm.stopPrank(); | |
// 5. Deposit new high collateral 2 | |
// another user tries to deposit again | |
rToMint = 400_000e18; | |
collateralAmount = rToMint.divUp(price).mulUp(initialCR); | |
vm.startPrank(DAVE); | |
collateralToken2.approve(address(positionManager), collateralAmount); | |
positionManager.managePosition( | |
collateralToken2, | |
DAVE, | |
collateralAmount, | |
true, // collateral increase | |
rToMint, | |
true, // debt increase | |
1e17, | |
emptySignature | |
); | |
emit Debug("raftDebtToken2.balanceOf(DAVE)", raftDebtToken2.balanceOf(DAVE)); | |
emit Debug("rToken.balanceOf(DAVE)", rToken.balanceOf(DAVE)); | |
// 6. See what happens to you and them | |
assertEq(raftDebtToken2.balanceOf(DAVE), rToken.balanceOf(DAVE)); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment