Strategy Creation
Creating and managing a tokenized strategy in the Fathom ecosystem involves a few critical functions. Below, we detail the essential functions your strategy must implement, focusing on asset deployment, yield optimization, and operational functions for comprehensive management.
Inheriting from BaseStrategy
BaseStrategy
BaseStrategy
implements all of the required functionality to seamlessly integrate with the TokenizedStrategy
implementation contract allowing anyone to easily build a fully permissionless ERC-4626 compliant Strategy by inheriting this contract and overriding three simple functions.
Storage Variables
In the context of the BaseStrategy
, there are a couple of built-in global variables that you will frequently access:
asset
: This variable represents the ERC-20 token that your strategy will use as the primary asset for operations like deposits, withdrawals, and yield generation.TokenizedStrategy
: This variable refers to the interface or instance of the strategy that includes core functions and state variables necessary for the strategy's operation.
If your strategy requires additional data or needs to check on operational states, you can access these through the TokenizedStrategy
variable. It provides access to various states like totalAssets
managed by the strategy.
Must Override Functions
1. _deployFunds(uint256 _amount)
_deployFunds(uint256 _amount)
Purpose
This function manages the deployment of the underlying asset into a yield-generating protocol each time a deposit is made into the strategy. It's responsible for ensuring that new deposits, as well as any funds previously not deployed, are effectively put to work to generate yield.
Parameters
_amount
: Represents the total quantity of the underlying assets that are available to be deployed. This includes both the new deposits and any funds that were previously idle within the strategy.
Behavior and Considerations
Permissionless: This function can be called without specific permissions, which means the operations (like swaps or LP staking) can be initiated by any entity. This open access requires careful management to prevent manipulation.
Partial Deployment: The strategy can choose not to deploy all available funds depending on its needs or conditions in the underlying protocols.
2. _freeFunds(uint256 _amount)
_freeFunds(uint256 _amount)
Purpose
This function is invoked when there is a need to withdraw funds from the yield source, typically triggered by a user's withdrawal request from the strategy.
Parameters
_amount
: The amount of the underlying asset required to be liquidated from the yield source to meet withdrawal requests.
3. _harvestAndReport()
_harvestAndReport()
Purpose
This function is central to the strategy's operational cycle, called periodically to manage the harvesting of rewards, reinvestment, and the reporting of the strategy's performance.
Returns
_totalAssets
: Provides a verified total of the strategy’s assets, including those deployed and idle, ensuring accurate performance tracking and fee calculation.
Behavior and Considerations
Permissioned: Unlike other functions, this one is permissioned to ensure only authorized addresses can execute it, safeguarding against unauthorized or harmful actions.
Comprehensive Asset Accounting: It is crucial for this function to accurately account for all assets to ensure correct profit, loss, and fee calculations.
Optional Override Functions
While overriding the primary functions in a strategy ensures basic compliance and operational capability, incorporating additional optional functions allows for more detailed control and customization of the strategy's behavior. These functions are instrumental for strategies seeking greater flexibility and complexity in managing asset interactions and operational constraints.
1. availableDepositLimit (address _owner)
availableDepositLimit (address _owner)
Purpose: Restricts the amount that can be deposited based on strategic constraints or protocol requirements.
Parameter:
_owner
is the depositor's address.Returns: The maximum allowable deposit amount.
Usage: Enforce deposit limits or maintain a whitelist. Defaults to
uint256 max
, meaning no limit unless specified.Best Practice: Implement logic to check protocol limits or system status to automatically adjust deposit capabilities.
2. availableWithdrawLimit (address _owner)
availableWithdrawLimit (address _owner)
Purpose: Limits the amount that can be withdrawn, useful for managing liquidity or protocol constraints.
Parameter:
_owner
refers to the shareholder.Returns: The permissible withdrawal amount.
Usage: This function is crucial for strategies that may have illiquid positions or need to manage large withdrawals carefully. It defaults to
uint256 max
, allowing for maximum flexibility unless specifically limited.Best Practice: Override to set limits based on current strategy liquidity or operational requirements.
3. _tend (uint256 _totalIdle)
_tend (uint256 _totalIdle)
Purpose: Allows for periodic maintenance or adjustments of the strategy's assets without a full report.
Parameter:
_totalIdle
represents the amount of idle assets available.Returns: None.
Usage: Ideal for strategies that require regular adjustments to maintain optimal investment positions or leverage levels.
Best Practice: Use this function to adjust positions based on market conditions or internal strategy targets.
4. _tendTrigger ()
_tendTrigger ()
Purpose: Indicates whether it's appropriate to perform a tend operation.
Returns: A boolean indicating whether a tend operation should be initiated.
Usage: Acts as a check to ensure that tend operations are called when necessary, based on specific strategy conditions or thresholds.
Best Practice: Implement logic that assesses current market conditions, strategy performance, or asset allocations to decide the necessity of a tend operation.
5. _emergencyWithdraw (uint256 _amount)
_emergencyWithdraw (uint256 _amount)
Purpose: Facilitates the withdrawal of funds in emergency situations, particularly after a strategy shutdown.
Parameter:
_amount
specifies how much of the underlying asset to withdraw.Returns: None.
Usage: Critical for withdrawing funds when a strategy has been halted due to significant issues or for decommissioning.
Best Practice: Ensure that the logic is straightforward and failsafe to prevent complications during emergency operations.
These optional functions provide strategists with the tools to fine-tune their strategy's interaction with underlying assets, offering flexibility to adapt to a variety of operational scenarios and market conditions.
Reporting
A critical operational process for strategists is the regular reporting of strategy performance. Reporting must be initiated by authorized addresses, specifically those designated as 'management' or 'keeper'. The report
function is instrumental in aggregating accrued rewards, documenting any profits or losses, and managing the assessment and distribution of fees. This function underpins the yield generation for vault depositors and the fee accrual for strategists.
Strategies should be designed with the expectation that reporting occurs at intervals defined by the strategy’s specific profitMaxUnlockTime
. This setup ensures that the strategy remains aligned with its yield targets and operational metrics.
_harvestAndReport
is the primary function called during a report; it is pivotal for collecting rewards and recalibrating strategy assets and positions. Strategies that require more frequent operational checks or adjustments should implement and utilize _tend
and tendTrigger
functions to handle necessary actions between reports.
Setters
Strategies come equipped with several modifiable parameters that management can adjust as needed:
Changing Management: To change the strategy's management, initiate a two-step process. First, the existing management should invoke
setPendingManagement(address)
with the new management address. Subsequently, the new address must callacceptManagement()
to finalize the transfer.Keeper: The strategy manager has the ability to designate a new keeper by calling
setKeeper(address)
.Emergency Admin: Initially set to
address(0)
, the emergency admin can be updated by management usingsetEmergencyAdmin(address)
.Performance Fee: The management can modify the performance fee rate, which is applied to gains during reporting, using
setPerformanceFee(uint16)
. This setting adheres to defined minimum and maximum limits.Performance Fee Recipient: Assign the recipient of the performance fees by calling
setPerformanceFeeRecipient(address)
.Profit Unlocking Period: Profits are gradually released to depositors over a period defined by
profitMaxUnlockTime
, which defaults to 10 days but can be adjusted by the strategist withsetProfitMaxUnlockTime(uint256)
.
Emergencies
Strategies incorporate two primary emergency functions:
Shutdown Strategy: Executable only by the management or emergency admin, this irreversible function halts new deposits and mints. However, it allows other operations such as withdrawals, redemptions, reports, and tending to continue, enabling ongoing profit and loss documentation and allowing users to access their funds post-shutdown. This function can be utilized in critical situations or to decommission a vault.
Emergency Withdraw: Upon strategy shutdown, management or the emergency admin may activate
emergencyWithdraw(uint256 _amount)
to extract a specified amount from the yield source and retain it within the vault in an idle state.
These emergency measures, along with any additional custom functions, are crucial tools for strategists to manage urgent scenarios effectively.
Last updated