diff --git a/.gitmodules b/.gitmodules index ae5ee093..02ccc320 100644 --- a/.gitmodules +++ b/.gitmodules @@ -11,3 +11,9 @@ [submodule "lib/reward-streams"] path = lib/reward-streams url = https://github.com/euler-xyz/reward-streams +[submodule "lib/openzeppelin-contracts-upgradeable"] + path = lib/openzeppelin-contracts-upgradeable + url = https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable +[submodule "lib/openzeppelin-contracts"] + path = lib/openzeppelin-contracts + url = https://github.com/OpenZeppelin/openzeppelin-contracts diff --git a/foundry.toml b/foundry.toml index 518361a2..c1df1e59 100644 --- a/foundry.toml +++ b/foundry.toml @@ -17,6 +17,9 @@ int_types = "long" quote_style = "double" number_underscore = "preserve" override_spacing = true +ignore = [ + "src/lib/StorageLib.sol" +] [profile.test] no_match_test = "Fuzz" diff --git a/lib/openzeppelin-contracts b/lib/openzeppelin-contracts new file mode 160000 index 00000000..dbb6104c --- /dev/null +++ b/lib/openzeppelin-contracts @@ -0,0 +1 @@ +Subproject commit dbb6104ce834628e473d2173bbc9d47f81a9eec3 diff --git a/lib/openzeppelin-contracts-upgradeable b/lib/openzeppelin-contracts-upgradeable new file mode 160000 index 00000000..723f8cab --- /dev/null +++ b/lib/openzeppelin-contracts-upgradeable @@ -0,0 +1 @@ +Subproject commit 723f8cab09cdae1aca9ec9cc1cfa040c2d4b06c1 diff --git a/remappings.txt b/remappings.txt index 1ad598ca..4d63589c 100644 --- a/remappings.txt +++ b/remappings.txt @@ -5,4 +5,5 @@ forge-std/=lib/forge-std/src/ evk/=lib/euler-vault-kit/ reward-streams=lib/reward-streams/src openzeppelin-contracts/=lib/reward-streams/lib/openzeppelin-contracts/contracts -@openzeppelin/=lib/ethereum-vault-connector/lib/openzeppelin-contracts/contracts/ +@openzeppelin/=lib/openzeppelin-contracts/ +@openzeppelin-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/ \ No newline at end of file diff --git a/src/AggregationLayerVault.sol b/src/AggregationLayerVault.sol new file mode 100644 index 00000000..074ac10e --- /dev/null +++ b/src/AggregationLayerVault.sol @@ -0,0 +1,587 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity ^0.8.0; + +// interfaces +import {IERC4626} from "@openzeppelin/contracts/interfaces/IERC4626.sol"; +import {IERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import {IBalanceTracker} from "reward-streams/interfaces/IBalanceTracker.sol"; +import {IFourSixTwoSixAgg} from "./interface/IFourSixTwoSixAgg.sol"; +import {IWithdrawalQueue} from "./interface/IWithdrawalQueue.sol"; +// contracts +import {Dispatch} from "./Dispatch.sol"; +import { + ERC4626Upgradeable, + ERC20Upgradeable +} from "@openzeppelin-upgradeable/token/ERC20/extensions/ERC4626Upgradeable.sol"; +import {AccessControlEnumerableUpgradeable} from + "@openzeppelin-upgradeable/access/extensions/AccessControlEnumerableUpgradeable.sol"; +import {Shared} from "./Shared.sol"; +import {ContextUpgradeable} from "@openzeppelin-upgradeable/utils/ContextUpgradeable.sol"; +// libs +import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; +import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol"; +import {Math} from "@openzeppelin/contracts/utils/math/Math.sol"; +import {StorageLib, AggregationVaultStorage, Strategy} from "./lib/StorageLib.sol"; +import {ErrorsLib} from "./lib/ErrorsLib.sol"; +import {EventsLib} from "./lib/EventsLib.sol"; + +/// @dev Do NOT use with fee on transfer tokens +/// @dev Do NOT use with rebasing tokens +/// @dev inspired by Yearn v3 ❤️ +contract AggregationLayerVault is + ERC4626Upgradeable, + AccessControlEnumerableUpgradeable, + Dispatch, + IFourSixTwoSixAgg +{ + using SafeERC20 for IERC20; + using SafeCast for uint256; + + // Roles + bytes32 public constant ALLOCATIONS_MANAGER = keccak256("ALLOCATIONS_MANAGER"); + bytes32 public constant ALLOCATIONS_MANAGER_ADMIN = keccak256("ALLOCATIONS_MANAGER_ADMIN"); + bytes32 public constant STRATEGY_ADDER = keccak256("STRATEGY_ADDER"); + bytes32 public constant STRATEGY_ADDER_ADMIN = keccak256("STRATEGY_ADDER_ADMIN"); + bytes32 public constant STRATEGY_REMOVER = keccak256("STRATEGY_REMOVER"); + bytes32 public constant STRATEGY_REMOVER_ADMIN = keccak256("STRATEGY_REMOVER_ADMIN"); + bytes32 public constant AGGREGATION_VAULT_MANAGER = keccak256("AGGREGATION_VAULT_MANAGER"); + bytes32 public constant AGGREGATION_VAULT_MANAGER_ADMIN = keccak256("AGGREGATION_VAULT_MANAGER_ADMIN"); + bytes32 public constant REBALANCER = keccak256("REBALANCER"); + bytes32 public constant REBALANCER_ADMIN = keccak256("REBALANCER_ADMIN"); + + /// @dev interest rate smearing period + uint256 public constant INTEREST_SMEAR = 2 weeks; + + /// @dev Euler saving rate struct + /// @dev Based on https://github.com/euler-xyz/euler-vault-kit/blob/master/src/Synths/EulerSavingsRate.sol + /// lastInterestUpdate: last timestamo where interest was updated. + /// interestSmearEnd: timestamp when the smearing of interest end. + /// interestLeft: amount of interest left to smear. + /// locked: if locked or not for update. + struct AggregationVaultSavingRate { + uint40 lastInterestUpdate; + uint40 interestSmearEnd; + uint168 interestLeft; + uint8 locked; + } + + struct InitParams { + address evc; + address balanceTracker; + address withdrawalQueuePeriphery; + address rebalancerPerihpery; + address aggregationVaultOwner; + address asset; + string name; + string symbol; + uint256 initialCashAllocationPoints; + } + + constructor(address _rewardsModule, address _hooksModule, address _feeModule, address _allocationPointsModule) + Dispatch(_rewardsModule, _hooksModule, _feeModule, _allocationPointsModule) + {} + + function init(InitParams calldata _initParams) external initializer { + __ERC4626_init_unchained(IERC20(_initParams.asset)); + __ERC20_init_unchained(_initParams.name, _initParams.symbol); + + if (_initParams.initialCashAllocationPoints == 0) revert ErrorsLib.InitialAllocationPointsZero(); + + AggregationVaultStorage storage $ = StorageLib._getAggregationVaultStorage(); + $.locked = REENTRANCYLOCK__UNLOCKED; + $.withdrawalQueue = _initParams.withdrawalQueuePeriphery; + $.strategies[address(0)] = Strategy({ + allocated: 0, + allocationPoints: _initParams.initialCashAllocationPoints.toUint120(), + active: true, + cap: 0 + }); + $.totalAllocationPoints = _initParams.initialCashAllocationPoints; + $.evc = _initParams.evc; + + _setBalanceTracker(_initParams.balanceTracker); + + // Setup DEFAULT_ADMIN + _grantRole(DEFAULT_ADMIN_ROLE, _initParams.aggregationVaultOwner); + // By default, the Rebalancer contract is assigned the REBALANCER role + _grantRole(REBALANCER, _initParams.rebalancerPerihpery); + + // Setup role admins + _setRoleAdmin(ALLOCATIONS_MANAGER, ALLOCATIONS_MANAGER_ADMIN); + _setRoleAdmin(STRATEGY_ADDER, STRATEGY_ADDER_ADMIN); + _setRoleAdmin(STRATEGY_REMOVER, STRATEGY_REMOVER_ADMIN); + _setRoleAdmin(AGGREGATION_VAULT_MANAGER, AGGREGATION_VAULT_MANAGER_ADMIN); + _setRoleAdmin(REBALANCER, REBALANCER_ADMIN); + } + + /// @notice Set performance fee recipient address + /// @notice @param _newFeeRecipient Recipient address + function setFeeRecipient(address _newFeeRecipient) external onlyRole(AGGREGATION_VAULT_MANAGER) use(MODULE_FEE) {} + + /// @notice Set performance fee (1e18 == 100%) + /// @notice @param _newFee Fee rate + function setPerformanceFee(uint256 _newFee) external onlyRole(AGGREGATION_VAULT_MANAGER) use(MODULE_FEE) {} + + /// @notice Opt in to strategy rewards + /// @param _strategy Strategy address + function optInStrategyRewards(address _strategy) + external + override + onlyRole(AGGREGATION_VAULT_MANAGER) + use(MODULE_REWARDS) + {} + + /// @notice Opt out of strategy rewards + /// @param _strategy Strategy address + function optOutStrategyRewards(address _strategy) + external + override + onlyRole(AGGREGATION_VAULT_MANAGER) + use(MODULE_REWARDS) + {} + + /// @notice Claim a specific strategy rewards + /// @param _strategy Strategy address. + /// @param _reward The address of the reward token. + /// @param _recipient The address to receive the claimed reward tokens. + /// @param _forfeitRecentReward Whether to forfeit the recent rewards and not update the accumulator. + function claimStrategyReward(address _strategy, address _reward, address _recipient, bool _forfeitRecentReward) + external + override + onlyRole(AGGREGATION_VAULT_MANAGER) + use(MODULE_REWARDS) + {} + + /// @notice Enables balance forwarding for sender + /// @dev Should call the IBalanceTracker hook with the current user's balance + function enableBalanceForwarder() external override use(MODULE_REWARDS) {} + + /// @notice Disables balance forwarding for the sender + /// @dev Should call the IBalanceTracker hook with the account's balance of 0 + function disableBalanceForwarder() external override use(MODULE_REWARDS) {} + + /// @notice Adjust a certain strategy's allocation points. + /// @dev Can only be called by an address that have the ALLOCATIONS_MANAGER + /// @param _strategy address of strategy + /// @param _newPoints new strategy's points + function adjustAllocationPoints(address _strategy, uint256 _newPoints) + external + use(MODULE_ALLOCATION_POINTS) + onlyRole(ALLOCATIONS_MANAGER) + {} + + /// @notice Set cap on strategy allocated amount. + /// @dev By default, cap is set to 0, not activated. + /// @param _strategy Strategy address. + /// @param _cap Cap amount + function setStrategyCap(address _strategy, uint256 _cap) + external + use(MODULE_ALLOCATION_POINTS) + onlyRole(ALLOCATIONS_MANAGER) + {} + + /// @notice Add new strategy with it's allocation points. + /// @dev Can only be called by an address that have STRATEGY_ADDER. + /// @param _strategy Address of the strategy + /// @param _allocationPoints Strategy's allocation points + function addStrategy(address _strategy, uint256 _allocationPoints) + external + use(MODULE_ALLOCATION_POINTS) + onlyRole(STRATEGY_ADDER) + {} + + /// @notice Remove strategy and set its allocation points to zero. + /// @dev This function does not pull funds, `harvest()` needs to be called to withdraw + /// @dev Can only be called by an address that have the STRATEGY_REMOVER + /// @param _strategy Address of the strategy + function removeStrategy(address _strategy) external use(MODULE_ALLOCATION_POINTS) onlyRole(STRATEGY_REMOVER) {} + + /// @notice Set hooks contract and hooked functions. + /// @dev This funtion should be overriden to implement access control. + /// @param _hooksTarget Hooks contract. + /// @param _hookedFns Hooked functions. + function setHooksConfig(address _hooksTarget, uint32 _hookedFns) + external + override + onlyRole(AGGREGATION_VAULT_MANAGER) + use(MODULE_HOOKS) + {} + + /// @notice Harvest strategy. + /// @param strategy address of strategy + function harvest(address strategy) external { + _harvest(strategy); + + _gulp(); + } + + /// @notice Harvest multiple strategies. + /// @param _strategies an array of strategy addresses. + function harvestMultipleStrategies(address[] calldata _strategies) external nonReentrant { + for (uint256 i; i < _strategies.length; ++i) { + _harvest(_strategies[i]); + } + _gulp(); + } + + function rebalance(address _strategy, uint256 _amountToRebalance, bool _isDeposit) + external + nonReentrant + onlyRole(REBALANCER) + { + AggregationVaultStorage storage $ = StorageLib._getAggregationVaultStorage(); + + Strategy memory strategyData = $.strategies[_strategy]; + + if (_isDeposit) { + // Do required approval (safely) and deposit + IERC20(asset()).safeIncreaseAllowance(_strategy, _amountToRebalance); + IERC4626(_strategy).deposit(_amountToRebalance, address(this)); + $.strategies[_strategy].allocated = uint120(strategyData.allocated + _amountToRebalance); + $.totalAllocated += _amountToRebalance; + } else { + IERC4626(_strategy).withdraw(_amountToRebalance, address(this), address(this)); + $.strategies[_strategy].allocated = (strategyData.allocated - _amountToRebalance).toUint120(); + $.totalAllocated -= _amountToRebalance; + } + + emit EventsLib.Rebalance(_strategy, _amountToRebalance, _isDeposit); + } + + /// @notice update accrued interest + function updateInterestAccrued() external { + return _updateInterestAccrued(); + } + + /// @notice gulp positive harvest yield + function gulp() external nonReentrant { + _gulp(); + } + + /// @notice Execute a withdraw from a strategy. + /// @dev Can only be called from the WithdrawalQueue contract. + /// @param _strategy Strategy's address. + /// @param _withdrawAmount Amount to withdraw. + function executeStrategyWithdraw(address _strategy, uint256 _withdrawAmount) external { + _isCallerWithdrawalQueue(); + + AggregationVaultStorage storage $ = StorageLib._getAggregationVaultStorage(); + + // Update allocated assets + $.strategies[_strategy].allocated -= uint120(_withdrawAmount); + $.totalAllocated -= _withdrawAmount; + + // Do actual withdraw from strategy + IERC4626(_strategy).withdraw(_withdrawAmount, address(this), address(this)); + } + + /// @notice Execute a withdraw from the AggregationVault + /// @dev This function should be called and can only be called by the WithdrawalQueue. + /// @param caller Withdraw call initiator. + /// @param receiver Receiver of the withdrawn asset. + /// @param owner Owner of shares to withdraw against. + /// @param assets Amount of asset to withdraw. + /// @param shares Amount of shares to withdraw against. + function executeAggregationVaultWithdraw( + address caller, + address receiver, + address owner, + uint256 assets, + uint256 shares + ) external { + _isCallerWithdrawalQueue(); + + AggregationVaultStorage storage $ = StorageLib._getAggregationVaultStorage(); + $.totalAssetsDeposited -= assets; + + super._withdraw(caller, receiver, owner, assets, shares); + + _gulp(); + } + + /// @notice Get strategy params. + /// @param _strategy strategy's address + /// @return Strategy struct + function getStrategy(address _strategy) external view returns (Strategy memory) { + AggregationVaultStorage storage $ = StorageLib._getAggregationVaultStorage(); + + return $.strategies[_strategy]; + } + + /// @notice Return the accrued interest + /// @return uint256 accrued interest + function interestAccrued() external view returns (uint256) { + return _interestAccruedFromCache(); + } + + function getAggregationVaultSavingRate() external view returns (AggregationVaultSavingRate memory) { + AggregationVaultStorage storage $ = StorageLib._getAggregationVaultStorage(); + AggregationVaultSavingRate memory avsr = AggregationVaultSavingRate({ + lastInterestUpdate: $.lastInterestUpdate, + interestSmearEnd: $.interestSmearEnd, + interestLeft: $.interestLeft, + locked: $.locked + }); + + return avsr; + } + + function totalAllocated() external view returns (uint256) { + AggregationVaultStorage storage $ = StorageLib._getAggregationVaultStorage(); + + return $.totalAllocated; + } + + function totalAllocationPoints() external view returns (uint256) { + AggregationVaultStorage storage $ = StorageLib._getAggregationVaultStorage(); + + return $.totalAllocationPoints; + } + + function totalAssetsDeposited() external view returns (uint256) { + AggregationVaultStorage storage $ = StorageLib._getAggregationVaultStorage(); + + return $.totalAssetsDeposited; + } + + function withdrawalQueue() external view returns (address) { + AggregationVaultStorage storage $ = StorageLib._getAggregationVaultStorage(); + + return $.withdrawalQueue; + } + + function performanceFeeConfig() external view returns (address, uint256) { + AggregationVaultStorage storage $ = StorageLib._getAggregationVaultStorage(); + + return ($.feeRecipient, $.performanceFee); + } + + /// @dev See {IERC4626-deposit}. + function deposit(uint256 assets, address receiver) public override nonReentrant returns (uint256) { + return super.deposit(assets, receiver); + } + + /// @dev See {IERC4626-mint}. + function mint(uint256 shares, address receiver) public override nonReentrant returns (uint256) { + return super.mint(shares, receiver); + } + + /// @dev See {IERC4626-withdraw}. + /// @dev this function update the accrued interest + function withdraw(uint256 assets, address receiver, address owner) + public + override + nonReentrant + returns (uint256 shares) + { + // Move interest to totalAssetsDeposited + _updateInterestAccrued(); + return super.withdraw(assets, receiver, owner); + } + + /// @dev See {IERC4626-redeem}. + /// @dev this function update the accrued interest + function redeem(uint256 shares, address receiver, address owner) + public + override + nonReentrant + returns (uint256 assets) + { + // Move interest to totalAssetsDeposited + _updateInterestAccrued(); + return super.redeem(shares, receiver, owner); + } + + /// @notice Return the total amount of assets deposited, plus the accrued interest. + /// @return uint256 total amount + function totalAssets() public view override returns (uint256) { + AggregationVaultStorage storage $ = StorageLib._getAggregationVaultStorage(); + + return $.totalAssetsDeposited + _interestAccruedFromCache(); + } + + /// @notice get the total assets allocatable + /// @dev the total assets allocatable is the amount of assets deposited into the aggregator + assets already deposited into strategies + /// @return uint256 total assets + function totalAssetsAllocatable() public view returns (uint256) { + AggregationVaultStorage storage $ = StorageLib._getAggregationVaultStorage(); + + return IERC20(asset()).balanceOf(address(this)) + $.totalAllocated; + } + + /// @dev Increate the total assets deposited, and call IERC4626._deposit() + /// @dev See {IERC4626-_deposit}. + function _deposit(address caller, address receiver, uint256 assets, uint256 shares) internal override { + _callHooksTarget(DEPOSIT, caller); + + AggregationVaultStorage storage $ = StorageLib._getAggregationVaultStorage(); + + $.totalAssetsDeposited += assets; + + super._deposit(caller, receiver, assets, shares); + } + + /// @dev Withdraw asset back to the user. + /// @dev See {IERC4626-_withdraw}. + /// @dev if the cash reserve can not cover the amount to withdraw, this function will loop through the strategies + /// to cover the remaining amount. This function will revert if the amount to withdraw is not available + function _withdraw(address caller, address receiver, address owner, uint256 assets, uint256 shares) + internal + override + { + _callHooksTarget(WITHDRAW, caller); + + AggregationVaultStorage storage $ = StorageLib._getAggregationVaultStorage(); + + uint256 assetsRetrieved = IERC20(asset()).balanceOf(address(this)); + + IWithdrawalQueue($.withdrawalQueue).callWithdrawalQueue( + caller, receiver, owner, assets, shares, assetsRetrieved + ); + } + + /// @notice update accrued interest. + function _updateInterestAccrued() internal { + uint256 accruedInterest = _interestAccruedFromCache(); + + AggregationVaultStorage storage $ = StorageLib._getAggregationVaultStorage(); + // it's safe to down-cast because the accrued interest is a fraction of interest left + $.interestLeft -= uint168(accruedInterest); + $.lastInterestUpdate = uint40(block.timestamp); + + // Move interest accrued to totalAssetsDeposited + $.totalAssetsDeposited += accruedInterest; + } + + /// @dev gulp positive yield and increment the left interest + function _gulp() internal { + _updateInterestAccrued(); + + AggregationVaultStorage storage $ = StorageLib._getAggregationVaultStorage(); + + if ($.totalAssetsDeposited == 0) return; + uint256 toGulp = totalAssetsAllocatable() - $.totalAssetsDeposited - $.interestLeft; + + if (toGulp == 0) return; + + uint256 maxGulp = type(uint168).max - $.interestLeft; + if (toGulp > maxGulp) toGulp = maxGulp; // cap interest, allowing the vault to function + + $.interestSmearEnd = uint40(block.timestamp + INTEREST_SMEAR); + $.interestLeft += uint168(toGulp); // toGulp <= maxGulp <= max uint168 + + emit EventsLib.Gulp($.interestLeft, $.interestSmearEnd); + } + + function _harvest(address _strategy) internal { + AggregationVaultStorage storage $ = StorageLib._getAggregationVaultStorage(); + + uint120 strategyAllocatedAmount = $.strategies[_strategy].allocated; + + if (strategyAllocatedAmount == 0) return; + + uint256 underlyingBalance = IERC4626(_strategy).maxWithdraw(address(this)); + + if (underlyingBalance == strategyAllocatedAmount) { + return; + } else if (underlyingBalance > strategyAllocatedAmount) { + // There's yield! + uint256 yield = underlyingBalance - strategyAllocatedAmount; + uint120 accruedPerformanceFee = _accruePerformanceFee(_strategy, yield); + + if (accruedPerformanceFee > 0) { + underlyingBalance -= accruedPerformanceFee; + yield -= accruedPerformanceFee; + } + + $.strategies[_strategy].allocated = uint120(underlyingBalance); + $.totalAllocated += yield; + } else { + uint256 loss = strategyAllocatedAmount - underlyingBalance; + + $.strategies[_strategy].allocated = uint120(underlyingBalance); + $.totalAllocated -= loss; + + if ($.interestLeft >= loss) { + $.interestLeft -= uint168(loss); + } else { + $.totalAssetsDeposited -= loss - $.interestLeft; + $.interestLeft = 0; + } + } + + emit EventsLib.Harvest(_strategy, underlyingBalance, strategyAllocatedAmount); + } + + function _accruePerformanceFee(address _strategy, uint256 _yield) internal returns (uint120) { + AggregationVaultStorage storage $ = StorageLib._getAggregationVaultStorage(); + + address cachedFeeRecipient = $.feeRecipient; + uint256 cachedPerformanceFee = $.performanceFee; + + if (cachedFeeRecipient == address(0) || cachedPerformanceFee == 0) return 0; + + // `feeAssets` will be rounded down to 0 if `yield * performanceFee < 1e18`. + uint256 feeAssets = Math.mulDiv(_yield, cachedPerformanceFee, 1e18, Math.Rounding.Floor); + + if (feeAssets > 0) { + IERC4626(_strategy).withdraw(feeAssets, cachedFeeRecipient, address(this)); + } + + emit EventsLib.AccruePerformanceFee(cachedFeeRecipient, _yield, feeAssets); + + return feeAssets.toUint120(); + } + + /// @dev Override _afterTokenTransfer hook to call IBalanceTracker.balanceTrackerHook() + /// @dev Calling .balanceTrackerHook() passing the address total balance + /// @param from Address sending the amount + /// @param to Address receiving the amount + function _update(address from, address to, uint256 value) internal override { + super._update(from, to, value); + + if (from == to) return; + + IBalanceTracker balanceTracker = IBalanceTracker(_balanceTrackerAddress()); + + if ((from != address(0)) && (_balanceForwarderEnabled(from))) { + balanceTracker.balanceTrackerHook(from, super.balanceOf(from), false); + } + + if ((to != address(0)) && (_balanceForwarderEnabled(to))) { + balanceTracker.balanceTrackerHook(to, super.balanceOf(to), false); + } + } + + /// @dev Get accrued interest without updating it. + /// @return uint256 accrued interest + function _interestAccruedFromCache() internal view returns (uint256) { + AggregationVaultStorage storage $ = StorageLib._getAggregationVaultStorage(); + + // If distribution ended, full amount is accrued + if (block.timestamp >= $.interestSmearEnd) { + return $.interestLeft; + } + + // If just updated return 0 + if ($.lastInterestUpdate == block.timestamp) { + return 0; + } + + // Else return what has accrued + uint256 totalDuration = $.interestSmearEnd - $.lastInterestUpdate; + uint256 timePassed = block.timestamp - $.lastInterestUpdate; + + return $.interestLeft * timePassed / totalDuration; + } + + function _msgSender() internal view override (ContextUpgradeable, Shared) returns (address) { + return Shared._msgSender(); + } + + function _isCallerWithdrawalQueue() internal view { + AggregationVaultStorage storage $ = StorageLib._getAggregationVaultStorage(); + + if (_msgSender() != $.withdrawalQueue) revert ErrorsLib.NotWithdrawaQueue(); + } +} diff --git a/src/AggregationLayerVaultFactory.sol b/src/AggregationLayerVaultFactory.sol new file mode 100644 index 00000000..fa22c4c0 --- /dev/null +++ b/src/AggregationLayerVaultFactory.sol @@ -0,0 +1,85 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity ^0.8.0; + +import {Clones} from "@openzeppelin/contracts/proxy/Clones.sol"; +// core modules +import {Rewards} from "./module/Rewards.sol"; +import {Hooks} from "./module/Hooks.sol"; +import {Fee} from "./module/Fee.sol"; +// core plugins +import {WithdrawalQueue} from "./plugin/WithdrawalQueue.sol"; +import {AggregationLayerVault} from "./AggregationLayerVault.sol"; + +contract AggregationLayerVaultFactory { + /// core dependencies + address public immutable evc; + address public immutable balanceTracker; + /// core modules + address public immutable rewardsModuleImpl; + address public immutable hooksModuleImpl; + address public immutable feeModuleImpl; + address public immutable allocationpointsModuleImpl; + /// plugins + /// @dev Rebalancer periphery, one instance can serve different aggregation vaults + address public immutable rebalancerAddr; + /// @dev Withdrawal queue perihperhy, need to be deployed per aggregation vault + address public immutable withdrawalQueueAddr; + + constructor( + address _evc, + address _balanceTracker, + address _rewardsModuleImpl, + address _hooksModuleImpl, + address _feeModuleImpl, + address _allocationpointsModuleImpl, + address _rebalancerAddr, + address _withdrawalQueueAddr + ) { + evc = _evc; + balanceTracker = _balanceTracker; + rewardsModuleImpl = _rewardsModuleImpl; + hooksModuleImpl = _hooksModuleImpl; + feeModuleImpl = _feeModuleImpl; + allocationpointsModuleImpl = _allocationpointsModuleImpl; + + rebalancerAddr = _rebalancerAddr; + withdrawalQueueAddr = _withdrawalQueueAddr; + } + + function deployEulerAggregationLayer( + address _asset, + string memory _name, + string memory _symbol, + uint256 _initialCashAllocationPoints + ) external returns (address) { + // cloning core modules + address rewardsModuleAddr = Clones.clone(rewardsModuleImpl); + address hooksModuleAddr = Clones.clone(hooksModuleImpl); + address feeModuleAddr = Clones.clone(feeModuleImpl); + address allocationpointsModuleAddr = Clones.clone(allocationpointsModuleImpl); + + // cloning plugins + WithdrawalQueue withdrawalQueue = WithdrawalQueue(Clones.clone(withdrawalQueueAddr)); + + // deploy new aggregation vault + AggregationLayerVault aggregationLayerVault = + new AggregationLayerVault(rewardsModuleAddr, hooksModuleAddr, feeModuleAddr, allocationpointsModuleAddr); + + AggregationLayerVault.InitParams memory aggregationVaultInitParams = AggregationLayerVault.InitParams({ + evc: evc, + balanceTracker: balanceTracker, + withdrawalQueuePeriphery: address(withdrawalQueue), + rebalancerPerihpery: rebalancerAddr, + aggregationVaultOwner: msg.sender, + asset: _asset, + name: _name, + symbol: _symbol, + initialCashAllocationPoints: _initialCashAllocationPoints + }); + + withdrawalQueue.init(msg.sender, address(aggregationLayerVault)); + aggregationLayerVault.init(aggregationVaultInitParams); + + return address(aggregationLayerVault); + } +} diff --git a/src/BalanceForwarder.sol b/src/BalanceForwarder.sol deleted file mode 100644 index 1ceac9c6..00000000 --- a/src/BalanceForwarder.sol +++ /dev/null @@ -1,72 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity ^0.8.0; - -import {IBalanceForwarder} from "./interface/IBalanceForwarder.sol"; -import {IBalanceTracker} from "reward-streams/interfaces/IBalanceTracker.sol"; - -/// @title BalanceForwarder contract -/// @custom:security-contact security@euler.xyz -/// @author Euler Labs (https://www.eulerlabs.com/) -/// @notice A generic contract to integrate with https://github.com/euler-xyz/reward-streams -abstract contract BalanceForwarder is IBalanceForwarder { - error NotSupported(); - error AlreadyEnabled(); - error AlreadyDisabled(); - - IBalanceTracker public immutable balanceTracker; - - mapping(address => bool) internal isBalanceForwarderEnabled; - - event EnableBalanceForwarder(address indexed _user); - event DisableBalanceForwarder(address indexed _user); - - constructor(address _balanceTracker) { - balanceTracker = IBalanceTracker(_balanceTracker); - } - - /// @notice Enables balance forwarding for the authenticated account - /// @dev Only the authenticated account can enable balance forwarding for itself - /// @dev Should call the IBalanceTracker hook with the current account's balance - function enableBalanceForwarder() external virtual; - - /// @notice Disables balance forwarding for the authenticated account - /// @dev Only the authenticated account can disable balance forwarding for itself - /// @dev Should call the IBalanceTracker hook with the account's balance of 0 - function disableBalanceForwarder() external virtual; - - /// @notice Retrieve the address of rewards contract, tracking changes in account's balances - /// @return The balance tracker address - function balanceTrackerAddress() external view returns (address) { - return address(balanceTracker); - } - - /// @notice Retrieves boolean indicating if the account opted in to forward balance changes to the rewards contract - /// @param _account Address to query - /// @return True if balance forwarder is enabled - function balanceForwarderEnabled(address _account) external view returns (bool) { - return isBalanceForwarderEnabled[_account]; - } - - function _enableBalanceForwarder(address _sender, uint256 _senderBalance) internal { - if (address(balanceTracker) == address(0)) revert NotSupported(); - if (isBalanceForwarderEnabled[_sender]) revert AlreadyEnabled(); - - isBalanceForwarderEnabled[_sender] = true; - balanceTracker.balanceTrackerHook(_sender, _senderBalance, false); - - emit EnableBalanceForwarder(_sender); - } - - /// @notice Disables balance forwarding for the authenticated account - /// @dev Only the authenticated account can disable balance forwarding for itself - /// @dev Should call the IBalanceTracker hook with the account's balance of 0 - function _disableBalanceForwarder(address _sender) internal { - if (address(balanceTracker) == address(0)) revert NotSupported(); - if (!isBalanceForwarderEnabled[_sender]) revert AlreadyDisabled(); - - isBalanceForwarderEnabled[_sender] = false; - balanceTracker.balanceTrackerHook(_sender, 0, false); - - emit DisableBalanceForwarder(_sender); - } -} diff --git a/src/Dispatch.sol b/src/Dispatch.sol new file mode 100644 index 00000000..465c43d9 --- /dev/null +++ b/src/Dispatch.sol @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity ^0.8.0; + +//contracts +import {Shared} from "./Shared.sol"; +import {HooksModule} from "./module/Hooks.sol"; +import {RewardsModule} from "./module/Rewards.sol"; + +abstract contract Dispatch is RewardsModule, HooksModule { + address public immutable MODULE_REWARDS; + address public immutable MODULE_HOOKS; + address public immutable MODULE_FEE; + address public immutable MODULE_ALLOCATION_POINTS; + + constructor(address _rewardsModule, address _hooksModule, address _feeModule, address _allocationPointsModule) + Shared() + { + MODULE_REWARDS = _rewardsModule; + MODULE_HOOKS = _hooksModule; + MODULE_FEE = _feeModule; + MODULE_ALLOCATION_POINTS = _allocationPointsModule; + } + + // Modifier proxies the function call to a module and low-level returns the result + modifier use(address module) { + _; // when using the modifier, it is assumed the function body is empty. + delegateToModule(module); + } + + function delegateToModule(address module) private { + assembly { + calldatacopy(0, 0, calldatasize()) + let result := delegatecall(gas(), module, 0, calldatasize(), 0, 0) + returndatacopy(0, 0, returndatasize()) + switch result + case 0 { revert(0, returndatasize()) } + default { return(0, returndatasize()) } + } + } +} diff --git a/src/FourSixTwoSixAgg.sol b/src/FourSixTwoSixAgg.sol deleted file mode 100644 index adc22130..00000000 --- a/src/FourSixTwoSixAgg.sol +++ /dev/null @@ -1,702 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity ^0.8.0; - -// external dep -import {Context} from "@openzeppelin/utils/Context.sol"; -import {ERC20, IERC20} from "@openzeppelin/token/ERC20/ERC20.sol"; -import {SafeERC20} from "@openzeppelin/token/ERC20/utils/SafeERC20.sol"; -import {ERC4626, IERC4626, Math} from "@openzeppelin/token/ERC20/extensions/ERC4626.sol"; -import {AccessControlEnumerable} from "@openzeppelin/access/AccessControlEnumerable.sol"; -import {SafeCast} from "@openzeppelin/utils/math/SafeCast.sol"; -import {EVCUtil} from "ethereum-vault-connector/utils/EVCUtil.sol"; -import {IRewardStreams} from "reward-streams/interfaces/IRewardStreams.sol"; -// internal dep -import {Hooks} from "./Hooks.sol"; -import {IFourSixTwoSixAgg} from "./interface/IFourSixTwoSixAgg.sol"; -import {BalanceForwarder, IBalanceForwarder} from "./BalanceForwarder.sol"; - -/// @dev Do NOT use with fee on transfer tokens -/// @dev Do NOT use with rebasing tokens -/// @dev Based on https://github.com/euler-xyz/euler-vault-kit/blob/master/src/Synths/EulerSavingsRate.sol -/// @dev inspired by Yearn v3 ❤️ -contract FourSixTwoSixAgg is IFourSixTwoSixAgg, BalanceForwarder, EVCUtil, ERC4626, AccessControlEnumerable, Hooks { - using SafeERC20 for IERC20; - using SafeCast for uint256; - - error Reentrancy(); - error ArrayLengthMismatch(); - error InitialAllocationPointsZero(); - error NotEnoughAssets(); - error NegativeYield(); - error InactiveStrategy(); - error OutOfBounds(); - error SameIndexes(); - error InvalidStrategyAsset(); - error StrategyAlreadyExist(); - error AlreadyRemoved(); - error PerformanceFeeAlreadySet(); - error MaxPerformanceFeeExceeded(); - error FeeRecipientNotSet(); - error FeeRecipientAlreadySet(); - error CanNotRemoveCashReserve(); - error DuplicateInitialStrategy(); - - uint8 internal constant REENTRANCYLOCK__UNLOCKED = 1; - uint8 internal constant REENTRANCYLOCK__LOCKED = 2; - - // Roles - bytes32 public constant STRATEGY_MANAGER = keccak256("STRATEGY_MANAGER"); - bytes32 public constant STRATEGY_MANAGER_ADMIN = keccak256("STRATEGY_MANAGER_ADMIN"); - bytes32 public constant WITHDRAW_QUEUE_MANAGER = keccak256("WITHDRAW_QUEUE_MANAGER"); - bytes32 public constant WITHDRAW_QUEUE_MANAGER_ADMIN = keccak256("WITHDRAW_QUEUE_MANAGER_ADMIN"); - bytes32 public constant STRATEGY_ADDER = keccak256("STRATEGY_ADDER"); - bytes32 public constant STRATEGY_ADDER_ADMIN = keccak256("STRATEGY_ADDER_ADMIN"); - bytes32 public constant STRATEGY_REMOVER = keccak256("STRATEGY_REMOVER"); - bytes32 public constant STRATEGY_REMOVER_ADMIN = keccak256("STRATEGY_REMOVER_ADMIN"); - bytes32 public constant MANAGER = keccak256("MANAGER"); - bytes32 public constant MANAGER_ADMIN = keccak256("MANAGER_ADMIN"); - bytes32 public constant REBALANCER = keccak256("REBALANCER"); - bytes32 public constant REBALANCER_ADMIN = keccak256("REBALANCER_ADMIN"); - - /// @dev The maximum performanceFee the vault can have is 50% - uint256 internal constant MAX_PERFORMANCE_FEE = 0.5e18; - uint256 public constant INTEREST_SMEAR = 2 weeks; - - /// @dev store the interest rate smearing params - ESR internal esrSlot; - - /// @dev Total amount of _asset deposited into FourSixTwoSixAgg contract - uint256 public totalAssetsDeposited; - /// @dev Total amount of _asset deposited across all strategies. - uint256 public totalAllocated; - /// @dev Total amount of allocation points across all strategies including the cash reserve. - uint256 public totalAllocationPoints; - /// @dev fee rate - uint256 public performanceFee; - /// @dev fee recipient address - address public feeRecipient; - - /// @dev An array of strategy addresses to withdraw from - address[] public withdrawalQueue; - - /// @dev Mapping between strategy address and it's allocation config - mapping(address => Strategy) internal strategies; - - /// @dev Euler saving rate struct - /// lastInterestUpdate: last timestamo where interest was updated. - /// interestSmearEnd: timestamp when the smearing of interest end. - /// interestLeft: amount of interest left to smear. - /// locked: if locked or not for update. - struct ESR { - uint40 lastInterestUpdate; - uint40 interestSmearEnd; - uint168 interestLeft; - uint8 locked; - } - - event SetFeeRecipient(address indexed oldRecipient, address indexed newRecipient); - event SetPerformanceFee(uint256 oldFee, uint256 newFee); - event OptInStrategyRewards(address indexed strategy); - event OptOutStrategyRewards(address indexed strategy); - event Gulp(uint256 interestLeft, uint256 interestSmearEnd); - event Harvest(address indexed strategy, uint256 strategyBalanceAmount, uint256 strategyAllocatedAmount); - event AdjustAllocationPoints(address indexed strategy, uint256 oldPoints, uint256 newPoints); - event ReorderWithdrawalQueue(uint8 index1, uint8 index2); - event AddStrategy(address indexed strategy, uint256 allocationPoints); - event RemoveStrategy(address indexed _strategy); - event AccruePerformanceFee(address indexed feeRecipient, uint256 yield, uint256 feeAssets); - event SetStrategyCap(address indexed strategy, uint256 cap); - event Rebalance(address indexed strategy, uint256 _amountToRebalance, bool _isDeposit); - - /// @dev Non reentrancy modifier for interest rate updates - modifier nonReentrant() { - if (esrSlot.locked == REENTRANCYLOCK__LOCKED) revert Reentrancy(); - - esrSlot.locked = REENTRANCYLOCK__LOCKED; - _; - esrSlot.locked = REENTRANCYLOCK__UNLOCKED; - } - - /// @dev Constructor - /// @param _evc EVC address - /// @param _asset Aggregator's asset address - /// @param _name Aggregator's name - /// @param _symbol Aggregator's symbol - /// @param _initialCashAllocationPoints Initial points to be allocated to the cash reserve - /// @param _initialStrategies An array of initial strategies addresses - /// @param _initialStrategiesAllocationPoints An array of initial strategies allocation points - constructor( - address _evc, - address _balanceTracker, - address _asset, - string memory _name, - string memory _symbol, - uint256 _initialCashAllocationPoints, - address[] memory _initialStrategies, - uint256[] memory _initialStrategiesAllocationPoints - ) BalanceForwarder(_balanceTracker) EVCUtil(_evc) ERC4626(IERC20(_asset)) ERC20(_name, _symbol) { - esrSlot.locked = REENTRANCYLOCK__UNLOCKED; - - if (_initialStrategies.length != _initialStrategiesAllocationPoints.length) revert ArrayLengthMismatch(); - if (_initialCashAllocationPoints == 0) revert InitialAllocationPointsZero(); - - strategies[address(0)] = - Strategy({allocated: 0, allocationPoints: _initialCashAllocationPoints.toUint120(), active: true, cap: 0}); - - uint256 cachedTotalAllocationPoints = _initialCashAllocationPoints; - - for (uint256 i; i < _initialStrategies.length; ++i) { - if (IERC4626(_initialStrategies[i]).asset() != asset()) { - revert InvalidStrategyAsset(); - } - - if (strategies[_initialStrategies[i]].active) revert DuplicateInitialStrategy(); - - strategies[_initialStrategies[i]] = Strategy({ - allocated: 0, - allocationPoints: _initialStrategiesAllocationPoints[i].toUint120(), - active: true, - cap: 0 - }); - - cachedTotalAllocationPoints += _initialStrategiesAllocationPoints[i]; - withdrawalQueue.push(_initialStrategies[i]); - } - totalAllocationPoints = cachedTotalAllocationPoints; - - // Setup DEFAULT_ADMIN - _grantRole(DEFAULT_ADMIN_ROLE, _msgSender()); - - // Setup role admins - _setRoleAdmin(STRATEGY_MANAGER, STRATEGY_MANAGER_ADMIN); - _setRoleAdmin(WITHDRAW_QUEUE_MANAGER, WITHDRAW_QUEUE_MANAGER_ADMIN); - _setRoleAdmin(STRATEGY_ADDER, STRATEGY_ADDER_ADMIN); - _setRoleAdmin(STRATEGY_REMOVER, STRATEGY_REMOVER_ADMIN); - _setRoleAdmin(MANAGER, MANAGER_ADMIN); - } - - /// @notice Set performance fee recipient address - /// @notice @param _newFeeRecipient Recipient address - function setFeeRecipient(address _newFeeRecipient) external onlyRole(MANAGER) { - if (_newFeeRecipient == feeRecipient) revert FeeRecipientAlreadySet(); - - emit SetFeeRecipient(feeRecipient, _newFeeRecipient); - - feeRecipient = _newFeeRecipient; - } - - /// @notice Set performance fee (1e18 == 100%) - /// @notice @param _newFee Fee rate - function setPerformanceFee(uint256 _newFee) external onlyRole(MANAGER) { - if (_newFee > MAX_PERFORMANCE_FEE) revert MaxPerformanceFeeExceeded(); - if (feeRecipient == address(0)) revert FeeRecipientNotSet(); - if (_newFee == performanceFee) revert PerformanceFeeAlreadySet(); - - emit SetPerformanceFee(performanceFee, _newFee); - - performanceFee = _newFee; - } - - /// @notice Opt in to strategy rewards - /// @param _strategy Strategy address - function optInStrategyRewards(address _strategy) external onlyRole(MANAGER) nonReentrant { - if (!strategies[_strategy].active) revert InactiveStrategy(); - - IBalanceForwarder(_strategy).enableBalanceForwarder(); - - emit OptInStrategyRewards(_strategy); - } - - /// @notice Opt out of strategy rewards - /// @param _strategy Strategy address - function optOutStrategyRewards(address _strategy) external onlyRole(MANAGER) nonReentrant { - IBalanceForwarder(_strategy).disableBalanceForwarder(); - - emit OptOutStrategyRewards(_strategy); - } - - /// @notice Claim a specific strategy rewards - /// @param _strategy Strategy address. - /// @param _reward The address of the reward token. - /// @param _recipient The address to receive the claimed reward tokens. - /// @param _forfeitRecentReward Whether to forfeit the recent rewards and not update the accumulator. - function claimStrategyReward(address _strategy, address _reward, address _recipient, bool _forfeitRecentReward) - external - onlyRole(MANAGER) - nonReentrant - { - address rewardStreams = IBalanceForwarder(_strategy).balanceTrackerAddress(); - - IRewardStreams(rewardStreams).claimReward(_strategy, _reward, _recipient, _forfeitRecentReward); - } - - /// @notice Enables balance forwarding for sender - /// @dev Should call the IBalanceTracker hook with the current user's balance - function enableBalanceForwarder() external override nonReentrant { - address user = _msgSender(); - uint256 userBalance = this.balanceOf(user); - - _enableBalanceForwarder(user, userBalance); - } - - /// @notice Disables balance forwarding for the sender - /// @dev Should call the IBalanceTracker hook with the account's balance of 0 - function disableBalanceForwarder() external override nonReentrant { - _disableBalanceForwarder(_msgSender()); - } - - /// @notice Harvest strategy. - /// @param strategy address of strategy - function harvest(address strategy) external nonReentrant { - _harvest(strategy); - - _gulp(); - } - - /// @notice Harvest multiple strategies. - /// @param _strategies an array of strategy addresses. - function harvestMultipleStrategies(address[] calldata _strategies) external nonReentrant { - for (uint256 i; i < _strategies.length; ++i) { - _harvest(_strategies[i]); - } - _gulp(); - } - - function rebalance(address _strategy, uint256 _amountToRebalance, bool _isDeposit) - external - nonReentrant - onlyRole(REBALANCER) - { - Strategy memory strategyData = strategies[_strategy]; - - if (_isDeposit) { - // Do required approval (safely) and deposit - IERC20(asset()).safeIncreaseAllowance(_strategy, _amountToRebalance); - IERC4626(_strategy).deposit(_amountToRebalance, address(this)); - strategies[_strategy].allocated = uint120(strategyData.allocated + _amountToRebalance); - totalAllocated += _amountToRebalance; - } else { - IERC4626(_strategy).withdraw(_amountToRebalance, address(this), address(this)); - strategies[_strategy].allocated = (strategyData.allocated - _amountToRebalance).toUint120(); - totalAllocated -= _amountToRebalance; - } - - emit Rebalance(_strategy, _amountToRebalance, _isDeposit); - } - - /// @notice Adjust a certain strategy's allocation points. - /// @dev Can only be called by an address that have the STRATEGY_MANAGER - /// @param _strategy address of strategy - /// @param _newPoints new strategy's points - function adjustAllocationPoints(address _strategy, uint256 _newPoints) - external - nonReentrant - onlyRole(STRATEGY_MANAGER) - { - Strategy memory strategyDataCache = strategies[_strategy]; - - if (!strategyDataCache.active) { - revert InactiveStrategy(); - } - - strategies[_strategy].allocationPoints = _newPoints.toUint120(); - totalAllocationPoints = totalAllocationPoints + _newPoints - strategyDataCache.allocationPoints; - - emit AdjustAllocationPoints(_strategy, strategyDataCache.allocationPoints, _newPoints); - } - - /// @notice Set cap on strategy allocated amount. - /// @dev By default, cap is set to 0, not activated. - /// @param _strategy Strategy address. - /// @param _cap Cap amount - function setStrategyCap(address _strategy, uint256 _cap) external nonReentrant onlyRole(STRATEGY_MANAGER) { - if (!strategies[_strategy].active) { - revert InactiveStrategy(); - } - - strategies[_strategy].cap = _cap.toUint120(); - - emit SetStrategyCap(_strategy, _cap); - } - - /// @notice Swap two strategies indexes in the withdrawal queue. - /// @dev Can only be called by an address that have the WITHDRAW_QUEUE_MANAGER. - /// @param _index1 index of first strategy - /// @param _index2 index of second strategy - function reorderWithdrawalQueue(uint8 _index1, uint8 _index2) - external - nonReentrant - onlyRole(WITHDRAW_QUEUE_MANAGER) - { - uint256 length = withdrawalQueue.length; - if (_index1 >= length || _index2 >= length) { - revert OutOfBounds(); - } - - if (_index1 == _index2) { - revert SameIndexes(); - } - - (withdrawalQueue[_index1], withdrawalQueue[_index2]) = (withdrawalQueue[_index2], withdrawalQueue[_index1]); - - emit ReorderWithdrawalQueue(_index1, _index2); - } - - /// @notice Add new strategy with it's allocation points. - /// @dev Can only be called by an address that have STRATEGY_ADDER. - /// @param _strategy Address of the strategy - /// @param _allocationPoints Strategy's allocation points - function addStrategy(address _strategy, uint256 _allocationPoints) external nonReentrant onlyRole(STRATEGY_ADDER) { - if (strategies[_strategy].active) { - revert StrategyAlreadyExist(); - } - - if (IERC4626(_strategy).asset() != asset()) { - revert InvalidStrategyAsset(); - } - - _callHooksTarget(ADD_STRATEGY, _msgSender()); - - strategies[_strategy] = - Strategy({allocated: 0, allocationPoints: _allocationPoints.toUint120(), active: true, cap: 0}); - - totalAllocationPoints += _allocationPoints; - withdrawalQueue.push(_strategy); - - emit AddStrategy(_strategy, _allocationPoints); - } - - /// @notice Remove strategy and set its allocation points to zero. - /// @dev This function does not pull funds, `harvest()` needs to be called to withdraw - /// @dev Can only be called by an address that have the STRATEGY_REMOVER - /// @param _strategy Address of the strategy - function removeStrategy(address _strategy) external nonReentrant onlyRole(STRATEGY_REMOVER) { - if (_strategy == address(0)) revert CanNotRemoveCashReserve(); - - Strategy storage strategyStorage = strategies[_strategy]; - - if (!strategyStorage.active) { - revert AlreadyRemoved(); - } - - _callHooksTarget(REMOVE_STRATEGY, _msgSender()); - - totalAllocationPoints -= strategyStorage.allocationPoints; - strategyStorage.active = false; - strategyStorage.allocationPoints = 0; - - // remove from withdrawalQueue - uint256 lastStrategyIndex = withdrawalQueue.length - 1; - - for (uint256 i = 0; i < lastStrategyIndex; ++i) { - if (withdrawalQueue[i] == _strategy) { - withdrawalQueue[i] = withdrawalQueue[lastStrategyIndex]; - - break; - } - } - - withdrawalQueue.pop(); - - emit RemoveStrategy(_strategy); - } - - /// @notice update accrued interest - /// @return struct ESR struct - function updateInterestAccrued() external returns (ESR memory) { - return _updateInterestAccrued(); - } - - /// @notice gulp positive harvest yield - function gulp() external nonReentrant { - _gulp(); - } - - /// @notice Get strategy params. - /// @param _strategy strategy's address - /// @return Strategy struct - function getStrategy(address _strategy) external view returns (Strategy memory) { - return strategies[_strategy]; - } - - /// @notice Return the withdrawal queue length. - /// @return uint256 length - function withdrawalQueueLength() external view returns (uint256) { - return withdrawalQueue.length; - } - - /// @notice Return the ESR struct - /// @return ESR struct - function getESRSlot() external view returns (ESR memory) { - return esrSlot; - } - - /// @notice Return the accrued interest - /// @return uint256 accrued interest - function interestAccrued() external view returns (uint256) { - return _interestAccruedFromCache(esrSlot); - } - - /// @dev See {IERC4626-deposit}. - function deposit(uint256 assets, address receiver) public override nonReentrant returns (uint256) { - return super.deposit(assets, receiver); - } - - /// @dev See {IERC4626-mint}. - function mint(uint256 shares, address receiver) public override nonReentrant returns (uint256) { - return super.mint(shares, receiver); - } - - /// @dev See {IERC4626-withdraw}. - /// @dev this function update the accrued interest - function withdraw(uint256 assets, address receiver, address owner) - public - override - nonReentrant - returns (uint256 shares) - { - // Move interest to totalAssetsDeposited - _updateInterestAccrued(); - return super.withdraw(assets, receiver, owner); - } - - /// @dev See {IERC4626-redeem}. - /// @dev this function update the accrued interest - function redeem(uint256 shares, address receiver, address owner) - public - override - nonReentrant - returns (uint256 assets) - { - // Move interest to totalAssetsDeposited - _updateInterestAccrued(); - return super.redeem(shares, receiver, owner); - } - - /// @notice Set hooks contract and hooked functions. - /// @dev This funtion should be overriden to implement access control. - /// @param _hooksTarget Hooks contract. - /// @param _hookedFns Hooked functions. - function setHooksConfig(address _hooksTarget, uint32 _hookedFns) public override onlyRole(MANAGER) nonReentrant { - _setHooksConfig(_hooksTarget, _hookedFns); - } - - /// @notice update accrued interest. - /// @return struct ESR struct. - function _updateInterestAccrued() internal returns (ESR memory) { - ESR memory esrSlotCache = esrSlot; - uint256 accruedInterest = _interestAccruedFromCache(esrSlotCache); - // it's safe to down-cast because the accrued interest is a fraction of interest left - esrSlotCache.interestLeft -= uint168(accruedInterest); - esrSlotCache.lastInterestUpdate = uint40(block.timestamp); - // write esrSlotCache back to storage in a single SSTORE - esrSlot = esrSlotCache; - // Move interest accrued to totalAssetsDeposited - totalAssetsDeposited += accruedInterest; - - return esrSlotCache; - } - - /// @notice Return the total amount of assets deposited, plus the accrued interest. - /// @return uint256 total amount - function totalAssets() public view override returns (uint256) { - return totalAssetsDeposited + _interestAccruedFromCache(esrSlot); - } - - /// @notice get the total assets allocatable - /// @dev the total assets allocatable is the amount of assets deposited into the aggregator + assets already deposited into strategies - /// @return uint256 total assets - function totalAssetsAllocatable() public view returns (uint256) { - return IERC20(asset()).balanceOf(address(this)) + totalAllocated; - } - - /// @dev Increate the total assets deposited, and call IERC4626._deposit() - /// @dev See {IERC4626-_deposit}. - function _deposit(address caller, address receiver, uint256 assets, uint256 shares) internal override { - _callHooksTarget(DEPOSIT, caller); - - totalAssetsDeposited += assets; - - super._deposit(caller, receiver, assets, shares); - } - - /// @dev Withdraw asset back to the user. - /// @dev See {IERC4626-_withdraw}. - /// @dev if the cash reserve can not cover the amount to withdraw, this function will loop through the strategies - /// to cover the remaining amount. This function will revert if the amount to withdraw is not available - function _withdraw(address caller, address receiver, address owner, uint256 assets, uint256 shares) - internal - override - { - _callHooksTarget(WITHDRAW, caller); - - totalAssetsDeposited -= assets; - uint256 assetsRetrieved = IERC20(asset()).balanceOf(address(this)); - - if (assetsRetrieved < assets) assetsRetrieved = _withdrawFromStrategies(assetsRetrieved, assets); - if (assetsRetrieved < assets) { - revert NotEnoughAssets(); - } - - _gulp(); - - super._withdraw(caller, receiver, owner, assets, shares); - } - - /// @dev Withdraw needed asset amount from strategies. - /// @param _currentBalance Aggregator asset balance. - /// @param _targetBalance target balance. - /// @return uint256 current balance after withdraw. - function _withdrawFromStrategies(uint256 _currentBalance, uint256 _targetBalance) internal returns (uint256) { - uint256 numStrategies = withdrawalQueue.length; - for (uint256 i; i < numStrategies; ++i) { - IERC4626 strategy = IERC4626(withdrawalQueue[i]); - - _harvest(address(strategy)); - - uint256 underlyingBalance = strategy.maxWithdraw(address(this)); - uint256 desiredAssets = _targetBalance - _currentBalance; - uint256 withdrawAmount = (underlyingBalance > desiredAssets) ? desiredAssets : underlyingBalance; - - // Update allocated assets - strategies[address(strategy)].allocated -= uint120(withdrawAmount); - totalAllocated -= withdrawAmount; - - // update assetsRetrieved - _currentBalance += withdrawAmount; - - // Do actual withdraw from strategy - strategy.withdraw(withdrawAmount, address(this), address(this)); - - if (_currentBalance >= _targetBalance) { - break; - } - } - - return _currentBalance; - } - - /// @dev gulp positive yield and increment the left interest - function _gulp() internal { - ESR memory esrSlotCache = _updateInterestAccrued(); - - if (totalAssetsDeposited == 0) return; - uint256 toGulp = totalAssetsAllocatable() - totalAssetsDeposited - esrSlotCache.interestLeft; - - if (toGulp == 0) return; - - uint256 maxGulp = type(uint168).max - esrSlotCache.interestLeft; - if (toGulp > maxGulp) toGulp = maxGulp; // cap interest, allowing the vault to function - - esrSlotCache.interestSmearEnd = uint40(block.timestamp + INTEREST_SMEAR); - esrSlotCache.interestLeft += uint168(toGulp); // toGulp <= maxGulp <= max uint168 - - // write esrSlotCache back to storage in a single SSTORE - esrSlot = esrSlotCache; - - emit Gulp(esrSlotCache.interestLeft, esrSlotCache.interestSmearEnd); - } - - function _harvest(address _strategy) internal { - uint120 strategyAllocatedAmount = strategies[_strategy].allocated; - - if (strategyAllocatedAmount == 0) return; - - uint256 underlyingBalance = IERC4626(_strategy).maxWithdraw(address(this)); - - if (underlyingBalance == strategyAllocatedAmount) { - return; - } else if (underlyingBalance > strategyAllocatedAmount) { - // There's yield! - uint256 yield = underlyingBalance - strategyAllocatedAmount; - uint120 accruedPerformanceFee = _accruePerformanceFee(_strategy, yield); - - if (accruedPerformanceFee > 0) { - underlyingBalance -= accruedPerformanceFee; - yield -= accruedPerformanceFee; - } - - strategies[_strategy].allocated = uint120(underlyingBalance); - totalAllocated += yield; - } else { - uint256 loss = strategyAllocatedAmount - underlyingBalance; - - strategies[_strategy].allocated = uint120(underlyingBalance); - totalAllocated -= loss; - - ESR memory esrSlotCache = esrSlot; - if (esrSlotCache.interestLeft >= loss) { - esrSlotCache.interestLeft -= uint168(loss); - } else { - totalAssetsDeposited -= loss - esrSlotCache.interestLeft; - esrSlotCache.interestLeft = 0; - } - esrSlot = esrSlotCache; - } - - emit Harvest(_strategy, underlyingBalance, strategyAllocatedAmount); - } - - function _accruePerformanceFee(address _strategy, uint256 _yield) internal returns (uint120) { - address cachedFeeRecipient = feeRecipient; - uint256 cachedPerformanceFee = performanceFee; - - if (cachedFeeRecipient == address(0) || cachedPerformanceFee == 0) return 0; - - // `feeAssets` will be rounded down to 0 if `yield * performanceFee < 1e18`. - uint256 feeAssets = Math.mulDiv(_yield, cachedPerformanceFee, 1e18, Math.Rounding.Down); - - if (feeAssets > 0) { - IERC4626(_strategy).withdraw(feeAssets, cachedFeeRecipient, address(this)); - } - - emit AccruePerformanceFee(cachedFeeRecipient, _yield, feeAssets); - - return feeAssets.toUint120(); - } - - /// @dev Override _afterTokenTransfer hook to call IBalanceTracker.balanceTrackerHook() - /// @dev Calling .balanceTrackerHook() passing the address total balance - /// @param from Address sending the amount - /// @param to Address receiving the amount - function _afterTokenTransfer(address from, address to, uint256 /*amount*/ ) internal override { - if (from == to) return; - - if ((from != address(0)) && (isBalanceForwarderEnabled[from])) { - balanceTracker.balanceTrackerHook(from, super.balanceOf(from), false); - } - - if ((to != address(0)) && (isBalanceForwarderEnabled[to])) { - balanceTracker.balanceTrackerHook(to, super.balanceOf(to), false); - } - } - - /// @dev Get accrued interest without updating it. - /// @param esrSlotCache Cached esrSlot - /// @return uint256 accrued interest - function _interestAccruedFromCache(ESR memory esrSlotCache) internal view returns (uint256) { - // If distribution ended, full amount is accrued - if (block.timestamp >= esrSlotCache.interestSmearEnd) { - return esrSlotCache.interestLeft; - } - - // If just updated return 0 - if (esrSlotCache.lastInterestUpdate == block.timestamp) { - return 0; - } - - // Else return what has accrued - uint256 totalDuration = esrSlotCache.interestSmearEnd - esrSlotCache.lastInterestUpdate; - uint256 timePassed = block.timestamp - esrSlotCache.lastInterestUpdate; - - return esrSlotCache.interestLeft * timePassed / totalDuration; - } - - /// @notice Retrieves the message sender in the context of the EVC. - /// @dev This function returns the account on behalf of which the current operation is being performed, which is - /// either msg.sender or the account authenticated by the EVC. - /// @return The address of the message sender. - function _msgSender() internal view override (Context, EVCUtil) returns (address) { - return EVCUtil._msgSender(); - } -} diff --git a/src/Hooks.sol b/src/Shared.sol similarity index 53% rename from src/Hooks.sol rename to src/Shared.sol index 8127a6fc..c87a970f 100644 --- a/src/Hooks.sol +++ b/src/Shared.sol @@ -1,16 +1,19 @@ // SPDX-License-Identifier: GPL-2.0-or-later pragma solidity ^0.8.0; -import {HooksLib} from "./lib/HooksLib.sol"; +// interfaces +import {IEVC} from "ethereum-vault-connector/utils/EVCUtil.sol"; import {IHookTarget} from "evk/src/interfaces/IHookTarget.sol"; +// libs +import {StorageLib, AggregationVaultStorage} from "./lib/StorageLib.sol"; +import {ErrorsLib} from "./lib/ErrorsLib.sol"; +import {HooksLib} from "./lib/HooksLib.sol"; -abstract contract Hooks { +contract Shared { using HooksLib for uint32; - error InvalidHooksTarget(); - error NotHooksContract(); - error InvalidHookedFns(); - error EmptyError(); + uint8 internal constant REENTRANCYLOCK__UNLOCKED = 1; + uint8 internal constant REENTRANCYLOCK__LOCKED = 2; uint32 public constant DEPOSIT = 1 << 0; uint32 public constant WITHDRAW = 1 << 1; @@ -18,50 +21,50 @@ abstract contract Hooks { uint32 public constant REMOVE_STRATEGY = 1 << 3; uint32 constant ACTIONS_COUNTER = 1 << 4; - uint256 public constant HOOKS_MASK = 0x00000000000000000000000000000000000000000000000000000000FFFFFFFF; + uint256 constant HOOKS_MASK = 0x00000000000000000000000000000000000000000000000000000000FFFFFFFF; - /// @dev storing the hooks target and kooked functions. - uint256 hooksConfig; + modifier nonReentrant() { + AggregationVaultStorage storage $ = StorageLib._getAggregationVaultStorage(); - event SetHooksConfig(address indexed hooksTarget, uint32 hookedFns); + if ($.locked == REENTRANCYLOCK__LOCKED) revert ErrorsLib.Reentrancy(); - /// @notice Get the hooks contract and the hooked functions. - /// @return address Hooks contract. - /// @return uint32 Hooked functions. - function getHooksConfig() external view returns (address, uint32) { - return _getHooksConfig(hooksConfig); + $.locked = REENTRANCYLOCK__LOCKED; + _; + $.locked = REENTRANCYLOCK__UNLOCKED; } - /// @notice Set hooks contract and hooked functions. - /// @dev This funtion should be overriden to implement access control and call _setHooksConfig(). - /// @param _hooksTarget Hooks contract. - /// @param _hookedFns Hooked functions. - function setHooksConfig(address _hooksTarget, uint32 _hookedFns) public virtual; + function _msgSender() internal view virtual returns (address) { + address sender = msg.sender; + AggregationVaultStorage storage $ = StorageLib._getAggregationVaultStorage(); + + if (sender == address($.evc)) { + (sender,) = IEVC($.evc).getCurrentOnBehalfOfAccount(address(0)); + } + + return sender; + } - /// @notice Set hooks contract and hooked functions. - /// @dev This funtion should be called when implementing setHooksConfig(). - /// @param _hooksTarget Hooks contract. - /// @param _hookedFns Hooked functions. function _setHooksConfig(address _hooksTarget, uint32 _hookedFns) internal { if (_hooksTarget != address(0) && IHookTarget(_hooksTarget).isHookTarget() != IHookTarget.isHookTarget.selector) { - revert NotHooksContract(); + revert ErrorsLib.NotHooksContract(); } if (_hookedFns != 0 && _hooksTarget == address(0)) { - revert InvalidHooksTarget(); + revert ErrorsLib.InvalidHooksTarget(); } - if (_hookedFns >= ACTIONS_COUNTER) revert InvalidHookedFns(); + if (_hookedFns >= ACTIONS_COUNTER) revert ErrorsLib.InvalidHookedFns(); - hooksConfig = (uint256(uint160(_hooksTarget)) << 32) | uint256(_hookedFns); - - emit SetHooksConfig(_hooksTarget, _hookedFns); + AggregationVaultStorage storage $ = StorageLib._getAggregationVaultStorage(); + $.hooksConfig = (uint256(uint160(_hooksTarget)) << 32) | uint256(_hookedFns); } /// @notice Checks whether a hook has been installed for the function and if so, invokes the hook target. /// @param _fn Function to call the hook for. /// @param _caller Caller's address. function _callHooksTarget(uint32 _fn, address _caller) internal { - (address target, uint32 hookedFns) = _getHooksConfig(hooksConfig); + AggregationVaultStorage storage $ = StorageLib._getAggregationVaultStorage(); + + (address target, uint32 hookedFns) = _getHooksConfig($.hooksConfig); if (hookedFns.isNotSet(_fn)) return; @@ -86,6 +89,6 @@ abstract contract Hooks { } } - revert EmptyError(); + revert ErrorsLib.EmptyError(); } } diff --git a/src/interface/IFourSixTwoSixAgg.sol b/src/interface/IFourSixTwoSixAgg.sol index b8323236..30300a6f 100644 --- a/src/interface/IFourSixTwoSixAgg.sol +++ b/src/interface/IFourSixTwoSixAgg.sol @@ -1,23 +1,20 @@ // SPDX-License-Identifier: GPL-2.0-or-later pragma solidity ^0.8.0; -interface IFourSixTwoSixAgg { - /// @dev A struct that hold a strategy allocation's config - /// allocated: amount of asset deposited into strategy - /// allocationPoints: number of points allocated to this strategy - /// active: a boolean to indice if this strategy is active or not - /// cap: an optional cap in terms of deposited underlying asset. By default, it is set to 0(not activated) - struct Strategy { - uint120 allocated; - uint120 allocationPoints; - bool active; - uint120 cap; - } +import {Strategy} from "../lib/StorageLib.sol"; +interface IFourSixTwoSixAgg { function rebalance(address _strategy, uint256 _amountToRebalance, bool _isDeposit) external; function gulp() external; function harvest(address strategy) external; - + function executeStrategyWithdraw(address _strategy, uint256 _withdrawAmount) external; + function executeAggregationVaultWithdraw( + address caller, + address receiver, + address owner, + uint256 assets, + uint256 shares + ) external; function getStrategy(address _strategy) external view returns (Strategy memory); function totalAllocationPoints() external view returns (uint256); function totalAllocated() external view returns (uint256); diff --git a/src/interface/IWithdrawalQueue.sol b/src/interface/IWithdrawalQueue.sol new file mode 100644 index 00000000..e5e68d0c --- /dev/null +++ b/src/interface/IWithdrawalQueue.sol @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity ^0.8.0; + +interface IWithdrawalQueue { + function init(address _owner, address _eulerAggregationVault) external; + function addStrategyToWithdrawalQueue(address _strategy) external; + function removeStrategyFromWithdrawalQueue(address _strategy) external; + function callWithdrawalQueue( + address caller, + address receiver, + address owner, + uint256 assets, + uint256 shares, + uint256 availableAssets + ) external; + function reorderWithdrawalQueue(uint8 _index1, uint8 _index2) external; + + function withdrawalQueueLength() external view returns (uint256); + function withdrawalQueue(uint256 _index) external view returns (address); +} diff --git a/src/lib/ErrorsLib.sol b/src/lib/ErrorsLib.sol new file mode 100644 index 00000000..b7ed440b --- /dev/null +++ b/src/lib/ErrorsLib.sol @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity ^0.8.0; + +library ErrorsLib { + error Reentrancy(); + error ArrayLengthMismatch(); + error InitialAllocationPointsZero(); + error NegativeYield(); + error InactiveStrategy(); + error InvalidStrategyAsset(); + error StrategyAlreadyExist(); + error AlreadyRemoved(); + error PerformanceFeeAlreadySet(); + error MaxPerformanceFeeExceeded(); + error FeeRecipientNotSet(); + error FeeRecipientAlreadySet(); + error CanNotRemoveCashReserve(); + error DuplicateInitialStrategy(); + error NotSupported(); + error AlreadyEnabled(); + error AlreadyDisabled(); + error InvalidHooksTarget(); + error NotHooksContract(); + error InvalidHookedFns(); + error EmptyError(); + error NotWithdrawaQueue(); +} diff --git a/src/lib/EventsLib.sol b/src/lib/EventsLib.sol new file mode 100644 index 00000000..952b8595 --- /dev/null +++ b/src/lib/EventsLib.sol @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity ^0.8.0; + +library EventsLib { + /// @dev AggregationLayerVault events + event Gulp(uint256 interestLeft, uint256 interestSmearEnd); + event Harvest(address indexed strategy, uint256 strategyBalanceAmount, uint256 strategyAllocatedAmount); + event AccruePerformanceFee(address indexed feeRecipient, uint256 yield, uint256 feeAssets); + event Rebalance(address indexed strategy, uint256 _amountToRebalance, bool _isDeposit); + + /// @dev Allocationpoints events + event AdjustAllocationPoints(address indexed strategy, uint256 oldPoints, uint256 newPoints); + event AddStrategy(address indexed strategy, uint256 allocationPoints); + event RemoveStrategy(address indexed _strategy); + event SetStrategyCap(address indexed strategy, uint256 cap); + + /// @dev Fee events + event SetFeeRecipient(address indexed oldRecipient, address indexed newRecipient); + event SetPerformanceFee(uint256 oldFee, uint256 newFee); + + /// @dev Hooks events + event SetHooksConfig(address indexed hooksTarget, uint32 hookedFns); + + /// @dev Rewards events + event OptInStrategyRewards(address indexed strategy); + event OptOutStrategyRewards(address indexed strategy); + event EnableBalanceForwarder(address indexed _user); + event DisableBalanceForwarder(address indexed _user); +} diff --git a/src/lib/StorageLib.sol b/src/lib/StorageLib.sol new file mode 100644 index 00000000..cab1b385 --- /dev/null +++ b/src/lib/StorageLib.sol @@ -0,0 +1,65 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity ^0.8.0; + +/// @custom:storage-location erc7201:euler_aggregation_vault.storage.AggregationVault +struct AggregationVaultStorage { + /// @dev EVC address + address evc; + /// @dev Total amount of _asset deposited into AggregationLayerVault contract + uint256 totalAssetsDeposited; + /// @dev Total amount of _asset deposited across all strategies. + uint256 totalAllocated; + /// @dev Total amount of allocation points across all strategies including the cash reserve. + uint256 totalAllocationPoints; + /// @dev fee rate + uint256 performanceFee; + /// @dev fee recipient address + address feeRecipient; + /// @dev Withdrawal queue contract's address + address withdrawalQueue; + /// @dev Mapping between strategy address and it's allocation config + mapping(address => Strategy) strategies; + + + /// lastInterestUpdate: last timestamo where interest was updated. + uint40 lastInterestUpdate; + /// interestSmearEnd: timestamp when the smearing of interest end. + uint40 interestSmearEnd; + /// interestLeft: amount of interest left to smear. + uint168 interestLeft; + /// locked: if locked or not for update. + uint8 locked; + + + address balanceTracker; + mapping(address => bool) isBalanceForwarderEnabled; + + + /// @dev storing the hooks target and kooked functions. + uint256 hooksConfig; +} + +/// @dev A struct that hold a strategy allocation's config +/// allocated: amount of asset deposited into strategy +/// allocationPoints: number of points allocated to this strategy +/// active: a boolean to indice if this strategy is active or not +/// cap: an optional cap in terms of deposited underlying asset. By default, it is set to 0(not activated) + +struct Strategy { + uint120 allocated; + uint120 allocationPoints; + bool active; + uint120 cap; +} + +library StorageLib { + // keccak256(abi.encode(uint256(keccak256("euler_aggregation_vault.storage.AggregationVault")) - 1)) & ~bytes32(uint256(0xff)) + bytes32 private constant AggregationVaultStorageLocation = + 0x7da5ece5aff94f3377324d715703a012d3253da37511270103c646f171c0aa00; + + function _getAggregationVaultStorage() internal pure returns (AggregationVaultStorage storage $) { + assembly { + $.slot := AggregationVaultStorageLocation + } + } +} diff --git a/src/module/AllocationPoints.sol b/src/module/AllocationPoints.sol new file mode 100644 index 00000000..439735b6 --- /dev/null +++ b/src/module/AllocationPoints.sol @@ -0,0 +1,107 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity ^0.8.0; + +// interfaces +import {IERC4626} from "@openzeppelin-upgradeable/token/ERC20/extensions/ERC4626Upgradeable.sol"; +import {IWithdrawalQueue} from "../interface/IWithdrawalQueue.sol"; +// contracts +import {Shared} from "../Shared.sol"; +// libs +import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol"; +import {StorageLib, AggregationVaultStorage, Strategy} from "../lib/StorageLib.sol"; +import {ErrorsLib} from "../lib/ErrorsLib.sol"; +import {EventsLib} from "../lib/EventsLib.sol"; + +abstract contract AllocationPointsModule is Shared { + using SafeCast for uint256; + + /// @notice Adjust a certain strategy's allocation points. + /// @dev Can only be called by an address that have the ALLOCATIONS_MANAGER + /// @param _strategy address of strategy + /// @param _newPoints new strategy's points + function adjustAllocationPoints(address _strategy, uint256 _newPoints) external virtual nonReentrant { + AggregationVaultStorage storage $ = StorageLib._getAggregationVaultStorage(); + + Strategy memory strategyDataCache = $.strategies[_strategy]; + + if (!strategyDataCache.active) { + revert ErrorsLib.InactiveStrategy(); + } + + $.strategies[_strategy].allocationPoints = _newPoints.toUint120(); + $.totalAllocationPoints = $.totalAllocationPoints + _newPoints - strategyDataCache.allocationPoints; + + emit EventsLib.AdjustAllocationPoints(_strategy, strategyDataCache.allocationPoints, _newPoints); + } + + /// @notice Set cap on strategy allocated amount. + /// @dev By default, cap is set to 0, not activated. + /// @param _strategy Strategy address. + /// @param _cap Cap amount + function setStrategyCap(address _strategy, uint256 _cap) external virtual nonReentrant { + AggregationVaultStorage storage $ = StorageLib._getAggregationVaultStorage(); + + if (!$.strategies[_strategy].active) { + revert ErrorsLib.InactiveStrategy(); + } + + $.strategies[_strategy].cap = _cap.toUint120(); + + emit EventsLib.SetStrategyCap(_strategy, _cap); + } + + /// @notice Add new strategy with it's allocation points. + /// @dev Can only be called by an address that have STRATEGY_ADDER. + /// @param _strategy Address of the strategy + /// @param _allocationPoints Strategy's allocation points + function addStrategy(address _strategy, uint256 _allocationPoints) external virtual nonReentrant { + AggregationVaultStorage storage $ = StorageLib._getAggregationVaultStorage(); + + if ($.strategies[_strategy].active) { + revert ErrorsLib.StrategyAlreadyExist(); + } + + if (IERC4626(_strategy).asset() != IERC4626(address(this)).asset()) { + revert ErrorsLib.InvalidStrategyAsset(); + } + + _callHooksTarget(ADD_STRATEGY, _msgSender()); + + $.strategies[_strategy] = + Strategy({allocated: 0, allocationPoints: _allocationPoints.toUint120(), active: true, cap: 0}); + + $.totalAllocationPoints += _allocationPoints; + IWithdrawalQueue($.withdrawalQueue).addStrategyToWithdrawalQueue(_strategy); + + emit EventsLib.AddStrategy(_strategy, _allocationPoints); + } + + /// @notice Remove strategy and set its allocation points to zero. + /// @dev This function does not pull funds, `harvest()` needs to be called to withdraw + /// @dev Can only be called by an address that have the STRATEGY_REMOVER + /// @param _strategy Address of the strategy + function removeStrategy(address _strategy) external virtual nonReentrant { + if (_strategy == address(0)) revert ErrorsLib.CanNotRemoveCashReserve(); + + AggregationVaultStorage storage $ = StorageLib._getAggregationVaultStorage(); + + Strategy storage strategyStorage = $.strategies[_strategy]; + + if (!strategyStorage.active) { + revert ErrorsLib.AlreadyRemoved(); + } + + _callHooksTarget(REMOVE_STRATEGY, _msgSender()); + + $.totalAllocationPoints -= strategyStorage.allocationPoints; + strategyStorage.active = false; + strategyStorage.allocationPoints = 0; + + // remove from withdrawalQueue + IWithdrawalQueue($.withdrawalQueue).removeStrategyFromWithdrawalQueue(_strategy); + + emit EventsLib.RemoveStrategy(_strategy); + } +} + +contract AllocationPoints is AllocationPointsModule {} diff --git a/src/module/Fee.sol b/src/module/Fee.sol new file mode 100644 index 00000000..c1436cdf --- /dev/null +++ b/src/module/Fee.sol @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity ^0.8.0; + +// interfaces +import {IBalanceForwarder} from "../interface/IBalanceForwarder.sol"; +import {IBalanceTracker} from "reward-streams/interfaces/IBalanceTracker.sol"; +import {IRewardStreams} from "reward-streams/interfaces/IRewardStreams.sol"; +import {IERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +// contracts +import {Shared} from "../Shared.sol"; +// libs +import {StorageLib, AggregationVaultStorage} from "../lib/StorageLib.sol"; +import {ErrorsLib} from "../lib/ErrorsLib.sol"; +import {EventsLib} from "../lib/EventsLib.sol"; + +abstract contract FeeModule is Shared { + /// @dev The maximum performanceFee the vault can have is 50% + uint256 internal constant MAX_PERFORMANCE_FEE = 0.5e18; + + /// @notice Set performance fee recipient address + /// @notice @param _newFeeRecipient Recipient address + function setFeeRecipient(address _newFeeRecipient) external { + AggregationVaultStorage storage $ = StorageLib._getAggregationVaultStorage(); + address feeRecipientCached = $.feeRecipient; + + if (_newFeeRecipient == feeRecipientCached) revert ErrorsLib.FeeRecipientAlreadySet(); + + emit EventsLib.SetFeeRecipient(feeRecipientCached, _newFeeRecipient); + + $.feeRecipient = _newFeeRecipient; + } + + /// @notice Set performance fee (1e18 == 100%) + /// @notice @param _newFee Fee rate + function setPerformanceFee(uint256 _newFee) external { + AggregationVaultStorage storage $ = StorageLib._getAggregationVaultStorage(); + + uint256 performanceFeeCached = $.performanceFee; + + if (_newFee > MAX_PERFORMANCE_FEE) revert ErrorsLib.MaxPerformanceFeeExceeded(); + if ($.feeRecipient == address(0)) revert ErrorsLib.FeeRecipientNotSet(); + if (_newFee == performanceFeeCached) revert ErrorsLib.PerformanceFeeAlreadySet(); + + emit EventsLib.SetPerformanceFee(performanceFeeCached, _newFee); + + $.performanceFee = _newFee; + } +} + +contract Fee is FeeModule {} diff --git a/src/module/Hooks.sol b/src/module/Hooks.sol new file mode 100644 index 00000000..3c799d2d --- /dev/null +++ b/src/module/Hooks.sol @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity ^0.8.0; + +// interfaces +import {IHookTarget} from "evk/src/interfaces/IHookTarget.sol"; +// contracts +import {Shared} from "../Shared.sol"; +// libs +import {StorageLib, AggregationVaultStorage} from "../lib/StorageLib.sol"; +import {HooksLib} from "../lib/HooksLib.sol"; +import {EventsLib} from "../lib/EventsLib.sol"; + +abstract contract HooksModule is Shared { + using HooksLib for uint32; + + /// @notice Set hooks contract and hooked functions. + /// @param _hooksTarget Hooks contract. + /// @param _hookedFns Hooked functions. + function setHooksConfig(address _hooksTarget, uint32 _hookedFns) external virtual nonReentrant { + _setHooksConfig(_hooksTarget, _hookedFns); + + emit EventsLib.SetHooksConfig(_hooksTarget, _hookedFns); + } + + /// @notice Get the hooks contract and the hooked functions. + /// @return address Hooks contract. + /// @return uint32 Hooked functions. + function getHooksConfig() external view returns (address, uint32) { + AggregationVaultStorage storage $ = StorageLib._getAggregationVaultStorage(); + + return _getHooksConfig($.hooksConfig); + } +} + +contract Hooks is HooksModule {} diff --git a/src/module/Rewards.sol b/src/module/Rewards.sol new file mode 100644 index 00000000..24fc79fd --- /dev/null +++ b/src/module/Rewards.sol @@ -0,0 +1,141 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity ^0.8.0; + +// interfaces +import {IBalanceForwarder} from "../interface/IBalanceForwarder.sol"; +import {IBalanceTracker} from "reward-streams/interfaces/IBalanceTracker.sol"; +import {IRewardStreams} from "reward-streams/interfaces/IRewardStreams.sol"; +import {IERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +// contracts +import {Shared} from "../Shared.sol"; +// libs +import {StorageLib, AggregationVaultStorage} from "../lib/StorageLib.sol"; +import {ErrorsLib} from "../lib/ErrorsLib.sol"; +import {EventsLib} from "../lib/EventsLib.sol"; + +/// @title BalanceForwarder contract +/// @custom:security-contact security@euler.xyz +/// @author Euler Labs (https://www.eulerlabs.com/) +/// @notice A generic contract to integrate with https://github.com/euler-xyz/reward-streams +abstract contract RewardsModule is IBalanceForwarder, Shared { + /// @notice Opt in to strategy rewards + /// @param _strategy Strategy address + function optInStrategyRewards(address _strategy) external virtual nonReentrant { + AggregationVaultStorage storage $ = StorageLib._getAggregationVaultStorage(); + + if (!$.strategies[_strategy].active) revert ErrorsLib.InactiveStrategy(); + + IBalanceForwarder(_strategy).enableBalanceForwarder(); + + emit EventsLib.OptInStrategyRewards(_strategy); + } + + /// @notice Opt out of strategy rewards + /// @param _strategy Strategy address + function optOutStrategyRewards(address _strategy) external virtual nonReentrant { + IBalanceForwarder(_strategy).disableBalanceForwarder(); + + emit EventsLib.OptOutStrategyRewards(_strategy); + } + + /// @notice Claim a specific strategy rewards + /// @param _strategy Strategy address. + /// @param _reward The address of the reward token. + /// @param _recipient The address to receive the claimed reward tokens. + /// @param _forfeitRecentReward Whether to forfeit the recent rewards and not update the accumulator. + function claimStrategyReward(address _strategy, address _reward, address _recipient, bool _forfeitRecentReward) + external + virtual + nonReentrant + { + address rewardStreams = IBalanceForwarder(_strategy).balanceTrackerAddress(); + + IRewardStreams(rewardStreams).claimReward(_strategy, _reward, _recipient, _forfeitRecentReward); + } + + /// @notice Enables balance forwarding for the authenticated account + /// @dev Only the authenticated account can enable balance forwarding for itself + /// @dev Should call the IBalanceTracker hook with the current account's balance + function enableBalanceForwarder() external virtual nonReentrant { + address user = _msgSender(); + uint256 userBalance = IERC20(address(this)).balanceOf(user); + + _enableBalanceForwarder(user, userBalance); + } + + /// @notice Disables balance forwarding for the authenticated account + /// @dev Only the authenticated account can disable balance forwarding for itself + /// @dev Should call the IBalanceTracker hook with the account's balance of 0 + function disableBalanceForwarder() external virtual nonReentrant { + _disableBalanceForwarder(_msgSender()); + } + + /// @notice Retrieve the address of rewards contract, tracking changes in account's balances + /// @return The balance tracker address + function balanceTrackerAddress() external view returns (address) { + AggregationVaultStorage storage $ = StorageLib._getAggregationVaultStorage(); + + return address($.balanceTracker); + } + + /// @notice Retrieves boolean indicating if the account opted in to forward balance changes to the rewards contract + /// @param _account Address to query + /// @return True if balance forwarder is enabled + function balanceForwarderEnabled(address _account) external view returns (bool) { + return _balanceForwarderEnabled(_account); + } + + function _enableBalanceForwarder(address _sender, uint256 _senderBalance) internal { + AggregationVaultStorage storage $ = StorageLib._getAggregationVaultStorage(); + IBalanceTracker balanceTrackerCached = IBalanceTracker($.balanceTracker); + + if (address(balanceTrackerCached) == address(0)) revert ErrorsLib.NotSupported(); + if ($.isBalanceForwarderEnabled[_sender]) revert ErrorsLib.AlreadyEnabled(); + + $.isBalanceForwarderEnabled[_sender] = true; + balanceTrackerCached.balanceTrackerHook(_sender, _senderBalance, false); + + emit EventsLib.EnableBalanceForwarder(_sender); + } + + /// @notice Disables balance forwarding for the authenticated account + /// @dev Only the authenticated account can disable balance forwarding for itself + /// @dev Should call the IBalanceTracker hook with the account's balance of 0 + function _disableBalanceForwarder(address _sender) internal { + AggregationVaultStorage storage $ = StorageLib._getAggregationVaultStorage(); + IBalanceTracker balanceTrackerCached = IBalanceTracker($.balanceTracker); + + if (address(balanceTrackerCached) == address(0)) revert ErrorsLib.NotSupported(); + if (!$.isBalanceForwarderEnabled[_sender]) revert ErrorsLib.AlreadyDisabled(); + + $.isBalanceForwarderEnabled[_sender] = false; + balanceTrackerCached.balanceTrackerHook(_sender, 0, false); + + emit EventsLib.DisableBalanceForwarder(_sender); + } + + function _setBalanceTracker(address _balancerTracker) internal { + AggregationVaultStorage storage $ = StorageLib._getAggregationVaultStorage(); + + $.balanceTracker = _balancerTracker; + } + + /// @notice Retrieves boolean indicating if the account opted in to forward balance changes to the rewards contract + /// @param _account Address to query + /// @return True if balance forwarder is enabled + function _balanceForwarderEnabled(address _account) internal view returns (bool) { + AggregationVaultStorage storage $ = StorageLib._getAggregationVaultStorage(); + + return $.isBalanceForwarderEnabled[_account]; + } + + /// @notice Retrieve the address of rewards contract, tracking changes in account's balances + /// @return The balance tracker address + function _balanceTrackerAddress() internal view returns (address) { + AggregationVaultStorage storage $ = StorageLib._getAggregationVaultStorage(); + + return address($.balanceTracker); + } +} + +contract Rewards is RewardsModule {} diff --git a/src/Rebalancer.sol b/src/plugin/Rebalancer.sol similarity index 93% rename from src/Rebalancer.sol rename to src/plugin/Rebalancer.sol index 089ba335..86f4c42d 100644 --- a/src/Rebalancer.sol +++ b/src/plugin/Rebalancer.sol @@ -1,8 +1,9 @@ // SPDX-License-Identifier: GPL-2.0-or-later pragma solidity ^0.8.0; -import {IFourSixTwoSixAgg} from "./interface/IFourSixTwoSixAgg.sol"; -import {IERC4626} from "@openzeppelin/token/ERC20/extensions/ERC4626.sol"; +// interfaces +import {IFourSixTwoSixAgg, Strategy} from "../interface/IFourSixTwoSixAgg.sol"; +import {IERC4626} from "@openzeppelin/contracts/token/ERC20/extensions/ERC4626.sol"; contract Rebalancer { event ExecuteRebalance( @@ -36,7 +37,7 @@ contract Rebalancer { IFourSixTwoSixAgg(_curatedVault).harvest(_strategy); - IFourSixTwoSixAgg.Strategy memory strategyData = IFourSixTwoSixAgg(_curatedVault).getStrategy(_strategy); + Strategy memory strategyData = IFourSixTwoSixAgg(_curatedVault).getStrategy(_strategy); uint256 totalAllocationPointsCache = IFourSixTwoSixAgg(_curatedVault).totalAllocationPoints(); uint256 totalAssetsAllocatableCache = IFourSixTwoSixAgg(_curatedVault).totalAssetsAllocatable(); diff --git a/src/plugin/WithdrawalQueue.sol b/src/plugin/WithdrawalQueue.sol new file mode 100644 index 00000000..2349355b --- /dev/null +++ b/src/plugin/WithdrawalQueue.sol @@ -0,0 +1,187 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity ^0.8.0; + +// interfaces +import {IERC4626} from "@openzeppelin/contracts/token/ERC20/extensions/ERC4626.sol"; +// internal dep +import {IFourSixTwoSixAgg} from "../interface/IFourSixTwoSixAgg.sol"; +// contracts +import {AccessControlEnumerableUpgradeable} from + "@openzeppelin-upgradeable/access/extensions/AccessControlEnumerableUpgradeable.sol"; + +contract WithdrawalQueue is AccessControlEnumerableUpgradeable { + error OutOfBounds(); + error SameIndexes(); + error NotEnoughAssets(); + error NotAuthorized(); + + bytes32 public constant WITHDRAW_QUEUE_MANAGER = keccak256("WITHDRAW_QUEUE_MANAGER"); + bytes32 public constant WITHDRAW_QUEUE_MANAGER_ADMIN = keccak256("WITHDRAW_QUEUE_MANAGER_ADMIN"); + + struct WithdrawalQueueStorage { + address eulerAggregationVault; + /// @dev An array of strategy addresses to withdraw from + address[] withdrawalQueue; + } + + // keccak256(abi.encode(uint256(keccak256("euler_aggregation_vault.storage.WithdrawalQueue")) - 1)) & ~bytes32(uint256(0xff)) + bytes32 private constant WithdrawalQueueStorageLocation = + 0x8522ce6e5838588854909d348b0c9f7932eae519636e8e48e91e9b2639174600; + + event ReorderWithdrawalQueue(uint8 index1, uint8 index2); + + /// @notice Initialize WithdrawalQueue. + /// @param _owner Aggregation layer vault owner. + /// @param _eulerAggregationVault Address of aggregation layer vault. + function init(address _owner, address _eulerAggregationVault) external initializer { + WithdrawalQueueStorage storage $ = _getWithdrawalQueueStorage(); + $.eulerAggregationVault = _eulerAggregationVault; + + // Setup DEFAULT_ADMIN + _grantRole(DEFAULT_ADMIN_ROLE, _owner); + _setRoleAdmin(WITHDRAW_QUEUE_MANAGER, WITHDRAW_QUEUE_MANAGER_ADMIN); + } + + /// @notice Add a strategy to withdrawal queue array. + /// @dev Can only be called by the aggregation layer vault's address. + /// @param _strategy Strategy address to add + function addStrategyToWithdrawalQueue(address _strategy) external { + _isCallerAggregationVault(); + + WithdrawalQueueStorage storage $ = _getWithdrawalQueueStorage(); + + $.withdrawalQueue.push(_strategy); + } + + /// @notice Remove a strategy from withdrawal queue array. + /// @dev Can only be called by the aggregation layer vault's address. + /// @param _strategy Strategy address to add. + function removeStrategyFromWithdrawalQueue(address _strategy) external { + _isCallerAggregationVault(); + + WithdrawalQueueStorage storage $ = _getWithdrawalQueueStorage(); + + uint256 lastStrategyIndex = $.withdrawalQueue.length - 1; + + for (uint256 i = 0; i < lastStrategyIndex; ++i) { + if ($.withdrawalQueue[i] == _strategy) { + $.withdrawalQueue[i] = $.withdrawalQueue[lastStrategyIndex]; + + break; + } + } + + $.withdrawalQueue.pop(); + } + + /// @notice Swap two strategies indexes in the withdrawal queue. + /// @dev Can only be called by an address that have the WITHDRAW_QUEUE_MANAGER role. + /// @param _index1 index of first strategy. + /// @param _index2 index of second strategy. + function reorderWithdrawalQueue(uint8 _index1, uint8 _index2) external onlyRole(WITHDRAW_QUEUE_MANAGER) { + WithdrawalQueueStorage storage $ = _getWithdrawalQueueStorage(); + + uint256 length = $.withdrawalQueue.length; + if (_index1 >= length || _index2 >= length) { + revert OutOfBounds(); + } + + if (_index1 == _index2) { + revert SameIndexes(); + } + + ($.withdrawalQueue[_index1], $.withdrawalQueue[_index2]) = + ($.withdrawalQueue[_index2], $.withdrawalQueue[_index1]); + + emit ReorderWithdrawalQueue(_index1, _index2); + } + + /// @notice Execute the withdraw initiated in the aggregation layer vault. + /// @dev Can only be called by the aggregation layer vault's address. + /// @param caller Initiator's address of withdraw. + /// @param receiver Withdraw receiver address. + /// @param owner Shares's owner to burn. + /// @param assets Amount of asset to withdraw. + /// @param shares Amount of shares to burn. + /// @param availableAssets Amount of available asset in aggregation layer vault's cash reserve. + function callWithdrawalQueue( + address caller, + address receiver, + address owner, + uint256 assets, + uint256 shares, + uint256 availableAssets + ) external { + _isCallerAggregationVault(); + + WithdrawalQueueStorage memory $ = _getWithdrawalQueueStorage(); + address eulerAggregationVaultCached = $.eulerAggregationVault; + + if (availableAssets < assets) { + uint256 numStrategies = $.withdrawalQueue.length; + for (uint256 i; i < numStrategies; ++i) { + IERC4626 strategy = IERC4626($.withdrawalQueue[i]); + + IFourSixTwoSixAgg(eulerAggregationVaultCached).harvest(address(strategy)); + + uint256 underlyingBalance = strategy.maxWithdraw(eulerAggregationVaultCached); + uint256 desiredAssets = assets - availableAssets; + uint256 withdrawAmount = (underlyingBalance > desiredAssets) ? desiredAssets : underlyingBalance; + + IFourSixTwoSixAgg(eulerAggregationVaultCached).executeStrategyWithdraw( + address(strategy), withdrawAmount + ); + + // update assetsRetrieved + availableAssets += withdrawAmount; + + if (availableAssets >= assets) { + break; + } + } + + // re-calculate shares in case of socialized loss + shares = IERC4626(eulerAggregationVaultCached).previewWithdraw(assets); + } + + if (availableAssets < assets) { + revert NotEnoughAssets(); + } + + IFourSixTwoSixAgg(eulerAggregationVaultCached).executeAggregationVaultWithdraw( + caller, receiver, owner, assets, shares + ); + } + + /// @notice Get strategy address from withdrawal queue by index. + /// @param _index Index to fetch. + /// @return address Strategy address. + function getWithdrawalQueueAtIndex(uint256 _index) external view returns (address) { + WithdrawalQueueStorage storage $ = _getWithdrawalQueueStorage(); + + return $.withdrawalQueue[_index]; + } + + /// @notice Return the withdrawal queue length. + /// @return uint256 length. + function withdrawalQueueLength() external pure returns (uint256) { + WithdrawalQueueStorage memory $ = _getWithdrawalQueueStorage(); + + return $.withdrawalQueue.length; + } + + /// @dev Check if the msg.sender is the aggregation layer vault. + function _isCallerAggregationVault() private view { + WithdrawalQueueStorage storage $ = _getWithdrawalQueueStorage(); + + if (msg.sender != $.eulerAggregationVault) revert NotAuthorized(); + } + + /// @dev Return storage pointer. + /// @return $ WithdrawalQueueStorage storage struct. + function _getWithdrawalQueueStorage() private pure returns (WithdrawalQueueStorage storage $) { + assembly { + $.slot := WithdrawalQueueStorageLocation + } + } +} diff --git a/test/common/AggregationLayerVaultBase.t.sol b/test/common/AggregationLayerVaultBase.t.sol new file mode 100644 index 00000000..a945e6f9 --- /dev/null +++ b/test/common/AggregationLayerVaultBase.t.sol @@ -0,0 +1,153 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity ^0.8.0; + +// interfaces +import {IHookTarget} from "evk/src/interfaces/IHookTarget.sol"; +import {IWithdrawalQueue} from "../../src/interface/IWithdrawalQueue.sol"; +// contracts +import "evk/test/unit/evault/EVaultTestBase.t.sol"; +import {AggregationLayerVault, Strategy} from "../../src/AggregationLayerVault.sol"; +import {Rebalancer} from "../../src/plugin/Rebalancer.sol"; +import {Hooks, HooksModule} from "../../src/module/Hooks.sol"; +import {Rewards} from "../../src/module/Rewards.sol"; +import {Fee} from "../../src/module/Fee.sol"; +import {AggregationLayerVaultFactory} from "../../src/AggregationLayerVaultFactory.sol"; +import {WithdrawalQueue} from "../../src/plugin/WithdrawalQueue.sol"; +import {AllocationPoints} from "../../src/module/AllocationPoints.sol"; +// libs +import {ErrorsLib} from "../../src/lib/ErrorsLib.sol"; + +contract AggregationLayerVaultBase is EVaultTestBase { + uint256 public constant CASH_RESERVE_ALLOCATION_POINTS = 1000e18; + + address deployer; + address user1; + address user2; + address manager; + + // core modules + Rewards rewardsImpl; + Hooks hooksImpl; + Fee feeModuleImpl; + AllocationPoints allocationPointsModuleImpl; + // plugins + Rebalancer rebalancer; + WithdrawalQueue withdrawalQueueImpl; + + AggregationLayerVaultFactory aggregationLayerVaultFactory; + AggregationLayerVault aggregationLayerVault; + WithdrawalQueue withdrawalQueue; + + function setUp() public virtual override { + super.setUp(); + + deployer = makeAddr("Deployer"); + user1 = makeAddr("User_1"); + user2 = makeAddr("User_2"); + + vm.startPrank(deployer); + rewardsImpl = new Rewards(); + hooksImpl = new Hooks(); + feeModuleImpl = new Fee(); + allocationPointsModuleImpl = new AllocationPoints(); + + rebalancer = new Rebalancer(); + withdrawalQueueImpl = new WithdrawalQueue(); + aggregationLayerVaultFactory = new AggregationLayerVaultFactory( + address(evc), + address(0), + address(rewardsImpl), + address(hooksImpl), + address(feeModuleImpl), + address(allocationPointsModuleImpl), + address(rebalancer), + address(withdrawalQueueImpl) + ); + + aggregationLayerVault = AggregationLayerVault( + aggregationLayerVaultFactory.deployEulerAggregationLayer( + address(assetTST), "assetTST_Agg", "assetTST_Agg", CASH_RESERVE_ALLOCATION_POINTS + ) + ); + withdrawalQueue = WithdrawalQueue(aggregationLayerVault.withdrawalQueue()); + + // grant admin roles to deployer + aggregationLayerVault.grantRole(aggregationLayerVault.ALLOCATIONS_MANAGER_ADMIN(), deployer); + aggregationLayerVault.grantRole(aggregationLayerVault.STRATEGY_ADDER_ADMIN(), deployer); + aggregationLayerVault.grantRole(aggregationLayerVault.STRATEGY_REMOVER_ADMIN(), deployer); + aggregationLayerVault.grantRole(aggregationLayerVault.AGGREGATION_VAULT_MANAGER_ADMIN(), deployer); + aggregationLayerVault.grantRole(aggregationLayerVault.REBALANCER_ADMIN(), deployer); + withdrawalQueue.grantRole(withdrawalQueue.WITHDRAW_QUEUE_MANAGER_ADMIN(), deployer); + + // grant roles to manager + aggregationLayerVault.grantRole(aggregationLayerVault.ALLOCATIONS_MANAGER(), manager); + aggregationLayerVault.grantRole(aggregationLayerVault.STRATEGY_ADDER(), manager); + aggregationLayerVault.grantRole(aggregationLayerVault.STRATEGY_REMOVER(), manager); + aggregationLayerVault.grantRole(aggregationLayerVault.AGGREGATION_VAULT_MANAGER(), manager); + withdrawalQueue.grantRole(withdrawalQueue.WITHDRAW_QUEUE_MANAGER(), manager); + + vm.stopPrank(); + } + + function testInitialParams() public { + Strategy memory cashReserve = aggregationLayerVault.getStrategy(address(0)); + + assertEq(cashReserve.allocated, 0); + assertEq(cashReserve.allocationPoints, CASH_RESERVE_ALLOCATION_POINTS); + assertEq(cashReserve.active, true); + + assertEq( + aggregationLayerVault.getRoleAdmin(aggregationLayerVault.ALLOCATIONS_MANAGER()), + aggregationLayerVault.ALLOCATIONS_MANAGER_ADMIN() + ); + assertEq( + aggregationLayerVault.getRoleAdmin(aggregationLayerVault.STRATEGY_ADDER()), + aggregationLayerVault.STRATEGY_ADDER_ADMIN() + ); + assertEq( + aggregationLayerVault.getRoleAdmin(aggregationLayerVault.STRATEGY_REMOVER()), + aggregationLayerVault.STRATEGY_REMOVER_ADMIN() + ); + assertEq( + aggregationLayerVault.getRoleAdmin(aggregationLayerVault.AGGREGATION_VAULT_MANAGER()), + aggregationLayerVault.AGGREGATION_VAULT_MANAGER_ADMIN() + ); + assertEq( + withdrawalQueue.getRoleAdmin(withdrawalQueue.WITHDRAW_QUEUE_MANAGER()), + withdrawalQueue.WITHDRAW_QUEUE_MANAGER_ADMIN() + ); + + assertTrue(aggregationLayerVault.hasRole(aggregationLayerVault.ALLOCATIONS_MANAGER_ADMIN(), deployer)); + assertTrue(aggregationLayerVault.hasRole(aggregationLayerVault.STRATEGY_ADDER_ADMIN(), deployer)); + assertTrue(aggregationLayerVault.hasRole(aggregationLayerVault.STRATEGY_REMOVER_ADMIN(), deployer)); + assertTrue(aggregationLayerVault.hasRole(aggregationLayerVault.AGGREGATION_VAULT_MANAGER_ADMIN(), deployer)); + assertTrue(withdrawalQueue.hasRole(withdrawalQueue.WITHDRAW_QUEUE_MANAGER_ADMIN(), deployer)); + + assertTrue(aggregationLayerVault.hasRole(aggregationLayerVault.ALLOCATIONS_MANAGER(), manager)); + assertTrue(aggregationLayerVault.hasRole(aggregationLayerVault.STRATEGY_ADDER(), manager)); + assertTrue(aggregationLayerVault.hasRole(aggregationLayerVault.STRATEGY_REMOVER(), manager)); + assertTrue(aggregationLayerVault.hasRole(aggregationLayerVault.AGGREGATION_VAULT_MANAGER(), manager)); + assertTrue(withdrawalQueue.hasRole(withdrawalQueue.WITHDRAW_QUEUE_MANAGER(), manager)); + } + + function _addStrategy(address from, address strategy, uint256 allocationPoints) internal { + vm.prank(from); + aggregationLayerVault.addStrategy(strategy, allocationPoints); + } + + function _getWithdrawalQueueLength() internal view returns (uint256) { + uint256 length = withdrawalQueue.withdrawalQueueLength(); + + return length; + } + + function _getWithdrawalQueue() internal view returns (address[] memory) { + uint256 length = withdrawalQueue.withdrawalQueueLength(); + + address[] memory queue = new address[](length); + for (uint256 i = 0; i < length; ++i) { + queue[i] = withdrawalQueue.getWithdrawalQueueAtIndex(i); + } + return queue; + } +} diff --git a/test/common/FourSixTwoSixAggBase.t.sol b/test/common/FourSixTwoSixAggBase.t.sol deleted file mode 100644 index fa71ddb0..00000000 --- a/test/common/FourSixTwoSixAggBase.t.sol +++ /dev/null @@ -1,113 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity ^0.8.0; - -import "evk/test/unit/evault/EVaultTestBase.t.sol"; -import {FourSixTwoSixAgg} from "../../src/FourSixTwoSixAgg.sol"; -import {Rebalancer} from "../../src/Rebalancer.sol"; -import {IHookTarget} from "evk/src/interfaces/IHookTarget.sol"; -import {Hooks} from "../../src/Hooks.sol"; - -contract FourSixTwoSixAggBase is EVaultTestBase { - uint256 public constant CASH_RESERVE_ALLOCATION_POINTS = 1000e18; - - address deployer; - address user1; - address user2; - address manager; - - FourSixTwoSixAgg fourSixTwoSixAgg; - Rebalancer rebalancer; - - function setUp() public virtual override { - super.setUp(); - - deployer = makeAddr("Deployer"); - user1 = makeAddr("User_1"); - user2 = makeAddr("User_2"); - - vm.startPrank(deployer); - rebalancer = new Rebalancer(); - fourSixTwoSixAgg = new FourSixTwoSixAgg( - address(evc), - address(0), - address(assetTST), - "assetTST_Agg", - "assetTST_Agg", - CASH_RESERVE_ALLOCATION_POINTS, - new address[](0), - new uint256[](0) - ); - - // grant admin roles to deployer - fourSixTwoSixAgg.grantRole(fourSixTwoSixAgg.STRATEGY_MANAGER_ADMIN(), deployer); - fourSixTwoSixAgg.grantRole(fourSixTwoSixAgg.WITHDRAW_QUEUE_MANAGER_ADMIN(), deployer); - fourSixTwoSixAgg.grantRole(fourSixTwoSixAgg.STRATEGY_ADDER_ADMIN(), deployer); - fourSixTwoSixAgg.grantRole(fourSixTwoSixAgg.STRATEGY_REMOVER_ADMIN(), deployer); - fourSixTwoSixAgg.grantRole(fourSixTwoSixAgg.MANAGER_ADMIN(), deployer); - fourSixTwoSixAgg.grantRole(fourSixTwoSixAgg.REBALANCER_ADMIN(), deployer); - - // grant roles to manager - fourSixTwoSixAgg.grantRole(fourSixTwoSixAgg.STRATEGY_MANAGER(), manager); - fourSixTwoSixAgg.grantRole(fourSixTwoSixAgg.WITHDRAW_QUEUE_MANAGER(), manager); - fourSixTwoSixAgg.grantRole(fourSixTwoSixAgg.STRATEGY_ADDER(), manager); - fourSixTwoSixAgg.grantRole(fourSixTwoSixAgg.STRATEGY_REMOVER(), manager); - fourSixTwoSixAgg.grantRole(fourSixTwoSixAgg.MANAGER(), manager); - - // grant rebalancing role - fourSixTwoSixAgg.grantRole(fourSixTwoSixAgg.REBALANCER(), address(rebalancer)); - - vm.stopPrank(); - } - - function testInitialParams() public { - FourSixTwoSixAgg.Strategy memory cashReserve = fourSixTwoSixAgg.getStrategy(address(0)); - - assertEq(cashReserve.allocated, 0); - assertEq(cashReserve.allocationPoints, CASH_RESERVE_ALLOCATION_POINTS); - assertEq(cashReserve.active, true); - - assertEq( - fourSixTwoSixAgg.getRoleAdmin(fourSixTwoSixAgg.STRATEGY_MANAGER()), - fourSixTwoSixAgg.STRATEGY_MANAGER_ADMIN() - ); - assertEq( - fourSixTwoSixAgg.getRoleAdmin(fourSixTwoSixAgg.WITHDRAW_QUEUE_MANAGER()), - fourSixTwoSixAgg.WITHDRAW_QUEUE_MANAGER_ADMIN() - ); - assertEq( - fourSixTwoSixAgg.getRoleAdmin(fourSixTwoSixAgg.STRATEGY_ADDER()), fourSixTwoSixAgg.STRATEGY_ADDER_ADMIN() - ); - assertEq( - fourSixTwoSixAgg.getRoleAdmin(fourSixTwoSixAgg.STRATEGY_REMOVER()), - fourSixTwoSixAgg.STRATEGY_REMOVER_ADMIN() - ); - assertEq(fourSixTwoSixAgg.getRoleAdmin(fourSixTwoSixAgg.MANAGER()), fourSixTwoSixAgg.MANAGER_ADMIN()); - - assertTrue(fourSixTwoSixAgg.hasRole(fourSixTwoSixAgg.STRATEGY_MANAGER_ADMIN(), deployer)); - assertTrue(fourSixTwoSixAgg.hasRole(fourSixTwoSixAgg.WITHDRAW_QUEUE_MANAGER_ADMIN(), deployer)); - assertTrue(fourSixTwoSixAgg.hasRole(fourSixTwoSixAgg.STRATEGY_ADDER_ADMIN(), deployer)); - assertTrue(fourSixTwoSixAgg.hasRole(fourSixTwoSixAgg.STRATEGY_REMOVER_ADMIN(), deployer)); - assertTrue(fourSixTwoSixAgg.hasRole(fourSixTwoSixAgg.MANAGER_ADMIN(), deployer)); - - assertTrue(fourSixTwoSixAgg.hasRole(fourSixTwoSixAgg.STRATEGY_MANAGER(), manager)); - assertTrue(fourSixTwoSixAgg.hasRole(fourSixTwoSixAgg.WITHDRAW_QUEUE_MANAGER(), manager)); - assertTrue(fourSixTwoSixAgg.hasRole(fourSixTwoSixAgg.STRATEGY_ADDER(), manager)); - assertTrue(fourSixTwoSixAgg.hasRole(fourSixTwoSixAgg.STRATEGY_REMOVER(), manager)); - assertTrue(fourSixTwoSixAgg.hasRole(fourSixTwoSixAgg.MANAGER(), manager)); - } - - function _addStrategy(address from, address strategy, uint256 allocationPoints) internal { - vm.prank(from); - fourSixTwoSixAgg.addStrategy(strategy, allocationPoints); - } - - function _getWithdrawalQueue() internal view returns (address[] memory) { - uint256 length = fourSixTwoSixAgg.withdrawalQueueLength(); - - address[] memory queue = new address[](length); - for (uint256 i = 0; i < length; ++i) { - queue[i] = fourSixTwoSixAgg.withdrawalQueue(i); - } - return queue; - } -} diff --git a/test/e2e/BalanceForwarderE2ETest.t.sol b/test/e2e/BalanceForwarderE2ETest.t.sol index 5e99ea0e..45fea881 100644 --- a/test/e2e/BalanceForwarderE2ETest.t.sol +++ b/test/e2e/BalanceForwarderE2ETest.t.sol @@ -1,18 +1,20 @@ // SPDX-License-Identifier: GPL-2.0-or-later pragma solidity ^0.8.0; +import {TrackingRewardStreams} from "reward-streams/TrackingRewardStreams.sol"; import { - FourSixTwoSixAggBase, - FourSixTwoSixAgg, + AggregationLayerVaultBase, + AggregationLayerVault, console2, EVault, IEVault, IRMTestDefault, - TestERC20 -} from "../common/FourSixTwoSixAggBase.t.sol"; -import {TrackingRewardStreams} from "reward-streams/TrackingRewardStreams.sol"; + TestERC20, + AggregationLayerVaultFactory, + Rewards +} from "../common/AggregationLayerVaultBase.t.sol"; -contract BalanceForwarderE2ETest is FourSixTwoSixAggBase { +contract BalanceForwarderE2ETest is AggregationLayerVaultBase { uint256 user1InitialBalance = 100000e18; address trackingReward; @@ -23,30 +25,35 @@ contract BalanceForwarderE2ETest is FourSixTwoSixAggBase { vm.startPrank(deployer); trackingReward = address(new TrackingRewardStreams(address(evc), 2 weeks)); - fourSixTwoSixAgg = new FourSixTwoSixAgg( + aggregationLayerVaultFactory = new AggregationLayerVaultFactory( address(evc), trackingReward, - address(assetTST), - "assetTST_Agg", - "assetTST_Agg", - CASH_RESERVE_ALLOCATION_POINTS, - new address[](0), - new uint256[](0) + address(rewardsImpl), + address(hooksImpl), + address(feeModuleImpl), + address(allocationPointsModuleImpl), + address(rebalancer), + address(withdrawalQueueImpl) + ); + aggregationLayerVault = AggregationLayerVault( + aggregationLayerVaultFactory.deployEulerAggregationLayer( + address(assetTST), "assetTST_Agg", "assetTST_Agg", CASH_RESERVE_ALLOCATION_POINTS + ) ); // grant admin roles to deployer - fourSixTwoSixAgg.grantRole(fourSixTwoSixAgg.STRATEGY_MANAGER_ADMIN(), deployer); - fourSixTwoSixAgg.grantRole(fourSixTwoSixAgg.WITHDRAW_QUEUE_MANAGER_ADMIN(), deployer); - fourSixTwoSixAgg.grantRole(fourSixTwoSixAgg.STRATEGY_ADDER_ADMIN(), deployer); - fourSixTwoSixAgg.grantRole(fourSixTwoSixAgg.STRATEGY_REMOVER_ADMIN(), deployer); - fourSixTwoSixAgg.grantRole(fourSixTwoSixAgg.MANAGER_ADMIN(), deployer); + aggregationLayerVault.grantRole(aggregationLayerVault.ALLOCATIONS_MANAGER_ADMIN(), deployer); + // aggregationLayerVault.grantRole(aggregationLayerVault.WITHDRAW_QUEUE_MANAGER_ADMIN(), deployer); + aggregationLayerVault.grantRole(aggregationLayerVault.STRATEGY_ADDER_ADMIN(), deployer); + aggregationLayerVault.grantRole(aggregationLayerVault.STRATEGY_REMOVER_ADMIN(), deployer); + aggregationLayerVault.grantRole(aggregationLayerVault.AGGREGATION_VAULT_MANAGER_ADMIN(), deployer); // grant roles to manager - fourSixTwoSixAgg.grantRole(fourSixTwoSixAgg.STRATEGY_MANAGER(), manager); - fourSixTwoSixAgg.grantRole(fourSixTwoSixAgg.WITHDRAW_QUEUE_MANAGER(), manager); - fourSixTwoSixAgg.grantRole(fourSixTwoSixAgg.STRATEGY_ADDER(), manager); - fourSixTwoSixAgg.grantRole(fourSixTwoSixAgg.STRATEGY_REMOVER(), manager); - fourSixTwoSixAgg.grantRole(fourSixTwoSixAgg.MANAGER(), manager); + aggregationLayerVault.grantRole(aggregationLayerVault.ALLOCATIONS_MANAGER(), manager); + // aggregationLayerVault.grantRole(aggregationLayerVault.WITHDRAW_QUEUE_MANAGER(), manager); + aggregationLayerVault.grantRole(aggregationLayerVault.STRATEGY_ADDER(), manager); + aggregationLayerVault.grantRole(aggregationLayerVault.STRATEGY_REMOVER(), manager); + aggregationLayerVault.grantRole(aggregationLayerVault.AGGREGATION_VAULT_MANAGER(), manager); vm.stopPrank(); uint256 initialStrategyAllocationPoints = 500e18; @@ -56,125 +63,125 @@ contract BalanceForwarderE2ETest is FourSixTwoSixAggBase { // deposit into aggregator uint256 amountToDeposit = 10000e18; { - uint256 balanceBefore = fourSixTwoSixAgg.balanceOf(user1); - uint256 totalSupplyBefore = fourSixTwoSixAgg.totalSupply(); - uint256 totalAssetsDepositedBefore = fourSixTwoSixAgg.totalAssetsDeposited(); + uint256 balanceBefore = aggregationLayerVault.balanceOf(user1); + uint256 totalSupplyBefore = aggregationLayerVault.totalSupply(); + uint256 totalAssetsDepositedBefore = aggregationLayerVault.totalAssetsDeposited(); uint256 userAssetBalanceBefore = assetTST.balanceOf(user1); vm.startPrank(user1); - assetTST.approve(address(fourSixTwoSixAgg), amountToDeposit); - fourSixTwoSixAgg.deposit(amountToDeposit, user1); + assetTST.approve(address(aggregationLayerVault), amountToDeposit); + aggregationLayerVault.deposit(amountToDeposit, user1); vm.stopPrank(); - assertEq(fourSixTwoSixAgg.balanceOf(user1), balanceBefore + amountToDeposit); - assertEq(fourSixTwoSixAgg.totalSupply(), totalSupplyBefore + amountToDeposit); - assertEq(fourSixTwoSixAgg.totalAssetsDeposited(), totalAssetsDepositedBefore + amountToDeposit); + assertEq(aggregationLayerVault.balanceOf(user1), balanceBefore + amountToDeposit); + assertEq(aggregationLayerVault.totalSupply(), totalSupplyBefore + amountToDeposit); + assertEq(aggregationLayerVault.totalAssetsDeposited(), totalAssetsDepositedBefore + amountToDeposit); assertEq(assetTST.balanceOf(user1), userAssetBalanceBefore - amountToDeposit); } } function testBalanceForwarderrAddress_Integrity() public view { - assertEq(address(fourSixTwoSixAgg.balanceTracker()), trackingReward); + assertEq(aggregationLayerVault.balanceTrackerAddress(), trackingReward); } function testEnableBalanceForwarder() public { vm.prank(user1); - fourSixTwoSixAgg.enableBalanceForwarder(); + aggregationLayerVault.enableBalanceForwarder(); - assertTrue(fourSixTwoSixAgg.balanceForwarderEnabled(user1)); + assertTrue(aggregationLayerVault.balanceForwarderEnabled(user1)); assertEq( - TrackingRewardStreams(trackingReward).balanceOf(user1, address(fourSixTwoSixAgg)), - fourSixTwoSixAgg.balanceOf(user1) + TrackingRewardStreams(trackingReward).balanceOf(user1, address(aggregationLayerVault)), + aggregationLayerVault.balanceOf(user1) ); } function testDisableBalanceForwarder() public { vm.prank(user1); - fourSixTwoSixAgg.enableBalanceForwarder(); + aggregationLayerVault.enableBalanceForwarder(); - assertTrue(fourSixTwoSixAgg.balanceForwarderEnabled(user1)); + assertTrue(aggregationLayerVault.balanceForwarderEnabled(user1)); vm.prank(user1); - fourSixTwoSixAgg.disableBalanceForwarder(); + aggregationLayerVault.disableBalanceForwarder(); - assertFalse(fourSixTwoSixAgg.balanceForwarderEnabled(user1)); - assertEq(TrackingRewardStreams(trackingReward).balanceOf(user1, address(fourSixTwoSixAgg)), 0); + assertFalse(aggregationLayerVault.balanceForwarderEnabled(user1)); + assertEq(TrackingRewardStreams(trackingReward).balanceOf(user1, address(aggregationLayerVault)), 0); } function testHookWhenReceiverEnabled() public { vm.prank(user1); - fourSixTwoSixAgg.enableBalanceForwarder(); + aggregationLayerVault.enableBalanceForwarder(); // deposit into aggregator uint256 amountToDeposit = 10000e18; { - uint256 balanceBefore = fourSixTwoSixAgg.balanceOf(user1); - uint256 totalSupplyBefore = fourSixTwoSixAgg.totalSupply(); - uint256 totalAssetsDepositedBefore = fourSixTwoSixAgg.totalAssetsDeposited(); + uint256 balanceBefore = aggregationLayerVault.balanceOf(user1); + uint256 totalSupplyBefore = aggregationLayerVault.totalSupply(); + uint256 totalAssetsDepositedBefore = aggregationLayerVault.totalAssetsDeposited(); uint256 userAssetBalanceBefore = assetTST.balanceOf(user1); vm.startPrank(user1); - assetTST.approve(address(fourSixTwoSixAgg), amountToDeposit); - fourSixTwoSixAgg.deposit(amountToDeposit, user1); + assetTST.approve(address(aggregationLayerVault), amountToDeposit); + aggregationLayerVault.deposit(amountToDeposit, user1); vm.stopPrank(); - assertEq(fourSixTwoSixAgg.balanceOf(user1), balanceBefore + amountToDeposit); - assertEq(fourSixTwoSixAgg.totalSupply(), totalSupplyBefore + amountToDeposit); - assertEq(fourSixTwoSixAgg.totalAssetsDeposited(), totalAssetsDepositedBefore + amountToDeposit); + assertEq(aggregationLayerVault.balanceOf(user1), balanceBefore + amountToDeposit); + assertEq(aggregationLayerVault.totalSupply(), totalSupplyBefore + amountToDeposit); + assertEq(aggregationLayerVault.totalAssetsDeposited(), totalAssetsDepositedBefore + amountToDeposit); assertEq(assetTST.balanceOf(user1), userAssetBalanceBefore - amountToDeposit); assertEq( - TrackingRewardStreams(trackingReward).balanceOf(user1, address(fourSixTwoSixAgg)), - fourSixTwoSixAgg.balanceOf(user1) + TrackingRewardStreams(trackingReward).balanceOf(user1, address(aggregationLayerVault)), + aggregationLayerVault.balanceOf(user1) ); } } function testHookWhenSenderEnabled() public { vm.prank(user1); - fourSixTwoSixAgg.enableBalanceForwarder(); + aggregationLayerVault.enableBalanceForwarder(); // deposit into aggregator uint256 amountToDeposit = 10000e18; { - uint256 balanceBefore = fourSixTwoSixAgg.balanceOf(user1); - uint256 totalSupplyBefore = fourSixTwoSixAgg.totalSupply(); - uint256 totalAssetsDepositedBefore = fourSixTwoSixAgg.totalAssetsDeposited(); + uint256 balanceBefore = aggregationLayerVault.balanceOf(user1); + uint256 totalSupplyBefore = aggregationLayerVault.totalSupply(); + uint256 totalAssetsDepositedBefore = aggregationLayerVault.totalAssetsDeposited(); uint256 userAssetBalanceBefore = assetTST.balanceOf(user1); vm.startPrank(user1); - assetTST.approve(address(fourSixTwoSixAgg), amountToDeposit); - fourSixTwoSixAgg.deposit(amountToDeposit, user1); + assetTST.approve(address(aggregationLayerVault), amountToDeposit); + aggregationLayerVault.deposit(amountToDeposit, user1); vm.stopPrank(); - assertEq(fourSixTwoSixAgg.balanceOf(user1), balanceBefore + amountToDeposit); - assertEq(fourSixTwoSixAgg.totalSupply(), totalSupplyBefore + amountToDeposit); - assertEq(fourSixTwoSixAgg.totalAssetsDeposited(), totalAssetsDepositedBefore + amountToDeposit); + assertEq(aggregationLayerVault.balanceOf(user1), balanceBefore + amountToDeposit); + assertEq(aggregationLayerVault.totalSupply(), totalSupplyBefore + amountToDeposit); + assertEq(aggregationLayerVault.totalAssetsDeposited(), totalAssetsDepositedBefore + amountToDeposit); assertEq(assetTST.balanceOf(user1), userAssetBalanceBefore - amountToDeposit); assertEq( - TrackingRewardStreams(trackingReward).balanceOf(user1, address(fourSixTwoSixAgg)), - fourSixTwoSixAgg.balanceOf(user1) + TrackingRewardStreams(trackingReward).balanceOf(user1, address(aggregationLayerVault)), + aggregationLayerVault.balanceOf(user1) ); } { - uint256 amountToWithdraw = fourSixTwoSixAgg.balanceOf(user1); - uint256 totalAssetsDepositedBefore = fourSixTwoSixAgg.totalAssetsDeposited(); - uint256 aggregatorTotalSupplyBefore = fourSixTwoSixAgg.totalSupply(); + uint256 amountToWithdraw = aggregationLayerVault.balanceOf(user1); + uint256 totalAssetsDepositedBefore = aggregationLayerVault.totalAssetsDeposited(); + uint256 aggregatorTotalSupplyBefore = aggregationLayerVault.totalSupply(); uint256 user1AssetTSTBalanceBefore = assetTST.balanceOf(user1); vm.prank(user1); - fourSixTwoSixAgg.redeem(amountToWithdraw, user1, user1); + aggregationLayerVault.redeem(amountToWithdraw, user1, user1); - assertEq(eTST.balanceOf(address(fourSixTwoSixAgg)), 0); - assertEq(fourSixTwoSixAgg.totalAssetsDeposited(), totalAssetsDepositedBefore - amountToWithdraw); - assertEq(fourSixTwoSixAgg.totalSupply(), aggregatorTotalSupplyBefore - amountToWithdraw); + assertEq(eTST.balanceOf(address(aggregationLayerVault)), 0); + assertEq(aggregationLayerVault.totalAssetsDeposited(), totalAssetsDepositedBefore - amountToWithdraw); + assertEq(aggregationLayerVault.totalSupply(), aggregatorTotalSupplyBefore - amountToWithdraw); assertEq( assetTST.balanceOf(user1), - user1AssetTSTBalanceBefore + fourSixTwoSixAgg.convertToAssets(amountToWithdraw) + user1AssetTSTBalanceBefore + aggregationLayerVault.convertToAssets(amountToWithdraw) ); - assertEq(TrackingRewardStreams(trackingReward).balanceOf(user1, address(fourSixTwoSixAgg)), 0); + assertEq(TrackingRewardStreams(trackingReward).balanceOf(user1, address(aggregationLayerVault)), 0); } } } diff --git a/test/e2e/DepositRebalanceHarvestWithdrawE2ETest.t.sol b/test/e2e/DepositRebalanceHarvestWithdrawE2ETest.t.sol index 8aae2567..96f902fa 100644 --- a/test/e2e/DepositRebalanceHarvestWithdrawE2ETest.t.sol +++ b/test/e2e/DepositRebalanceHarvestWithdrawE2ETest.t.sol @@ -2,16 +2,18 @@ pragma solidity ^0.8.0; import { - FourSixTwoSixAggBase, - FourSixTwoSixAgg, + AggregationLayerVaultBase, + AggregationLayerVault, console2, EVault, IEVault, IRMTestDefault, - TestERC20 -} from "../common/FourSixTwoSixAggBase.t.sol"; + TestERC20, + WithdrawalQueue, + Strategy +} from "../common/AggregationLayerVaultBase.t.sol"; -contract DepositRebalanceHarvestWithdrawE2ETest is FourSixTwoSixAggBase { +contract DepositRebalanceHarvestWithdrawE2ETest is AggregationLayerVaultBase { uint256 user1InitialBalance = 100000e18; function setUp() public virtual override { @@ -28,41 +30,42 @@ contract DepositRebalanceHarvestWithdrawE2ETest is FourSixTwoSixAggBase { // deposit into aggregator { - uint256 balanceBefore = fourSixTwoSixAgg.balanceOf(user1); - uint256 totalSupplyBefore = fourSixTwoSixAgg.totalSupply(); - uint256 totalAssetsDepositedBefore = fourSixTwoSixAgg.totalAssetsDeposited(); + uint256 balanceBefore = aggregationLayerVault.balanceOf(user1); + uint256 totalSupplyBefore = aggregationLayerVault.totalSupply(); + uint256 totalAssetsDepositedBefore = aggregationLayerVault.totalAssetsDeposited(); uint256 userAssetBalanceBefore = assetTST.balanceOf(user1); vm.startPrank(user1); - assetTST.approve(address(fourSixTwoSixAgg), amountToDeposit); - fourSixTwoSixAgg.deposit(amountToDeposit, user1); + assetTST.approve(address(aggregationLayerVault), amountToDeposit); + aggregationLayerVault.deposit(amountToDeposit, user1); vm.stopPrank(); - assertEq(fourSixTwoSixAgg.balanceOf(user1), balanceBefore + amountToDeposit); - assertEq(fourSixTwoSixAgg.totalSupply(), totalSupplyBefore + amountToDeposit); - assertEq(fourSixTwoSixAgg.totalAssetsDeposited(), totalAssetsDepositedBefore + amountToDeposit); + assertEq(aggregationLayerVault.balanceOf(user1), balanceBefore + amountToDeposit); + assertEq(aggregationLayerVault.totalSupply(), totalSupplyBefore + amountToDeposit); + assertEq(aggregationLayerVault.totalAssetsDeposited(), totalAssetsDepositedBefore + amountToDeposit); assertEq(assetTST.balanceOf(user1), userAssetBalanceBefore - amountToDeposit); } // rebalance into strategy vm.warp(block.timestamp + 86400); { - FourSixTwoSixAgg.Strategy memory strategyBefore = fourSixTwoSixAgg.getStrategy(address(eTST)); + Strategy memory strategyBefore = aggregationLayerVault.getStrategy(address(eTST)); - assertEq(eTST.convertToAssets(eTST.balanceOf(address(fourSixTwoSixAgg))), strategyBefore.allocated); + assertEq(eTST.convertToAssets(eTST.balanceOf(address(aggregationLayerVault))), strategyBefore.allocated); - uint256 expectedStrategyCash = fourSixTwoSixAgg.totalAssetsAllocatable() * strategyBefore.allocationPoints - / fourSixTwoSixAgg.totalAllocationPoints(); + uint256 expectedStrategyCash = aggregationLayerVault.totalAssetsAllocatable() + * strategyBefore.allocationPoints / aggregationLayerVault.totalAllocationPoints(); vm.prank(user1); address[] memory strategiesToRebalance = new address[](1); strategiesToRebalance[0] = address(eTST); - rebalancer.executeRebalance(address(fourSixTwoSixAgg), strategiesToRebalance); + rebalancer.executeRebalance(address(aggregationLayerVault), strategiesToRebalance); - assertEq(fourSixTwoSixAgg.totalAllocated(), expectedStrategyCash); - assertEq(eTST.convertToAssets(eTST.balanceOf(address(fourSixTwoSixAgg))), expectedStrategyCash); + assertEq(aggregationLayerVault.totalAllocated(), expectedStrategyCash); + assertEq(eTST.convertToAssets(eTST.balanceOf(address(aggregationLayerVault))), expectedStrategyCash); assertEq( - (fourSixTwoSixAgg.getStrategy(address(eTST))).allocated, strategyBefore.allocated + expectedStrategyCash + (aggregationLayerVault.getStrategy(address(eTST))).allocated, + strategyBefore.allocated + expectedStrategyCash ); } @@ -70,37 +73,37 @@ contract DepositRebalanceHarvestWithdrawE2ETest is FourSixTwoSixAggBase { // partial withdraw, no need to withdraw from strategy as cash reserve is enough uint256 amountToWithdraw = 6000e18; { - FourSixTwoSixAgg.Strategy memory strategyBefore = fourSixTwoSixAgg.getStrategy(address(eTST)); - uint256 strategyShareBalanceBefore = eTST.balanceOf(address(fourSixTwoSixAgg)); - uint256 totalAssetsDepositedBefore = fourSixTwoSixAgg.totalAssetsDeposited(); - uint256 aggregatorTotalSupplyBefore = fourSixTwoSixAgg.totalSupply(); + Strategy memory strategyBefore = aggregationLayerVault.getStrategy(address(eTST)); + uint256 strategyShareBalanceBefore = eTST.balanceOf(address(aggregationLayerVault)); + uint256 totalAssetsDepositedBefore = aggregationLayerVault.totalAssetsDeposited(); + uint256 aggregatorTotalSupplyBefore = aggregationLayerVault.totalSupply(); uint256 user1AssetTSTBalanceBefore = assetTST.balanceOf(user1); vm.prank(user1); - fourSixTwoSixAgg.withdraw(amountToWithdraw, user1, user1); + aggregationLayerVault.withdraw(amountToWithdraw, user1, user1); - assertEq(eTST.balanceOf(address(fourSixTwoSixAgg)), strategyShareBalanceBefore); - assertEq(fourSixTwoSixAgg.totalAssetsDeposited(), totalAssetsDepositedBefore - amountToWithdraw); - assertEq(fourSixTwoSixAgg.totalSupply(), aggregatorTotalSupplyBefore - amountToWithdraw); + assertEq(eTST.balanceOf(address(aggregationLayerVault)), strategyShareBalanceBefore); + assertEq(aggregationLayerVault.totalAssetsDeposited(), totalAssetsDepositedBefore - amountToWithdraw); + assertEq(aggregationLayerVault.totalSupply(), aggregatorTotalSupplyBefore - amountToWithdraw); assertEq(assetTST.balanceOf(user1), user1AssetTSTBalanceBefore + amountToWithdraw); - assertEq((fourSixTwoSixAgg.getStrategy(address(eTST))).allocated, strategyBefore.allocated); + assertEq((aggregationLayerVault.getStrategy(address(eTST))).allocated, strategyBefore.allocated); } // full withdraw, will have to withdraw from strategy as cash reserve is not enough { amountToWithdraw = amountToDeposit - amountToWithdraw; - uint256 totalAssetsDepositedBefore = fourSixTwoSixAgg.totalAssetsDeposited(); - uint256 aggregatorTotalSupplyBefore = fourSixTwoSixAgg.totalSupply(); + uint256 totalAssetsDepositedBefore = aggregationLayerVault.totalAssetsDeposited(); + uint256 aggregatorTotalSupplyBefore = aggregationLayerVault.totalSupply(); uint256 user1AssetTSTBalanceBefore = assetTST.balanceOf(user1); vm.prank(user1); - fourSixTwoSixAgg.withdraw(amountToWithdraw, user1, user1); + aggregationLayerVault.withdraw(amountToWithdraw, user1, user1); - assertEq(eTST.balanceOf(address(fourSixTwoSixAgg)), 0); - assertEq(fourSixTwoSixAgg.totalAssetsDeposited(), totalAssetsDepositedBefore - amountToWithdraw); - assertEq(fourSixTwoSixAgg.totalSupply(), aggregatorTotalSupplyBefore - amountToWithdraw); + assertEq(eTST.balanceOf(address(aggregationLayerVault)), 0); + assertEq(aggregationLayerVault.totalAssetsDeposited(), totalAssetsDepositedBefore - amountToWithdraw); + assertEq(aggregationLayerVault.totalSupply(), aggregatorTotalSupplyBefore - amountToWithdraw); assertEq(assetTST.balanceOf(user1), user1AssetTSTBalanceBefore + amountToWithdraw); - assertEq((fourSixTwoSixAgg.getStrategy(address(eTST))).allocated, 0); + assertEq((aggregationLayerVault.getStrategy(address(eTST))).allocated, 0); } } @@ -109,67 +112,67 @@ contract DepositRebalanceHarvestWithdrawE2ETest is FourSixTwoSixAggBase { // deposit into aggregator { - uint256 balanceBefore = fourSixTwoSixAgg.balanceOf(user1); - uint256 totalSupplyBefore = fourSixTwoSixAgg.totalSupply(); - uint256 totalAssetsDepositedBefore = fourSixTwoSixAgg.totalAssetsDeposited(); + uint256 balanceBefore = aggregationLayerVault.balanceOf(user1); + uint256 totalSupplyBefore = aggregationLayerVault.totalSupply(); + uint256 totalAssetsDepositedBefore = aggregationLayerVault.totalAssetsDeposited(); uint256 userAssetBalanceBefore = assetTST.balanceOf(user1); vm.startPrank(user1); - assetTST.approve(address(fourSixTwoSixAgg), amountToDeposit); - fourSixTwoSixAgg.deposit(amountToDeposit, user1); + assetTST.approve(address(aggregationLayerVault), amountToDeposit); + aggregationLayerVault.deposit(amountToDeposit, user1); vm.stopPrank(); - assertEq(fourSixTwoSixAgg.balanceOf(user1), balanceBefore + amountToDeposit); - assertEq(fourSixTwoSixAgg.totalSupply(), totalSupplyBefore + amountToDeposit); - assertEq(fourSixTwoSixAgg.totalAssetsDeposited(), totalAssetsDepositedBefore + amountToDeposit); + assertEq(aggregationLayerVault.balanceOf(user1), balanceBefore + amountToDeposit); + assertEq(aggregationLayerVault.totalSupply(), totalSupplyBefore + amountToDeposit); + assertEq(aggregationLayerVault.totalAssetsDeposited(), totalAssetsDepositedBefore + amountToDeposit); assertEq(assetTST.balanceOf(user1), userAssetBalanceBefore - amountToDeposit); } // rebalance into strategy vm.warp(block.timestamp + 86400); { - FourSixTwoSixAgg.Strategy memory strategyBefore = fourSixTwoSixAgg.getStrategy(address(eTST)); + Strategy memory strategyBefore = aggregationLayerVault.getStrategy(address(eTST)); - assertEq(eTST.convertToAssets(eTST.balanceOf(address(fourSixTwoSixAgg))), strategyBefore.allocated); + assertEq(eTST.convertToAssets(eTST.balanceOf(address(aggregationLayerVault))), strategyBefore.allocated); - uint256 expectedStrategyCash = fourSixTwoSixAgg.totalAssetsAllocatable() * strategyBefore.allocationPoints - / fourSixTwoSixAgg.totalAllocationPoints(); + uint256 expectedStrategyCash = aggregationLayerVault.totalAssetsAllocatable() + * strategyBefore.allocationPoints / aggregationLayerVault.totalAllocationPoints(); vm.prank(user1); address[] memory strategiesToRebalance = new address[](1); strategiesToRebalance[0] = address(eTST); - rebalancer.executeRebalance(address(fourSixTwoSixAgg), strategiesToRebalance); + rebalancer.executeRebalance(address(aggregationLayerVault), strategiesToRebalance); - assertEq(fourSixTwoSixAgg.totalAllocated(), expectedStrategyCash); - assertEq(eTST.convertToAssets(eTST.balanceOf(address(fourSixTwoSixAgg))), expectedStrategyCash); - assertEq((fourSixTwoSixAgg.getStrategy(address(eTST))).allocated, expectedStrategyCash); + assertEq(aggregationLayerVault.totalAllocated(), expectedStrategyCash); + assertEq(eTST.convertToAssets(eTST.balanceOf(address(aggregationLayerVault))), expectedStrategyCash); + assertEq((aggregationLayerVault.getStrategy(address(eTST))).allocated, expectedStrategyCash); } vm.warp(block.timestamp + 86400); // mock an increase of strategy balance by 10% - uint256 aggrCurrentStrategyShareBalance = eTST.balanceOf(address(fourSixTwoSixAgg)); + uint256 aggrCurrentStrategyShareBalance = eTST.balanceOf(address(aggregationLayerVault)); uint256 aggrCurrentStrategyUnderlyingBalance = eTST.convertToAssets(aggrCurrentStrategyShareBalance); uint256 aggrNewStrategyUnderlyingBalance = aggrCurrentStrategyUnderlyingBalance * 11e17 / 1e18; uint256 yield = aggrNewStrategyUnderlyingBalance - aggrCurrentStrategyUnderlyingBalance; assetTST.mint(address(eTST), yield); - eTST.skim(type(uint256).max, address(fourSixTwoSixAgg)); + eTST.skim(type(uint256).max, address(aggregationLayerVault)); // full withdraw, will have to withdraw from strategy as cash reserve is not enough { - uint256 amountToWithdraw = fourSixTwoSixAgg.balanceOf(user1); - uint256 totalAssetsDepositedBefore = fourSixTwoSixAgg.totalAssetsDeposited(); - uint256 aggregatorTotalSupplyBefore = fourSixTwoSixAgg.totalSupply(); + uint256 amountToWithdraw = aggregationLayerVault.balanceOf(user1); + uint256 totalAssetsDepositedBefore = aggregationLayerVault.totalAssetsDeposited(); + uint256 aggregatorTotalSupplyBefore = aggregationLayerVault.totalSupply(); uint256 user1AssetTSTBalanceBefore = assetTST.balanceOf(user1); vm.prank(user1); - fourSixTwoSixAgg.redeem(amountToWithdraw, user1, user1); + aggregationLayerVault.redeem(amountToWithdraw, user1, user1); - assertEq(eTST.balanceOf(address(fourSixTwoSixAgg)), yield); - assertEq(fourSixTwoSixAgg.totalAssetsDeposited(), totalAssetsDepositedBefore - amountToWithdraw); - assertEq(fourSixTwoSixAgg.totalSupply(), aggregatorTotalSupplyBefore - amountToWithdraw); + assertEq(eTST.balanceOf(address(aggregationLayerVault)), yield); + assertEq(aggregationLayerVault.totalAssetsDeposited(), totalAssetsDepositedBefore - amountToWithdraw); + assertEq(aggregationLayerVault.totalSupply(), aggregatorTotalSupplyBefore - amountToWithdraw); assertEq( assetTST.balanceOf(user1), - user1AssetTSTBalanceBefore + fourSixTwoSixAgg.convertToAssets(amountToWithdraw) + user1AssetTSTBalanceBefore + aggregationLayerVault.convertToAssets(amountToWithdraw) ); } } @@ -194,19 +197,19 @@ contract DepositRebalanceHarvestWithdrawE2ETest is FourSixTwoSixAggBase { // deposit into aggregator { - uint256 balanceBefore = fourSixTwoSixAgg.balanceOf(user1); - uint256 totalSupplyBefore = fourSixTwoSixAgg.totalSupply(); - uint256 totalAssetsDepositedBefore = fourSixTwoSixAgg.totalAssetsDeposited(); + uint256 balanceBefore = aggregationLayerVault.balanceOf(user1); + uint256 totalSupplyBefore = aggregationLayerVault.totalSupply(); + uint256 totalAssetsDepositedBefore = aggregationLayerVault.totalAssetsDeposited(); uint256 userAssetBalanceBefore = assetTST.balanceOf(user1); vm.startPrank(user1); - assetTST.approve(address(fourSixTwoSixAgg), amountToDeposit); - fourSixTwoSixAgg.deposit(amountToDeposit, user1); + assetTST.approve(address(aggregationLayerVault), amountToDeposit); + aggregationLayerVault.deposit(amountToDeposit, user1); vm.stopPrank(); - assertEq(fourSixTwoSixAgg.balanceOf(user1), balanceBefore + amountToDeposit); - assertEq(fourSixTwoSixAgg.totalSupply(), totalSupplyBefore + amountToDeposit); - assertEq(fourSixTwoSixAgg.totalAssetsDeposited(), totalAssetsDepositedBefore + amountToDeposit); + assertEq(aggregationLayerVault.balanceOf(user1), balanceBefore + amountToDeposit); + assertEq(aggregationLayerVault.totalSupply(), totalSupplyBefore + amountToDeposit); + assertEq(aggregationLayerVault.totalAssetsDeposited(), totalAssetsDepositedBefore + amountToDeposit); assertEq(assetTST.balanceOf(user1), userAssetBalanceBefore - amountToDeposit); } @@ -215,20 +218,19 @@ contract DepositRebalanceHarvestWithdrawE2ETest is FourSixTwoSixAggBase { // 10k deposited; 4000 for reserve, 2000 for eTST, 4000 for eTSTsecondary vm.warp(block.timestamp + 86400); { - FourSixTwoSixAgg.Strategy memory eTSTstrategyBefore = fourSixTwoSixAgg.getStrategy(address(eTST)); - FourSixTwoSixAgg.Strategy memory eTSTsecondarystrategyBefore = - fourSixTwoSixAgg.getStrategy(address(eTSTsecondary)); + Strategy memory eTSTstrategyBefore = aggregationLayerVault.getStrategy(address(eTST)); + Strategy memory eTSTsecondarystrategyBefore = aggregationLayerVault.getStrategy(address(eTSTsecondary)); - assertEq(eTST.convertToAssets(eTST.balanceOf(address(fourSixTwoSixAgg))), eTSTstrategyBefore.allocated); + assertEq(eTST.convertToAssets(eTST.balanceOf(address(aggregationLayerVault))), eTSTstrategyBefore.allocated); assertEq( - eTSTsecondary.convertToAssets(eTSTsecondary.balanceOf(address(fourSixTwoSixAgg))), + eTSTsecondary.convertToAssets(eTSTsecondary.balanceOf(address(aggregationLayerVault))), eTSTsecondarystrategyBefore.allocated ); - uint256 expectedeTSTStrategyCash = fourSixTwoSixAgg.totalAssetsAllocatable() - * eTSTstrategyBefore.allocationPoints / fourSixTwoSixAgg.totalAllocationPoints(); - uint256 expectedeTSTsecondaryStrategyCash = fourSixTwoSixAgg.totalAssetsAllocatable() - * eTSTsecondarystrategyBefore.allocationPoints / fourSixTwoSixAgg.totalAllocationPoints(); + uint256 expectedeTSTStrategyCash = aggregationLayerVault.totalAssetsAllocatable() + * eTSTstrategyBefore.allocationPoints / aggregationLayerVault.totalAllocationPoints(); + uint256 expectedeTSTsecondaryStrategyCash = aggregationLayerVault.totalAssetsAllocatable() + * eTSTsecondarystrategyBefore.allocationPoints / aggregationLayerVault.totalAllocationPoints(); assertTrue(expectedeTSTStrategyCash != 0); assertTrue(expectedeTSTsecondaryStrategyCash != 0); @@ -237,29 +239,31 @@ contract DepositRebalanceHarvestWithdrawE2ETest is FourSixTwoSixAggBase { strategiesToRebalance[0] = address(eTST); strategiesToRebalance[1] = address(eTSTsecondary); vm.prank(user1); - rebalancer.executeRebalance(address(fourSixTwoSixAgg), strategiesToRebalance); + rebalancer.executeRebalance(address(aggregationLayerVault), strategiesToRebalance); - assertEq(fourSixTwoSixAgg.totalAllocated(), expectedeTSTStrategyCash + expectedeTSTsecondaryStrategyCash); - assertEq(eTST.convertToAssets(eTST.balanceOf(address(fourSixTwoSixAgg))), expectedeTSTStrategyCash); assertEq( - eTSTsecondary.convertToAssets(eTSTsecondary.balanceOf(address(fourSixTwoSixAgg))), + aggregationLayerVault.totalAllocated(), expectedeTSTStrategyCash + expectedeTSTsecondaryStrategyCash + ); + assertEq(eTST.convertToAssets(eTST.balanceOf(address(aggregationLayerVault))), expectedeTSTStrategyCash); + assertEq( + eTSTsecondary.convertToAssets(eTSTsecondary.balanceOf(address(aggregationLayerVault))), expectedeTSTsecondaryStrategyCash ); - assertEq((fourSixTwoSixAgg.getStrategy(address(eTST))).allocated, expectedeTSTStrategyCash); + assertEq((aggregationLayerVault.getStrategy(address(eTST))).allocated, expectedeTSTStrategyCash); assertEq( - (fourSixTwoSixAgg.getStrategy(address(eTSTsecondary))).allocated, expectedeTSTsecondaryStrategyCash + (aggregationLayerVault.getStrategy(address(eTSTsecondary))).allocated, expectedeTSTsecondaryStrategyCash ); assertEq( - assetTST.balanceOf(address(fourSixTwoSixAgg)), + assetTST.balanceOf(address(aggregationLayerVault)), amountToDeposit - (expectedeTSTStrategyCash + expectedeTSTsecondaryStrategyCash) ); } vm.warp(block.timestamp + 86400); // mock an increase of aggregator balance due to yield - uint256 aggrCurrenteTSTShareBalance = eTST.balanceOf(address(fourSixTwoSixAgg)); + uint256 aggrCurrenteTSTShareBalance = eTST.balanceOf(address(aggregationLayerVault)); uint256 aggrCurrenteTSTUnderlyingBalance = eTST.convertToAssets(aggrCurrenteTSTShareBalance); - uint256 aggrCurrenteTSTsecondaryShareBalance = eTSTsecondary.balanceOf(address(fourSixTwoSixAgg)); + uint256 aggrCurrenteTSTsecondaryShareBalance = eTSTsecondary.balanceOf(address(aggregationLayerVault)); uint256 aggrCurrenteTSTsecondaryUnderlyingBalance = eTST.convertToAssets(aggrCurrenteTSTsecondaryShareBalance); uint256 aggrNeweTSTUnderlyingBalance = aggrCurrenteTSTUnderlyingBalance * 11e17 / 1e18; uint256 aggrNeweTSTsecondaryUnderlyingBalance = aggrCurrenteTSTsecondaryUnderlyingBalance * 11e17 / 1e18; @@ -268,25 +272,25 @@ contract DepositRebalanceHarvestWithdrawE2ETest is FourSixTwoSixAggBase { assetTST.mint(address(eTST), eTSTYield); assetTST.mint(address(eTSTsecondary), eTSTsecondaryYield); - eTST.skim(type(uint256).max, address(fourSixTwoSixAgg)); - eTSTsecondary.skim(type(uint256).max, address(fourSixTwoSixAgg)); + eTST.skim(type(uint256).max, address(aggregationLayerVault)); + eTSTsecondary.skim(type(uint256).max, address(aggregationLayerVault)); // full withdraw, will have to withdraw from strategy as cash reserve is not enough { - uint256 amountToWithdraw = fourSixTwoSixAgg.balanceOf(user1); - uint256 totalAssetsDepositedBefore = fourSixTwoSixAgg.totalAssetsDeposited(); - uint256 aggregatorTotalSupplyBefore = fourSixTwoSixAgg.totalSupply(); + uint256 amountToWithdraw = aggregationLayerVault.balanceOf(user1); + uint256 totalAssetsDepositedBefore = aggregationLayerVault.totalAssetsDeposited(); + uint256 aggregatorTotalSupplyBefore = aggregationLayerVault.totalSupply(); uint256 user1AssetTSTBalanceBefore = assetTST.balanceOf(user1); vm.prank(user1); - fourSixTwoSixAgg.redeem(amountToWithdraw, user1, user1); + aggregationLayerVault.redeem(amountToWithdraw, user1, user1); - assertEq(eTST.balanceOf(address(fourSixTwoSixAgg)), 0); - assertEq(fourSixTwoSixAgg.totalAssetsDeposited(), totalAssetsDepositedBefore - amountToWithdraw); - assertEq(fourSixTwoSixAgg.totalSupply(), aggregatorTotalSupplyBefore - amountToWithdraw); + assertEq(eTST.balanceOf(address(aggregationLayerVault)), 0); + assertEq(aggregationLayerVault.totalAssetsDeposited(), totalAssetsDepositedBefore - amountToWithdraw); + assertEq(aggregationLayerVault.totalSupply(), aggregatorTotalSupplyBefore - amountToWithdraw); assertEq( assetTST.balanceOf(user1), - user1AssetTSTBalanceBefore + fourSixTwoSixAgg.convertToAssets(amountToWithdraw) + user1AssetTSTBalanceBefore + aggregationLayerVault.convertToAssets(amountToWithdraw) ); } } @@ -296,70 +300,72 @@ contract DepositRebalanceHarvestWithdrawE2ETest is FourSixTwoSixAggBase { // deposit into aggregator { - uint256 balanceBefore = fourSixTwoSixAgg.balanceOf(user1); - uint256 totalSupplyBefore = fourSixTwoSixAgg.totalSupply(); - uint256 totalAssetsDepositedBefore = fourSixTwoSixAgg.totalAssetsDeposited(); + uint256 balanceBefore = aggregationLayerVault.balanceOf(user1); + uint256 totalSupplyBefore = aggregationLayerVault.totalSupply(); + uint256 totalAssetsDepositedBefore = aggregationLayerVault.totalAssetsDeposited(); uint256 userAssetBalanceBefore = assetTST.balanceOf(user1); vm.startPrank(user1); - assetTST.approve(address(fourSixTwoSixAgg), amountToDeposit); - fourSixTwoSixAgg.deposit(amountToDeposit, user1); + assetTST.approve(address(aggregationLayerVault), amountToDeposit); + aggregationLayerVault.deposit(amountToDeposit, user1); vm.stopPrank(); - assertEq(fourSixTwoSixAgg.balanceOf(user1), balanceBefore + amountToDeposit); - assertEq(fourSixTwoSixAgg.totalSupply(), totalSupplyBefore + amountToDeposit); - assertEq(fourSixTwoSixAgg.totalAssetsDeposited(), totalAssetsDepositedBefore + amountToDeposit); + assertEq(aggregationLayerVault.balanceOf(user1), balanceBefore + amountToDeposit); + assertEq(aggregationLayerVault.totalSupply(), totalSupplyBefore + amountToDeposit); + assertEq(aggregationLayerVault.totalAssetsDeposited(), totalAssetsDepositedBefore + amountToDeposit); assertEq(assetTST.balanceOf(user1), userAssetBalanceBefore - amountToDeposit); } // rebalance into strategy vm.warp(block.timestamp + 86400); { - FourSixTwoSixAgg.Strategy memory strategyBefore = fourSixTwoSixAgg.getStrategy(address(eTST)); + Strategy memory strategyBefore = aggregationLayerVault.getStrategy(address(eTST)); - assertEq(eTST.convertToAssets(eTST.balanceOf(address(fourSixTwoSixAgg))), strategyBefore.allocated); + assertEq(eTST.convertToAssets(eTST.balanceOf(address(aggregationLayerVault))), strategyBefore.allocated); - uint256 expectedStrategyCash = fourSixTwoSixAgg.totalAssetsAllocatable() * strategyBefore.allocationPoints - / fourSixTwoSixAgg.totalAllocationPoints(); + uint256 expectedStrategyCash = aggregationLayerVault.totalAssetsAllocatable() + * strategyBefore.allocationPoints / aggregationLayerVault.totalAllocationPoints(); vm.prank(user1); address[] memory strategiesToRebalance = new address[](1); strategiesToRebalance[0] = address(eTST); - rebalancer.executeRebalance(address(fourSixTwoSixAgg), strategiesToRebalance); + rebalancer.executeRebalance(address(aggregationLayerVault), strategiesToRebalance); - assertEq(fourSixTwoSixAgg.totalAllocated(), expectedStrategyCash); - assertEq(eTST.convertToAssets(eTST.balanceOf(address(fourSixTwoSixAgg))), expectedStrategyCash); - assertEq((fourSixTwoSixAgg.getStrategy(address(eTST))).allocated, expectedStrategyCash); + assertEq(aggregationLayerVault.totalAllocated(), expectedStrategyCash); + assertEq(eTST.convertToAssets(eTST.balanceOf(address(aggregationLayerVault))), expectedStrategyCash); + assertEq((aggregationLayerVault.getStrategy(address(eTST))).allocated, expectedStrategyCash); } vm.warp(block.timestamp + 86400); // mock an increase of strategy balance by 10% - uint256 aggrCurrentStrategyShareBalance = eTST.balanceOf(address(fourSixTwoSixAgg)); + uint256 aggrCurrentStrategyShareBalance = eTST.balanceOf(address(aggregationLayerVault)); uint256 aggrCurrentStrategyUnderlyingBalance = eTST.convertToAssets(aggrCurrentStrategyShareBalance); uint256 aggrNewStrategyUnderlyingBalance = aggrCurrentStrategyUnderlyingBalance * 11e17 / 1e18; uint256 yield = aggrNewStrategyUnderlyingBalance - aggrCurrentStrategyUnderlyingBalance; assetTST.mint(address(eTST), yield); - eTST.skim(type(uint256).max, address(fourSixTwoSixAgg)); + eTST.skim(type(uint256).max, address(aggregationLayerVault)); // harvest vm.prank(user1); - fourSixTwoSixAgg.harvest(address(eTST)); + aggregationLayerVault.harvest(address(eTST)); vm.warp(block.timestamp + 2 weeks); // full withdraw, will have to withdraw from strategy as cash reserve is not enough { - uint256 amountToWithdraw = fourSixTwoSixAgg.balanceOf(user1); - uint256 totalAssetsDepositedBefore = fourSixTwoSixAgg.totalAssetsDeposited(); - uint256 aggregatorTotalSupplyBefore = fourSixTwoSixAgg.totalSupply(); + uint256 amountToWithdraw = aggregationLayerVault.balanceOf(user1); + uint256 totalAssetsDepositedBefore = aggregationLayerVault.totalAssetsDeposited(); + uint256 aggregatorTotalSupplyBefore = aggregationLayerVault.totalSupply(); uint256 user1AssetTSTBalanceBefore = assetTST.balanceOf(user1); vm.prank(user1); - fourSixTwoSixAgg.redeem(amountToWithdraw, user1, user1); + aggregationLayerVault.redeem(amountToWithdraw, user1, user1); // all yield is distributed - assertApproxEqAbs(eTST.balanceOf(address(fourSixTwoSixAgg)), 0, 1); - assertApproxEqAbs(fourSixTwoSixAgg.totalAssetsDeposited(), totalAssetsDepositedBefore - amountToWithdraw, 1); - assertEq(fourSixTwoSixAgg.totalSupply(), aggregatorTotalSupplyBefore - amountToWithdraw); + assertApproxEqAbs(eTST.balanceOf(address(aggregationLayerVault)), 0, 1); + assertApproxEqAbs( + aggregationLayerVault.totalAssetsDeposited(), totalAssetsDepositedBefore - amountToWithdraw, 1 + ); + assertEq(aggregationLayerVault.totalSupply(), aggregatorTotalSupplyBefore - amountToWithdraw); assertApproxEqAbs(assetTST.balanceOf(user1), user1AssetTSTBalanceBefore + amountToDeposit + yield, 1); } } @@ -384,19 +390,19 @@ contract DepositRebalanceHarvestWithdrawE2ETest is FourSixTwoSixAggBase { // deposit into aggregator { - uint256 balanceBefore = fourSixTwoSixAgg.balanceOf(user1); - uint256 totalSupplyBefore = fourSixTwoSixAgg.totalSupply(); - uint256 totalAssetsDepositedBefore = fourSixTwoSixAgg.totalAssetsDeposited(); + uint256 balanceBefore = aggregationLayerVault.balanceOf(user1); + uint256 totalSupplyBefore = aggregationLayerVault.totalSupply(); + uint256 totalAssetsDepositedBefore = aggregationLayerVault.totalAssetsDeposited(); uint256 userAssetBalanceBefore = assetTST.balanceOf(user1); vm.startPrank(user1); - assetTST.approve(address(fourSixTwoSixAgg), amountToDeposit); - fourSixTwoSixAgg.deposit(amountToDeposit, user1); + assetTST.approve(address(aggregationLayerVault), amountToDeposit); + aggregationLayerVault.deposit(amountToDeposit, user1); vm.stopPrank(); - assertEq(fourSixTwoSixAgg.balanceOf(user1), balanceBefore + amountToDeposit); - assertEq(fourSixTwoSixAgg.totalSupply(), totalSupplyBefore + amountToDeposit); - assertEq(fourSixTwoSixAgg.totalAssetsDeposited(), totalAssetsDepositedBefore + amountToDeposit); + assertEq(aggregationLayerVault.balanceOf(user1), balanceBefore + amountToDeposit); + assertEq(aggregationLayerVault.totalSupply(), totalSupplyBefore + amountToDeposit); + assertEq(aggregationLayerVault.totalAssetsDeposited(), totalAssetsDepositedBefore + amountToDeposit); assertEq(assetTST.balanceOf(user1), userAssetBalanceBefore - amountToDeposit); } @@ -405,20 +411,19 @@ contract DepositRebalanceHarvestWithdrawE2ETest is FourSixTwoSixAggBase { // 10k deposited; 4000 for reserve, 2000 for eTST, 4000 for eTSTsecondary vm.warp(block.timestamp + 86400); { - FourSixTwoSixAgg.Strategy memory eTSTstrategyBefore = fourSixTwoSixAgg.getStrategy(address(eTST)); - FourSixTwoSixAgg.Strategy memory eTSTsecondarystrategyBefore = - fourSixTwoSixAgg.getStrategy(address(eTSTsecondary)); + Strategy memory eTSTstrategyBefore = aggregationLayerVault.getStrategy(address(eTST)); + Strategy memory eTSTsecondarystrategyBefore = aggregationLayerVault.getStrategy(address(eTSTsecondary)); - assertEq(eTST.convertToAssets(eTST.balanceOf(address(fourSixTwoSixAgg))), eTSTstrategyBefore.allocated); + assertEq(eTST.convertToAssets(eTST.balanceOf(address(aggregationLayerVault))), eTSTstrategyBefore.allocated); assertEq( - eTSTsecondary.convertToAssets(eTSTsecondary.balanceOf(address(fourSixTwoSixAgg))), + eTSTsecondary.convertToAssets(eTSTsecondary.balanceOf(address(aggregationLayerVault))), eTSTsecondarystrategyBefore.allocated ); - uint256 expectedeTSTStrategyCash = fourSixTwoSixAgg.totalAssetsAllocatable() - * eTSTstrategyBefore.allocationPoints / fourSixTwoSixAgg.totalAllocationPoints(); - uint256 expectedeTSTsecondaryStrategyCash = fourSixTwoSixAgg.totalAssetsAllocatable() - * eTSTsecondarystrategyBefore.allocationPoints / fourSixTwoSixAgg.totalAllocationPoints(); + uint256 expectedeTSTStrategyCash = aggregationLayerVault.totalAssetsAllocatable() + * eTSTstrategyBefore.allocationPoints / aggregationLayerVault.totalAllocationPoints(); + uint256 expectedeTSTsecondaryStrategyCash = aggregationLayerVault.totalAssetsAllocatable() + * eTSTsecondarystrategyBefore.allocationPoints / aggregationLayerVault.totalAllocationPoints(); assertTrue(expectedeTSTStrategyCash != 0); assertTrue(expectedeTSTsecondaryStrategyCash != 0); @@ -427,20 +432,22 @@ contract DepositRebalanceHarvestWithdrawE2ETest is FourSixTwoSixAggBase { strategiesToRebalance[0] = address(eTST); strategiesToRebalance[1] = address(eTSTsecondary); vm.prank(user1); - rebalancer.executeRebalance(address(fourSixTwoSixAgg), strategiesToRebalance); + rebalancer.executeRebalance(address(aggregationLayerVault), strategiesToRebalance); - assertEq(fourSixTwoSixAgg.totalAllocated(), expectedeTSTStrategyCash + expectedeTSTsecondaryStrategyCash); - assertEq(eTST.convertToAssets(eTST.balanceOf(address(fourSixTwoSixAgg))), expectedeTSTStrategyCash); assertEq( - eTSTsecondary.convertToAssets(eTSTsecondary.balanceOf(address(fourSixTwoSixAgg))), + aggregationLayerVault.totalAllocated(), expectedeTSTStrategyCash + expectedeTSTsecondaryStrategyCash + ); + assertEq(eTST.convertToAssets(eTST.balanceOf(address(aggregationLayerVault))), expectedeTSTStrategyCash); + assertEq( + eTSTsecondary.convertToAssets(eTSTsecondary.balanceOf(address(aggregationLayerVault))), expectedeTSTsecondaryStrategyCash ); - assertEq((fourSixTwoSixAgg.getStrategy(address(eTST))).allocated, expectedeTSTStrategyCash); + assertEq((aggregationLayerVault.getStrategy(address(eTST))).allocated, expectedeTSTStrategyCash); assertEq( - (fourSixTwoSixAgg.getStrategy(address(eTSTsecondary))).allocated, expectedeTSTsecondaryStrategyCash + (aggregationLayerVault.getStrategy(address(eTSTsecondary))).allocated, expectedeTSTsecondaryStrategyCash ); assertEq( - assetTST.balanceOf(address(fourSixTwoSixAgg)), + assetTST.balanceOf(address(aggregationLayerVault)), amountToDeposit - (expectedeTSTStrategyCash + expectedeTSTsecondaryStrategyCash) ); } @@ -450,9 +457,9 @@ contract DepositRebalanceHarvestWithdrawE2ETest is FourSixTwoSixAggBase { uint256 eTSTsecondaryYield; { // mock an increase of aggregator balance due to yield - uint256 aggrCurrenteTSTShareBalance = eTST.balanceOf(address(fourSixTwoSixAgg)); + uint256 aggrCurrenteTSTShareBalance = eTST.balanceOf(address(aggregationLayerVault)); uint256 aggrCurrenteTSTUnderlyingBalance = eTST.convertToAssets(aggrCurrenteTSTShareBalance); - uint256 aggrCurrenteTSTsecondaryShareBalance = eTSTsecondary.balanceOf(address(fourSixTwoSixAgg)); + uint256 aggrCurrenteTSTsecondaryShareBalance = eTSTsecondary.balanceOf(address(aggregationLayerVault)); uint256 aggrCurrenteTSTsecondaryUnderlyingBalance = eTST.convertToAssets(aggrCurrenteTSTsecondaryShareBalance); uint256 aggrNeweTSTUnderlyingBalance = aggrCurrenteTSTUnderlyingBalance * 11e17 / 1e18; @@ -462,8 +469,8 @@ contract DepositRebalanceHarvestWithdrawE2ETest is FourSixTwoSixAggBase { assetTST.mint(address(eTST), eTSTYield); assetTST.mint(address(eTSTsecondary), eTSTsecondaryYield); - eTST.skim(type(uint256).max, address(fourSixTwoSixAgg)); - eTSTsecondary.skim(type(uint256).max, address(fourSixTwoSixAgg)); + eTST.skim(type(uint256).max, address(aggregationLayerVault)); + eTSTsecondary.skim(type(uint256).max, address(aggregationLayerVault)); } // harvest @@ -471,22 +478,24 @@ contract DepositRebalanceHarvestWithdrawE2ETest is FourSixTwoSixAggBase { strategiesToHarvest[0] = address(eTST); strategiesToHarvest[1] = address(eTSTsecondary); vm.prank(user1); - fourSixTwoSixAgg.harvestMultipleStrategies(strategiesToHarvest); + aggregationLayerVault.harvestMultipleStrategies(strategiesToHarvest); vm.warp(block.timestamp + 2 weeks); // full withdraw, will have to withdraw from strategy as cash reserve is not enough { - uint256 amountToWithdraw = fourSixTwoSixAgg.balanceOf(user1); - uint256 totalAssetsDepositedBefore = fourSixTwoSixAgg.totalAssetsDeposited(); - uint256 aggregatorTotalSupplyBefore = fourSixTwoSixAgg.totalSupply(); + uint256 amountToWithdraw = aggregationLayerVault.balanceOf(user1); + uint256 totalAssetsDepositedBefore = aggregationLayerVault.totalAssetsDeposited(); + uint256 aggregatorTotalSupplyBefore = aggregationLayerVault.totalSupply(); uint256 user1AssetTSTBalanceBefore = assetTST.balanceOf(user1); vm.prank(user1); - fourSixTwoSixAgg.redeem(amountToWithdraw, user1, user1); + aggregationLayerVault.redeem(amountToWithdraw, user1, user1); - assertApproxEqAbs(eTST.balanceOf(address(fourSixTwoSixAgg)), 0, 0); - assertApproxEqAbs(fourSixTwoSixAgg.totalAssetsDeposited(), totalAssetsDepositedBefore - amountToWithdraw, 1); - assertEq(fourSixTwoSixAgg.totalSupply(), aggregatorTotalSupplyBefore - amountToWithdraw); + assertApproxEqAbs(eTST.balanceOf(address(aggregationLayerVault)), 0, 0); + assertApproxEqAbs( + aggregationLayerVault.totalAssetsDeposited(), totalAssetsDepositedBefore - amountToWithdraw, 1 + ); + assertEq(aggregationLayerVault.totalSupply(), aggregatorTotalSupplyBefore - amountToWithdraw); assertApproxEqAbs( assetTST.balanceOf(user1), user1AssetTSTBalanceBefore + amountToDeposit + eTSTYield + eTSTsecondaryYield, @@ -515,19 +524,19 @@ contract DepositRebalanceHarvestWithdrawE2ETest is FourSixTwoSixAggBase { // deposit into aggregator { - uint256 balanceBefore = fourSixTwoSixAgg.balanceOf(user1); - uint256 totalSupplyBefore = fourSixTwoSixAgg.totalSupply(); - uint256 totalAssetsDepositedBefore = fourSixTwoSixAgg.totalAssetsDeposited(); + uint256 balanceBefore = aggregationLayerVault.balanceOf(user1); + uint256 totalSupplyBefore = aggregationLayerVault.totalSupply(); + uint256 totalAssetsDepositedBefore = aggregationLayerVault.totalAssetsDeposited(); uint256 userAssetBalanceBefore = assetTST.balanceOf(user1); vm.startPrank(user1); - assetTST.approve(address(fourSixTwoSixAgg), amountToDeposit); - fourSixTwoSixAgg.deposit(amountToDeposit, user1); + assetTST.approve(address(aggregationLayerVault), amountToDeposit); + aggregationLayerVault.deposit(amountToDeposit, user1); vm.stopPrank(); - assertEq(fourSixTwoSixAgg.balanceOf(user1), balanceBefore + amountToDeposit); - assertEq(fourSixTwoSixAgg.totalSupply(), totalSupplyBefore + amountToDeposit); - assertEq(fourSixTwoSixAgg.totalAssetsDeposited(), totalAssetsDepositedBefore + amountToDeposit); + assertEq(aggregationLayerVault.balanceOf(user1), balanceBefore + amountToDeposit); + assertEq(aggregationLayerVault.totalSupply(), totalSupplyBefore + amountToDeposit); + assertEq(aggregationLayerVault.totalAssetsDeposited(), totalAssetsDepositedBefore + amountToDeposit); assertEq(assetTST.balanceOf(user1), userAssetBalanceBefore - amountToDeposit); } @@ -536,20 +545,19 @@ contract DepositRebalanceHarvestWithdrawE2ETest is FourSixTwoSixAggBase { // 10k deposited; 4000 for reserve, 2000 for eTST, 4000 for eTSTsecondary vm.warp(block.timestamp + 86400); { - FourSixTwoSixAgg.Strategy memory eTSTstrategyBefore = fourSixTwoSixAgg.getStrategy(address(eTST)); - FourSixTwoSixAgg.Strategy memory eTSTsecondarystrategyBefore = - fourSixTwoSixAgg.getStrategy(address(eTSTsecondary)); + Strategy memory eTSTstrategyBefore = aggregationLayerVault.getStrategy(address(eTST)); + Strategy memory eTSTsecondarystrategyBefore = aggregationLayerVault.getStrategy(address(eTSTsecondary)); - assertEq(eTST.convertToAssets(eTST.balanceOf(address(fourSixTwoSixAgg))), eTSTstrategyBefore.allocated); + assertEq(eTST.convertToAssets(eTST.balanceOf(address(aggregationLayerVault))), eTSTstrategyBefore.allocated); assertEq( - eTSTsecondary.convertToAssets(eTSTsecondary.balanceOf(address(fourSixTwoSixAgg))), + eTSTsecondary.convertToAssets(eTSTsecondary.balanceOf(address(aggregationLayerVault))), eTSTsecondarystrategyBefore.allocated ); - uint256 expectedeTSTStrategyCash = fourSixTwoSixAgg.totalAssetsAllocatable() - * eTSTstrategyBefore.allocationPoints / fourSixTwoSixAgg.totalAllocationPoints(); - uint256 expectedeTSTsecondaryStrategyCash = fourSixTwoSixAgg.totalAssetsAllocatable() - * eTSTsecondarystrategyBefore.allocationPoints / fourSixTwoSixAgg.totalAllocationPoints(); + uint256 expectedeTSTStrategyCash = aggregationLayerVault.totalAssetsAllocatable() + * eTSTstrategyBefore.allocationPoints / aggregationLayerVault.totalAllocationPoints(); + uint256 expectedeTSTsecondaryStrategyCash = aggregationLayerVault.totalAssetsAllocatable() + * eTSTsecondarystrategyBefore.allocationPoints / aggregationLayerVault.totalAllocationPoints(); assertTrue(expectedeTSTStrategyCash != 0); assertTrue(expectedeTSTsecondaryStrategyCash != 0); @@ -558,20 +566,22 @@ contract DepositRebalanceHarvestWithdrawE2ETest is FourSixTwoSixAggBase { strategiesToRebalance[0] = address(eTST); strategiesToRebalance[1] = address(eTSTsecondary); vm.prank(user1); - rebalancer.executeRebalance(address(fourSixTwoSixAgg), strategiesToRebalance); + rebalancer.executeRebalance(address(aggregationLayerVault), strategiesToRebalance); - assertEq(fourSixTwoSixAgg.totalAllocated(), expectedeTSTStrategyCash + expectedeTSTsecondaryStrategyCash); - assertEq(eTST.convertToAssets(eTST.balanceOf(address(fourSixTwoSixAgg))), expectedeTSTStrategyCash); assertEq( - eTSTsecondary.convertToAssets(eTSTsecondary.balanceOf(address(fourSixTwoSixAgg))), + aggregationLayerVault.totalAllocated(), expectedeTSTStrategyCash + expectedeTSTsecondaryStrategyCash + ); + assertEq(eTST.convertToAssets(eTST.balanceOf(address(aggregationLayerVault))), expectedeTSTStrategyCash); + assertEq( + eTSTsecondary.convertToAssets(eTSTsecondary.balanceOf(address(aggregationLayerVault))), expectedeTSTsecondaryStrategyCash ); - assertEq((fourSixTwoSixAgg.getStrategy(address(eTST))).allocated, expectedeTSTStrategyCash); + assertEq((aggregationLayerVault.getStrategy(address(eTST))).allocated, expectedeTSTStrategyCash); assertEq( - (fourSixTwoSixAgg.getStrategy(address(eTSTsecondary))).allocated, expectedeTSTsecondaryStrategyCash + (aggregationLayerVault.getStrategy(address(eTSTsecondary))).allocated, expectedeTSTsecondaryStrategyCash ); assertEq( - assetTST.balanceOf(address(fourSixTwoSixAgg)), + assetTST.balanceOf(address(aggregationLayerVault)), amountToDeposit - (expectedeTSTStrategyCash + expectedeTSTsecondaryStrategyCash) ); } @@ -581,9 +591,9 @@ contract DepositRebalanceHarvestWithdrawE2ETest is FourSixTwoSixAggBase { uint256 eTSTsecondaryYield; { // mock an increase of aggregator balance due to yield - uint256 aggrCurrenteTSTShareBalance = eTST.balanceOf(address(fourSixTwoSixAgg)); + uint256 aggrCurrenteTSTShareBalance = eTST.balanceOf(address(aggregationLayerVault)); uint256 aggrCurrenteTSTUnderlyingBalance = eTST.convertToAssets(aggrCurrenteTSTShareBalance); - uint256 aggrCurrenteTSTsecondaryShareBalance = eTSTsecondary.balanceOf(address(fourSixTwoSixAgg)); + uint256 aggrCurrenteTSTsecondaryShareBalance = eTSTsecondary.balanceOf(address(aggregationLayerVault)); uint256 aggrCurrenteTSTsecondaryUnderlyingBalance = eTST.convertToAssets(aggrCurrenteTSTsecondaryShareBalance); uint256 aggrNeweTSTUnderlyingBalance = aggrCurrenteTSTUnderlyingBalance * 11e17 / 1e18; @@ -593,26 +603,26 @@ contract DepositRebalanceHarvestWithdrawE2ETest is FourSixTwoSixAggBase { assetTST.mint(address(eTST), eTSTYield); assetTST.mint(address(eTSTsecondary), eTSTsecondaryYield); - eTST.skim(type(uint256).max, address(fourSixTwoSixAgg)); - eTSTsecondary.skim(type(uint256).max, address(fourSixTwoSixAgg)); + eTST.skim(type(uint256).max, address(aggregationLayerVault)); + eTSTsecondary.skim(type(uint256).max, address(aggregationLayerVault)); } // harvest address[] memory strategiesToHarvest = new address[](1); strategiesToHarvest[0] = address(eTST); vm.prank(user1); - fourSixTwoSixAgg.harvestMultipleStrategies(strategiesToHarvest); + aggregationLayerVault.harvestMultipleStrategies(strategiesToHarvest); vm.warp(block.timestamp + 2 weeks); vm.prank(manager); - fourSixTwoSixAgg.removeStrategy(address(eTSTsecondary)); + aggregationLayerVault.removeStrategy(address(eTSTsecondary)); { - uint256 amountToWithdraw = fourSixTwoSixAgg.balanceOf(user1); + uint256 amountToWithdraw = aggregationLayerVault.balanceOf(user1); vm.prank(user1); - vm.expectRevert(FourSixTwoSixAgg.NotEnoughAssets.selector); - fourSixTwoSixAgg.redeem(amountToWithdraw, user1, user1); + vm.expectRevert(WithdrawalQueue.NotEnoughAssets.selector); + aggregationLayerVault.redeem(amountToWithdraw, user1, user1); } } } diff --git a/test/e2e/HooksE2ETest.t.sol b/test/e2e/HooksE2ETest.t.sol index efff9207..59bb388b 100644 --- a/test/e2e/HooksE2ETest.t.sol +++ b/test/e2e/HooksE2ETest.t.sol @@ -2,18 +2,18 @@ pragma solidity ^0.8.0; import { - FourSixTwoSixAggBase, - FourSixTwoSixAgg, + AggregationLayerVaultBase, + AggregationLayerVault, console2, EVault, IEVault, IRMTestDefault, TestERC20, IHookTarget, - Hooks -} from "../common/FourSixTwoSixAggBase.t.sol"; + ErrorsLib +} from "../common/AggregationLayerVaultBase.t.sol"; -contract HooksE2ETest is FourSixTwoSixAggBase { +contract HooksE2ETest is AggregationLayerVaultBase { uint256 user1InitialBalance = 100000e18; function setUp() public virtual override { @@ -26,38 +26,38 @@ contract HooksE2ETest is FourSixTwoSixAggBase { } function testSetHooksConfig() public { - uint32 expectedHookedFns = fourSixTwoSixAgg.DEPOSIT() | fourSixTwoSixAgg.WITHDRAW() - | fourSixTwoSixAgg.ADD_STRATEGY() | fourSixTwoSixAgg.REMOVE_STRATEGY(); + uint32 expectedHookedFns = aggregationLayerVault.DEPOSIT() | aggregationLayerVault.WITHDRAW() + | aggregationLayerVault.ADD_STRATEGY() | aggregationLayerVault.REMOVE_STRATEGY(); vm.startPrank(manager); address hooksContract = address(new HooksContract()); - fourSixTwoSixAgg.setHooksConfig(hooksContract, expectedHookedFns); + aggregationLayerVault.setHooksConfig(hooksContract, expectedHookedFns); vm.stopPrank(); - (address hookTarget, uint32 hookedFns) = fourSixTwoSixAgg.getHooksConfig(); + (address hookTarget, uint32 hookedFns) = aggregationLayerVault.getHooksConfig(); assertEq(hookTarget, hooksContract); assertEq(hookedFns, expectedHookedFns); } function testSetHooksConfigWithAddressZero() public { - uint32 expectedHookedFns = fourSixTwoSixAgg.DEPOSIT() | fourSixTwoSixAgg.WITHDRAW() - | fourSixTwoSixAgg.ADD_STRATEGY() | fourSixTwoSixAgg.REMOVE_STRATEGY(); + uint32 expectedHookedFns = aggregationLayerVault.DEPOSIT() | aggregationLayerVault.WITHDRAW() + | aggregationLayerVault.ADD_STRATEGY() | aggregationLayerVault.REMOVE_STRATEGY(); vm.startPrank(manager); - vm.expectRevert(Hooks.InvalidHooksTarget.selector); - fourSixTwoSixAgg.setHooksConfig(address(0), expectedHookedFns); + vm.expectRevert(ErrorsLib.InvalidHooksTarget.selector); + aggregationLayerVault.setHooksConfig(address(0), expectedHookedFns); vm.stopPrank(); } function testSetHooksConfigWithNotHooksContract() public { - uint32 expectedHookedFns = fourSixTwoSixAgg.DEPOSIT() | fourSixTwoSixAgg.WITHDRAW() - | fourSixTwoSixAgg.ADD_STRATEGY() | fourSixTwoSixAgg.REMOVE_STRATEGY(); + uint32 expectedHookedFns = aggregationLayerVault.DEPOSIT() | aggregationLayerVault.WITHDRAW() + | aggregationLayerVault.ADD_STRATEGY() | aggregationLayerVault.REMOVE_STRATEGY(); vm.startPrank(manager); address hooksContract = address(new NotHooksContract()); - vm.expectRevert(Hooks.NotHooksContract.selector); - fourSixTwoSixAgg.setHooksConfig(hooksContract, expectedHookedFns); + vm.expectRevert(ErrorsLib.NotHooksContract.selector); + aggregationLayerVault.setHooksConfig(hooksContract, expectedHookedFns); vm.stopPrank(); } @@ -65,34 +65,34 @@ contract HooksE2ETest is FourSixTwoSixAggBase { uint32 expectedHookedFns = 1 << 5; vm.startPrank(manager); address hooksContract = address(new HooksContract()); - vm.expectRevert(Hooks.InvalidHookedFns.selector); - fourSixTwoSixAgg.setHooksConfig(hooksContract, expectedHookedFns); + vm.expectRevert(ErrorsLib.InvalidHookedFns.selector); + aggregationLayerVault.setHooksConfig(hooksContract, expectedHookedFns); vm.stopPrank(); } function testHookedDeposit() public { - uint32 expectedHookedFns = fourSixTwoSixAgg.DEPOSIT(); + uint32 expectedHookedFns = aggregationLayerVault.DEPOSIT(); vm.startPrank(manager); address hooksContract = address(new HooksContract()); - fourSixTwoSixAgg.setHooksConfig(hooksContract, expectedHookedFns); + aggregationLayerVault.setHooksConfig(hooksContract, expectedHookedFns); vm.stopPrank(); uint256 amountToDeposit = 10000e18; // deposit into aggregator { - uint256 balanceBefore = fourSixTwoSixAgg.balanceOf(user1); - uint256 totalSupplyBefore = fourSixTwoSixAgg.totalSupply(); - uint256 totalAssetsDepositedBefore = fourSixTwoSixAgg.totalAssetsDeposited(); + uint256 balanceBefore = aggregationLayerVault.balanceOf(user1); + uint256 totalSupplyBefore = aggregationLayerVault.totalSupply(); + uint256 totalAssetsDepositedBefore = aggregationLayerVault.totalAssetsDeposited(); uint256 userAssetBalanceBefore = assetTST.balanceOf(user1); vm.startPrank(user1); - assetTST.approve(address(fourSixTwoSixAgg), amountToDeposit); - fourSixTwoSixAgg.deposit(amountToDeposit, user1); + assetTST.approve(address(aggregationLayerVault), amountToDeposit); + aggregationLayerVault.deposit(amountToDeposit, user1); vm.stopPrank(); - assertEq(fourSixTwoSixAgg.balanceOf(user1), balanceBefore + amountToDeposit); - assertEq(fourSixTwoSixAgg.totalSupply(), totalSupplyBefore + amountToDeposit); - assertEq(fourSixTwoSixAgg.totalAssetsDeposited(), totalAssetsDepositedBefore + amountToDeposit); + assertEq(aggregationLayerVault.balanceOf(user1), balanceBefore + amountToDeposit); + assertEq(aggregationLayerVault.totalSupply(), totalSupplyBefore + amountToDeposit); + assertEq(aggregationLayerVault.totalAssetsDeposited(), totalAssetsDepositedBefore + amountToDeposit); assertEq(assetTST.balanceOf(user1), userAssetBalanceBefore - amountToDeposit); } } diff --git a/test/e2e/PerformanceFeeE2ETest.t.sol b/test/e2e/PerformanceFeeE2ETest.t.sol index f72e6eb8..1bb5cb55 100644 --- a/test/e2e/PerformanceFeeE2ETest.t.sol +++ b/test/e2e/PerformanceFeeE2ETest.t.sol @@ -2,16 +2,17 @@ pragma solidity ^0.8.0; import { - FourSixTwoSixAggBase, - FourSixTwoSixAgg, + AggregationLayerVaultBase, + AggregationLayerVault, console2, EVault, IEVault, IRMTestDefault, - TestERC20 -} from "../common/FourSixTwoSixAggBase.t.sol"; + TestERC20, + Strategy +} from "../common/AggregationLayerVaultBase.t.sol"; -contract PerformanceFeeE2ETest is FourSixTwoSixAggBase { +contract PerformanceFeeE2ETest is AggregationLayerVaultBase { uint256 user1InitialBalance = 100000e18; address feeRecipient; @@ -28,123 +29,132 @@ contract PerformanceFeeE2ETest is FourSixTwoSixAggBase { } function testSetPerformanceFee() public { - assertEq(fourSixTwoSixAgg.performanceFee(), 0); + { + (, uint256 fee) = aggregationLayerVault.performanceFeeConfig(); + assertEq(fee, 0); + } uint256 newPerformanceFee = 3e17; vm.startPrank(manager); - fourSixTwoSixAgg.setFeeRecipient(feeRecipient); - fourSixTwoSixAgg.setPerformanceFee(newPerformanceFee); + aggregationLayerVault.setFeeRecipient(feeRecipient); + aggregationLayerVault.setPerformanceFee(newPerformanceFee); vm.stopPrank(); - assertEq(fourSixTwoSixAgg.performanceFee(), newPerformanceFee); - assertEq(fourSixTwoSixAgg.feeRecipient(), feeRecipient); + (address feeRecipientAddr, uint256 fee) = aggregationLayerVault.performanceFeeConfig(); + assertEq(fee, newPerformanceFee); + assertEq(feeRecipientAddr, feeRecipient); } function testHarvestWithFeeEnabled() public { uint256 newPerformanceFee = 3e17; vm.startPrank(manager); - fourSixTwoSixAgg.setFeeRecipient(feeRecipient); - fourSixTwoSixAgg.setPerformanceFee(newPerformanceFee); + aggregationLayerVault.setFeeRecipient(feeRecipient); + aggregationLayerVault.setPerformanceFee(newPerformanceFee); vm.stopPrank(); uint256 amountToDeposit = 10000e18; // deposit into aggregator { - uint256 balanceBefore = fourSixTwoSixAgg.balanceOf(user1); - uint256 totalSupplyBefore = fourSixTwoSixAgg.totalSupply(); - uint256 totalAssetsDepositedBefore = fourSixTwoSixAgg.totalAssetsDeposited(); + uint256 balanceBefore = aggregationLayerVault.balanceOf(user1); + uint256 totalSupplyBefore = aggregationLayerVault.totalSupply(); + uint256 totalAssetsDepositedBefore = aggregationLayerVault.totalAssetsDeposited(); uint256 userAssetBalanceBefore = assetTST.balanceOf(user1); vm.startPrank(user1); - assetTST.approve(address(fourSixTwoSixAgg), amountToDeposit); - fourSixTwoSixAgg.deposit(amountToDeposit, user1); + assetTST.approve(address(aggregationLayerVault), amountToDeposit); + aggregationLayerVault.deposit(amountToDeposit, user1); vm.stopPrank(); - assertEq(fourSixTwoSixAgg.balanceOf(user1), balanceBefore + amountToDeposit); - assertEq(fourSixTwoSixAgg.totalSupply(), totalSupplyBefore + amountToDeposit); - assertEq(fourSixTwoSixAgg.totalAssetsDeposited(), totalAssetsDepositedBefore + amountToDeposit); + assertEq(aggregationLayerVault.balanceOf(user1), balanceBefore + amountToDeposit); + assertEq(aggregationLayerVault.totalSupply(), totalSupplyBefore + amountToDeposit); + assertEq(aggregationLayerVault.totalAssetsDeposited(), totalAssetsDepositedBefore + amountToDeposit); assertEq(assetTST.balanceOf(user1), userAssetBalanceBefore - amountToDeposit); } // rebalance into strategy vm.warp(block.timestamp + 86400); { - FourSixTwoSixAgg.Strategy memory strategyBefore = fourSixTwoSixAgg.getStrategy(address(eTST)); + Strategy memory strategyBefore = aggregationLayerVault.getStrategy(address(eTST)); - assertEq(eTST.convertToAssets(eTST.balanceOf(address(fourSixTwoSixAgg))), strategyBefore.allocated); + assertEq(eTST.convertToAssets(eTST.balanceOf(address(aggregationLayerVault))), strategyBefore.allocated); - uint256 expectedStrategyCash = fourSixTwoSixAgg.totalAssetsAllocatable() * strategyBefore.allocationPoints - / fourSixTwoSixAgg.totalAllocationPoints(); + uint256 expectedStrategyCash = aggregationLayerVault.totalAssetsAllocatable() + * strategyBefore.allocationPoints / aggregationLayerVault.totalAllocationPoints(); vm.prank(user1); address[] memory strategiesToRebalance = new address[](1); strategiesToRebalance[0] = address(eTST); - rebalancer.executeRebalance(address(fourSixTwoSixAgg), strategiesToRebalance); + rebalancer.executeRebalance(address(aggregationLayerVault), strategiesToRebalance); - assertEq(fourSixTwoSixAgg.totalAllocated(), expectedStrategyCash); - assertEq(eTST.convertToAssets(eTST.balanceOf(address(fourSixTwoSixAgg))), expectedStrategyCash); - assertEq((fourSixTwoSixAgg.getStrategy(address(eTST))).allocated, expectedStrategyCash); + assertEq(aggregationLayerVault.totalAllocated(), expectedStrategyCash); + assertEq(eTST.convertToAssets(eTST.balanceOf(address(aggregationLayerVault))), expectedStrategyCash); + assertEq((aggregationLayerVault.getStrategy(address(eTST))).allocated, expectedStrategyCash); } vm.warp(block.timestamp + 86400); // mock an increase of strategy balance by 10% uint256 yield; { - uint256 aggrCurrentStrategyShareBalance = eTST.balanceOf(address(fourSixTwoSixAgg)); + uint256 aggrCurrentStrategyShareBalance = eTST.balanceOf(address(aggregationLayerVault)); uint256 aggrCurrentStrategyUnderlyingBalance = eTST.convertToAssets(aggrCurrentStrategyShareBalance); uint256 aggrNewStrategyUnderlyingBalance = aggrCurrentStrategyUnderlyingBalance * 11e17 / 1e18; yield = aggrNewStrategyUnderlyingBalance - aggrCurrentStrategyUnderlyingBalance; assetTST.mint(address(eTST), yield); - eTST.skim(type(uint256).max, address(fourSixTwoSixAgg)); + eTST.skim(type(uint256).max, address(aggregationLayerVault)); } - uint256 expectedPerformanceFee = yield * fourSixTwoSixAgg.performanceFee() / 1e18; + (, uint256 performanceFee) = aggregationLayerVault.performanceFeeConfig(); + uint256 expectedPerformanceFee = yield * performanceFee / 1e18; - FourSixTwoSixAgg.Strategy memory strategyBeforeHarvest = fourSixTwoSixAgg.getStrategy(address(eTST)); - uint256 totalAllocatedBefore = fourSixTwoSixAgg.totalAllocated(); + Strategy memory strategyBeforeHarvest = aggregationLayerVault.getStrategy(address(eTST)); + uint256 totalAllocatedBefore = aggregationLayerVault.totalAllocated(); // harvest vm.prank(user1); - fourSixTwoSixAgg.harvest(address(eTST)); + aggregationLayerVault.harvest(address(eTST)); assertEq(assetTST.balanceOf(feeRecipient), expectedPerformanceFee); assertEq( - fourSixTwoSixAgg.getStrategy(address(eTST)).allocated, + aggregationLayerVault.getStrategy(address(eTST)).allocated, strategyBeforeHarvest.allocated + yield - expectedPerformanceFee ); - assertEq(fourSixTwoSixAgg.totalAllocated(), totalAllocatedBefore + yield - expectedPerformanceFee); + assertEq(aggregationLayerVault.totalAllocated(), totalAllocatedBefore + yield - expectedPerformanceFee); // full withdraw, will have to withdraw from strategy as cash reserve is not enough { - uint256 amountToWithdraw = fourSixTwoSixAgg.balanceOf(user1); - uint256 totalAssetsDepositedBefore = fourSixTwoSixAgg.totalAssetsDeposited(); - uint256 aggregatorTotalSupplyBefore = fourSixTwoSixAgg.totalSupply(); + uint256 amountToWithdraw = aggregationLayerVault.balanceOf(user1); + uint256 totalAssetsDepositedBefore = aggregationLayerVault.totalAssetsDeposited(); + uint256 aggregatorTotalSupplyBefore = aggregationLayerVault.totalSupply(); uint256 user1AssetTSTBalanceBefore = assetTST.balanceOf(user1); - uint256 expectedAssetTST = fourSixTwoSixAgg.convertToAssets(fourSixTwoSixAgg.balanceOf(user1)); + uint256 expectedAssetTST = aggregationLayerVault.convertToAssets(aggregationLayerVault.balanceOf(user1)); vm.prank(user1); - fourSixTwoSixAgg.redeem(amountToWithdraw, user1, user1); + aggregationLayerVault.redeem(amountToWithdraw, user1, user1); - assertApproxEqAbs(fourSixTwoSixAgg.totalAssetsDeposited(), totalAssetsDepositedBefore - expectedAssetTST, 1); - assertEq(fourSixTwoSixAgg.totalSupply(), aggregatorTotalSupplyBefore - amountToWithdraw); + assertApproxEqAbs( + aggregationLayerVault.totalAssetsDeposited(), totalAssetsDepositedBefore - expectedAssetTST, 1 + ); + assertEq(aggregationLayerVault.totalSupply(), aggregatorTotalSupplyBefore - amountToWithdraw); assertApproxEqAbs(assetTST.balanceOf(user1), user1AssetTSTBalanceBefore + expectedAssetTST, 1); } // full withdraw of recipient fees { - uint256 totalAssetsDepositedBefore = fourSixTwoSixAgg.totalAssetsDeposited(); + uint256 totalAssetsDepositedBefore = aggregationLayerVault.totalAssetsDeposited(); uint256 assetTSTBalanceBefore = assetTST.balanceOf(feeRecipient); - uint256 feeShares = fourSixTwoSixAgg.balanceOf(feeRecipient); - uint256 expectedAssets = fourSixTwoSixAgg.convertToAssets(feeShares); + uint256 feeShares = aggregationLayerVault.balanceOf(feeRecipient); + uint256 expectedAssets = aggregationLayerVault.convertToAssets(feeShares); vm.prank(feeRecipient); - fourSixTwoSixAgg.redeem(feeShares, feeRecipient, feeRecipient); + aggregationLayerVault.redeem(feeShares, feeRecipient, feeRecipient); - assertApproxEqAbs(fourSixTwoSixAgg.totalAssetsDeposited(), totalAssetsDepositedBefore - expectedAssets, 1); - assertEq(fourSixTwoSixAgg.totalSupply(), 0); + assertApproxEqAbs( + aggregationLayerVault.totalAssetsDeposited(), totalAssetsDepositedBefore - expectedAssets, 1 + ); + assertEq(aggregationLayerVault.totalSupply(), 0); assertApproxEqAbs(assetTST.balanceOf(feeRecipient), assetTSTBalanceBefore + expectedAssets, 1); } } diff --git a/test/e2e/StrategyCapE2ETest.t.sol b/test/e2e/StrategyCapE2ETest.t.sol index e0235ecd..c5ebcfc6 100644 --- a/test/e2e/StrategyCapE2ETest.t.sol +++ b/test/e2e/StrategyCapE2ETest.t.sol @@ -2,16 +2,18 @@ pragma solidity ^0.8.0; import { - FourSixTwoSixAggBase, - FourSixTwoSixAgg, + AggregationLayerVaultBase, + AggregationLayerVault, console2, EVault, IEVault, IRMTestDefault, - TestERC20 -} from "../common/FourSixTwoSixAggBase.t.sol"; + TestERC20, + Strategy, + ErrorsLib +} from "../common/AggregationLayerVaultBase.t.sol"; -contract StrategyCapE2ETest is FourSixTwoSixAggBase { +contract StrategyCapE2ETest is AggregationLayerVaultBase { uint256 user1InitialBalance = 100000e18; function setUp() public virtual override { @@ -26,12 +28,12 @@ contract StrategyCapE2ETest is FourSixTwoSixAggBase { function testSetCap() public { uint256 cap = 1000000e18; - assertEq((fourSixTwoSixAgg.getStrategy(address(eTST))).cap, 0); + assertEq((aggregationLayerVault.getStrategy(address(eTST))).cap, 0); vm.prank(manager); - fourSixTwoSixAgg.setStrategyCap(address(eTST), cap); + aggregationLayerVault.setStrategyCap(address(eTST), cap); - FourSixTwoSixAgg.Strategy memory strategy = fourSixTwoSixAgg.getStrategy(address(eTST)); + Strategy memory strategy = aggregationLayerVault.getStrategy(address(eTST)); assertEq(strategy.cap, cap); } @@ -40,54 +42,55 @@ contract StrategyCapE2ETest is FourSixTwoSixAggBase { uint256 cap = 1000000e18; vm.prank(manager); - vm.expectRevert(FourSixTwoSixAgg.InactiveStrategy.selector); - fourSixTwoSixAgg.setStrategyCap(address(0x2), cap); + vm.expectRevert(ErrorsLib.InactiveStrategy.selector); + aggregationLayerVault.setStrategyCap(address(0x2), cap); } function testRebalanceAfterHittingCap() public { uint256 cap = 3333333333333333333333; vm.prank(manager); - fourSixTwoSixAgg.setStrategyCap(address(eTST), cap); + aggregationLayerVault.setStrategyCap(address(eTST), cap); uint256 amountToDeposit = 10000e18; // deposit into aggregator { - uint256 balanceBefore = fourSixTwoSixAgg.balanceOf(user1); - uint256 totalSupplyBefore = fourSixTwoSixAgg.totalSupply(); - uint256 totalAssetsDepositedBefore = fourSixTwoSixAgg.totalAssetsDeposited(); + uint256 balanceBefore = aggregationLayerVault.balanceOf(user1); + uint256 totalSupplyBefore = aggregationLayerVault.totalSupply(); + uint256 totalAssetsDepositedBefore = aggregationLayerVault.totalAssetsDeposited(); uint256 userAssetBalanceBefore = assetTST.balanceOf(user1); vm.startPrank(user1); - assetTST.approve(address(fourSixTwoSixAgg), amountToDeposit); - fourSixTwoSixAgg.deposit(amountToDeposit, user1); + assetTST.approve(address(aggregationLayerVault), amountToDeposit); + aggregationLayerVault.deposit(amountToDeposit, user1); vm.stopPrank(); - assertEq(fourSixTwoSixAgg.balanceOf(user1), balanceBefore + amountToDeposit); - assertEq(fourSixTwoSixAgg.totalSupply(), totalSupplyBefore + amountToDeposit); - assertEq(fourSixTwoSixAgg.totalAssetsDeposited(), totalAssetsDepositedBefore + amountToDeposit); + assertEq(aggregationLayerVault.balanceOf(user1), balanceBefore + amountToDeposit); + assertEq(aggregationLayerVault.totalSupply(), totalSupplyBefore + amountToDeposit); + assertEq(aggregationLayerVault.totalAssetsDeposited(), totalAssetsDepositedBefore + amountToDeposit); assertEq(assetTST.balanceOf(user1), userAssetBalanceBefore - amountToDeposit); } // rebalance into strategy vm.warp(block.timestamp + 86400); { - FourSixTwoSixAgg.Strategy memory strategyBefore = fourSixTwoSixAgg.getStrategy(address(eTST)); + Strategy memory strategyBefore = aggregationLayerVault.getStrategy(address(eTST)); - assertEq(eTST.convertToAssets(eTST.balanceOf(address(fourSixTwoSixAgg))), strategyBefore.allocated); + assertEq(eTST.convertToAssets(eTST.balanceOf(address(aggregationLayerVault))), strategyBefore.allocated); - uint256 expectedStrategyCash = fourSixTwoSixAgg.totalAssetsAllocatable() * strategyBefore.allocationPoints - / fourSixTwoSixAgg.totalAllocationPoints(); + uint256 expectedStrategyCash = aggregationLayerVault.totalAssetsAllocatable() + * strategyBefore.allocationPoints / aggregationLayerVault.totalAllocationPoints(); vm.prank(user1); address[] memory strategiesToRebalance = new address[](1); strategiesToRebalance[0] = address(eTST); - rebalancer.executeRebalance(address(fourSixTwoSixAgg), strategiesToRebalance); + rebalancer.executeRebalance(address(aggregationLayerVault), strategiesToRebalance); - assertEq(fourSixTwoSixAgg.totalAllocated(), expectedStrategyCash); - assertEq(eTST.convertToAssets(eTST.balanceOf(address(fourSixTwoSixAgg))), expectedStrategyCash); + assertEq(aggregationLayerVault.totalAllocated(), expectedStrategyCash); + assertEq(eTST.convertToAssets(eTST.balanceOf(address(aggregationLayerVault))), expectedStrategyCash); assertEq( - (fourSixTwoSixAgg.getStrategy(address(eTST))).allocated, strategyBefore.allocated + expectedStrategyCash + (aggregationLayerVault.getStrategy(address(eTST))).allocated, + strategyBefore.allocated + expectedStrategyCash ); } @@ -95,17 +98,17 @@ contract StrategyCapE2ETest is FourSixTwoSixAggBase { vm.warp(block.timestamp + 86400); vm.startPrank(user1); - assetTST.approve(address(fourSixTwoSixAgg), amountToDeposit); - fourSixTwoSixAgg.deposit(amountToDeposit, user1); + assetTST.approve(address(aggregationLayerVault), amountToDeposit); + aggregationLayerVault.deposit(amountToDeposit, user1); - uint256 strategyAllocatedBefore = (fourSixTwoSixAgg.getStrategy(address(eTST))).allocated; + uint256 strategyAllocatedBefore = (aggregationLayerVault.getStrategy(address(eTST))).allocated; address[] memory strategiesToRebalance = new address[](1); strategiesToRebalance[0] = address(eTST); - rebalancer.executeRebalance(address(fourSixTwoSixAgg), strategiesToRebalance); + rebalancer.executeRebalance(address(aggregationLayerVault), strategiesToRebalance); vm.stopPrank(); - assertEq(strategyAllocatedBefore, (fourSixTwoSixAgg.getStrategy(address(eTST))).allocated); + assertEq(strategyAllocatedBefore, (aggregationLayerVault.getStrategy(address(eTST))).allocated); } function testRebalanceWhentargetAllocationGreaterThanCap() public { @@ -113,45 +116,45 @@ contract StrategyCapE2ETest is FourSixTwoSixAggBase { // deposit into aggregator { - uint256 balanceBefore = fourSixTwoSixAgg.balanceOf(user1); - uint256 totalSupplyBefore = fourSixTwoSixAgg.totalSupply(); - uint256 totalAssetsDepositedBefore = fourSixTwoSixAgg.totalAssetsDeposited(); + uint256 balanceBefore = aggregationLayerVault.balanceOf(user1); + uint256 totalSupplyBefore = aggregationLayerVault.totalSupply(); + uint256 totalAssetsDepositedBefore = aggregationLayerVault.totalAssetsDeposited(); uint256 userAssetBalanceBefore = assetTST.balanceOf(user1); vm.startPrank(user1); - assetTST.approve(address(fourSixTwoSixAgg), amountToDeposit); - fourSixTwoSixAgg.deposit(amountToDeposit, user1); + assetTST.approve(address(aggregationLayerVault), amountToDeposit); + aggregationLayerVault.deposit(amountToDeposit, user1); vm.stopPrank(); - assertEq(fourSixTwoSixAgg.balanceOf(user1), balanceBefore + amountToDeposit); - assertEq(fourSixTwoSixAgg.totalSupply(), totalSupplyBefore + amountToDeposit); - assertEq(fourSixTwoSixAgg.totalAssetsDeposited(), totalAssetsDepositedBefore + amountToDeposit); + assertEq(aggregationLayerVault.balanceOf(user1), balanceBefore + amountToDeposit); + assertEq(aggregationLayerVault.totalSupply(), totalSupplyBefore + amountToDeposit); + assertEq(aggregationLayerVault.totalAssetsDeposited(), totalAssetsDepositedBefore + amountToDeposit); assertEq(assetTST.balanceOf(user1), userAssetBalanceBefore - amountToDeposit); } // rebalance into strategy vm.warp(block.timestamp + 86400); { - FourSixTwoSixAgg.Strategy memory strategyBefore = fourSixTwoSixAgg.getStrategy(address(eTST)); + Strategy memory strategyBefore = aggregationLayerVault.getStrategy(address(eTST)); - assertEq(eTST.convertToAssets(eTST.balanceOf(address(fourSixTwoSixAgg))), strategyBefore.allocated); + assertEq(eTST.convertToAssets(eTST.balanceOf(address(aggregationLayerVault))), strategyBefore.allocated); - uint256 expectedStrategyCash = fourSixTwoSixAgg.totalAssetsAllocatable() * strategyBefore.allocationPoints - / fourSixTwoSixAgg.totalAllocationPoints(); + uint256 expectedStrategyCash = aggregationLayerVault.totalAssetsAllocatable() + * strategyBefore.allocationPoints / aggregationLayerVault.totalAllocationPoints(); // set cap 10% less than target allocation uint256 cap = expectedStrategyCash * 9e17 / 1e18; vm.prank(manager); - fourSixTwoSixAgg.setStrategyCap(address(eTST), cap); + aggregationLayerVault.setStrategyCap(address(eTST), cap); vm.prank(user1); address[] memory strategiesToRebalance = new address[](1); strategiesToRebalance[0] = address(eTST); - rebalancer.executeRebalance(address(fourSixTwoSixAgg), strategiesToRebalance); + rebalancer.executeRebalance(address(aggregationLayerVault), strategiesToRebalance); - assertEq(fourSixTwoSixAgg.totalAllocated(), cap); - assertEq(eTST.convertToAssets(eTST.balanceOf(address(fourSixTwoSixAgg))), cap); - assertEq((fourSixTwoSixAgg.getStrategy(address(eTST))).allocated, strategyBefore.allocated + cap); + assertEq(aggregationLayerVault.totalAllocated(), cap); + assertEq(eTST.convertToAssets(eTST.balanceOf(address(aggregationLayerVault))), cap); + assertEq((aggregationLayerVault.getStrategy(address(eTST))).allocated, strategyBefore.allocated + cap); } } } diff --git a/test/e2e/StrategyRewardsE2ETest.t.sol b/test/e2e/StrategyRewardsE2ETest.t.sol index edbcb9a9..91303088 100644 --- a/test/e2e/StrategyRewardsE2ETest.t.sol +++ b/test/e2e/StrategyRewardsE2ETest.t.sol @@ -2,17 +2,17 @@ pragma solidity ^0.8.0; import { - FourSixTwoSixAggBase, - FourSixTwoSixAgg, + AggregationLayerVaultBase, + AggregationLayerVault, console2, EVault, IEVault, IRMTestDefault, TestERC20 -} from "../common/FourSixTwoSixAggBase.t.sol"; +} from "../common/AggregationLayerVaultBase.t.sol"; import {TrackingRewardStreams} from "reward-streams/TrackingRewardStreams.sol"; -contract StrategyRewardsE2ETest is FourSixTwoSixAggBase { +contract StrategyRewardsE2ETest is AggregationLayerVaultBase { uint256 user1InitialBalance = 100000e18; function setUp() public virtual override { @@ -26,19 +26,19 @@ contract StrategyRewardsE2ETest is FourSixTwoSixAggBase { function testOptInStrategyRewards() public { vm.prank(manager); - fourSixTwoSixAgg.optInStrategyRewards(address(eTST)); + aggregationLayerVault.optInStrategyRewards(address(eTST)); - assertTrue(eTST.balanceForwarderEnabled(address(fourSixTwoSixAgg))); + assertTrue(eTST.balanceForwarderEnabled(address(aggregationLayerVault))); } function testOptOutStrategyRewards() public { vm.prank(manager); - fourSixTwoSixAgg.optInStrategyRewards(address(eTST)); - assertTrue(eTST.balanceForwarderEnabled(address(fourSixTwoSixAgg))); + aggregationLayerVault.optInStrategyRewards(address(eTST)); + assertTrue(eTST.balanceForwarderEnabled(address(aggregationLayerVault))); vm.prank(manager); - fourSixTwoSixAgg.optOutStrategyRewards(address(eTST)); + aggregationLayerVault.optOutStrategyRewards(address(eTST)); - assertFalse(eTST.balanceForwarderEnabled(address(fourSixTwoSixAgg))); + assertFalse(eTST.balanceForwarderEnabled(address(aggregationLayerVault))); } } diff --git a/test/fuzz/AdjustAllocationPointsFuzzTest.t.sol b/test/fuzz/AdjustAllocationPointsFuzzTest.t.sol index c5415507..ceac1837 100644 --- a/test/fuzz/AdjustAllocationPointsFuzzTest.t.sol +++ b/test/fuzz/AdjustAllocationPointsFuzzTest.t.sol @@ -1,9 +1,9 @@ // SPDX-License-Identifier: GPL-2.0-or-later pragma solidity ^0.8.0; -import {FourSixTwoSixAggBase, FourSixTwoSixAgg} from "../common/FourSixTwoSixAggBase.t.sol"; +import {AggregationLayerVaultBase, AggregationLayerVault, Strategy} from "../common/AggregationLayerVaultBase.t.sol"; -contract AdjustAllocationsPointsFuzzTest is FourSixTwoSixAggBase { +contract AdjustAllocationsPointsFuzzTest is AggregationLayerVaultBase { function setUp() public virtual override { super.setUp(); @@ -14,27 +14,27 @@ contract AdjustAllocationsPointsFuzzTest is FourSixTwoSixAggBase { function testFuzzAdjustAllocationPoints(uint256 _newAllocationPoints) public { _newAllocationPoints = bound(_newAllocationPoints, 0, type(uint120).max); - uint256 strategyAllocationPoints = (fourSixTwoSixAgg.getStrategy(address(eTST))).allocationPoints; - uint256 totalAllocationPointsBefore = fourSixTwoSixAgg.totalAllocationPoints(); - uint256 withdrawalQueueLengthBefore = fourSixTwoSixAgg.withdrawalQueueLength(); + uint256 strategyAllocationPoints = (aggregationLayerVault.getStrategy(address(eTST))).allocationPoints; + uint256 totalAllocationPointsBefore = aggregationLayerVault.totalAllocationPoints(); + uint256 withdrawalQueueLengthBefore = _getWithdrawalQueueLength(); vm.prank(manager); - fourSixTwoSixAgg.adjustAllocationPoints(address(eTST), _newAllocationPoints); + aggregationLayerVault.adjustAllocationPoints(address(eTST), _newAllocationPoints); - FourSixTwoSixAgg.Strategy memory strategy = fourSixTwoSixAgg.getStrategy(address(eTST)); + Strategy memory strategy = aggregationLayerVault.getStrategy(address(eTST)); if (_newAllocationPoints < strategyAllocationPoints) { assertEq( - fourSixTwoSixAgg.totalAllocationPoints(), + aggregationLayerVault.totalAllocationPoints(), totalAllocationPointsBefore - (strategyAllocationPoints - _newAllocationPoints) ); } else { assertEq( - fourSixTwoSixAgg.totalAllocationPoints(), + aggregationLayerVault.totalAllocationPoints(), totalAllocationPointsBefore + (_newAllocationPoints - strategyAllocationPoints) ); } - assertEq(fourSixTwoSixAgg.withdrawalQueueLength(), withdrawalQueueLengthBefore); + assertEq(_getWithdrawalQueueLength(), withdrawalQueueLengthBefore); assertEq(strategy.allocationPoints, _newAllocationPoints); } } diff --git a/test/fuzz/DepositWithdrawMintBurnFuzzTest.t.sol b/test/fuzz/DepositWithdrawMintBurnFuzzTest.t.sol index ae9b9efc..dea9b6df 100644 --- a/test/fuzz/DepositWithdrawMintBurnFuzzTest.t.sol +++ b/test/fuzz/DepositWithdrawMintBurnFuzzTest.t.sol @@ -1,9 +1,9 @@ // SPDX-License-Identifier: GPL-2.0-or-later pragma solidity ^0.8.0; -import {console2, FourSixTwoSixAggBase, FourSixTwoSixAgg} from "../common/FourSixTwoSixAggBase.t.sol"; +import {console2, AggregationLayerVaultBase, AggregationLayerVault} from "../common/AggregationLayerVaultBase.t.sol"; -contract DepositWithdrawMintBurnFuzzTest is FourSixTwoSixAggBase { +contract DepositWithdrawMintBurnFuzzTest is AggregationLayerVaultBase { uint256 constant MAX_ALLOWED = type(uint256).max; function setUp() public virtual override { @@ -14,16 +14,16 @@ contract DepositWithdrawMintBurnFuzzTest is FourSixTwoSixAggBase { // moch the scenario of _assets ownership assetTST.mint(user1, _assets); - uint256 balanceBefore = fourSixTwoSixAgg.balanceOf(user1); - uint256 totalSupplyBefore = fourSixTwoSixAgg.totalSupply(); - uint256 totalAssetsDepositedBefore = fourSixTwoSixAgg.totalAssetsDeposited(); + uint256 balanceBefore = aggregationLayerVault.balanceOf(user1); + uint256 totalSupplyBefore = aggregationLayerVault.totalSupply(); + uint256 totalAssetsDepositedBefore = aggregationLayerVault.totalAssetsDeposited(); uint256 userAssetBalanceBefore = assetTST.balanceOf(user1); _deposit(user1, _assets); - assertEq(fourSixTwoSixAgg.balanceOf(user1), balanceBefore + _assets); - assertEq(fourSixTwoSixAgg.totalSupply(), totalSupplyBefore + _assets); - assertEq(fourSixTwoSixAgg.totalAssetsDeposited(), totalAssetsDepositedBefore + _assets); + assertEq(aggregationLayerVault.balanceOf(user1), balanceBefore + _assets); + assertEq(aggregationLayerVault.totalSupply(), totalSupplyBefore + _assets); + assertEq(aggregationLayerVault.totalAssetsDeposited(), totalAssetsDepositedBefore + _assets); assertEq(assetTST.balanceOf(user1), userAssetBalanceBefore - _assets); } @@ -45,36 +45,36 @@ contract DepositWithdrawMintBurnFuzzTest is FourSixTwoSixAggBase { vm.warp(block.timestamp + _timestampAfterDeposit); // fuzz partial & full withdraws - uint256 balanceBefore = fourSixTwoSixAgg.balanceOf(user1); - uint256 totalSupplyBefore = fourSixTwoSixAgg.totalSupply(); - uint256 totalAssetsDepositedBefore = fourSixTwoSixAgg.totalAssetsDeposited(); + uint256 balanceBefore = aggregationLayerVault.balanceOf(user1); + uint256 totalSupplyBefore = aggregationLayerVault.totalSupply(); + uint256 totalAssetsDepositedBefore = aggregationLayerVault.totalAssetsDeposited(); uint256 receiverAssetBalanceBefore = assetTST.balanceOf(_receiver); vm.startPrank(user1); - fourSixTwoSixAgg.withdraw(_assetsToWithdraw, _receiver, user1); + aggregationLayerVault.withdraw(_assetsToWithdraw, _receiver, user1); vm.stopPrank(); - assertEq(fourSixTwoSixAgg.balanceOf(user1), balanceBefore - _assetsToWithdraw); - assertEq(fourSixTwoSixAgg.totalSupply(), totalSupplyBefore - _assetsToWithdraw); - assertEq(fourSixTwoSixAgg.totalAssetsDeposited(), totalAssetsDepositedBefore - _assetsToWithdraw); + assertEq(aggregationLayerVault.balanceOf(user1), balanceBefore - _assetsToWithdraw); + assertEq(aggregationLayerVault.totalSupply(), totalSupplyBefore - _assetsToWithdraw); + assertEq(aggregationLayerVault.totalAssetsDeposited(), totalAssetsDepositedBefore - _assetsToWithdraw); assertEq(assetTST.balanceOf(_receiver), receiverAssetBalanceBefore + _assetsToWithdraw); } function testFuzzMint(uint256 _shares) public { // moch the scenario of _assets ownership - uint256 assets = fourSixTwoSixAgg.previewMint(_shares); + uint256 assets = aggregationLayerVault.previewMint(_shares); assetTST.mint(user1, assets); - uint256 balanceBefore = fourSixTwoSixAgg.balanceOf(user1); - uint256 totalSupplyBefore = fourSixTwoSixAgg.totalSupply(); - uint256 totalAssetsDepositedBefore = fourSixTwoSixAgg.totalAssetsDeposited(); + uint256 balanceBefore = aggregationLayerVault.balanceOf(user1); + uint256 totalSupplyBefore = aggregationLayerVault.totalSupply(); + uint256 totalAssetsDepositedBefore = aggregationLayerVault.totalAssetsDeposited(); uint256 userAssetBalanceBefore = assetTST.balanceOf(user1); _mint(user1, assets, _shares); - assertEq(fourSixTwoSixAgg.balanceOf(user1), balanceBefore + _shares); - assertEq(fourSixTwoSixAgg.totalSupply(), totalSupplyBefore + _shares); - assertEq(fourSixTwoSixAgg.totalAssetsDeposited(), totalAssetsDepositedBefore + assets); + assertEq(aggregationLayerVault.balanceOf(user1), balanceBefore + _shares); + assertEq(aggregationLayerVault.totalSupply(), totalSupplyBefore + _shares); + assertEq(aggregationLayerVault.totalAssetsDeposited(), totalAssetsDepositedBefore + assets); assertEq(assetTST.balanceOf(user1), userAssetBalanceBefore - assets); } @@ -91,38 +91,38 @@ contract DepositWithdrawMintBurnFuzzTest is FourSixTwoSixAggBase { _timestampAfterDeposit = bound(_timestampAfterDeposit, 0, 86400); // deposit - uint256 assetsToDeposit = fourSixTwoSixAgg.previewMint(_sharesToMint); + uint256 assetsToDeposit = aggregationLayerVault.previewMint(_sharesToMint); assetTST.mint(user1, assetsToDeposit); _mint(user1, assetsToDeposit, _sharesToMint); vm.warp(block.timestamp + _timestampAfterDeposit); // fuzz partial & full redeem - uint256 balanceBefore = fourSixTwoSixAgg.balanceOf(user1); - uint256 totalSupplyBefore = fourSixTwoSixAgg.totalSupply(); - uint256 totalAssetsDepositedBefore = fourSixTwoSixAgg.totalAssetsDeposited(); + uint256 balanceBefore = aggregationLayerVault.balanceOf(user1); + uint256 totalSupplyBefore = aggregationLayerVault.totalSupply(); + uint256 totalAssetsDepositedBefore = aggregationLayerVault.totalAssetsDeposited(); uint256 receiverAssetBalanceBefore = assetTST.balanceOf(_receiver); vm.startPrank(user1); - uint256 assetsToWithdraw = fourSixTwoSixAgg.redeem(_sharesToRedeem, _receiver, user1); + uint256 assetsToWithdraw = aggregationLayerVault.redeem(_sharesToRedeem, _receiver, user1); vm.stopPrank(); - assertEq(fourSixTwoSixAgg.balanceOf(user1), balanceBefore - _sharesToRedeem); - assertEq(fourSixTwoSixAgg.totalSupply(), totalSupplyBefore - _sharesToRedeem); - assertEq(fourSixTwoSixAgg.totalAssetsDeposited(), totalAssetsDepositedBefore - assetsToWithdraw); + assertEq(aggregationLayerVault.balanceOf(user1), balanceBefore - _sharesToRedeem); + assertEq(aggregationLayerVault.totalSupply(), totalSupplyBefore - _sharesToRedeem); + assertEq(aggregationLayerVault.totalAssetsDeposited(), totalAssetsDepositedBefore - assetsToWithdraw); assertEq(assetTST.balanceOf(_receiver), receiverAssetBalanceBefore + assetsToWithdraw); } function _deposit(address _from, uint256 _assets) private { vm.startPrank(_from); - assetTST.approve(address(fourSixTwoSixAgg), _assets); - fourSixTwoSixAgg.deposit(_assets, _from); + assetTST.approve(address(aggregationLayerVault), _assets); + aggregationLayerVault.deposit(_assets, _from); vm.stopPrank(); } function _mint(address _from, uint256 _assets, uint256 _shares) private { vm.startPrank(_from); - assetTST.approve(address(fourSixTwoSixAgg), _assets); - fourSixTwoSixAgg.mint(_shares, _from); + assetTST.approve(address(aggregationLayerVault), _assets); + aggregationLayerVault.mint(_shares, _from); vm.stopPrank(); } } diff --git a/test/unit/AddStrategyTest.t.sol b/test/unit/AddStrategyTest.t.sol index 97c9893b..0efc9e8c 100644 --- a/test/unit/AddStrategyTest.t.sol +++ b/test/unit/AddStrategyTest.t.sol @@ -1,29 +1,29 @@ // SPDX-License-Identifier: GPL-2.0-or-later pragma solidity ^0.8.0; -import {FourSixTwoSixAggBase, FourSixTwoSixAgg} from "../common/FourSixTwoSixAggBase.t.sol"; +import {AggregationLayerVaultBase, AggregationLayerVault} from "../common/AggregationLayerVaultBase.t.sol"; -contract AddStrategyTest is FourSixTwoSixAggBase { +contract AddStrategyTest is AggregationLayerVaultBase { function setUp() public virtual override { super.setUp(); } function testAddStrategy() public { uint256 allocationPoints = 500e18; - uint256 totalAllocationPointsBefore = fourSixTwoSixAgg.totalAllocationPoints(); + uint256 totalAllocationPointsBefore = aggregationLayerVault.totalAllocationPoints(); - assertEq(fourSixTwoSixAgg.withdrawalQueueLength(), 0); + assertEq(_getWithdrawalQueueLength(), 0); _addStrategy(manager, address(eTST), allocationPoints); - assertEq(fourSixTwoSixAgg.totalAllocationPoints(), allocationPoints + totalAllocationPointsBefore); - assertEq(fourSixTwoSixAgg.withdrawalQueueLength(), 1); + assertEq(aggregationLayerVault.totalAllocationPoints(), allocationPoints + totalAllocationPointsBefore); + assertEq(_getWithdrawalQueueLength(), 1); } function testAddStrategy_FromUnauthorizedAddress() public { uint256 allocationPoints = 500e18; - assertEq(fourSixTwoSixAgg.withdrawalQueueLength(), 0); + assertEq(_getWithdrawalQueueLength(), 0); vm.expectRevert(); _addStrategy(deployer, address(eTST), allocationPoints); @@ -32,7 +32,7 @@ contract AddStrategyTest is FourSixTwoSixAggBase { function testAddStrategy_WithInvalidAsset() public { uint256 allocationPoints = 500e18; - assertEq(fourSixTwoSixAgg.withdrawalQueueLength(), 0); + assertEq(_getWithdrawalQueueLength(), 0); vm.expectRevert(); _addStrategy(manager, address(eTST2), allocationPoints); @@ -40,14 +40,14 @@ contract AddStrategyTest is FourSixTwoSixAggBase { function testAddStrategy_AlreadyAddedStrategy() public { uint256 allocationPoints = 500e18; - uint256 totalAllocationPointsBefore = fourSixTwoSixAgg.totalAllocationPoints(); + uint256 totalAllocationPointsBefore = aggregationLayerVault.totalAllocationPoints(); - assertEq(fourSixTwoSixAgg.withdrawalQueueLength(), 0); + assertEq(_getWithdrawalQueueLength(), 0); _addStrategy(manager, address(eTST), allocationPoints); - assertEq(fourSixTwoSixAgg.totalAllocationPoints(), allocationPoints + totalAllocationPointsBefore); - assertEq(fourSixTwoSixAgg.withdrawalQueueLength(), 1); + assertEq(aggregationLayerVault.totalAllocationPoints(), allocationPoints + totalAllocationPointsBefore); + assertEq(_getWithdrawalQueueLength(), 1); vm.expectRevert(); _addStrategy(manager, address(eTST), allocationPoints); diff --git a/test/unit/AdjustAllocationPointsTest.t.sol b/test/unit/AdjustAllocationPointsTest.t.sol index da9ef58c..bf440e35 100644 --- a/test/unit/AdjustAllocationPointsTest.t.sol +++ b/test/unit/AdjustAllocationPointsTest.t.sol @@ -1,9 +1,14 @@ // SPDX-License-Identifier: GPL-2.0-or-later pragma solidity ^0.8.0; -import {FourSixTwoSixAggBase, FourSixTwoSixAgg} from "../common/FourSixTwoSixAggBase.t.sol"; - -contract AdjustAllocationsPointsTest is FourSixTwoSixAggBase { +import { + AggregationLayerVaultBase, + AggregationLayerVault, + Strategy, + ErrorsLib +} from "../common/AggregationLayerVaultBase.t.sol"; + +contract AdjustAllocationsPointsTest is AggregationLayerVaultBase { uint256 initialStrategyAllocationPoints = 500e18; function setUp() public virtual override { @@ -14,19 +19,19 @@ contract AdjustAllocationsPointsTest is FourSixTwoSixAggBase { function testAdjustAllocationPoints() public { uint256 newAllocationPoints = 859e18; - uint256 totalAllocationPointsBefore = fourSixTwoSixAgg.totalAllocationPoints(); - uint256 withdrawalQueueLengthBefore = fourSixTwoSixAgg.withdrawalQueueLength(); + uint256 totalAllocationPointsBefore = aggregationLayerVault.totalAllocationPoints(); + uint256 withdrawalQueueLengthBefore = _getWithdrawalQueueLength(); vm.prank(manager); - fourSixTwoSixAgg.adjustAllocationPoints(address(eTST), newAllocationPoints); + aggregationLayerVault.adjustAllocationPoints(address(eTST), newAllocationPoints); - FourSixTwoSixAgg.Strategy memory strategy = fourSixTwoSixAgg.getStrategy(address(eTST)); + Strategy memory strategy = aggregationLayerVault.getStrategy(address(eTST)); assertEq( - fourSixTwoSixAgg.totalAllocationPoints(), + aggregationLayerVault.totalAllocationPoints(), totalAllocationPointsBefore + (newAllocationPoints - initialStrategyAllocationPoints) ); - assertEq(fourSixTwoSixAgg.withdrawalQueueLength(), withdrawalQueueLengthBefore); + assertEq(_getWithdrawalQueueLength(), withdrawalQueueLengthBefore); assertEq(strategy.allocationPoints, newAllocationPoints); } @@ -35,7 +40,7 @@ contract AdjustAllocationsPointsTest is FourSixTwoSixAggBase { vm.startPrank(deployer); vm.expectRevert(); - fourSixTwoSixAgg.adjustAllocationPoints(address(eTST), newAllocationPoints); + aggregationLayerVault.adjustAllocationPoints(address(eTST), newAllocationPoints); vm.stopPrank(); } @@ -43,8 +48,8 @@ contract AdjustAllocationsPointsTest is FourSixTwoSixAggBase { uint256 newAllocationPoints = 859e18; vm.startPrank(manager); - vm.expectRevert(FourSixTwoSixAgg.InactiveStrategy.selector); - fourSixTwoSixAgg.adjustAllocationPoints(address(eTST2), newAllocationPoints); + vm.expectRevert(ErrorsLib.InactiveStrategy.selector); + aggregationLayerVault.adjustAllocationPoints(address(eTST2), newAllocationPoints); vm.stopPrank(); } } diff --git a/test/unit/GulpTest.t.sol b/test/unit/GulpTest.t.sol index 41c20510..f1ac33ff 100644 --- a/test/unit/GulpTest.t.sol +++ b/test/unit/GulpTest.t.sol @@ -1,9 +1,15 @@ // SPDX-License-Identifier: GPL-2.0-or-later pragma solidity ^0.8.0; -import {FourSixTwoSixAggBase, FourSixTwoSixAgg, console2, EVault} from "../common/FourSixTwoSixAggBase.t.sol"; - -contract GulpTest is FourSixTwoSixAggBase { +import { + AggregationLayerVaultBase, + AggregationLayerVault, + console2, + EVault, + Strategy +} from "../common/AggregationLayerVaultBase.t.sol"; + +contract GulpTest is AggregationLayerVaultBase { uint256 user1InitialBalance = 100000e18; uint256 amountToDeposit = 10000e18; @@ -17,140 +23,142 @@ contract GulpTest is FourSixTwoSixAggBase { // deposit into aggregator { - uint256 balanceBefore = fourSixTwoSixAgg.balanceOf(user1); - uint256 totalSupplyBefore = fourSixTwoSixAgg.totalSupply(); - uint256 totalAssetsDepositedBefore = fourSixTwoSixAgg.totalAssetsDeposited(); + uint256 balanceBefore = aggregationLayerVault.balanceOf(user1); + uint256 totalSupplyBefore = aggregationLayerVault.totalSupply(); + uint256 totalAssetsDepositedBefore = aggregationLayerVault.totalAssetsDeposited(); uint256 userAssetBalanceBefore = assetTST.balanceOf(user1); vm.startPrank(user1); - assetTST.approve(address(fourSixTwoSixAgg), amountToDeposit); - fourSixTwoSixAgg.deposit(amountToDeposit, user1); + assetTST.approve(address(aggregationLayerVault), amountToDeposit); + aggregationLayerVault.deposit(amountToDeposit, user1); vm.stopPrank(); - assertEq(fourSixTwoSixAgg.balanceOf(user1), balanceBefore + amountToDeposit); - assertEq(fourSixTwoSixAgg.totalSupply(), totalSupplyBefore + amountToDeposit); - assertEq(fourSixTwoSixAgg.totalAssetsDeposited(), totalAssetsDepositedBefore + amountToDeposit); + assertEq(aggregationLayerVault.balanceOf(user1), balanceBefore + amountToDeposit); + assertEq(aggregationLayerVault.totalSupply(), totalSupplyBefore + amountToDeposit); + assertEq(aggregationLayerVault.totalAssetsDeposited(), totalAssetsDepositedBefore + amountToDeposit); assertEq(assetTST.balanceOf(user1), userAssetBalanceBefore - amountToDeposit); } // rebalance into strategy vm.warp(block.timestamp + 86400); { - FourSixTwoSixAgg.Strategy memory strategyBefore = fourSixTwoSixAgg.getStrategy(address(eTST)); + Strategy memory strategyBefore = aggregationLayerVault.getStrategy(address(eTST)); - assertEq(eTST.convertToAssets(eTST.balanceOf(address(fourSixTwoSixAgg))), strategyBefore.allocated); + assertEq(eTST.convertToAssets(eTST.balanceOf(address(aggregationLayerVault))), strategyBefore.allocated); - uint256 expectedStrategyCash = fourSixTwoSixAgg.totalAssetsAllocatable() * strategyBefore.allocationPoints - / fourSixTwoSixAgg.totalAllocationPoints(); + uint256 expectedStrategyCash = aggregationLayerVault.totalAssetsAllocatable() + * strategyBefore.allocationPoints / aggregationLayerVault.totalAllocationPoints(); vm.prank(user1); address[] memory strategiesToRebalance = new address[](1); strategiesToRebalance[0] = address(eTST); - rebalancer.executeRebalance(address(fourSixTwoSixAgg), strategiesToRebalance); + rebalancer.executeRebalance(address(aggregationLayerVault), strategiesToRebalance); - assertEq(fourSixTwoSixAgg.totalAllocated(), expectedStrategyCash); - assertEq(eTST.convertToAssets(eTST.balanceOf(address(fourSixTwoSixAgg))), expectedStrategyCash); - assertEq((fourSixTwoSixAgg.getStrategy(address(eTST))).allocated, expectedStrategyCash); + assertEq(aggregationLayerVault.totalAllocated(), expectedStrategyCash); + assertEq(eTST.convertToAssets(eTST.balanceOf(address(aggregationLayerVault))), expectedStrategyCash); + assertEq((aggregationLayerVault.getStrategy(address(eTST))).allocated, expectedStrategyCash); } } function testGulpAfterNegativeYieldEqualToInterestLeft() public { - fourSixTwoSixAgg.gulp(); - FourSixTwoSixAgg.ESR memory ers = fourSixTwoSixAgg.getESRSlot(); - assertEq(fourSixTwoSixAgg.interestAccrued(), 0); + aggregationLayerVault.gulp(); + AggregationLayerVault.AggregationVaultSavingRate memory ers = + aggregationLayerVault.getAggregationVaultSavingRate(); + assertEq(aggregationLayerVault.interestAccrued(), 0); assertEq(ers.interestLeft, 0); vm.warp(block.timestamp + 2 days); - fourSixTwoSixAgg.gulp(); - assertEq(fourSixTwoSixAgg.interestAccrued(), 0); + aggregationLayerVault.gulp(); + assertEq(aggregationLayerVault.interestAccrued(), 0); vm.warp(block.timestamp + 1 days); - assertEq(fourSixTwoSixAgg.interestAccrued(), 0); + assertEq(aggregationLayerVault.interestAccrued(), 0); uint256 yield; { - uint256 aggrCurrentStrategyShareBalance = eTST.balanceOf(address(fourSixTwoSixAgg)); + uint256 aggrCurrentStrategyShareBalance = eTST.balanceOf(address(aggregationLayerVault)); uint256 aggrCurrentStrategyUnderlyingBalance = eTST.convertToAssets(aggrCurrentStrategyShareBalance); uint256 aggrNewStrategyUnderlyingBalance = aggrCurrentStrategyUnderlyingBalance * 11e17 / 1e18; yield = aggrNewStrategyUnderlyingBalance - aggrCurrentStrategyUnderlyingBalance; assetTST.mint(address(eTST), yield); - eTST.skim(type(uint256).max, address(fourSixTwoSixAgg)); + eTST.skim(type(uint256).max, address(aggregationLayerVault)); } vm.prank(user1); - fourSixTwoSixAgg.harvest(address(eTST)); + aggregationLayerVault.harvest(address(eTST)); - assertEq(fourSixTwoSixAgg.interestAccrued(), 0); + assertEq(aggregationLayerVault.interestAccrued(), 0); vm.warp(block.timestamp + 1 days); // interest per day 23.809523809523 - assertEq(fourSixTwoSixAgg.interestAccrued(), 23809523809523809523); - fourSixTwoSixAgg.gulp(); - ers = fourSixTwoSixAgg.getESRSlot(); + assertEq(aggregationLayerVault.interestAccrued(), 23809523809523809523); + aggregationLayerVault.gulp(); + ers = aggregationLayerVault.getAggregationVaultSavingRate(); assertEq(ers.interestLeft, yield - 23809523809523809523); // move close to end of smearing vm.warp(block.timestamp + 11 days); - fourSixTwoSixAgg.gulp(); - ers = fourSixTwoSixAgg.getESRSlot(); + aggregationLayerVault.gulp(); + ers = aggregationLayerVault.getAggregationVaultSavingRate(); // mock a decrease of strategy balance by ers.interestLeft - uint256 aggrCurrentStrategyBalance = eTST.balanceOf(address(fourSixTwoSixAgg)); + uint256 aggrCurrentStrategyBalance = eTST.balanceOf(address(aggregationLayerVault)); uint256 aggrCurrentStrategyBalanceAfterNegYield = aggrCurrentStrategyBalance - ers.interestLeft; vm.mockCall( address(eTST), - abi.encodeWithSelector(EVault.balanceOf.selector, address(fourSixTwoSixAgg)), + abi.encodeWithSelector(EVault.balanceOf.selector, address(aggregationLayerVault)), abi.encode(aggrCurrentStrategyBalanceAfterNegYield) ); vm.prank(user1); - fourSixTwoSixAgg.harvest(address(eTST)); + aggregationLayerVault.harvest(address(eTST)); } function testGulpAfterNegativeYieldBiggerThanInterestLeft() public { - fourSixTwoSixAgg.gulp(); - FourSixTwoSixAgg.ESR memory ers = fourSixTwoSixAgg.getESRSlot(); - assertEq(fourSixTwoSixAgg.interestAccrued(), 0); + aggregationLayerVault.gulp(); + AggregationLayerVault.AggregationVaultSavingRate memory ers = + aggregationLayerVault.getAggregationVaultSavingRate(); + assertEq(aggregationLayerVault.interestAccrued(), 0); assertEq(ers.interestLeft, 0); vm.warp(block.timestamp + 2 days); - fourSixTwoSixAgg.gulp(); - assertEq(fourSixTwoSixAgg.interestAccrued(), 0); + aggregationLayerVault.gulp(); + assertEq(aggregationLayerVault.interestAccrued(), 0); vm.warp(block.timestamp + 1 days); - assertEq(fourSixTwoSixAgg.interestAccrued(), 0); + assertEq(aggregationLayerVault.interestAccrued(), 0); uint256 yield; { - uint256 aggrCurrentStrategyShareBalance = eTST.balanceOf(address(fourSixTwoSixAgg)); + uint256 aggrCurrentStrategyShareBalance = eTST.balanceOf(address(aggregationLayerVault)); uint256 aggrCurrentStrategyUnderlyingBalance = eTST.convertToAssets(aggrCurrentStrategyShareBalance); uint256 aggrNewStrategyUnderlyingBalance = aggrCurrentStrategyUnderlyingBalance * 11e17 / 1e18; yield = aggrNewStrategyUnderlyingBalance - aggrCurrentStrategyUnderlyingBalance; assetTST.mint(address(eTST), yield); - eTST.skim(type(uint256).max, address(fourSixTwoSixAgg)); + eTST.skim(type(uint256).max, address(aggregationLayerVault)); } vm.prank(user1); - fourSixTwoSixAgg.harvest(address(eTST)); + aggregationLayerVault.harvest(address(eTST)); - assertEq(fourSixTwoSixAgg.interestAccrued(), 0); + assertEq(aggregationLayerVault.interestAccrued(), 0); vm.warp(block.timestamp + 1 days); // interest per day 23.809523809523 - assertEq(fourSixTwoSixAgg.interestAccrued(), 23809523809523809523); - fourSixTwoSixAgg.gulp(); - ers = fourSixTwoSixAgg.getESRSlot(); + assertEq(aggregationLayerVault.interestAccrued(), 23809523809523809523); + aggregationLayerVault.gulp(); + ers = aggregationLayerVault.getAggregationVaultSavingRate(); assertEq(ers.interestLeft, yield - 23809523809523809523); // move close to end of smearing vm.warp(block.timestamp + 11 days); - fourSixTwoSixAgg.gulp(); - ers = fourSixTwoSixAgg.getESRSlot(); + aggregationLayerVault.gulp(); + ers = aggregationLayerVault.getAggregationVaultSavingRate(); // mock a decrease of strategy balance by ers.interestLeft - uint256 aggrCurrentStrategyBalance = eTST.balanceOf(address(fourSixTwoSixAgg)); + uint256 aggrCurrentStrategyBalance = eTST.balanceOf(address(aggregationLayerVault)); uint256 aggrCurrentStrategyBalanceAfterNegYield = aggrCurrentStrategyBalance - (ers.interestLeft * 2); vm.mockCall( address(eTST), - abi.encodeWithSelector(EVault.balanceOf.selector, address(fourSixTwoSixAgg)), + abi.encodeWithSelector(EVault.balanceOf.selector, address(aggregationLayerVault)), abi.encode(aggrCurrentStrategyBalanceAfterNegYield) ); vm.prank(user1); - fourSixTwoSixAgg.harvest(address(eTST)); + aggregationLayerVault.harvest(address(eTST)); } } diff --git a/test/unit/HarvestTest.t.sol b/test/unit/HarvestTest.t.sol index 7ee54b8d..4687df28 100644 --- a/test/unit/HarvestTest.t.sol +++ b/test/unit/HarvestTest.t.sol @@ -1,9 +1,15 @@ // SPDX-License-Identifier: GPL-2.0-or-later pragma solidity ^0.8.0; -import {FourSixTwoSixAggBase, FourSixTwoSixAgg, console2, EVault} from "../common/FourSixTwoSixAggBase.t.sol"; - -contract HarvestTest is FourSixTwoSixAggBase { +import { + AggregationLayerVaultBase, + AggregationLayerVault, + console2, + EVault, + Strategy +} from "../common/AggregationLayerVaultBase.t.sol"; + +contract HarvestTest is AggregationLayerVaultBase { uint256 user1InitialBalance = 100000e18; uint256 amountToDeposit = 10000e18; @@ -17,76 +23,77 @@ contract HarvestTest is FourSixTwoSixAggBase { // deposit into aggregator { - uint256 balanceBefore = fourSixTwoSixAgg.balanceOf(user1); - uint256 totalSupplyBefore = fourSixTwoSixAgg.totalSupply(); - uint256 totalAssetsDepositedBefore = fourSixTwoSixAgg.totalAssetsDeposited(); + uint256 balanceBefore = aggregationLayerVault.balanceOf(user1); + uint256 totalSupplyBefore = aggregationLayerVault.totalSupply(); + uint256 totalAssetsDepositedBefore = aggregationLayerVault.totalAssetsDeposited(); uint256 userAssetBalanceBefore = assetTST.balanceOf(user1); vm.startPrank(user1); - assetTST.approve(address(fourSixTwoSixAgg), amountToDeposit); - fourSixTwoSixAgg.deposit(amountToDeposit, user1); + assetTST.approve(address(aggregationLayerVault), amountToDeposit); + aggregationLayerVault.deposit(amountToDeposit, user1); vm.stopPrank(); - assertEq(fourSixTwoSixAgg.balanceOf(user1), balanceBefore + amountToDeposit); - assertEq(fourSixTwoSixAgg.totalSupply(), totalSupplyBefore + amountToDeposit); - assertEq(fourSixTwoSixAgg.totalAssetsDeposited(), totalAssetsDepositedBefore + amountToDeposit); + assertEq(aggregationLayerVault.balanceOf(user1), balanceBefore + amountToDeposit); + assertEq(aggregationLayerVault.totalSupply(), totalSupplyBefore + amountToDeposit); + assertEq(aggregationLayerVault.totalAssetsDeposited(), totalAssetsDepositedBefore + amountToDeposit); assertEq(assetTST.balanceOf(user1), userAssetBalanceBefore - amountToDeposit); } // rebalance into strategy vm.warp(block.timestamp + 86400); { - FourSixTwoSixAgg.Strategy memory strategyBefore = fourSixTwoSixAgg.getStrategy(address(eTST)); + Strategy memory strategyBefore = aggregationLayerVault.getStrategy(address(eTST)); - assertEq(eTST.convertToAssets(eTST.balanceOf(address(fourSixTwoSixAgg))), strategyBefore.allocated); + assertEq(eTST.convertToAssets(eTST.balanceOf(address(aggregationLayerVault))), strategyBefore.allocated); - uint256 expectedStrategyCash = fourSixTwoSixAgg.totalAssetsAllocatable() * strategyBefore.allocationPoints - / fourSixTwoSixAgg.totalAllocationPoints(); + uint256 expectedStrategyCash = aggregationLayerVault.totalAssetsAllocatable() + * strategyBefore.allocationPoints / aggregationLayerVault.totalAllocationPoints(); vm.prank(user1); address[] memory strategiesToRebalance = new address[](1); strategiesToRebalance[0] = address(eTST); - rebalancer.executeRebalance(address(fourSixTwoSixAgg), strategiesToRebalance); + rebalancer.executeRebalance(address(aggregationLayerVault), strategiesToRebalance); - assertEq(fourSixTwoSixAgg.totalAllocated(), expectedStrategyCash); - assertEq(eTST.convertToAssets(eTST.balanceOf(address(fourSixTwoSixAgg))), expectedStrategyCash); - assertEq((fourSixTwoSixAgg.getStrategy(address(eTST))).allocated, expectedStrategyCash); + assertEq(aggregationLayerVault.totalAllocated(), expectedStrategyCash); + assertEq(eTST.convertToAssets(eTST.balanceOf(address(aggregationLayerVault))), expectedStrategyCash); + assertEq((aggregationLayerVault.getStrategy(address(eTST))).allocated, expectedStrategyCash); } } function testHarvest() public { // no yield increase - FourSixTwoSixAgg.Strategy memory strategyBefore = fourSixTwoSixAgg.getStrategy(address(eTST)); - uint256 totalAllocatedBefore = fourSixTwoSixAgg.totalAllocated(); + Strategy memory strategyBefore = aggregationLayerVault.getStrategy(address(eTST)); + uint256 totalAllocatedBefore = aggregationLayerVault.totalAllocated(); - assertTrue(eTST.convertToAssets(eTST.balanceOf(address(fourSixTwoSixAgg))) == strategyBefore.allocated); + assertTrue(eTST.convertToAssets(eTST.balanceOf(address(aggregationLayerVault))) == strategyBefore.allocated); vm.prank(user1); - fourSixTwoSixAgg.harvest(address(eTST)); + aggregationLayerVault.harvest(address(eTST)); - assertEq((fourSixTwoSixAgg.getStrategy(address(eTST))).allocated, strategyBefore.allocated); - assertEq(fourSixTwoSixAgg.totalAllocated(), totalAllocatedBefore); + assertEq((aggregationLayerVault.getStrategy(address(eTST))).allocated, strategyBefore.allocated); + assertEq(aggregationLayerVault.totalAllocated(), totalAllocatedBefore); // positive yield vm.warp(block.timestamp + 86400); // mock an increase of strategy balance by 10% - uint256 aggrCurrentStrategyBalance = eTST.balanceOf(address(fourSixTwoSixAgg)); + uint256 aggrCurrentStrategyBalance = eTST.balanceOf(address(aggregationLayerVault)); vm.mockCall( address(eTST), - abi.encodeWithSelector(EVault.balanceOf.selector, address(fourSixTwoSixAgg)), + abi.encodeWithSelector(EVault.balanceOf.selector, address(aggregationLayerVault)), abi.encode(aggrCurrentStrategyBalance * 11e17 / 1e18) ); - assertTrue(eTST.convertToAssets(eTST.balanceOf(address(fourSixTwoSixAgg))) > strategyBefore.allocated); - uint256 expectedAllocated = eTST.maxWithdraw(address(fourSixTwoSixAgg)); + assertTrue(eTST.convertToAssets(eTST.balanceOf(address(aggregationLayerVault))) > strategyBefore.allocated); + uint256 expectedAllocated = eTST.maxWithdraw(address(aggregationLayerVault)); vm.prank(user1); - fourSixTwoSixAgg.harvest(address(eTST)); + aggregationLayerVault.harvest(address(eTST)); - assertEq((fourSixTwoSixAgg.getStrategy(address(eTST))).allocated, expectedAllocated); + assertEq((aggregationLayerVault.getStrategy(address(eTST))).allocated, expectedAllocated); assertEq( - fourSixTwoSixAgg.totalAllocated(), totalAllocatedBefore + (expectedAllocated - strategyBefore.allocated) + aggregationLayerVault.totalAllocated(), + totalAllocatedBefore + (expectedAllocated - strategyBefore.allocated) ); } @@ -94,49 +101,49 @@ contract HarvestTest is FourSixTwoSixAggBase { vm.warp(block.timestamp + 86400); // mock a decrease of strategy balance by 10% - uint256 aggrCurrentStrategyBalance = eTST.balanceOf(address(fourSixTwoSixAgg)); + uint256 aggrCurrentStrategyBalance = eTST.balanceOf(address(aggregationLayerVault)); vm.mockCall( address(eTST), - abi.encodeWithSelector(EVault.balanceOf.selector, address(fourSixTwoSixAgg)), + abi.encodeWithSelector(EVault.balanceOf.selector, address(aggregationLayerVault)), abi.encode(aggrCurrentStrategyBalance * 9e17 / 1e18) ); - FourSixTwoSixAgg.Strategy memory strategyBefore = fourSixTwoSixAgg.getStrategy(address(eTST)); + Strategy memory strategyBefore = aggregationLayerVault.getStrategy(address(eTST)); - assertTrue(eTST.convertToAssets(eTST.balanceOf(address(fourSixTwoSixAgg))) < strategyBefore.allocated); + assertTrue(eTST.convertToAssets(eTST.balanceOf(address(aggregationLayerVault))) < strategyBefore.allocated); vm.prank(user1); - fourSixTwoSixAgg.harvest(address(eTST)); + aggregationLayerVault.harvest(address(eTST)); } function testHarvestNegativeYieldAndWithdrawSingleUser() public { vm.warp(block.timestamp + 86400); // mock a decrease of strategy balance by 10% - uint256 aggrCurrentStrategyBalance = eTST.balanceOf(address(fourSixTwoSixAgg)); + uint256 aggrCurrentStrategyBalance = eTST.balanceOf(address(aggregationLayerVault)); uint256 aggrCurrentStrategyBalanceAfterNegYield = aggrCurrentStrategyBalance * 9e17 / 1e18; vm.mockCall( address(eTST), - abi.encodeWithSelector(EVault.balanceOf.selector, address(fourSixTwoSixAgg)), + abi.encodeWithSelector(EVault.balanceOf.selector, address(aggregationLayerVault)), abi.encode(aggrCurrentStrategyBalanceAfterNegYield) ); - FourSixTwoSixAgg.Strategy memory strategyBefore = fourSixTwoSixAgg.getStrategy(address(eTST)); - assertTrue(eTST.convertToAssets(eTST.balanceOf(address(fourSixTwoSixAgg))) < strategyBefore.allocated); - uint256 negativeYield = strategyBefore.allocated - eTST.maxWithdraw(address(fourSixTwoSixAgg)); + Strategy memory strategyBefore = aggregationLayerVault.getStrategy(address(eTST)); + assertTrue(eTST.convertToAssets(eTST.balanceOf(address(aggregationLayerVault))) < strategyBefore.allocated); + uint256 negativeYield = strategyBefore.allocated - eTST.maxWithdraw(address(aggregationLayerVault)); - uint256 user1SharesBefore = fourSixTwoSixAgg.balanceOf(user1); - uint256 user1SocializedLoss = user1SharesBefore * negativeYield / fourSixTwoSixAgg.totalSupply(); + uint256 user1SharesBefore = aggregationLayerVault.balanceOf(user1); + uint256 user1SocializedLoss = user1SharesBefore * negativeYield / aggregationLayerVault.totalSupply(); uint256 expectedUser1Assets = - user1SharesBefore * amountToDeposit / fourSixTwoSixAgg.totalSupply() - user1SocializedLoss; + user1SharesBefore * amountToDeposit / aggregationLayerVault.totalSupply() - user1SocializedLoss; uint256 user1AssetTSTBalanceBefore = assetTST.balanceOf(user1); vm.startPrank(user1); - fourSixTwoSixAgg.harvest(address(eTST)); - fourSixTwoSixAgg.redeem(user1SharesBefore, user1, user1); + aggregationLayerVault.harvest(address(eTST)); + aggregationLayerVault.redeem(user1SharesBefore, user1, user1); vm.stopPrank(); - uint256 user1SharesAfter = fourSixTwoSixAgg.balanceOf(user1); + uint256 user1SharesAfter = aggregationLayerVault.balanceOf(user1); assertEq(user1SharesAfter, 0); assertApproxEqAbs(assetTST.balanceOf(user1), user1AssetTSTBalanceBefore + expectedUser1Assets, 1); @@ -148,42 +155,42 @@ contract HarvestTest is FourSixTwoSixAggBase { // deposit into aggregator { vm.startPrank(user2); - assetTST.approve(address(fourSixTwoSixAgg), user2InitialBalance); - fourSixTwoSixAgg.deposit(user2InitialBalance, user2); + assetTST.approve(address(aggregationLayerVault), user2InitialBalance); + aggregationLayerVault.deposit(user2InitialBalance, user2); vm.stopPrank(); } vm.warp(block.timestamp + 86400); // mock a decrease of strategy balance by 10% - uint256 aggrCurrentStrategyBalance = eTST.balanceOf(address(fourSixTwoSixAgg)); + uint256 aggrCurrentStrategyBalance = eTST.balanceOf(address(aggregationLayerVault)); uint256 aggrCurrentStrategyBalanceAfterNegYield = aggrCurrentStrategyBalance * 9e17 / 1e18; vm.mockCall( address(eTST), - abi.encodeWithSelector(EVault.balanceOf.selector, address(fourSixTwoSixAgg)), + abi.encodeWithSelector(EVault.balanceOf.selector, address(aggregationLayerVault)), abi.encode(aggrCurrentStrategyBalanceAfterNegYield) ); - FourSixTwoSixAgg.Strategy memory strategyBefore = fourSixTwoSixAgg.getStrategy(address(eTST)); - assertTrue(eTST.convertToAssets(eTST.balanceOf(address(fourSixTwoSixAgg))) < strategyBefore.allocated); - uint256 negativeYield = strategyBefore.allocated - eTST.maxWithdraw(address(fourSixTwoSixAgg)); - uint256 user1SharesBefore = fourSixTwoSixAgg.balanceOf(user1); - uint256 user1SocializedLoss = user1SharesBefore * negativeYield / fourSixTwoSixAgg.totalSupply(); - uint256 user2SharesBefore = fourSixTwoSixAgg.balanceOf(user2); - uint256 user2SocializedLoss = user2SharesBefore * negativeYield / fourSixTwoSixAgg.totalSupply(); + Strategy memory strategyBefore = aggregationLayerVault.getStrategy(address(eTST)); + assertTrue(eTST.convertToAssets(eTST.balanceOf(address(aggregationLayerVault))) < strategyBefore.allocated); + uint256 negativeYield = strategyBefore.allocated - eTST.maxWithdraw(address(aggregationLayerVault)); + uint256 user1SharesBefore = aggregationLayerVault.balanceOf(user1); + uint256 user1SocializedLoss = user1SharesBefore * negativeYield / aggregationLayerVault.totalSupply(); + uint256 user2SharesBefore = aggregationLayerVault.balanceOf(user2); + uint256 user2SocializedLoss = user2SharesBefore * negativeYield / aggregationLayerVault.totalSupply(); uint256 expectedUser1Assets = user1SharesBefore * (amountToDeposit + user2InitialBalance) - / fourSixTwoSixAgg.totalSupply() - user1SocializedLoss; + / aggregationLayerVault.totalSupply() - user1SocializedLoss; uint256 expectedUser2Assets = user2SharesBefore * (amountToDeposit + user2InitialBalance) - / fourSixTwoSixAgg.totalSupply() - user2SocializedLoss; + / aggregationLayerVault.totalSupply() - user2SocializedLoss; vm.prank(user1); - fourSixTwoSixAgg.harvest(address(eTST)); + aggregationLayerVault.harvest(address(eTST)); - uint256 user1SharesAfter = fourSixTwoSixAgg.balanceOf(user1); - uint256 user1AssetsAfter = fourSixTwoSixAgg.convertToAssets(user1SharesAfter); - uint256 user2SharesAfter = fourSixTwoSixAgg.balanceOf(user2); - uint256 user2AssetsAfter = fourSixTwoSixAgg.convertToAssets(user2SharesAfter); + uint256 user1SharesAfter = aggregationLayerVault.balanceOf(user1); + uint256 user1AssetsAfter = aggregationLayerVault.convertToAssets(user1SharesAfter); + uint256 user2SharesAfter = aggregationLayerVault.balanceOf(user2); + uint256 user2AssetsAfter = aggregationLayerVault.convertToAssets(user2SharesAfter); assertApproxEqAbs(user1AssetsAfter, expectedUser1Assets, 1); assertApproxEqAbs(user2AssetsAfter, expectedUser2Assets, 1); diff --git a/test/unit/RebalanceTest.t.sol b/test/unit/RebalanceTest.t.sol index 5342e9b0..ca0f69fb 100644 --- a/test/unit/RebalanceTest.t.sol +++ b/test/unit/RebalanceTest.t.sol @@ -2,16 +2,17 @@ pragma solidity ^0.8.0; import { - FourSixTwoSixAggBase, - FourSixTwoSixAgg, + AggregationLayerVaultBase, + AggregationLayerVault, console2, EVault, IEVault, IRMTestDefault, - TestERC20 -} from "../common/FourSixTwoSixAggBase.t.sol"; + TestERC20, + Strategy +} from "../common/AggregationLayerVaultBase.t.sol"; -contract RebalanceTest is FourSixTwoSixAggBase { +contract RebalanceTest is AggregationLayerVaultBase { uint256 user1InitialBalance = 100000e18; function setUp() public virtual override { @@ -28,40 +29,41 @@ contract RebalanceTest is FourSixTwoSixAggBase { // deposit into aggregator { - uint256 balanceBefore = fourSixTwoSixAgg.balanceOf(user1); - uint256 totalSupplyBefore = fourSixTwoSixAgg.totalSupply(); - uint256 totalAssetsDepositedBefore = fourSixTwoSixAgg.totalAssetsDeposited(); + uint256 balanceBefore = aggregationLayerVault.balanceOf(user1); + uint256 totalSupplyBefore = aggregationLayerVault.totalSupply(); + uint256 totalAssetsDepositedBefore = aggregationLayerVault.totalAssetsDeposited(); uint256 userAssetBalanceBefore = assetTST.balanceOf(user1); vm.startPrank(user1); - assetTST.approve(address(fourSixTwoSixAgg), amountToDeposit); - fourSixTwoSixAgg.deposit(amountToDeposit, user1); + assetTST.approve(address(aggregationLayerVault), amountToDeposit); + aggregationLayerVault.deposit(amountToDeposit, user1); vm.stopPrank(); - assertEq(fourSixTwoSixAgg.balanceOf(user1), balanceBefore + amountToDeposit); - assertEq(fourSixTwoSixAgg.totalSupply(), totalSupplyBefore + amountToDeposit); - assertEq(fourSixTwoSixAgg.totalAssetsDeposited(), totalAssetsDepositedBefore + amountToDeposit); + assertEq(aggregationLayerVault.balanceOf(user1), balanceBefore + amountToDeposit); + assertEq(aggregationLayerVault.totalSupply(), totalSupplyBefore + amountToDeposit); + assertEq(aggregationLayerVault.totalAssetsDeposited(), totalAssetsDepositedBefore + amountToDeposit); assertEq(assetTST.balanceOf(user1), userAssetBalanceBefore - amountToDeposit); } // rebalance into strategy vm.warp(block.timestamp + 86400); - FourSixTwoSixAgg.Strategy memory strategyBefore = fourSixTwoSixAgg.getStrategy(address(eTST)); + Strategy memory strategyBefore = aggregationLayerVault.getStrategy(address(eTST)); - assertEq(eTST.convertToAssets(eTST.balanceOf(address(fourSixTwoSixAgg))), strategyBefore.allocated); + assertEq(eTST.convertToAssets(eTST.balanceOf(address(aggregationLayerVault))), strategyBefore.allocated); - uint256 expectedStrategyCash = fourSixTwoSixAgg.totalAssetsAllocatable() * strategyBefore.allocationPoints - / fourSixTwoSixAgg.totalAllocationPoints(); + uint256 expectedStrategyCash = aggregationLayerVault.totalAssetsAllocatable() * strategyBefore.allocationPoints + / aggregationLayerVault.totalAllocationPoints(); vm.prank(user1); address[] memory strategiesToRebalance = new address[](1); strategiesToRebalance[0] = address(eTST); - rebalancer.executeRebalance(address(fourSixTwoSixAgg), strategiesToRebalance); + rebalancer.executeRebalance(address(aggregationLayerVault), strategiesToRebalance); - assertEq(fourSixTwoSixAgg.totalAllocated(), expectedStrategyCash); - assertEq(eTST.convertToAssets(eTST.balanceOf(address(fourSixTwoSixAgg))), expectedStrategyCash); + assertEq(aggregationLayerVault.totalAllocated(), expectedStrategyCash); + assertEq(eTST.convertToAssets(eTST.balanceOf(address(aggregationLayerVault))), expectedStrategyCash); assertEq( - (fourSixTwoSixAgg.getStrategy(address(eTST))).allocated, strategyBefore.allocated + expectedStrategyCash + (aggregationLayerVault.getStrategy(address(eTST))).allocated, + strategyBefore.allocated + expectedStrategyCash ); } @@ -70,45 +72,47 @@ contract RebalanceTest is FourSixTwoSixAggBase { // deposit into aggregator { - uint256 balanceBefore = fourSixTwoSixAgg.balanceOf(user1); - uint256 totalSupplyBefore = fourSixTwoSixAgg.totalSupply(); - uint256 totalAssetsDepositedBefore = fourSixTwoSixAgg.totalAssetsDeposited(); + uint256 balanceBefore = aggregationLayerVault.balanceOf(user1); + uint256 totalSupplyBefore = aggregationLayerVault.totalSupply(); + uint256 totalAssetsDepositedBefore = aggregationLayerVault.totalAssetsDeposited(); uint256 userAssetBalanceBefore = assetTST.balanceOf(user1); vm.startPrank(user1); - assetTST.approve(address(fourSixTwoSixAgg), amountToDeposit); - fourSixTwoSixAgg.deposit(amountToDeposit, user1); + assetTST.approve(address(aggregationLayerVault), amountToDeposit); + aggregationLayerVault.deposit(amountToDeposit, user1); vm.stopPrank(); - assertEq(fourSixTwoSixAgg.balanceOf(user1), balanceBefore + amountToDeposit); - assertEq(fourSixTwoSixAgg.totalSupply(), totalSupplyBefore + amountToDeposit); - assertEq(fourSixTwoSixAgg.totalAssetsDeposited(), totalAssetsDepositedBefore + amountToDeposit); + assertEq(aggregationLayerVault.balanceOf(user1), balanceBefore + amountToDeposit); + assertEq(aggregationLayerVault.totalSupply(), totalSupplyBefore + amountToDeposit); + assertEq(aggregationLayerVault.totalAssetsDeposited(), totalAssetsDepositedBefore + amountToDeposit); assertEq(assetTST.balanceOf(user1), userAssetBalanceBefore - amountToDeposit); } // rebalance into strategy vm.warp(block.timestamp + 86400); - FourSixTwoSixAgg.Strategy memory strategyBefore = fourSixTwoSixAgg.getStrategy(address(eTST)); + Strategy memory strategyBefore = aggregationLayerVault.getStrategy(address(eTST)); - assertEq(eTST.convertToAssets(eTST.balanceOf(address(fourSixTwoSixAgg))), strategyBefore.allocated); + assertEq(eTST.convertToAssets(eTST.balanceOf(address(aggregationLayerVault))), strategyBefore.allocated); - uint256 expectedStrategyCash = fourSixTwoSixAgg.totalAssetsAllocatable() * strategyBefore.allocationPoints - / fourSixTwoSixAgg.totalAllocationPoints(); + uint256 expectedStrategyCash = aggregationLayerVault.totalAssetsAllocatable() * strategyBefore.allocationPoints + / aggregationLayerVault.totalAllocationPoints(); uint256 expectedToDeposit = expectedStrategyCash - strategyBefore.allocated; uint256 eTSTMaxDeposit = expectedToDeposit * 7e17 / 1e18; // mock max deposit vm.mockCall( - address(eTST), abi.encodeCall(eTST.maxDeposit, (address(fourSixTwoSixAgg))), abi.encode(eTSTMaxDeposit) + address(eTST), abi.encodeCall(eTST.maxDeposit, (address(aggregationLayerVault))), abi.encode(eTSTMaxDeposit) ); vm.prank(user1); address[] memory strategiesToRebalance = new address[](1); strategiesToRebalance[0] = address(eTST); - rebalancer.executeRebalance(address(fourSixTwoSixAgg), strategiesToRebalance); + rebalancer.executeRebalance(address(aggregationLayerVault), strategiesToRebalance); - assertEq(fourSixTwoSixAgg.totalAllocated(), eTSTMaxDeposit); - assertEq(eTST.convertToAssets(eTST.balanceOf(address(fourSixTwoSixAgg))), eTSTMaxDeposit); - assertEq((fourSixTwoSixAgg.getStrategy(address(eTST))).allocated, strategyBefore.allocated + eTSTMaxDeposit); + assertEq(aggregationLayerVault.totalAllocated(), eTSTMaxDeposit); + assertEq(eTST.convertToAssets(eTST.balanceOf(address(aggregationLayerVault))), eTSTMaxDeposit); + assertEq( + (aggregationLayerVault.getStrategy(address(eTST))).allocated, strategyBefore.allocated + eTSTMaxDeposit + ); } function testRebalanceByDepositingWhenToDepositIsGreaterThanCashAvailable() public { @@ -116,19 +120,19 @@ contract RebalanceTest is FourSixTwoSixAggBase { // deposit into aggregator { - uint256 balanceBefore = fourSixTwoSixAgg.balanceOf(user1); - uint256 totalSupplyBefore = fourSixTwoSixAgg.totalSupply(); - uint256 totalAssetsDepositedBefore = fourSixTwoSixAgg.totalAssetsDeposited(); + uint256 balanceBefore = aggregationLayerVault.balanceOf(user1); + uint256 totalSupplyBefore = aggregationLayerVault.totalSupply(); + uint256 totalAssetsDepositedBefore = aggregationLayerVault.totalAssetsDeposited(); uint256 userAssetBalanceBefore = assetTST.balanceOf(user1); vm.startPrank(user1); - assetTST.approve(address(fourSixTwoSixAgg), amountToDeposit); - fourSixTwoSixAgg.deposit(amountToDeposit, user1); + assetTST.approve(address(aggregationLayerVault), amountToDeposit); + aggregationLayerVault.deposit(amountToDeposit, user1); vm.stopPrank(); - assertEq(fourSixTwoSixAgg.balanceOf(user1), balanceBefore + amountToDeposit); - assertEq(fourSixTwoSixAgg.totalSupply(), totalSupplyBefore + amountToDeposit); - assertEq(fourSixTwoSixAgg.totalAssetsDeposited(), totalAssetsDepositedBefore + amountToDeposit); + assertEq(aggregationLayerVault.balanceOf(user1), balanceBefore + amountToDeposit); + assertEq(aggregationLayerVault.totalSupply(), totalSupplyBefore + amountToDeposit); + assertEq(aggregationLayerVault.totalAssetsDeposited(), totalAssetsDepositedBefore + amountToDeposit); assertEq(assetTST.balanceOf(user1), userAssetBalanceBefore - amountToDeposit); } @@ -137,7 +141,7 @@ contract RebalanceTest is FourSixTwoSixAggBase { vm.prank(user1); address[] memory strategiesToRebalance = new address[](1); strategiesToRebalance[0] = address(eTST); - rebalancer.executeRebalance(address(fourSixTwoSixAgg), strategiesToRebalance); + rebalancer.executeRebalance(address(aggregationLayerVault), strategiesToRebalance); // create new strategy & add it IEVault eTSTsecondary; @@ -154,29 +158,32 @@ contract RebalanceTest is FourSixTwoSixAggBase { // rebalance into eTSTsecondary vm.warp(block.timestamp + 86400); { - FourSixTwoSixAgg.Strategy memory strategyBefore = fourSixTwoSixAgg.getStrategy(address(eTSTsecondary)); + Strategy memory strategyBefore = aggregationLayerVault.getStrategy(address(eTSTsecondary)); assertEq( - eTSTsecondary.convertToAssets(eTSTsecondary.balanceOf(address(fourSixTwoSixAgg))), + eTSTsecondary.convertToAssets(eTSTsecondary.balanceOf(address(aggregationLayerVault))), strategyBefore.allocated ); - uint256 targetCash = fourSixTwoSixAgg.totalAssetsAllocatable() - * fourSixTwoSixAgg.getStrategy(address(0)).allocationPoints / fourSixTwoSixAgg.totalAllocationPoints(); - uint256 currentCash = fourSixTwoSixAgg.totalAssetsAllocatable() - fourSixTwoSixAgg.totalAllocated(); + uint256 targetCash = aggregationLayerVault.totalAssetsAllocatable() + * aggregationLayerVault.getStrategy(address(0)).allocationPoints + / aggregationLayerVault.totalAllocationPoints(); + uint256 currentCash = + aggregationLayerVault.totalAssetsAllocatable() - aggregationLayerVault.totalAllocated(); uint256 expectedStrategyCash = currentCash - targetCash; vm.prank(user1); address[] memory strategiesToRebalance = new address[](1); strategiesToRebalance[0] = address(eTSTsecondary); - rebalancer.executeRebalance(address(fourSixTwoSixAgg), strategiesToRebalance); + rebalancer.executeRebalance(address(aggregationLayerVault), strategiesToRebalance); - // assertEq(fourSixTwoSixAgg.totalAllocated(), eTSTsecondaryMaxDeposit); + // assertEq(aggregationLayerVault.totalAllocated(), eTSTsecondaryMaxDeposit); assertEq( - eTSTsecondary.convertToAssets(eTSTsecondary.balanceOf(address(fourSixTwoSixAgg))), expectedStrategyCash + eTSTsecondary.convertToAssets(eTSTsecondary.balanceOf(address(aggregationLayerVault))), + expectedStrategyCash ); assertEq( - (fourSixTwoSixAgg.getStrategy(address(eTSTsecondary))).allocated, + (aggregationLayerVault.getStrategy(address(eTSTsecondary))).allocated, strategyBefore.allocated + expectedStrategyCash ); } @@ -187,42 +194,42 @@ contract RebalanceTest is FourSixTwoSixAggBase { // deposit into aggregator { - uint256 balanceBefore = fourSixTwoSixAgg.balanceOf(user1); - uint256 totalSupplyBefore = fourSixTwoSixAgg.totalSupply(); - uint256 totalAssetsDepositedBefore = fourSixTwoSixAgg.totalAssetsDeposited(); + uint256 balanceBefore = aggregationLayerVault.balanceOf(user1); + uint256 totalSupplyBefore = aggregationLayerVault.totalSupply(); + uint256 totalAssetsDepositedBefore = aggregationLayerVault.totalAssetsDeposited(); uint256 userAssetBalanceBefore = assetTST.balanceOf(user1); vm.startPrank(user1); - assetTST.approve(address(fourSixTwoSixAgg), amountToDeposit); - fourSixTwoSixAgg.deposit(amountToDeposit, user1); + assetTST.approve(address(aggregationLayerVault), amountToDeposit); + aggregationLayerVault.deposit(amountToDeposit, user1); vm.stopPrank(); - assertEq(fourSixTwoSixAgg.balanceOf(user1), balanceBefore + amountToDeposit); - assertEq(fourSixTwoSixAgg.totalSupply(), totalSupplyBefore + amountToDeposit); - assertEq(fourSixTwoSixAgg.totalAssetsDeposited(), totalAssetsDepositedBefore + amountToDeposit); + assertEq(aggregationLayerVault.balanceOf(user1), balanceBefore + amountToDeposit); + assertEq(aggregationLayerVault.totalSupply(), totalSupplyBefore + amountToDeposit); + assertEq(aggregationLayerVault.totalAssetsDeposited(), totalAssetsDepositedBefore + amountToDeposit); assertEq(assetTST.balanceOf(user1), userAssetBalanceBefore - amountToDeposit); } // rebalance into strategy vm.warp(block.timestamp + 86400); - FourSixTwoSixAgg.Strategy memory strategyBefore = fourSixTwoSixAgg.getStrategy(address(eTST)); + Strategy memory strategyBefore = aggregationLayerVault.getStrategy(address(eTST)); - assertEq(eTST.convertToAssets(eTST.balanceOf(address(fourSixTwoSixAgg))), strategyBefore.allocated); + assertEq(eTST.convertToAssets(eTST.balanceOf(address(aggregationLayerVault))), strategyBefore.allocated); uint256 eTSTMaxDeposit = 0; // mock max deposit vm.mockCall( - address(eTST), abi.encodeCall(eTST.maxDeposit, (address(fourSixTwoSixAgg))), abi.encode(eTSTMaxDeposit) + address(eTST), abi.encodeCall(eTST.maxDeposit, (address(aggregationLayerVault))), abi.encode(eTSTMaxDeposit) ); vm.prank(user1); address[] memory strategiesToRebalance = new address[](1); strategiesToRebalance[0] = address(eTST); - rebalancer.executeRebalance(address(fourSixTwoSixAgg), strategiesToRebalance); + rebalancer.executeRebalance(address(aggregationLayerVault), strategiesToRebalance); - assertEq(fourSixTwoSixAgg.totalAllocated(), strategyBefore.allocated); - assertEq(eTST.convertToAssets(eTST.balanceOf(address(fourSixTwoSixAgg))), strategyBefore.allocated); - assertEq((fourSixTwoSixAgg.getStrategy(address(eTST))).allocated, strategyBefore.allocated); + assertEq(aggregationLayerVault.totalAllocated(), strategyBefore.allocated); + assertEq(eTST.convertToAssets(eTST.balanceOf(address(aggregationLayerVault))), strategyBefore.allocated); + assertEq((aggregationLayerVault.getStrategy(address(eTST))).allocated, strategyBefore.allocated); } function testRebalanceByWithdrawing() public { @@ -230,19 +237,19 @@ contract RebalanceTest is FourSixTwoSixAggBase { // deposit into aggregator { - uint256 balanceBefore = fourSixTwoSixAgg.balanceOf(user1); - uint256 totalSupplyBefore = fourSixTwoSixAgg.totalSupply(); - uint256 totalAssetsDepositedBefore = fourSixTwoSixAgg.totalAssetsDeposited(); + uint256 balanceBefore = aggregationLayerVault.balanceOf(user1); + uint256 totalSupplyBefore = aggregationLayerVault.totalSupply(); + uint256 totalAssetsDepositedBefore = aggregationLayerVault.totalAssetsDeposited(); uint256 userAssetBalanceBefore = assetTST.balanceOf(user1); vm.startPrank(user1); - assetTST.approve(address(fourSixTwoSixAgg), amountToDeposit); - fourSixTwoSixAgg.deposit(amountToDeposit, user1); + assetTST.approve(address(aggregationLayerVault), amountToDeposit); + aggregationLayerVault.deposit(amountToDeposit, user1); vm.stopPrank(); - assertEq(fourSixTwoSixAgg.balanceOf(user1), balanceBefore + amountToDeposit); - assertEq(fourSixTwoSixAgg.totalSupply(), totalSupplyBefore + amountToDeposit); - assertEq(fourSixTwoSixAgg.totalAssetsDeposited(), totalAssetsDepositedBefore + amountToDeposit); + assertEq(aggregationLayerVault.balanceOf(user1), balanceBefore + amountToDeposit); + assertEq(aggregationLayerVault.totalSupply(), totalSupplyBefore + amountToDeposit); + assertEq(aggregationLayerVault.totalAssetsDeposited(), totalAssetsDepositedBefore + amountToDeposit); assertEq(assetTST.balanceOf(user1), userAssetBalanceBefore - amountToDeposit); } @@ -251,53 +258,52 @@ contract RebalanceTest is FourSixTwoSixAggBase { vm.prank(user1); address[] memory strategiesToRebalance = new address[](1); strategiesToRebalance[0] = address(eTST); - rebalancer.executeRebalance(address(fourSixTwoSixAgg), strategiesToRebalance); + rebalancer.executeRebalance(address(aggregationLayerVault), strategiesToRebalance); // decrease allocation points uint256 newAllocationPoints = 300e18; vm.prank(manager); - fourSixTwoSixAgg.adjustAllocationPoints(address(eTST), newAllocationPoints); + aggregationLayerVault.adjustAllocationPoints(address(eTST), newAllocationPoints); vm.warp(block.timestamp + 86400); - FourSixTwoSixAgg.Strategy memory strategyBefore = fourSixTwoSixAgg.getStrategy(address(eTST)); + Strategy memory strategyBefore = aggregationLayerVault.getStrategy(address(eTST)); - assertEq(eTST.convertToAssets(eTST.balanceOf(address(fourSixTwoSixAgg))), strategyBefore.allocated); + assertEq(eTST.convertToAssets(eTST.balanceOf(address(aggregationLayerVault))), strategyBefore.allocated); - uint256 expectedStrategyCash = fourSixTwoSixAgg.totalAssetsAllocatable() * strategyBefore.allocationPoints - / fourSixTwoSixAgg.totalAllocationPoints(); + uint256 expectedStrategyCash = aggregationLayerVault.totalAssetsAllocatable() * strategyBefore.allocationPoints + / aggregationLayerVault.totalAllocationPoints(); vm.prank(user1); strategiesToRebalance[0] = address(eTST); - rebalancer.executeRebalance(address(fourSixTwoSixAgg), strategiesToRebalance); + rebalancer.executeRebalance(address(aggregationLayerVault), strategiesToRebalance); - assertEq(fourSixTwoSixAgg.totalAllocated(), expectedStrategyCash); - assertEq(eTST.convertToAssets(eTST.balanceOf(address(fourSixTwoSixAgg))), expectedStrategyCash); + assertEq(aggregationLayerVault.totalAllocated(), expectedStrategyCash); + assertEq(eTST.convertToAssets(eTST.balanceOf(address(aggregationLayerVault))), expectedStrategyCash); assertEq( - (fourSixTwoSixAgg.getStrategy(address(eTST))).allocated, + (aggregationLayerVault.getStrategy(address(eTST))).allocated, strategyBefore.allocated - (strategyBefore.allocated - expectedStrategyCash) ); } - /// TODO: update this test function testRebalanceByWithdrawingWhenToWithdrawIsGreaterThanMaxWithdraw() public { uint256 amountToDeposit = 10000e18; // deposit into aggregator { - uint256 balanceBefore = fourSixTwoSixAgg.balanceOf(user1); - uint256 totalSupplyBefore = fourSixTwoSixAgg.totalSupply(); - uint256 totalAssetsDepositedBefore = fourSixTwoSixAgg.totalAssetsDeposited(); + uint256 balanceBefore = aggregationLayerVault.balanceOf(user1); + uint256 totalSupplyBefore = aggregationLayerVault.totalSupply(); + uint256 totalAssetsDepositedBefore = aggregationLayerVault.totalAssetsDeposited(); uint256 userAssetBalanceBefore = assetTST.balanceOf(user1); vm.startPrank(user1); - assetTST.approve(address(fourSixTwoSixAgg), amountToDeposit); - fourSixTwoSixAgg.deposit(amountToDeposit, user1); + assetTST.approve(address(aggregationLayerVault), amountToDeposit); + aggregationLayerVault.deposit(amountToDeposit, user1); vm.stopPrank(); - assertEq(fourSixTwoSixAgg.balanceOf(user1), balanceBefore + amountToDeposit); - assertEq(fourSixTwoSixAgg.totalSupply(), totalSupplyBefore + amountToDeposit); - assertEq(fourSixTwoSixAgg.totalAssetsDeposited(), totalAssetsDepositedBefore + amountToDeposit); + assertEq(aggregationLayerVault.balanceOf(user1), balanceBefore + amountToDeposit); + assertEq(aggregationLayerVault.totalSupply(), totalSupplyBefore + amountToDeposit); + assertEq(aggregationLayerVault.totalAssetsDeposited(), totalAssetsDepositedBefore + amountToDeposit); assertEq(assetTST.balanceOf(user1), userAssetBalanceBefore - amountToDeposit); } @@ -306,36 +312,38 @@ contract RebalanceTest is FourSixTwoSixAggBase { vm.prank(user1); address[] memory strategiesToRebalance = new address[](1); strategiesToRebalance[0] = address(eTST); - rebalancer.executeRebalance(address(fourSixTwoSixAgg), strategiesToRebalance); + rebalancer.executeRebalance(address(aggregationLayerVault), strategiesToRebalance); // decrease allocation points uint256 newAllocationPoints = 300e18; vm.prank(manager); - fourSixTwoSixAgg.adjustAllocationPoints(address(eTST), newAllocationPoints); + aggregationLayerVault.adjustAllocationPoints(address(eTST), newAllocationPoints); vm.warp(block.timestamp + 86400); - FourSixTwoSixAgg.Strategy memory strategyBefore = fourSixTwoSixAgg.getStrategy(address(eTST)); + Strategy memory strategyBefore = aggregationLayerVault.getStrategy(address(eTST)); - assertEq(eTST.convertToAssets(eTST.balanceOf(address(fourSixTwoSixAgg))), strategyBefore.allocated); + assertEq(eTST.convertToAssets(eTST.balanceOf(address(aggregationLayerVault))), strategyBefore.allocated); - uint256 expectedStrategyCash = fourSixTwoSixAgg.totalAssetsAllocatable() * strategyBefore.allocationPoints - / fourSixTwoSixAgg.totalAllocationPoints(); + uint256 expectedStrategyCash = aggregationLayerVault.totalAssetsAllocatable() * strategyBefore.allocationPoints + / aggregationLayerVault.totalAllocationPoints(); uint256 expectedToWithdraw = strategyBefore.allocated - expectedStrategyCash; uint256 eTSTMaxWithdraw = expectedToWithdraw * 7e17 / 1e18; // mock max withdraw vm.mockCall( - address(eTST), abi.encodeCall(eTST.maxWithdraw, (address(fourSixTwoSixAgg))), abi.encode(eTSTMaxWithdraw) + address(eTST), + abi.encodeCall(eTST.maxWithdraw, (address(aggregationLayerVault))), + abi.encode(eTSTMaxWithdraw) ); vm.prank(user1); strategiesToRebalance[0] = address(eTST); - rebalancer.executeRebalance(address(fourSixTwoSixAgg), strategiesToRebalance); + rebalancer.executeRebalance(address(aggregationLayerVault), strategiesToRebalance); - // assertEq(fourSixTwoSixAgg.totalAllocated(), strategyBefore.allocated - eTSTMaxWithdraw); + // assertEq(aggregationLayerVault.totalAllocated(), strategyBefore.allocated - eTSTMaxWithdraw); // assertEq( - // eTST.convertToAssets(eTST.balanceOf(address(fourSixTwoSixAgg))), strategyBefore.allocated - eTSTMaxWithdraw + // eTST.convertToAssets(eTST.balanceOf(address(aggregationLayerVault))), strategyBefore.allocated - eTSTMaxWithdraw // ); - // assertEq((fourSixTwoSixAgg.getStrategy(address(eTST))).allocated, strategyBefore.allocated - eTSTMaxWithdraw); + // assertEq((aggregationLayerVault.getStrategy(address(eTST))).allocated, strategyBefore.allocated - eTSTMaxWithdraw); } } diff --git a/test/unit/RemoveStrategy.t.sol b/test/unit/RemoveStrategy.t.sol index 9bfb2f66..3846ccd2 100644 --- a/test/unit/RemoveStrategy.t.sol +++ b/test/unit/RemoveStrategy.t.sol @@ -1,9 +1,14 @@ // SPDX-License-Identifier: GPL-2.0-or-later pragma solidity ^0.8.0; -import {FourSixTwoSixAggBase, FourSixTwoSixAgg, IEVault} from "../common/FourSixTwoSixAggBase.t.sol"; - -contract RemoveStrategyTest is FourSixTwoSixAggBase { +import { + AggregationLayerVaultBase, + AggregationLayerVault, + IEVault, + Strategy +} from "../common/AggregationLayerVaultBase.t.sol"; + +contract RemoveStrategyTest is AggregationLayerVaultBase { uint256 strategyAllocationPoints; IEVault anotherStrategy; @@ -16,18 +21,18 @@ contract RemoveStrategyTest is FourSixTwoSixAggBase { } function testRemoveStrategy() public { - uint256 totalAllocationPointsBefore = fourSixTwoSixAgg.totalAllocationPoints(); - uint256 withdrawalQueueLengthBefore = fourSixTwoSixAgg.withdrawalQueueLength(); + uint256 totalAllocationPointsBefore = aggregationLayerVault.totalAllocationPoints(); + uint256 withdrawalQueueLengthBefore = _getWithdrawalQueueLength(); vm.prank(manager); - fourSixTwoSixAgg.removeStrategy(address(eTST)); + aggregationLayerVault.removeStrategy(address(eTST)); - FourSixTwoSixAgg.Strategy memory strategyAfter = fourSixTwoSixAgg.getStrategy(address(eTST)); + Strategy memory strategyAfter = aggregationLayerVault.getStrategy(address(eTST)); assertEq(strategyAfter.active, false); assertEq(strategyAfter.allocationPoints, 0); - assertEq(fourSixTwoSixAgg.totalAllocationPoints(), totalAllocationPointsBefore - strategyAllocationPoints); - assertEq(fourSixTwoSixAgg.withdrawalQueueLength(), withdrawalQueueLengthBefore - 1); + assertEq(aggregationLayerVault.totalAllocationPoints(), totalAllocationPointsBefore - strategyAllocationPoints); + assertEq(_getWithdrawalQueueLength(), withdrawalQueueLengthBefore - 1); } function testRemoveStrategyWithMultipleStrategies() public { @@ -36,18 +41,18 @@ contract RemoveStrategyTest is FourSixTwoSixAggBase { ); _addStrategy(manager, address(anotherStrategy), strategyAllocationPoints); - uint256 totalAllocationPointsBefore = fourSixTwoSixAgg.totalAllocationPoints(); - uint256 withdrawalQueueLengthBefore = fourSixTwoSixAgg.withdrawalQueueLength(); + uint256 totalAllocationPointsBefore = aggregationLayerVault.totalAllocationPoints(); + uint256 withdrawalQueueLengthBefore = _getWithdrawalQueueLength(); vm.prank(manager); - fourSixTwoSixAgg.removeStrategy(address(eTST)); + aggregationLayerVault.removeStrategy(address(eTST)); - FourSixTwoSixAgg.Strategy memory strategyAfter = fourSixTwoSixAgg.getStrategy(address(eTST)); + Strategy memory strategyAfter = aggregationLayerVault.getStrategy(address(eTST)); assertEq(strategyAfter.active, false); assertEq(strategyAfter.allocationPoints, 0); - assertEq(fourSixTwoSixAgg.totalAllocationPoints(), totalAllocationPointsBefore - strategyAllocationPoints); - assertEq(fourSixTwoSixAgg.withdrawalQueueLength(), withdrawalQueueLengthBefore - 1); + assertEq(aggregationLayerVault.totalAllocationPoints(), totalAllocationPointsBefore - strategyAllocationPoints); + assertEq(_getWithdrawalQueueLength(), withdrawalQueueLengthBefore - 1); } function testRemoveStrategy_WithdrawalQueueOrdering() public { @@ -70,7 +75,7 @@ contract RemoveStrategyTest is FourSixTwoSixAggBase { assertEq(withdrawalQueue[3], strategy3); vm.prank(manager); - fourSixTwoSixAgg.removeStrategy(strategy2); + aggregationLayerVault.removeStrategy(strategy2); withdrawalQueue = _getWithdrawalQueue(); assertEq(withdrawalQueue.length, 3); @@ -79,7 +84,7 @@ contract RemoveStrategyTest is FourSixTwoSixAggBase { assertEq(withdrawalQueue[2], strategy3); vm.prank(manager); - fourSixTwoSixAgg.removeStrategy(strategy3); + aggregationLayerVault.removeStrategy(strategy3); withdrawalQueue = _getWithdrawalQueue(); assertEq(withdrawalQueue.length, 2); @@ -87,14 +92,14 @@ contract RemoveStrategyTest is FourSixTwoSixAggBase { assertEq(withdrawalQueue[1], strategy1); vm.prank(manager); - fourSixTwoSixAgg.removeStrategy(address(eTST)); + aggregationLayerVault.removeStrategy(address(eTST)); withdrawalQueue = _getWithdrawalQueue(); assertEq(withdrawalQueue.length, 1); assertEq(withdrawalQueue[0], strategy1); vm.prank(manager); - fourSixTwoSixAgg.removeStrategy(strategy1); + aggregationLayerVault.removeStrategy(strategy1); withdrawalQueue = _getWithdrawalQueue(); assertEq(withdrawalQueue.length, 0); @@ -103,12 +108,12 @@ contract RemoveStrategyTest is FourSixTwoSixAggBase { function testRemoveStrategy_fromUnauthorized() public { vm.prank(deployer); vm.expectRevert(); - fourSixTwoSixAgg.removeStrategy(address(eTST)); + aggregationLayerVault.removeStrategy(address(eTST)); } function testRemoveStrategy_AlreadyRemoved() public { vm.prank(manager); vm.expectRevert(); - fourSixTwoSixAgg.removeStrategy(address(eTST2)); + aggregationLayerVault.removeStrategy(address(eTST2)); } } diff --git a/test/unit/ReorderWithdrawalQueueTest.t.sol b/test/unit/ReorderWithdrawalQueueTest.t.sol index a68e8341..3251194e 100644 --- a/test/unit/ReorderWithdrawalQueueTest.t.sol +++ b/test/unit/ReorderWithdrawalQueueTest.t.sol @@ -1,9 +1,14 @@ // SPDX-License-Identifier: GPL-2.0-or-later pragma solidity ^0.8.0; -import {FourSixTwoSixAggBase, FourSixTwoSixAgg, IEVault} from "../common/FourSixTwoSixAggBase.t.sol"; - -contract ReorderWithdrawalQueueTest is FourSixTwoSixAggBase { +import { + AggregationLayerVaultBase, + AggregationLayerVault, + IEVault, + WithdrawalQueue +} from "../common/AggregationLayerVaultBase.t.sol"; + +contract ReorderWithdrawalQueueTest is AggregationLayerVaultBase { uint256 eTSTAllocationPoints = 500e18; uint256 eTSTsecondaryAllocationPoints = 700e18; @@ -25,37 +30,31 @@ contract ReorderWithdrawalQueueTest is FourSixTwoSixAggBase { } function testReorderWithdrawalQueue() public { + assertEq(aggregationLayerVault.getStrategy(_getWithdrawalQueue()[0]).allocationPoints, eTSTAllocationPoints); assertEq( - fourSixTwoSixAgg.getStrategy(fourSixTwoSixAgg.withdrawalQueue(0)).allocationPoints, eTSTAllocationPoints - ); - assertEq( - fourSixTwoSixAgg.getStrategy(fourSixTwoSixAgg.withdrawalQueue(1)).allocationPoints, - eTSTsecondaryAllocationPoints + aggregationLayerVault.getStrategy(_getWithdrawalQueue()[1]).allocationPoints, eTSTsecondaryAllocationPoints ); vm.prank(manager); - fourSixTwoSixAgg.reorderWithdrawalQueue(0, 1); + withdrawalQueue.reorderWithdrawalQueue(0, 1); assertEq( - fourSixTwoSixAgg.getStrategy(fourSixTwoSixAgg.withdrawalQueue(0)).allocationPoints, - eTSTsecondaryAllocationPoints - ); - assertEq( - fourSixTwoSixAgg.getStrategy(fourSixTwoSixAgg.withdrawalQueue(1)).allocationPoints, eTSTAllocationPoints + aggregationLayerVault.getStrategy(_getWithdrawalQueue()[0]).allocationPoints, eTSTsecondaryAllocationPoints ); + assertEq(aggregationLayerVault.getStrategy(_getWithdrawalQueue()[1]).allocationPoints, eTSTAllocationPoints); } function testReorderWithdrawalQueueWhenOutOfBounds() public { vm.startPrank(manager); - vm.expectRevert(FourSixTwoSixAgg.OutOfBounds.selector); - fourSixTwoSixAgg.reorderWithdrawalQueue(0, 3); + vm.expectRevert(WithdrawalQueue.OutOfBounds.selector); + withdrawalQueue.reorderWithdrawalQueue(0, 3); vm.stopPrank(); } function testReorderWithdrawalQueueWhenSameIndex() public { vm.startPrank(manager); - vm.expectRevert(FourSixTwoSixAgg.SameIndexes.selector); - fourSixTwoSixAgg.reorderWithdrawalQueue(1, 1); + vm.expectRevert(WithdrawalQueue.SameIndexes.selector); + withdrawalQueue.reorderWithdrawalQueue(0, 0); vm.stopPrank(); } }