diff --git a/docs/developers/v3/strategy_development.md b/docs/developers/v3/strategy_development.md index a24042fabe..bde435da65 100644 --- a/docs/developers/v3/strategy_development.md +++ b/docs/developers/v3/strategy_development.md @@ -6,64 +6,64 @@ So you wanna be a Yearn strategist? Can you write 3 lines of code? -Well then you came to the right place. +Well, then you came to the right place. -The strategy creation process has been very simplified in V3 so that it is technically possible to write a Tokenized Strategy with only 3 lines of code. However, of course most strategies will need more than that. This will guide you through the full strategy development process from getting your local repo set up, through deployment, automation all the way to cashing out those sweet sweet strategist fees. +The strategy creation process has been very simplified in V3, so it is technically possible to write a Tokenized Strategy with only 3 lines of code. However, most strategies will need more than that. This will guide you through the entire strategy development process from getting your local repo set up through deployment and automation to cashing out those sweet sweet strategist fees. ## Introduction -A strategies job is to hold the actual logic that is responsible for generating yield on some underlying asset. It should hold the code to integrate with an external protocol and do any needed asset deployment, withdraw logic, reward selling, reinvesting LTV maintenance etc. to most efficiently generate the most possible yield from that particular source. +A strategy's job is to hold the logic responsible for generating yield on some underlying asset. It should hold the code to integrate with an external protocol and do any needed asset deployment, withdraw logic, reward selling, reinvesting LTV maintenance etc. to generate the most possible yield from that particular source most efficiently. -The biggest update to Yearn V3 from V2 was the introduction of "Tokenized Strategies". In V2 strategies were stand alone contracts that were attached to one specific vault. That vault was the only one who could ever deposit or withdraw funds from the strategy and each had a trusted relationship with the other. +The most significant update to Yearn V3 from V2 was the introduction of "Tokenized Strategies". In V2 strategies were stand-alone contracts that were attached to one specific vault. That vault was the only one who could ever deposit or withdraw funds from the strategy and each had a trusted relationship with the other. -In V3 strategies are now themselves fully ERC-4626 compliant stand alone vaults. Though their job remains the same (i.e. generate yield from one external source), strategies can now not only be connected to many different vaults at the same time but also deposited directly into by an end user. +In V3 strategies are now fully ERC-4626-compliant stand-alone vaults. Though their job remains the same (i.e., generate yield from one external source), strategies can now be connected to many different vaults simultaneously and deposited directly into by an end user. -This increased functionality not only means strategies have a much larger potential market of depositers, but also means anyone (including you) now have the ability to build, deploy, market and maintain your own Yearn strategy without any need for an endorsement or permission from Yearn. +This increased functionality not only means strategies have a much larger potential market of depositors but also means anyone (including you) now can build, deploy, market, and maintain your own Yearn strategy without any need for an endorsement or permission from Yearn. ## Why? - *Strategist Fees!* - V3 brings back the ability for developers of strategies to earn the fees generated from their strategy. Meaning your earning potential is unlimited. -- *Codify Your yield Farming* - Tokenized strategies make it super easy for anyone to codify their own yield generating strategies. Wanna keep your alpha private? No problem they come fully customizable to allow for you to be the only one allowed to deposit. -- *Simple 4626 Wrappers* - Tokenized Strategies make a super easy and cheap way to give any previously deployed protocol a ERC-4626 interface. This opens up any protocol to easily integrate into the rapidly growing 4626 ecosystem (including Yearn Meta Vaults). +- *Codify Your Yield Farming* - Tokenized strategies make it easy for anyone to codify their yield-generating strategies. Wanna keep your alpha private? No problem they come fully customizable to allow for you to be the only one allowed to deposit. +- *Simple 4626 Wrappers* - Tokenized Strategies make a super easy and cheap way to give any previously deployed protocol an ERC-4626 interface. This opens up any protocol to easily integrate into the rapidly growing 4626 ecosystem (including Yearn Meta Vaults). ## Definitions - [Strategy](https://github.com/yearn/tokenized-strategy) : A strategy or "Tokenized Strategy" in V3 refers to an ERC-4626 compliant contract that utilizes the [TokenizedStrategy](https://github.com/yearn/tokenized-strategy/blob/master/src/TokenizedStrategy.sol#L14-L26) pattern that either meta vaults or individual users can deposit directly into and receive shares in return. The strategy takes the underlying asset and deploys it in a single source in order to generate yield on that asset. - Asset: Any ERC20-compliant token -- Shares: ERC20-compliant token that tracks the asset balance in the strategy for every depositer. +- Shares: ERC20-compliant token that tracks the asset balance in the strategy for every depositor. - [TokenizedStrategy.sol](https://github.com/yearn/tokenized-strategy/blob/master/src/TokenizedStrategy.sol): The implementation contract that all strategies delegateCall to for the standard ERC4626 and profit locking functions. - [BaseTokenizedStrategy.sol](https://github.com/yearn/tokenized-strategy/blob/master/src/BaseTokenizedStrategy.sol): The abstract contract that a strategy should inherit from that handles all communication with the Tokenized Strategy contract. - Strategist: The developer of a specific strategy. - Depositor: Account that deposits the asset and holds Shares -- Vault: Or "Meta Vault" is an Yearn ERC4626 compliant Smart contract that receives assets from Depositors to then distribute them among the different Strategies added to the vault, managing accounting and asset distribution. +- Vault: Or "Meta Vault" is a Yearn ERC4626 compliant Smart contract that receives assets from Depositors to distribute among the different Strategies added to the vault, managing accounting and asset distribution. - Management: The owner of the specific strategy that can set fees, profit unlocking time etc. - Keeper: the address of a contract allowed to call report() and tend() on a strategy. - Factory: The factory that all meta vaults of a specific API version are cloned from that also controls the protocol fee amount and recipient for a strategy. -- Performance Fee: The fee strategies charge during reports base on the yield earned since the last report. +- Performance Fee: The fee strategies charge during reports based on the yield earned since the last report. - Performance Fee recipient: The address that receives the shares charged as performance fees. -- Protocol Fee: A fee on the fees charged by a strategists sent to the Yearn Treasury. +- Protocol Fee: A fee on the fees charged by strategist sent to the Yearn Treasury. - Profit Max Unlock Time: Time in seconds over which reported profits will unlock over. -- `totalIdle` : The amount of loose asset that is sitting in a strategy. +- `totalIdle` : The amount of loose asset sitting in a strategy. - `totalDebt` : The amount of deployed funds that a strategy has control over. -- `report`: Called by management or keepers to accrue all profits or losses, charge fees and lock profit to be distributed. -- `tend`: Called by management or keepers between reports for any maintenence that should happen that doesn't require a full report. +- `report`: Called by management or keepers to accrue all profits or losses, charge fees, and lock profit to be distributed. +- `tend`: Called by management or keepers between reports for any maintenance that should happen that doesn't require a full report. - API Version: The version that a specific Strategy is using for its logic. ## Architecture While the complete architecture of the Tokenized Strategy is out of the scope of this document you can read more about how it works [here](https://github.com/yearn/tokenized-strategy/blob/master/SPECIFICATION.md) -**TLDR**: V3 strategies use an immutable proxy pattern to outsource all of its complex, high risk and redundant code to one [TokenizedStrategy.sol](https://github.com/yearn/tokenized-strategy/blob/master/src/TokenizedStrategy.sol) implementation contract that is used by every strategy of a specific api version. To use this pattern you simply need to inherit the [BaseTokenizedStrategy.sol](https://github.com/yearn/tokenized-strategy/blob/master/src/BaseTokenizedStrategy.sol) contract, that holds all of the logic to communicate with the implementation contract, and then just override a few simple functions with your specific strategy logic. +**TLDR**: V3 strategies use an immutable proxy pattern to outsource all of its complex, high risk, and redundant code to one [TokenizedStrategy.sol](https://github.com/yearn/tokenized-strategy/blob/master/src/TokenizedStrategy.sol) implementation contract that is used by every strategy of a specific API version. To use this pattern you simply need to inherit the [BaseTokenizedStrategy.sol](https://github.com/yearn/tokenized-strategy/blob/master/src/BaseTokenizedStrategy.sol) contract, that holds all of the logic to communicate with the implementation contract, and then just override a few simple functions with your specific strategy logic. ## Getting started -Yearn has base templates made to build off of built in both [Ape Worx](https://www.apeworx.io/), a python based development toolkit, and [Foundry](https://book.getfoundry.sh/). +Yearn has base templates made to build off of built-in both [Ape Worx](https://www.apeworx.io/), a python-based development toolkit, and [Foundry](https://book.getfoundry.sh/). 1. Choose your development framework. - [Tokenized Strategy Foundry Mix](https://github.com/yearn/tokenized-strategy-foundry-mix) - [Tokenized Strategy Ape Mix](https://github.com/yearn/tokenized-strategy-ape-mix) -2. Set up local environment with selected mix. Each mix has detailed instructions in the "How To Start" section of the README, of specific requirements as well as cloning instructions and needed environment variables. -4. Assure tests pass. Each mix comes with a small set of pre-written tests, to serve as examples and can be used to make sure your local repository is set up properly before adding your own logic. +2. Set up the local environment with the selected mix. Each mix has detailed instructions in the "How To Start" section of the README, of specific requirements, cloning instructions, and needed environment variables. +4. Assure tests pass. Each mix comes with a small set of pre-written tests, to serve as examples and can be used to ensure your local repository is set up correctly before adding your logic. ## Strategy Writing @@ -75,15 +75,15 @@ ___ 1. *_deployFunds(uint256 _amount)* **Purpose**: - - This function is called during every deposit into your strategy to give it the opportunity to deploy the underlying asset just deposited into the yield source. + - This function is called during every deposit into your strategy to allow it to deploy the underlying asset deposited into the yield source. **Parameters**: - - `_amount`: The total amount of underlying asset that is currently available for the strategy to deploy including the amount deposited and previously idle funds. + - `_amount`: The total amount of underlying assets currently available for the deployment strategy, including the amount deposited and previously idle funds. **Returns**: NONE. **Good to Know**: - - This function is entirely permissionless, so anything such as swaps or lp movements can be sandwiched or otherwise manipulated. + - This function is permissionless, so swaps or LP movements can't be sandwiched or manipulated. - This does not need to deploy the full `_amount` if the strategy doesn't want to. **Best Practice**: @@ -97,7 +97,7 @@ ___ 2. *_freeFunds(uint256 _amount)* **Purpose**: - - This function is called during withdraws from your strategy if there is not enough idle asset to service the full withdraw. + - This function is called during withdraws from your strategy if there is insufficient idle asset to service the full withdrawal. **Parameters**: - `_amount`: The amount of the underlying asset that needs to be pulled from the yield source. @@ -105,13 +105,13 @@ ___ **Returns**: NONE. **Good to Know**: - - The amount of loose asset has already been accounted for. - - This function is also entirely permissionless, so anything such as swaps or lp values can be sandwiched or otherwise manipulated. + - The amount of loose assets has already been accounted for. + - This function is also entirely permissionless, so swaps or lp values can't be sandwiched or otherwise manipulated. **Best Practice**: - Use the `_amount` parameter passed in rather than relying on .balanceOf(address(this)). - **Any difference between the `_amount` parameter and the actual amount withdrawn will count as a loss and be passed on to the withdrawer. It may be preferred to revert for temporary issues such as liquidity constraints rather than pass on a loss**. - - If your strategy is illiquid or can not always service full withdraws, you can limit the amount by overriding `availableWithdrawLimt` which is outlined below. + - If your strategy is illiquid or can not always service full withdraws, you can limit the amount by overriding `availableWithdrawLimt` outlined below. **Example**: @@ -121,7 +121,7 @@ ___ 3. *_harvestAndReport()* **Purpose**: - - Called during every report. This should harvest and sell any rewards, reinvest any proceeds, perform any position maintanence and return a full accounting of a trusted amount denominated in the underlying asset that the strategy holds. + - Called during every report. This should harvest and sell any rewards, reinvest any proceeds, perform any position maintenance and return a full accounting of a trusted amount denominated in the underlying asset the strategy holds. **Parameters**: NONE @@ -129,17 +129,17 @@ ___ - `_totalAssets`: A trusted and accurate account for the total amount of 'asset' the strategy currently holds including loose funds. **Good to Know**: - - This can only be called by a permissioned address so if set up correctly can be trusted to be through a protected relay in order to perform swaps, lp movements etc. - - It is safe to account for loose asset in this function since any profit reported is immediately locked and therefore is not subject to price per share manipulation. + - This can only be called by a permissioned address so if set up correctly, it can be trusted to be through a protected relay to perform swaps, LP movements etc. + - It is safe to account for loose assets in this function since any reported profit is immediately locked and not subject to price-per-share manipulation. **Best Practice**: - - The returned value is used to account for all strategy profits, losses and fees so care should be taken when relying on oracle values, lp prices etc. that have the potential to be manipulated. - - This can still be called after a strategy has been shutdown so you may want to check if the strategy is shutdown before performing certain functions like re-deploying loose funds. + - The returned value is used to account for all strategy profits, losses and fees so care should be taken when relying on oracle values, LP prices etc. that have the potential to be manipulated. + - This can still be called after a strategy has been shut down so you may want to check if the strategy is shut down before performing certain functions like re-deploying loose funds. **Example**: function _harvestAndReport() internal override returns (uint256 _totalAssets) { - // Only harvest and redeploy if strategy is not shutdown. + // Only harvest and redeploy if the strategy is not shutdown. if(!TokenizedStrategy.isShutdown()) { // Claim all rewards and sell to asset. _claminAndSellRewards(); @@ -154,9 +154,9 @@ ___ } ### Optional Functions -Simply overriding those three function will make your strategy a fully functional, permissionless, 4626 compliant stand alone vault. It can work entirely on its own or be integrated seemlessly into any Yearn V3 vault. +Simply overriding those three functions will make your strategy a fully functional, permissionless, 4626-compliant stand-alone vault. It can work independently or seamlessly into any Yearn V3 vault. -While that may be all that's necessary for some of the most simple strategies it is likely that most strategists may want to add a bit more customization or complexity to their strategy. Their are five more optional functions that can be overriden by a strategist if desired to continue to build out their Tokenized Strategy. +While that may be all that's necessary for some of the most straightforward strategies, most strategists may want to add more customization or complexity to their strategy. There are five more optional functions that can be overridden by a strategist if desired to continue to build out their Tokenized Strategy. 1. *availableDeositLimit(address _owner)* @@ -164,17 +164,17 @@ While that may be all that's necessary for some of the most simple strategies it - This is called during any deposits and can be used to enforce any deposit limit or white list that the strategist desires. **Parameters**: - - `_owner`: The address that would be receiving the shares minted during the deposit. + - `_owner`: The address receiving the shares minted during the deposit. **Returns**: - The limit if any that should be enforced on the deposit. **Good to Know**: - This will default to return uint256 max. - - This does not need to take into account any conversion rates from assets to shares. But should know that any limit under uint256 max may get converted to shares and should not be high enough to overflow on multiplication. + - This does not need to consider any conversion rates from assets to shares. But you should know that any limit under uint256 max may get converted to shares and should not be high enough to overflow on multiplication. **Best Practices**: - - Make sure to implement setter functions for any deposit limit or whitelist's that are enforced. + - Make sure to implement setter functions for any deposit limit or whitelist that are enforced. **Example**: @@ -196,14 +196,14 @@ While that may be all that's necessary for some of the most simple strategies it - The limit if any that should be enforced on withdraws. **Good to Know**: - - This does not need to take into account the balance of the _owner. + - This does not need to consider the balance of the _owner. - This can be more than the actual amount available to withdraw. - Defaults to max uint256. **Best Practices**: - This should be overridden for strategies that have illiquid, or sandwichable positions to prevent reporting incorrect losses on withdraws. - **This should never be lower than TokenizedStrategy.totalIdle()**. - - This does not need to take into account any conversion rates from assets to shares. But should know that any limit under uint256 max may get converted to shares and should not be high enough to overflow on multiplication. + - This does not need to consider conversion rates from assets to shares. But you should know that any limit under uint256 max may get converted to shares and should not be high enough to overflow on multiplication. **Example**: @@ -231,15 +231,15 @@ While that may be all that's necessary for some of the most simple strategies it - This would get called during a `tend` call and can be used if a strategy needs to perform any maintenance or other actions that don't require a full report. If used the strategy should also implement a `tendTrigger` that keepers can monitor to know when it should be called. **Parameters**: - - `_totalIdle`: The amount of asset that is currently loose in the strategy. + - `_totalIdle`: The amount of asset currently loose in the strategy. **Returns**: NONE **Good to Know**: - - The strategies totalDebt and totalIdle amounts will be automatically updated after this completes based on the end state, but will keep the totalAssets the same as to not have any effect on PPS. + - The strategies `totalDebt` and `totalIdle` amounts will be automatically updated after this completes based on the end state, but will keep the totalAssets the same as not to have any effect on PPS. **Best Practices**: - - This can only be called by the keeper or management so should be from a trusted source. + - This can only be called by the keeper or management so it should be from a trusted source. - Can be used to perform LTV adjustments on leveraged strategies. - Can be used to know a trusted relay has been used to deposit idle funds for a strategy that doesn't deploy funds during deposits. @@ -266,7 +266,7 @@ While that may be all that's necessary for some of the most simple strategies it - Default return value is false. **Best Practices**: - - Can implement checks on the current base fee of the chain to assure the gas cost isn't to high. + - Can implement checks on the current base fee of the chain to ensure the gas cost isn't too high. **Example**: @@ -280,7 +280,7 @@ While that may be all that's necessary for some of the most simple strategies it 1. *_emergencyWithdraw(uint256 _amount)* **Purpose**: - - Allows management the option to manually pull funds from the yield source once a strategy has been shutdown. + - Allows management to manually pull funds from the yield source once a strategy has been shut down. **Parameters**: - `_amount`: The specific amount to pull from the yield source @@ -288,12 +288,12 @@ While that may be all that's necessary for some of the most simple strategies it **Returns**: NONE. **Good to Know**: - - This can only be called once a strategy is shutdown. + - This can only be called once a strategy is shut down. - The `_amount` can be more than is available to pull. - - The totalDebt and totalIdle will be updated based on the end state after the emergencyWithdraw keeping totalAssets the same. + - The totalDebt and totalIdle will be updated based on the end state after the emergencyWithdraw, keeping totalAssets the same. **Best Practices**: - - Keep the withdraw logic as simple as possible. + - Keep the withdrawal logic as simple as possible. - Check `_amount` against the available amount to withdraw. **Example**: @@ -309,14 +309,14 @@ While that may be all that's necessary for some of the most simple strategies it All other functionality, such as reward selling, upgradability, etc., is up to the strategist to determine what best fits their vision. Due to the ability of strategies to stand alone from a Vault, it is expected and encouraged for strategists to experiment with more complex, risky, or previously unfeasible Strategies. ### FYI -NOTE: The only default global variables from the BaseTokenizedStrategy that can be accessed from storage is `asset` and `TokenizedStrategy`. If other global variables are needed for your specific strategy, you can use the `TokenizedStrategy` variable to quickly retrieve any other needed variables within the strategy, such as totalAssets, totalDebt, isShutdown etc. +NOTE: The only default global variables from the BaseTokenizedStrategy that can be accessed from storage is `asset` and `TokenizedStrategy`. If other global variables are needed for your specific strategy, you can use the `TokenizedStrategy` variable to quickly retrieve any other needed variables, such as `totalAssets`, `totalDebt`, `isShutdown` etc. Example: require(!TokenizedStrategy.isShutdown(), "strategy is shutdown"); -NOTE: It is impossible to write to a strategy's default global storage state internally post-deployment. You must make external calls from the `management` address to configure any of the desired variables. +NOTE: Writing to a strategy's default global storage state internally post-deployment is impossible. You must make external calls from the `management` address to configure any desired variables. To include permissioned functions such as extra setters, the two modifiers of `onlyManagement` and `onlyManagementAndKeepers` are available by default. @@ -328,32 +328,32 @@ The symbol used for each tokenized Strategy is set automatically with a standard To make Strategy writing as simple as possible, a suite of optional 'Periphery' helper contracts can be inherited by your Strategy to provide standardized and tested functionality for things like swaps. A complete list of the periphery contracts can be viewed here https://github.com/yearn/tokenized-strategy-periphery. -*All periphery contracts are optional, and strategists are free to choose if they wish to use them. +*All periphery contracts are optional; strategists can choose if they wish to use them. ### [Swappers](https://github.com/yearn/tokenized-strategy-periphery/tree/master/src/swappers) -In order to make reward swapping as easy and standardized as possible there are multiple swapper contracts that can be inherited by a strategy to inherit pre-built and tested logic for whichever method of reward swapping is desired. This allows a strategist to only need to set a few global variables and then simply use the default syntax of `_swapFrom(tokenFrom, tokenTo, amountIn, minAmountOut)` to swap any tokens easily during `_harvestAndReport`. +To make reward swapping as easy and standardized as possible, multiple swapper contracts can be inherited by a strategy to inherit pre-built and tested logic for whichever method of reward swapping is desired. This allows a strategist only to need to set a few global variables and then simply use the default syntax of `_swapFrom(tokenFrom, tokenTo, amountIn, minAmountOut)` to swap any tokens easily during `_harvestAndReport`. ### [APR Oracles](https://github.com/yearn/tokenized-strategy-periphery/tree/master/src/AprOracle) -In order for easy integration with Vaults, front ends, debt allocators etc. There is the option to create an [APR oracle](https://github.com/yearn/tokenized-strategy-periphery/blob/master/src/AprOracle/AprOracleBase.sol) contract for your specific strategy that should return the expected APR of the Strategy based on some given `debtChange`. +For easy integration with Vaults, front ends, debt allocators, etc. There is the option to create an [APR oracle](https://github.com/yearn/tokenized-strategy-periphery/blob/master/src/AprOracle/AprOracleBase.sol) contract for your specific strategy that should return the expected APR of the Strategy based on some given `debtChange`. ### [HealthCheck](https://github.com/Schlagonia/tokenized-strategy-periphery/tree/master/src/HealthCheck) -In order to prevent automated reports from reporting losses/excessive profits that may not be accurate, a strategist can inherit and implement the [HealthCheck](https://github.com/yearn/tokenized-strategy-periphery/blob/master/src/HealthCheck/HealthCheck.sol) contract. Using this can assure that a keeper will not call a report that may incorrectly realize incorrect losses or excessive gains. It can cause the report to revert if the gain/loss is outside of the desired bounds and will require manual intervention to assure the strategy is reporting correctly. +To prevent automated reports from reporting losses/excessive profits that may not be accurate, a strategist can inherit and implement the [HealthCheck](https://github.com/yearn/tokenized-strategy-periphery/blob/master/src/HealthCheck/HealthCheck.sol) contract. This can ensure that a keeper will not call a report that may incorrectly realize incorrect losses or excessive gains. It can cause the report to revert if the gain/loss is outside of the desired bounds and will require manual intervention to ensure the strategy is reporting correctly. NOTE: It is recommended to implement some checks in `_harvestAndReport` for leveraged or manipulatable strategies that could report incorrect losses due to unforeseen circumstances. ### [Report Triggers](https://github.com/yearn/tokenized-strategy-periphery/tree/master/src/ReportTrigger) -The expected behavior is that strategies report profits/losses on a set schedule based on their specific `profitMaxUnlockTime` that management can customize. If a custom trigger cycle is desired or extra checks should be added a strategist can create their own [customReportTrigger](https://github.com/yearn/tokenized-strategy-periphery/blob/master/src/ReportTrigger/CustomStrategyTriggerBase.sol) that can be added to the default contract for a specific strategy. +The expected behavior is that strategies report profits/losses on a schedule based on their specific `profitMaxUnlockTime` that management can customize. If a custom trigger cycle is desired or extra checks should be added a strategist can create their own [customReportTrigger](https://github.com/yearn/tokenized-strategy-periphery/blob/master/src/ReportTrigger/CustomStrategyTriggerBase.sol) that can be added to the default contract for a specific strategy. -*More information on this can be found below in the "Reporting" section. +*More information can be found below in the "Reporting" section. ## Testing -Due to the nature of the BaseTokenizedStrategy utilizing an external contract for the majority of its logic, the default interface for any 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 testing setups in each mix. 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 BaseTokenizedStrategy utilizing an external contract for most of its logic, the default interface for any 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 testing setups in each mix. You can add any external functions you add for your specific strategy to this interface to test all functions with one variable. Foundry Example: @@ -369,14 +369,14 @@ Due to the permissionless nature of the tokenized Strategies, all tests are writ ## Deployment -For strategies that will be used with multiple different asset's it is recommended to build a factory, that can be deployed once and then all strategies can be deployed on chain using the factory. +Building a factory that can be deployed once is recommended for strategies that will be used with multiple different assets. Then, all strategies can be deployed on the chain using the factory. **Cloning is not recommended for Tokenized Strategies.** #### Contract Verification -Once the Strategy is deployed and verified, you will need to verify the TokenizedStrategy functions as well. To do this, navigate to the /#code page on etherscan. +Once the Strategy is deployed and verified, you must also verify the TokenizedStrategy functions. To do this, navigate to the /#code page on Etherscan. 1. Click on the `More Options` drop-down menu. 2. Click "is this a proxy?". @@ -389,13 +389,13 @@ This should add all of the external `TokenizedStrategy` functions to the contrac Once deployed your strategy should be able to be interacted with as any other ERC-4626 vault. -In addition to the normal 4626 interface Tokenized Strategies come built in with some simple function for management to properly maintain the strategy. +In addition to the normal 4626 interface, Tokenized Strategies come built-in with some simple functions for management to properly maintain the strategy. ### Reporting The main operational procedure strategists need to take care of is the reporting of a strategy. Calling `report` on a strategy must be done by either the 'management' or 'keeper' address. -Reporting causes the strategy to accrue rewards, record any gains or losses as well as charge and pay fees. It is needed in order for the depositers of a vault to earn yield as well as for the strategist to to earn fees. +Reporting causes the strategy to accrue rewards, and record any gains or losses, as charges and paid fees. It is needed for the depositors of a vault to earn yield and for the strategist to earn fees. It is recommended to build strategies on the assumption that reports will happen based on the strategies specific `profitMaxUnlockTime`. @@ -403,31 +403,31 @@ Since reports are the only time _harvestAndReport will be called any strategies #### Keepers -The easiest way to assure regular reports and tends on your strategy is to hook it up with a 3rd party keeper. +The easiest way to ensure regular reports and tends on your strategy is to hook it up with a 3rd party keeper. -The recommended keeper network to use is the [Gelato Network](https://www.gelato.network/). +The recommended keeper network is the [Gelato Network](https://www.gelato.network/). ### Setters -The strategy comes with some default variables that the management of a strategy has the ability to set and update. +The strategy comes with some default variables that the management of a strategy can set and update. -1. Changing management: Changing the strategies management is a two step process. First the current management must call `setPendingManagment(address)` with the desired address to transfer the management to. Then that address must call `acceptManagement()` in order for the change to go into effect. -2. Keeper. The manager of a strategy can set a new address to be the keeper at any time with `setKeeper(address)`. +1. Changing management: Changing the strategies management is a two-step process. First, the current management must call `setPendingManagment(address)` with the desired address to transfer the management to. Then, that address must call `acceptManagement()` for the change to go into effect. +2. Keeper. A strategy manager can set a new address to be the keeper at any time with `setKeeper(address)`. 3. Performance Fee. Management can adjust the amount of the gain realized during a report that gets charged as a performance fee with `setPerformanceFee(uint16)`. - **Subject to min and max's. -4. Performance Fee Recipient. Can set the address that will receive the performance fees charged during a report with `setPerformanceFeeRecipient(address)`. -5. Profit Unlocking Period. Profits recorded during reports are slowly unlocked to depositers of a strategy over the strategy specific 'profitMaxUnlockTime'. This defaults to 10 days and can be changed at any time by the strategist with `setProfitMaxUnlockTime(uint256)`. + **Subject to min and max. +4. Performance Fee Recipient. Set the address to receive the performance fees charged during a report with `setPerformanceFeeRecipient(address)`. +5. Profit Unlocking Period. Profits recorded during reports are slowly unlocked to depositors of a strategy over the strategy-specific 'profitMaxUnlockTime'. This defaults to 10 days and can be changed at any time by the strategist with `setProfitMaxUnlockTime(uint256)`. ### Emergencies -There is two default emergency functions built in. First of which is `shutdownStrategy()`. This can only ever be called by the management and is non-reversible. +There are two default emergency functions built in. The first of which is `shutdownStrategy()`. This can only ever be called by the management and is non-reversible. -Once this is called it will stop any further deposit or mints but will have no effect on any other functionality including withdraw, redeem, report and tend. This is to allow management to continue potentially recording profits or losses and users to withdraw even post shutdown. +Once this is called it will stop any further deposits or mints but will not affect any other functionality including withdraw, redeem, report and tend. This allows management to continue recording profits or losses and users to withdraw even post-shutdown. This can be used in an emergency or simply to retire a vault. -Once a strategy is shutdown management can also call `emergencyWithdraw(_amount)`. Which will tell the strategy to withdraw a specified `_amount` from the yield source and keep it as idle in the vault. This function will also do any needed updates to totalDebt and totalIdle, based on amounts withdrawn to assure withdraws continue to function properly. +Once a strategy is shut down management can also call `emergencyWithdraw(_amount)`, which will tell the strategy to withdraw a specified `_amount` from the yield source and keep it idle in the vault. This function will also do any needed updates to `totalDebt` and `totalIdle`, based on amounts withdrawn to ensure withdraws continue functioning correctly. All other emergency functionality is left up to the individual strategist.