From 0e02fb60f1637afeda52e6d6f44ac2ff0fac5fa1 Mon Sep 17 00:00:00 2001 From: Schlagonia Date: Tue, 5 Mar 2024 20:29:51 -0700 Subject: [PATCH 1/8] chore: remove old version --- lib/tokenized-strategy | 1 - 1 file changed, 1 deletion(-) delete mode 160000 lib/tokenized-strategy diff --git a/lib/tokenized-strategy b/lib/tokenized-strategy deleted file mode 160000 index c5c34db6..00000000 --- a/lib/tokenized-strategy +++ /dev/null @@ -1 +0,0 @@ -Subproject commit c5c34db64df9b68f87627996596d91479e3b4f90 From 10df6c3f02b7fc52c80f3777a78ac9128192eac2 Mon Sep 17 00:00:00 2001 From: Schlagonia Date: Tue, 5 Mar 2024 20:31:06 -0700 Subject: [PATCH 2/8] chore: remove old versions --- .gitmodules | 8 -------- lib/tokenized-strategy-periphery | 1 - 2 files changed, 9 deletions(-) delete mode 160000 lib/tokenized-strategy-periphery diff --git a/.gitmodules b/.gitmodules index 624adfd9..8c8f254e 100644 --- a/.gitmodules +++ b/.gitmodules @@ -6,11 +6,3 @@ path = lib/openzeppelin-contracts url = https://github.com/OpenZeppelin/openzeppelin-contracts branch = v4.8.2 -[submodule "lib/tokenized-strategy"] - path = lib/tokenized-strategy - url = https://github.com/yearn/tokenized-strategy - branch = v3.0.1 -[submodule "lib/tokenized-strategy-periphery"] - path = lib/tokenized-strategy-periphery - url = https://github.com/yearn/tokenized-strategy-periphery - branch = master \ No newline at end of file diff --git a/lib/tokenized-strategy-periphery b/lib/tokenized-strategy-periphery deleted file mode 160000 index ae73e78f..00000000 --- a/lib/tokenized-strategy-periphery +++ /dev/null @@ -1 +0,0 @@ -Subproject commit ae73e78f6a796d9ebf9a99c33c27a905768ccea4 From 569aac7e06d9a182e9c94e8c8c6e3f0ff7ebbfb2 Mon Sep 17 00:00:00 2001 From: Schlagonia Date: Tue, 5 Mar 2024 20:33:53 -0700 Subject: [PATCH 3/8] forge install: tokenized-strategy v3.0.2 --- .gitmodules | 3 +++ lib/tokenized-strategy | 1 + 2 files changed, 4 insertions(+) create mode 160000 lib/tokenized-strategy diff --git a/.gitmodules b/.gitmodules index 8c8f254e..97c5de03 100644 --- a/.gitmodules +++ b/.gitmodules @@ -6,3 +6,6 @@ path = lib/openzeppelin-contracts url = https://github.com/OpenZeppelin/openzeppelin-contracts branch = v4.8.2 +[submodule "lib/tokenized-strategy"] + path = lib/tokenized-strategy + url = https://github.com/yearn/tokenized-strategy diff --git a/lib/tokenized-strategy b/lib/tokenized-strategy new file mode 160000 index 00000000..0d90dee1 --- /dev/null +++ b/lib/tokenized-strategy @@ -0,0 +1 @@ +Subproject commit 0d90dee170d53a0e04af3ff41d2f7a4f3ac395bd From 12e567cb7a6f5202643bfeb2524c2db587ac4e2c Mon Sep 17 00:00:00 2001 From: Schlagonia Date: Tue, 5 Mar 2024 21:02:16 -0700 Subject: [PATCH 4/8] forge install: tokenized-strategy-periphery 62fff222eac29f544ce8a1cd8ee2a4b478aaf628 --- .gitmodules | 3 +++ lib/tokenized-strategy-periphery | 1 + 2 files changed, 4 insertions(+) create mode 160000 lib/tokenized-strategy-periphery diff --git a/.gitmodules b/.gitmodules index 97c5de03..466ef104 100644 --- a/.gitmodules +++ b/.gitmodules @@ -9,3 +9,6 @@ [submodule "lib/tokenized-strategy"] path = lib/tokenized-strategy url = https://github.com/yearn/tokenized-strategy +[submodule "lib/tokenized-strategy-periphery"] + path = lib/tokenized-strategy-periphery + url = https://github.com/yearn/tokenized-strategy-periphery diff --git a/lib/tokenized-strategy-periphery b/lib/tokenized-strategy-periphery new file mode 160000 index 00000000..62fff222 --- /dev/null +++ b/lib/tokenized-strategy-periphery @@ -0,0 +1 @@ +Subproject commit 62fff222eac29f544ce8a1cd8ee2a4b478aaf628 From af774ed40c18df232582ccb9934917642bd4595b Mon Sep 17 00:00:00 2001 From: Schlagonia Date: Tue, 5 Mar 2024 21:13:18 -0700 Subject: [PATCH 5/8] chore: update comments --- .gitmodules | 2 ++ foundry.toml | 2 ++ remappings.txt | 4 ---- src/Strategy.sol | 18 ++++++++---------- src/test/utils/Setup.sol | 12 +++++++++--- 5 files changed, 21 insertions(+), 17 deletions(-) delete mode 100644 remappings.txt diff --git a/.gitmodules b/.gitmodules index 466ef104..45c3e214 100644 --- a/.gitmodules +++ b/.gitmodules @@ -9,6 +9,8 @@ [submodule "lib/tokenized-strategy"] path = lib/tokenized-strategy url = https://github.com/yearn/tokenized-strategy + release = v3.0.2 [submodule "lib/tokenized-strategy-periphery"] path = lib/tokenized-strategy-periphery url = https://github.com/yearn/tokenized-strategy-periphery + release = v3.0.2 \ No newline at end of file diff --git a/foundry.toml b/foundry.toml index f3e432f9..d6aeb4e4 100644 --- a/foundry.toml +++ b/foundry.toml @@ -4,6 +4,8 @@ out = 'out' libs = ['lib'] solc = "0.8.18" +auto_detect_remappings = false + remappings = [ "@openzeppelin/=lib/openzeppelin-contracts/", "forge-std/=lib/forge-std/src/", diff --git a/remappings.txt b/remappings.txt deleted file mode 100644 index a9536806..00000000 --- a/remappings.txt +++ /dev/null @@ -1,4 +0,0 @@ -@openzeppelin/=lib/openzeppelin-contracts/ -forge-std/=lib/forge-std/src/ -@tokenized-strategy/=lib/tokenized-strategy/src/ -@periphery/=lib/tokenized-strategy-periphery/src/ diff --git a/src/Strategy.sol b/src/Strategy.sol index 4f6b3c64..72499cd9 100644 --- a/src/Strategy.sol +++ b/src/Strategy.sol @@ -33,14 +33,14 @@ contract Strategy is BaseStrategy { //////////////////////////////////////////////////////////////*/ /** - * @dev Should deploy up to '_amount' of 'asset' in the yield source. + * @dev Can deploy up to '_amount' of 'asset' in the yield source. * * This function is called at the end of a {deposit} or {mint} * call. Meaning that unless a whitelist is implemented it will * be entirely permissionless and thus can be sandwiched or otherwise * manipulated. * - * @param _amount The amount of 'asset' that the strategy should attempt + * @param _amount The amount of 'asset' that the strategy can attempt * to deposit in the yield source. */ function _deployFunds(uint256 _amount) internal override { @@ -50,9 +50,9 @@ contract Strategy is BaseStrategy { } /** - * @dev Will attempt to free the '_amount' of 'asset'. + * @dev Should attempt to free the '_amount' of 'asset'. * - * The amount of 'asset' that is already loose has already + * NOTE: The amount of 'asset' that is already loose has already * been accounted for. * * This function is called during {withdraw} and {redeem} calls. @@ -134,9 +134,7 @@ contract Strategy is BaseStrategy { * sandwiched can use the tend when a certain threshold * of idle to totalAssets has been reached. * - * The TokenizedStrategy contract will do all needed debt and idle updates - * after this has finished and will have no effect on PPS of the strategy - * till report() is called. + * This will have no effect on PPS of the strategy till report() is called. * * @param _totalIdle The current amount of idle funds that are available to deploy. * @@ -191,10 +189,10 @@ contract Strategy is BaseStrategy { * * This function will be called before any withdraw or redeem to enforce * any limits desired by the strategist. This can be used for illiquid - * or sandwichable strategies. It should never be lower than `totalIdle`. + * or sandwichable strategies. * * EX: - * return TokenIzedStrategy.totalIdle(); + * return asset.balanceOf(address(this));; * * This does not need to take into account the `_owner`'s share balance * or conversion rates from shares to assets. @@ -208,7 +206,7 @@ contract Strategy is BaseStrategy { TODO: If desired Implement withdraw limit logic and any needed state variables. EX: - return TokenizedStrategy.totalIdle(); + return asset.balanceOf(address(this)); } */ diff --git a/src/test/utils/Setup.sol b/src/test/utils/Setup.sol index dc817c93..99793794 100644 --- a/src/test/utils/Setup.sol +++ b/src/test/utils/Setup.sol @@ -115,9 +115,15 @@ contract Setup is ExtendedTest, IEvents { uint256 _totalDebt, uint256 _totalIdle ) public { - assertEq(_strategy.totalAssets(), _totalAssets, "!totalAssets"); - assertEq(_strategy.totalDebt(), _totalDebt, "!totalDebt"); - assertEq(_strategy.totalIdle(), _totalIdle, "!totalIdle"); + uint256 _assets = _strategy.totalAssets(); + uint256 _balance = ERC20(_strategy.asset()).balanceOf( + address(_strategy) + ); + uint256 _idle = _balance > _assets ? _assets : _balance; + uint256 _debt = _assets - _idle; + assertEq(_assets, _totalAssets, "!totalAssets"); + assertEq(_debt, _totalDebt, "!totalDebt"); + assertEq(_idle, _totalIdle, "!totalIdle"); assertEq(_totalAssets, _totalDebt + _totalIdle, "!Added"); } From f58c01314b084a1033ec31d6f9b1cd745409f562 Mon Sep 17 00:00:00 2001 From: Schlagonia Date: Tue, 5 Mar 2024 21:14:11 -0700 Subject: [PATCH 6/8] chore: remove old oz --- .gitmodules | 4 ---- lib/openzeppelin-contracts | 1 - 2 files changed, 5 deletions(-) delete mode 160000 lib/openzeppelin-contracts diff --git a/.gitmodules b/.gitmodules index 45c3e214..6fa1207f 100644 --- a/.gitmodules +++ b/.gitmodules @@ -2,10 +2,6 @@ path = lib/forge-std url = https://github.com/foundry-rs/forge-std branch = v1.5.3 -[submodule "lib/openzeppelin-contracts"] - path = lib/openzeppelin-contracts - url = https://github.com/OpenZeppelin/openzeppelin-contracts - branch = v4.8.2 [submodule "lib/tokenized-strategy"] path = lib/tokenized-strategy url = https://github.com/yearn/tokenized-strategy diff --git a/lib/openzeppelin-contracts b/lib/openzeppelin-contracts deleted file mode 160000 index d00acef4..00000000 --- a/lib/openzeppelin-contracts +++ /dev/null @@ -1 +0,0 @@ -Subproject commit d00acef4059807535af0bd0dd0ddf619747a044b From 024d9c647632d5263e4a41c5765d21db0e0b8121 Mon Sep 17 00:00:00 2001 From: Schlagonia Date: Tue, 5 Mar 2024 21:15:40 -0700 Subject: [PATCH 7/8] forge install: openzeppelin-contracts v4.9.5 --- .gitmodules | 5 ++++- lib/openzeppelin-contracts | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) create mode 160000 lib/openzeppelin-contracts diff --git a/.gitmodules b/.gitmodules index 6fa1207f..a5533c1d 100644 --- a/.gitmodules +++ b/.gitmodules @@ -9,4 +9,7 @@ [submodule "lib/tokenized-strategy-periphery"] path = lib/tokenized-strategy-periphery url = https://github.com/yearn/tokenized-strategy-periphery - release = v3.0.2 \ No newline at end of file + release = v3.0.2 +[submodule "lib/openzeppelin-contracts"] + path = lib/openzeppelin-contracts + url = https://github.com/OpenZeppelin/openzeppelin-contracts diff --git a/lib/openzeppelin-contracts b/lib/openzeppelin-contracts new file mode 160000 index 00000000..bd325d56 --- /dev/null +++ b/lib/openzeppelin-contracts @@ -0,0 +1 @@ +Subproject commit bd325d56b4c62c9c5c1aff048c37c6bb18ac0290 From a8c79570dac5223ce3f0b94dfd6c4381a276516a Mon Sep 17 00:00:00 2001 From: Schlagonia Date: Tue, 5 Mar 2024 21:23:01 -0700 Subject: [PATCH 8/8] test: update tests --- .github/workflows/lint.yaml | 2 +- README.md | 10 ++++------ foundry.toml | 2 -- src/test/FunctionSignature.t.sol | 9 ++------- src/test/Operation.t.sol | 9 --------- src/test/Shutdown.t.sol | 6 ------ 6 files changed, 7 insertions(+), 31 deletions(-) diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml index aacacd3f..9fb5b1f1 100644 --- a/.github/workflows/lint.yaml +++ b/.github/workflows/lint.yaml @@ -20,7 +20,7 @@ jobs: - name: Setup node.js uses: actions/setup-node@v1 with: - node-version: '16.x' + node-version: 18 - name: Set yarn cache directory path id: yarn-cache-dir-path diff --git a/README.md b/README.md index eba862c5..31a7e413 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ This repo will allow you to write, test and deploy V3 "Tokenized Strategies" using [Foundry](https://book.getfoundry.sh/). -You will only need to override the three functions in Strategy.sol of `_deployFunds`, `_freeFunds` and `_harvestAndReport`. With the option to also override `_tend`, `_tendTrigger`, `availableDepositLimit`, `availableWithdrawLimit` and `_emegencyWithdraw` if desired. +You will only need to override the three functions in Strategy.sol of `_deployFunds`, `_freeFunds` and `_harvestAndReport`. With the option to also override `_tend`, `_tendTrigger`, `availableDepositLimit`, `availableWithdrawLimit` and `_emergencyWithdraw` if desired. For a more complete overview of how the Tokenized Strategies work please visit the [TokenizedStrategy Repo](https://github.com/yearn/tokenized-strategy). @@ -13,10 +13,10 @@ For a more complete overview of how the Tokenized Strategies work please visit t First you will need to install [Foundry](https://book.getfoundry.sh/getting-started/installation). NOTE: If you are on a windows machine it is recommended to use [WSL](https://learn.microsoft.com/en-us/windows/wsl/install) -### Fork this repository +### Clone this repository ```sh -git clone --recursive https://github.com/user/tokenized-strategy-foundry-mix +git clone --recursive https://github.com/yearn/tokenized-strategy-foundry-mix cd tokenized-strategy-foundry-mix @@ -52,7 +52,7 @@ For a complete guide to creating a Tokenized Strategy please visit: https://docs ## Testing -Due to the nature of the BaseStrategy utilizing an external contract for the majority of its logic, the default interface for any tokenized strategy will not allow proper testing of all functions. Testing of your Strategy should utilize the pre-built [IStrategyInterface](https://github.com/Schlagonia/tokenized-strategy-foundry-mix/blob/master/src/interfaces/IStrategyInterface.sol) to cast any deployed strategy through for testing, as seen in the Setup example. You can add any external functions that you add for your specific strategy to this interface to be able to test all functions with one variable. +Due to the nature of the BaseStrategy utilizing an external contract for the majority of its logic, the default interface for any tokenized strategy will not allow proper testing of all functions. Testing of your Strategy should utilize the pre-built [IStrategyInterface](https://github.com/yearn/tokenized-strategy-foundry-mix/blob/master/src/interfaces/IStrategyInterface.sol) to cast any deployed strategy through for testing, as seen in the Setup example. You can add any external functions that you add for your specific strategy to this interface to be able to test all functions with one variable. Example: @@ -106,8 +106,6 @@ Once the Strategy is fully deployed and verified, you will need to verify the To This should add all of the external `TokenizedStrategy` functions to the contract interface on Etherscan. -See the ApeWorx [documentation](https://docs.apeworx.io/ape/stable/) and [GitHub](https://github.com/ApeWorX/ape) for more information. - ## CI This repo uses [GitHub Actions](.github/workflows) for CI. There are three workflows: lint, test and slither for static analysis. diff --git a/foundry.toml b/foundry.toml index d6aeb4e4..f3e432f9 100644 --- a/foundry.toml +++ b/foundry.toml @@ -4,8 +4,6 @@ out = 'out' libs = ['lib'] solc = "0.8.18" -auto_detect_remappings = false - remappings = [ "@openzeppelin/=lib/openzeppelin-contracts/", "forge-std/=lib/forge-std/src/", diff --git a/src/test/FunctionSignature.t.sol b/src/test/FunctionSignature.t.sol index d5eb16e5..ea8ad4f6 100644 --- a/src/test/FunctionSignature.t.sol +++ b/src/test/FunctionSignature.t.sol @@ -15,7 +15,7 @@ contract FunctionSignatureTest is Setup { function test_functionCollisions() public { uint256 wad = 1e18; vm.expectRevert("initialized"); - strategy.init( + strategy.initialize( address(asset), "name", management, @@ -34,11 +34,8 @@ contract FunctionSignatureTest is Setup { assertEq(strategy.totalSupply(), 0, "total supply"); assertEq(strategy.unlockedShares(), 0, "unlocked shares"); assertEq(strategy.asset(), address(asset), "asset"); - assertEq(strategy.apiVersion(), "3.0.1", "api"); - assertEq(strategy.totalIdle(), 0, "idle"); - assertEq(strategy.totalDebt(), 0, "debt"); + assertEq(strategy.apiVersion(), "3.0.2", "api"); assertEq(strategy.MAX_FEE(), 5_000, "max fee"); - assertEq(strategy.MIN_FEE(), 500, "min fee"); assertEq(strategy.fullProfitUnlockDate(), 0, "unlock date"); assertEq(strategy.profitUnlockingRate(), 0, "unlock rate"); assertGt(strategy.lastReport(), 0, "last report"); @@ -71,8 +68,6 @@ contract FunctionSignatureTest is Setup { // Assure checks are being used vm.startPrank(strategy.management()); - vm.expectRevert("MIN FEE"); - strategy.setPerformanceFee(uint16(0)); vm.expectRevert("Cannot be self"); strategy.setPerformanceFeeRecipient(address(strategy)); vm.expectRevert("too long"); diff --git a/src/test/Operation.t.sol b/src/test/Operation.t.sol index dbfd8183..bfaad36a 100644 --- a/src/test/Operation.t.sol +++ b/src/test/Operation.t.sol @@ -25,10 +25,7 @@ contract OperationTest is Setup { // Deposit into strategy mintAndDepositIntoStrategy(strategy, user, _amount); - // TODO: Implement logic so totalDebt is _amount and totalIdle = 0. assertEq(strategy.totalAssets(), _amount, "!totalAssets"); - assertEq(strategy.totalDebt(), 0, "!totalDebt"); - assertEq(strategy.totalIdle(), _amount, "!totalIdle"); // Earn Interest skip(1 days); @@ -66,10 +63,7 @@ contract OperationTest is Setup { // Deposit into strategy mintAndDepositIntoStrategy(strategy, user, _amount); - // TODO: Implement logic so totalDebt is _amount and totalIdle = 0. assertEq(strategy.totalAssets(), _amount, "!totalAssets"); - assertEq(strategy.totalDebt(), 0, "!totalDebt"); - assertEq(strategy.totalIdle(), _amount, "!totalIdle"); // Earn Interest skip(1 days); @@ -114,10 +108,7 @@ contract OperationTest is Setup { // Deposit into strategy mintAndDepositIntoStrategy(strategy, user, _amount); - // TODO: Implement logic so totalDebt is _amount and totalIdle = 0. assertEq(strategy.totalAssets(), _amount, "!totalAssets"); - assertEq(strategy.totalDebt(), 0, "!totalDebt"); - assertEq(strategy.totalIdle(), _amount, "!totalIdle"); // Earn Interest skip(1 days); diff --git a/src/test/Shutdown.t.sol b/src/test/Shutdown.t.sol index d30b1f76..b8313328 100644 --- a/src/test/Shutdown.t.sol +++ b/src/test/Shutdown.t.sol @@ -14,10 +14,7 @@ contract ShutdownTest is Setup { // Deposit into strategy mintAndDepositIntoStrategy(strategy, user, _amount); - // TODO: Implement logic so totalDebt is _amount and totalIdle = 0. assertEq(strategy.totalAssets(), _amount, "!totalAssets"); - assertEq(strategy.totalDebt(), 0, "!totalDebt"); - assertEq(strategy.totalIdle(), _amount, "!totalIdle"); // Earn Interest skip(1 days); @@ -26,10 +23,7 @@ contract ShutdownTest is Setup { vm.prank(management); strategy.shutdownStrategy(); - // TODO: Implement logic so totalDebt is _amount and totalIdle = 0. assertEq(strategy.totalAssets(), _amount, "!totalAssets"); - assertEq(strategy.totalDebt(), 0, "!totalDebt"); - assertEq(strategy.totalIdle(), _amount, "!totalIdle"); // Make sure we can still withdraw the full amount uint256 balanceBefore = asset.balanceOf(user);