Documentation

Rewards Engine (Technicals)

Cliques’ rewards layer is the on-chain brain that tracks, allocates, and distributes yield to activated participants with precision, transparency, and built-in early-mover alpha.


Core Concepts

1. Normalized Reward Accounting

Rewards deposited from games are normalized to a fixed decimal base (9 decimals) so disparate SPL tokens can be handled uniformly. Deposits update a global counter (total_rewards_deposited_normalized), and the engine safely calculates per-share value using fixed-point math (via MULT) to avoid precision loss or overflow.

2. Vault & Share Architecture

  • Reward Vault State: Holds accumulated rewards-per-share (acc_rps), last known balance, and per-mint active share count (mint_shares).
  • Reward Vault Config: Tracks the creator, associated token mint, and total staked metadata.
  • First Activator Pot: A reserve of unallocated rewards that becomes the launch bonus for the first participant to activate a given token’s rewards (the “first activator bonus”). This creates strong early incentives—early activation gets all pending unallocated rewards before the distribution shifts to stake-weighted sharing.

3. Activation & Positioning

  • UserRewardPosition: Each user has a position with share, debt, and last claim timestamp.
  • Init Flow: On first activation (init_user_rewards), the vault syncs, first-activator bonuses are applied if appropriate (without contaminating their initial debt), and the user’s share is added to mint_shares while their debt is initialized to reflect accrual logic.
  • Debt Model: Debt ensures users only claim incremental earnings; owed = share * acc_rps / MULT, and pending = owed − debt.

4. Dynamic Distribution

  • When new rewards are deposited (deposit_game_rewards):
    • If no active users (mint_shares == 0), amount accumulates in the first activator pot.
    • Otherwise, acc_rps is bumped proportionally: reward × MULT / mint_shares.
    • Vault syncing logic (sync_vault) keeps acc_rps up to date when vault balance grows outside of planned flows.

5. Claiming & Cleanup

  • Claiming: Users call claim_user_rewards to realize pending rewards. Vault is synced, user share/debt is reconciled, and difference is transferred.
  • Registry: Each user has a registry tracking which token mints they’ve activated, ensuring batched queries and cleanup.
  • Cleanup: If no active users and cleanup period elapsed, unclaimed rewards can be burned (cleanup_unclaimed_rewards), resetting state and preventing stale accumulation.

6. First Activator Bonus

Designed as “alpha, not a bug”:

  • Grants the entire unallocated pot to the first real staker/activator for a token, giving enormous upside to early engagement while seeding usage.
  • Subsequent activations shift distribution to a stake-weighted model, preserving fairness once activity stabilizes.

7. Integration & Security

  • PDA-safe flows: Vaults and state are derived deterministically with seeds (e.g., CFG_SEED, VAULT_SEED, USER_SEED) to avoid ambiguity.
  • Authorization: Deposits require being from authorized actors (admin, game program, staking program, or valid PDAs).
  • Overflow guards: All arithmetic uses safe checked math; helpers like mul_div_u128 and normalization routines guard against precision loss and overflow.
  • Eventing: Cleanup, bonus grants, and share updates emit structured events for observability and indexing.

8. Rich Read APIs

  • Batch and single-token getters expose pending rewards, vault health, user share status, and global normalized stats, enabling front ends to feed real-time dashboards without heavy client logic.

Staking Engine (Technicals)

The staking layer is the leverage point—“taking a long position on giveaway activation.” It aligns capital with protocol growth, enforces commitment via lockups, and feeds the rewards layer for systematic yield.


Core Mechanics

1. Lockup & Commitment

  • Stake Lockup: When staking, tokens are locked for a minimum of 7 days before they can enter an unstake phase.
  • Unstake Lockup: After requesting unstake, there is an additional 7-day redemption delay before the user can claim their tokens.
    This two-step mechanism enforces time-based skin in the game, discouraging churn and aligning staker incentives with healthier long-term activation behavior.

2. Stake Info & Fee Vault

  • StakeInfo: Per-user state contains amount staked, reward debt, pending unstake amounts, timestamps for last stake, and lockup windows.
  • FeeVault: Global aggregator tracking total staked, accumulated reward-per-share (acc_reward_per_share), pending distributions, and global pending unstakes—serving as the source of truth for reward calculations.

3. Reward Debt / Accrual

  • Users accumulate reward entitlement via acc_reward_per_share.
  • On stake/unstake, pending rewards are settled (difference between accumulated and stored debt), then the stake amount and debt are updated.
  • This ensures users only receive what they have legitimately earned according to their share and the global rate.

4. Integration with Rewards Program

  • Dual coordination: After local stake updates, the system conditionally pushes updates into the rewards engine (CliquesRewards) using CPI:
    • If the user already has an activated reward position, global share counters are adjusted via update_global_shares.
    • The user’s per-token position is updated via update_user_position, ensuring upstream reward accounting reflects the current stake.
    • New stakers defer formal activation until they call init_user_rewards, avoiding premature inflation of global counters.
  • Stake-aware activation: This layered activation decouples raw staking from reward activation, giving builders control over when a staker “shows up” in yield calculus.

5. Unstaking & Claiming

  • Requesting Unstake: Validates lockup expiry, updates pending unstake, and imposes redemption wait.
  • Claiming Unstaked: After redemption window, tokens are returned; global share counters are updated only if the user was activated, avoiding stale impact.
  • Admin Force Unstake: Emergency migration path that returns full amounts (stake + pending) and adjusts share state, with CPI calls to reconcile downstream reward state.

6. Reward Distribution

  • Protocol-side rewards (e.g., SOL rewards) are injected into the fee vault.
  • Rewards expand the acc_reward_per_share based on total staked:
    increment = rewards × MULTIPLIER / total_staked
  • Stakers’ pending rewards are derived from their stake × acc_reward_per_share minus their debt.
  • Claiming settles pending rewards and updates debt to current accumulated state.

7. Economics & Safety

  • Fixed-point precision: Use of large multipliers prevents rounding drift during division-heavy reward math.
  • Sanity checks: All flows validate ownership, lockup constraints, and arithmetic bounds.
  • Paused state: Admin can pause the contract to halt new actions if needed (guardrail for abnormal conditions).
  • Fallback / Migration: Configurable fallback wallet and force-unstake paths support resilient operations in edge cases.

8. Event & State Visibility

  • Staking info, reward debt, pending amounts, and time-until-claimable are queryable via a dedicated getter that packages a user’s entire current position.
  • Updates to global shares or user positions get propagated to the rewards layer, maintaining eventual consistency without trusting off-chain reconcilers.