diff --git a/docs/Functions.md b/docs/Functions.md index 6a1ee5799..115d20e1d 100644 --- a/docs/Functions.md +++ b/docs/Functions.md @@ -66,7 +66,9 @@ - pool inflator and inflatorUpdate state reverts on: + - block timestamp greater than expiry TransactionExpired() - deposits locked RemoveDepositLockedByAuctionDebt() + - head auction not cleared AuctionNotCleared() - LenderActions.moveQuoteToken(): - same index MoveToSameIndex() - dust amount DustAmountNotExceeded() diff --git a/src/base/Pool.sol b/src/base/Pool.sol index 5f26cb0fb..3643fd56c 100644 --- a/src/base/Pool.sol +++ b/src/base/Pool.sol @@ -34,6 +34,8 @@ import { ReserveAuctionState, Bucket, Lender, + Borrower, + Kicker, BurnEvent, Liquidation } from '../interfaces/pool/commons/IPoolState.sol'; @@ -188,6 +190,9 @@ abstract contract Pool is Clone, ReentrancyGuard, Multicall, IPool { bool revertIfBelowLup_ ) external override nonReentrant returns (uint256 fromBucketLP_, uint256 toBucketLP_, uint256 movedAmount_) { _revertAfterExpiry(expiry_); + + _revertIfAuctionClearable(auctions, loans); + PoolState memory poolState = _accruePoolInterest(); _revertIfAuctionDebtLocked(deposits, poolState.t0DebtInAuction, fromIndex_, poolState.inflator); @@ -759,7 +764,7 @@ abstract contract Pool is Clone, ReentrancyGuard, Multicall, IPool { address prev_, bool alreadyTaken_ ) { - Liquidation memory liquidation = auctions.liquidations[borrower_]; + Liquidation storage liquidation = auctions.liquidations[borrower_]; return ( liquidation.kicker, liquidation.bondFactor, @@ -778,10 +783,11 @@ abstract contract Pool is Clone, ReentrancyGuard, Multicall, IPool { function borrowerInfo( address borrower_ ) external view override returns (uint256, uint256, uint256) { + Borrower storage borrower = loans.borrowers[borrower_]; return ( - loans.borrowers[borrower_].t0Debt, - loans.borrowers[borrower_].collateral, - loans.borrowers[borrower_].t0Np + borrower.t0Debt, + borrower.collateral, + borrower.t0Np ); } @@ -821,7 +827,7 @@ abstract contract Pool is Clone, ReentrancyGuard, Multicall, IPool { /// @inheritdoc IPoolState function burnInfo(uint256 burnEventEpoch_) external view returns (uint256, uint256, uint256) { - BurnEvent memory burnEvent = reserveAuction.burnEvents[burnEventEpoch_]; + BurnEvent storage burnEvent = reserveAuction.burnEvents[burnEventEpoch_]; return ( burnEvent.timestamp, @@ -906,9 +912,10 @@ abstract contract Pool is Clone, ReentrancyGuard, Multicall, IPool { function kickerInfo( address kicker_ ) external view override returns (uint256, uint256) { + Kicker storage kicker = auctions.kickers[kicker_]; return( - auctions.kickers[kicker_].claimable, - auctions.kickers[kicker_].locked + kicker.claimable, + kicker.locked ); } diff --git a/tests/forge/unit/ERC20Pool/ERC20PoolLiquidationsMisc.t.sol b/tests/forge/unit/ERC20Pool/ERC20PoolLiquidationsMisc.t.sol index eb0f6198a..4298bcb0f 100644 --- a/tests/forge/unit/ERC20Pool/ERC20PoolLiquidationsMisc.t.sol +++ b/tests/forge/unit/ERC20Pool/ERC20PoolLiquidationsMisc.t.sol @@ -250,6 +250,19 @@ contract ERC20PoolLiquidationsMiscTest is ERC20HelperContract { toIndex: _i9_81 }); + uint256 snapshot = vm.snapshot(); + skip(73 hours); + + // lender cannot move funds if auction not cleared + _assertMoveDepositAuctionNotClearedRevert({ + from: _lender, + amount: 10.0 * 1e18, + fromIndex: _i9_72, + toIndex: _i9_81 + }); + + vm.revertTo(snapshot); + // lender can add / remove liquidity in buckets that are not within liquidation debt changePrank(_lender1); _pool.addQuoteToken(2_000 * 1e18, 5000, block.timestamp + 1 minutes, false); diff --git a/tests/forge/utils/DSTestPlus.sol b/tests/forge/utils/DSTestPlus.sol index 653f0ddd7..ef8eaa9df 100644 --- a/tests/forge/utils/DSTestPlus.sol +++ b/tests/forge/utils/DSTestPlus.sol @@ -1304,6 +1304,17 @@ abstract contract DSTestPlus is Test, IPoolEvents { _pool.moveQuoteToken(amount, fromIndex, toIndex, type(uint256).max, false); } + function _assertMoveDepositAuctionNotClearedRevert( + address from, + uint256 amount, + uint256 fromIndex, + uint256 toIndex + ) internal { + changePrank(from); + vm.expectRevert(IPoolErrors.AuctionNotCleared.selector); + _pool.moveQuoteToken(amount, fromIndex, toIndex, type(uint256).max, false); + } + function _assertMoveDepositBelowLUPRevert( address from, uint256 amount,