Strategies rely on external protocols and come with their own risks. Users should carefully evaulate the strategy design and the risks associated with any protocol that a strategy interacts with. While strategies are designed to be robust and secure, users may still be exposed to the risks of external protocols.
Underlying (asset to farm): [USDC, USDT or DAI]
Reward tokens: CVX, CRV
Support other reward tokens: True
Description: This strategy provides single sided liquidity to Curve’s 3pool. Then uses the LP Token 3CRV to provide single sided liquidity to a Curve Meta Pool, for example MIM or FRAX. It then stakes the Meta Pool LP Tokens in Convex, periodically harvesting CVX and CRV rewards to sell for the Underlying.
Here is an overview of which contracts this strategy interacts with and how each contract is used (on a high level).
ERC20 tokens used:¶
- CVX: 0x4e3FBD56CD56c3e72c1403e103b45Db9da5B9D2B
Native token of Convex
- CRV: 0xD533a949740bb3306d119CC777fa900bA034cd52
Governance token of Curve
- WETH: 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2
Wrapped ETH (ERC20 compatible)
- Underlying: [set per strategy]
Deposited into Curve 3pool as single sided liquidity
- 3CRV: 0x6c3F90f043a72FA612cbac8115EE7e52BDe6E490
Minted by depositing into Curve 3pool
Deposited into Curve MetaPool as single sided liquidity
Burned to redeem underlying
- Curve LP Token: [set per strategy]
Minted by depositing 3CRV into Curve MetaPool
Deposited in Convex Booster contract
Burned to redeem 3CRV
- Uniswap: 0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D
Swap coin X for Y if AMM is set as default
- SushiSwap: 0xd9e1cE17f2641f24aE83637ab66a2cca9C378B9F
Swap coin X for Y if AMM is set as default
- Curve CVX/ETH Pool: 0xB576491F1E6e5E62f1d8F26062Ee822B40B0E0d4
Swap CVX rewards for WETH
- Curve CRV/ETH Pool: 0x8301AE4fc9c624d1D396cbDAa1ed877821D7C511
Swap CRV rewards for WETH
Curve contracts used:¶
- Curve 3pool: 0xbEbc44782C7dB0a1A60Cb6fe97d0b483032FF1C7
Deposit underlying to mint 3CRV
Burn 3CRV to redeem underlying
- Curve MetaPool: [set per strategy]
Deposit 3CRV to mint LP Token
Burn LP Token to redeem 3CRV
Convex contracts used:¶
- Booster: 0xF403C135812408BFbE8713b5A23a04b3D48AAE31
Deposit and Withdraw Curve LP Token
- Rewards: [set per strategy]
Stake Convex LP Token to earn CRV, CVX and other rewards
Convex Finance is a protocol built around Curve, which essentially allows Curve LPs to receive a higher boost on CRV rewards by staking Curve LP tokens on Convex and not directly on Curve. Furthermore, CRV holders can lock their CRV on Convex for veCRV and in exchange receive cvxCRV, which is essentially tokenized veCRV. Note that once CRV is deposited on Convex, it cannot be withdrawn. However, Convex incentivizes LPs of Sushiswap pools for CRV-cvxCRV pools, by rewarding these LPs with CVX tokens. Additionally, CVX rewards get minted on a per rata basis as CRV rewards are received by Convex LPs. A platform fee is charged by Convex on CRV rewards, which goes in part to users that lock CRV for cvxCRV (and stake cvxCRV), as well as CVX stakers. Stakers of cvxCRV also receive 3CRV rewards, which are the governance fees paid by Curve on a weekly basis.
Overall there are three roles a user can have on Convex to earn rewards:
Liquidity provider (stake Curve LP tokens):
Claim CRV rewards from Convex
Claim CVX rewards from Convex
CRV depositor (lock CRV for cvxCRV; stake cvxCRV):
Receive 3CRV (Curve trading fees)
Receive CRV (Convex platform fees)
Receive cvxCRV (platform fees)
The TRI-HOP-CVX strategy has the following core components.
strategy.deposit(), all available underlying held by the strategy will be provided as single sided liquidity into the Curve 3pool. The Curve 3CRV LP Token will then be provided as single sided liquidity into a Curve MetaPool. The Curve MetaPool LP Token will then be deposited into the Convex
Booster contract (details here). Finally the Convex LP Token is staked for CRV and CVX rewards in the Convex
The Convex reward pools all implement the
IRewardStaking interface. You can find the implementation of these reward pools here. Rewards are claimed by calling the
getReward() method on the
There may be a situation whereby a Curve pool is incentivized, i.e. LPs of the pools receive additional reward tokens for depositing funds. These extra rewards would be also be claimed through Convex on getReward(). In order to be able to process these on the strategy side, the strategy contains a list of all the possible`rewardTokens` in which it may hold funds. New tokens can be added to this list by the admin. When funds are liquidated, the reward tokens are liquidated for the underlying.
strategy.harvest() is called (by the vault), CRV and CVX rewards will be claimed. All CVX and CRV rewards earned by the strategy are first taxed, where the taxed amount goes to the Mero CVX reserve and gets vote locked on Convex. The net CVX and CRV rewards earned are all sold off for the underlying.
harvest() does not automatically redeposit underlying into Convex (reduce gas costs).
The balance of the strategy includes idle underlying, idle 3CRV, idle Curve LP Tokens and staked Curve LP Tokens. Any unclaimed rewards are not included in the balance. The balance function uses get_virtual_price which is a view of the Curve Pools. This function returns the price of the LP Token relative to the assets of the pool. This may differ from the actual amount that can be withdrawn from the pool at any point in time, as if the pool is imblanaced, then the withdrawable amount may be less than or greater than the virtual price. This is in place as a security measure to protect against attacks that intentionally cause imbalance in curve pools to manipulate the balance of a strategy.
Providing single sided liquidity into Curve pools can be undesirable if the pool is significantly imbalanced. If a malicious actor frontran deposit and withdrawal transactions and caused an imbalance in the pool, the strategy could receive very little LP tokens when depositing, or receive very little of the underlying when withdrawing. To protect against this, the strategy uses imbalance tolerance thresholds to ensure that the pool is balanced within a range when withdrawing and depositing.
When depositing into the pool using the
add_liquidity function, the
min_mint_amount is set to specify the minimum amount of LP tokens to accept for the deposit. This value is set by using the
get_virtual_price function to get the expected LP received for a perfectly balanced pool. Then this value is reduced by a percent
imbalanceToleranceIn to get the minimum that we are willing to accept considering that the pool may have slight imbalances.
Similarly with withdrawing using
remove_liquidity_one_coin the maximum LP burned is set with
max_burn_amount and the minimum underlying received is set with
min_amount respectively. Both of these use the percent multiplier
imbalanceToleranceOut to add a buffer on what is an acceptable amount.