From 0bc8f01c44efdd44802ff88264c11421e74f8b00 Mon Sep 17 00:00:00 2001 From: Santiago Sanchez Avalos Date: Wed, 17 May 2023 16:01:22 -0300 Subject: [PATCH] =?UTF-8?q?=F0=9F=A4=A1=20mocks:=20add=20`MockBalancerVaul?= =?UTF-8?q?t`=20contract?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gas-snapshot | 43 +++++++++++----------- contracts/mocks/MockBalancerVault.sol | 53 +++++++++++++++++++++++++++ test/solidity/Leverager.t.sol | 17 +++++++++ 3 files changed, 92 insertions(+), 21 deletions(-) create mode 100644 contracts/mocks/MockBalancerVault.sol diff --git a/.gas-snapshot b/.gas-snapshot index 1bea77cbd..c20d0d2ed 100644 --- a/.gas-snapshot +++ b/.gas-snapshot @@ -15,45 +15,46 @@ InterestRateModelTest:testFloatingBorrowRate() (gas: 6236) InterestRateModelTest:testMinFixedRate() (gas: 7610) InterestRateModelTest:testRevertFixedMaxUtilizationLowerThanWad() (gas: 81593) InterestRateModelTest:testRevertFloatingMaxUtilizationLowerThanWad() (gas: 81681) -LeveragerTest:testApproveMaliciousMarket() (gas: 24153) +LeveragerTest:testApproveMaliciousMarket() (gas: 24198) LeveragerTest:testApproveMarket() (gas: 56626) LeveragerTest:testAvailableLiquidity() (gas: 95129) -LeveragerTest:testCallReceiveFlashLoanFromAnyAddress() (gas: 25074) +LeveragerTest:testCallReceiveFlashLoanFromAnyAddress() (gas: 25030) LeveragerTest:testDeleverage() (gas: 449866) -LeveragerTest:testDeleverageHalfBorrowPosition() (gas: 488966) +LeveragerTest:testDeleverageHalfBorrowPosition() (gas: 488989) LeveragerTest:testFixedDeleverage() (gas: 429772) LeveragerTest:testFixedRoll() (gas: 515399) LeveragerTest:testFixedRollSameMaturityWithThreeLoops() (gas: 394620) LeveragerTest:testFixedRollWithAccurateBorrowSlippage() (gas: 693262) LeveragerTest:testFixedRollWithAccurateBorrowSlippageWithThreeLoops() (gas: 1026387) LeveragerTest:testFixedRollWithAccurateRepaySlippage() (gas: 693033) -LeveragerTest:testFixedRollWithAccurateRepaySlippageWithThreeLoops() (gas: 1020923) +LeveragerTest:testFixedRollWithAccurateRepaySlippageWithThreeLoops() (gas: 1020901) LeveragerTest:testFixedToFloatingRoll() (gas: 461239) -LeveragerTest:testFixedToFloatingRollHigherThanAvailableLiquidity() (gas: 528322) +LeveragerTest:testFixedToFloatingRollHigherThanAvailableLiquidity() (gas: 528278) LeveragerTest:testFixedToFloatingRollHigherThanAvailableLiquidityWithSlippage() (gas: 722384) -LeveragerTest:testFixedToFloatingRollHigherThanAvailableLiquidityWithSlippageWithThreeLoops() (gas: 879457) -LeveragerTest:testFixedToFloatingRollWithAccurateSlippage() (gas: 601851) -LeveragerTest:testFlashloanFeeGreaterThanZero() (gas: 400935) +LeveragerTest:testFixedToFloatingRollHigherThanAvailableLiquidityWithSlippageWithThreeLoops() (gas: 879435) +LeveragerTest:testFixedToFloatingRollWithAccurateSlippage() (gas: 601833) +LeveragerTest:testFlashloanFeeGreaterThanZero() (gas: 400913) LeveragerTest:testFloatingToFixedRoll() (gas: 506215) LeveragerTest:testFloatingToFixedRollHigherThanAvailableLiquidity() (gas: 590990) LeveragerTest:testFloatingToFixedRollHigherThanAvailableLiquidityWithSlippage() (gas: 895933) -LeveragerTest:testFloatingToFixedRollHigherThanAvailableLiquidityWithSlippageWithThreePools() (gas: 1105462) -LeveragerTest:testFloatingToFixedRollWithAccurateSlippage() (gas: 724462) -LeveragerTest:testFloatingToFixedRollWithAccurateSlippageWithPreviousPosition() (gas: 675363) +LeveragerTest:testFloatingToFixedRollHigherThanAvailableLiquidityWithSlippageWithThreePools() (gas: 1105440) +LeveragerTest:testFloatingToFixedRollWithAccurateSlippage() (gas: 724440) +LeveragerTest:testFloatingToFixedRollWithAccurateSlippageWithPreviousPosition() (gas: 675341) LeveragerTest:testLateFixedDeleverage() (gas: 471140) -LeveragerTest:testLateFixedRoll() (gas: 526122) +LeveragerTest:testLateFixedRoll() (gas: 526100) LeveragerTest:testLateFixedRollWithThreeLoops() (gas: 707888) LeveragerTest:testLateFixedToFloatingRoll() (gas: 470476) -LeveragerTest:testLateFixedToFloatingRollWithThreeLoops() (gas: 633582) -LeveragerTest:testLeverage() (gas: 365861) -LeveragerTest:testLeverageShouldFailWhenHealthFactorNearOne() (gas: 719076) -LeveragerTest:testLeverageWithAlreadyDepositedAmount() (gas: 394241) -LeveragerTest:testLeverageWithInvalidBalancerVault() (gas: 2691948) -LeveragerTest:testPartialFixedDeleverage() (gas: 516098) -LeveragerTest:testPartialFixedRoll() (gas: 578654) +LeveragerTest:testLateFixedToFloatingRollWithThreeLoops() (gas: 633670) +LeveragerTest:testLeverage() (gas: 365839) +LeveragerTest:testLeverageShouldFailWhenHealthFactorNearOne() (gas: 719054) +LeveragerTest:testLeverageWithAlreadyDepositedAmount() (gas: 394197) +LeveragerTest:testLeverageWithInvalidBalancerVault() (gas: 2691971) +LeveragerTest:testMockBalancerVault() (gas: 3727680) +LeveragerTest:testPartialFixedDeleverage() (gas: 516121) +LeveragerTest:testPartialFixedRoll() (gas: 578742) LeveragerTest:testPartialFixedToFloatingRoll() (gas: 539354) -LeveragerTest:testPartialLateFixedRoll() (gas: 571143) -LeveragerTest:testPartialLateFixedToFloatingRoll() (gas: 538030) +LeveragerTest:testPartialLateFixedRoll() (gas: 571121) +LeveragerTest:testPartialLateFixedToFloatingRoll() (gas: 538008) MarketTest:testAccountLiquidityAdjustedDebt() (gas: 380765) MarketTest:testAnotherUserRedeemWhenOwnerHasShortfall() (gas: 483813) MarketTest:testAnotherUserWithdrawWhenOwnerHasShortfall() (gas: 472690) diff --git a/contracts/mocks/MockBalancerVault.sol b/contracts/mocks/MockBalancerVault.sol new file mode 100644 index 000000000..73e66ccf8 --- /dev/null +++ b/contracts/mocks/MockBalancerVault.sol @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity 0.8.17; + +import { ERC20 } from "solmate/src/tokens/ERC20.sol"; +import { ReentrancyGuard } from "solmate/src/utils/ReentrancyGuard.sol"; +import { SafeTransferLib } from "solmate/src/utils/SafeTransferLib.sol"; + +contract MockBalancerVault is ReentrancyGuard { + using SafeTransferLib for ERC20; + + function flashLoan( + IFlashLoanRecipient recipient, + ERC20[] memory tokens, + uint256[] memory amounts, + bytes memory userData + ) external nonReentrant { + assert(tokens.length == amounts.length); + + uint256[] memory preLoanBalances = new uint256[](tokens.length); + + // Used to ensure `tokens` is sorted in ascending order, which ensures token uniqueness. + ERC20 previousToken = ERC20(address(0)); + + for (uint256 i = 0; i < tokens.length; ++i) { + ERC20 token = tokens[i]; + uint256 amount = amounts[i]; + + require(token > previousToken, token == ERC20(address(0)) ? "Zero token" : "Unsorted tokens"); + previousToken = token; + + preLoanBalances[i] = token.balanceOf(address(this)); + + require(preLoanBalances[i] >= amount, "Insufficient flashloan balance"); + token.safeTransfer(address(recipient), amount); + } + + recipient.receiveFlashLoan(tokens, amounts, new uint256[](tokens.length), userData); + + for (uint256 i = 0; i < tokens.length; ++i) { + uint256 postLoanBalance = tokens[i].balanceOf(address(this)); + require(postLoanBalance >= preLoanBalances[i], "Invalid post flashloan balance"); + } + } +} + +interface IFlashLoanRecipient { + function receiveFlashLoan( + ERC20[] memory tokens, + uint256[] memory amounts, + uint256[] memory feeAmounts, + bytes memory userData + ) external; +} diff --git a/test/solidity/Leverager.t.sol b/test/solidity/Leverager.t.sol index 3f246786f..9a61bbbbc 100644 --- a/test/solidity/Leverager.t.sol +++ b/test/solidity/Leverager.t.sol @@ -12,6 +12,7 @@ import { InvalidOperation } from "../../contracts/periphery/Leverager.sol"; import { Auditor, Market, InsufficientAccountLiquidity, MarketNotListed } from "../../contracts/Auditor.sol"; +import { MockBalancerVault } from "../../contracts/mocks/MockBalancerVault.sol"; import { FixedLib } from "../../contracts/utils/FixedLib.sol"; contract LeveragerTest is Test { @@ -590,6 +591,22 @@ contract LeveragerTest is Test { assertEq(availableAssets[1].liquidity, usdc.balanceOf(address(leverager.balancerVault()))); } + function testMockBalancerVault() external { + MockBalancerVault mockBalancerVault = new MockBalancerVault(); + leverager = new Leverager(leverager.auditor(), IBalancerVault(address(mockBalancerVault))); + marketUSDC.approve(address(leverager), type(uint256).max); + marketUSDC.deposit(100_000e6, address(this)); + marketUSDC.borrow(50_000e6, address(this), address(this)); + + vm.expectRevert(bytes("")); + leverager.floatingRoll(marketUSDC, true, maturity, type(uint256).max, 1e18); + + deal(address(usdc), address(mockBalancerVault), 50000000001); + leverager.floatingRoll(marketUSDC, true, maturity, type(uint256).max, 1e18); + (uint256 principal, ) = marketUSDC.fixedBorrowPositions(maturity, address(this)); + assertEq(principal, 50_000e6 + 1); + } + function previewActualRepay(uint256 percentage) internal view returns (uint256 actualRepay) { FixedLib.Position memory position; (position.principal, position.fee) = marketUSDC.fixedBorrowPositions(maturity, address(this));