Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: 3.0.1 #24

Merged
merged 8 commits into from
Oct 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@
path = lib/openzeppelin-contracts
url = https://github.com/OpenZeppelin/openzeppelin-contracts
branch = v4.8.2
[submodule "lib/yearn-vaults-v3"]
path = lib/yearn-vaults-v3
url = https://github.com/yearn/yearn-vaults-v3
branch = v3.0.0
[submodule "lib/tokenized-strategy"]
path = lib/tokenized-strategy
url = https://github.com/yearn/tokenized-strategy
branch = v3.0.0
branch = v3.0.1
[submodule "lib/yearn-vaults-v3"]
path = lib/yearn-vaults-v3
url = https://github.com/yearn/yearn-vaults-v3
branch = v3.0.1
2 changes: 1 addition & 1 deletion lib/yearn-vaults-v3
Submodule yearn-vaults-v3 updated 37 files
+3 −1 .solhint.json
+4 −1 README.md
+9 −0 SECURITY.md
+41 −23 TECH_SPEC.md
+10 −10 contracts/VaultFactory.vy
+350 −105 contracts/VaultV3.vy
+8 −0 contracts/interfaces/IDeployer.sol
+0 −25 contracts/interfaces/IStrategyERC4626.sol
+241 −3 contracts/interfaces/IVault.sol
+55 −0 contracts/interfaces/IVaultFactory.sol
+32 −0 contracts/interfaces/VaultConstants.sol
+7 −24 contracts/test/ERC4626BaseStrategy.sol
+1 −1 contracts/test/Token.sol
+2 −10 contracts/test/mocks/ERC4626/BaseStrategyMock.sol
+19 −1 contracts/test/mocks/ERC4626/FaultyStrategy.sol
+1 −1 contracts/test/mocks/ERC4626/Generic4626.sol
+1 −8 contracts/test/mocks/ERC4626/LiquidStrategy.sol
+9 −7 contracts/test/mocks/ERC4626/LockedStrategy.sol
+33 −19 contracts/test/mocks/ERC4626/LossyStrategy.sol
+2 −5 contracts/test/mocks/periphery/Accountant.vy
+2 −5 contracts/test/mocks/periphery/FaultyAccountant.vy
+2 −5 contracts/test/mocks/periphery/FlexibleAccountant.vy
+55 −0 contracts/test/mocks/periphery/LimitModule.vy
+1 −1 package.json
+95 −0 scripts/deploy.py
+14 −0 tests/conftest.py
+63 −13 tests/unit/vault/test_buy_debt.py
+109 −25 tests/unit/vault/test_debt_management.py
+51 −6 tests/unit/vault/test_emergency_shutdown.py
+733 −2 tests/unit/vault/test_erc4626.py
+279 −1 tests/unit/vault/test_profit_unlocking.py
+238 −17 tests/unit/vault/test_role_base_access.py
+152 −1 tests/unit/vault/test_role_permissioned_access.py
+7 −7 tests/unit/vault/test_shares.py
+683 −5 tests/unit/vault/test_strategy_withdraw.py
+6 −4 tests/utils/constants.py
+4 −4 yarn.lock
10 changes: 7 additions & 3 deletions script/Deploy.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,29 +6,33 @@ import "forge-std/Script.sol";
// Deploy a contract to a deterministic address with create2
contract Deploy is Script {

Deployer public deployer = Deployer(0x8D85e7c9A4e369E53Acc8d5426aE1568198b0112);

function run() external {
uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY");
vm.startBroadcast(deployerPrivateKey);

// Encode constructor arguments
bytes memory construct = abi.encode();

// Append constructor args to the bytecode
bytes memory bytecode = abi.encodePacked(vm.getCode("CommonReportTrigger.sol:CommonReportTrigger"), construct);

// Pick an unique salt
uint256 salt = uint256(keccak256("v3.0.0"));

address contractAddress = deploy(bytecode, salt);
address contractAddress = deployer.deploy(bytecode, salt);

console.log("Address is ", contractAddress);

vm.stopBroadcast();
}
}

contract Deployer {
event Deployed(address addr, uint256 salt);

function deploy(bytes memory code, uint256 salt) public returns (address) {
function deploy(bytes memory code, uint256 salt) external returns (address) {
address addr;
assembly {
addr := create2(0, add(code, 0x20), mload(code), salt)
Expand Down
46 changes: 0 additions & 46 deletions script/Deploy2.s.sol

This file was deleted.

25 changes: 8 additions & 17 deletions src/AprOracle/AprOracle.sol
Original file line number Diff line number Diff line change
@@ -1,17 +1,8 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.18;

import {IStrategy} from "../interfaces/IStrategy.sol";

interface IVault {
function totalAssets() external view returns (uint256);

function profitUnlockingRate() external view returns (uint256);

function fullProfitUnlockDate() external view returns (uint256);

function convertToAssets(uint256) external view returns (uint256);
}
import {IVault} from "@yearn-vaults/interfaces/IVault.sol";
import {IStrategy} from "@tokenized-strategy/interfaces/IStrategy.sol";

interface IOracle {
function aprAfterDebtChange(
Expand All @@ -30,7 +21,7 @@ interface IOracle {
* based on the current profit unlocking rate. As well as the
* expected APR given some change in totalAssets.
*
* This can also be used to retreive the expexted APR a strategy
* This can also be used to retrieve the expected APR a strategy
* is making, thats yet to be reported, if a strategy specific
* oracle has been added.
*
Expand All @@ -41,7 +32,7 @@ contract AprOracle {
// Mapping of a strategy to its specific apr oracle.
mapping(address => address) public oracles;

// Used to get the Current and Expexted APRS.
// Used to get the Current and Expected APR'S.
uint256 internal constant MAX_BPS_EXTENDED = 1_000_000_000_000;
uint256 internal constant SECONDS_PER_YEAR = 31_556_952;

Expand All @@ -50,15 +41,15 @@ contract AprOracle {
* @dev Will revert if an oracle has not been set for that strategy.
*
* This will be different than the {getExpectedApr()} which returns
* the current APR bassed off of previously reported profits that
* the current APR based off of previously reported profits that
* are currently unlocking.
*
* This will return the APR the stratey is currently earning that
* This will return the APR the strategy is currently earning that
* has yet to be reported.
*
* @param _strategy Address of the strategy to check.
* @param _debtChange Positive or negative change in debt.
* @return . The expected APR it will be earning repersented as 1e18.
* @return . The expected APR it will be earning represented as 1e18.
*/
function getStrategyApr(
address _strategy,
Expand Down Expand Up @@ -122,7 +113,7 @@ contract AprOracle {
* Will return 0 if there is no profit unlocking or no assets.
*
* This can be used to predict the change in current apr given some
* deposit or withdra to the vault.
* deposit or withdraw to the vault.
*
* @param _vault The address of the vault or strategy.
* @param _delta The positive or negative change in `totalAssets`.
Expand Down
4 changes: 2 additions & 2 deletions src/AprOracle/AprOracleBase.sol
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,13 @@ abstract contract AprOracleBase is Governance {

/**
* @notice Will return the expected Apr of a strategy post a debt change.
* @dev _delta is a signed integer so that it can also repersent a debt
* @dev _delta is a signed integer so that it can also represent a debt
* decrease.
*
* _delta will be == 0 to get the current apr.
*
* This will potentially be called during non-view functions so gas
* effeciency should be taken into account.
* efficiency should be taken into account.
*
* @param _strategy The strategy to get the apr for.
* @param _delta The difference in debt.
Expand Down
25 changes: 4 additions & 21 deletions src/HealthCheck/BaseHealthCheck.sol
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.18;

import {BaseTokenizedStrategy} from "@tokenized-strategy/BaseTokenizedStrategy.sol";
import {BaseStrategy, ERC20} from "@tokenized-strategy/BaseStrategy.sol";

/**
* @title Base Health Check
Expand All @@ -22,15 +22,7 @@
* losses, but rather can make sure manual intervention is
* needed before reporting an unexpected loss or profit.
*/
abstract contract BaseHealthCheck is BaseTokenizedStrategy {
// Optional modifier that can be placed on any function
// to perform checks such as debt/PPS before running.
// Must override `_checkHealth()` for this to work.
modifier checkHealth() {
_checkHealth();
_;
}

abstract contract BaseHealthCheck is BaseStrategy {
// Can be used to determine if a healthcheck should be called.
// Defaults to true;
bool public doHealthCheck = true;
Expand All @@ -46,7 +38,7 @@
constructor(
address _asset,
string memory _name
) BaseTokenizedStrategy(_asset, _name) {}
) BaseStrategy(_asset, _name) {}

Check warning on line 41 in src/HealthCheck/BaseHealthCheck.sol

View workflow job for this annotation

GitHub Actions / solidity

Code contains empty blocks

/**
* @notice Returns the current profit limit ratio.
Expand Down Expand Up @@ -117,15 +109,6 @@
doHealthCheck = _doHealthCheck;
}

/**
* @notice Check important invariants for the strategy.
* @dev This can be overriden to check any important strategy
* specific invariants.
*
* NOTE: Should revert if unhealthy for the modifier to work.
*/
function _checkHealth() internal virtual {}

/**
* @dev To be called during a report to make sure the profit
* or loss being recorded is within the acceptable bound.
Expand All @@ -138,7 +121,7 @@
return;
}

// Get the curent total assets from the implementation.
// Get the current total assets from the implementation.
uint256 currentTotalAssets = TokenizedStrategy.totalAssets();

if (_newTotalAssets > currentTotalAssets) {
Expand Down
38 changes: 17 additions & 21 deletions src/ReportTrigger/CommonReportTrigger.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@

import {Governance} from "../utils/Governance.sol";

import {IVault} from "../interfaces/IVault.sol";
import {IStrategy} from "../interfaces/IStrategy.sol";
import {IVault} from "@yearn-vaults/interfaces/IVault.sol";
import {IStrategy} from "@tokenized-strategy/interfaces/IStrategy.sol";

interface ICustomStrategyTrigger {
function reportTrigger(
Expand Down Expand Up @@ -72,7 +72,7 @@

string public name = "Yearn Common Report Trigger";

// Address to retreive the current base fee on the network from.
// Address to retrieve the current base fee on the network from.
address public baseFeeProvider;

// Default base fee the trigger will accept for a trigger to return `true`.
Expand All @@ -88,7 +88,7 @@
// `acceptableBaseFee` will be used.
mapping(address => uint256) public customStrategyBaseFee;

// Mapping of a vault adddress and one of its strategies address to a
// Mapping of a vault address and one of its strategies address to a
// custom report trigger. If address(0) the default trigger will be used.
// vaultAddress => strategyAddress => customTriggerContract.
mapping(address => mapping(address => address)) public customVaultTrigger;
Expand All @@ -99,7 +99,7 @@
// vaultAddress => strategyAddress => customBaseFee.
mapping(address => mapping(address => uint256)) public customVaultBaseFee;

constructor(address _governance) Governance(_governance) {}

Check warning on line 102 in src/ReportTrigger/CommonReportTrigger.sol

View workflow job for this annotation

GitHub Actions / solidity

Code contains empty blocks

/*//////////////////////////////////////////////////////////////
CUSTOM SETTERS
Expand Down Expand Up @@ -227,7 +227,7 @@
* the default trigger flow.
*
* @param _strategy The address of the strategy to check the trigger for.
* @return . Bool repersenting if the strategy is ready to report.
* @return . Bool representing if the strategy is ready to report.
* @return . Bytes with either the calldata or reason why False.
*/
function strategyReportTrigger(
Expand All @@ -246,7 +246,7 @@

/**
* @notice The default trigger logic for a strategy.
* @dev This is kept in a seperate function so it can still
* @dev This is kept in a separate function so it can still
* be used by custom triggers even if extra checks are needed
* first or after.
*
Expand All @@ -261,7 +261,7 @@
* 4. The time since the last report be > the strategies `profitMaxUnlockTime`.
*
* @param _strategy The address of the strategy to check the trigger for.
* @return . Bool repersenting if the strategy is ready to report.
* @return . Bool representing if the strategy is ready to report.
* @return . Bytes with either the calldata or reason why False.
*/
function defaultStrategyReportTrigger(
Expand All @@ -273,7 +273,7 @@
// Don't report if the strategy is shutdown.
if (strategy.isShutdown()) return (false, bytes("Shutdown"));

// Dont't report if the strategy has no assets.
// Don't report if the strategy has no assets.
if (strategy.totalAssets() == 0) return (false, bytes("Zero Assets"));

// Check if a `baseFeeProvider` is set.
Expand All @@ -285,7 +285,7 @@
? customAcceptableBaseFee
: acceptableBaseFee;

// Dont report if the base fee is to high.
// Don't report if the base fee is to high.
if (
IBaseFee(_baseFeeProvider).basefee_global() > _acceptableBaseFee
) return (false, bytes("Base Fee"));
Expand Down Expand Up @@ -329,7 +329,7 @@

/**
* @notice The default trigger logic for a vault.
* @dev This is kept in a seperate function so it can still
* @dev This is kept in a separate function so it can still
* be used by custom triggers even if extra checks are needed
* before or after.
*
Expand Down Expand Up @@ -361,8 +361,8 @@
// Cache the strategy parameters.
IVault.StrategyParams memory params = vault.strategies(_strategy);

// Don't report if the strategy is not acitve or has no funds.
if (params.activation == 0 || params.currentDebt == 0)
// Don't report if the strategy is not active or has no funds.
if (params.activation == 0 || params.current_debt == 0)
return (false, bytes("Not Active"));

// Check if a `baseFeeProvider` is set.
Expand All @@ -376,15 +376,15 @@
? customAcceptableBaseFee
: acceptableBaseFee;

// Dont report if the base fee is to high.
// Don't report if the base fee is to high.
if (
IBaseFee(_baseFeeProvider).basefee_global() > _acceptableBaseFee
) return (false, bytes("Base Fee"));
}

return (
// Return true is the full profit unlock time has passed since the last report.
block.timestamp - params.lastReport > vault.profitMaxUnlockTime(),
block.timestamp - params.last_report > vault.profitMaxUnlockTime(),
// Return the function selector and the strategy as the parameter to use.
abi.encodeCall(vault.process_report, _strategy)
);
Expand All @@ -405,12 +405,8 @@
function strategyTendTrigger(
address _strategy
) external view returns (bool, bytes memory) {
return (
// Return the status of the tend trigger.
IStrategy(_strategy).tendTrigger(),
// And the needed calldata either way.
abi.encodeWithSelector(IStrategy.tend.selector)
);
// Return the status of the tend trigger.
return IStrategy(_strategy).tendTrigger();
}

/**
Expand All @@ -427,7 +423,7 @@

/**
* @notice Returns wether or not the current base fee is acceptable
* baseed on the default `acceptableBaseFee`.
* based on the default `acceptableBaseFee`.
* @dev Can be used in custom triggers to easily still use this contracts
* fee provider and acceptableBaseFee. And makes it backwards compatible to V2.
*
Expand Down
Loading
Loading