Prime token
PrimeV2
PrimeV2 is the Prime token contract with leaderboard-based distribution. Prime status is decided by the PrimeLeaderboard contract based on time-weighted XVS staking, and boosted rewards are distributed to Prime holders across supported markets.
Solidity API
WRAPPED_NATIVE_TOKEN
Address of wrapped native token
address WRAPPED_NATIVE_TOKENNATIVE_MARKET
Address of native market vToken
address NATIVE_MARKETxvsVault
Address of XVSVault contract
address xvsVaultxvsVaultRewardToken
Reward token address in XVSVault
xvsVaultPoolId
Pool ID in XVSVault
constructor
PrimeV2 constructor. Sets the immutable references above and disables further initialization of the implementation contract.
Parameters
wrappedNativeToken_
address
Address of wrapped native token
nativeMarket_
address
Address of native market
xvsVault_
address
Address of XVSVault contract
xvsVaultRewardToken_
address
Reward token address in XVSVault
xvsVaultPoolId_
uint256
Pool ID in XVSVault
timeBased_
bool
A boolean indicating whether the contract is based on time or block
blocksPerYear_
uint256
Total blocks per year
❌ Errors
Throw InvalidAddress if xvsVault_ or xvsVaultRewardToken_ is the zero address
initialize
PrimeV2 initializer
Parameters
alphaNumerator_
uint128
numerator of alpha. If alpha is 0.5 then numerator is 1
alphaDenominator_
uint128
denominator of alpha. If alpha is 0.5 then denominator is 2
accessControlManager_
address
Address of AccessControlManager
primeLiquidityProvider_
address
Address of PrimeLiquidityProvider
corePoolComptroller_
address
Address of core pool comptroller
oracle_
address
Address of Oracle
loopsLimit_
uint256
Maximum number of loops allowed in a single transaction
❌ Errors
Throw InvalidAddress if any of the address is zero
Throw InvalidAlphaArguments if alpha arguments are invalid
claimPrime
Mint a Prime token for a user in a permissionless way. Checks the user's Prime Score (their effective stake, read via PrimeLeaderboard.getEffectiveStake) against mintThreshold. Anyone can call this on behalf of an eligible user; no ACM required. Reverts while the contract is paused.
Parameters
user
address
User address to mint for
📅 Events
Emits Mint event on new token issuance
❌ Errors
Throw InvalidAddress if user is the zero address
Throw ScoreUpdateInProgress if a score update round is active
Throw UserAlreadyHasPrimeToken if user already has a token
Throw LeaderboardNotSet if primeLeaderboard address is not configured
Throw MintThresholdNotSet if mintThreshold is zero
Throw EligibilityBelowThreshold if user's Prime Score < mintThreshold
Throw InvalidLimit if mint limit would be exceeded
Throw MintWindowClosed if the minting deadline has passed
claimPrimeBatch
Mint Prime tokens for multiple users in a permissionless way. Non-holders below mintThreshold are skipped with a SkippedIneligibleUser event (not reverted). Existing Prime holders are silently skipped. Anyone can call this; no ACM required. Reverts while the contract is paused.
Parameters
users
address[]
Array of user addresses to mint for
📅 Events
Emits Mint event for each new token issuance
Emits SkippedIneligibleUser for each non-holder below threshold
❌ Errors
Throw ScoreUpdateInProgress if a score update round is active
Throw LeaderboardNotSet if primeLeaderboard address is not configured
Throw MintThresholdNotSet if mintThreshold is zero
Throw MintWindowClosed if the minting deadline has passed
Throw InvalidLimit if mint limit would be exceeded
Throw MaxLoopsLimitExceeded if the batch is larger than loopsLimit
issue
Issue a Prime token to a single user (admin function)
Parameters
user
address
User address
📅 Events
Emits Mint event on new token issuance
⛔️ Access Requirements
Controlled by ACM
❌ Errors
Throw InvalidAddress if user is zero address
Throw InvalidLimit if mint limit would be exceeded
Throw UserAlreadyHasPrimeToken if user already has a token
Throw ScoreUpdateInProgress if a score update round is active
issueBatch
Issue Prime tokens to multiple users (admin function)
Parameters
users
address[]
Array of user addresses
📅 Events
Emits Mint event on new token issuance
⛔️ Access Requirements
Controlled by ACM
❌ Errors
Throw InvalidAddress if any user in the batch is zero address
Throw InvalidLimit if mint limit would be exceeded
Throw ScoreUpdateInProgress if a score update round is active
Throw MaxLoopsLimitExceeded if the batch is larger than loopsLimit
burn
Burn a user's Prime token (admin function)
Parameters
user
address
User address
📅 Events
Emits Burn event
⛔️ Access Requirements
Controlled by ACM
❌ Errors
Throw UserHasNoPrimeToken if user has no prime token
Throw ScoreUpdateInProgress if a score update round is active
burnBatch
Burn Prime tokens for multiple users (admin function)
Parameters
users
address[]
Array of user addresses
📅 Events
Emits Burn event for each user
⛔️ Access Requirements
Controlled by ACM
❌ Errors
Throw ScoreUpdateInProgress if a score update round is active
Throw MaxLoopsLimitExceeded if the batch is larger than loopsLimit
isUserPrimeHolder
Check if a user has a Prime token
Parameters
user
address
User address
Return Values
[0]
bool
whether the user has a Prime token
claimInterest
Claim accrued interest for a market (to msg.sender). If the PrimeV2 balance is insufficient, funds are pulled from the PrimeLiquidityProvider in the same transaction; any remaining shortfall stays recorded as accrued and claimable later (partial claim, no revert). Residual accrued interest remains claimable even after a market is removed. Reverts while the contract is paused.
Parameters
vToken
address
Market address
Return Values
[0]
uint256
amount claimed
📅 Events
Emits InterestClaimed event
❌ Errors
Throw MarketNotSupported if market is not supported (only when the vToken is not a current Prime market — never added, or since removed — and the user has no residual accrued balance)
claimInterest
Claim accrued interest for a market to a specific address. Permissionless: anyone can trigger a claim on behalf of a user. Tokens are always sent to the user address, never to msg.sender. Same shortfall behavior as the single-argument overload: partial claim with the remainder kept as accrued, no revert. Reverts while the contract is paused.
Parameters
vToken
address
Market address
user
address
Recipient address
Return Values
[0]
uint256
amount claimed
📅 Events
Emits InterestClaimed event
❌ Errors
Throw MarketNotSupported if market is not supported (only when the vToken is not a current Prime market — never added, or since removed — and the user has no residual accrued balance)
accrueInterest
Accrue interest for a market. Intentionally not gated by the pause to ensure fair reward distribution during pauses.
Parameters
vToken
address
Market address
❌ Errors
Throw MarketNotSupported if market is not supported
accrueInterestAndUpdateScore
Accrue interest and update score for a user in a specific market. Called by the Comptroller hooks.
Parameters
user
address
User address
market
address
Market address
accrueInterestAndUpdateScore
Accrue interest and update score for a user across all markets. Called by PrimeLeaderboard when a user's XVS stake changes, so rewards are accrued at the old score before the score is recalculated.
Parameters
user
address
User address
❌ Errors
Throw OnlyPrimeLeaderboard if caller is not the PrimeLeaderboard contract
getPendingRewards
Get pending rewards for a user (accrues first)
Parameters
user
address
User address
Return Values
pendingRewards
struct PrimeV2StorageV1.PendingReward[]
Array of pending rewards per market
getPendingRewardsStatic
Get pending rewards for a user (view-only, does not accrue). Returns rewards based on the last accrued state without triggering new accrual.
Parameters
user
address
User address
Return Values
pendingRewards
struct PrimeV2StorageV1.PendingReward[]
Array of pending rewards per market
getLifetimeAccruedByMarket
Lifetime accrued rewards for many users in a single market. Pure view over the lifetimeAccrued field; intended for the off-chain cycle pipeline to snapshot per-(market, user) earnings without indexing events.
Parameters
market
address
vToken address
users
address[]
Array of user addresses
Return Values
amounts
uint256[]
Lifetime accrued amounts, indexed parallel to users
getLifetimeAccruedByUser
Lifetime accrued rewards for one user across many markets.
Parameters
user
address
User address
markets_
address[]
Array of vToken addresses
Return Values
amounts
uint256[]
Lifetime accrued amounts, indexed parallel to markets_
updateScores
Update scores for a batch of users. Intentionally not gated by the pause — the keeper must complete rounds even during pauses.
Parameters
users
address[]
Array of user addresses
📅 Events
Emits UserScoreUpdated event
❌ Errors
Throw NoScoreUpdatesRequired if no score updates are required
Throw MaxLoopsLimitExceeded if the batch is larger than loopsLimit
getAllMarkets
Get all Prime markets
Return Values
[0]
address[]
Array of market addresses
xvsBalanceOfUser
Get a user's XVS balance from the vault (net of pending withdrawals)
Parameters
user
address
User address
Return Values
[0]
uint256
User's XVS balance
addMarket
Add a market to Prime. Opens a new score-update round: all Prime holders' scores must be recomputed via updateScores before issuing, burning and claiming Prime tokens are unblocked.
Parameters
market
address
Market address
supplyMultiplier
uint256
Supply multiplier, scaled by 1e18
borrowMultiplier
uint256
Borrow multiplier, scaled by 1e18
📅 Events
Emits MarketAdded event
Emits IncompleteRoundDiscarded if a previous score-update round was still in progress
⛔️ Access Requirements
Controlled by ACM
❌ Errors
Throw MarketAlreadyExists if market already exists
Throw InvalidMultipliers if both multipliers are zero
Throw InvalidVToken if market is not listed
Throw AssetAlreadyExists if asset already has a market
Throw MaxLoopsLimitExceeded if listing this market would exceed loopsLimit
Throw UnsupportedUnderlyingDecimals if underlying token has decimals > 18
removeMarket
Remove a market from the Prime program
Parameters
market
address
Market vToken address to remove
📅 Events
Emits MarketRemoved event
⛔️ Access Requirements
Controlled by ACM
❌ Errors
Throw MarketNotSupported if market doesn't exist
Throw MarketHasActiveMembers if market still has members with scores
setLimit
Update mint limit (maximum Prime tokens)
Parameters
tokenLimit_
uint256
New token limit
📅 Events
Emits MintLimitUpdated event
⛔️ Access Requirements
Controlled by ACM
❌ Errors
Throw InvalidLimit if limit is less than current count
updateAlpha
Update alpha parameter. Opens a new score-update round: all Prime holders' scores must be recomputed via updateScores before issuing, burning and claiming Prime tokens are unblocked.
Parameters
alphaNumerator_
uint128
New alpha numerator
alphaDenominator_
uint128
New alpha denominator
📅 Events
Emits AlphaUpdated event
Emits IncompleteRoundDiscarded if a previous score-update round was still in progress
⛔️ Access Requirements
Controlled by ACM
❌ Errors
Throw InvalidAlphaArguments if alpha arguments are invalid
updateMultipliers
Update market multipliers. Opens a new score-update round: all Prime holders' scores must be recomputed via updateScores before issuing, burning and claiming Prime tokens are unblocked.
Parameters
market
address
Market address
supplyMultiplier
uint256
New supply multiplier
borrowMultiplier
uint256
New borrow multiplier
📅 Events
Emits MultiplierUpdated event
Emits IncompleteRoundDiscarded if a previous score-update round was still in progress
⛔️ Access Requirements
Controlled by ACM
❌ Errors
Throw MarketNotSupported if market is not supported
Throw InvalidMultipliers if both multipliers are zero
pause
Pause the contract
📅 Events
Emits Paused event
⛔️ Access Requirements
Controlled by ACM
unpause
Unpause the contract
📅 Events
Emits Unpaused event
⛔️ Access Requirements
Controlled by ACM
setMaxLoopsLimit
Set the max loops limit
Parameters
loopsLimit
uint256
New loops limit
📅 Events
Emits MaxLoopsLimitUpdated event
⛔️ Access Requirements
Controlled by ACM
setPrimeLeaderboard
Set the PrimeLeaderboard contract address used for permissionless mint eligibility
Parameters
primeLeaderboard_
address
Address of PrimeLeaderboard contract
📅 Events
Emits PrimeLeaderboardSet event
⛔️ Access Requirements
Controlled by ACM
❌ Errors
Throw InvalidAddress if address is zero
setMintThreshold
Set the minimum Prime Score threshold and minting deadline for permissionless Prime minting. Each epoch is one calendar month; governance typically calls this at end-of-epoch with the #500 user's Prime Score as the threshold. Pass mintThreshold_ = 0 to disable the permissionless minting window immediately. Pass mintDeadline_ = 0 for no expiry; otherwise the window auto-closes once block.timestamp exceeds it.
Parameters
mintThreshold_
uint256
New mint threshold (set to 0 to close the window)
mintDeadline_
uint256
Unix timestamp after which minting is closed (0 = no deadline)
📅 Events
Emits MintThresholdUpdated event
⛔️ Access Requirements
Controlled by ACM
❌ Errors
Throw InvalidDeadline if mintDeadline_ is non-zero and not strictly in the future
recordCycleSnapshot
Emit a cycle-start anchor event so the off-chain reward pipeline can recover cycle boundaries by indexing the event log. Operational hook, not a policy lever. Not idempotent on-chain: duplicate cycleIds emit duplicate events and must be de-duplicated by the indexer.
Parameters
cycleId
uint256
Identifier of the cycle whose start is being recorded
📅 Events
Emits CycleSnapshotRecorded(cycleId, block.number, block.timestamp)
⛔️ Access Requirements
Controlled by ACM — grant
recordCycleSnapshot(uint256)to a keeper EOA/bot, not the Timelock (cycles fire on a recurring schedule)
sweepUndistributed
Reclaim PLP income that accrued for a market while no scored members existed in it. Flushes any pending PLP delta via accrueInterest first, then transfers the recorded slice to the recipient.
Parameters
vToken
address
Market address whose underlying slice should be swept
to
address
Recipient of the swept tokens
📅 Events
Emits UndistributedSwept on a non-zero transfer
⛔️ Access Requirements
Controlled by ACM
❌ Errors
Throw InvalidAddress if to is the zero address
Note: for a removed Prime market the call does not revert; it returns without transferring once the market's undistributedReward slice is zero. Passing an address that is not a vToken at all reverts when resolving its underlying token.
Last updated

