Skip to content

Commit

Permalink
✨ debt-manager: support cross-deleverage
Browse files Browse the repository at this point in the history
  • Loading branch information
itofarina authored and santichez committed Jun 26, 2023
1 parent ba05342 commit 59b6d17
Show file tree
Hide file tree
Showing 4 changed files with 153 additions and 51 deletions.
5 changes: 5 additions & 0 deletions .changeset/tiny-bears-hammer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@exactly/protocol": patch
---

✨ debt-manager: support cross-deleverage
100 changes: 52 additions & 48 deletions .gas-snapshot
Original file line number Diff line number Diff line change
Expand Up @@ -10,55 +10,59 @@ AuditorTest:testEnableMarketAuditorMismatch() (gas: 24805)
AuditorTest:testEnableMarketShouldRevertWithInvalidPriceFeed() (gas: 149281)
AuditorTest:testEnterExitMarket() (gas: 178761)
AuditorTest:testExitMarketOwning() (gas: 177445)
DebtManagerTest:testApproveMaliciousMarket() (gas: 29094)
DebtManagerTest:testApproveMarket() (gas: 61541)
DebtManagerTest:testAvailableLiquidity() (gas: 127236)
DebtManagerTest:testBalancerFlashloanCallFromDifferentOrigin() (gas: 65836)
DebtManagerTest:testCallReceiveFlashLoanFromAnyAddress() (gas: 33615)
DebtManagerTest:testCrossLeverageFromUSDCToWETH() (gas: 972581)
DebtManagerTest:testCrossLeverageFromwstETHtoWETH() (gas: 934255)
DebtManagerTest:testCrossLeverageWithDeposit() (gas: 924350)
DebtManagerTest:testCrossLeverageWithInvalidFee() (gas: 154892)
DebtManagerTest:testDeleverage() (gas: 760044)
DebtManagerTest:testDeleverageHalfBorrowPosition() (gas: 800712)
DebtManagerTest:testDeleverageWithWithdraw() (gas: 794237)
DebtManagerTest:testFixedDeleverage() (gas: 732125)
DebtManagerTest:testFixedRoll() (gas: 832061)
DebtManagerTest:testApproveMaliciousMarket() (gas: 29116)
DebtManagerTest:testApproveMarket() (gas: 61563)
DebtManagerTest:testAvailableLiquidity() (gas: 127148)
DebtManagerTest:testBalancerFlashloanCallFromDifferentOrigin() (gas: 65858)
DebtManagerTest:testCallReceiveFlashLoanFromAnyAddress() (gas: 33637)
DebtManagerTest:testCrossDeleverageFromWETHToUSDC() (gas: 1129135)
DebtManagerTest:testCrossDeleverageFromwstETHToWETH() (gas: 1052805)
DebtManagerTest:testCrossDeleverageWithInvalidFee() (gas: 785986)
DebtManagerTest:testCrossDeleverageWithInvalidPercentage() (gas: 1104620)
DebtManagerTest:testCrossLeverageFromUSDCToWETH() (gas: 973049)
DebtManagerTest:testCrossLeverageFromwstETHtoWETH() (gas: 934723)
DebtManagerTest:testCrossLeverageWithDeposit() (gas: 924818)
DebtManagerTest:testCrossLeverageWithInvalidFee() (gas: 155019)
DebtManagerTest:testDeleverage() (gas: 760132)
DebtManagerTest:testDeleverageHalfBorrowPosition() (gas: 800866)
DebtManagerTest:testDeleverageWithWithdraw() (gas: 794325)
DebtManagerTest:testFixedDeleverage() (gas: 732169)
DebtManagerTest:testFixedRoll() (gas: 832083)
DebtManagerTest:testFixedRollSameMaturityWithThreeLoops() (gas: 690162)
DebtManagerTest:testFixedRollWithAccurateBorrowSlippage() (gas: 1156577)
DebtManagerTest:testFixedRollWithAccurateBorrowSlippageWithThreeLoops() (gas: 2080139)
DebtManagerTest:testFixedRollWithAccurateRepaySlippage() (gas: 1156537)
DebtManagerTest:testFixedRollWithAccurateRepaySlippageWithThreeLoops() (gas: 2074877)
DebtManagerTest:testFixedToFloatingRoll() (gas: 787156)
DebtManagerTest:testFixedToFloatingRollHigherThanAvailableLiquidity() (gas: 917251)
DebtManagerTest:testFixedToFloatingRollHigherThanAvailableLiquidityWithSlippage() (gas: 1349570)
DebtManagerTest:testFixedToFloatingRollHigherThanAvailableLiquidityWithSlippageWithThreeLoops() (gas: 1948971)
DebtManagerTest:testFixedToFloatingRollWithAccurateSlippage() (gas: 1053097)
DebtManagerTest:testFlashloanFeeGreaterThanZero() (gas: 692539)
DebtManagerTest:testFloatingToFixedRoll() (gas: 808584)
DebtManagerTest:testFloatingToFixedRollHigherThanAvailableLiquidity() (gas: 956240)
DebtManagerTest:testFloatingToFixedRollHigherThanAvailableLiquidityWithSlippage() (gas: 1452843)
DebtManagerTest:testFloatingToFixedRollHigherThanAvailableLiquidityWithSlippageWithThreePools() (gas: 2218100)
DebtManagerTest:testFloatingToFixedRollWithAccurateSlippage() (gas: 1133688)
DebtManagerTest:testFloatingToFixedRollWithAccurateSlippageWithPreviousPosition() (gas: 1141687)
DebtManagerTest:testLateFixedDeleverage() (gas: 857112)
DebtManagerTest:testLateFixedRoll() (gas: 915668)
DebtManagerTest:testLateFixedRollWithThreeLoops() (gas: 1432856)
DebtManagerTest:testLateFixedToFloatingRoll() (gas: 869320)
DebtManagerTest:testLateFixedToFloatingRollWithThreeLoops() (gas: 1359083)
DebtManagerTest:testLeverage() (gas: 634676)
DebtManagerTest:testLeverageShouldFailWhenHealthFactorNearOne() (gas: 1270622)
DebtManagerTest:testLeverageWithAlreadyDepositedAmount() (gas: 668330)
DebtManagerTest:testLeverageWithInvalidBalancerVault() (gas: 3757470)
DebtManagerTest:testMockBalancerVault() (gas: 5443352)
DebtManagerTest:testPartialFixedDeleverage() (gas: 798591)
DebtManagerTest:testPartialFixedRoll() (gas: 875325)
DebtManagerTest:testPartialFixedToFloatingRoll() (gas: 845410)
DebtManagerTest:testPartialLateFixedRoll() (gas: 960501)
DebtManagerTest:testPartialLateFixedToFloatingRoll() (gas: 936905)
DebtManagerTest:testPermit2AndLeverage() (gas: 781144)
DebtManagerTest:testPermitAndDeleverage() (gas: 835432)
DebtManagerTest:testPermitAndRollFloatingToFixed() (gas: 893978)
DebtManagerTest:testFixedRollWithAccurateBorrowSlippage() (gas: 1156621)
DebtManagerTest:testFixedRollWithAccurateBorrowSlippageWithThreeLoops() (gas: 2080183)
DebtManagerTest:testFixedRollWithAccurateRepaySlippage() (gas: 1156603)
DebtManagerTest:testFixedRollWithAccurateRepaySlippageWithThreeLoops() (gas: 2074921)
DebtManagerTest:testFixedToFloatingRoll() (gas: 787178)
DebtManagerTest:testFixedToFloatingRollHigherThanAvailableLiquidity() (gas: 917273)
DebtManagerTest:testFixedToFloatingRollHigherThanAvailableLiquidityWithSlippage() (gas: 1349614)
DebtManagerTest:testFixedToFloatingRollHigherThanAvailableLiquidityWithSlippageWithThreeLoops() (gas: 1949037)
DebtManagerTest:testFixedToFloatingRollWithAccurateSlippage() (gas: 1053163)
DebtManagerTest:testFlashloanFeeGreaterThanZero() (gas: 692583)
DebtManagerTest:testFloatingToFixedRoll() (gas: 808606)
DebtManagerTest:testFloatingToFixedRollHigherThanAvailableLiquidity() (gas: 956262)
DebtManagerTest:testFloatingToFixedRollHigherThanAvailableLiquidityWithSlippage() (gas: 1452887)
DebtManagerTest:testFloatingToFixedRollHigherThanAvailableLiquidityWithSlippageWithThreePools() (gas: 2218166)
DebtManagerTest:testFloatingToFixedRollWithAccurateSlippage() (gas: 1133754)
DebtManagerTest:testFloatingToFixedRollWithAccurateSlippageWithPreviousPosition() (gas: 1141753)
DebtManagerTest:testLateFixedDeleverage() (gas: 857156)
DebtManagerTest:testLateFixedRoll() (gas: 915690)
DebtManagerTest:testLateFixedRollWithThreeLoops() (gas: 1432878)
DebtManagerTest:testLateFixedToFloatingRoll() (gas: 869342)
DebtManagerTest:testLateFixedToFloatingRollWithThreeLoops() (gas: 1359105)
DebtManagerTest:testLeverage() (gas: 634720)
DebtManagerTest:testLeverageShouldFailWhenHealthFactorNearOne() (gas: 1270732)
DebtManagerTest:testLeverageWithAlreadyDepositedAmount() (gas: 668352)
DebtManagerTest:testLeverageWithInvalidBalancerVault() (gas: 4043629)
DebtManagerTest:testMockBalancerVault() (gas: 5729555)
DebtManagerTest:testPartialFixedDeleverage() (gas: 798613)
DebtManagerTest:testPartialFixedRoll() (gas: 875347)
DebtManagerTest:testPartialFixedToFloatingRoll() (gas: 845454)
DebtManagerTest:testPartialLateFixedRoll() (gas: 960590)
DebtManagerTest:testPartialLateFixedToFloatingRoll() (gas: 936927)
DebtManagerTest:testPermit2AndLeverage() (gas: 781166)
DebtManagerTest:testPermitAndDeleverage() (gas: 835476)
DebtManagerTest:testPermitAndRollFloatingToFixed() (gas: 893911)
InterestRateModelTest:testFixedBorrowRate() (gas: 8089)
InterestRateModelTest:testFloatingBorrowRate() (gas: 6236)
InterestRateModelTest:testMinFixedRate() (gas: 7610)
Expand Down
54 changes: 51 additions & 3 deletions contracts/periphery/DebtManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,42 @@ contract DebtManager is Initializable {
outAsset: v.outAsset,
principal: deposit ? principal : 0,
account: msg.sender,
fee: fee
fee: fee,
leverage: true
})
)
);
}

/// @notice Cross-deleverages the floating position of `msg.sender`
/// @param inMarket The Market to withdraw the leveraged position.
/// @param outMarket The Market to repay the leveraged position.
/// @param fee The fee of the pool that will be used to swap the assets.
/// @param percentage The percentage that the position will be deleveraged.
function crossDeleverage(Market inMarket, Market outMarket, uint24 fee, uint256 percentage) external {
LeverageVars memory v;
v.inAsset = address(inMarket.asset());
v.outAsset = address(outMarket.asset());

(, , uint256 floatingBorrowShares) = outMarket.accounts(msg.sender);
v.amount = outMarket.previewRefund(floatingBorrowShares.mulWadDown(percentage));

PoolKey memory poolKey = PoolAddress.getPoolKey(v.inAsset, v.outAsset, fee);
IUniswapV3Pool(PoolAddress.computeAddress(uniswapV3Factory, poolKey)).swap(
address(this),
v.inAsset == poolKey.token0,
-int256(v.amount),
v.inAsset == poolKey.token0 ? MIN_SQRT_RATIO + 1 : MAX_SQRT_RATIO - 1,
abi.encode(
SwapCallbackData({
inMarket: inMarket,
outMarket: outMarket,
inAsset: v.inAsset,
outAsset: v.outAsset,
principal: v.amount,
account: msg.sender,
fee: fee,
leverage: false
})
)
);
Expand Down Expand Up @@ -406,8 +441,20 @@ contract DebtManager is Initializable {
PoolKey memory poolKey = PoolAddress.getPoolKey(s.inAsset, s.outAsset, s.fee);
assert(msg.sender == PoolAddress.computeAddress(uniswapV3Factory, poolKey));

s.inMarket.deposit(s.principal + uint256(-(s.inAsset == poolKey.token0 ? amount0Delta : amount1Delta)), s.account);
s.outMarket.borrow(uint256(s.inAsset == poolKey.token1 ? amount0Delta : amount1Delta), msg.sender, s.account);
if (s.leverage) {
s.inMarket.deposit(
s.principal + uint256(-(s.inAsset == poolKey.token0 ? amount0Delta : amount1Delta)),
s.account
);
s.outMarket.borrow(uint256(s.inAsset == poolKey.token1 ? amount0Delta : amount1Delta), msg.sender, s.account);
} else {
s.outMarket.repay(s.principal, s.account);
s.inMarket.withdraw(
s.inAsset == poolKey.token1 ? uint256(amount1Delta) : uint256(amount0Delta),
msg.sender,
s.account
);
}
}

/// @notice Calls `token.permit` on behalf of `permit.account`.
Expand Down Expand Up @@ -574,6 +621,7 @@ contract DebtManager is Initializable {
address account;
uint256 principal;
uint24 fee;
bool leverage;
}
}

Expand Down
45 changes: 45 additions & 0 deletions test/solidity/DebtManager.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -752,6 +752,51 @@ contract DebtManagerTest is Test {
debtManager.crossLeverage(marketUSDC, marketWETH, 200, 100_000e6, 1.1e18, true);
}

function testCrossDeleverageFromwstETHToWETH() external _checkBalances {
marketwstETH.asset().approve(address(debtManager), type(uint256).max);
debtManager.auditor().enterMarket(marketwstETH);
debtManager.crossLeverage(marketwstETH, marketWETH, 500, 10e18, 1.02e18, true);
(, , uint256 floatingBorrowShares) = marketWETH.accounts(address(this));
uint256 percentage = 1e18;
debtManager.crossDeleverage(marketwstETH, marketWETH, 500, percentage);

assertEq(marketwstETH.maxWithdraw(address(this)), 9_980_645_608_672_055_653);
(, , uint256 newFloatingBorrowShares) = marketWETH.accounts(address(this));
assertEq(newFloatingBorrowShares, floatingBorrowShares - floatingBorrowShares.mulWadDown(percentage));
}

function testCrossDeleverageFromWETHToUSDC() external _checkBalances {
marketWETH.asset().approve(address(debtManager), type(uint256).max);
debtManager.auditor().enterMarket(marketWETH);
debtManager.crossLeverage(marketWETH, marketUSDC, 500, 10e18, 1.02e18, true);
(, , uint256 floatingBorrowShares) = marketUSDC.accounts(address(this));
uint256 percentage = 1e18;
debtManager.crossDeleverage(marketWETH, marketUSDC, 500, percentage);

uint256 maxWithdraw = marketWETH.maxWithdraw(address(this));
assertEq(maxWithdraw, 9_970_057_426_084_898_139);
(, , uint256 newFloatingBorrowShares) = marketUSDC.accounts(address(this));
assertEq(newFloatingBorrowShares, floatingBorrowShares - floatingBorrowShares.mulWadDown(percentage));
}

function testCrossDeleverageWithInvalidFee() external _checkBalances {
marketwstETH.asset().approve(address(debtManager), type(uint256).max);
debtManager.auditor().enterMarket(marketwstETH);
debtManager.crossLeverage(marketwstETH, marketWETH, 500, 10_000e6, 1.02e18, true);

vm.expectRevert(bytes(""));
debtManager.crossDeleverage(marketwstETH, marketWETH, 200, 1e18);
}

function testCrossDeleverageWithInvalidPercentage() external _checkBalances {
marketwstETH.asset().approve(address(debtManager), type(uint256).max);
debtManager.auditor().enterMarket(marketwstETH);
debtManager.crossLeverage(marketwstETH, marketWETH, 500, 10e18, 1.02e18, true);
uint256 percentage = 2e18;
vm.expectRevert(abi.encodeWithSelector(InsufficientAccountLiquidity.selector));
debtManager.crossDeleverage(marketwstETH, marketWETH, 500, percentage);
}

function testPermitAndRollFloatingToFixed() external {
marketUSDC.deposit(100_000e6, bob);
vm.prank(bob);
Expand Down

0 comments on commit 59b6d17

Please sign in to comment.