LP staking vault (LpStakingVault7D)
LpStakingVault7D lets users stake Aerodrome WETH/CLAIM LP tokens and harvest CLAIM rewards.
User lifecycle
Stake:
- stake(amount)
- updates reward accounting and increases stakedBalance
Unbond:
- beginUnbond(amount) -> creates an unbond entry
- UNBONDING_PERIOD = 7 days
- MAX_UNBONDS_PER_USER = 25
Withdraw:
- withdrawUnbond(unbondId)
- only after unlockTime
Harvest (CLAIM rewards):
- getReward()
- UI verb: Harvest
Reward sources
Rewards distributed by the vault can come from:
- Furnace LP top-up split (lpBonus)
- Furnace LP overflow drip (protocol -> LP pot)
- The vault’s own Aerodrome fee harvest (see below)
Reward accounting is standard “reward per token” style using ACC = 1e18.
Fee harvest: Aerodrome LP fees -> rewards
Method:
- harvestFeesToRewards(deadline, minClaimOut)
- permissionless
Flow:
- calls Aerodrome pool claimFees() (WETH + CLAIM)
- pays a WETH bounty (staleness-gated)
- swaps remaining WETH -> CLAIM
- credits total CLAIM (direct fee CLAIM + bought CLAIM) as new rewards
Bounty constants (v1.0.0):
- STALE_BOUNTY_AFTER = 60 minutes
- BOUNTY_BPS = 100 (1%)
- MAX_BOUNTY_WETH = 0.01 ETH (in WETH)
Bounty rules:
- if last harvest was within STALE_BOUNTY_AFTER: bounty = 0
- if harvest is stale: bounty = min(MAX_BOUNTY_WETH, feeWeth * 1%)
Operational expectation:
- the official keeper harvest cadence is < 60 minutes, so bounty is typically 0
- the bounty is a liveness backstop, not a steady incentive
Auto-compound (vault rewards -> veCLAIM)
Users can opt in to auto-compound their vault $CLAIM rewards into the Furnace.
Key rules (v1.0.0):
- Auto-compound is disabled by default (explicit user opt-in).
- Auto-compound does not create new locks in v1.0.0:
- a destination
tokenIdis required.
- a destination
- Execution is permissionless (official executor is an offchain maintainer bot).
Config per user (onchain):
enabled,pausedtokenIddestination (must be owned by the user, not listed, not expired)durationSeconds(target lock duration for extension-only compounding)
Execution:
compoundFor(user)compoundForMany(users[], minVeOuts[], maxUsers)(bounded + best-effort per user)
Behavior:
- Best-effort per user (batch does not revert for a single failure).
- Skips if
claimableRewards(user) == 0. - Computes effective duration as extension-only:
effectiveDurationSeconds = max(configDurationSeconds, remainingDurationSeconds(tokenId))- AutoMax forces
MAX_LOCK_DURATION.
- Pauses config if the destination lock becomes ineligible at execution time (listed/expired/not owned).
- User must save a new config to resume.
UI/UX integration (recommended):
- LP Vault rewards actions should mirror Royalties:
- Primary (default): Harvest $CLAIM
- Secondary: Harvest & Lock
- Optional: “Remember my choice” toggle (local preference).
- After a successful Harvest & Lock, show: “Enable Auto-compound?” (routes to config modal, prefilled).
notifyRewards allowlist
To prevent arbitrary reward injection, notifyRewards is allowlisted. Expected authorized sources:
- Furnace
- this vault itself (self-notify from harvestFeesToRewards)
Operational note:
- Upstream funders may treat
notifyRewardsas best-effort (swallow reverts) to avoid DoS on unrelated flows (e.g. user locking). - This vault uses balance-delta accounting (amount is ignored), so any CLAIM transferred without a successful notify can still be accounted on a later successful notify (including
notifyRewards(0)).
Integrator notes
- If you display APR, use the canonical APR spec in docs/spec/apr-calculation-spec-v1.0.0.md.
- Do not label CLAIM rewards as “claim” in UI. Use Harvest.