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

Operation
Gas Complexity
Notes

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

Function
Access
Reason

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:

  • ReentrancyGuard from OpenZeppelin

  • CEI (Checks-Effects-Interactions) pattern

Edge Cases

  1. Zero Total Staked: distributeBoost() with no stakers leaves FXRP in contract (no division by zero)

  2. Late Joiner: New stakers only earn from distributions after their stake

  3. Partial Withdraw: Updates checkpoint before releasing tokens

  4. Double Claim: Second claim returns 0 (rewards already claimed)


Test Coverage

test/boost-flow.ts (16 tests)

Tests 1-4: Reward Accumulator

  • distributeBoost updates rewardPerTokenStored correctly

  • earned() returns correct proportional amounts

  • Multiple distributions accumulate correctly

  • Late stakers only earn from post-stake distributions

Tests 5-8: Claim Integration

  • claim() mints shXRP to staker only

  • Non-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 rewards

  • claimAndWithdraw() convenience function works

  • Admin can update global boost cap

Security Tests

  • Zero totalStaked handled gracefully

  • Only owner can set RevenueRouter

  • setStakingBoost() is one-time only

  • Reentrancy protection verified

  • Correct events emitted

  • Excess token recovery works


Configuration Parameters

Parameter
Default
Range
Description

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

  1. One-Time Setter: vault.setStakingBoost() cannot be changed after initial setup

  2. Immutable Vault: StakingBoost's vault reference is immutable

Upgrade Path

To upgrade StakingBoost:

  1. Deploy new StakingBoost contract

  2. Deploy new ShXRPVault contract

  3. Wire them using the three-step process

  4. 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