diff --git a/.changeset/slimy-numbers-reply.md b/.changeset/slimy-numbers-reply.md new file mode 100644 index 00000000..2bdea0ae --- /dev/null +++ b/.changeset/slimy-numbers-reply.md @@ -0,0 +1,5 @@ +--- +"@exactly/protocol": patch +--- + +⚡️ market: transfer liquidator repayment first diff --git a/.gas-snapshot b/.gas-snapshot index 2f3ec041..c02616ed 100644 --- a/.gas-snapshot +++ b/.gas-snapshot @@ -143,7 +143,7 @@ InterestRateModelTest:testFixedRateRevertUtilizationExceeded() (gas: 2053399) InterestRateModelTest:testFloatingBorrowRate() (gas: 2045540) InterestRateModelTest:testFuzzFixedRateGrowth(uint256,uint256,uint256,uint256) (runs: 256, μ: 2067117, ~: 2063904) InterestRateModelTest:testFuzzFixedRateTimeSensitivity(uint256,uint256,uint256) (runs: 256, μ: 2073166, ~: 2073210) -InterestRateModelTest:testFuzzReferenceLegacyRateFixed(uint32,uint256,uint256[2],uint256[2],uint256,uint256,uint256) (runs: 256, μ: 9956141, ~: 10120698) +InterestRateModelTest:testFuzzReferenceLegacyRateFixed(uint32,uint256,uint256[2],uint256[2],uint256,uint256,uint256) (runs: 256, μ: 9955962, ~: 10120518) InterestRateModelTest:testFuzzReferenceRateFixed(uint256,uint256,uint256,uint256,uint256,uint256,(uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,int256,uint256,uint256)) (runs: 256, μ: 2337454, ~: 2339865) InterestRateModelTest:testFuzzReferenceRateFloating(uint256,uint256,(uint256,uint256,uint256,uint256,uint256,uint256,uint256)) (runs: 256, μ: 2275596, ~: 2276456) InterestRateModelTest:testMinTimeToMaturity() (gas: 2063554) @@ -155,13 +155,13 @@ MarketTest:testBorrowAfterFreezing() (gas: 491482) MarketTest:testBorrowAtMaturity() (gas: 499544) MarketTest:testBorrowAtMaturityAfterFreezing() (gas: 573160) MarketTest:testBorrowAtMaturityUpdatesFloatingDebtAndFloatingAssets() (gas: 884694) -MarketTest:testBorrowAtMaturityWhenFrozen() (gas: 93718) +MarketTest:testBorrowAtMaturityWhenFrozen() (gas: 93696) MarketTest:testBorrowAtMaturityWithZeroAssets() (gas: 40425) MarketTest:testBorrowDisagreement() (gas: 295415) MarketTest:testBorrowFromFreeLunchShouldNotRevertWithFloatingFullUtilization() (gas: 1294314) MarketTest:testBorrowWhenFrozen() (gas: 93224) MarketTest:testBorrowWithZeroAssets() (gas: 39771) -MarketTest:testCappedLiquidation() (gas: 1197518) +MarketTest:testCappedLiquidation() (gas: 1197582) MarketTest:testChargeTreasuryToEarlyWithdraws() (gas: 1218518) MarketTest:testChargeTreasuryToFixedBorrows() (gas: 1576488) MarketTest:testClearBadDebtAvoidingFixedBorrowsIfAccumulatorLower() (gas: 2277467) @@ -171,32 +171,32 @@ MarketTest:testClearBadDebtPartiallyRepaysEachFixedBorrow() (gas: 1955355) MarketTest:testClearBadDebtPartiallyRepaysFloatingDebt() (gas: 2285567) MarketTest:testClearBadDebtShouldAccrueAccumulatedEarningsBeforeSpreadingLosses() (gas: 2075328) MarketTest:testClearBadDebtWithEmptyAccumulatorShouldNotRevert() (gas: 969888) -MarketTest:testClearMaturity() (gas: 1681888) +MarketTest:testClearMaturity() (gas: 1681866) MarketTest:testCollectTreasuryFreeLunchToEarlyWithdraws() (gas: 1766265) MarketTest:testCollectTreasuryFreeLunchToEarlyWithdrawsWithZeroFees() (gas: 559337) MarketTest:testCollectTreasuryFreeLunchToFixedBorrows() (gas: 1808756) -MarketTest:testCollectTreasuryFreeLunchToFixedBorrowsWithZeroFees() (gas: 722718) -MarketTest:testCrossMaturityLiquidation() (gas: 2627137) -MarketTest:testDepositAfterFreezing() (gas: 256227) +MarketTest:testCollectTreasuryFreeLunchToFixedBorrowsWithZeroFees() (gas: 722696) +MarketTest:testCrossMaturityLiquidation() (gas: 2627134) +MarketTest:testDepositAfterFreezing() (gas: 256205) MarketTest:testDepositAtMaturity() (gas: 193478) MarketTest:testDepositAtMaturityAfterFreezing() (gas: 267449) MarketTest:testDepositAtMaturityWhenFrozen() (gas: 93209) MarketTest:testDepositAtMaturityWithZeroAssets() (gas: 39977) MarketTest:testDepositDisagreement() (gas: 73882) -MarketTest:testDepositShouldUpdateFlexibleBorrowVariables() (gas: 716971) +MarketTest:testDepositShouldUpdateFlexibleBorrowVariables() (gas: 716949) MarketTest:testDepositToSmartPool() (gas: 181849) MarketTest:testDepositWhenFrozen() (gas: 176471) MarketTest:testDistributeMultipleAccumulatedEarnings() (gas: 1371073) -MarketTest:testDistributionOfLossesShouldReduceFromFloatingBackupBorrowedAccordingly() (gas: 6401787) -MarketTest:testEarlyRepayLiquidationUnassignedEarnings() (gas: 2063718) +MarketTest:testDistributionOfLossesShouldReduceFromFloatingBackupBorrowedAccordingly() (gas: 6401781) +MarketTest:testEarlyRepayLiquidationUnassignedEarnings() (gas: 2063715) MarketTest:testEarlyRepaymentWithExcessiveAmountOfFees() (gas: 3407434) MarketTest:testEarlyWithdrawFromFreeLunchShouldNotRevertWithFloatingFullUtilization() (gas: 1050081) MarketTest:testEmergencyAdminRole() (gas: 317196) MarketTest:testEmitFrozen() (gas: 91114) -MarketTest:testFixedBorrowFailingWhenFlexibleBorrowAccruesDebt() (gas: 1530855) +MarketTest:testFixedBorrowFailingWhenFlexibleBorrowAccruesDebt() (gas: 1530833) MarketTest:testFixedBorrowRateToMaturity() (gas: 562488) MarketTest:testFixedOperationsUpdateFloatingDebt() (gas: 865363) -MarketTest:testFlexibleBorrow() (gas: 423656) +MarketTest:testFlexibleBorrow() (gas: 423743) MarketTest:testFlexibleBorrowAccountingDebt() (gas: 607131) MarketTest:testFlexibleBorrowChargingDebtToTreasury() (gas: 751177) MarketTest:testFlexibleBorrowExceedingReserve() (gas: 878408) @@ -206,44 +206,45 @@ MarketTest:testFlexibleBorrowFromAnotherUserSubtractsAllowance() (gas: 469265) MarketTest:testFlexibleBorrowFromAnotherUserWithAllowance() (gas: 458659) MarketTest:testFlexibleBorrowFromAnotherUserWithoutAllowance() (gas: 252359) MarketTest:testFrontRunSmartPoolEarningsDistributionWithBigPenaltyRepayment() (gas: 1370263) -MarketTest:testFullPause() (gas: 5938463) +MarketTest:testFullPause() (gas: 5956320) MarketTest:testInitiallyUnfrozen() (gas: 15614) MarketTest:testInsufficientProtocolLiquidity() (gas: 1940379) -MarketTest:testLiquidateAndChargeIncentiveForLenders() (gas: 2431163) -MarketTest:testLiquidateAndDistributeLosses() (gas: 3228072) -MarketTest:testLiquidateAndSeizeExactAmountWithDustAsCollateral() (gas: 2795855) +MarketTest:testLiquidateAndChargeIncentiveForLenders() (gas: 2431160) +MarketTest:testLiquidateAndDistributeLosses() (gas: 3228069) +MarketTest:testLiquidateAndSeizeExactAmountWithDustAsCollateral() (gas: 2795830) MarketTest:testLiquidateAndSeizeFromEmptyCollateral() (gas: 1039302) -MarketTest:testLiquidateAndSubtractLossesFromAccumulator() (gas: 3920997) -MarketTest:testLiquidateFlexibleAndFixedBorrowPositionsInSingleCall() (gas: 2631851) -MarketTest:testLiquidateFlexibleBorrow() (gas: 2156192) -MarketTest:testLiquidateFlexibleBorrowChargeLendersAssetsToLiquidator() (gas: 1150182) -MarketTest:testLiquidateFlexibleBorrowConsideringDebtOverTime() (gas: 1166273) -MarketTest:testLiquidateLeavingDustAsCollateral() (gas: 3610427) -MarketTest:testLiquidateUpdateFloatingDebt() (gas: 1901729) -MarketTest:testLiquidateWhenFrozen() (gas: 1230791) -MarketTest:testLiquidateWithTwoUnitsAsMaxAssets() (gas: 1576945) -MarketTest:testLiquidateWithZeroAsMaxAssets() (gas: 1039165) -MarketTest:testLiquidationClearingDebtOfAllAccountMarkets() (gas: 3093417) -MarketTest:testLiquidationResultingInZeroCollateralAndZeroDebt() (gas: 1969111) -MarketTest:testMaturityInsufficientProtocolLiquidity() (gas: 1464075) -MarketTest:testMultipleBorrowsForMultipleAssets() (gas: 2463367818) -MarketTest:testMultipleDepositsToSmartPool() (gas: 915573) +MarketTest:testLiquidateAndSubtractLossesFromAccumulator() (gas: 3920994) +MarketTest:testLiquidateFlexibleAndFixedBorrowPositionsInSingleCall() (gas: 2631842) +MarketTest:testLiquidateFlexibleBorrow() (gas: 2156186) +MarketTest:testLiquidateFlexibleBorrowChargeLendersAssetsToLiquidator() (gas: 1150179) +MarketTest:testLiquidateFlexibleBorrowConsideringDebtOverTime() (gas: 1166270) +MarketTest:testLiquidateLeavingDustAsCollateral() (gas: 3622684) +MarketTest:testLiquidateTransferRepayAssetsBeforeSeize() (gas: 1045448) +MarketTest:testLiquidateUpdateFloatingDebt() (gas: 1901726) +MarketTest:testLiquidateWhenFrozen() (gas: 1230788) +MarketTest:testLiquidateWithTwoUnitsAsMaxAssets() (gas: 1576942) +MarketTest:testLiquidateWithZeroAsMaxAssets() (gas: 1039143) +MarketTest:testLiquidationClearingDebtOfAllAccountMarkets() (gas: 3093414) +MarketTest:testLiquidationResultingInZeroCollateralAndZeroDebt() (gas: 1969108) +MarketTest:testMaturityInsufficientProtocolLiquidity() (gas: 1464163) +MarketTest:testMultipleBorrowsForMultipleAssets() (gas: 2463367095) +MarketTest:testMultipleDepositsToSmartPool() (gas: 915551) MarketTest:testMultipleFixedBorrowsRepays() (gas: 1348303) -MarketTest:testMultipleLiquidationSameUser() (gas: 2946704) -MarketTest:testNotEnteredMarketShouldNotBeSeized() (gas: 8537325) -MarketTest:testOnlyAdminCanFreezeUnfreeze() (gas: 207703) +MarketTest:testMultipleLiquidationSameUser() (gas: 2946695) +MarketTest:testNotEnteredMarketShouldNotBeSeized() (gas: 8537120) +MarketTest:testOnlyAdminCanFreezeUnfreeze() (gas: 207681) MarketTest:testOperationsShouldUpdateFloatingAssetsAverage() (gas: 1395020) -MarketTest:testOperationsWithBtcWbtcRate() (gas: 8215417) -MarketTest:testOperationsWithStEthAsset() (gas: 8102759) -MarketTest:testPausable() (gas: 158136) +MarketTest:testOperationsWithBtcWbtcRate() (gas: 8215237) +MarketTest:testOperationsWithStEthAsset() (gas: 8102579) +MarketTest:testPausable() (gas: 158114) MarketTest:testPauserRole() (gas: 78206) MarketTest:testPreviewOperationsWithSmartPoolCorrectlyAccountingEarnings() (gas: 1976217) MarketTest:testRepayAtMaturity() (gas: 586699) MarketTest:testRepayDisagreement() (gas: 594020) MarketTest:testRepayFlexibleBorrow() (gas: 1076351) MarketTest:testRepayWhenFrozen() (gas: 535304) -MarketTest:testRoundingDownAssetsToValidateShortfallWhenTransferring() (gas: 7521025) -MarketTest:testRoundingDownAssetsToValidateShortfallWhenTransferringFrom() (gas: 7576332) +MarketTest:testRoundingDownAssetsToValidateShortfallWhenTransferring() (gas: 7520833) +MarketTest:testRoundingDownAssetsToValidateShortfallWhenTransferringFrom() (gas: 7576140) MarketTest:testRoundingDownAssetsWhenTransferingFromAnAccountWithoutShortfall() (gas: 1030122) MarketTest:testRoundingDownAssetsWhenTransferingWithAnAccountWithoutShortfall() (gas: 974777) MarketTest:testRoundingUpAllowanceWhenBorrowingAtMaturity() (gas: 845574) @@ -266,7 +267,7 @@ MarketTest:testTotalAssetsProjectingFloatingDebtCorrectly() (gas: 713915) MarketTest:testUpdateAccumulatedEarningsFactorToZero() (gas: 1470345) MarketTest:testUpdateFloatingAssetsAverageWhenDepositingAndBorrowingContinuously() (gas: 344749) MarketTest:testUpdateFloatingAssetsAverageWhenDepositingRightBeforeBorrow() (gas: 630288) -MarketTest:testUpdateFloatingAssetsAverageWhenDepositingRightBeforeEarlyWithdraw() (gas: 630543) +MarketTest:testUpdateFloatingAssetsAverageWhenDepositingRightBeforeEarlyWithdraw() (gas: 630610) MarketTest:testUpdateFloatingAssetsAverageWhenDepositingSomeSecondsBeforeBorrow() (gas: 854932) MarketTest:testUpdateFloatingAssetsAverageWhenWithdrawingRightBeforeBorrow() (gas: 643352) MarketTest:testUpdateFloatingAssetsAverageWhenWithdrawingRightBeforeEarlyWithdraw() (gas: 643673) @@ -277,7 +278,7 @@ MarketTest:testUpdateFloatingDebtBeforeSettingTreasury() (gas: 106395) MarketTest:testWithdrawAtMaturity() (gas: 304303) MarketTest:testWithdrawFromSmartPool() (gas: 279199) MarketTest:testWithdrawShouldUpdateFlexibleBorrowVariables() (gas: 864003) -MarketTest:testWithdrawWhenFrozen() (gas: 325961) +MarketTest:testWithdrawWhenFrozen() (gas: 325939) PoolLibTest:testAtomicDepositBorrowRepayWithdraw() (gas: 46018) PoolLibTest:testBackupBorrow() (gas: 33676) PoolLibTest:testEarningsAccrual() (gas: 38999) @@ -290,24 +291,24 @@ PreviewerTest:testAccountsReturningUtilizationForDifferentMaturities() (gas: 418 PreviewerTest:testAccountsWithAccountOnlyDeposit() (gas: 862391) PreviewerTest:testAccountsWithAccountThatHasBalances() (gas: 2265026) PreviewerTest:testAccountsWithEmptyAccount() (gas: 690558) -PreviewerTest:testAccountsWithIntermediateOperationsReturningAccurateAmounts() (gas: 17600319) +PreviewerTest:testAccountsWithIntermediateOperationsReturningAccurateAmounts() (gas: 17600139) PreviewerTest:testActualTimeBeforeStartDistributionRewards() (gas: 7753427) PreviewerTest:testEmptyExactly() (gas: 5645469) PreviewerTest:testExactlyReturningInterestRateModelData() (gas: 688149) -PreviewerTest:testFixedAvailableLiquidityProjectingNewFloatingDebt() (gas: 13284412) -PreviewerTest:testFixedPoolsA() (gas: 19301157) +PreviewerTest:testFixedAvailableLiquidityProjectingNewFloatingDebt() (gas: 13284232) +PreviewerTest:testFixedPoolsA() (gas: 19300977) PreviewerTest:testFixedPoolsChangingMaturityInTime() (gas: 1627253) -PreviewerTest:testFixedPoolsRatesAndUtilizations() (gas: 14797900) -PreviewerTest:testFixedPoolsWithFloatingAssetsAverage() (gas: 15621124) -PreviewerTest:testFlexibleAvailableLiquidity() (gas: 17225253) +PreviewerTest:testFixedPoolsRatesAndUtilizations() (gas: 14797720) +PreviewerTest:testFixedPoolsWithFloatingAssetsAverage() (gas: 15620944) +PreviewerTest:testFlexibleAvailableLiquidity() (gas: 17225073) PreviewerTest:testFlexibleBorrowSharesAndAssets() (gas: 4401038) -PreviewerTest:testFloatingAvailableLiquidityProjectingNewFloatingDebt() (gas: 12537150) +PreviewerTest:testFloatingAvailableLiquidityProjectingNewFloatingDebt() (gas: 12536970) PreviewerTest:testFloatingRateAndUtilization() (gas: 1128246) PreviewerTest:testJustUpdatedRewardRatesShouldStillReturnRate() (gas: 7174821) PreviewerTest:testMaxBorrowAssetsCapacity() (gas: 2469700) -PreviewerTest:testMaxBorrowAssetsCapacityForAccountWithShortfall() (gas: 10974644) -PreviewerTest:testMaxBorrowAssetsCapacityPerMarket() (gas: 13164794) -PreviewerTest:testOraclePriceReturningAccurateValues() (gas: 10116484) +PreviewerTest:testMaxBorrowAssetsCapacityForAccountWithShortfall() (gas: 10974464) +PreviewerTest:testMaxBorrowAssetsCapacityPerMarket() (gas: 13164614) +PreviewerTest:testOraclePriceReturningAccurateValues() (gas: 10116304) PreviewerTest:testPreviewBorrowAtAllMaturitiesReturningAccurateAmount() (gas: 4240988) PreviewerTest:testPreviewBorrowAtMaturityReturningAccurateAmount() (gas: 623350) PreviewerTest:testPreviewBorrowAtMaturityReturningAccurateAmountWithIntermediateOperations() (gas: 1954376) @@ -353,8 +354,8 @@ PreviewerTest:testReserveFactor() (gas: 707280) PreviewerTest:testReturnRewardAssetUsdPrice() (gas: 6697322) PreviewerTest:testRewardsRateAfterDistributionEnd() (gas: 7481122) PreviewerTest:testRewardsRateOnlyWithFixedBorrows() (gas: 6788297) -PreviewerTest:testRewardsRateWithDifferentRewardLengths() (gas: 19224084) -PreviewerTest:testRewardsRateWithMarketWithDifferentDecimals() (gas: 18355108) +PreviewerTest:testRewardsRateWithDifferentRewardLengths() (gas: 19223904) +PreviewerTest:testRewardsRateWithMarketWithDifferentDecimals() (gas: 18354928) PreviewerTest:testRewardsRateX() (gas: 8127662) PriceFeedDoubleTest:testPriceFeedDoubleReturningAccurateDecimals() (gas: 597567) PriceFeedDoubleTest:testPriceFeedDoubleReturningPrice() (gas: 53190) @@ -373,10 +374,10 @@ PriceFeedWrapperTest:testPriceFeedWrapperWithActualOnChainValues() (gas: 75210) PriceFeedWrapperTest:testPriceFeedWrapperWithNegativePriceShouldRevert() (gas: 164216) PriceFeedWrapperTest:testPriceFeedWrapperWithUsdPriceFeed() (gas: 1243191) RewardsControllerTest:testAccrueRewardsForWholeDistributionPeriod() (gas: 1245256) -RewardsControllerTest:testAccrueRewardsWithBadDebtClearingOfFixedBorrow() (gas: 3338582) -RewardsControllerTest:testAccrueRewardsWithRepayOfBorrowBalance() (gas: 1602530) -RewardsControllerTest:testAccrueRewardsWithRepayOfFixedBorrowBalance() (gas: 1791604) -RewardsControllerTest:testAccrueRewardsWithSeizeOfAllDepositShares() (gas: 1991095) +RewardsControllerTest:testAccrueRewardsWithBadDebtClearingOfFixedBorrow() (gas: 3338579) +RewardsControllerTest:testAccrueRewardsWithRepayOfBorrowBalance() (gas: 1602527) +RewardsControllerTest:testAccrueRewardsWithRepayOfFixedBorrowBalance() (gas: 1791601) +RewardsControllerTest:testAccrueRewardsWithSeizeOfAllDepositShares() (gas: 1991092) RewardsControllerTest:testAfterDistributionPeriodEnd() (gas: 1818279) RewardsControllerTest:testAllClaimableUSDCWithAnotherAccountInPool() (gas: 2273354) RewardsControllerTest:testAllClaimableUSDCWithDeposit() (gas: 1627706) @@ -408,7 +409,7 @@ RewardsControllerTest:testLastUndistributed() (gas: 2189661) RewardsControllerTest:testOperationAfterDistributionEnded() (gas: 722976) RewardsControllerTest:testOperationsBeforeDistributionStart() (gas: 1674576) RewardsControllerTest:testPermitClaim() (gas: 1275282) -RewardsControllerTest:testSetDistributionConfigWithDifferentDecimals() (gas: 11427857) +RewardsControllerTest:testSetDistributionConfigWithDifferentDecimals() (gas: 11427677) RewardsControllerTest:testSetDistributionOperationShouldUpdateIndex() (gas: 136200) RewardsControllerTest:testSetDistributionWithOnGoingMarketOperations() (gas: 1202358) RewardsControllerTest:testSetHigherTotalDistribution() (gas: 1831201) diff --git a/contracts/Market.sol b/contracts/Market.sol index 71384a38..1047edb2 100644 --- a/contracts/Market.sol +++ b/contracts/Market.sol @@ -605,6 +605,8 @@ contract Market is Initializable, AccessControlUpgradeable, PausableUpgradeable, (uint256 lendersAssets, uint256 seizeAssets) = auditor.calculateSeize(this, seizeMarket, borrower, repaidAssets); earningsAccumulator += lendersAssets; + asset.safeTransferFrom(msg.sender, address(this), repaidAssets + lendersAssets); + if (address(seizeMarket) == address(this)) { internalSeize(this, msg.sender, borrower, seizeAssets); } else { @@ -616,8 +618,6 @@ contract Market is Initializable, AccessControlUpgradeable, PausableUpgradeable, emit Liquidate(msg.sender, borrower, repaidAssets, lendersAssets, seizeMarket, seizeAssets); auditor.handleBadDebt(borrower); - - asset.safeTransferFrom(msg.sender, address(this), repaidAssets + lendersAssets); } /// @notice Clears floating and fixed debt for an account spreading the losses to the `earningsAccumulator`. diff --git a/test/Market.t.sol b/test/Market.t.sol index b057f9c1..f1b9cb58 100644 --- a/test/Market.t.sol +++ b/test/Market.t.sol @@ -1543,6 +1543,31 @@ contract MarketTest is Test { } } + function testLiquidateTransferRepayAssetsBeforeSeize() external { + auditor.setAdjustFactor(market, 0.9e18); + + vm.startPrank(ALICE); + + // ALICE deposits and borrows DAI + uint256 assets = 10_000 ether; + ERC20 asset = market.asset(); + deal(address(asset), ALICE, assets); + market.deposit(assets, ALICE); + market.borrow((assets * 9 * 9) / 10 / 10, ALICE, ALICE); + + vm.stopPrank(); + + skip(10 days); + + // LIQUIDATION doesn't fail as transfer from is before withdrawing collateral + address liquidator = makeAddr("liquidator"); + deal(address(asset), liquidator, 100_000 ether); + vm.startPrank(liquidator); + asset.approve(address(market), type(uint256).max); + market.liquidate(ALICE, type(uint256).max, market); + vm.stopPrank(); + } + function testLiquidateAndSubtractLossesFromAccumulator() external { vm.warp(1); marketWETH.deposit(1.3 ether, address(this));