Prime tokens
Only available on BNB chain
Overview
This technical article explains implementation details of the Venus Prime program. The overview of the Venus Prime program can be checked here.
Rewards
(Main explanation of Prime rewards)
Qualifiable supply and borrow amounts limits are set by the staked XVS limit and the market multiplier. The USD values of the tokens and the USD value of XVS will be taken into account to calculate these caps. The following pseudocode shows how is calculated considering the caps:
Significance of α
A higher α value increases the weight of stake contributions when determining rewards and decreases the weight of supply/borrow contributions. The value of α is between 0-1 (both excluded).
A default weight of 0.5 has been evaluated as a good ratio and is not likely to be changed. A higher value would only be needed if Venus wanted to attract more XVS stake from the Prime token holders at the expense of supply/borrow rewards.
Here is an example to show how the score is impacted based on the value of α:
Implementation of the rewards in solidity
rewardIndex
and sumOfMembersScore
are global variables in supported markets used when calculating rewards. sumOfMembersScore
represents the current sum of all the Prime token holders score and rewardIndex
needs to be updated whenever a user’s staked XVS or supply/borrow changes.
Whenever a user’s supply/borrow or XVS Vault balance changes we will recalculate the rewards accrued and add them to their account:
In Comptroller (specifically in the
PolicyFacet
), after executing any operation that could impact the Prime score or interest, we accrue the interest and update the score for the Prime user by callingaccrueInterestAndUpdateScore
.In the
XVSVault
, after depositing or requesting a withdrawal, the functionxvsUpdated
is invoked, to review the requirements of Prime holders.
This is how we will calculate the user rewards:
Then we will update the userRewardIndex
(interests[market][account]
) to their current global values.
Income collection and distribution
Every market in Venus (including Isolated Lending markets) contributes to the rewards that the Prime contract will distribute, following the protocol tokenomics. The following diagram shows the current implementation for the flow of funds.
Rewards will be distributed to Prime users only in USDT, USDC, BTC and ETH tokens. Other tokens will have to be converted to the tokens used for rewarding users in Prime. This conversion should follow a configurable (via VIP) distribution table, that initially will be:
Prime market | Distribution |
---|---|
USDT | 40% |
USDC | 30% |
ETH | 25% |
BTC | 5% |
For example:
The CAKE market generates 1,000 CAKE of total income
10% of the CAKE total income should be allocated to Prime → 100 CAKE (following the protocol tokenomics)
We should convert 100 CAKE to USDC, USDT, BTC and ETH, because in Prime the rewards are defined in these tokens
The conversion should follow the previous table:
40 CAKE should be converted to USDT
30 CAKE should be converted to USDC
25 CAKE should be converted to ETH
5 CAKE should be converted to BTC
Interest reserves (part of the protocol income) from Isolated Pools and the Core Pool markets are sent to the PSR (Protocol Share Reserve) contract. Based on the configuration, a percentage of income from all markers is reserved for Prime token holders. The interest reserves will be sent to the PSR periodically (currently every 24 hours, but this can be changed by the community via VIP).
The PSR has a function releaseFunds
that needs to be invoked to release the funds to the destination contracts. We have SingleTokenConverter contracts which receive income from the PSR and convert them to Prime supported reward tokens.
Each SingleTokenConverter
sends funds to PrimeLiquidityProvider
contract which releases the funds to Prime
contract. Distribution speeds for each of the reward token is configured in the PrimeLiquidityProvider
contract and based on those speeds Prime
distributes rewards.
If a user tries to claim their rewards and the Prime
contract doesn’t have enough funds, then we trigger the release of funds from PrimeLiquidityProvider
to Prime
contract in the same transaction i.e., in the claimInterest
function.
The following diagram shows the integration of the SingleTokenConverter
contracts with the Prime contracts:
More information about income collection and distribution can be found here.
Update cap multipliers and alpha
Market multipliers and alpha can be updated at anytime and then need to be propagated to all users. Changes will be gradually applied to users as they borrow/supply assets and their individual scores are recalculated. This strategy has limitations because the scores will be wrong in aggregate until all Prime users have interacted with the markets.
To mitigate this issue, Venus will supply a script that will use the permission-less function updateScores
to update the scores of all users. This script won’t pause market and Prime
contracts. The scores will need to be updated in multiple transactions because a single transaction will run out of gas trying to update all scores.
As markets won't be paused, there could be inconsistencies due to user supply/borrow transactions in between updating scores transactions. These inconsistencies will be very minor compared to letting it update gradually when users will borrow/supply.
There are two main objectives for creating this script:
If the Venus community wants to update all users scores when multipliers or alpha are changed then we have an immediate option.
After minting Prime tokens if the Venus community decides to add an existing market to the Prime token program then users scores need to be updated in order for them to being receiving rewards. The scores cannot be applied gradually in this case as the first Prime users in the market will receive disproportionally large rewards until the rest of the users in the market have their scores updated. A script to quickly update score for all users in a market will prevent this scenario.
There is a variable named totalScoreUpdatesRequired
to track how many score updates are pending. This is for tracking purposes and visible to the community.
Calculate APR associated with a Prime market and user
The goal is to offer a view function that allows the Venus UI to show an estimation of the APR associated with the Prime token and the borrow/supply position of a user.
The steps to perform this calculation are:
Fetch the income per block from PrimeLiquidityProvider
Calculate the user yearly income by multiplying (1) with blocks per year
Calculate the user score and total sum of scores for the market. This we can calculate the total rewards aloocation for the user for an year.
Calculate the capped supply and borrow of the user for the market
Calculate the ratio of allocation of the rewards based on capped supply and borrow of the user
Now borrow and supply APR of user can be calculated based on ratio of capped borrow and supply of the user.
Example:
Income per block 0.00003 USDT
Income per year is 10512000 blocks/year * 0.00003 = 315.36 USDT
Assuming the user score for USDT: 3, and the sum of scores for USDT: 10, then we would have 94.608 USDT (yearly income for this user, generated by Prime)
Assuming the user has the following positions:
borrow: 30 USDT. Let's say it's capped at 15 USDT, so we'll consider 15 USDT
supply: 10 USDT. Let's say it's also capped at 15 USDT, so we'll consider 10 USDT
Allocating the rewards (94.608 USDT), considering these capped versions, we would have:
borrow: 94.608 * 15/25 = 56.76 USDT
supply: 94.608 * 10/25 = 37.84 USDT
Calculating the APR with these allocations, we would have:
borrow: 56.76/30 = 1.89 = 189%
supply: 37.84/10 = 3.78 = 378%
Only the supply and borrow amounts below the cap generate Prime rewards. The supply and borrow amounts above the cap do not generate extra rewards. In the example, if the user supplies more USDT, they won't generate more rewards (because the supply amount to be considered is capped at 15 USDT). Therefore the supply APR would decrease if they supply more USDT.
Bootstrap liquidity for the Prime program
There will be bootstrap liquidity available for the Prime program. This liquidity:
should be uniformly distributed over a period of time, configurable via VIP
is defined by the tokens enabled for the Prime program
These requirements will be enforced with the PrimeLiquidityProvider
contract:
The
Prime
contract has a reference to thePrimeLiquidityProvider
contractThe
Prime
contract will transfer to itself the available liquidity from thePrimeLiquidityProvider
as soon as it’s needed when a user claims interests, to reduce the number of transfersThe
Prime
contract takes into account the tokens available in thePrimeLiquidityProvider
contract, when the interests are accrued and the estimated APR calculated
Regarding the PrimeLiquidityProvider
:
The
PrimeLiquidityProvider
contract maintains a speed per token (seetokenDistributionSpeeds
, with the number of tokens to release each block), and the needed indexes, to release the required funds per blockAnyone can send tokens to the
PrimeLiquidityProvider
contractOnly accounts authorized via ACM will be able to change the
tokenDistributionSpeeds
attributeThe
PrimeLiquidityProvider
provides a view function to get the available funds that could be transferred for a specific token, taking into account:the current block number
the speed associated with the token
the last time those tokens were released
The
PrimeLiquidityProvider
provides a function to transfer the available funds to thePrime
contract.
Pause claimInterest
claimInterest
There is a feature flag to enable/disable the function claimInterest
. When this feature is paused, no users will be able to invoke this function.
The OpenZeppelin PausableUpgradeable
contract is used. Only the claimInterest
function is under control of this pause mechanism.
Last updated