Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Reduce bytecode size #22

Merged
merged 9 commits into from
Jun 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ jobs:
version: nightly

- name: Run foundry build
run: forge build
run: forge build --sizes

- name: Run foundry fmt check
run: forge fmt --check
Expand Down
2 changes: 1 addition & 1 deletion foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ out = "out"
libs = ["lib"]
test = 'test'
optimizer = true
optimizer_runs = 20_000
optimizer_runs = 1000
# solc = "0.8.0"
gas_reports = ["*"]
fs_permissions = [{ access = "read", path = "./"}]
Expand Down
251 changes: 85 additions & 166 deletions src/FourSixTwoSixAgg.sol

Large diffs are not rendered by default.

7 changes: 3 additions & 4 deletions src/Hooks.sol
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,10 @@ abstract contract Hooks {

uint32 public constant DEPOSIT = 1 << 0;
uint32 public constant WITHDRAW = 1 << 1;
uint32 public constant REBALANCE = 1 << 2;
uint32 public constant ADD_STRATEGY = 1 << 3;
uint32 public constant REMOVE_STRATEGY = 1 << 4;
uint32 public constant ADD_STRATEGY = 1 << 2;
uint32 public constant REMOVE_STRATEGY = 1 << 3;

uint32 constant ACTIONS_COUNTER = 1 << 5;
uint32 constant ACTIONS_COUNTER = 1 << 4;

/// @dev Contract with hooks implementation
address public hookTarget;
Expand Down
93 changes: 93 additions & 0 deletions src/Rebalancer.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
// 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";

contract Rebalancer {
event ExecuteRebalance(
address indexed curatedVault,
address indexed strategy,
uint256 currentAllocation,
uint256 targetAllocation,
uint256 amountToRebalance
);

/// @notice Rebalance strategies allocation for a specific curated vault.
/// @param _curatedVault Curated vault address.
/// @param _strategies Strategies addresses.
function executeRebalance(address _curatedVault, address[] calldata _strategies) external {
for (uint256 i; i < _strategies.length; ++i) {
_rebalance(_curatedVault, _strategies[i]);
}
}

/// @dev This function will first harvest yield, gulps and update interest.
/// @dev If current allocation is greater than target allocation, the aggregator will withdraw the excess assets.
/// If current allocation is less than target allocation, the aggregator will:
/// - Try to deposit the delta, if the cash is not sufficient, deposit all the available cash
/// - If all the available cash is greater than the max deposit, deposit the max deposit
/// @param _curatedVault Curated vault address.
/// @param _strategy Strategy address.
function _rebalance(address _curatedVault, address _strategy) private {
if (_strategy == address(0)) {
return; //nothing to rebalance as that's the cash reserve
}

IFourSixTwoSixAgg(_curatedVault).harvest(_strategy);

IFourSixTwoSixAgg.Strategy memory strategyData = IFourSixTwoSixAgg(_curatedVault).getStrategy(_strategy);

// no rebalance if strategy have an allocated amount greater than cap
if ((strategyData.cap > 0) && (strategyData.allocated >= strategyData.cap)) return;

uint256 totalAllocationPointsCache = IFourSixTwoSixAgg(_curatedVault).totalAllocationPoints();
uint256 totalAssetsAllocatableCache = IFourSixTwoSixAgg(_curatedVault).totalAssetsAllocatable();
uint256 targetAllocation =
totalAssetsAllocatableCache * strategyData.allocationPoints / totalAllocationPointsCache;

if ((strategyData.cap > 0) && (targetAllocation > strategyData.cap)) targetAllocation = strategyData.cap;

uint256 amountToRebalance;
bool isDeposit;
if (strategyData.allocated > targetAllocation) {
// Withdraw
amountToRebalance = strategyData.allocated - targetAllocation;

uint256 maxWithdraw = IERC4626(_strategy).maxWithdraw(_curatedVault);
if (amountToRebalance > maxWithdraw) {
amountToRebalance = maxWithdraw;
}

isDeposit = false;
} else if (strategyData.allocated < targetAllocation) {
// Deposit
uint256 targetCash = totalAssetsAllocatableCache
* IFourSixTwoSixAgg(_curatedVault).getStrategy(address(0)).allocationPoints / totalAllocationPointsCache;
uint256 currentCash = totalAssetsAllocatableCache - IFourSixTwoSixAgg(_curatedVault).totalAllocated();

// Calculate available cash to put in strategies
uint256 cashAvailable = (currentCash > targetCash) ? currentCash - targetCash : 0;

amountToRebalance = targetAllocation - strategyData.allocated;
if (amountToRebalance > cashAvailable) {
amountToRebalance = cashAvailable;
}

uint256 maxDeposit = IERC4626(_strategy).maxDeposit(_curatedVault);
if (amountToRebalance > maxDeposit) {
amountToRebalance = maxDeposit;
}

if (amountToRebalance == 0) {
return; // No cash to deposit
}

isDeposit = true;
}

IFourSixTwoSixAgg(_curatedVault).rebalance(_strategy, amountToRebalance, isDeposit);

emit ExecuteRebalance(_curatedVault, _strategy, strategyData.allocated, targetAllocation, amountToRebalance);
}
}
25 changes: 25 additions & 0 deletions src/interface/IFourSixTwoSixAgg.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// 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;
}

function rebalance(address _strategy, uint256 _amountToRebalance, bool _isDeposit) external;
function gulp() external;
function harvest(address strategy) external;

function getStrategy(address _strategy) external view returns (Strategy memory);
function totalAllocationPoints() external view returns (uint256);
function totalAllocated() external view returns (uint256);
function totalAssetsAllocatable() external view returns (uint256);
}
70 changes: 37 additions & 33 deletions test/common/FourSixTwoSixAggBase.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ 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";

Expand All @@ -15,6 +16,7 @@ contract FourSixTwoSixAggBase is EVaultTestBase {
address manager;

FourSixTwoSixAgg fourSixTwoSixAgg;
Rebalancer rebalancer;

function setUp() public virtual override {
super.setUp();
Expand All @@ -24,6 +26,7 @@ contract FourSixTwoSixAggBase is EVaultTestBase {
user2 = makeAddr("User_2");

vm.startPrank(deployer);
rebalancer = new Rebalancer();
fourSixTwoSixAgg = new FourSixTwoSixAgg(
evc,
address(0),
Expand All @@ -36,18 +39,22 @@ contract FourSixTwoSixAggBase is EVaultTestBase {
);

// grant admin roles to deployer
fourSixTwoSixAgg.grantRole(fourSixTwoSixAgg.STRATEGY_MANAGER_ROLE_ADMINROLE(), deployer);
fourSixTwoSixAgg.grantRole(fourSixTwoSixAgg.WITHDRAW_QUEUE_MANAGER_ROLE_ADMINROLE(), deployer);
fourSixTwoSixAgg.grantRole(fourSixTwoSixAgg.STRATEGY_ADDER_ROLE_ADMINROLE(), deployer);
fourSixTwoSixAgg.grantRole(fourSixTwoSixAgg.STRATEGY_REMOVER_ROLE_ADMINROLE(), deployer);
fourSixTwoSixAgg.grantRole(fourSixTwoSixAgg.MANAGER_ROLE_ADMINROLE(), 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_ROLE(), manager);
fourSixTwoSixAgg.grantRole(fourSixTwoSixAgg.WITHDRAW_QUEUE_MANAGER_ROLE(), manager);
fourSixTwoSixAgg.grantRole(fourSixTwoSixAgg.STRATEGY_ADDER_ROLE(), manager);
fourSixTwoSixAgg.grantRole(fourSixTwoSixAgg.STRATEGY_REMOVER_ROLE(), manager);
fourSixTwoSixAgg.grantRole(fourSixTwoSixAgg.MANAGER_ROLE(), 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();
}
Expand All @@ -60,36 +67,33 @@ contract FourSixTwoSixAggBase is EVaultTestBase {
assertEq(cashReserve.active, true);

assertEq(
fourSixTwoSixAgg.getRoleAdmin(fourSixTwoSixAgg.STRATEGY_MANAGER_ROLE()),
fourSixTwoSixAgg.STRATEGY_MANAGER_ROLE_ADMINROLE()
);
assertEq(
fourSixTwoSixAgg.getRoleAdmin(fourSixTwoSixAgg.WITHDRAW_QUEUE_MANAGER_ROLE()),
fourSixTwoSixAgg.WITHDRAW_QUEUE_MANAGER_ROLE_ADMINROLE()
fourSixTwoSixAgg.getRoleAdmin(fourSixTwoSixAgg.STRATEGY_MANAGER()),
fourSixTwoSixAgg.STRATEGY_MANAGER_ADMIN()
);
assertEq(
fourSixTwoSixAgg.getRoleAdmin(fourSixTwoSixAgg.STRATEGY_ADDER_ROLE()),
fourSixTwoSixAgg.STRATEGY_ADDER_ROLE_ADMINROLE()
fourSixTwoSixAgg.getRoleAdmin(fourSixTwoSixAgg.WITHDRAW_QUEUE_MANAGER()),
fourSixTwoSixAgg.WITHDRAW_QUEUE_MANAGER_ADMIN()
);
assertEq(
fourSixTwoSixAgg.getRoleAdmin(fourSixTwoSixAgg.STRATEGY_REMOVER_ROLE()),
fourSixTwoSixAgg.STRATEGY_REMOVER_ROLE_ADMINROLE()
fourSixTwoSixAgg.getRoleAdmin(fourSixTwoSixAgg.STRATEGY_ADDER()), fourSixTwoSixAgg.STRATEGY_ADDER_ADMIN()
);
assertEq(
fourSixTwoSixAgg.getRoleAdmin(fourSixTwoSixAgg.MANAGER_ROLE()), fourSixTwoSixAgg.MANAGER_ROLE_ADMINROLE()
fourSixTwoSixAgg.getRoleAdmin(fourSixTwoSixAgg.STRATEGY_REMOVER()),
fourSixTwoSixAgg.STRATEGY_REMOVER_ADMIN()
);

assertTrue(fourSixTwoSixAgg.hasRole(fourSixTwoSixAgg.STRATEGY_MANAGER_ROLE_ADMINROLE(), deployer));
assertTrue(fourSixTwoSixAgg.hasRole(fourSixTwoSixAgg.WITHDRAW_QUEUE_MANAGER_ROLE_ADMINROLE(), deployer));
assertTrue(fourSixTwoSixAgg.hasRole(fourSixTwoSixAgg.STRATEGY_ADDER_ROLE_ADMINROLE(), deployer));
assertTrue(fourSixTwoSixAgg.hasRole(fourSixTwoSixAgg.STRATEGY_REMOVER_ROLE_ADMINROLE(), deployer));
assertTrue(fourSixTwoSixAgg.hasRole(fourSixTwoSixAgg.MANAGER_ROLE_ADMINROLE(), deployer));

assertTrue(fourSixTwoSixAgg.hasRole(fourSixTwoSixAgg.STRATEGY_MANAGER_ROLE(), manager));
assertTrue(fourSixTwoSixAgg.hasRole(fourSixTwoSixAgg.WITHDRAW_QUEUE_MANAGER_ROLE(), manager));
assertTrue(fourSixTwoSixAgg.hasRole(fourSixTwoSixAgg.STRATEGY_ADDER_ROLE(), manager));
assertTrue(fourSixTwoSixAgg.hasRole(fourSixTwoSixAgg.STRATEGY_REMOVER_ROLE(), manager));
assertTrue(fourSixTwoSixAgg.hasRole(fourSixTwoSixAgg.MANAGER_ROLE(), manager));
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 {
Expand Down
20 changes: 10 additions & 10 deletions test/e2e/BalanceForwarderE2ETest.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -35,18 +35,18 @@ contract BalanceForwarderE2ETest is FourSixTwoSixAggBase {
);

// grant admin roles to deployer
fourSixTwoSixAgg.grantRole(fourSixTwoSixAgg.STRATEGY_MANAGER_ROLE_ADMINROLE(), deployer);
fourSixTwoSixAgg.grantRole(fourSixTwoSixAgg.WITHDRAW_QUEUE_MANAGER_ROLE_ADMINROLE(), deployer);
fourSixTwoSixAgg.grantRole(fourSixTwoSixAgg.STRATEGY_ADDER_ROLE_ADMINROLE(), deployer);
fourSixTwoSixAgg.grantRole(fourSixTwoSixAgg.STRATEGY_REMOVER_ROLE_ADMINROLE(), deployer);
fourSixTwoSixAgg.grantRole(fourSixTwoSixAgg.MANAGER_ROLE_ADMINROLE(), 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);

// grant roles to manager
fourSixTwoSixAgg.grantRole(fourSixTwoSixAgg.STRATEGY_MANAGER_ROLE(), manager);
fourSixTwoSixAgg.grantRole(fourSixTwoSixAgg.WITHDRAW_QUEUE_MANAGER_ROLE(), manager);
fourSixTwoSixAgg.grantRole(fourSixTwoSixAgg.STRATEGY_ADDER_ROLE(), manager);
fourSixTwoSixAgg.grantRole(fourSixTwoSixAgg.STRATEGY_REMOVER_ROLE(), manager);
fourSixTwoSixAgg.grantRole(fourSixTwoSixAgg.MANAGER_ROLE(), 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);
vm.stopPrank();

uint256 initialStrategyAllocationPoints = 500e18;
Expand Down
18 changes: 12 additions & 6 deletions test/e2e/DepositRebalanceHarvestWithdrawE2ETest.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,9 @@ contract DepositRebalanceHarvestWithdrawE2ETest is FourSixTwoSixAggBase {
/ fourSixTwoSixAgg.totalAllocationPoints();

vm.prank(user1);
fourSixTwoSixAgg.rebalance(address(eTST));
address[] memory strategiesToRebalance = new address[](1);
strategiesToRebalance[0] = address(eTST);
rebalancer.executeRebalance(address(fourSixTwoSixAgg), strategiesToRebalance);

assertEq(fourSixTwoSixAgg.totalAllocated(), expectedStrategyCash);
assertEq(eTST.convertToAssets(eTST.balanceOf(address(fourSixTwoSixAgg))), expectedStrategyCash);
Expand Down Expand Up @@ -134,7 +136,9 @@ contract DepositRebalanceHarvestWithdrawE2ETest is FourSixTwoSixAggBase {
/ fourSixTwoSixAgg.totalAllocationPoints();

vm.prank(user1);
fourSixTwoSixAgg.rebalance(address(eTST));
address[] memory strategiesToRebalance = new address[](1);
strategiesToRebalance[0] = address(eTST);
rebalancer.executeRebalance(address(fourSixTwoSixAgg), strategiesToRebalance);

assertEq(fourSixTwoSixAgg.totalAllocated(), expectedStrategyCash);
assertEq(eTST.convertToAssets(eTST.balanceOf(address(fourSixTwoSixAgg))), expectedStrategyCash);
Expand Down Expand Up @@ -233,7 +237,7 @@ contract DepositRebalanceHarvestWithdrawE2ETest is FourSixTwoSixAggBase {
strategiesToRebalance[0] = address(eTST);
strategiesToRebalance[1] = address(eTSTsecondary);
vm.prank(user1);
fourSixTwoSixAgg.rebalanceMultipleStrategies(strategiesToRebalance);
rebalancer.executeRebalance(address(fourSixTwoSixAgg), strategiesToRebalance);

assertEq(fourSixTwoSixAgg.totalAllocated(), expectedeTSTStrategyCash + expectedeTSTsecondaryStrategyCash);
assertEq(eTST.convertToAssets(eTST.balanceOf(address(fourSixTwoSixAgg))), expectedeTSTStrategyCash);
Expand Down Expand Up @@ -319,7 +323,9 @@ contract DepositRebalanceHarvestWithdrawE2ETest is FourSixTwoSixAggBase {
/ fourSixTwoSixAgg.totalAllocationPoints();

vm.prank(user1);
fourSixTwoSixAgg.rebalance(address(eTST));
address[] memory strategiesToRebalance = new address[](1);
strategiesToRebalance[0] = address(eTST);
rebalancer.executeRebalance(address(fourSixTwoSixAgg), strategiesToRebalance);

assertEq(fourSixTwoSixAgg.totalAllocated(), expectedStrategyCash);
assertEq(eTST.convertToAssets(eTST.balanceOf(address(fourSixTwoSixAgg))), expectedStrategyCash);
Expand Down Expand Up @@ -421,7 +427,7 @@ contract DepositRebalanceHarvestWithdrawE2ETest is FourSixTwoSixAggBase {
strategiesToRebalance[0] = address(eTST);
strategiesToRebalance[1] = address(eTSTsecondary);
vm.prank(user1);
fourSixTwoSixAgg.rebalanceMultipleStrategies(strategiesToRebalance);
rebalancer.executeRebalance(address(fourSixTwoSixAgg), strategiesToRebalance);

assertEq(fourSixTwoSixAgg.totalAllocated(), expectedeTSTStrategyCash + expectedeTSTsecondaryStrategyCash);
assertEq(eTST.convertToAssets(eTST.balanceOf(address(fourSixTwoSixAgg))), expectedeTSTStrategyCash);
Expand Down Expand Up @@ -552,7 +558,7 @@ contract DepositRebalanceHarvestWithdrawE2ETest is FourSixTwoSixAggBase {
strategiesToRebalance[0] = address(eTST);
strategiesToRebalance[1] = address(eTSTsecondary);
vm.prank(user1);
fourSixTwoSixAgg.rebalanceMultipleStrategies(strategiesToRebalance);
rebalancer.executeRebalance(address(fourSixTwoSixAgg), strategiesToRebalance);

assertEq(fourSixTwoSixAgg.totalAllocated(), expectedeTSTStrategyCash + expectedeTSTsecondaryStrategyCash);
assertEq(eTST.convertToAssets(eTST.balanceOf(address(fourSixTwoSixAgg))), expectedeTSTStrategyCash);
Expand Down
Loading
Loading