Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Launched in 2020, Venus Protocol (a.k.a. “Venus”) pushed the edges of decentralized finance through its composition of two pre-existing solutions and deployment on BNB chain, lowering the barrier to entry for millions of new users around the globe. By combining the stablecoin minting facility introduced by Maker and algorithmic money markets developed by Compound, Venus simplified the user experience and provided core capabilities that enabled decentralized finance to flourish in a single application. As a result, Venus found remarkable success and quickly rose to be one of the most widely used decentralized applications in web3.
The latest iteration of Venus Protocol, the most trusted and battle-tested lending and borrowing protocol on the BNB Chain, builds on prior successes and lessons learned to improve in 3 key areas:
Risk management
Decentralization
User experience
In doing so, Venus continues to push the boundaries of what's possible within the realm of decentralized finance.
Venus Protocol is a trusted decentralized finance lending and borrowing protocol that's deployed on the BNB Chain. Initially launched in 2020, it combines the stablecoin minting facility of Maker and the algorithmic money markets developed by Compound, providing a simplified user experience and core capabilities in a single application.
Interacting with Venus V4 is straightforward. Supply your chosen asset and the amount to start earning interest. Additionally, once you supply assets, you can also borrow against them. Any interest earned from supplying assets can help offset the interest you accrue when borrowing.
Your supplied funds are stored in a smart contract on the BNB Chain. The contract's code is public, open-source, and has been formally verified and audited by external auditors. You can withdraw your funds on demand or receive Venus Tokens (vTokens) representing your stake. vTokens are as freely tradable as any other cryptographic asset on BNB Chain.
Transactions on the Venus V4 protocol require BNB Chain fees, which depend on network congestion and the complexity of the transaction.
No platform can be considered entirely risk-free. Risks associated with Venus V4 include smart contract risk and liquidation risk. However, every possible step has been taken to minimize these risks, including making the protocol code public and conducting thorough audits.
Venus Protocol focuses on improving three main areas:
Risk Management: Prioritizing the risk management , Venus introduces new features like Isolated Pools and more sophisticated risk parameters.
Decentralization: The governance model has been enhanced by introducing fast-track VIPs, role-based access control, and a fine-grained pause mechanism.
User Experience: The latest version offers an enhanced user interface, a more effective reward system, and isolated lending. Future releases for V4 will feature stable rate borrowing and the Venus Prime Soulbound Token, all aimed at providing a smooth user experience.
The Resilient Price Oracle introduced in Venus V4 fetches prices from multiple sources and validates them, providing a more reliable price indicator and protecting against price manipulations. It supports the integration of new price oracles and allows enabling and disabling price oracles per token.
Isolated Pools are a new feature in Venus V4, designed to overcome the limitations of a single core pool. Each Isolated Pool is an independent collection of assets with custom risk management configurations. This setup allows users to better manage their risk and earn yield, while also preventing failures in one market from impacting others.
In Venus V4, a risk fund is maintained for each pool. A percentage of the protocol's revenue is deposited into this fund, aiming to counterbalance bad debt and prevent potential market insolvencies.
Venus V4 features a new governance model that introduces fast-track Venus Improvement Proposals (VIPs), role-based access control, and a fine-grained pause mechanism. This new model allows for more agile and accurate decision-making, ensuring the protocol remains competitive and secure.
To be released
Stable Rate Borrowing is a distinctive feature of the Venus Protocol that provides an alternative to variable interest rate loans. Stable-rate loans set their interest rates at issuance until a rebalancing event occurs. This approach shields users who borrow at a stable rate from being affected by individual actions of other users and large fluctuations in the market.
The interest rates for stable and variable rate borrowing are determined based on several calculations involving parameters such as utilization rate, stable loan adoption rate, and total supply. For instance, the stable interest rate will include a base premium plus an additional premium that depends on the stable loan adoption rate.
The model parameters involved in the calculations include slopes for the variable interest rate, a base rate per block, the optimal utilization rate (kink), a reserve factor, base premium, and other parameters related to stable loan borrowing.
The fixed rate of a stable loan persists until certain rebalancing conditions are met. These conditions involve the utilization rate and the comparison between the market average borrow rate and the variable borrow rate. The stable rate provides predictability for the borrower but may come at a cost of higher interest rates compared to the variable rate.
The Venus Protocol introduces E-Mode (Efficiency Mode) to the BNB Chain Core Pool, a new feature designed to boost capital efficiency for specific asset pools, such as stablecoins or ETH-based tokens. It also aims to isolate risk within these pools while reusing liquidity from the Core Pool.
E-Mode allows users to activate specialized pools within the Core Pool, each with customized risk settings. By selecting an E-Mode pool, your eligible assets follow optimized parameters for collateral factor (CF) and liquidation threshold (LT), which are increased, while the liquidation incentive (LI) is decreased, making borrowing more efficient and cost-effective while keeping risks contained.
To support E-Mode, the Core Pool itself has been enhanced with new risk mechanics:
Liquidation Threshold (LT) Support – Similar to isolated pools, LT is now used to determine liquidation conditions, separate from CF.
Per-Market Liquidation Incentive (LI) – LI is no longer global; each market has its own incentive, configurable by Governance.
User-Specific Risk Factors – Effective CF, LT, and LI now depend on the user’s selected E-Mode pool, giving each user a tailored borrowing and collateral profile.
E-Mode operates as a lightweight overlay on the Core Pool, enabling per-user risk management without moving funds to separate pools.
Core Pool (poolId = 0): The default pool for all users. Supports per-market LIs and LT, even for non-E-Mode users.
E-Mode Pools (poolId > 0): Each pool defines a set of assets (e.g., Stablecoin Pool, ETH Pool) with customized CF, LT, and LI for each asset in the pool. Users select a pool to activate its risk parameters.
Pool-Market: Markets are tracked per pool, allowing pool-specific overrides while preserving Core Pool compatibility.
This architecture ensures flexibility, backward compatibility, and gas efficiency, while giving users higher borrowing efficiency and better risk isolation.
No Action Needed – Users remain in the Core Pool by default. Their positions continue to function normally without switching to E-Mode.
Optional Upgrade – By entering an E-Mode pool, your account will use its risk settings for approved assets.
Note: Improved Risk Mechanics – Even without switching, Core Pool users now benefit from per-market liquidation incentives (LI) and liquidation threshold (LT) support, making liquidation calculations and account health evaluations more precise.
E-Mode introduces more precision and flexibility for liquidators in the Core Pool:
Per-Market Liquidation Incentives – Liquidation incentives (LI) are now set on a per-market basis rather than being global. Before liquidating, liquidators should check the LI for each asset. If a user is in an E-Mode pool and uses collateral that isn’t enabled in that pool, the LI for that asset can be zero.
Liquidation Thresholds (LT) – LT now determines when accounts can be liquidated, replacing the older CF-based check for liquidations.
User-Specific Risk Factors – Effective CF, LT, and LI can vary per user depending on their E-Mode pool, making liquidation decisions more targeted and strategic.
This gives liquidators smarter targeting, higher transparency, and better reward optimization across markets.
Default in the Core Pool All users start in the Core Pool and can continue their positions normally.
Select an E-Mode Pool Explore available pools (e.g., Stablecoin) via the Venus App or Venus Lens.
Check Your Borrows Borrowed assets must be approved in the selected pool. Repay any disallowed assets first.
Check Core Pool Fallback Each E-Mode pool has a flag allowCorePoolFallback
For a detailed technical explanation, including implementation and user examples, check out the .
The Venus Reward Distributor allows for the configuration and management of rewards for lenders and borrowers, dependent on the user's activity within the associated markets. The addition of one or more reward distributors to a pool is facilitated through the addRewardsDistributor feature, enhancing the protocol's capability to customize distribution rates on a per-market basis.
In the Venus Protocol V4, the reward system has been upgraded to allow for rewards per market and lending activity, as well as the support for multiple reward tokens. This revamp serves to provide further incentives and yield opportunities for users.
Venus Protocol offers variable interest rates for markets using two different models: the Jump Rate Model and the Whitepaper Rate Model. Each market operates under one of these models with specifically set risk parameters at the market's inception. Notably, the community can update these parameters through the Governance process. Moreover, some markets feature a stable rate, introduced in Venus V4.
Head to the Venus dApp () and ensure you are connected to the BNB Chain.
Click on the “E-mode” icon to view current e-mode groups.
Make sure your wallet is connected.
Click “Enable” in the e-mode group you would like to enable. Just like that, enjoy increased LTV on the assets listed in that e-mode group!
Vaults within Venus Protocol provide a secure and efficient mechanism for users to stake their tokens, whether XVS or VAI, and earn passive income. This staking process allows users to actively participate in and contribute to the stability and security of the Venus ecosystem, while maximizing returns on their holdings.
Staking in XVS Vault
Navigate to the Venus app (app.venus.io) and connect your BNB Chain Wallet or other supported wallet apps.
On the left side of the screen, click on the 'Vault' tab.
Protocol revenues, sourced from reserve interests and liquidations, are processed through the module. Once allocated, these underlying tokens are subsequently sent to various Token Converters, each transforming the received income into specific tokens, automating and optimizing this conversion process.
XVS is the native token of Venus Protocol and serves as its governance token. By staking XVS tokens in the vault, users gain voting power proportionate to the amount staked. This voting power enables them to participate in the voting process for Venus Improvement Proposals (VIPs), thereby playing a critical role in the development and evolution of the Venus Protocol.
Furthermore, users who stake their XVS tokens in the vault have the potential to earn yield, creating an incentive for participation in the Venus governance process. This aligns the interests of XVS holders with the overall health and success of the Venus Protocol.
This contract contains the functions defined in the different facets of the Diamond, plus the getters to the public variables. This contract cannot be deployed, due to its size. Its main purpose is to allow the easy generation of an ABI and the typechain to interact with the Unitroller contract in a simple way
Isolated Pools are made up of separate collections of assets with tailored risk management configurations. This design offers users broader opportunities to manage risk and allocate assets to earn yield. Moreover, it prevents hypothetical failures from affecting the liquidity of the entire protocol as they are confined to isolated markets.
Isolated Pools also offer custom rewards for each market in the pool, incentivizing users accordingly.
The 2-Kink Interest Rate Curve introduces a new model to optimize interest rates and utilization across Venus protocol markets. By incorporating two separate "kinks", this model aims to provide more flexible control over market dynamics, enhancing both the predictability and efficiency of APYs (Annual Percentage Yields) for borrowers and suppliers.
This design helps reduce the volatility of APYs during periods of high demand, such as during launchpool events, and encourages greater participation by offering more predictable costs and returns.
The Rewards Distributor system is centered around the RewardsDistributor contract. This contract maintains the functionality to configure, track and distribute rewards to users based on their borrow and supply activities within the protocol. Upon initialization, each RewardsDistributor proxy is associated with a specific reward token and Comptroller, from which point the reward token can be disseminated to users that supply or borrow in the corresponding pool.
Users have a range of possible interactions with the Reward Distributor:
Supply: Users can supply assets and earn rewards based on the supply speeds set for the reward token.
Borrow: Users can borrow assets and earn rewards according to the configured borrow speed of the reward token.
Claim Rewards: Users can claim their accrued reward tokens for individual markets, a feature that significantly reduces gas fees and streamlines the reward claiming process.
A new screen will display two options: XVS and VAI vaults. Select the 'XVS' vault.
Once you select the XVS vault, a new interface will show. Click the 'Stake' button.
A pop-up will appear asking for the amount of XVS you want to stake. Input the desired amount and confirm.
After entering the amount, a prompt will ask for the transaction's confirmation in your wallet. Confirm this.
Once you've staked your XVS tokens, the interface will show the staked amount, your potential rewards, and other vault statistics.
Staking in VAI Vault
Follow the same steps as above to access the 'Vault' tab in the Venus app.
This time, select the 'VAI' vault.
Upon clicking on the 'VAI' vault, you'll see the option to 'Stake'.
Enter the amount of VAI you'd like to stake and confirm the staking action.
Just like with the XVS vault, you'll need to confirm the transaction in your wallet.
After staking, the interface will show the staked amount, potential rewards, and other relevant statistics related to the VAI vault.
The upcoming Venus Prime program adds a new dimension to the utility of XVS tokens. As Venus Protocol continues to innovate:
The launch of Venus Prime will provide opportunities for additional yield to committed users, using protocol's revenue instead of just relying on the token supply.
The program will introduce unique, non-transferable tokens for eligible participants, adding a new layer of user interaction.
These developments further emphasize the importance of the XVS token in the ecosystem, providing holders with more ways to earn and participate in the protocol's future.
User Pool Tracking: Each user is associated with exactly one pool at a time via userPoolId. Switching pools updates this mapping and triggers the relevant risk rules.
Enter E-Mode
Eligible assets follow E-Mode risk settings, while the behavior of assets not included in the E-Mode pool depends on the allowCorePoolFallback flag.
Enjoy Higher Efficiency Borrow and manage positions with optimized collateral and liquidation rules.
Simulate interest rate curve fo a specific interest rate model given a reference borrow amount and reserve factor
Parameters
referenceAmountInWei
uint256
Borrow amount to use in simulation
interestRateModel
address
Address for interest rate model to simulate
reserveFactorMantissa
uint256
Reserve Factor to use in simulation
Return Values
[0]
struct InterestRateModelLens.SimulationResponse
struct SimulationResponse {
uint256[] borrowSimulation;
uint256[] supplySimulation;
}function getSimulationResponse(uint256 referenceAmountInWei, address interestRateModel, uint256 reserveFactorMantissa) external view returns (struct InterestRateModelLens.SimulationResponse)The Jump Rate Model uses the following formulas to calculate the interest:
For Borrow rate:
And, for Supply rate:
Where,
The borrow rate employs different formulas when the utilization rate falls into two distinct ranges:
If u < kink:
If u > kink:
Model Parameters
a1: Variable interest rate slope1.
a2: Variable interest rate slope2.
b: Base rate per block (baseRatePerYear / blocksPerYear).
kink: Optimal utilization rate, at which the variable interest rate slope shifts from slope1 to slope2.
reserve_factor: Part of interest income withdrawn from the protocol, i.e., not distributed to suppliers.
The utilization rate (u) is defined as:
Where:
borrows: Amount of borrows in the market, in terms of the underlying asset, excluding bad debt.
cash: Total amount of the underlying asset owned by the market at a specific time.
reserves: Amount of the underlying asset owned by the market but unavailable for borrowers or suppliers, reserved for various uses defined by the protocol's tokenomics.
bad_debt: After liquidators repay as much debt as possible, reducing collateral to a minimal amount, the remaining debt is tagged as bad debt. Bad debt doesn’t accrue interest.
The Whitepaper Rate Model is simpler, where the borrow rate depends linearly on the utilization:
For Borrow rate:
For Supply rate:
Where,
When e-mode is enabled, you can only borrow assets listed in that group. These assets will be marked in the “borrowable” column for your reference.
Currently, only the Stablecoins e-mode group is enabled. We plan to release BTC and BNB e-mode groups within the next few weeks. Keep following us on X or join our Telegram and Discord groups to be the first to know!


The Token Converter works on four key principles:
Distributed and Autonomous: No centralized management or human interactions needed, ensuring a secure and seamless conversion process.
Efficient: The system is designed to maximize the amount of specific tokens we receive while protecting against potential risks like sandwich attacks.
Streaming: The conversions occur continually, without waiting for scheduled intervals.
Transparent: All conversions are publicly recorded in the blockchain, reinforcing our commitment to transparency.
Venus Protocol will offer discounts to incentivize these conversions. This incentive will create arbitrage opportunities in the market, and external agents can potentially gain from these opportunities.
Before the Token Converter, token conversions were not as seamless and efficient. Venus Protocol needed a system that could constantly convert the received income into specific tokens, with no room for errors or delays.
The Token Converter streamlines the conversion process by allowing key elements in the Venus Protocol, such as the XVSVaultConverter and RiskFundConverter, to autonomously offer token conversions. This solution follows the rules of distributed and autonomous systems, removing the need for human intervention.
Moreover, the introduction of incentives through discounts encourages external agents to take part in the conversion process, thus creating a win-win situation for all. This is in line with the vision of decentralization, where processes are not only transparent but also rewarding for participants.
The dashed lines represent transactions initiated by external agents (VIP’s, scripts, arbitrage bots, etc.), and the solid lines represent transfers of funds.
Executes a flashLoan operation with the requested assets
Transfers the specified assets to the receiver contract and handles repayment. Supports both full repayment and partial repayment where unpaid amounts become ongoing debt positions.
Parameters
onBehalf
address payable
The address of the user whose debt position will be created in case of partial repayment
receiver
address payable
The address of the contract that will receive the flashLoan amount and execute the operation
vTokens
VToken[]
The addresses of the vToken assets to be loaned
underlyingAmounts
uint256[]
The amounts of each underlying assets to be loaned
The Isolated Pools system is based on the PoolRegistry contract. It maintains a directory of isolated lending pools, allows the creation and registration of new pools, and offers getter methods to fetch pool details.
To add a new market to an existing lending pool, the PoolRegistry deploys a JumpRateModelV2 or a WhitePaperInterestRateModel contract, deploying the upgradable VToken for the market before gaining the approval of the market's Comptroller.
Users can perform the following actions on any market in a pool:
Deposit: Users can deposit an asset, receiving vTokens that correspond to the liquidity deposited. These vTokens accrue interest until they are burned on redeem or liquidated.
Borrow: Users can borrow assets, in exchange for locked collateral.
Redeem: Users can redeem vTokens for the underlying asset based on the exchange rate.
Repay Borrow: Users can repay the borrowed asset and accrued interest.
The 2-Kink IR Curve is built into the Interest Rate Models used by Venus markets. It allows for two distinct kinks in the curve, separating the initial utilization phase from the high-utilization phase. This enables better control over borrow and supply rates as utilization increases.
The curve is defined by:
Kink: A utilization threshold where the interest rate curve’s slope changes.
Multiplier: The rate at which the interest rate increases before and after the kink, controlling the curve’s steepness.
Base Rate: A predefined APY jump at the start of the curve or any kink, providing a step-up in interest rates as utilization increases.
By using two kinks and base rates, the protocol can more accurately balance supply and borrow demand, especially in markets with varying demand cycles like launchpools.
More Predictable APYs: By introducing a second kink, the interest rate curve allows for smoother transitions in APYs as market utilization changes.
Increased Participation: Both borrowers and suppliers benefit from more predictable rates, encouraging greater market participation even during high-demand periods.
Optimized Market Efficiency: By reducing sharp spikes in borrow APYs, the 2-Kink IR Curve improves the overall efficiency of Venus markets, ensuring better control over utilization rates and protocol reserves.
Open the Venus app and connect your wallet.
Make sure you are connected to the ZKsync network. If you are not, switch your wallet’s network to ZKsync.
In this example, we will approve the use of the ZK market as collateral.
Navigate to the ZK market on Venus.
Click on "Collateral" to enable the use of this market as collateral.
Instead of sending a typical transaction, you will be prompted to sign a message. This step authorizes Zyfi to pay for the gas fee of the transaction on your behalf.
Sign the message in your wallet. The gas for the transaction will be covered by Zyfi Paymaster, so you don’t need ETH in your wallet.
Once signed, Zyfi processes the transaction, and it is sent to the ZKsync blockchain with gas paid through their vault.
You can verify the transaction on the ZKsync Explorer. The transaction will display Zyfi as the Paymaster, covering the gas fees.
Venus Protocol's governance relies on participants locking XVS tokens into a vault to acquire voting power for Venus Improvement Proposals (VIPs). A 48-hour timelock period after voting ensures transparency and protection against malicious proposals. However, the initial model's rigidity prompted the introduction of a new governance structure in Venus V4. This upgraded model incorporates fast-track VIPs, role-based access control, and a fine-grained pause mechanism for enhanced flexibility and timely adjustments.
Venus V4 introduces an improved governance structure with the following components:
Fast-track and Critical VIPs
Role-based access control
Fine-grained pause
Fast-track and Critical Improvement Proposals
Venus Governance has now categorized VIPs into three types: Normal, Fast-track, and Critical.
Normal VIPs encompass significant updates like contract upgrades or changes in access controls.
Fast-track VIPs deal with risk parameter adjustments such as interest rates or collateral factors.
Critical VIPs are utilized during emergencies demanding an immediate reaction.
Each VIP type has its unique proposal threshold, timelock, and voting periods, reflecting the potential risk and impact of the proposed changes.
The initial voting and delay periods for these types are as follows:
Normal VIP: 24 hour voting period + 48 hour delay (+ 48 hour delay to execute commands on networks other than BNB Chain)
Fast-track VIP: 24 hour voting period + 6 hour delay (+ 6 hour delay to execute commands on networks other than BNB Chain)
Critical VIP: 6 hour voting period + 1 hour delay (+ 1 hour delay to execute commands on networks other than BNB Chain)
Role-based Access Control
Venus V4 employs a separate Access Control Manager contract that validates access permissions rather than merely verifying the caller as an "admin". This allows certain actions to bypass voting, enabling them to take the fast-track or critical route, or even to be executed directly through a multisig by guardians. It can be particularly useful for implementing borrowing and supply caps, pausing specific market actions, or responding to rapid market fluctuations.
Fine-grained Pause
A fine-grained pause mechanism allows the pause guardian to individually halt any action on any market. Unlike previous versions, where the entire protocol was paused for damage control or protection against attacks, the updated model enables guardians to pause individual market actions like supply, borrow, and enabling collateral, offering greater control and flexibility.
VAI is the primary stablecoin of the Venus Protocol. It is carefully designed and integrated with a series of stability mechanisms to maintain its peg to 1 USD.
VAI sustains its value via a stability fee system. This fee is a charge that users incur when they repay their minted VAI. Calculated on a block-by-block basis, this fee gets added to the user's minted VAI balance. This fee system encourages users to either mint or burn VAI in response to its price fluctuations, thereby contributing to its stability.
The stability fee is determined through the following formula:
The baseRate is a fixed rate that users must always pay, while max(0, (1 - currentPriceOfVAI)) * floatingRate is a variable rate that users pay based on outstanding VAI. This incentivizes users to burn or mint VAI according to its price. The variable rate will always be greater or equal to zero, meaning the minimum stability fee will be the base rate.
Revenue generated from the stability fee serves as a financial cushion during extreme market conditions, such as bad debt scenarios.
Proxy contract for the VAI Vault
Admin Functions **
Accepts new implementation of VAI Vault. msg.sender must be pendingImplementation
Return Values
Begins transfer of admin rights. The newPendingAdmin must call _acceptAdmin to finalize the transfer.
Parameters
Return Values
Accepts transfer of admin rights. msg.sender must be pendingAdmin
Return Values
Venus Protocol manages risks of high volatility tokens with isolated pools. Each pool (Isolated Pools and the Core pool) has an associated risk fund receiving a percentage of the pool's income (interest and liquidation bonus) in USDT to prevent insolvency. The specific percentage is defined by the tokenomics of the project. The risk fund also covers bad debt in case of bankruptcy without a liquidator.
The risk fund concerns three main contracts:
ProtocolShareReserve
RiskFund
ReserveHelpers
These three contracts are designed to hold funds that have been accumulated from interest reserves and liquidation incentives, send a portion to the protocol treasury, and send the remainder to the RiskFund contract. When reduceReserves() is called in a vToken contract, all accumulated liquidation fees and interests reserves are sent to the ProtocolShareReserve contract. Once funds are transferred to the ProtocolShareReserve, anyone can call releaseFunds() to transfer 50% to the protocolIncome address and the other 50% to the riskFund contract. Once in the riskFund contract, the tokens can be swapped via PancakeSwap pairs to the convertible base asset, which can be updated by the authorized accounts. When tokens are converted to the convertibleBaseAsset, they can be used in the Shortfall contract to auction off the pool's bad debt. Note that just as each pool is isolated, the risk funds for each pool are also isolated: only the associated risk fund for a pool can be used when auctioning off the bad debt of the pool.
When a borrower's shortfall (total borrowed amount converted to USD is greater than the total supplied amount converted to USD) is detected in a market in the Isolated Pools, Venus halts the interest accrual, writes off the borrower's balance, and tracks the bad debt.
Shortfall is an auction contract designed to auction off the convertibleBaseAsset accumulated in RiskFund. The convertibleBaseAsset is auctioned in exchange for users paying off the pool's bad debt. An auction can be started by anyone once a pool's bad debt has reached a minimum value (see Shortfall.minimumPoolBadDebt()). This value is set and can be changed by the authorized accounts. If the pool’s bad debt exceeds the risk fund plus a 10% incentive, then the auction winner is determined by who will pay off the largest percentage of the pool's bad debt. The auction winner repays the bid percentage of the bad debt in exchange for the entire risk fund. Otherwise, if the risk fund covers the pool's bad debt plus the 10% incentive, then the auction winner is determined by who will take the smallest percentage of the risk fund in exchange for paying off all the pool's bad debt.
The main configurable (via VIP) parameters in the Shortfall contract , and their initial values, are:
minimumPoolBadDebt - Minimum USD bad debt in the pool to allow the initiation of an auction. Initial value set to 1,000 USD
waitForFirstBidder - Blocks to wait for first bidder. Initial value sets to 100 blocks
nextBidderBlockLimit - Time to wait for next bidder. Initial value set to 100 blocks
This is the proxy contract for the VAIComptroller
Admin Functions **
Accepts new implementation of comptroller. msg.sender must be pendingImplementation
Return Values
Begins transfer of admin rights. The newPendingAdmin must call _acceptAdmin to finalize the transfer.
Parameters
Return Values
Accepts transfer of admin rights. msg.sender must be pendingAdmin
Return Values
XVS Vault Proxy contract
Admin Functions **
Accepts new implementation of XVS Vault. msg.sender must be pendingImplementation
Return Values
Begins transfer of admin rights. The newPendingAdmin must call _acceptAdmin to finalize the transfer.
Parameters
Return Values
Accepts transfer of admin rights. msg.sender must be pendingAdmin
Return Values
This contract stores XVS received from XVSVaultConverter and funds XVSVault
The xvs token address
The xvsvault address
This function transfers funds to the XVS vault
Parameters
📅 Events
FundsTransferredToXVSStore emits on success
⛔️ Access Requirements
Restricted by ACM
❌ Errors
InsufficientBalance is thrown when amount entered is greater than balance
This function sweep tokens from the contract
Parameters
📅 Events
SweepToken emits on success
⛔️ Access Requirements
Restricted by ACM
Let's take a quick look at the Venus interface and the features available in each menu of the navigation bar.
In the center of the Dashboard interface, you will find the Supply and Borrow markets. You'll also notice a new column called 'Pool' which identifies the pool to which each market belongs. The Supply market allows you to lend your cryptocurrency assets and earn interest on them. You can choose which assets to supply and specify the amount you want to lend. On the other hand, the Borrow market allows you to borrow cryptocurrency assets by using your supplied assets as collateral. You can select the assets you want to borrow and specify the amount you need.
The Account interface provides an overview of your supplied and borrowed assets. Here, you can keep track of your balances and monitor the status of your transactions.
The Core Pool interface is your hub for exploring all primary markets available. It allows you to click on each market to examine essential metrics such as 'Supply APY', 'Borrow APY', and 'Total Liquidity', among others. This interface centralizes all your lending and borrowing activities within the main markets.
The Pools interface allows you to explore all isolated pools available. You can click on each pool to view all the markets within it. In the markets, you can see various metrics such as 'Supply APY', 'Borrow APY', 'Total Liquidity', and more.
The Vaults interface allows you to access and manage the vaults associated with Venus Protocol. Vaults are designed to provide users with automated strategies for optimizing their yields and managing their assets more efficiently.
The Swap interface enables you to swap one cryptocurrency for another within the Venus Protocol. You can exchange your assets conveniently and quickly.
In the History interface, you can review transaction history and track your previous activities on the Protocol.
The Governance interface provides access to Venus Protocol's governance features. Here, users can participate in voting and contribute to decision-making processes that shape the future of the protocol.
The XVS interface displays the current daily reward distribution rate for each of the protocol markets.
The VAI interface is where you can mint and manage the VAI stablecoin. VAI is created on Venus Protocol and is pegged to the value of one USD.
This guide provides step-by-step instructions on how to borrow VAI, the stablecoin of Venus Protocol, available exclusively for prime users. Borrowing involves using your account's total core pool collateral to secure the loan, and this tutorial will walk you through the VAI UI to accomplish this.
Navigate to the Venus Protocol website and select the "VAI" option from the sidebar menu. This will take you to the VAI dashboard, where you can manage your borrowings and repayments.
Click on the "Connect wallet" button in the top right corner of the VAI dashboard to connect your wallet. This is necessary to interact with the Venus Protocol and manage your VAI borrowings.
In the "Borrow" tab, enter the amount of VAI you wish to borrow in the provided field. You can also see your maximum borrow limit based on your account's total collateral. Ensure that the amount you wish to borrow does not exceed this limit.
After entering the desired amount, review the details of your borrowing transaction, including the collateral used and the borrow limit. Once you've confirmed that everything is correct, click on the "Borrow" button to initiate the transaction.
A wallet pop-up will appear, asking for your confirmation to proceed with the transaction. Confirm to finalize the borrowing process.
To repay your VAI debt, access the VAI dashboard again and select the "Repay" tab. This interface allows you to make repayments towards your borrowed VAI.
In the "Repay" tab, enter the amount of VAI you wish to repay. You can choose to repay part of your debt or the entire amount.
Review your repayment details carefully. Once you are ready, click on the "Repay VAI" button to proceed. Confirm the transaction in your wallet pop-up to complete the repayment process.
Borrowing and repaying VAI on Venus Protocol is straightforward with the VAI UI. By following these steps and ensuring you have enough collateral, you can manage your stablecoin needs effectively. Always be mindful of your borrow limits and repayment responsibilities to maintain a healthy financial position within the protocol.
The NativeTokenGateway contract serves the purpose of facilitating seamless interaction with Wrapped Native Token markets, even for users who do not possess any Wrapped Native Tokens. It achieves this by allowing users to utilize the native currency in their wallets directly.
The Venus contracts deployed on the new networks do not directly support native currencies. For example on Ethereum instead of a native ether market there is a market for WETH. Wrapped Native Token markets address this limitation by facilitating the conversion of native currency into a format compatible with the ERC-20 standard.
To streamline user experience and eliminate the need for an additional transaction to convert native tokens into wrapped tokens, wrapping an unwrapping of native tokens is done behind the scenes when users interact with the market.
Venus Protocol is deeply committed to ensuring the highest level of security and risk management for our users. This section of the documentation outlines our comprehensive approach to risk management, emphasizing our continuous monitoring practices, partnerships for enhanced security, real-time alert systems, and ongoing risk assessments.
Some assets, such as Liquid Staking Tokens (LSTs), are closely tied to an underlying asset, often featuring an added growth component.
The exchange rate between an asset and its underlying is typically sourced from an onchain smart contract, which can be susceptible to manipulation. A capped oracle is a design mechanism that mitigates potential losses from such manipulation by limiting the rate at which the exchange rate is allowed to grow.
The capped oracle mechanism should be used for any asset whose price is derived through an intermediary token, where the exchange rate between the source asset and the intermediary is fetched onchain and includes a growth component.
At a high level, the capped oracle determines the maximum allowable exchange rate at the queried block based on a predefined growth rate. It then compares this with the current onchain exchange rate, and if the current rate exceeds the calculated maximum, it caps it to that maximum value.
Typically, the current maximum exchange rate at a given block is calculated by taking a historical exchange rate from a past block and applying a predefined per-second growth rate up to the current block timestamp. However, since the exchange rate may not grow consistently over time, the historical reference rate is periodically updated to ensure a more accurate and reliable maximum exchange rate.
The historical reference rate is periodically refreshed through a process called snapshotting. During this process, the new reference rate is set to the lower of the current onchain exchange rate or the maximum rate derived from the previous reference rate, helping maintain a more accurate and robust cap. Before querying an asset’s price from the capped oracle, the consumer should trigger the snapshotting process. If the configured interval has elapsed, a new snapshot will be taken.
Venus Protocol incorporates Risk Oracles and Risk Stewards to ensure risk parameters remain up-to-date, resilient, and aligned with real-time market conditions—all while preserving decentralized governance. Previously, Venus relied on manually created VIPs to apply risk updates based on Chaos Labs recommendations. With the introduction of the Risk Steward and its on-chain receiver, this process is now automated through a secure and permissioned mechanism. In the initial phase, only market cap-related parameters—specifically supply caps and borrow caps—will be updated automatically, improving responsiveness and operational efficiency.
The Venus Protocol tokenomics have been reevaluated to optimize income distribution and cater to the protocol's present and future needs. of the Venus Protocol revenue distribution model addresses the need and optimizes the allocation between rewards, treasury reserves, a risk fund and BNB burns.
function executeFlashLoan(
address payable onBehalf,
address payable receiver,
VToken[] memory vTokens,
uint256[] memory underlyingAmounts,
bytes memory param
) externalincentiveBps - Incentive to auction participants. Initial value set to 1000 bps or 10%
The funds generated in the Core pool, that should be allocated to the risk fund, are temporarily sent to the Venus Treasury contract. With the relase of the Automatic income allocation feature, this income will be sent to the ProtocolShareReserve contract, where there will be distributed following the tokenomics of the project.
The funds associated with the Core pool, accumulated in the RiskFund contract, will be used to repay the bad debt of the Core pool via VIP.
The Chaos Labs Risk Oracle is a system designed to continuously analyze market conditions—such as price volatility, liquidity, asset utilization, and liquidation events—and generate risk parameter recommendations tailored to the Venus Protocol.
Real-time updates to key parameters like supply and borrow caps
Automated adjustments to ensure optimal lending and borrowing rates
More responsive risk management with lower latency
Reduced operational overhead for the Venus community
The Risk Oracle makes Venus more adaptable while ensuring parameters remain within safe and governance-approved limits.
A Risk Steward is an on-chain smart contract that executes risk parameter updates on behalf of the protocol, based on recommendations from the Risk Oracle. Venus has introduced this role to bridge off-chain risk intelligence with on-chain execution in a controlled, transparent way.
Reads values from the Risk Oracle during execution
Updates only pre-approved risk parameters (e.g., supply caps, borrow caps)
Operates within limits set by Venus governance
Cannot modify critical protocol settings such as interest rate models, market listings, or governance controls
This structure ensures faster, automated adjustments without compromising community control.
Data Source: Chaos Labs publishes updated recommendations via the Risk Oracle.
Keeper Role: A Keeper bot observes changes and initiates transactions to update Venus Protocol’s parameters.
Validation: During execution, Venus contracts read and apply new values only if they are within predefined safety bounds.
Challenge Window: Critical updates, which will be introduced in an upcoming phase, will go through governance and can be challenged or vetoed during a defined challenge window before they take effect.
Importantly, this system does not bypass protocol governance. All automated updates happen within constraints defined and approved by the Venus community.
Any change made through the Risk Oracle follows an optimistic governance model:
This process preserves decentralization while enabling faster, safer protocol maintenance.
Initially, the integration focuses on automating supply and borrow cap updates. Over time, additional parameters may be supported as part of a gradual rollout, always subject to DAO approval and governance-defined constraints.
param
bytes
The bytes passed in the executeOperation call




The capped exchange rate between intervals is constrained by a per-second growth limit. However, since the actual exchange rate may exceed this cap, we inflate the snapshotted exchange rate by a predefined buffer to avoid imposing a hard limit.
The following configuration needs to be defined when configuring the capped oracle for a token:
Annual Growth Rate: This defines the maximum growth in exchange rate per year. Internally this is converted to growth rate per second.
Snapshot Interval: After the number of seconds window at which the reference exchange rate is recalculated,
Initial Snapshot Exchange Rate and Timestamp: Defines the initial reference exchange rate and the timestamp at which the exchange rate is taken from.
Snapshot Gap: Used to define the inflation of the exchange rate at each snapshot.
Note that all the above variables values can be updated using the governance process after the deployment with the initial values.
Let’s walk through an example to understand how the capped oracle functions. Suppose we want to retrieve the exchange rate between wstETH and stETH.
Annual Growth Rate: Assume an annual growth rate of 2.9%, based on Lido’s estimated APY. Taking into account Lido compounding period is daily, the estimated APY would be 2.9423% (compounding should be considered when the caps are defined). So, the associated capped oracle could be configured with a maximum annual growth rate of 5%. Internally, this will be converted into a per-second growth rate.
Snapshot Interval: The snapshot can be updated once per month to refresh the reference exchange rate.
Initial Snapshot: We fetch the current exchange rate and timestamp from the onchain wstETH contract. For instance, the current exchange rate is 1.200101369591475639 and the timestamp is 1744895950. We apply a buffer on top of the current exchange rate: for example 1% of the maximum annual growth rate, that is 1% * 5% = 0.05%. So, the initial snapshot value would be 1.200101369591475639 * 1.0005 = 1.20070142027627137681. This way, the capped oracle won't cap spikes on the wstETH exchange rate just after the initialization.
Snapshot Gap: The same concept of the buffer applied to calculate the initial snapshot in the previous step, but to be considered every time the snapshot is automatically updated. This cap could be set to 1.200101369591475639 * 0.0005 = 0.0006, and reviewed periodically.
Given this initial setup:
after 15 days, the maximum exchange rate allowed will be 1.20070142027627137681 * (1 + (0.05 * 15 / 365)) = 1.20316860954764085647
after 1 month, the snapshot will be automatically updated. Assuming the exchange rate at that time is 1.20300161856832627043, after applying the snapshot gap, the new maximum exchange rate will be 1.20360161856832627043 (1.20300161856832627043 + 0.0006)
after 15 days, the maximum exchange rate allowed will be 1.20360161856832627043 * (1 + (0.05 * 15 / 365)) = 1.20607476713814428156
















[0]
uint256
uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
newPendingAdmin
address
New pending admin.
[0]
uint256
uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
[0]
uint256
uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
[0]
uint256
uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
newPendingAdmin
address
New pending admin.
[0]
uint256
uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
[0]
uint256
uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
[0]
uint256
uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
newPendingAdmin
address
New pending admin.
[0]
uint256
uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
[0]
uint256
uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
amountMantissa
uint256
Amount to be sent to XVS vault
tokenAddress
address
Address of the asset(token)
to
address
Address to which assets will be transferred
amount
uint256
Amount need to sweep from the contract
tokenAddress
address
The address of treasury token
withdrawAmount
uint256
The withdraw amount to owner
withdrawAddress
address
The withdraw address
withdrawAmount
uint256
The withdraw amount to owner
withdrawAddress
address payable
The withdraw address
function _setPendingImplementation(address newPendingImplementation) public returns (uint256)function _acceptImplementation() public returns (uint256)function _setPendingAdmin(address newPendingAdmin) public returns (uint256)function _acceptAdmin() public returns (uint256)function _setPendingImplementation(address newPendingImplementation) public returns (uint256)function _acceptImplementation() public returns (uint256)function _setPendingAdmin(address newPendingAdmin) public returns (uint256)function _acceptAdmin() public returns (uint256)function _setPendingImplementation(address newPendingImplementation) public returns (uint256)function _acceptImplementation() public returns (uint256)function _setPendingAdmin(address newPendingAdmin) public returns (uint256)function _acceptAdmin() public returns (uint256)address XVS_ADDRESSaddress xvsVaultfunction fundXVSVault(uint256 amountMantissa) externalfunction sweepToken(address tokenAddress, address to, uint256 amount) externalfallback() external payablefunction withdrawTreasuryBEP20(address tokenAddress, uint256 withdrawAmount, address withdrawAddress) externalfunction withdrawTreasuryBNB(uint256 withdrawAmount, address payable withdrawAddress) external payableThe introduction of the NativeTokenGateway contract significantly enhances the user experience when interacting with wrapped native token markets. Unlike before, where users were required to have the wrapped native token to engage with markets, they now have the flexibility to choose between native currency or wrapped version for market interaction.
If the user opts for native currency, the following functions are executed to facilitate interaction with the protocol:
The updateDelegate function facilitates the granting or revocation of borrowing and redeeming delegate rights to or from an account. By invoking this function, borrowing delegate rights or redeeming delegate rights can be assigned to a specific address (delegate), enabling them to borrow or redeeming funds on behalf of the User.
This mechanism provides flexibility and control over borrowing and redeeming activities within the protocol, enhancing the overall efficiency and functionality of the system.
The wrapAndSupply function is invoked sending the native currency, and the execution proceeds as follows:
Native currency is wrapped, providing the wrapped token.
VWrappedNative tokens are minted on behalf of the user.
VWrappedNative tokens are transferred to the user.
redeemUnderlyingAndUnwrap
The user approves the NativeTokenGateway contract as the delegate.
The redeemUnderlyingAndUnwrap function is called with the amount of underlying tokens to redeem, and the execution proceeds as follows:
VWrappedNative tokens are redeemed by the NativeTokenGateway contract on behalf of the user.
Received wrapped native tokens are unwrapped to obtain native currency.
Native currency is transferred to the user.
redeemAndUnwrap
The user approves the NativeTokenGateway contract as the delegate.
The redeemAndUnwrap function is called with the amount of VWrappedNative tokens to redeem, and the execution proceeds as follows:
The user approves the NativeTokenGateway contract as the delegate.
The borrowAndUnwrap function is invoked, and the execution proceeds as follows:
Wrapped native tokens are borrowed on behalf of the user.
The borrowed wrapped native tokens are unwrapped to obtain native currency.
Native currency is transferred to the user.
The wrapAndRepay function is invoked sending the native currency, and the execution proceeds as follows:
The native currency sent is wrapped, providing the wrapped native.
The NativeTokenGateway repays the debt on behalf of the user.
Any unused native currency for repayment is returned to the user.
Prior to deployment, Venus Protocol undergoes extensive audits conducted by industry-leading security firms. The results of these audits are publicly accessible and have been fully implemented, ensuring a robust and secure framework.
Access our detailed audit reports here: Security and Audits.
Venus Protocol has partnered with Chaos Labs, a leader in blockchain security and monitoring. This partnership equips us with sophisticated tools for continuous on-chain monitoring, significantly enhancing our risk control and mitigation strategies.
Explore our monitoring dashboard for real-time insights: Chaos Labs Risk Overview.
To further enhance our risk management, we have implemented a real-time alert system via Telegram. This system provides immediate notifications for critical events such as market high utilization, significant whale movements, and borrow/supply cap utilization.
Join our alert channel to stay updated: Chaos Labs Telegram Alerts.
In collaboration with Chaos Labs, we continuously analyze market conditions and adjust risk parameters across all pools regularly or anytime there is need for adjustment to mitigate risks due to market conditions. These adjustments are based on comprehensive data analysis and are integral to maintaining the stability and security of the protocol.
Several security measures have been implemented to mitigate the security risks associated with the frontend app deployed at https://app.venus.io.
The Venus Protocol UI is deployed on AWS infrastructure. Additionally, Cloudflare is employed to distribute the web app. The relevant security services in both AWS and Cloudflare are properly configured to detect and mitigate security risks.
SPF and DKIM are configured to protect every email sent from a @venus.io account.
Web certificates, generated by AWS, are set to auto-renew.
Venus nameservers are hosted on Cloudflare, serving as our DNS provider.
The Venus Protocol UI utilizes to assess the risk profile associated with web3 addresses. If the risk is deemed high, the connection is disallowed, preventing any interactions with contracts from the UI involving that risky address.
Only privileged users have the authority to deploy the open-source code, accessible on Github (https://github.com/VenusProtocol/venus-protocol-interface), to the domain app.venus.io. Additionally, only privileged users are authorized to merge pull requests in the Github repository.
The risk management practices at Venus Protocol are designed to provide a secure and stable environment for our users. Our commitment to continuous monitoring, real-time alerts, and dynamic risk adjustments ensure that we are always at the forefront of blockchain security. We encourage our community to explore the provided resources for a deeper understanding of our risk management protocols.
The XVS Staking Vault is an integral component of the Venus ecosystem. It enables governance voting participation and is a prerequisite for Venus Prime eligibility. To incentivize XVS staking, additional rewards will be offered in the form of Base Rewards (previously referred to as Legacy Rewards).
These rewards will be transferred every six months from the XVS Distributor to the XVS Vault Store, where they will be emitted at a rate of 308.7 XVS per day.
Protocol reserves are mainly composed of accumulated borrow fees. The model for revenue allocation from these reserves divides income into three main segments:
Treasury Reserve (15%): The treasury reserve is used to fund community-driven initiatives and essential protocol expenses for its ongoing operations.
XVS Vault Rewards (20%): This allocation is designated for the buyback of XVS, which is then distributed via vault rewards.
Venus Prime Token Program (20%): Used to boost select market APYs with organic rewards for users that qualify.
Risk Fund (20%): This fund is established to address potential shortfalls in the protocol, particularly in situations of ineffective or delayed liquidations.
BNB Burn (25%): See community proposal .
Other revenue streams include liquidation penalties and potential income generated from future product releases. The revenue distribution for these streams is as follows:
Treasury Reserves (35%)
XVS Vault Rewards (20%)
Risk Fund (20%)
BNB Burn (25%)
The methodology behind these adjustments includes an assessment of the existing tokenomics, past changes, their impact on the ecosystem, and analysis of market dynamics and trends.
This dual allocation model accounts for the diverse revenue sources within the Venus Protocol ecosystem, ensuring robust and responsive financial management. As the protocol evolves and introduces new products, these models may further be adjusted to optimally serve the Venus community.
Click on the "Connect wallet" button in the top right corner of the Venus Bridge interface to connect your wallet.
If you have supply positions in other DeFi protocols (we currently only support Aave, with more to come soon) for which we can propose a better APY, a modal will automatically appear showing you options to import your positions to the Venus Protocol.
If you close this modal, it won't be shown to you ever again. You can still access this UI by selecting the "Import" item in the side menu.
Click on the "Import" button next to any position listed.
A confirmation pop-up will appear in your wallet for you to approve the transaction. Note that this transaction is sponsored by the Venus Protocol, therefore it is free of charge.
Confirm the transaction in your wallet. The interface will show the transaction as pending, indicating that it is being processed. This may take from a few seconds to a few minutes depending on the current network activity.
You can import all your positions one-by-one by repeating the process.
Once the transaction is complete, the new positions will appear in the "Account" page.
Navigate to the Venus Protocol and select the "Bridge" option from the sidebar menu. XVS Bridge
Click on the "Connect wallet" button in the top right corner of the Venus Bridge interface to connect your wallet.
From: Ensure "BNB mainnet" is selected in the "From" dropdown menu.
To: Select "Ethereum" in the "To" dropdown menu to set the destination network.
Enter the amount of XVS you wish to transfer in the "Amount" field. You can also use the "MAX" button to transfer the total available balance.
Check your "Wallet balance" to confirm you have sufficient XVS and BNB for gas fees.
Before initiating the transfer, you must give the bridge contract permission to access your XVS tokens. Click on the "Approve XVS" button to do this.
A wallet pop-up will request your confirmation for the approval. Confirm to proceed.
After approving XVS token usage, the interface will update to reflect the next step. Click the "Transfer" button (which replaces the "Approve XVS" button after approval) to initiate the bridging process.
A confirmation pop-up will appear in your wallet for you to approve the transaction.
Confirm the transaction in your wallet. The Venus Bridge interface will show the transaction as pending, indicating that it is being processed. This may take a few minutes.
Once the transaction is complete, the XVS tokens will be available in your Ethereum wallet.
Bridging XVS tokens from BNB Chain to Ethereum is made simple with the Venus Protocol. Remember to approve your tokens for use by the bridge and to check transaction details carefully before confirming to ensure a smooth bridging experience.
The contracts under the Venus Protocol employ a system called Exponential.sol. This system uses exponential mathematics to represent fractional quantities with high precision.
Most numbers in this system are represented by a mantissa, an unsigned integer scaled by a factor of 1 * 10^18. This scaling ensures basic mathematical operations can be performed with a high degree of accuracy.
Prices and exchange rates are adjusted according to the unique decimal scaling of each asset. vTokens, which are BEP-20 tokens, are scaled with 8 decimal places. However, their underlying tokens may have different decimal scaling, which is indicated by a public member called 'decimals'.
For further details, please refer to the respective token contract addresses.
The exchange rate of vTokens is adjusted based on the decimal difference between the vToken and its underlying asset.
Here is an example illustrating how to determine the value of one vBUSD in BUSD using the Web3.js JavaScript library.
As BNB lacks an underlying contract, you must set the 'underlyingDecimals' to 18 when dealing with vBNB.
To calculate the number of underlying tokens that can be redeemed using vTokens, you should multiply the total amount of vTokens by the previously computed 'oneVTokenInUnderlying' value.
Interest rates for each market are updated in any block where there is a change in the ratio of borrowed assets to supplied assets. The magnitude of this change in interest rates depends on the interest rate model smart contract in place for the market, and the degree of change in the aforementioned ratio.
For a visualization of the current interest rate model applied to each market, refer to the market pages at the .
The accrual of interest to suppliers and borrowers in a market occurs when any wallet interacts with the market's vToken contract. This interaction could be any of the following functions: mint, redeem, borrow, or repay. A successful execution of any of these functions triggers the accrueInterest method, leading to the addition of interest to the underlying balance of every supplier and borrower in the market. Interest accrues for the current block, as well as any previous blocks where the accrueInterest method was not triggered due to lack of interaction with the vToken contract. Interest only accumulates during blocks where one of the aforementioned methods is invoked on the vToken contract.
Let's consider an example of supply interest accrual: Alice supplies 1 BNB to the Venus Protocol. At the time of her supply, the supplyRatePerBlock is 37893605 Wei, which equates to 0.000000000037893605 BNB per block. For 3 blocks, no interactions occur with the vBNB contract. On the subsequent 4th block, Bob borrows some BNB. As a result, Alice’s underlying balance is updated to 1.000000000151574420 BNB (calculated by multiplying 37893605 Wei by 4 blocks and adding the original 1 BNB). From this point onwards, the accrued interest on Alice’s underlying BNB balance will be based on the updated value of 1.000000000151574420 BNB, rather than the initial 1 BNB. It is important to note that the supplyRatePerBlock value may alter at any given time.
The Annual Percentage Yield (APY) for either supplying or borrowing in each market can be computed using the supplyRatePerBlock (for Supply APY) or borrowRatePerBlock (for Borrow APY) values. These rates can be used in the following formula (assuming a daily compound):
Here is an example of calculating the supply and borrow APY with Web3.js JavaScript:
The purpose of this document is to explain the technical details for distributing incomes generated by the Venus Protocol. The distributed incomes are generated from the spread of lending rates (borrow minus supply rates) and liquidations (part of the liquidation incentives). The distribution process for both the Core Pool and Isolated Pools as well as how the different amounts are allocated to different destinations based on specific rules and the approach for near-streaming income distribution are covered.
The Venus Protocol generates income from two main sources:
Spread between the borrowing rate and the supply rate
Part of the liquidation incentives
goes into more detail about the distribution schema and desired outcomes.
The initial distribution excludes VAI funds, which are kept in the VTreasury.
The Venus Protocol aims to distribute accumulated reserves in the markets automatically and in near-real-time, leveraging transactions executed by users. This approach eliminates the need for external tools to manage the distribution process. The ProtocolShareReserve contract serves as the designated destination for liquidation incomes, allowing for tracking and distribution within the Venus Protocol.
Accumulated reserves in the Core Pool markets will be distributed after reaching a specified threshold. The threshold is based on the number of blocks since the last transfer of reserves. This strategy helps socialize part of the cost associated with distribution.
In the Core Pool, liquidation income is transferred to the Liquidator contract in the form of vTokens. During a liquidation transaction, the Liquidator contract will try to redeem the protocol's portion of the liquidation incentive in vTokens for the underlying tokens. If the redemption process is successful, the underlying tokens will be sent to the ProtocolShareReserve contract. However, if the redemption fails the underlying tokens will be added to a list of pending redemptions and the Liquidator contract will try to redeem the pending redemptions again in subsequent liquidation transactions.
Distribution of income generated by the interest rate spread in Isolated Pools is socialized and distributed periodically just like in the Core Pool
The Isolated Pools liquidations are managed by the VToken contracts. During a liquidation transaction, the protocol's percentage of the seized amount is transferred directly to the ProtocolShareReserve contract. No other action is required.
The distribution of collected incomes is facilitated by the ProtocolShareReserve contract. It supports WBNB transfers but not BNB transfers. Therefore, BNB needs to be wrapped into WBNB before transferring to the ProtocolShareReserve contract.
updateAssetsState FunctionThe updateAssetsState function enables the transfer of funds to the ProtocolShareReserve contract. After transferring funds to the ProtocolShareReserve contract, the updateAssetsState function is invoked with the following parameters:
address comptroller: The Comptroller where the market generated the income.
address asset: The asset transferred to the ProtocolShareReserve.
IncomeOrigin origin: The origin type, either "spread" or "liquidation."
Within the updateAssetsState function, the following steps are performed:
Calculate the transferred balance, taking into account the previous balance of the asset.
Assign the received amount to the appropriate entry (comptroller - asset - schema).
Track the total balance of the received asset for future distribution.
releaseFunds FunctionThe releaseFunds function is responsible for distributing the accumulated funds to the different destinations. This function can be invoked by anyone and follows a two-step process:
Transfer the tokens to the destination addresses.
Invoke the updateAssetsState function in the receiver contract.
VBNBAdmin contract is the admin of the vBNB vToken. All the other vToken contracts send revenue to PSR directly whereas vBNB sends the reserves to the admin i.e., the vBNBAdmin contract. This pattern is different for vBNB because it's not a upgradable contract.
Whenever the VBNBAdmin receives BNB from the vBNB contract it converts it to WBNB and then sends it to the Protocol share reserve contract.
To release the reserves of vBNB contract you need to call the reduceReserves() function of the VBNBAdmin contract.
Construct an interest rate model
Parameters
Calculates the utilization rate of the market: borrows / (cash + borrows - reserves)
Parameters
Return Values
Calculates the current borrow rate per block, with the error code expected by the market
Parameters
Return Values
Calculates the current supply rate per block
Parameters
Return Values
Venus Protocol's governance model allows XVS token holders to propose and vote on Venus Improvement Proposals (VIPs). Here's a step-by-step guide to help you create and submit a proposal.
Navigate to the Venus Governance Portal using your preferred web browser. You can access the portal at .
To submit a proposal, you need to connect your wallet by clicking on the "Connect Wallet" button at the top right corner of the screen. A menu will appear listing various wallets that the Venus Governance Portal supports. Select your wallet from the menu and follow the instructions to connect your wallet to the portal.
Now that your wallet is connected, you can create a proposal. Look for the "Create Proposal" button at the top right corner of the screen and click on it.
This action will open a modal presenting two options - "Upload file" and "Create Manually":
The fastest way to create a proposal is by importing a VIP file. The import uses a JSON file containing all the information needed to create a VIP, such as the proposal's title, type, actions and parameters.
Venus makes available a tool to generate VIP files, which you can find . You can also check an example of a valid proposal file . Note that all the fields will be validated according to their requirements and types.
Clicking "Upload file" will lead you to choose the proposal file you want to upload. After uploading the desired file, it will be parsed and validated and any possible errors found will be reported by the interface.
Once the import is successfully validated, the interface will present all the VIP data for your review:
If everything looks good, click "Create" at the bottom of the modal to confirm the creation of your VIP.
Proposals can also be created manually by clicking on "Create manually".
After clicking the "Create manually" button, a new interface will pop up prompting you to select the proposal type. Select the relevant proposal type for the change you want to propose.
The next step is to provide detailed information about your proposal. This includes the proposal's title, a brief description, and a link to an off-chain discussion related to your proposal. Ensure the information you provide is clear and concise to facilitate understanding by other community members.
The third screen is where you can specify descriptions for the voting options (for, against, abstain).
Next add the actions that will take place if the proposal is approved. An action requires an contract address, function signature and arguments so that the operation can be created correctly.
Finally, just like after the VIP import, you will be able to review your proposal to ensure all details are accurate. After confirming everything is correct, click the "Submit" button to submit your proposal. You'll see a confirmation prompt on your connected wallet. Confirm the transaction to complete the proposal submission process.
Congratulations! You've successfully submitted a Venus Improvement Proposal. The Venus community will now review your proposal and vote on it. Remember, your active involvement in Venus Protocol's governance process is crucial for its continued development and success.
This innovation is designed to distribute the incomes generated by Venus Protocol seamlessly, channeling them to different destinations according to specific rules and percentages. This functionality will incorporate incomes generated through various sources, including interest reserves and liquidation incentives, for both the Core pools and Isolated pools. The goal is to distribute these incomes in underlying tokens and not in vTokens, based on the latest protocol tokenomics.
Near-Streaming Distribution: The income will be distributed in a near-streaming fashion, from the different pools to the ProtocolShareReserve contract.
Flexible Distribution Rules: The incomes generated by Venus Protocol will be distributed according to two schemas:
Schema (PROTOCOL_RESERVES): Applied specifically to income generated by the interest reserves in every Venus market.
Efficiency: Automating the income distribution process allows for quicker and more accurate allocation.
Transparency: All distributions are recorded on the blockchain, reinforcing Venus Protocol's commitment to clear and open practices.
Flexibility: The ability to define specific rules and percentages for different destinations ensures that the distribution aligns with the community's needs and goals.
The dashed lines represent transactions initiated by external agents (VIP’s, scripts, arbitrage bots, etc.), and the solid lines represent transfers of funds.
In this guide, we will focus on using Venus Protocol to earn interest and borrow assets. If you’re looking for a more technical understanding of what’s happening under the hood, check out .
Once you’ve created your Web3 wallet on or any other supported wallet App, open the Venus app (). The interface will ask you to connect your Web3 wallet. Connecting your wallet to Venus Protocol enables you to authorize transactions, view balances, and perform other essential actions.
After successfully connecting your wallet, you will gain access to all the features of the Venus Protocol interface. In the Dashboard menu you will find all the markets. Clicking one of the markets a new modal will pop out, enabling you to interact with the selected market. Just make sure you are under the "Supply" or "Borrow" tab, depending on the desired action.
Received wrapped native tokens are unwrapped to obtain native currency.
Native currency is transferred to the user.








15% to Treasury
20% to XVS Vault rewards
20% to Venus Prime
20% to Risk Fund
25% to BNB Burn
Schema (ADDITIONAL_REVENUE): Valid for liquidation and other product developments.
35% to Treasury
20% to XVS Vault rewards
20% to Risk Fund
25% to BNB Burn
Integration with Existing Architecture: The Automatic Income Allocation will seamlessly integrate with the existing ProtocolShareReserve contract, ensuring that the incomes are sent to their designated reserves.






baseRatePerYear
uint256
The approximate target base APR, as a mantissa (scaled by 1e18)
multiplierPerYear
uint256
The rate of increase in interest rate wrt utilization (scaled by 1e18)
jumpMultiplierPerYear
uint256
The multiplierPerBlock after hitting a specified utilization point
kink_
uint256
The utilization point at which the jump multiplier is applied
cash
uint256
The amount of cash in the market
borrows
uint256
The amount of borrows in the market
reserves
uint256
The amount of reserves in the market (currently unused)
[0]
uint256
The utilization rate as a mantissa between [0, 1e18]
cash
uint256
The amount of cash in the market
borrows
uint256
The amount of borrows in the market
reserves
uint256
The amount of reserves in the market
[0]
uint256
The borrow rate percentage per block as a mantissa (scaled by 1e18)
cash
uint256
The amount of cash in the market
borrows
uint256
The amount of borrows in the market
reserves
uint256
The amount of reserves in the market
reserveFactorMantissa
uint256
The current reserve factor for the market
[0]
uint256
The supply rate percentage per block as a mantissa (scaled by 1e18)
Safely transfer rewards. Only active reward tokens can be sent using this function. Only callable by owner
Parameters
token
address
Reward token to transfer
_to
address
Destination address of the reward
_amount
uint256
Amount to transfer
Allows the admin to propose a new admin Only callable admin
Parameters
_admin
address
Propose an account as admin of the XVS store
Allows an account that is pending as admin to accept the role nly calllable by the pending admin
Set the contract owner
Parameters
_owner
address
The address of the owner to set Only callable admin
Set or disable a reward token
Parameters
_tokenAddress
address
The address of a token to set as active or inactive
status
bool
Set whether a reward token is active or not
Security function to allow the owner of the contract to withdraw from the contract
Parameters
_tokenAddress
address
Reward token address to withdraw
_amount
uint256
Amount of token to withdraw
Pause vault
Resume vault
Deposit VAI to VAIVault for XVS allocation
Parameters
_amount
uint256
The amount to deposit to vault
Withdraw VAI from VAIVault
Parameters
_amount
uint256
The amount to withdraw from vault
Claim XVS from VAIVault
Claim XVS from VAIVault
Parameters
account
address
The account for which to claim XVS
View function to see pending XVS on frontend
Parameters
_user
address
The user to see pending XVS
Return Values
[0]
uint256
Amount of XVS the user can claim
Function that updates pending rewards
Admin Functions **
Sets the address of the access control of this contract
Parameters
newAccessControlAddress
address
New address for the access control
address of vBNB
address of WBNB contract
Used to initialize non-immutable variables
PSR setter.
Parameters
protocolShareReserve_
contract IProtocolShareReserve
Address of the PSR contract
📅 Events
Emits ProtocolShareReserveUpdated event.
⛔️ Access Requirements
Only owner (Governance)
Reduce reserves of vBNB, wrap them and send them to the PSR contract
Parameters
reduceAmount
uint256
amount of reserves to reduce
📅 Events
Emits ReservesReduced event.
Sets the interest rate model of the vBNB contract
Parameters
newInterestRateModel
address
Address of the new interest rate model
⛔️ Access Requirements
Controlled by ACM
Invoked when BNB is sent to this contract
⛔️ Access Requirements
Only vBNB is considered a valid sender
Invoked when called function does not exist in the contract. The function will be executed in the vBNB contract.
⛔️ Access Requirements
Only owner (Governance)
Oracle which gives the price of any given asset
Multiplier used to calculate the maximum repayAmount when liquidating a borrow
Multiplier representing the discount on collateral that a liquidator receives
Per-account mapping of "assets you are in"
Official mapping of vTokens -> Market metadata
A list of all markets
Borrow caps enforced by borrowAllowed for each vToken address. Defaults to zero which restricts borrowing.
Minimal collateral required for regular (non-batch) liquidations
Supply caps enforced by mintAllowed for each vToken address. Defaults to zero which corresponds to minting not allowed
Flag indicating whether forced liquidation enabled for a market
Prime token address
Whether the delegate is allowed to borrow or redeem on behalf of the user
const vTokenDecimals = 8; // all vTokens have 8 decimal places
const underlying = new web3.eth.Contract(bep20Abi, busdAddress);
const vToken = new web3.eth.Contract(vTokenAbi, vBusdAddress);
const underlyingDecimals = await underlying.methods.decimals().call();
const exchangeRateCurrent = await vToken.methods.exchangeRateCurrent().call();
const mantissa = 18 + parseInt(underlyingDecimals) - vTokenDecimals;
const oneVTokenInUnderlying = exchangeRateCurrent / Math.pow(10, mantissa);
console.log('1 vBUSD can be redeemed for', oneVTokenInUnderlying, 'BUSD');Rate = vToken.supplyRatePerBlock(); // Integer
Rate = 37893566
BNB Mantissa = 1 * 10 ^ 18 (BNB has 18 decimal places)
Blocks Per Day = 80 * 60 * 24 (based on 80 blocks occurring every minute on BNB Chain)
Days Per Year = 365
APY = (((Rate / BNB Mantissa) * Blocks Per Day) + 1) ^ (Days Per Year - 1) * 100const ethMantissa = 1e18;
const blocksPerDay = 80 * 60 * 24;
const daysPerYear = 365;
const vToken = new web3.eth.Contract(vBnbAbi, vBnbAddress);
const supplyRatePerBlock = await vToken.methods.supplyRatePerBlock().call();
const borrowRatePerBlock = await vToken.methods.borrowRatePerBlock().call();
const supplyApy = Math.pow(((supplyRatePerBlock / bnbMantissa) * blocksPerDay) + 1, daysPerYear - 1) * 100;
const borrowApy = Math.pow(((borrowRatePerBlock / bnbMantissa) * blocksPerDay) + 1, daysPerYear - 1) * 100;
console.log(`Supply APY for BNB ${supplyApy} %`);
console.log(`Borrow APY for BNB ${borrowApy} %`);constructor(uint256 baseRatePerYear, uint256 multiplierPerYear, uint256 jumpMultiplierPerYear, uint256 kink_) publicfunction utilizationRate(uint256 cash, uint256 borrows, uint256 reserves) public pure returns (uint256)function getBorrowRate(uint256 cash, uint256 borrows, uint256 reserves) public view returns (uint256)function getSupplyRate(uint256 cash, uint256 borrows, uint256 reserves, uint256 reserveFactorMantissa) public view returns (uint256)function safeRewardTransfer(address token, address _to, uint256 _amount) externalfunction setPendingAdmin(address _admin) externalfunction acceptAdmin() externalfunction setNewOwner(address _owner) externalfunction setRewardToken(address _tokenAddress, bool status) externalfunction emergencyRewardWithdraw(address _tokenAddress, uint256 _amount) externalfunction pause() externalfunction resume() externalfunction deposit(uint256 _amount) externalfunction withdraw(uint256 _amount) externalfunction claim() externalfunction claim(address account) externalfunction pendingXVS(address _user) public view returns (uint256)function updatePendingRewards() publicfunction _become(contract VAIVaultProxy vaiVaultProxy) externalfunction setAccessControl(address newAccessControlAddress) externalcontract VTokenInterface vBNBcontract IWBNB WBNBfunction initialize(contract IProtocolShareReserve _protocolShareReserve, address accessControlManager) externalfunction setProtocolShareReserve(contract IProtocolShareReserve protocolShareReserve_) externalfunction reduceReserves(uint256 reduceAmount) externalfunction setInterestRateModel(address newInterestRateModel) public returns (uint256)receive() external payablefallback(bytes data) external payable returns (bytes)struct LiquidationOrder {
contract VToken vTokenCollateral;
contract VToken vTokenBorrowed;
uint256 repayAmount;
}struct AccountLiquiditySnapshot {
uint256 totalCollateral;
uint256 weightedCollateral;
uint256 borrows;
uint256 effects;
uint256 liquidity;
uint256 shortfall;
}struct RewardSpeeds {
address rewardToken;
uint256 supplySpeed;
uint256 borrowSpeed;
}struct Market {
bool isListed;
uint256 collateralFactorMantissa;
uint256 liquidationThresholdMantissa;
mapping(address => bool) accountMembership;
}enum Action {
MINT,
REDEEM,
BORROW,
REPAY,
SEIZE,
LIQUIDATE,
TRANSFER,
ENTER_MARKET,
EXIT_MARKET
}contract ResilientOracleInterface oracleuint256 closeFactorMantissauint256 liquidationIncentiveMantissamapping(address => contract VToken[]) accountAssetsmapping(address => struct ComptrollerStorage.Market) marketscontract VToken[] allMarketsmapping(address => uint256) borrowCapsuint256 minLiquidatableCollateralmapping(address => uint256) supplyCapsmapping(address => bool) isForcedLiquidationEnabledcontract IPrime primemapping(address => mapping(address => bool)) approvedDelegatesConnect your Web3 wallet on MetaMask or other supported wallet app to the Venus app (https://app.venus.io).
Navigate to the "Dashboard" menu and choose the asset you want to supply. For example, if you want to supply TRX, click on the TRX market.
Enable the asset. This will prompt a transaction confirmation in your wallet. Remember that a small gas fee applies, so ensure some native tokens (BNB for BNB chain, or ETH for Ethereum, for example) are available in your wallet.
Specify the amount you want to supply. The selected assets are transferred directly from your wallet to Venus Protocol, earning interest immediately. This interest will be automatically added to your Supply Balance.
Your borrowing limit on Venus Protocol is a function of the assets you have supplied. The following steps guide you to manage it:
Navigate to the "Account" section.
Here, you'll find your Borrow Limit on each pool, represented as a percentage of the total value of your supplied assets.
To adjust this limit, you can either supply more assets or repay some of your outstanding loans.
After supplying assets, you can borrow other assets within your borrowing limit:
From the "Dashboard" menu, select the asset you want to borrow.
Input the amount you wish to borrow and confirm the transaction.
In addition to earning interest on supplied assets, you can also farm $XVS tokens:
In the "Vaults" section, you can stake your XVS or VAI tokens to earn XVS tokens.
Click on 'Stake'. You will be prompted to confirm the transaction in your wallet.
Let's assume you supply 1000 TRX to Venus, and the vTRX/TRX rate is 0.0204. You'd receive approximately 49,019 vTRX in return (1000 / 0.0204). If the vTRX/TRX rate increases to 0.0215 after a year, your 49,019 vTRX would be worth 1021.5 TRX (49019 * 0.0215), an increase of 21.5 TRX.
Remember that these vTokens represent your collateral in Venus Protocol. It's crucial not to trade or transfer them if you have an active loan, as they're required to maintain your borrowing limit.
ETH is the native token for the Ethereum blockchain, used to pay gas fees, for example. WETH is an ERC-20 token representing ETH. Most Web3 apps (including Venus) are compatible with ERC-20 tokens, so it's necessary to convert ETH to WETH.
The conversion of ETH -> WETH and WETH -> ETH is always available in the WETH token itself, and the exchange rate is always 1:1:
If you wrap 1 ETH, you'll receive 1 WETH.
If you unwrap 1 WETH, you'll receive 1 ETH.
Only the gas fee to execute the wrap/unwrap transactions will need to be paid. Each Ethereum network (including L2s) has its own WETH token (see the full list on CoinMarketCap)).
An easy way to get WETH from ETH is by using Uniswap. For example, on the Ethereum mainnet, the process would be:
Go to the Uniswap page to wrap ETH on Ethereum.
Connect your wallet.
Type the amount of ETH you want to wrap.
Click on Wrap.
Review and accept the transaction in your Web3 wallet.
Remember to add the WETH token to your Web3 wallet to see your WETH balance.
To unwrap WETH tokens (getting ETH), you can also use Uniswap, switching the input and output currencies.
Venus Protocol is excited to announce Venus Prime, a revolutionary incentive program aimed to bolster user engagement and growth within the protocol. An integral part of Venus Tokenomics v3.1, Venus Prime aims to enhance rewards and promote $XVS staking, focusing on markets including USDT, USDC, BTC and ETH.
Venus Prime's uniqueness lies in its self-sustaining rewards system, instead of external sources, rewards are derived from the protocol's revenue, fostering a sustainable and ever-growing program.
Eligible $XVS holders will receive a unique, non-transferable Soulbound Token, which boosts rewards across selected markets.
Prime Tokens:
Venus Prime encourages user commitment through two unique Prime Tokens:
Revocable Prime Token:
Users need to stake at least 1,000 XVS for 90 days in a row.
After these 90 days, users can mint their Prime Token.
Venus Prime aims to incentivize larger stake sizes and diverse user participation. This is expected to significantly increase the staking of XVS, the Total Value Locked (TVL), and market growth.
Venus Prime intends to promote user loyalty and the overall growth of the protocol. By endorsing long-term staking, discouraging premature withdrawals, and incentivizing larger stakes, Venus Prime sets a new course in user engagement and liquidity, contributing to Venus Protocol's success.
Stake your $XVS tokens today to be eligible for Venus Prime, an exciting new venture in the DeFi landscape.
Reward Formula: Cobb-Douglas function
Where:
= Rewards for user in market
= Protocol Reserve Revenue for market
= Proportion to be distributed as rewards
Qualifiable XVS Staked:
Qualifiable supply and borrow:
Note: There will be a limit for the qualifiable supply and borrow amounts, set by the staked XVS limit and the market multiplier.
Model Parameters
= 0.5
= 744,164
= 8 BTC
= 0.2
User Parameters
Qualifiable Staked XVS
Qualifiable Supply and Borrow
User Rewards
Expected Rewards Function
Rewards in the Venus Prime program will automatically increase as a user increases its XVS Stake, so long as the amount staked and market participation fall within the limits outlined in the "Technical Reward Details" section below.
The graph above demonstrates the relationship between an increased XVS staked amount and its effect on market rewards, assuming a constant participation of $2.5K USD in the BTC supply market. This helps visualize how an increase in the staked amount influences the APY.
As features continued to be introduced to the Core Pool Comptroller contract, it grew to exceed the maximum allowable size of 24KB. In response to this challenge and to preemptively address similar issues in the future, a multifaceted diamond pattern was implemented.
The original comptroller was refactored using the EIP-2535 diamond pattern into distinct facets. This restructuring aligns the storage layout with that of the Comptroller proxy, streamlining the contract's organization and enhancing efficiency. As a consequence user interactions now trigger two delegate calls.
The previous implementation of Venus used a transparent upgrade proxy delegate pattern. For the diamond proxy we needed a slightly different implementation of fallback function.
Comptroller proxy(Unitroller): https://bscscan.com/address/0xfd36e2c2a6789db23113685031d7f16329158384
Comptroller implementation before enabling the Diamond Proxy: https://bscscan.com/address/0x909dd16b24cef96c7be13065a9a0eaf8a126ffa5
The following diagram shows the previous design:
The Unitroller contract delegated calls to the Comptroller. The Comptroller had the storage layout defined by ComptrollerV12Storage, which extended the UnitrollerAdminStorage.
The Diamond Proxy pattern is widely used in Solidity development for its ability to separate concerns and improve code maintainability. It is often used in complex contracts that require multiple facets with shared functionality.
The Diamond Proxy pattern involves creating a "proxy" contract that acts as a single entry point for all functionality shared by multiple contracts. This allows contracts to share functionality without having to duplicate code in each contract.
Each contract that needs to share functionality with the proxy contract is referred to as a "facet." Facets are separate contracts that can be upgraded or modified independently of each other and the proxy contract.
The proxy contract delegates function calls to the correct facet contract based on the function selector. This allows the proxy contract to act as a single entry point for all shared functionality.
Step 1: The first step was creating the Diamond proxy contract. This contract contains a mapping to hold the addresses of the facet contracts and a fallback function that delegates the function call to the appropriate facet.
Chained delegate calls are used. This means calldata is delegated from Unitroller to the Diamond contract and then a chained delegate call is made to a specific facet based on the function selector.
The Diamond contract checks for the facet address in the selectors-to-facet-address mapping (_selectorToFacetAndPosition internal variable) and then makes a delegate call to that facet address. Facets inherit the ComptrollerStorage (ComptrollerV13Storage) to access the state.
Step 2: Division of the comptroller into multiple facets based on separation of concerns.
Generally is used with the diamond pattern. Since the Core Pool contracts still use Solidity 0.5.16 this wasn't an option and storage is handled using the same pattern as the original comptroller, by inheriting storage contracts.
Comptroller storage contains the facet addresses, mapping of the function selectors to the facet address, and mapping of all selectors to the facet address.
Users will continue to interact with the Unitroller proxy contract same as before with one significant difference. Now the Diamond proxy serves as the implementation contract for the Unitroller, and the Comptroller's implementation has been divided into multiple facets. These facets will function as the various components of the Diamond proxy.
Following a user's interaction with the Unitroller, the delegateCall operation will be directed towards the Diamond proxy. Once the delegateCall reaches the Diamond proxy, it will analyze the function selector and determine the appropriate facet address to which the delegateCall will be forwarded.
Scenario: A new state variable is to be introduced for an upgrade, which is being used by all or few facets.
Add a new state variable in the comptrollerStorage by extending the storage to ComptrollerV14Storage just like new state is added to facets by extending the previous storage.
Scenario: Add a new facet to the Diamond or update the existing facet by add/replace/remove function selectors.
Deploy the facet with the functions/methods that need to be added to the Comptroller Implementation.
Execute the diamondCut method(admin access) to add the new facet to the comptrollerStorage.
To execute the diamondCut through VIP, the cut argument can be generated using the by customizing the generateCutParams to provide the correct actions on the provided function seletors.
The Comptroller of the core pool is divided into 4 facets and 2 parent contracts extended by the facets. Facets will receive the function call through a chained delegateCall from Unitroller, and each facet holds its own responsibility as explained below:
: This facet contains all the external pre-hook functions related to vToken.
: This facet contains all setter configuration functions.
: This facet provides market information including account activity in the market. It is also responsible for entering and exiting the market.
: This facet provides the external functions related to all claims and rewards of the protocol.
: This contract contains functions related to access and checks.
XVSRewardsHelper: This contract contains the shared functions used by the RewardFacet and PolicyFacet.
The following diagram shows the inheritance and association relationships among the different contracts:
The Peg Stability Module (PSM) is a crucial component of the Venus Protocol designed to maintain the value of the VAI stablecoin at $1. It functions similarly to the system provided by MakerDAO for DAI. The PSM contract utilizes two stablecoins: VAI (the target stablecoin) and USDT (used to help maintain the peg).
Convert Functionality:
Users can exchange VAI and USDT with a "fixed" conversion rate of 1 VAI = $1.
Users can send VAI to the PSM and receive USDT if enough USDT is available in the PSM.
Users can send USDT to the PSM and receive VAI, provided that the PSM hasn't reached its maximum allowed minted VAI limit.
No Stability Fee
The VAI minted through the PSM does not accrue any interest or stability fee.
Configurable Parameters:
The PSM contract has three configurable variables set via the Venus Improvement Proposal (VIP):
feeIn: Fee charged when users send USDT to the PSM.
feeOut: Fee charged when users send VAI to the PSM.
maxMintedVAI: The maximum amount of VAI that the PSM can distribute. Conversions that exceed this limit will be reverted.
Fees Sent to Treasury: The collected fees are sent to the Venus Treasury contract in each operation.
Integration with Oracle Price: The PSM considers the USD value of the stablecoin to peg VAI to its value accurately.
swapStableForVAIThis function allows users to exchange the paired stablecoin (USDT) for VAI.
Expected Parameters:
receiver: Address of the user who will receive the VAI.
amount: The amount of stablecoin (USDT) the sender wants to convert.
The received stablecoins will be held by the PSM, and the fee specified by feeIn will be sent to the Treasury contract.
This function returns the amount of VAI transferred to the receiver.
swapVAIForStableThis function enables users to exchange VAI for the paired stablecoin (USDT).
Expected Parameters:
receiver: Address of the user who will receive the stablecoin.
amount: The expected amount of stablecoin (USDT) the user should receive.
The received VAI will be burnt, and the fee specified by feeOut will be sent to the Treasury contract.
This function returns the amount of VAI transferred from the sender (burnt + fee).
The PSM also offers preview functions that help users estimate the outcome of convert operations:
previewSwapVAIForStable(uint256 stableTknAmount)Returns the amount of VAI that the sender would transfer (burnt + fee) to receive the specified stablecoin amount.
previewSwapStableForVAI(uint256 stableTknAmount)Returns the amount of VAI that the receiver would receive after executing the swapVAIForStable function with the specified stablecoin amount.
To protect the value of VAI and consider the USD value of the paired stablecoin, the PSM integrates with the Resilient Oracle. The following rules are applied:
swapVAIForStable (the user sends VAI and receives USDT)
If the oracle price of the paired stablecoin is below $1, the conversion rate is 1 stablecoin = $1.
If the oracle price of the paired stablecoin is above $1, the conversion rate is 1 stablecoin = oracle price.
swapStableForVAI (the user sends USDT and receives VAI)
If the oracle price of the paired stablecoin is below $1, the conversion rate is 1 stablecoin = oracle price.
If the oracle price of the paired stablecoin is above $1, the conversion rate is 1 stablecoin = $1.
This documentation is designed to be user-friendly and does not cover the technical implementation details of the Peg Stability Module. For technical information, developers and smart contract auditors can refer to the .
Venus DAO is an autonomous and decentralized organization that functions via smart contracts on a blockchain, meaning it operates without any central authority or control. The purpose of DAOs is to facilitate trustless collaboration and decision-making among members, who can be individuals or entities involved in the organization. Governance within Venus DAO encompasses making decisions, establishing rules, and managing resources.
1/ Token Holders: DAOs typically have a native token, representing membership and voting rights within the organization. For Venus Protocol, this native token is XVS. Token holders partake in the decision-making process by voting on proposals.
2/ Proposals: Venus DAO members who stake XVS in the Vault can create proposals, which suggest changes, initiatives, or organizational actions. Proposals can span a variety of topics such as protocol upgrades, funding requests, or changes to the DAO's rules. To propose, one requires "Voting power" of 300,000 XVS. To vote on a proposal, one needs "Voting power" of 600,000 XVS, either individually owned or delegated by other members.
3/ Voting: Following a proposal's creation, token holders can vote on it. Venus DAO manages the voting process, queuing and voting on protocol updates within 48-hour timelocks. The voting method could entail a simple majority vote, a supermajority, or weighted voting based on each participant's token count, as is the case with Venus Protocol.
4/ Voting Period: Venus DAO recognizes three Venus Improvement Proposals (VIP) roles: Normal, Fast Track, and Critical. Each VIP role has a unique proposal threshold, timelock, and voting period, which can be configured by Governance. This duration allows token holders ample time to review, discuss, and cast their votes. The votes are tallied once the voting period concludes.
5/ Execution: After a proposal garners support and votes, all Venus DAO members can execute the VIP directly in the Venus dapp through smart contracts.
6/ Transparency and Auditability: All Venus DAO transactions and governance activities take place on a public blockchain, enabling transparency and auditability for anyone interested. This level of transparency helps maintain accountability and minimizes potential fraud or manipulation risks.
It's crucial to understand that DAO governance is an evolving field, with different DAOs adopting unique governance structures and processes. The specific rules and mechanisms are continually refined and adapted to best meet the needs of all Venus DAO members.\
Step 1: Visit the Venus Governance Portal
Access the Venus governance portal via your browser. The URL is .
Step 2: Connect Your Wallet
On the top right corner of the screen, click on the "Connect Wallet" button. Choose your wallet from the dropdown menu and follow the prompts to connect.
Step 3: Delegate Your Voting Power
Once your wallet is connected, click on the "Delegate" button in the Governance section. This will open up a new dialogue box.
Step 4: Enter Your Address
In the new dialogue box, click on the "Paste your address" field. Your connected wallet address should automatically populate.
Step 5: Redelegate Your Votes
Click on the "Redelegate" button. This will submit the address for vote delegation.
Step 6: Confirm the Transaction
A confirmation prompt will appear in your connected wallet (for example, MetaMask). Confirm the transaction to complete the voting power delegation process.
Congratulations, you've now enabled your XVS in the vault to participate in Venus Protocol's governance. Your tokens are now ready to vote on upcoming VIP proposals. Remember, your engagement in the protocol’s decision-making process is vital for its future development and success.
To vote on a Venus Improvement Proposal (VIP), navigate to the list of active proposals on the Venus Governance Portal. Click on the title of the VIP you wish to vote on. Remember, your voting eligibility requires your address to be delegated.
After selecting the VIP, you'll see voting options for the proposal. You can choose 'For' to vote in favor of the proposal, 'Against' to vote against it, or 'Abstain' to remain neutral.
Before you submit your vote, you have an option to provide a comment explaining the reasoning behind your decision. This step is not mandatory, but it contributes to a more transparent and inclusive voting process.
Once you've made your decision and optionally left a comment, click the 'Submit Vote' button to cast your vote.
Congratulations, you've successfully voted on a VIP proposal! Your participation is integral to the development and success of the Venus Protocol. Thank you for your contribution to our community's decision-making process. Remember, every vote counts in shaping the future of Venus Protocol.
The parameterized model described in section 2.4 of the original Venus Protocol whitepaper
Construct an interest rate model
Parameters
Calculates the utilization rate of the market: borrows / (cash + borrows - reserves)
Parameters
Return Values
Calculates the current borrow rate per block, with the error code expected by the market
Parameters
Return Values
Calculates the current supply rate per block
Parameters
Return Values
The limit to the number of revocable Prime tokens is 500 on BNB chain. Source. It can be changed with a VIP.
Irrevocable "OG" Prime Token (Phase 2):
To be defined
= XVS staked amount for user
= Sum of qualified supply and borrow balance for user
= Sum for all users in markets
BTC Supply Multiplier = 2
XVS Price = $4.0
Staked XVS
1,200
$4,800
BTC Supply
0.097
$2,500


The Diamond Proxy pattern also supports multiple inheritances. This means that each facet can inherit from other contracts, including other facets. This allows for a high degree of code reuse and modular design.
The user needs to send 1 VAI (1 USDT * 1 $/USDT) + fees.
Assuming feeOut = 10%, 0.10 VAI will be sent to the treasury, and 1 VAI will be burnt, resulting in a total of 1.1 VAI provided by the user.
The fee is calculated considering the "principal" VAI amount that we are to burn (1 VAI = $1).
The user needs to send 11 VAI (10 USDT * 1.1 $/USDT) + fees.
Assuming feeOut = 10%, 1.1 VAI will be sent to the treasury, and 10 VAI will be burnt, resulting in a total of 12.1 VAI provided by the user.
The fee is calculated considering the "principal" VAI amount that we are to burn (11 VAI = $11).
The user will receive 9 VAI (10 USDT * 0.9) - fees.
Assuming feeIn = 10%, 0.9 VAI will be sent to the treasury, and 8.1 VAI will be sent to the user.
The fee is calculated considering the "principal" VAI amount (9 VAI = $9).
Calculation: The conversion rate to consider is min(1, 1.1) => 10 USDT = $10 = 10 VAI.
The user will receive 10 VAI (10 USDT * 1.0) - fees.
Assuming feeIn = 10%, 1 VAI will be sent to the treasury, and 9 VAI will be sent to the user.
The fee is calculated considering the "principal" VAI amount (10 VAI = $10).










baseRatePerYear
uint256
The approximate target base APR, as a mantissa (scaled by 1e18)
multiplierPerYear
uint256
The rate of increase in interest rate wrt utilization (scaled by 1e18)
cash
uint256
The amount of cash in the market
borrows
uint256
The amount of borrows in the market
reserves
uint256
The amount of reserves in the market (currently unused)
[0]
uint256
The utilization rate as a mantissa between [0, 1e18]
cash
uint256
The amount of cash in the market
borrows
uint256
The amount of borrows in the market
reserves
uint256
The amount of reserves in the market
[0]
uint256
The borrow rate percentage per block as a mantissa (scaled by 1e18)
cash
uint256
The amount of cash in the market
borrows
uint256
The amount of borrows in the market
reserves
uint256
The amount of reserves in the market
reserveFactorMantissa
uint256
The current reserve factor for the market
[0]
uint256
The supply rate percentage per block as a mantissa (scaled by 1e18)
Mapping to get prime token's metadata
Tracks total irrevocable tokens minted
Tracks total revocable tokens minted
Indicates maximum revocable tokens that can be minted
Indicates maximum irrevocable tokens that can be minted
Tracks when prime token eligible users started staking for claiming prime token
vToken to market configuration
vToken to user to user index
numerator of alpha. Ex: if alpha is 0.5 then this will be 1
denominator of alpha. Ex: if alpha is 0.5 then this will be 2
address of XVS vault
address of XVS vault reward token
address of XVS vault pool id
mapping to check if a account's score was updated in the round
unique id for next round
total number of accounts whose score needs to be updated
total number of accounts whose score is yet to be updated
mapping used to find if an asset is part of prime markets
address of core pool comptroller contract
unreleased income from PLP that's already distributed to prime holders
The address of PLP contract
The address of ResilientOracle contract
Call _acceptImplementation to accept the diamond proxy as new implementaion
Parameters
unitroller
contract Unitroller
Address of the unitroller
To add function selectors to the facet's mapping
Parameters
diamondCut_
struct IDiamondCut.FacetCut[]
IDiamondCut contains facets address, action and function selectors
Get all function selectors mapped to the facet address
Parameters
facet
address
Address of the facet
Return Values
[0]
bytes4[]
selectors Array of function selectors
Get facet position in the _facetFunctionSelectors through facet address
Parameters
facet
address
Address of the facet
Return Values
[0]
uint256
Position of the facet
Get all facet addresses
Return Values
[0]
address[]
facetAddresses Array of facet addresses
Get facet address and position through function selector
Parameters
functionSelector
bytes4
function selector
Return Values
[0]
struct ComptrollerV13Storage.FacetAddressAndPosition
FacetAddressAndPosition facet address and position
Get all facets address and their function selector
Return Values
[0]
struct Diamond.Facet[]
facets_ Array of Facet
constructor(uint256 baseRatePerYear, uint256 multiplierPerYear) publicfunction utilizationRate(uint256 cash, uint256 borrows, uint256 reserves) public pure returns (uint256)function getBorrowRate(uint256 cash, uint256 borrows, uint256 reserves) public view returns (uint256)function getSupplyRate(uint256 cash, uint256 borrows, uint256 reserves, uint256 reserveFactorMantissa) public view returns (uint256)struct Token {
bool exists;
bool isIrrevocable;
}struct Market {
uint256 supplyMultiplier;
uint256 borrowMultiplier;
uint256 rewardIndex;
uint256 sumOfMembersScore;
bool exists;
}struct Interest {
uint256 accrued;
uint256 score;
uint256 rewardIndex;
}struct PendingReward {
address vToken;
address rewardToken;
uint256 amount;
}mapping(address => struct PrimeStorageV1.Token) tokensuint256 totalIrrevocableuint256 totalRevocableuint256 revocableLimituint256 irrevocableLimitmapping(address => uint256) stakedAtmapping(address => struct PrimeStorageV1.Market) marketsmapping(address => mapping(address => struct PrimeStorageV1.Interest)) interestsuint128 alphaNumeratoruint128 alphaDenominatoraddress xvsVaultaddress xvsVaultRewardTokenuint256 xvsVaultPoolIdmapping(uint256 => mapping(address => bool)) isScoreUpdateduint256 nextScoreUpdateRoundIduint256 totalScoreUpdatesRequireduint256 pendingScoreUpdatesmapping(address => address) vTokenForAssetaddress comptrollermapping(address => uint256) unreleasedPLPIncomeaddress primeLiquidityProvidercontract ResilientOracleInterface oraclestruct Facet {
address facetAddress;
bytes4[] functionSelectors;
}function _become(contract Unitroller unitroller) publicfunction diamondCut(struct IDiamondCut.FacetCut[] diamondCut_) publicfunction facetFunctionSelectors(address facet) external view returns (bytes4[])function facetPosition(address facet) external view returns (uint256)function facetAddresses() external view returns (address[])function facetAddress(bytes4 functionSelector) external view returns (struct ComptrollerV13Storage.FacetAddressAndPosition)function facets() external view returns (struct Diamond.Facet[])The multiplier of utilization rate per block that gives the slope 1 of the interest rate scaled by EXP_SCALE
The base interest rate per block which is the y-intercept when utilization rate is 0 scaled by EXP_SCALE
The utilization point at which the multiplier2 is applied
The multiplier of utilization rate per block that gives the slope 2 of the interest rate scaled by EXP_SCALE
The base interest rate per block which is the y-intercept when utilization rate hits KINK_1 scaled by EXP_SCALE
The maximum kink interest rate scaled by EXP_SCALE
The utilization point at which the jump multiplier is applied
The multiplier of utilization rate per block that gives the slope 3 of interest rate scaled by EXP_SCALE
The maximum kink interest rate scaled by EXP_SCALE
Construct an interest rate model
Parameters
baseRatePerYear_
int256
The approximate target base APR, as a mantissa (scaled by EXP_SCALE)
multiplierPerYear_
int256
The rate of increase or decrease in interest rate wrt utilization (scaled by EXP_SCALE)
kink1_
int256
The utilization point at which the multiplier2 is applied
multiplier2PerYear_
int256
The rate of increase or decrease in interest rate wrt utilization after hitting KINK_1 (scaled by EXP_SCALE)
Calculates the current borrow rate per slot (block)
Parameters
cash
uint256
The amount of cash in the market
borrows
uint256
The amount of borrows in the market
reserves
uint256
The amount of reserves in the market
Return Values
[0]
uint256
The borrow rate percentage per slot (block) as a mantissa (scaled by EXP_SCALE)
Calculates the current supply rate per slot (block)
Parameters
cash
uint256
The amount of cash in the market
borrows
uint256
The amount of borrows in the market
reserves
uint256
The amount of reserves in the market
reserveFactorMantissa
uint256
The current reserve factor for the market
Return Values
[0]
uint256
The supply rate percentage per slot (block) as a mantissa (scaled by EXP_SCALE)
Calculates the utilization rate of the market: borrows / (cash + borrows - reserves)
Parameters
cash
uint256
The amount of cash in the market
borrows
uint256
The amount of borrows in the market
reserves
uint256
The amount of reserves in the market
Return Values
[0]
uint256
The utilization rate as a mantissa between [0, EXP_SCALE]
A set of processes are executed in a market when a shortfall (total borrowed amount converted to USD is greater than the total supplied amount converted to USD) is detected for a borrower to pause the interest accrual on the borrow, write off the borrower's borrow balance and track the market bad debt.
V represents the total bad debt including the accrued interest on the bad debt. To calculate the accrued interest the borrow index when the bad debt is detected is divided by the initial borrow index and then multiplied by the borrowed amount. For example, if the initial borrow index is 1.2 and when bad debt of 100 USDC is detected the borrow index is 1.5 then the V (total bad debt) becomes 100 * (1.5/1.2) = 125 USDC.
The calculated total bad debt of the account is written off for the borrower and interest accrual is stopped on the bad debt.
When the pool's bad debt reaches a minimum amount the risk fund reserve is auctioned off to cover the bad debt (see Shortfall.minimumPoolBadDebt()). Anyone will be allowed to start or restart an auction if the constraints are satisfied:
no other auction is in progress for the same pool (Shortfall.auctions(comptrollerAddress).status in (AuctionStatus.NOT_STARTED, AuctionStatus.ENDED))
the bad debt accumulated in the pool, in USD, is greater than Shortfall.minimumPoolBadDebt()
Auction participants receive a maximum 10% incentive (configurable by the community via VIP, see RiskFund.incentiveBps()) for covering the bad debt. Depending on the size of the reserve in the risk fund, either 100% of bad debt or a portion of it is raised.
N represents the total pool’s bad debt denoted in USD and M represents total risk fund balance in USD. When an auction begins, a starting bid is set to prevent bidders from taking advantage of the auction by opening with an undervalued bid. The highest bidder’s funds are locked, and when the auction closes the market(s) total cash reserve is increased, the bad debt of the market(s) is decreased and the risk fund partially/completely transferred to the winning bidder.
In scenario 1, X% indicates the percentage of bad debt the bidder is willing to pay and in scenario 2, the Y% indicates the percentage of the risk fund the bidder is willing to seize. During the auction, bidders are only allowed to specify X% or Y% depending on the type of auction.
A bid will be successful only if the bidder has sufficient funds to cover the bad debt they are bidding for and they make the best offer. When a bid is placed it is transferred to the Shortfall contract, and released if they are out bid. Subsequent bids should be placed within 100 blocks (adjustable via VIP, see Shortfall.nextBidderBlockLimit()) of the previous bid, otherwise anyone (including the winning bidder) can close the auction. If there is no bid for 100 blocks (adjustable via VIP, see Shortfall.waitForFirstBidder()) the auction can be restarted accounting for any changes in the risk fund and bad debt balance.
The auction process attempts to cover as much market bad debt as possible. In scenario 1, all of the bad debt may not be covered by the auction. In this case, the bad debt not covered will be maintained in the system until a new auction is started.
Let’s take a scenario when bad debt is greater than the total risk fund balance.
Bad Debt: Assuming that pool bad debt is 10 BTC and the price of BTC is $20,000. Then, the total bad debt is $200,000. If the incentive is 10% then the final bad debt is $220,000.
Risk Fund: Given the risk fund is stored in USDT token, the token risk fund balance is 100,000 USDT and 1 USDT is equal to $1, then the total risk fund balance is $100,000
Minimum Bid: In order for a user to bid they have to supply a minimum percentage of bad debt calculated as (100000/220000) * 0.9 = 40.90%
Scenario when bad debt is less than total risk fund balance
Bad Debt: Assuming pool bad debt is 10 BTC and the price of BTC is $20,000. Then, the total bad debt is $200,000. Suppose the incentive is 10% then the final bad debt is $220,000.
Risk Fund: Given the risk fund is stored in USDT token, the token risk fund balance is 500,000 USDT and 1 USDT is equal to $1, then the total risk fund balance is $500,000
Maximum Bid: Now for a user to bid they have to supply 100% of the bad debt and can claim a maximum of (220000 * 1.1) * 500000 = 48.40% of the risk fund balance.
Scenario when the auction was started and nobody participated so instead of starting a new auction we need to restart the auction
Auction Started: Suppose an auction was started and there was no bidder till 100 blocks. Then in this case the auction is stale and bids cannot be placed.
Restart Auction: Now suppose a user wants to restart the auction and/or place a bid then they can restart using:
Restart Auction Signature: restartAuction(comtrollerAddress)
We have a strict policy on how we should commit our work. Following these guidelines will help us to:
Avoid hard to solve merge conflicts. Our workflow favors rebase over merge in feature branches, so there are no complex dependencies between branches. We sacrifice the “full history” in favor of just “meaningful history”, thus avoiding unnecessary diffs.
Make our contracts more secure. It's easy to make a small mistake that would cost millions of dollars to the contract users. We need to peer review our contracts as thoroughly as possible, thus our workflow ensures the process is easy and rewarding for the reviewers.
int256 MULTIPLIER_PER_BLOCKint256 BASE_RATE_PER_BLOCKint256 KINK_1int256 MULTIPLIER_2_PER_BLOCKint256 BASE_RATE_2_PER_BLOCKint256 RATE_1int256 KINK_2int256 JUMP_MULTIPLIER_PER_BLOCKint256 RATE_2constructor(int256 baseRatePerYear_, int256 multiplierPerYear_, int256 kink1_, int256 multiplier2PerYear_, int256 baseRate2PerYear_, int256 kink2_, int256 jumpMultiplierPerYear_) publicfunction getBorrowRate(uint256 cash, uint256 borrows, uint256 reserves) external view returns (uint256)function getSupplyRate(uint256 cash, uint256 borrows, uint256 reserves, uint256 reserveFactorMantissa) public view virtual returns (uint256)function utilizationRate(uint256 cash, uint256 borrows, uint256 reserves) public pure returns (uint256)baseRate2PerYear_
int256
The additional base APR after hitting KINK_1, as a mantissa (scaled by EXP_SCALE)
kink2_
int256
The utilization point at which the jump multiplier is applied
jumpMultiplierPerYear_
int256
The multiplier after hitting KINK_2
User A Starts Auction: User A notices that the pool’s bad debt is greater than the minimum bad debt required to start an auction, then they can start an auction using this function call:
Minimum Pool Bad Debt: You can find the minimum required bad debt for a pool to start an auction using minimumPoolBadDebt state variable and the bad debt of individual markets using the badDebt state variable of the vToken contract.
Start Auction Signature: startAuction(comptrollerAddress)
Address of the pool’s comptroller.
Starting an auction triggers AuctionStarted event which can be monitored to get notifications.
User A Places Bid: Now user A sees that the auction has started and wishes to place a bid. In this case, the user will place the minimum bid and try to seize the risk fund balance at the lowest value possible:
Block Limit: Note that the first bid has to be placed within 100 blocks from starting the auction, otherwise the auction needs to be restarted.
Approval: You need to give approval to the Shortfall contract to transfer the bid amount of funds to itself.
To calculate the amount for approval you need to first decide the bid bps. In this case, the minimum bid bps can be read using auctions[comptrollerAddress].startBidBps state variable.
In this example, it’s 4090 i.e., 40.90%. So you need to transfer 40.90% of 10 BTC which is 4.9 BTC. This is the approval amount. If there are multiple tokens as part of the bad debt then you have to provide 40.90% of each of the tokens bad debt.
You can find the list of markets involved in the bad debt by using auctions[comptrollerAddress].markets variable and then retrieving the underlying token of each of the markets using underlying()
Place Bid Signature: placeBid(comptrollerAddress, bidBps, auctionStartBlock)
Auction Start Block: This is the block number when the auction was started. You can find this using: auctions[comptrollerAddress].startBlock state variable.
Placing a bid triggers BidPlaced
User B Places Bid: Now user B sees an opportunity and decides to place a bid. They have to place a bid bigger than 40.90% bid bps to succeed in placing the bid. For example, user B places a bid for 41% to outperform User A’s bid.
Refund: User A will immediately receive back the BTC they sent to the Shortfall contract as part of the first bid.
User A Places Improved Bid: Now user A sees that User B places a better bid. Then User A can wish to complete with a better bid again. Suppose user A places a new bid for 43%.
User A Closed Auction: After placing a bid, User A waits for 100 blocks and sees there are no new bids that outperform their bid then they can close the auction and win it.
Close Auction Signature: closeAuction(comptrollerAddress)
Risk Fund Transfer: At this point in time all the 100,000 USDT is transferred from the risk fund to user A’s address.
User A Starts Auction: Now suppose user A notices that the pool’s bad debt is greater than the minimum bad debt required to start an auction, then they can start an auction.
Minimum Pool Bad Debt: You can find the minimum required bad debt for a pool to start an auction using minimumPoolBadDebt state variable and the bad debt of individual markets using badDebt state variable of the vToken contract.
Start Auction Signature: startAuction(comptrollerAddress)
Address of the pool’s comptroller.
Starting an auction triggers AuctionStarted event which can be monitored to get notifications.
User A Places Bid: Now user A sees that the auction has started and wishes to place a bid. In this case, the user will place the maximum bid and try to seize the maximum possible risk fund balance by covering 100% of bad debt:
Block Limit: Note that the first bid has to be placed within 100 blocks from starting the auction, otherwise it needs to be restarted.
Approval: You need to give approval to the Shortfall contract to transfer the bid amount of funds to itself.
Amount: You need to transfer 10 BTC i.e., the complete bad debt. This is the approval amount. If there are multiple tokens as part of the bad debt then you have to provide complete bad debt for each token.
You can find the list of markets involved in the bad debt using auctions[comptrollerAddress].markets variable and then read the underlying token of each of the markets using underlying() function.
Place Bid Signature: placeBid(comptrollerAddress, bidBps, auctionStartBlock)
Auction Start Block: This is the block number when the auction was started. You can find this using: auctions[comptrollerAddress].startBidBps state variable.
Bid BPS: In this example, the bid bps is 100% which indicates 100% of 48.40% (i.e., 242,000 USDT).
User B Places Bid: Now user B sees an opportunity and decides to place a bid. They have to place a bid lower than 100% bid bps to succeed in placing a bid. Image user B places a bid for 95% (i.e., risk fund seize amount is 242000 - (100-95)% = 229900 ) to outperform User A’s bid.
Refund: User A will immediately receive back the BTC they sent to the Shortfall contract as part of the first bid.
User A Places Improved Bid: Now user A sees that User B places a better bid. Then User A can wish to complete with a better bid again. Suppose user A places a new bid for 94%.
User A Closed Auction: After placing a bid, User A waits for 100 blocks and sees there are no new bids that outperform their bid then they can close the auction and win it.
Close Auction Signature: closeAuction(comptrollerAddress)
Risk Fund Transfer: At this point in time 94% of 242,000 USDT i.e., 227,480 USDT is transferred from the risk fund to user A’s address.
Place Bids and Close Auction: Now just like previous steps a user can place bids and close the auction.

Although the policy may seem too restrictive, it is usually quite easy to follow. It may require you to learn git a bit deeper than you're used to — please follow along, we'll show the necessary commands :)
By default, git merges the upstream changes into your local branch on pull. This silently spoils your history and may introduce unnecessary merge conflicts that are hard to solve and reason about. We encourage you to turn off this feature by running git config --global pull.ff only.
Prefer to base your feature branches on master. If it is not possible, make sure to not include someone else's commits in your PR later.
Prefer short and descriptive names for branches (good: polynomial-interest-curve, bad: fix-rate).
Use lowercase words separated by dashes (good: xvs-vault, bad: XVSVault).
You may include work type into the branch name (ok: feature/polynomial-interest-curve).
Make sure no-one else works in your feature branch.
Commit messages will need to follow a standard format in order to be able to correctly bumpt the next version and format the release. Conventional commits is a nice standard to use for formatting the commit messages. There are different tools available to enforce these messages
Breaking changes will result in a major version bump. These can be triggered by placing BREAKING CHANGE or BREAKING CHANGES in the footer of the commit message or by placing an exclamation point after the type. See next section on commit format
commitlint - Precommit hook with husky ( currently implement in the api repo)
breaking change
major
true
feat
minor
true
build
false
false
ci
false
Once you have made your changes, it's time to present them to the reviewers. It is quite important that the reviewers only see the relevant up-to-date changes structured by commits.
While you've been working on your feature branch, the master branch has most likely evolved. Rebase your changes on top of master by running git rebase --onto master <parent>, where <parent> is the hash of the commit immediately preceding your first commit. You can find <parent> by looking at the history: git log --oneline.
Your feature branch should have linear history. No merge commits are allowed.
The commits in your PR should not solve the problems introduced in your previous commits. The reviewers often look at the code commit by commit, and they may comment on the problems you later solve. By making sure your commits are self-contained, you free the reviewers of unnecessary work. Use the interactive rebase feature (git rebase -i <parent>) to squash, reorder or drop your commits.
When you rewrite your history, GitHub will refuse to accept your changes. This is to protect you from wiping out someone else's contributions. We need to follow certain rules to make sure our history is clean and the others' contributions are intact.
Every feature branch should have one active maintainer. No-one else is allowed to directly commit to your feature branch.
You can safely force-push to your feature branch. If your colleague wants to contribute, ask them to push their changes into a separate branch, and then cherry-pick. If you want to help your colleague, push your changes to a separate branch and let your colleague cherry-pick. This would help you to avoid any potential conflicts stemming from force-pushing.
Always use --force-with-lease and not --force/-f to force-push. Things happen, and someone may violate the “one active maintainer” rule. Force with lease would save you the trouble of recovering someone's work :)
Never force-push to master or any branch that has several maintainers. The only exception to this rule is when a secret (API key, private key, etc.) is accidentially committed, in which case you should immediately wipe it out and notify the security team as soon as possible.
Make sure your commit history follows the guidelines written above. Rebase once again if necessary.
If your PR is work in progress, explicitly mark it as WIP.
During the review, your history does not need to satisfy the criteria above. The reviewers are interested in how you have addressed their comments, so do not squash your fixes with your previous commits during the review. You can use git commit --fixup <target_commit> to make a fix to a specific commit.
Avoid fixing up a fixup :)
After addressing all of the review comments, rebase your work so that the commits are self-contained again. You can use git rebase -i --autosquash to squash the fixup commits into the target commits automatically.
Do not add any new changes to the code after the review (except for squashing and reordering the commits).
This policy may require some time and effort: writing lenghty commit messages and doing an interactive rebase isn't as straightforward as git commit -am. This pays out quickly, however. When you do git bisect to find a bug, you'd really appreciate descriptive commits instead of just "Update file" or "Some fixes". When you're reviewing a PR, you can limit the mental burden by looking at individual commits instead of diving straight into 40 files changed. When you're a newcomer and wonder why a function you wanted to use suddenly disappeared before you fully understood the code, you'll be happy to see the reason straight in git log. The same goes for when you git blame to understand why a certain line of code is written the way it is.
If we were to summarize everything written above into just three bullet points, we'd go with:
Always describe the reason for your changes in commit messages like you're talking with the 5-year-old.
Leave only meaningful changes in your PR history. Git history can't and shouldn't encompass everything, just like your school history textbook.
Choose only one person responsible for a feature. Avoid unnecessary interference.
Computes the number of collateral tokens to be seized in a liquidation event
Parameters
comptroller
address
Address of comptroller
vTokenBorrowed
address
Address of the borrowed vToken
vTokenCollateral
address
Address of collateral for the borrow
actualRepayAmount
uint256
Repayment amount i.e amount to be repaid of total borrowed amount
Return Values
[0]
uint256
A tuple of error code, and tokens to seize
[1]
uint256
Computes the number of collateral tokens to be seized in a liquidation event
Parameters
borrower
address
Address of borrower whose collateral is being seized
comptroller
address
Address of comptroller
vTokenBorrowed
address
Address of the borrowed vToken
vTokenCollateral
address
Return Values
[0]
uint256
A tuple of error code, and tokens to seize
[1]
uint256
Computes the number of VAI tokens to be seized in a liquidation event
Parameters
comptroller
address
Address of comptroller
vTokenCollateral
address
Address of collateral for vToken
actualRepayAmount
uint256
Repayment amount i.e amount to be repaid of the total borrowed amount
Return Values
[0]
uint256
A tuple of error code, and tokens to seize
[1]
uint256
Computes the hypothetical liquidity and shortfall of an account given a hypothetical borrow A snapshot of the account is taken and the total borrow amount of the account is calculated
Parameters
comptroller
address
Address of comptroller
account
address
Address of the borrowed vToken
vTokenModify
contract VToken
Address of collateral for vToken
redeemTokens
uint256
Return Values
[0]
uint256
Returns a tuple of error code, liquidity, and shortfall
[1]
uint256
[2]
uint256
Claim all the xvs accrued by holder in all markets and VAI
Parameters
holder
address
The address to claim XVS for
Claim all the xvs accrued by holder in the specified markets
Parameters
holder
address
The address to claim XVS for
vTokens
contract VToken[]
The list of markets to claim XVS in
Claim all xvs accrued by the holders
Parameters
holders
address[]
The addresses to claim XVS for
vTokens
contract VToken[]
The list of markets to claim XVS in
borrowers
bool
Whether or not to claim XVS earned by borrowing
suppliers
bool
Claim all the xvs accrued by holder in all markets, a shorthand for claimVenus with collateral set to true
Parameters
holder
address
The address to claim XVS for
Transfer XVS to the recipient
Parameters
recipient
address
The address of the recipient to transfer XVS to
amount
uint256
The amount of XVS to (possibly) transfer
Seize XVS rewards allocated to holders
Parameters
holders
address[]
Addresses of the XVS holders
recipient
address
Address of the XVS token recipient
Return Values
[0]
uint256
The total amount of XVS tokens seized and transferred to recipient
Claim all xvs accrued by the holders
Parameters
holders
address[]
The addresses to claim XVS for
vTokens
contract VToken[]
The list of markets to claim XVS in
borrowers
bool
Whether or not to claim XVS earned by borrowing
suppliers
bool
Returns the XVS vToken address
Return Values
[0]
address
The address of XVS vToken
The Risk Stewards system introduces a secure and modular mechanism for automatically updating borrow and supply caps in the Venus Protocol. In the earlier model, these risk parameters were modified manually via governance proposals (VIPs). This new architecture eliminates manual intervention by enabling fully on-chain, automated updates.
In this updated model, Chaos Labs provides risk parameter updates through their on-chain Risk Oracle. These updates are delivered directly to dedicated steward contracts, such as MarketCapsRiskSteward, which are responsible for applying the changes to the protocol.
All updates are executed through a central router contract, RiskStewardReceiver
<type>[optional scope]: <description>
[optional body]
[optional footer(s)]struct AccountLiquidityLocalVars {
uint256 sumCollateral;
uint256 sumBorrowPlusEffects;
uint256 vTokenBalance;
uint256 borrowBalance;
uint256 exchangeRateMantissa;
uint256 oraclePriceMantissa;
struct ExponentialNoError.Exp weightedFactor;
struct ExponentialNoError.Exp exchangeRate;
struct ExponentialNoError.Exp oraclePrice;
struct ExponentialNoError.Exp tokensToDenom;
}function liquidateCalculateSeizeTokens(address comptroller, address vTokenBorrowed, address vTokenCollateral, uint256 actualRepayAmount) external view returns (uint256, uint256)function liquidateCalculateSeizeTokens(address borrower, address comptroller, address vTokenBorrowed, address vTokenCollateral, uint256 actualRepayAmount) external view returns (uint256, uint256)function liquidateVAICalculateSeizeTokens(address comptroller, address vTokenCollateral, uint256 actualRepayAmount) external view returns (uint256, uint256)function getHypotheticalAccountLiquidity(address comptroller, address account, contract VToken vTokenModify, uint256 redeemTokens, uint256 borrowAmount, enum WeightFunction weightingStrategy) external view returns (uint256, uint256, uint256)function claimVenus(address holder) publicfunction claimVenus(address holder, contract VToken[] vTokens) publicfunction claimVenus(address[] holders, contract VToken[] vTokens, bool borrowers, bool suppliers) publicfunction claimVenusAsCollateral(address holder) externalfunction _grantXVS(address recipient, uint256 amount) externalfunction seizeVenus(address[] holders, address recipient) external returns (uint256)function claimVenus(address[] holders, contract VToken[] vTokens, bool borrowers, bool suppliers, bool collateral) publicfunction getXVSVTokenAddress() external view returns (address)Placing a bid triggers BidPlaced event which can be monitored.
false
fix
patch
true
refactor
patch
false
test
false
false
Address of collateral for the borrow
actualRepayAmount
uint256
Repayment amount i.e amount to be repaid of total borrowed amount
Number of vTokens being redeemed
borrowAmount
uint256
Amount borrowed
weightingStrategy
enum WeightFunction
The weighting strategy to use: - WeightFunction.USE_COLLATERAL_FACTOR to use collateral factor - WeightFunction.USE_LIQUIDATION_THRESHOLD to use liquidation threshold
Whether or not to claim XVS earned by supplying
Whether or not to claim XVS earned by supplying
collateral
bool
Whether or not to use XVS earned as collateral, only takes effect when the holder has a shortfall
Address of vBNB contract.
Address of Venus Unitroller contract.
Address of VAIUnitroller contract.
Address of wBNB contract
Constructor for the implementation contract. Sets immutable variables.
Parameters
comptroller_
address
The address of the Comptroller contract
vBnb_
address payable
The address of the VBNB
wBNB_
address
The address of wBNB
Initializer for the implementation contract.
Parameters
treasuryPercentMantissa_
uint256
Treasury share, scaled by 1e18 (e.g. 0.2 * 1e18 for 20%)
accessControlManager_
address
address of access control manager
protocolShareReserve_
address
The address of the protocol share reserve contract
An admin function to restrict liquidations to allowed addresses only.
Parameters
borrower
address
The address of the borrower
An admin function to remove restrictions for liquidations.
Parameters
borrower
address
The address of the borrower
An admin function to add the liquidator to the allowedLiquidatorsByAccount mapping for a certain borrower. If the liquidations are restricted, only liquidators from the allowedLiquidatorsByAccount mapping can participate in liquidating the positions of this borrower.
Parameters
borrower
address
The address of the borrower
liquidator
address
An admin function to remove the liquidator from the allowedLiquidatorsByAccount mapping of a certain borrower. If the liquidations are restricted, this liquidator will not be able to liquidate the positions of this borrower.
Parameters
borrower
address
The address of the borrower
liquidator
address
Liquidates a borrow and splits the seized amount between protocol share reserve and liquidator. The liquidators should use this interface instead of calling vToken.liquidateBorrow(...) directly. Checks force VAI liquidation first; vToken should be address of vaiController if vaiDebt is greater than threshold For BNB borrows msg.value should be equal to repayAmount; otherwise msg.value should be zero.
Parameters
vToken
address
Borrowed vToken
borrower
address
The address of the borrower
repayAmount
uint256
The amount to repay on behalf of the borrower
vTokenCollateral
contract IVToken
The collateral to seize
Sets the new percent of the seized amount that goes to treasury. Should be less than or equal to comptroller.liquidationIncentiveMantissa().sub(1e18).
Parameters
newTreasuryPercentMantissa
uint256
New treasury percent (scaled by 10^18).
Sets protocol share reserve contract address
Parameters
protocolShareReserve_
address payable
The address of the protocol share reserve contract
Reduce the reserves of the pending accumulated reserves
Sets the threshold for minimum amount of vaiLiquidate
Parameters
minLiquidatableVAI_
uint256
New address for the access control
Length of the pendingRedeem array to be consider while redeeming in Liquidation transaction
Parameters
newLength_
uint256
Length of the chunk
Pause Force Liquidation of VAI
Resume Force Liquidation of VAI
contract IVBNB vBnbcontract IComptroller comptrollercontract IVAIController vaiControlleraddress wBNBconstructor(address comptroller_, address payable vBnb_, address wBNB_) publicfunction initialize(uint256 treasuryPercentMantissa_, address accessControlManager_, address protocolShareReserve_) external virtualfunction restrictLiquidation(address borrower) externalfunction unrestrictLiquidation(address borrower) externalfunction addToAllowlist(address borrower, address liquidator) externalfunction removeFromAllowlist(address borrower, address liquidator) externalfunction liquidateBorrow(address vToken, address borrower, uint256 repayAmount, contract IVToken vTokenCollateral) external payablefunction setTreasuryPercent(uint256 newTreasuryPercentMantissa) externalfunction setProtocolShareReserve(address payable protocolShareReserve_) externalfunction reduceReserves() externalfunction setMinLiquidatableVAI(uint256 minLiquidatableVAI_) externalfunction setPendingRedeemChunkLength(uint256 newLength_) externalfunction pauseForceVAILiquidate() externalfunction resumeForceVAILiquidate() externalOnly pre-approved steward contracts are allowed to execute logic
Updates adhere to protocol-defined rules such as:
Debounce periods between consecutive updates
Maximum allowable percentage change in parameters
Access control enforced through Venus’s AccessControlManager
This architecture enables faster response to market dynamics while maintaining the safety and integrity of the protocol’s core risk parameters.
The RiskStewardReceiver contract acts as the central entry point for processing on-chain risk parameter updates in the Venus Protocol. It integrates directly with the Chaos Labs Risk Oracle, pulling risk recommendations (like borrow/supply caps) and forwarding them to the appropriate RiskSteward contract (e.g., MarketCapsRiskSteward) for enforcement.
Its key role is to:
Validate, deduplicate, and throttle risk updates,
And delegate the actual update execution to the appropriate steward contract responsible for enforcing specific risk parameter types.
This contract enables a modular and secure pipeline for processing real-time risk recommendations on-chain.
Oracle Integration:
Directly reads data from the IRiskOracle, which provides structured RiskParameterUpdate records.
Per-Type Configuration:
Maintains a riskParameterConfigs mapping to register:
Which updateType is supported,
Which steward contract should handle it,
What debounce period (minimum time between updates) is enforced.
Validation Checks Before Processing: Before an update is executed, the contract validates that:
The update type is active (ConfigNotActive)
The update is not expired (UpdateIsExpired)
Processing Updates: Provides two ways to trigger an update:
processUpdateById(updateId)
processUpdateByParameterAndMarket(updateType, market)
Both functions:
State Tracking:
lastProcessedTime: Tracks last update per (market + updateType) to enforce debounce period
processedUpdates: Marks updates that have already been processed, preventing replay
Governance and Controls:
Uses AccessControlledV8 to restrict who can:
Set or modify risk configs
Pause or unpause the contract
The MarketCapsRiskSteward contract is responsible for processing supply cap and borrow cap updates for Venus markets. These updates originate from the RiskStewardReceiver, which itself receives on-chain recommendations from the Chaos Labs Risk Oracle.
This contract does not fetch or validate updates directly. Instead, it:
Receives validated updates delegated by the RiskStewardReceiver
Performs delta checks to ensure caps are within allowed bounds
Writes new cap values into the correct pool comptroller (either Core or Isolated)
Emits events for transparency and downstream indexing
Parameter Enforcement Applies updates only for:
supplyCap
borrowCap
Source Validation
Ensures updates can only be executed by the trusted RiskStewardReceiver.
→ Any direct call from an external or malicious contract is rejected (OnlyRiskStewardReceiver).
Delta Bounding
Before updating any cap, the new value is validated against the previous cap. The change is only allowed if it’s within the maxDeltaBps (basis points) threshold.
→ Ensures the system remains stable and avoids drastic risk shifts (UpdateNotInRange).
Governance Access
AccessControlledV8 is used to restrict who can:
Set the maxDeltaBps
Initialize the contract
This example walks through a complete end-to-end flow where Chaos Labs updates a borrow cap for a market using the on-chain risk oracle, and the change is processed securely through the steward contracts.
Chaos Labs
Publishes risk parameter updates on-chain via a Risk Oracle
Keeper Bot
External off-chain agent responsible for calling the RiskStewardReceiver to apply updates
RiskStewardReceiver
Central processor that validates updates and routes them to the correct steward
MarketCapsRiskSteward
Applies validated supply/borrow cap updates to the appropriate pool comptroller
Chaos Labs recommends updating the borrow cap for the USDC market (vUSDC) from 5,000,000 to 6,000,000 tokens.
Chaos Labs publishes the following to the on-chain Risk Oracle contract:
This update is stored in the oracle contract and made available via getUpdateById(updateId).
A Keeper Bot regularly polls the Risk Oracle and calls:
Upon receiving the call, RiskStewardReceiver performs strict validations:
✅ Checks that the update is the latest from the oracle for the given market and type
✅ Validates the update is active in config (ConfigNotActive)
✅ Verifies it is not expired (timestamp + 1 day > now) (UpdateIsExpired)
✅ Ensures it is not already processed (ConfigAlreadyProcessed)
✅ Ensures debounce interval has passed for the (market + updateType) pair (UpdateTooFrequent)
If any check fails, the transaction reverts with the corresponding error.
Once the update passes all validations, the RiskStewardReceiver uses the updateType to determine which RiskSteward contract should handle it, and delegates the update to MarketCapsRiskSteward:
Here, the steward performs:
✅ Validates that the msg.sender is RiskStewardReceiver (OnlyRiskStewardReceiver)
✅ Confirms that updateType is either supplyCap or borrowCap (UnsupportedUpdateType)
✅ Retrieves the current cap from the comptroller and validates that the new cap change is within the allowed delta range defined by maxDeltaBps:
✅ Writes the new cap into the pool comptroller:
✅ Emits BorrowCapUpdated(market, newCap) for downstream indexing
✅ Applies the update to the pool’s comptroller, by directly making a call to the appropriate setter function: comptroller.setMarketSupplyCaps(newSupplyCapMarkets, newSupplyCaps)
Once the steward call completes:
The update ID is marked as processed
The (market + updateType) debounce timer is updated with the current block time
RiskParameterUpdated(updateId) is emitted
Keeper calls too late (e.g. after 24h)
UpdateIsExpired
Revert
Keeper tries again for same ID
ConfigAlreadyProcessed
Revert
Another update was already applied for the same market+type
UpdateIsExpired
Revert
Debounce timer has not passed
UpdateTooFrequent
While the Risk Steward system enables secure and automated updates to certain risk parameters, there are important limitations to keep in mind:
This architecture allows updates (e.g., supply and borrow caps) to be applied automatically, without going through the formal governance process.
Critical parameters such as collateral factors, liquidation thresholds, and reserve factors are intentionally excluded.
These parameters are considered sensitive and must be proposed and approved through governance (via Venus Improvement Proposals or VIPs) to ensure proper transparency and community review.
The current design supports only same-chain update processing.
Updates on a specific chain can only be processed if a Risk Oracle is deployed and supported on that chain..
For operational efficiency and monitoring, it would be beneficial to register or reflect these updates on BNB Chain, where monitoring systems and automation (such as keeper bots) are primarily active.
Venus Protocol introduces native ERC-4626 vaults, bringing standardized, composable yield vaults to the Venus ecosystem. This integration represents a significant advancement in making Venus's yield-bearing markets more accessible and composable within the broader DeFi ecosystem.
{
"updateId": 101,
"market": "0x...vUSDC",
"updateType": "borrowCap",
"newValue": 6000000,
"timestamp": 1721036000,
"additionalData": "<encoded underlyingAddress/chainId>"
}riskStewardReceiver.processUpdateById(101); IRiskSteward(riskParameterConfigs[update.updateType].riskSteward).processUpdate(update);The update has not already been processed (ConfigAlreadyProcessed)
The debounce period since the last update has passed (UpdateTooFrequent)
Fetch the update from the risk oracle
Validate its status
Delegate the update execution to the configured IRiskSteward contract
Can be paused to halt all update processing using OpenZeppelin’s PausableUpgradeable
Revert
Chaos Labs sets too large a delta
UpdateNotInRange
Revert
Cap type is misspelled
UnsupportedUpdateType
Revert
Non-receiver tries to call steward
OnlyRiskStewardReceiver
Revert
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 α:
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 calling accrueInterestAndUpdateScore.
In the XVSVault, after depositing or requesting a withdrawal, the function xvsUpdated 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.
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:
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 6 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.
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:
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.
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 the PrimeLiquidityProvider contract
The Prime contract will transfer to itself the available liquidity from the PrimeLiquidityProvider 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 the PrimeLiquidityProvider contract, when the interests are accrued and the estimated APR calculated
Regarding the PrimeLiquidityProvider:
The PrimeLiquidityProvider contract maintains a speed per token (see tokenDistributionSpeeds, 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 PrimeLiquidityProvider provides a function to transfer the available funds to the Prime 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.
Full ERC-4626 Compliance – Interoperable with DeFi primitives (DAOs, aggregators, etc.)
Native Venus Yield Integration – Auto-compounding via vTokens
Gas-Optimized Architecture – Beacon proxy pattern for efficient deployments, so all vaults share the same implementation contract.
Secure & Upgradeable – Governance-controlled upgrades and reward management
ERC-4626 is a tokenized vault standard designed to unify how yield-bearing assets are deposited, managed, and withdrawn in DeFi protocols. It builds on the ERC-20 token standard and introduces a consistent interface for vaults that accept a specific asset (like USDC) and issue shares representing ownership in the vault.
The primary goal of ERC-4626 is standardization—allowing developers to integrate with vaults without needing to understand their internal mechanics. Functions like deposit, withdraw, mint, and redeem, follow predictable behaviors across all compliant contracts.
In essence, ERC-4626 makes it easier for users to earn yield on their assets and for protocols to plug into vaults in a reliable, composable way—enhancing both usability and interoperability across the DeFi ecosystem.
Deploys individual vaults for individual vTokens via BeaconProxy
Ensures deterministic addresses using CREATE2
Managed by Venus Governance
ERC-4626-compliant mint, deposit, redeem, and withdraw functions
Integrates with Venus vToken interest accrual
Handles reward distribution (e.g., XVS)
The factory contract implements a sophisticated deployment system using OpenZeppelin's upgradeability patterns:
UpgradeableBeacon: Stores the current implementation address.
BeaconProxy: Proxy delegates to beacon implementation.
CREATE2: Deterministic deployment with fixed salt for beacon proxies.
Single implementation contract shared by all vaults.
Gas-efficient deployments.
Centralized upgrade capability.
This ensures:
Only legitimate Venus vTokens can create vaults.
Proper asset/vToken pairing.
Compliance with Venus's risk parameters.
Deterministic Deployment: Uses a constant salt to enable deterministic address generation for ERC-4626 vault proxies.
Upgradeable Architecture: Utilizes a beacon proxy pattern to support upgradeability of all deployed vaults via a single beacon.
Vault Tracking: Maintains a mapping createdVaults of vTokens to their corresponding deployed ERC-4626 vaults.
Reward Routing: Allows configuration of a centralized reward recipient for all vaults and supports liquidity mining incentives.
Permissioned Admin: Restricts administrative operations (e.g., setting reward recipient, max loops) via Access Control Manager (ACM).
CreateERC4626 (event): Emitted when a new ERC-4626 vault is created for a vToken.
RewardRecipientUpdated (event): Emitted when the reward recipient address is updated.
SALT (bytes32): Constant salt used for deterministic deployment of vaults.
beacon (UpgradeableBeacon): Stores the address of the beacon contract holding the ERC-4626 vault implementation.
poolRegistry (PoolRegistryInterface): Reference to the Venus Pool Registry contract.
rewardRecipient (address): Address designated to receive liquidity mining rewards.
createdVaults (mapping(address => ERC4626Upgradeable)): Maps vTokens to their deployed ERC-4626 vault instances.
initialize(): Initializes the factory with core configuration.
createERC4626(address vToken): Creates a new ERC-4626 vault for the specified vToken.
computeVaultAddress(address vToken): Returns the predicted address of a vault for a specific vToken.
setRewardRecipient(address newRecipient): Updates the address receiving reward distributions (ACM-restricted).
setMaxLoopsLimit(uint256 loopsLimit): Configures the maximum allowed loop iterations (ACM-restricted).
Admin-Only Functions (via AccessControlledV8):
setRewardRecipient()
setMaxLoopsLimit()
upgradeBeacon() (for emergency fixes)
ensureNonzeroAddress() prevents invalid configurations.
Threat Vector
Mitigation Strategy
Reentrancy
nonReentrant modifiers
Invalid vTokens
PoolRegistry validation
Governance attacks
ACM with timelocks
Upgrade risks
Beacon ownership controls
The VenusERC4626 contract serves as an ERC-4626 compliant wrapper around Venus's yield-bearing vTokens. It inherits from multiple OpenZeppelin and Venus-specific base contracts to provide a secure, feature-rich implementation:
ERC-4626 Compliant: Fully compliant with the ERC-4626 Tokenized Vault standard, enabling integrations with yield aggregators and frontends.
vToken Wrapping: Provides tokenized access to underlying vTokens with proportional interest accrual.
Dual-Stage Initialization: Separates base contract setup and access/reward configuration for modular deployment.
Reward Claiming: Allows vaults to claim accrued rewards and direct them to a predefined recipient.
Failsafes and Admin Tools: Includes recovery mechanisms, such as sweepToken, and loop control for security and operational safety.
ERC4626Upgradeable: Uses OpenZeppelin's 4626 contract as the base implementation of the ERC-4626 standard.
AccessControlledV8: Venus role-based access control system.
ReentrancyGuardUpgradeable: Protection against reentrancy attacks.
MaxLoopsLimitHelper: Prevents gas exhaustion in loops.
ClaimRewards (event): Emitted when rewards are claimed and distributed.
RewardRecipientUpdated (event): Emitted when the reward recipient address is updated.
SweepToken (event): Emitted when ERC-20 tokens are swept from the contract.
vToken (VToken): The underlying Venus vToken being wrapped.
comptroller (IComptroller): The Comptroller contract associated with the vToken.
rewardRecipient (address): Address designated to receive reward tokens.
deposit(uint256 assets, address receiver): Deposits assets and mints shares to the receiver.
mint(uint256 shares, address receiver): Mints exact shares by depositing required assets.
Note - It can mint slightly fewer shares than requested, because vToken.mint rounds down.
withdraw(uint256 assets, address receiver, address owner): Withdraws exact assets and burns shares from the owner.
Note - Receiver can receive slightly more assets than requested, because VToken.redeemUnderlying rounds up
redeem(uint256 shares, address receiver, address owner): Redeems exact shares and transfers assets to the receiver.
totalAssets(): Returns the total underlying assets held by the vault.
initialize(address vToken_): Initializes the vault with the target vToken (first-stage init).
initialize2(address accessControlManager_, address rewardRecipient_, uint256 loopsLimit_): Second-stage initialization with access control, reward recipient, and loop limit.
claimRewards(): Claims all available rewards and sends them to the recipient.
setRewardRecipient(address newRecipient): Updates the reward recipient address (ACM-restricted).
sweepToken(IERC20Upgradeable token): Allows the owner to recover any ERC-20 tokens that were mistakenly sent to the vault.
setMaxLoopsLimit(uint256 loopsLimit): Configures the maximum loop iterations (ACM-restricted).
VenusError(uint256 errorCode): Generic error returned from Venus protocol operations.
ERC4626__ZeroAmount(string operation): Thrown when a zero amount is provided during an operation.
ERC4626__DepositMoreThanMax(): Error triggered when a deposit exceeds the maximum limit.
ERC4626__MintMoreThanMax(): Error triggered when a mint exceeds the maximum limit.
ERC4626__WithdrawMoreThanMax(): Error triggered when a withdrawal exceeds the maximum limit.
ERC4626__RedeemMoreThanMax(): Error triggered when a redeem exceeds the maximum limit.
Validates input parameters.
Calculates shares to mint.
Transfers assets from the user.
Mints vTokens via Venus Protocol.
Issues vault shares to the receiver.
Scenario: Alice deposits 100 USDC.
Alice gets 100 vault shares.
Vault holds 100 vUSDC (earning yield).
Validates input parameters.
Calculates shares to burn.
Redeems underlying assets from Venus.
Transfers assets to the receiver.
Burns vault shares.
Scenario: Alice withdraws 50 USDC (after interest accrual).
Alice receives 50 USDC.
Vault burns shares adjusted for interest (e.g., 48.54 shares at a 1.03 exchange rate).
Reentrancy Protection:
All state-changing functions use the nonReentrant modifier.
Critical Venus operations (mint/redeem) are atomic.
Input Validation:
Zero-address checks are performed via ensureNonzeroAddress.
Zero-amount validation for all operations.
Explicit error codes for Venus operations.
Access Control:
Sensitive functions are protected by Venus's ACM.
The reward recipient can only be changed by authorized accounts.
The divisor used to convert fees to basis points.
The mantissa value representing 1 (used for calculations).
The value representing one dollar in the stable token.
VAI token contract.
The address of the stable token contract.
The address of ResilientOracle contract wrapped in its interface.
The address of the Venus Treasury contract.
The incoming stableCoin fee. (Fee for swapStableForVAI).
The outgoing stableCoin fee. (Fee for swapVAIForStable).
The maximum amount of VAI that can be minted through this contract.
The total amount of VAI minted through this contract.
A flag indicating whether the contract is currently paused or not.
Initializes the contract via Proxy Contract with the required parameters.
Parameters
accessControlManager_
address
The address of the AccessControlManager contract.
venusTreasury_
address
The address where fees will be sent.
oracleAddress_
address
The address of the ResilientOracle contract.
feeIn_
uint256
Swaps VAI for a stable token.
Parameters
receiver
address
The address where the stablecoin will be sent.
stableTknAmount
uint256
The amount of stable tokens to receive.
Return Values
[0]
uint256
The amount of VAI received and burnt from the sender.
Swaps stable tokens for VAI with fees.
Parameters
receiver
address
The address that will receive the VAI tokens.
stableTknAmount
uint256
The amount of stable tokens to be swapped.
Return Values
[0]
uint256
Amount of VAI minted to the sender.
Pause the PSM contract.
Resume the PSM contract.
Set the fee percentage for incoming swaps.
Parameters
feeIn_
uint256
The new fee percentage for incoming swaps.
Set the fee percentage for outgoing swaps.
Parameters
feeOut_
uint256
The new fee percentage for outgoing swaps.
Set the address of the Venus Treasury contract.
Parameters
venusTreasury_
address
The new address of the Venus Treasury contract.
Set the address of the ResilientOracle contract.
Parameters
oracleAddress_
address
The new address of the ResilientOracle contract.
Calculates the amount of VAI that would be burnt from the user.
Parameters
stableTknAmount
uint256
The amount of stable tokens to be received after the swap.
Return Values
[0]
uint256
The amount of VAI that would be taken from the user.
Calculates the amount of VAI that would be sent to the receiver.
Parameters
stableTknAmount
uint256
The amount of stable tokens provided for the swap.
Return Values
[0]
uint256
The amount of VAI that would be sent to the receiver.
Venus Protocol contracts are divided in these repositories:
isolated-pools: Contains core contracts for isolated lending, including logic for supplying, borrowing, liquidations, pool and market deployments, and interest rate models.
oracle: This repo has contracts for oracles that we support as well as logic for validating prices returned from those oracles.
: The core protocol is located in this repo. It contains logic central to lending and borrowing of the core pool.
: The contracts used for proposing, voting and executing changes are kept in the `governance-contracts repo.
: The contracts use to bridge XVS to different networks.
There are 2 categories of isolated pools contracts:
Pool
Risk Management
Pool contracts can be divided into 4 categories:
Configuration
Logic
Miscellaneous
Configuration contracts are used to deploy, configure, and manage pools.
Creating and managing pools is done by the . It can add markets to pools, update pool metadata, and return pool information.
The contract is the central contract for each lending pool. It contains functionality central to borrowing activity in the pool like supplying and borrowing assets and liquidations. Configuration values for the pool such as the liquidation incentive, close factor, and collateral factor can also be set and retrieved from the comptroller. Account liquidity and positions can also be retrieved from the comptroller.
in isolated lending play an identical role as vTokens in the Core Pool. They represent a users supplied tokens to the protocol and can be redeemed (burned) for those tokens.
Isolated Pools use additional contracts such as lenses, rewards, ect.
Users are rewarded for borrowing and lending activities with a reward tokens. The manages these distributions using a configurable rate.
To make querying pool data easier, Isolated Pools contains a that queries and formats pool data. These calls can be gas intensive so as a general rule of thumb this contract should not be used in transactions.
Lending comes with the inherent risk that borrows will not be able to repay their loan, which is a threat to the protocol's insolvency. Venus mitigates this risk with a . A percentage of protocol revenues is transferred to the RiskFund as it is accrued. When bad debt is detected, this fund can be auctioned off and used to cover the bad debt.
When bad deb is auctioned off the contract is responsible for running the action and paying the winner.
The acts as a treasury where each isolated pool can transfer their revenue.
Venus Protocol implements secondary, primary and pivot oracles to create a validation and fallback strategy that avoids creating a single point of a failure by relying on a single source for prices. The contract is responsible for fetching and validating prices for a given vToken and managing which oracles are used for a particular vToken.
is the primary oracle. If a token isn't support by Chainlink then prices will be fetched from a secondary oracle.
is used in the Classic model (Chainlink-compatible interface) as a pivot oracle to validate prices returned by main and fallback oracles.
contract is responsible for fetching token prices from the Binance oracle. It is used as a secondary oracle.
is used as a pivot oracle to validate prices returned by primary and secondary oracles.
Venus Protocol contracts can be grouped as follows:
Lending
Tokens
Vault
Lens
At the heart of the Core Pool is the comptroller. The latest version is . The comptroller is responsible for listing markets, managing user's positions in markets, liquidations, and emitting rewards. It contains setters and getters for market configuration variables such as collateral factor, close factor, and liquidation incentive. Lending actions can be be paused globally or per market from the comptroller.
Each market gets deployed with an interest rate model. The uses a linear curve to determine interest rates based on supply and demand of the asset until it reaches the kink after which there is a sharp increase in rates.
Another interest rate model that can be deployed with markets is the . It is similar to the JumpRateModel except it doesn't include a kink. Instead it contains a fixed base rate.
When a borrow becomes insolvent it may be liquidated. The handles this process. When a borrow is liquidated the seized amount is split between the liquidator and the
Revenue earned by the protocol is kept in the .
XVS is an important token in the Venus ecosystem because it powers Venus governance. The token contract defines a lockable BEP20 token with additional methods that enable voting and vote delegation. To vote, a user must first lock their XVS in the vault.
is the Venus stable coin that can be minted against collateral. Users who mint VAI are charged a fee based on the outstanding supply and price of VAI to keep its value pegged at $1. The controls the amount of VAI a user is allowed to mint which is determined by the collateral a user has provided and their liquidity.
When a user supplies a token to the protocol, vTokens are minted to represent their supply. The contract contains methods that support lending activities for the asset including lending, borrowing and liquidating
XVS Vault
XVS can be locked in the to earn XVS and enable voting. Each XVS locked gives the locking address one vote to use or delegate.
VAI Vault
VAI staked in the earn XVS. Staking rewards are accumulated daily.
ComptrollerLens
The contains methods for fetching the liquidity of an account and the amount of tokens that can be seized for a repayable amount
SnapshotLens
The contains methods for getting the details of account for a specific market or all markets where an account is active.
VenusLens
Protocol level data is made available through the . It contains getters related to XVS distribution, governance, and markets.
There are three main Governance contracts:
GovernorBravoDelegate
AccessControlManager
Timelock
GovernorBravoDelegate
The core logic for governance proposals is in the contract. It enables submitting proposals, moving proposals through time-gated stages, canceling and executing proposals as well as voting logic. The voting threshold as well as timelocks are set on this contract.
AccessControlManager
To enhance security of the protocol, Venus Protocol uses the to grant accounts access to call specific functions on contracts. This contract is responsible for granting and revoking those permissions. It also provides a getter to check if an address is allowed to call a specific function.
Timelock Once a proposal has succeeded its execution is managed by the contract. The Timelock can place the proposal in a queue for execution and execute the proposal. It also enables canceling the proposal.
This is a step-by-step guide on how to perform liquidations on the Venus Protocol. Liquidations involve seizing collateral from under-collateralized accounts to repay outstanding debts. The instructions are targeted towards developers or bots that aim to automate the liquidation process.
Venus Protocol uses two calculations to determine account liquidity: Collateral Factor (CF) and Liquidation Threshold (LT).
Collateral Factor is the percentage of the supplied funds that can be used to cover a loan. Comptroller.getAccountLiquidity in the Core Pool and Comptroller.getBorrowingPower in Isolated Pools return the liquidity or an account. They use the Resilient Oracle to retrieve the value of the asset and the collateral factor for the market to determine the percentage of supply can be used as collateral. Relying on getBorrowingPower is not sufficient for identifying accounts in need of liquidation on Isolated Pools.
The Liquidation Threshold represents the point at which an account becomes under-collateralized, triggering the possibility of liquidation. In the Core Pool this is the same as the collateral factor. In Isolated Pools, the LT can be retrieved with Comptroller.getAccountLiquidity.
Liquidators often use external monitoring systems or other strategies to accurately identify under-collateralized accounts.
By combining the information obtained from these functions, one can accurately identify under-collateralized accounts that are suitable for liquidation.
The Comptroller.minLiquidatableCollateral variable represents the minimal collateral in USD required for regular (non-batch) liquidations. Accounts with collateral below this threshold may not be eligible for non-batch liquidations. It's defined in USD value (18 decimals scale).
The first step to performing a liquidation is to identify under-collateralized accounts. Here's a suggested approach to finding under-collateralized accounts:
Create a record of account balances: To identify under-collateralized accounts efficiently, liquidators can maintain an off-chain mapping of accounts and balances by indexing market events to detect new positions and update existing ones:
Mint: Event emitted when tokens are minted.
Redeem: Event emitted when tokens are redeemed.
Consider using a subgraph to index these events.
Get account balances: Use the vTokenBalancesAll function provided by PoolLens (VenusLens on the Core Pool) to retrieve supply and borrow balances for multiple vTokens associated with an account. This function takes an array of vTokens and the account address as parameters.
Get underlying asset prices: Use the vTokenUnderlyingPriceAll function provided by the PoolLens (VenusLens on the Core Pool) to retrieve the underlying asset prices for multiple vTokens. This function takes an array of vTokens as a parameter.
Calculate liquidity shortfall: With the supply and borrow balances obtained from step 2 and the underlying asset prices from step 3, calculate the liquidity shortfall for each account. This can be done by taking the scalar product of the balances and prices and comparing them against the LT values.
By following this approach, you can efficiently identify under-collateralized accounts based on the CF and LT calculations.
Please note that the functions mentioned above are provided by PoolLens and may require integration within your liquidation bot. Additionally, it's important to stay updated with any changes or updates to Venus Protocol that may impact the process of finding under-collateralized accounts.
Once an under-collateralized account has been identified, the liquidation process can be initiated using either liquidateBorrow , liquidateAccount or healAccount function. liquidateBorrow is provided by the relevant vToken contract (Liquidator contract on the Core Pool) whereas liquidateAccount and healAccount are provided in Comptroller. Here's an overview of the steps involved:
Please note that healAccount is an extension of the liquidation mechanism to address handling of bad debt and offseting it with protocol revenue/fees. On the other hand, liquidateAccount allows batches of liquidations in a single transaction. In both cases, the total collateral must be lower than the threshold Comptroller.minLiquidatableCollateral. Those two functions are only available in Isolated Pools. For Core Pool liquidateBorrow function provided by Liquidator contract is the only available mechanism to perform liquidations.
Calculate the liquidation amount: Determine the amount of debt to be repaid and the collateral to be seized. This is typically calculated by examining the borrower's debt balance, the market's collateral factor, and any discounts or liquidation incentives offered.
When performing the liquidation, there are 3 different types of liquidations that can be called, taking in mind the collateral, minimum liquidatable collateral and solvency of the account:
Collateral > minLiquidatableCollateral --> liquidateBorrow(): Call the liquidateBorrow function on the relevant vToken contract. This function requires several parameters, including the borrower's address, the liquidator's address, the amount of debt to be repaid, and the collateral to be seized. Refer to the vToken contract documentation for specific details on the function's required parameters.
Collateral < minLiquidatableCollateral && account is solvent --> liquidateAccount(): this function liquidates all borrows of the borrower.
Collateral < minLiquidatableCollateral && account is insolvent --> healAccount(): this function seizes all the remaining collateral from the borrower, requires the person initiating the liquidation (msg.sender) to repay the borrower's existing debt, and treats any remaining debt as bad debt. The sender has to repay a certain percentage of the debt, computed as collateral / (borrows * liquidationIncentive)
Handle liquidation results: After invoking liquidateBorrow, monitor the transaction's success and handle any resulting events or errors. Successful liquidations will transfer the seized collateral to the liquidator's address and repay the debt from the borrower's account.
Please note that the liquidation process involves complex calculations and requires a deep understanding of Venus Protocol. It's essential to thoroughly test and validate your liquidation bot before deploying it in a production environment. Additionally, keep track of any changes or updates to the Venus Protocol that may impact the liquidation process.
Usually, accounts are only eligible to be liquidated if they are under-collateralized, as described in the previous sections. An exception is if "forced liquidations" are enabled for a market or an individual account in a market. In this case, borrow positions can be liquidated in that market even when the health rate of the account is greater than 1 (i.e. when the account is sufficiently collateralized). Additionally, the close factor check is ignored, allowing the liquidation of 100% of the debt in one transaction.
This feature is based on the implementation done by Compound V2 . Compound V2 allows "forced liquidations" on markets as soon as the Collateral factor is zero, the Reserve factor is 100% and the borrows are paused. Venus defines a feature flag to enable/disable "forced liquidations", configurable directly via VIP, not based on other parameters. Compound community talked about this feature in .
On Venus, forced liquidations can be enabled either for an entire market (all borrow positions in the market can be forcefully liquidated), or for individual accounts in a market (only the borrows of a particular account can be forcefully liquidated in the market).
To check if forced liquidations are enabled for an entire market, the function Comptroller.isForcedLiquidationEnabled(address vToken) can be called on the Comptroller contract of the pool with the address of the market. To check if forced liquidations are enabled for an individual account in the market, the function Comptroller.isForcedLiquidationEnabledForUser(address borrower, address vToken) can be used, providing the account and market address as arguments.
This feature is disabled. Liquidators will have to change their codebase to consider the forced sequence of liquidations when there is a VAI debt. After having the confirmation from the main Liquidators that they have adapted their code, a VIP will be proposed to enable this feature.
In the previous section, liquidations are carried out on all accounts without taking into consideration specific amounts of VAI debt. The forceVAILiquidate feature enhances the liquidation process by forcing liquidations of borrowers with VAI debt greater than minLiquidatableVAI. Forcing VAI liquidations allows the protocol to better manage risk and prevent potential losses due to excessive VAI debt accumulation.
For borrowers with outstanding VAI debt, the force VAI liquidation first includes checks to ensure that only eligible accounts are liquidated before starting the liquidation process.
Check that VAI liquidations are not paused in Comptroller.
The forceVAILiquidate flag is set to true.
Verify whether the borrower's VAI debt is greater than the minimum amount of liquidatable VAI (initially 1,000 VAI).
If the above conditions are true then the protocol checks that the current vToken sent to be liquidated is VAI, otherwise the liquidation fails.
In the Core Pool, liquidation income is transferred to the Liquidator contract in the form of vTokens. During a liquidation transaction, the Liquidator contract will try to redeem the protocol's portion of the liquidation incentive in vTokens for the underlying tokens. If the redemption process is successful, the underlying tokens will be sent to the ProtocolShareReserve contract. However, if the redemption fails the underlying tokens will be added to a list of pending redemptions and the Liquidator contract will try to redeem the pending redemptions again in subsequent liquidation transactions.
The seized collateral is distributed between the Liquidator and the ProtocolShareReserve contract:
Liquidator's Share:
The Liquidator receives a designated portion of the collateral as an incentive.
ProtocolShareReserve contract's Share:
The Liquidator contract attempts to redeem the protocol's portion of the liquidation incentive in underlying tokens for the VTokens:
Successful Redemption:
If the redemption is successful, the underlying tokens are sent to the ProtocolShareReserve contract.
Failed Redemption:
Subsequent liquidation transactions leverage the list of pending redemptions: during each liquidation, the Liquidator contract attempts to redeem pending VTokens for their underlying tokens, and send these underlying tokens to the ProtocolShareReserve contract.
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 + supplyQVLUser 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// every time accrueInterest is called. delta is interest per score
delta = totalIncomeToDistribute / sumOfMembersScore;
rewardIndex += delta;rewards = (rewardIndex - userRewardIndex) * scoreOfUser;contract VenusERC4626Factory is AccessControlledV8, MaxLoopsLimitHelper {
UpgradeableBeacon public beacon;
mapping(address vToken => ERC4626Upgradeable vault) public createdVaults;
function createERC4626(address vToken) external returns (ERC4626Upgradeable) {
// Deployment logic...
}
}function createERC4626(address vToken) external {
// Validate vToken is registered in PoolRegistry
if (vToken != poolRegistry.getVTokenForAsset(comptroller, underlying)) {
revert VenusERC4626Factory__InvalidVToken();
}
// Proceed with deployment...
}contract VenusERC4626 is
ERC4626Upgradeable,
AccessControlledV8,
MaxLoopsLimitHelper,
ReentrancyGuardUpgradeable {
// Implementation...
}function deposit(uint256 assets, address receiver)
public
override
nonReentrant
returns (uint256)
{
// Input validation
if (assets == 0) revert ERC4626__ZeroAmount("deposit");
if (assets > maxDeposit(receiver)) revert ERC4626__DepositMoreThanMax();
// Process deposit
uint256 shares = previewDeposit(assets);
_deposit(_msgSender(), receiver, assets, shares);
return shares;
}function withdraw(uint256 assets, address receiver, address owner)
public
override
nonReentrant
returns (uint256)
{
// Input validation
if (assets == 0) revert ERC4626__ZeroAmount("withdraw");
if (assets > maxWithdraw(owner)) revert ERC4626__WithdrawMoreThanMax();
// Process withdrawal
uint256 shares = previewWithdraw(assets);
beforeWithdraw(assets); // Redeems from Venus
_withdraw(_msgSender(), receiver, owner, assets, shares);
return shares;
}enum FeeDirection {
IN,
OUT
}uint256 BASIS_POINTS_DIVISORuint256 MANTISSA_ONEuint256 ONE_DOLLARcontract IVAI VAIaddress STABLE_TOKEN_ADDRESScontract ResilientOracleInterface oracleaddress venusTreasuryuint256 feeInuint256 feeOutuint256 vaiMintCapuint256 vaiMintedbool isPausedfunction initialize(address accessControlManager_, address venusTreasury_, address oracleAddress_, uint256 feeIn_, uint256 feeOut_, uint256 vaiMintCap_) externalfunction swapVAIForStable(address receiver, uint256 stableTknAmount) external returns (uint256)function swapStableForVAI(address receiver, uint256 stableTknAmount) external returns (uint256)function pause() externalfunction resume() externalfunction setFeeIn(uint256 feeIn_) externalfunction setFeeOut(uint256 feeOut_) externalfunction setVenusTreasury(address venusTreasury_) externalfunction setOracle(address oracleAddress_) externalfunction previewSwapVAIForStable(uint256 stableTknAmount) external view returns (uint256)function previewSwapStableForVAI(uint256 stableTknAmount) external view returns (uint256)The percentage of fees to be applied to a stablecoin -> VAI swap.
feeOut_
uint256
The percentage of fees to be applied to a VAI -> stablecoin swap.
vaiMintCap_
uint256
The cap for the total amount of VAI that can be minted.
Borrow: Event emitted when underlying is borrowed.
RepayBorrow: Event emitted when a borrow is repaid. By listening to these events, liquidators can track changes in positions and update the balances of users accordingly.
Liquidation Threshold: 60%
Borrow Amount: $13,000
Collateral Amount: $20,000
Liquidation Incentive: 110%
Protocol Share Percentage: 5%
The borrowed amount is $1,000 above the liquidation threshold ($12,000), therefore the position is eligible for liquidation. Liquidation can be called with a repayment of up to $6,500 (borrow amount * close factor). Let's assume the liquidator initiates the liquidation process with a repayment amount of $1,000 Let's Calculate the Collateral Seized Amount (the amount that is seized from the borrower's collateral):
Collateral Seized Amount = Repayment Amount * Liquidation Incentive
Collateral Seized Amount = $1,000 * 1.1
Collateral Seized Amount = $1,100
Therefore, if the borrowed asset value reaches $13,000 and the repayment amount is $1,000, the total collateral seized will be $1,100 considering the liquidation incentive of 10%. In order to calculate what amount the liquidator will get we need to consider treasuryPercentMantissa (in the Core pool) or protocolSeizeShareMantissa (in the Isolated pools). This variable (Protocol Share Percentage) sets the percentage of the collateral seized that will go to the protocol. Let's assume that the protocol shares for liquidations is 5% and calculate the liquidator received amount:
Liquidator Receive Amount = Collateral Seized - Protocol Shares
Protocol Shares = (Collateral Seized / Liquidation Incentive) * Protocol Share Percentage
Protocol Shares = ($1,100 / 1.1) * 0.05 = $50
Liquidator Receive Amount = $1,100 - $50 = $1,050
In conclusion, the liquidator will provide $1,000 for the liquidation. After the liquidation, the liquidator will receive $1,050 and the rest $50 will go to the protocol.
Borrow Amount: $60
Collateral Amount: $90
Position is already eligible for liquidation since Borrow Amount >= $54. We should call liquidateAccount() because collateral < $100 and account is solvent.
Borrow Amount: $90
Collateral Amount: $60
Position is eligible for liquidation and collateral is < $100, but the account is insolvent, so we need to call healAccount() to ensure that the remaining debt ($30) is treated as bad debt for the protocol.
Close factor: 50%
Liquidation incentive: 10%
User with the following positions:
Supply: 500 USDT
Borrow: 200 BUSD
Borrow: 100 USDC
The health rate for this user would be (500 * 0.8) / (200 + 100) = 1.33. So, in normal circumstances, this user is not eligible to be liquidated.
Now, let’s say we enable the forced liquidations in the BUSD market (via VIP). Then:
Anyone will be allowed to liquidate the BUSD position of the previous user. Moreover, the close factor limit won’t be taken into account. So, the following liquidation would be doable:
Repay amount: 200 BUSD
Collateral market to seize: USDT
By doing this liquidation, 220 USDT (repay amount + liquidation incentive) would be seized from the user’s collateral.
After the liquidation, the global position of our user would be:
Supply: 280 USDT (500 USDT - 220 USDT seized during the liquidation)
Borrow: 0 BUSD
Borrow: 100 USDC
So, the new health rate would be (280 * 0.8 / 100) = 2.24. They will be still ineligible for regular liquidations
Because the forced liquidation is not enabled in the USDC market, the USDC debt cannot be liquidated (because the health rate is greater than 1).
2,000 VAI
5,000 USDT
Liquidators will be required to liquidate the VAI position first because it is greater than minLiquidatableVAI. If they try to liquidate first the USDT position, the liquidation transaction will be reverted.
500 VAI
5,000 USDT
Liquidators will be allowed to liquidate first the VAI position or the USDT position. Both liquidations will work because the VAI debt is less than minLiquidatableVAI
ProtocolShareReserve contract.Conversion (if applicable):
BNB:
If the seized collateral is BNB, it is converted to Wrapped BNB (wBNB) before sending it to the ProtocolShareReserve contract.
Other VTokens:
For other VTokens, the underlying tokens are redeemed and transferred to the ProtocolShareReserve contract.
The default max token distribution speed
Address of the Prime contract
The rate at which token is distributed (per block)
The max token distribution speed for token
The rate at which token is distributed to the Prime contract
The token accrued but not yet transferred to prime contract
PrimeLiquidityProvider initializer
Parameters
accessControlManager_
address
AccessControlManager contract address
tokens_
address[]
Array of addresses of the tokens
distributionSpeeds_
uint256[]
New distribution speeds for tokens
maxDistributionSpeeds_
uint256[]
❌ Errors
Throw InvalidArguments on different length of tokens and speeds array
Initialize the distribution of the token
Parameters
tokens_
address[]
Array of addresses of the tokens to be intialized
⛔️ Access Requirements
Only Governance
Pause fund transfer of tokens to Prime contract
⛔️ Access Requirements
Controlled by ACM
Resume fund transfer of tokens to Prime contract
⛔️ Access Requirements
Controlled by ACM
Set distribution speed (amount of token distribute per block)
Parameters
tokens_
address[]
Array of addresses of the tokens
distributionSpeeds_
uint256[]
New distribution speeds for tokens
⛔️ Access Requirements
Controlled by ACM
❌ Errors
Throw InvalidArguments on different length of tokens and speeds array
Set max distribution speed for token (amount of maximum token distribute per block)
Parameters
tokens_
address[]
Array of addresses of the tokens
maxDistributionSpeeds_
uint256[]
New distribution speeds for tokens
⛔️ Access Requirements
Controlled by ACM
❌ Errors
Throw InvalidArguments on different length of tokens and speeds array
Set the prime token contract address
Parameters
prime_
address
The new address of the prime token contract
📅 Events
Emits PrimeTokenUpdated event
⛔️ Access Requirements
Only owner
Set the limit for the loops can iterate to avoid the DOS
Parameters
loopsLimit
uint256
Limit for the max loops can execute at a time
📅 Events
Emits MaxLoopsLimitUpdated event on success
⛔️ Access Requirements
Controlled by ACM
Claim all the token accrued till last block
Parameters
token_
address
The token to release to the Prime contract
📅 Events
Emits TokenTransferredToPrime event
❌ Errors
Throw InvalidArguments on Zero address(token)
Throw FundsTransferIsPaused is paused
Throw InvalidCaller if the sender is not the Prime contract
A public function to sweep accidental ERC-20 transfers to this contract. Tokens are sent to user
Parameters
token_
contract IERC20Upgradeable
The address of the ERC-20 token to sweep
to_
address
The address of the recipient
amount_
uint256
The amount of tokens needs to transfer
📅 Events
Emits SweepToken event
⛔️ Access Requirements
Only Governance
❌ Errors
Throw InsufficientBalance if amount_ is greater than the available balance of the token in the contract
Get rewards per block for token
Parameters
token_
address
Address of the token
Return Values
[0]
uint256
speed returns the per block reward
Accrue token by updating the distribution state
Parameters
token_
address
Address of the token
📅 Events
Emits TokensAccrued event
Get the latest block number
Return Values
[0]
uint256
blockNumber returns the block number
VenusERC4626 is an upgradeable, ERC4626-compliant vault that wraps a Venus vToken, enabling standard ERC4626 vault interactions with the Venus Protocol. It manages deposits, withdrawals, minting, redeeming, and reward distribution, with additional access control and loop limit protections.
uint256 DEFAULT_MAX_DISTRIBUTION_SPEEDaddress primemapping(address => uint256) tokenDistributionSpeedsmapping(address => uint256) maxTokenDistributionSpeedsmapping(address => uint256) lastAccruedBlockmapping(address => uint256) tokenAmountAccruedfunction initialize(address accessControlManager_, address[] tokens_, uint256[] distributionSpeeds_, uint256[] maxDistributionSpeeds_, uint256 loopsLimit_) externalfunction initializeTokens(address[] tokens_) externalfunction pauseFundsTransfer() externalfunction resumeFundsTransfer() externalfunction setTokensDistributionSpeed(address[] tokens_, uint256[] distributionSpeeds_) externalfunction setMaxTokensDistributionSpeed(address[] tokens_, uint256[] maxDistributionSpeeds_) externalfunction setPrimeToken(address prime_) externalfunction setMaxLoopsLimit(uint256 loopsLimit) externalfunction releaseFunds(address token_) externalfunction sweepToken(contract IERC20Upgradeable token_, address to_, uint256 amount_) externalfunction getEffectiveDistributionSpeed(address token_) external view returns (uint256)function accrueTokens(address token_) publicfunction getBlockNumber() public view virtual returns (uint256)loopsLimit_
uint256
Maximum number of loops allowed in a single transaction
The Venus Protocol generates income in various underlying tokens from interest and liquidation fees, that are then sent to the ProtocolShareReserve contract. The ProtocolShareReserve contract disburses these earnings to number of destinations. The distributions to the converter contracts are listed next.
RiskFundConverter
USDT
20%
20%
XVSVaultConverter
XVS
20%
20%
USDTPrimeConverter
USDT
11%
RiskFundConverter
USDT
0%
0%
XVSVaultConverter
XVS
20%
20%
USDTPrimeConverter
USDT
1.2%
XVSVaultConverter
XVS
20%
20%
USDTPrimeConverter
USDT
5%
0%
USDCPrimeConverter
USDC
5%
XVSVaultConverter and every Prime converter are instances of SingleTokenConverter contract.
RiskFundConverter and SingleTokenConverter convert incoming earnings into specific tokens, with RiskFundConverter converting them into RiskFund's convertible base asset and SingleTokenConverters converting them into their baseAsset. Each time a conversion is completed, the resulting tokens are sent to their respective destination addresses.
The following diagram illustrates the flow of funds between contracts and its architecture:
The transfer of funds to and from the ProtocolShareReserve contract are initiated by external agents (permissionless).
The transfers of funds from the Token Converters to their destinations are performed on each conversion. The conversions are performed by external agents (permissionless).
The transfer of XVS from the XVSVaultTreasury to the XVSVault will be performed via VIP.
RiskFundConverter and SingleTokenConverters possess the ability to "facilitate" token conversions for the income they receive, obtaining the desired tokens (base asset) by relying on oracle prices as reference points to accept conversions that external agents will carry out.
Venus encourages these conversions by providing incentives that create arbitrage opportunities in the market, with the expectation that external agents will seize these opportunities.
The diagram below illustrates the connection between income harvesting (the process by which Venus transfers income to the ProtocolShareReserve), distribution (application of the protocol's Tokenomics-defined rules), and conversion (acquiring the required base assets).
RiskFund already includes the integration with the Shortfall contract. The USDT received in the conversions will be auctioned off in the Shortfall contract.
XVSVaultTreasury accumulates the XVS received in the conversions. Those XVS will be sent to the XVSVault eventually via VIP, which will update also the APR in the XVSVault.
PrimeLiquidityProvider accumulates and distributes them according to the speeds configured via VIP.
AbstractTokenConverter contract provides required features to configure and convert desired assets. The RiskFundConverter and the SingleTokenConverters extend this abstract contract (that could also be extended by other contracts in the future because it provides these features agnostically).
There will be one configuration per pair tokenAddressIn / tokenAddressOut. Only authorized contracts (Governance) will be able to add or update these configurations. The configuration for a conversion includes:
tokenAddressIn and tokenAddressOut: address of the token accepted by the converter in the conversion, and the address of the token sent to the user/wallet from the converter in the conversion
incentive: percentage used to increase the amount finally sent to the user (see below).
conversionAccess:
NONE: Conversion is disabled for the pair
ALL: Conversion is enabled for private conversion and users
ONLY_FOR_CONVERTERS: Conversion is enabled only for private conversion (see more about private conversions below)
For example, in the XVSVaultConverter there would be a configuration entry with these values:
tokenAdressIn: XVS token address (the converter accepts XVS)
tokenAddressOut: BTCB token address (the converter offers BTCB)
incentive: 0 (initially there won't be any incentive)
conversionAccess: ALL (everyone can perform conversions of XVS for BTCB in the XVSVaultConverter)
To incentivize conversions we allow an increase in the final amount sent out from the converter contract.
Example:
Given:
Conversion rate provided by the oracle: 1 XVS = 5 USDC
Incentive: 10%
If the user sends 1 XVS to the contract, they will receive 5.5 USDC (5 USDC base + 0.5 USDC applying the incentive).
The incentive is applied on the base out amount calculated using the conversion rate, which is based on oracle prices. Incentives will be defined using normal VIP’s, following the Governance mechanism. Each pair of tokens can have a different incentive value. Bigger incentives can be set for converting tokens with lower liquidity, for example.
View function getAmountOut(uint256 amountInMantissa, address tokenAddressIn, address tokenAddressOut) returns (uint256 amountConvertedMantissa, uint256 amountOutMantissa), to request the amount of tokenAddressOut tokens that a sender would receive providing amountInMantissa tokens of tokenAddressIn.
Where:
Params:
amountInMantissa: the amount of tokenAddressIn tokens the sender would provide to perform the conversion. It is defined in terms of the mantissa of tokenAddressIn
tokenAddressIn: the address of the token provided by the sender to get tokens of tokenAddressOut
tokenAddressOut: the address of the token to get after the conversion
Returned values:
amountConvertedMantissa: the amount of tokenAddressIn that would ultimately be transferred from the sender to the contract. This will be the lesser of the converter's liquidity (available with balanceOf(address token)) or amountConvertedMantissa.
amountOutMantissa
Internally, this function uses:
the oracle to calculate the conversion rate to apply
the configuration for the pair tokenAddressIn / tokenAddressOut, to apply the right discount
There must be a ConversionConfig entry for the pair tokenAddressIn / tokenAddressOut. Otherwise, the transaction is reverted.
The convert functions use this view to calculate how many tokens must be transferred.
Example:
Given:
There is a configuration entry for the pair tokenAddressIn / tokenAddressOut: XVS/USDC. That means, the contract accepts conversions where the sender sends XVS to the contract, and the contract sends USDC to the sender. This would be a possible configuration in the XVSVaultConverter contract.
Current liquidity: 100 USDC
Current conversion rate, given by the oracle: 1 XVS = 5 USDC
Configured discount: 1%
Invocation 1: getAmountOut(15 * 10^18, address(XVS), address(USDC))
It means: how many USDC would the sender receive if they would provide 15 XVS to the contract
Response:
Invocation 2: getAmountOut(25 * 10^18, address(XVS), address(USDC))
How many USDC would the sender receive if they provided 25 XVS to the contract?
In this case, there isn’t enough liquidity to convert 100% of the input amount (25 XVS would be 126.25 USDC), so 100% of the liquidity will be the amountOutMantissa, and this function (getAmountOut) calculates the input amount needed to “cover” that amount (taking into account the discount).
View function getAmountIn(uint256 amountOutMantissa, address tokenAddressIn, address tokenAddressOut) returns (uint256 amountInMantissa, uint256 amountConvertedMantissa), to request the amount of tokenAddressIn tokens that a sender should send to the contract, to receive amountOutMantissa tokens of tokenAddressOut.
Where:
Parameters:
amountOutMantissa: the amount of tokenAddressOut tokens the sender would like to receive in the conversion. It is defined in terms of the mantissa of tokenAddressOut
tokenAddressIn: the address of the token provided by the sender to get tokens of tokenAddressOut
tokenAddressOut: the address of the token to get after the conversion
Returned values:
amountInMantissa: the amount of tokenAddressIn tokens that the sender has to send to the contract to receive amountConvertedMantissa tokens of tokenAddressOut
amountConvertedMantissa
Example:
Invocation 1: getAmountIn(40 * 10^18, address(XVS), address(USDC))
Response:
amountInMantissa: $8 * 10^{18}$ (XVS)
amountConvertedMantissa: $40 * 10^{18}$ (USDC), equal to the amountOutMantissa param
Invocation 2: getAmountIn(120 * 10^18, address(XVS), address(USDC))
Response:
amountInMantissa: $20 * 10^{18}$ (XVS)
Function convertExactTokens(uint256 amountInMantissa, uint256 amountOutMinMantissa, address tokenAddressIn, address tokenAddressOut, address to).
Where:
amountInMantissa: the number of tokens (tokensAddressIn) the sender wants to convert
It’s defined in the mantissa of the tokenAddressIn Example: -amountOutMinMantissa: the minimum amount of tokenAddressOut tokens the sender is willing to receive in the conversion. It’s defined in the mantissa of the tokenAddressOut.
If the amount that would finally be transferred to to is less than amountOutMinMantissa, the transaction is reverted
tokenAddressIn: the address of the token provided by the sender to perform the conversion. For instance, in the XVSVaultConverter and in the RiskFundConverter there will be configurations to accept XVS and USDT token addresses respectively
tokenAddressOut: the address of the token the sender wants to receive with the execution of the conversion
to: the address where the tokens of tokenAddressOut should be sent
The received tokens (amountInMantissa) are transferred, in the same transaction, to the destination address. The destination address is configured as a storage attribute in the AbstractTokenConverter contract.
If the received amount is less than amountInMantissa or the transferred out amount is less than the expected one, the transaction is reverted because we don’t support tokens with fees on transferring in this function.
There must be a ConversionConfig entry for the pair tokenAddressIn / tokenAddressOut. Otherwise, the transaction will be reverted.
What if there is not enough liquidity?
The contract will send to to 100% of the available liquidity, and it will only transfer from the sender the needed amount to cover the conversion (that will be less than the amountInMantissa) It must satisfy the constraint of sending more than amountOutMinMantissa
See the second invocation example in the section Get amount out
Function convertForExactTokens(uint256 amountInMaxMantissa, uint256 amountOutMantissa, address tokenAddressIn, address tokenAddressOut, address to).
Where:
amountInMaxMantissa: the maximum amount of tokenAddressIn tokens that the sender wants to convert. If the needed amount is greater than this param, the transaction is reverted
amountOutMantissa: the exact amount of tokenAddressOut tokens that the sender wants to receive in the conversion
tokenAddressIn: the address of the token that the sender is providing to complete the conversion
tokenAddressOut: the address of the token that the sender wants to receive in the conversion
to: the address where the tokens of tokenAddressOut should be sent
The received tokens (amountInMantissa) are transferred, in the same transaction, to the destination address. The destination address is configured as a storage attribute in the AbstractTokenConverter contract.
If the received or the transferred out amounts are less than the required amounts, the transaction is reverted, because we don’t support tokens with fees on transferring in this function.
There must be a ConversionConfig entry for the pair tokenAddressIn / tokenAddressOut. Otherwise, the transaction will be reverted.
This implementation of this function can use the getAmountIn function internally because the same liquidity check is needed. If the amountConvertedMantissa amount is less than the param amountOutMantissa, the transaction is reverted. This constraint is similar to checking that the liquidity of tokenAddressOut is less than amountOutMantissa.
Private Conversions aims to maximize the conversion of tokens received from the ProtocolShareReserve contract (to any converter) among existing converters in the same ConverterNetwork contract. This is done to preserve incentives and reduce the dependency on users to perform conversions. Converters will autonomously carry out Private Conversions whenever funds are received from ProtocolShareReserve. No incentives will be provided during this process.
The following diagram illustrates the flow of private conversion.
The RiskFundConverter contract extends the AbtractTokenConverter contract. It maintains a distribution of assets per comptroller and assets. ProtocolShareReserve sends the RiskFund's share of income to this contract which will convert the assets and send them to the RiskFund contract.
The SingleTokenConverter contract extends the AbtractTokenConverter contract. ProtocolShareReserve distributes the income share among various SingleTokenConverter contracts, such as the USDTPrimeConverter contract. This particular contract facilitates the conversion of assets to its base asset and subsequently sends them to their designated destination address.
Users can convert tokens through these contracts(RiskFundConverter and SingleTokenConverters) and receive the converted tokens along with an incentive. A conversion config for the tokenAddressIn / tokenAddressOut pair is necessary for a successful conversion; otherwise, the conversion will revert.
One instance of XVSVaultTreasury is configured as the destination address in the XVSVaultConverter. This treasury is used to fund the XVSVault.
This contract contains the list of all the converters and will provide valid converters which can perform conversions. Converters will interact with this contract to get the list of other converters open for Private Conversions.
NO_ERROR (uint256, internal constant):
Error code representing no errors in Venus operations.
vToken (VToken, public):
The Venus vToken associated with this ERC4626 vault.
comptroller (IComptroller, public):
The Venus Comptroller contract responsible for market operations.
rewardRecipient (address, public):
The address that receives rewards distributed by the Venus Protocol.
ClaimRewards(uint256 amount, address indexed rewardToken)
Emitted when rewards are claimed.
amount: The amount of reward tokens claimed.
rewardToken: The address of the reward token claimed.
RewardRecipientUpdated(address indexed oldRecipient, address indexed newRecipient)
Emitted when the reward recipient address is updated.
oldRecipient: The previous reward recipient address.
newRecipient: The new reward recipient address.
SweepToken(address indexed token, address indexed receiver, uint256 amount)
Emitted when tokens are swept from the contract.
token: The token address.
receiver: The receiver address.
VenusERC4626__VenusError(uint256 errorCode)
Thrown when a Venus protocol call returns an error.
errorCode: The error code returned by Venus.
ERC4626__DepositMoreThanMax()
Thrown when a deposit exceeds the maximum allowed.
ERC4626__MintMoreThanMax()
Thrown when a mint operation exceeds the maximum allowed.
ERC4626__WithdrawMoreThanMax()
Thrown when a withdrawal exceeds the maximum available assets.
ERC4626__RedeemMoreThanMax()
Thrown when a redemption exceeds the maximum redeemable shares.
ERC4626__ZeroAmount(string operation)
Thrown when attempting an operation with a zero amount.
operation: The name of the operation (e.g., "deposit", "withdraw", "mint", "redeem").
@custom:oz-upgrades-unsafe-allow constructor Disables initializers for the upgradeable contract pattern.
Initializes the VenusERC4626 vault with the associated vToken address.
Parameters
vToken_
address
The vToken associated with the vault, representing the yield-bearing asset.
Notes
Only the vToken address is set in this function.
initialize2 must be called to complete the configuration.
Completes the configuration of the VenusERC4626 vault by setting additional attributes.
Parameters
accessControlManager_
address
The address of the access control manager contract.
rewardRecipient_
address
The initial recipient of rewards.
loopsLimit_
uint256
The maximum number of loops for certain operations to enhance security.
vaultOwner_
address
The address of the vault owner.
Notes
Can only be called once.
Use with caution to avoid misconfiguration.
Sets the maximum number of loops for certain operations.
Parameters
loopsLimit
uint256
The new maximum loops limit to be set.
Events
Emits MaxLoopsLimitUpdated on success.
Access
Controlled by the Access Control Manager (ACM).
Sets a new recipient for rewards distributed by the Venus Protocol.
Parameters
newRecipient
address
The address of the new reward recipient.
Events
Emits RewardRecipientUpdated on success.
Access
Controlled by the ACM.
Sweeps the specified token from the contract and sends it to the contract owner.
Parameters
token
IERC20Upgradeable
Address of the token.
Events
Emits SweepToken on success.
Access
Only the owner.
Claims rewards from all reward distributors associated with the vToken and transfers them to the reward recipient.
Notes
Iterates through all reward distributors fetched from the comptroller, claims rewards, and transfers them if available.
Deposits assets into the vault, minting corresponding shares to the receiver.
Parameters
assets
uint256
The amount of assets to deposit.
receiver
address
The address to receive shares.
Returns
shares
uint256
Amount of shares minted.
Notes
Overrides ERC4626Upgradeable deposit.
Includes non-reentrant protection and custom Venus logic.
Mints new shares of the vault, allocating the corresponding amount of assets to the receiver.
Parameters
shares
uint256
The amount of shares to mint.
receiver
address
The address to receive shares.
Returns
assets
uint256
Amount of assets deposited.
Notes
Overrides ERC4626Upgradeable mint.
Includes non-reentrant protection and custom Venus logic.
Withdraws assets from the vault, burning the corresponding amount of shares from the owner's balance.
Parameters
assets
uint256
The amount of assets to withdraw.
receiver
address
The address to receive assets.
owner
address
The address whose shares are burned.
Returns
shares
uint256
Amount of shares burned.
Notes
Overrides ERC4626Upgradeable withdraw.
Includes non-reentrant protection and custom Venus logic.
Redeems shares of the vault, returning the corresponding amount of assets to the receiver.
Parameters
shares
uint256
The amount of shares to redeem.
receiver
address
The address to receive assets.
owner
address
The address whose shares are redeemed.
Returns
assets
uint256
Amount of assets returned.
Notes
Overrides ERC4626Upgradeable redeem.
Includes non-reentrant protection and custom Venus logic.
Returns the total amount of assets managed by the vault, including both deposited assets and accrued rewards.
Returns
assets
uint256
Total assets managed by the vault.
Notes
Overrides ERC4626Upgradeable totalAssets.
Returns the maximum deposit allowed, based on Venus supply caps.
Parameters
account
address
The address of the account.
Returns
amount
uint256
Maximum assets that can be deposited.
Notes
Returns 0 if minting is paused or the supply cap has been reached.
Returns the maximum amount of shares that can be minted.
Parameters
account
address
The address of the account.
Returns
shares
uint256
Maximum shares that can be minted.
Notes
Derived from the maximum deposit amount converted to shares.
Returns the maximum amount of assets that can be withdrawn.
Parameters
receiver
address
The address of the account withdrawing.
Returns
amount
uint256
Maximum assets that can be withdrawn.
Notes
This value is limited by the available cash in the vault.
Returns the maximum amount of shares that can be redeemed.
Parameters
receiver
address
The address of the account redeeming.
Returns
shares
uint256
Maximum shares that can be redeemed.
Notes
Limited by the available cash in the vault.
This is the implementation contract for the VAIUnitroller proxy
Initial index used in interest computations
poolId for core Pool
The mintVAI function mints and transfers VAI from the protocol to the user, and adds a borrow balance. The amount minted must be less than the user's Account Liquidity and the mint vai limit.
Parameters
Return Values
The repay function transfers VAI interest into the protocol and burns the rest, reducing the borrower's borrow balance. Before repaying VAI, users must first approve VAIController to access their VAI balance.
Parameters
Return Values
The repay on behalf function transfers VAI interest into the protocol and burns the rest, reducing the borrower's borrow balance. Borrowed VAIs are repaid by another user (possibly the borrower). Before repaying VAI, the payer must first approve VAIController to access their VAI balance.
Parameters
Return Values
The sender liquidates the vai minters collateral. The collateral seized is transferred to the liquidator.
Parameters
Return Values
Sets a new comptroller
Return Values
Set the prime token contract address
Parameters
Set the VAI token contract address
Parameters
Toggle mint only for prime holder
Return Values
Function that returns the amount of VAI a user can mint based on their account liquidy and the VAI mint rate If mintEnabledOnlyForPrimeHolder is true, only Prime holders are able to mint VAI
Parameters
Return Values
Update treasury data
Parameters
Gets yearly VAI interest rate based on the VAI price
Return Values
Get interest rate per block
Return Values
Get the last updated interest index for a VAI Minter
Parameters
Return Values
Get the current total VAI a user needs to repay
Parameters
Return Values
Calculate how much VAI the user needs to repay
Parameters
Return Values
Accrue interest on outstanding minted VAI
Sets the address of the access control of this contract
Parameters
Set VAI borrow base rate
Parameters
Set VAI borrow float rate
Parameters
Set VAI stability fee receiver address
Parameters
Set VAI mint cap
Parameters
Return the address of the VAI token
Return Values
Venus Protocol has natively integrated a sophisticated flash loan mechanism directly into its Core Pool, enabling users to borrow assets without collateral, provided the loan is repaid within the same transaction. This feature unlocks powerful DeFi strategies including arbitrage, self-liquidation, and portfolio rebalancing, while maintaining the protocol's security and capital efficiency.
The system is designed for seamless integration with existing Venus markets, offering a trustless and composable foundation for advanced financial operations.
function initialize(address vToken_) public initializerfunction initialize2(address accessControlManager_, address rewardRecipient_, uint256 loopsLimit_, address vaultOwner_) publicfunction setMaxLoopsLimit(uint256 loopsLimit) externalfunction setRewardRecipient(address newRecipient) externalfunction sweepToken(IERC20Upgradeable token) external onlyOwnerfunction claimRewards() externalfunction deposit(uint256 assets, address receiver) public override nonReentrant returns (uint256)function mint(uint256 shares, address receiver) public override nonReentrant returns (uint256)function withdraw(uint256 assets, address receiver, address owner) public override nonReentrant returns (uint256)function redeem(uint256 shares, address receiver, address owner) public override nonReentrant returns (uint256)function totalAssets() public view virtual override returns (uint256)function maxDeposit(address account) public view virtual override returns (uint256)function maxMint(address account) public view virtual override returns (uint256)function maxWithdraw(address receiver) public view virtual override returns (uint256)function maxRedeem(address receiver) public view virtual override returns (uint256)amount: The amount swept.
ONLY_FOR_USERS: Conversion is enabled only for userstokenAddressOutamountInMantissatokenAddressIntokenAddressOutamountConvertedMantissa: $ 15 * 10^{18} $ There is enough liquidity of USDC to use 100% of the provided amountamountOutMantissa: $(15 * (5/1) * 10^{18}) * 1.01 = 75.75 * 10^{18}$. That is 75.75 USDC.
Where:
15 is the input amount
1,01 is the application of the discount
5/1 is the conversion rate given by the oracles
Response:
amountConvertedMantissa: $((100 / 1,01) / 5) * 10^{18}$ = 19.80$ Where:
100 is the liquidity of USDC in the contract
1,01 is the application of the discount
5 is the conversion rate given by the oracles
19.80 is the amount of XVS needed to review the available liquidity
amountOutMantissa: 100 * 10^18. That is 100 USDC
tokenAddressOutamountInMantissatokenAddressInamountConvertedMantissa: $100 * 10^{18}$ (USDC), different from the amountOutMantissa param because there is not enough liquidity0%
USDCPrimeConverter
USDC
6%
0%
BTCBPrimeConverter
BTCB
1%
0%
ETHPrimeConverter
ETH
2%
0%
WBNBBurnConverter
WBNB
25%
25%
0%
USDCPrimeConverter
USDC
1.2%
0%
WBTCPrimeConverter
WBTC
0.6%
0%
WETHPrimeConverter
WETH
17.0%
0%
0%
WBTCPrimeConverter
WBTC
3%
0%
WETHPrimeConverter
WETH
7%
0%
mintVAIAmount
uint256
The amount of the VAI to be minted.
[0]
uint256
0 on success, otherwise an error code
amount
uint256
The amount of VAI to be repaid.
[0]
uint256
Error code (0=success, otherwise a failure, see ErrorReporter.sol)
[1]
uint256
Actual repayment amount
borrower
address
The account to repay the debt for.
amount
uint256
The amount of VAI to be repaid.
[0]
uint256
Error code (0=success, otherwise a failure, see ErrorReporter.sol)
[1]
uint256
Actual repayment amount
borrower
address
The borrower of vai to be liquidated
repayAmount
uint256
The amount of the underlying borrowed asset to repay
vTokenCollateral
contract VTokenInterface
The market in which to seize collateral from the borrower
[0]
uint256
Error code (0=success, otherwise a failure, see ErrorReporter.sol)
[1]
uint256
Actual repayment amount
[0]
uint256
uint256 0=success, otherwise a failure (see ErrorReporter.sol for details)
prime_
address
The new address of the prime token contract
vai_
address
The new address of the VAI token contract
[0]
uint256
uint256 0=success, otherwise a failure (see ErrorReporter.sol for details)
minter
address
The account to check mintable VAI
[0]
uint256
Error code (0=success, otherwise a failure, see ErrorReporter.sol for details)
[1]
uint256
Mintable amount (with 18 decimals)
newTreasuryGuardian
address
New Treasury Guardian address
newTreasuryAddress
address
New Treasury Address
newTreasuryPercent
uint256
New fee percentage for minting VAI that is sent to the treasury
[0]
uint256
uint256 Yearly VAI interest rate
[0]
uint256
uint256 Interest rate per bock
minter
address
Address of VAI minter
[0]
uint256
uint256 Returns the interest rate index for a minter
account
address
The address of the VAI borrower
[0]
uint256
(uint256) The total amount of VAI the user needs to repay
borrower
address
The address of the VAI borrower
repayAmount
uint256
The amount of VAI being returned
[0]
uint256
Amount of VAI to be burned
[1]
uint256
Amount of VAI the user needs to pay in current interest
[2]
uint256
Amount of VAI the user needs to pay in past interest
newAccessControlAddress
address
New address for the access control
newBaseRateMantissa
uint256
the base rate multiplied by 10**18
newFloatRateMantissa
uint256
the VAI float rate multiplied by 10**18
newReceiver
address
the address of the VAI fee receiver
_mintCap
uint256
the amount of VAI that can be minted
[0]
address
The address of VAI
Multi-Asset Support – Borrow single or multiple assets in a single atomic transaction, enabling complex strategies across different markets without intermediate steps.
Adaptive Repayment Logic:
Instant Full Repayment: Repay the full principal plus flashLoan fees to complete the transaction (standard flash loan model).
Partial Repayment Conversion: If a user has existing supplied collateral and repays partially, the outstanding balance automatically converts to a traditional borrow position secured by their collateral, preventing liquidation and failed transactions.
Streamlined Fee Mechanism:
A single configurable flashLoanFeeMantissa determines the total cost of the loan.
The protocol's share (flashLoanProtocolShare) is automatically calculated and routed to the Protocol Share Reserve, ensuring proper incentive alignment for the ecosystem.
Robust Security Model:
Governance Controlled: Critical parameters (fee structure, activation) are managed through Venus's governance system.
Upgradeable Design: Built using modular architecture for future improvements and maintenance.
Non-Custodial: Funds never leave the protocol's control during the transaction, eliminating counterparty risk.
This architecture positions Venus as a capital-efficient platform for both simple flash loans and sophisticated multi-step strategies, all while maintaining the protocol's security guarantees and economic sustainability.
A flash loan is an uncollateralized loan that must be initiated and repaid within the boundaries of a single atomic transaction. This atomicity is enforced by the blockchain itself; if the borrowed amount plus fees is not returned to the protocol by the end of the transaction, the entire operation reverts as if it never happened. This mechanism eliminates credit risk for the protocol while granting users unprecedented capital efficiency.
Venus Protocol significantly enhances the basic flash loan model by introducing a partial repayment system, adding a crucial layer of flexibility and user safety.
1. Instant Full Repayment (Classic Model): The borrower repays the entire principal plus the accrued fee within the transaction. This is the standard flash loan model used for strategies like arbitrage and liquidation, where the profit is guaranteed to cover the cost.
2. Partial Repayment & Automatic Debt Conversion (Venus Model): This is a unique fail-safe mechanism. The user must repay at least the flash loan fee; otherwise, the transaction will revert. However, if a borrower repays the fee but cannot fully repay the principal and has existing supplied collateral on Venus, the protocol does not force a full revert. Instead, the unpaid principal shortfall is automatically converted into a standard borrow position against the user's existing collateral. This prevents immediate liquidation from a failed flash loan and allows for more complex, multi-block strategy planning. Crucially, for users with no collateral, full repayment of both principal and fee remains mandatory. Any shortfall will cause the transaction to revert, protecting the protocol from unsecured debt.
Let's imagine a user, Alice, who has supplied 10 ETH as collateral on Venus.
Objective: Alice uses a flash loan to perform a complex arbitrage trade that she expects will take several transactions to complete.
Action: She takes a flash loan of 100,000 USDC.
Outcome A (Success): Her arbitrage is successful within the single transaction. She repays the 100,000 USDC plus a 0.09% fee (90 USDC). The transaction completes, and she keeps her profit.
Outcome B (Partial Success - Venus's Advantage):
Her strategy only partially works. By the end of the transaction, she has only generated 80,000 USDC, leaving a shortfall of 20,000 USDC plus the fee.
On another protocol, her transaction would revert, she'd lose her gas fees, and potentially miss her profit opportunity.
On Venus, because she has 10 ETH as collateral and she has repaid the flashLoan fee amount, the protocol does not revert. Instead, it automatically converts the 20,000 USDC shortfall into a standard borrow position against her 10 ETH. Her flash loan is settled, and she now has a regular debt to manage over time, potentially still allowing her to profit from the 80,000 USDC she successfully generated.
Outcome C (Failure):
Her strategy fails completely. She is only able to repay 50 USDC of the 90 USDC fee, leaving both a fee shortfall and the full principal unpaid.
In this scenario, the transaction will revert. The protocol's safety mechanism triggers because the user must repay at least the full flash loan fee, regardless of their collateral position. This protects the protocol from accumulating bad debt.
This innovative approach makes Venus flash loans both more powerful and more accessible, enabling a wider range of financial strategies while maintaining robust protocol security.
Handles core flash loan operations including:
Asset transfers
Fee calculations
Repayment logic
Event emissions
Explanation: This function serves as the main entry point for initiating both single or multi-asset flash loans. It orchestrates the complete flash loan lifecycle through a phased approach: validating request parameters, transferring multiple assets, executing the user's custom logic via a callback, and enforcing repayment with fee distribution. The entire operation is atomic; if any condition fails (e.g., insufficient repayment or unauthorized access), the transaction reverts, ensuring protocol safety.
Array Integrity: Ensures the vTokens and underlyingAmounts arrays are non-empty and of identical length to prevent parameter mismatches.
Asset Checks: For each vToken, verifies that:
The vToken is listed.
Flash loans are enabled for the asset (isFlashLoanEnabled()).
The requested loan amount is non-zero.
Authorization:
Initiator Authorization: Validates that the initiating contract (msg.sender) is pre-authorized (authorizedFlashLoan[msg.sender]) by the protocol to execute flash loans. This ensures only whitelisted, secure contracts can perform these operations.
Delegate Authorization: If the flash loan is executed on behalf of another user (onBehalf), it additionally validates that the initiator is an approved delegate (approvedDelegates[onBehalf][msg.sender]) for that specific user. This enables delegated trading strategies while maintaining security.
Address Validation: Ensures the receiver contract is a non-zero address.
The core logic is delegated to an internal function that structures the process into three distinct phases:
Fee Calculation: Computes the total fee and protocol fee for each asset using the vToken's fee parameters.
Asset Transfer: Calls transferOutUnderlying on each vToken contract to disburse the underlying assets to the receiver contract.
Balance Snapshot: Records the cash balance of each vToken market after transfer for subsequent repayment verification.
Callback Invocation: Calls executeOperation on the receiver contract, passing the loan details (assets, amounts, fees, initiator, onBehalf) and the param data. This is where the user's custom strategy (e.g., arbitrage, liquidation) is executed.
Approval Tracking: Returns an array (tokensApproved) indicating whether the receiver approved each asset for repayment transfer.
Repayment Processing: For each asset, handles repayment based on the receiver's approval and the amount transferred back:
Full Repayment: If the receiver approved and transferred the full amount (principal + fees), the loan is settled.
Debt Conversion: If the receiver did not approve or only partially repaid(atleast the fees), the shortfall is converted into a standard borrow position for the onBehalf (requires existing collateral).
Fee Distribution: Routes the protocol's share of fees to the Protocol Share Reserve (PSR) and credits supplier fees to the respective vToken markets.
Balance Verification: Ensures the final vToken balances reflect the correct repayment amounts, reverting if discrepancies are detected.
Upon successful completion, a FlashLoanExecuted event is emitted, logging the receiver address, the vTokens involved, and the amounts loaned.
Non-Reentrancy: The function and its internal phases are protected against reentrancy attacks (implied by nonReentrant modifier or equivalent checks).
Atomicity: The entire operation succeeds or reverts entirely, preventing partial state changes.
Authorization Enforcement: Strict access control ensures only whitelisted initiators can trigger flash loans.
Collateral Checks: For debt conversion, the initiator must have sufficient collateral to cover the converted borrow position; otherwise, the transaction reverts.
This file contains administrative functions to manage flash loan permissions.
Explanation:
This function is a central access control mechanism. In its initial phase, flash loans might be permissioned to prevent unknown or potentially malicious contracts from using the system until it's battle-tested. This function allows the admin or governance approved address to explicitly grant or revoke permission for a specific address (account) to call the executeFlashLoan function.
Whitelisting (_isWhiteListed = true) : Adds the account to a mapping of allowed addresses. This account can now initiate flash loans for itself.
Blacklisting/Removing (_isWhiteListed = false) : Removes the account from the whitelist, revoking its permission to initiate flash loans.
This is a temporary measure often used during a phased rollout before opening the system to permissionless access.
Manages the underlying asset transfers, flash loan fee calculations, and creation of debt positions.
1.transferOutUnderlyingFlashLoan
Explanation: This function is the work horse for moving assets during flash loan operations. When FlashLoanFacet.sol calls this during a flash loan, it performs several critical actions:
Authorization Check: Ensures only the Comptroller contract can call this function.
Flash Loan State Management: Sets the flashLoanAmount to track the active flashloan and prevents concurrent flash loans.
Asset Transfer: Performs the low-level transfer of the underlying asset to the receiver address.
Event Emission: Emits TransferOutUnderlyingFlashLoan event for tracking.
2. calculateFlashLoanFee
Explanation: This function computes the cost of a flash loan by calculating the total fee and the protocol's share. It uses fixed-point arithmetic to ensure precision in fee calculations, which is critical for maintaining protocol economics and ensuring accurate revenue distribution between suppliers and the protocol.
Total Fee Calculation : Multiplies the loan amount by the global flashLoanFeeMantissa (a scaled value, e.g., 0.09% represented as 9e14).
Protocol Fee Allocation : Calculates the protocol's portion by multiplying the totalFee by flashLoanProtocolShare (a scaled value representing the protocol's percentage share).
3. transferInUnderlyingFlashLoan
Explanation: This function handles the repayment phase of flash loans with enhanced parameter validation. When called by the Comptroller, it performs several critical operations:
Authorization Check: Ensures only the Comptroller contract can call this function.
Asset Collection: Transfers the repayment amount from the receiver contract to the vToken.
Repayment Validation: Validates that the actual transferred amount meets the minimum fee requirement.
Protocol Fee Distribution: Automatically transfers the protocol fee portion to the Protocol Share Reserve.
State Management: Resets the flashLoanAmount to 0, completing the flash loan cycle.
Event Emission: Emits TransferInUnderlyingFlashLoan event with detailed repayment information.
3. setFlashLoanEnabled
Explanation: An administrative function that allows governance to explicitly enable or disable flash loan functionality for a specific vToken market. Unlike a toggle function, this takes a boolean parameter to set the exact desired state, preventing accidental state changes. This would be used to disable flash loans if a vulnerability is suspected in a particular asset's market or to enable them after security verification.
4. setFlashLoanFeeMantissa
Explanation: This governance-controlled function updates the core economic parameters for flash loans. It allows the protocol to adjust both the total fee charged for flash loans and how that fee is distributed between the protocol treasury and liquidity suppliers. These parameters directly impact the protocol's revenue generation and the attractiveness of providing liquidity.
flashLoanFeeMantissa_ : This is the total fee rate charged for flash loans (scaled by 1e18).
flashLoanProtocolShare_ : This is the percentage of the total fee allocated to the Protocol Share Reserve (scaled by 1e18).
5. getCash
Explanation: This function provides cash balance reporting with modified behavior during active flash loan operations. During normal operations, it returns the actual underlying token balance held by the vToken contract. However, during active flash loans (flashLoanAmount > 0), it returns the reduced cash balance reflecting funds temporarily transferred out.
The protocol now internally uses _getCashPriorWithFlashLoan() which returns getCashPrior() + flashLoanAmount to calculate total available liquidity including active flash loans. This design ensures accurate accounting while maintaining protocol stability through consistent interest rate and exchange rate calculations.
There is a standardized interface for contracts wishing to receive and handle flash loans from Venus Protocol:
Purpose: For complex strategies requiring multiple assets in a single flash loan operation.
Interface: IFlashLoanReceiver
Key Parameters:
vTokens: Array of VToken addresses borrowed
amounts: Corresponding amounts for each asset
premiums: Fee amounts for each asset
initiator: Address that initiated the flash loan
onBehalf: Address whose debt position will be used for any unpaid balance
param: Custom encoded data for strategy execution
Return Value:
success: Success status (must return true for transaction to complete)
repayAmounts: Array of actual repayment amounts for each asset
Base Contract: FlashLoanReceiverBase
Provides immutable Comptroller reference
Inherited by multi-asset receiver contracts
Ensures protocol governance integration
Use Cases: Cross-protocol arbitrage, multi-asset liquidations, complex portfolio rebalancing.
Receiver Contracts Must:
Receive Assets: Acknowledge and handle the received flash-loaned assets.
Execute Strategy: Perform intended operations (arbitrage, liquidation, etc.)
Ensure Repayment: Ensure sufficient funds are available and approved for repayment:
Must approve at least the fee amount to each vToken contract
Return actual repayment amounts in the repayAmounts array
For partial repayment: unpaid balance becomes debt against onBehalf address
Return Success: Return true to signal successful operation.
Handle Reversion: If operation fails, return false or revert to unwind the entire transaction.
Critical Security Note: The entire flash loan transaction is atomic. If executeOperation returns false or reverts, the entire transaction reverts, ensuring protocol safety while allowing complex strategies to fail gracefully.
TransferOutUnderlyingFlashLoan - Emitted on successful transfer of amount to receiver during flash loan initiation.
TransferInUnderlyingFlashLoan - Emitted on successful transfer of repayment amount from receiver to vToken.
FlashLoanExecuted – Emitted after a flash loan is executed successfully.
FlashLoanStatusChanged – Emitted when flash loan status is changed for a market.
IsAccountFlashLoanWhitelisted – Emitted when trying to set whitelist flashloan account.
FlashLoanNotEnabled - Thrown if flash loan is not enabled for the asset.
InvalidAmount - Thrown when the requested flash loan amount is zero.
SenderNotAuthorizedForFlashLoan - Thrown when the sender is not authorized to use flash loan.
NoAssetsRequested - Thrown if no assets are requested for the flash loan.
InvalidFlashLoanParams - Thrown if the flash loan params are invalid.
ExecuteFlashLoanFailed - Thrown when executeOperation on the receiver contract fails.
NotEnoughRepayment - Thrown if the repayment amount is less than the required total fee.
FailedToCreateDebtPosition - Thrown when failing to create a debt position.
InvalidComptroller - Thrown if the caller is not the Comptroller contract.
FlashLoanAlreadyActive - Thrown if a flash loan is already in progress.
NotAnApprovedDelegate - Thrown when the sender is not an approved delegate for the onBehalf address.
MarketNotListed - Thrown when trying to flash loan from a market that is not listed in the core pool.
InsufficientRepayment - Thrown when the actual transferred amount is less than the required total fee.
User: Alice (has 10 ETH collateral on Venus)
Goal: Arbitrage 100,000 USDC between DEXs
Request: Alice's ArbitrageContract calls executeFlashLoan() requesting 100000 USDC.
Transfer: Venus sends 100,000 USDC to Alice's contract + calculates fee (e.g., 90 USDC)
Execution:
Venus calls executeOperation() on Alice's contract
Contract performs arbitrage (buy low, sell high)
Profits 100,200 USDC
Approves full repayment of 100,090 USDC
Repayment: Venus pulls the approved 100,090 USDC
Result: Alice keeps 110 USDC profit. Transaction completes.
Request: Alice's ArbitrageContract calls executeFlashLoan() requesting 100000 USDC.
Transfer: Venus sends 100,000 USDC + calculates fee (90 USDC)
Execution:
Arbitrage fails due to slippage → only gets 99,500 USDC
Approves partial repayment of 99,500 USDC
Debt Conversion:
Venus pulls 99,500 USDC
Shortfall detected: 590 USDC (100,090 required - 99,500 paid)
Converts shortfall into a borrow position against Alice's 10 ETH collateral
Result: Transaction does not revert. Alice now owes 590 USDC to Venus.
Request: Alice's ArbitrageContract calls executeFlashLoan() requesting 100,000 USDC.
Transfer: Venus sends 100,000 USDC + calculates fee (90 USDC)
Execution:
Arbitrage fails completely → only gets 50 USDC
Approves insufficient amount of 50 USDC (less than the 90 USDC fee)
Validation Failure:
Venus attempts to pull funds but detects fee shortfall
Protocol requires at minimum the full flash loan fee to be repaid 5 Result: Transaction reverts completely. No debt conversion occurs. Alice loses gas fees but protocol remains secure.
Full Repayment: Strategy must profit enough to cover principal + fees.
Partial Repayment: Unique Venus feature. Requires existing collateral and atleast fees repayment.
Fee Not Paid: Transaction always reverts - critical safety mechanism.
No Collateral? Full repayment mandatory; otherwise transaction reverts.
Auto-Conversion: Shortfall automatically becomes secured debt, preventing liquidation.
Venus Protocol’s flash loan implementation provides a secure, composable, and flexible foundation for advanced DeFi strategies. It enables atomic transactions, multi-asset borrowing, and deep composability with Venus and other DeFi protocols.
uint256 INITIAL_VAI_MINT_INDEXuint96 CORE_POOL_IDfunction mintVAI(uint256 mintVAIAmount) external returns (uint256)function repayVAI(uint256 amount) external returns (uint256, uint256)function repayVAIBehalf(address borrower, uint256 amount) external returns (uint256, uint256)function liquidateVAI(address borrower, uint256 repayAmount, contract VTokenInterface vTokenCollateral) external returns (uint256, uint256)function _setComptroller(contract ComptrollerInterface comptroller_) external returns (uint256)function setPrimeToken(address prime_) externalfunction setVAIToken(address vai_) externalfunction toggleOnlyPrimeHolderMint() external returns (uint256)struct AccountAmountLocalVars {
uint256 oErr;
enum CarefulMath.MathError mErr;
uint256 sumSupply;
uint256 marketSupply;
uint256 sumBorrowPlusEffects;
uint256 vTokenBalance;
uint256 borrowBalance;
uint256 exchangeRateMantissa;
uint256 oraclePriceMantissa;
struct ExponentialNoError.Exp exchangeRate;
struct ExponentialNoError.Exp oraclePrice;
struct ExponentialNoError.Exp tokensToDenom;
}function getMintableVAI(address minter) public view returns (uint256, uint256)function _setTreasuryData(address newTreasuryGuardian, address newTreasuryAddress, uint256 newTreasuryPercent) external returns (uint256)function getVAIRepayRate() public view returns (uint256)function getVAIRepayRatePerBlock() public view returns (uint256)function getVAIMinterInterestIndex(address minter) public view returns (uint256)function getVAIRepayAmount(address account) public view returns (uint256)function getVAICalculateRepayAmount(address borrower, uint256 repayAmount) public view returns (uint256, uint256, uint256)function accrueVAIInterest() publicfunction setAccessControl(address newAccessControlAddress) externalfunction setBaseRate(uint256 newBaseRateMantissa) externalfunction setFloatRate(uint256 newFloatRateMantissa) externalfunction setReceiver(address newReceiver) externalfunction setMintCap(uint256 _mintCap) externalfunction getVAIAddress() public view virtual returns (address)function executeFlashLoan(
address payable onBehalf,
address payable receiver,
VToken[] memory vTokens,
uint256[] memory underlyingAmounts,
bytes memory param
) external nonReentrant {
// Validation, asset transfer, fee calculation, repayment logic...
}function setWhiteListFlashLoanAccount(address account, bool _isWhiteListed) external;function transferOutUnderlyingFlashLoan(address payable to, uint256 amount) external nonReentrant;function calculateFlashLoanFee(uint256 amount) public view returns (uint256, uint256);function transferInUnderlyingFlashLoan(
address payable from,
uint256 repaymentAmount,
uint256 totalFee,
uint256 protocolFee
) external nonReentrant returns (uint256);function setFlashLoanEnabled(bool enabled) external returns (uint256);function setFlashLoanFeeMantissa(
uint256 flashLoanFeeMantissa_,
uint256 flashLoanProtocolShare_
) external returns (uint256);function getCash() external view override returns (uint); function executeOperation(
VToken[] calldata vTokens,
uint256[] calldata amounts,
uint256[] calldata premiums,
address initiator,
address onBehalf,
bytes calldata param
) external returns (bool success, uint256[] memory repayAmounts);Omnichain Governance is designed to facilitate the execution of VIP across multiple blockchain networks, integrating with the Access Control Manager (ACM) and LayerZero communication protocol. It extends the governance model proposed by LayerZero.
VIP Types and Delays:
Provides three VIP options: Normal, Fast-track, and Critical.
Delays can be configured prior to remote execution on destination networks.
Normal VIPs have the greatest delays, whereas Critical VIPs have the smallest delays, indicating their urgency and importance.
Proposing and Voting:
Proposers send VIPs with BNB Chain commands and remote commands.
Voting takes place on the BNB Chain utilizing existing governance contracts.
Proposals are validated and approved according to predetermined criteria and threshold.
Proposing a remote VIP on BNB Chain
A proposer submits a VIP through the existing governance mechanism on the BNB Chain.
The must VIP include a command invoking the OmnichainProposalSender::execute function which will send the remote VIP payload.
The execute function takes four arguments:
Eligibility checks and limits
Before sending the remote execution message, the system verifies eligibility based on predefined thresholds and limits. These restrictions ensure responsible resource allocation and prevent potential misuse.
Remote proposal ID generation
It's crucial to understand that the proposal ID for the remote execution on the destination network differs from the initial VIP ID proposed on the BNB Chain. This remote proposal ID starts from 1.
Message relay based on outcome
Success: If the eligibility checks and limits are met, the encoded message (payload) is relayed across chains using the LayerZero bridge.
Failure: If the checks fail, the system handles the situation differently based on the cause:
Insufficient Gas: The retryExecute function is used to attempt redelivering the message with potentially adjusted gas fees.
Receiving and Queuing on the Destination Network
Upon successful reception by the destination network's executor contract (OmnichainGovernanceExecutor), the remote proposal enters a "Queued" state.
This queuing process applies additional eligibility checks specific to the receiving network, ensuring compliance with its governance rules and thresholds of commands limits.
Delay mechanism and execution
Once the configured delay for the remote proposal type (Normal, Fast-track, Critical) elapses, the proposal becomes eligible for execution.
Any user can then trigger the execution of the queued commands on the destination network.
Ownership and Access Control
OmnichainProposalSender (BNB Chain):
Owned by: NormalTimelock contract on the BNB Chain.
Authorized callers: Timelocks (Normal, Critical, Fast-track) are authorized to call the execute function on this contract.
If a VIP fails to send the proposal from source chain (BNB Chain) to destination network, the message will be saved and can be retried with the retryExecute function. This mechanism allows for the redelivery of the message with potentially adjusted gas fees to ensure successful execution.
In case where the VIP fails to send the proposal from source chain (BNB Chain) to destination network due to non-retryable conditions and funds are stuck in the OmnichainProposalSender contract, funds can be withdrawn by invoking the fallbackWithdraw function. This ensures that funds are not permanently locked in the contract due to failed execution attempts.
BaseOmnichainControllerSrcThis contract serves as the framework for secure omnichain (cross-chain) communication. Its primary responsibilities include managing daily command limits and enabling pausing of controlled message transmission across chains.
Access Control Integration: Integrates an AccessControlManager contract to enforce access control for critical functions. This ensures that only authorised entities can execute commands, enhancing security.
Daily Command Limits: Establishes a per-chain limit on the number of commands that can be sent within a 24-hour window. This feature prevents potential abuse and maintains system stability.
Pausable: Implements a pausing mechanism, inherited from the OpenZeppelin Pausable contract. This functionality allows the contract owner to temporarily halt omnichain communication if necessary.
Inheritance: Extends the functionalities of the Ownable and Pausable contracts from OpenZeppelin, inheriting ownership management and pausing capabilities.
accessControlManager (address): Stores the address of the AccessControlManager contract.
chainIdToMaxDailyLimit (mapping): Maps chain IDs to their corresponding daily command limits.
chainIdToLast24HourCommandsSent (mapping): Tracks the number of commands sent within the last 24 hours for each chain.
SetMaxDailyLimit (event): Emitted when the daily command limit for a chain is modified.
NewAccessControlManager (event): Triggered when the address of the AccessControlManager is updated.
constructor(address accessControlManager_): Initializes the contract with the address of the AccessControlManager.
setMaxDailyLimit(uint16 chainId_, uint256 limit_): Sets the maximum daily command limit for a specific chain ID. Requires permission from the AccessControlManager.
OmnichainProposalSenderThis contract facilitates cross-chain message transmission triggered by governor proposals on the main (BNB) chain. It sends proposal execution data to designated remote chains for processing.
LayerZero Integration: Utilises the LayerZero communication protocol for efficient and reliable cross-chain message delivery.
Remote Chain Management: Allows defining trusted remote contracts (receivers) on other chains using setTrustedRemoteAddress.
Failed Message Handling: Stores the execution hashes of failed messages to facilitate resending or clearing them in case of insufficient fees or other issues.
Inheritance: Inherits functionalities from both the ReentrancyGuard and BaseOmnichainControllerSrc contracts, providing reentrancy protection and foundational omnichain communication capabilities.
proposalCount (uint256): Tracks the total number of remote proposals.
storedExecutionHashes (mapping): Stores the execution hashes of failed messages for retry or clearing purposes.
LZ_ENDPOINT (ILayerZeroEndpoint): Interface for interacting with the LayerZero communication protocol.
SetTrustedRemoteAddress (event): Triggered when a trusted remote address is set for a remote chain.
TrustedRemoteRemoved (event): Emitted when a trusted remote address is removed from storage.
ExecuteRemoteProposal (event): Indicates the execution of a proposal on a remote chain.
constructor(ILayerZeroEndpoint lzEndpoint_, address accessControlManager_): Initializes the contract with the LayerZero endpoint and the address of the AccessControlManager.
estimateFees(uint16 remoteChainId_, bytes calldata payload_, bytes calldata adapterParams_) : Estimates LayerZero fees for cross-chain message delivery based on payload and adapter parameters.
BaseOmnichainControllerDestThis contract serves as the base for the Omnichain controller destination contract. It provides functionality related to daily command limits and pausing.
maxDailyReceiveLimit (uint256): Maximum daily limit for receiving commands from BNB Chain.
last24HourCommandsReceived (uint256): Total received commands within the last 24-hour window from BNB Chain.
last24HourReceiveWindowStart (uint256): Timestamp when the last 24-hour window started from BNB Chain.
SetMaxDailyReceiveLimit (event): Emitted when the maximum daily limit for receiving commands from BNB Chain is modified.
constructor(address endpoint_): Initializes the contract with the LayerZero endpoint address.
setMaxDailyReceiveLimit(uint256 limit_): Sets the maximum daily limit for receiving commands. Only callable by the contract owner.
pause(): Triggers the paused state of the controller. Only callable by the contract owner.
OmnichainGovernanceExecutorThis contract executes proposal transactions sent from the main chain. It controls LayerZero configuration and implements a non-blocking behavior.
GUARDIAN (address): A privileged role that can cancel any proposal.
srcChainId (uint16): Stores the layerzero endpoint ID.
lastProposalReceived (uint256): Last proposal count received.
ProposalReceived (event): Emitted when a proposal is received.
ProposalQueued (event): Emitted when a proposal is queued.
ProposalExecuted (event): Emitted when a proposal is executed.
constructor(address endpoint_, address guardian_, uint16 srcChainId_): Initialises the contract with the LayerZero endpoint address, guardian address, and source chain ID.
setSrcChainId(uint16 srcChainId_): Updates the source layerzero endpoint ID. Only callable by the contract owner.
addTimelocks(ITimelock[] memory timelocks_): Adds Timelocks to the ProposalTimelocks mapping. Only callable by the contract owner.
OmnichainExecutorOwnerThe OmnichainExecutorOwner contract serves as a governance and access control mechanism for managing the OmnichainGovernanceExecutor contract. It allows the owner to control the functions that can be executed on the OmnichainGovernanceExecutor contract, upsert function signatures into a registry, and transfer ownership of the OmnichainGovernanceExecutor contract.
OMNICHAIN_GOVERNANCE_EXECUTOR (immutable):
This variable holds the address of the OmnichainGovernanceExecutor contract and is immutable once initialized.
functionRegistry (mapping):
FunctionRegistryChanged (event):
This event is emitted when a function is added or removed from the function registry.
It provides information about the function signature and whether it is active (added) or inactive (removed).
constructor(address omnichainGovernanceExecutor_):
Initializes the contract with the address of the OmnichainGovernanceExecutor contract.
This constructor ensures that the provided address is not zero.
TimelockV8The TimelockV8 contract is a Solidity V8 implementation of a timelock mechanism designed to execute transactions with a delay. It incorporates additional features such as setting a delay period, accepting pending admins, and queuing, executing, and canceling transactions. This contract ensures that specific transactions can only be executed after a predefined period, enhancing security and providing governance control.
Delayed Transaction Execution: Allows transactions to be queued with an associated delay period before execution.
Admin Management: Supports the transition of admin roles by accepting pending admin proposals.
Transaction Queueing: Provides functionality to queue transactions for future execution, ensuring timely processing.
Transaction Execution: Executes queued transactions after the specified delay period has elapsed, subject to admin authorisation.
NewAdmin (event): Signals the acceptance of a new admin account.
NewPendingAdmin (event): Indicates the proposal of a new admin account.
NewDelay (event): Notifies when the delay period for transaction execution is updated.
DEFAULT_GRACE_PERIOD: Default grace period for executing queued transactions (14 days).
DEFAULT_MINIMUM_DELAY: Default minimum delay period for queuing transactions (1 hour).
DEFAULT_MAXIMUM_DELAY: Default maximum delay period for queuing transactions (30 days).
admin (address): Stores the address of the current admin authorised to manage the timelock.
pendingAdmin (address) : Stores the address of the proposed admin awaiting acceptance.
delay (uint256) : Specifies the delay period for executing queued transactions.
setDelay(uint256 delay_): Allows the admin to set the delay period for transaction execution.
acceptAdmin(): Enables the pending admin to accept the admin role.
setPendingAdmin(address pendingAdmin_): Allows to propose a new admin account via proposal or admin.
Inter-chain communication:
LayerZero provides secure and reliable cross-chain messaging for remote execution commands.
Bridging:
Works with a bridge solution to deliver messages to destination networks.
Enables smooth interoperability between the BNB Chain and other supported networks.
Bridge configurations are flexible to accommodate various networks.
Guardian account:
Authorized by the ACM to revoke orders before they are executed on the target network.
Serves as a fail-safe mechanism, preventing unauthorized or incorrect commands from being performed.
Command limits and pausing:
Allows you to establish daily command restrictions for destination networks.
Adds pause/resume functionality for execution to temporarily halt operations in case of an emergency.
Remote Execution Flow:
Commands for destination networks generate a "Remote VIPs payload”
The payload is routed to the destination network using the bridge solution.
Delay Mechanism:
Remote execution has two delays: bridge delay and executor delay.
Bridge delay is the time it takes for the bridge to propagate a message to the target network, which is commonly measured in minutes.
Executor delay is the duration between the message's arrival on the target network and its execution, which is customizable dependent on VIP type (Normal, Fast-track, or Critical)
Execution and Expiry:
User-triggered execution occurs once both delays have passed, signaling the destination network's readiness to perform the orders via Timelock.
The Guardian account can cancel orders before they are executed, offering a safeguard against malicious or erroneous acts.
"Remote VIPs" become "Expired" if no execution happens within a set grace period, avoiding stale or outdated commands from being executed.
Command Restrictions:
VIPs can only include one set of commands per destination network to prevent duplication and conflicts.
Duplicate commands for the same network within a VIP are not permitted, ensuring consistent and reliable execution.
Executor-Side Features:
Sets a daily limit on the number of commands received per network.
Implements pause/resume functionality for the execute function in the target governance contract, enabling administrators to manage the system's operational state effectively.
chainID: Identifies the destination network for the remote execution (endpointId according to LayerZero).
payload: Encoded data (off-chain) containing the specific commands to be executed on the target network.
adapterParams: The params used to specify the custom amount of gas required for the execution on the destination encoded as (ethers.utils.solidityPack(['uint16','uint256'],[1, gasValue])).
zroPaymentAddress_: The address of the ZRO token holder who would pay for the transaction.
Logical Error or Check Failure: The fallbackWithdraw function removes the message from the queue, preventing further retries if the failure stems from inherent logic errors or failed eligibility checks.
OmnichainGovernanceExecutor (destination network):Owned by: OmnichainExecutorOwner contract. This owner performs Access Control Manager (ACM) checks before allowing any function calls on this contract.
TimelockV8:
Owned by: OmnichainGovernanceExecutor contract. This ownership grants TimelockV8 the authority to perform specific actions like queuing, canceling, and executing remote proposals.
retryMessage function.If a proposal's queueing fails on the destination network due to reasons such as reaching caps or other constraints, the message will be saved and can be retried with the retryMessage function. This provides flexibility in addressing various failure scenarios and ensures that execution attempts are made until successful.
If a proposal's queueing fails on the destination network because the contract has been paused, the message will be saved and can be retried with the retryMessage function after the contract has been unpaused.
chainIdToLast24HourWindowStart (mapping): Records the timestamp when the last 24-hour window for a chain began.
chainIdToLastProposalSentTimestamp (mapping): maintains the timestamp of the last proposal sent to a specific chain to prevent sending multiple proposals within the same block.
AccessControlManagerunpause(): Resumes omnichain communication from the paused state. Requires AccessControlManager permission.
setAccessControlManager(address accessControlManager_): Updates the address of the AccessControlManager contract. Only callable by the contract owner.
isEligibleToSend(uint16 dstChainId, uint256 noOfCommands_): Checks if sending the specified number of commands to the given chain is permissible based on daily limits and time windows.
ensureAllowed(string memory functionSig): Ensures the caller has permission to execute a specific function, leveraging the AccessControlManager.
AccessControlManager for critical functions.trustedRemoteLookup (mapping): Maps remote chain IDs to trusted remote contract addresses for message transmission.
ClearPayload (event): Signals the successful clearing of a previously failed message.
StorePayload (event): Records the storage of an execution hash for a failed message, along with relevant details.
FallbackWithdraw (event): Indicates a fallback withdrawal of funds in case of failed messages.
retryExecute(...): Resends a previously failed message with potentially additional fees, ensuring reentrancy protection.
fallbackWithdraw(...): Allows the owner to withdraw funds in case of failed messages.
setTrustedRemoteAddress(uint16 remoteChainId_, bytes calldata newRemoteAddress_): Sets the remote message receiver address for a specified remote chain, requiring AccessControlManager permission.
setConfig(uint16 version_, uint16 chainId_, uint256 configType_, bytes calldata config_): Sets the configuration of the LayerZero messaging library, controlled by the AccessControlManager.
setSendVersion(uint16 version_): Sets the messaging library version, with permission from the AccessControlManager.
getConfig(uint16 version_, uint16 chainId_, uint256 configType_): Retrieves the configuration of the LayerZero messaging library.
unpause(): Triggers the resume state of the controller. Only callable by the contract owner.
renounceOwnership(): Overrides the renounceOwnership function to prevent accidental renouncement of ownership.
_isEligibleToReceive(uint256 noOfCommands_): Checks the eligibility to receive commands based on the daily limit and updates the state accordingly.
proposals (mapping): Official record of all proposals ever proposed.
proposalTimelocks (mapping): Mapping containing Timelock addresses for each proposal type.
queued (mapping): Represents the queue state of a proposal.
ReceivePayloadFailed (event): Emitted when a payload receive fails.
ProposalCanceled (event): Emitted when a proposal is canceled.
TimelockAdded (event): Emitted when a Timelock is added.
SetSrcChainId (event): Emitted when the source layer zero endpoint ID is updated.
SetTimelockPendingAdmin (event): Emitted when pending admin of Timelock is updated.
NewGuardian (event): Emitted when guardian of OmnichainGovernanceExecutor is updated.
execute(uint256 proposalId_) : Executes a queued proposal if the ETA has passed.
cancel(uint256 proposalId_): Cancels a proposal if the sender is the guardian and the proposal is not executed.
state(uint256 proposalId_): Gets the state of a proposal.
_blockingLzReceive(...) and _nonblockingLzReceive(...): Process LayerZero receive requests, with blocking and non-blocking behaviour respectively.
_queue(uint256 proposalId_): Queues a proposal for execution.
_queueOrRevertInternal(...): Checks for a unique proposal and queues it or reverts if already queued.
setTimelockPendingAdmin(address pendingAdmin_, uint8 proposalType_): Sets the new pending admin of the Timelock.
setGuardian(address newGuardian): Sets the new guardian of the OmnichainGovernanceExecutor.
This mapping stores the function signatures along with their corresponding 4-byte hash values.
It allows the contract owner to register which functions are permitted to be executed on the OmnichainGovernanceExecutor contract.
initialize(address accessControlManager_):
Initializes the contract with the address of the access control manager.
This function sets up access control for the contract.
fallback(bytes calldata data_):
Acts as a fallback function that is invoked when a called function does not exist in the contract.
It checks if the function signature exists in the function registry and if the caller has permission to execute it.
Then it forwards the function call to the OmnichainGovernanceExecutor contract.
If the call fails, it reverts with an error message.
upsertSignature(string[] calldata signatures_, bool[] calldata active_):
Allows the owner to upsert (add or remove) function signatures into the function registry.
The owner can specify whether each function signature should be added (true) or removed (false).
This function ensures that input arrays have the same length.
It emits the FunctionRegistryChanged event for each function signature that is added or removed.
transferBridgeOwnership(address newOwner_):
Transfers the ownership of the OmnichainGovernanceExecutor contract from this contract to a new owner.
This function is controlled by the access control manager to ensure that only authorized entities can transfer ownership.
It ensures that the new owner address is not zero before transferring ownership.
renounceOwnership():
Overrides the renounceOwnership function from the parent contract to provide an empty implementation.
This prevents accidental renouncement of ownership, as ownership renouncement is handled through the transferBridgeOwnership function.
Transaction Cancellation: Allows cancellation of queued transactions before execution, providing flexibility and control.
CancelTransaction (event): Broadcasts the cancellation of a queued transaction.
ExecuteTransaction (event): Broadcasts the execution of a queued transaction.
QueueTransaction (event): Broadcasts the queuing of a new transaction for future execution.
queueTransaction(...): Queues a transaction for future execution after a specified delay.
cancelTransaction(...): Cancels a queued transaction before execution.
executeTransaction(...): Executes a queued transaction after the delay period has elapsed.
The Venus Protocol Core Pool on BNB Chain has been enhanced with E-Mode (Efficiency Mode), a feature designed to provide users with greater capital efficiency when lending and borrowing. E-Mode introduces specialized pools of assets—such as correlated ones—each with its own customized risk parameters.
When a user activates an E-Mode pool, their borrowing is restricted to assets within that pool but with higher collateral factors (CF) and liquidation thresholds (LT) compared to the default Core Pool. A lower liquidation incentive (LI) is also applied, reducing the penalty at liquidation and making borrowing within E-Mode more efficient.
This allows users to unlock more borrowing power while keeping risk contained within the pool.
Unlike isolated pools, which fully segregate assets into separate environments, E-Mode keeps everything within the Core Pool. Users do not need to transfer assets to benefit from different risk profiles. Instead, they can simply activate an E-Mode pool, gaining higher efficiency while maintaining their existing positions. This design balances capital optimization with contained risk management, making E-Mode a powerful extension of the Core Pool.
Increased Borrowing Power: Higher CF and LT enable users to leverage more borrowing capacity in E-Mode pools.
Reduced Liquidation Penalties: Lower LI minimizes losses during volatile market conditions.
Seamless Integration: No asset transfers are required; all operations remain in the Core Pool.
Risk Isolation: Borrowing limits prevent cross-pool exposure, reducing systemic risks.
Borrow Restrictions: Users must ensure existing borrows align with the target pool's allowed assets.
VAI Incompatibility: Users with VAI debt cannot enter E-Mode, ensuring stablecoin-specific isolation.
Parameter Changes: Governance updates (e.g., lowering CF) can impact the user positions.
Core Pool Fallback Behavior: Controlled by a per-pool flag
The introduction of E-Mode in the Venus Core Pool on BNB Chain required significant enhancements to the Comptroller contract. These changes enable fine-grained risk management while preserving the existing Core Pool functionality. Below is a summary of the major updates:
The implementation extends the Comptroller contract to support:
Pool-specific risk configurations.
User-driven pool selection.
Refined, pool-based risk management.
All of this is achieved while maintaining backward compatibility with the Core Pool’s legacy operations.
The core data structure for tracking markets has been upgraded to handle multiple pools efficiently.
Previously: Address as index
Now: bytes32 as index
Core Pool (poolId = 0): The PoolMarketId is the vToken address left-padded to 32 bytes, preserving storage layout for compatibility.
E-Mode Pools (poolId > 0): The key is constructed by combining the poolId (uint96, shifted left by 160 bits) with the vToken address (uint160).
This approach ensures:
No collisions between pool-market pairs.
Pool-specific overrides (e.g., CF/LT/LI).
Backward compatibility is preserved through updated getter functions, which return Core Pool values when called with only a vToken address, while maintaining the same function signatures.
The Market struct now includes fields to support LT, per-market LI, and pool-specific borrowing rules:
accountMembership: Stored only in Core Pool entries, since borrows and collateral are tracked globally across all pools. In E-Mode entries, this mapping remains empty for structural consistency, reducing storage overhead.
isBorrowAllowed: A pool-level flag that Governance can toggle, overriding global borrow caps for E-Mode restrictions.
Pools are defined and managed via a dedicated mapping for metadata and asset lists:
lastPoolId tracks the latest assigned poolId (0 is reserved for Core).
Pools hold metadata, a list of associated vTokens, and the allowCorePoolFallback flag (default: false).
Governance Workflow: New pools are created via createPool(string calldata label), which assigns the next poolId and initializes the PoolData with allowCorePoolFallback = false by default. Governance can update this behavior via setAllowCorePoolFallback(uint96 poolId, bool allowed). This allows for easy expansion to new pools like "ETH Correlated" or "BNB Derivatives" while choosing the desired fallback behavior.
Each user is associated with exactly one pool at a time, simplifying state management:
Defaults to 0 (Core Pool).
Switching updates userPoolId with proper validations.
This ensures all collateral and borrowing operations are evaluated within the context of the user’s active pool. Edge Case Handling: If a user's pool is disabled by Governance, their userPoolId is automatically reset to 0, triggering a fallback event.
Governance configures E-Mode via a suite of administrative functions:
Add/Remove: addPoolMarkets and removePoolMarket manage vTokens in non-Core pools.
Borrow Control: setIsBorrowAllowed toggles borrowing eligibility.
Risk Parameters: Setters for CF, LT, and LI support poolId for E-Mode and address-only for Core.
Example Setters:
Every user starts in the Core Pool (poolId = 0).
Core Pool applies standard parameters (lower CF/LT, higher LI).
If the user never switches pools, nothing changes—ensuring zero disruption for legacy users.
Users can discover available E-Mode pools using:
Venus Lens: By calling the getAllPoolsData function to fetch pool data directly from the Comptroller. This returns supported E-Mode pools and their vTokens along with parameters such as CF, LT, LI, and borrow permissions.
Venus App UI: A user-friendly interface that displays the same information without requiring direct blockchain queries.
Before switching, make sure all your borrowed assets are supported as borrowable assets in the E-Mode pool you want to enter.
If any borrowed asset is not allowed in the target pool, the enterPool transaction will revert on: hasValidPoolBorrows() check.
Call: enterPool(uint96 poolId)
Comptroller checks:
Pool exists and user isn’t already in it.
Borrow compatibility (hasValidPoolBorrows
Borrowing: Restricted to markets marked isBorrowAllowed in chosen pool.
Collateral:
Pool assets use pool CF/LT/LI.
Example: A user has borrowed BTCB and tries to enter the Stablecoins Pool.
BTCB is not part of that pool, so it is not listed as borrowable.
Result: enterPool fails with IncompatibleBorrowedAssets.
Users can provide collateral outside of the E-Mode pool’s listed assets if the pool’s allowCorePoolFallback flag is set to true.
If allowCorePoolFallback = true: Non-pool assets use Core Pool parameters (CF, LT, LI). Since Core Pool LI is typically higher, liquidators may target these assets first during liquidation.
If allowCorePoolFallback = false (default): Non-pool collateral
Example: In the Stablecoins Pool, a user supplies USDC + UNI:
USDC → CF/LT/LI from E-Mode (e.g., LI = 5%).
UNI →
If allowCorePoolFallback = true: CF/LT/LI from Core Pool (e.g., LI = 10%).
Switching back is allowed only if the account remains healthy under Core Pool’s stricter parameters.
Example: In Stablecoins Pool, a user is safe with CF = 0.90. Switching back to Core Pool with CF = 0.60 may immediately create a shortfall → reverts with LiquidityCheckFailed.
Important scenario:
Governance has significant control over pool configurations, which can directly affect user positions:
Borrow Restrictions:
Governance can set isBorrowAllowed = false for a market.
Existing borrows remain, but new borrows are blocked.
This behaves similarly to setting the borrow cap to 0 in the Core Pool.
Rule of Risk Factor Selection:
If a parameter (CF, LT, LI) is defined in the active E-Mode pool, that value is used.
If Governance sets a value to 0 in the pool (e.g., CF = 0), the 0 applies — it does not fall back to Core.
If the asset is not included in the E-Mode pool:
To see how E-Mode changes borrowing power, liquidation, and borrow restrictions, let’s follow a single user journey. This example uses hypothetical parameters to illustrate key mechanics.
Supplies: $1,000 USDC
Borrows: $500 DAI
Liquidity Calculation:
Liquidity = $100, Shortfall = $0 → safe
Alex wants to switch to the Stablecoins Pool.
Borrowed DAI is not allowed in the target pool (isBorrowAllowed = false).
Comptroller checks fail → transaction reverts with IncompatibleBorrowedAssets.
This demonstrates borrow restrictions in E-Mode: existing borrows in disallowed markets prevent entering the pool.
Alex repays $500 DAI → no active borrows.
Calls enterPool(stablecoinPoolId) → succeeds.
Liquidity Calculation in E-Mode:
Effect of E-Mode Activation:
Collateral Factor (CF) for USDC increases from 60% → 90%
Liquidation Incentive (LI) for USDC decreases from 10% → 5%
Can borrow USDC (allowed), but cannot borrow DAI (isBorrowAllowed = false).
Alex borrows $500 USDC
Borrowing DAI fails (restricted by pool-level isBorrowAllowed)
Liquidity Calculation after borrow:
Suppose Alex borrowed up to $850 USDC in E-Mode.
Core Pool Borrow Limit:
To switch safely, Alex can either:
Add collateral → $500 more USDC → new Core borrow limit = 1500 × 0.6 = 900 → liquidity = 900 - 850 = 50 → switch succeeds.
Repay debt → reduce borrow ≤ $600 → liquidity ≥ 0 → switch succeeds.
The introduction of E-Mode in the Core Pool on BNB Chain also changes how liquidators must evaluate accounts and select assets for liquidation. To remain effective and profitable, liquidators need to adapt to the updated mechanics and new getter functions.
The Core Pool no longer uses a global LI.
Each market now has its own per-market liquidation incentive, configurable by Governance.
Impact: Liquidators must always query the market’s specific LI before deciding which collateral to seize, since incentives may differ significantly between assets.
Strategy: Prioritize assets with higher LI when selecting which collateral to liquidate for maximum profit.
The Core Pool now supports Liquidation Thresholds (LT), just like isolated pools.
Unlike Collateral Factors (CF), which only define borrow limits, LT determines liquidation conditions.
Impact: Liquidators must check account health against LT rather than CF.
Recommended Function
Because E-Mode overrides Core parameters with pool-specific ones, the protocol provides new getters to return the effective factors for any user and market.
Get Effective LTV (Collateral Factor or LT depending on weighting):
Use weightingStrategy = 0 to fetch the effective CF.
Use weightingStrategy = 1 to fetch the effective LT.
Efficiency Boost: E-Mode lets you use higher Collateral Factors (CF) and Liquidation Thresholds (LT), plus lower Liquidation Incentives (LI), for some set of assets (e.g., stablecoins).
Borrow Limits: You can only borrow from pool-approved assets (isBorrowAllowed = true). If you have borrows in non-approved assets, you can't enter; new borrows are blocked to keep risks isolated.
How Risk Factors Are Chosen:
In E-Mode Pool: Use the pool's CF/LT/LI values (even if set to 0).
If the asset isn't in your pool:
If allowCorePoolFallback = true: Use Core Pool values.
Liquidator Notes:
Core Pool now uses per-market LI (no global incentive). Liquidators should always fetch the effective liquidation incentive for each user’s market, as markets associated with different E-Mode pools may have different LI values. Additionally, assets outside the E-Mode pool that do not contribute to borrowing power may have LI = 0, even if supplied as collateral.
Liquidation Threshold (LT) replaces CF as the trigger for liquidations—use getAccountLiquidity for checks.
Use new getters to fetch effective parameters considering pool overrides:
The read only functions on the VenusLens contract provide a view into: - metadata of vToken - daily XVS rewards for an account - account balance for a single vToken - account balances for all vTokens in an account - underlying price of a vToken - underlying prices for a set of vTokens - get liquidity and shortfall of an account - get user's vote history - get proposal details for a set of proposals - get account XVS balance, total votes, and delegated votes - get historical voting balance for a user - get pending XVS Rewards for an account
Blocks Per Day
Total actions available on VToken
Holds full market information for a single vToken within a specific pool (excluding the Core Pool)
Struct representing a pool (excluding the Core Pool) and its associated markets
Query the metadata of a vToken by its address
Parameters
Return Values
Get VTokenMetadata for an array of vToken addresses
Parameters
Return Values
Get amount of XVS distributed daily to an account
Parameters
Return Values
Get the current vToken balance (outstanding borrows) for an account
Parameters
Return Values
Get the current vToken balances (outstanding borrows) for all vTokens on an account
Parameters
Return Values
Get the price for the underlying asset of a vToken
Parameters
Return Values
Query the underlyingPrice of an array of vTokens
Parameters
Return Values
Query the account liquidity and shortfall of an account
Parameters
Return Values
Query the XVSBalance info of an account
Parameters
Return Values
Query the XVSBalance extended info of an account
Parameters
Return Values
Query the voting power for an account at a specific list of block numbers
Parameters
Return Values
Calculate the total XVS tokens pending and accrued by a user account
Parameters
Return Values
Returns all pools (excluding the Core Pool) along with their associated market data
Parameters
Return Values
Retrieves full market data for all vTokens in a specific pool (excluding the Core Pool)
Parameters
Return Values
❌ Errors
PoolDoesNotExist Reverts if the given pool ID does not exist
InvalidOperationForCorePool Reverts if called on the Core Pool (poolId = 0)
This documentation provides detailed instructions and explanations for using the XVS Cross-Chain Bridge. The bridge allows users to transfer tokens between different blockchain networks, including the and multiple destination chains. The supported networks are as follows:
vToken
contract VToken
The address of the vToken to fetch VTokenMetadata
[0]
struct VenusLens.VTokenMetadata
VTokenMetadata struct with vToken supply and borrow information.
vTokens
contract VToken[]
Array of vToken addresses to fetch VTokenMetadata
[0]
struct VenusLens.VTokenMetadata[]
Array of structs with vToken supply and borrow information.
account
address payable
Address of account to fetch the daily XVS distribution
comptrollerAddress
address
Address of the comptroller proxy
[0]
uint256
Amount of XVS distributed daily to an account
vToken
contract VToken
Address of the token to check the balance of
account
address payable
Account address to fetch the balance of
[0]
struct VenusLens.VTokenBalances
VTokenBalances with token balance information
vTokens
contract VToken[]
Addresses of the tokens to check the balance of
account
address payable
Account address to fetch the balance of
[0]
struct VenusLens.VTokenBalances[]
VTokenBalances Array with token balance information
vToken
contract VToken
address of the vToken
[0]
struct VenusLens.VTokenUnderlyingPrice
response struct with underlyingPrice info of vToken
vTokens
contract VToken[]
Array of vToken addresses
[0]
struct VenusLens.VTokenUnderlyingPrice[]
array of response structs with underlying price information of vTokens
comptroller
contract ComptrollerInterface
Address of comptroller proxy
account
address
Address of the account to query
[0]
struct VenusLens.AccountLimits
Struct with markets user has entered, liquidity, and shortfall of the account
xvs
contract IXVS
XVS contract address
account
address
Account address
[0]
struct VenusLens.XVSBalanceMetadata
Struct with XVS balance and voter details
xvs
contract IXVS
XVS contract address
comptroller
contract ComptrollerInterface
Comptroller proxy contract address
account
address
Account address
[0]
struct VenusLens.XVSBalanceMetadataExt
Struct with XVS balance and voter details and XVS allocation
xvs
contract IXVS
XVS contract address
account
address
Address of the account
blockNumbers
uint32[]
Array of blocks to query
[0]
struct VenusLens.VenusVotes[]
Array of VenusVotes structs with block number and vote count
holder
address
Account to query pending XVS
comptroller
contract ComptrollerInterface
Address of the comptroller
[0]
struct VenusLens.RewardSummary
Reward object contraining the totalRewards and pending rewards for each market
comptroller
contract ComptrollerInterface
The Comptroller contract to query
poolsData
struct VenusLens.PoolWithMarkets[]
An array of PoolWithMarkets structs, each containing pool info and its markets
poolId
uint96
The pool ID to fetch data for
comptroller
contract ComptrollerInterface
The address of the Comptroller contract
result
struct VenusLens.MarketData[]
An array of MarketData structs containing detailed market info for the given pool
Governance Flexibility: Pool parameters can be dynamically adjusted via Venus Governance proposals.
allowCorePoolFallbackfalseIf true: Assets not included in the E-Mode pool use Core Pool risk parameters (CF, LT, LI).
If false: Assets not included in the E-Mode pool have no risk factors applied (effectively CF = 0 and LI = 0), so users are recommended to exit such markets before switching into that E-Mode pool.
Fallback Control: setAllowCorePoolFallback(uint96 poolId, bool allowed) controls whether non-pool assets use Core Pool risk parameters.
VAI check: Users with outstanding VAI debt or active minting positions cannot switch into E-Mode.
Liquidity check: Runs _getAccountLiquidity with new pool’s CF/LT.
❌ If shortfall > 0 (would become liquidatable), tx reverts.
On success:
userPoolId updated
PoolSelected event emitted
allowCorePoolFallback:If true: Non-pool assets use Core parameters (typically lower CF, higher LI).
If false (default): Non-pool assets have no applicable risk factors in the selected E-Mode pool (effectively CF = 0 and LI = 0).
Liquidation:
Pool assets → more efficient (lower LI).
Non-pool assets → liquidators prefer them due to higher LI.
VAI: Minting and repayment only possible in Core Pool.
isBorrowAllowed = false. In this case, supplying the asset as collateral is fine, but new borrows of that asset are restricted.allowCorePoolFallback = falseHowever, if they attempt to switch back to Core, the stricter parameters would again make them liquidatable, so the transaction reverts.
This ensures users cannot bypass liquidation risk by cycling between pools.
When borrow cap set to 0, no additional borrows are possible, but existing borrows are unaffected.
Market Removal from E-Mode:
If Governance removes a market from an E-Mode pool, the market’s risk factors instantly revert to its Core Pool values.
This is effectively the same as updating CF, LT, or LI parameters via a VIP.
Users need to monitor VIP proposals to anticipate changes.
Disabling Core Pool Fallback:
Governance can disable Core Pool fallback for a pool.
Assets outside the E-Mode pool will no longer use Core Pool parameters, which can affect user health.
Such changes are implemented only after complete risk analysis and with advanced notice to users so they can adjust their positions safely.
Disabling an E-Mode Pool:
Governance can disable an entire E-Mode pool by setting the isActive flag to false.
When this happens, all users in the disabled pool automatically fall back to Core Pool parameters.
Users who remain in a disabled E-Mode pool cannot initiate new borrows and are encouraged to either return to the Core Pool or switch to another active E-Mode pool.
If allowCorePoolFallback = true: Use the asset's Core Pool CF/LT/LI.
If allowCorePoolFallback = false: Treat CF/LT/LI as 0 for that asset in E-Mode; users are recommended to exit such markets.
If the pool is disabled, users automatically fall back to Core Pool parameters.
DAI
60%
65%
10%
90%
93%
5%
No
UNI
50%
55%
12%
N/A (Fallback to Core)
N/A
N/A
N/A
This function has been updated to use LT internally when computing liquidity and shortfall.
Get Effective Liquidation Incentive (LI):
allowCorePoolFallback = false (default): Treat CF/LT/LI as 0; exit such markets.Pool Disabled: Falls back to Core Pool parameters.
getEffectiveLtvFactor(account, vToken, 0) → effective CF
getEffectiveLtvFactor(account, vToken, 1) → effective LT
getEffectiveLiquidationIncentive(account, vToken) → effective LI
Liquidation Threshold (LT) Support in Core Pool
The Core Pool now supports Liquidation Thresholds, similar to isolated pools. LT allows borrowing limits (CF) and liquidation conditions (LT) to be defined separately, improving risk control.
Enables more precise liquidity calculations, separating borrow caps from liquidation triggers for better user safety.
Per-Market Liquidation Incentives (LI)
The global LI has been replaced with per-market LIs, enabling Governance to assign asset-specific liquidation rewards based on risk.
Liquidators receive tailored incentives, optimizing protocol security and efficiency for high-risk vs. low-risk assets.
Unified Pool-Market Mapping
The existing markets mapping has been replaced with _poolMarkets, a flexible structure keyed by a new PoolMarketId type (bytes32), which uniquely identifies each pool-market pair while maintaining backward compatibility for existing market getters.
Supports multiple pools without storage conflicts, allowing pool-specific overrides while maintaining legacy access.
USDC
60%
65%
10%
90%
93%
5%
Yes
uint256 BLOCKS_PER_DAYuint256 VTOKEN_ACTIONSstruct VenusMarketState {
uint224 index;
uint32 block;
}struct VTokenMetadata {
address vToken;
uint256 exchangeRateCurrent;
uint256 supplyRatePerBlock;
uint256 borrowRatePerBlock;
uint256 reserveFactorMantissa;
uint256 totalBorrows;
uint256 totalReserves;
uint256 totalSupply;
uint256 totalCash;
bool isListed;
uint256 collateralFactorMantissa;
address underlyingAssetAddress;
uint256 vTokenDecimals;
uint256 underlyingDecimals;
uint256 venusSupplySpeed;
uint256 venusBorrowSpeed;
uint256 dailySupplyXvs;
uint256 dailyBorrowXvs;
uint256 pausedActions;
}struct VTokenBalances {
address vToken;
uint256 balanceOf;
uint256 borrowBalanceCurrent;
uint256 balanceOfUnderlying;
uint256 tokenBalance;
uint256 tokenAllowance;
}struct VTokenUnderlyingPrice {
address vToken;
uint256 underlyingPrice;
}struct AccountLimits {
contract VToken[] markets;
uint256 liquidity;
uint256 shortfall;
}struct XVSBalanceMetadata {
uint256 balance;
uint256 votes;
address delegate;
}struct XVSBalanceMetadataExt {
uint256 balance;
uint256 votes;
address delegate;
uint256 allocated;
}struct VenusVotes {
uint256 blockNumber;
uint256 votes;
}struct ClaimVenusLocalVariables {
uint256 totalRewards;
uint224 borrowIndex;
uint32 borrowBlock;
uint224 supplyIndex;
uint32 supplyBlock;
}struct PendingReward {
address vTokenAddress;
uint256 amount;
}struct RewardSummary {
address distributorAddress;
address rewardTokenAddress;
uint256 totalRewards;
struct VenusLens.PendingReward[] pendingRewards;
}struct MarketData {
uint96 poolId;
string poolLabel;
address vToken;
bool isListed;
uint256 collateralFactor;
bool isVenus;
uint256 liquidationThreshold;
uint256 liquidationIncentive;
bool isBorrowAllowed;
}struct PoolWithMarkets {
uint96 poolId;
string label;
struct VenusLens.MarketData[] markets;
}function vTokenMetadata(contract VToken vToken) public returns (struct VenusLens.VTokenMetadata)function vTokenMetadataAll(contract VToken[] vTokens) external returns (struct VenusLens.VTokenMetadata[])function getDailyXVS(address payable account, address comptrollerAddress) external returns (uint256)function vTokenBalances(contract VToken vToken, address payable account) public returns (struct VenusLens.VTokenBalances)function vTokenBalancesAll(contract VToken[] vTokens, address payable account) external returns (struct VenusLens.VTokenBalances[])function vTokenUnderlyingPrice(contract VToken vToken) public view returns (struct VenusLens.VTokenUnderlyingPrice)function vTokenUnderlyingPriceAll(contract VToken[] vTokens) external view returns (struct VenusLens.VTokenUnderlyingPrice[])function getAccountLimits(contract ComptrollerInterface comptroller, address account) public view returns (struct VenusLens.AccountLimits)function getXVSBalanceMetadata(contract IXVS xvs, address account) external view returns (struct VenusLens.XVSBalanceMetadata)function getXVSBalanceMetadataExt(contract IXVS xvs, contract ComptrollerInterface comptroller, address account) external returns (struct VenusLens.XVSBalanceMetadataExt)function getVenusVotes(contract IXVS xvs, address account, uint32[] blockNumbers) external view returns (struct VenusLens.VenusVotes[])function pendingRewards(address holder, contract ComptrollerInterface comptroller) external view returns (struct VenusLens.RewardSummary)function getAllPoolsData(contract ComptrollerInterface comptroller) external view returns (struct VenusLens.PoolWithMarkets[] poolsData)function getMarketsDataByPool(uint96 poolId, contract ComptrollerInterface comptroller) public view returns (struct VenusLens.MarketData[] result)function getEffectiveLiquidationIncentive(
address account,
address vToken
) external view returns (uint256);mapping(address => Market) public markets;type PoolMarketId is bytes32;
mapping(PoolMarketId => Market) public _poolMarkets;struct Market {
bool isListed;
uint256 collateralFactorMantissa;
mapping(address => bool) accountMembership;
bool isVenus;
uint256 liquidationThresholdMantissa;
uint256 liquidationIncentiveMantissa;
uint96 poolId;
bool isBorrowAllowed;
}struct PoolData {
string label; // e.g., "Stablecoins"
address[] vTokens; // Markets in this pool
bool allowCorePoolFallback; // If true, non-pool assets use Core Pool CF/LT/LI; if false, CF/LT/LI treated as 0
}
mapping(uint96 => PoolData) public pools;
uint96 public lastPoolId;mapping(address => uint96) public userPoolId;// E-Mode setter
function setCollateralFactor(uint96 poolId, VToken vToken, uint256 newCollateralFactorMantissa, uint256 newLiquidationThresholdMantissa) external returns (uint256);
// Core Pool setter
function setCollateralFactor(VToken vToken, uint256 newCollateralFactorMantissa, uint256 newLiquidationThresholdMantissa) external returns (uint256);enum WeightFunction {
USE_COLLATERAL_FACTOR, // 0
USE_LIQUIDATION_THRESHOLD // 1
}
function getEffectiveLtvFactor(
address account,
address vToken,
WeightFunction weightingStrategy
) external view returns (uint256);function getAccountLiquidity(address account) external view returns (uint256, uint256, uint256);The bridge supports transfers between all network pairs, providing users with enhanced flexibility and interoperability across blockchain ecosystems.
The system consists of multiple contracts, including XVSBridgeAdmin, XVSProxySrc, XVSProxyDest, and XVS token contracts.
The functionality of the bridge relies on LayerZero for the seamless transfer of XVS tokens across different networks. Consequently, the security and integrity of the token on each network are subject to potential vulnerabilities inherent in the bridging mechanism. It is essential to note that these risks are a general characteristic of integrating with network bridges and do not stem from any particular weaknesses within the token implementation.
To start using the XVS Cross-Chain Bridge, follow these steps:
Before transferring XVS tokens, you need to approve the Bridge contract on the BNB chain to spend XVS tokens on your behalf. Follow these steps:
Call the approve function of the XVS token contract with the following parameters:
_spender: Address of the Bridge contract on the BNB chain.
_amount: Amount of XVS tokens to approve for transfer.
To estimate the transaction fees required to send XVS tokens to the destination chain, call the estimateSend function of the Bridge contract with the following parameters:
_dstChainId: Destination chain ID, defined by LayerZero (e.g., Ethereum virtual chain ID (101))
_toAddress: Receiver address on the destination chain
_amount: Amount of XVS tokens you want to send, defined with 18 decimals
_useZro: false (indicating that you are not paying in LayerZero ZRO tokens)
_adapterParams: 0x000100000000000000000000000000000000000000000000000000000000000493E0 (ethers.utils.solidityPack(['uint16','uint256'],[1, gasValue]) the gas value should be greater then minDestGas which is set to 300k).
The actual token transfer is performed using the sendFrom function of the Bridge contract. Follow these steps:
Call the sendFrom function of the Bridge contract with the following parameters::
_from: Your address on the BNB chain
_dstChainId: Destination chain ID defined by LayerZero (e.g., Ethereum virtual chain ID (101))
_toAddress: The address on the destination chain where you want to receive the XVS tokens
_amount: Amount of XVS tokens you want to send, defined with 18 decimals
_callParams: ["RefundGasAddress", "ZROaddress", "adapterParams"]
RefundGasAddress: Address where you want to receive a refund for excessive gas sent. It can be the sender's address.
ZROaddress: 0x0000000000000000000000000000000000000000 (indicating that you are not paying in ZRO tokens)
When you send XVS tokens to the destination chain using the bridge, the tokens will be minted by the Bridge contract to the receiver's address on the destination chain.
To transfer XVS tokens back to the BNB chain, follow a similar process as mentioned in the earlier send section. You don't need to approve the Bridge contract on the destination chain to spend XVS tokens on your behalf. The tokens will be burned on the destination chain on your behalf and unlocked and transferred to the receiver's address on the BNB chain.
To transfer XVS tokens between destination chains, such as from Ethereum to opBNB, the process remains similar to the earlier send section. You don't need to approve the Bridge contract on the destination chain to spend XVS tokens on your behalf. The tokens will be burned on the one destination chain (Ethereum) and minted on the other destination chain (opBNB).
After initiating a token transfer, you should wait for the transaction to confirm. This process may take a few minutes. Once the transaction confirms, you will receive the bridged XVS tokens on the destination chain. You can use LayerZero scan to monitor your cross-chain transactions.
Use the transferOwnership method in the XVSBridgeAdmin contract to transfer ownership of the admin contract.
Use the transferBridgeOwnership method to transfer ownership of the Bridge contract from one contract to another.
Ownership control is crucial in case of emergencies or security issues.
The owner of the XVSBridgeAdmin contract will be initially the Guardian, but it will be transferred to Governance as soon as the MultichainGovernance module is deployed.
The Bridge includes a pause and unpause mechanism. Use the pause method to halt the contract's functionality and unpause to resume.
Pausing is a security measure to prevent further transactions during emergencies or potential attacks.
XVS Cross-chain messages that attempt to mint or release tokens to the receiver can be received by the destination Bridge contract. These messages will fail, but they can be retried once the destination Bridge Contract has been unpaused.
Example: Limit the maximum XVS transfer to USD 1,000 in one transaction and USD 100,000 in one day. These limits can be adjusted using VIPs.
Configurable delay after XVS transfers to the target network by specifying a minimum number of blocks in the LayerZero endpoint configuration.
Token Controller contract within the XVS token deployed on the target network to blacklist addresses, preventing them from transferring or receiving XVS. Integrated with the ACM.
Cap on the amount of tokens that can be minted in the destination target network. This feature can be integrated in Token Controller.
If XVS become stuck between bridges due to exceeding the mint cap, the system will extend the mint cap via VIP. The failed message will be retried.
The XVSProxyOFTDest contract serves as the Bridge model. It will be authorized to mint and burn XVS in the destination chain. Limits on these actions will be set by Governance or the Guardian.
While the initial deployment involves one Bridge contract per network, the system is designed to support several bridges simultaneously, providing users with flexibility.
The system's architecture allows for the deployment of multiple bridges within the same network, offering users the option to choose different bridges for their transactions. This flexibility ensures efficient and diverse token bridging capabilities.
Example of Bridging in Case of Multiple Active Bridges:
In the event that a Bridge contract needs replacement, such as due to a security risk, the following steps will be taken:
Pause the Bridge:
Temporarily pause the Bridge contract to prevent further transactions.
Token Evaluation:
Evaluate whether pausing the XVS token is necessary during the replacement process.
Migrate MinterToMintedAmount:
Move the minterToMintedAmount value to a different Bridge contract address using the migrateMintedTokens function.
Reduce MintCap:
Reduce the mintCap to zero for the Bridge contract address with security issues.
These steps ensure a secure and systematic replacement of a Bridge contract, maintaining the integrity of the token. Simultaneously, on the BNB chain, the locked XVS will be transferred and locked in the other Bridge contract, ensuring a fix total supply of XVS.
Currently, the Bridge relies on a single relayer, the default by LayerZero, to generate proofs and submit them to target chains. While this configuration is functional, it's important to be aware of the potential implications. If the relayer goes offline or encounters problems, there's no immediate backup to maintain bridge functionality, potentially delaying or preventing transactions. In the event of unforeseen downtime affecting the default LayerZero relayer, a wallet can be authorized to temporarily generate proofs and submit them on the target network on behalf of the relayer. This authorization is granted only in exceptional circumstances via VIP.
Here, we provide more details about the key contracts used in the XVS Cross-chain Bridge:
XVSBridgeAdmin is the admin contract for the bridge, ensuring proper setup.
It contains a functionRegistry mapping for function signatures, allowing the contract to call corresponding methods in destination contracts after ensuring access control permissions.
Ownership transfers for XVSBridgeAdmin and Bridge can be executed via the transferOwnership and transferBridgeOwnership methods respectively.
XVSProxySrc extends the BaseOFTV2 contract and includes custom logic for token transfers.
It overrides the _debitFrom and _creditTo functions, checking transaction limits and user eligibility.
It enforces transaction limits, tracks 24-hour window limits, and allows whitelisting of users.
XVSProxySrc can be paused and resumed in emergencies.
XVSProxyDest is similar to XVSProxySrc but with specific differences.
Transaction limits are enforced primarily for outbound amounts only in the source chain.
It overrides the debitFrom function to include custom logic for checking transaction limits in USD and performs an external call to the XVS token contract to burn tokens from the sender.
It overrides the creditTo function to trigger an external call to the XVS token contract to mint tokens for the receiver.
When sending tokens from the destination chain to the BNB chain, it burns user tokens, with the burning logic residing in the XVS token contract.
When receiving tokens from the BNB chain (to the Destination Chain), it mints tokens for the receiver, with the minting logic residing in the XVS token contract.
The XVS token contract is deployed on destination chains, and it is used within the XVSProxyDest contract.
The XVS token follows the ERC20 standard and extends the TokenController ownable contract, which contains all controlling mechanisms of the XVS.
It is responsible for setting minting limits for the minter (in this case, the remote Bridge contract).
When receiving transactions and tokens from the source chain's Bridge contract, an external call is made to mint tokens for the receiver.
When sending tokens to the source chain's Bridge contract, an external call is made from the Bridge contract to burn tokens from the sender.
Offers a blacklisting feature to prevent certain users from receiving, transferring and bridging XVS tokens.
integration is used for setting minting caps and blacklisting, and these settings can be configured via VIPs or Guardian.
In addition to the core functionality, the XVS Cross-chain Bridge includes additional features to enhance its capabilities:
The contract incorporates an oracle integration through the ResilientOracleInterface. It allows the contract to fetch price data for the token using the getPrice function.
The contract implements a whitelist mechanism to skip checks on transaction limits for whitelisted addresses. The whitelist mapping is used to track whitelisted addresses. The setWhitelist function allows adding or removing addresses from the whitelist.
The contract introduces transaction limits for both sending and receiving transactions, based on a daily and single transaction basis. The limits are defined using chainIdToMaxSingleTransactionLimit, chainIdToMaxDailyLimit, chainIdToMaxSingleReceiveTransactionLimit, and chainIdToMaxDailyReceiveLimit.
Single Send Limit (source network in the first column, destination network in the first row)
Daily Send Limit (source network in the first column, destination network in the first row)
Single Receive Limit = Single Send Limit + 2%
Daily Receive Limit = Daily Send Limit + 2%
Note: The additional 2% provides a margin to account for potential price fluctuations during the processing of bridging transactions.
The contract incorporates a pause and unpause mechanism using the Pausable library. The pause and unpause functions can be used to halt and resume the contract's functionality, respectively.
The oracle temporarily fails due to reasons including being paused by the owner, incorrect address configuration, or price validation failures.
The transfer amount exceeds the single or daily sending transaction limit.
The transfer amount is too small, becoming zero after removing dust.
The sender is blacklisted by the XVS token.
The destination bridge is not configured as a trusted remote.
The oracle temporarily fails due to reasons including being paused by the owner, incorrect address configuration, or price validation failures.
The transfer amount exceeds the single or daily receiving transaction limit.
The recipient is blacklisted by the XVS token.
The minting cap on the destination bridge is exceeded.
In the event of a failed transaction, follow the below step-by-step process using block explorers and the retryMessage function to retry transactions on the respective blockchain. Here's a detailed guide:
Identify the Failed Transaction:
Use LayerZero scan to identify the failed transaction within the target network by providing the transaction hash from the source network where the transaction was initiated.
Examine the MessageFailed Log:
Access the emitted events of the failed transaction and specifically examine the log. This log contains essential function parameters needed for the retry.
Extract Function Parameters:
From the MessageFailed log, extract the following essential function parameters:
_srcChainId
Construct a RetryMessage:
In the event of a transaction failure on the BNB chain, invoke the retryMessage function of the XVSProxyOFTSrc contract on the BNB chain. Use the parameters extracted from the MessageFailed log for this operation. Conversely, if the transaction fails on any network other than BNB chain, invoke the retryMessage function of the XVSProxyOFTDest contract on that network.
adapterParams: 0x000100000000000000000000000000000000000000000000000000000000000493E0 (ethers.utils.solidityPack(['uint16','uint256'],[1, gasValue]) the gas value should be greater then minDestGas which is set to 300k).
$20,000
-
$20,000
$20,000
$20,000
$20,000
Ethereum
$100,000
$10,000
$20,000
-
$20,000
$20,000
$20,000
ZKsync
$20,000
$20,000
$20,000
$20,000
-
$20,000
$20,000
Optimism
$20,000
$20,000
$20,000
$20,000
$20,000
-
$20,000
Base
$20,000
$20,000
$20,000
$20,000
$20,000
$20,000
-
$1,000,000
$100,000
$100,000
$100,000
opBNB
$50,000
-
$100,000
$50,000
$100,000
$100,000
$100,000
Arbitrum
$100,000
$100,000
-
$100,000
$100,000
$100,000
$100,000
Ethereum
$1,000,000
$50,000
$100,000
-
$100,000
$100,000
$100,000
ZKsync
$100,000
$100,000
$100,000
$100,000
-
$100,000
$100,000
Optimism
$100,000
$100,000
$100,000
$100,000
$100,000
-
$100,000
Base
$100,000
$100,000
$100,000
$100,000
$100,000
$100,000
-
_srcAddress_nonce
_payload
BNB
-
$10,000
$20,000
$100,000
$20,000
$20,000
$20,000
opBNB
$10,000
-
$20,000
$10,000
$20,000
$20,000
$20,000
Arbitrum
BNB
-
$50,000
$20,000
$100,000
1. Initial Setup:
- Bridge Contract A (BridgeA) has a minterToMintedAmount of 100 XVS.
- User A holds all 100 XVS minted by BridgeA.
2. Separate Bridge Contract B Setup:
- Bridge Contract B (BridgeB) has a separate minterToMintedAmount of 50 XVS.
- User B holds all 50 XVS minted by BridgeB.
3. User B Bridges Off Tokens Using Bridge A:
- User B decides to use BridgeA to bridge off his 50 XVS.
- After the successful bridging process, BridgeA's minterToMintedAmount is now 50, reflecting the XVS burned by User B through this BridgeA.
4. User A Bridges Off Tokens Using Both Bridges:
- Now, User A intends to bridge off his 100 XVS, splitting them between BridgeA and BridgeB.
- User A uses BridgeA for 50 XVS and BridgeB for the remaining 50 XVS.The XVS Vault allows XVS holders to lock their XVS to recieve voting rights in Venus governance and are rewarded with XVS.
Pauses vault
Resume vault
Returns the number of pools with the specified reward token
Parameters
Return Values
Add a new token pool
Parameters
Update the given pool's reward allocation point
Parameters
Update the given reward token's amount per block
Parameters
Update the lock period after which a requested withdrawal can be executed
Parameters
Deposit XVSVault for XVS allocation
Parameters
Claim rewards for pool
Parameters
Execute withdrawal to XVSVault for XVS allocation
Parameters
Request withdrawal to XVSVault for XVS allocation
Parameters
Get unlocked withdrawal amount
Parameters
Return Values
Get requested amount
Parameters
Return Values
Returns the array of withdrawal requests that have not been executed yet
Parameters
Return Values
View function to see pending XVSs on frontend
Parameters
Return Values
Update reward variables of the given pool to be up-to-date
Parameters
Get user info with reward token address and pid
Parameters
Return Values
Gets the total pending withdrawal amount of a user before upgrade
Parameters
Return Values
Delegate votes from msg.sender to delegatee
Parameters
Delegates votes from signatory to delegatee
Parameters
Gets the current votes balance for account
Parameters
Return Values
Determine the xvs stake balance for an account
Parameters
Return Values
Admin Functions **
Sets the address of the access control of this contract
Parameters
_lockPeriod
uint256
A period between withdrawal request and a moment when it's executable
r
bytes32
Half of the ECDSA signature pair
s
bytes32
Half of the ECDSA signature pair
rewardToken
address
Reward token address
[0]
uint256
Number of pools that distribute the specified token as a reward
_rewardToken
address
Reward token address
_allocPoint
uint256
Number of allocation points assigned to this pool
_token
contract IBEP20
Staked token
_rewardPerBlock
uint256
_rewardToken
address
Reward token address
_pid
uint256
Pool index
_allocPoint
uint256
Number of allocation points assigned to this pool
_rewardToken
address
Reward token address
_rewardAmount
uint256
Number of allocation points assigned to this pool
_rewardToken
address
Reward token address
_pid
uint256
Pool index
_newPeriod
uint256
New lock period
_rewardToken
address
The Reward Token Address
_pid
uint256
The Pool Index
_amount
uint256
The amount to deposit to vault
_account
address
The account for which to claim rewards
_rewardToken
address
The Reward Token Address
_pid
uint256
The Pool Index
_rewardToken
address
The Reward Token Address
_pid
uint256
The Pool Index
_rewardToken
address
The Reward Token Address
_pid
uint256
The Pool Index
_amount
uint256
The amount to withdraw from the vault
_rewardToken
address
The Reward Token Address
_pid
uint256
The Pool Index
_user
address
The User Address
withdrawalAmount
uint256
Amount that the user can withdraw
_rewardToken
address
The Reward Token Address
_pid
uint256
The Pool Index
_user
address
The User Address
[0]
uint256
Total amount of requested but not yet executed withdrawals (including both executable and locked ones)
_rewardToken
address
The Reward Token Address
_pid
uint256
The Pool Index
_user
address
The User Address
[0]
struct XVSVaultStorageV1.WithdrawalRequest[]
An array of withdrawal requests
_rewardToken
address
Reward token address
_pid
uint256
Pool index
_user
address
User address
[0]
uint256
Reward the user is eligible for in this pool, in terms of _rewardToken
_rewardToken
address
Reward token address
_pid
uint256
Pool index
_rewardToken
address
Reward token address
_pid
uint256
Pool index
_user
address
User address
amount
uint256
Deposited amount
rewardDebt
uint256
Reward debt (technical value used to track past payouts)
pendingWithdrawals
uint256
Requested but not yet executed withdrawals
_rewardToken
address
The Reward Token Address
_pid
uint256
The Pool Index
_user
address
The address of the user
beforeUpgradeWithdrawalAmount
uint256
Total pending withdrawal amount in requests made before the vault upgrade
delegatee
address
The address to delegate votes to
delegatee
address
The address to delegate votes to
nonce
uint256
The contract state required to match the signature
expiry
uint256
The time at which to expire the signature
v
uint8
account
address
The address to get votes balance
[0]
uint96
The number of current votes for account
account
address
The address of the account to check
blockNumber
uint256
The block number to get the vote balance at
[0]
uint96
The balance that user staked
newAccessControlAddress
address
New address for the access control
Initial reward per block, in terms of _rewardToken
The recovery byte of the signature
function pause() externalfunction resume() externalfunction poolLength(address rewardToken) external view returns (uint256)function add(address _rewardToken, uint256 _allocPoint, contract IBEP20 _token, uint256 _rewardPerBlock, uint256 _lockPeriod) externalfunction set(address _rewardToken, uint256 _pid, uint256 _allocPoint) externalfunction setRewardAmountPerBlock(address _rewardToken, uint256 _rewardAmount) externalfunction setWithdrawalLockingPeriod(address _rewardToken, uint256 _pid, uint256 _newPeriod) externalfunction deposit(address _rewardToken, uint256 _pid, uint256 _amount) externalfunction claim(address _account, address _rewardToken, uint256 _pid) externalfunction executeWithdrawal(address _rewardToken, uint256 _pid) externalfunction requestWithdrawal(address _rewardToken, uint256 _pid, uint256 _amount) externalfunction getEligibleWithdrawalAmount(address _rewardToken, uint256 _pid, address _user) external view returns (uint256 withdrawalAmount)function getRequestedAmount(address _rewardToken, uint256 _pid, address _user) external view returns (uint256)function getWithdrawalRequests(address _rewardToken, uint256 _pid, address _user) external view returns (struct XVSVaultStorageV1.WithdrawalRequest[])function pendingReward(address _rewardToken, uint256 _pid, address _user) external view returns (uint256)function updatePool(address _rewardToken, uint256 _pid) externalfunction getUserInfo(address _rewardToken, uint256 _pid, address _user) external view returns (uint256 amount, uint256 rewardDebt, uint256 pendingWithdrawals)function pendingWithdrawalsBeforeUpgrade(address _rewardToken, uint256 _pid, address _user) public view returns (uint256 beforeUpgradeWithdrawalAmount)function delegate(address delegatee) externalfunction delegateBySig(address delegatee, uint256 nonce, uint256 expiry, uint8 v, bytes32 r, bytes32 s) externalfunction getCurrentVotes(address account) external view returns (uint96)function getPriorVotes(address account, uint256 blockNumber) external view returns (uint96)function _become(contract XVSVaultProxy xvsVaultProxy) externalfunction setAccessControl(address newAccessControlAddress) externaltotal blocks per year
address of WBNB contract
address of VBNB contract
minimum amount of XVS user needs to stake to become a prime member
maximum XVS taken in account when calculating user score
number of days user need to stake to claim prime token
Prime initializer
Parameters
xvsVault_
address
Address of XVSVault
xvsVaultRewardToken_
address
Address of XVSVault reward token
xvsVaultPoolId_
uint256
Pool id of XVSVault
alphaNumerator_
uint128
❌ Errors
Throw InvalidAddress if any of the address is invalid
Returns boosted pending interest accrued for a user for all markets
Parameters
user
address
the account for which to get the accrued interests
Return Values
pendingRewards
struct PrimeStorageV1.PendingReward[]
the number of underlying tokens accrued by the user for all markets
Update total score of multiple users and market
Parameters
users
address[]
accounts for which we need to update score
📅 Events
Emits UserScoreUpdated event
❌ Errors
Throw NoScoreUpdatesRequired if no score updates are required
Throw UserHasNoPrimeToken if user has no prime token
Update value of alpha
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
📅 Events
Emits AlphaUpdated event
⛔️ Access Requirements
Controlled by ACM
Update multipliers for a market
Parameters
market
address
address of the market vToken
supplyMultiplier
uint256
new supply multiplier for the market, scaled by 1e18
borrowMultiplier
uint256
new borrow multiplier for the market, scaled by 1e18
📅 Events
Emits MultiplierUpdated event
⛔️ Access Requirements
Controlled by ACM
❌ Errors
Throw MarketNotSupported if market is not supported
Update staked at timestamp for multiple users
Parameters
users
address[]
accounts for which we need to update staked at timestamp
timestamps
uint256[]
new staked at timestamp for the users
📅 Events
Emits StakedAtUpdated event for each user
⛔️ Access Requirements
Controlled by ACM
❌ Errors
Throw InvalidLength if users and timestamps length are not equal
Add a market to prime program
Parameters
market
address
address of the market vToken
supplyMultiplier
uint256
the multiplier for supply cap. It should be converted to 1e18
borrowMultiplier
uint256
the multiplier for borrow cap. It should be converted to 1e18
📅 Events
Emits MarketAdded event
⛔️ Access Requirements
Controlled by ACM
❌ Errors
Throw MarketAlreadyExists if market already exists
Throw InvalidVToken if market is not valid
Set limits for total tokens that can be minted
Parameters
_irrevocableLimit
uint256
total number of irrevocable tokens that can be minted
_revocableLimit
uint256
total number of revocable tokens that can be minted
📅 Events
Emits MintLimitsUpdated event
⛔️ Access Requirements
Controlled by ACM
❌ Errors
Throw InvalidLimit if any of the limit is less than total tokens minted
Set the limit for the loops can iterate to avoid the DOS
Parameters
loopsLimit
uint256
Number of loops limit
📅 Events
Emits MaxLoopsLimitUpdated event on success
⛔️ Access Requirements
Controlled by ACM
Directly issue prime tokens to users
Parameters
isIrrevocable
bool
are the tokens being issued
users
address[]
list of address to issue tokens to
⛔️ Access Requirements
Controlled by ACM
Executed by XVSVault whenever user's XVSVault balance changes
Parameters
user
address
the account address whose balance was updated
accrues interes and updates score for an user for a specific market
Parameters
user
address
the account address for which to accrue interest and update score
market
address
the market for which to accrue interest and update score
For claiming prime token when staking period is completed
For burning any prime token
Parameters
user
address
the account address for which the prime token will be burned
⛔️ Access Requirements
Controlled by ACM
To pause or unpause claiming of interest
⛔️ Access Requirements
Controlled by ACM
For user to claim boosted yield
Parameters
vToken
address
the market for which claim the accrued interest
Return Values
[0]
uint256
amount the amount of tokens transferred to the msg.sender
For user to claim boosted yield
Parameters
vToken
address
the market for which claim the accrued interest
user
address
the user for which to claim the accrued interest
Return Values
[0]
uint256
amount the amount of tokens transferred to the user
Retrieves an array of all available markets
Return Values
[0]
address[]
an array of addresses representing all available markets
fetch the numbers of seconds remaining for staking period to complete
Parameters
user
address
the account address for which we are checking the remaining time
Return Values
[0]
uint256
timeRemaining the number of seconds the user needs to wait to claim prime token
Returns supply and borrow APR for user for a given market
Parameters
market
address
the market for which to fetch the APR
user
address
the account for which to get the APR
Return Values
supplyAPR
uint256
supply APR of the user in BPS
borrowAPR
uint256
borrow APR of the user in BPS
Returns supply and borrow APR for estimated supply, borrow and XVS staked
Parameters
market
address
the market for which to fetch the APR
user
address
the account for which to get the APR
borrow
uint256
hypothetical borrow amount
supply
uint256
Return Values
supplyAPR
uint256
supply APR of the user in BPS
borrowAPR
uint256
borrow APR of the user in BPS
Distributes income from market since last distribution
Parameters
vToken
address
the market for which to distribute the income
❌ Errors
Throw MarketNotSupported if market is not supported
Returns boosted interest accrued for a user
Parameters
vToken
address
the market for which to fetch the accrued interest
user
address
the account for which to get the accrued interest
Return Values
[0]
uint256
interestAccrued the number of underlying tokens accrued by the user since the last accrual
Checks if the account should be allowed to mint tokens in the given market
Parameters
vToken
address
The market to verify the mint against
minter
address
The account which would get the minted tokens
mintAmount
uint256
The amount of underlying being supplied to the market in exchange for tokens
Return Values
[0]
uint256
0 if the mint is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol)
Validates mint, accrues interest and updates score in prime. Reverts on rejection. May emit logs.
Parameters
vToken
address
Asset being minted
minter
address
The address minting the tokens
actualMintAmount
uint256
The amount of the underlying asset being minted
mintTokens
uint256
Checks if the account should be allowed to redeem tokens in the given market
Parameters
vToken
address
The market to verify the redeem against
redeemer
address
The account which would redeem the tokens
redeemTokens
uint256
The number of vTokens to exchange for the underlying asset in the market
Return Values
[0]
uint256
0 if the redeem is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol)
Validates redeem, accrues interest and updates score in prime. Reverts on rejection. May emit logs.
Parameters
vToken
address
Asset being redeemed
redeemer
address
The address redeeming the tokens
redeemAmount
uint256
The amount of the underlying asset being redeemed
redeemTokens
uint256
Checks if the account should be allowed to borrow the underlying asset of the given market
Parameters
vToken
address
The market to verify the borrow against
borrower
address
The account which would borrow the asset
borrowAmount
uint256
The amount of underlying the account would borrow
Return Values
[0]
uint256
0 if the borrow is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol)
Validates borrow, accrues interest and updates score in prime. Reverts on rejection. May emit logs.
Parameters
vToken
address
Asset whose underlying is being borrowed
borrower
address
The address borrowing the underlying
borrowAmount
uint256
The amount of the underlying asset requested to borrow
Checks if the account should be allowed to repay a borrow in the given market
Parameters
vToken
address
The market to verify the repay against
payer
address
The account which would repay the asset
borrower
address
The account which borrowed the asset
repayAmount
uint256
Return Values
[0]
uint256
0 if the repay is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol)
Validates repayBorrow, accrues interest and updates score in prime. Reverts on rejection. May emit logs.
Parameters
vToken
address
Asset being repaid
payer
address
The address repaying the borrow
borrower
address
The address of the borrower
actualRepayAmount
uint256
Checks if the liquidation should be allowed to occur
Parameters
vTokenBorrowed
address
Asset which was borrowed by the borrower
vTokenCollateral
address
Asset which was used as collateral and will be seized
liquidator
address
The address repaying the borrow and seizing the collateral
borrower
address
Validates liquidateBorrow, accrues interest and updates score in prime. Reverts on rejection. May emit logs.
Parameters
vTokenBorrowed
address
Asset which was borrowed by the borrower
vTokenCollateral
address
Asset which was used as collateral and will be seized
liquidator
address
The address repaying the borrow and seizing the collateral
borrower
address
Checks if the seizing of assets should be allowed to occur
Parameters
vTokenCollateral
address
Asset which was used as collateral and will be seized
vTokenBorrowed
address
Asset which was borrowed by the borrower
liquidator
address
The address repaying the borrow and seizing the collateral
borrower
address
Validates seize, accrues interest and updates score in prime. Reverts on rejection. May emit logs.
Parameters
vTokenCollateral
address
Asset which was used as collateral and will be seized
vTokenBorrowed
address
Asset which was borrowed by the borrower
liquidator
address
The address repaying the borrow and seizing the collateral
borrower
address
Checks if the account should be allowed to transfer tokens in the given market
Parameters
vToken
address
The market to verify the transfer against
src
address
The account which sources the tokens
dst
address
The account which receives the tokens
transferTokens
uint256
Return Values
[0]
uint256
0 if the transfer is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol)
Validates transfer, accrues interest and updates score in prime. Reverts on rejection. May emit logs.
Parameters
vToken
address
Asset being transferred
src
address
The account which sources the tokens
dst
address
The account which receives the tokens
transferTokens
uint256
Alias to getAccountLiquidity to support the Isolated Lending Comptroller Interface
Parameters
account
address
The account get liquidity for
Return Values
[0]
uint256
(possible error code (semi-opaque), account liquidity in excess of collateral requirements, account shortfall below collateral requirements)
[1]
uint256
[2]
uint256
Determine the current account liquidity wrt liquidation threshold requirements
Parameters
account
address
The account get liquidity for
Return Values
[0]
uint256
(possible error code (semi-opaque), account liquidity in excess of liquidation threshold requirements, account shortfall below liquidation threshold requirements)
[1]
uint256
[2]
uint256
Determine what the account liquidity would be if the given amounts were redeemed/borrowed
Parameters
account
address
The account to determine liquidity for
vTokenModify
address
The market to hypothetically redeem/borrow in
redeemTokens
uint256
The number of tokens to hypothetically redeem
borrowAmount
uint256
Return Values
[0]
uint256
(possible error code (semi-opaque), hypothetical account liquidity in excess of collateral requirements, hypothetical account shortfall below collateral requirements)
[1]
uint256
[2]
uint256
Set XVS speed for a single market
Parameters
vTokens
contract VToken[]
The market whose XVS speed to update
supplySpeeds
uint256[]
New XVS speed for supply
borrowSpeeds
uint256[]
New XVS speed for borrow
This facet contract contains all the configurational setter functions
Alias to _setPriceOracle to support the Isolated Lending Comptroller Interface
Parameters
Return Values
Sets a new price oracle for the comptroller
Parameters
Return Values
Alias to _setCloseFactor to support the Isolated Lending Comptroller Interface
Parameters
Return Values
Sets the closeFactor used when liquidating borrows
Parameters
Return Values
Sets the address of the access control of this contract
Parameters
Return Values
Sets the collateral factor and liquidation threshold for a market in the Core Pool only.
Parameters
Return Values
Sets the liquidation incentive for a market in the Core Pool only.
Parameters
Return Values
Sets the collateral factor and liquidation threshold for a market in the specified pool.
Parameters
Return Values
Sets the liquidation incentive for a market in the specified pool.
Parameters
Return Values
Update the address of the liquidator contract
Parameters
Admin function to change the Pause Guardian
Parameters
Return Values
Alias to _setMarketBorrowCaps to support the Isolated Lending Comptroller Interface
Parameters
Set the given borrow caps for the given vToken market Borrowing that brings total borrows to or above borrow cap will revert
Parameters
Alias to _setMarketSupplyCaps to support the Isolated Lending Comptroller Interface
Parameters
Set the given supply caps for the given vToken market Supply that brings total Supply to or above supply cap will revert
Parameters
Set whole protocol pause/unpause state
Parameters
Return Values
Alias to _setActionsPaused to support the Isolated Lending Comptroller Interface
Parameters
Pause/unpause certain actions
Parameters
Sets a new VAI controller
Return Values
Set the VAI mint rate
Parameters
Return Values
Set the minted VAI amount of the owner
Parameters
Return Values
Set the treasury data.
Parameters
Return Values
Set the amount of XVS distributed per block to VAI Vault
Parameters
Set the VAI Vault infos
Parameters
Alias to _setPrimeToken to support the Isolated Lending Comptroller Interface
Parameters
Return Values
Sets the prime token contract for the comptroller
Parameters
Return Values
Alias to _setForcedLiquidation to support the Isolated Lending Comptroller Interface
Parameters
Enables forced liquidations for a market. If forced liquidation is enabled, borrows in the market may be liquidated regardless of the account liquidity
Parameters
Enables forced liquidations for user's borrows in a certain market. If forced liquidation is enabled, user's borrows in the market may be liquidated regardless of the account liquidity. Forced liquidation may be enabled for a user even if it is not enabled for the entire market.
Parameters
Explanation: This function grants or revokes an account's permission to use the protocol's flash loan feature, enforcing access control and address validation.
Parameters
Return Values
Set the address of the XVS token
Parameters
Set the address of the XVS vToken
Parameters
updates active status for a specific pool (excluding the Core Pool)
Parameters
📅 Events
PoolActiveStatusUpdated Emitted after the pool active status is updated.
❌ Errors
InvalidOperationForCorePool Reverts when attempting to call pool-specific methods on the Core Pool.
PoolDoesNotExist Reverts if the target pool ID does not exist.
Updates the isBorrowAllowed flag for a market in a pool.
Parameters
📅 Events
BorrowAllowedUpdated Emitted after the borrow permission for a market is updated.
❌ Errors
PoolDoesNotExist Reverts if the pool ID is invalid.
MarketConfigNotFound Reverts if the market is not listed in the pool.
This facet contract contains functions regarding markets
Indicator that this is a Comptroller contract (for inspection)
Returns the vToken markets an account has entered in the Core Pool
Parameters
Return Values
Return all of the markets
Return Values
Calculate number of tokens of collateral asset to seize given an underlying amount
Parameters
Return Values
Calculate number of tokens of collateral asset to seize given an underlying amount
Parameters
Return Values
Calculate number of tokens of collateral asset to seize given an underlying amount
Parameters
Return Values
Returns whether the given account has entered the specified vToken market in the Core Pool
Parameters
Return Values
Checks whether the given vToken market is listed in the Core Pool (poolId = 0)
Parameters
Return Values
Add assets to be included in account liquidity calculation
Parameters
Return Values
Unlists the given vToken market from the Core Pool (poolId = 0) by setting isListed to false
Parameters
Return Values
Removes asset from sender's account liquidity calculation
Parameters
Return Values
Alias to _supportMarket to support the Isolated Lending Comptroller Interface
Parameters
Return Values
Adds the given vToken market to the Core Pool (poolId = 0) and marks it as listed
Parameters
Return Values
Grants or revokes the borrowing or redeeming delegate rights to / from an account If allowed, the delegate will be able to borrow funds on behalf of the sender Upon a delegated borrow, the delegate will receive the funds, and the borrower will see the debt on their account Upon a delegated redeem, the delegate will receive the redeemed amount and the approver will see a deduction in his vToken balance
Parameters
Allows a user to switch to a new pool (e.g., e-mode ).
Parameters
📅 Events
PoolSelected Emitted after a successful pool switch.
❌ Errors
PoolDoesNotExist The specified pool ID does not exist.
AlreadyInSelectedPool The user is already in the target pool.
IncompatibleBorrowedAssets The user's current borrows are incompatible with the new pool.
LiquidityCheckFailed The user's liquidity is insufficient after switching pools.
Creates a new pool with the given label.
Parameters
Return Values
📅 Events
PoolCreated Emitted after successfully creating a new pool.
❌ Errors
EmptyPoolLabel Reverts if the provided label is an empty string.
Batch initializes market entries with basic config.
Parameters
📅 Events
PoolMarketInitialized Emitted after successfully initializing a market in a pool.
❌ Errors
ArrayLengthMismatch Reverts if poolIds and vTokens arrays have different lengths or if the length is zero.
InvalidOperationForCorePool Reverts when attempting to call pool-specific methods on the Core Pool.
PoolDoesNotExist Reverts if the target pool ID does not exist.
Removes a market (vToken) from the specified pool.
Parameters
📅 Events
PoolMarketRemoved Emitted after a market is successfully removed from a pool.
❌ Errors
InvalidOperationForCorePool Reverts if called on the Core Pool.
PoolMarketNotFound Reverts if the market is not listed in the pool.
Get the core pool collateral factor for a vToken
Parameters
Return Values
Get the core pool liquidation threshold for a vToken
Parameters
Return Values
Get the core pool liquidation Incentive for a vToken
Parameters
Return Values
Returns the effective loan-to-value factor (collateral factor or liquidation threshold) for a given account and market.
Parameters
Return Values
Get the Effective liquidation Incentive for a given account and market
Parameters
Return Values
Returns the full list of vTokens for a given pool ID.
Parameters
Return Values
❌ Errors
PoolDoesNotExist Reverts if the given pool ID do not exist.
InvalidOperationForCorePool Reverts if called on the Core Pool.
Returns the market configuration for a vToken in the core pool (poolId = 0).
Parameters
Return Values
Returns the market configuration for a vToken from _poolMarkets.
Parameters
Return Values
❌ Errors
PoolDoesNotExist Reverts if the given pool ID do not exist.
Returns true if the user can switch to the given target pool, i.e., all markets they have borrowed from are also borrowable in the target pool.
Parameters
Return Values
uint256 BLOCKS_PER_YEARaddress WBNBaddress VBNBuint256 MINIMUM_STAKED_XVSuint256 MAXIMUM_XVS_CAPuint256 STAKING_PERIODfunction initialize(address xvsVault_, address xvsVaultRewardToken_, uint256 xvsVaultPoolId_, uint128 alphaNumerator_, uint128 alphaDenominator_, address accessControlManager_, address primeLiquidityProvider_, address comptroller_, address oracle_, uint256 loopsLimit_) externalfunction getPendingRewards(address user) external returns (struct PrimeStorageV1.PendingReward[] pendingRewards)function updateScores(address[] users) externalfunction updateAlpha(uint128 _alphaNumerator, uint128 _alphaDenominator) externalfunction updateMultipliers(address market, uint256 supplyMultiplier, uint256 borrowMultiplier) externalfunction setStakedAt(address[] users, uint256[] timestamps) externalfunction addMarket(address market, uint256 supplyMultiplier, uint256 borrowMultiplier) externalfunction setLimit(uint256 _irrevocableLimit, uint256 _revocableLimit) externalfunction setMaxLoopsLimit(uint256 loopsLimit) externalfunction issue(bool isIrrevocable, address[] users) externalfunction xvsUpdated(address user) externalfunction accrueInterestAndUpdateScore(address user, address market) externalfunction claim() externalfunction burn(address user) externalfunction togglePause() externalfunction claimInterest(address vToken) external returns (uint256)function claimInterest(address vToken, address user) external returns (uint256)function getAllMarkets() external view returns (address[])function claimTimeRemaining(address user) external view returns (uint256)function calculateAPR(address market, address user) external view returns (uint256 supplyAPR, uint256 borrowAPR)function estimateAPR(address market, address user, uint256 borrow, uint256 supply, uint256 xvsStaked) external view returns (uint256 supplyAPR, uint256 borrowAPR)function accrueInterest(address vToken) publicfunction getInterestAccrued(address vToken, address user) public returns (uint256)function mintAllowed(address vToken, address minter, uint256 mintAmount) external returns (uint256)function mintVerify(address vToken, address minter, uint256 actualMintAmount, uint256 mintTokens) externalfunction redeemAllowed(address vToken, address redeemer, uint256 redeemTokens) external returns (uint256)function redeemVerify(address vToken, address redeemer, uint256 redeemAmount, uint256 redeemTokens) externalfunction borrowAllowed(address vToken, address borrower, uint256 borrowAmount) external returns (uint256)function borrowVerify(address vToken, address borrower, uint256 borrowAmount) externalfunction repayBorrowAllowed(address vToken, address payer, address borrower, uint256 repayAmount) external returns (uint256)function repayBorrowVerify(address vToken, address payer, address borrower, uint256 actualRepayAmount, uint256 borrowerIndex) externalfunction liquidateBorrowAllowed(address vTokenBorrowed, address vTokenCollateral, address liquidator, address borrower, uint256 repayAmount) external view returns (uint256)function liquidateBorrowVerify(address vTokenBorrowed, address vTokenCollateral, address liquidator, address borrower, uint256 actualRepayAmount, uint256 seizeTokens) externalfunction seizeAllowed(address vTokenCollateral, address vTokenBorrowed, address liquidator, address borrower, uint256 seizeTokens) external returns (uint256)function seizeVerify(address vTokenCollateral, address vTokenBorrowed, address liquidator, address borrower, uint256 seizeTokens) externalfunction transferAllowed(address vToken, address src, address dst, uint256 transferTokens) external returns (uint256)function transferVerify(address vToken, address src, address dst, uint256 transferTokens) externalfunction getBorrowingPower(address account) external view returns (uint256, uint256, uint256)function getAccountLiquidity(address account) external view returns (uint256, uint256, uint256)function getHypotheticalAccountLiquidity(address account, address vTokenModify, uint256 redeemTokens, uint256 borrowAmount) external view returns (uint256, uint256, uint256)function _setVenusSpeeds(contract VToken[] vTokens, uint256[] supplySpeeds, uint256[] borrowSpeeds) externalnumerator of alpha. If alpha is 0.5 then numerator is 1. alphaDenominator_ must be greater than alphaNumerator_, alphaDenominator_ cannot be zero and alphaNumerator_ cannot be zero
alphaDenominator_
uint128
denominator of alpha. If alpha is 0.5 then denominator is 2. alpha is alphaNumerator_/alphaDenominator_. So, 0 < alpha < 1
accessControlManager_
address
Address of AccessControlManager
primeLiquidityProvider_
address
Address of PrimeLiquidityProvider
comptroller_
address
Address of Comptroller
oracle_
address
Address of Oracle
loopsLimit_
uint256
Maximum number of loops allowed in a single transaction
hypothetical supply amount
xvsStaked
uint256
hypothetical staked XVS amount
The number of tokens being minted
The number of tokens being redeemed
The amount of the underlying asset the account would repay
The amount of underlying being repaid
borrowerIndex
uint256
The address of the borrower
repayAmount
uint256
The amount of underlying being repaid
The address of the borrower
actualRepayAmount
uint256
The amount of underlying being repaid
seizeTokens
uint256
The amount of collateral token that will be seized
The address of the borrower
seizeTokens
uint256
The number of collateral tokens to seize
The address of the borrower
seizeTokens
uint256
The number of collateral tokens to seize
The number of vTokens to transfer
The number of vTokens to transfer
The amount of underlying to hypothetically borrow
newOracle
contract ResilientOracleInterface
The new price oracle to set
[0]
uint256
uint256 0=success, otherwise a failure (see ErrorReporter.sol for details)
newOracle
contract ResilientOracleInterface
The new price oracle to set
[0]
uint256
uint256 0=success, otherwise a failure (see ErrorReporter.sol for details)
newCloseFactorMantissa
uint256
New close factor, scaled by 1e18
[0]
uint256
uint256 0=success, otherwise will revert
newCloseFactorMantissa
uint256
New close factor, scaled by 1e18
[0]
uint256
uint256 0=success, otherwise will revert
newAccessControlAddress
address
New address for the access control
[0]
uint256
uint256 0=success, otherwise will revert
vToken
contract VToken
The market to set the factor on
newCollateralFactorMantissa
uint256
The new collateral factor, scaled by 1e18
newLiquidationThresholdMantissa
uint256
The new liquidation threshold, scaled by 1e18
[0]
uint256
uint256 0=success, otherwise a failure. (See ErrorReporter for details)
vToken
address
The market to set the liquidationIncentive for
newLiquidationIncentiveMantissa
uint256
New liquidationIncentive scaled by 1e18
[0]
uint256
uint256 0=success, otherwise a failure. (See ErrorReporter for details)
poolId
uint96
The ID of the pool.
vToken
contract VToken
The market to set the factor on
newCollateralFactorMantissa
uint256
The new collateral factor, scaled by 1e18
newLiquidationThresholdMantissa
uint256
[0]
uint256
uint256 0=success, otherwise a failure. (See ErrorReporter for details)
poolId
uint96
The ID of the pool.
vToken
address
The market to set the liquidationIncentive for
newLiquidationIncentiveMantissa
uint256
New liquidationIncentive scaled by 1e18
[0]
uint256
uint256 0=success, otherwise a failure. (See ErrorReporter for details)
newLiquidatorContract_
address
The new address of the liquidator contract
newPauseGuardian
address
The address of the new Pause Guardian
[0]
uint256
uint256 0=success, otherwise a failure. (See enum Error for details)
vTokens
contract VToken[]
The addresses of the markets (tokens) to change the borrow caps for
newBorrowCaps
uint256[]
The new borrow cap values in underlying to be set. A value of 0 corresponds to Borrow not allowed
vTokens
contract VToken[]
The addresses of the markets (tokens) to change the borrow caps for
newBorrowCaps
uint256[]
The new borrow cap values in underlying to be set. A value of 0 corresponds to Borrow not allowed
vTokens
contract VToken[]
The addresses of the markets (tokens) to change the supply caps for
newSupplyCaps
uint256[]
The new supply cap values in underlying to be set. A value of 0 corresponds to Minting NotAllowed
vTokens
contract VToken[]
The addresses of the markets (tokens) to change the supply caps for
newSupplyCaps
uint256[]
The new supply cap values in underlying to be set. A value of 0 corresponds to Minting NotAllowed
state
bool
The new state (true=paused, false=unpaused)
[0]
bool
bool The updated state of the protocol
markets_
address[]
Markets to pause/unpause the actions on
actions_
enum Action[]
List of action ids to pause/unpause
paused_
bool
The new paused state (true=paused, false=unpaused)
markets_
address[]
Markets to pause/unpause the actions on
actions_
enum Action[]
List of action ids to pause/unpause
paused_
bool
The new paused state (true=paused, false=unpaused)
[0]
uint256
uint256 0=success, otherwise a failure (see ErrorReporter.sol for details)
newVAIMintRate
uint256
The new VAI mint rate to be set
[0]
uint256
uint256 0=success, otherwise a failure (see ErrorReporter.sol for details)
owner
address
The address of the account to set
amount
uint256
The amount of VAI to set to the account
[0]
uint256
The number of minted VAI by owner
newTreasuryGuardian
address
The new address of the treasury guardian to be set
newTreasuryAddress
address
The new address of the treasury to be set
newTreasuryPercent
uint256
The new treasury percent to be set
[0]
uint256
uint256 0=success, otherwise a failure (see ErrorReporter.sol for details)
venusVAIVaultRate_
uint256
The amount of XVS wei per block to distribute to VAI Vault
vault_
address
The address of the VAI Vault
releaseStartBlock_
uint256
The start block of release to VAI Vault
minReleaseAmount_
uint256
The minimum release amount to VAI Vault
_prime
contract IPrime
The new prime token contract to be set
[0]
uint256
uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
_prime
contract IPrime
The new prime token contract to be set
[0]
uint256
uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
vTokenBorrowed
address
Borrowed vToken
enable
bool
Whether to enable forced liquidations
vTokenBorrowed
address
Borrowed vToken
enable
bool
Whether to enable forced liquidations
borrower
address
The address of the borrower
vTokenBorrowed
address
Borrowed vToken
enable
bool
Whether to enable forced liquidations
account
address
The account to whitelist or remove
_isWhiteListed
bool
True to whitelist, false to remove
None
xvs_
address
The address of the XVS token
xvsVToken_
address
The address of the XVS vToken
poolId
uint96
id of the pool to update
active
bool
true to enable, false to disable
poolId
uint96
The ID of the pool.
vToken
address
The address of the market (vToken).
borrowAllowed
bool
The new borrow allowed status.
The new liquidation threshold, scaled by 1e18
InactivePool The user is trying to enter inactive pool.
MarketAlreadyListed Reverts if the given market is already listed in the specified pool.
InactivePool Reverts if attempted to add markets to an inactive pool.
liquidationIncentiveMantissa
uint256
The max liquidation incentive allowed for this market, in mantissa.
marketPoolId
uint96
The pool ID this market belongs to.
isBorrowAllowed
bool
Whether borrowing is allowed in this market.
liquidationIncentiveMantissa
uint256
The liquidation incentive allowed for this market, in mantissa.
marketPoolId
uint96
The pool ID this market belongs to.
isBorrowAllowed
bool
Whether borrowing is allowed in this market.
account
address
The address of the account to query
[0]
contract VToken[]
assets A dynamic array of vToken markets the account has entered
[0]
contract VToken[]
The list of market addresses
vTokenBorrowed
address
The address of the borrowed vToken
vTokenCollateral
address
The address of the collateral vToken
actualRepayAmount
uint256
The amount of vTokenBorrowed underlying to convert into vTokenCollateral tokens
[0]
uint256
(errorCode, number of vTokenCollateral tokens to be seized in a liquidation)
[1]
uint256
borrower
address
Address of borrower whose collateral is being seized
vTokenBorrowed
address
The address of the borrowed vToken
vTokenCollateral
address
The address of the collateral vToken
actualRepayAmount
uint256
[0]
uint256
(errorCode, number of vTokenCollateral tokens to be seized in a liquidation)
[1]
uint256
vTokenCollateral
address
The address of the collateral vToken
actualRepayAmount
uint256
The amount of vTokenBorrowed underlying to convert into vTokenCollateral tokens
[0]
uint256
(errorCode, number of vTokenCollateral tokens to be seized in a liquidation)
[1]
uint256
account
address
The address of the account to check
vToken
contract VToken
The vToken to check
[0]
bool
True if the account is in the asset, otherwise false
vToken
contract VToken
The vToken Address of the market to check
[0]
bool
listed True if the (Core Pool, vToken) market is listed, otherwise false
vTokens
address[]
The list of addresses of the vToken markets to be enabled
[0]
uint256[]
Success indicator for whether each corresponding market was entered
market
address
The address of the market (vToken) to unlist
[0]
uint256
uint256 0=success, otherwise a failure (See enum Error for details)
vTokenAddress
address
The address of the asset to be removed
[0]
uint256
Whether or not the account successfully exited the market
vToken
contract VToken
The address of the market (token) to list
[0]
uint256
uint256 0=success, otherwise a failure. (See enum Error for details)
vToken
contract VToken
The address of the vToken market to list in the Core Pool
[0]
uint256
uint256 0=success, otherwise a failure. (See enum Error for details)
delegate
address
The address to update the rights for
approved
bool
Whether to grant (true) or revoke (false) the borrowing or redeeming rights
poolId
uint96
The ID of the pool the user wants to enter.
label
string
name for the pool (must be non-empty).
[0]
uint96
poolId The incremental unique identifier of the newly created pool.
poolIds
uint96[]
Array of pool IDs.
vTokens
address[]
Array of market (vToken) addresses.
poolId
uint96
The ID of the pool from which the market should be removed.
vToken
address
The address of the market token to remove.
vToken
address
The address of the vToken to get the collateral factor for
[0]
uint256
The collateral factor for the vToken, scaled by 1e18
vToken
address
The address of the vToken to get the liquidation threshold for
[0]
uint256
The liquidation threshold for the vToken, scaled by 1e18
vToken
address
The address of the vToken to get the liquidation Incentive for
[0]
uint256
liquidationIncentive The liquidation incentive for the vToken, scaled by 1e18
account
address
The account whose pool is used to determine the market's risk parameters.
vToken
address
The address of the vToken market.
weightingStrategy
enum WeightFunction
The weighting strategy to use: - WeightFunction.USE_COLLATERAL_FACTOR to use collateral factor - WeightFunction.USE_LIQUIDATION_THRESHOLD to use liquidation threshold
[0]
uint256
factor The effective loan-to-value factor, scaled by 1e18.
account
address
The account whose pool is used to determine the market's risk parameters
vToken
address
The address of the vToken market
[0]
uint256
The liquidation Incentive for the vToken, scaled by 1e18
poolId
uint96
The ID of the pool whose vTokens are being queried.
[0]
address[]
An array of vToken addresses associated with the pool.
vToken
address
The address of the vToken whose market configuration is to be fetched.
isListed
bool
Whether the market is listed and enabled.
collateralFactorMantissa
uint256
The maximum borrowable percentage of collateral, in mantissa.
isVenus
bool
Whether this market is eligible for VENUS rewards.
liquidationThresholdMantissa
uint256
poolId
uint96
The ID of the pool whose market configuration is being queried.
vToken
address
The address of the vToken whose market configuration is to be fetched.
isListed
bool
Whether the market is listed and enabled.
collateralFactorMantissa
uint256
The maximum borrowable percentage of collateral, in mantissa.
isVenus
bool
Whether this market is eligible for XVS rewards.
liquidationThresholdMantissa
uint256
account
address
The address of the user attempting to switch pools.
targetPoolId
uint96
The pool ID the user wants to switch into.
[0]
bool
bool True if the switch is allowed, otherwise False.
The amount of vTokenBorrowed underlying to convert into vTokenCollateral tokens
The threshold at which liquidation is triggered, in mantissa.
The threshold at which liquidation is triggered, in mantissa.
function setPriceOracle(contract ResilientOracleInterface newOracle) external returns (uint256)function _setPriceOracle(contract ResilientOracleInterface newOracle) external returns (uint256)function setCloseFactor(uint256 newCloseFactorMantissa) external returns (uint256)function _setCloseFactor(uint256 newCloseFactorMantissa) external returns (uint256)function _setAccessControl(address newAccessControlAddress) external returns (uint256)function setCollateralFactor(contract VToken vToken, uint256 newCollateralFactorMantissa, uint256 newLiquidationThresholdMantissa) external returns (uint256)function setLiquidationIncentive(address vToken, uint256 newLiquidationIncentiveMantissa) external returns (uint256)function setCollateralFactor(uint96 poolId, contract VToken vToken, uint256 newCollateralFactorMantissa, uint256 newLiquidationThresholdMantissa) external returns (uint256)function setLiquidationIncentive(uint96 poolId, address vToken, uint256 newLiquidationIncentiveMantissa) external returns (uint256)function _setLiquidatorContract(address newLiquidatorContract_) externalfunction _setPauseGuardian(address newPauseGuardian) external returns (uint256)function setMarketBorrowCaps(contract VToken[] vTokens, uint256[] newBorrowCaps) externalfunction _setMarketBorrowCaps(contract VToken[] vTokens, uint256[] newBorrowCaps) externalfunction setMarketSupplyCaps(contract VToken[] vTokens, uint256[] newSupplyCaps) externalfunction _setMarketSupplyCaps(contract VToken[] vTokens, uint256[] newSupplyCaps) externalfunction _setProtocolPaused(bool state) external returns (bool)function setActionsPaused(address[] markets_, enum Action[] actions_, bool paused_) externalfunction _setActionsPaused(address[] markets_, enum Action[] actions_, bool paused_) externalfunction _setVAIController(contract VAIControllerInterface vaiController_) external returns (uint256)function _setVAIMintRate(uint256 newVAIMintRate) external returns (uint256)function setMintedVAIOf(address owner, uint256 amount) external returns (uint256)function _setTreasuryData(address newTreasuryGuardian, address newTreasuryAddress, uint256 newTreasuryPercent) external returns (uint256)function _setVenusVAIVaultRate(uint256 venusVAIVaultRate_) externalfunction _setVAIVaultInfo(address vault_, uint256 releaseStartBlock_, uint256 minReleaseAmount_) externalfunction setPrimeToken(contract IPrime _prime) external returns (uint256)function _setPrimeToken(contract IPrime _prime) external returns (uint256)function setForcedLiquidation(address vTokenBorrowed, bool enable) externalfunction _setForcedLiquidation(address vTokenBorrowed, bool enable) externalfunction _setForcedLiquidationForUser(address borrower, address vTokenBorrowed, bool enable) externalfunction setWhiteListFlashLoanAccount(address account, bool _isWhiteListed) external function _setXVSToken(address xvs_) externalfunction _setXVSVToken(address xvsVToken_) externalfunction setPoolActive(uint96 poolId, bool active) externalfunction setIsBorrowAllowed(uint96 poolId, address vToken, bool borrowAllowed) externalfunction isComptroller() public pure returns (bool)function getAssetsIn(address account) external view returns (contract VToken[])function getAllMarkets() external view returns (contract VToken[])function liquidateCalculateSeizeTokens(address vTokenBorrowed, address vTokenCollateral, uint256 actualRepayAmount) external view returns (uint256, uint256)function liquidateCalculateSeizeTokens(address borrower, address vTokenBorrowed, address vTokenCollateral, uint256 actualRepayAmount) external view returns (uint256, uint256)function liquidateVAICalculateSeizeTokens(address vTokenCollateral, uint256 actualRepayAmount) external view returns (uint256, uint256)function checkMembership(address account, contract VToken vToken) external view returns (bool)function isMarketListed(contract VToken vToken) external view returns (bool)function enterMarkets(address[] vTokens) external returns (uint256[])function unlistMarket(address market) external returns (uint256)function exitMarket(address vTokenAddress) external returns (uint256)function supportMarket(contract VToken vToken) external returns (uint256)function _supportMarket(contract VToken vToken) external returns (uint256)function updateDelegate(address delegate, bool approved) externalfunction enterPool(uint96 poolId) externalfunction createPool(string label) external returns (uint96)function addPoolMarkets(uint96[] poolIds, address[] vTokens) externalfunction removePoolMarket(uint96 poolId, address vToken) externalfunction getCollateralFactor(address vToken) external view returns (uint256)function getLiquidationThreshold(address vToken) external view returns (uint256)function getLiquidationIncentive(address vToken) external view returns (uint256)function getEffectiveLtvFactor(address account, address vToken, enum WeightFunction weightingStrategy) external view returns (uint256)function getEffectiveLiquidationIncentive(address account, address vToken) external view returns (uint256)function getPoolVTokens(uint96 poolId) external view returns (address[])function markets(address vToken) external view returns (bool isListed, uint256 collateralFactorMantissa, bool isVenus, uint256 liquidationThresholdMantissa, uint256 liquidationIncentiveMantissa, uint96 marketPoolId, bool isBorrowAllowed)function poolMarkets(uint96 poolId, address vToken) public view returns (bool isListed, uint256 collateralFactorMantissa, bool isVenus, uint256 liquidationThresholdMantissa, uint256 liquidationIncentiveMantissa, uint96 marketPoolId, bool isBorrowAllowed)function hasValidPoolBorrows(address account, uint96 targetPoolId) public view returns (bool)Abstract base for vTokens
Transfer amount tokens from msg.sender to dst
Parameters
Return Values
Transfer amount tokens from src to dst
Parameters
Return Values
Approve spender to transfer up to amount from src
Parameters
Return Values
Get the underlying balance of the owner
Parameters
Return Values
Returns the current total borrows plus accrued interest
Return Values
Accrue interest to updated borrowIndex and then calculate account's borrow balance using the updated borrowIndex
Parameters
Return Values
Transfers collateral tokens (this market) to the liquidator.
Parameters
Return Values
Begins transfer of admin rights. The newPendingAdmin must call _acceptAdmin to finalize the transfer.
Parameters
Return Values
Accepts transfer of admin rights. msg.sender must be pendingAdmin
Return Values
accrues interest and sets a new reserve factor for the protocol using _setReserveFactorFresh
Return Values
Sets the address of the access control manager of this contract
Parameters
Return Values
Accrues interest and reduces reserves by transferring to protocol share reserve
Parameters
Return Values
Get the current allowance from owner for spender
Parameters
Return Values
Get the token balance of the owner
Parameters
Return Values
Get a snapshot of the account's balances, and the cached exchange rate
Parameters
Return Values
Returns the current per-block supply interest rate for this vToken
Return Values
Returns the current per-block borrow interest rate for this vToken
Return Values
Get cash balance of this vToken in the underlying asset
Return Values
Governance function to set new threshold of block difference after which funds will be sent to the protocol share reserve
Parameters
Sets protocol share reserve contract address
Parameters
Initialize the money market
Parameters
Accrue interest then return the up-to-date exchange rate
Return Values
Applies accrued interest to total borrows and reserves
Sets a new comptroller for the market
Return Values
Accrues interest and updates the interest rate model using _setInterestRateModelFresh
Parameters
Return Values
Calculates the exchange rate from the underlying to the VToken
Return Values
Return the borrow balance of account based on stored data
Parameters
Return Values
Transfers the underlying asset to the specified address for flash loan operations.
Can only be called by the Comptroller contract. This function performs the actual transfer of the underlying asset and tracks the flash loan amount.
Parameters
Transfers the underlying asset from the specified address for flash loan repayment.
Can only be called by the Comptroller contract. This function performs the actual transfer of the underlying asset for flash loan repayment and handles protocol fee distribution to the protocol share reserve.
Parameters
Return Values
Calculates the total fee and protocol fee for a flash loan amount. Reverts if flash loans are disabled.
Parameters
Return Values
Sets flash loan status for the market. Governance-restricted.
Parameters
Return Values
Updates the flash loan fee parameters. Governance-restricted.
Parameters
Return Values
struct MintLocalVars {
enum CarefulMath.MathError mathErr;
uint256 exchangeRateMantissa;
uint256 mintTokens;
uint256 totalSupplyNew;
uint256 accountTokensNew;
uint256 actualMintAmount;
}struct RedeemLocalVars {
enum CarefulMath.MathError mathErr;
uint256 exchangeRateMantissa;
uint256 redeemTokens;
uint256 redeemAmount;
uint256 totalSupplyNew;
uint256 accountTokensNew;
}struct BorrowLocalVars {
enum CarefulMath.MathError mathErr;
uint256 accountBorrows;
uint256 accountBorrowsNew;
uint256 totalBorrowsNew;
}struct RepayBorrowLocalVars {
enum TokenErrorReporter.Error err;
enum CarefulMath.MathError mathErr;
uint256 repayAmount;
uint256 borrowerIndex;
uint256 accountBorrows;
uint256 accountBorrowsNew;
uint256 totalBorrowsNew;
uint256 actualRepayAmount;
}symbol_
string
EIP-20 symbol of this token
decimals_
uint8
EIP-20 decimal precision of this token
dst
address
The address of the destination account
amount
uint256
The number of tokens to transfer
[0]
bool
Whether or not the transfer succeeded
src
address
The address of the source account
dst
address
The address of the destination account
amount
uint256
The number of tokens to transfer
[0]
bool
Whether or not the transfer succeeded
spender
address
The address of the account which may transfer tokens
amount
uint256
The number of tokens that are approved (type(uint256).max means infinite)
[0]
bool
Whether or not the approval succeeded
owner
address
The address of the account to query
[0]
uint256
The amount of underlying owned by owner
[0]
uint256
The total borrows with interest
account
address
The address whose balance should be calculated after updating borrowIndex
[0]
uint256
The calculated balance
liquidator
address
The account receiving seized collateral
borrower
address
The account having collateral seized
seizeTokens
uint256
The number of vTokens to seize
[0]
uint256
uint Returns 0 on success, otherwise returns a failure code (see ErrorReporter.sol for details).
newPendingAdmin
address payable
New pending admin.
[0]
uint256
uint Returns 0 on success, otherwise returns a failure code (see ErrorReporter.sol for details).
[0]
uint256
uint Returns 0 on success, otherwise returns a failure code (see ErrorReporter.sol for details).
[0]
uint256
uint Returns 0 on success, otherwise returns a failure code (see ErrorReporter.sol for details).
newAccessControlManagerAddress
address
New address for the access control
[0]
uint256
uint 0=success, otherwise will revert
reduceAmount_
uint256
Amount of reduction to reserves
[0]
uint256
uint Returns 0 on success, otherwise returns a failure code (see ErrorReporter.sol for details).
owner
address
The address of the account which owns the tokens to be spent
spender
address
The address of the account which may transfer tokens
[0]
uint256
The number of tokens allowed to be spent (type(uint256).max means infinite)
owner
address
The address of the account to query
[0]
uint256
The number of tokens owned by owner
account
address
Address of the account to snapshot
[0]
uint256
(possible error, token balance, borrow balance, exchange rate mantissa)
[1]
uint256
[2]
uint256
[3]
uint256
[0]
uint256
The supply interest rate per block, scaled by 1e18
[0]
uint256
The borrow interest rate per block, scaled by 1e18
[0]
uint256
The quantity of underlying asset owned by this contract
newReduceReservesBlockDelta_
uint256
block difference value
protcolShareReserve_
address payable
The address of protocol share reserve contract
comptroller_
contract ComptrollerInterface
The address of the Comptroller
interestRateModel_
contract InterestRateModelV8
The address of the interest rate model
initialExchangeRateMantissa_
uint256
The initial exchange rate, scaled by 1e18
name_
string
[0]
uint256
Calculated exchange rate scaled by 1e18
[0]
uint256
uint Returns 0 on success, otherwise returns a failure code (see ErrorReporter.sol for details).
newInterestRateModel_
contract InterestRateModelV8
The new interest rate model to use
[0]
uint256
uint Returns 0 on success, otherwise returns a failure code (see ErrorReporter.sol for details).
[0]
uint256
Calculated exchange rate scaled by 1e18
account
address
The address whose balance should be calculated
[0]
uint256
The calculated balance
to
address payable
The address to which the underlying asset is transferred
amount
uint256
The amount of the underlying asset to transfer
from
address payable
The address from which the underlying asset is transferred
repaymentAmount
uint256
The amount of the underlying asset to transfer
totalFee
uint256
The total fee amount for the flash loan
protocolFee
uint256
The protocol fee amount to be transferred to the protocol share reserve
[0]
uint256
The actual amount transferred in
amount
uint256
The amount of the flash loan
[0]
uint256
The total fee for the flash loan
[1]
uint256
The portion of the total fees that goes to the protocol share reserve
enabled
bool
True to enable flash loans, false to disable
[0]
uint256
Status code (e.g., success/failure)
flashLoanFeeMantissa_
uint256
New flash loan fee (scaled by 1e18)
flashLoanProtocolShare_
uint256
New protocol fee share (scaled by 1e18)
[0]
uint256
Status code (e.g., success/failure)
EIP-20 name of this token
function transfer(address dst, uint256 amount) external returns (bool)function transferFrom(address src, address dst, uint256 amount) external returns (bool)function approve(address spender, uint256 amount) external returns (bool)function balanceOfUnderlying(address owner) external returns (uint256)function totalBorrowsCurrent() external returns (uint256)function borrowBalanceCurrent(address account) external returns (uint256)function seize(address liquidator, address borrower, uint256 seizeTokens) external returns (uint256)function _setPendingAdmin(address payable newPendingAdmin) external returns (uint256)function _acceptAdmin() external returns (uint256)function _setReserveFactor(uint256 newReserveFactorMantissa_) external returns (uint256)function setAccessControlManager(address newAccessControlManagerAddress) external returns (uint256)function _reduceReserves(uint256 reduceAmount_) external virtual returns (uint256)function allowance(address owner, address spender) external view returns (uint256)function balanceOf(address owner) external view returns (uint256)function getAccountSnapshot(address account) external view returns (uint256, uint256, uint256, uint256)function supplyRatePerBlock() external view returns (uint256)function borrowRatePerBlock() external view returns (uint256)function getCash() external view returns (uint256)function setReduceReservesBlockDelta(uint256 newReduceReservesBlockDelta_) externalfunction setProtocolShareReserve(address payable protcolShareReserve_) externalfunction initialize(contract ComptrollerInterface comptroller_, contract InterestRateModelV8 interestRateModel_, uint256 initialExchangeRateMantissa_, string name_, string symbol_, uint8 decimals_) publicfunction exchangeRateCurrent() public returns (uint256)function accrueInterest() public virtual returns (uint256)function _setComptroller(contract ComptrollerInterface newComptroller) public returns (uint256)function _setInterestRateModel(contract InterestRateModelV8 newInterestRateModel_) public returns (uint256)function exchangeRateStored() public view returns (uint256)function borrowBalanceStored(address account) public view returns (uint256)function transferOutUnderlyingFlashLoan(address payable to, uint256 amount) externalfunction transferInUnderlyingFlashLoan(
address payable from,
uint256 repaymentAmount,
uint256 totalFee,
uint256 protocolFee
) external returns (uint256)function calculateFlashLoanFee(uint256 amount)
public
view
returns (uint256, uint256);function setFlashLoanEnabled(bool enabled) external returns (uint256)function setFlashLoanFeeMantissa(
uint256 flashLoanFeeMantissa_,
uint256 flashLoanProtocolShare_
)
external
returns (uint256);The Comptroller is designed to provide checks for all minting, redeeming, transferring, borrowing, lending, repaying, liquidating, and seizing done by the vToken contract. Each pool has one Comptroller checking these interactions across markets. When a user interacts with a given market by one of these main actions, a call is made to a corresponding hook in the associated Comptroller, which either allows or reverts the transaction. These hooks also update supply and borrow rewards as they are called. The comptroller holds the logic for assessing liquidity snapshots of an account via the collateral factor and liquidation threshold. This check determines the collateral needed for a borrow, as well as how much of a borrow may be liquidated. A user may borrow a portion of their collateral with the maximum amount determined by the markets collateral factor. However, if their borrowed amount exceeds an amount calculated using the market’s corresponding liquidation threshold, the borrow is eligible for liquidation.
The Comptroller also includes two functions liquidateAccount() and healAccount(), which are meant to handle accounts that do not exceed the minLiquidatableCollateral for the Comptroller:
healAccount(): This function is called to seize all of a given user’s collateral, requiring the msg.sender repay a certain percentage of the debt calculated by collateral/(borrows*liquidationIncentive). The function can only be called if the calculated percentage does not exceed 100%, because otherwise no badDebt would be created and liquidateAccount() should be used instead. The difference in the actual amount of debt and debt paid off is recorded as badDebt for each market, which can then be auctioned off for the risk reserves of the associated pool.
Add assets to be included in account liquidity calculation; enabling them to be used as collateral
Parameters
Return Values
📅 Events
MarketEntered is emitted for each market on success
⛔️ Access Requirements
Not restricted
❌ Errors
ActionPaused error is thrown if entering any of the markets is paused
MarketNotListed error is thrown if any of the markets is not listed
Grants or revokes the borrowing delegate rights to / from an account If allowed, the delegate will be able to borrow funds on behalf of the sender Upon a delegated borrow, the delegate will receive the funds, and the borrower will see the debt on their account
Parameters
📅 Events
DelegateUpdated emits on success
⛔️ Access Requirements
Not restricted
❌ Errors
ZeroAddressNotAllowed is thrown when delegate address is zero
Removes asset from sender's account liquidity calculation; disabling them as collateral
Parameters
Return Values
📅 Events
MarketExited is emitted on success
⛔️ Access Requirements
Not restricted
❌ Errors
ActionPaused error is thrown if exiting the market is paused
NonzeroBorrowBalance error is thrown if the user has an outstanding borrow in this market
MarketNotListed error is thrown when the market is not listed
InsufficientLiquidity error is thrown if exiting the market would lead to user's insolvency
Checks if the account should be allowed to mint tokens in the given market
Parameters
⛔️ Access Requirements
Not restricted
❌ Errors
ActionPaused error is thrown if supplying to this market is paused
MarketNotListed error is thrown when the market is not listed
SupplyCapExceeded error is thrown if the total supply exceeds the cap after minting
Validates mint, accrues interest and updates score in prime. Reverts on rejection. May emit logs.
Parameters
Checks if the account should be allowed to redeem tokens in the given market
Parameters
⛔️ Access Requirements
Not restricted
❌ Errors
ActionPaused error is thrown if withdrawals are paused in this market
MarketNotListed error is thrown when the market is not listed
InsufficientLiquidity error is thrown if the withdrawal would lead to user's insolvency
SnapshotError is thrown if some vToken fails to return the account's supply and borrows
Validates redeem, accrues interest and updates score in prime. Reverts on rejection. May emit logs.
Parameters
Validates repayBorrow, accrues interest and updates score in prime. Reverts on rejection. May emit logs.
Parameters
Validates liquidateBorrow, accrues interest and updates score in prime. Reverts on rejection. May emit logs.
Parameters
Validates seize, accrues interest and updates score in prime. Reverts on rejection. May emit logs.
Parameters
Validates transfer, accrues interest and updates score in prime. Reverts on rejection. May emit logs.
Parameters
disable-eslint
Validates borrow, accrues interest and updates score in prime. Reverts on rejection. May emit logs.
Parameters
Checks if the account should be allowed to repay a borrow in the given market
Parameters
⛔️ Access Requirements
Not restricted
❌ Errors
ActionPaused error is thrown if repayments are paused in this market
MarketNotListed error is thrown when the market is not listed
Checks if the liquidation should be allowed to occur
Parameters
❌ Errors
ActionPaused error is thrown if liquidations are paused in this market
MarketNotListed error is thrown if either collateral or borrowed token is not listed
TooMuchRepay error is thrown if the liquidator is trying to repay more than allowed by close factor
MinimalCollateralViolated is thrown if the users' total collateral is lower than the threshold for non-batch liquidations
Checks if the seizing of assets should be allowed to occur
Parameters
⛔️ Access Requirements
Not restricted
❌ Errors
ActionPaused error is thrown if seizing this type of collateral is paused
MarketNotListed error is thrown if either collateral or borrowed token is not listed
ComptrollerMismatch error is when seizer contract or seized asset belong to different pools
Checks if the account should be allowed to transfer tokens in the given market
Parameters
⛔️ Access Requirements
Not restricted
❌ Errors
ActionPaused error is thrown if withdrawals are paused in this market
MarketNotListed error is thrown when the market is not listed
InsufficientLiquidity error is thrown if the withdrawal would lead to user's insolvency
SnapshotError is thrown if some vToken fails to return the account's supply and borrows
Seizes all the remaining collateral, makes msg.sender repay the existing borrows, and treats the rest of the debt as bad debt (for each market). The sender has to repay a certain percentage of the debt, computed as collateral / (borrows * liquidationIncentive).
Parameters
⛔️ Access Requirements
Not restricted
❌ Errors
CollateralExceedsThreshold error is thrown when the collateral is too big for healing
SnapshotError is thrown if some vToken fails to return the account's supply and borrows
PriceError is thrown if the oracle returns an incorrect price for some asset
Liquidates all borrows of the borrower. Callable only if the collateral is less than a predefined threshold, and the account collateral can be seized to cover all borrows. If the collateral is higher than the threshold, use regular liquidations. If the collateral is below the threshold, and the account is insolvent, use healAccount.
Parameters
⛔️ Access Requirements
Not restricted
❌ Errors
CollateralExceedsThreshold error is thrown when the collateral is too big for a batch liquidation
InsufficientCollateral error is thrown when there is not enough collateral to cover the debt
SnapshotError is thrown if some vToken fails to return the account's supply and borrows
PriceError is thrown if the oracle returns an incorrect price for some asset
Sets the closeFactor to use when liquidating borrows
Parameters
📅 Events
Emits NewCloseFactor on success
⛔️ Access Requirements
Controlled by AccessControlManager
Sets the collateralFactor for a market
Parameters
📅 Events
Emits NewCollateralFactor when collateral factor is updated
and NewLiquidationThreshold when liquidation threshold is updated
⛔️ Access Requirements
Controlled by AccessControlManager
❌ Errors
MarketNotListed error is thrown when the market is not listed
InvalidCollateralFactor error is thrown when collateral factor is too high
InvalidLiquidationThreshold error is thrown when liquidation threshold is lower than collateral factor
PriceError is thrown when the oracle returns an invalid price for the asset
Sets liquidationIncentive
Parameters
📅 Events
Emits NewLiquidationIncentive on success
⛔️ Access Requirements
Controlled by AccessControlManager
Add the market to the markets mapping and set it as listed
Parameters
⛔️ Access Requirements
Only PoolRegistry
❌ Errors
MarketAlreadyListed is thrown if the market is already listed in this pool
Set the given borrow caps for the given vToken markets. Borrowing that brings total borrows to or above borrow cap will revert.
Parameters
⛔️ Access Requirements
Controlled by AccessControlManager
Set the given supply caps for the given vToken markets. Supply that brings total Supply to or above supply cap will revert.
Parameters
⛔️ Access Requirements
Controlled by AccessControlManager
Pause/unpause specified actions
Parameters
⛔️ Access Requirements
Controlled by AccessControlManager
Set the given collateral threshold for non-batch liquidations. Regular liquidations will fail if the collateral amount is less than this threshold. Liquidators should use batch operations like liquidateAccount or healAccount.
Parameters
⛔️ Access Requirements
Controlled by AccessControlManager
Add a new RewardsDistributor and initialize it with all markets. We can add several RewardsDistributor contracts with the same rewardToken, and there could be overlaping among them considering the last reward block
Parameters
📅 Events
Emits NewRewardsDistributor with distributor address
⛔️ Access Requirements
Only Governance
Sets a new price oracle for the Comptroller
Parameters
📅 Events
Emits NewPriceOracle on success
❌ Errors
ZeroAddressNotAllowed is thrown when the new oracle address is zero
Set the for loop iteration limit to avoid DOS
Parameters
Sets the prime token contract for the comptroller
Parameters
Enables forced liquidations for a market. If forced liquidation is enabled, borrows in the market may be liquidated regardless of the account liquidity
Parameters
Determine the current account liquidity with respect to liquidation threshold requirements
Parameters
Return Values
Determine the current account liquidity with respect to collateral requirements
Parameters
Return Values
Determine what the account liquidity would be if the given amounts were redeemed/borrowed
Parameters
Return Values
Return all of the markets
Return Values
Check if a market is marked as listed (active)
Parameters
Return Values
Returns the assets an account has entered
Parameters
Return Values
Returns whether the given account is entered in a given market
Parameters
Return Values
Calculate number of tokens of collateral asset to seize given an underlying amount
Parameters
Return Values
❌ Errors
PriceError if the oracle returns an invalid price
Returns reward speed given a vToken
Parameters
Return Values
Return all reward distributors for this pool
Return Values
A marker method that returns true for a valid Comptroller contract
Return Values
Update the prices of all the tokens associated with the provided account
Parameters
Checks if a certain action is paused on a market
Parameters
Return Values
liquidateAccount(): This function can only be called if the collateral seized will cover all borrows of an account, as well as the liquidation incentive. Otherwise, the pool will incur bad debt, in which case the function healAccount() should be used instead. This function skips the logic verifying that the repay amount does not exceed the close factor.SnapshotError is thrown if some vToken fails to return the account's supply and borrows
PriceError is thrown if the oracle returns an incorrect price for some asset
PriceError is thrown if the oracle returns an incorrect price for some asset
borrowerIndex
uint256
actualRepayAmount
uint256
The amount of underlying being repaid
seizeTokens
uint256
The amount of collateral token that will be seized
seizeTokens
uint256
The number of collateral tokens to seize
skipLiquidityCheck
bool
Allows the borrow to be liquidated regardless of the account liquidity
InsufficientShortfall is thrown when trying to liquidate a healthy account
SnapshotError is thrown if some vToken fails to return the account's supply and borrows
PriceError is thrown if the oracle returns an incorrect price for some asset
PriceError is thrown if the oracle returns an incorrect price for some asset
vTokens
address[]
The list of addresses of the vToken markets to be enabled
[0]
uint256[]
errors An array of NO_ERROR for compatibility with Venus core tooling
delegate
address
The address to update the rights for
allowBorrows
bool
Whether to grant (true) or revoke (false) the rights
vTokenAddress
address
The address of the asset to be removed
[0]
uint256
error Always NO_ERROR for compatibility with Venus core tooling
vToken
address
The market to verify the mint against
minter
address
The account which would get the minted tokens
mintAmount
uint256
The amount of underlying being supplied to the market in exchange for tokens
vToken
address
Asset being minted
minter
address
The address minting the tokens
actualMintAmount
uint256
The amount of the underlying asset being minted
mintTokens
uint256
vToken
address
The market to verify the redeem against
redeemer
address
The account which would redeem the tokens
redeemTokens
uint256
The number of vTokens to exchange for the underlying asset in the market
vToken
address
Asset being redeemed
redeemer
address
The address redeeming the tokens
redeemAmount
uint256
The amount of the underlying asset being redeemed
redeemTokens
uint256
vToken
address
Asset being repaid
payer
address
The address repaying the borrow
borrower
address
The address of the borrower
actualRepayAmount
uint256
vTokenBorrowed
address
Asset which was borrowed by the borrower
vTokenCollateral
address
Asset which was used as collateral and will be seized
liquidator
address
The address repaying the borrow and seizing the collateral
borrower
address
vTokenCollateral
address
Asset which was used as collateral and will be seized
vTokenBorrowed
address
Asset which was borrowed by the borrower
liquidator
address
The address repaying the borrow and seizing the collateral
borrower
address
vToken
address
Asset being transferred
src
address
The account which sources the tokens
dst
address
The account which receives the tokens
transferTokens
uint256
vToken
address
Asset whose underlying is being borrowed
borrower
address
The address borrowing the underlying
borrowAmount
uint256
The amount of the underlying asset requested to borrow
vToken
address
The market to verify the repay against
borrower
address
The account which would borrowed the asset
vTokenBorrowed
address
Asset which was borrowed by the borrower
vTokenCollateral
address
Asset which was used as collateral and will be seized
borrower
address
The address of the borrower
repayAmount
uint256
vTokenCollateral
address
Asset which was used as collateral and will be seized
seizerContract
address
Contract that tries to seize the asset (either borrowed vToken or Comptroller)
liquidator
address
The address repaying the borrow and seizing the collateral
borrower
address
vToken
address
The market to verify the transfer against
src
address
The account which sources the tokens
dst
address
The account which receives the tokens
transferTokens
uint256
user
address
account to heal
borrower
address
the borrower address
orders
struct ComptrollerStorage.LiquidationOrder[]
an array of liquidation orders
newCloseFactorMantissa
uint256
New close factor, scaled by 1e18
vToken
contract VToken
The market to set the factor on
newCollateralFactorMantissa
uint256
The new collateral factor, scaled by 1e18
newLiquidationThresholdMantissa
uint256
The new liquidation threshold, scaled by 1e18
newLiquidationIncentiveMantissa
uint256
New liquidationIncentive scaled by 1e18
vToken
contract VToken
The address of the market (token) to list
vTokens
contract VToken[]
The addresses of the markets (tokens) to change the borrow caps for
newBorrowCaps
uint256[]
The new borrow cap values in underlying to be set. A value of type(uint256).max corresponds to unlimited borrowing.
vTokens
contract VToken[]
The addresses of the markets (tokens) to change the supply caps for
newSupplyCaps
uint256[]
The new supply cap values in underlying to be set. A value of type(uint256).max corresponds to unlimited supply.
marketsList
contract VToken[]
Markets to pause/unpause the actions on
actionsList
enum ComptrollerStorage.Action[]
List of action ids to pause/unpause
paused
bool
The new paused state (true=paused, false=unpaused)
newMinLiquidatableCollateral
uint256
The new min liquidatable collateral (in USD).
_rewardsDistributor
contract RewardsDistributor
Address of the RewardDistributor contract to add
newOracle
contract ResilientOracleInterface
Address of the new price oracle to set
limit
uint256
Limit for the max loops can execute at a time
_prime
contract IPrime
Address of the Prime contract
vTokenBorrowed
address
Borrowed vToken
enable
bool
Whether to enable forced liquidations
account
address
The account get liquidity for
error
uint256
Always NO_ERROR for compatibility with Venus core tooling
liquidity
uint256
Account liquidity in excess of liquidation threshold requirements,
shortfall
uint256
Account shortfall below liquidation threshold requirements
account
address
The account get liquidity for
error
uint256
Always NO_ERROR for compatibility with Venus core tooling
liquidity
uint256
Account liquidity in excess of collateral requirements,
shortfall
uint256
Account shortfall below collateral requirements
account
address
The account to determine liquidity for
vTokenModify
address
The market to hypothetically redeem/borrow in
redeemTokens
uint256
The number of tokens to hypothetically redeem
borrowAmount
uint256
error
uint256
Always NO_ERROR for compatibility with Venus core tooling
liquidity
uint256
Hypothetical account liquidity in excess of collateral requirements,
shortfall
uint256
Hypothetical account shortfall below collateral requirements
[0]
contract VToken[]
markets The list of market addresses
vToken
contract VToken
vToken Address for the market to check
[0]
bool
listed True if listed otherwise false
account
address
The address of the account to pull assets for
[0]
contract VToken[]
A list with the assets the account has entered
account
address
The address of the account to check
vToken
contract VToken
The vToken to check
[0]
bool
True if the account is in the market specified, otherwise false.
vTokenBorrowed
address
The address of the borrowed vToken
vTokenCollateral
address
The address of the collateral vToken
actualRepayAmount
uint256
The amount of vTokenBorrowed underlying to convert into vTokenCollateral tokens
error
uint256
Always NO_ERROR for compatibility with Venus core tooling
tokensToSeize
uint256
Number of vTokenCollateral tokens to be seized in a liquidation
vToken
address
The vToken to get the reward speeds for
rewardSpeeds
struct ComptrollerStorage.RewardSpeeds[]
Array of total supply and borrow speeds and reward token for all reward distributors
[0]
contract RewardsDistributor[]
Array of RewardDistributor addresses
[0]
bool
Always true
account
address
Address of the account to get associated tokens with
market
address
vToken address
action
enum ComptrollerStorage.Action
Action to check
[0]
bool
paused True if the action is paused otherwise false
The number of tokens being minted
The number of tokens being redeemed
The amount of underlying being repaid
The address of the borrower
The address of the borrower
The number of vTokens to transfer
The amount of underlying being repaid
The address of the borrower
The number of vTokens to transfer
The amount of underlying to hypothetically borrow
function enterMarkets(address[] vTokens) external returns (uint256[])function updateDelegate(address delegate, bool allowBorrows) externalfunction exitMarket(address vTokenAddress) external returns (uint256)function preMintHook(address vToken, address minter, uint256 mintAmount) externalfunction mintVerify(address vToken, address minter, uint256 actualMintAmount, uint256 mintTokens) externalfunction preRedeemHook(address vToken, address redeemer, uint256 redeemTokens) externalfunction redeemVerify(address vToken, address redeemer, uint256 redeemAmount, uint256 redeemTokens) externalfunction repayBorrowVerify(address vToken, address payer, address borrower, uint256 actualRepayAmount, uint256 borrowerIndex) externalfunction liquidateBorrowVerify(address vTokenBorrowed, address vTokenCollateral, address liquidator, address borrower, uint256 actualRepayAmount, uint256 seizeTokens) externalfunction seizeVerify(address vTokenCollateral, address vTokenBorrowed, address liquidator, address borrower, uint256 seizeTokens) externalfunction transferVerify(address vToken, address src, address dst, uint256 transferTokens) externalfunction preBorrowHook(address vToken, address borrower, uint256 borrowAmount) externalfunction borrowVerify(address vToken, address borrower, uint256 borrowAmount) externalfunction preRepayHook(address vToken, address borrower) externalfunction preLiquidateHook(address vTokenBorrowed, address vTokenCollateral, address borrower, uint256 repayAmount, bool skipLiquidityCheck) externalfunction preSeizeHook(address vTokenCollateral, address seizerContract, address liquidator, address borrower) externalfunction preTransferHook(address vToken, address src, address dst, uint256 transferTokens) externalfunction healAccount(address user) externalfunction liquidateAccount(address borrower, struct ComptrollerStorage.LiquidationOrder[] orders) externalfunction setCloseFactor(uint256 newCloseFactorMantissa) externalfunction setCollateralFactor(contract VToken vToken, uint256 newCollateralFactorMantissa, uint256 newLiquidationThresholdMantissa) externalfunction setLiquidationIncentive(uint256 newLiquidationIncentiveMantissa) externalfunction supportMarket(contract VToken vToken) externalfunction setMarketBorrowCaps(contract VToken[] vTokens, uint256[] newBorrowCaps) externalfunction setMarketSupplyCaps(contract VToken[] vTokens, uint256[] newSupplyCaps) externalfunction setActionsPaused(contract VToken[] marketsList, enum ComptrollerStorage.Action[] actionsList, bool paused) externalfunction setMinLiquidatableCollateral(uint256 newMinLiquidatableCollateral) externalfunction addRewardsDistributor(contract RewardsDistributor _rewardsDistributor) externalfunction setPriceOracle(contract ResilientOracleInterface newOracle) externalfunction setMaxLoopsLimit(uint256 limit) externalfunction setPrimeToken(contract IPrime _prime) externalfunction setForcedLiquidation(address vTokenBorrowed, bool enable) externalfunction getAccountLiquidity(address account) external view returns (uint256 error, uint256 liquidity, uint256 shortfall)function getBorrowingPower(address account) external view returns (uint256 error, uint256 liquidity, uint256 shortfall)function getHypotheticalAccountLiquidity(address account, address vTokenModify, uint256 redeemTokens, uint256 borrowAmount) external view returns (uint256 error, uint256 liquidity, uint256 shortfall)function getAllMarkets() external view returns (contract VToken[])function isMarketListed(contract VToken vToken) external view returns (bool)function getAssetsIn(address account) external view returns (contract VToken[])function checkMembership(address account, contract VToken vToken) external view returns (bool)function liquidateCalculateSeizeTokens(address vTokenBorrowed, address vTokenCollateral, uint256 actualRepayAmount) external view returns (uint256 error, uint256 tokensToSeize)function getRewardsByMarket(address vToken) external view returns (struct ComptrollerStorage.RewardSpeeds[] rewardSpeeds)function getRewardDistributors() external view returns (contract RewardsDistributor[])function isComptroller() external pure returns (bool)function updatePrices(address account) publicfunction actionPaused(address market, enum ComptrollerStorage.Action action) public view returns (bool)In its previous version, Venus was fully reliant on the Chainlink price oracle for fetching prices. This dependence, while generally reliable, created a single point of failure. An erroneous or stale price could, without a secondary mechanism for validation, pose threats such as unwarranted liquidations or inflated borrowing.
In light of these risks, Venus V4 introduces the Resilient Price Oracle, a more robust system capable of pulling data from multiple sources for cross-validation. The Resilient Oracle is equipped with an algorithm to verify prices between two or more sources, providing a safeguard in cases where the primary source proves unreliable or fails.
Furthermore, the improved oracle infrastructure supports the integration of new price oracles in real-time and permits the enabling and disabling of price oracles per token.
The Resilient Price Feeds replace the single source price provider used in the Comptroller contract with a more robust and reliable solution. This new component not only fetches asset prices from various on-chain sources but also includes a fallback mechanism to protect the protocol from oracle failures. Presently, this feature incorporates Chainlink, RedStone, Pyth Network and Binance oracles, with the possibility of adding more in the future.
The Resilient Price Feeds system can be configured by the Venus governance via Venus Improvement Proposals (VIPs). These configurations include pause and resume functionalities for the oracle, price feed configurations, and fixed price settings, among others.
In implementing the Resilient Price Oracle, several safety measures have been adopted to ensure the security and continuity of the Venus Protocol:
Price Continuity: Asset prices pre and post upgrade were validated in a simulated environment to ensure consistency.
Testnet Deployment: The oracles have been deployed and tested in the Venus Protocol testnet environment.
Auditing: The code has been audited by OpenZeppelin, Peckshield, Certik, and Hacken.
For correlated tokens, like Liquid Staked Tokens (LST), best practice suggests oracles quote first smart contracts to get the exchange rate between the correlated assets, and then multiply that by the USD market price of the second token to complete the calculation.
In Venus we use dedicated oracles for each LST asset in order to calculate the price as follows:
convert the LST to the underlying tokens (using the exchange rate provided by the LST contracts)
convert the underlying token calculated in the previous step to USD, using a “traditional” oracle based on market price
The current list of correlated token oracles in Venus is:
AnkrBNBOracle. It returns the USD price of the token, converting on-chain from ankrBNB to BNB using the exchange rate from the ankrBNB contract.
BNBxOracle. It returns the USD price of the token, converting on-chain from BNBx to BNB using the exchange rate from the contract.
eBTCAccountantOracle (instance of EtherfiAccountantOracle
Assumption on Liquid Staked Tokens
WeETHOracle and WstETHOracle assume a 1:1 price ratio between the LST and the underlying asset (e.g. 1 ETH = 1 stETH). The primary risks associated with this approach involve smart contract vulnerabilities and counterparty risks that could impact the redemption processes of the LSTs. In cases of substantial counterparty risk, particularly if the underlying tokens are not redeemable against the LSTs, the direct smart contract pricing might become unreliable. Here's our plan to mitigate such situations:
For more detailed information, refer to the following resources:
PendleOracle. It returns the USD price of the PT Pendle token, converting on-chain from the PT token to the underlying token using a Pendle market contract.
SFraxOracle. It returns the USD price of the sFRAX token, converting on-chain from sFRAX to FRAX using the exchange rate from the sFRAX contract.
SlisBNBOracle. It returns the USD price of the slisBNB token, converting on-chain from slisBNB to BNB using the exchange rate from the stake manager contract.
AsBNBOracle. It returns the USD price of the asBNB token, converting on-chain from asBNB to slisBNB using the exchange rate from the asBNB minter contract.
StkBNBOracle. It returns the USD price of the stkBNB token, converting on-chain from stkBNB to BNB using the exchange rate from the stake pool contract.
WBETHOracle. It returns the USD price of the WBETH token, converting on-chain from WBETH to BNB using the exchange rate from the WBETH contract.
WeETHOracle. It returns the USD price of the weETH token, converting on-chain from weETH to eETH using the exchange rate from the liquidity pool contract, and assumming 1 eETH = 1 ETH.
WeETHsOracle (instance of WeETHAccountantOracle). It returns the USD price of the weETHs token, converting on-chain from weETHs to WETH using the exchange rate from the Accountant contract.
We will deploy two on-chain oracles for each LST token:
The first oracle will return the price based on the assumption of a 1:1 ratio between the LST token and the underlying asset.
The second oracle will return the price based on a secondary market feed (using Chainlink, for instance).
By default, the ResilientOracle will be configured to use only the oracle assuming a 1:1 ratio between the LST asset and the underlying, serving as the primary oracle.
The second oracle, which derives price from the market price feed without assuming a 1:1 ratio, will not be initially configured in our ResilientOracle.
We have implemented an off-chain monitoring system to track the prices returned by both oracles. In the event of a significant deviation over an extended period, the situation will be reviewed. It will be determined whether to switch the primary oracle from the one assuming a 1:1 ratio to the one that does not, or whether to temporarily include the latter as a pivot oracle in the ResilientOracle configuration.
-
Upper bound: 1.05. Lower bound: 0.95
Core
asBNB
-
Upper bound: 1.05. Lower bound: 0.95
Core
BCH
-
Upper bound: 1.05. Lower bound: 0.95
Core
BETH (Paused)
-
-
Core
BNB
Upper bound: 1.01. Lower bound: 0.99
Core
BTCB
Upper bound: 1.01. Lower bound: 0.99
Core
BUSD (Paused)
-
-
Core
CAKE
-
Upper bound: 1.05. Lower bound: 0.95
Core
DAI
-
Upper bound: 1.05. Lower bound: 0.95
Core
DOGE
-
Upper bound: 1.05. Lower bound: 0.95
Core
DOT
-
Upper bound: 1.05. Lower bound: 0.95
Core
ETH
Upper bound: 1.01. Lower bound: 0.99
Core
FDUSD
-
Upper bound: 1.05. Lower bound: 0.95
Core
FIL
-
Upper bound: 1.05. Lower bound: 0.95
Core
LINK
-
Upper bound: 1.05. Lower bound: 0.95
Core
lisUSD
-
-
Core
LTC
-
Upper bound: 1.05. Lower bound: 0.95
Core
MATIC (Paused)
-
-
Price feed from
Core
PT-sUSDE-26JUN2025 (Paused)
-
-
Core
SOL
-
Upper bound: 1.05. Lower bound: 0.95
Core
SolvBTC
-
Upper bound: 1.05. Lower bound: 0.95
Core
sUSDe
Upper bound: 1.01. Lower bound: 0.99
Core
SXP(Paused)
-
-
Core
THE
-
Upper bound: 1.05. Lower bound: 0.95
Core
TRX
-
Upper bound: 1.01. Lower bound: 0.99
Core
TRXOLD(Paused)
-
Upper bound: 1.01. Lower bound: 0.99
Core
TUSD
-
Upper bound: 1.05. Lower bound: 0.95
Core
TUSDOLD (Paused)
-
-
Core
TWT
-
-
Core
UNI
-
Upper bound: 1.05. Lower bound: 0.95
Core
USDC
Upper bound: 1.01. Lower bound: 0.99
Core
USDe
Upper bound: 1.06. Lower bound: 0.94
Core
USDT
Upper bound: 1.01. Lower bound: 0.99
Core
USD1
Core
VAI
-
Upper bound: 1.05. Lower bound: 0.95
Core
WBETH
-
Upper bound: 1.05. Lower bound: 0.95
Core
XRP
-
Upper bound: 1.05. Lower bound: 0.95
Core
xSolvBTC
-
-
Core
XVS
-
Upper bound: 1.05. Lower bound: 0.95
Stablecoins
lisUSD
-
-
Stablecoins
USDD
-
-
Stablecoins
USDT
Upper bound: 1.01. Lower bound: 0.99
Stablecoins
EURA
-
-
DeFi
BSW
-
-
DeFi
ALPACA
-
-
DeFi
USDT
Upper bound: 1.01. Lower bound: 0.99
DeFi
USDD
-
-
DeFi
ANKR
-
-
DeFi
ankrBNB
-
-
DeFi
TWT
-
-
DeFi
PLANET
-
-
GameFi
RACA
-
-
GameFi
FLOKI
-
-
GameFi
USDD
-
-
GameFi
USDT
Upper bound: 1.01. Lower bound: 0.99
Liquid Staked BNB
ankrBNB
-
Liquid Staked BNB
asBNB
-
Upper bound: 1.05. Lower bound: 0.95
Liquid Staked BNB
BNBx
-
-
Liquid Staked BNB
PT-clisBNB-24APR2025
-
Liquid Staked BNB
stkBNB
-
Liquid Staked BNB
slisBNB
-
-
Liquid Staked BNB
WBNB
-
-
Meme
BabyDoge
-
-
Meme
USDT
Upper bound: 1.01. Lower bound: 0.99
Tron
BTT
-
-
Tron
TRX
-
-
Tron
WIN
-
-
Tron
USDD
-
-
Tron
USDT
Upper bound: 1.01. Lower bound: 0.99
Liquid Staked ETH
ETH
Upper bound: 1.01. Lower bound: 0.99
Liquid Staked ETH
weETH
Upper bound: 1.01. Lower bound: 0.99
Liquid Staked ETH
wstETH
Upper bound: 1.01. Lower bound: 0.99
BTC
BTCB
Upper bound: 1.01. Lower bound: 0.99
BTC
PT-SolvBTC.BBN-27MAR2025
-
-
-
Core
TUSD
-
-
Core
USDC
-
-
Core
USDT
-
-
Core
WBTC
-
-
Core
WETH
-
-
Core
FRAX
-
-
Core
LBTC
-
-
Core
EIGEN
-
-
Core
sFRAX
-
-
Core
eBTC
-
-
Core
USDS
-
-
Core
sUSDS
-
-
Core
BAL
-
-
Core
yvUSDC-1
-
-
Core
yvUSDS-1
-
-
Core
yvUSDT-1
-
-
Core
yvWETH-1
-
-
Core
sUSDe
-
-
Core
USDe
Upper bound: 1.01. Lower bound: 0.99
Core
tBTC
-
-
Curve
crvUSD
-
-
Curve
CRV
-
-
Ethena
PT-sUSDE-27MAR2025
-
-
Ethena
PT-USDe-27MAR2025
-
-
Ethena
sUSDe
-
-
Ethena
USDC
-
-
Ethena
USDe
Upper bound: 1.01. Lower bound: 0.99
Liquid Staked ETH
ezETH
Upper bound: 1.01. Lower bound: 0.99
Liquid Staked ETH
PTweETH-26DEC2024
-
-
Liquid Staked ETH
pufETH
-
-
Liquid Staked ETH
rsETH
Upper bound: 1.01. Lower bound: 0.99
Liquid Staked ETH
sfrxETH
-
-
Liquid Staked ETH
WETH
-
-
Liquid Staked ETH
wstETH
-
-
Assume 1:1 for ETH:stETH
Liquid Staked ETH
weETH
-
-
Assume 1:1 for ETH:eETH
Liquid Staked ETH
weETHs
-
-
-
Core
FDUSD
-
-
Core
USDT
-
-
Core
WBNB
-
-
-
Core
USDC
-
-
Core
USDT
-
-
Core
gmWETH-USDC
-
-
Core
gmBTC-USDC
-
-
Core
ARB
-
-
Liquid Staked ETH
weETH
-
-
Liquid Staked ETH
wstETH
-
-
Liquid Staked ETH
WETH
-
-
-
Core
USDC
-
-
Core
USDC_E
-
-
Core
USDT
-
-
Core
ZK
Upper bound: 1.01. Lower bound: 0.99
Core
wstETH
-
-
Core
wUSDM
-
-
Core
zkETH
-
-
Assume 1:1 for WETH:rzkETH
-
Core
USDC
-
-
Core
USDT
-
-
Core
OP
-
-
-
Core
USDC
-
-
Core
wsuperOETHb
-
-
Core
wstETH
-
-
-
Core
USDC
-
-
Core
USD₮0
-
-
Core
UNI
-
-
Core
weETH
-
-
Core
wstETH
-
-
Core
AAVE
-
Upper bound: 1.05. Lower bound: 0.95
Core
ADA
Core
crvUSD
-
-
Core
DAI
Core
BTCB
-
-
Core
ETH
Core
WBTC
-
-
Core
WETH
Core
WBTC
-
-
Core
WETH
Core
WBTC
-
-
Core
WETH
Core
cbBTC
-
-
Core
WETH
Core
WBTC
-
-
Core
WETH

-
-
-
-
-
-
-