Convex Finance Protocol Adapter

The Convex adapter enables the Yieldinator Facet to integrate with Convex Finance, allowing vaults to earn boosted CRV rewards and additional CVX rewards by staking Curve LP tokens in Convex pools.

Overview

Convex Finance is a protocol built on top of Curve Finance that provides boosted rewards for Curve LP token holders. By staking Curve LP tokens through Convex, users can earn higher CRV rewards without needing to lock CRV tokens themselves, as well as additional CVX token rewards. The Convex adapter facilitates deposits into Convex pools, manages staked positions, and harvests both CRV and CVX rewards.

Implementation Details

Contract: ConvexAdapter.sol

The adapter implements the standard YieldinatorAdapter interface with Convex-specific functionality:

contract ConvexAdapter is YieldinatorAdapter {
    // Convex contracts
    IConvexBooster public convexBooster;
    address public cvxToken;
    address public crvToken;
    
    // Pool configuration
    struct PoolConfig {
        uint256 pid; // Convex pool ID
        address lpToken; // Curve LP token address
        address rewardContract; // Convex reward contract
        bool active; // Whether the pool is active
    }
    
    // Mapping from token (Curve LP token) to pool configuration
    mapping(address => PoolConfig) public tokenToPool;
    
    // Deposited amounts per token
    mapping(address => uint256) public depositedAmount;
    
    // Constructor and core functions...
}

Key Functions

Pool Registration

Before using the adapter for a specific Curve LP token, the Convex pool must be registered:

function registerPool(address _token, uint256 _pid) external onlyRole(ADAPTER_ADMIN_ROLE)

The function:

  1. Retrieves pool information from the Convex booster contract

  2. Verifies the pool is not shutdown

  3. Confirms the LP token address matches the provided token

  4. Stores the pool configuration for future use

Deposit

Deposits Curve LP tokens into Convex:

function deposit(address _token, uint256 _amount) external override onlyRole(YIELDINATOR_ROLE) nonReentrant returns (bool)

The function:

  1. Transfers LP tokens from the caller to the adapter

  2. Approves the Convex booster to spend the LP tokens

  3. Deposits LP tokens into Convex and automatically stakes them in the rewards contract

  4. Updates the deposited amount tracking

Withdraw

Withdraws LP tokens from Convex:

function withdraw(address _token, uint256 _amount) external override onlyRole(YIELDINATOR_ROLE) nonReentrant returns (bool)

The function:

  1. Withdraws LP tokens from the Convex rewards contract

  2. Withdraws LP tokens from the Convex booster

  3. Transfers LP tokens to the caller

  4. Updates the deposited amount tracking

Harvest Yield

Harvests CRV, CVX, and any additional rewards:

function harvestYield(address _token) external override onlyRole(YIELDINATOR_ROLE) nonReentrant returns (uint256)

The function:

  1. Claims rewards from the Convex rewards contract

  2. Transfers CRV tokens to the caller

  3. Transfers CVX tokens to the caller

  4. Attempts to claim and transfer any additional reward tokens

Emergency Withdraw

Provides emergency withdrawal functionality:

function emergencyWithdraw(address _token) external override onlyRole(YIELDINATOR_ROLE) nonReentrant returns (uint256)

APY Calculation

Returns the current APY for a token in Convex:

function getCurrentAPY(address _token) external view override returns (uint256)

Note: In a production environment, this would require external data sources to calculate accurately.

Additional Functions

The adapter includes additional Convex-specific functions:

function getClaimableRewards(address _token) external view returns (uint256, uint256)
function deactivatePool(address _token) external onlyRole(ADAPTER_ADMIN_ROLE)
function reactivatePool(address _token) external onlyRole(ADAPTER_ADMIN_ROLE)

Usage Example

// Initialize the adapter
ConvexAdapter convexAdapter = new ConvexAdapter(
    convexBoosterAddress,
    cvxTokenAddress,
    crvTokenAddress,
    adminAddress
);

// Register a pool
convexAdapter.registerPool(curve3PoolLpTokenAddress, 3); // Pool ID 3 for 3pool

// Deposit LP tokens
convexAdapter.deposit(curve3PoolLpTokenAddress, 1000 * 1e18);

// After some time, harvest yield
uint256 harvestedYield = convexAdapter.harvestYield(curve3PoolLpTokenAddress);

// Withdraw LP tokens
convexAdapter.withdraw(curve3PoolLpTokenAddress, 500 * 1e18);

// In case of emergency
convexAdapter.emergencyWithdraw(curve3PoolLpTokenAddress);

// Check claimable rewards
(uint256 claimableCrv, uint256 claimableCvx) = convexAdapter.getClaimableRewards(curve3PoolLpTokenAddress);

Security Considerations

  • The adapter uses OpenZeppelin's SafeERC20 for token transfers to prevent common ERC20 vulnerabilities.

  • Non-reentrancy guards protect against reentrancy attacks during external calls.

  • Role-based access control ensures only authorized addresses can call sensitive functions.

  • The adapter includes pool activation/deactivation functionality to handle potential issues with Convex pools.

Gas Optimization

  • The adapter deposits and stakes LP tokens in a single transaction to save gas.

  • Token approvals are set exactly to the amount being deposited to avoid unnecessary approvals.

  • The adapter claims all rewards in a single transaction during yield harvesting.

Integration Requirements

To use the Convex adapter, the following components are required:

  1. The Convex Booster contract address

  2. The CVX token address

  3. The CRV token address

  4. Convex pool IDs for the target Curve LP tokens

  5. Proper role assignments for the Yieldinator Facet

Reward Mechanism

Convex provides two primary types of rewards:

  1. CRV Rewards: Boosted CRV rewards from Curve gauges

  2. CVX Rewards: Additional CVX tokens minted based on CRV rewards

The adapter handles both reward types and can also claim additional rewards that may be distributed through Convex (e.g., SNX, SPELL, etc.).