Strategy Contract
Last Update: February 2023
Strategy Contracts are the primary driver of Beefy's investment model, which facilitate the autocompounding of yield farm rewards. Beefy's process has three key steps: (1) staking deposited tokens in the relevant farms; (2) harvesting rewards; and (3) swapping rewards for more deposit tokens and reinvesting the proceeds
Each strategy contract is ultimately dependent on a Vault Contract for the capital they deploy, and do not have any direct interaction with ordinary users. The vault and strategy contracts are kept separate to isolate any risks in the strategy from user deposits.
Dependencies
All Beefy strategies rely on a range of dependencies and interfaces which are imported into the strategy contract on deployment. The core dependencies, which allow the strategy to inherit a range of functionality are:
the StratFeeManager Contract; and
Interfaces
The key interfaces which allow the strategy to interact with third party contracts are:
the router contract interface - which allows for swaps between the different tokens involved in the autocompounding process (e.g. IUniswapRouterETH.sol);
the liquidity pool contract interface - which is the underlying pool that our vaults provide liquidity to and that the farms are built on top of (e.g. IUniswapV2Pair.sol); and
the chef contract interface - the farm which is issuing rewards for providing liquidity (e.g. IMiniChefV2.sol).
View Functions
balanceOf() / balanceOfWant()
Checks the amount of the underlying farm token (or "want") stored in the strategy. Returns the specific amount of tokens.
balanceOfPool()
Checks the amount of underlying farm token (or "want") stored in the chef contract. Returns the specific amount of tokens.
rewardsAvailable()
Checks the amount of pending rewards held by the chef contract capable of being claimed by the strategy contract. Returns the specific amount of tokens.
callReward()
Most strategies include a callReward() function, which is used to determine the amount of "native" token rewards available to the harvest() caller.
Write Functions
deposit()
Deposits the underlying farm token (or "want") into in the farm by way of the connected chef contract. First checks that the strategy is holding some of the underlying farm token (or "want") before depositing the entire balance in the chef.
withdraw()
External function called by the vault to facilitate user withdrawals. First checks that the balance of the underlying farm token (or "want") is sufficient to fulfil the request, and then withdraws that amount from the chef contract, before transferring back to the vault contract.
harvest()
Harvest invokes the compounding of the vault for all users. Specifically, this harvests from the chef contract, charges fees on the harvest and then deposits the harvested rewards back into the farm to achieve the autocompounding effect.
This function is completely decentralized, meaning that anyone is able to call the function, and can earn a reward between 0.05 - 0.5% of the total yield. This can be called by any one of three methods, detailed below.
chargeFees()
Internal method to charge fees on every harvest() call, by swapping the native token in the strategy to the output token via the router contract. The contract then calculates the output for the different fee recipient and transfers the output tokens according to the allocation. The recipients are the harvest caller, the strategist who deployed the contract and the Beefy treasury.
addLiquidity()
Internal method to add liquidity to the underlying pool for the farm as part of the harvest() function. Swaps the output token to the underlying tokens of the farm, and then adds both to the liquidity pool to obtain the underlying farm deposit token (or "want"). The remainder of the harvest() call then deposits these tokens in the farm.
setHarvestOnDeposit()
Most Beefy vaults harvest on deposit. This means that, before the user's funds enter the strategy, the yield on the entire vault is harvested and reinvested. This prevents new depositors from stealing the yield of existing depositors. As a result, any vault that is set to harvest on deposit is able to remove the withdrawal fee completely.
harvestOnDeposit is a boolean variable which is set to true when the vault is harvesting on deposit. This is toggled by the setHarvestOnDeposit() function, set out below:
beforeDeposit()
External function used to facilitate harvests on deposit, if active. Checks first that harvest on deposit is active and that the caller is the vault, before harvesting.
panic()
Beefy does not directly touch any user funds held in the protocol. During times of uncertainty or upgrades to the underlying yield farm, Beefy can withdraw all funds out of third party contracts and hold them safely in the strategy using the panic() function. By "panicking" the strategy, users remain able to withdraw their funds from the vault without any delay or exposure to third party risks. This function also removes all allowances to both the UniRouter and the underlying yield farm contract, to ensure no funds can be withdrawn by those contracts.
pause() / unpause()
All Beefy strategies are pausable, meaning that functionality can be halted during the strategy's ordinary operations by the strategy manager. This is inherited through StratManager.sol, and relies on the standard Pausable.sol abstract contract. This function also removes all allowances to both the UniRouter and the underlying yield farm contract, to ensure no funds can be withdrawn by those contracts.
In the reverse, strategies can also be unpaused, by reversing the actions in the pause function.
The functions affected by a pause in most strategy contracts are deposit(), withdraw() and harvest().
_giveAllowances / _removeAllowances()
Internal functions used to set and remove all allowances with third party contracts, to control whether third party contracts have the necessary permissions to withdraw funds from the strategy. The relevant contracts are the underlying farm token/want() (e.g. LP token), the strategy output token (often the same as the want()), the native chain token (used for gas) and the underlying tokens used for the farm.
retireStrat()
External function used as part of a migration from one strategy to another. This effectively closes down the strategy by withdrawing all funds and transferring them back to the vault. It can only be triggered by a call from the vault contract.
Last updated