From 79dfa139ad1f3195b9171405d97f4c358ae0c94d Mon Sep 17 00:00:00 2001 From: Santiago Sanchez Avalos Date: Fri, 17 May 2024 11:21:49 -0300 Subject: [PATCH] =?UTF-8?q?=F0=9F=91=94=20market:=20add=20early=20repay=20?= =?UTF-8?q?liquidation=20discount=20to=20accumulator?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .changeset/itchy-bottles-push.md | 5 ++ .gas-snapshot | 133 ++++++++++++++++--------------- contracts/Market.sol | 15 ++-- test/Market.t.sol | 55 ++++++++++++- 4 files changed, 135 insertions(+), 73 deletions(-) create mode 100644 .changeset/itchy-bottles-push.md diff --git a/.changeset/itchy-bottles-push.md b/.changeset/itchy-bottles-push.md new file mode 100644 index 00000000..1d6f2362 --- /dev/null +++ b/.changeset/itchy-bottles-push.md @@ -0,0 +1,5 @@ +--- +"@exactly/protocol": patch +--- + +👔 market: add early repay liquidation discount to accumulator diff --git a/.gas-snapshot b/.gas-snapshot index 56d9189c..a772a9ca 100644 --- a/.gas-snapshot +++ b/.gas-snapshot @@ -143,52 +143,53 @@ 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, μ: 9916153, ~: 10074255) -InterestRateModelTest:testFuzzReferenceRateFixed(uint256,uint256,uint256,uint256,uint256,uint256,(uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,int256,uint256,uint256)) (runs: 256, μ: 2337417, ~: 2339559) +InterestRateModelTest:testFuzzReferenceLegacyRateFixed(uint32,uint256,uint256[2],uint256[2],uint256,uint256,uint256) (runs: 256, μ: 9923051, ~: 10081153) +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) InterestRateModelTest:testRevertMaxUtilizationLowerThanWad() (gas: 266682) MarketTest:testAccountLiquidityAdjustedDebt() (gas: 499481) MarketTest:testAnotherUserRedeemWhenOwnerHasShortfall() (gas: 819094) -MarketTest:testAnotherUserWithdrawWhenOwnerHasShortfall() (gas: 806786) +MarketTest:testAnotherUserWithdrawWhenOwnerHasShortfall() (gas: 806764) MarketTest:testBorrowAfterFreezing() (gas: 491397) -MarketTest:testBorrowAtMaturity() (gas: 499472) +MarketTest:testBorrowAtMaturity() (gas: 499563) MarketTest:testBorrowAtMaturityAfterFreezing() (gas: 573201) -MarketTest:testBorrowAtMaturityUpdatesFloatingDebtAndFloatingAssets() (gas: 884625) +MarketTest:testBorrowAtMaturityUpdatesFloatingDebtAndFloatingAssets() (gas: 884713) MarketTest:testBorrowAtMaturityWhenFrozen() (gas: 93740) MarketTest:testBorrowAtMaturityWithZeroAssets() (gas: 40425) MarketTest:testBorrowDisagreement() (gas: 295456) -MarketTest:testBorrowFromFreeLunchShouldNotRevertWithFloatingFullUtilization() (gas: 1276372) -MarketTest:testBorrowWhenFrozen() (gas: 93157) -MarketTest:testBorrowWithZeroAssets() (gas: 39793) -MarketTest:testCappedLiquidation() (gas: 1188653) +MarketTest:testBorrowFromFreeLunchShouldNotRevertWithFloatingFullUtilization() (gas: 1276350) +MarketTest:testBorrowWhenFrozen() (gas: 93224) +MarketTest:testBorrowWithZeroAssets() (gas: 39771) +MarketTest:testCappedLiquidation() (gas: 1192794) MarketTest:testChargeTreasuryToEarlyWithdraws() (gas: 1183503) MarketTest:testChargeTreasuryToFixedBorrows() (gas: 1576414) MarketTest:testClearBadDebtAvoidingFixedBorrowsIfAccumulatorLower() (gas: 2264240) MarketTest:testClearBadDebtCalledByAccount() (gas: 34955) -MarketTest:testClearBadDebtExactlyRepaysFixedBorrowWithAccumulatorAmount() (gas: 1981742) +MarketTest:testClearBadDebtExactlyRepaysFixedBorrowWithAccumulatorAmount() (gas: 1981749) MarketTest:testClearBadDebtPartiallyRepaysEachFixedBorrow() (gas: 1942150) MarketTest:testClearBadDebtPartiallyRepaysFloatingDebt() (gas: 2272362) MarketTest:testClearBadDebtShouldAccrueAccumulatedEarningsBeforeSpreadingLosses() (gas: 2048902) MarketTest:testClearBadDebtWithEmptyAccumulatorShouldNotRevert() (gas: 969932) -MarketTest:testClearMaturity() (gas: 1647506) -MarketTest:testCollectTreasuryFreeLunchToEarlyWithdraws() (gas: 1712239) +MarketTest:testClearMaturity() (gas: 1647523) +MarketTest:testCollectTreasuryFreeLunchToEarlyWithdraws() (gas: 1712217) MarketTest:testCollectTreasuryFreeLunchToEarlyWithdrawsWithZeroFees() (gas: 541373) MarketTest:testCollectTreasuryFreeLunchToFixedBorrows() (gas: 1759670) MarketTest:testCollectTreasuryFreeLunchToFixedBorrowsWithZeroFees() (gas: 704645) -MarketTest:testCrossMaturityLiquidation() (gas: 2608710) +MarketTest:testCrossMaturityLiquidation() (gas: 2612851) MarketTest:testDepositAfterFreezing() (gas: 256160) -MarketTest:testDepositAtMaturity() (gas: 180716) +MarketTest:testDepositAtMaturity() (gas: 180694) MarketTest:testDepositAtMaturityAfterFreezing() (gas: 254665) -MarketTest:testDepositAtMaturityWhenFrozen() (gas: 93231) +MarketTest:testDepositAtMaturityWhenFrozen() (gas: 93209) MarketTest:testDepositAtMaturityWithZeroAssets() (gas: 39977) MarketTest:testDepositDisagreement() (gas: 57120) MarketTest:testDepositShouldUpdateFlexibleBorrowVariables() (gas: 716993) -MarketTest:testDepositToSmartPool() (gas: 181871) +MarketTest:testDepositToSmartPool() (gas: 181849) MarketTest:testDepositWhenFrozen() (gas: 176515) -MarketTest:testDistributeMultipleAccumulatedEarnings() (gas: 1334265) -MarketTest:testDistributionOfLossesShouldReduceFromFloatingBackupBorrowedAccordingly() (gas: 6240694) -MarketTest:testEarlyRepaymentWithExcessiveAmountOfFees() (gas: 3395968) +MarketTest:testDistributeMultipleAccumulatedEarnings() (gas: 1334332) +MarketTest:testDistributionOfLossesShouldReduceFromFloatingBackupBorrowedAccordingly() (gas: 6260129) +MarketTest:testEarlyRepayLiquidationUnassignedEarnings() (gas: 2045748) +MarketTest:testEarlyRepaymentWithExcessiveAmountOfFees() (gas: 3395975) MarketTest:testEarlyWithdrawFromFreeLunchShouldNotRevertWithFloatingFullUtilization() (gas: 1032117) MarketTest:testEmergencyAdminRole() (gas: 317196) MarketTest:testEmitFrozen() (gas: 91047) @@ -196,56 +197,56 @@ MarketTest:testFixedBorrowFailingWhenFlexibleBorrowAccruesDebt() (gas: 1530874) MarketTest:testFixedBorrowRateToMaturity() (gas: 562485) MarketTest:testFlexibleBorrow() (gas: 423678) MarketTest:testFlexibleBorrowAccountingDebt() (gas: 607131) -MarketTest:testFlexibleBorrowChargingDebtToTreasury() (gas: 751199) +MarketTest:testFlexibleBorrowChargingDebtToTreasury() (gas: 751177) MarketTest:testFlexibleBorrowExceedingReserve() (gas: 878430) MarketTest:testFlexibleBorrowExceedingReserveIncludingFixedBorrow() (gas: 1267465) MarketTest:testFlexibleBorrowExceedingReserveWithNewDebt() (gas: 1001231) MarketTest:testFlexibleBorrowFromAnotherUserSubtractsAllowance() (gas: 469265) MarketTest:testFlexibleBorrowFromAnotherUserWithAllowance() (gas: 458703) MarketTest:testFlexibleBorrowFromAnotherUserWithoutAllowance() (gas: 252381) -MarketTest:testFrontRunSmartPoolEarningsDistributionWithBigPenaltyRepayment() (gas: 1338262) -MarketTest:testFullPause() (gas: 5882758) +MarketTest:testFrontRunSmartPoolEarningsDistributionWithBigPenaltyRepayment() (gas: 1338240) +MarketTest:testFullPause() (gas: 5882743) MarketTest:testInitiallyUnfrozen() (gas: 15614) -MarketTest:testInsufficientProtocolLiquidity() (gas: 1940310) -MarketTest:testLiquidateAndChargeIncentiveForLenders() (gas: 2401575) -MarketTest:testLiquidateAndDistributeLosses() (gas: 3185348) +MarketTest:testInsufficientProtocolLiquidity() (gas: 1940288) +MarketTest:testLiquidateAndChargeIncentiveForLenders() (gas: 2412178) +MarketTest:testLiquidateAndDistributeLosses() (gas: 3195951) MarketTest:testLiquidateAndSeizeExactAmountWithDustAsCollateral() (gas: 2777923) MarketTest:testLiquidateAndSeizeFromEmptyCollateral() (gas: 1039213) -MarketTest:testLiquidateAndSubtractLossesFromAccumulator() (gas: 3883803) -MarketTest:testLiquidateFlexibleAndFixedBorrowPositionsInSingleCall() (gas: 2607212) -MarketTest:testLiquidateFlexibleBorrow() (gas: 2142990) -MarketTest:testLiquidateFlexibleBorrowChargeLendersAssetsToLiquidator() (gas: 1150226) +MarketTest:testLiquidateAndSubtractLossesFromAccumulator() (gas: 3887968) +MarketTest:testLiquidateFlexibleAndFixedBorrowPositionsInSingleCall() (gas: 2617638) +MarketTest:testLiquidateFlexibleBorrow() (gas: 2142968) +MarketTest:testLiquidateFlexibleBorrowChargeLendersAssetsToLiquidator() (gas: 1150204) MarketTest:testLiquidateFlexibleBorrowConsideringDebtOverTime() (gas: 1166273) MarketTest:testLiquidateLeavingDustAsCollateral() (gas: 3589695) MarketTest:testLiquidateWhenFrozen() (gas: 1230791) -MarketTest:testLiquidateWithTwoUnitsAsMaxAssets() (gas: 1568077) +MarketTest:testLiquidateWithTwoUnitsAsMaxAssets() (gas: 1572196) MarketTest:testLiquidateWithZeroAsMaxAssets() (gas: 1039184) MarketTest:testLiquidationClearingDebtOfAllAccountMarkets() (gas: 3066991) -MarketTest:testLiquidationResultingInZeroCollateralAndZeroDebt() (gas: 1946936) +MarketTest:testLiquidationResultingInZeroCollateralAndZeroDebt() (gas: 1951163) MarketTest:testMaturityInsufficientProtocolLiquidity() (gas: 1424359) -MarketTest:testMultipleBorrowsForMultipleAssets() (gas: 2463271131) +MarketTest:testMultipleBorrowsForMultipleAssets() (gas: 2463298677) MarketTest:testMultipleDepositsToSmartPool() (gas: 915595) -MarketTest:testMultipleFixedBorrowsRepays() (gas: 1313796) +MarketTest:testMultipleFixedBorrowsRepays() (gas: 1313882) MarketTest:testMultipleLiquidationSameUser() (gas: 2916558) -MarketTest:testNotEnteredMarketShouldNotBeSeized() (gas: 8523059) +MarketTest:testNotEnteredMarketShouldNotBeSeized() (gas: 8529957) MarketTest:testOnlyAdminCanFreezeUnfreeze() (gas: 207636) MarketTest:testOperationsShouldUpdateFloatingAssetsAverage() (gas: 1374231) -MarketTest:testOperationsWithBtcWbtcRate() (gas: 8201063) -MarketTest:testOperationsWithStEthAsset() (gas: 8088405) +MarketTest:testOperationsWithBtcWbtcRate() (gas: 8207961) +MarketTest:testOperationsWithStEthAsset() (gas: 8095303) MarketTest:testPausable() (gas: 158158) MarketTest:testPauserRole() (gas: 78161) MarketTest:testPreviewOperationsWithSmartPoolCorrectlyAccountingEarnings() (gas: 1960190) -MarketTest:testRepayAtMaturity() (gas: 578478) -MarketTest:testRepayDisagreement() (gas: 576789) -MarketTest:testRepayFlexibleBorrow() (gas: 1076306) +MarketTest:testRepayAtMaturity() (gas: 578548) +MarketTest:testRepayDisagreement() (gas: 576774) +MarketTest:testRepayFlexibleBorrow() (gas: 1076284) MarketTest:testRepayWhenFrozen() (gas: 535348) -MarketTest:testRoundingDownAssetsToValidateShortfallWhenTransferring() (gas: 7506699) -MarketTest:testRoundingDownAssetsToValidateShortfallWhenTransferringFrom() (gas: 7561963) +MarketTest:testRoundingDownAssetsToValidateShortfallWhenTransferring() (gas: 7513552) +MarketTest:testRoundingDownAssetsToValidateShortfallWhenTransferringFrom() (gas: 7568838) MarketTest:testRoundingDownAssetsWhenTransferingFromAnAccountWithoutShortfall() (gas: 1030163) MarketTest:testRoundingDownAssetsWhenTransferingWithAnAccountWithoutShortfall() (gas: 974729) -MarketTest:testRoundingUpAllowanceWhenBorrowingAtMaturity() (gas: 845500) +MarketTest:testRoundingUpAllowanceWhenBorrowingAtMaturity() (gas: 845587) MarketTest:testRoundingUpAllowanceWhenWithdrawingAtMaturity() (gas: 763364) -MarketTest:testSetAssetSymbol() (gas: 54929) +MarketTest:testSetAssetSymbol() (gas: 55013) MarketTest:testSetAssetSymbolNotAdmin() (gas: 66288) MarketTest:testSetDampSpeedFactorShouldUpdateFloatingAssetsAverage() (gas: 386894) MarketTest:testSetEarningsAccumulatorSmoothFactorShouldDistributeEarnings() (gas: 704407) @@ -256,23 +257,23 @@ MarketTest:testShareValueNotDecreasingWhenMintingToTreasury() (gas: 763200) MarketTest:testSingleFloatingBorrow() (gas: 417449) MarketTest:testSingleFloatingRepay() (gas: 484671) MarketTest:testSmartPoolEarningsDistribution() (gas: 1092764) -MarketTest:testSmartPoolSharesDoNotAccountUnassignedEarningsFromMoreThanOneIntervalPastMaturities() (gas: 528443) +MarketTest:testSmartPoolSharesDoNotAccountUnassignedEarningsFromMoreThanOneIntervalPastMaturities() (gas: 528421) MarketTest:testSumDebtPlusEffectsShouldntRoundUpWhenWithdrawing() (gas: 1005543) MarketTest:testTotalAssetsProjectingBackupEarningsCorrectly() (gas: 508238) MarketTest:testTotalAssetsProjectingFloatingDebtCorrectly() (gas: 713870) MarketTest:testUpdateAccumulatedEarningsFactorToZero() (gas: 1457121) -MarketTest:testUpdateFloatingAssetsAverageWhenDepositingAndBorrowingContinuously() (gas: 344661) +MarketTest:testUpdateFloatingAssetsAverageWhenDepositingAndBorrowingContinuously() (gas: 344749) MarketTest:testUpdateFloatingAssetsAverageWhenDepositingRightBeforeBorrow() (gas: 630219) MarketTest:testUpdateFloatingAssetsAverageWhenDepositingRightBeforeEarlyWithdraw() (gas: 612579) MarketTest:testUpdateFloatingAssetsAverageWhenDepositingSomeSecondsBeforeBorrow() (gas: 854948) -MarketTest:testUpdateFloatingAssetsAverageWhenWithdrawingRightBeforeBorrow() (gas: 643371) -MarketTest:testUpdateFloatingAssetsAverageWhenWithdrawingRightBeforeEarlyWithdraw() (gas: 625731) +MarketTest:testUpdateFloatingAssetsAverageWhenWithdrawingRightBeforeBorrow() (gas: 643349) +MarketTest:testUpdateFloatingAssetsAverageWhenWithdrawingRightBeforeEarlyWithdraw() (gas: 625709) MarketTest:testUpdateFloatingAssetsAverageWhenWithdrawingSomeSecondsBeforeBorrow() (gas: 373134) MarketTest:testUpdateFloatingAssetsAverageWithDampSpeedDown() (gas: 358070) -MarketTest:testUpdateFloatingAssetsAverageWithDampSpeedUp() (gas: 199719) -MarketTest:testUpdateFloatingDebtBeforeSettingTreasury() (gas: 106329) -MarketTest:testWithdrawAtMaturity() (gas: 287144) -MarketTest:testWithdrawFromSmartPool() (gas: 279221) +MarketTest:testUpdateFloatingAssetsAverageWithDampSpeedUp() (gas: 199697) +MarketTest:testUpdateFloatingDebtBeforeSettingTreasury() (gas: 106395) +MarketTest:testWithdrawAtMaturity() (gas: 287213) +MarketTest:testWithdrawFromSmartPool() (gas: 279199) MarketTest:testWithdrawShouldUpdateFlexibleBorrowVariables() (gas: 864003) MarketTest:testWithdrawWhenFrozen() (gas: 325983) PoolLibTest:testAtomicDepositBorrowRepayWithdraw() (gas: 46018) @@ -287,24 +288,24 @@ PreviewerTest:testAccountsReturningUtilizationForDifferentMaturities() (gas: 418 PreviewerTest:testAccountsWithAccountOnlyDeposit() (gas: 862391) PreviewerTest:testAccountsWithAccountThatHasBalances() (gas: 2232872) PreviewerTest:testAccountsWithEmptyAccount() (gas: 690558) -PreviewerTest:testAccountsWithIntermediateOperationsReturningAccurateAmounts() (gas: 17586034) +PreviewerTest:testAccountsWithIntermediateOperationsReturningAccurateAmounts() (gas: 17592926) PreviewerTest:testActualTimeBeforeStartDistributionRewards() (gas: 7753427) PreviewerTest:testEmptyExactly() (gas: 5645469) PreviewerTest:testExactlyReturningInterestRateModelData() (gas: 688149) -PreviewerTest:testFixedAvailableLiquidityProjectingNewFloatingDebt() (gas: 13270130) -PreviewerTest:testFixedPoolsA() (gas: 19247527) +PreviewerTest:testFixedAvailableLiquidityProjectingNewFloatingDebt() (gas: 13277022) +PreviewerTest:testFixedPoolsA() (gas: 19254426) PreviewerTest:testFixedPoolsChangingMaturityInTime() (gas: 1627253) -PreviewerTest:testFixedPoolsRatesAndUtilizations() (gas: 14783618) -PreviewerTest:testFixedPoolsWithFloatingAssetsAverage() (gas: 15589549) -PreviewerTest:testFlexibleAvailableLiquidity() (gas: 17171635) +PreviewerTest:testFixedPoolsRatesAndUtilizations() (gas: 14790510) +PreviewerTest:testFixedPoolsWithFloatingAssetsAverage() (gas: 15596446) +PreviewerTest:testFlexibleAvailableLiquidity() (gas: 17178534) PreviewerTest:testFlexibleBorrowSharesAndAssets() (gas: 4401038) -PreviewerTest:testFloatingAvailableLiquidityProjectingNewFloatingDebt() (gas: 12522874) +PreviewerTest:testFloatingAvailableLiquidityProjectingNewFloatingDebt() (gas: 12529766) PreviewerTest:testFloatingRateAndUtilization() (gas: 1128246) PreviewerTest:testJustUpdatedRewardRatesShouldStillReturnRate() (gas: 7174821) PreviewerTest:testMaxBorrowAssetsCapacity() (gas: 2469700) -PreviewerTest:testMaxBorrowAssetsCapacityForAccountWithShortfall() (gas: 10960356) -PreviewerTest:testMaxBorrowAssetsCapacityPerMarket() (gas: 13150518) -PreviewerTest:testOraclePriceReturningAccurateValues() (gas: 10102196) +PreviewerTest:testMaxBorrowAssetsCapacityForAccountWithShortfall() (gas: 10967254) +PreviewerTest:testMaxBorrowAssetsCapacityPerMarket() (gas: 13157410) +PreviewerTest:testOraclePriceReturningAccurateValues() (gas: 10109094) PreviewerTest:testPreviewBorrowAtAllMaturitiesReturningAccurateAmount() (gas: 4222096) PreviewerTest:testPreviewBorrowAtMaturityReturningAccurateAmount() (gas: 623347) PreviewerTest:testPreviewBorrowAtMaturityReturningAccurateAmountWithIntermediateOperations() (gas: 1935493) @@ -326,8 +327,8 @@ PreviewerTest:testPreviewDepositAtMaturityWithOneUnit() (gas: 589393) PreviewerTest:testPreviewDepositAtMaturityWithSameTimestamp() (gas: 48970) PreviewerTest:testPreviewDepositAtMaturityWithZeroAmount() (gas: 589415) PreviewerTest:testPreviewRepayAtMaturityLastAccrualIsMaturity() (gas: 1409069) -PreviewerTest:testPreviewRepayAtMaturityReturningAccurateAmount() (gas: 1230788) -PreviewerTest:testPreviewRepayAtMaturityReturningAccurateAmountWithIntermediateOperations() (gas: 1496906) +PreviewerTest:testPreviewRepayAtMaturityReturningAccurateAmount() (gas: 1230795) +PreviewerTest:testPreviewRepayAtMaturityReturningAccurateAmountWithIntermediateOperations() (gas: 1496927) PreviewerTest:testPreviewRepayAtMaturityWithEmptyMaturity() (gas: 35313) PreviewerTest:testPreviewRepayAtMaturityWithEmptyMaturityAndZeroAmount() (gas: 35355) PreviewerTest:testPreviewRepayAtMaturityWithInvalidMaturity() (gas: 35355) @@ -350,8 +351,8 @@ PreviewerTest:testReserveFactor() (gas: 707280) PreviewerTest:testReturnRewardAssetUsdPrice() (gas: 6697322) PreviewerTest:testRewardsRateAfterDistributionEnd() (gas: 7481122) PreviewerTest:testRewardsRateOnlyWithFixedBorrows() (gas: 6788294) -PreviewerTest:testRewardsRateWithDifferentRewardLengths() (gas: 19209808) -PreviewerTest:testRewardsRateWithMarketWithDifferentDecimals() (gas: 18340829) +PreviewerTest:testRewardsRateWithDifferentRewardLengths() (gas: 19216700) +PreviewerTest:testRewardsRateWithMarketWithDifferentDecimals() (gas: 18347721) PreviewerTest:testRewardsRateX() (gas: 8127659) PriceFeedDoubleTest:testPriceFeedDoubleReturningAccurateDecimals() (gas: 597567) PriceFeedDoubleTest:testPriceFeedDoubleReturningPrice() (gas: 53190) @@ -405,7 +406,7 @@ RewardsControllerTest:testLastUndistributed() (gas: 2189661) RewardsControllerTest:testOperationAfterDistributionEnded() (gas: 722976) RewardsControllerTest:testOperationsBeforeDistributionStart() (gas: 1674576) RewardsControllerTest:testPermitClaim() (gas: 1275282) -RewardsControllerTest:testSetDistributionConfigWithDifferentDecimals() (gas: 11413569) +RewardsControllerTest:testSetDistributionConfigWithDifferentDecimals() (gas: 11420467) RewardsControllerTest:testSetDistributionOperationShouldUpdateIndex() (gas: 136200) RewardsControllerTest:testSetDistributionWithOnGoingMarketOperations() (gas: 1202358) RewardsControllerTest:testSetHigherTotalDistribution() (gas: 1831201) diff --git a/contracts/Market.sol b/contracts/Market.sol index 8172a196..4c55778c 100644 --- a/contracts/Market.sol +++ b/contracts/Market.sol @@ -493,19 +493,22 @@ contract Market is Initializable, AccessControlUpgradeable, PausableUpgradeable, // early repayment allows a discount from the unassigned earnings if (block.timestamp < maturity) { - if (canDiscount) { - // calculate the deposit fee considering the amount of debt the account'll pay - (uint256 discountFee, uint256 backupFee) = pool.calculateDeposit(principalCovered, backupFeeRate); - - // remove the fee from unassigned earnings - pool.unassignedEarnings -= discountFee + backupFee; + // calculate the deposit fee considering the amount of debt the account'll pay + (uint256 discountFee, uint256 backupFee) = pool.calculateDeposit(principalCovered, backupFeeRate); + // remove the fee from unassigned earnings + pool.unassignedEarnings -= discountFee + backupFee; + if (canDiscount) { // the fee charged to the fixed pool supplier goes to the earnings accumulator earningsAccumulator += backupFee; // the fee gets discounted from the account through `actualRepayAssets` actualRepayAssets = debtCovered - discountFee; } else { + // all fees go to the earnings accumulator + earningsAccumulator += discountFee + backupFee; + + // there is no discount due to liquidation actualRepayAssets = debtCovered; } } else { diff --git a/test/Market.t.sol b/test/Market.t.sol index eeb0346d..eaf7ba5c 100644 --- a/test/Market.t.sol +++ b/test/Market.t.sol @@ -833,6 +833,54 @@ contract MarketTest is Test { assertEq(remainingDebt, 0); } + function testEarlyRepayLiquidationUnassignedEarnings() public { + uint256 maturity = FixedLib.INTERVAL; + uint256 assets = 10_000 ether; + ERC20 asset = market.asset(); + deal(address(asset), ALICE, assets); + + vm.startPrank(ALICE); + + // ALICE deposits + market.deposit(assets, ALICE); + + // ALICE borrows at maturity, using backup from the deposit + market.borrowAtMaturity(maturity, assets / 10, type(uint256).max, ALICE, ALICE); + + // ALICE borrows the maximum possible using floating rate + (uint256 collateral, uint256 debt) = auditor.accountLiquidity(address(ALICE), Market(address(0)), 0); + uint256 borrow = ((collateral - debt) * 8) / 10; // max borrow capacity + market.borrow(borrow, ALICE, ALICE); + + vm.stopPrank(); + + skip(1 days); + + // LIQUIDATOR liquidates ALICE, wiping ALICE'S maturity borrow + // and ignores its unassigned rewards + address liquidator = makeAddr("liquidator"); + vm.startPrank(liquidator); + deal(address(asset), liquidator, assets); + asset.approve(address(market), assets); + market.liquidate(ALICE, type(uint256).max, market); + vm.stopPrank(); + + // ATTACKER deposits to borrow at maturity + address attacker = makeAddr("attacker"); + deal(address(asset), attacker, 20); + vm.startPrank(attacker); + asset.approve(address(market), 20); + market.deposit(10, attacker); + + // ATTACKER borrows at maturity, making floatingBackupBorrowed = 1 > supply = 0 + market.borrowAtMaturity(maturity, 1, type(uint256).max, attacker, attacker); + + // ATTACKER deposits just 1 at maturity, claiming all the unassigned earnings + // by only providing 1 principal + uint256 positionAssets = market.depositAtMaturity(maturity, 1, 0, attacker); + assertEq(positionAssets, 1); + } + function testBorrowFromFreeLunchShouldNotRevertWithFloatingFullUtilization() external { marketWETH.deposit(1.15 ether, address(this)); daiPriceFeed.setPrice(0.0002e18); @@ -1491,6 +1539,7 @@ contract MarketTest is Test { uint256 earningsAccumulatorBefore = market.earningsAccumulator(); uint256 lendersIncentive = 1181818181818181800; uint256 badDebt = 981818181818181818100 + 1100000000000000000000 + 1100000000000000000000 + 1100000000000000000000; + uint256 earlyRepayEarnings = 3069658128703695345; uint256 accumulatedEarnings = (earningsAccumulatorBefore + lendersIncentive).mulDivDown( block.timestamp - market.lastAccumulatorAccrual(), block.timestamp - @@ -1506,7 +1555,11 @@ contract MarketTest is Test { assertGt(market.earningsAccumulator(), 0); assertApproxEqRel( badDebt, - earningsAccumulatorBefore - market.earningsAccumulator() - accumulatedEarnings + lendersIncentive, + earningsAccumulatorBefore - + market.earningsAccumulator() - + accumulatedEarnings + + earlyRepayEarnings + + lendersIncentive, 1e2 ); (, uint256 fixedBorrows, ) = market.accounts(address(this));