StakingBoost Technical Specification
Complete technical specification for the "Stake SHIELD → Boost shXRP Yield" feature.
See also: Whitepaper (PDF) — Section 3 contains the full mathematical framework with formal notation.
Overview
StakingBoost implements a Synthetix-style reward accumulator to distribute FXRP rewards pro-rata to SHIELD stakers. When stakers claim their rewards, shXRP shares are minted directly to their wallet via vault.donateOnBehalf(), creating differentiated yield for stakers vs non-stakers.
Formula (from Whitepaper)
Boost APY = Base APY + (Annual Protocol Revenue → FXRP) × (Your Locked SHIELD ÷ Total Locked SHIELD)Key Property: 100% of the boost allocation is distributed pro-rata to SHIELD lockers. No minting. No inflation. Pure revenue-share.
Architecture
Contract Interactions
┌─────────────────────────────────────────────────────────────────────────────┐
│ Revenue Distribution Flow │
│ │
│ ┌──────────────┐ deposit/withdraw fees ┌───────────────────┐ │
│ │ ShXRPVault │ ───────────────────────────► │ RevenueRouter │ │
│ │ (ERC-4626) │ │ (Fee Splitter) │ │
│ └──────┬───────┘ └─────────┬─────────┘ │
│ │ │ │
│ │ donateOnBehalf() │ distribute() │
│ │ (mints shXRP) │ │
│ │ ▼ │
│ │ ┌─────────────────────┐ │
│ │ │ Revenue Split │ │
│ │ │ ────────────────── │ │
│ │ │ 50% → Burn SHIELD │ │
│ │ │ 40% → FXRP → Boost │ │
│ │ │ 10% → Reserves │ │
│ │ └─────────┬─────────┘ │
│ │ │ │
│ │ │ distributeBoost() │
│ │ ▼ │
│ │ ┌─────────────────────┐ │
│ │ │ StakingBoost │ │
│ │ │ ─────────────────── │ │
│ │ │ rewardPerToken += │ │
│ │ │ fxrp/totalStaked │ │
│ └─────────────────────────────────────│ │ │
│ claim() │ SHIELD stakers │ │
│ └─────────────────────┘ │
└─────────────────────────────────────────────────────────────────────────────┘Circular Dependency Solution
StakingBoost and ShXRPVault have a mutual dependency:
StakingBoost needs vault address to call
donateOnBehalf()Vault needs StakingBoost address for access control on
donateOnBehalf()
Solution: Three-Step Deployment
Synthetix Reward Accumulator
The reward accumulator pattern enables O(1) gas complexity for reward distribution, regardless of the number of stakers.
Core State Variables
Mathematics
On Distribution (distributeBoost):
Computing Earned Rewards:
On Stake/Withdraw/Claim:
Gas Complexity
stake()
O(1)
Single storage update
withdraw()
O(1)
Single storage update
distributeBoost()
O(1)
Single division, no loops
claim()
O(1)
Fixed number of storage operations
earned()
O(1)
View function, no loops
Smart Contract Interface
StakingBoost.sol
ShXRPVault.sol Additions
RevenueRouter.sol (FXRP-Based)
Key Change (Dec 2025): RevenueRouter now accepts FXRP directly from vault fees (not wFLR). StakingBoost receives FXRP directly for reward distribution, eliminating an extra swap step.
Events
StakingBoost Events
ShXRPVault Events
Security Considerations
Access Control
distributeBoost()
onlyRevenueRouter
Prevents arbitrary reward injection
donateOnBehalf()
onlyStakingBoost
Prevents unauthorized share minting
setStakingBoost()
onlyOwner + one-time
Immutable after initial setup
setGlobalBoostCap()
onlyOwner
Governance control
setRevenueRouter()
onlyOwner
Governance control
recoverTokens()
onlyOwner
Emergency recovery (not staked tokens)
Reentrancy Protection
All state-changing functions use:
ReentrancyGuardfrom OpenZeppelinCEI (Checks-Effects-Interactions) pattern
Edge Cases
Zero Total Staked:
distributeBoost()with no stakers leaves FXRP in contract (no division by zero)Late Joiner: New stakers only earn from distributions after their stake
Partial Withdraw: Updates checkpoint before releasing tokens
Double Claim: Second claim returns 0 (rewards already claimed)
Test Coverage
test/boost-flow.ts (16 tests)
Tests 1-4: Reward Accumulator
distributeBoostupdatesrewardPerTokenStoredcorrectlyearned()returns correct proportional amountsMultiple distributions accumulate correctly
Late stakers only earn from post-stake distributions
Tests 5-8: Claim Integration
claim()mints shXRP to staker onlyNon-stakers have zero earned, receive nothing
Multiple stakers get proportional shares
Only StakingBoost can call
donateOnBehalf()
Tests 9-12: End-to-End
Complete flow: stake → distribute → claim → verify shXRP
getStakeInfo()returns correct pending rewardsclaimAndWithdraw()convenience function worksAdmin can update global boost cap
Security Tests
Zero totalStaked handled gracefully
Only owner can set RevenueRouter
setStakingBoost()is one-time onlyReentrancy protection verified
Correct events emitted
Excess token recovery works
Configuration Parameters
LOCK_PERIOD
30 days
Fixed
Minimum stake duration
globalBoostCapBps
2500
0-10000
Max boost % (25% default)
boostAllocationBps
4000
0-5000
% of revenue to boost (40%)
Upgrade Considerations
Current Design Limitations
One-Time Setter:
vault.setStakingBoost()cannot be changed after initial setupImmutable Vault: StakingBoost's vault reference is immutable
Upgrade Path
To upgrade StakingBoost:
Deploy new StakingBoost contract
Deploy new ShXRPVault contract
Wire them using the three-step process
Migrate user stakes via governance proposal
Future Improvements (Post-V1)
Governance-controlled StakingBoost setter on vault
Proxy pattern for upgradeable StakingBoost
Multi-asset boost support
Deployment Checklist
Last Updated: December 6, 2025
Last updated