From abd96116c5625619757b40869a30389645da3fbe Mon Sep 17 00:00:00 2001 From: joelkrusala Date: Mon, 6 Jan 2025 09:48:11 +0200 Subject: [PATCH] feat: update test --- src/Strategy.sol | 6 --- src/StrategyFactory.sol | 15 ++++-- src/interfaces/IStrategyInterface.sol | 2 +- src/test/FunctionSignature.t.sol | 35 ++++++------- src/test/Operation.t.sol | 75 ++++++++++++++------------- src/test/utils/Setup.sol | 64 +++++++++++++++-------- 6 files changed, 109 insertions(+), 88 deletions(-) diff --git a/src/Strategy.sol b/src/Strategy.sol index cbaf8868..c8095fad 100644 --- a/src/Strategy.sol +++ b/src/Strategy.sol @@ -68,12 +68,6 @@ contract Strategy is Module, BaseStrategy { transferOwnership(_owner); } - function initialize(address _asset, address _yieldSource) public { - require(yieldSource == address(0)); - yieldSource = _yieldSource; - ERC20(_asset).approve(_yieldSource, type(uint256).max); - } - /*////////////////////////////////////////////////////////////// NEEDED TO BE OVERRIDDEN BY STRATEGIST //////////////////////////////////////////////////////////////*/ diff --git a/src/StrategyFactory.sol b/src/StrategyFactory.sol index cfdd2b29..ebc5d4e8 100644 --- a/src/StrategyFactory.sol +++ b/src/StrategyFactory.sol @@ -1,6 +1,9 @@ // SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.18; +import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol"; +import "octant-v2-core/src/dragons/DragonTokenizedStrategy.sol"; +import "forge-std/console2.sol"; import {Strategy, ERC20} from "./Strategy.sol"; import {IStrategyInterface} from "./interfaces/IStrategyInterface.sol"; @@ -12,10 +15,14 @@ contract StrategyFactory { /// @notice Track the deployments. strategyId => strategy address mapping(uint256 => address) public deployments; + address public strategyImplementation; + address public dragonTokenizedStrategyImplementation; uint256 public strategyId; constructor() { strategyId = 0; + strategyImplementation = address(new Strategy()); + dragonTokenizedStrategyImplementation = address(new DragonTokenizedStrategy()); } /** @@ -23,9 +30,11 @@ contract StrategyFactory { * @param initializeParams The encoded parameters to initialize the strategy with * @return address The address of the newly deployed strategy */ - function newStrategy(bytes calldata initializeParams) external virtual returns (address) { - IStrategyInterface _newStrategy = IStrategyInterface(address(new Strategy())); - _newStrategy.setUp(initializeParams); + function newStrategy(bytes memory initializeParams) external virtual returns (address) { + ERC1967Proxy _newStrategy = new ERC1967Proxy( + strategyImplementation, + abi.encodeWithSelector(Strategy(payable(address(0))).setUp.selector, initializeParams) + ); uint256 currentId = strategyId; deployments[currentId] = address(_newStrategy); diff --git a/src/interfaces/IStrategyInterface.sol b/src/interfaces/IStrategyInterface.sol index 09bde845..83054655 100644 --- a/src/interfaces/IStrategyInterface.sol +++ b/src/interfaces/IStrategyInterface.sol @@ -4,5 +4,5 @@ pragma solidity ^0.8.18; import {IStrategy} from "octant-v2-core/src/interfaces/IStrategy.sol"; interface IStrategyInterface is IStrategy { - function setUp(bytes calldata initializeParams) external; + function setUp(bytes memory initializeParams) external; } diff --git a/src/test/FunctionSignature.t.sol b/src/test/FunctionSignature.t.sol index bdad09f4..fafc5e42 100644 --- a/src/test/FunctionSignature.t.sol +++ b/src/test/FunctionSignature.t.sol @@ -14,8 +14,8 @@ contract FunctionSignatureTest is Setup { // Does not check functions that are strategy dependant and will be checked in other tests function test_functionCollisions() public { uint256 wad = 1e18; - vm.expectRevert("initialized"); - strategy.initialize(address(asset), "name", management, performanceFeeRecipient, keeper); + // vm.expectRevert("initialized"); + // strategy.initialize(address(asset), yieldSource); // Check view functions assertEq(strategy.convertToAssets(wad), wad, "convert to assets"); @@ -26,16 +26,15 @@ contract FunctionSignatureTest is Setup { assertEq(strategy.previewRedeem(wad), wad, "preview redeem"); assertEq(strategy.totalAssets(), 0, "total assets"); assertEq(strategy.totalSupply(), 0, "total supply"); - assertEq(strategy.unlockedShares(), 0, "unlocked shares"); + assertEq(strategy.unlockedShares(user), 0, "unlocked shares"); assertEq(strategy.asset(), address(asset), "asset"); - assertEq(strategy.apiVersion(), "3.0.4", "api"); - assertEq(strategy.MAX_FEE(), 5_000, "max fee"); - assertEq(strategy.fullProfitUnlockDate(), 0, "unlock date"); - assertEq(strategy.profitUnlockingRate(), 0, "unlock rate"); + assertEq(strategy.apiVersion(), "1.0.0", "api"); + // assertEq(strategy.fullProfitUnlockDate(), 0, "unlock date"); + // assertEq(strategy.profitUnlockingRate(), 0, "unlock rate"); assertGt(strategy.lastReport(), 0, "last report"); assertEq(strategy.pricePerShare(), 10 ** asset.decimals(), "pps"); assertTrue(!strategy.isShutdown()); - assertEq(strategy.symbol(), string(abi.encodePacked("ys", asset.symbol())), "symbol"); + assertEq(strategy.symbol(), string(abi.encodePacked("dgn", asset.symbol())), "symbol"); assertEq(strategy.decimals(), asset.decimals(), "decimals"); // Assure modifiers are working @@ -48,20 +47,20 @@ contract FunctionSignatureTest is Setup { strategy.setKeeper(user); vm.expectRevert("!management"); strategy.setEmergencyAdmin(user); - vm.expectRevert("!management"); - strategy.setPerformanceFee(uint16(2_000)); - vm.expectRevert("!management"); - strategy.setPerformanceFeeRecipient(user); - vm.expectRevert("!management"); - strategy.setProfitMaxUnlockTime(1); + // vm.expectRevert("!management"); + // strategy.setPerformanceFee(uint16(2_000)); + // vm.expectRevert("!management"); + // strategy.setPerformanceFeeRecipient(user); + // vm.expectRevert("!management"); + // strategy.setProfitMaxUnlockTime(1); vm.stopPrank(); // Assure checks are being used vm.startPrank(strategy.management()); - vm.expectRevert("Cannot be self"); - strategy.setPerformanceFeeRecipient(address(strategy)); - vm.expectRevert("too long"); - strategy.setProfitMaxUnlockTime(type(uint256).max); + // vm.expectRevert("Cannot be self"); + // strategy.setPerformanceFeeRecipient(address(strategy)); + // vm.expectRevert("too long"); + // strategy.setProfitMaxUnlockTime(type(uint256).max); vm.stopPrank(); // Mint some shares to the user diff --git a/src/test/Operation.t.sol b/src/test/Operation.t.sol index 91f4c470..d1b01df4 100644 --- a/src/test/Operation.t.sol +++ b/src/test/Operation.t.sol @@ -14,8 +14,9 @@ contract OperationTest is Setup { assertTrue(address(0) != address(strategy)); assertEq(strategy.asset(), address(asset)); assertEq(strategy.management(), management); - assertEq(strategy.performanceFeeRecipient(), performanceFeeRecipient); assertEq(strategy.keeper(), keeper); + assertEq(strategy.dragonRouter(), dragonRouter); + assertEq(strategy.name(), "Tokenized Strategy"); // TODO: add additional check on strat params } @@ -38,7 +39,7 @@ contract OperationTest is Setup { assertGe(profit, 0, "!profit"); assertEq(loss, 0, "!loss"); - skip(strategy.profitMaxUnlockTime()); + // skip(strategy.profitMaxUnlockTime()); uint256 balanceBefore = asset.balanceOf(user); @@ -73,7 +74,7 @@ contract OperationTest is Setup { assertGe(profit, toAirdrop, "!profit"); assertEq(loss, 0, "!loss"); - skip(strategy.profitMaxUnlockTime()); + // skip(strategy.profitMaxUnlockTime()); uint256 balanceBefore = asset.balanceOf(user); @@ -84,55 +85,55 @@ contract OperationTest is Setup { assertGe(asset.balanceOf(user), balanceBefore + _amount, "!final balance"); } - function test_profitableReport_withFees(uint256 _amount, uint16 _profitFactor) public { - vm.assume(_amount > minFuzzAmount && _amount < maxFuzzAmount); - _profitFactor = uint16(bound(uint256(_profitFactor), 10, MAX_BPS)); + // function test_profitableReport_withFees(uint256 _amount, uint16 _profitFactor) public { + // vm.assume(_amount > minFuzzAmount && _amount < maxFuzzAmount); + // _profitFactor = uint16(bound(uint256(_profitFactor), 10, MAX_BPS)); - // Set protocol fee to 0 and perf fee to 10% - setFees(0, 1_000); + // // Set protocol fee to 0 and perf fee to 10% + // setFees(0, 1_000); - // Deposit into strategy - mintAndDepositIntoStrategy(strategy, user, _amount); + // // Deposit into strategy + // mintAndDepositIntoStrategy(strategy, user, _amount); - assertEq(strategy.totalAssets(), _amount, "!totalAssets"); + // assertEq(strategy.totalAssets(), _amount, "!totalAssets"); - // Earn Interest - skip(1 days); + // // Earn Interest + // skip(1 days); - // TODO: implement logic to simulate earning interest. - uint256 toAirdrop = (_amount * _profitFactor) / MAX_BPS; - airdrop(asset, address(strategy), toAirdrop); + // // TODO: implement logic to simulate earning interest. + // uint256 toAirdrop = (_amount * _profitFactor) / MAX_BPS; + // airdrop(asset, address(strategy), toAirdrop); - // Report profit - vm.prank(keeper); - (uint256 profit, uint256 loss) = strategy.report(); + // // Report profit + // vm.prank(keeper); + // (uint256 profit, uint256 loss) = strategy.report(); - // Check return Values - assertGe(profit, toAirdrop, "!profit"); - assertEq(loss, 0, "!loss"); + // // Check return Values + // assertGe(profit, toAirdrop, "!profit"); + // assertEq(loss, 0, "!loss"); - skip(strategy.profitMaxUnlockTime()); + // skip(strategy.profitMaxUnlockTime()); - // Get the expected fee - uint256 expectedShares = (profit * 1_000) / MAX_BPS; + // // Get the expected fee + // uint256 expectedShares = (profit * 1_000) / MAX_BPS; - assertEq(strategy.balanceOf(performanceFeeRecipient), expectedShares); + // assertEq(strategy.balanceOf(performanceFeeRecipient), expectedShares); - uint256 balanceBefore = asset.balanceOf(user); + // uint256 balanceBefore = asset.balanceOf(user); - // Withdraw all funds - vm.prank(user); - strategy.redeem(_amount, user, user); + // // Withdraw all funds + // vm.prank(user); + // strategy.redeem(_amount, user, user); - assertGe(asset.balanceOf(user), balanceBefore + _amount, "!final balance"); + // assertGe(asset.balanceOf(user), balanceBefore + _amount, "!final balance"); - vm.prank(performanceFeeRecipient); - strategy.redeem(expectedShares, performanceFeeRecipient, performanceFeeRecipient); + // vm.prank(performanceFeeRecipient); + // strategy.redeem(expectedShares, performanceFeeRecipient, performanceFeeRecipient); - checkStrategyTotals(strategy, 0, 0, 0); + // checkStrategyTotals(strategy, 0, 0, 0); - assertGe(asset.balanceOf(performanceFeeRecipient), expectedShares, "!perf fee out"); - } + // assertGe(asset.balanceOf(performanceFeeRecipient), expectedShares, "!perf fee out"); + // } function test_tendTrigger(uint256 _amount) public { vm.assume(_amount > minFuzzAmount && _amount < maxFuzzAmount); @@ -159,7 +160,7 @@ contract OperationTest is Setup { assertTrue(!trigger); // Unlock Profits - skip(strategy.profitMaxUnlockTime()); + // skip(strategy.profitMaxUnlockTime()); (trigger,) = strategy.tendTrigger(); assertTrue(!trigger); diff --git a/src/test/utils/Setup.sol b/src/test/utils/Setup.sol index ce552416..c8b5010f 100644 --- a/src/test/utils/Setup.sol +++ b/src/test/utils/Setup.sol @@ -29,11 +29,16 @@ contract Setup is ExtendedTest, IEvents { mapping(string => address) public tokenAddrs; // Addresses for different roles we will use repeatedly. - address public user = address(10); - address public keeper = address(4); - address public management = address(1); - address public performanceFeeRecipient = address(3); + address public user = address(1); + address public keeper = address(2); + address public management = address(3); + address public dragonRouter = address(4); address public emergencyAdmin = address(5); + address public yieldSource = address(6); + address public deployer = address(7); + address public owner = address(8); + address public tokenizedStrategyImplementation; + address public dragonTokenizedStrategyImplementation; // Address of the real deployed Factory address public factory; @@ -41,6 +46,7 @@ contract Setup is ExtendedTest, IEvents { // Integer variables that will be used repeatedly. uint256 public decimals; uint256 public MAX_BPS = 10_000; + uint256 public maxReportDelay = 1 days; // Fuzz from $0.01 of 1e6 stable coins up to 1 trillion of a 1e18 coin uint256 public maxFuzzAmount = 1e30; @@ -58,12 +64,14 @@ contract Setup is ExtendedTest, IEvents { // Set decimals decimals = asset.decimals(); - strategyFactory = new StrategyFactory(management, performanceFeeRecipient, keeper, emergencyAdmin); - + strategyFactory = new StrategyFactory(); + tokenizedStrategyImplementation = address(strategyFactory.strategyImplementation()); + dragonTokenizedStrategyImplementation = address(strategyFactory.dragonTokenizedStrategyImplementation()); // Deploy strategy and set variables strategy = IStrategyInterface(setUpStrategy()); - factory = strategy.FACTORY(); + // factory = strategy.FACTORY(); + factory = address(strategyFactory); // label all the used addresses for traces vm.label(keeper, "keeper"); @@ -71,16 +79,26 @@ contract Setup is ExtendedTest, IEvents { vm.label(address(asset), "asset"); vm.label(management, "management"); vm.label(address(strategy), "strategy"); - vm.label(performanceFeeRecipient, "performanceFeeRecipient"); + vm.label(dragonRouter, "dragonRouter"); } function setUpStrategy() public returns (address) { + // Encode initialization parameters + bytes memory initParams = abi.encode( + owner, + abi.encode( + dragonTokenizedStrategyImplementation, + address(asset), + yieldSource, + management, + keeper, + dragonRouter, + maxReportDelay, + "Tokenized Strategy" + ) + ); // we save the strategy as a IStrategyInterface to give it the needed interface - IStrategyInterface _strategy = - IStrategyInterface(address(strategyFactory.newStrategy(address(asset), "Tokenized Strategy"))); - - vm.prank(management); - _strategy.acceptManagement(); + IStrategyInterface _strategy = IStrategyInterface(address(strategyFactory.newStrategy(initParams))); return address(_strategy); } @@ -120,19 +138,19 @@ contract Setup is ExtendedTest, IEvents { deal(address(_asset), _to, balanceBefore + _amount); } - function setFees(uint16 _protocolFee, uint16 _performanceFee) public { - address gov = IFactory(factory).governance(); + // function setFees(uint16 _protocolFee, uint16 _performanceFee) public { + // address gov = IFactory(factory).governance(); - // Need to make sure there is a protocol fee recipient to set the fee. - vm.prank(gov); - IFactory(factory).set_protocol_fee_recipient(gov); + // // Need to make sure there is a protocol fee recipient to set the fee. + // vm.prank(gov); + // IFactory(factory).set_protocol_fee_recipient(gov); - vm.prank(gov); - IFactory(factory).set_protocol_fee_bps(_protocolFee); + // vm.prank(gov); + // IFactory(factory).set_protocol_fee_bps(_protocolFee); - vm.prank(management); - strategy.setPerformanceFee(_performanceFee); - } + // vm.prank(management); + // strategy.setPerformanceFee(_performanceFee); + // } function _setTokenAddrs() internal { tokenAddrs["WBTC"] = 0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599;