diff --git a/src/RepoTokenList.sol b/src/RepoTokenList.sol index 9075f68..9c1d339 100644 --- a/src/RepoTokenList.sol +++ b/src/RepoTokenList.sol @@ -197,6 +197,14 @@ library RepoTokenList { address current = listData.head; while (current != NULL_NODE) { + // Filter by a specific repoToken, address(0) bypasses this filter + if (repoTokenToMatch != address(0) && current != repoTokenToMatch) { + // Not a match, do not add to totalPresentValue + // Move to the next token in the list + current = _getNext(listData, current); + continue; + } + uint256 currentMaturity = getRepoTokenMaturity(current); uint256 repoTokenBalance = ITermRepoToken(current).balanceOf(address(this)); uint256 repoTokenPrecision = 10**ERC20(current).decimals(); @@ -217,10 +225,9 @@ library RepoTokenList { totalPresentValue += repoTokenBalanceInBaseAssetPrecision; } - // If filtering by a specific repo token, stop early if matched + // Filter by a specific repo token, address(0) bypasses this condition if (repoTokenToMatch != address(0) && current == repoTokenToMatch) { - // matching a specific repoToken and terminate early because the list is sorted - // with no duplicates + // Found a match, terminate early break; } @@ -304,7 +311,6 @@ library RepoTokenList { * @notice Validates a repoToken against specific criteria * @param listData The list data * @param repoToken The repoToken to validate - * @param termController The term controller * @param asset The address of the base asset * @return redemptionTimestamp The redemption timestamp of the validated repoToken * @@ -314,14 +320,8 @@ library RepoTokenList { function validateRepoToken( RepoTokenListData storage listData, ITermRepoToken repoToken, - ITermController termController, address asset ) internal view returns (uint256 redemptionTimestamp) { - // Ensure the repo token is deployed by term - if (!termController.isTermDeployed(address(repoToken))) { - revert InvalidRepoToken(address(repoToken)); - } - // Retrieve repo token configuration address purchaseToken; address collateralManager; @@ -357,7 +357,6 @@ library RepoTokenList { * @notice Validate and insert a repoToken into the list data * @param listData The list data * @param repoToken The repoToken to validate and insert - * @param termController The term controller * @param discountRateAdapter The discount rate adapter * @param asset The address of the base asset * @return discountRate The discount rate to be applied to the validated repoToken @@ -366,7 +365,6 @@ library RepoTokenList { function validateAndInsertRepoToken( RepoTokenListData storage listData, ITermRepoToken repoToken, - ITermController termController, ITermDiscountRateAdapter discountRateAdapter, address asset ) internal returns (uint256 discountRate, uint256 redemptionTimestamp) { @@ -388,7 +386,7 @@ library RepoTokenList { } else { discountRate = discountRateAdapter.getDiscountRate(address(repoToken)); - redemptionTimestamp = validateRepoToken(listData, repoToken, termController, asset); + redemptionTimestamp = validateRepoToken(listData, repoToken, asset); insertSorted(listData, address(repoToken)); listData.discountRates[address(repoToken)] = discountRate; diff --git a/src/Strategy.sol b/src/Strategy.sol index 01fe2d7..7e5ef49 100644 --- a/src/Strategy.sol +++ b/src/Strategy.sol @@ -45,6 +45,8 @@ contract Strategy is BaseStrategy, Pausable, ReentrancyGuard { error BalanceBelowliquidityReserveRatio(); error InsufficientLiquidBalance(uint256 have, uint256 want); error RepoTokenConcentrationTooHigh(address repoToken); + error RepoTokenBlacklisted(address repoToken); + error DepositPaused(); // Immutable state variables ITermVaultEvents public immutable TERM_VAULT_EVENT_EMITTER; @@ -52,7 +54,10 @@ contract Strategy is BaseStrategy, Pausable, ReentrancyGuard { IERC4626 public immutable YEARN_VAULT; // State variables - ITermController public termController; + /// @notice previous term controller + ITermController public prevTermController; + /// @notice current term controller + ITermController public currTermController; ITermDiscountRateAdapter public discountRateAdapter; RepoTokenListData internal repoTokenListData; TermAuctionListData internal termAuctionListData; @@ -60,6 +65,15 @@ contract Strategy is BaseStrategy, Pausable, ReentrancyGuard { uint256 public liquidityReserveRatio; // purchase token precision (underlying) uint256 public discountRateMarkup; // 1e18 (TODO: check this) uint256 public repoTokenConcentrationLimit; + mapping(address => bool) repoTokenBlacklist; + bool depositLock; + + modifier notBlacklisted(address repoToken) { + if (repoTokenBlacklist[repoToken]) { + revert RepoTokenBlacklisted(repoToken); + } + _; + } /*////////////////////////////////////////////////////////////// MANAGEMENT FUNCTIONS @@ -82,17 +96,33 @@ contract Strategy is BaseStrategy, Pausable, ReentrancyGuard { /** * @notice Pause the contract */ - function pause() external onlyManagement { + function pauseDeposit() external onlyManagement { + depositLock = true; + TERM_VAULT_EVENT_EMITTER.emitDepositPaused(); + } + + /** + * @notice Unpause the contract + */ + function unpauseDeposit() external onlyManagement { + depositLock = false; + TERM_VAULT_EVENT_EMITTER.emitDepositUnpaused(); + } + + /** + * @notice Pause the contract + */ + function pauseStrategy() external onlyManagement { _pause(); - TERM_VAULT_EVENT_EMITTER.emitPaused(); + TERM_VAULT_EVENT_EMITTER.emitStrategyPaused(); } /** * @notice Unpause the contract */ - function unpause() external onlyManagement { + function unpauseStrategy() external onlyManagement { _unpause(); - TERM_VAULT_EVENT_EMITTER.emitUnpaused(); + TERM_VAULT_EVENT_EMITTER.emitStrategyUnpaused(); } /** @@ -103,11 +133,13 @@ contract Strategy is BaseStrategy, Pausable, ReentrancyGuard { address newTermController ) external onlyManagement { require(newTermController != address(0)); + address current = address(currTermController); TERM_VAULT_EVENT_EMITTER.emitTermControllerUpdated( - address(termController), + current, newTermController ); - termController = ITermController(newTermController); + prevTermController = ITermController(current); + currTermController = ITermController(newTermController); } /** @@ -196,6 +228,11 @@ contract Strategy is BaseStrategy, Pausable, ReentrancyGuard { repoTokenListData.collateralTokenParams[tokenAddr] = minCollateralRatio; } + function setRepoTokenBlacklist(address repoToken, bool blacklisted) external onlyManagement { + TERM_VAULT_EVENT_EMITTER.emitRepoTokenBlacklistUpdated(repoToken, blacklisted); + repoTokenBlacklist[repoToken] = blacklisted; + } + /*////////////////////////////////////////////////////////////// VIEW FUNCTIONS //////////////////////////////////////////////////////////////*/ @@ -261,12 +298,16 @@ contract Strategy is BaseStrategy, Pausable, ReentrancyGuard { ) external view returns (uint256) { // do not validate if we are simulating with existing repoTokens if (repoToken != address(0)) { - repoTokenListData.validateRepoToken( + if (!_isTermDeployed(repoToken)) { + revert RepoTokenList.InvalidRepoToken(address(repoToken)); + } + + uint256 redemptionTimestamp = repoTokenListData.validateRepoToken( ITermRepoToken(repoToken), - termController, address(asset) ); + uint256 discountRate = discountRateAdapter.getDiscountRate(repoToken); uint256 repoTokenPrecision = 10 ** ERC20(repoToken).decimals(); uint256 repoTokenAmountInBaseAssetPrecision = (ITermRepoToken( repoToken @@ -274,10 +315,17 @@ contract Strategy is BaseStrategy, Pausable, ReentrancyGuard { amount * PURCHASE_TOKEN_PRECISION) / (repoTokenPrecision * RepoTokenUtils.RATE_PRECISION); + uint256 proceeds = RepoTokenUtils.calculatePresentValue( + repoTokenAmountInBaseAssetPrecision, + PURCHASE_TOKEN_PRECISION, + redemptionTimestamp, + discountRate + discountRateMarkup + ); + _validateRepoTokenConcentration( repoToken, repoTokenAmountInBaseAssetPrecision, - 0 + proceeds ); } @@ -441,45 +489,6 @@ contract Strategy is BaseStrategy, Pausable, ReentrancyGuard { revert RepoTokenConcentrationTooHigh(repoToken); } } - - /** - * @notice Validates the resulting weighted time to maturity when submitting a new offer - * @param repoToken The address of the repoToken associated with the Term auction offer - * @param newOfferAmount The amount associated with the Term auction offer - * @param newLiquidBalance The new liquid balance of the strategy after accounting for the new offer - * - * @dev This function calculates the resulting weighted time to maturity assuming that a submitted offer is accepted - * and checks if it exceeds the predefined threshold (`timeToMaturityThreshold`). If the threshold is exceeded, - * the function reverts the transaction with an error. - */ - function _validateWeightedMaturity( - address repoToken, - uint256 newOfferAmount, - uint256 newLiquidBalance - ) private { - // Calculate the precision of the repoToken - uint256 repoTokenPrecision = 10 ** ERC20(repoToken).decimals(); - - // Convert the new offer amount to repoToken precision - uint256 offerAmountInRepoPrecision = RepoTokenUtils - .purchaseToRepoPrecision( - repoTokenPrecision, - PURCHASE_TOKEN_PRECISION, - newOfferAmount - ); - - // Calculate the resulting weighted time to maturity - uint256 resultingWeightedTimeToMaturity = _calculateWeightedMaturity( - repoToken, - offerAmountInRepoPrecision, - newLiquidBalance - ); - - // Check if the resulting weighted time to maturity exceeds the threshold - if (resultingWeightedTimeToMaturity > timeToMaturityThreshold) { - revert TimeToMaturityAboveThreshold(); - } - } /** * @notice Calculates the weighted time to maturity for the strategy's holdings, including the impact of a specified repoToken and amount @@ -526,7 +535,6 @@ contract Strategy is BaseStrategy, Pausable, ReentrancyGuard { bool foundInOfferList ) = termAuctionListData.getCumulativeOfferData( repoTokenListData, - termController, repoToken, repoTokenAmount, PURCHASE_TOKEN_PRECISION @@ -572,6 +580,16 @@ contract Strategy is BaseStrategy, Pausable, ReentrancyGuard { YEARN_VAULT.deposit(IERC20(asset).balanceOf(address(this)), address(this)); } + function _isTermDeployed(address termContract) private view returns (bool) { + if (address(currTermController) != address(0) && currTermController.isTermDeployed(termContract)) { + return true; + } + if (address(prevTermController) != address(0) && prevTermController.isTermDeployed(termContract)) { + return true; + } + return false; + } + /** * @notice Rebalances the strategy's assets by sweeping assets and redeeming matured repoTokens * @param liquidAmountRequired The amount of liquid assets required to be maintained by the strategy @@ -586,7 +604,6 @@ contract Strategy is BaseStrategy, Pausable, ReentrancyGuard { // Remove completed auction offers termAuctionListData.removeCompleted( repoTokenListData, - termController, discountRateAdapter, address(asset) ); @@ -617,6 +634,40 @@ contract Strategy is BaseStrategy, Pausable, ReentrancyGuard { STRATEGIST FUNCTIONS //////////////////////////////////////////////////////////////*/ + function _validateAndGetOfferLocker( + ITermAuction termAuction, + address repoToken, + uint256 purchaseTokenAmount + ) private view returns (ITermAuctionOfferLocker) { + // Verify that the term auction and repo token are valid and deployed by term + if (!_isTermDeployed(address(termAuction))) { + revert InvalidTermAuction(address(termAuction)); + } + if (!_isTermDeployed(repoToken)) { + revert RepoTokenList.InvalidRepoToken(address(repoToken)); + } + + require(termAuction.termRepoId() == ITermRepoToken(repoToken).termRepoId(), "repoToken does not match term repo ID"); + + // Validate purchase token, min collateral ratio and insert the repoToken if necessary + repoTokenListData.validateRepoToken( + ITermRepoToken(repoToken), + address(asset) + ); + + // Prepare and submit the offer + ITermAuctionOfferLocker offerLocker = ITermAuctionOfferLocker( + termAuction.termAuctionOfferLocker() + ); + require( + block.timestamp > offerLocker.auctionStartTime() || + block.timestamp < termAuction.auctionEndTime(), + "Auction not open" + ); + + return offerLocker; + } + /** * @notice Submits an offer into a term auction for a specified repoToken * @param termAuction The address of the term auction @@ -630,7 +681,7 @@ contract Strategy is BaseStrategy, Pausable, ReentrancyGuard { * and rebalances liquidity to support the offer submission. It handles both new offers and edits to existing offers. */ function submitAuctionOffer( - address termAuction, + ITermAuction termAuction, address repoToken, bytes32 idHash, bytes32 offerPriceHash, @@ -639,90 +690,28 @@ contract Strategy is BaseStrategy, Pausable, ReentrancyGuard { external whenNotPaused nonReentrant + notBlacklisted(repoToken) onlyManagement returns (bytes32[] memory offerIds) { require(purchaseTokenAmount > 0, "Purchase token amount must be greater than zero"); - // Verify that the term auction is valid and deployed by term - if (!termController.isTermDeployed(termAuction)) { - revert InvalidTermAuction(termAuction); - } - - ITermAuction auction = ITermAuction(termAuction); - require(auction.termRepoId() == ITermRepoToken(repoToken).termRepoId(), "repoToken does not match term repo ID"); - - // Validate purchase token, min collateral ratio and insert the repoToken if necessary - repoTokenListData.validateRepoToken( - ITermRepoToken(repoToken), - termController, - address(asset) - ); - - _validateRepoTokenConcentration(repoToken, purchaseTokenAmount, 0); - - // Prepare and submit the offer - ITermAuctionOfferLocker offerLocker = ITermAuctionOfferLocker( - auction.termAuctionOfferLocker() - ); - require( - block.timestamp > offerLocker.auctionStartTime() || - block.timestamp < auction.auctionEndTime(), - "Auction not open" + ITermAuctionOfferLocker offerLocker = _validateAndGetOfferLocker( + termAuction, + repoToken, + purchaseTokenAmount ); // Sweep assets, redeem matured repoTokens and ensure liquid balances up to date _sweepAsset(); _redeemRepoTokens(0); - // Retrieve the total liquid balance - uint256 liquidBalance = _totalLiquidBalance(address(this)); - - uint256 newOfferAmount = purchaseTokenAmount; bytes32 offerId = _generateOfferId(idHash, address(offerLocker)); + uint256 newOfferAmount = purchaseTokenAmount; uint256 currentOfferAmount = termAuctionListData .offers[offerId] .offerAmount; - // Handle adjustments if editing an existing offer - if (newOfferAmount > currentOfferAmount) { - // increasing offer amount - uint256 offerDebit; - unchecked { - // checked above - offerDebit = newOfferAmount - currentOfferAmount; - } - if (liquidBalance < offerDebit) { - revert InsufficientLiquidBalance(liquidBalance, offerDebit); - } - uint256 newLiquidBalance = liquidBalance - offerDebit; - if (newLiquidBalance < liquidityReserveRatio) { - revert BalanceBelowliquidityReserveRatio(); - } - _validateWeightedMaturity( - repoToken, - newOfferAmount, - newLiquidBalance - ); - } else if (currentOfferAmount > newOfferAmount) { - // decreasing offer amount - uint256 offerCredit; - unchecked { - offerCredit = currentOfferAmount - newOfferAmount; - } - uint256 newLiquidBalance = liquidBalance + offerCredit; - if (newLiquidBalance < liquidityReserveRatio) { - revert BalanceBelowliquidityReserveRatio(); - } - _validateWeightedMaturity( - repoToken, - newOfferAmount, - newLiquidBalance - ); - } else { - // no change in offer amount, do nothing - } - // Submit the offer and lock it in the auction ITermAuctionOfferLocker.TermAuctionOfferSubmission memory offer; offer.id = currentOfferAmount > 0 ? offerId : idHash; @@ -731,14 +720,39 @@ contract Strategy is BaseStrategy, Pausable, ReentrancyGuard { offer.amount = purchaseTokenAmount; offer.purchaseToken = address(asset); + // InsufficientLiquidBalance checked inside _submitOffer offerIds = _submitOffer( - auction, + termAuction, offerLocker, offer, repoToken, newOfferAmount, currentOfferAmount ); + + // Retrieve the total liquid balance + uint256 liquidBalance = _totalLiquidBalance(address(this)); + + // Check that new offer does not violate reserve ratio constraint + if (liquidBalance < liquidityReserveRatio) { + revert BalanceBelowliquidityReserveRatio(); + } + + // Calculate the resulting weighted time to maturity + // Passing in 0 adjustment because offer and balance already updated + uint256 resultingWeightedTimeToMaturity = _calculateWeightedMaturity( + address(0), + 0, + liquidBalance + ); + + // Check if the resulting weighted time to maturity exceeds the threshold + if (resultingWeightedTimeToMaturity > timeToMaturityThreshold) { + revert TimeToMaturityAboveThreshold(); + } + + // Passing in 0 amount and 0 liquid balance adjustment because offer and balance already updated + _validateRepoTokenConcentration(repoToken, 0, 0); } /** @@ -778,6 +792,12 @@ contract Strategy is BaseStrategy, Pausable, ReentrancyGuard { // checked above offerDebit = newOfferAmount - currentOfferAmount; } + + uint256 liquidBalance = _totalLiquidBalance(address(this)); + if (liquidBalance < offerDebit) { + revert InsufficientLiquidBalance(liquidBalance, offerDebit); + } + _withdrawAsset(offerDebit); IERC20(asset).safeApprove( address(repoServicer.termRepoLocker()), @@ -823,7 +843,7 @@ contract Strategy is BaseStrategy, Pausable, ReentrancyGuard { bytes32[] calldata offerIds ) external onlyManagement { // Validate if the term auction is deployed by term - if (!termController.isTermDeployed(termAuction)) { + if (!_isTermDeployed(termAuction)) { revert InvalidTermAuction(termAuction); } @@ -839,7 +859,6 @@ contract Strategy is BaseStrategy, Pausable, ReentrancyGuard { // Update the term auction list data and remove completed offers termAuctionListData.removeCompleted( repoTokenListData, - termController, discountRateAdapter, address(asset) ); @@ -882,15 +901,19 @@ contract Strategy is BaseStrategy, Pausable, ReentrancyGuard { function sellRepoToken( address repoToken, uint256 repoTokenAmount - ) external whenNotPaused nonReentrant { + ) external whenNotPaused nonReentrant notBlacklisted(repoToken) { // Ensure the amount of repoTokens to sell is greater than zero require(repoTokenAmount > 0); + // Make sure repo token is valid and deployed by Term + if (!_isTermDeployed(repoToken)) { + revert RepoTokenList.InvalidRepoToken(address(repoToken)); + } + // Validate and insert the repoToken into the list, retrieve auction rate and redemption timestamp (uint256 discountRate, uint256 redemptionTimestamp) = repoTokenListData .validateAndInsertRepoToken( ITermRepoToken(repoToken), - termController, discountRateAdapter, address(asset) ); @@ -935,7 +958,8 @@ contract Strategy is BaseStrategy, Pausable, ReentrancyGuard { } // Ensure the remaining liquid balance is above the liquidity threshold - if ((liquidBalance - proceeds) < liquidityReserveRatio) { + uint256 newLiquidBalance = liquidBalance - proceeds; + if (newLiquidBalance < liquidityReserveRatio) { revert BalanceBelowliquidityReserveRatio(); } @@ -1000,6 +1024,10 @@ contract Strategy is BaseStrategy, Pausable, ReentrancyGuard { * to deposit in the yield source. */ function _deployFunds(uint256 _amount) internal override whenNotPaused { + if (depositLock) { + revert DepositPaused(); + } + _sweepAsset(); _redeemRepoTokens(0); } @@ -1087,16 +1115,7 @@ contract Strategy is BaseStrategy, Pausable, ReentrancyGuard { function availableWithdrawLimit( address /*_owner*/ ) public view override returns (uint256) { - // NOTE: Withdraw limitations such as liquidity constraints should be accounted for HERE - // rather than _freeFunds in order to not count them as losses on withdraws. - - // TODO: If desired implement withdraw limit logic and any needed state variables. - - // EX: - // if(yieldSource.notShutdown()) { - // return asset.balanceOf(address(this)) + asset.balanceOf(yieldSource); - // } - return type(uint256).max; + return _totalLiquidBalance(address(this)); } /** diff --git a/src/TermAuctionList.sol b/src/TermAuctionList.sol index aa7d1f2..3176f59 100644 --- a/src/TermAuctionList.sol +++ b/src/TermAuctionList.sol @@ -169,7 +169,6 @@ library TermAuctionList { * @notice Removes completed or cancelled offers from the list data and processes the corresponding repoTokens * @param listData The list data * @param repoTokenListData The repoToken list data - * @param termController The term controller * @param discountRateAdapter The discount rate adapter * @param asset The address of the asset * @@ -180,7 +179,6 @@ library TermAuctionList { function removeCompleted( TermAuctionListData storage listData, RepoTokenListData storage repoTokenListData, - ITermController termController, ITermDiscountRateAdapter discountRateAdapter, address asset ) internal { @@ -230,6 +228,8 @@ library TermAuctionList { } if (insertRepoToken) { + // TODO: do we need to validate termDeployed(repoToken) here? + // Auction still open => include offerAmount in totalValue // (otherwise locked purchaseToken will be missing from TV) // Auction completed but not closed => include offer.offerAmount in totalValue @@ -237,7 +237,7 @@ library TermAuctionList { // This applies if the repoToken hasn't been added to the repoTokenList // (only for new auctions, not reopenings). repoTokenListData.validateAndInsertRepoToken( - ITermRepoToken(offer.repoToken), termController, discountRateAdapter, asset + ITermRepoToken(offer.repoToken), discountRateAdapter, asset ); } @@ -277,8 +277,9 @@ library TermAuctionList { for (uint256 i; i < offers.length; i++) { PendingOfferMemory memory offer = offers[i]; - // Filter by specific repo token if provided + // Filter by specific repo token if provided, address(0) bypasses this filter if (repoTokenToMatch != address(0) && offer.repoToken != repoTokenToMatch) { + // Not a match, skip continue; } @@ -317,7 +318,6 @@ library TermAuctionList { * @notice Get cumulative offer data for a specified repoToken * @param listData The list data * @param repoTokenListData The repoToken list data - * @param termController The term controller * @param repoToken The address of the repoToken (optional) * @param newOfferAmount The new offer amount for the specified repoToken * @param purchaseTokenPrecision The precision of the purchase token @@ -333,7 +333,6 @@ library TermAuctionList { function getCumulativeOfferData( TermAuctionListData storage listData, RepoTokenListData storage repoTokenListData, - ITermController termController, address repoToken, uint256 newOfferAmount, uint256 purchaseTokenPrecision diff --git a/src/TermVaultEventEmitter.sol b/src/TermVaultEventEmitter.sol index b749408..dc0f23a 100644 --- a/src/TermVaultEventEmitter.sol +++ b/src/TermVaultEventEmitter.sol @@ -59,12 +59,20 @@ contract TermVaultEventEmitter is Initializable, UUPSUpgradeable, AccessControlU emit RepoTokenConcentrationLimitUpdated(oldLimit, newLimit); } - function emitPaused() external onlyRole(VAULT_CONTRACT) { - emit Paused(); + function emitDepositPaused() external onlyRole(VAULT_CONTRACT) { + emit DepositPaused(); } - function emitUnpaused() external onlyRole(VAULT_CONTRACT) { - emit Unpaused(); + function emitDepositUnpaused() external onlyRole(VAULT_CONTRACT) { + emit DepositUnpaused(); + } + + function emitStrategyPaused() external onlyRole(VAULT_CONTRACT) { + emit StrategyPaused(); + } + + function emitStrategyUnpaused() external onlyRole(VAULT_CONTRACT) { + emit StrategyUnpaused(); } function emitDiscountRateAdapterUpdated( @@ -74,6 +82,10 @@ contract TermVaultEventEmitter is Initializable, UUPSUpgradeable, AccessControlU emit DiscountRateAdapterUpdated(oldAdapter, newAdapter); } + function emitRepoTokenBlacklistUpdated(address repoToken, bool blacklisted) external onlyRole(VAULT_CONTRACT) { + emit RepoTokenBlacklistUpdated(repoToken, blacklisted); + } + // ======================================================================== // = Admin =============================================================== // ======================================================================== diff --git a/src/interfaces/term/ITermVaultEvents.sol b/src/interfaces/term/ITermVaultEvents.sol index 0181b09..6537400 100644 --- a/src/interfaces/term/ITermVaultEvents.sol +++ b/src/interfaces/term/ITermVaultEvents.sol @@ -14,15 +14,24 @@ interface ITermVaultEvents { event RepoTokenConcentrationLimitUpdated(uint256 oldLimit, uint256 newLimit); - event Paused(); + event DepositPaused(); - event Unpaused(); + event DepositUnpaused(); + + event StrategyPaused(); + + event StrategyUnpaused(); event DiscountRateAdapterUpdated( address indexed oldAdapter, address indexed newAdapter ); + event RepoTokenBlacklistUpdated( + address indexed repoToken, + bool blacklisted + ); + function emitTermControllerUpdated(address oldController, address newController) external; function emitTimeToMaturityThresholdUpdated(uint256 oldThreshold, uint256 newThreshold) external; @@ -35,12 +44,18 @@ interface ITermVaultEvents { function emitRepoTokenConcentrationLimitUpdated(uint256 oldLimit, uint256 newLimit) external; - function emitPaused() external; + function emitDepositPaused() external; - function emitUnpaused() external; + function emitDepositUnpaused() external; + + function emitStrategyPaused() external; + + function emitStrategyUnpaused() external; function emitDiscountRateAdapterUpdated( address oldAdapter, address newAdapter ) external; + + function emitRepoTokenBlacklistUpdated(address repoToken, bool blacklisted) external; } diff --git a/src/test/TestUSDCOffers.t.sol b/src/test/TestUSDCOffers.t.sol index 8b35261..5dfccf4 100644 --- a/src/test/TestUSDCOffers.t.sol +++ b/src/test/TestUSDCOffers.t.sol @@ -50,12 +50,12 @@ contract TestUSDCSubmitOffer is Setup { // test: only management can submit offers vm.expectRevert("!management"); bytes32[] memory offerIds = termStrategy.submitAuctionOffer( - address(repoToken1WeekAuction), address(repoToken1Week), idHash, bytes32("test price"), offerAmount + repoToken1WeekAuction, address(repoToken1Week), idHash, bytes32("test price"), offerAmount ); vm.prank(management); offerIds = termStrategy.submitAuctionOffer( - address(repoToken1WeekAuction), address(repoToken1Week), idHash, bytes32("test price"), offerAmount + repoToken1WeekAuction, address(repoToken1Week), idHash, bytes32("test price"), offerAmount ); assertEq(offerIds.length, 1); @@ -80,7 +80,7 @@ contract TestUSDCSubmitOffer is Setup { vm.prank(management); bytes32[] memory offerIds = termStrategy.submitAuctionOffer( - address(repoToken1WeekAuction), address(repoToken1Week), idHash1, bytes32("test price"), offerAmount + repoToken1WeekAuction, address(repoToken1Week), idHash1, bytes32("test price"), offerAmount ); assertEq(termStrategy.totalLiquidBalance(), initialState.totalLiquidBalance - offerAmount); diff --git a/src/test/TestUSDCSellRepoToken.t.sol b/src/test/TestUSDCSellRepoToken.t.sol index 898aa5c..f80ed50 100644 --- a/src/test/TestUSDCSellRepoToken.t.sol +++ b/src/test/TestUSDCSellRepoToken.t.sol @@ -303,7 +303,7 @@ contract TestUSDCSellRepoToken is Setup { vm.prank(management); termStrategy.submitAuctionOffer( - address(repoToken4WeekAuction), address(repoToken4Week), idHash, bytes32("test price"), 3e6 + repoToken4WeekAuction, address(repoToken4Week), idHash, bytes32("test price"), 3e6 ); assertEq(termStrategy.simulateWeightedTimeToMaturity(address(0), 0), 1108800); @@ -319,9 +319,11 @@ contract TestUSDCSellRepoToken is Setup { vm.prank(management); termStrategy.setTermController(address(0)); + address currentController = address(termStrategy.currTermController()); vm.prank(management); termStrategy.setTermController(address(newController)); - assertEq(address(termStrategy.termController()), address(newController)); + assertEq(address(termStrategy.currTermController()), address(newController)); + assertEq(address(termStrategy.prevTermController()), currentController); vm.expectRevert("!management"); termStrategy.setTimeToMaturityThreshold(12345); @@ -552,10 +554,10 @@ contract TestUSDCSellRepoToken is Setup { mockUSDC.mint(testDepositor, depositAmount); vm.expectRevert("!management"); - termStrategy.pause(); + termStrategy.pauseStrategy(); vm.prank(management); - termStrategy.pause(); + termStrategy.pauseStrategy(); vm.startPrank(testDepositor); mockUSDC.approve(address(termStrategy), type(uint256).max); diff --git a/src/test/TestUSDCSubmitOffer.t.sol b/src/test/TestUSDCSubmitOffer.t.sol index 26d4c70..35a5aa1 100644 --- a/src/test/TestUSDCSubmitOffer.t.sol +++ b/src/test/TestUSDCSubmitOffer.t.sol @@ -50,12 +50,12 @@ contract TestUSDCSubmitOffer is Setup { // test: only management can submit offers vm.expectRevert("!management"); bytes32[] memory offerIds = termStrategy.submitAuctionOffer( - address(repoToken1WeekAuction), address(repoToken1Week), idHash, bytes32("test price"), offerAmount + repoToken1WeekAuction, address(repoToken1Week), idHash, bytes32("test price"), offerAmount ); vm.prank(management); offerIds = termStrategy.submitAuctionOffer( - address(repoToken1WeekAuction), address(repoToken1Week), idHash, bytes32("test price"), offerAmount + repoToken1WeekAuction, address(repoToken1Week), idHash, bytes32("test price"), offerAmount ); assertEq(offerIds.length, 1); @@ -80,7 +80,7 @@ contract TestUSDCSubmitOffer is Setup { vm.prank(management); bytes32[] memory offerIds = termStrategy.submitAuctionOffer( - address(repoToken1WeekAuction), address(repoToken1Week), idHash1, bytes32("test price"), offerAmount + repoToken1WeekAuction, address(repoToken1Week), idHash1, bytes32("test price"), offerAmount ); assertEq(termStrategy.totalLiquidBalance(), initialState.totalLiquidBalance - offerAmount);