Convex f(x) Staking (cvxFXN)
The Convex-f(x) staking platform lets users trustlessly stake positions on the f(x) gauge system while borrowing Convex's boosting power via veFXN. As with the Convex-Frax platform, Convex creates a unique proxy vault per (pool, user) pair which only the user can operate for principal changes, isolating deposits and keeping users in control of their funds. The vault is granted permission to share in Convex's veFXN boost, increasing farming efficiency. In return, Convex takes a percentage of the FXN farmed as a fee.
GitHub: https://github.com/convex-eth/function_x
Core architecture
FxnVoterProxy (voteProxy)
holds the protocol's veFXN; source of boosting power
Booster
management entry point; creates vaults, manages pools/fees/roles
PoolRegistry (poolReg)
pool configuration (implementation, gauges, staking tokens)
StakingProxyBase / StakingProxyERC20 / StakingProxyRebalancePool
per-user vault implementations
MultiRewards
extra rewards for a pool outside the gauge
FeeRegistry (feeReg)
holds the fee % applied on claimed FXN
FeeDepositV2
receives collected FXN fees, routes to platform + cvxFXN
cvxFxn
the Convex-Function(X) token
cvxFxnStaking
staking contract for cvxFXN (reward-token set managed on-chain)
FxnDepositor
deposits FXN → veFXN and mints cvxFXN
Burner
burns cvxFXN (no token conversion)
LpRewardHook
asks the current Booster to claimFees() for LPs (not an LP reward claimer itself)
Vault-per-user model
Identical in shape to the cvxFXS platform:
Convex creates vault implementation contracts — proxy staking interfaces to the underlying Function(X) gauge (
StakingProxyERC20for Curve-convex LPs,StakingProxyRebalancePoolfor rebalance pools).Convex creates a pool and assigns an implementation —
addPool(implementation, stakingAddress, stakingToken)on the Booster/PoolRegistry; aMultiRewardscontract is created for extra rewards. Pools can be marked inactive to halt new vault creation (existing vaults remain operable).A user creates their own vault —
booster.createVault(_pid)clones the implementation (initialize(_owner, _pid)). One vault per(pool, user); only the owner can perform principal operations (deposit/withdraw).Convex enables the vault to use the protocol's veFXN boost at creation time via
setVeFXNProxy.The user stakes/claims through their vault —
deposit(_amount),withdraw(_amount),earned(),getReward(bool _claim, address[] _tokenList).
Reward claims are not exclusively owner-callable: earned()/un-guarded getReward() are public. Principal operations are owner-only. FXN claimed through the vault has the fee applied and sent to the Convex system for distribution. On StakingProxyERC20, tokens other than FXN returned by the gauge are claimed directly to the vault owner via the gauge's setRewardReceiver() mechanism; rebalance-pool vaults instead claim to the vault itself and transfer active non-FXN rewards to the owner.
Vault interface
Note: _claim only toggles whether the underlying gauge claim (and any related mint) is invoked — there is no conversion/redeposit step. transferTokens deliberately skips FXN (fee must be applied) and the gauge token.
Fee flow
The FXN fee is a flat rate from the FeeRegistry (0x4f258feCc91b2ff162cA702c2Bd9ABf2AF089611), applied as fxnBalance * totalFees / 10000. Current settings: totalFees = 1700 (17%), capped at maxFees = 2000, denominator 10000. When a vault claims, that fraction of the FXN balance is transferred to feeRegistry.getFeeDepositor(...) and the remainder goes to the vault owner.
The collected FXN sits in FeeDepositV2 (0x8133F7D5CD1A1E184228C373F5bEFa98Fa01395D) and is split on processFees() between the receivers:
platform
platformIncentive = 5000 bps (50%)
→ platformReceiver (Convex treasury)
vlCVX
vlcvxIncentive = 0 bps
configurable; → vlcvxReceiver
cvxFXN
remainder (50%)
→ cvxfxnReceiver (FeeReceiverCvxFxn), which notifies into the cvxFXN staking reward stream
So of a gross 17% fee, the current default is ~8.5% to platform and ~8.5% into the cvxFXN staking reward stream (0% to vlCVX). This is a direct FXN reward stream for staked cvxFXN.
These setters are restricted to the registry owner (the veFXN voter proxy). Do not assume a current Booster provides a working external forwarding path to these — check the Booster ABI (its own encoded fee setters target different signatures).
cvxFXN token & staking
FxnDepositor.sol (0x56B3c8eF8A095f8637B6A84942aA898326B82b91) accepts FXN (0x365AccFCa291e7D3914637ABf1F7635dB165Bb09), locks it into veFXN (via Escrow 0xEC6B8A3F3605B083F7044C0F31f2cac0caf1d469), and mints cvxFxn (0x183395DbD0B5e93323a7286D1973150697FFFCB3). The mint itself is always 1:1. A separate, conditional platformHolding diversion can apply on top: after minting, if amount + cvxFxn.totalSupply() <= veFXN.locked(staker) (i.e. total minted cvxFXN stays within the veFXN backing), up to platformHolding bps of the user's incoming FXN is instead transferred to platformDeposit (a governance-set address/rate — read the live values before integrating). Deposits support _lock=false (deferred locking) and _lock=true (immediate lock).
cvxFxnStaking (0xEC60Cd4a5866fb3B0DD317A46d3B474a24e06beF) is the staking/reward contract for cvxFXN. It exposes the standard triad — stake/deposit, withdraw, getReward(address, forwardTo) — plus setRewardRedirect(address), notifyRewardAmount, and reward-token management. Query rewardTokenLength()/rewardTokens(i) for the current reward-token set (a governance-managed list, not a fixed inventory).
Design decisions (from the repo)
User funds are controlled solely by user-owned vaults; Convex admin never has direct access to funds.
Vault functions that admin does control relate to boost (which veFXN proxy a vault uses) and fees, with hard-coded upper limits on fees.
Creating a vault requires an extra initial transaction, but vaults keep funds un-co-mingled and rewards directly linked to the vault — no trailing reward structure or harvesting is required.
Vaults allow users to execute arbitrary functions within limits (e.g. claim an airdrop on gauge interactions).
Addresses
Mainnet: Booster 0xAffe966B27ba3E4Ebb8A0eC124C7b7019CC762f8, PoolRegistry 0xdB95d646012bB87aC2E6CD63eAb2C42323c1F5AF, voteProxy 0xd11a4Ee017cA0BECA8FA45fF2abFe9C6267b7881. contracts/contracts.json lists the registered pools (implementation, staking address/token, rewards) — query PoolRegistry.poolLength() for the live count; per-user vault addresses are created per user and not catalogued there.
Last updated
Was this helpful?