Validator Incentive Program
Performance-weighted bonuses with early adopter tiers, loyalty multipliers, and heartbeat-based uptime tracking.
Validator Incentive Program
The Validator Incentive Program rewards validators who participate in the AXIO block engine with performance-weighted bonuses. Early adopters receive enhanced tiers, and continuous uptime earns loyalty multipliers. Going offline for more than 24 hours resets your loyalty streak.
1. What It Does
The program manages a reward pool funded by the Reward Distributor's validator incentive channel. When rewards are distributed, each validator's share is computed based on four factors:
- Base reward -- the per-epoch allocation from the incentive pool
- Early adopter tier bonus -- +25% for first 20 validators, +15% for next 30
- Loyalty multiplier -- scales with consecutive uptime (up to 1.5x at 90 days)
- Performance score -- uptime and bundle inclusion rate (rolling 7-day average)
These four factors combine multiplicatively. A tier-1 validator with 90-day loyalty and perfect performance earns significantly more than a late joiner with inconsistent uptime.
2. Early Adopter Tiers
Tiers are assigned at registration time based on the order validators join the program:
| Tier | Validators | Bonus | Effect |
|---|---|---|---|
| Tier 1 | First 20 | +25% (2,500 bps) | Base reward multiplied by 1.25 |
| Tier 2 | Next 30 (21--50) | +15% (1,500 bps) | Base reward multiplied by 1.15 |
| No Tier | 51+ | 0% | Base reward only |
Tier assignment is permanent. If you are the 15th validator to register, you receive Tier 1 for the lifetime of your registration. Tiers cannot be changed or transferred.
3. Loyalty Multiplier
The loyalty multiplier rewards consistent uptime. It is based on consecutive_active_slots -- the number of continuous slots the validator has been active without a gap exceeding 24 hours.
| Consecutive Uptime | Multiplier | Value (bps) |
|---|---|---|
| < 30 days | 1.0x | 10,000 |
| 30 days | 1.1x | 11,000 |
| 60 days | 1.25x | 12,500 |
| 90 days | 1.5x | 15,000 |
24-Hour Offline Reset
If the gap between heartbeats or performance recordings exceeds 216,000 slots (~24 hours), the consecutive_active_slots counter resets to zero. The validator must build their loyalty streak from scratch.
gap = current_slot - last_active_slot
if gap > 216,000: // 24 hours
consecutive_active_slots = 0 // loyalty reset
else:
consecutive_active_slots += gap // loyalty growsThis reset applies in both the Heartbeat and RecordPerformance instructions.
4. Performance Scoring
Two metrics are tracked per validator with a rolling 7-day exponential moving average:
| Metric | Description | Update Formula |
|---|---|---|
uptime_bps | Uptime percentage (10,000 = 100%) | new = old * 0.9 + current * 0.1 |
inclusion_rate_bps | Bundle inclusion rate (10,000 = 100%) | new = old * 0.9 + current * 0.1 |
Both start at 10,000 (100%) when a validator registers and adjust with each RecordPerformance call.
5. Reward Calculation
The compute_reward function combines all four factors:
reward = base_reward
* (10,000 + tier_bonus_bps) / 10,000
* loyalty_multiplier / 10,000
* uptime_bps / 10,000
* inclusion_rate_bps / 10,000Example Calculations
Tier 1 validator, 90-day loyalty, perfect performance:
reward = 1,000,000
* (10,000 + 2,500) / 10,000 = 1,250,000
* 15,000 / 10,000 = 1,875,000
* 10,000 / 10,000 = 1,875,000
* 10,000 / 10,000 = 1,875,000 lamportsNo-tier validator, 45-day loyalty, 95% uptime, 80% inclusion:
reward = 1,000,000
* (10,000 + 0) / 10,000 = 1,000,000
* 11,000 / 10,000 = 1,100,000
* 9,500 / 10,000 = 1,045,000
* 8,000 / 10,000 = 836,000 lamportsThe tier-1 validator earns 2.24x the base reward. The late-joining validator with lower performance earns 0.84x.
6. PDA Derivation
| Account | Seeds | Description |
|---|---|---|
| IncentiveConfig | ["incentive_config"] | Global config, one per deployment |
| ValidatorRecord | ["validator_record", vote_account] | Per-validator record, keyed by vote account |
const [configPda] = PublicKey.findProgramAddressSync(
[Buffer.from("incentive_config")],
VALIDATOR_INCENTIVE_PROGRAM_ID
);
const [recordPda] = PublicKey.findProgramAddressSync(
[Buffer.from("validator_record"), voteAccountPubkey.toBuffer()],
VALIDATOR_INCENTIVE_PROGRAM_ID
);7. Instructions
7.1 Initialize
Create the incentive config with default tier and loyalty parameters. Admin only.
Parameters: None.
Accounts:
| # | Account | Signer | Writable | Description |
|---|---|---|---|---|
| 0 | Admin | Yes | No | Program admin |
| 1 | IncentiveConfig PDA | No | Yes | Config account (created) |
| 2 | Reward Pool | No | No | Pool account for incentive funds |
| 3 | System Program | No | No | System program |
Default values set at initialization:
- Tier 1: +25% bonus, first 20 validators
- Tier 2: +15% bonus, validators 21--50
- Loyalty: 1.1x at 30d, 1.25x at 60d, 1.5x at 90d
7.2 Register
Register a validator for the incentive program. The validator self-registers by signing with their identity key. Tier is assigned based on registration order.
Parameters:
| Parameter | Type | Description |
|---|---|---|
reward_destination | Pubkey | Account to receive incentive payouts |
Accounts:
| # | Account | Signer | Writable | Description |
|---|---|---|---|---|
| 0 | Validator Identity | Yes | No | Validator signing key |
| 1 | IncentiveConfig PDA | No | Yes | Config (counter incremented) |
| 2 | ValidatorRecord PDA | No | Yes | Record account (created) |
| 3 | Vote Account | No | No | Must be owned by vote program |
| 4 | System Program | No | No | System program |
| 5 | Clock Sysvar | No | No | For registration timestamp |
The vote account is verified to be owned by the Solana vote program. Initial performance metrics are set to 100% uptime and 100% inclusion rate.
7.3 RecordPerformance
Update a validator's performance metrics. Admin-only (authorized cranker). Also updates the loyalty streak and checks for 24-hour offline gaps.
Parameters:
| Parameter | Type | Description |
|---|---|---|
uptime_bps | u16 | Current uptime measurement (0--10,000) |
inclusion_rate_bps | u16 | Current bundle inclusion rate (0--10,000) |
bundles_included_delta | u64 | Bundles included since last recording |
tips_earned_delta | u64 | Tips earned since last recording (lamports) |
Accounts:
| # | Account | Signer | Writable | Description |
|---|---|---|---|---|
| 0 | Cranker (Admin) | Yes | No | Must be config admin |
| 1 | IncentiveConfig PDA | No | No | Config (read for admin check) |
| 2 | ValidatorRecord PDA | No | Yes | Record (updated) |
| 3 | Vote Account | No | No | For identity verification |
| 4 | Clock Sysvar | No | No | For gap detection |
Performance metrics use a rolling average: new = old * 0.9 + current * 0.1 (integer math: (old * 9 + current) / 10).
7.4 ClaimReward
Claim incentive rewards. Can be called by the admin (cranker distributing rewards) or by the validator directly.
Parameters:
| Parameter | Type | Description |
|---|---|---|
base_reward | u64 | Base reward amount for this epoch (lamports) |
Accounts:
| # | Account | Signer | Writable | Description |
|---|---|---|---|---|
| 0 | Caller | Yes | No | Admin or validator |
| 1 | IncentiveConfig PDA | No | Yes | Config (accounting updated) |
| 2 | ValidatorRecord PDA | No | Yes | Record (claim tracking updated) |
| 3 | Reward Pool | No | Yes | Source of reward funds |
| 4 | Reward Destination | No | Yes | Must match record's reward_destination |
| 5 | System Program | No | No | System program |
| 6 | Clock Sysvar | No | No | For claim timestamp |
The actual payout is compute_reward(base_reward) -- not the raw base amount. The reward pool must have sufficient balance above rent-exempt minimum. If the pool is underfunded, the instruction fails with InsufficientFunds.
7.5 Heartbeat
Record that a validator is online. Updates last_active_slot and consecutive_active_slots. Can be called by the validator or their reward destination.
Parameters: None.
Accounts:
| # | Account | Signer | Writable | Description |
|---|---|---|---|---|
| 0 | Signer | Yes | No | Validator identity or reward destination |
| 1 | ValidatorRecord PDA | No | Yes | Record (timestamps updated) |
| 2 | Clock Sysvar | No | No | For current slot |
If the gap since last_active_slot exceeds 24 hours (216,000 slots), consecutive_active_slots resets to 0 and a log message is emitted. Otherwise, the gap is added to the consecutive counter.
Validators should send heartbeats at least once per day to maintain their loyalty streak. The recommended cadence is every epoch or every few hours.
8. Validator Record State
ValidatorRecord (119 bytes)
| Field | Type | Description |
|---|---|---|
is_initialized | bool | Initialization flag |
vote_account | Pubkey | Validator's vote account |
reward_destination | Pubkey | Payout destination |
registered_slot | u64 | Registration timestamp |
last_active_slot | u64 | Last heartbeat/performance slot |
consecutive_active_slots | u64 | Loyalty streak counter |
uptime_bps | u16 | Rolling 7-day uptime (bps) |
inclusion_rate_bps | u16 | Rolling 7-day inclusion rate (bps) |
total_bundles_included | u64 | Lifetime bundles included |
total_tips_earned | u64 | Lifetime tips earned (lamports) |
tier | u8 | Early adopter tier (1, 2, or 0) |
total_incentive_claimed | u64 | Lifetime incentive payouts |
last_claim_slot | u64 | Last claim timestamp |
bump | u8 | PDA bump seed |
9. Heartbeat Strategy
To maintain the maximum 1.5x loyalty multiplier, validators should implement an automated heartbeat. A simple approach:
import { Connection, Keypair, PublicKey, Transaction } from "@solana/web3.js";
const HEARTBEAT_INTERVAL_SLOTS = 54_000; // ~6 hours
async function heartbeatLoop(
connection: Connection,
validatorKey: Keypair,
recordPda: PublicKey,
programId: PublicKey,
) {
while (true) {
const heartbeatIx = createHeartbeatInstruction({
signer: validatorKey.publicKey,
validatorRecord: recordPda,
programId,
});
const tx = new Transaction().add(heartbeatIx);
tx.feePayer = validatorKey.publicKey;
const sig = await connection.sendTransaction(tx, [validatorKey]);
await connection.confirmTransaction(sig);
console.log(`Heartbeat sent: ${sig}`);
// Wait ~6 hours worth of slots
await sleep(6 * 60 * 60 * 1000);
}
}Missing a single 24-hour window resets the entire loyalty streak. The heartbeat transaction costs minimal fees and should be treated as critical infrastructure.