Comment on page
Prime tokens
This technical article explains implementation details of the Venus Prime program. The overview of the Venus Prime program can be checked here.
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:
borrowUSDCap = toUSD(xvsBalanceOfUser * marketBorrowMultipler)
supplyUSDCap = toUSD(xvsBalanceOfUser * marketSupplyMultipler)
borrowUSD = toUSD(borrowTokens)
supplyUSD = toUSD(supplyTokens)
// borrow side
if (borrowUSD < borrowUSDCap) {
borrowQVL = borrowTokens
else {
borrowQVL = borrowTokens * borrowUSDCap/borrowUSD
}
// supply side
if (supplyUSD < supplyUSDCap) {
supplyQVL = supplyTokens
else {
supplyQVL = supplyTokens * supplyUSDCap/supplyUSD
}
return borrowQVL + supplyQVL
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 α:
User A:
Stake: 200
Supply/Borrow: 500
User B:
Stake: 100
Supply/Borrow: 1000
If alpha is 0.7 then:
user A score: 263.2764409
user B score: 199.5262315
If alpha is 0.3 then:
user A score: 379.8288965
user B score: 501.1872336
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.// every time accrueInterest is called. delta is interest per score
delta = totalIncomeToDistribute / sumOfMembersScore;
rewardIndex += delta;
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:
rewards = (rewardIndex - userRewardIndex) * scoreOfUser;
Then we will update the
userRewardIndex
(interests[market][account]
) to their current global values.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 |
---|---|
USDC | 19.24% |
USDT | 41.94% |
BTC | 17.70% |
ETH | 21.13% |
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:
- 19.24 CAKE should be converted to USDC
- 41.94 CAKE should be converted to USDT
- 17.70 CAKE should be converted to BTC
- 21.13 CAKE should be converted to ETH
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: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.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:
- 1.Fetch the income per block from PrimeLiquidityProvider
- 2.Calculate the user yearly income by multiplying (1) with blocks per year
- 3.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.
- 4.Calculate the capped supply and borrow of the user for the market
- 5.Calculate the ratio of allocation of the rewards based on capped supply and borrow of the user
- 6.Now borrow and supply APR of user can be calculated based on ratio of capped borrow and supply of the user.
Example:
- 1.Income per block 0.00003 USDT
- 2.Income per year is 10512000 blocks/year * 0.00003 = 315.36 USDT
- 3.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)
- 4.Assuming the user has the following positions:
- 1.borrow: 30 USDT. Let's say it's capped at 15 USDT, so we'll consider 15 USDT
- 2.supply: 10 USDT. Let's say it's also capped at 15 USDT, so we'll consider 10 USDT
- 5.Allocating the rewards (94.608 USDT), considering these capped versions, we would have:
- 1.borrow: 94.608 * 15/25 = 56.76 USDT
- 2.supply: 94.608 * 10/25 = 37.84 USDT
- 6.Calculating the APR with these allocations, we would have:
- 1.borrow: 56.76/30 = 1.89 = 189%
- 2.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.
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
contract - The
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 transfers - The
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 block - Anyone can send tokens to the
PrimeLiquidityProvider
contract - Only accounts authorized via ACM will be able to change the
tokenDistributionSpeeds
attribute - The
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.
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 modified 23d ago