Skip to content

Prime leaderboard

PrimeLeaderboard manages Prime V2 eligibility with time-weighted scoring. It tracks per-deposit timestamps for LIFO withdrawals and computes each user’s Prime Score. It is called by the XVSVault via the existing xvsUpdated() callback. Governance reads getEffectiveStakeBatch() off-chain, ranks users by Prime Score, and either sets a mint threshold on PrimeV2 (for permissionless minting) or calls PrimeV2.issue() / burn() directly.

Sets immutable XVS Vault references and disables initialization on the implementation.

constructor(address xvsVault_, address xvsVaultRewardToken_, uint256 xvsVaultPoolId_)

Address of XVSVault contract

address xvsVault

Reward token address in XVSVault

address xvsVaultRewardToken

Pool ID in XVSVault

uint256 xvsVaultPoolId

PrimeLeaderboard initializer. Initializes the default multiplier tiers: 30 days → 1.3x, 60 days → 1.6x, 90 days → 2.0x (cap).

function initialize(address accessControlManager_, uint256 loopsLimit_) external
NameTypeDescription
accessControlManager_addressAddress of AccessControlManager
loopsLimit_uint256Maximum number of loops allowed in a single transaction

Batch-seed existing stakers’ deposit data during migration. Idempotent: skips users with totalStaked[user] != 0 (already seeded). Caller must batch appropriately to avoid exceeding block gas limits.

function initializeStakers(address[] users, uint256[] amounts, uint64[] timestamps) external
NameTypeDescription
usersaddress[]Array of user addresses to initialize
amountsuint256[]Array of staked amounts (in XVS wei)
timestampsuint64[]Array of deposit timestamps
  • Emits StakerInitialized for each user successfully seeded
  • Controlled by ACM
  • Throw StakersAlreadyInitialized if finalizeInitialization was already called
  • Throw LengthMismatch if array lengths don’t match
  • Throw InvalidTimestamp if a seeded timestamp is zero or in the future

Finalize staker initialization, preventing further seeding. Must be called after all initializeStakers batches are complete.

function finalizeInitialization() external
  • Emits StakersInitializationFinalized
  • Controlled by ACM
  • Throw StakersAlreadyInitialized if already finalized

Called by the XVSVault (via primeToken.xvsUpdated) when a user’s stake changes. Reads the user’s current vault balance, diffs it against totalStaked, and records the appropriate deposit or LIFO withdrawal internally. Then forwards accrueInterestAndUpdateScore(user) to PrimeV2 if set.

function xvsUpdated(address user) external
NameTypeDescription
useraddressThe user whose stake changed
  • Emits DepositRecorded event on deposit
  • Emits WithdrawalRecorded event on withdrawal
  • Emits DepositsCompacted event if deposits are compacted
  • Only callable by XVSVault
  • Throw OnlyXVSVaultAllowed if caller is not XVSVault
  • Throw ZeroAddress if user address is zero

Get a user’s current Prime Score (time-weighted score)

function getEffectiveStake(address user) public view returns (uint256 effectiveStake)
NameTypeDescription
useraddressThe user’s address
NameTypeDescription
effectiveStakeuint256The user’s Prime Score (time-weighted)

Batch view to get Prime Scores for multiple users

function getEffectiveStakeBatch(address[] users) external view returns (uint256[] scores)
NameTypeDescription
usersaddress[]Array of user addresses
NameTypeDescription
scoresuint256[]Array of Prime Scores

Get a user’s total staked amount

function getTotalStaked(address user) external view returns (uint256)
NameTypeDescription
useraddressThe user’s address
NameTypeDescription
[0]uint256The total XVS staked

Get a user’s deposit stack

function getDeposits(address user) external view returns (struct IPrimeLeaderboard.Deposit[] deposits)
NameTypeDescription
useraddressThe user’s address
NameTypeDescription
depositsstruct IPrimeLeaderboard.Deposit[]Array of deposits (index 0 = oldest)

Get the number of deposit tranches for a user

function getDepositCount(address user) external view returns (uint256 count)
NameTypeDescription
useraddressThe user’s address
NameTypeDescription
countuint256Number of deposit tranches

Calculate the multiplier for a given holding duration

function getMultiplier(uint256 holdingDuration) external view returns (uint256 multiplier)
NameTypeDescription
holdingDurationuint256Duration in seconds
NameTypeDescription
multiplieruint256The multiplier (scaled by 1e18)

Get the multiplier tier configuration

function getMultiplierTiers() external view returns (uint256[] durations, uint256[] multipliers)
NameTypeDescription
durationsuint256[]Array of duration thresholds
multipliersuint256[]Array of multiplier values

Set the multiplier tiers. Durations and multipliers must be strictly ascending, and each multiplier must be ≥ the base multiplier (1e18).

function setMultiplierTiers(uint256[] durations, uint256[] multipliers) external
NameTypeDescription
durationsuint256[]Array of duration thresholds in seconds
multipliersuint256[]Array of multiplier values (scaled by 1e18)
  • Emits MultiplierTiersUpdated event
  • Controlled by ACM
  • Throw LengthMismatch if durations and multipliers arrays have different lengths
  • Throw InvalidValue if durations array is empty
  • Throw InvalidMultiplierTiers if tiers are not in ascending order or multipliers below base

Set the PrimeV2 contract address

function setPrimeV2(address primeV2_) external
NameTypeDescription
primeV2_addressAddress of PrimeV2 contract
  • Emits PrimeV2Set event
  • Controlled by ACM
  • Throw ZeroAddress if address is zero

Set the limit for the loops that can iterate to avoid DOS

function setMaxLoopsLimit(uint256 loopsLimit) external
NameTypeDescription
loopsLimituint256Limit for the max loops that can execute at a time
  • Emits MaxLoopsLimitUpdated event
  • Controlled by ACM