Additional Rewards & Interception Management
What Are Additional Rewards?
Additional rewards are incentive tokens distributed outside the normal yield flow by protocols to encourage usage. These rewards are distributed via side channels and can significantly enhance user returns.
Common Examples
- AAVE: Receives stkAAVE rewards on deposits
- Compound: Receives COMP token incentives
- Morpho: Receives MORPHO reward tokens
- Ethena: Receives ENA token airdrops
- Liquidity Mining Programs: Various governance tokens
Key Characteristic
- Rewards don’t flow through the normal deposit/redeem lifecycle
- Distributed directly to vehicle addresses by external reward contracts
- Must be claimed and distributed separately from base yield
The Interceptor Standard
The Interceptor standard is Railnet’s solution for managing additional rewards distribution. It provides a declarative on-chain configuration that off-chain indexing services read to correctly distribute rewards.
How It Works
- Vehicle declares interception rules via
interceptions()view function - Off-chain indexers (e.g., reward distributors, airdrop systems) query these rules
- Rewards automatically routed according to declared rules
- No on-chain reward claiming needed - indexers handle distribution
Core Concepts
Interception Configuration:
struct Interception {
address asset; // Reward token (address(0) = all assets)
Recipient[] recipients; // Distribution rules
}
struct Recipient {
address target; // Where rewards go
uint256 shareBps; // Share in basis points (10000 = 100%)
uint256 chainId; // Target chain (0 = all chains)
} Key Features:
- Asset-specific rules: Different routing for different reward tokens
- Multi-recipient: Split rewards among multiple addresses
- Cross-chain support: Route rewards to different chains
- Pass-through: Unallocated rewards pass through to users
- Dynamic updates: Change rules without redeploying
Configuration Function
Update interception rules on any vehicle:
multiVehicle.setInterceptions(Interceptor.Interception[] calldata interceptions); Requirements:
- Caller must have
Roles.VEHICLE_SET_INTERCEPTIONSrole
Use Case 1: Pass-Through (100% to Users)
Goal: All additional rewards flow directly to end users without any operator intervention.
When to use
- Maximum user alignment
- Simplest configuration
- No operator reward management needed
- Common for community-first strategies
Configuration
// Empty interceptions = 100% pass-through
Interceptor.Interception[] memory interceptions = new Interceptor.Interception[](0);
multiVehicle.setInterceptions(interceptions); Result
- AAVE rewards → flow to user addresses directly
- COMP rewards → flow to user addresses directly
- Any other rewards → flow to user addresses directly
- No operator receives anything
Best for:
- DAOs with community governance
- Public goods strategies
- Maximum transparency setups
Use Case 2: Fee Collection (Split Distribution)
Goal: Operator takes a small fee (e.g., 5%) on additional rewards, users receive the rest (95%).
When to use
- Operator provides active management and deserves compensation
- Sustainable business model for professional operators
- Balance between operator incentives and user returns
- Common for institutional strategies
Configuration
// Take 5% fee on all additional rewards
Interceptor.Interception[] memory interceptions = new Interceptor.Interception[](1);
interceptions[0] = Interceptor.Interception({
asset: address(0), // All reward tokens
recipients: new Interceptor.Recipient[](1)
});
interceptions[0].recipients[0] = Interceptor.Recipient({
target: operatorFeeAddress, // Operator's address
shareBps: 500, // 5% = 500 basis points
chainId: 0 // All chains
});
multiVehicle.setInterceptions(interceptions); Asset-Specific Fee Example
// Different fees for different reward tokens
Interceptor.Interception[] memory interceptions = new Interceptor.Interception[](3);
// Default: 5% on all tokens
interceptions[0] = Interceptor.Interception({
asset: address(0),
recipients: new Interceptor.Recipient[](1)
});
interceptions[0].recipients[0] = Interceptor.Recipient({
target: operatorFeeAddress,
shareBps: 500, // 5%
chainId: 0
});
// AAVE rewards: 10% fee (higher because more valuable)
interceptions[1] = Interceptor.Interception({
asset: address(AAVE_TOKEN),
recipients: new Interceptor.Recipient[](1)
});
interceptions[1].recipients[0] = Interceptor.Recipient({
target: operatorFeeAddress,
shareBps: 1000, // 10%
chainId: 1 // Ethereum mainnet only
});
// COMP rewards: 3% fee (lower to incentivize Compound usage)
interceptions[2] = Interceptor.Interception({
asset: address(COMP_TOKEN),
recipients: new Interceptor.Recipient[](1)
});
interceptions[2].recipients[0] = Interceptor.Recipient({
target: operatorFeeAddress,
shareBps: 300, // 3%
chainId: 0
});
multiVehicle.setInterceptions(interceptions); Multi-Recipient Split Example
// Split fees between operator (3%) and DAO treasury (2%)
Interceptor.Interception[] memory interceptions = new Interceptor.Interception[](1);
interceptions[0] = Interceptor.Interception({
asset: address(0),
recipients: new Interceptor.Recipient[](2)
});
interceptions[0].recipients[0] = Interceptor.Recipient({
target: operatorAddress,
shareBps: 300, // 3% to operator
chainId: 0
});
interceptions[0].recipients[1] = Interceptor.Recipient({
target: daoTreasuryAddress,
shareBps: 200, // 2% to DAO
chainId: 0
});
// Remaining 95% passes through to users
multiVehicle.setInterceptions(interceptions); Result
- 1000 COMP earned → 50 COMP to operator, 950 COMP to users
- 500 AAVE earned → 25 AAVE to operator, 475 AAVE to users
- Operator can claim fees from their address
- Users receive proportional shares automatically
Best for:
- Professional strategy operators
- Sustainable long-term operations
- Transparent fee models
Use Case 3: Reinvestment Strategy (100% to Operator)
Goal: Operator intercepts 100% of additional rewards, sells them for base asset, and reinvests to increase share price for all holders.
When to use
- Maximize compounding efficiency
- Simplify user experience (no reward token claims)
- Operator has infrastructure to sell rewards efficiently
- Common for yield-focused strategies
Why This Works
- Calling
sectorAccountingEngine.deposit()without minting shares increasestotalAssets - Share price =
totalAssets / totalSupply - Higher
totalAssetswith sametotalSupply= higher share price - All existing holders benefit proportionally (like a dividend to all shareholders)
Configuration
// Intercept 100% of all additional rewards
Interceptor.Interception[] memory interceptions = new Interceptor.Interception[](1);
interceptions[0] = Interceptor.Interception({
asset: address(0), // All reward tokens
recipients: new Interceptor.Recipient[](1)
});
interceptions[0].recipients[0] = Interceptor.Recipient({
target: operatorRewardVault, // Operator-controlled address for reward management
shareBps: 10000, // 100% = 10000 basis points
chainId: 0 // All chains
});
multiVehicle.setInterceptions(interceptions); Operational Flow
1. Rewards accumulate at operatorRewardVault address
2. Operator monitors accumulated reward balances
3. Operator sells rewards for base asset (e.g., COMP → USDC, AAVE → USDC)
4. Operator reinvests by calling deposit() with allocate=false
// Operator workflow (off-chain bot or manual)
function reinvestRewards() external onlyOperator {
// 1. Sell accumulated rewards for base asset
uint256 compBalance = COMP.balanceOf(operatorRewardVault);
uint256 aaveBalance = AAVE.balanceOf(operatorRewardVault);
// Sell via DEX aggregator (e.g., 1inch, Paraswap)
uint256 usdcFromComp = sellTokens(COMP, USDC, compBalance);
uint256 usdcFromAave = sellTokens(AAVE, USDC, aaveBalance);
uint256 totalUsdc = usdcFromComp + usdcFromAave;
// 2. Approve and deposit to accounting engine
USDC.approve(address(sectorAccountingEngine), totalUsdc);
sectorAccountingEngine.deposit(
totalUsdc,
false // allocate=false: assets go to the AVAILABLE sector (idle)
);
// 3. Optionally allocate immediately (or batch later)
// ... manual allocation logic ...
} Important Role Setup
// Operator needs MULTI_VEHICLE_DEPOSIT role to call deposit()
// grantRole takes (role, account). A scoped grant is grantScopedRole.
accessControl.grantScopedRole(
Roles.MULTI_VEHICLE_DEPOSIT,
address(sectorAccountingEngine), // scope
operatorAddress // grantee
); Share Price Impact Example
Before Reinvestment:
Total assets: 1,000,000 USDC
Total supply: 1,000,000 shares
Share price: 1.0 USDC/share Rewards Earned & Sold:
10,000 COMP earned, sold for 50,000 USDC
5,000 AAVE earned, sold for 100,000 USDC
Total to reinvest: 150,000 USDC After Reinvestment:
Total assets: 1,150,000 USDC (1M + 150k)
Total supply: 1,000,000 shares (unchanged - no new minting)
Share price: 1.15 USDC/share (+15% from rewards) User A with 10,000 shares:
Before: 10,000 shares × $1.0 = $10,000 value
After: 10,000 shares × $1.15 = $11,500 value (+$1,500 gain) Result
- Users receive value via increased share price (not via reward token claims)
- Simpler UX (users don’t manage multiple reward tokens)
- Operator handles complexity of selling/reinvesting
- Transparent on-chain (
totalAssetsincreases visible to all)
Best for:
- Yield aggregators
- Single-asset strategies
- Professional operators with trading infrastructure
- Users who prefer simplicity over reward token exposure
Advanced Configuration Patterns
Pattern 1: Hybrid Fee + Reinvestment
Goal: Take small fee (2%) and reinvest the rest (98%).
Interceptor.Interception[] memory interceptions = new Interceptor.Interception[](1);
interceptions[0] = Interceptor.Interception({
asset: address(0),
recipients: new Interceptor.Recipient[](2)
});
interceptions[0].recipients[0] = Interceptor.Recipient({
target: operatorFeeAddress,
shareBps: 200, // 2% fee
chainId: 0
});
interceptions[0].recipients[1] = Interceptor.Recipient({
target: operatorRewardVault,
shareBps: 9800, // 98% reinvest
chainId: 0
});
// Remaining 0% passes through (full interception)
multiVehicle.setInterceptions(interceptions); Pattern 2: Governance Token Pass-Through, Others Reinvest
Goal: Let users keep governance tokens, operator reinvests yield tokens.
Interceptor.Interception[] memory interceptions = new Interceptor.Interception[](3);
// Default: Reinvest all
interceptions[0] = Interceptor.Interception({
asset: address(0),
recipients: new Interceptor.Recipient[](1)
});
interceptions[0].recipients[0] = Interceptor.Recipient({
target: operatorRewardVault,
shareBps: 10000, // 100%
chainId: 0
});
// COMP: Pass through (users vote in Compound governance)
interceptions[1] = Interceptor.Interception({
asset: address(COMP_TOKEN),
recipients: new Interceptor.Recipient[](0) // 0% interception = 100% pass-through
});
// AAVE: Pass through (users participate in AAVE governance)
interceptions[2] = Interceptor.Interception({
asset: address(AAVE_TOKEN),
recipients: new Interceptor.Recipient[](0) // 0% interception = 100% pass-through
});
multiVehicle.setInterceptions(interceptions); Pattern 3: Multi-Chain Reward Routing
Goal: Route mainnet rewards to operator, L2 rewards to users.
Interceptor.Interception[] memory interceptions = new Interceptor.Interception[](1);
interceptions[0] = Interceptor.Interception({
asset: address(0),
recipients: new Interceptor.Recipient[](2)
});
// Mainnet (chainId 1): Operator intercepts 100%
interceptions[0].recipients[0] = Interceptor.Recipient({
target: operatorRewardVault,
shareBps: 10000, // 100%
chainId: 1 // Mainnet
});
// All other chains: Pass through
interceptions[0].recipients[1] = Interceptor.Recipient({
target: address(0), // Dummy (will be ignored due to 0 shareBps)
shareBps: 0, // 0% = pass through
chainId: 0 // Wildcard for other chains
});
multiVehicle.setInterceptions(interceptions); Best Practices for Reward Management
1. Document Your Interception Strategy
Clearly communicate to users:
## Reward Distribution Policy
**Additional Rewards Handling:**
- AAVE/COMP/MORPHO governance tokens: 100% pass-through to users
- Other incentive tokens: 5% operator fee, 95% to users
- Operator fee funds ongoing strategy management and gas costs
**How to Claim:**
Users can claim their proportional rewards via [reward platform URL] 2. Regular Reinvestment Schedule
For reinvestment strategies:
- Daily: High-volume strategies, high-value rewards
- Weekly: Medium-volume strategies, moderate rewards
- Monthly: Low-volume strategies, small rewards
// Example: Automated weekly reinvestment
function weeklyReinvest() external {
require(block.timestamp >= lastReinvest + 7 days, "Too soon");
uint256 totalRewards = estimateRewardValue();
require(totalRewards >= minReinvestThreshold, "Rewards too small");
// Execute reinvestment
reinvestRewards();
lastReinvest = block.timestamp;
} 3. Gas-Efficient Reward Sales
Considerations:
- Use DEX aggregators (1inch, Paraswap) for best prices
- Batch multiple reward tokens in single transaction
- Set slippage limits to prevent sandwich attacks
- Consider gas costs vs reward value
// Only reinvest if economical
uint256 estimatedGasCost = 200_000 * tx.gasprice * nativeTokenPrice / 1e18;
uint256 rewardValue = estimateRewardValue();
if (rewardValue > estimatedGasCost * 3) { // 3x gas cost minimum
reinvestRewards();
} 4. Monitor Interception Effectiveness
Track metrics:
- Reward capture rate: % of distributed rewards actually received
- Reinvestment frequency: Time between reward sale and redeposit
- Share price impact: APY contribution from reinvested rewards
- Fee collection: Revenue from intercepted fees
5. Transparent Reporting
Provide visibility to users:
## Monthly Reward Report (March 2025)
**Rewards Earned:**
- 12,500 COMP tokens ($156,250 value)
- 8,200 AAVE tokens ($737,000 value)
- Total: $893,250
**Distribution:**
- Operator Fee (5%): $44,662
- Reinvested (95%): $848,588
- Share Price Impact: +0.85%
**Next Reinvestment:** April 1, 2025 6. Update Interceptions for New Rewards
When protocols launch new incentives:
// Protocol announces new REWARDS_TOKEN distribution
// Update interceptions to include it
// Fetch current interceptions
Interceptor.Interception[] memory current = multiVehicle.interceptions();
// Add new reward token configuration
Interceptor.Interception[] memory updated = new Interceptor.Interception[](current.length + 1);
// ... copy existing + add new ...
multiVehicle.setInterceptions(updated); 7. Emergency Fee Adjustment
In extreme market conditions:
// During bear market: Reduce fees to keep users
Interceptor.Interception[] memory interceptions = new Interceptor.Interception[](1);
interceptions[0].recipients[0].shareBps = 200; // Reduce from 5% to 2%
// During bull market: Increase fees (if governance approves)
interceptions[0].recipients[0].shareBps = 1000; // Increase to 10% Comparison of Strategies
| Strategy | User Experience | Operator Complexity | Share Price Impact | Governance Rights |
|---|---|---|---|---|
| Pass-Through | Users claim multiple tokens | None | None | Users keep tokens |
| Fee Collection | Users claim reduced amounts | Low (just receive fees) | None | Users keep 95%+ |
| Reinvestment | Simple (share price grows) | High (selling + redepositing) | Positive (+APY) | Operator controls |
Recommendation by Strategy Type
- Community DAO: Pass-Through (maximum alignment)
- Yield Aggregator: Reinvestment (maximize APY)
- Professional Manager: Fee Collection 3-10% (sustainable revenue)
- Hybrid Strategy: 2% fee + reinvest remaining (balanced incentives)