From 9a258338c4c8d2cf96dae7755922258812df1923 Mon Sep 17 00:00:00 2001 From: Schlag <89420541+Schlagonia@users.noreply.github.com> Date: Thu, 19 Oct 2023 08:44:42 -0600 Subject: [PATCH] fix: api version (#184) * fix: api version * fix: factory interface * test: add tokenized strategy tests (#185) * test: add tokenized strategy tests * test: use lossy tokenized * fix: use safe approve * fix: cleanup --- ape-config.yaml | 5 + contracts/VaultFactory.vy | 2 +- contracts/VaultV3.vy | 19 +++- contracts/interfaces/IVault.sol | 8 +- contracts/interfaces/IVaultFactory.sol | 20 +++- contracts/test/ERC4626BaseStrategy.sol | 11 +- .../test/mocks/ERC4626/LiquidStrategy.sol | 28 ----- .../test/mocks/ERC4626/LossyStrategy.sol | 107 ++++++++++-------- .../mocks/ERC4626/MockTokenizedStrategy.sol | 79 +++++++++++++ tests/conftest.py | 25 +++- tests/e2e/test_profitable_strategy_flow.py | 3 + tests/unit/strategy/test_strategy.py | 6 +- tests/unit/vault/test_debt_management.py | 8 +- tests/unit/vault/test_profit_unlocking.py | 19 ++-- tests/unit/vault/test_protocol_fees.py | 1 + tests/unit/vault/test_role_base_access.py | 11 +- .../vault/test_role_permissioned_access.py | 12 +- tests/unit/vault/test_shares.py | 1 + tests/unit/vault/test_strategy_accounting.py | 10 ++ tests/unit/vault/test_strategy_withdraw.py | 5 +- 20 files changed, 255 insertions(+), 125 deletions(-) delete mode 100644 contracts/test/mocks/ERC4626/LiquidStrategy.sol create mode 100644 contracts/test/mocks/ERC4626/MockTokenizedStrategy.sol diff --git a/ape-config.yaml b/ape-config.yaml index 752b8806..7f5685e4 100644 --- a/ape-config.yaml +++ b/ape-config.yaml @@ -13,10 +13,15 @@ dependencies: - name: openzeppelin github: OpenZeppelin/openzeppelin-contracts version: 4.7.3 + - name: tokenized-strategy + github: yearn/tokenized-strategy + branch: master + contracts_folder: src solidity: import_remapping: - "@openzeppelin/contracts=openzeppelin/v4.7.3" + - "@tokenized-strategy=tokenized-strategy/master" ethereum: local: diff --git a/contracts/VaultFactory.vy b/contracts/VaultFactory.vy index cf79c3fa..0be88b58 100644 --- a/contracts/VaultFactory.vy +++ b/contracts/VaultFactory.vy @@ -146,7 +146,7 @@ def vault_blueprint()-> address: @view @external -def api_version() -> String[28]: +def apiVersion() -> String[28]: """ @notice Get the API version of the factory. @return The API version of the factory. diff --git a/contracts/VaultV3.vy b/contracts/VaultV3.vy index ebd1beef..67b7080b 100644 --- a/contracts/VaultV3.vy +++ b/contracts/VaultV3.vy @@ -254,14 +254,14 @@ open_roles: public(HashMap[Roles, bool]) role_manager: public(address) # Temporary variable to store the address of the next role_manager until the role is accepted. future_role_manager: public(address) -# State of the vault - if set to true, only withdrawals will be available. It can't be reverted. -shutdown: public(bool) # ERC20 - name of the vaults token. name: public(String[64]) # ERC20 - symbol of the vaults token. symbol: public(String[32]) +# State of the vault - if set to true, only withdrawals will be available. It can't be reverted. +shutdown: bool # The amount of time profits will unlock over. profit_max_unlock_time: uint256 # The timestamp of when the current unlocking period ends. @@ -1439,7 +1439,7 @@ def set_minimum_total_idle(minimum_total_idle: uint256): log UpdateMinimumTotalIdle(minimum_total_idle) @external -def set_profit_max_unlock_time(new_profit_max_unlock_time: uint256): +def setProfitMaxUnlockTime(new_profit_max_unlock_time: uint256): """ @notice Set the new profit max unlock time. @dev The time is denominated in seconds and must be less than 1 year. @@ -1562,9 +1562,18 @@ def accept_role_manager(): log UpdateRoleManager(msg.sender) # VAULT STATUS VIEWS + +@view +@external +def isShutdown() -> bool: + """ + @notice Get if the vault is shutdown. + @return Bool representing the shutdown status + """ + return self.shutdown @view @external -def unlocked_shares() -> uint256: +def unlockedShares() -> uint256: """ @notice Get the amount of shares that have been unlocked. @return The amount of shares that are have been unlocked. @@ -2076,7 +2085,7 @@ def previewRedeem(shares: uint256) -> uint256: @view @external -def api_version() -> String[28]: +def apiVersion() -> String[28]: """ @notice Get the API version of the vault. @return The API version of the vault. diff --git a/contracts/interfaces/IVault.sol b/contracts/interfaces/IVault.sol index d7cecd7b..847785b2 100644 --- a/contracts/interfaces/IVault.sol +++ b/contracts/interfaces/IVault.sol @@ -75,7 +75,7 @@ interface IVault is IERC4626 { function future_role_manager() external view returns (address); - function shutdown() external view returns (bool); + function isShutdown() external view returns (bool); function nonces(address) external view returns (uint256); @@ -97,7 +97,7 @@ interface IVault is IERC4626 { function set_minimum_total_idle(uint256 minimum_total_idle) external; - function set_profit_max_unlock_time( + function setProfitMaxUnlockTime( uint256 new_profit_max_unlock_time ) external; @@ -115,7 +115,7 @@ interface IVault is IERC4626 { function accept_role_manager() external; - function unlocked_shares() external view returns (uint256); + function unlockedShares() external view returns (uint256); function pricePerShare() external view returns (uint256); @@ -149,7 +149,7 @@ interface IVault is IERC4626 { function totalDebt() external view returns (uint256); - function api_version() external view returns (string memory); + function apiVersion() external view returns (string memory); function assess_share_of_unrealised_losses( address strategy, diff --git a/contracts/interfaces/IVaultFactory.sol b/contracts/interfaces/IVaultFactory.sol index ff476a5d..11e14ed6 100644 --- a/contracts/interfaces/IVaultFactory.sol +++ b/contracts/interfaces/IVaultFactory.sol @@ -1,6 +1,8 @@ // SPDX-License-Identifier: GPL-3.0 pragma solidity 0.8.18; +import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; + interface IVaultFactory { event NewVault(address indexed vaultAddress, address indexed asset); event UpdateProtocolFeeBps( @@ -17,8 +19,22 @@ interface IVaultFactory { event NewPendingGovernance(address newPendingGovernance); event UpdateGovernance(address newGovernance); + function shutdown() external view returns (bool); + + function governance() external view returns (address); + + function pending_governance() external view returns (address); + + function name() external view returns (string memory); + + function default_protocol_fee_config() external view returns (uint256); + + function custom_protocol_fee(address) external view returns (uint16); + + function use_custom_protocol_fee(address) external view returns (bool); + function deploy_new_vault( - address asset, + ERC20 asset, string memory name, string memory symbol, address role_manager, @@ -27,7 +43,7 @@ interface IVaultFactory { function vault_blueprint() external view returns (address); - function api_version() external view returns (string memory); + function apiVersion() external view returns (string memory); function protocol_fee_config() external diff --git a/contracts/test/ERC4626BaseStrategy.sol b/contracts/test/ERC4626BaseStrategy.sol index f550eac2..c4a75e35 100644 --- a/contracts/test/ERC4626BaseStrategy.sol +++ b/contracts/test/ERC4626BaseStrategy.sol @@ -15,6 +15,7 @@ abstract contract ERC4626BaseStrategy is ERC4626 { address public vault; uint8 private _decimals; + address public keeper; constructor( address _vault, @@ -27,11 +28,8 @@ abstract contract ERC4626BaseStrategy is ERC4626 { _decimals = IERC20Metadata(address(_asset)).decimals(); vault = _vault; - // // using approve since initialization is only called once - // IERC20(_asset).approve(_vault, type(uint256).max); // Give Vault unlimited access (might save gas) } - /** @dev See {IERC20Metadata-decimals}. */ function decimals() public view @@ -42,9 +40,6 @@ abstract contract ERC4626BaseStrategy is ERC4626 { return _decimals; } - // TODO: add roles (including vault) - // TODO: should we force invest and freeFunds to be in deposit and withdraw functions? - function invest() external virtual {} function freeFunds( @@ -58,4 +53,8 @@ abstract contract ERC4626BaseStrategy is ERC4626 { ) internal virtual returns (uint256 amountFreed); function sweep(address _token) external {} + + function report() external virtual returns (uint256, uint256) { + return (0, 0); + } } diff --git a/contracts/test/mocks/ERC4626/LiquidStrategy.sol b/contracts/test/mocks/ERC4626/LiquidStrategy.sol deleted file mode 100644 index 5973a2f5..00000000 --- a/contracts/test/mocks/ERC4626/LiquidStrategy.sol +++ /dev/null @@ -1,28 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0 -pragma solidity 0.8.18; - -import {ERC4626BaseStrategyMock, IERC20} from "./BaseStrategyMock.sol"; -import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; -import {Math} from "@openzeppelin/contracts/utils/math/Math.sol"; - -contract ERC4626LiquidStrategy is ERC4626BaseStrategyMock { - using SafeERC20 for IERC20; - - constructor( - address _vault, - address _asset - ) ERC4626BaseStrategyMock(_vault, _asset) {} - - // doesn't do anything in liquid strategy as all funds are free - function _freeFunds( - uint256 _amount - ) internal override returns (uint256 _amountFreed) { - _amountFreed = IERC20(asset()).balanceOf(address(this)); - } - - function maxWithdraw( - address _owner - ) public view override returns (uint256) { - return _convertToAssets(balanceOf(_owner), Math.Rounding.Down); - } -} diff --git a/contracts/test/mocks/ERC4626/LossyStrategy.sol b/contracts/test/mocks/ERC4626/LossyStrategy.sol index 20a416f9..788a93e8 100644 --- a/contracts/test/mocks/ERC4626/LossyStrategy.sol +++ b/contracts/test/mocks/ERC4626/LossyStrategy.sol @@ -1,23 +1,55 @@ // SPDX-License-Identifier: GPL-3.0 pragma solidity 0.8.18; -import {ERC4626BaseStrategyMock, IERC20} from "./BaseStrategyMock.sol"; +import {MockTokenizedStrategy, ERC20} from "./MockTokenizedStrategy.sol"; import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; -contract ERC4626LossyStrategy is ERC4626BaseStrategyMock { - using SafeERC20 for IERC20; +contract YieldSource { + using SafeERC20 for ERC20; + + ERC20 public asset; + + constructor(address _asset) { + asset = ERC20(_asset); + asset.safeApprove(msg.sender, type(uint256).max); + } + + function deposit(uint256 _amount) external { + asset.safeTransferFrom(msg.sender, address(this), _amount); + } + + function withdraw(uint256 _amount) external { + asset.safeTransfer(msg.sender, _amount); + } +} + +contract ERC4626LossyStrategy is MockTokenizedStrategy { + using SafeERC20 for ERC20; int256 public withdrawingLoss; uint256 public lockedFunds; + address public vault; + address public yieldSource; constructor( - address _vault, - address _asset - ) ERC4626BaseStrategyMock(_vault, _asset) {} + address _asset, + string memory _name, + address _management, + address _keeper, + address _vault + ) MockTokenizedStrategy(_asset, _name, _management, _keeper) { + yieldSource = address(new YieldSource(_asset)); + ERC20(_asset).safeApprove(yieldSource, type(uint256).max); + // So we can record losses when it happens. + strategyStorage().management = address(this); + vault = _vault; + } // used to generate losses, accepts single arg to send losses to function setLoss(address _target, uint256 _loss) external { - IERC20(asset()).safeTransfer(_target, _loss); + strategyStorage().asset.safeTransferFrom(yieldSource, _target, _loss); + // Record the loss + MockTokenizedStrategy(address(this)).report(); } function setWithdrawingLoss(int256 _loss) external { @@ -28,53 +60,36 @@ contract ERC4626LossyStrategy is ERC4626BaseStrategyMock { lockedFunds = _lockedFunds; } - function totalAssets() public view override returns (uint256) { - if (withdrawingLoss < 0) { - return - uint256( - int256(IERC20(asset()).balanceOf(address(this))) + - withdrawingLoss - ); - } else { - return super.totalAssets(); - } + function deployFunds(uint256 _amount) external override { + YieldSource(yieldSource).deposit(_amount); } - function _withdraw( - address _caller, - address _receiver, - address _owner, - uint256 _assets, - uint256 _shares - ) internal override { - if (_caller != _owner) { - _spendAllowance(_owner, _caller, _shares); - } + function freeFunds(uint256 _amount) external override { + // Adjust the amount to withdraw. + uint256 toWithdraw = uint256(int256(_amount) - withdrawingLoss); + YieldSource(yieldSource).withdraw(toWithdraw); - uint256 toWithdraw = uint256(int256(_assets) - withdrawingLoss); - _burn(_owner, _shares); - // Withdrawing loss simulates a loss while withdrawing - IERC20(asset()).safeTransfer(_receiver, toWithdraw); - if (withdrawingLoss > 0) { - // burns (to simulate loss while withdrawing) - IERC20(asset()).safeTransfer(asset(), uint256(withdrawingLoss)); + if (withdrawingLoss < 0) { + // Over withdraw to the vault + strategyStorage().asset.safeTransfer( + vault, + uint256(-withdrawingLoss) + ); } - - emit Withdraw(_caller, _receiver, _owner, toWithdraw, _shares); } - function _freeFunds( - uint256 _amount - ) internal override returns (uint256 _amountFreed) {} - - function maxWithdraw(address) public view override returns (uint256) { - return IERC20(asset()).balanceOf(address(this)) - lockedFunds; + function harvestAndReport() external override returns (uint256) { + return + strategyStorage().asset.balanceOf(address(this)) + + strategyStorage().asset.balanceOf(yieldSource); } - function maxRedeem(address) public view override returns (uint256) { + function availableWithdrawLimit( + address + ) public view override returns (uint256) { return - convertToShares( - IERC20(asset()).balanceOf(address(this)) - lockedFunds - ); + strategyStorage().asset.balanceOf(address(this)) + + strategyStorage().asset.balanceOf(yieldSource) - + lockedFunds; } } diff --git a/contracts/test/mocks/ERC4626/MockTokenizedStrategy.sol b/contracts/test/mocks/ERC4626/MockTokenizedStrategy.sol new file mode 100644 index 00000000..37774fa2 --- /dev/null +++ b/contracts/test/mocks/ERC4626/MockTokenizedStrategy.sol @@ -0,0 +1,79 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity 0.8.18; + +import {TokenizedStrategy, ERC20} from "@tokenized-strategy/TokenizedStrategy.sol"; + +contract MockTokenizedStrategy is TokenizedStrategy { + uint256 public minDebt; + uint256 public maxDebt = type(uint256).max; + + // Private variables and functions used in this mock. + bytes32 public constant BASE_STRATEGY_STORAGE = + bytes32(uint256(keccak256("yearn.base.strategy.storage")) - 1); + + function strategyStorage() internal pure returns (StrategyData storage S) { + // Since STORAGE_SLOT is a constant, we have to put a variable + // on the stack to access it from an inline assembly block. + bytes32 slot = BASE_STRATEGY_STORAGE; + assembly { + S.slot := slot + } + } + + constructor( + address _asset, + string memory _name, + address _management, + address _keeper + ) { + // Cache storage pointer + StrategyData storage S = strategyStorage(); + + // Set the strategy's underlying asset + S.asset = ERC20(_asset); + // Set the Strategy Tokens name. + S.name = _name; + // Set decimals based off the `asset`. + S.decimals = ERC20(_asset).decimals(); + + // Set last report to this block. + S.lastReport = uint128(block.timestamp); + + // Set the default management address. Can't be 0. + require(_management != address(0), "ZERO ADDRESS"); + S.management = _management; + S.performanceFeeRecipient = _management; + // Set the keeper address + S.keeper = _keeper; + } + + function setMinDebt(uint256 _minDebt) external { + minDebt = _minDebt; + } + + function setMaxDebt(uint256 _maxDebt) external { + maxDebt = _maxDebt; + } + + function availableDepositLimit( + address + ) public view virtual returns (uint256) { + uint256 _totalAssets = strategyStorage().totalIdle; + uint256 _maxDebt = maxDebt; + return _maxDebt > _totalAssets ? _maxDebt - _totalAssets : 0; + } + + function availableWithdrawLimit( + address /*_owner*/ + ) public view virtual returns (uint256) { + return type(uint256).max; + } + + function deployFunds(uint256 _amount) external virtual {} + + function freeFunds(uint256 _amount) external virtual {} + + function harvestAndReport() external virtual returns (uint256) { + return strategyStorage().asset.balanceOf(address(this)); + } +} diff --git a/tests/conftest.py b/tests/conftest.py index 5c929590..b46227ae 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -233,9 +233,15 @@ def create_vault( # create default liquid strategy with 0 fee @pytest.fixture(scope="session") -def create_strategy(project, strategist): +def create_strategy(project, strategist, gov): def create_strategy(vault): - return strategist.deploy(project.ERC4626LiquidStrategy, vault, vault.asset()) + return strategist.deploy( + project.MockTokenizedStrategy, + vault.asset(), + "Mock Tokenized Strategy", + strategist, + gov, + ) yield create_strategy @@ -251,9 +257,16 @@ def create_locked_strategy(vault): # create lossy strategy with 0 fee @pytest.fixture(scope="session") -def create_lossy_strategy(project, strategist): +def create_lossy_strategy(project, strategist, gov): def create_lossy_strategy(vault): - return strategist.deploy(project.ERC4626LossyStrategy, vault, vault.asset()) + return strategist.deploy( + project.ERC4626LossyStrategy, + vault.asset(), + "Mock Tokenized Strategy", + strategist, + gov, + vault, + ) yield create_lossy_strategy @@ -410,7 +423,7 @@ def sign_vault_permit( override_nonce=None, ): name = "Yearn Vault" - version = vault.api_version() + version = vault.apiVersion() if override_nonce: nonce = override_nonce else: @@ -468,7 +481,7 @@ def user_deposit(user, vault, token, amount) -> ContractLog: @pytest.fixture(scope="session") def airdrop_asset(): def airdrop_asset(gov, asset, target, amount): - asset.mint(target.address, amount, sender=gov) + asset.mint(target, amount, sender=gov) return airdrop_asset diff --git a/tests/e2e/test_profitable_strategy_flow.py b/tests/e2e/test_profitable_strategy_flow.py index cf82f286..0734f42a 100644 --- a/tests/e2e/test_profitable_strategy_flow.py +++ b/tests/e2e/test_profitable_strategy_flow.py @@ -59,6 +59,8 @@ def test_profitable_strategy_flow( # we simulate profit on strategy total_fee = first_profit * (performance_fee / MAX_BPS_ACCOUNTANT) asset.transfer(strategy, first_profit, sender=whale) + strategy.report(sender=gov) + tx = vault.process_report(strategy.address, sender=gov) event = list(tx.decode_logs(vault.StrategyReported)) assert event[0].gain == first_profit @@ -84,6 +86,7 @@ def test_profitable_strategy_flow( # We generate second profit asset.transfer(strategy, second_profit, sender=whale) + strategy.report(sender=gov) assets_before_profit = vault.totalAssets() tx = vault.process_report(strategy.address, sender=gov) event = list(tx.decode_logs(vault.StrategyReported)) diff --git a/tests/unit/strategy/test_strategy.py b/tests/unit/strategy/test_strategy.py index 792e59d4..dbb8931f 100644 --- a/tests/unit/strategy/test_strategy.py +++ b/tests/unit/strategy/test_strategy.py @@ -54,15 +54,15 @@ def test_lossy_strategy__with_multiple_losses( loss = 10**18 mint_and_deposit_into_strategy(strategy, vault, amount) - assert asset.balanceOf(strategy) == amount + assert strategy.totalAssets() == amount assert strategy.maxWithdraw(vault) == amount strategy.setLoss(fish.address, loss, sender=gov) initial_loss = amount - loss - assert asset.balanceOf(strategy) == initial_loss + assert strategy.totalAssets() == initial_loss assert strategy.maxWithdraw(vault) == initial_loss strategy.setLoss(fish.address, loss, sender=gov) secondary_loss = initial_loss - loss - assert asset.balanceOf(strategy) == secondary_loss + assert strategy.totalAssets() == secondary_loss assert strategy.maxWithdraw(vault) == secondary_loss diff --git a/tests/unit/vault/test_debt_management.py b/tests/unit/vault/test_debt_management.py index 553f0505..d10f44d0 100644 --- a/tests/unit/vault/test_debt_management.py +++ b/tests/unit/vault/test_debt_management.py @@ -510,7 +510,7 @@ def test_update_debt__with_faulty_strategy_that_withdraws_more_than_requested__o new_debt = target_debt - extra difference = current_debt - new_debt - airdrop_asset(gov, asset, lossy_strategy, extra) + airdrop_asset(gov, asset, lossy_strategy.yieldSource(), extra) lossy_strategy.setWithdrawingLoss(-extra, sender=gov) initial_pps = vault.pricePerShare() @@ -526,7 +526,7 @@ def test_update_debt__with_faulty_strategy_that_withdraws_more_than_requested__o # assert we recorded correctly assert vault.pricePerShare() == initial_pps assert vault.strategies(lossy_strategy.address).current_debt == new_debt - assert asset.balanceOf(lossy_strategy) == target_debt + assert lossy_strategy.totalAssets() == target_debt assert asset.balanceOf(vault) == difference assert vault.totalIdle() == difference assert vault.totalDebt() == new_debt @@ -546,7 +546,7 @@ def test_update_debt__with_faulty_strategy_that_withdraws_more_than_requested( new_debt = 0 difference = current_debt - airdrop_asset(gov, asset, lossy_strategy, extra) + airdrop_asset(gov, asset, lossy_strategy.yieldSource(), extra) lossy_strategy.setWithdrawingLoss(-extra, sender=gov) initial_pps = vault.pricePerShare() @@ -561,7 +561,7 @@ def test_update_debt__with_faulty_strategy_that_withdraws_more_than_requested( assert vault.pricePerShare() == initial_pps assert vault.strategies(lossy_strategy.address).current_debt == new_debt - assert asset.balanceOf(lossy_strategy) == new_debt + assert lossy_strategy.totalAssets() == new_debt assert asset.balanceOf(vault) == (vault_balance + extra) assert vault.totalIdle() == vault_balance assert vault.totalDebt() == new_debt diff --git a/tests/unit/vault/test_profit_unlocking.py b/tests/unit/vault/test_profit_unlocking.py index 983649eb..18a05cfc 100644 --- a/tests/unit/vault/test_profit_unlocking.py +++ b/tests/unit/vault/test_profit_unlocking.py @@ -35,6 +35,8 @@ def create_and_check_profit( # We create a virtual profit initial_debt = vault.strategies(strategy).current_debt asset.transfer(strategy, profit, sender=gov) + # Record profits at the strategy level. + strategy.report(sender=gov) tx = vault.process_report(strategy, sender=gov) event = list(tx.decode_logs(vault.StrategyReported)) @@ -1199,6 +1201,7 @@ def test_gain_fees_no_refunds_not_enough_buffer( assert accountant.fees(strategy).performance_fee == second_performance_fee asset.transfer(strategy, second_profit, sender=gov) + strategy.report(sender=gov) price_per_share_before_2nd_profit = vault.pricePerShare() / 10 ** vault.decimals() accountant_shares_before_2nd_profit = vault.balanceOf(accountant) @@ -2516,7 +2519,7 @@ def test_increase_profit_max_period__no_change( ) # update profit max unlock time - vault.set_profit_max_unlock_time(WEEK * 2, sender=gov) + vault.setProfitMaxUnlockTime(WEEK * 2, sender=gov) time_passed = chain.pending_timestamp - timestamp # assure the all the amounts is what is originally would have been @@ -2585,7 +2588,7 @@ def test_decrease_profit_max_period__no_change( ) # update profit max unlock time - vault.set_profit_max_unlock_time(WEEK // 2, sender=gov) + vault.setProfitMaxUnlockTime(WEEK // 2, sender=gov) time_passed = chain.pending_timestamp - timestamp # assure the all the amounts is what is originally would have been @@ -2655,7 +2658,7 @@ def test_increase_profit_max_period__next_report_works( ) # update profit max unlock time - vault.set_profit_max_unlock_time(WEEK * 2, sender=gov) + vault.setProfitMaxUnlockTime(WEEK * 2, sender=gov) time_passed = chain.pending_timestamp - timestamp # assure the all the amounts is what is originally would have been @@ -2760,7 +2763,7 @@ def test_decrease_profit_max_period__next_report_works( ) # update profit max unlock time - vault.set_profit_max_unlock_time(WEEK // 2, sender=gov) + vault.setProfitMaxUnlockTime(WEEK // 2, sender=gov) time_passed = chain.pending_timestamp - timestamp # assure the all the amounts is what is originally would have been @@ -2869,7 +2872,7 @@ def test_set_profit_max_period_to_zero__resets_rates( assert vault.profitUnlockingRate() != 0 # update profit max unlock time - vault.set_profit_max_unlock_time(0, sender=gov) + vault.setProfitMaxUnlockTime(0, sender=gov) assert vault.profitMaxUnlockTime() == 0 assert vault.balanceOf(vault.address) == 0 @@ -2924,7 +2927,7 @@ def test_set_profit_max_period_to_zero__doesnt_lock( vault, strategy, _ = initial_set_up(asset, gov, amount, fish) # update profit max unlock time - vault.set_profit_max_unlock_time(0, sender=gov) + vault.setProfitMaxUnlockTime(0, sender=gov) assert vault.profitMaxUnlockTime() == 0 assert vault.balanceOf(vault.address) == 0 @@ -2989,7 +2992,7 @@ def test_set_profit_max_period_to_zero__with_fees_doesnt_lock( ) # update profit max unlock time - vault.set_profit_max_unlock_time(0, sender=gov) + vault.setProfitMaxUnlockTime(0, sender=gov) assert vault.profitMaxUnlockTime() == 0 assert vault.balanceOf(vault.address) == 0 @@ -3068,7 +3071,7 @@ def test_set_profit_max_period_to_zero___report_loss( ) # update profit max unlock time - vault.set_profit_max_unlock_time(0, sender=gov) + vault.setProfitMaxUnlockTime(0, sender=gov) assert vault.profitMaxUnlockTime() == 0 assert vault.balanceOf(vault.address) == 0 diff --git a/tests/unit/vault/test_protocol_fees.py b/tests/unit/vault/test_protocol_fees.py index e231b0af..9dc85135 100644 --- a/tests/unit/vault/test_protocol_fees.py +++ b/tests/unit/vault/test_protocol_fees.py @@ -73,6 +73,7 @@ def test__report_gain_with_protocol_fees__accountant_fees( # Create a profit airdrop_asset(gov, asset, strategy, profit) + strategy.report(sender=gov) expected_accountant_fee = profit * performance_fee / MAX_BPS_ACCOUNTANT expected_protocol_fee = expected_accountant_fee * protocol_fee / MAX_BPS_ACCOUNTANT diff --git a/tests/unit/vault/test_role_base_access.py b/tests/unit/vault/test_role_base_access.py index 9310ec0d..f27877e4 100644 --- a/tests/unit/vault/test_role_base_access.py +++ b/tests/unit/vault/test_role_base_access.py @@ -331,10 +331,10 @@ def test_shutdown_vault__emergency_manager(gov, vault, bunny): assert event[0].account == bunny.address assert event[0].role == ROLES.EMERGENCY_MANAGER - assert vault.shutdown() == False + assert vault.isShutdown() == False tx = vault.shutdown_vault(sender=bunny) - assert vault.shutdown() == True + assert vault.isShutdown() == True event = list(tx.decode_logs(vault.Shutdown)) assert len(event) == 1 # lets ensure that we give the EMERGENCY_MANAGER DEBT_MANAGER permissions after shutdown @@ -374,6 +374,7 @@ def test_process_report__reporting_manager( add_debt_to_strategy(gov, strategy, vault, 2) # airdrop gain to strategy airdrop_asset(gov, asset, strategy, 1) + strategy.report(sender=gov) tx = vault.process_report(strategy.address, sender=bunny) @@ -456,7 +457,7 @@ def test_set_use_default_queue__queue_manager(gov, vault, strategy, bunny): def test_set_profit_unlock__no_profit_unlock_manager__reverts(bunny, vault): with ape.reverts("not allowed"): - vault.set_profit_max_unlock_time(WEEK // 2, sender=bunny) + vault.setProfitMaxUnlockTime(WEEK // 2, sender=bunny) def test_set_profit_unlock__profit_unlock_manager(gov, vault, bunny): @@ -470,7 +471,7 @@ def test_set_profit_unlock__profit_unlock_manager(gov, vault, bunny): time = WEEK // 2 assert vault.profitMaxUnlockTime() != time - vault.set_profit_max_unlock_time(time, sender=bunny) + vault.setProfitMaxUnlockTime(time, sender=bunny) assert vault.profitMaxUnlockTime() == time @@ -487,7 +488,7 @@ def test_set_profit_unlock__to_high__reverts(gov, vault, bunny): current_time = vault.profitMaxUnlockTime() with ape.reverts("profit unlock time too long"): - vault.set_profit_max_unlock_time(time, sender=bunny) + vault.setProfitMaxUnlockTime(time, sender=bunny) assert vault.profitMaxUnlockTime() == current_time diff --git a/tests/unit/vault/test_role_permissioned_access.py b/tests/unit/vault/test_role_permissioned_access.py index 7dff5116..2d0c1971 100644 --- a/tests/unit/vault/test_role_permissioned_access.py +++ b/tests/unit/vault/test_role_permissioned_access.py @@ -236,6 +236,8 @@ def test_process_report__set_reporting_role_open( assert event[0].status == RoleStatusChange.OPENED asset.mint(new_strategy, fish_amount, sender=gov) + new_strategy.report(sender=gov) + tx = vault.process_report(new_strategy, sender=bunny) event = list(tx.decode_logs(vault.StrategyReported)) assert len(event) == 1 @@ -267,6 +269,8 @@ def test_process_report__set_reporting_role_open_then_close__reverts( assert event[0].status == RoleStatusChange.OPENED asset.mint(new_strategy, fish_amount, sender=gov) + new_strategy.report(sender=gov) + tx = vault.process_report(new_strategy, sender=bunny) event = list(tx.decode_logs(vault.StrategyReported)) assert len(event) == 1 @@ -289,7 +293,7 @@ def test_process_report__set_reporting_role_open_then_close__reverts( def test_update_profit_unlock__profit_unlock_role_closed__reverts(vault, bunny): with ape.reverts(): - vault.set_profit_max_unlock_time(WEEK * 2, sender=bunny) + vault.setProfitMaxUnlockTime(WEEK * 2, sender=bunny) def test_update_profit_unlock__set_profit_unlock_role_role_open(vault, bunny, gov): @@ -300,7 +304,7 @@ def test_update_profit_unlock__set_profit_unlock_role_role_open(vault, bunny, go assert event[0].role == ROLES.PROFIT_UNLOCK_MANAGER assert event[0].status == RoleStatusChange.OPENED - tx = vault.set_profit_max_unlock_time(WEEK * 2, sender=bunny) + tx = vault.setProfitMaxUnlockTime(WEEK * 2, sender=bunny) event = list(tx.decode_logs(vault.UpdateProfitMaxUnlockTime)) assert len(event) == 1 assert event[0].profit_max_unlock_time == WEEK * 2 @@ -317,7 +321,7 @@ def test_update_profit_unlock__set_profit_unlock_role_role_open_then_close__reve assert event[0].role == ROLES.PROFIT_UNLOCK_MANAGER assert event[0].status == RoleStatusChange.OPENED - tx = vault.set_profit_max_unlock_time(WEEK * 2, sender=bunny) + tx = vault.setProfitMaxUnlockTime(WEEK * 2, sender=bunny) event = list(tx.decode_logs(vault.UpdateProfitMaxUnlockTime)) assert len(event) == 1 assert event[0].profit_max_unlock_time == WEEK * 2 @@ -330,7 +334,7 @@ def test_update_profit_unlock__set_profit_unlock_role_role_open_then_close__reve assert event[0].status == RoleStatusChange.CLOSED with ape.reverts(): - vault.set_profit_max_unlock_time(WEEK, sender=bunny) + vault.setProfitMaxUnlockTime(WEEK, sender=bunny) # ACCOUNTING MANAGEMENT diff --git a/tests/unit/vault/test_shares.py b/tests/unit/vault/test_shares.py index 36dbb2b1..ff26749f 100644 --- a/tests/unit/vault/test_shares.py +++ b/tests/unit/vault/test_shares.py @@ -457,6 +457,7 @@ def create_profit( # We create a virtual profit initial_debt = vault.strategies(strategy).current_debt asset.transfer(strategy, profit, sender=gov) + strategy.report(sender=gov) tx = vault.process_report(strategy, sender=gov) event = list(tx.decode_logs(vault.StrategyReported)) diff --git a/tests/unit/vault/test_strategy_accounting.py b/tests/unit/vault/test_strategy_accounting.py index 8c375465..0b067e78 100644 --- a/tests/unit/vault/test_strategy_accounting.py +++ b/tests/unit/vault/test_strategy_accounting.py @@ -42,6 +42,8 @@ def test_process_report__with_gain_and_zero_fees( # add debt to strategy add_debt_to_strategy(gov, strategy, vault, new_debt) airdrop_asset(gov, asset, strategy, gain) + # record gain + strategy.report(sender=gov) strategy_params = vault.strategies(strategy.address) initial_debt = strategy_params.current_debt @@ -87,6 +89,8 @@ def test_process_report__with_gain_and_zero_management_fees( add_debt_to_strategy(gov, strategy, vault, new_debt) # airdrop gain to strategy airdrop_asset(gov, asset, strategy, gain) + # record gain + strategy.report(sender=gov) # set up accountant set_fees_for_strategy(gov, strategy, accountant, management_fee, performance_fee) @@ -145,6 +149,8 @@ def test_process_report__with_gain_and_zero_performance_fees( add_debt_to_strategy(gov, strategy, vault, new_debt) # airdrop gain to strategy airdrop_asset(gov, asset, strategy, gain) + # record gain + strategy.report(sender=gov) # set up accountant set_fees_for_strategy(gov, strategy, accountant, management_fee, performance_fee) @@ -202,6 +208,8 @@ def test_process_report__with_gain_and_both_fees( add_debt_to_strategy(gov, strategy, vault, new_debt) # airdrop gain to strategy airdrop_asset(gov, asset, strategy, gain) + # record gain + strategy.report(sender=gov) # set up accountant set_fees_for_strategy(gov, strategy, accountant, management_fee, performance_fee) @@ -256,6 +264,8 @@ def test_process_report__with_fees_exceeding_fee_cap( add_debt_to_strategy(gov, strategy, vault, new_debt) # airdrop gain to strategy airdrop_asset(gov, asset, strategy, gain) + # record gain + strategy.report(sender=gov) # set up accountant set_fees_for_strategy(gov, strategy, accountant, management_fee, performance_fee) diff --git a/tests/unit/vault/test_strategy_withdraw.py b/tests/unit/vault/test_strategy_withdraw.py index 0efe8aa5..c3d3b3ef 100644 --- a/tests/unit/vault/test_strategy_withdraw.py +++ b/tests/unit/vault/test_strategy_withdraw.py @@ -1413,7 +1413,6 @@ def test_withdraw__from_lossy_strategy_with_unrealised_losses_and_max_redeem( assert vault.totalIdle() == 0 assert vault.totalDebt() == amount - amount_to_withdraw assert asset.balanceOf(vault) == 0 - assert asset.balanceOf(lossy_strategy) == amount_to_lock assert lossy_strategy.totalAssets() == amount_to_lock assert asset.balanceOf(strategy) == 0 assert liquid_strategy.totalAssets() == 0 @@ -1510,7 +1509,6 @@ def test_redeem__from_lossy_strategy_with_unrealised_losses_and_max_redeem( assert vault.totalIdle() == 0 assert vault.totalDebt() == amount - amount_to_withdraw assert asset.balanceOf(vault) == 0 - assert asset.balanceOf(lossy_strategy) == amount_to_lock assert lossy_strategy.totalAssets() == amount_to_lock assert asset.balanceOf(strategy) == 0 assert liquid_strategy.totalAssets() == 0 @@ -1793,7 +1791,7 @@ def test_withdraw__half_of_strategy_assets_from_lossy_strategy_with_unrealised_l assert asset.balanceOf(vault) == 0 assert asset.balanceOf(liquid_strategy) == amount_per_strategy assert ( - asset.balanceOf(lossy_strategy) + lossy_strategy.totalAssets() == amount_per_strategy - amount_to_lose - amount_to_lose // 2 ) # withdrawn from strategy assert ( @@ -1994,6 +1992,7 @@ def test_withdraw__with_multiple_liquid_strategies_more_assets_than_debt__withdr airdrop_asset(gov, asset, gov, fish_amount) asset.transfer(first_strategy, profit, sender=gov) + first_strategy.report(sender=gov) tx = vault.withdraw( shares,