Developers
Search…
🏯
Strategies
Method to get yield on collateral

1. Introduction

Common contract to all strategies implemented in PoolManager. These contracts are in charge of the investment of part of the reserves owned by a PoolManager, they only control one type of ERC20 for a single stablecoin as each PoolManager is dedicated to a stablecoin/collateral pair. Strategies can be considered as workers for the corresponding PoolManager. They have a governance defined allowance from the manager (specified by their debtRatio), and they are entitled to invest as dictated by the initial strategy agreement.
One example of such strategy is to lend to multiple protocols (Compound, Aave, ...) and rebalance into the one with the highest APR. Governance has full authority on the farmed strategies and therefore assesses the risks and benefits of each Strategy. In the first place, Angle Core Team wishes to push for lower risk farming opportunities to limit the composability risk.
Most of the logic related to Strategies has been adapted from yVaults. In particular, the BaseStrategy contract was forked from Yearn-BaseStrategy.
This contract should be inherited and the abstract methods implemented to adapt the Strategy to the particular needs. The contract Strategy in the code is the first example of strategy implementation.

2. Contract Details

Interfaces

Implements BaseStrategyEvents and AccessControl.

Parameters

  • poolManager: Reference to the PoolManager
  • want: Reference to the ERC20 farmed
  • rewards: Reference to the ERC20 distributed as a reward by the strategy. This ERC20 cannot be equal to want.
  • minReportDelay: The minimum number of seconds between harvest calls
  • maxReportDelay: The maximum number of seconds between harvest calls
  • minimumAmountMoved: The minimum amount moved for a call to havest to be "justifiable"
  • debtThreshold: Used this to adjust the threshold at which running a debt causes a harvest trigger
  • emergencyExit: In case of emergency, this parameter states that the protocol should withdraw all ERC20 when asked to
  • rewardAmount: Amount of the reward obtained by calling harvest. A positive rewardAmount means that reward distribution is activated

Access Control

  • POOLMANAGER_ROLE : some functions can only be called by accepted PoolManager
  • GUARDIAN_ROLE : In this contract, there is no need for a GOVERNOR_ROLE, all the governor addresses, as well as the PoolManager contract associated have this GUARDIAN_ROLE

3. Key Mechanisms & Concepts

External Functions

harvest

1
function harvest() external;
Copied!
Harvests the Strategy, recognizing any profits or losses and adjusting the Strategy's position. In the rare case the Strategy is in emergency shutdown, this will exit the Strategy's position. When harvest() is called, the Strategy reports to the Manager (via manager.report()), so in some cases harvest() must be called in order to take in profits, to borrow newly available funds from the PoolManager, or otherwise adjust its position. In other cases harvest() must be called to report to the PoolManager on the Strategy's position, especially if any losses have occurred.

ethToWant

1
function ethToWant(uint256 _amtInWei) public view returns (uint256);
Copied!
Provide an accurate conversion from _amtInWei (denominated in wei) to want (using the native decimal characteristics of want). Care must be taken when working with decimals to assure that the conversion is compatible. As an example: given 1e17 wei (0.1 ETH) as input, and want is USDC (6 decimals), with 1 ETH worth 1800 USDC, this should give back 1800000000 (180 USDC).
Parameters:
  • _amtInWei: The amount (in wei/1e-18 ETH) to convert to want
Return Values:
  • The amount in want of _amtInEth converted to want

estimatedTotalAssets

1
function estimatedTotalAssets() public view returns (uint256);
Copied!
Provide an accurate estimate for the total amount of assets (principle + return) that this Strategy is currently managing, denominated in terms of want tokens. This total should be "realizable" e.g. the total value that could actually be obtained from this Strategy if it were to divest its entire position based on current on-chain conditions. Care must be taken in using this function, since it relies on external systems, which could be manipulated by the attacker to give an inflated (or reduced) value produced by this function, based on current on-chain conditions (e.g. this function is possible to influence through flashloan attacks, oracle manipulations, or other DeFi attack mechanisms).
Return Values:
  • The estimated total assets in this Strategy.

isActive

1
function isActive() public view returns (bool);
Copied!
Provide an indication of whether this strategy is currently "active" in that it is managing an active position, or will manage a position in the future. This should correlate to harvest() activity, so that Harvest events can be tracked externally by indexing agents.
Return Values:
  • True if the strategy is actively managing a position.

harvestTrigger

1
function harvestTrigger(uint256 callCostInWei) public view returns (bool);
Copied!
Provide a signal to the keeper that harvest() should be called. The keeper will provide the estimated gas cost that they would pay to call harvest(), and this function should use that estimate to make a determination if calling it is "worth it" for the keeper. This is not the only consideration into issuing this trigger, for example if the position would be negatively affected if harvest() is not called shortly, then this can return true even if the keeper might be "at a loss"callCostInWei must be priced in terms of wei (1e-18 ETH).
See min/maxReportDelay, debtThreshold to adjust thestrategist-controlled parameters that will influence whether this call returns true or not. These parameters will be used in conjunction with the parameters reported to the Manager (see params) to determine if calling harvest() is merited.
Parameters:
  • callCostInWei: The keeper's estimated gas cost to call harvest() (in wei).
Return Values:
  • if harvest() should be called, false otherwise.

numLenders

1
function numLenders() external returns(uint256);
Copied!
View function to check the number of lending platforms

PoolManager only Functions

The following functions can only be called by the PoolManager contract

withdraw

1
function withdraw(uint256 _amountNeeded) external returns (uint256 amountFreed, uint256 _loss);
Copied!
Withdraws _amountNeeded to manager. If the strategy couldn't withdraw_amountNeeded, then amountFreed (which is inferior to _amountNeeded) is withdrawn.
Parameters:
  • _amountNeeded: How much want to withdraw.
Return Values:
  • _loss: Any realized losses
  • amountFreed: Amount of want withdrawn

setEmergencyExit

1
function setEmergencyExit() external;
Copied!
Activates emergency exit. Once activated, the Strategy will exit its position upon the next harvest, depositing all funds into the Manager as quickly as is reasonable given on-chain conditions.
The PoolManager also has functions it can call in the Strategy to propagate changes from the PoolManager to all the Lenders it interacts with.
These functions include:
  • addGuardian
  • revokeGuardian

Guardian only Functions

The following functions can only be called by the guardian or governor addresses propagating some changes or modifying parameters.

manualAllocation

1
function manualAllocation(LenderRatio[] memory _newPositions) external;
Copied!
Reallocates all funds between according to a new distributions. This allows governance to decide to which platform they want to lend more specifically.
Parameters:
  • _newPositions: List of shares to specify the new allocation

sweep

1
function sweep(address _token, address to) external;
Copied!
Removes tokens from this Strategy that are not the type of tokens managed by this Strategy. This may be used in case of accidentally sending the wrong kind of token to this Strategy. Tokens will be sent to governance(). This will fail if an attempt is made to sweep want, or any tokens that are protected by this Strategy. This may only be called by governance.
Parameters:
  • _token: The token to transfer out of this manager.
  • to: Address to send the tokens to.

addLender

1
function addLender(IGenericLender newLender) external;
Copied!
Adds a new lender for this strategy

safeRemoveLender

1
function safeRemoveLender(address lender) external;
Copied!
Removes a lending platform and fails if total withdrawal is impossible

forceRemoveLender

1
function forceRemoveLender(address lender) external;
Copied!
Removes a lending platform, even if total withdrawal of all the assets from the strategy is impossible
Parameters:
  • lender: The address of the adapter to the lending platform to remove

Setter Functions

Governance has also access to multiple setters in the Strategy contract:
  • setRewards: Used to change the address to use for pulling rewards
  • setRewardAmountAndMinimumAmountMoved: Used to change the reward amount given to keepers calling harvest and the minimum amount moved for this reward to be justifiable.
  • setOracle: Changes the oracle contract used in the EthToWant function
  • setMinReportDelay: Used to change minReportDelay. minReportDelay is the minimum number of blocks that should pass for harvest() to be called.
  • setMaxReportDelay: Used to change maxReportDelay. maxReportDelay is the maximum number of blocks that should pass for harvest() to be called. For external keepers (such as the Keep3r network), this is the maximum time between jobs to wait.
  • setDebtThreshold: Sets how far the Strategy can go into loss without a harvest and report being required. By default this is 0, meaning any losses would cause a harvest which will subsequently report the loss to the PoolManager for tracking.