# Overview

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:

1. Risk management
2. Decentralization
3. User experience

In doing so, Venus continues to push the boundaries of what's possible within the realm of decentralized finance.

<figure><img src="/files/KC84JuvPscRrz5Np49Y4" alt=""><figcaption></figcaption></figure>


# FAQ

### **What is Venus Protocol?**

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.

### How do I interact with Venus Protocol?

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.

### Where are my supplied funds stored?

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.

### **What is the cost of interacting with Venus Protocol?**

Transactions on the Venus V4 protocol require BNB Chain fees, which depend on network congestion and the complexity of the transaction.

### **Is there any risk?**

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.

### **What are the key areas Venus Protocol V4 aims to improve?**

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, isolated lending, and the Venus Prime Soulbound Token, all aimed at providing a smooth user experience.

### **What is the Resilient Price Oracle?**

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.

### **What are Isolated Pools?**

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.

### **What is the Risk Fund?**

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.

### **What changes were made to the governance model in Venus V4?**

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.


# Fixed Term Vaults

Venus Protocol is introducing a new way to earn and borrow: **Fixed Term Vaults**.

Instead of the variable rates and shared liquidity pools of Venus core markets, Fixed Term Vaults offer something simpler and more predictable. An institution wants to borrow stablecoins for a set period at a set rate. Suppliers fund that loan, earn a target APR, and get their principal back at maturity. The rate and lock duration are set at vault creation — no mid-term rate changes.

Each vault is **entirely self-contained**. It involves one stablecoin, one institution, and one contract. It shares no liquidity, no risk parameters, and no liquidation flow with Venus core markets or any other vault. Each vault stands or falls on its own.

Every vault implements the **ERC-4626 tokenised vault standard**, so suppliers interact through the familiar `deposit`, `withdraw`, `redeem`, and `balanceOf` interface — no custom integration required. Share tokens are standard ERC-20s, freely transferable at any point in the vault's life.

<figure><img src="/files/5mGyixbV6sUOJjCfHlsd" alt="Fixed Term Vault fund flow diagram"><figcaption><p>Suppliers supply stablecoins into the vault, the institution receives the loan and repays with interest, and suppliers redeem principal plus target yield at maturity</p></figcaption></figure>

## How a Vault Progresses

<figure><img src="/files/YD5fEcldBGF1ZyNdwmjK" alt="Fixed Term Vault state machine diagram"><figcaption><p>Fixed Term Vault state transitions</p></figcaption></figure>

Every vault follows the same journey from creation to close. States move in one direction only — there's no going back.

1. **Waiting for margin** — the vault exists on-chain, but the institution must post the full required collateral margin in a single transaction before anything else can happen.
2. **Margin deposited** — the margin is locked in escrow. Governance reviews the vault and calls `openVault()` to begin the fundraising window.
3. **Fundraising** — suppliers can now supply. The vault accepts stablecoins up to its maximum borrow cap. During this same window, the institution tops up their collateral to the required level. Both sides must complete their part before the window closes.
4. **Lock** — fundraising succeeded. The fixed-term loan begins. Total interest is computed and fixed immediately as a single lump sum — the full lifetime obligation is known from this moment.
5. **Pending settlement** — the lock period has ended. The institution now has until the settlement deadline to repay principal plus interest in full.
6. **Settlement deadline exceeded** — the deadline passed with debt still outstanding. The institution can still repay voluntarily; if they don't, whitelisted settlers can trigger overdue liquidation.
7. **Terminal states** — the vault resolves into one of three outcomes, after which governance calls `closeVault()`:
   * **Matured** — the institution repaid in full. Suppliers redeem their shares for principal plus yield.
   * **Failed** — two distinct cases: (a) *Raise shortfall* — not enough suppliers funded the vault; suppliers recover their principal and the institution recovers all collateral including the margin. (b) *Collateral underdelivery* — the raise met its minimum but the institution didn't post full collateral by close; the margin is confiscated and distributed pro-rata to suppliers in the collateral asset.
   * **Liquidated** — bad-debt rescue completed. The collateral value fell below outstanding debt and a permissionless repayer covered the principal; suppliers redeem against the settlement waterfall over the remaining assets.

## Participants

### Suppliers

Fixed Term Vaults are designed to give lenders certainty:

* **You know your target yield upfront.** The target APR and lock duration are set before fundraising opens — there's nothing to guess or monitor.
* **Collateral is posted before you can supply.** The institution's margin is on-chain and locked before the fundraising window opens. Combined with full vault isolation, a default in one vault cannot affect any other vault or Venus core markets.
* **Your position stays liquid.** Vault shares are transferable ERC-20s. You can move or sell them to another party at any time during the vault's life.

### Institutions

Fixed Term Vaults give borrowers control over their cost of capital:

* **Predictable cost.** The target APR is fixed at vault creation — no variable-rate exposure over the loan term.
* **Your collateral stays safe.** It is locked in the vault contract and never lent out or rehypothecated — no third party can touch it. If it appreciates during the loan, that upside is still entirely yours.
* **Plan your repayment from day one.** The total amount owed is calculable at lock entry, so there are no surprises when the settlement window opens.

## Liquidations

Fixed Term Vaults run their own liquidation system, independent of Venus core. Two paths exist:

* **Health-based liquidation** — available during the Lock and settlement phases if the vault's outstanding debt exceeds the liquidation-threshold value of its collateral. Whitelisted liquidators repay a portion of the debt (capped by the global close factor) and receive collateral at the liquidation incentive rate. A share of the bonus goes to the protocol.
* **Overdue liquidation** — available once the institution has missed the settlement deadline, regardless of collateral health. The same close-factor cap applies, but collateral is seized at the late-penalty rate.

Both paths route through the `LiquidationAdapter`, which maintains separate ACM-gated whitelists for health-based liquidators and overdue settlers. Direct vault calls are blocked.

## Go Deeper

* [Supplier Guide](/guides/fixed-rate-vaults/supplier-guide) — step-by-step walkthrough for lenders.
* [Institution Guide](/guides/fixed-rate-vaults/institution-guide) — step-by-step walkthrough for borrowers.
* [Fixed Term Vaults Technical Reference](/technical-reference/reference-technical-articles/fixed-rate-vaults) — contract architecture, math, and liquidation paths in full detail.
* [Solidity API Reference](/technical-reference/reference-fixed-rate-vaults) — full function-level reference for all contracts.


# Trade

{% hint style="info" %}
Available on BNB Chain Core Pool.
{% endhint %}

## Overview

**Venus Trade** is a relative performance trading product built on top of Venus Protocol's existing lending and borrowing infrastructure. It allows users to express a view that one asset will outperform another — packaged into a single, easy-to-manage position.

Instead of manually managing separate lending and borrowing positions across multiple markets, Trade combines everything into **one unified action** with automated execution, proportional closing, and built-in yield generation.

This is not directional trading. Trade positions profit (or lose) based on the **relative price movement between two assets**, regardless of whether the overall market is going up or down.

## What's New

Trade introduces a set of new periphery contracts and capabilities alongside Venus's existing lending infrastructure:

| Component                          | Description                                                                                                                                                                                                                                  |
| ---------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **RelativePositionManager**        | The main orchestration contract that manages the full lifecycle of Trade positions — from activation and opening to proportional closing and deactivation                                                                                    |
| **PositionAccount**                | A dedicated smart contract account deployed per user per trading pair. All collateral, borrow positions, and yield accrual live here, fully isolated from other positions                                                                    |
| **Paired Positions**               | Long and short legs treated as a single unit with combined PnL, health, and lifecycle management                                                                                                                                             |
| **Default Settlement Asset (DSA)** | A designated stablecoin (USDT or USDC) that users must supply as the initial collateral backing the position. All borrows of the short asset are secured against this DSA collateral, and all realized profits and losses are settled in DSA |
| **Proportional Closing**           | Flexible partial or full position closing using on-chain flash loans and token swaps, with automatic dust handling                                                                                                                           |
| **Capital Utilization Tracking**   | Real-time calculation of how much deposited collateral is locked by open positions, enabling accurate withdrawable balance reporting                                                                                                         |

## Architecture Overview

Trade is built as a peripheral orchestration layer. No changes were made to the Venus Core Pool, Comptroller, or vToken contracts.

<figure><img src="/files/49VdJpEi3LbQGCt8oobA" alt="Trade Architecture Overview"><figcaption></figcaption></figure>

Each user gets a **dedicated PositionAccount** per trading pair, deployed as a minimal proxy clone. This account holds all funds, enters markets on the Comptroller, and delegates all position operations to the RelativePositionManager.

All funds inside a PositionAccount are **owned exclusively by that account** — no external party can move them. The only contract permitted to execute operations on a PositionAccount is the RelativePositionManager, and the RPM enforces that every call must originate from the account's owner (`msg.sender`). This means neither the RPM nor any third party can act on a user's position without the user's direct on-chain request.

PositionAccounts are **deterministically deployed** using the owner's `msg.sender` address and the trading pair as the salt. The same wallet will always produce the same PositionAccount address for a given pair — no registry lookup required.

### Position Isolation

Every `(user, trading pair)` combination gets its own isolated PositionAccount. Collateral, debt, and Health Factor are entirely separate — a loss or liquidation on one position cannot affect another.

<figure><img src="/files/aJyJzsPkEu6En0dAXqVZ" alt="Trade Position Isolation"><figcaption></figcaption></figure>

## Key Concepts

### Long Leg and Short Leg

A Trade position always consists of two legs:

* **Long Leg** — the asset you believe will outperform. The system supplies this asset into Venus to earn lending yield.
* **Short Leg** — the asset you believe will underperform. The system borrows this asset from Venus.

You never manage these legs separately. Trade treats them as a single position.

### Default Settlement Asset (DSA)

When activating a position, you choose a **Default Settlement Asset** — either USDT or USDC. This stablecoin is supplied as the initial collateral into the PositionAccount and is the asset against which all borrows of the short asset are secured. The DSA's collateral factor determines the maximum borrow capacity and therefore the maximum available leverage. All realized profits and losses are also settled in DSA — think of it as the "home currency" for the entire position lifecycle.

### Leverage

Trade supports leveraged positions, amplifying your exposure to relative price movements. The maximum available leverage is determined by the collateral factors of the assets involved. Leverage is fixed at activation and cannot be changed while a position is open.

### Capital Utilization

Capital utilization tells you how much of your deposited collateral is currently locked by your open position. The remaining portion — **Available Capital** — can be used to open additional positions or withdrawn.

## How It Works

### Step 1 — Activate and Open

Deposit your DSA collateral, select a trading pair, set your leverage, and submit in one transaction. Behind the scenes, the system:

1. Deploys a dedicated PositionAccount for this pair (first time only)
2. Enters the DSA market and supplies your collateral
3. Flash loans the short asset via LeverageStrategiesManager
4. Swaps the short asset to the long asset
5. Supplies the long asset to Venus, establishing the leveraged position

### Step 2 — Monitor and Manage

Once open, your position generates yield automatically:

* **Supply APY** on the long asset
* **DSA APY** on your collateral
* minus **Borrow APY** on the short asset

You can monitor Health Factor, PnL, entry price, and liquidation price at any time. Available management actions include increasing the position, supplying additional collateral, proportionally reducing the position, withdrawing unused collateral, or fully closing and deactivating.

### Step 3 — Reduce and Exit

Reducing is proportional — you specify what fraction of the position to close (1% to 100%) in a single transaction. Profits are automatically converted into DSA collateral. Losses are covered by your existing DSA collateral.

After a full reduce (100% reduce), the position account remains active for re-entry. Use **Deactivate** (Exit Market) to fully withdraw and shut down the position account.

We also provide a one-click Exit function that completes both "reduce 100%" and "Exit Market" in a single transaction.

## Impact on Existing Users

Trade is an entirely new feature built as a peripheral contract layer. **No changes were made** to the Venus Core Pool, vToken markets, interest rate models, Comptroller, oracles, or any existing protocol infrastructure. Existing users are not affected.

## Security

The RelativePositionManager and PositionAccount contracts were independently audited before deployment. Reports are available in the [Security & Audits](/links/security-and-audits) section.

For a full technical breakdown of the implementation, see the [Trade Technical Article](/technical-reference/reference-technical-articles/trade).


# Leveraged Positions

The Leveraged Positions feature allows users to significantly amplify their exposure in the protocol using a single-click workflow powered by flash loans. Instead of manually looping borrow → swap → supply multiple times, users can instantly achieve their desired leverage level in one atomic transaction, while maintaining full control and precision.

The feature consists of two complementary tools:

## **1. Boost**

The Boost tab enables users to open a leveraged position by fully utilizing their available (unused) borrowing power.

**How it works**

* Users must first supply assets to the protocol and enable them as collateral.
* The interface displays the maximum “available to boost” amount, which is derived from the user’s remaining borrowing power.
* When a Boost is executed, the protocol uses a flash loan to temporarily borrow a larger amount, swaps it into the chosen collateral asset, and supplies it — all in a single transaction.
* This results in a leveraged position consisting of a larger supplied (collateral) amount and a corresponding borrowed amount.
* Upon execution, the user's health factor will be greater than 1, which avoids immediate liquidation. Thereafter, the user must continue monitoring their health factor, as the protocol is not responsible for any subsequent liquidations that may occur.

**Key benefit**

With only a modest amount of unused borrowing power, users can open positions that are multiple times larger than what would be possible through ordinary borrowing — achieving high leverage efficiently and effortlessly.

## **2. Repay with Collateral**

Repaying debt or reducing a leveraged position is equally straightforward.

Instead of needing to hold the borrowed asset in their wallet to repay debt, users can directly repay any outstanding borrow using their supplied collateral in one click.

This is particularly convenient for deleveraging or fully closing leveraged positions, as it eliminates the need for additional swaps or external funds.

Together, Boost and Repay with Collateral provide a seamless, user-friendly way to enter and exit highly leveraged positions while keeping the process safe, fast, and capital-efficient.


# E-Mode

{% hint style="info" %}
Only available on BNB Chain Core Pool.
{% endhint %}

## Overview

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.

## What’s Changed

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.

## Architecture Overview

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.
* **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.

This architecture ensures **flexibility, backward compatibility, and gas efficiency**, while giving users **higher borrowing efficiency and better risk isolation**.

## Impact on Users

* **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.

## Impact on Liquidators

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.

## How It Works

1. **Default in the Core Pool**\
   All users start in the Core Pool and can continue their positions normally.
2. **Select an E-Mode Pool**\
   Explore available pools (e.g., Stablecoin) via the Venus App or Venus Lens.
3. **Check Your Borrows**\
   Borrowed assets must be approved in the selected pool. Repay any disallowed assets first.
4. **Check Core Pool Fallback** Each E-Mode pool has a flag `allowCorePoolFallback` that determines whether assets not included in the E-Mode pool will use the Core Pool’s risk factors (i.e. CF, LT, LI). If fallback is not allowed, users must exit these markets (i.e., remove such assets as collateral) to ensure they aren’t unintentionally liquidated.
5. **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.
6. **Enjoy Higher Efficiency**\
   Borrow and manage positions with optimized collateral and liquidation rules.

For a **detailed technical explanation**, including implementation and user examples, check out the [full E-Mode technical article](/technical-reference/reference-technical-articles/emode).


# Isolated E-Mode

## **Overview**

Isolation Mode enables the safe addition of new or highly volatile assets to the protocol, preventing any potential risks from spreading system-wide. Assets listed in this mode can serve as collateral exclusively for borrowing a predefined set of assets—usually stablecoins—subject to a fixed debt ceiling. This approach effectively isolates risk while broadening the range of supported assets.

## **Why is it important**

When a user chooses to enable an Isolated asset as a collateral

* Only specifically permitted assets can be borrowed.
* Borrowing is capped through a conservative supply cap.
* No additional assets can be used as a collateral.

This mechanism safeguards the protocol by restricting the total debt against higher-risk assets, thereby minimizing potential systemic impact.

<div align="center"><img src="https://github.com/user-attachments/assets/c1fccc4b-8754-47cb-bf13-5798452470e3" alt="image" height="254" width="592"></div>


# Reward Distributor

### Overview

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.

### Reward Distributor Architecture

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.

### User Interactions

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.


# Peg Stability Module

## Overview

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).

## Features

**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.

## Convert Functions

### Function `swapStableForVAI`

This 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.

### Function `swapVAIForStable`

This 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).

## Preview Functions

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.

## Integration of the Oracle Price

<figure><img src="/files/7hCfzPcALd886h9KBOth" alt="USD price considered by the Peg Stability Module at Venus"><figcaption></figcaption></figure>

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.

{% hint style="info" %}
**For example if 1 USDT = $0.90**

* Input: The user wishes to receive 1 USDT.

* Calculation: The conversion rate to consider is max(1, 0.9) => 1 USDT = $1 = 1 VAI.

* 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).
  {% endhint %}

* If the oracle price of the paired stablecoin is above $1, the conversion rate is 1 stablecoin = oracle price.

{% hint style="info" %}
**For example if 1 USDT = $1.1**

* Input: The user desires to receive 10 USDT.
* Calculation: The conversion rate to consider is max(1, 1.1) => 1 USDT = $1.1 = 1.1 VAI.
* 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).
  {% endhint %}

**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.

{% hint style="info" %}
**For example if 1 USDT = $0.90**

* Input: The user wishes to send 10 USDT to the PSM.

* Calculation: The conversion rate to consider is min(1, 0.9) => 10 USDT = $9 = 9 VAI.

* 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).
  {% endhint %}

* If the oracle price of the paired stablecoin is above $1, the conversion rate is 1 stablecoin = $1.

{% hint style="info" %}
**For example if 1 USDT = $1.1**

* 1 USDT = $1.1 (conversion rate according to our oracles)
* Input: The user wishes to send 10 USDT to the PSM.
* 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).
  {% endhint %}

{% hint style="warning" %}
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 [smart contract code](https://github.com/VenusProtocol/venus-protocol/blob/develop/contracts/PegStability/PegStability.sol).
{% endhint %}


# Automatic Income Allocation

### Overview

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](https://snapshot.org/#/venus-xvs.eth/proposal/0xc9d270ccecb7b91c75b95b8d9af24fc7c20cd38c0c0c44888ed4e7724f4e7ce9).

### Key Aspects of Automatic Income Allocation

* **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.
    * 40% to Treasury
    * 20% to XVS Vault rewards
    * 20% to Venus Prime
    * 20% to Risk Fund
  * **Schema (ADDITIONAL\_REVENUE)**: Valid for liquidation and other product developments.
    * 60% to Treasury
    * 20% to XVS Vault rewards
    * 20% to Risk Fund
* **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.

### Benefits

* **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.

### Architecture

<figure><img src="/files/Mb0MVSgcAK0Bru6qn0uQ" alt=""><figcaption></figcaption></figure>

*The dashed lines represent transactions initiated by external agents (VIP’s, scripts, arbitrage bots, etc.), and the solid lines represent transfers of funds.*


# TokenBuyback Contract

### Overview

Token Converter Phase 2 replaces the original community-driven Token Converter system with a single, lightweight contract class — `TokenBuyback` — deployed as one instance per (destination, base asset) pair. Conversions are now executed by an ACM-authorized finance-team cron job using DEX aggregators at market rate, eliminating the dependency on external community participation entirely.

Protocol revenues, sourced from reserve interests and liquidations, are processed through the [Automatic Income Allocation](/whats-new/automatic-income-allocation) module. Once allocated, these underlying tokens are sent to the appropriate `TokenBuyback` instances, which swap them on a defined schedule and forward the output to the configured destination.

### Problem with the Original System

The original Token Converter relied on external community members to manually trigger token swaps. In practice:

* Tokens sat idle for hours or days waiting for someone to act
* When conversions did happen, the protocol paid up to 50% above market price as an incentive to attract participants
* The system spanned 5 contract classes across 8 deployed instances (\~2,000+ lines of Solidity), making it expensive to audit and slow to iterate on
* No guaranteed conversion cadence — protocol income accumulation was unpredictable

### Solution: TokenBuyback

A single upgradeable contract (`TokenBuyback`) is deployed as a Transparent Proxy per (destination, base asset) pair. Each instance:

* Passively accumulates any token sent by `ProtocolShareReserve` (PSR)
* Swaps on demand via `executeBuyback`, which is ACM-restricted to the finance-team cron job
* Forwards the `BASE_ASSET` directly to its `DESTINATION` after each swap
* Enforces a rolling 24h USD cap on per-token consumption (`executeBuyback` reverts past the cap) to bound blast radius if the operator key is compromised
* Uses `ResilientOracle` to USD-price `tokenIn` and `BASE_ASSET` for the cap and for an event-only abnormal-slippage signal

No community. No premium. Conversions happen on a defined schedule at market rate using off-chain-built DEX calldata. Oracle is used only for safety rails (cap + slippage signal), not for swap pricing.

### Key Design Decisions

| Aspect                       | Detail                                                                                                                                                                                                                                                                                                                              |
| ---------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `DESTINATION` & `BASE_ASSET` | Constructor immutables — changing either requires a new deployment                                                                                                                                                                                                                                                                  |
| Swap routing                 | Off-chain (cron builds DEX calldata); router must be on the on-chain allowlist                                                                                                                                                                                                                                                      |
| `updateAssetsState` caller   | Pinned to `PROTOCOL_SHARE_RESERVE` immutable — prevents spoofed `AssetsReceived` events                                                                                                                                                                                                                                             |
| Pool attribution             | No per-pool accounting on-chain; `comptroller` is echoed in events for off-chain attribution                                                                                                                                                                                                                                        |
| Upgradeability               | Transparent Proxy — upgradeable without migrating accumulated funds                                                                                                                                                                                                                                                                 |
| Daily USD cap                | Rolling 24h leaky bucket (`dailyCapUsd`); linear decay rate `dailyCapUsd / 24h`; `executeBuyback` reverts with `DailyCapExceeded` past the cap. Default `$30,000`.                                                                                                                                                                  |
| Abnormal slippage detection  | Event-only — `executeBuyback` emits `AbnormalSlippage` when `usdIn − usdOut > slippageEventUsd` (default `$500`). Does not revert.                                                                                                                                                                                                  |
| Oracle dependency            | `RESILIENT_ORACLE` constructor immutable — used only to USD-price the cap and the slippage signal, not for swap pricing. `executeBuyback` calls `updateAssetPrice(tokenIn)` and `updateAssetPrice(BASE_ASSET)` before reading prices, so the cap and slippage check use a freshly pushed oracle snapshot rather than a stale value. |

### Contract Architecture

`PSR` requires no contract changes — `TokenBuyback` implements `IIncomeDestination`, the same interface used by the original converters. The migration is a governance VIP that rewires PSR's `distributionTargets` rows to point to the new instances.

### Key Functions

**`updateAssetsState(address comptroller, address asset)`**

Called by PSR after transferring tokens. Records the balance delta and emits `AssetsReceived` for off-chain tracking. Only callable by `PROTOCOL_SHARE_RESERVE`. `AssetsReceived` is only emitted when the balance delta is non-zero. The reported amount is the observed `balanceOf(this)` delta against the previous watermark — tokens transferred directly to the contract outside the PSR flow are merged into the next event under whatever comptroller PSR is processing at the time.

**`executeBuyback(address tokenIn, uint256 amountIn, uint256 minAmountOut, uint256 deadline, address router, bytes calldata routerCalldata, address comptroller)`**

ACM-restricted. Swaps `amountIn` of `tokenIn` to `BASE_ASSET` via the specified router (must be allowlisted). Validates slippage against `minAmountOut`. Forwards the output directly to `DESTINATION`. Emits `BuybackExecuted`. The reported `amountIn` in `BuybackExecuted` is the actual on-chain `tokenIn` delta consumed by the router (`balanceBefore − balanceAfter`), not the caller-supplied `amountIn` parameter, so the event is honest about what the router actually pulled. After the swap settles, the call pushes a fresh oracle price for both `tokenIn` and `BASE_ASSET` (`updateAssetPrice`), then enforces the rolling 24h USD cap on `tokenIn` consumption (reverts with `DailyCapExceeded` if exceeded) and emits `AbnormalSlippage` if `usdIn − usdOut` exceeds `slippageEventUsd`.

**`forwardBaseAsset(address comptroller, uint256 amount)`**

ACM-restricted. Forwards a caller-specified `amount` of accumulated `BASE_ASSET` to `DESTINATION` without a swap. The `amount` parameter lets the operator partition multi-pool `BASE_ASSET` inflows so each portion is attributed separately via `BaseAssetForwarded` events.

**`setAllowedRouter(address router, bool allowed)`**

Governance-only. Adds or removes a DEX router from the allowlist.

**`setDailyCapUsd(uint256 newCap)`**

ACM-restricted. Updates the rolling 24h USD cap on `tokenIn` consumption (1e18-scaled). Reverts with `ZeroValueNotAllowed` if `newCap` is zero (the cap cannot be used to fully disable buybacks — use ACM revocation for that). Emits `DailyCapUpdated`.

**`setSlippageEventUsd(uint256 newThreshold)`**

ACM-restricted. Updates the absolute USD threshold above which `AbnormalSlippage` fires (1e18-scaled). Reverts with `ZeroValueNotAllowed` if `newThreshold` is zero. Emits `SlippageEventUsdUpdated`.

**`sweepToken(address token, address to, uint256 amount)`**

Governance-only. Emergency token recovery from the contract. Also the canonical recovery path for tokens transferred directly to the contract outside the PSR flow.

### Events

| Event                                                                 | When emitted                                                            |
| --------------------------------------------------------------------- | ----------------------------------------------------------------------- |
| `AssetsReceived(comptroller, asset, amount)`                          | PSR deposits tokens                                                     |
| `BuybackExecuted(tokenIn, amountIn, amountOut, router, comptroller)`  | Successful DEX swap                                                     |
| `BaseAssetForwarded(comptroller, amount)`                             | `BASE_ASSET` forwarded without swap                                     |
| `RouterAllowlisted(router, allowed)`                                  | Router added/removed from allowlist                                     |
| `SweepToken(token, to, amount)`                                       | Emergency token sweep                                                   |
| `AbnormalSlippage(tokenIn, actualAmountIn, amountOut, usdIn, usdOut)` | Swap returned less USD value than input by more than `slippageEventUsd` |
| `DailyCapUpdated(oldCap, newCap)`                                     | `setDailyCapUsd` succeeds                                               |
| `SlippageEventUsdUpdated(oldThreshold, newThreshold)`                 | `setSlippageEventUsd` succeeds                                          |

### BSC: Before & After

**Before (8 contracts)**

| Contract             | Destination              |
| -------------------- | ------------------------ |
| `RiskFundConverter`  | `RiskFundV2`             |
| `USDTPrimeConverter` | `PrimeLiquidityProvider` |
| `USDCPrimeConverter` | `PrimeLiquidityProvider` |
| `BTCBPrimeConverter` | `PrimeLiquidityProvider` |
| `ETHPrimeConverter`  | `PrimeLiquidityProvider` |
| `XVSVaultConverter`  | `XVSVaultTreasury`       |
| `WBNBBurnConverter`  | Retired (was burn path)  |
| `ConverterNetwork`   | Retired (registry)       |

**After (10 TokenBuyback instances, deployed on BSC mainnet)**

| Instance              | Base Asset | Destination              | Proxy address                                                                                                          |
| --------------------- | ---------- | ------------------------ | ---------------------------------------------------------------------------------------------------------------------- |
| `UTreasuryBuyback`    | U          | `VTreasury`              | [`0xec63411423D03327De19135446dDdA3055D2feA8`](https://bscscan.com/address/0xec63411423D03327De19135446dDdA3055D2feA8) |
| `BTCBTreasuryBuyback` | BTCB       | `VTreasury`              | [`0x1F306a0d929a7098a0A0b12248Ba97600AB79026`](https://bscscan.com/address/0x1F306a0d929a7098a0A0b12248Ba97600AB79026) |
| `ETHTreasuryBuyback`  | ETH        | `VTreasury`              | [`0x41954F0bf26959dF2e1B8302DEBf736B5b154B64`](https://bscscan.com/address/0x41954F0bf26959dF2e1B8302DEBf736B5b154B64) |
| `USDTTreasuryBuyback` | USDT       | `VTreasury`              | [`0xB3dDf13E8B6b8dE10F5826087C202b80F1D1b490`](https://bscscan.com/address/0xB3dDf13E8B6b8dE10F5826087C202b80F1D1b490) |
| `USDCTreasuryBuyback` | USDC       | `VTreasury`              | [`0xd7aC40f9bd9A1beb8E2d121b4446CF90417cf169`](https://bscscan.com/address/0xd7aC40f9bd9A1beb8E2d121b4446CF90417cf169) |
| `XVSTreasuryBuyback`  | XVS        | `VTreasury`              | [`0x6D2d239c16453062cF145A7a5128A6a60710d236`](https://bscscan.com/address/0x6D2d239c16453062cF145A7a5128A6a60710d236) |
| `USDTPrimeBuyback`    | USDT       | `PrimeLiquidityProvider` | [`0xD721932C7CA41Eb5305867287010587a266346a8`](https://bscscan.com/address/0xD721932C7CA41Eb5305867287010587a266346a8) |
| `UPrimeBuyback`       | U          | `PrimeLiquidityProvider` | [`0xBC9fFBfb799B2d189669D3816E2B7273c69041bd`](https://bscscan.com/address/0xBC9fFBfb799B2d189669D3816E2B7273c69041bd) |
| `RiskFundBuyback`     | USDT       | `RiskFundV2`             | [`0x0c71EFabD00329E839745ef23aB946d3ed24A805`](https://bscscan.com/address/0x0c71EFabD00329E839745ef23aB946d3ed24A805) |
| `XVSBuyback`          | XVS        | `XVSVaultTreasury`       | [`0x637E6246BBb0F9aBae9d764F5e1bB6347f028C12`](https://bscscan.com/address/0x637E6246BBb0F9aBae9d764F5e1bB6347f028C12) |

`WBNBBurnConverter` and `ConverterNetwork` are retired. The 6 `TreasuryBuyback` instances are new — treasury previously accepted arbitrary tokens without conversion.

### RiskFundV2 Changes

`RiskFundV2` is upgraded as part of this migration:

* `poolAssetsFunds` mapping removed — per-pool accounting deprecated (isolated pools wound down; core pool does not auction via Shortfall)
* `preSweepToken` simplified — plain balance check replaces the `getPools()` proportional loop
* `transferReserveForAuction` draws against contract balance; `comptroller` retained only for ABI parity and event attribution
* `getPoolsBaseAssetReserves` returns 0 for ABI parity with `Shortfall.sol`

### Migration

BSC mainnet migration executed across two governance proposals — [VIP-620](https://app.venus.io/#/governance/proposal/620?chainId=56) and [VIP-621](https://app.venus.io/#/governance/proposal/621?chainId=56) ([vips PR #708](https://github.com/VenusProtocol/vips/pull/708)). The work was originally proposed as a single transaction in [VIP-618](https://app.venus.io/#/governance/proposal/618?chainId=56), which became unexecutable when BSC's Osaka hardfork enforced a hard per-tx gas cap of 2^24 = 16,777,216: the single-call `helper.execute()` required \~17.5M gas, driven primarily by the converter drain (6 converters × 47 core-pool tokens) and the router allowlist (10 buybacks × 9 routers). Splitting the drain + router allowlist into a separate `execute2()` entrypoint drops both halves comfortably under the cap.

**Pre-VIP** (deploy-script setup):

* 10 new `TokenBuyback` proxies redeployed (the proxies originally deployed for VIP-618 are abandoned), each initialized with its `(DESTINATION, BASE_ASSET, PROTOCOL_SHARE_RESERVE, RESILIENT_ORACLE)` immutables and `pendingOwner = TokenBuybackMigrationHelper`
* New `RiskFundV2` implementation deployed (see *RiskFundV2 Changes* above)
* `TokenBuybackMigrationHelper` redeployed with three one-shot entrypoints — `execute1()`, `executeSwap()` and `execute2()` — each gated to `NormalTimelock`

**VIP-620 (Part 1)** — non-drain, non-allowlist phase plus the May 2026 Prime Rewards Allocation:

1. Grant `DEFAULT_ADMIN_ROLE` on ACM to the helper (renounced inside `execute1()` so the helper retains no residual ACM privilege between the two VIPs)
2. Transfer ownership of the 6 timelock-owned legacy converters to the helper
3. `helper.execute1()` accepts all 16 ownerships, pauses every timelock-owned converter and `Shortfall` auctions, repoints PSR's `distributionTargets` to the new buybacks (18 rows added, 12 stale rows zeroed, in a sequence that respects PSR's `maxLoopsLimit` and the per-schema percentage invariant at every checkpoint), grants the cron operator persistent `executeBuyback` + `forwardBaseAsset` ACM permissions on every buyback, and renounces `DEFAULT_ADMIN_ROLE`. The helper retains ownership of all 16 contracts across the gap between the two VIPs but holds no ACM privileges.
4. May 2026 Prime Rewards Allocation, driven directly from `NormalTimelock` (the helper only wraps the swap leg): `Prime.addMarket(coreComptroller, vU, ...)`, `PrimeLiquidityProvider.initializeTokens([U])`, `PrimeLiquidityProvider.setMaxTokensDistributionSpeed([U], [1e18])`, `PrimeLiquidityProvider.sweepToken(USDC, helper, 10_000e18)`, `helper.executeSwap()` (single soft-failing USDC → USDT → U multihop on PancakeSwap V3 with a 1% slippage floor; the deep USDT/U pool is required because the direct USDC/U pool is too thin), `PrimeLiquidityProvider.setTokensDistributionSpeed([USDT, U], [...])`.
5. Upgrade `RiskFundV2` to the new implementation. Safe because `RiskFundConverter` was paused inside `execute1()`, so no in-flight `convertExactTokens` callback can reach the removed `updatePoolState` selector.

**Between Part 1 and Part 2**: the 6 legacy converters are paused, PSR no longer routes revenue to them, and `Shortfall` auctions are paused — so converter balances are frozen and there is no economic surface from them while the helper still holds ownership.

**VIP-621 (Part 2)** — router allowlist, converter drain, ownership handback:

1. `helper.execute2()` allowlists 9 swap routers on every buyback (PancakeSwap V2 / V3 / Smart / Universal, Uniswap V2 SwapRouter02 / V3 SwapRouter02 / V4 / Universal, 1inch v5), drains every non-zero core-pool ERC20 balance off each timelock-owned converter into its replacement buyback, and transfers ownership of all 16 contracts (10 buybacks + 6 converters) back to `NormalTimelock`.
2. `NormalTimelock` accepts ownership of all 16 contracts.

**Post-VIP**:

* The 6 timelock-owned legacy converters (`RiskFundConverter`, `USDTPrimeConverter`, `USDCPrimeConverter`, `BTCBPrimeConverter`, `ETHPrimeConverter`, `XVSVaultConverter`) remain deployed but are paused and empty
* `WBNBBurnConverter` is Guardian-owned and was not handed to the helper; its sub-dollar residual is drained in a separate multisig transaction, and its PSR distribution row was already removed inside `execute1()`
* `ConverterNetwork` is unreferenced — no contract changes were needed to it
* All 10 new buybacks are owned by `NormalTimelock` and ready to receive PSR distributions
* The finance-team cron operator can now call `executeBuyback` and `forwardBaseAsset` on each buyback via its ACM permissions
* The migration helper holds no privileges, no balances, and no ownership over any contract; all three entrypoints revert `AlreadyExecuted` on any subsequent call
* Pre-existing ACM grants on legacy converter functions are not explicitly revoked; conversions are paused, which renders those permissions inert

### Impact Summary

| Metric                   | Before                         | After                              |
| ------------------------ | ------------------------------ | ---------------------------------- |
| Solidity lines           | \~2,160 across 5 contracts     | \~425 lines, single contract class |
| Deployed instances (BSC) | 8                              | 10 (all `TokenBuyback`)            |
| Conversion trigger       | External community (voluntary) | Finance cron (scheduled)           |
| Pricing                  | Oracle + up to 50% premium     | DEX market rate                    |
| Community dependency     | Required                       | None                               |


# Venus Prime

### **Overview**

Venus Prime is the protocol's flagship incentive program, designed to reward long-term, committed users by boosting their yield across selected markets. It focuses on the core markets USDT, USDC, BTC, ETH and BNB, and promotes sustained $XVS staking.

Venus Prime is powered by two contracts:

* **PrimeV2** — the boost engine. It holds each user's non-transferable (Soulbound) Prime token, tracks per-market scores, and distributes boosted rewards funded by protocol revenue.
* **PrimeLeaderboard** — the eligibility engine. It measures how much $XVS each user has staked and for how long, producing a time-weighted **Prime Score** that ranks users for Prime eligibility.

### **Venus Prime Essentials**

Venus Prime's uniqueness lies in its self-sustaining rewards system: instead of relying on external sources or token emissions, rewards are derived from the protocol's revenue, fostering a sustainable and ever-growing program.

Eligible $XVS stakers receive a single, non-transferable Soulbound Prime token, which boosts rewards across the selected markets. The token is capped at a configurable supply (`tokenLimit`, **500** by default), changeable via VIP.

#### Eligibility: time-weighted Prime Score

Prime eligibility is no longer a fixed "stake X for Y days" rule. Instead, PrimeLeaderboard computes a **Prime Score** that rewards both the size and the age of each XVS deposit.

Every deposit and withdrawal in the XVS Vault is reported to PrimeLeaderboard, which records individual deposit tranches and applies a duration-based multiplier to each:

| Holding duration | Multiplier  |
| ---------------- | ----------- |
| < 30 days        | 1.0x (base) |
| ≥ 30 days        | 1.3x        |
| ≥ 60 days        | 1.6x        |
| ≥ 90 days        | 2.0x (cap)  |

A user's Prime Score is the sum, across all of their active deposits, of:

```
amount × multiplier(holdingDuration) × min(holdingDuration, 90 days)
```

Withdrawals are processed **LIFO** (newest deposits first), so a user's oldest, highest-multiplier stake is preserved for as long as possible. The tiers and the 90-day cap are configurable by governance via `setMultiplierTiers`.

#### Minting a Prime token

The primary minting path is **governance issuance**. Each epoch is one calendar month. After each epoch, a keeper reads the leaderboard off-chain (via `getEffectiveStakeBatch`), ranks users by Prime Score, and governance mints Prime tokens to the qualifying users with the ACM-gated `issue`/`issueBatch` functions (and revokes them, when needed, via `burn`/`burnBatch`).

A **permissionless minting** window is available as a fallback and is **disabled by default**. It only becomes usable if governance opens it by setting a minimum Prime Score threshold with `setMintThreshold(threshold, deadline)`; until then, `mintThreshold` is `0` and `claimPrime` reverts. When open, anyone can call `claimPrime(user)` (or `claimPrimeBatch`) to mint a Prime token for any user whose Prime Score is at or above the threshold, until the optional deadline passes. This serves as a last resort if the keeper-driven flow is unavailable. Governance can close it again at any time by setting the threshold back to `0`.

There is no separate "revocable" vs. "irrevocable" token — there is a single Prime token whose lifecycle is managed by governance based on the leaderboard.

### **Expected Impact**

Venus Prime incentivizes larger stake sizes and, through the time-weighted leaderboard, rewards users who keep their XVS staked. This is expected to increase XVS staking, Total Value Locked (TVL), and market growth, while discouraging premature withdrawals.

Stake your $XVS tokens today to climb the leaderboard and become eligible for Venus Prime.

### Technical Reward Details

Once a user holds a Prime token, their boosted rewards in each market are distributed with a Cobb-Douglas function, weighting their XVS stake against their qualified supply and borrow balances.

**Reward Formula: Cobb-Douglas function**

$$
Rewards\_{i,m} = \Gamma\_m \times \mu \times \frac{\tau\_{i}^\alpha \times \sigma\_{i,m}^{1-\alpha}}{\sum\_{j,m} \tau\_{j}^\alpha \times \sigma\_{j,m}^{1-\alpha}}
$$

Where:

* $$Rewards\_{i,m}$$ = Rewards for user $$i$$ in market $$m$$
* $$\Gamma\_m$$ = Protocol Reserve Revenue for market $$m$$
* $$μ$$ = Proportion to be distributed as rewards
* $$α$$ = Protocol stake and supply & borrow amplification weight
* $$τ\_{i}​$$ = XVS staked amount for user $$i$$
* $$\sigma\_i$$ = Sum of **qualified** supply and borrow balance for user $$i$$
* $$∑\_{j,m}​$$ = Sum for all users $$j$$ in markets $$m$$

**Qualifiable supply and borrow:**

$$
\begin{align\*} \sigma\_{i,m} &= \min(\tau\_i \times borrowMultiplier\_m, borrowedAmount\_{i,m}) \ &+ \min(\tau\_i \times supplyMultiplier\_m, suppliedAmount\_{i,m}) \end{align\*}
$$

*Note: There is a limit for the qualifiable supply and borrow amounts, set by the staked XVS value and the market multiplier.*

### User Reward Example:

*Note: the example below uses a BTC market for illustration; the same math applies to whichever reward markets are enabled.*

**Model Parameters**

* $$α$$ = 0.5
* $${\sum\_{j,BTC} \tau\_{j}^\alpha \times \sigma\_{j,BTC}^{1-\alpha}}$$ = 744,164
* $$\Gamma\_{BTC}$$ = 8 BTC
* $$\mu$$ = 0.2
* BTC Supply Multiplier = 2
* XVS Price = $4.0

**User Parameters**

| User Parameters | Token Value | USD Value |
| --------------- | ----------- | --------- |
| Staked XVS      | 1,200       | $4,800    |
| BTC Supply      | 0.097       | $2,500    |

**Qualifiable Supply and Borrow**

$$\sigma\_{i,\text{BTC}} = \textit{min}(\text{$9600}, \text{$2500})$$

**User Rewards**

$$Rewards\_{i, BTC} = 8\times 0.2\times \dfrac{1,200^{0.5}\times 2,500^{0.5}}{744,164}$$

$$Rewards\_{i, BTC} = \ 0.00372$$

$$\text{User APY Increase} = \dfrac{0.00372}{0.097} = 3.88%$$

**Expected Rewards Function**

Rewards in the Venus Prime program 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.

<figure><img src="/files/TgBLuIaaIaoIkS09xE6D" alt=""><figcaption><p><em>Please note that the rewards can vary based on the total market participation and the amount of XVS staked, as illustrated by the formula and example above.</em></p></figcaption></figure>

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.


# Liquidity Hub

### Overview

The **Venus Liquidity Hub** is a per-asset *allocator vault*. A lender deposits a single asset (USDT, for example) and receives a yield-bearing share token. Under a governance-set policy, the Hub automatically spreads that capital across the yield families it is wired to — **Core** (Venus Core lending), **Flux** (Fluid Lending, a third-party protocol), **FRV** (Venus Fixed-Rate Vaults) and new yield sources as they come online — blending the underlying returns into a single yield, removing the need for lenders to pick a product, allocate across it, and assess each one's risk on their own. Capital routed to Flux is exposed to Fluid's contracts, not only to Venus's.

There is **one Hub per asset**, with no cross-asset coupling: a USDT Hub only ever holds and routes USDT. Each Hub is a standard [ERC-4626](https://eips.ethereum.org/EIPS/eip-4626) vault, so any wallet, aggregator, or partner that already speaks ERC-4626 can integrate it once and automatically benefit as Venus adds new yield products behind it.

Yield accrues through a **rising exchange rate** — one share becomes redeemable for more underlying over time — never by rebasing. The number of shares in a wallet does not change; their redemption value does.

### Why a Liquidity Hub

Today a lender has to choose between independent products — Venus Core lending, Fluid-backed Flux markets, and Venus Fixed-Rate Vaults — allocate manually, and monitor each separately. Large and institutional lenders especially want a single, transparent entry point rather than onboarding to each vault individually. The Liquidity Hub shifts the lender experience from *"pick a vault per product"* to *"one-click deposit per asset,"* while giving governance a curated, transparent allocation layer on top of products it already runs.

The Hub is purely a routing layer. It does **not** modify the parameters or governance of the underlying Core / Flux / FRV products — it only moves capital into and out of them.

### The three yield families (Sources)

A **Source** groups downstream products of the same kind behind one uniform interface. v1 ships three:

| Source   | Underlying protocol         | What the Hub holds                      |
| -------- | --------------------------- | --------------------------------------- |
| **Core** | Venus Core lending          | vTokens (Compound-style receipt tokens) |
| **Flux** | Fluid Lending (third-party) | fTokens (ERC-4626 shares)               |
| **FRV**  | Venus Fixed-Rate Vaults     | Fixed-Rate Vault shares (ERC-4626)      |

At launch only **Core** and **Flux** hold a live product. The FRV Source is registered on every Hub with its caps set, but no Fixed-Rate Vault instance exists for these assets on BNB Chain yet, so it is wired to nothing and receives no capital until a follow-up proposal adds one.

The Source set is **governance-extensible**: new yield families can be added later without changing the Hub or the share token, because every Source is reached through the same interface.

### How deposits and withdrawals are routed

The Hub holds two independent, governance-configured ordered queues — a **deposit queue** and a **withdraw queue**. Neither is derived from the other.

* **Deposit** — capital cascades down the deposit queue. Each Source absorbs up to its available capacity (bounded by its cap), and any remainder overflows to the next Source. If the total deposit is larger than the combined free capacity of every Source, the **entire transaction reverts** — there is no partial fill.
* **Withdraw** — the Hub serves the request from its own idle balance first, then walks the withdraw queue, pulling liquidity in order until the request is filled. If the request exceeds total available liquidity, or exceeds the per-transaction withdrawal cap, the **entire transaction reverts**.

At launch the queues are configured **Core-first in, Flux-first out** — deposit `[Core, Flux]`, withdraw `[Flux, Core, FRV]`. Core absorbs everyday inflows, so new capital lands in the deepest and most liquid market first; withdrawals are served from Flux ahead of Core, which keeps Core's balance intact as a buffer. FRV is out of the deposit queue entirely (nothing to route into) and sits last on the withdraw side, where an empty Source costs nothing to walk past. The two orders are set independently and governance can reorder either.

### Operator rebalancing

Beyond user-driven flow, a privileged **Operator** can proactively rebalance capital between *already-registered* Sources and products — for example, pulling funds back to Core when general-market utilization tightens, or seeding a newly onboarded product. Rebalancing is **net-zero** (the amount pulled equals the amount pushed; nothing enters or leaves the Hub) and is bounded by the same caps governance sets. The Operator can never create a new route or move funds outside the registered set.

### Safety envelope

* **Atomic-or-revert** — deposits, withdrawals, and rebalances either complete in full or revert. No partial fills, no stranded remainder.
* **Dual caps per Source** — each Source carries both an absolute cap and a percentage-of-Hub cap; the stricter one binds. A large Source can never quietly exceed its share of the Hub.
* **Per-transaction withdrawal cap** — bounds any single withdrawal so one transaction cannot drain a downstream product's liquidity.
* **Multi-level pause** — the Hub, an individual Source, or a single product can each be paused independently. A broader pause blocks everything beneath it; unaffected siblings keep operating, and the underlying products themselves keep running normally even while the Hub is paused.
* **Asymmetric permissions** — every privileged function is a separate role, and the split governs who holds it *besides* governance. *Loosening* — unpausing at any level, registering a new route, raising the per-transaction withdrawal cap, setting fees — is governance-only, behind a VIP. *Tightening* — lowering a cap, pausing — governance holds as well, but it is additionally delegated to the **Operator**, and pausing is delegated further to a **Guardian** multisig that acts with no timelock delay so it can contain an incident immediately. The Guardian is granted containment only: it can pause at every level but holds no unpause, so it can never undo a governance-ordered pause. The one deliberate exception to the pattern is raising a Source's cap, which the Operator also holds so it can open headroom immediately before a rebalance; it remains bounded by everything else governance set.

### Fees

The Hub supports three governance-controlled fees:

* **Management fee** — a time-based fee on assets under management, minted as dilution shares to a fee recipient.
* **Performance fee** — charged only on gains above a high-water mark, so a fee can never be claimed twice on the same gain. The mark ratchets upward on every accrual and is re-anchored to the entry price only when the vault is refilled after emptying completely, so a new cohort is neither shielded by nor charged for a prior cohort's high. Also minted as dilution shares.
* **Redeem fee** — an exit fee applied when a lender withdraws or redeems. Unlike the other two it is **not protocol revenue** and is never paid to the fee recipient: it stays in the vault and is socialised to the remaining lenders as a price-per-share uplift. Its purpose is anti-sandwich friction — it discourages racing out ahead of a downward repricing at a Fixed-Rate Vault settlement.

At launch all three are set to **0%**. The machinery exists for governance to enable them later; the management and performance fees are capped at 50%, and the redeem fee at 5%.

### Status

The Liquidity Hub launches on **BNB Chain** with three supported assets — **USDT**, **USDC** and **U** — and more to follow. All fees are set to `0` at launch, the Operator role is held by a Venus operations multisig (the routine keeper), and a separate Guardian multisig holds pause rights with no timelock delay. Only **Core** and **Flux** carry a live product at launch: an FRV Source is registered on every Hub, but no Fixed-Rate Vault exists for these assets yet, so no capital routes to it until a follow-up proposal wires one. Contract addresses are listed in the [technical reference](/technical-reference/reference-liquidity-hub#deployment).

For the contract-level architecture, flows, and full API, see the [Liquidity Hub technical reference](/technical-reference/reference-liquidity-hub).


# VIPs

### Overview

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.

### Governance Upgrade

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** were utilized during emergencies demanding an immediate reaction.

{% hint style="info" %}
Since [VIP-645](https://app.venus.io/#/governance/proposal/645?chainId=56), the Critical Timelock holds no permission on any network, so the Critical route can no longer execute privileged actions. Emergency responses rely on the fine-grained pause mechanism (see below) and Fast-track VIPs.
{% endhint %}

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 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.

<figure><img src="/files/xlaoGx8rZGAMV2cuGbD5" alt=""><figcaption><p><em>Governance Process</em></p></figcaption></figure>


# Tokenomics

### Overview

The Venus Protocol tokenomics have been reevaluated to optimize income distribution and cater to the protocol's present and future needs. [Version 4.1](https://snapshot.box/#/s:venus-xvs.eth/proposal/0xb8f03ad2dd2988a6d2e89a1adbebc52c7a62b284ea493008752c71b7f00b3386) of the Venus Protocol revenue distribution model optimizes the allocation between rewards, treasury reserves, and a risk fund. Following the cessation of the BNB Burn program ([VIP-585](https://app.venus.io/#/governance/proposal/585)), the previous 25% BNB Burn allocation has been redistributed to the Treasury.

### XVS Vault Base Rewards

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](https://bscscan.com/address/0xfd36e2c2a6789db23113685031d7f16329158384) to the [XVS Vault Store](https://www.bscscan.com/address/0x1e25cf968f12850003db17e0dba32108509c4359), where they will be emitted at a rate of 308.7 XVS per day.

### Revenue Distribution from Protocol Reserves

Protocol reserves are mainly composed of accumulated borrow fees. The model for revenue allocation from these reserves divides income into four segments:

* **Treasury Reserve (40%)**: 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.

### Allocation for Additional Revenue Streams

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 (60%)**
* **XVS Vault Rewards (20%)**
* **Risk Fund (20%)**

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.

### Chain Eligibility

Revenue distribution to XVS Vault Rewards and Venus Prime is subject to a chain eligibility threshold: a chain must generate at least $50,000 in average monthly revenue over a rolling 6-month period to qualify. Chains that do not meet this threshold send 100% of their revenue to the Treasury.

<figure><img src="/files/YUGDFflpCpgfdXwg8Wg3" alt=""><figcaption></figcaption></figure>


# Resilient Price Oracle

### Overview

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.

### Key Features

#### Resilient Price Feeds

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, Binance, Atlas and APRO oracles, with the possibility of adding more in the future.

#### Governance Configurations

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.

### Safety Measures

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.

<figure><img src="/files/6DDcELKFV4a4Ik9NHidM" alt=""><figcaption></figcaption></figure>

### Protection Mode

For low-liquidity collateral assets, the Resilient Oracle's spot price is wrapped by the [DeviationBoundedOracle](/technical-reference/reference-oracle/deviation-bounded-oracle) on the borrow-power path. When the spot deviates beyond a per-asset threshold from the recent rolling window, [Protection Mode](/risk/protection-mode) activates and the Comptroller switches to bounded prices — `min(spot, windowMin)` for collateral and `max(spot, windowMax)` for debt — until conditions normalize. Liquidations continue to use the Resilient Oracle's spot price directly.

### Correlated Token Oracles

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 [ankrBNB](https://bscscan.com/address/0x52F24a5e03aee338Da5fd9Df68D2b6FAe1178827) token, converting on-chain from ankrBNB to BNB using the exchange rate from the ankrBNB contract.
* `BNBxOracle`. It returns the USD price of the [BNBx](https://bscscan.com/address/0x1bdd3Cf7F79cfB8EdbB955f20ad99211551BA275) token, converting on-chain from BNBx to BNB using the exchange rate from the [stake manager](https://bscscan.com/address/0x3b961e83400D51e6E1AF5c450d3C7d7b80588d28) contract.
* `eBTCAccountantOracle` (instance of `EtherfiAccountantOracle`). It returns the USD price of the [eBTC](https://etherscan.io/token/0x657e8C867D8B37dCC18fA4Caead9C45EB088C642) token, converting on-chain from eBTC to WBTC using the exchange rate from the [Accountant](https://etherscan.io/address/0x1b293DC39F94157fA0D1D36d7e0090C8B8B8c13F) contract.
* `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](https://etherscan.io/token/0xa663b02cf0a4b149d2ad41910cb81e23e1c41c32) 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](https://bscscan.com/address/0xB0b84D294e0C75A6abe60171b70edEb2EFd14A1B) token, converting on-chain from slisBNB to BNB using the exchange rate from the [stake manager](https://bscscan.com/address/0x1adB950d8bB3dA4bE104211D5AB038628e477fE6) contract.
* `AsBNBOracle`. It returns the USD price of the [asBNB](https://bscscan.com/address/0x77734e70b6E88b4d82fE632a168EDf6e700912b6) token, converting on-chain from asBNB to slisBNB using the exchange rate from the [asBNB minter](https://bscscan.com/address/0x2F31ab8950c50080E77999fa456372f276952fD8) contract.
* `StkBNBOracle`. It returns the USD price of the [stkBNB](https://bscscan.com/address/0xc2E9d07F66A89c44062459A47a0D2Dc038E4fb16) token, converting on-chain from stkBNB to BNB using the exchange rate from the [stake pool](https://bscscan.com/address/0xC228CefDF841dEfDbD5B3a18dFD414cC0dbfa0D8) contract.
* `WBETHOracle`. It returns the USD price of the [WBETH](https://bscscan.com/address/0xa2e3356610840701bdf5611a53974510ae27e2e1) 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](https://etherscan.io/token/0xcd5fe23c85820f7b72d0926fc9b05b43e359b7ee) token, converting on-chain from weETH to eETH using the exchange rate from the [liquidity pool](https://etherscan.io/address/0x308861A430be4cce5502d0A12724771Fc6DaF216) contract, and assumming 1 eETH = 1 ETH.
* `WeETHsOracle` (instance of `WeETHAccountantOracle`). It returns the USD price of the [weETHs](https://etherscan.io/token/0x917ceE801a67f933F2e6b33fC0cD1ED2d5909D88) token, converting on-chain from weETHs to WETH using the exchange rate from the [Accountant](https://etherscan.io/address/0xbe16605B22a7faCEf247363312121670DFe5afBE) contract.
* `WstETHOracle`. It returns the USD price of the [wstETH](https://etherscan.io/token/0x7f39c581f595b53c5cb19bd0b3f8da6c935e2ca0) token, converting on-chain from wstETH to stETH using the exchange rate from the [stETH](https://etherscan.io/token/0xae7ab96520de3a18e5e111b5eaab095312d7fe84) contract, and assumming 1 stETH = 1 ETH.

{% hint style="warning" %}
**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:

* 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.
  {% endhint %}

### Current configuration

#### BNB chain

| Pool | Market                      | MAIN oracle                                                                                                 | PIVOT oracle                                                                                              | FALLBACK oracle                                                                    | Notes                                                                                                  |
| ---- | --------------------------- | ----------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------ |
| Core | AAVE                        | [Chainlink](https://bscscan.com/address/0x1B2103441A0A108daD8848D8F5d790e4D402921F)                         | [Atlas](https://bscscan.com/address/0x9E6928Ec418948ceb9f1cd9872fD312b13D841D0)                           | [RedStone](https://bscscan.com/address/0x8455EFA4D7Ff63b8BFD96AdD889483Ea7d39B70a) | Upper bound: 1.05. Lower bound: 0.95                                                                   |
| Core | ADA                         | [Chainlink](https://bscscan.com/address/0x1B2103441A0A108daD8848D8F5d790e4D402921F)                         | [RedStone](https://bscscan.com/address/0x8455EFA4D7Ff63b8BFD96AdD889483Ea7d39B70a)                        | [Atlas](https://bscscan.com/address/0x9E6928Ec418948ceb9f1cd9872fD312b13D841D0)    | Upper bound: 1.05. Lower bound: 0.95                                                                   |
| Core | asBNB                       | [AsBNBOracle](https://bscscan.com/address/0x652B90D1d45a7cD5BE82c5Fb61a4A00bA126dde5)                       | [Atlas](https://bscscan.com/address/0x9E6928Ec418948ceb9f1cd9872fD312b13D841D0)                           | -                                                                                  | Upper bound: 1.05. Lower bound: 0.95                                                                   |
| Core | BCH                         | [Chainlink](https://bscscan.com/address/0x1B2103441A0A108daD8848D8F5d790e4D402921F)                         | [Atlas](https://bscscan.com/address/0x9E6928Ec418948ceb9f1cd9872fD312b13D841D0)                           | [RedStone](https://bscscan.com/address/0x8455EFA4D7Ff63b8BFD96AdD889483Ea7d39B70a) | Upper bound: 1.05. Lower bound: 0.95                                                                   |
| Core | BETH (Paused)               | [Chainlink](https://bscscan.com/address/0x1B2103441A0A108daD8848D8F5d790e4D402921F)                         | -                                                                                                         | -                                                                                  |                                                                                                        |
| Core | BNB                         | [Chainlink](https://bscscan.com/address/0x1B2103441A0A108daD8848D8F5d790e4D402921F)                         | [RedStone](https://bscscan.com/address/0x8455EFA4D7Ff63b8BFD96AdD889483Ea7d39B70a)                        | [Atlas](https://bscscan.com/address/0x9E6928Ec418948ceb9f1cd9872fD312b13D841D0)    | Upper bound: 1.01. Lower bound: 0.99                                                                   |
| Core | WBNB                        | [Chainlink](https://bscscan.com/address/0x1B2103441A0A108daD8848D8F5d790e4D402921F)                         | [RedStone](https://bscscan.com/address/0x8455EFA4D7Ff63b8BFD96AdD889483Ea7d39B70a)                        | [Atlas](https://bscscan.com/address/0x9E6928Ec418948ceb9f1cd9872fD312b13D841D0)    | Upper bound: 1.01. Lower bound: 0.99                                                                   |
| Core | BTCB                        | [Chainlink](https://bscscan.com/address/0x1B2103441A0A108daD8848D8F5d790e4D402921F)                         | [RedStone](https://bscscan.com/address/0x8455EFA4D7Ff63b8BFD96AdD889483Ea7d39B70a)                        | [Atlas](https://bscscan.com/address/0x9E6928Ec418948ceb9f1cd9872fD312b13D841D0)    | Upper bound: 1.01. Lower bound: 0.99                                                                   |
| Core | BUSD (Paused)               | [Chainlink](https://bscscan.com/address/0x1B2103441A0A108daD8848D8F5d790e4D402921F)                         | -                                                                                                         | -                                                                                  | [Price fixed to $1](https://app.venus.io/#/governance/proposal/226?chainId=56)                         |
| Core | CAKE                        | [Chainlink](https://bscscan.com/address/0x1B2103441A0A108daD8848D8F5d790e4D402921F)                         | [RedStone](https://bscscan.com/address/0x8455EFA4D7Ff63b8BFD96AdD889483Ea7d39B70a)                        | [Atlas](https://bscscan.com/address/0x9E6928Ec418948ceb9f1cd9872fD312b13D841D0)    | Upper bound: 1.05. Lower bound: 0.95                                                                   |
| Core | DAI                         | [Chainlink](https://bscscan.com/address/0x1B2103441A0A108daD8848D8F5d790e4D402921F)                         | [RedStone](https://bscscan.com/address/0x8455EFA4D7Ff63b8BFD96AdD889483Ea7d39B70a)                        | [Atlas](https://bscscan.com/address/0x9E6928Ec418948ceb9f1cd9872fD312b13D841D0)    | Upper bound: 1.05. Lower bound: 0.95                                                                   |
| Core | DOGE                        | [Chainlink](https://bscscan.com/address/0x1B2103441A0A108daD8848D8F5d790e4D402921F)                         | [Atlas](https://bscscan.com/address/0x9E6928Ec418948ceb9f1cd9872fD312b13D841D0)                           | [RedStone](https://bscscan.com/address/0x8455EFA4D7Ff63b8BFD96AdD889483Ea7d39B70a) | Upper bound: 1.05. Lower bound: 0.95                                                                   |
| Core | DOT                         | [Chainlink](https://bscscan.com/address/0x1B2103441A0A108daD8848D8F5d790e4D402921F)                         | [Atlas](https://bscscan.com/address/0x9E6928Ec418948ceb9f1cd9872fD312b13D841D0)                           | [RedStone](https://bscscan.com/address/0x8455EFA4D7Ff63b8BFD96AdD889483Ea7d39B70a) | Upper bound: 1.05. Lower bound: 0.95                                                                   |
| Core | ETH                         | [Chainlink](https://bscscan.com/address/0x1B2103441A0A108daD8848D8F5d790e4D402921F)                         | [RedStone](https://bscscan.com/address/0x8455EFA4D7Ff63b8BFD96AdD889483Ea7d39B70a)                        | [Atlas](https://bscscan.com/address/0x9E6928Ec418948ceb9f1cd9872fD312b13D841D0)    | Upper bound: 1.01. Lower bound: 0.99                                                                   |
| Core | FDUSD                       | [Chainlink](https://bscscan.com/address/0x1B2103441A0A108daD8848D8F5d790e4D402921F)                         | [Atlas](https://bscscan.com/address/0x9E6928Ec418948ceb9f1cd9872fD312b13D841D0)                           | [RedStone](https://bscscan.com/address/0x8455EFA4D7Ff63b8BFD96AdD889483Ea7d39B70a) | Upper bound: 1.05. Lower bound: 0.95                                                                   |
| Core | FIL                         | [Chainlink](https://bscscan.com/address/0x1B2103441A0A108daD8848D8F5d790e4D402921F)                         | [Atlas](https://bscscan.com/address/0x9E6928Ec418948ceb9f1cd9872fD312b13D841D0)                           | [RedStone](https://bscscan.com/address/0x8455EFA4D7Ff63b8BFD96AdD889483Ea7d39B70a) | Upper bound: 1.05. Lower bound: 0.95                                                                   |
| Core | LINK                        | [Chainlink](https://bscscan.com/address/0x1B2103441A0A108daD8848D8F5d790e4D402921F)                         | [Atlas](https://bscscan.com/address/0x9E6928Ec418948ceb9f1cd9872fD312b13D841D0)                           | [RedStone](https://bscscan.com/address/0x8455EFA4D7Ff63b8BFD96AdD889483Ea7d39B70a) | Upper bound: 1.05. Lower bound: 0.95                                                                   |
| Core | lisUSD                      | [Atlas](https://bscscan.com/address/0x9E6928Ec418948ceb9f1cd9872fD312b13D841D0)                             | -                                                                                                         | -                                                                                  |                                                                                                        |
| Core | LTC                         | [Chainlink](https://bscscan.com/address/0x1B2103441A0A108daD8848D8F5d790e4D402921F)                         | [Atlas](https://bscscan.com/address/0x9E6928Ec418948ceb9f1cd9872fD312b13D841D0)                           | [RedStone](https://bscscan.com/address/0x8455EFA4D7Ff63b8BFD96AdD889483Ea7d39B70a) | Upper bound: 1.05. Lower bound: 0.95                                                                   |
| Core | MATIC (Paused)              | [Chainlink](https://bscscan.com/address/0x1B2103441A0A108daD8848D8F5d790e4D402921F)                         | -                                                                                                         | -                                                                                  | Price feed from [$POL](https://data.chain.link/feeds/bsc/mainnet/pol-usd)                              |
| Core | SOL                         | [Chainlink](https://bscscan.com/address/0x1B2103441A0A108daD8848D8F5d790e4D402921F)                         | [Atlas](https://bscscan.com/address/0x9E6928Ec418948ceb9f1cd9872fD312b13D841D0)                           | [RedStone](https://bscscan.com/address/0x8455EFA4D7Ff63b8BFD96AdD889483Ea7d39B70a) | Upper bound: 1.05. Lower bound: 0.95                                                                   |
| Core | slisBNB                     | [SlisBNBOracle](https://bscscan.com/address/0xDDE6446E66c786afF4cd3D183a908bCDa57DF9c1)                     | [Atlas](https://bscscan.com/address/0x9E6928Ec418948ceb9f1cd9872fD312b13D841D0)                           | -                                                                                  | Upper bound: 1.05. Lower bound: 0.95                                                                   |
| Core | solvBTC                     | [SolvBTCOneJumpChainlinkOracle](https://bscscan.com/address/0x3f4bC081E749032cffF29dcA2E8408Ec375e745A)     | [SolvBTCOneJumpFundamentalOracle](https://bscscan.com/address/0x1f785B1AFE0808d69d1188db9e47b7B9Dd95ab09) | -                                                                                  | Upper bound: 1.02. Lower bound: 0.98. MAIN reads the Chainlink SolvBTC/BTC exchange rate feed          |
| Core | sUSDe                       | [sUSDeOneJumpRedstoneOracle](https://bscscan.com/address/0x2B2895104f958E1EC042E6Ba5cbfeCbAD3C5beDb)        | [sUSDeOneJumpChainlinkOracle](https://bscscan.com/address/0xA67F01322AF8EBa444D788Ee398775b446de51a0)     | -                                                                                  | Upper bound: 1.01. Lower bound: 0.99                                                                   |
| Core | SXP (Paused)                | [Chainlink](https://bscscan.com/address/0x1B2103441A0A108daD8848D8F5d790e4D402921F)                         | -                                                                                                         | -                                                                                  | [Price fixed to $0.00046](https://app.venus.io/#/governance/proposal/631?chainId=56)                   |
| Core | THE                         | [RedStone](https://bscscan.com/address/0x8455EFA4D7Ff63b8BFD96AdD889483Ea7d39B70a)                          | [Atlas](https://bscscan.com/address/0x9E6928Ec418948ceb9f1cd9872fD312b13D841D0)                           | -                                                                                  | Upper bound: 1.05. Lower bound: 0.95                                                                   |
| Core | TRX                         | [Chainlink](https://bscscan.com/address/0x1B2103441A0A108daD8848D8F5d790e4D402921F)                         | [RedStone](https://bscscan.com/address/0x8455EFA4D7Ff63b8BFD96AdD889483Ea7d39B70a)                        | [Atlas](https://bscscan.com/address/0x9E6928Ec418948ceb9f1cd9872fD312b13D841D0)    | Upper bound: 1.01. Lower bound: 0.99                                                                   |
| Core | TUSD                        | [Chainlink](https://bscscan.com/address/0x1B2103441A0A108daD8848D8F5d790e4D402921F)                         | [Atlas](https://bscscan.com/address/0x9E6928Ec418948ceb9f1cd9872fD312b13D841D0)                           | -                                                                                  | Upper bound: 1.05. Lower bound: 0.95                                                                   |
| Core | TRXOLD (Paused)             | [Chainlink](https://bscscan.com/address/0x1B2103441A0A108daD8848D8F5d790e4D402921F)                         | [RedStone](https://bscscan.com/address/0x8455EFA4D7Ff63b8BFD96AdD889483Ea7d39B70a)                        | -                                                                                  | Upper bound: 1.01. Lower bound: 0.99                                                                   |
| Core | TUSDOLD (Paused)            | [Chainlink](https://bscscan.com/address/0x1B2103441A0A108daD8848D8F5d790e4D402921F)                         | -                                                                                                         | -                                                                                  |                                                                                                        |
| Core | TWT                         | [Atlas](https://bscscan.com/address/0x9E6928Ec418948ceb9f1cd9872fD312b13D841D0)                             | [RedStone](https://bscscan.com/address/0x8455EFA4D7Ff63b8BFD96AdD889483Ea7d39B70a)                        | -                                                                                  | Upper bound: 1.05. Lower bound: 0.95                                                                   |
| Core | UNI                         | [Chainlink](https://bscscan.com/address/0x1B2103441A0A108daD8848D8F5d790e4D402921F)                         | [Atlas](https://bscscan.com/address/0x9E6928Ec418948ceb9f1cd9872fD312b13D841D0)                           | [RedStone](https://bscscan.com/address/0x8455EFA4D7Ff63b8BFD96AdD889483Ea7d39B70a) | Upper bound: 1.05. Lower bound: 0.95                                                                   |
| Core | USDC                        | [Chainlink](https://bscscan.com/address/0x1B2103441A0A108daD8848D8F5d790e4D402921F)                         | [RedStone](https://bscscan.com/address/0x8455EFA4D7Ff63b8BFD96AdD889483Ea7d39B70a)                        | [Atlas](https://bscscan.com/address/0x9E6928Ec418948ceb9f1cd9872fD312b13D841D0)    | Upper bound: 1.01. Lower bound: 0.99                                                                   |
| Core | USDe                        | [USDTChainlinkOracle](https://bscscan.com/address/0x22Dc2BAEa32E95AB07C2F5B8F63336CbF61aB6b8)               | [Chainlink](https://bscscan.com/address/0x1B2103441A0A108daD8848D8F5d790e4D402921F)                       | [RedStone](https://bscscan.com/address/0x8455EFA4D7Ff63b8BFD96AdD889483Ea7d39B70a) | Upper bound: 1.06. Lower bound: 0.94                                                                   |
| Core | USDT                        | [Chainlink](https://bscscan.com/address/0x1B2103441A0A108daD8848D8F5d790e4D402921F)                         | [RedStone](https://bscscan.com/address/0x8455EFA4D7Ff63b8BFD96AdD889483Ea7d39B70a)                        | [Atlas](https://bscscan.com/address/0x9E6928Ec418948ceb9f1cd9872fD312b13D841D0)    | Upper bound: 1.01. Lower bound: 0.99                                                                   |
| Core | USD1                        | [Chainlink](https://bscscan.com/address/0x1B2103441A0A108daD8848D8F5d790e4D402921F)                         | [RedStone](https://bscscan.com/address/0x8455EFA4D7Ff63b8BFD96AdD889483Ea7d39B70a)                        | [Atlas](https://bscscan.com/address/0x9E6928Ec418948ceb9f1cd9872fD312b13D841D0)    |                                                                                                        |
| Core | VAI                         | [Chainlink](https://bscscan.com/address/0x1B2103441A0A108daD8848D8F5d790e4D402921F)                         | [Binance](https://bscscan.com/address/0x594810b741d136f1960141C0d8Fb4a91bE78A820)                         | -                                                                                  | Upper bound: 1.05. Lower bound: 0.95                                                                   |
| Core | WBETH                       | [WBETHOracle](https://bscscan.com/address/0x49938fc72262c126eb5D4BdF6430C55189AEB2BA)                       | [Atlas](https://bscscan.com/address/0x9E6928Ec418948ceb9f1cd9872fD312b13D841D0)                           | -                                                                                  | Upper bound: 1.05. Lower bound: 0.95                                                                   |
| Core | XRP                         | [Chainlink](https://bscscan.com/address/0x1B2103441A0A108daD8848D8F5d790e4D402921F)                         | [RedStone](https://bscscan.com/address/0x8455EFA4D7Ff63b8BFD96AdD889483Ea7d39B70a)                        | [Atlas](https://bscscan.com/address/0x9E6928Ec418948ceb9f1cd9872fD312b13D841D0)    | Upper bound: 1.05. Lower bound: 0.95                                                                   |
| Core | xSolvBTC                    | [xSolvBTCOneJumpChainlinkOracle](https://bscscan.com/address/0xDfDbF9DAFbc94Cb1F827d3364637dDBB26823739)    | [xSolvBTCOneJumpRedstoneOracle](https://bscscan.com/address/0xf5534f78Df9b610B19A63956d498d00CFaD8B9D3)   | -                                                                                  | Upper bound: 1.02. Lower bound: 0.98. MAIN reads the Chainlink SVR xSolvBTC/SolvBTC exchange rate feed |
| Core | XVS                         | [Chainlink](https://bscscan.com/address/0x1B2103441A0A108daD8848D8F5d790e4D402921F)                         | [RedStone](https://bscscan.com/address/0x8455EFA4D7Ff63b8BFD96AdD889483Ea7d39B70a)                        | [Atlas](https://bscscan.com/address/0x9E6928Ec418948ceb9f1cd9872fD312b13D841D0)    | Upper bound: 1.05. Lower bound: 0.95                                                                   |
| Core | U                           | [Chainlink](https://bscscan.com/address/0x1B2103441A0A108daD8848D8F5d790e4D402921F)                         | [Atlas](https://bscscan.com/address/0x9E6928Ec418948ceb9f1cd9872fD312b13D841D0)                           | -                                                                                  | Upper bound: 1.01. Lower bound: 0.99                                                                   |
| Core | PT-clisBNB-25JUN2026        | [PendleOracle-PT-clisBNB-25JUN2026](https://bscscan.com/address/0x0FfFBb55d51cD46cD10C7dc865Dc73BD76201310) | -                                                                                                         | -                                                                                  |                                                                                                        |
| Core | PT-sUSDE-26JUN2025 (Paused) | [PendleOracle-PT-sUSDe-26JUN2025](https://bscscan.com/address/0x176ca46D7DcB4e001b8ee5F12d0fcd6D279214f4)   | -                                                                                                         | -                                                                                  |                                                                                                        |
| Core | TSLAB                       | [Atlas](https://bscscan.com/address/0x9E6928Ec418948ceb9f1cd9872fD312b13D841D0)                             | [APRO](https://bscscan.com/address/0x04480f1Ba2252CDF89deB022B58d0a03d1B4cF91)                            | -                                                                                  | Upper bound: 1.05. Lower bound: 0.95. Oracle Dynamic Protection (16.67% deviation trigger)             |
| Core | NVDAB                       | [Atlas](https://bscscan.com/address/0x9E6928Ec418948ceb9f1cd9872fD312b13D841D0)                             | [APRO](https://bscscan.com/address/0x04480f1Ba2252CDF89deB022B58d0a03d1B4cF91)                            | -                                                                                  | Upper bound: 1.05. Lower bound: 0.95. Oracle Dynamic Protection (16.67% deviation trigger)             |
| Core | SPCXB                       | [Atlas](https://bscscan.com/address/0x9E6928Ec418948ceb9f1cd9872fD312b13D841D0)                             | [APRO](https://bscscan.com/address/0x04480f1Ba2252CDF89deB022B58d0a03d1B4cF91)                            | -                                                                                  | Upper bound: 1.05. Lower bound: 0.95. Oracle Dynamic Protection (16.67% deviation trigger)             |
| Core | SKHYB                       | [Atlas](https://bscscan.com/address/0x9E6928Ec418948ceb9f1cd9872fD312b13D841D0)                             | [APRO](https://bscscan.com/address/0x04480f1Ba2252CDF89deB022B58d0a03d1B4cF91)                            | -                                                                                  | Upper bound: 1.05. Lower bound: 0.95. Oracle Dynamic Protection (16.67% deviation trigger)             |

#### Ethereum

| Pool | Market         | MAIN oracle                                                                                              | PIVOT oracle                                                                         | FALLBACK oracle                                                                      | Notes                                |
| ---- | -------------- | -------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------ | ------------------------------------ |
| Core | crvUSD         | [Chainlink](https://etherscan.io/address/0x94c3A2d6B7B2c051aDa041282aec5B0752F8A1F2)                     | -                                                                                    | -                                                                                    |                                      |
| Core | DAI            | [Chainlink](https://etherscan.io/address/0x94c3A2d6B7B2c051aDa041282aec5B0752F8A1F2)                     | -                                                                                    | -                                                                                    |                                      |
| Core | TUSD (Paused)  | [Chainlink](https://etherscan.io/address/0x94c3A2d6B7B2c051aDa041282aec5B0752F8A1F2)                     | -                                                                                    | -                                                                                    |                                      |
| Core | USDC           | [Chainlink](https://etherscan.io/address/0x94c3A2d6B7B2c051aDa041282aec5B0752F8A1F2)                     | -                                                                                    | -                                                                                    |                                      |
| Core | USDT           | [Chainlink](https://etherscan.io/address/0x94c3A2d6B7B2c051aDa041282aec5B0752F8A1F2)                     | -                                                                                    | -                                                                                    |                                      |
| Core | WBTC           | [Chainlink](https://etherscan.io/address/0x94c3A2d6B7B2c051aDa041282aec5B0752F8A1F2)                     | -                                                                                    | -                                                                                    |                                      |
| Core | WETH           | [Chainlink](https://etherscan.io/address/0x94c3A2d6B7B2c051aDa041282aec5B0752F8A1F2)                     | -                                                                                    | -                                                                                    |                                      |
| Core | FRAX (Paused)  | [Chainlink](https://etherscan.io/address/0x94c3A2d6B7B2c051aDa041282aec5B0752F8A1F2)                     | -                                                                                    | -                                                                                    |                                      |
| Core | LBTC           | [LBTCOneJumpRedStoneOracle](https://etherscan.io/address/0x54B033D102db7DD734E0Ad649463E90fFA78D853)     | -                                                                                    | -                                                                                    |                                      |
| Core | EIGEN (Paused) | [Chainlink](https://etherscan.io/address/0x94c3A2d6B7B2c051aDa041282aec5B0752F8A1F2)                     | -                                                                                    | -                                                                                    |                                      |
| Core | sFRAX (Paused) | [SFraxOracle](https://etherscan.io/address/0x1aDCE75BB3164bBf6060a4f44262df5414473110)                   | -                                                                                    | -                                                                                    |                                      |
| Core | eBTC           | [eBTCAccountantOracle](https://etherscan.io/address/0x04d6096A6F089047C7af6E4644D18fB766B8d4cE)          | -                                                                                    | -                                                                                    |                                      |
| Core | USDS           | [Chainlink](https://etherscan.io/address/0x94c3A2d6B7B2c051aDa041282aec5B0752F8A1F2)                     | -                                                                                    | -                                                                                    |                                      |
| Core | sUSDS          | [sUSDS-ERC4646Oracle](https://etherscan.io/address/0xEC3865a8a5DCb8C507781DA17A38b754E3d01C50)           | -                                                                                    | -                                                                                    |                                      |
| Core | weETHs         | [WeETHAccountantOracle(weETHs)](https://etherscan.io/address/0x47f7a7f3486b08a019e0c10af969adc4b6e415cd) | -                                                                                    | -                                                                                    |                                      |
| Core | BAL (Paused)   | [Chainlink](https://etherscan.io/address/0x94c3A2d6B7B2c051aDa041282aec5B0752F8A1F2)                     | -                                                                                    | -                                                                                    |                                      |
| Core | sUSDe          | [sUSDe-ERC4626Oracle](https://etherscan.io/address/0xaE847E81ff6dD2bdFB1fD563ccB4f848c74D2B70)           | -                                                                                    | -                                                                                    |                                      |
| Core | USDe           | [RedStone](https://etherscan.io/address/0x0FC8001B2c9Ec90352A46093130e284de5889C86)                      | [Chainlink](https://etherscan.io/address/0x94c3A2d6B7B2c051aDa041282aec5B0752F8A1F2) | [Chainlink](https://etherscan.io/address/0x94c3A2d6B7B2c051aDa041282aec5B0752F8A1F2) | Upper bound: 1.01. Lower bound: 0.99 |
| Core | tBTC           | [Chainlink](https://etherscan.io/address/0x94c3A2d6B7B2c051aDa041282aec5B0752F8A1F2)                     | -                                                                                    | -                                                                                    |                                      |

#### Arbitrum One

| Pool | Market      | MAIN oracle                                                                                        | PIVOT oracle | FALLBACK oracle | Notes |
| ---- | ----------- | -------------------------------------------------------------------------------------------------- | ------------ | --------------- | ----- |
| Core | WBTC        | [SequencerChainlinkOracle](https://arbiscan.io/address/0x9cd9fcc7e3deda360de7c080590aad377ac9f113) | -            | -               |       |
| Core | WETH        | [SequencerChainlinkOracle](https://arbiscan.io/address/0x9cd9fcc7e3deda360de7c080590aad377ac9f113) | -            | -               |       |
| Core | USDC        | [SequencerChainlinkOracle](https://arbiscan.io/address/0x9cd9fcc7e3deda360de7c080590aad377ac9f113) | -            | -               |       |
| Core | USDT        | [SequencerChainlinkOracle](https://arbiscan.io/address/0x9cd9fcc7e3deda360de7c080590aad377ac9f113) | -            | -               |       |
| Core | gmWETH-USDC | [SequencerChainlinkOracle](https://arbiscan.io/address/0x9cd9fcc7e3deda360de7c080590aad377ac9f113) | -            | -               |       |
| Core | gmBTC-USDC  | [SequencerChainlinkOracle](https://arbiscan.io/address/0x9cd9fcc7e3deda360de7c080590aad377ac9f113) | -            | -               |       |
| Core | ARB         | [SequencerChainlinkOracle](https://arbiscan.io/address/0x9cd9fcc7e3deda360de7c080590aad377ac9f113) | -            | -               |       |

#### ZKsync Mainnet

| Pool | Market  | MAIN oracle                                                                                                   | PIVOT oracle                                                                                     | FALLBACK oracle                                                                                  | Notes                                |
| ---- | ------- | ------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------ | ------------------------------------ |
| Core | WBTC    | [ChainlinkOracle](https://explorer.zksync.io/address/0x4FC29E1d3fFFbDfbf822F09d20A5BE97e59F66E5)              | -                                                                                                | -                                                                                                |                                      |
| Core | WETH    | [ChainlinkOracle](https://explorer.zksync.io/address/0x4FC29E1d3fFFbDfbf822F09d20A5BE97e59F66E5)              | -                                                                                                | -                                                                                                |                                      |
| Core | USDC    | [ChainlinkOracle](https://explorer.zksync.io/address/0x4FC29E1d3fFFbDfbf822F09d20A5BE97e59F66E5)              | -                                                                                                | -                                                                                                |                                      |
| Core | USDC\_E | [ChainlinkOracle](https://explorer.zksync.io/address/0x4FC29E1d3fFFbDfbf822F09d20A5BE97e59F66E5)              | -                                                                                                | -                                                                                                |                                      |
| Core | USDT    | [ChainlinkOracle](https://explorer.zksync.io/address/0x4FC29E1d3fFFbDfbf822F09d20A5BE97e59F66E5)              | -                                                                                                | -                                                                                                |                                      |
| Core | ZK      | [RedStoneOracle](https://explorer.zksync.io/address/0xFa1e65e714CDfefDC9729130496AB5b5f3708fdA)               | [ChainlinkOracle](https://explorer.zksync.io/address/0x4FC29E1d3fFFbDfbf822F09d20A5BE97e59F66E5) | [ChainlinkOracle](https://explorer.zksync.io/address/0x4FC29E1d3fFFbDfbf822F09d20A5BE97e59F66E5) | Upper bound: 1.01. Lower bound: 0.99 |
| Core | wstETH  | [wstETHOneJumpChainlinkOracle](https://explorer.zksync.io/address/0x2DAaeb94E19145BA7633cAB2C38c76fD8c493198) | -                                                                                                | -                                                                                                |                                      |
| Core | wUSDM   | [wUSDM-ERC4626Oracle](https://explorer.zksync.io/address/0x22cE94e302c8C80a6C2dCfa9Da6c5286e9f28692)          | -                                                                                                | -                                                                                                |                                      |
| Core | zkETH   | [ZkETHOracle](https://explorer.zksync.io/address/0x407dE1229BCBD2Ec876d063F3F93c4D8a38bd81a)                  | -                                                                                                | -                                                                                                | Assume 1:1 for WETH:rzkETH           |

#### Base Mainnet

| Pool | Market      | MAIN oracle                                                                                             | PIVOT oracle | FALLBACK oracle | Notes |
| ---- | ----------- | ------------------------------------------------------------------------------------------------------- | ------------ | --------------- | ----- |
| Core | cbBTC       | [ChainlinkOracle](https://basescan.org/address/0x6F2eA73597955DB37d7C06e1319F0dC7C7455dEb)              | -            | -               |       |
| Core | WETH        | [ChainlinkOracle](https://basescan.org/address/0x6F2eA73597955DB37d7C06e1319F0dC7C7455dEb)              | -            | -               |       |
| Core | USDC        | [ChainlinkOracle](https://basescan.org/address/0x6F2eA73597955DB37d7C06e1319F0dC7C7455dEb)              | -            | -               |       |
| Core | wsuperOETHb | [wsuperOETHb-ERC4626Oracle](https://basescan.org/address/0xcd1d2C99642165440c2CC023AFa2092b487f033e)    | -            | -               |       |
| Core | wstETH      | [wstETHOneJumpChainlinkOracle](https://basescan.org/address/0xDDD4F0836c8016E11fC6741A4886E97B3c3d20C1) | -            | -               |       |

### Further Reading

For more detailed information, refer to the following resources:

#### Audit reports

* [Resilient Price Oracle](/links/security-and-audits#oracles)
* [Resilient Price Oracle upgrade](/links/security-and-audits#oracles-upgrade-2023-07-24)
* [WstETH oracle](/links/security-and-audits#oracle-for-wsteth)
* [Correlated token oracles](/links/security-and-audits#correlated-token-oracles)

#### References

* [Repository](https://github.com/VenusProtocol/oracle)
* [Community post about Venus V4, introducing Resilient Price Feeds](https://community.venus.io/t/proposing-venus-v4/3188#price-feed-redundancy-6)
* [Venus Stars blog post about Binance Oracle](https://venusstars.io/community/index.php/2023/05/09/venus-enhances-resilience-binance-oracle-feeds/)


# Protection Mode

### Overview

Venus already protects every market with the [Resilient Oracle](/risk/resilient-price-oracle), which validates prices across multiple independent sources before any value is used by the protocol. Protection Mode adds a second layer on top of that foundation for whitelisted assets prone to manipulation (typically low-liquidity tokens, used as either collateral or borrow asset): when a sudden price move on an asset looks like manipulation, Protection Mode activates and switches its borrow-capacity price to a conservative, manipulation-resistant value, while liquidations continue to use real-time spot.

The risk it mitigates is well-known on lending protocols. An attacker can pump the price of a low-liquidity token they hold as collateral, borrow far more than the token's real value warrants, and exit before the protocol can recover — leaving the protocol holding collateral worth a fraction of the outstanding debt, bad debt that socializes losses across all lenders. The mirror attack on the debt side has the same structure: an attacker manipulates the oracle to undervalue a borrow asset, drains far more of it than the collateral truly warrants at fair value, and exits before the price recovers — leaving the protocol with debt whose true value exceeds the collateral backing it.

Protection Mode prevents this by introducing a per-asset rolling spot-price window. When the current spot deviates beyond a configured threshold from that window, the asset's borrow-power calculation switches to a conservative dual-price scheme:

* **Collateral value** is computed at `min(spot, windowMin)` — caps borrow power at the recent window low so a pumped asset cannot be over-borrowed against.
* **Debt value** is computed at `max(spot, windowMax)` — floors the valuation of debt at the recent window high so a crashed borrow asset cannot be over-borrowed at the manipulated low price.
* **Liquidations continue to use spot price** — eligibility and seize-amount calculations stay on real-time prices so liquidator incentives stay correct and underwater positions are still caught immediately.
* **Only new actions are constrained** — existing positions keep their health factor evaluated at spot, so activation does not endanger any open position; the bounded prices apply only to new borrows and additional collateral movements.

### Key Mechanics

#### Rolling Price Window

For each whitelisted asset the [DeviationBoundedOracle](/technical-reference/reference-oracle/deviation-bounded-oracle) tracks a `(minPrice, maxPrice)` pair representing the lowest and highest spot prices observed inside a short rolling window (target: \~15 minutes). It is maintained from two sources:

* **User-triggered, expansion only.** Every relevant price read pulls spot from the [Resilient Oracle](/risk/resilient-price-oracle). If spot is below `minPrice` it is pulled down to spot; if above `maxPrice`, pushed up. User activity can only widen the window — never contract it.
* **Keeper-triggered, bidirectional.** An off-chain keeper maintains the true rolling window and pushes corrected `minPrice` / `maxPrice` values on-chain. The keeper queries `checkAndGetWindowDrift` to identify assets whose stored bounds have drifted past the 5% `KEEPER_DEADBAND` and only pushes those, to avoid wasting gas on no-op corrections. This is what brings the window back inwards once an extreme has aged out.

Keeper writes are validated on-chain to prevent inverted or implausible windows: a `newMin` must be `≤ spot` and `≤ maxPrice`, and a `newMax` must be `≥ spot` and `≥ minPrice`. The deadband itself is *not* enforced on-chain — it is purely a keeper-side push decision. Keeper liveness is a hard dependency for window correctness.

#### Trigger

Protection activates as a side-effect of a price read when the spot crosses the deviation threshold relative to the stored bounds:

* **Pump:** `spot > minPrice × (1 + triggerThreshold)` — spot is significantly above the recent low.
* **Crash:** `spot < maxPrice × (1 − triggerThreshold)` — spot is significantly below the recent high.

The trigger threshold is set per asset by governance, sits between 5% and 50% (the lower bound keeps routine keeper corrections from accidentally firing it), and is informed by the asset's collateral factor. The cooldown timer is re-stamped only when spot makes a *new* extreme (a new window low or high) while the trigger is sustained; recovery within the existing window keeps the cooldown ticking, so exit remains reachable once the price stabilises.

#### Exit

Protection cannot turn itself off. Exit is gated by two conditions, both of which must hold:

1. **Cooldown elapsed** since the most recent trigger.
2. **Window converged**: `(maxPrice − minPrice) / minPrice < resetThreshold`, where `resetThreshold` is configured below `triggerThreshold`.

When both conditions are satisfied, the off-chain monitor / keeper calls `exitProtectionMode(asset)` (or includes an `ExitProtectionMode` item inside `syncPriceBoundsAndProtections`) to clear the flag. Governance retains a fallback path.

#### Per-Asset Whitelist and Configuration

Protection Mode is opt-in per asset. Governance enables it by calling `setTokenConfig` (or the batch variant) on the DeviationBoundedOracle, which:

* Initializes the rolling window from the current spot.
* Stores the per-asset `cooldownPeriod`, `triggerThreshold`, and `resetThreshold`.
* Sets the bounded-pricing whitelist flag from the `enableBoundedPricing` argument — when `true` the asset participates in the Comptroller's bounded borrow-power path; when `false` the asset is initialized but the DBO short-circuits to spot until governance flips the flag with `setAssetBoundedPricingEnabled`.
* Sets the per-asset transient-cache flag from the `enableCaching` argument (configurable later via `setCachingEnabled`).

VAI is hard-rejected at config time and can never be whitelisted. For all other assets, whether Protection Mode is enabled is a governance decision driven by each asset's liquidity profile and manipulation surface; it can be toggled later with `setAssetBoundedPricingEnabled` (it cannot be turned off while protection is active).

### Where Protection Mode Applies

| Operation                                 | Price Used When Protected | Price Used Otherwise |
| ----------------------------------------- | ------------------------- | -------------------- |
| Borrow-power evaluation (collateral side) | `min(spot, windowMin)`    | spot                 |
| Borrow-power evaluation (debt side)       | `max(spot, windowMax)`    | spot                 |
| Liquidation eligibility                   | spot                      | spot                 |
| Liquidation seize amount                  | spot                      | spot                 |

The Comptroller routes borrow-power price fetches through the DeviationBoundedOracle; the liquidation path is unchanged and continues to call the Resilient Oracle directly. Non-whitelisted markets always use spot.

### Effect on Existing Positions

Three consequences follow directly from the design and are worth stating explicitly:

1. **Liquidations are unaffected.** Eligibility and seize-amount calculations continue to use the Resilient Oracle's spot price exactly as today — no code path change, and liquidator incentives stay identical.
2. **Existing positions are not retroactively endangered.** Because liquidation eligibility is evaluated at spot, switching an asset into Protection Mode does not, by itself, push any user closer to liquidation. Bounded prices apply only to the borrow-power check, so an active position keeps its existing health factor at spot. What Protection Mode restricts is **new borrow capacity** — additional borrows and collateral withdrawals are evaluated against the conservative bounded prices, reducing the headroom for new actions until protection clears.
3. **Keeper failure or misbehavior cannot threaten existing positions either.** The keeper's on-chain write constraints are limited to `newMin ≤ spot ∧ newMin ≤ maxPrice` and `newMax ≥ spot ∧ newMax ≥ minPrice` — they prevent inverted windows but do not stop a keeper from pushing the window toward an extreme. So in principle a faulty or adversarial keeper could push the window toward an extreme, either triggering Protection Mode unnecessarily or keeping it active longer than warranted. In either case the worst-case effect is still confined to the borrow-power path — it can over-tighten the bounded prices and **block new borrows or collateral withdrawals**, but it cannot trigger a liquidation, change a seize amount, or otherwise alter an open position. Keeper risk is bounded to denial of new capacity, never harm to existing exposure.

### Roles

* **DeviationBoundedOracle** — stores the per-asset window and protection state, performs the trigger check on every read, returns the bounded or spot price as appropriate. Wraps the Resilient Oracle, never replaces it.
* **Resilient Oracle** — the canonical spot-price source, untouched by Protection Mode and read by the DeviationBoundedOracle.
* **Keeper** — off-chain service that maintains the true rolling window, pushes `minPrice` / `maxPrice` corrections, and submits exit transactions when conditions are met.
* **Off-chain monitor** — observes protection activations and confirms price normalization before any keeper-driven exit.
* **Governance** — whitelists assets, configures thresholds and cooldowns, and acts as a fallback for disabling protection if the keeper path is unavailable.

### Frontend Indication

When Protection Mode is active for a market, the Venus interface surfaces a protection icon next to the affected asset in the dashboard, market list, and asset pages.

### Further Reading

* [DeviationBoundedOracle contract reference](/technical-reference/reference-oracle/deviation-bounded-oracle)
* [Resilient Price Oracle](/risk/resilient-price-oracle) — the spot-price source Protection Mode wraps
* [Repository](https://github.com/VenusProtocol/oracle)


# Interest Rate Model

### Overview

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.

#### **Jump Rate Model**

The Jump Rate Model uses the following formulas to calculate the interest:

For Borrow rate:

$$
borrow\_rate (u) = b + a\_1 \cdot kink + a\_1 \cdot \min(0, u-kink) + a\_2 \cdot \max(0,u-kink)
$$

And, for Supply rate:

$$
supply\_rate(u) = borrow\_rate(u) \cdot us \cdot (1 - reserve\_factor)
$$

Where,

$$
us = \frac{borrows}{cash + borrows - reserves + badDebt}
$$

The borrow rate employs different formulas when the utilization rate falls into two distinct ranges:

If `u < kink`:

$$
borrow\_rate(u) = a\_1 \cdot u + b
$$

If `u > kink`:

$$
borrow\_rate(u) = a\_1 \cdot kink + a\_2 \cdot (u-kink) + b
$$

**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:

$$
utilization\_rate = \frac{(borrows + bad\_debt)}{(cash + borrows + bad\_debt - reserves)}
$$

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.

#### Whitepaper Rate Model

The Whitepaper Rate Model is simpler, where the borrow rate depends linearly on the utilization:

For Borrow rate:

$$
borrow\_rate (u) = a \cdot u + b
$$

For Supply rate:

$$
supply\_rate(u) = borrow\_rate(u) \cdot us \cdot (1 - reserve\_factor)
$$

Where,

$$
us = \frac{borrows}{cash + borrows - reserves + badDebt}
$$


# Risk Fund and Shortfall Handling

### **Overview**

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](/governance/tokenomics) of the project. The risk fund also covers bad debt in case of bankruptcy without a liquidator.

### Risk fund

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.

### Shortfall

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
* `incentiveBps` - Incentive to auction participants. Initial value set to 1000 bps or 10%

{% hint style="info" %}
**Availability**:

* `Shortfall` contract will be used only for the markets in the Isolated Pools.
* The markets in the Core pool don't track the bad debt at the moment, so it cannot be reduced automatically.
* The funds generated in the Core pool, that should be allocated to the risk fund, are temporarily sent to the [Venus Treasury](https://bscscan.com/address/0xf322942f644a996a617bd29c16bd7d231d9f35e9) contract. With the relase of the [Automatic income allocation](/whats-new/automatic-income-allocation) feature, this income will be sent to the `ProtocolShareReserve` contract, where there will be distributed following the [tokenomics](/governance/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.
  {% endhint %}


# Risk Management

### Introduction

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.

### Multiple Audits Before Deployment

* 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.](https://docs-v4.venus.io/links/security-and-audits)

### Continuous On-Chain Monitoring

* 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](https://community.chaoslabs.xyz/venus/risk/overview).

### Real-Time Alert System

* 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](https://community.chaoslabs.xyz/venus/risk/alerts).

### Dynamic Risk Management

* 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.

### Frontend

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 [Chainalysis](https://www.chainalysis.com) 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.

### Conclusion

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.


# Risk Oracle & Risk Stewards

## Overview

Venus Protocol uses a **Risk Oracle** and a set of **Risk Stewards** to keep risk parameters aligned with real-time market conditions while preserving decentralized governance. Previously, every risk-parameter change went through the same full VIP process, no matter how routine. The framework now lets governance-approved risk managers apply pre-authorized adjustments through a secure, automated on-chain pipeline, but no risk provider is ever given open-ended authority: each change is first proposed openly in the Venus community, and can only move a parameter within limits the DAO has set. Routine moves within a governance-set **safe delta** apply automatically within minutes; anything larger is held for a cooldown period and released only by a whitelisted Venus executor (who can also reject it), while the most sensitive changes still require a full VIP. Governance sets every limit, approves who may publish and who may execute, and can pause the system at any time.

The framework currently automates four parameter types: **supply caps**, **borrow caps**, **collateral factors** (with their liquidation thresholds), and **interest rate models**, across all supported Venus chains. BNB Chain acts as the source chain, and updates targeting other chains are propagated via LayerZero. Every recommendation and execution is recorded on the Risk Oracle, so anyone can inspect a proposed change on-chain, before and after it takes effect.

## How the System Fits Together

<figure><img src="/files/ivDFoxbpvP3yRSWi2Ju0" alt="Risk Stewards architecture: whitelisted providers publish to the Venus Risk Oracle on BNB Chain; the RiskStewardReceiver applies updates locally or forwards them over LayerZero to a Destination Steward Receiver on other chains; governance configures and gates everything"><figcaption><p>Whitelisted providers publish to the Risk Oracle on BNB Chain; the Risk Steward Receiver applies updates locally or bridges them to other chains. Governance configures and gates the whole pipeline.</p></figcaption></figure>

The pipeline has four parts:

* **Risk Oracle** (BNB Chain): where whitelisted providers publish recommendations.
* **Risk Steward Receiver** (BNB Chain, the source chain): validates each recommendation, decides how it should be applied, executes local changes, and forwards cross-chain ones via LayerZero.
* **Destination Steward Receiver** (every other supported chain): receives bridged updates, holds them for a short delay, and lets a Venus executor apply them.
* **Risk Stewards** (Market Caps, Collateral Factors, IRM): deployed on each chain to perform the actual change in the relevant Comptroller or vToken.

The contract-level detail lives in the [Risk Stewards technical article](/technical-reference/reference-technical-articles/risk-stewards).

## Risk Oracle

The **Risk Oracle** is Venus Protocol's own on-chain contract and the single source of truth for risk-parameter recommendations. It is owned and controlled by Venus governance, not by any third party.

Whitelisted **risk parameter providers** publish recommendations to it. A provider can be an external risk manager such as Chaos Labs or Allez Labs, or Venus's own risk team. Providers are added or removed only through governance (via the `AccessControlManager`), so the set of authorized senders is fully under DAO control. Each recommendation records the target market, the parameter type, the new value, the destination chain, and a reference ID (typically a link to a Venus community post explaining the change).

## Risk Stewards

A **Risk Steward** is an on-chain contract that applies one family of risk-parameter changes on behalf of the protocol, strictly within bounds set by governance:

| Risk Steward                        | Parameters it can change                      |
| ----------------------------------- | --------------------------------------------- |
| **Market Caps Risk Steward**        | Supply caps, borrow caps                      |
| **Collateral Factors Risk Steward** | Collateral factors and liquidation thresholds |
| **IRM Risk Steward**                | Interest rate model contract for a market     |

Each steward applies only validated updates routed to it, enforces a **safe delta** (changes within a governance-set percentage of the current value can execute immediately; larger ones require a timelock and executor approval), and cannot touch any parameter outside its mandate.

## How Updates Are Applied

Anyone can trigger processing of a published recommendation; the entry point is permissionless. Before anything happens, the recommendation is validated against governance's configuration: the update type must be active, it must be the latest for that market and type, it must not have expired, and a debounce window since the last change must have passed. From there it follows one of two paths.

### On BNB Chain (local updates)

<figure><img src="/files/RTYwMbCJNMxwkU6LoEbt" alt="Local update flow: a provider publishes to the Risk Oracle, anyone triggers processing on the Risk Steward Receiver, and the change either applies immediately when within the safe delta or is registered behind a timelock for a whitelisted executor to apply"><figcaption><p>A BNB Chain update applies immediately when it is within the safe delta; otherwise it waits through a timelock and is applied (or rejected) by a whitelisted executor.</p></figcaption></figure>

If the change is within the steward's safe delta, it is applied immediately. If it exceeds the safe delta it is registered behind a timelock; after the delay a whitelisted Venus executor applies it, or rejects it. Interest rate model updates and eMode collateral-factor updates always take the timelocked path, regardless of size.

### On Other Chains (remote updates)

<figure><img src="/files/z62cuOdoxTdFFo1GSYFJ" alt="Remote update flow: a provider publishes on BNB Chain, the Risk Steward Receiver forwards the update over LayerZero to the Destination Steward Receiver on the target chain, which holds it for a remote delay before a whitelisted executor applies it through the local steward"><figcaption><p>An update targeting another chain is forwarded over LayerZero, held for a remote delay on the destination chain, then applied by a whitelisted executor there.</p></figcaption></figure>

When a recommendation targets a market on another chain, the Risk Steward Receiver forwards it over LayerZero to that chain's Destination Steward Receiver, where it is held for a remote delay and then applied by a whitelisted executor on the destination chain. Cross-chain updates therefore always pass through a delay and an executor.

## Roles and Permissions

| Role                                   | Can do                                                                                                                            | Set by                     |
| -------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------- | -------------------------- |
| **Risk parameter providers**           | Publish recommendations to the Risk Oracle; trigger processing of their own updates                                               | Governance (ACM whitelist) |
| **Anyone**                             | Trigger processing of a published recommendation                                                                                  | Permissionless             |
| **Whitelisted executors (Venus team)** | Apply timelocked and cross-chain updates after their delay; reject updates                                                        | Governance (ACM whitelist) |
| **Governance / ACM**                   | Configure debounce, timelock, safe-delta bounds, and supported update types; add/remove providers and executors; pause processing | DAO (VIP)                  |

## Safeguards and Governance Control

This system does **not** bypass governance; it operates entirely within constraints the DAO approves:

* **Bounded changes**: stewards can only move the four supported parameters, and only within the safe-delta / timelock rules set by governance.
* **Frequency limits**: a debounce period prevents rapid repeated changes to the same market and parameter.
* **Timelock + veto**: larger changes, IRM changes, and eMode collateral-factor changes wait through a timelock during which a Venus executor can reject them.
* **Expiration & replay protection**: updates expire if not executed in time and can never be processed twice.
* **Pause**: governance can pause update processing at any time.
* **Reserved for governance**: high-impact parameters outside the four supported types still require a full VIP.

The framework was enabled on BNB Chain in [VIP-592](https://app.venus.io/#/governance/proposal/592?chainId=56), which also onboarded Allez Labs as the first external risk provider. At launch, governance set a 3-day debounce, a 6-hour timelock, a 50% safe delta for market caps, and a 10% safe delta for collateral factors. These values are set by governance and can be adjusted through it.

## What's Next

The framework starts with supply caps, borrow caps, collateral factors, and interest rate models across supported chains. Additional parameters and refinements may be added over time, always subject to DAO approval and governance-defined constraints.

## Learn More

* [Risk Stewards technical article](/technical-reference/reference-technical-articles/risk-stewards)
* [Proposed Risk Stewards Framework for More Efficient Risk Management](https://community.venus.io/t/proposed-risk-stewards-framework-for-more-efficient-risk-management/5606)
* [VIP-592: Risk Stewards Framework Implementation](https://app.venus.io/#/governance/proposal/592?chainId=56)


# XVS

### Overview

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.

### Next Steps and Future of XVS

The [Venus Prime](/whats-new/prime-yield) program adds a new dimension to the utility of XVS tokens. As Venus Protocol continues to innovate:

* Venus Prime provides opportunities for additional yield to committed users, using the protocol's revenue instead of just relying on the token supply.
* Eligibility is driven by a time-weighted leaderboard that rewards both the size and the age of a user's XVS stake, granting a unique, non-transferable Soulbound token to qualifying participants.

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.


# VAI

### Overview

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.

### Stability Fee and Optimised Minting

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:

$$
\text{{stabilityFee}}(%) = \text{{baseRate}}(%) + \max(0, (1 - \text{{currentPriceOfVAI}})) \times \text{{floatingRate}}(%)
$$

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.


# VAIController

## VAI Comptroller

This is the implementation contract for the VAIUnitroller proxy

## Solidity API

#### INITIAL\_VAI\_MINT\_INDEX

Initial index used in interest computations

```solidity
uint256 INITIAL_VAI_MINT_INDEX
```

***

#### CORE\_POOL\_ID

poolId for core Pool

```solidity
uint96 CORE_POOL_ID
```

***

#### mintVAI

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.

```solidity
function mintVAI(uint256 mintVAIAmount) external returns (uint256)
```

**Parameters**

| Name          | Type    | Description                         |
| ------------- | ------- | ----------------------------------- |
| mintVAIAmount | uint256 | The amount of the VAI to be minted. |

**Return Values**

| Name | Type    | Description                           |
| ---- | ------- | ------------------------------------- |
| \[0] | uint256 | 0 on success, otherwise an error code |

***

#### repayVAI

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.

```solidity
function repayVAI(uint256 amount) external returns (uint256, uint256)
```

**Parameters**

| Name   | Type    | Description                     |
| ------ | ------- | ------------------------------- |
| amount | uint256 | The amount of VAI to be repaid. |

**Return Values**

| Name | Type    | Description                                                        |
| ---- | ------- | ------------------------------------------------------------------ |
| \[0] | uint256 | Error code (0=success, otherwise a failure, see ErrorReporter.sol) |
| \[1] | uint256 | Actual repayment amount                                            |

***

#### repayVAIBehalf

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.

```solidity
function repayVAIBehalf(address borrower, uint256 amount) external returns (uint256, uint256)
```

**Parameters**

| Name     | Type    | Description                        |
| -------- | ------- | ---------------------------------- |
| borrower | address | The account to repay the debt for. |
| amount   | uint256 | The amount of VAI to be repaid.    |

**Return Values**

| Name | Type    | Description                                                        |
| ---- | ------- | ------------------------------------------------------------------ |
| \[0] | uint256 | Error code (0=success, otherwise a failure, see ErrorReporter.sol) |
| \[1] | uint256 | Actual repayment amount                                            |

***

#### liquidateVAI

The sender liquidates the vai minters collateral. The collateral seized is transferred to the liquidator.

```solidity
function liquidateVAI(address borrower, uint256 repayAmount, contract VTokenInterface vTokenCollateral) external returns (uint256, uint256)
```

**Parameters**

| Name             | Type                     | Description                                               |
| ---------------- | ------------------------ | --------------------------------------------------------- |
| 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 |

**Return Values**

| Name | Type    | Description                                                        |
| ---- | ------- | ------------------------------------------------------------------ |
| \[0] | uint256 | Error code (0=success, otherwise a failure, see ErrorReporter.sol) |
| \[1] | uint256 | Actual repayment amount                                            |

***

#### \_setComptroller

Sets a new comptroller

```solidity
function _setComptroller(contract ComptrollerInterface comptroller_) external returns (uint256)
```

**Return Values**

| Name | Type    | Description                                                                |
| ---- | ------- | -------------------------------------------------------------------------- |
| \[0] | uint256 | uint256 0=success, otherwise a failure (see ErrorReporter.sol for details) |

***

#### setPrimeToken

Set the prime token contract address

```solidity
function setPrimeToken(address prime_) external
```

**Parameters**

| Name    | Type    | Description                                 |
| ------- | ------- | ------------------------------------------- |
| prime\_ | address | The new address of the prime token contract |

***

#### setVAIToken

Set the VAI token contract address

```solidity
function setVAIToken(address vai_) external
```

**Parameters**

| Name  | Type    | Description                               |
| ----- | ------- | ----------------------------------------- |
| vai\_ | address | The new address of the VAI token contract |

***

#### toggleOnlyPrimeHolderMint

Toggle mint only for prime holder

```solidity
function toggleOnlyPrimeHolderMint() external returns (uint256)
```

**Return Values**

| Name | Type    | Description                                                                |
| ---- | ------- | -------------------------------------------------------------------------- |
| \[0] | uint256 | uint256 0=success, otherwise a failure (see ErrorReporter.sol for details) |

***

```solidity
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;
}
```

#### getMintableVAI

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

```solidity
function getMintableVAI(address minter) public view returns (uint256, uint256)
```

**Parameters**

| Name   | Type    | Description                       |
| ------ | ------- | --------------------------------- |
| minter | address | The account to check mintable VAI |

**Return Values**

| Name | Type    | Description                                                                    |
| ---- | ------- | ------------------------------------------------------------------------------ |
| \[0] | uint256 | Error code (0=success, otherwise a failure, see ErrorReporter.sol for details) |
| \[1] | uint256 | Mintable amount (with 18 decimals)                                             |

***

#### \_setTreasuryData

Update treasury data

```solidity
function _setTreasuryData(address newTreasuryGuardian, address newTreasuryAddress, uint256 newTreasuryPercent) external returns (uint256)
```

**Parameters**

| Name                | Type    | Description                                                     |
| ------------------- | ------- | --------------------------------------------------------------- |
| 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 |

***

#### getVAIRepayRate

Gets yearly VAI interest rate based on the VAI price

```solidity
function getVAIRepayRate() public view returns (uint256)
```

**Return Values**

| Name | Type    | Description                      |
| ---- | ------- | -------------------------------- |
| \[0] | uint256 | uint256 Yearly VAI interest rate |

***

#### getVAIRepayRatePerBlock

Get interest rate per block

```solidity
function getVAIRepayRatePerBlock() public view returns (uint256)
```

**Return Values**

| Name | Type    | Description                    |
| ---- | ------- | ------------------------------ |
| \[0] | uint256 | uint256 Interest rate per bock |

***

#### getVAIMinterInterestIndex

Get the last updated interest index for a VAI Minter

```solidity
function getVAIMinterInterestIndex(address minter) public view returns (uint256)
```

**Parameters**

| Name   | Type    | Description           |
| ------ | ------- | --------------------- |
| minter | address | Address of VAI minter |

**Return Values**

| Name | Type    | Description                                          |
| ---- | ------- | ---------------------------------------------------- |
| \[0] | uint256 | uint256 Returns the interest rate index for a minter |

***

#### getVAIRepayAmount

Get the current total VAI a user needs to repay

```solidity
function getVAIRepayAmount(address account) public view returns (uint256)
```

**Parameters**

| Name    | Type    | Description                     |
| ------- | ------- | ------------------------------- |
| account | address | The address of the VAI borrower |

**Return Values**

| Name | Type    | Description                                               |
| ---- | ------- | --------------------------------------------------------- |
| \[0] | uint256 | (uint256) The total amount of VAI the user needs to repay |

***

#### getVAICalculateRepayAmount

Calculate how much VAI the user needs to repay

```solidity
function getVAICalculateRepayAmount(address borrower, uint256 repayAmount) public view returns (uint256, uint256, uint256)
```

**Parameters**

| Name        | Type    | Description                      |
| ----------- | ------- | -------------------------------- |
| borrower    | address | The address of the VAI borrower  |
| repayAmount | uint256 | The amount of VAI being returned |

**Return Values**

| Name | Type    | Description                                             |
| ---- | ------- | ------------------------------------------------------- |
| \[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    |

***

#### accrueVAIInterest

Accrue interest on outstanding minted VAI

```solidity
function accrueVAIInterest() public
```

***

#### setAccessControl

Sets the address of the access control of this contract

```solidity
function setAccessControl(address newAccessControlAddress) external
```

**Parameters**

| Name                    | Type    | Description                        |
| ----------------------- | ------- | ---------------------------------- |
| newAccessControlAddress | address | New address for the access control |

***

#### setBaseRate

Set VAI borrow base rate

```solidity
function setBaseRate(uint256 newBaseRateMantissa) external
```

**Parameters**

| Name                | Type    | Description                          |
| ------------------- | ------- | ------------------------------------ |
| newBaseRateMantissa | uint256 | the base rate multiplied by 10\*\*18 |

***

#### setFloatRate

Set VAI borrow float rate

```solidity
function setFloatRate(uint256 newFloatRateMantissa) external
```

**Parameters**

| Name                 | Type    | Description                               |
| -------------------- | ------- | ----------------------------------------- |
| newFloatRateMantissa | uint256 | the VAI float rate multiplied by 10\*\*18 |

***

#### setReceiver

Set VAI stability fee receiver address

```solidity
function setReceiver(address newReceiver) external
```

**Parameters**

| Name        | Type    | Description                         |
| ----------- | ------- | ----------------------------------- |
| newReceiver | address | the address of the VAI fee receiver |

***

#### setMintCap

Set VAI mint cap

```solidity
function setMintCap(uint256 _mintCap) external
```

**Parameters**

| Name      | Type    | Description                          |
| --------- | ------- | ------------------------------------ |
| \_mintCap | uint256 | the amount of VAI that can be minted |

***

#### getVAIAddress

Return the address of the VAI token

```solidity
function getVAIAddress() public view virtual returns (address)
```

**Return Values**

| Name | Type    | Description        |
| ---- | ------- | ------------------ |
| \[0] | address | The address of VAI |

***


# VAIUnitroller

## VAI Unitroller

This is the proxy contract for the VAIComptroller

## Solidity API

#### \_setPendingImplementation

* Admin Functions \*\*

```solidity
function _setPendingImplementation(address newPendingImplementation) public returns (uint256)
```

***

#### \_acceptImplementation

Accepts new implementation of comptroller. msg.sender must be pendingImplementation

```solidity
function _acceptImplementation() public returns (uint256)
```

**Return Values**

| Name | Type    | Description                                                             |
| ---- | ------- | ----------------------------------------------------------------------- |
| \[0] | uint256 | uint 0=success, otherwise a failure (see ErrorReporter.sol for details) |

***

#### \_setPendingAdmin

Begins transfer of admin rights. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer.

```solidity
function _setPendingAdmin(address newPendingAdmin) public returns (uint256)
```

**Parameters**

| Name            | Type    | Description        |
| --------------- | ------- | ------------------ |
| newPendingAdmin | address | New pending admin. |

**Return Values**

| Name | Type    | Description                                                             |
| ---- | ------- | ----------------------------------------------------------------------- |
| \[0] | uint256 | uint 0=success, otherwise a failure (see ErrorReporter.sol for details) |

***

#### \_acceptAdmin

Accepts transfer of admin rights. msg.sender must be pendingAdmin

```solidity
function _acceptAdmin() public returns (uint256)
```

**Return Values**

| Name | Type    | Description                                                             |
| ---- | ------- | ----------------------------------------------------------------------- |
| \[0] | uint256 | uint 0=success, otherwise a failure (see ErrorReporter.sol for details) |

***


# Venus interface

Let's take a quick look at the Venus interface and the features available in each menu of the navigation bar.

### Dashboard

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.

<figure><img src="/files/aJHuZJj6MiJeKUXKqaVA" alt=""><figcaption></figcaption></figure>

### Account

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.

<figure><img src="/files/RU0apAhiQp9E9r33spYd" alt=""><figcaption></figcaption></figure>

### Core Pool

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.

<figure><img src="/files/gXsBgaSPNqtVTshIllP9" alt=""><figcaption></figcaption></figure>

### Pools

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.

<figure><img src="/files/LJwHGbKWKXHCEQTt1kZ2" alt=""><figcaption></figcaption></figure>

### Vaults

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.

<figure><img src="/files/vL3B2gXC34DsxOBeMj4l" alt=""><figcaption></figcaption></figure>

### Swap

The Swap interface enables you to swap one cryptocurrency for another within the Venus Protocol. You can exchange your assets conveniently and quickly.

<figure><img src="/files/cHpn4hpEXT0qu31bEhLK" alt=""><figcaption></figcaption></figure>

### History

In the History interface, you can review transaction history and track your previous activities on the Protocol.

<figure><img src="/files/mbGJjOI8jekTG8z4jPBC" alt=""><figcaption></figcaption></figure>

### Governance

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.

<figure><img src="/files/CL01yW4BTZ48HOkke9t5" alt=""><figcaption></figcaption></figure>

### XVS

The XVS interface displays the current daily reward distribution rate for each of the protocol markets.

<figure><img src="/files/xxApRkWIWjrHKVJFgfpj" alt=""><figcaption></figcaption></figure>

### VAI

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.

<figure><img src="/files/1SHHDftdMtFnHKCmeJFb" alt=""><figcaption></figcaption></figure>


# Supplying and borrowing

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 [Venus Protocol’s whitepaper](https://github.com/VenusProtocol/venus-protocol-documentation/blob/main/whitepapers/Venus-whitepaper-v4.pdf).

Once you’ve created your Web3 wallet on [MetaMask](https://metamask.io) or any other supported wallet App, open the Venus app (<https://app.venus.io>). 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.

## Supply Assets to Earn Interest

1. Connect your Web3 wallet on MetaMask or other supported wallet app to the Venus app (<https://app.venus.io>).
2. 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.
3. 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.
4. 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.

Each market has a **supply cap** — the maximum total amount of that asset the protocol will accept as supply, set by governance to limit risk concentration; once it is reached, no further supply of that asset is possible until the cap is raised.

## Manage your Borrowing Limit

Your borrowing limit on Venus Protocol is a function of the assets you have supplied. The following steps guide you to manage it:

1. Navigate to the "Account" section.
2. Here, you'll find your Borrow Limit on each pool, represented as a percentage of the total value of your supplied assets.
3. To adjust this limit, you can either supply more assets or repay some of your outstanding loans.

## Borrow Assets on Venus Protocol

After supplying assets, you can borrow other assets within your borrowing limit:

1. From the "Dashboard" menu, select the asset you want to borrow.
2. Input the amount you wish to borrow and confirm the transaction.

## Farm $XVS tokens

In addition to earning interest on supplied assets, you can also farm $XVS tokens:

1. In the "Vaults" section, you can stake your XVS or VAI tokens to earn XVS tokens.
2. Click on 'Stake'. You will be prompted to confirm the transaction in your wallet.

## Lending and Borrowing Example

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.

## WETH

ETH is the native token for the Ethereum blockchain, used to pay gas fees, for example. WETH is an [ERC-20](https://ethereum.org/developers/docs/standards/tokens/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](https://coinmarketcap.com/currencies/weth/))).

An easy way to get WETH from ETH is by using Uniswap. For example, on the Ethereum mainnet, the process would be:

1. Go to the [Uniswap page to wrap ETH on Ethereum](https://app.uniswap.org/swap?chain=mainnet\&inputCurrency=ETH\&outputCurrency=0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2).
2. Connect your wallet.
3. Type the amount of ETH you want to wrap.
4. Click on `Wrap`.
5. Review and accept the transaction in your Web3 wallet.
6. Remember to add the WETH token to your Web3 wallet to see your WETH balance.

<figure><img src="/files/OzRZv8lRbCEljUXEZ2xE" alt="Wrap ETH at Uniswap" width="75%"><figcaption><p>Wrap ETH at Uniswap</p></figcaption></figure>

To unwrap WETH tokens (getting ETH), you can also use [Uniswap](https://app.uniswap.org/swap?chain=mainnet\&inputCurrency=0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2\&outputCurrency=ETH), switching the input and output currencies.

<figure><img src="/files/1OFFLKeevTIPmcBaQcMK" alt="Unwrap ETH at Uniswap" width="75%"><figcaption><p>Unwrap ETH at Uniswap</p></figcaption></figure>


# Liquidations

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.

## Account Liquidity Calculations

Venus Protocol uses two calculations to determine account liquidity: Collateral Factor (CF) and Liquidation Threshold (LT).

### Collateral Factor (CF)

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.

### Liquidation Threshold (LT)

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.

{% hint style="info" %}
**Iterating over all accounts and checking the CF and LT for every account is extremely inefficient.**

Instead, liquidators should rely on off-chain computations and maintain an off-chain mapping for accounts and balances. Using functions like `vTokenBalancesAll` and `vTokenUnderlyingPriceAll` from PoolLens can help retrieve balances and prices efficiently for multiple vTokens associated with an account.
{% endhint %}

By combining the information obtained from these functions, one can accurately identify under-collateralized accounts that are suitable for liquidation.

### Minimum Liquidatable Collateral

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).

## Finding Under-Collateralized Accounts

The first step to performing a liquidation is to identify under-collateralized accounts. Here's a suggested approach to finding under-collateralized accounts:

1. 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.
   * `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.

Consider using a subgraph to index these events.

2. 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.
3. 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.
4. 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.

{% hint style="warning" %}
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.
{% endhint %}

## Performing the Liquidation

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:

{% hint style="warning" %}
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.
{% endhint %}

1. 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.
2. 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.

{% hint style="info" %}
**Example**

Given:

* Collateral Factor: 50%
* Close Factor: 50%
* 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.
{% endhint %}

* **Collateral < minLiquidatableCollateral && account is solvent -->** `liquidateAccount()`: this function liquidates all borrows of the borrower.

{% hint style="info" %}
**Example**

* Collateral Factor: 50%
* Liquidation Threshold: 60%
* Min Liquidatable Collateral: $100
* 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**.
{% endhint %}

* **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)`

{% hint style="info" %}
**Example**

* Collateral Factor: 50%
* Liquidation Threshold: 60%
* Min Liquidatable Collateral: $100
* 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.
{% endhint %}

3. 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.

{% hint style="warning" %}
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.
{% endhint %}

## Forced liquidations

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 [here](https://github.com/compound-finance/compound-protocol/pull/123/files). 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 [this post](https://www.comp.xyz/t/deprecate-fei-market/3513).

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.

{% hint style="info" %}
**Availability**: Forced Liquidations for entire markets are available in the Core pool since [VIP-172](https://app.venus.io/#/governance/proposal/172), in the Isolated pools since [VIP-186](https://app.venus.io/#/governance/proposal/186). Forced Liquidations for individual accounts are available only in the Core pool since [VIP-210](https://app.venus.io/#/governance/proposal/210).
{% endhint %}

{% hint style="info" %}

#### Example

Given:

* `vUSDT` collateral factor: 80%
* 1 USDT = 1 BUSD = 1 USDC = $1 (for simplicity)
* 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).
  {% endhint %}

## Force VAI Debt First

{% hint style="danger" %}
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.
{% endhint %}

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.

#### Checks

1. Check that VAI liquidations are not paused in Comptroller.
2. The forceVAILiquidate flag is set to true.
3. Verify whether the borrower's VAI debt is greater than the minimum amount of liquidatable VAI (initially 1,000 VAI).

{% hint style="warning" %}
If the above conditions are true then the protocol checks that the current vToken sent to be liquidated is VAI, otherwise the liquidation fails.
{% endhint %}

{% hint style="info" %}
**Example 1**

Given:

* this feature is enabled
* a user is eligible to be liquidated with the following debt:
  * 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.
{% endhint %}

{% hint style="info" %}
**Example 2**

Given:

* this feature is enabled
* a user eligible to be liquidated with the following debts:
  * 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`
{% endhint %}

## Automatic Income Allocation

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.

### Distributing Seized Amount

The seized collateral is distributed between the Liquidator and the `ProtocolShareReserve` contract:

1. **Liquidator's Share:**
   * The Liquidator receives a designated portion of the collateral as an incentive.
2. **`ProtocolShareReserve` contract's Share:**
   * The remaining portion of the collateral is sent to the `ProtocolShareReserve` contract.
3. **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.

### Redemption Handling

The Liquidator contract attempts to redeem the protocol's portion of the liquidation incentive in underlying tokens for the VTokens:

1. **Successful Redemption:**
   * If the redemption is successful, the underlying tokens are sent to the `ProtocolShareReserve` contract.
2. **Failed Redemption:**
   * If the redemption fails due to insufficient liquidity or other reasons, the VTokens representing the pending redemption are added to a list for later processing.

### Pending Redemption Management

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.


# Governance


# Submitting a VIP

### Overview

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.

{% hint style="info" %}
Remember, you need a voting weight of at least 300,000 to submit a proposal.
{% endhint %}

### Step 1: Visit the Venus Governance Portal

Navigate to the Venus Governance Portal using your preferred web browser. You can access the portal at <https://app.venus.io/governance>.

### Step 2: Connect Your Wallet

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.

### Step 3: Create a Proposal

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.

<figure><img src="/files/L8TFLQakc78ltn7UTUsU" alt=""><figcaption></figcaption></figure>

This action will open a modal presenting two options - "Upload file" and "Create Manually":

<figure><img src="/files/JpWrLngfn43Egov2Beqs" alt=""><figcaption></figcaption></figure>

### Step 4: Upload a proposal file

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 [here](https://github.com/VenusProtocol/vips#create-proposal). You can also check an example of a valid proposal file [here](https://github.com/VenusProtocol/venus-protocol-interface/blob/main/src/assets/proposals/vip-123.json). Note that all the fields will be validated according to their requirements and types.

#### Step 4.1: Choose a VIP file

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.

#### Step 4.2: Confirm the Proposal

Once the import is successfully validated, the interface will present all the VIP data for your review:

<figure><img src="/files/BWB8mLG5nvcWsAXCLQra" alt=""><figcaption></figcaption></figure>

If everything looks good, click "Create" at the bottom of the modal to confirm the creation of your VIP.

### Step 5: Create a Proposal Manually

Proposals can also be created manually by clicking on "Create manually".

#### Step 5.1: Choose the Proposal Type

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.

<figure><img src="/files/TrTjniS6X0VIJeUO3f5Q" alt=""><figcaption></figcaption></figure>

#### Step 5.2: Enter Proposal Information

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.

<figure><img src="/files/zzBkPCGaoKtDbmC3R11K" alt=""><figcaption></figcaption></figure>

#### Step 5.3: Set the Voting Options

The third screen is where you can specify descriptions for the voting options (for, against, abstain).

<figure><img src="/files/OecF8RCjl8bz7WJ5wwrh" alt=""><figcaption></figcaption></figure>

#### Step 5.4: Specify the Actions

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.

<figure><img src="/files/6lIUm5b5vGUXI2Vzm20Z" alt=""><figcaption></figcaption></figure>

#### Step 5.5: Confirm the Proposal Submission

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.

<figure><img src="/files/7zLSAxLWT1iQiSUkeWGx" alt=""><figcaption></figcaption></figure>

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.


# Delegating & Voting

### Overview

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.

### It includes the following components:

**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. Note that since [VIP-645](https://app.venus.io/#/governance/proposal/645?chainId=56) the Critical Timelock holds no permission, so in practice proposals use the Normal or Fast Track roles. 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.\\

### Delegate Voting Power

**Step 1: Visit the Venus Governance Portal**

Access the Venus governance portal via your browser. The URL is <https://app.venus.io/governance>.

**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.

<figure><img src="/files/TJlkkSk56xxUiDEGOWDi" alt=""><figcaption></figcaption></figure>

**Step 4: Enter Your Address**

In the new dialogue box, click on the "Paste your address" field. Your connected wallet address should automatically populate.

<figure><img src="/files/BQMoW05FsnzI5Ey9bLXy" alt=""><figcaption></figcaption></figure>

**Step 5: Redelegate Your Votes**

Click on the "Redelegate" button. This will submit the address for vote delegation.

<figure><img src="/files/SH1O33ZupZjq5MhBydCh" alt=""><figcaption></figcaption></figure>

**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.

### Vote for a VIP

#### Step 7: Select the VIP Proposal

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.***

<figure><img src="/files/Tta0rky8tDckX5Du8Dpa" alt=""><figcaption></figcaption></figure>

#### Step 8: Cast Your Vote

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.

<figure><img src="/files/4tPu4yys85EE8im6X1fZ" alt=""><figcaption></figcaption></figure>

#### Step 9: Add a Comment

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.

<figure><img src="/files/BTOIqzYdia9fYw5U2VAZ" alt=""><figcaption></figcaption></figure>

#### Step 10: Submit Your Vote

Once you've made your decision and optionally left a comment, click the 'Submit Vote' button to cast your vote.

<figure><img src="/files/WWqov6zak7higm0I8XDI" alt=""><figcaption></figcaption></figure>

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.


# Vaults

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**

1. Navigate to the Venus app (app.venus.io) and connect your BNB Chain Wallet or other supported wallet apps.
2. On the left side of the screen, click on the 'Vault' tab.
3. A new screen will display two options: XVS and VAI vaults. Select the 'XVS' vault.
4. Once you select the XVS vault, a new interface will show. Click the 'Stake' button.
5. A pop-up will appear asking for the amount of XVS you want to stake. Input the desired amount and confirm.
6. After entering the amount, a prompt will ask for the transaction's confirmation in your wallet. Confirm this.
7. 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**

1. Follow the same steps as above to access the 'Vault' tab in the Venus app.
2. This time, select the 'VAI' vault.
3. Upon clicking on the 'VAI' vault, you'll see the option to 'Stake'.
4. Enter the amount of VAI you'd like to stake and confirm the staking action.
5. Just like with the XVS vault, you'll need to confirm the transaction in your wallet.
6. After staking, the interface will show the staked amount, potential rewards, and other relevant statistics related to the VAI vault.


# Protocol Math

### Overview

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.

### vToken and Underlying Decimals

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.

{% content-ref url="/pages/BRkHBw517w98geU4WqFA" %}
[Markets](/deployed-contracts/markets)
{% endcontent-ref %}

### Interpreting Exchange Rates

The exchange rate of vTokens is adjusted based on the decimal difference between the vToken and its underlying asset.

$$
oneVTokenInUnderlying = \frac{exchangeRateCurrent}{1 \times 10^{(18 + underlyingDecimals - vTokenDecimals)}}
$$

Here is an example illustrating how to determine the value of one vBUSD in BUSD using the Web3.js JavaScript library.

```javascript
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');
```

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.

$$
underlyingTokens = vTokenAmount \times oneVTokenInUnderlying
$$

### Calculating Accrued Interest

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 [Venus app](https://app.venus.io).

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.

### Calculating the APY Using Rate Per Block

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):

```javascript
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) * 100
```

Here is an example of calculating the supply and borrow APY with Web3.js JavaScript:

```javascript
const 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} %`);
```


# XVS Bridge

### Introduction

This guide provides step-by-step instructions on how to bridge XVS tokens from the BNB Chain to the Ethereum network.

### Steps for Bridging XVS from BNB Chain to Ethereum

#### Step 1: Access the Venus Bridge

* Navigate to the Venus Protocol and select the "Bridge" option from the sidebar menu. [XVS Bridge](https://app.venus.io/#/bridge)

#### Step 2: Connect Your Wallet

* Click on the "Connect wallet" button in the top right corner of the Venus Bridge interface to connect your wallet.

<figure><img src="/files/HmHfUmRll0GFB3zJGjUR" alt=""><figcaption></figcaption></figure>

#### Step 3: Configure the Bridge Transaction

* **From**: Ensure "BNB mainnet" is selected in the "From" dropdown menu.
* **To**: Select "Ethereum" in the "To" dropdown menu to set the destination network.

<figure><img src="/files/EhEn8ayDYKiMp8m8IAmA" alt=""><figcaption></figcaption></figure>

#### Step 4: Enter the Amount to Bridge

* 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.

#### Step 5: Approve XVS Token

* 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.

<figure><img src="/files/Ud2hReqFLgWatUARWQDv" alt=""><figcaption></figcaption></figure>

#### Step 6: Initiate the Transfer

* 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.

#### Step 7: Confirm and Wait

* 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.

#### Step 8: Transaction Completion

* Once the transaction is complete, the XVS tokens will be available in your Ethereum wallet.

### Conclusion

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.


# Borrowing VAI

### Introduction

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.

### Steps for Borrowing VAI

#### Step 1: Access VAI Borrowing UI

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.

#### Step 2: Connect Your Wallet

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.

<figure><img src="/files/iFEioDKTedjb1JDaF0us" alt=""><figcaption></figcaption></figure>

#### Step 3: Enter Borrow Amount

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.

<figure><img src="/files/eyrljANiMerosOOeuXco" alt=""><figcaption></figcaption></figure>

#### Step 4: Review and Confirm Borrowing

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.

### Repaying VAI Debt

#### Step 1: Navigate to Repay Tab

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.

<figure><img src="/files/GKIBKXVWaMt7H1aP8U1S" alt=""><figcaption></figcaption></figure>

#### Step 2: Enter Repayment Amount

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.

#### Step 3: Review and Confirm Repayment

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.

### Conclusion

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.


# Gasless Transactions on zkSync

This guide will walk you through the steps to interact with Venus Protocol on ZKsync without needing ETH to cover gas fees, thanks to the integration of [Zyfi Paymaster](https://www.zyfi.org/). All transactions will be sponsored, so you can focus on using the protocol without worrying about gas expenses.

### Step-by-Step Guide

#### Step 1: Connect to ZKsync on Venus

1. Open the [Venus app](https://app.venus.io) and connect your wallet.
2. Make sure you are connected to the ZKsync network. If you are not, switch your wallet’s network to ZKsync.

<figure><img src="/files/oBhBwYAqdE5hdHzOZFgM" alt="Selection of ZKsync network"><figcaption><p>Selection of ZKsync network</p></figcaption></figure>

#### Step 2: Interact with the Venus Protocol

In this example, we will approve the use of the ZK market as collateral.

1. Navigate to the ZK market on Venus.
2. Click on "Collateral" to enable the use of this market as collateral.

<figure><img src="/files/XulaeHJIMbExbBkGhHvG" alt="Interaction with any feature on ZKsync"><figcaption><p>Interaction with any feature on ZKsync</p></figcaption></figure>

#### Step 3: Sign the Transaction

1. 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.
2. 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.
3. Once signed, Zyfi processes the transaction, and it is sent to the ZKsync blockchain with gas paid through their vault.

<figure><img src="/files/u0feeQYTaeD6s5qqYtwR" alt="Sign a message with Rabby, instead of sending a transaction"><figcaption><p>Sign a message with Rabby, instead of sending a transaction</p></figcaption></figure>

<figure><img src="/files/9OAxEUiI56jUfMFeZe11" alt="Sign a message with Metamask, instead of sending a transaction"><figcaption><p>Sign a message with Metamask, instead of sending a transaction</p></figcaption></figure>

#### Viewing the Transaction

You can verify the transaction on the [ZKsync Explorer](https://explorer.zksync.io/). The transaction will display Zyfi as the Paymaster, covering the gas fees.


# Import Positions

### Introduction

This guide provides step-by-step instructions on how to import your supply positions from other DeFi platforms into the Venus Protocol.

### Steps for importing supply positions from other DeFi platforms)

#### Step 1: Connect Your Wallet

* Click on the "Connect wallet" button in the top right corner of the Venus Bridge interface to connect your wallet.

<figure><img src="/files/HmHfUmRll0GFB3zJGjUR" alt=""><figcaption></figcaption></figure>

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.

<figure><img src="/files/LSJMnqa7iImH8cSFI6YO" alt=""><figcaption></figcaption></figure>

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.

<figure><img src="/files/ZPIo1If9MNWCY0jrhYwy" alt=""><figcaption></figcaption></figure>

#### Step 2: Initiate an Import

* 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.

#### Step 3: Confirm and Wait

* 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.

#### Step 4: Transaction Completion

* Once the transaction is complete, the new positions will appear in the "Account" page.


# Enable E-mode

### Want to try out e-mode?

Head to the Venus dApp ([app.venus.io](https://app.venus.io)) and ensure you are connected to the BNB Chain.

Click on the “E-mode” icon to view current e-mode groups.

<figure><img src="/files/P51Ul5x1Nwi9itwtR882" alt=""><figcaption></figcaption></figure>

Make sure your wallet is connected.

<figure><img src="/files/PbAQOknYExo2Z4pamYJS" alt=""><figcaption></figcaption></figure>

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!

<figure><img src="/files/Te8aEORZKwWOGwLkPQKB" alt=""><figcaption></figcaption></figure>

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!


# Isolated E-mode

## Introduction to Isolated E-mode

**Introduction**

**Isolation Mode** in Venus Protocol is a safeguard mechanism designed to securely onboard high-volatility or newly listed assets—such as RWAs—by limiting their exposure to other assets within the protocol. Assets classified as **“Isolated Collateral Assets”** can only be used to borrow specific assets, such as BNB and stablecoins, as determined through our risk management framework and Venus Protocol Governance. This structure effectively mitigates the risks associated with such assets. Within the Venus Protocol user interface, assets restricted to supply in Isolated E-Mode are clearly marked with the label **“Isolated.”**

## E-mode vs Isolation Mode

**What are the key differences between E-mode and Isolated asset?**

E-Mode refers to Efficiency Mode. It enables users to maximize the potential of their collateral, allowing them to pursue various yield strategies on Venus by offering a higher Loan-to-Value (LTV) ratio for correlated assets within the same E-Mode group.

<div align="center"><img src="https://github.com/user-attachments/assets/940cb81f-9ae3-4315-ad7e-927470fb567e" alt="image" height="322" width="591"></div>

Assets in the Isolation Mode feature more conservative parameters and supply caps than standard core pool assets. However, users can still utilize them as collateral without exposing the protocol to widespread risk.

<div align="center"><img src="https://github.com/user-attachments/assets/70fdf0c8-1171-4c93-b2bc-a19510ff5184" alt="image" height="273" width="587"></div>

## Supplying an Isolated Asset

**Supplying an Isolated Asset**

Before using an isolated asset as a collateral, users must ensure that their account is debt-free. Once this condition is met, they can navigate to the user interface and enable the Isolated E-mode group. When supplying an isolated asset in Isolation mode, users gain access to the core pool's stablecoin liquidity and other designated assets.

## Borrowing in Isolation Mode

**Borrowing in Isolation Mode**

When using an Isolated Asset as collateral, you are limited to borrowing only the stablecoins and other designated assets (i,e BNB) that are approved for the Isolation E-Mode group via Venus risk management process and governance. This restriction helps manage the risk associated with these assets. Additionally, while in Isolation Mode, you cannot use any other assets as collateral,though users may still earn interest on their other supplied assets on the core pool.

## Use-case for users

**Example use-case for users**

Isolated assets listed on Venus offer significant upside potential for both asset holders and the protocol itself—particularly for real-world asset (RWA) tokenizations, such as tokenized stocks. For example, listing $AAPL as an isolated asset with the ability to borrow stablecoins or BNB unlocks powerful use cases for users, including:

* **Instant Borrowing Against AAPL Shares**: Users can borrow funds against their tokenized $AAPL holdings, gaining immediate liquidity without bank visits, paperwork, or approval delays. On Venus, this process is fully permissionless and completes in seconds.
* **Earning Annual Yield Through Smart Strategies**: Users deposit $AAPL, borrow $BNB against it, then stake the $BNB on Aster to earn asBNB—typically yielding 10–13% annually.
* **Shorting $AAPL on Venus**: Users borrow $AAPL using stablecoins, sell it on the open market, and later repurchase $AAPL to repay the loan and close the position.

## Exiting Isolation Mode

**Exiting Isolation Mode**

If users choose to exit the Isolation Mode group, they must first repay all outstanding debt linked to the Isolated group. Once the debt is fully settled, they may disable the Isolated asset, enabling them to return to the standard mode.


# Withdrawing from deprecated isolated pools

Venus isolated pools have been fully deprecated. The isolated pools page and all isolated pool market screens have been removed from the Venus app, so positions can no longer be managed through the interface. If you still hold a position — supplied assets, an outstanding borrow, or both — you can still exit it by interacting directly with the market contracts through a block explorer. This guide explains how.

Isolated pools are only affected on the chains where they were deployed: **BNB Chain**, **Ethereum**, and **Arbitrum**. Your positions on the Core pool and every other Venus product are unchanged.

## Before you begin

* You will interact with the Venus market contracts directly through a block explorer's **Read/Write Contract** tabs, connecting the same wallet that holds the position:
  * BNB Chain — [BscScan](https://bscscan.com)
  * Ethereum — [Etherscan](https://etherscan.io)
  * Arbitrum — [Arbiscan](https://arbiscan.io)
* Keep a small amount of the network's native token (BNB on BNB Chain, ETH on Ethereum and Arbitrum) in your wallet to pay for gas.
* All isolated pool vToken addresses are listed in the Venus documentation under [**Deployed Contracts → Markets**](/deployed-contracts/markets). On that page, every pool other than **Core Pool** is an isolated pool — the pools are named BTC, DeFi, GameFi, Meme, Stablecoin, Tron, Liquid Staked BNB/ETH, Curve, and Ethena. For the authoritative machine-readable source, see the [`isolated-pools` deployment artifacts on GitHub](https://github.com/VenusProtocol/isolated-pools/tree/main/deployments). You can also find your isolated pool markets in the token-holdings list of your wallet address on the block explorer (they appear as `Venus <asset>` tokens) or in your Venus transaction history.

Each isolated pool market is a **vToken** contract. Supplying an asset mints you vTokens (an ERC-20 balance held in your wallet); borrowing creates a debt tracked by that same vToken contract. Withdrawing and repaying are done on the vToken contract; approvals are done on the underlying asset's own token contract.

## Step 1 — Identify your positions

For each isolated pool vToken you interacted with, open its contract on the relevant block explorer and use the **Read Contract** tab to check your balances:

* `balanceOf(<your address>)` — your vToken balance. A non-zero value means you have a **supplied** position to withdraw.
* `borrowBalanceStored(<your address>)` — your outstanding **borrow** in units of the underlying asset. A non-zero value means you have a borrow to repay. (This is the last stored value; the live amount including freshly accrued interest is returned by `borrowBalanceCurrent` on the **Write Contract** tab.)
* `underlying()` — the address of the underlying asset for that market, which you will need for the repay approval in Step 2.

Note the vTokens where either balance is non-zero — those are the positions you need to close.

## Step 2 — Repay your borrows

Do this only for markets where `borrowBalanceStored` is non-zero. If you have no borrows, skip to Step 3.

1. Open the **underlying asset's** token contract on the block explorer (the address returned by `underlying()` in Step 1) and, on the **Write Contract** tab, call `approve(spender, amount)` where:
   * `spender` is the **vToken** contract address for that market.
   * `amount` is at least your outstanding borrow. To avoid a shortfall from interest accruing between transactions, approve a comfortable margin above `borrowBalanceCurrent`.
2. Open the **vToken** contract on the **Write Contract** tab and call `repayBorrow(repayAmount)`. Pass `repayAmount = 115792089237316195423570985008687907853269984665640564039457584007913129639935` (this is `type(uint256).max`); the contract automatically caps the repayment at your full outstanding balance, so this repays the borrow in full including accrued interest.

Repeat for every market where you have an outstanding borrow, on every affected chain.

## Step 3 — Withdraw your supplied assets

For each market where `balanceOf` is non-zero, open the **vToken** contract on the **Write Contract** tab and withdraw using either of:

* `redeem(redeemTokens)` — burns `redeemTokens` vTokens and returns the underlying. To withdraw your entire supplied balance, pass the value returned by `balanceOf(<your address>)` in Step 1.
* `redeemUnderlying(redeemAmount)` — withdraws a specific amount of the underlying asset (in the underlying's own decimals).

Repeat for every market where you have a supplied balance, on every affected chain.

**If a withdrawal reverts unexpectedly:** the Comptroller prices every market you are a member of before allowing a withdrawal, and a degraded or stale oracle on any one of those markets — even an unrelated one — will cause the call to revert. Calling `exitMarket` does not help because it runs the same price check. If your withdrawal fails for no obvious reason (you have no open borrows, your account is healthy), please contact Venus support.

**A note on borrows and withdrawals:** you do not necessarily have to repay *every* borrow before withdrawing collateral. A withdrawal only reverts if it would leave your account with a shortfall (undercollateralized), and if the supplied asset was never enabled as collateral the check is skipped entirely. In practice, the simplest and safest way to fully exit is to repay all borrows first (Step 2) and then withdraw everything (Step 3) — that guarantees no withdrawal is blocked.

## Reward claims

Isolated pool rewards are no longer surfaced in the app's **Rewards** section. Any pending rewards you have accrued in an isolated pool remain claimable on-chain: open that pool's **RewardsDistributor** contract on the block explorer (its address is listed in the [`isolated-pools` deployment artifacts](https://github.com/VenusProtocol/isolated-pools/tree/main/deployments)) and call `claimRewardToken(<your address>)` on the **Write Contract** tab. `claimRewardToken` is overloaded — the block explorer will show two entries; use the **one-argument** version (the one that takes only your address), which claims across all markets in that pool. Claiming rewards is optional and independent of repaying and withdrawing your positions.


# Boost and Repay with Collateral

## **Looping Made Easy on Venus Protocol**

On Venus Protocol, building leveraged positions — traditionally known as “looping” — used to require users to manually repeat a tedious cycle: borrow → swap on an external DEX → supply as collateral → borrow again, often 5–20 times. Each step cost gas, time, and risk of transaction failures.

Auto-leverage boost changes that completely.

With Venus’s one-click Boost feature, the entire looping process is fully automated and executed in a single, atomic transaction using flash loans.

Here’s what happens behind the scenes when you click “Boost”:

* Venus instantly calculates the maximum safe leverage based on your current borrowing power and the selected collateral’s loan-to-value (LTV) ratio.
* A flash loan borrows a large amount (far beyond your normal borrowing power).
* The borrowed asset is swapped (via the best available route) into your chosen collateral asset.
* The resulting tokens are supplied as collateral on Venus.
* The loop repeats internally as many times as needed — all in the same transaction — until your target leverage is reached.
* The flash loan is repaid at the end, leaving you with a fully leveraged position.

Result: What once took dozens of manual transactions, high gas costs, and constant monitoring is now instant, and completely safe from liquidation on execution (health factor is always kept > 1).

Whether you’re looping 2×, 5×, or pushing close to the maximum LTV of assets like BNB, BTCB, or stablecoins, Venus does all the heavy lifting.

Looping is no longer reserved for advanced users — on Venus Protocol, it’s literally as easy as clicking Boost.

***

## **Repay Debt with Collateral**

Closing or reducing a leveraged position on Venus Protocol is just as simple as opening one. The Repay with Collateral feature lets you instantly repay any borrowed asset using the collateral you already have supplied — without needing to hold the borrowed token in your wallet.

### **How it works**

• Select the loan you want to repay (fully or partially).\
• Venus automatically withdraws the required amount from one or more of your supplied assets.\
• It swaps the withdrawn collateral into the exact borrowed asset (using the best available route).\
• The debt is repaid immediately, and any leftover tokens are returned to your wallet.

### **Perfect for leveraged positions**

When you have a looped (Boosted) position, your wallet typically holds little or none of the borrowed asset. Repay with Collateral eliminates the need to manually unwind loops by letting you deleverage or fully close the position in a single transaction — even if you want to exit at maximum leverage.

### **Key benefits**

• No need to source the borrowed token externally\
• One-click full or partial deleveraging\
• Minimal slippage thanks to optimized routing\
• Works seamlessly with Boost positions\
• Saves a lot of time

Combined with the Boost feature, Repay with Collateral makes entering and exiting leveraged positions on Venus faster, and more user-friendly than ever before.

***

## **Key Use Cases for Users**

**Yield Farmers – Maximize APY with one click**\
Loop stablecoins or blue-chip assets (e.g., USDT, USDD, BTCB) up to the maximum safe LTV and earn higher lending + VAI rewards without manually repeating borrow->swap->supply dozens of times.

**Long-term Bulls – Amplify exposure instantly**\
Want 4–8× exposure to an asset with only your existing collateral? Boost turns a modest position into a highly leveraged long in seconds.

**Bearish Traders – Short an asset instantly**\
Believe an asset is overvalued? Boost lets you instantly borrow and swap into stablecoins, creating a 5–10× leveraged short position in a single click.

**Quick deleveraging during volatility**\
When prices move against you, repay any borrow instantly using your supplied collateral, no scrambling for tokens or manual unwinding.

**Closing Boosted positions – cleanly**\
Exit an entire looped position (long or short) in one transaction. Repay with Collateral handles all withdrawals, swaps, and debt repayment automatically.

**Capital-efficient entry & exit**\
Enter high-leverage long or short strategies with zero upfront capital beyond your initial supply, and exit cleanly without ever holding large amounts of the borrowed asset.

Boost + Repay with Collateral turns advanced leveraged strategies — long or short — into simple, one-click actions on Venus Protocol.

***

## **Risks of Using Boost & Repay with Collateral**

While the one-click experience makes leveraging incredibly fast and simple, the risks remain the same as any leveraged position on Venus — just easier to enter at higher ratios.

### **Key risks you must understand:**

**Liquidation Risk**\
Boosted positions run very close to the asset’s maximum LTV. A small adverse price move can drop your health factor below 1.1 and trigger liquidation.

**Amplified Price Exposure**\
5–10× leverage magnifies gains and losses. A 10 % drop in the collateral asset price can wipe out 50–100 % of your equity.

**Execution & Slippage Risk**\
In rare cases of extreme market conditions, the internal swaps during Boost may fail or experience high slippage, causing the transaction to revert (you only lose gas).

**Oracle Risk**\
Venus relies on price oracles. Temporary oracle mispricing can lead to unexpected liquidations or failed Boost attempts.

**Borrow Interest Erosion**\
High or rising borrow rates on leveraged positions can reduce net yield over time and can turn a profitable strategy negative.

**Impermanent Loss (LP tokens)**\
Boosting with liquidity-provider tokens adds impermanent loss risk on top of borrowing costs.

### **Best practices**

• Only use funds you can afford to lose\
• Leave a safety margin instead of always maxing leverage\
• Monitor your health factor regularly\
• Know the exact liquidation price before confirming Boost

Leverage is a double-edged sword — Boost makes it easy to wield, but the responsibility remains yours.

***

## **How Venus Calculates Your Maximum Boost (With Example)**

Venus automatically determines the highest safe leverage so your health factor is above 1 after using Boost.

Note: Upon execution, the user's health factor will be greater than 1, which avoids immediate liquidation. Thereafter, the user must continue monitoring their health factor, as the protocol is not responsible for any subsequent liquidations that may occur.

### **Internal Formula**

**Maximum Additional Borrow = Unused Borrowing Power ÷ (1 − Collateral Factor)**

### **Example – Looping USDT (Collateral Factor = 80%)**

**Your Current Position:**\
• Supplied: 100 USDT (enabled as collateral)\
• Already borrowed: 20 USDT

#### **Step-by-Step Calculation (Performed Instantly by the Protocol)**

1. **Unused Borrowing Power**\
   Unused Borrowing Power = (Supplied × Collateral Factor) − Existing Borrow\
   → (100 × 0.8) − 20 = 80 − 20 = 60 USDT
2. **Maximum Additional Borrow with Boost**\
   → 60 ÷ (1 − 0.8) = 60 ÷ 0.2 = 300 USDT

#### **Result After Clicking Boost**

• Total supplied: ≈ 400 USDT\
• Total borrowed: ≈ 320 USDT\
• Net equity: still ≈ 80 USDT (your original capital)\
• Effective leverage achieved: ≈ 5×

With only 60 USDT of unused borrowing power, Boost instantly creates a 5× leveraged position — something that would normally require 8–10 manual loops and multiple transactions.

The Boost interface shows the exact boost amount, the final leverage multiplier, and the updated health factor before you confirm — no manual calculations needed.


# Trade

Venus Trade lets you express a view that one asset will outperform another, without needing to predict absolute price direction. This guide walks through the full lifecycle of a Trade position — from opening to closing — and explains all available management actions along the way.

***

## What Is a Trade Position?

A Trade position is made up of two legs that are managed as a single unit:

* **Long Leg** — an asset you believe will outperform, supplied into Venus to earn lending yield
* **Short Leg** — an asset you believe will underperform, borrowed from Venus

When you open a position, the protocol borrows the short asset, swaps it into the long asset, and supplies it — all in a single transaction. When you close, the process reverses automatically.

All profits and losses are settled in your chosen stablecoin (**DSA** — Default Settlement Asset), which is either USDT or USDC.

***

## Step 1: Choose a Trading Pair

<figure><img src="/files/DP9c2dHpKO9dExvWz6ym" alt="Trading pairs overview"><figcaption></figcaption></figure>

Browse the available trading pairs. Each pair shows:

* The current relative price between the long and short asset
* Available liquidity on both the long (supply) and short (borrow) side
* Supply APY, and borrow APY

Pick the pair that matches your market view. For example, if you believe WBNB will outperform ETH, select the WBNB/ETH pair (WBNB = long, ETH = short). You can also go purely long or short on a single asset by pairing it with a stablecoin.

{% hint style="info" %}
The long asset must have a Collateral Factor (CF) > 0 in the Venus Core Pool. The short asset must be available for borrowing in the Venus Core Pool.
{% endhint %}

***

## Step 2: Initialize Your Position

<figure><img src="/files/RjijubU6IBxz9qmPI6rY" alt="Initialize position form"><figcaption></figcaption></figure>

This step activates a new position account for the selected pair and opens your first trade in one atomic transaction.

**What to configure:**

| Field                  | Description                                                                                                                                    |
| ---------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
| **DSA**                | Choose USDT or USDC as your collateral and settlement currency. This cannot be changed later without fully exiting.                            |
| **Collateral Amount**  | The amount of DSA to deposit. This is your initial principal.                                                                                  |
| **Leverage**           | Your exposure multiplier. Higher leverage amplifies both gains and losses. The maximum depends on the collateral factors of the chosen assets. |
| **Short Amount**       | The amount of the short asset to borrow. Cannot exceed the maximum allowed by your available capital and leverage.                             |
| **Slippage Tolerance** | Minimum long asset amount you expect from the swap. The transaction reverts if the swap output is below this.                                  |

Select your desired leverage multiplier and set the short amount to borrow. The UI displays the maximum leverage available based on the collateral factors of the selected assets.

<figure><img src="/files/Byz77xquqoURiK5ru4tq" alt="Selecting leverage and short amount"><figcaption></figcaption></figure>

**Before submitting:**

* Review the estimated Assets amount changes, Health Factor, entry price (short/long ratio), liquidation price, and Net APY
* Approve the DSA token spend on the RelativePositionManager

<figure><img src="/files/mTaDCbHCFWpWqjLynCvH" alt="Confirm transaction"><figcaption></figcaption></figure>

**What happens on-chain:**

1. A dedicated PositionAccount is deployed for this trading pair (first time only)
2. Your DSA collateral is supplied into Venus on behalf of the PositionAccount
3. The short asset is borrowed via a flash loan
4. The short asset is swapped into the long asset
5. The long asset is supplied to Venus as leveraged collateral
6. Any dust from the swap is returned to your wallet

{% hint style="info" %}
Leverage and DSA cannot be changed while a position is open. To adjust either, you must fully close all positions, withdraw all collateral, and deactivate (Exit Market), then re-initialize.
{% endhint %}

***

## Step 3: Monitor Your Position

<figure><img src="/files/eqqOguz2J7X40tJgcSMu" alt="Position monitoring dashboard"><figcaption></figcaption></figure>

Once open, track your position from the dashboard:

| Metric                | Description                                                                            |
| --------------------- | -------------------------------------------------------------------------------------- |
| **PnL %**             | Relative price performance since entry, amplified by leverage                          |
| **PnL (USD)**         | Absolute profit or loss converted to USD                                               |
| **Long Supply**       | Current supplied balance of the long asset                                             |
| **Short Borrow**      | Current outstanding borrow of the short asset                                          |
| **Health Factor**     | How close to liquidation your position is. HF > 1 is safe; HF < 1 triggers liquidation |
| **Entry Price (EP)**  | The short/long ratio at the time of opening                                            |
| **Liquidation Price** | The short/long ratio at which liquidation would occur                                  |
| **Net APY**           | DSA APY + Supply APY − Borrow APY                                                      |
| **Available Capital** | Deposited collateral minus capital currently locked by open positions                  |
| \*\* Collateral\*\*   | Collateral allocated as DSA for this position                                          |

{% hint style="warning" %}
Each position has its own independent Health Factor. If you hold multiple positions, monitor each one individually. The liquidation price may fluctuate as the prices of both legs and the DSA change; always **monitor your Health Factor** closely to avoid unexpected liquidation.
{% endhint %}

***

## Step 4: Manage Your Position

While a position is active, four management actions are available.

### Increase Position (Scale)

Adds to your existing position using available collateral or additional DSA principal. The same leverage ratio applies.

Use this when you want to increase your relative exposure without changing your DSA, leverage, or position account.

**How it works:**

* Based on the current available DSA collateral, the system borrows more of the short asset and swaps it into additional long collateral.
* Your leverage ratio stays the same, capital utilization will increase

### Supply Collateral

Deposits additional DSA into your PositionAccount without opening a new trade. This increases your Available Capital and improves your Health Factor without changing your position size.

Use this when your Health Factor is declining and you want to reduce liquidation risk without unwinding any exposure. The deposited DSA earns supply APY immediately and increases the buffer between your current borrow value and the liquidation threshold.

### Reduce Position

Closes a percentage of your position (from 1% to 100%) and settles PnL.

You can also use a small partial reduce (e.g. 5–20%) as a Health Factor management tool: closing part of the position repays a proportional slice of the short debt, which directly raises your Health Factor without requiring a full exit.

* **With profit:** The excess long collateral (above what's needed to repay the debt fraction) is swapped back to DSA and added to your principal balance
* **With loss:** The long collateral is swapped to repay as much of the debt fraction as possible, and remaining debt is covered by redeeming DSA collateral

After reducing, your collateral remains in the PositionAccount. You can open new trades or withdraw at any time.

{% hint style="info" %}
A position remains visible even after a full reduce. This lets you re-enter the same market without deploying a new PositionAccount. To fully exit, use **Close Market**.
{% endhint %}

### Withdraw Collateral

Removes Available Capital from your PositionAccount back to your wallet.

Only the portion of collateral not locked by an open position can be withdrawn. The withdrawable amount decreases as your position size increases and increases as you reduce or add collateral.

Withdrawing collateral reduces your Health Factor. Always ensure it remains above 1.0 after any withdrawal to avoid liquidation.

***

## Step 5: Close and Deactivate

**Close Market** fully exits the trading pair in one transaction:

1. Closes all remaining open positions and settles PnL (same as a 100% reduce)
2. Exits the DSA market and withdraws all collateral to your wallet
3. Deactivates the PositionAccount

After deactivation, you can re-initialize at any time — with a different DSA, different leverage, or different collateral amount.

***

## Understanding PnL

Trade PnL is based on the **relative price movement** between your two assets, amplified by leverage.

### Formula

$$
\text{PnL%} = \left(\frac{R\_t}{R\_0} - 1\right) \times \text{leverage}
$$

$$
\text{PnL (USD)} = \left(R\_t \times \text{Long Amount} - \text{Short Amount}\right) \times \text{Price(Short)}
$$

Where:

* $R\_0$ = Entry price ratio (short asset / long asset at open)
* $R\_t$ = Current price ratio

### Example

You open a WBNB/ETH position:

* Entry ratio ($R\_0$): 0.50 ETH per BNB
* Leverage: 2x
* Short Amount: 5 ETH, Long Amount: 10 BNB

**If BNB outperforms (ratio moves to 0.55):** PnL% = (0.55 / 0.50 − 1) × 2 = **+20%**

**If ETH outperforms (ratio drops to 0.45):** PnL% = (0.45 / 0.50 − 1) × 2 = **−20%**

***

## Understanding Risks

### Liquidation Risk

Trade uses the same liquidation mechanism as Venus Core. If your Health Factor falls below 1, a third-party liquidator can repay part of your borrow and seize a portion of your collateral.

To manage liquidation risk:

* **Monitor your Health Factor regularly** and track the current ratio vs. your liquidation price
* **Supply more DSA principal** (via Supply Collateral) to improve your Health Factor without changing position size
* **Partially reduce your position** (e.g. 5–20%) to repay a slice of short debt, which raises the Health Factor directly
* Understand that leverage amplifies both gains and losses — a 2x leveraged position has twice the liquidation sensitivity

### Slippage

Opening and closing positions involve on-chain swaps, which are subject to slippage. Set a realistic slippage tolerance before confirming. In extreme market conditions, a transaction may revert if the swap cannot meet the minimum output; you only lose gas in that case.

### Market Risk

Relative performance positions can still lose money. If the asset you are shorting outperforms the asset you are longing, your PnL will be negative. Leverage amplifies both gains and losses symmetrically.

### Interest Rate Risk

You pay borrow interest on the short leg continuously. If the borrow rate rises significantly, your Net APY can turn negative, increasing the effective cost of holding the position.

### Smart Contract Risk

Trade is built on top of Venus's audited lending and borrowing infrastructure. No changes were made to core contracts, risk parameters, or liquidation engines. The new RelativePositionManager and PositionAccount contracts have been independently audited. Audit reports are available in the [Security & Audits](/links/security-and-audits) section.

***

## Frequently Asked Questions

**Can I change my DSA after opening a position?** No. Your DSA is locked while the position is active. To change it, fully close all positions, withdraw all collateral, and deactivate (Exit Market), then re-initialize with a different DSA.

**Can I change my leverage after opening?** No. Leverage is fixed for the lifecycle of each activation cycle. Close, deactivate, and re-activate with the new leverage setting.

**What happens if my position gets liquidated?** Liquidation works the same as Venus Core. A liquidator repays part of your borrow and seizes a portion of your collateral at a discount. After liquidation, your position remains open but with a reduced size. You can continue managing it normally.

**Is my collateral shared across different positions?** No. Each trading pair has its own isolated PositionAccount. A liquidation on one pair does not affect your positions on other pairs.

**What does "Available Capital" mean?** Available Capital = your total deposited collateral minus the amount currently locked by your open position. This is how much you can either use to open additional exposure or withdraw from the account.

**Can I have multiple positions on the same pair?** Each pair has one PositionAccount per wallet. Within that account, you can increase or decrease your position size, but it is managed as a single position.

**What fees do I pay?** You pay standard Venus Protocol borrowing interest on the short leg. On-chain swaps during open and close incur normal DEX trading fees and slippage. Currently, there are no additional platform fees specific to Trade.

**What is the difference between "Reduce Position" and "Close Market"?**

* **Reduce Position** closes your long/short trade and settles PnL, but leaves your collateral in the PositionAccount. You can re-enter the same market immediately.
* **Close Market** does everything at once — closes all positions, settles PnL, withdraws all collateral to your wallet, and deactivates the account.

***

## Glossary

| Term                    | Definition                                                                                         |
| ----------------------- | -------------------------------------------------------------------------------------------------- |
| **DSA**                 | Default Settlement Asset — the stablecoin (USDT or USDC) used as collateral and for PnL settlement |
| **Long Leg**            | The asset you believe will outperform, supplied into Venus                                         |
| **Short Leg**           | The asset you believe will underperform, borrowed from Venus                                       |
| **Leverage**            | Multiplier applied to your position size relative to your collateral; fixed at activation          |
| **Health Factor (HF)**  | Position safety metric; liquidation occurs when HF < 1                                             |
| **Entry Price**         | The short/long ratio at the time of opening                                                        |
| **Liquidation Price**   | The short/long ratio at which liquidation is triggered                                             |
| **Capital Utilization** | How much of your deposited collateral is locked by open positions                                  |
| **Available Capital**   | Deposited collateral minus capital utilization; available to trade or withdraw                     |
| **Net APY**             | Supply APY on the long asset plus DSA APY minus borrow APY on the short asset                      |
| **PositionAccount**     | A dedicated on-chain smart contract per wallet per trading pair; auto-deployed on first trade      |
| **Increase Position**   | Add to your existing position using available capital at the same leverage                         |
| **Reduce Position**     | Partially or fully reduce the long/short size; PnL is settled into DSA collateral                  |
| **Close Market**        | Fully close all positions, settle PnL, withdraw all collateral, and deactivate the PositionAccount |


# Fixed Term Vaults

Fixed Term Vaults let institutions borrow stablecoins for a fixed term at a fixed interest rate, backing the loan with on-chain collateral. Suppliers fund the loan during a fundraising window and earn the target APR at maturity. Each vault funds a single loan and closes once settlement is complete.

The product has two sides:

* **Institution** (borrower) — deposits collateral, claims the raised funds, repays at maturity, and recovers any remaining collateral.
* **Supplier** (lender) — supplies the loan asset during fundraising, holds through the lock period, and redeems principal plus the target yield once the institution has repaid.

Available on BNB Chain.

## Pick Your Guide

| Role                                                                                                                                           | Guide                                                            |
| ---------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------- |
| **Institution** — you want to borrow against collateral at a fixed rate and need to get a vault from Venus and walk through the full lifecycle | [Institution Guide](/guides/fixed-rate-vaults/institution-guide) |
| **Supplier** — you want to supply during fundraising and earn the target yield at maturity                                                     | [Supplier Guide](/guides/fixed-rate-vaults/supplier-guide)       |

For the contract-level details, see the [Fixed Term Vaults Technical Reference](/technical-reference/reference-technical-articles/fixed-rate-vaults).


# Institution Guide

This guide walks through the institution's lifecycle in a Fixed Term Vault. It covers getting allocated a vault by Venus, depositing the margin, topping up collateral during fundraising, claiming the raised funds, repaying the loan, and recovering any remaining collateral.

## Getting a Vault

To get started, reach out to the Venus team. Once the terms are agreed upon off-chain, Venus will deploy a vault for you.

After deployment, you receive two things:

* The **vault address**: the target of every later action.
* A **position NFT** minted to the operator address you nominated. The NFT is the credential for all institution-side actions. Whoever holds it controls the vault.

NFT transfers are blocked unless Venus approves a specific recipient. The vault is now ready for your first action.

> Every institution action below is called directly on **your vault** contract. Opening and cancelling the vault happen on the **InstitutionalVaultController** and are performed by Venus governance, with no action from you.

## Step 1: Deposit the Margin

Deposit the margin into the vault in a single transaction. Partial deposits below the required threshold are rejected.

The margin is a fixed percentage of the ideal collateral amount set at vault deployment. If you never deposit the margin, the vault simply sits idle. Venus can cancel and clean it up.

* **Function:** `depositCollateral(amount)` (approve the collateral asset to the vault first)
* **Callable in:** `WaitingForMargin` (the same function is also used in `Fundraising` and `Lock`)
* **Keep in mind:** `amount` must cover the full margin (`marginRate × idealCollateralAmount`) in one transaction; anything below the threshold reverts. On success the vault advances to `MarginDeposited`.

## Step 2: Wait for the Vault to Open

After the margin lands, Venus opens the vault and starts the fundraising window. Suppliers can now supply the loan asset. No action is required from you in this step.

* **Function:** `openVault(vault)`, called on the **InstitutionalVaultController** by Venus governance, not by you. (Governance can instead `cancelVault(vault)` from `MarginDeposited` if needed, which refunds your margin.)

## Step 3: Top Up Collateral During Fundraising

While fundraising is open, bring the collateral balance up from the margin to the full ideal collateral amount.

The full amount must be in place **before the fundraising window closes**. If it isn't, the vault fails, and the outcome depends on the raise:

* **The raise also fell short of the minimum:** you recover all deposited collateral, including the margin.
* **The raise succeeded but collateral was underdelivered:** the margin is confiscated and distributed to suppliers. You recover only the remaining non-margin collateral.
* **Function:** `depositCollateral(amount)` (same call as the margin deposit; approve the collateral asset first)
* **Callable in:** `Fundraising`
* **Keep in mind:** bring `totalCollateralDeposited` up to the full `idealCollateralAmount` **before the fundraising window closes**. Falling short here is what triggers the failure outcomes above.

{% hint style="warning" %}
If fundraising succeeds but you don't top up the collateral in time, the margin is confiscated. There is no recovery path once that happens.
{% endhint %}

## Step 4: Claim the Raised Funds

Once fundraising closes successfully, the vault enters the lock period and the raised funds become available.

* **Function:** `claimRaisedFunds()` (transfers the entire raised amount to you)
* **Callable in:** `Lock`
* **Keep in mind:** one-shot, all-or-nothing, with no partial draw.

**During the lock period**, you can add collateral at any time to defend the position's health if the collateral price drops. You can also withdraw any collateral above the minimum floor, as long as the position stays within the liquidation threshold. If either constraint is breached, the withdrawal is rejected.

* **Add collateral:** `depositCollateral(amount)`, callable in `Lock`; the most direct way to restore health when the collateral price falls.
* **Withdraw collateral:** `withdrawCollateral(amount)`, callable in `Lock` (and later in `Matured` / `Failed`); in `Lock` it must keep collateral above the minimum floor and the position within the liquidation threshold, or it reverts.

If you don't claim before the lock period ends, the funds stay in the vault. Interest is still owed at maturity either way, so claiming late means paying interest on capital you never used.

## Step 5: Repay Before the Settlement Deadline

When the lock period ends, repayment is due. You have until the settlement deadline to repay in full.

Repayments can be partial, and any wallet can repay on your behalf. Once the debt clears, the vault matures and suppliers can begin redeeming.

* **Function:** `repay(amount)` (approve the supply asset to the vault first)
* **Callable in:** `Lock`, `PendingSettlement`, `SettlementDeadlineExceeded`
* **Keep in mind:** the call is **permissionless**, so any wallet can call it on your behalf. Partial repayments are allowed and overpayment is clamped to the outstanding debt. Interest is fixed for the full lock duration, so repaying early does not reduce what you owe, but it frees collateral and removes late-payment risk.

{% hint style="warning" %}
Missing the settlement deadline makes the vault liquidatable at the late-penalty rate, even if your collateral is healthy.
{% endhint %}

## Key Risks You Must Understand

A Fixed Term Vault is a fixed-term commitment with a few timing-sensitive obligations. Be aware of the following before participating:

1. **Margin confiscation**

   If fundraising clears the minimum but you don't top up the collateral to the ideal amount before the fundraising window closes, the margin is permanently confiscated and distributed to suppliers.
2. **Overdue liquidation**

   Missing the settlement deadline makes the vault liquidatable at the late-penalty rate, even if your collateral is healthy.
3. **Health-based liquidation**

   If the collateral price drops during the lock period and pushes the position below the liquidation threshold, the vault is liquidatable at the standard incentive rate.
4. **No early changes to terms**

   Target APR, lock duration, settlement window, and the borrow caps are all set at deployment and cannot be renegotiated on-chain. Confirm the terms with Venus off-chain before the vault is created.

## Best Practices

* **Monitor collateral price during the lock period.** Top up early when the price moves against you. Once the funds are claimed, that is the only way to defend the position.
* **Repay as soon as you can.** Interest is fixed for the full lock duration regardless of when you repay, but repaying early frees up your collateral and removes the late-payment risk.
* **Keep the position NFT in a wallet you control.** Whoever holds the NFT controls the vault. If you delegate it to an operator, treat that wallet with the same security as a treasury wallet.

For the on-chain details, including the full state machine, function signatures, math, and liquidation paths, see the [Fixed Term Vaults Technical Reference](/technical-reference/reference-technical-articles/fixed-rate-vaults).


# Supplier Guide

This guide walks through how to participate in a Fixed Term Vault as a supplier. You supply the loan asset during the fundraising window, hold through the lock period, and redeem principal plus the target yield at maturity.

{% hint style="warning" %}
**Capital is at risk.** The target APR is set at vault deployment and is not a guaranteed return. Actual proceeds at settlement depend on counterparty performance and may be less than the amount supplied. This product is not available to retail investors or persons in restricted jurisdictions (US, UK, Canada, mainland China, or OFAC-sanctioned countries).
{% endhint %}

## Finding a Vault

Fixed Term Vaults live on the Venus **Vaults** page: [venus.io/#/vaults?chainId=56](https://venus.io/#/vaults?chainId=56). Open the app, make sure your network is set to BNB Chain, and select **Vaults** in the top navigation.

Each vault is shown as a card. A Fixed Term Vault is labelled **Fixed-Term** next to the supply asset (for example, *USDT Fixed-Term*) and shows its headline terms — the target APR, total supplied against the cap, the minimum requested raise, when the supply period ends, and the venue.

<figure><img src="/files/x3SgAq6H4czzLPCoJBVD" alt="Venus Vaults page with a Fixed-Term vault card in the middle"><figcaption><p>The Vaults page. The middle card is a Fixed-Term vault — note the <code>Fixed-Term</code> label, the target APR, and the supply period.</p></figcaption></figure>

## Reading the Vault Terms

Click the vault card to open its detail panel, and review the terms before committing — they are fixed at deployment and cannot change once the vault is live.

The **Position** tab shows the **Target APR** (net of the protocol reserve factor) and the **Supply period ends** deadline.

<figure><img src="/files/mnxTpCzAYHlt2RzqkWFH" alt="Fixed-Term vault Position tab showing Target APR and supply period"><figcaption><p>Position tab: target APR and the supply-period deadline.</p></figcaption></figure>

The **Overview** tab shows total supplied and the **campaign timeline** — Supply → Locked → Repaying → Claim. The gap between the supply close and the lock end is your lock duration.

<figure><img src="/files/4zo3xqL52vGn5ZYj1o96" alt="Overview tab showing total supplied and the campaign timeline"><figcaption><p>Overview tab: total supplied and the campaign timeline (Supply → Locked → Repaying → Claim).</p></figcaption></figure>

**Market info** shows the venue (the institution that borrows the funds), the collateral backing the loan, and the risk disclosures.

<figure><img src="/files/2vq4ozx4ya0NS6nalz7l" alt="Market info showing venue, collateral, and risk disclosures"><figcaption><p>Market info: the venue (recipient), the collateral asset, and the risk disclosures.</p></figcaption></figure>

## Step 1: Supply During Fundraising

While the supply period is open, connect your wallet using **Connect wallet** in the top-right, then open the vault and go to the **Position** tab.

1. Enter the amount of the supply asset you want to deposit, or use the percentage slider. The **Available** balance is shown above the input.
2. Tick the box confirming you agree to the Fixed-Term Vault Terms of Use and that you are not a restricted person.
3. If this is your first supply of this asset, approve the token spend, then click **Supply** and confirm the transaction in your wallet.

You receive vault share tokens representing your claim. The shares are freely transferable, so you can hold them in any wallet. A **minimum supply floor** applies unless you're filling the final residual capacity, in which case the floor is waived so the cap can actually be reached.

<figure><img src="/files/QdooRnwzODXMI5Hv4Uua" alt="Supply form on a Fixed-Term vault showing the amount input, terms checkbox, and Supply button"><figcaption><p>The supply form: enter an amount, accept the terms, then Supply. Funds are locked once the lock period begins.</p></figcaption></figure>

## Step 2: Hold Through the Lock Period

When the supply window closes with the raise above the minimum, the vault enters the lock period. At this point:

* **Supplying and withdrawing are blocked.** There is no early exit.
* **The yield amount is fixed.** Interest is calculated upfront on the full raise for the entire lock duration.
* **Shares remain transferable.** You can move or sell them at any time, even while funds are locked.

In the app, the vault's badge changes to **Locked** and the **Position** tab shows your **Currently supplied** balance, the **Target APR**, your **Total target rewards**, and the **Lock end date**. The action buttons are gone — funds can only be claimed once the vault reaches the Claim or Refund period.

<figure><img src="/files/Xxb2lxr1TAeUfdKcCqmX" alt="Position tab of a locked vault showing supplied balance, target rewards, and lock end date"><figcaption><p>A locked position. Funds are committed until maturity — there is no early exit.</p></figcaption></figure>

## Step 3: Wait for Settlement

When the lock duration elapses, the loan is due and the institution has until the settlement deadline to repay in full. Suppliers cannot withdraw during this window.

Either the institution repays in full and the vault matures, or the settlement deadline passes with debt outstanding and the vault becomes eligible for overdue liquidation at the late-penalty rate. Either way, no action is required from the supplier.

## Step 4: Redeem at Maturity

Once the institution has repaid the full debt, the vault matures and its badge changes to **Claim**. Open the vault, go to the **Position** tab, and click **Claim** to burn your shares and receive principal plus your share of the interest. Confirm the transaction in your wallet.

<figure><img src="/files/TrXp1vQE7X6DZ20lALaD" alt="Position tab of a matured vault showing the Claim button"><figcaption><p>A matured vault. Click <strong>Claim</strong> to burn your shares and withdraw principal plus interest.</p></figcaption></figure>

### Example: Estimating Your Payout

A vault raises 100,000 USDC at an 8% target APR for a 90-day lock. You supply 10,000 USDC and receive shares representing 10% of the vault.

* Total interest at maturity: $$100{,}000 \times 0.08 \times 90/365 \approx 1{,}972.60 \text{ USDC}$$
* Assume a 10% protocol fee on interest: $$1{,}972.60 \times 0.10 \approx 197.26 \text{ USDC}$$
* Net target interest paid to suppliers: $$1{,}972.60 - 197.26 \approx 1{,}775.34 \text{ USDC}$$
* Settlement pool: $$100{,}000 + 1{,}775.34 = 101{,}775.34 \text{ USDC}$$
* Your share (10%): **\~10,177.53 USDC**. That should be a return of \~1.78% over the 90-day term on your 10,000 USDC principal.

## Key Risks You Must Understand

A Fixed Term Vault is a fixed-term commitment. Be aware of the following before participating:

* **No early exit during the lock period.** Funds are locked until maturity.
* **Fundraising shortfall.** If the raise falls short of the minimum, the vault fails and you get your principal back with no interest.
* **Collateral underdelivery.** If the institution doesn't top up collateral in time, you get your principal back plus a pro-rata share of the confiscated margin in the collateral asset.
* **Overdue liquidation.** If the institution misses the settlement deadline, the vault is liquidated at the late-penalty rate, which can reduce the amount available for suppliers.
* **Liquidation may reduce recovery.** If collateral didn't fully cover the debt, your payout may be less than the target rewards.

## Best Practices

* **Read the vault terms carefully.** Target APR, lock duration, and the minimum-raise threshold determine your worst-case outcome.
* **Track the settlement deadline.** Once it approaches, watch for repayment activity. If the institution misses it, you'll need to wait for either a catch-up repayment or a liquidation to settle the vault.
* **Redeem as soon as possible.** If funds remain unclaimed for too long, Venus may sweep the remaining assets and close the vault.

## Recovering Your Funds

A vault has three end states — **Matured**, **Failed**, and **Liquidated**. In any of them your shares become redeemable: open the vault, go to the **Position** tab, and click **Claim**. This burns your shares and pays you a share of the vault's assets proportional to how much of the vault you hold. What that payout consists of depends on how the vault ended.

| End state                                                | What you receive                                                                                                                                  |
| -------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Matured** — institution repaid in full                 | Your principal plus your pro-rata share of the interest, paid in the supply asset.                                                                |
| **Failed** — raise stayed below the minimum              | Your full principal back in the supply asset. No interest, because no loan was made.                                                              |
| **Failed** — institution didn't post enough collateral   | Your full principal back in the supply asset, **plus** your pro-rata share of the institution's confiscated margin, paid in the collateral asset. |
| **Liquidated** — bad debt was repaid to settle the vault | Your pro-rata share of whatever supply asset the vault holds. This can be less than your principal if the collateral didn't cover the full debt.  |

***

For the on-chain details, including the full state machine, function signatures, math, and liquidation paths, see the [Fixed Term Vaults Technical Reference](/technical-reference/reference-technical-articles/fixed-rate-vaults).


# Contracts Overview

Venus Protocol contracts are divided in these repositories:

* [isolated-pools](https://github.com/VenusProtocol/isolated-pools): Contains core contracts for isolated lending, including logic for supplying, borrowing, liquidations, pool and market deployments, and interest rate models.
* [oracle](https://github.com/VenusProtocol/oracle): This repo has contracts for oracles that we support as well as logic for validating prices returned from those oracles.
* [venus-protocol](https://github.com/VenusProtocol/venus-protocol): The core protocol is located in this repo. It contains logic central to lending and borrowing of the core pool.
* [governance-contracts](https://github.com/VenusProtocol/governance-contracts): The contracts used for proposing, voting and executing changes are kept in the \`governance-contracts repo.
* [token-bridge](https://github.com/VenusProtocol/token-bridge): The contracts use to bridge XVS to different networks.
* [venus-periphery](https://github.com/VenusProtocol/venus-periphery): Auxiliary contracts for advanced DeFi operations including leverage strategies and token swaps.

## Isolated Pools Contracts

There are 2 categories of isolated pools contracts:

* Pool
* Risk Management

### Pool

Pool contracts can be divided into 4 categories:

* Configuration
* Logic
* Miscellaneous

#### Configuration

Configuration contracts are used to deploy, configure, and manage pools.

[**PoolRegistry**](/technical-reference/reference-isolated-pools/pool-registry/pool-registry)

Creating and managing pools is done by the [PoolRegistry](https://github.com/VenusProtocol/isolated-pools/blob/main/contracts/Pool/PoolRegistry.sol). It can add markets to pools, update pool metadata, and return pool information.

#### Logic contracts

[**Comptroller**](/technical-reference/reference-isolated-pools/comptroller/comptroller)

The [Comptroller](https://github.com/VenusProtocol/isolated-pools/blob/main/contracts/Comptroller.sol) 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.

[**vToken**](/technical-reference/reference-isolated-pools/vtoken/vtoken)

[vTokens](https://github.com/VenusProtocol/isolated-pools/blob/main/contracts/VToken.sol) 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.

#### Miscellaneous contracts

Isolated Pools use additional contracts such as lenses, rewards, ect.

[**RewardsDistributor**](/technical-reference/reference-isolated-pools/rewards-distributor)

Users are rewarded for borrowing and lending activities with a reward tokens. The [RewardsDistributor](https://github.com/VenusProtocol/isolated-pools/blob/main/contracts/Rewards/RewardsDistributor.sol) manages these distributions using a configurable rate.

[**PoolLens**](/technical-reference/reference-isolated-pools/pool-lens)

To make querying pool data easier, Isolated Pools contains a [lens](https://github.com/VenusProtocol/isolated-pools/blob/main/contracts/Lens/PoolLens.sol) 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.

#### Risk Management

[**RiskFund**](https://github.com/VenusProtocol/venus-protocol-documentation/blob/main/technical-reference/reference-isolated-pools/risk-fund-and-shortfall/risk-fund.md)

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 [RiskFund](https://github.com/VenusProtocol/isolated-pools/blob/main/contracts/RiskFund/RiskFund.sol). 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.

[**Shortfall**](/technical-reference/reference-isolated-pools/risk-fund-and-shortfall/shortfall)

When bad deb is auctioned off the [Shortfall](https://github.com/VenusProtocol/isolated-pools/blob/main/contracts/Shortfall/Shortfall.sol) contract is responsible for running the action and paying the winner.

[**ProtocolShareReserve**](/technical-reference/reference-isolated-pools/risk-fund-and-shortfall/protocol-share-reserve)

The [ProtocolShareReserve](https://github.com/VenusProtocol/protocol-reserve/blob/main/contracts/ProtocolReserve/ProtocolShareReserve.sol) acts as a treasury where each isolated pool can transfer their revenue.

## Oracle Contracts

[**ResilientOracle**](/technical-reference/reference-oracle/resilient-oracle)

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 [ResilientOracle](https://github.com/VenusProtocol/oracle/blob/main/contracts/ResilientOracle.sol) contract is responsible for fetching and validating prices for a given vToken and managing which oracles are used for a particular vToken.

[**DeviationBoundedOracle**](/technical-reference/reference-oracle/deviation-bounded-oracle)

The [DeviationBoundedOracle](https://github.com/VenusProtocol/oracle/blob/main/contracts/DeviationBoundedOracle.sol) wraps the ResilientOracle to provide manipulation-resistant pricing for whitelisted assets on the borrow-power path. It maintains a per-asset rolling spot-price window and, when the spot deviates beyond a configured threshold, switches collateral pricing to `min(spot, windowMin)` and debt pricing to `max(spot, windowMax)`. Liquidations continue to use the spot price from the ResilientOracle. See [Protection Mode](/risk/protection-mode) for the feature-level description.

### Oracles

[**ChainlinkOracle**](/technical-reference/reference-oracle/oracles/chainlink-oracle)

[ChainLinkOracle](https://github.com/VenusProtocol/oracle/blob/main/contracts/oracles/ChainlinkOracle.sol) is the primary oracle. If a token isn't support by Chainlink then prices will be fetched from a secondary oracle.

[**RedStoneOracle**](https://redstone.finance/)

[RedstoneOracle](https://docs.redstone.finance/docs/smart-contract-devs/get-started/redstone-classic) is used in the Classic model (Chainlink-compatible interface) as a pivot oracle to validate prices returned by main and fallback oracles.

[**BinanceOracle**](/technical-reference/reference-oracle/oracles/binance-oracle)

[BinanceOracle](https://github.com/VenusProtocol/oracle/blob/main/contracts/oracles/BinanceOracle.sol) contract is responsible for fetching token prices from the Binance oracle. It is used as a secondary oracle.

[**PythOracle**](https://github.com/VenusProtocol/venus-protocol-documentation/blob/main/technical-reference/broken-reference/README.md)

[PythOracle](https://github.com/VenusProtocol/oracle/blob/main/contracts/oracles/PythOracle.sol) is used as a pivot oracle to validate prices returned by primary and secondary oracles.

## Venus Protocol

Venus Protocol contracts can be grouped as follows:

* Lending
* Tokens
* Vault
* Lens

### Lending Contracts

[**Comptroller**](https://github.com/VenusProtocol/venus-protocol-documentation/blob/main/technical-reference/reference-core-pool/comptroller/Diamond/Diamond.md)

At the heart of the Core Pool is the comptroller. The latest version is [Comptroller](https://github.com/VenusProtocol/venus-protocol/blob/develop/contracts/Comptroller/Diamond/Diamond.sol). 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.

[**JumpRateModel**](https://github.com/VenusProtocol/venus-protocol-documentation/blob/main/technical-reference/reference-core-pool/interest-rate-models/jump-model.md)

Each market gets deployed with an interest rate model. The [JumpRateModel](https://github.com/VenusProtocol/venus-protocol/blob/main/contracts/InterestRateModels/JumpRateModel.sol) 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.

[**WhitePaperInterestRateModel**](https://github.com/VenusProtocol/venus-protocol-documentation/blob/main/technical-reference/reference-core-pool/interest-rate-models/white-paper-interest-rate-model.md)

Another interest rate model that can be deployed with markets is the [WhitePaperInterestRateModel](https://github.com/VenusProtocol/venus-protocol/blob/main/contracts/InterestRateModels/WhitePaperInterestRateModel.sol). It is similar to the JumpRateModel except it doesn't include a kink. Instead it contains a fixed base rate.

[**Liquidator**](/technical-reference/reference-core-pool/liquidator)

When a borrow becomes insolvent it may be liquidated. The [Liquidator](https://github.com/VenusProtocol/venus-protocol/blob/main/contracts/Liquidator/Liquidator.sol) handles this process. When a borrow is liquidated the seized amount is split between the liquidator and the [treasury](/technical-reference/reference-core-pool/vtreasury)

[**VTreasury**](/technical-reference/reference-core-pool/vtreasury)

Revenue earned by the protocol is kept in the [VTreasury](https://github.com/VenusProtocol/venus-protocol/blob/main/contracts/Governance/VTreasury.sol).

### Token Contracts

[**XVS**](/tokens/xvs)

XVS is an important token in the Venus ecosystem because it powers Venus governance. The [XVS](https://github.com/VenusProtocol/venus-protocol/blob/main/contracts/Tokens/XVS/XVS.sol) 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.

[**VAI**](/tokens/vai)

[VAI](https://github.com/VenusProtocol/venus-protocol/blob/main/contracts/Tokens/VAI/VAI.sol) 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 [VAIController](https://github.com/VenusProtocol/venus-protocol/blob/develop/contracts/Tokens/VAI/VAIController.sol) controls the amount of VAI a user is allowed to mint which is determined by the collateral a user has provided and their liquidity.

[**vTokens**](/technical-reference/reference-core-pool/vtoken)

When a user supplies a token to the protocol, vTokens are minted to represent their supply. The [VToken](https://github.com/VenusProtocol/venus-protocol/blob/main/contracts/Tokens/VTokens/VBep20.sol) contract contains methods that support lending activities for the asset including lending, borrowing and liquidating

### Vault Contracts

**XVS Vault**

XVS can be locked in the [XVSVault](https://github.com/VenusProtocol/venus-protocol/blob/main/contracts/XVSVault/XVSVault.sol) 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 [VAIVault](https://github.com/VenusProtocol/venus-protocol/blob/main/contracts/Vault/VAIVault.sol) earn XVS. Staking rewards are accumulated daily.

#### Misc Contracts

**ComptrollerLens**

The [ComptrollerLens](https://github.com/VenusProtocol/venus-protocol/blob/main/contracts/Lens/ComptrollerLens.sol) contains methods for fetching the liquidity of an account and the amount of tokens that can be seized for a repayable amount

**SnapshotLens**

The [SnapshotLens](https://github.com/VenusProtocol/venus-protocol/blob/main/contracts/Lens/SnapshotLens.sol) 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 [VenusLens](https://github.com/VenusProtocol/venus-protocol/blob/main/contracts/Lens/VenusLens.sol). It contains getters related to XVS distribution, governance, and markets.

### Governance Contracts

There are three main Governance contracts:

* GovernorBravoDelegate
* AccessControlManager
* Timelock

**GovernorBravoDelegate**

The core logic for governance proposals is in the [GovernorBraveDelegate](https://github.com/VenusProtocol/governance-contracts/blob/main/contracts/Governance/GovernorBravoDelegate.sol) 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 [AccessControlManager](https://github.com/VenusProtocol/governance-contracts/blob/main/contracts/Governance/AccessControlManager.sol) 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 [Timelock](https://github.com/VenusProtocol/governance-contracts/blob/main/contracts/Governance/Timelock.sol) contract. The Timelock can place the proposal in a queue for execution and execute the proposal. It also enables canceling the proposal.

## Periphery Contracts

Periphery contracts extend core protocol functionality with auxiliary features for advanced DeFi operations.

[**LeverageStrategiesManager**](/technical-reference/reference-periphery/leverage-strategies-manager)

The [LeverageStrategiesManager](https://github.com/VenusProtocol/venus-periphery/blob/main/contracts/LeverageManager/LeverageStrategiesManager.sol) enables users to enter and exit leveraged positions atomically using flash loans. It consolidates multiple operations (borrow, swap, supply) into single transactions.

[**SwapHelper**](/technical-reference/reference-periphery/swap-helper)

The [SwapHelper](https://github.com/VenusProtocol/venus-periphery/blob/main/contracts/SwapHelper/SwapHelper.sol) provides a secure multicall interface for token swaps with backend signature verification. It enables authorized interactions with external DEX protocols.


# Technical articles


# Automatic income allocation

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.

## Income Distribution Schema

The Venus Protocol generates income from two main sources:

* Spread between the borrowing rate and the supply rate
* Part of the liquidation incentives

[Tokenomics](/governance/tokenomics) goes into more detail about the distribution schema and desired outcomes.

The initial distribution excludes VAI funds, which are kept in the VTreasury.

## Streaming Income Distribution

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.

### Core Pool - Spread Income

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.

### Core Pook - Liquidation Income

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.

### Isolated Pool - Spread Income

Distribution of income generated by the interest rate spread in Isolated Pools is socialized and distributed periodically just like in the Core Pool

### Isolated Pool - Liquidation Income

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.

## Distribution of Collected Incomes

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` Function

The `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` Function

The `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:

1. Transfer the tokens to the destination addresses.
2. Invoke the `updateAssetsState` function in the receiver contract.

## VBNBAdmin

`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.


# Capped Oracles

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.

<figure><img src="/files/cTAqef1kcEiVRg1mcTxu" alt="Capped Oracle main elements"><figcaption></figcaption></figure>

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.

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.

## Configuration

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.

## Example

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`


# Contributing

We have a strict policy on how we should commit our work. Following these guidelines will help us to:

1. 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.
2. 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.
3. Save newcomers' time. When new developers join the team, they want to know how the code evolved and why certain design decisions were made. Our workflow encourages exhaustive commit messages that describe the reason behind each change.

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 :)

## Configure your git

By default, git merges the upstream changes into your local branch on pull. This **silently** [spoils your history](https://blog.sffc.xyz/post/185195398930/why-you-should-use-git-pull-ff-only-git-is-a) 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`.

## Create a feature branch

1. 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.
2. Prefer short and descriptive names for branches (good: `polynomial-interest-curve`, bad: `fix-rate`).
3. Use lowercase words separated by dashes (good: `xvs-vault`, bad: `XVSVault`).
4. You may include work type into the branch name (ok: `feature/polynomial-interest-curve`).
5. Make sure no-one else works in your feature branch.

## Make commmits

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](https://www.conventionalcommits.org/en/v1.0.0/#summary) is a nice standard to use for formatting the commit messages. There are different tools available to enforce these messages

### Structure

```bash
<type>[optional scope]: <description>

[optional body]

[optional footer(s)]
```

### Breaking changes

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

### Enforcing commits

[commitlint](https://github.com/conventional-changelog/commitlint) - Precommit hook with husky ( currently implement in the api repo)

| Type            | Release | Included in Changelog |
| --------------- | ------- | --------------------- |
| breaking change | major   | true                  |
| feat            | minor   | true                  |
| build           | false   | false                 |
| ci              | false   | false                 |
| fix             | patch   | true                  |
| refactor        | patch   | false                 |
| test            | false   | false                 |

## Prettify your history

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.

1. 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`.
2. Your feature branch should have linear history. No merge commits are allowed.
3. 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.

## Notes on force pushing

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.

1. Every feature branch should have one active maintainer. No-one else is allowed to directly commit to your feature branch.
2. 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.
3. **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 :)
4. **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 a pull request

1. Make sure your commit history follows the guidelines written above. Rebase once again if necessary.
2. If your PR is work in progress, explicitly mark it as WIP.

## Pass the review

1. 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.
2. Avoid fixing up a fixup :)
3. 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.
4. Do not add any new changes to the code after the review (except for squashing and reordering the commits).

## Closing thoughts

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.


# Diamond Comptroller in the Core pool

As features continued to be introduced to the Core Pool Comptroller contract, it grew to exceed the [maximum allowable size of 24KB](https://eips.ethereum.org/EIPS/eip-170). 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](https://eips.ethereum.org/EIPS/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.

## Venus Comptroller - Refactored to EIP 2535

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:

<figure><img src="/files/4dTSJx7P88vQuxiYx4Hz" alt="Diamond - Previous hierarchy of contracts"><figcaption></figcaption></figure>

The Unitroller contract delegated calls to the Comptroller. The Comptroller had the storage layout defined by ComptrollerV12Storage, which extended the UnitrollerAdminStorage.

## EIP - 2535 Overview

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.

1. 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.
2. 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.
3. 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.
4. 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.

## Enabling Venus Integration with the existing Unitroller - Diamond and Transparent proxy combination

**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.

<figure><img src="/files/RXXNRrjqUUBNbfPcKrwM" alt="Diamond facets"><figcaption></figcaption></figure>

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 [AppStorage](https://eips.ethereum.org/EIPS/eip-2535#storage) 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.

## User interaction with new diamond pattern

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.

## How will new Upgrades work?

**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 [facet-cut-params-generator script](https://github.com/VenusProtocol/venus-protocol/blob/develop/script/deploy/comptroller/facet-cut-params-generator.ts) by customizing the `generateCutParams` to provide the correct actions on the provided function seletors.

## Diamond proxy implementation for Core Pool Comptroller

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:

### Facets

[**PolicyFacet**](https://github.com/VenusProtocol/venus-protocol-documentation/blob/main/technical-reference/reference-core-pool/comptroller/Diamond/Facets/PolicyFacet.md)**:** This facet contains all the external pre-hook functions related to vToken.

[**SetterFacet**](https://github.com/VenusProtocol/venus-protocol-documentation/blob/main/technical-reference/reference-core-pool/comptroller/Diamond/Facets/SetterFacet.md)**:** This facet contains all setter configuration functions.

[**MarketFacet**](https://github.com/VenusProtocol/venus-protocol-documentation/blob/main/technical-reference/reference-core-pool/comptroller/Diamond/Facets/MarketFacet.md)**:** This facet provides market information including account activity in the market. It is also responsible for entering and exiting the market.

[**RewardFacet**](https://github.com/VenusProtocol/venus-protocol-documentation/blob/main/technical-reference/reference-core-pool/comptroller/Diamond/Facets/RewardFacet.md)**:** This facet provides the external functions related to all claims and rewards of the protocol.

### Parent contracts

[**FacetBase**](https://github.com/VenusProtocol/venus-protocol-documentation/blob/main/technical-reference/reference-core-pool/comptroller/Diamond/facets/facet-base.md)**:** 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:

<figure><img src="/files/1GvtTZ89zSrInJfkjnsO" alt="Diamond - New hierarchy of contracts"><figcaption></figcaption></figure>


# E-Mode

{% hint style="info" %}
Only available on BNB Chain Core Pool.
{% endhint %}

## Overview

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.

### Key Benefits of E-Mode

* **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.
* **Governance Flexibility**: Pool parameters can be dynamically adjusted via Venus Governance proposals.

### Potential Risks and Considerations

* **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 `allowCorePoolFallback` (defaults to `false`).
  * If `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.

## Comptroller Changes for E-Mode in Core Pool

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:

| Change                                              | Description                                                                                                                                                                                                                                                      | Impact                                                                                                                  |
| --------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- |
| **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.    |

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.

## Implementation Details

### 1. Markets Mapping

The core data structure for tracking markets has been upgraded to handle multiple pools efficiently.

**Previously**: Address as index

```solidity
mapping(address => Market) public markets;
```

**Now**: `bytes32` as index

```solidity
type PoolMarketId is bytes32;
mapping(PoolMarketId => Market) public _poolMarkets;
```

* **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.

### 2. Market Struct

The `Market` struct now includes fields to support LT, per-market LI, and pool-specific borrowing rules:

```solidity
struct Market {
    bool isListed;
    uint256 collateralFactorMantissa;
    mapping(address => bool) accountMembership;
    bool isVenus;
    uint256 liquidationThresholdMantissa;
    uint256 liquidationIncentiveMantissa;
    uint96 poolId;
    bool isBorrowAllowed;
}
```

* `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.

### 3. Pool Tracking

Pools are defined and managed via a dedicated mapping for metadata and asset lists:

```solidity
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;
```

* `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.

### 4. User Pool Selection

Each user is associated with exactly one pool at a time, simplifying state management:

```solidity
mapping(address => uint96) public userPoolId;
```

* 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.

### 5. Pool Markets Configuration

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.
* **Fallback Control**: `setAllowCorePoolFallback(uint96 poolId, bool allowed)` controls whether non-pool assets use Core Pool risk parameters.

**Example Setters**:

```solidity
// 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);
```

## E-Mode: User Journey

### 1. Default State

* 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.

### 2. Explore Available Pools

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.

### 3. Validate Compatibility

* 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.

### 4. Enter the Pool

* **Call**: enterPool(uint96 poolId)
* **Comptroller checks**:
  * Pool exists and user isn’t already in it.
  * Borrow compatibility (`hasValidPoolBorrows`).
  * **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

### 5. Post-Entry Impacts

* **Borrowing**: Restricted to markets marked `isBorrowAllowed` in chosen pool.
* **Collateral**:
  * Pool assets use **pool CF/LT/LI**.
  * Non-pool assets behavior depends on `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.

## Common Scenarios

### Borrowed Asset Not Allowed

* 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`.
* Even if an asset is included in a pool, Governance can set `isBorrowAllowed = false`. In this case, supplying the asset as collateral is fine, but new borrows of that asset are restricted.

### Mixed Collateral

* 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 **does not contribute to borrowing power**. CF, LT, and LI are treated as **0** in the E-Mode context. Users are strongly recommended to **exit these markets** before or immediately after switching to E-Mode to avoid unnecessary seizure risk for these assets during liquidations.

**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%).
  * If `allowCorePoolFallback = false`: CF/LT/LI = 0 → does not contribute to borrowing power.

### Switching Back to Core

* 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**:
  * If a user is close to liquidation in Core Pool, they may switch into an E-Mode pool (with higher CF/LT) to immediately improve their account health and avoid liquidation.
  * However, 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.

### Governance Changes

Governance has significant control over pool configurations, which can directly affect user positions:

1. **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.
   * When borrow cap set to 0, no additional borrows are possible, but existing borrows are unaffected.
2. **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.
3. **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.
4. **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.

**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:
  * 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.

## Effect on User on Switching Into E-Mode

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.

### Pool Setup

| Asset    | Core Pool CF | Core Pool LT | Core Pool LI | E-Mode CF              | E-Mode LT | E-Mode LI | E-Mode Borrow Allowed? |
| -------- | ------------ | ------------ | ------------ | ---------------------- | --------- | --------- | ---------------------- |
| **USDC** | 60%          | 65%          | 10%          | 90%                    | 93%       | 5%        | Yes                    |
| **DAI**  | 60%          | 65%          | 10%          | 90%                    | 93%       | 5%        | No                     |
| **UNI**  | 50%          | 55%          | 12%          | N/A (Fallback to Core) | N/A       | N/A       | N/A                    |

### Step 1: Alex in Core Pool

* Supplies: **$1,000 USDC**
* Borrows: **$500 DAI**

**Liquidity Calculation**:

$$
\text{Borrow Limit} = 1000 \times 0.6 = 600
$$

$$
\text{Liquidity} = \text{Borrow Limit} - \text{Total Borrow} = 600 - 500 = 100
$$

$$
\text{Shortfall} = 0 \quad (\text{since liquidity ≥ 0})
$$

* **Liquidity = $100, Shortfall = $0 → safe**

### Step 2: Attempting to Enter Stablecoins E-Mode

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.

### Step 3: Adjusting Position and Entering

* Alex repays $500 DAI → no active borrows.
* Calls `enterPool(stablecoinPoolId)` → succeeds.

**Liquidity Calculation in E-Mode**:

$$
\text{Borrow Limit} = 1000 \times 0.9 = 900
$$

$$
\text{Liquidity} = 900 - 0 = 900
$$

$$
\text{Shortfall} = 0 \quad (\text{safe})
$$

**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).

### Step 4: Borrowing in E-Mode

* Alex borrows **$500 USDC**
* Borrowing **DAI fails** (restricted by pool-level `isBorrowAllowed`)

**Liquidity Calculation after borrow**:

$$
\text{Borrow Limit} = 1000 \times 0.9 = 900
$$

$$
\text{Liquidity} = 900 - 500 = 400
$$

$$
\text{Shortfall} = 0 \quad (\text{safe})
$$

### Step 5: Switching Back to Core

Suppose Alex borrowed up to **$850 USDC** in E-Mode.

**Core Pool Borrow Limit**:

$$
\text{Borrow Limit} = 1000 \times 0.6 = 600
$$

$$
\text{Liquidity} = 600 - 850 = -250
$$

$$
\text{Shortfall} = 250 \quad (\text{tx reverts})
$$

To switch safely, Alex can either:

1. **Add collateral** → $500 more USDC → new Core borrow limit = 1500 × 0.6 = 900 → liquidity = 900 - 850 = 50 → switch succeeds.
2. **Repay debt** → reduce borrow ≤ $600 → liquidity ≥ 0 → switch succeeds.

## Liquidator Considerations in E-Mode

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.

### 1. Per-Market Liquidation Incentives (LI)

* 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.

### 2. Liquidation Thresholds (LT) in Core Pool

* 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**:

  ```solidity
  function getAccountLiquidity(address account) external view returns (uint256, uint256, uint256);
  ```

  This function has been updated to use LT internally when computing liquidity and shortfall.

### 3. Effective Risk Factor Queries

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):**

  ```solidity
  enum WeightFunction {
      USE_COLLATERAL_FACTOR,        // 0
      USE_LIQUIDATION_THRESHOLD     // 1
  }

  function getEffectiveLtvFactor(
      address account,
      address vToken,
      WeightFunction weightingStrategy
  ) external view returns (uint256);
  ```

  * Use `weightingStrategy = 0` to fetch the **effective CF**.
  * Use `weightingStrategy = 1` to fetch the **effective LT**.
* **Get Effective Liquidation Incentive (LI):**

  ```solidity
  function getEffectiveLiquidationIncentive(
      address account,
      address vToken
  ) external view returns (uint256);
  ```

***

### TL;DR: E-Mode in Venus BNB Chain Core Pool

**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.
  * If `allowCorePoolFallback = false` (default): Treat CF/LT/LI as 0; exit such markets.
* **Pool Disabled**: Falls back to Core Pool parameters.

**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:
  * `getEffectiveLtvFactor(account, vToken, 0)` → effective CF
  * `getEffectiveLtvFactor(account, vToken, 1)` → effective LT
  * `getEffectiveLiquidationIncentive(account, vToken)` → effective LI


# Trade

{% hint style="info" %}
Available on BNB Chain Core Pool.
{% endhint %}

## Overview

**Venus Trade** is a relative performance trading system built as a peripheral orchestration layer on top of Venus Protocol's existing lending and borrowing infrastructure. It allows users to express a view that one asset will outperform another — packaged into a single, easy-to-manage position with automated execution, proportional closing, and built-in yield generation.

Users deposit a stablecoin collateral (the **Default Settlement Asset**, or DSA), select a long and short vToken pair, and Trade handles all leveraged execution — flash loans, swaps, supply, and borrow — atomically in a single transaction.

This is not directional trading. Trade positions profit (or lose) based on the **relative price movement between two assets**, regardless of whether the overall market is going up or down. While held, positions also generate yield: supply APY on the long asset, DSA APY on collateral, minus borrow APY on the short asset.

| Component                          | Description                                                                                                                                                               |
| ---------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **RelativePositionManager**        | The main orchestration contract that manages the full lifecycle of Trade positions — from activation and opening to proportional closing and deactivation                 |
| **PositionAccount**                | A dedicated smart contract account deployed per user per trading pair. All collateral, borrow positions, and yield accrual live here, fully isolated from other positions |
| **Paired Positions**               | Long and short legs treated as a single unit with combined PnL, health, and lifecycle management                                                                          |
| **Default Settlement Asset (DSA)** | A designated stablecoin (USDT or USDC) used as collateral and as the currency for all PnL settlement                                                                      |
| **Proportional Closing**           | Flexible partial or full position closing using on-chain flash loans and token swaps, with automatic dust handling                                                        |
| **Capital Utilization Tracking**   | Real-time calculation of how much deposited collateral is locked by open positions, enabling accurate withdrawable balance reporting                                      |

No changes were made to the Venus Core Pool, Comptroller, vToken contracts, interest rate models, oracles, or any existing protocol infrastructure. Existing users are not affected.

***

## Architecture

The Trade system consists of four contracts:

| Contract                      | Role                                                                                                                                                            |
| ----------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **RelativePositionManager**   | Central orchestration contract. Manages position state, validates operations, calculates utilization, and delegates execution to PositionAccount.               |
| **PositionAccount**           | A minimal proxy clone deployed per user per trading pair. Holds all funds, enters Venus markets, and delegates leverage execution to LeverageStrategiesManager. |
| **LeverageStrategiesManager** | Pre-existing Venus periphery contract. Executes flash loans via the Comptroller and invokes the SwapHelper.                                                     |
| **SwapHelper**                | Pre-existing Venus periphery contract. Executes authorized on-chain swaps using signed multicall data.                                                          |

<figure><img src="/files/49VdJpEi3LbQGCt8oobA" alt="Trade Architecture Overview"><figcaption></figcaption></figure>

### Position Isolation

Every unique `(user, longVToken, shortVToken)` triple gets its own **PositionAccount** — a minimal EIP-1167 clone deployed with a deterministic CREATE2 salt. Collateral, debt, and Health Factor are entirely independent across accounts. A liquidation or loss on one PositionAccount cannot affect any other.

<figure><img src="/files/aJyJzsPkEu6En0dAXqVZ" alt="Trade Position Isolation"><figcaption></figcaption></figure>

| Layer                        | Mechanism                                                                                                                                                                                                                                               |
| ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Fund custody**             | Each PositionAccount is a separate on-chain address. Venus vTokens and underlying balances are held there, not in the RelativePositionManager.                                                                                                          |
| **Access restriction**       | `PositionAccount.onlyRelativePositionManager` reverts any call not originating from the single trusted manager address.                                                                                                                                 |
| **Comptroller membership**   | Each PositionAccount enters Venus markets independently. Its Health Factor is computed solely from its own supplied and borrowed balances.                                                                                                              |
| **Delegate approval**        | During initialization the PositionAccount approves both the RelativePositionManager and LeverageStrategiesManager as delegates in the Comptroller — this allows flash-loan execution while keeping all debt on the PositionAccount, not on the manager. |
| **Deterministic deployment** | Clones are deployed with `ClonesUpgradeable.cloneDeterministic(impl, keccak256(user, long, short))`. A given user cannot create two accounts for the same pair; the address is unique and pre-determined.                                               |

***

## Key Concepts

### Long Leg and Short Leg

A Trade position always consists of two legs:

* **Long Leg** — the asset expected to outperform. Supplied into Venus to earn supply APY.
* **Short Leg** — the asset expected to underperform. Borrowed from Venus, creating an interest cost.

The two legs are treated as a single position with combined PnL — users never manage them separately.

### Default Settlement Asset (DSA)

When activating a position, the user selects a **Default Settlement Asset** (USDT or USDC). The DSA serves as:

* The initial collateral deposited into the PositionAccount
* The asset that backs borrow risk (its collateral factor determines how much can be borrowed)
* The currency in which realized profits are accumulated
* The asset used to cover losses on close

### Leverage

Leverage amplifies exposure to relative price movement. The maximum leverage is derived from the collateral factors of the DSA and long asset:

$$
\text{maxLeverage} = \frac{CF\_{DSA}}{1 - CF\_{long} \times (1 - \text{tolerance})}
$$

Where `tolerance` is the `proportionalCloseTolerance`, used as a buffer to prevent activations that would immediately be at the boundary of the safe borrow range. Leverage is recorded at activation and is fixed for the position's lifecycle.

### Capital Utilization

Capital utilization measures how much of the deposited DSA principal is "locked" by the open leveraged position. The remainder — **Available Capital** — can be withdrawn or used to scale the position further. See [Capital Utilization](#capital-utilization-1) for the full formula.

### Yield Generation

Trade positions generate yield while held:

| Component      | Description                                                      |
| -------------- | ---------------------------------------------------------------- |
| **Supply APY** | The long asset is supplied into Venus and earns lending yield    |
| **DSA APY**    | The stablecoin collateral is supplied into Venus and earns yield |
| **Borrow APY** | Interest paid on the borrowed short asset (deducted from yield)  |
| **Net APY**    | DSA APY + Supply APY − Borrow APY                                |

All yield accrues automatically and is reflected in position balances in real time. There is no claim or harvest step.

***

## Implementation Details

### 1. RelativePositionManager

The primary external interface for all Trade operations. All user-facing calls pass through this contract, which enforces lifecycle rules, validates parameters, computes capital utilization, and delegates execution to the PositionAccount.

**Inheritance:**

* `AccessControlledV8` — governance-gated admin functions via AccessControlManager
* `ReentrancyGuardUpgradeable` — reentrancy protection on all state-changing calls
* Custom two-level pause — `isPartiallyPaused` / `isCompletelyPaused` with `whenNotPaused` and `whenNotCompletelyPaused` modifiers

**Key state:**

```solidity
// Per-position state
mapping(address user => mapping(address longVToken => mapping(address shortVToken => Position))) positions;

// DSA configuration
mapping(uint8 index => address vToken) dsaVTokens;
mapping(address vToken => bool active) isDsaVTokenActive;

// Proportional close tolerance (BPS, default 100 = 1%)
uint256 proportionalCloseTolerance;
```

#### activateAndOpenPosition

Atomically activates a new position for the caller and executes the first leveraged open in a single transaction. If a PositionAccount clone does not yet exist for this `(user, long, short)` triple, it is deployed in the same transaction.

The function executes three sequential phases:

1. **Validation** — verifies that `longVToken` and `shortVToken` are listed in the Comptroller and are not the same market, that neither is vBNB, that the DSA index maps to an active registered DSA, that `effectiveLeverage` is in `[1e18, maxLeverage]`, and that no active position already exists for this pair.
2. **Activation** — deploys the PositionAccount clone if needed (via `ClonesUpgradeable.cloneDeterministic`), increments `cycleId`, records the position configuration, calls `Comptroller.enterMarketBehalf` to register the DSA market for the PositionAccount, and calls `vToken.mintBehalf` to deposit `initialPrincipal`. The returned vToken amount is stored as `suppliedPrincipalVTokens`.
3. **Open** — validates `shortAmount ≤ maxBorrow` (available capital × clamped leverage / short price), then calls `positionAccount.enterLeverage(longVToken, 0, shortVToken, shortAmount, minLongAmount, swapData)`. The LeverageStrategiesManager flash-loans `shortAmount`, swaps to the long asset, and supplies it to the PositionAccount's long vToken position.

```solidity
function activateAndOpenPosition(
    address longVToken,
    address shortVToken,
    uint8 dsaIndex,
    uint256 initialPrincipal,
    uint256 effectiveLeverage,
    uint256 shortAmount,
    uint256 minLongAmount,
    bytes calldata swapData
) external;
```

The caller must approve `initialPrincipal` of the DSA underlying to the RelativePositionManager before calling. The function uses `mintBehalf` so that the vToken balance accrues directly on the PositionAccount — the RPM itself holds no collateral.

***

#### scalePosition

Adds additional short exposure to an existing active position. Optionally accepts more DSA principal if `additionalPrincipal > 0`.

Scaling recalculates `maxBorrow` from the updated available capital (including any newly deposited principal) before validating `shortAmount`. The stored `effectiveLeverage` is **not updated** by scaling — it remains fixed at the value set during activation and is used for utilization calculations across the position's lifecycle.

```solidity
function scalePosition(
    IVToken longVToken,
    IVToken shortVToken,
    uint256 additionalPrincipal,
    uint256 shortAmount,
    uint256 minLongAmount,
    bytes calldata swapData
) external;
```

***

#### closeWithProfit

Proportionally closes a fraction of the position when the long asset has outperformed the short asset. Takes two swap legs: one to repay debt and one to harvest the profit into DSA principal.

The caller specifies `closeFractionBps` (1–10000) to indicate what fraction of the position to close. The protocol validates that the total long amount specified (`longAmountToRedeemForRepay + longAmountToRedeemForProfit`) is within `proportionalCloseTolerance` of the expected proportional amount:

```
expectedLong = currentLongBalance × closeFractionBps / 10000
assert |totalLong − expectedLong| ≤ expectedLong × tolerance / 10000
```

**Execution flow:**

1. Redeem `longAmountToRedeemForRepay` from the PositionAccount's long vToken position
2. Swap long → short via `positionAccount.exitLeverage()` to repay the proportional debt
3. Redeem `longAmountToRedeemForProfit` from the long vToken position
4. Swap long → DSA and mint as DSA principal on the PositionAccount
5. Update `suppliedPrincipalVTokens` += newly minted DSA vTokens (profit increases Available Capital)

```solidity
function closeWithProfit(
    IVToken longVToken,
    IVToken shortVToken,
    uint256 closeFractionBps,
    uint256 longAmountToRedeemForRepay,
    uint256 minAmountOutRepay,
    bytes calldata swapDataRepay,
    uint256 longAmountToRedeemForProfit,
    uint256 minAmountOutProfit,
    bytes calldata swapDataProfit
) external;
```

**One-leg close (skip profit conversion):** The profit swap leg is optional. Pass `longAmountToRedeemForProfit = 0`, `minAmountOutProfit = 0`, and `swapDataProfit = "0x"` to skip it. The repay leg always executes. If there is outstanding short debt, `longAmountToRedeemForRepay` must be non-zero — passing zero while debt exists reverts with `MinAmountOutRepayBelowDebt`.

***

#### closeWithLoss

Proportionally closes a fraction of the position when the long asset value is insufficient to cover the proportional short debt. Uses a two-leg approach to repay the full debt fraction.

* **Leg 1** — redeems long collateral, swaps long → short, repays as much debt as possible
* **Leg 2** — redeems DSA collateral, swaps DSA → short (or uses directly if DSA == short via `exitSingleAssetLeverage`), repays remaining debt

Leg 2 is optional — pass `dsaAmountToRedeemForSecondSwap = 0` if leg 1 fully covers the debt. The `suppliedPrincipalVTokens` counter is decremented by the DSA vTokens burned in leg 2, reflecting the principal consumed to cover the loss.

```solidity
function closeWithLoss(
    IVToken longVToken,
    IVToken shortVToken,
    uint256 closeFractionBps,
    uint256 longAmountToRedeemForFirstSwap,
    uint256 shortAmountToRepayForFirstSwap,
    uint256 minAmountOutFirst,
    bytes calldata swapDataFirst,
    uint256 dsaAmountToRedeemForSecondSwap,
    uint256 minAmountOutSecond,
    bytes calldata swapDataSecond
) external;
```

**One-leg close behavior:** Both legs are individually optional, enabling single-asset close paths:

| Close path    | How to invoke                                                                         | When to use                                                                                                  |
| ------------- | ------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------ |
| **Long only** | Set `dsaAmountToRedeemForSecondSwap = 0`                                              | Leg 1 (long → short swap) fully covers the proportional debt; no DSA needs to be burned                      |
| **DSA only**  | Set `longAmountToRedeemForFirstSwap = 0` **and** `shortAmountToRepayForFirstSwap = 0` | Long collateral has been partially or fully seized by a liquidator; only DSA principal remains to repay debt |

**Restriction:** If `longAmountToRedeemForFirstSwap = 0` but `shortAmountToRepayForFirstSwap != 0`, the call reverts with `InvalidLongAmountToRedeem`. Skipping the long leg while claiming a non-zero repay from it would illegitimately reduce the second-leg repay obligation without any actual collateral being redeemed.

***

#### supplyPrincipal

Deposits additional DSA collateral into the PositionAccount without opening a new leveraged trade. Transfers DSA from the caller, calls `vToken.mintBehalf` to supply it on the PositionAccount, and increments `suppliedPrincipalVTokens`.

This is the primary **defensive Health Factor management** tool. Supplying more principal increases the DSA collateral backing the borrow, directly raising the Health Factor without any position unwind or swap. Users facing a declining Health Factor should call this before the position becomes liquidatable. Allowed during partial pause — classified as a defensive operation and never blocked during incidents.

```solidity
function supplyPrincipal(address longVToken, address shortVToken, uint256 amount) external;
```

***

#### withdrawPrincipal

Withdraws Available Capital (unused DSA collateral) from the PositionAccount to the caller's wallet.

The maximum withdrawable amount is computed by `getUtilizationInfo()` as `availableCapitalUSD / dsaPrice`. The function redeems the corresponding DSA vTokens from the PositionAccount and decrements `suppliedPrincipalVTokens`. Blocked during partial pause.

```solidity
function withdrawPrincipal(IVToken longVToken, IVToken shortVToken, uint256 amount) external;
```

***

#### deactivatePosition

Fully exits a position after the short debt has been repaid to zero. Exits all Venus markets, redeems all remaining collateral (both DSA and long), and transfers everything to the caller's wallet.

After deactivation, `isActive` is set to `false` and `suppliedPrincipalVTokens` is cleared. The PositionAccount contract remains deployed — a subsequent call to `activateAndOpenPosition` increments `cycleId` and starts a fresh cycle without redeploying the clone.

When DSA ≠ long, collateral is redeemed from two separate markets. When DSA == long, a single redemption is performed with a treasury fee grossup to avoid over-redemption:

```
grossedUpAmount = ⌈amount / (1 − treasuryPercent)⌉
```

```solidity
function deactivatePosition(IVToken longVToken, IVToken shortVToken) external;
```

***

### 2. PositionAccount

A minimal proxy clone (EIP-1167) deployed per user per trading pair. It holds all collateral and debt positions in Venus and is the sole entity that enters markets and executes borrows and supplies — the RelativePositionManager never holds funds itself.

**Deployment:** Clones use `ClonesUpgradeable.cloneDeterministic` with a CREATE2 salt:

```solidity
salt = keccak256(abi.encodePacked(user, longVToken, shortVToken))
```

This makes the PositionAccount address deterministic and pre-computable via `getPositionAccountAddress()` before the account is deployed.

**Access control:** The `onlyRelativePositionManager` modifier reverts any call not originating from the single trusted RelativePositionManager address. No EOA or other contract can directly move funds out of a PositionAccount.

#### initialize

Called once when the clone is first deployed. Sets the position owner, long vToken, and short vToken for this clone, and approves both the RelativePositionManager and LeverageStrategiesManager as delegates in the Venus Comptroller.

The delegate approval is what allows the RelativePositionManager to call `Comptroller.enterMarketBehalf` and `vToken.mintBehalf` on behalf of the PositionAccount while the PositionAccount remains the on-chain owner of all collateral and debt. The RelativePositionManager and LeverageStrategiesManager addresses are set in the constructor as immutables shared across all clones.

```solidity
function initialize(address owner_, address longVToken_, address shortVToken_) external;
```

***

#### enterLeverage

Initiates the flash loan sequence to open a leveraged long position. Called by the RelativePositionManager as part of `activateAndOpenPosition` and `scalePosition`.

Internally delegates to `LeverageStrategiesManager.flashLoan(...)`, which:

1. Flash-loans `borrowedAmountToFlashLoan` of the short asset from the Comptroller's flash loan module
2. Swaps the short asset to the long asset via the SwapHelper using `swapData`
3. Supplies the resulting long tokens to the PositionAccount's long vToken position via `vToken.mintBehalf`
4. Repays the flash loan by opening a borrow on the PositionAccount's short vToken position

```solidity
function enterLeverage(
    IVToken collateralMarket,
    uint256 collateralAmountSeed,
    IVToken borrowedMarket,
    uint256 borrowedAmountToFlashLoan,
    uint256 minAmountOutAfterSwap,
    bytes calldata swapData
) external onlyRelativePositionManager;
```

***

#### exitLeverage

Initiates the flash loan sequence to close a leveraged position — redeem collateral, swap, and repay debt. Used in both `closeWithProfit` and `closeWithLoss`.

Internally delegates to `LeverageStrategiesManager.flashLoan(...)`, which:

1. Flash-loans `borrowedAmountToFlashLoan` of the short asset
2. Redeems `collateralAmountToRedeemForSwap` from the PositionAccount's collateral vToken position
3. Swaps the redeemed collateral to the short asset via the SwapHelper
4. Repays the flash loan + the original borrow debt using the swap output

```solidity
function exitLeverage(
    IVToken collateralMarket,
    uint256 collateralAmountToRedeemForSwap,
    IVToken borrowedMarket,
    uint256 borrowedAmountToFlashLoan,
    uint256 minAmountOutAfterSwap,
    bytes calldata swapData
) external onlyRelativePositionManager;
```

***

#### exitSingleAssetLeverage

Used when the DSA and the short asset are the same token (e.g., the position uses USDC as both DSA and borrow). In this case, no swap is required to repay the debt — DSA collateral is redeemed directly to cover the borrow.

```solidity
function exitSingleAssetLeverage(
    IVToken collateralMarket,
    uint256 collateralAmountToFlashLoan
) external onlyRelativePositionManager;
```

***

## Position Data Model

```solidity
struct Position {
    address user;                     // Position owner
    address longVToken;               // vToken for the long (supplied) asset
    address shortVToken;              // vToken for the short (borrowed) asset
    address positionAccount;          // Address of the PositionAccount clone
    bool isActive;                    // Whether the position is currently active
    uint8 dsaIndex;                   // Index of the DSA in the dsaVTokens registry
    address dsaVToken;                // vToken for the DSA (collateral and settlement)
    uint256 suppliedPrincipalVTokens; // DSA principal tracked in vToken units
    uint256 effectiveLeverage;        // Stored leverage in 1e18 mantissa
    uint256 cycleId;                  // Incremented each time a position is activated
}
```

**cycleId** provides a monotonically increasing identifier for each activation. This allows off-chain systems and events to distinguish between different activation cycles of the same pair without ambiguity.

**suppliedPrincipalVTokens** is updated on every principal supply, withdrawal, profit conversion, and after liquidations (synced down if the actual balance has been reduced by a liquidator).

***

## Position Lifecycle

### Stage 1: Activation and Opening

`activateAndOpenPosition()` is the entry point. It combines activation and first open into one atomic transaction.

**Activation steps:**

1. Validate that the long and short markets are listed in the Comptroller and are not the same market
2. Validate that vBNB is not used (not supported)
3. Validate that the DSA index refers to an active, registered DSA vToken
4. Validate leverage is in the range `[1e18, maxLeverage]`
5. Deploy a PositionAccount clone if one does not exist for this `(user, long, short)` triple
6. Set `isActive = true`, increment `cycleId`, record `dsaIndex`, `dsaVToken`, `effectiveLeverage`
7. Enter the DSA market on behalf of the PositionAccount via `Comptroller.enterMarketBehalf`
8. Transfer DSA from the user and mint vTokens on behalf of the PositionAccount via `vToken.mintBehalf`
9. Record `suppliedPrincipalVTokens`
10. Emit `PositionActivated` and `PrincipalSupplied`

**Opening steps (executed after activation):**

1. Calculate `maxBorrow` from available capital and clamped leverage
2. Validate `shortAmount <= maxBorrow`
3. Call `positionAccount.enterLeverage(longVToken, 0, shortVToken, shortAmount, minLongAmount, swapData)`
4. LeverageStrategiesManager flash-loans `shortAmount` of the short asset, swaps to the long asset, and mints it on the PositionAccount
5. Any dust from the swap is swept from the PositionAccount to the user's wallet
6. Emit `PositionOpened`

**Maximum leverage formula:**

$$
\text{maxLeverage} = \frac{CF\_{DSA}}{1 - CF\_{long} \times (1 - \text{tolerance})}
$$

Where `tolerance` is the `proportionalCloseTolerance` used as a buffer. This prevents activations that would immediately be at the boundary of the safe borrow range.

***

### Stage 2: Scaling (Adding to a Position)

`scalePosition()` adds additional exposure to an existing active position.

* Optionally supplies additional DSA principal if `additionalPrincipal > 0`
* Recalculates `maxBorrow` using the updated available capital
* Calls `positionAccount.enterLeverage(...)` for the additional amount
* Emits `PositionScaled`

The stored `effectiveLeverage` is not changed by scaling. Only `suppliedPrincipalVTokens` increases if additional principal is supplied.

***

### Stage 3: Closing

Closing is proportional. The caller specifies `closeFractionBps` (1–10000 BPS, where 10000 = 100%) and the system closes exactly that fraction of the current position.

There are two closing paths depending on whether the position is in profit or in loss.

#### Profit Close (`closeWithProfit`)

Used when the long asset value (converted to short asset) exceeds the proportional short debt.

**Validation:**

```
expectedLong = currentLongBalance × closeFractionBps / 10000
totalLong = longAmountToRedeemForRepay + longAmountToRedeemForProfit
assert |totalLong − expectedLong| ≤ expectedLong × proportionalCloseTolerance / 10000
assert minAmountOutRepay ≥ expectedShortDebt (with tolerance bump for 100% closes)
```

**Execution:**

1. Redeem `longAmountToRedeemForRepay` from the PositionAccount's long vToken position
2. Swap long → short via `positionAccount.exitLeverage()`
3. Repay `amountToRepay` of short debt
4. Redeem `longAmountToRedeemForProfit` from the long vToken position
5. Swap long → DSA and mint as DSA principal on the PositionAccount
6. Update `suppliedPrincipalVTokens` += newly minted DSA vTokens
7. Emit `PositionClosed` and `ProfitConverted`

#### Loss Close (`closeWithLoss`)

Used when the proportional long asset value is insufficient to cover the full proportional short debt.

**Two-leg repayment:**

* **Leg 1:** Redeem long collateral → swap to short → repay as much debt as possible
* **Leg 2:** Redeem DSA collateral → swap to short (or use directly if DSA == short) → repay remaining debt

Both legs are individually optional. Set `dsaAmountToRedeemForSecondSwap = 0` to use long collateral only (leg 1 fully covers debt). Set `longAmountToRedeemForFirstSwap = 0` and `shortAmountToRepayForFirstSwap = 0` together to use DSA only (leg 2 only) — this is the correct path when the long collateral has been partially or fully seized by a liquidator and only DSA principal remains.

**Validation:**

```
expectedLong = currentLongBalance × closeFractionBps / 10000
assert |longAmountToRedeemForFirstSwap − expectedLong| within tolerance
expectedShort = currentShortDebt × closeFractionBps / 10000
amountToRepayFirst = min(leg1Output, expectedShort)
amountToRepaySecond = expectedShort − amountToRepayFirst
assert shortDust ≤ expectedShort × proportionalCloseTolerance / 10000
```

**Execution:**

1. Leg 1 (if `longAmountToRedeemForFirstSwap > 0`): `positionAccount.exitLeverage(longVToken → shortVToken)` — redeems long collateral, swaps to short, repays debt
2. Leg 2 (if `dsaAmountToRedeemForSecondSwap > 0`): `positionAccount.exitLeverage(dsaVToken → shortVToken)` — or `exitSingleAssetLeverage` when DSA == short
3. Update `suppliedPrincipalVTokens` -= DSA vTokens burned in leg 2
4. Emit `PositionClosed`

***

### Stage 4: Principal Management

**`supplyPrincipal()`** — deposit additional DSA without opening a new trade. Transfers DSA from the user, mints vTokens on the PositionAccount, increments `suppliedPrincipalVTokens`. This is the recommended action when the Health Factor is declining: adding DSA principal directly increases the collateral backing the borrow and raises HF without any position unwind. A small partial close (`closeWithProfit` or `closeWithLoss` with a low `closeFractionBps`) is the alternative: it repays a proportional slice of debt, which similarly raises HF but also reduces position size.

**`withdrawPrincipal()`** — withdraw Available Capital back to the user's wallet. Validates that `amount <= withdrawableAmount` (from `getUtilizationInfo()`), redeems the corresponding DSA vTokens from the PositionAccount, and decrements `suppliedPrincipalVTokens`.

***

### Stage 5: Deactivation

`deactivatePosition()` fully exits the position account for a trading pair.

**Prerequisites:** The short debt must be fully repaid (zero borrow balance).

**Steps:**

1. Set `isActive = false`, clear `suppliedPrincipalVTokens`
2. Exit all markets and redeem all remaining collateral:
   * **DSA ≠ long:** Redeem all long vTokens, exit DSA market, redeem all DSA vTokens separately
   * **DSA == long:** Redeem all vTokens from the shared market (accounting for the treasury redemption fee grossup)
3. Transfer all redeemed underlying to the user's wallet
4. Emit `PositionDeactivated`

After deactivation, the PositionAccount contract remains deployed. A new activation (`activateAndOpenPosition`) will increment `cycleId` and start a fresh position cycle without redeploying the contract.

***

## Capital Utilization

Capital utilization determines how much of the user's DSA principal is "in use" by the open position and how much can be withdrawn or used to open new positions.

### Formula

```
// Nominal utilization: based on the stored leverage ratio
nominalCapitalUtilized = ⌈borrowValueUSD × 1e18 / clampedLeverage⌉

// Actual utilization: based on how much DSA backing is needed given long collateral
excessBorrow = max(0, borrowValueUSD − longValueUSD × CF_long)
actualCapitalUtilized =
    if CF_dsa > 0: ⌈excessBorrow × 1e18 / CF_dsa⌉
    if CF_dsa == 0 and excessBorrow > 0: suppliedPrincipalUSD  // entire principal is at risk

// Final utilization: conservative (use whichever is higher)
finalCapitalUtilized = min(suppliedPrincipalUSD, max(nominalCapitalUtilized, actualCapitalUtilized))

// Available capital
availableCapitalUSD = suppliedPrincipalUSD − finalCapitalUtilized
withdrawableAmount = availableCapitalUSD × 1e18 / dsaPrice
```

### Leverage Clamping

The stored `effectiveLeverage` is the leverage set at activation. However, if collateral factors change after activation (e.g., governance lowers a CF), the actual maximum leverage may drop below the stored value. In this case, `clampedLeverage = min(storedLeverage, currentMaxLeverage)` is used for all utilization and borrow capacity calculations.

This ensures that capital utilization reporting and borrow limits remain conservative and safe even when market parameters change post-activation.

### Two Utilization Paths

The system tracks utilization from two perspectives simultaneously:

**Nominal:** "Given the leverage ratio I agreed to, how much capital does this position conceptually consume?"

* This path uses the stored leverage and is predictable for users.

**Actual:** "Given the current value of my long collateral and short debt, how much DSA backing is actually needed to maintain the position safely?"

* This path accounts for real market prices and collateral factors.
* The long asset's CF reduces the DSA backing needed (long collateral partially covers the borrow).
* As prices diverge from the entry, this number can grow.

The **maximum of the two** is used as the final utilization, ensuring the most conservative estimate is always applied.

***

## DSA Mechanics

### DSA ≠ Long (Standard Case)

The PositionAccount holds two separate vToken positions:

* Long vTokens (from leveraged swaps)
* DSA vTokens (user's principal)

Principal tracking: `suppliedPrincipalVTokens` directly maps to the DSA vToken balance. Long collateral balance is simply `longVToken.balanceOfUnderlying(positionAccount)`.

### DSA == Long (Shared Market Case)

When the user selects a DSA that is the same token as the long asset (e.g., USDC as both DSA and long), the PositionAccount holds only **one** vToken balance that represents the sum of both.

The RelativePositionManager separates them using:

```
totalVTokens = dsaVToken.balanceOf(positionAccount)
longCollateralVTokens = totalVTokens − suppliedPrincipalVTokens
```

When `suppliedPrincipalVTokens` exceeds `totalVTokens` (which can happen if the position is partially liquidated), the system syncs `suppliedPrincipalVTokens` down to `totalVTokens` and emits `RefreshedSuppliedPrincipal`. This prevents the system from treating liquidated collateral as still available.

**Deactivation in this case** redeems from the shared market in a single call, accounting for the treasury fee grossup to avoid over-redemption:

```
grossedUpAmount = ⌈amount / (1 − treasuryPercent)⌉
```

***

## Proportional Close Tolerance

`proportionalCloseTolerance` (default 100 BPS = 1%) defines the acceptable deviation band for close amounts.

**Why it is needed:** Interest accrues continuously on the borrow position, and swap outputs are subject to slippage. The close amount derived from `closeFractionBps × currentBalance` will not match exactly by the time the transaction executes.

**Tolerance band for long amounts:**

```
lower = expectedLong × (10000 − tolerance) / 10000
upper = expectedLong × (10000 + tolerance) / 10000
assert lower ≤ totalLong ≤ upper
```

**Tolerance bump for 100% closes:** For full closes (closeFractionBps = 10000), the repay amount is bumped by the tolerance to ensure that accumulated interest since the close was estimated does not cause a dust leftover:

```
amountToRepay = expectedShortDebt × (10000 + tolerance) / 10000
```

Any short dust remaining after the repay is validated to be within:

```
shortDust ≤ expectedShort × tolerance / 10000
```

**Governance can adjust `proportionalCloseTolerance`** via `setProportionalCloseTolerance()`. A wider tolerance allows more flexibility but reduces proportionality precision; a narrower tolerance enforces stricter accounting but may cause more reverts due to market movement between estimation and execution.

***

## Flash Loan Integration

Trade uses the existing `LeverageStrategiesManager` for all flash loan execution. The PositionAccount calls into the LeverageStrategiesManager which uses the Venus Comptroller's flash loan module.

### Opening a Position (`enterLeverage`)

```
positionAccount.enterLeverage(
    collateralMarket = longVToken,
    collateralAmountSeed = 0,           // DSA is the true collateral seed, not long
    borrowedMarket = shortVToken,
    borrowedAmountToFlashLoan = shortAmount,
    minAmountOutAfterSwap = minLongAmount,
    swapData = signedMulticallData
)

LeverageStrategiesManager:
  1. Flash loan shortAmount on shortVToken
  2. Swap shortAmount (short) → longAmount (long) using swapData
  3. Mint longAmount into positionAccount.longVToken position
  4. Repay flash loan from positionAccount.shortVToken (opens borrow)
```

### Closing a Position (`exitLeverage`)

```
positionAccount.exitLeverage(
    collateralMarket = longVToken,
    collateralAmountToRedeemForSwap = longAmountToRedeem,
    borrowedMarket = shortVToken,
    borrowedAmountToFlashLoan = shortAmountToRepay,
    minAmountOutAfterSwap = minAmountOutRepay,
    swapData = signedMulticallData
)

LeverageStrategiesManager:
  1. Flash loan shortAmountToRepay on shortVToken
  2. Redeem longAmountToRedeem from positionAccount.longVToken
  3. Swap longAmount (long) → shortAmount (short) using swapData
  4. Repay flash loan + original debt
```

### Same-Asset Close (`exitSingleAssetLeverage`)

When DSA == short (e.g., closing a loss using USDC as both DSA and borrow repayment), no swap is needed:

```
positionAccount.exitSingleAssetLeverage(
    collateralMarket = dsaVToken,      // same as shortVToken
    collateralAmountToFlashLoan = amountToRepay
)

LeverageStrategiesManager:
  1. Flash loan amountToRepay on dsaVToken
  2. Redeem amountToRepay from positionAccount.dsaVToken
  3. Repay flash loan + original debt (no swap)
```

***

## Liquidation

Trade positions are subject to the standard Venus liquidation mechanism. The PositionAccount is a regular address from the Comptroller's perspective — it enters markets, borrows, and supplies like any other account.

When the Health Factor drops below 1 (i.e., the borrow value exceeds the liquidation threshold-weighted collateral value), third-party liquidators can call `liquidateBorrow` on the appropriate vToken. This repays part of the debt and seizes a portion of the supplied collateral at a discount.

**Post-liquidation behavior:**

* If DSA == long, `suppliedPrincipalVTokens` may now exceed the actual vToken balance. The next call to `_getLongCollateralBalance` or `_getSuppliedPrincipalBalance` will detect this and emit `RefreshedSuppliedPrincipal` to sync the counter down.
* The position remains `isActive = true` after liquidation. The user can still manage (close, supply, withdraw) the reduced position.

***

## Pause Mechanism

The contract supports two pause levels:

| Pause Level        | Blocked Operations                                                                    | Allowed Operations                                    |
| ------------------ | ------------------------------------------------------------------------------------- | ----------------------------------------------------- |
| **Partial Pause**  | `activateAndOpenPosition`, `scalePosition`, `withdrawPrincipal`, `deactivatePosition` | `closeWithProfit`, `closeWithLoss`, `supplyPrincipal` |
| **Complete Pause** | All state-changing operations                                                         | None                                                  |

This design allows governance to freeze risky operations (opening new exposure, withdrawing, deactivating) while keeping defensive operations (closing, adding collateral) available during an incident.

***

## Governance and Access Control

All privileged functions are gated via the Venus `AccessControlManager`.

| Function                            | Permission Required | Notes                                         |
| ----------------------------------- | ------------------- | --------------------------------------------- |
| `setPositionAccountImplementation`  | Admin               | One-time; locked after first call             |
| `addDSAVToken`                      | Admin               | Adds a new stablecoin to the DSA registry     |
| `setDSAVTokenActive`                | Admin               | Enables/disables DSA for new activations      |
| `setProportionalCloseTolerance`     | Admin               | Adjusts the close tolerance band              |
| `partialPause` / `partialUnpause`   | Admin               | Toggles partial pause                         |
| `completePause` / `completeUnpause` | Admin               | Toggles complete pause                        |
| `executePositionAccountCall`        | Admin               | Emergency call forwarder (e.g., asset rescue) |

**DSA management:** When a DSA is set to inactive (`setDSAVTokenActive(index, false)`), existing positions using that DSA are unaffected. Only new position activations are blocked from selecting that DSA index.

**PositionAccount implementation:** The EIP-1167 clone implementation is set once and then locked (`isPositionAccountImplementationLocked = true`). This prevents governance from changing the implementation after positions have been deployed, ensuring users' PositionAccount contracts are immutable.

***

## Security Considerations

### Access Control

* Only the RelativePositionManager can call PositionAccount methods. All external position operations are gated through this single entrypoint.
* All admin functions are controlled by the Venus `AccessControlManager`.

### Reentrancy

* `ReentrancyGuardUpgradeable` is applied to all state-changing external functions on the RelativePositionManager.

### Oracle Dependency

* All USD value calculations use the Venus `ResilientOracle`. If an oracle price is zero or stale, the relevant function reverts with `InvalidOraclePrice`.

### Flash Loan Safety

* The flash loan callback (`executeOperation`) on the LeverageStrategiesManager validates that the initiator is the LeverageStrategiesManager itself and that the caller is the Comptroller, preventing unauthorized replay.

### Proportional Close Integrity

* The tolerance band enforces that close amounts cannot deviate significantly from the intended BPS fraction. This prevents griefing attacks that would allow disproportionate collateral extraction relative to debt repayment.

### PositionAccount Immutability

* The EIP-1167 clone implementation is locked after the first call to `setPositionAccountImplementation`. This means the RelativePositionManager cannot upgrade the PositionAccount logic for existing positions after deployment.

***

## Audits

RelativePositionManager and PositionAccount were audited by CertiK and Quantstamp before mainnet deployment. Audit reports are available in the [venus-periphery repository](https://github.com/VenusProtocol/venus-periphery/tree/main/audits) and in the [Security & Audits](/links/security-and-audits) section of the Venus documentation.


# Fixed Term Vaults

A Fixed Term Vault is a two-party, fixed-term loan between an institution and a pool of on-chain suppliers. The institution borrows a stablecoin against crypto collateral at a rate and duration agreed at vault creation. Suppliers commit capital during a short fundraising window; at maturity they redeem their shares for principal plus the fixed interest, regardless of market conditions between entry and settlement.

Each vault is a fully isolated contract clone — its own collateral, its own debt, its own supplier shares. A default, liquidation, or governance action in one vault has zero effect on any other vault or on Venus core markets.

## Architecture

### Contracts

The system is composed of four contracts. Each vault is an independent clone deployed by the controller — there is no shared state between loans.

<figure><img src="/files/BCy7XO489DsdQwQfHaf5" alt="Fixed Term Vault contract architecture diagram"><figcaption><p>The controller deploys a fresh vault clone and mints a position NFT per loan; all liquidation calls are routed through the LiquidationAdapter</p></figcaption></figure>

[**InstitutionalVaultController**](/technical-reference/reference-fixed-rate-vaults/institutional-vault-controller) is the sole factory and the only conduit through which any admin operation reaches a vault. It deploys each vault clone and mints the corresponding position NFT in the same transaction. It also exposes the ACM-gated lifecycle calls (`openVault`, `cancelVault`, `partialPauseVault`, `completePauseVault`, `unpauseVault`, `closeVault`) and risk-parameter updates that governance invokes separately over the life of each vault. All ACM permission checks are enforced here — individual vaults carry no ACM wiring and trust calls from the controller implicitly. Deployed behind a transparent proxy, so governance policy can be updated without touching live contracts.

[**InstitutionalLoanVault**](/technical-reference/reference-fixed-rate-vaults/institutional-loan-vault) is the core execution contract for a single loan. It holds all assets — collateral and supply stablecoin — enforces the `VaultState` machine, and is the only place debt is created, tracked, and cleared. Suppliers interact through the standard ERC-4626 interface (`deposit`, `mint`, `withdraw`, `redeem`); institution-side calls (`depositCollateral`, `claimRaisedFunds`, `withdrawCollateral`) are gated by `onlyPositionHolder`; liquidation entry points are gated by `onlyLiquidationAdapter`. Each vault is deployed as an EIP-1167 minimal proxy clone — non-upgradeable and single-use. Its rules are immutable from the moment it goes live, and renewing a deal always means deploying a fresh clone rather than resetting an existing one.

[**InstitutionPositionToken**](/technical-reference/reference-fixed-rate-vaults/institution-position-token) is a singleton ERC-721 shared across all vaults — one contract, one token ID per vault. Whoever holds a given token ID controls all institution-side operations on that vault, since `depositCollateral`, `claimRaisedFunds`, and `withdrawCollateral` all resolve to `positionToken.ownerOf(positionTokenId)` at call time. Keeping ownership in a transferable NFT rather than hardcoded in the vault means control can move to a new address without any state change inside the vault itself. Every transfer requires a prior single-use governance approval via `approvePositionTransfer(vault, recipient)`, consumed on the next `safeTransferFrom`.

[**LiquidationAdapter**](/technical-reference/reference-fixed-rate-vaults/liquidation-adapter) is the only address permitted to call `vault.liquidate()`, enforced by `onlyLiquidationAdapter` on each vault. The vault itself does one thing: check whether the health factor permits liquidation. Everything else — who is allowed to liquidate, how much they can seize, at what incentive rate, and what share goes to the protocol — is owned entirely by the adapter. Whitelisted liquidators and overdue settlers are registered here via two independent ACM-gated lists. Parameters like `closeFactor` and `protocolLiquidationShare` live here too, meaning governance can tune liquidation behaviour across the entire system without touching any deployed vault. The adapter also accumulates the protocol's share of seized collateral and transfers it to PSR via `sweepProtocolShareToReserve(address collateral)`.

### BaseVault, ERC-4626, and extensibility

`InstitutionalLoanVault` inherits `BaseVault`, an abstract contract built on top of ERC-4626 that was designed to be reusable across different kinds of fixed-term vault. `BaseVault` captures everything that any such vault has in common — fundraising, interest computation, the settlement waterfall, state machine scaffolding, and the pause system — so a new vault type only has to implement what is specific to its loan structure. Future vault types follow the same pattern: inherit `BaseVault`, override its three virtual hooks (`_checkAndAdvanceState`, `_afterWithdrawHook`, `_beforeClaimRaisedFunds`), and add the remaining type-specific logic on top.

ERC-4626 is used as the supplier-facing API, but several methods deviate from the specification to enforce lifecycle constraints:

| Method        | Standard behaviour                      | Vault behaviour                                                                 |
| ------------- | --------------------------------------- | ------------------------------------------------------------------------------- |
| `deposit`     | Always open; reverts on cap breach      | Only in `Fundraising`; excess silently clamped to remaining cap, not reverted   |
| `mint`        | Always open; reverts on cap breach      | Only in `Fundraising`; excess silently clamped                                  |
| `withdraw`    | Available any time (subject to balance) | Only in terminal states (`Matured`, `Failed`, `Liquidated`)                     |
| `redeem`      | Available any time (subject to balance) | Only in terminal states                                                         |
| `maxDeposit`  | Returns `type(uint256).max`             | Returns `maxBorrowCap − totalRaised`; zero outside `Fundraising`                |
| `maxWithdraw` | Returns asset value of shares           | Zero outside terminal states                                                    |
| `maxRedeem`   | Returns `balanceOf(owner)`              | Zero outside terminal states                                                    |
| `totalAssets` | Returns live underlying balance         | Returns `totalRaised` pre-terminal; switches to `settlementAmount` once settled |

`totalAssets()` is backed by internal accounting variables (`totalRaised` and `settlementAmount`) rather than `balanceOf(address(this))`. Tokens sent directly to the vault address have no effect on the share price, which removes the donation-based inflation attack that affects naive ERC-4626 implementations.

`minSupplierDeposit` adds a minimum deposit floor absent from the spec. The floor is waived for the final deposit that fills the remaining capacity exactly, preventing the vault from getting permanently stuck below `maxBorrowCap` when the residual slot is smaller than the minimum. Fee-on-transfer and rebasing tokens are not supported for either the supply asset or collateral.

### Oracle

All USD valuations in the system route through Venus `ResilientOracle`. The vault calls `oracle.getPrice(asset)`, which returns a price scaled to `36 − asset.decimals()` decimal places — always expressed as an 18-decimal USD value per token unit regardless of the token's own decimals. A zero price reverts with `InvalidOraclePrice`.

Both the supply asset and the collateral asset must have a non-zero oracle price at vault creation. The controller probes the oracle during `createVault` and reverts with `InvalidConfig` if either price is missing. This prevents a vault from entering price-dependent states — liquidation checks, claim validation, bad-debt detection — with an asset the oracle cannot price.

## State machine

The vault tracks lifecycle as a `VaultState` enum. Transitions are monotonic — no state ever goes backward. Every non-view entry point calls `_checkAndAdvanceState()` before its own logic, so state advances automatically on the first relevant call after a trigger condition is met. All transitions after `openVault` are automatic — no governance call is needed to move the vault from `Fundraising` through `Lock`, `PendingSettlement`, and into a terminal state. For cases where no interaction is pending but conditions for a transition are already met, anyone can call `updateVaultState()` to advance the state explicitly.

<figure><img src="/files/YD5fEcldBGF1ZyNdwmjK" alt="Fixed Term Vault state machine diagram"><figcaption><p>State transitions are monotonic — no state ever goes backward. Dashed red paths show cancel and failure routes; the grey arrows at the bottom show all three terminal states collapsing into Closed via <code>closeVault()</code></p></figcaption></figure>

## Core mechanics

### Margin deposit

Before suppliers can interact, the institution must post a security deposit — the required margin — in a single `depositCollateral` call. It acts as a credible commitment: the institution either tops up collateral to `idealCollateralAmount` before fundraising closes or forfeits the margin to suppliers. The vault stays in `WaitingForMargin` until this condition is met:

$$\text{requiredMargin} = \text{idealCollateralAmount} \times \frac{\text{marginRate}}{10^{18}}$$

Once `totalCollateralDeposited ≥ requiredMargin` the vault advances to `MarginDeposited`, where it waits for governance to inspect the configuration and call `openVault()` to open the fundraising window.

### Fundraising

`deposit` and `mint` are permissionless during `Fundraising`. Unlike standard ERC-4626, both calls silently clamp to remaining capacity (`maxBorrowCap - totalRaised`): a `deposit` that exceeds the cap fills the residual and mints fewer shares than requested, rather than reverting. `minSupplierDeposit` is enforced on every call except one that fills or exceeds the remaining capacity — because the residual may be smaller than the minimum, skipping the check on that deposit prevents the vault from being permanently stuck below `maxBorrowCap`. Share tokens are standard ERC-20s, freely transferable at all times.

At `fundraisingEndTime` both sides are evaluated simultaneously. If `totalRaised ≥ minBorrowCap` and `totalCollateralDeposited ≥ idealCollateralAmount` the vault transitions to `Lock` and the loan begins.

If either condition is not met, the vault transitions to `Failed`. Two distinct failure modes are possible, distinguished by `InstitutionalRuntime.institutionDefaulted`:

**Raise shortfall** (`totalRaised < minBorrowCap` at window close). `institutionDefaulted = false`. No default has occurred; suppliers recover full principal and the institution recovers all collateral including the margin.

**Collateral underdelivery** (`totalRaised ≥ minBorrowCap` but `totalCollateralDeposited < idealCollateralAmount` at window close). `institutionDefaulted = true`. Only the pre-determined margin is confiscated, not the institution's full collateral position. `confiscatedMargin` is set to exactly `requiredMargin`:

$$\text{requiredMargin} = \text{idealCollateralAmount} \times \frac{\text{marginRate}}{10^{18}}$$

Suppliers recover principal plus a pro-rata share of `confiscatedMargin` (see [Margin confiscation](#margin-confiscation-collateral-underdelivery) for the per-redemption distribution). The institution recovers `totalCollateralDeposited - confiscatedMargin`.

#### Margin confiscation: collateral underdelivery

When the vault fails via collateral underdelivery, `confiscatedMargin = requiredMargin`. Each `withdraw` / `redeem` triggers `_afterWithdrawHook`, which distributes a pro-rata slice of the remaining confiscated margin:

$$\text{compensation} = \text{confiscatedMarginRemaining} \times \frac{\text{shares}}{\text{totalSupplyBeforeBurn}}$$

Compensation is denominated in the **collateral asset** (e.g. BTC or ETH), not the supply stablecoin. `confiscatedMarginRemaining` decrements on every redemption, so early redeemers and late redeemers receive the same proportion.

### Lock entry and borrowing

When the vault transitions to `Lock`, two values are fixed for the lifetime of the loan:

**Total interest** is stored immediately as `totalDebt` and is owed in full regardless of when the institution repays — there is no early-repayment discount:

$$\text{totalInterest} = \frac{\text{totalRaised} \times \text{fixedAPY} \times \text{lockDuration}}{\text{BPS} \times \text{YEAR}}$$

`BPS = 10000`, `YEAR = 365 days`. `totalDebt = totalInterest` at lock entry; after `claimRaisedFunds` it becomes `totalInterest + totalRaised`.

**Minimum collateral floor** is recalculated proportionally to the actual raise. When the raise underfills `maxBorrowCap`, the floor scales down, freeing excess collateral above it for withdrawal during `Lock`:

$$\text{minimumCollateralRequired} = \text{idealCollateralAmount} \times \frac{\text{totalRaised}}{\text{maxBorrowCap}}$$

#### Claiming raised funds

`claimRaisedFunds()` is a one-shot call (gated by `fundsWithdrawn`), available only in `Lock`. It transfers the entire supply asset balance to the position-NFT holder. Before releasing funds, it simulates **interest plus principal** against current collateral via `_getHypotheticalVaultLiquidity(0, totalRaised)` — not just the principal being claimed. The call reverts with `ClaimWouldBreachLT` if the combined debt would breach the liquidation threshold.

After a successful claim, `totalDebt = totalInterest + totalRaised` — the full lifetime obligation.

#### Repaying

`repay(amount)` is unrestricted: any address can reduce `totalDebt` by pulling supply asset from its own balance. This is intentional — third parties can service the debt without holding the position NFT. Available in `Lock`, `PendingSettlement`, and `SettlementDeadlineExceeded`; overpayment silently clamps to `outstandingDebt()`.

#### Collateral during Lock

The institution may add or withdraw collateral during `Lock`. Withdrawal requires both checks to pass:

1. **Floor check** — `totalCollateralDeposited − amount ≥ minimumCollateralRequired`. The locked floor cannot be touched.
2. **LT health check** — the post-withdrawal state must not produce an LT shortfall.

The tighter of the two determines how much can be withdrawn.

### Settlement window

At `lockEndTime` the vault enters `PendingSettlement`. This state is never skipped — even if the institution cleared all debt before the lock expired, the vault holds in `Lock` until `block.timestamp ≥ lockEndTime`, then moves to `PendingSettlement`, and only transitions to `Matured` once `outstandingDebt() == 0`.

The institution has until `settlementDeadline` to repay in full. `repay()` remains available and unrestricted throughout. If the debt is cleared before the deadline the vault moves to `Matured` and the settlement waterfall runs. If the deadline passes with debt still outstanding the vault enters `SettlementDeadlineExceeded` — the institution may still repay voluntarily, but whitelisted settlers can now trigger overdue liquidation at the late-penalty rate (see [Overdue](#overdue)).

### Settlement waterfall

On entry to `Matured` or `Liquidated`, `_settleProtocolShare` runs once and distributes the supply asset balance:

| Branch                     | Condition                                               | Protocol fee                                | `settlementAmount`                  |
| -------------------------- | ------------------------------------------------------- | ------------------------------------------- | ----------------------------------- |
| Full repayment             | `available ≥ totalRaised + totalInterest`               | `totalInterest × reserveFactor`             | `available − protocolFee − surplus` |
| Partial interest shortfall | `totalRaised < available < totalRaised + totalInterest` | `(available − totalRaised) × reserveFactor` | `available − protocolFee`           |
| Principal shortfall        | `available ≤ totalRaised`                               | 0                                           | `available`                         |

Surplus above `totalRaised + totalInterest` is forwarded to PSR. `ShortfallDetected(expected, available)` fires in the shortfall branches.

`totalAssets()` returns `totalRaised` throughout `Lock` and `PendingSettlement`, then switches to `settlementAmount` once the vault settles — the conversion anchor for all ERC-4626 share-to-asset calculations on redemption. Each supplier's payout on redemption is:

$$\text{payout} = \text{shares} \times \frac{\text{settlementAmount}}{\text{totalSupply}}$$

### Liquidation

#### Health factor

The vault's health is computed by `_getHypotheticalVaultLiquidity`, which follows the same accounting approach as Compound V2 (the protocol Venus is built on) — collateral is weighted by a liquidation threshold and compared against outstanding debt, both expressed in USD:

$$\text{LT-cap} = \frac{\text{collateralUSD} \times \text{liquidationThreshold}}{10^{18}}$$

$$\begin{cases} \text{liquidity} = \text{LT-cap} - \text{debtUSD} & \text{if } \text{debtUSD} \leq \text{LT-cap} \ \text{shortfall} = \text{debtUSD} - \text{LT-cap} & \text{otherwise} \end{cases}$$

`liquidationThreshold` is a mantissa (e.g. `0.85e18` = 85%). A shortfall greater than zero means the vault is liquidatable. The same function is used with non-zero `withdrawAmount` or `additionalDebt` arguments to simulate hypothetical state changes — called by `claimRaisedFunds` and `withdrawCollateral` before executing the action, so neither operation can push the vault into an underwater position.

#### Seize calculation and Compound V2 lineage

The collateral seize formula is taken directly from Compound V2. In Compound V2, liquidators repay debt in the borrowed asset and receive collateral at a bonus rate. The same principle applies here: the repaid value is converted to USD, multiplied by the incentive multiplier, then divided by the collateral price to arrive at collateral units:

$$\text{seizeAmount} = \frac{\text{repayAmount} \times \text{supplyPrice} \times \text{incentive}}{10^{18} \times \text{collateralPrice}}$$

`incentive` is `liquidationIncentive` for health-based liquidations and `latePenaltyRate` for overdue liquidations. Both are mantissa-encoded multipliers greater than `1e18` — an incentive of `1.1e18` means the liquidator receives 10% more collateral than the repaid debt's USD value. Prices come from `ResilientOracle.getPrice()` scaled to `36 − asset.decimals()` decimal places.

The vault transfers the full `seizeAmount` to `LiquidationAdapter`. The adapter then isolates the bonus slice and takes the protocol's share of that slice only — not of the full seizure:

```
repayEquivalent  = totalSeized × MANTISSA_ONE / incentive
incentiveAmount  = totalSeized − repayEquivalent
protocolAmount   = incentiveAmount × protocolLiquidationShare / MANTISSA_ONE
callerAmount     = totalSeized − protocolAmount
```

This mirrors Compound V2's `liquidationIncentiveMantissa` accounting: the protocol treasury participates only in the bonus, leaving the principal-equivalent collateral recovery entirely with the liquidator.

#### Health-based

Available in `Lock`, `PendingSettlement`, and `SettlementDeadlineExceeded` when the vault has a non-zero shortfall (see [Health factor](#health-factor) above).

Whitelisted liquidators call `LiquidationAdapter.liquidate(vault, repayAmount)`. The adapter validates vault registration and forwards to `vault.liquidate(repayAmount)` through the `onlyLiquidationAdapter` modifier. Inside the vault, `liquidate()` checks for an LT shortfall and reverts with `NotLiquidatable` if none exists; `_executeLiquidation` then enforces the close factor: if `actualRepay > outstandingDebt × closeFactor` the call reverts with `ExceedsCloseFactor` — it is a hard revert, not a silent cap. (`actualRepay` is `min(repayAmount, outstandingDebt)` — the close-factor check fires on the clamped value, not the raw input.) Seized collateral is split between the caller and the protocol per the formula above.

A health-based liquidation does not directly trigger a state transition. The vault advances normally — through `PendingSettlement` and into `Matured` once debt is zero. The `Liquidated` state is never reached via health-based liquidation.

#### Overdue

Available once the vault enters `SettlementDeadlineExceeded`. No LT shortfall is required — the time breach alone qualifies. The same `closeFactor` cap applies, but collateral is seized at `latePenaltyRate` instead of `liquidationIncentive`. A vault that breaches both the LT cap and the deadline can be liquidated through either path; the chosen path determines the bonus rate. Like health-based liquidation, an overdue liquidation that clears all debt transitions the vault to `Matured`, not `Liquidated`. The `Liquidated` state is reached exclusively via `repayBadDebt`.

#### Bad-debt rescue

Available in `Lock`, `PendingSettlement`, and `SettlementDeadlineExceeded` whenever the USD value of deposited collateral falls below the USD value of outstanding debt. `repayBadDebt` is permissionless — any address may call it. The repayment must be large enough to reduce `totalDebt` to at most `totalInterest` in a single call (i.e., the principal must be fully covered); the call reverts with `InsufficientRepayment` otherwise. Once that condition is met the vault transitions to `Liquidated` and the settlement waterfall runs immediately over the combined supply asset balance. Without a rescue the vault remains in whichever state it was in and suppliers have no recourse beyond ordinary liquidation.

## Risk parameters

All tunable parameters grouped by contract, mutability, and who sets them.

**Set once at vault creation via `createVault` — fixed for the life of the vault:**

| Parameter                | Location                                    | Units                  | Constraint                                                     |
| ------------------------ | ------------------------------------------- | ---------------------- | -------------------------------------------------------------- |
| Supply asset             | `VaultConfig.supplyAsset`                   | address                | Must have non-zero oracle price; must differ from collateral   |
| Collateral asset         | `InstitutionalConfig.collateralAsset`       | address                | Must have non-zero oracle price; must differ from supply asset |
| Target APR               | `VaultConfig.fixedAPY`                      | basis points           | 1 – 10 000                                                     |
| Reserve factor           | `VaultConfig.reserveFactor`                 | mantissa               | ≤ `1e18`                                                       |
| Minimum borrow cap       | `VaultConfig.minBorrowCap`                  | supply asset units     | > 0; ≤ `maxBorrowCap`                                          |
| Maximum borrow cap       | `VaultConfig.maxBorrowCap`                  | supply asset units     | ≥ `minBorrowCap`                                               |
| Minimum supplier deposit | `VaultConfig.minSupplierDeposit`            | supply asset units     | 0 = no floor                                                   |
| Fundraising duration     | `VaultConfig.openDuration`                  | seconds                | > 0                                                            |
| Lock duration            | `VaultConfig.lockDuration`                  | seconds                | > 0                                                            |
| Settlement window        | `VaultConfig.settlementWindow`              | seconds                | > 0                                                            |
| Ideal collateral amount  | `InstitutionalConfig.idealCollateralAmount` | collateral token units | > 0                                                            |
| Margin rate              | `InstitutionalConfig.marginRate`            | mantissa               | 0 < rate ≤ `1e18`                                              |

**Set at vault creation — mutable per vault by governance via the controller:**

| Parameter             | Location                          | Units    | Constraint                                                       |
| --------------------- | --------------------------------- | -------- | ---------------------------------------------------------------- |
| Liquidation threshold | `RiskConfig.liquidationThreshold` | mantissa | 0 < LT ≤ `1e18`; `LT × LI < 1e36`; `LT × latePenaltyRate < 1e36` |
| Liquidation incentive | `RiskConfig.liquidationIncentive` | mantissa | `1e18 < LI ≤ 1.5e18`; `LT × LI < 1e36`                           |
| Late penalty rate     | `RiskConfig.latePenaltyRate`      | mantissa | `1e18 < rate ≤ 1.5e18`; `LT × rate < 1e36`                       |

**Held on `LiquidationAdapter` — global across all vaults, mutable by governance:**

| Parameter                  | Field                      | Constraint      |
| -------------------------- | -------------------------- | --------------- |
| Close factor               | `closeFactor`              | 0 < CF ≤ `1e18` |
| Protocol liquidation share | `protocolLiquidationShare` | ≤ `1e18`        |

The constraint `LT × LI < 1e36` (and the equivalent for `latePenaltyRate`) ensures that a liquidation always improves vault health rather than worsening it. The controller enforces this invariant on both creation (`_validateLiquidationInvariant`) and every subsequent per-vault update.

## Governance and access control

### Pause system

A two-level pause is controlled by governance via `partialPauseVault` / `completePauseVault`:

| Level        | Blocked                                                    | Live                                       |
| ------------ | ---------------------------------------------------------- | ------------------------------------------ |
| **Partial**  | `deposit`, `mint`, `depositCollateral`, `claimRaisedFunds` | `repay`, `liquidate`, `withdraw`, `redeem` |
| **Complete** | All vault interactions                                     | —                                          |

By design, governance can freeze new supply and collateral operations without interrupting active debt service or liquidations.

### Position NFT

`depositCollateral`, `claimRaisedFunds`, and `withdrawCollateral` are gated by `onlyPositionHolder`, which checks `positionToken.ownerOf(positionTokenId) == msg.sender` at call time. Transferring the NFT immediately reassigns control of all three. `repay` carries no such guard — intentional, for the permissionless debt-service case.

NFT transfers require a single-use governance approval: `approvePositionTransfer(vault, recipient)` records the approved target, consumed on the next `safeTransferFrom`. `revokePositionTransfer` cancels a pending approval before it is used.

### ACM permissions

Governance operations (create, open, cancel, pause, close, risk-parameter updates) route through `InstitutionalVaultController` and are gated per selector by the Venus AccessControlManager. Liquidation entry points on the vault are gated by `onlyLiquidationAdapter`; the adapter maintains its own ACM-gated whitelists for liquidators and settlers independently.

## Further reading

* [Supplier Guide](/guides/fixed-rate-vaults/supplier-guide)
* [Institution Guide](/guides/fixed-rate-vaults/institution-guide)
* [Solidity API Reference](/technical-reference/reference-fixed-rate-vaults)
* [Repository](https://github.com/VenusProtocol/fixed-rate-vaults)


# Native Token Gateway

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.

## Overview

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.

## User Journey

The 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:

### Approve Delegate

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.

## Interaction with the NativeTokenGateway contract

### Supply (**wrapAndSupply**)

* 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.

### Redeem

1. **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.
2. **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:
     * 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.

### Borrow (**borrowAndUnwrap**)

* 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.

### Repay (**wrapAndRepay**)

* 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.


# Omnichain Governance

## System Overview

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](https://github.com/LayerZero-Labs/omnichain-governance-executor/tree/main).

### Key features

1. **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.
2. **Inter-chain communication:**
   * LayerZero provides secure and reliable cross-chain messaging for remote execution commands.
3. **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.
4. **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.
5. **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.

### Detailed breakdown

1. **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.
2. **Remote Execution Flow:**
   * Commands for destination networks generate a "Remote VIPs payload”
   * The payload is routed to the destination network using the bridge solution.
3. **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)
4. **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.
5. **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.
6. **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.

## Detailed overview of remote proposal execution (step-by-step)

1. 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:
  * `chainID`: Identifies the destination network for the remote execution (`endpointId` according to [LayerZero](https://layerzero.gitbook.io/docs/technical-reference/mainnet/supported-chain-ids)).
  * `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.

2. 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.

3. 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.

4. 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.
  * **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.

5. Receiving and Queuing on the Destination Network

<figure><img src="/files/PsMi3yvCWBJ5rlFDfnex" alt="Omnichain Governance VIP states"><figcaption></figcaption></figure>

* 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.

6. 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.

7. Ownership and Access Control

* `OmnichainProposalSender` (BNB Chain):
  * Owned by: NormalTimelock contract on the BNB Chain.
  * Authorized callers: the Normal and Fast-track Timelocks are authorized to call the `execute` function on this contract. The Critical Timelock was also authorized originally, but every permission it held was revoked in [VIP-645](https://app.venus.io/#/governance/proposal/645?chainId=56).
* `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.

## Potential Failures and Retry Options

* 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.
* If a proposal's queueing fails on the destination network due to insufficient gas, the message will be saved and can be retried with the `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.

## Contracts overview

<figure><img src="/files/HPXhwasfcFIJ2Ejq5qPm" alt="Omnichain Governance contracts"><figcaption></figcaption></figure>

### Contract 1: `BaseOmnichainControllerSrc`

#### Functionality

This 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.

#### Key features

1. **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.
2. **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.
3. **Pausable**: Implements a pausing mechanism, inherited from the OpenZeppelin `Pausable` contract. This functionality allows the contract owner to temporarily halt omnichain communication if necessary.

#### Architecture

* **Inheritance**: Extends the functionalities of the `Ownable` and `Pausable` contracts from OpenZeppelin, inheriting ownership management and pausing capabilities.

#### State variables

* **`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.
* **`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.

#### Events

* **`SetMaxDailyLimit (event)`**: Emitted when the daily command limit for a chain is modified.
* **`NewAccessControlManager (event)`**: Triggered when the address of the `AccessControlManager` is updated.

#### Functions

* **`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`.
* **`pause()`**: Triggers the paused state, halting omnichain communication. Requires `AccessControlManager` permission.
* **`unpause()`**: 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`.

### Contract 2: `OmnichainProposalSender`

#### Functionality

This 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.

#### Key features

* **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.
* **Security Measures**: Enforces access control using the `AccessControlManager` for critical functions.

#### Architecture

* **Inheritance**: Inherits functionalities from both the `ReentrancyGuard` and `BaseOmnichainControllerSrc` contracts, providing reentrancy protection and foundational omnichain communication capabilities.

#### State variables

* **`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.
* **`trustedRemoteLookup (mapping)`**: Maps remote chain IDs to trusted remote contract addresses for message transmission.

#### Events

* **`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.
* **`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.

#### Functions

* **`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.
* **`execute(uint16 remoteChainId_, bytes calldata payload_, bytes calldata adapterParams_)`**: Sends a message to execute a remote proposal, storing execution hashes if the message fails.
* **`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.

### Contract 3: `BaseOmnichainControllerDest`

#### Functionality

This contract serves as the base for the Omnichain controller destination contract. It provides functionality related to daily command limits and pausing.

#### State variables

* **`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.

#### Events

* **`SetMaxDailyReceiveLimit (event)`**: Emitted when the maximum daily limit for receiving commands from BNB Chain is modified.

#### Functions

* **`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.
* **`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.

### Contract 4: `OmnichainGovernanceExecutor`

#### Functionality

This contract executes proposal transactions sent from the main chain. It controls LayerZero configuration and implements a non-blocking behavior.

#### State variables

* **`GUARDIAN (address)`**: A privileged role that can cancel any proposal.
* **`srcChainId (uint16)`**: Stores the layerzero endpoint ID.
* **`lastProposalReceived (uint256)`**: Last proposal count received.
* **`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.

#### Events

* **`ProposalReceived (event)`**: Emitted when a proposal is received.
* **`ProposalQueued (event)`**: Emitted when a proposal is queued.
* **`ProposalExecuted (event)`**: Emitted when a proposal is executed.
* **`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.

#### Functions

* **`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.
* **`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.

### Contract 5: `OmnichainExecutorOwner`

#### Functionality

The 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.

#### State variables

* **`OMNICHAIN_GOVERNANCE_EXECUTOR (immutable)`:**
  * This variable holds the address of the `OmnichainGovernanceExecutor` contract and is immutable once initialized.
* **`functionRegistry (mapping)`:**
  * 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.

#### Events

* **`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).

#### Functions

* **`constructor(address omnichainGovernanceExecutor_)`:**
  * Initializes the contract with the address of the `OmnichainGovernanceExecutor` contract.
  * This constructor ensures that the provided address is not zero.
* **`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.

### Contract 6: `TimelockV8`

#### Functionality

The `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.

#### Key features

* **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.
* **Transaction Cancellation:** Allows cancellation of queued transactions before execution, providing flexibility and control.

#### Events

* **`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.
* **`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.

#### Constants

* **`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).

#### State variables

* **`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.

#### Functions

* **`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.
* **`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.


# Prime tokens

{% hint style="info" %}
Venus Prime runs on the PrimeV2 + PrimeLeaderboard architecture, live on BNB Chain mainnet. Other networks still run the earlier Prime (V1) contract and migrate to PrimeV2 per-chain via governance.
{% endhint %}

## Overview

This technical article explains the implementation details of the Venus Prime program. The high-level overview of the program can be found [here](/whats-new/prime-yield).

Venus Prime is split across two contracts:

* **PrimeV2** — holds Soulbound Prime tokens, tracks per-market user scores, and distributes boosted rewards funded by protocol revenue through `PrimeLiquidityProvider`.
* **PrimeLeaderboard** — tracks time-weighted XVS staking and exposes a **Prime Score** used to decide who is eligible to mint a Prime token.

<figure><img src="/files/L9d4m7kuHcja4nw8OMix" alt="Venus Prime architecture: XVSVault, PrimeLeaderboard, PrimeV2, PrimeLiquidityProvider and governance"><figcaption><p>PrimeV2 architecture — eligibility, governance and reward wiring</p></figcaption></figure>

## Eligibility and the leaderboard

### Prime Score

A user's **Prime Score** is their time-weighted stake, exposed on-chain via `getEffectiveStake` / `getEffectiveStakeBatch` (the contract returns it as `effectiveStake`).

`PrimeLeaderboard` records each user's XVS deposits as individual tranches (amount + timestamp). It is notified of every stake change by the `XVSVault` through the existing `xvsUpdated(user)` callback, which diffs the user's current vault stake (net of pending withdrawal requests) against the last known total and records a deposit or a LIFO withdrawal accordingly.

Each tranche earns a multiplier based on how long it has been held:

| Holding duration | Multiplier (1e18) |
| ---------------- | ----------------- |
| < 30 days        | 1.0x (base)       |
| ≥ 30 days        | 1.3x              |
| ≥ 60 days        | 1.6x              |
| ≥ 90 days        | 2.0x (cap)        |

The Prime Score is:

```jsx
primeScore = Σ  deposit.amount × multiplier(holdingDuration) × min(holdingDuration, capSeconds)
```

where `capSeconds` is the longest configured tier duration (90 days by default). Tiers and the cap are configurable via `setMultiplierTiers(durations, multipliers)`; durations and multipliers must be strictly ascending and multipliers must be ≥ base (1e18).

Withdrawals are processed **LIFO** so the oldest, highest-multiplier deposits survive longest. To bound gas, a user keeps at most `MAX_DEPOSITS_PER_USER` (30) tranches; when the limit is reached, deposits are compacted — first by losslessly merging all max-tier tranches, then, if needed, by merging tranches within the same tier using an amount-weighted average timestamp.

### Minting

The primary minting path is **governance issuance**:

* `issue(user)` / `issueBatch(users)` let governance mint Prime tokens directly (ACM-gated). A keeper reads the leaderboard off-chain with `getEffectiveStakeBatch(users)`, ranks users, and governance issues tokens to the qualifying set.
* `burn(user)` / `burnBatch(users)` let governance revoke tokens (ACM-gated).

A **permissionless minting** window exists as a fallback and is **disabled by default**: `mintThreshold` initializes to `0`, so `claimPrime` / `claimPrimeBatch` revert with `MintThresholdNotSet`. Governance can open the window by calling `setMintThreshold(threshold, deadline)` — intended as a last resort if the keeper-driven issuance flow is unavailable. While open:

* `claimPrime(user)` / `claimPrimeBatch(users)` are permissionless — anyone can mint a Prime token for any user whose Prime Score ≥ `mintThreshold`. In the batch variant, users below the threshold are skipped (with a `SkippedIneligibleUser` event) rather than reverting the whole call.

Total Prime tokens are capped by `tokenLimit` (default 500). Setting `mintThreshold` back to `0` closes the window; a non-zero `mintDeadline` auto-closes it once `block.timestamp` passes it.

### Staker migration

When PrimeLeaderboard is first deployed, existing stakers are seeded with `initializeStakers(users, amounts, timestamps)` in batches (idempotent — already-seeded users are skipped). Once seeding is complete, `finalizeInitialization()` locks it permanently. The `XVSVault.primeToken` reference is then pointed at the leaderboard to begin live tracking.

## Rewards

([*Main explanation of Prime rewards*](/whats-new/prime-yield#technical-reward-details))

Qualifiable supply and borrow amount limits are set by the staked XVS value and the market multiplier. The USD values of the tokens and of XVS are taken into account to calculate these caps. The following pseudocode shows how $$\sigma\_{i,m}$$ is calculated considering the caps:

```jsx
// xvsBalanceOfUser is the user's XVS Vault stake, net of pending withdrawal requests
borrowUSDCap = toUSD(xvsBalanceOfUser * marketBorrowMultipler)
supplyUSDCap = toUSD(xvsBalanceOfUser * marketSupplyMultipler)
borrowUSD = toUSD(borrowTokens)
supplyUSD = toUSD(supplyTokens)

// borrow side
if (borrowUSD < borrowUSDCap) {
  borrowQVL = borrowTokens
else {
  borrowQVL = borrowTokens * borrowUSDCap/borrowUSD
}

// supply side
if (supplyUSD < supplyUSDCap) {
  supplyQVL = supplyTokens
else {
  supplyQVL = supplyTokens * supplyUSDCap/supplyUSD
}

return borrowQVL + supplyQVL
```

**Significance of α**

A higher α value increases the weight of stake contributions when determining rewards and decreases the weight of supply/borrow contributions. The value of α is between 0-1 (both excluded).

A default weight of 0.5 has been evaluated as a good ratio and is not likely to be changed. A higher value would only be needed if Venus wanted to attract more XVS stake from 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 α:

```jsx
User A:
Stake: 200
Supply/Borrow: 500

User B:
Stake: 100
Supply/Borrow: 1000

If alpha is 0.7 then:
user A score: 263.2764409
user B score: 199.5262315

If alpha is 0.3 then:
user A score: 379.8288965
user B score: 501.1872336
```

### Implementation of the rewards in solidity

`rewardIndex` and `sumOfMembersScore` are global variables in supported markets used when calculating rewards. `sumOfMembersScore` represents the current sum of all Prime token holders' scores, and `rewardIndex` is updated whenever interest is accrued for a market.

```jsx
// every time accrueInterest is called. delta is interest per score
delta = distributionIncome / sumOfMembersScore;
rewardIndex += delta;
```

If interest accrues for a market while it has no scored members yet, the slice is recorded in `undistributedReward[underlying]` so governance can reclaim it later via `sweepUndistributed` instead of stranding it.

Whenever a user's supply/borrow or XVS Vault balance changes, the rewards accrued are recalculated and added to their account:

* In the Comptroller (specifically in the `PolicyFacet`), after any operation that could impact a Prime score or interest, `accrueInterestAndUpdateScore(user, market)` is called on PrimeV2.
* In the `XVSVault`, after depositing or requesting a withdrawal, `xvsUpdated(user)` is invoked on `PrimeLeaderboard`. The leaderboard updates its deposit tracking and then calls `accrueInterestAndUpdateScore(user)` on PrimeV2 so rewards are accrued at the old score before the score is recalculated.

User rewards are calculated as:

```jsx
rewards = (rewardIndex - userRewardIndex) * scoreOfUser;
```

The `userRewardIndex` (`interests[market][account].rewardIndex`) is then updated to the current global value.

### Per-cycle reward accounting

Rewards are tracked in monthly **cycles** for off-chain reporting. Each user's `interests[market][user].lifetimeAccrued` is a monotonic running total of every reward ever accrued to that user in that market — it grows alongside `accrued` but is never reset on claim. The off-chain pipeline computes a user's earnings for a given cycle as the difference between their `lifetimeAccrued` at the cycle's start and end.

Cycle boundaries are anchored on-chain: a keeper calls `recordCycleSnapshot(cycleId)`, which emits `CycleSnapshotRecorded(cycleId, block.number, block.timestamp)`. This is an operational hook (ACM-gated to a keeper, not the Timelock) and is intentionally not idempotent — the indexer de-duplicates repeated `cycleId`s. The snapshots themselves are read off-chain via `getLifetimeAccruedByMarket` / `getLifetimeAccruedByUser`, so no per-cycle state is stored on-chain beyond `lifetimeAccrued`.

## Income collection and distribution

Every market in Venus (including Isolated Lending markets) contributes to the rewards that PrimeV2 distributes, following the protocol [tokenomics](/governance/tokenomics).

Prime rewards are denominated in the reward tokens accumulated by the `PrimeLiquidityProvider`. Protocol income that arrives in other tokens is converted into those reward tokens by [TokenBuyback](/whats-new/token-converter) instances whose destination is the `PrimeLiquidityProvider`. On BNB Chain these are `USDTPrimeBuyback` (base asset USDT) and `UPrimeBuyback` (base asset U), so Prime rewards accumulate in USDT and U.

Interest reserves (part of the protocol income) from Isolated Pools and Core Pool markets are sent to the PSR ([Protocol Share Reserve](https://github.com/VenusProtocol/protocol-reserve/blob/main/contracts/ProtocolReserve/ProtocolShareReserve.sol)) contract. Based on the configuration, a percentage of income from all markets is reserved for Prime token holders. The interest reserves are sent to the PSR periodically (currently every 6 hours, changeable by the community via [VIP](https://app.venus.io/governance)).

The PSR has a function `releaseFunds` that releases the funds to the destination contracts. The Prime-destined `TokenBuyback` instances receive income from the PSR, swap it into the Prime reward tokens at DEX market rate via an ACM-authorized finance-team cron, and forward the output to `PrimeLiquidityProvider`. How much of each reward token is released to Prime users over time is controlled by the per-token distribution speeds configured in the `PrimeLiquidityProvider` via VIP (`setTokensDistributionSpeed`); there is no fixed allocation percentage hardcoded in Prime.

`PrimeLiquidityProvider` then releases the funds to the PrimeV2 contract according to distribution speeds configured per reward token.

If a user tries to claim their rewards and PrimeV2 doesn't have enough funds, the release of funds from `PrimeLiquidityProvider` to PrimeV2 is triggered in the same transaction (in the `claimInterest` function).

Two details about `claimInterest`:

* A permissionless overload `claimInterest(vToken, user)` lets anyone trigger a claim on behalf of a user — the reward tokens are always sent to the user, never to the caller.
* If the balance is still insufficient after pulling from the `PrimeLiquidityProvider`, the claim is partial: the shortfall stays recorded in the user's `accrued` balance and can be claimed later, instead of the transaction reverting.

The following diagram shows the integration of the `TokenBuyback` contracts with the Prime contracts:

<figure><img src="/files/O2oBBB1lBcxNbDs3JSvs" alt="Integration of the TokenBuyback contracts with the Prime contracts"><figcaption><p>PSR → Prime buybacks → PrimeLiquidityProvider → PrimeV2 → users</p></figcaption></figure>

More information about income collection and distribution can be found [here](/whats-new/automatic-income-allocation).

## Update cap multipliers and alpha

Market multipliers and alpha can be updated at any time and then need to be propagated to all users. When `addMarket`, `updateMultipliers` or `updateAlpha` is called, PrimeV2 opens a new score-update round: it increments `nextScoreUpdateRoundId` and sets `pendingScoreUpdates` to the total number of Prime tokens. If a previous round was still in progress, it is discarded with an `IncompleteRoundDiscarded` event.

While `pendingScoreUpdates > 0`, issuing and burning are blocked (`ScoreUpdateInProgress`) until all scores have been recomputed. A keeper completes the round by calling the permissionless `updateScores(users)` in batches (split across multiple transactions to avoid running out of gas). Each user is updated at most once per round, tracked via `isScoreUpdated[roundId][user]`.

This mechanism ensures that when multipliers/alpha change, or a new market is added to the program, all Prime users' scores are brought up to date promptly rather than drifting until each user next interacts with the markets — which would otherwise let the first users in a new market collect disproportionately large rewards.

### Adding and removing markets

`addMarket(market, supplyMultiplier, borrowMultiplier)` (ACM-gated) enrolls a Core Pool market into the program. The market must be listed in the Core Pool Comptroller, its underlying token must have at most 18 decimals, and only one Prime market can exist per underlying asset. As described above, adding a market opens a score-update round.

`removeMarket(market)` (ACM-gated) removes a market from the program. It is only allowed once no Prime holder retains a score in that market (`sumOfMembersScore == 0`, enforced with `MarketHasActiveMembers`) — which happens only once every Prime holder has zero capital (supply and borrow) in that market and their scores have been recomputed, or the holders' Prime tokens have been burned. Before deletion, any pending income slice from the `PrimeLiquidityProvider` is flushed into `undistributedReward` so it stays recoverable via `sweepUndistributed`. Rewards already accrued by users in a removed market remain claimable through `claimInterest`.

## Calculate APR associated with a Prime market and user

APR estimation lives in a separate read-only contract, [**PrimeLens**](/technical-reference/reference-core-pool/prime/prime-lens), kept out of PrimeV2 to stay within the EVM contract-size limit. The [Venus UI](https://app.venus.io) calls it to show the APR a user's Prime boost adds in a given market.

* `calculateAPR(market, user)` returns an `APRInfo` struct with the user's `supplyAPR` and `borrowAPR` (in BPS) plus the inputs behind them: `userScore`, `totalScore`, `xvsBalanceForScore`, `capital`, `cappedSupply`, `cappedBorrow`, `supplyCapUSD`, `borrowCapUSD`.
* `estimateAPR(market, user, borrow, supply, xvsStaked)` returns the same `APRInfo` struct for a hypothetical position — the supply, borrow and staked XVS amounts are passed in rather than read from the user's current state, so the UI can simulate the APR impact of a planned action.
* `incomeDistributionYearly(vToken)` returns the annualized income for a market — the PrimeLiquidityProvider effective distribution speed for the market's underlying multiplied by `blocksOrSecondsPerYear` (PrimeV2 runs on `TimeManagerV8`, so this is per-second on time-based chains and per-block otherwise).

Conceptually the lens performs these steps:

1. Fetch the annualized income for the market (`incomeDistributionYearly`)
2. Compute the user's score and the market's total score, giving the user's share of that income over a year
3. Compute the user's capped supply and borrow for the market
4. Split the user's income share across the capped supply and borrow legs
5. Derive the supply and borrow APR from those legs

**Example:**

1. Annualized market income: 315.36 USDT
2. With user score 3 and total market score 10, the user's yearly income is 94.608 USDT
3. User positions — borrow 30 USDT (capped at 15), supply 10 USDT (capped at 10)
4. Allocating 94.608 USDT across the capped legs (15 + 10 = 25): borrow 94.608 × 15/25 = 56.76 USDT, supply 94.608 × 10/25 = 37.84 USDT
5. APR: borrow 56.76/30 = 189%, supply 37.84/10 = 378%

Only the supply and borrow amounts below the cap generate Prime rewards. Amounts above the cap do not generate extra rewards. In the example, if the user supplies more USDT they won't generate more rewards (the supply amount considered is capped), so the supply APR would decrease.

`getPendingRewards(user)` / `getPendingRewardsStatic(user)` on PrimeV2 remain available for reading already-accrued, claimable rewards per market (the former accrues first, the latter is a read-only view).

## Bootstrap liquidity for the Prime program

There is 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 are enforced with the `PrimeLiquidityProvider` contract:

* PrimeV2 holds a reference to the `PrimeLiquidityProvider` contract
* PrimeV2 transfers to itself the available liquidity from the `PrimeLiquidityProvider` as soon as it is needed when a user claims interest, to reduce the number of transfers
* PrimeV2 takes into account the tokens available in the `PrimeLiquidityProvider` contract when interest is accrued and the estimated APR is calculated

Regarding the `PrimeLiquidityProvider`:

* It maintains a speed per token (`tokenDistributionSpeeds`, the number of tokens to release each block or second, depending on the chain — PrimeLiquidityProvider runs on `TimeManagerV8`) and the indexes needed to release the required funds
* Anyone can send tokens to it
* Only accounts authorized via ACM can change the `tokenDistributionSpeeds`
* It accrues the distributable funds for a token via `accrueTokens` (public), based on the elapsed blocks or seconds, the token's speed, and the last accrued block/second; `getEffectiveDistributionSpeed` returns the current effective per-block/second rate for a token
* It exposes a function to transfer the available funds to the PrimeV2 contract

## Pausing

PrimeV2 uses OpenZeppelin's `PausableUpgradeable`. The ACM-gated `pause()` / `unpause()` functions control the user-facing entry points (`claimPrime`, `claimPrimeBatch`, `claimInterest`). Accrual and score-update functions (`accrueInterest`, `accrueInterestAndUpdateScore`, `updateScores`) are intentionally **not** gated by the pause, so reward accounting stays fair and keepers can finish score rounds even while the contract is paused.


# DeviationBoundedOracle

The DeviationBoundedOracle (DBO) is the contract that sits between the [ResilientOracle](/technical-reference/reference-oracle/resilient-oracle) and the Core Pool Comptroller on the borrow-power path. It maintains a per-asset rolling price window, detects when spot deviates beyond a configured threshold, and returns conservative bounded prices while the deviation persists. Its user-visible behaviour is the [Protection Mode](/risk/protection-mode) feature; this article covers the contract itself — where it gets prices, what it stores, and how the Comptroller calls it.

For function-level signatures, structs, events, and errors see the [DeviationBoundedOracle reference](/technical-reference/reference-oracle/deviation-bounded-oracle).

## Pricing stack

<figure><img src="/files/uXNBxpRtw9yL4BED02QL" alt="DeviationBoundedOracle pricing stack architecture diagram"><figcaption><p>DeviationBoundedOracle pricing stack</p></figcaption></figure>

* The **ResilientOracle** fetches and cross-validates spot from the configured sources, exactly as today. The DBO does not replace this — it wraps it. The borrow-power path on the Comptroller never queries the ResilientOracle itself; the DBO is the only oracle the Comptroller talks to on that path.
* The **DeviationBoundedOracle (DBO)** is the single entry point for every borrow-power read on every market. On each call it fetches spot from the ResilientOracle, then returns one of three outcomes:
  * **Asset not whitelisted** (bounded pricing disabled): returns `(spot, spot)` immediately. No window read, no trigger logic, no storage write — a thin pass-through.
  * **Asset whitelisted, protection inactive**: returns `(spot, spot)`. The price equals spot, but the call still expands the rolling window if needed and runs the trigger check, so this is the path that *enters* protection mode if a deviation appears.
  * **Asset whitelisted, protection active**: returns `(min(spot, windowMin), max(spot, windowMax))`.
* The **liquidation path** (`USE_LIQUIDATION_THRESHOLD` and `liquidateCalculateSeizeTokens`) calls the ResilientOracle directly and never touches the DBO. Eligibility, seize amount, and incentive calculations stay on real-time spot regardless of whether protection is active on either side of the position.

So the DBO is always in the call chain for the borrow-power path. For non-whitelisted markets it is transparent and the price the Comptroller sees is identical to what the ResilientOracle returned; for whitelisted markets it adds the window/trigger logic on top.

## Rolling price window

For each whitelisted asset the DBO stores a `(minPrice, maxPrice)` pair representing the lowest and highest spot prices observed inside a short rolling window (target \~15 minutes). It is maintained from two distinct sources:

* **User-triggered, expansion only.** Every relevant price read pulls spot from the ResilientOracle. If `spot < minPrice`, `minPrice` is pulled down to spot; if `spot > maxPrice`, `maxPrice` is pushed up. User activity can only widen the window — never contract it.
* **Keeper-triggered, bidirectional.** The keeper maintains the true rolling window off-chain and pushes corrected values via `updateMinPrice` / `updateMaxPrice`. On-chain validation enforces both a spot bound (`newMin ≤ spot`, `newMax ≥ spot`) and a cross bound (`newMin ≤ maxPrice`, `newMax ≥ minPrice`) so the window can never be inverted. The 5% `KEEPER_DEADBAND` is *not* enforced inside the write path; the keeper queries `checkAndGetWindowDrift` (a view) to skip pushes whose delta is below the deadband, purely as a gas-saving heuristic. This is what brings the window back inwards once an extreme has aged out.

## Trigger and exit

Protection activates as a side-effect of the price read whenever spot has moved past the deviation threshold relative to the stored window:

```
pump:  spot >  minPrice × (1 + triggerThreshold)
crash: spot <  maxPrice × (1 − triggerThreshold)
```

`triggerThreshold` is per-asset, configured by governance, and bounded between `MIN_THRESHOLD = 5%` and `MAX_THRESHOLD = 50%` (the 5% floor keeps routine keeper corrections from accidentally firing it). The cooldown timer (`lastProtectionTriggeredAt`) is re-stamped only on the first activation or when spot makes a *new* extreme this update (`windowExpanded == true`). Recovery within the existing window keeps the cooldown ticking, so `exitProtectionMode` remains reachable once the price stabilises — sustained reads at the same elevated/depressed level do not, by themselves, defer exit.

Exit cannot turn itself off. Both conditions must hold:

```
1. now − lastTrigger ≥ cooldownPeriod
2. (maxPrice − minPrice) / minPrice < resetThreshold        // resetThreshold < triggerThreshold
```

When both are satisfied, the keeper / monitor calls `exitProtectionMode(asset)` (or includes an `ExitProtectionMode` item inside `syncPriceBoundsAndProtections`) to clear the active flag. Governance retains a fallback path.

## Bounded-price computation

For each whitelisted asset the DBO returns a `(collateralPrice, debtPrice)` pair:

```
protection inactive:  collateralPrice = spot,                  debtPrice = spot
protection active:    collateralPrice = min(spot, windowMin),  debtPrice = max(spot, windowMax)
```

* Collateral is capped at the recent window low so a pumped asset cannot be over-borrowed against.
* Debt is floored at the recent window high so a crashed borrow asset cannot be repaid cheaply.
* Both legs collapse back to spot once the trigger clears.

## Transient price cache

Every non-view path writes the resolved `(collateralPrice, debtPrice)` pair into EIP-1153 transient storage so a follow-up `getBoundedPricesView` in the same transaction can return it without re-fetching spot. The cache is per-asset, transaction-scoped, and clears at the end of the transaction.

Caching is configurable per asset via `setCachingEnabled(asset, enabled)`, independently of the bounded-pricing flag. When disabled, writes are no-ops and reads always miss, so every view call recomputes live from the ResilientOracle — a safety lever for forcing fresh evaluation, not a default knob.

## Function surface

The contract exposes three small groups of entry points, one per caller role.

**Comptroller — borrow-power path.** Computing a bounded price requires fetching fresh spot and updating the rolling window — both are state-mutating, so they cannot live inside a `view` function. But the borrow-power check runs through `ComptrollerLens`, which is `view`. The DBO splits the work into two calls and uses the transient cache (above) as the bridge:

* `updateProtectionState(vToken)` — non-view. Pulls fresh spot, expands the window, evaluates the trigger, and writes the resolved pair to the cache. The Comptroller calls this once per entered asset at the start of every borrow-power check, *before* the lens runs. This is also the single non-view entry point that advances DBO state day-to-day.
* `getBoundedPricesView(vToken)` (and the per-leg `getBoundedCollateralPriceView` / `getBoundedDebtPriceView`) — view. Returns the cached pair if `updateProtectionState` ran earlier in the same transaction; otherwise recomputes live from spot without any state writes.
* `getBoundedPrices(vToken)` — non-view convenience that does both in one call; for integrators that don't need the pre-warmed-cache split.

**Keeper — window correction and exit.** All three actions are gated by `AccessControlManager`.

* `updateMinPrice(asset, newMin)` / `updateMaxPrice(asset, newMax)` — push corrected bounds. On-chain checks enforce `newMin ≤ spot ∧ newMin ≤ maxPrice` and `newMax ≥ spot ∧ newMax ≥ minPrice`. The 5% `KEEPER_DEADBAND` is checked *off-chain* via `checkAndGetWindowDrift`, not in this write path.
* `exitProtectionMode(asset)` — clears the active flag once cooldown has elapsed and the window has converged below `resetThreshold`. Reverts otherwise.
* `syncPriceBoundsAndProtections(items[])` — atomic batch of the above across multiple assets in a single ACM check; any item revert rolls back the whole batch.

**Governance — configuration.**

* `setTokenConfig(...)` (and the batch variant) — initializes a market's `MarketProtectionState`, sets `triggerThreshold`, `resetThreshold`, `cooldownPeriod`, the initial `cachingEnabled` flag, and the initial bounded-pricing flag. Reverts on `MarketAlreadyInitialized`, `VAINotAllowed` (VAI is rejected by design), threshold violations, or if the seeded spot price overflows `uint128`. The initial bounded-pricing flag is independent of initialization, so an asset can be configured first and whitelisted later via `setAssetBoundedPricingEnabled`.
* `setAssetBoundedPricingEnabled(asset, enabled)` — toggles whether the DBO runs the full window/trigger logic for the asset or short-circuits to spot.
* `setCachingEnabled(asset, enabled)` — toggles the per-asset transient cache participation independently of bounded pricing.

## Liquidation path is unchanged

```
Liquidator → Comptroller (USE_LIQUIDATION_THRESHOLD) → ComptrollerLens → ResilientOracle.getUnderlyingPrice(...)
```

The borrow-power path uses `WeightFunction.USE_COLLATERAL_FACTOR` and is the only path that calls `_updateProtectionStates`. The liquidation path uses `WeightFunction.USE_LIQUIDATION_THRESHOLD` and reads spot from the ResilientOracle directly. No bounded prices touch eligibility, seize-amount, or incentive calculations regardless of whether protection is active on either side of the position.

## Off-chain components

* **Keeper.** Maintains the authoritative 15-minute rolling window off-chain and pushes corrected `minPrice` / `maxPrice` on-chain whenever the stored values have drifted past the 5% deadband. The on-chain writes are constrained by `newMin ≤ spot` and `newMax ≥ spot`. Once the on-chain exit conditions are satisfied — cooldown elapsed and window converged below `resetThreshold` — the keeper submits `exitProtectionMode(asset)`, or includes an `ExitProtectionMode` item inside a `syncPriceBoundsAndProtections` batch.
* **Monitor.** Observes protection events and price normalization across independent feeds; gates keeper exit calls on real recovery rather than just the on-chain timer.
* **Governance.** Whitelists assets via `setTokenConfig` (single or batch), sets per-asset `triggerThreshold`, `resetThreshold`, and `cooldownPeriod`, can toggle bounded pricing through `setAssetBoundedPricingEnabled`, and retains a fallback path to disable protection for an asset if the keeper path is unavailable.

## Further Reading

* [Protection Mode (risk overview)](/risk/protection-mode)
* [DeviationBoundedOracle contract reference](/technical-reference/reference-oracle/deviation-bounded-oracle)
* [Resilient Price Oracle](/risk/resilient-price-oracle)
* [Repository](https://github.com/VenusProtocol/oracle)


# FlashLoan

## Overview

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.

### Key Features and Technical Architecture

* **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.

***

## Understanding Flash Loans

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.

### The Venus Innovation: Flexible Repayment & Debt Conversion

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.

### Example: A Practical Use Case

Let's imagine a user, Alice, who has supplied 10 ETH as collateral on Venus.

1. **Objective:** Alice uses a flash loan to perform a complex arbitrage trade that she expects will take several transactions to complete.
2. **Action:** She takes a flash loan of 100,000 USDC.
3. **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.
4. **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.
5. **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.

***

## Core Smart Contracts

### **1. FlashLoanFacet.sol – FlashLoan Execution & Validation**

Handles core flash loan operations including:

* Asset transfers
* Fee calculations
* Repayment logic
* Event emissions

#### Key Function

```solidity
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...
}
```

**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.

### Step-by-Step Workflow:

#### 1. **Validation & Initial Checks**

* **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.

#### 2. **Phased Execution**

The core logic is delegated to an internal function that structures the process into three distinct phases:

#### **Phase 1: Pre-Transfer Setup & Asset Disbursement**

* **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.

#### **Phase 2: User Logic Execution**

* **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.

#### **Phase 3: Repayment Handling & Settlement**

* **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.

#### 3. **Event Emission**

* Upon successful completion, a **FlashLoanExecuted** event is emitted, logging the receiver address, the vTokens involved, and the amounts loaned.

### Critical Security Features:

* **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.

***

### **2. SetterFacet.sol - Setter Functions For Flashloan**

This file contains administrative functions to manage flash loan permissions.

#### **Functions**

#### `setWhiteListFlashLoanAccount`

```solidity
function setWhiteListFlashLoanAccount(address account, bool _isWhiteListed) external;
```

**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.

***

### **3. VToken.sol – Asset Transfer & Fee Calculation**

Manages the underlying asset transfers, flash loan fee calculations, and creation of debt positions.

#### Key Functions

**1.`transferOutUnderlyingFlashLoan`**

```solidity
function transferOutUnderlyingFlashLoan(address payable to, uint256 amount) external nonReentrant;
```

**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:

1. **Authorization Check**: Ensures only the Comptroller contract can call this function.
2. **Flash Loan State Management**: Sets the flashLoanAmount to track the active flashloan and prevents concurrent flash loans.
3. **Asset Transfer**: Performs the low-level transfer of the underlying asset to the receiver address.
4. **Event Emission**: Emits TransferOutUnderlyingFlashLoan event for tracking.

***

**2. `calculateFlashLoanFee`**

```solidity
function calculateFlashLoanFee(uint256 amount) public view returns (uint256, uint256);
```

**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.

1. **Total Fee Calculation** : Multiplies the loan amount by the global **flashLoanFeeMantissa** (a scaled value, e.g., 0.09% represented as 9e14).
2. **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`**

```solidity
function transferInUnderlyingFlashLoan(
    address payable from,
    uint256 repaymentAmount,
    uint256 totalFee,
    uint256 protocolFee
) external nonReentrant returns (uint256);
```

**Explanation:** This function handles the repayment phase of flash loans with enhanced parameter validation. When called by the Comptroller, it performs several critical operations:

1. **Authorization Check**: Ensures only the Comptroller contract can call this function.
2. **Asset Collection**: Transfers the repayment amount from the receiver contract to the vToken.
3. **Repayment Validation**: Validates that the actual transferred amount meets the minimum fee requirement.
4. **Protocol Fee Distribution**: Automatically transfers the protocol fee portion to the Protocol Share Reserve.
5. **State Management**: Resets the flashLoanAmount to 0, completing the flash loan cycle.
6. **Event Emission**: Emits `TransferInUnderlyingFlashLoan` event with detailed repayment information.

***

**3. `setFlashLoanEnabled`**

```solidity
function setFlashLoanEnabled(bool enabled) external returns (uint256);
```

**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`**

```solidity
function setFlashLoanFeeMantissa(
    uint256 flashLoanFeeMantissa_,
    uint256 flashLoanProtocolShare_
) external returns (uint256);
```

**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.

1. **flashLoanFeeMantissa\_** : This is the total fee rate charged for flash loans (scaled by 1e18).
2. **flashLoanProtocolShare\_** : This is the percentage of the total fee allocated to the Protocol Share Reserve (scaled by 1e18).

***

**5. `getCash`**

```solidity
function getCash() external view override returns (uint);
```

**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.

***

### **4. Flash Loan Receiver Standards**

There is a standardized interface for contracts wishing to receive and handle flash loans from Venus Protocol:

#### **1. IFlashLoanReceiver - Multi-Asset Standard**

**Purpose:** For complex strategies requiring multiple assets in a single flash loan operation.

**Interface: IFlashLoanReceiver**

```solidity
    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);
```

**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.

### **Core Requirements for the Standard**

Receiver Contracts Must:

1. **Receive Assets**: Acknowledge and handle the received flash-loaned assets.
2. **Execute Strategy**: Perform intended operations (arbitrage, liquidation, etc.)
3. **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
4. **Return Success**: Return true to signal successful operation.
5. **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.

***

## Key Events

* **`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.

***

## Key Errors

* **`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.

***

## Example FlashLoan Flow: Alice's Arbitrage

**User:** Alice (has 10 ETH collateral on Venus)

**Goal:** Arbitrage 100,000 USDC between DEXs

### **1. Full Repayment (Successful Trade)**

1. **Request:** Alice's ArbitrageContract calls executeFlashLoan() requesting 100000 USDC.
2. **Transfer:** Venus sends 100,000 USDC to Alice's contract + calculates fee (e.g., 90 USDC)
3. **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
4. **Repayment:** Venus pulls the approved 100,090 USDC
5. **Result:** Alice keeps 110 USDC profit. Transaction completes.

### **2. Partial Repayment (Failed Trade → Debt Conversion)**

1. **Request:** Alice's ArbitrageContract calls executeFlashLoan() requesting 100000 USDC.
2. **Transfer:** Venus sends 100,000 USDC + calculates fee (90 USDC)
3. **Execution:**
   * Arbitrage fails due to slippage → only gets 99,500 USDC
   * **Approves partial repayment** of 99,500 USDC
4. **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
5. **Result:** Transaction does not revert. Alice now owes 590 USDC to Venus.

### **3. Fee Not Paid (Critical Failure → Transaction Reverts)**

1. **Request:** Alice's ArbitrageContract calls executeFlashLoan() requesting 100,000 USDC.
2. **Transfer:** Venus sends 100,000 USDC + calculates fee (90 USDC)
3. **Execution:**
   * Arbitrage fails completely → only gets 50 USDC
   * **Approves insufficient amount** of 50 USDC (less than the 90 USDC fee)
4. **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.

### **Key Mechanism**

* **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.

***

## Conclusion

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.


# Risk Stewards

The Risk Stewards system is a permissioned, automated pipeline for applying a bounded set of risk-parameter changes to Venus markets without a manual governance proposal for each one. Whitelisted risk providers publish recommendations to a Venus-owned on-chain oracle; the protocol validates each one, applies small changes immediately, holds larger ones behind a timelock, and bridges changes destined for other chains over LayerZero. Governance keeps control of everything that matters: who may publish, who may execute held updates, the bounds, and an emergency pause.

It currently supports four update types: `supplyCap`, `borrowCap`, `collateralFactors` (collateral factor and liquidation threshold, set together), and `interestRateModel`. Anything outside this set still requires a full VIP.

This article describes the contracts and the update lifecycle. For function-level signatures, structs, events, and errors, see the reference page linked under each contract.

## Architecture

<figure><img src="/files/ivDFoxbpvP3yRSWi2Ju0" alt="Risk Stewards architecture: providers publish to the Risk Oracle on BNB Chain; the RiskStewardReceiver routes updates to local stewards or forwards them over LayerZero to a Destination Steward Receiver on remote chains; governance configures the whole system"><figcaption><p>Providers publish to the Risk Oracle on BNB Chain; the RiskStewardReceiver applies updates locally or bridges them to a Destination Steward Receiver on remote chains. Governance configures and gates the whole pipeline.</p></figcaption></figure>

BNB Chain is the **source chain**: it hosts the oracle and the source-chain receiver. Every update is published there, even ones destined for another chain. Each supported chain (including BNB Chain itself) hosts the steward contracts that perform the actual change, plus a destination receiver on non-source chains.

[**Risk Oracle**](/technical-reference/reference-governance/risk-oracle) is the single source of truth for recommendations. A whitelisted provider calls `publishRiskParameterUpdate(referenceId, newValue, updateType, market, poolId, dstEid, additionalData)`; the oracle assigns a monotonic `updateId`, records the previous value for history, and emits `UpdatePublished`. Senders are added and removed only by governance (`addAuthorizedSender` / `removeAuthorizedSender`), as are the supported update-type strings (`addUpdateType`, `setUpdateTypeActive`). The oracle only stores recommendations; it never touches the protocol itself.

[**RiskStewardReceiver**](/technical-reference/reference-governance/risk-steward-receiver) **(RSR)** on BNB Chain is where updates are processed. `processUpdate(updateId)` is permissionless: anyone can push a published update through the pipeline. The RSR holds a per-type config (`riskParameterConfigs`) mapping each update type to its steward, a `debounce` period, and a `timelock`, all set by governance. It validates the update, decides the execution path, and either applies it locally, registers it behind a timelock, or forwards it cross-chain.

[**DestinationStewardReceiver**](/technical-reference/reference-governance/destination-steward-receiver) **(DSR)** lives on each non-source chain. It receives bridged updates over LayerZero, registers them with status `Pending`, and holds them for a fixed `remoteDelay` (6 hours by default) before a whitelisted executor applies them.

**Risk Stewards** do the actual writing. All three inherit [**BaseRiskSteward**](/technical-reference/reference-governance/base-risk-steward), which holds the `safeDeltaBps` bound and enforces that `applyUpdate` may only be called by the steward's receiver (`OnlyRiskStewardReceiver`). Each steward owns one parameter family:

| Steward                                                                                                   | Update type(s)           | Encoded `newValue`     | Writes via                                                         |
| --------------------------------------------------------------------------------------------------------- | ------------------------ | ---------------------- | ------------------------------------------------------------------ |
| [MarketCapsRiskSteward](/technical-reference/reference-governance/market-caps-risk-steward)               | `supplyCap`, `borrowCap` | one `uint256`          | `setMarketSupplyCaps` / `setMarketBorrowCaps`                      |
| [CollateralFactorsRiskSteward](/technical-reference/reference-governance/collateral-factors-risk-steward) | `collateralFactors`      | two `uint256` (CF, LT) | `setCollateralFactor`                                              |
| [IRMRiskSteward](/technical-reference/reference-governance/irm-risk-steward)                              | `interestRateModel`      | one `address`          | `_setInterestRateModel` (core) / `setInterestRateModel` (isolated) |

## Update types and encoding

Each update carries its new value as opaque ABI-encoded `bytes`. Passing it this way is deliberate: one `newValue` field (and so a single `publishRiskParameterUpdate` entry point and one update struct) can express payloads of completely different shapes. A market cap is a single number, collateral factors are a pair (the factor and its liquidation threshold), and an interest rate model is an address; each steward decodes the bytes into the shape it expects and rejects anything of the wrong length. New parameter types can therefore be added later without changing the oracle or receiver interfaces.

The encoding per type (type strings are case-sensitive):

```
supplyCap / borrowCap   abi.encode(uint256)            // 18-decimal amount
collateralFactors       abi.encode(uint256, uint256)   // collateral factor, liquidation threshold (both required)
interestRateModel       abi.encode(address)            // new IRM contract
```

`poolId` selects the pool: `0` for core-pool and isolated-pool markets, and a non-zero group id for an eMode pool inside the core pool. `dstEid` is `0` (or the source chain's own endpoint id) for a local BNB Chain update, or a LayerZero endpoint id for a remote chain.

## Validation and routing

`processUpdate` is permissionless, and that is safe by design: every safety property lives in the validation below and in the steward bounds, not in gating who may call it; the caller only supplies the gas. Before acting, the RSR validates the update:

* the update type's config is **active**;
* it is the **latest** published update for that market and type: a newer recommendation supersedes an older one, which then reverts as `UpdateIsExpired`, so a provider corrects a mistake simply by publishing again;
* it has **not expired** (updates are valid for `UPDATE_EXPIRATION_TIME`, 2 days, from publication) and has **not already been resolved** (executed, rejected, or expired);
* registering it behind a timelock would not push the unlock time past that 2-day expiry (`UpdateWillExpireBeforeUnlock`), so the system never parks an update that could never be executed in time; and
* for local updates, the **debounce** window since the last applied change for that `(market, updateType)` has passed, and no other non-expired pending update of the same type is already registered.

Debounce and timelock are different levers: **debounce** rate-limits how often a given market/type can change at all; **timelock** delays an individual large change so it can be reviewed. A change can clear debounce yet still be timelocked. Once validated, the RSR asks the steward whether the change is safe for immediate execution and routes it down one of three paths: local-immediate, local-timelocked, or cross-chain.

## Local execution: immediate vs. timelocked

<figure><img src="/files/RTYwMbCJNMxwkU6LoEbt" alt="Local update flow on BNB Chain: provider publishes to the Risk Oracle, anyone calls processUpdate on the RiskStewardReceiver, which either applies the change immediately when it is within the safe delta or registers it behind a timelock for an executor to apply"><figcaption><p>A local (BNB Chain) update. Within the safe delta it applies immediately; otherwise it is registered behind a timelock and applied later by a whitelisted executor.</p></figcaption></figure>

The split is decided by the steward's `isSafeForDirectExecution`, which compares the new value against the live on-chain value using `safeDeltaBps`:

* **Market caps** execute immediately when the change is within `±safeDeltaBps` of the current cap, but only if the current cap is non-zero. Setting a cap from zero always takes the timelock, because there is no baseline to bound the change against.
* **Collateral factors** execute immediately only when *both* the collateral factor and the liquidation threshold move within `safeDeltaBps`, and neither current value is zero. **eMode** updates (`poolId != 0`) always take the timelock; eMode runs at higher leverage, so its collateral changes are never auto-applied.
* **Interest rate model** changes *always* take the timelock: an IRM is a contract address, so there is no meaningful "small change" to bound.

A redundant update (new value equal to the current one) reverts with `RedundantValue`.

The bound is symmetric and per-steward. `safeDeltaBps` is applied to the absolute difference (`|new − current| ≤ safeDeltaBps × current`), so a 50% bound permits a move of up to ±50% in either direction. Each steward holds its own bound, set independently by governance: at launch the Market Caps steward uses 50% and the Collateral Factors steward 10%; collateral factors and liquidation thresholds bear directly on account solvency, so they are allowed a far smaller automatic move than caps.

When the change is safe, the RSR applies it in the same `processUpdate` transaction. Otherwise it registers the update with `unlockTime = now + timelock` and status `Pending`; after the timelock a **whitelisted executor** calls `executeRegisteredUpdate(updateId)` to apply it, or `rejectUpdate(updateId)` to discard it. A registered update that is neither executed nor rejected within the 2-day window expires.

## Cross-chain execution

<figure><img src="/files/z62cuOdoxTdFFo1GSYFJ" alt="Remote update flow: provider publishes on BNB Chain, the RiskStewardReceiver forwards the update over LayerZero to the Destination Steward Receiver on the target chain, which holds it for the remote delay before a whitelisted executor applies it through the local steward"><figcaption><p>A remote update is forwarded over LayerZero, registered on the destination chain, held for the remote delay, then applied by a whitelisted executor through the destination-chain steward.</p></figcaption></figure>

When `dstEid` points at another chain, the RSR never executes locally. It registers the update and forwards it over LayerZero with `lzSend`; the local status becomes `SENT_TO_DESTINATION`. If a bridge message fails to deliver, a whitelisted executor can re-send it with `resendRemoteUpdate`.

On the destination chain the DSR receives the message (`_lzReceive`), registers it as `Pending`, and stamps its arrival time. A whitelisted executor on that chain calls `executeUpdate(updateId)` once `remoteDelay` has elapsed and before the 2-day expiry, or `rejectUpdate(updateId)` to discard it. The write is performed by the same kind of steward as on the source chain. Remote updates therefore always pass through a delay and an executor; there is no immediate cross-chain path.

Two design choices make this robust. First, the delay clock lives on the destination, not the source: the RSR is a LayerZero OApp sender and the DSR a receiver, and because bridge latency is unpredictable the DSR measures `remoteDelay` from the message's *arrival* time. Its config carries no timelock field at all (only a steward, a debounce, and the chain-wide `remoteDelay`), so locally the forwarded update is recorded with an immediate unlock and status `SENT_TO_DESTINATION` purely as bookkeeping, while the real wait plays out on the destination. Second, the RSR pays the LayerZero messaging fee from its own native balance (funded through its `receive()` and recoverable by governance with `sweepNative`), so the `processUpdate` caller never pre-pays the bridge, and a message that fails to deliver can be re-sent with `resendRemoteUpdate` rather than re-published.

## Roles and governance

| Role                     | Capability                                                                                                                   | Granted by       |
| ------------------------ | ---------------------------------------------------------------------------------------------------------------------------- | ---------------- |
| Risk parameter providers | Publish recommendations; may also call `processUpdate` for their own                                                         | Governance (ACM) |
| Anyone                   | Call `processUpdate`                                                                                                         | Permissionless   |
| Whitelisted executors    | Execute / reject timelocked and remote updates; resend failed bridges                                                        | Governance (ACM) |
| Governance / ACM         | Whitelist providers & executors; set debounce, timelock, `safeDeltaBps`, `remoteDelay`; register update types; pause the RSR | DAO (VIP)        |

The framework never bypasses governance. Stewards can only touch the four supported parameters, and only within governance-set bounds; larger, IRM, and eMode changes are delayed and vetoable; updates expire and cannot be replayed; and governance can pause processing or remove a provider at any time. The framework was enabled on BNB Chain in [VIP-592](https://app.venus.io/#/governance/proposal/592?chainId=56), which onboarded Allez Labs as the first external risk provider; at launch governance set a 3-day debounce, a 6-hour timelock, a 50% safe delta for market caps, and a 10% safe delta for collateral factors.

## Further reading

* [Risk Oracle & Risk Stewards (overview)](/risk/risk-oracle-and-risk-stewards)
* Contract references: [Risk Oracle](/technical-reference/reference-governance/risk-oracle) · [RiskStewardReceiver](/technical-reference/reference-governance/risk-steward-receiver) · [DestinationStewardReceiver](/technical-reference/reference-governance/destination-steward-receiver) · [BaseRiskSteward](/technical-reference/reference-governance/base-risk-steward) · [MarketCapsRiskSteward](/technical-reference/reference-governance/market-caps-risk-steward) · [CollateralFactorsRiskSteward](/technical-reference/reference-governance/collateral-factors-risk-steward) · [IRMRiskSteward](/technical-reference/reference-governance/irm-risk-steward)
* [VIP-592: Risk Stewards Framework Implementation](https://app.venus.io/#/governance/proposal/592?chainId=56)
* [Repository](https://github.com/VenusProtocol/governance-contracts)


# Shortfall and auctions

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.

<figure><img src="/files/3Ouifldw5ivxpDPmLcoK" alt="Auction scenarios"><figcaption></figcaption></figure>

## Auction scenarios

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.

## Examples

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%`
* **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()` 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].startBlock` state variable.
    * Placing a bid triggers `BidPlaced` event which can be monitored.
* **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.

***

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.
* **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).
    * Placing a bid triggers `BidPlaced` event which can be monitored.
* **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. Imagine 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.

***

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)`
* **Place Bids and Close Auction**: Now just like previous steps a user can place bids and close the auction.


# TokenBuyback Contract

{% hint style="info" %}
See the [TokenBuyback overview](/whats-new/token-converter) for migration context and the [deployed-contracts page](/deployed-contracts/token-converters) for proxy addresses. Live on BNB Chain via [VIP-620](https://app.venus.io/#/governance/proposal/620?chainId=56) and [VIP-621](https://app.venus.io/#/governance/proposal/621?chainId=56);
{% endhint %}

## Overview

`TokenBuyback` is the contract that holds protocol income arriving from `ProtocolShareReserve` (PSR) and converts it into a configured `BASE_ASSET` via on-chain DEX swaps. Each instance is deployed as a Transparent Proxy bound to a `(DESTINATION, BASE_ASSET)` pair at construction time; both addresses are immutable, so retargeting either requires a new deployment.

Swaps are initiated by an ACM-authorized finance-team cron, not by external community members. The cron builds the router calldata off-chain using DEX aggregators and submits it to `executeBuyback`. The contract validates a minimum output, pulls the actual `tokenIn` delta consumed by the router, forwards the resulting `BASE_ASSET` directly to `DESTINATION`, and applies two on-chain safety rails (USD daily cap + abnormal-slippage event) using a `ResilientOracle` reference price.

`TokenBuyback` implements `IIncomeDestination`, the same interface as the legacy converters, so PSR rewires to the new instances via a governance VIP without any PSR contract changes.

## Architecture

<figure><img src="/files/X5KVCp8nW2uICJzZQMci" alt="TokenBuyback architecture and PSR distribution flow"><figcaption><p>PSR distribution across TokenBuyback instances and their destinations (example: BNB Chain — 10 instances; percentages from PSR schema 0 — interest reserves)</p></figcaption></figure>

Per-instance state:

| Slot                                 | Purpose                                                                                           |
| ------------------------------------ | ------------------------------------------------------------------------------------------------- |
| `DESTINATION` (immutable)            | Address that receives `BASE_ASSET` after each swap or forward                                     |
| `BASE_ASSET` (immutable)             | Output token of every buyback — every swap converts into this                                     |
| `PROTOCOL_SHARE_RESERVE` (immutable) | Only address permitted to call `updateAssetsState` — prevents spoofed `AssetsReceived` events     |
| `RESILIENT_ORACLE` (immutable)       | USD-pricing source for the daily cap and the abnormal-slippage signal — not used for swap pricing |
| `allowedRouters`                     | On-chain allowlist of DEX routers (governance-managed)                                            |
| `assetsReserves[token]`              | Balance watermark used to derive the inflow delta on each PSR call                                |
| `dailyCapUsd`                        | Rolling 24h USD cap on `tokenIn` consumption (1e18-scaled)                                        |
| `slippageEventUsd`                   | Absolute USD threshold above which `AbnormalSlippage` fires (1e18-scaled)                         |
| `usdConsumedInWindow`, `lastUpdate`  | Leaky-bucket accumulator state for the daily cap                                                  |

## Income Flow

1. PSR transfers underlying tokens to `TokenBuyback` and calls `updateAssetsState(comptroller, asset)`.
2. The contract reads `balanceOf(this)`, compares against the `assetsReserves[asset]` watermark, emits `AssetsReceived(comptroller, asset, delta)` when the delta is non-zero, and resyncs the watermark to the current balance.
3. The cron monitors `AssetsReceived` events to know which token landed and from which pool.
4. When the cron decides to convert, it calls `executeBuyback` with off-chain-built router calldata.
5. `executeBuyback` swaps `tokenIn → BASE_ASSET` through the allowlisted router, validates `minAmountOut`, forwards the output to `DESTINATION`, pushes fresh oracle prices, enforces the daily cap, and emits `AbnormalSlippage` if the USD delta crosses the threshold.
6. `BASE_ASSET` that lands without needing a swap (e.g. PSR delivers `BASE_ASSET` directly) is sent on via `forwardBaseAsset`, which partitions the balance by caller-supplied `amount` so each portion can be attributed to a different comptroller via separate events.

## Daily USD Cap (leaky bucket)

`executeBuyback` enforces a rolling 24h USD cap on `tokenIn` consumption. The accumulator decays linearly between calls:

```
elapsed   = block.timestamp - lastUpdate
decayed   = elapsed >= WINDOW ? 0 : usdConsumedInWindow * (WINDOW - elapsed) / WINDOW
newUsage  = decayed + usdIn
require(newUsage <= dailyCapUsd)
usdConsumedInWindow = newUsage
lastUpdate          = block.timestamp
```

Where `WINDOW = 24 hours` and `usdIn = actualAmountIn * priceIn / 1e18`. The accumulator `usdConsumedInWindow` is bounded by `dailyCapUsd` at every moment, which caps sustainable throughput at `dailyCapUsd / 24h` plus a one-time burst of up to `dailyCapUsd` (so worst-case cumulative consumption over any rolling 24h interval is up to \~2 × `dailyCapUsd`). Reverts with `DailyCapExceeded(attempted, cap)` past the cap.

Default: **$30,000** cap at deploy. Tunable via `setDailyCapUsd` (ACM-restricted, rejects zero).

## Abnormal Slippage Signal

After settling the swap, `executeBuyback` USD-prices both legs and emits `AbnormalSlippage(tokenIn, actualAmountIn, amountOut, usdIn, usdOut)` when `usdIn − usdOut > slippageEventUsd`. The event is informational only — it does not revert. Used by off-chain monitoring to flag swaps routed through hostile pools or stale-aggregator outputs.

Default: **$500** absolute. Tunable via `setSlippageEventUsd` (ACM-restricted, rejects zero).

The slippage check uses the same oracle snapshot as the cap, refreshed via `oracle.updateAssetPrice(tokenIn)` and `oracle.updateAssetPrice(BASE_ASSET)` immediately before the read.

## Functions

### `updateAssetsState(address comptroller, address asset)`

PSR-only. Records the balance delta against the `assetsReserves[asset]` watermark and emits `AssetsReceived(comptroller, asset, delta)` when non-zero. Restricted by the `PROTOCOL_SHARE_RESERVE` immutable. The reported amount is a balance delta, not an authenticated source-of-funds record — tokens transferred directly to the contract outside the PSR flow are merged into the next event under whichever comptroller PSR happens to be processing.

### `executeBuyback(tokenIn, amountIn, minAmountOut, deadline, router, routerCalldata, comptroller)`

ACM-restricted. Performs the swap via the supplied router (must be on the allowlist) and forwards the output to `DESTINATION`.

Sequence:

1. Validate `deadline`, `tokenIn != BASE_ASSET`, router allowlisted, `amountIn > 0` and within `balanceOf(this)`.
2. Snapshot `tokenIn` and `BASE_ASSET` balances on this contract.
3. `forceApprove(router, amountIn)`, `router.functionCall(routerCalldata)`, `forceApprove(router, 0)`.
4. Compute `actualAmountIn = tokenInBefore - tokenInAfter` and `amountOut = baseAssetAfter - baseAssetBefore`.
5. Revert with `SlippageExceeded` if `amountOut < minAmountOut`.
6. Transfer `amountOut` of `BASE_ASSET` to `DESTINATION` and resync both watermarks.
7. Push fresh oracle prices, enforce the daily USD cap, emit `AbnormalSlippage` if applicable.
8. Emit `BuybackExecuted(tokenIn, actualAmountIn, amountOut, router, comptroller)`.

The reported `amountIn` in `BuybackExecuted` is the actual router consumption, not the caller-supplied parameter — the event reflects what the router actually pulled.

### `forwardBaseAsset(address comptroller, uint256 amount)`

ACM-restricted. Forwards a caller-specified `amount` of accumulated `BASE_ASSET` to `DESTINATION` without a swap. The `amount` parameter is exposed so the operator can partition multi-pool `BASE_ASSET` inflows and attribute each portion via a separate `BaseAssetForwarded(comptroller, amount)` event. No-op when `amount == 0`. Resyncs the `BASE_ASSET` watermark after the transfer.

### `setAllowedRouter(address router, bool allowed)`

Governance-only. Adds or removes a DEX router from the on-chain allowlist. Emits `RouterAllowlisted(router, allowed)`.

### `setDailyCapUsd(uint256 newCap)`

ACM-restricted. Updates the rolling 24h USD cap (1e18-scaled). Reverts with `ZeroValueNotAllowed` if `newCap` is zero — the cap is not a kill switch; revoke ACM permissions to fully disable buybacks. Emits `DailyCapUpdated(oldCap, newCap)`.

### `setSlippageEventUsd(uint256 newThreshold)`

ACM-restricted. Updates the absolute USD slippage-event threshold (1e18-scaled). Reverts with `ZeroValueNotAllowed` if `newThreshold` is zero. Emits `SlippageEventUsdUpdated(oldThreshold, newThreshold)`.

### `sweepToken(address token, address to, uint256 amount)`

Governance-only. Emergency token recovery. Also the canonical recovery path for tokens transferred directly to the contract outside the PSR flow, since on-chain accounting cannot distinguish donations from authenticated inflows. Resyncs `assetsReserves[token]` to the post-transfer balance. Emits `SweepToken(token, to, amount)`.

## Events

| Event                                                                 | When emitted                                                            |
| --------------------------------------------------------------------- | ----------------------------------------------------------------------- |
| `AssetsReceived(comptroller, asset, amount)`                          | PSR delivers tokens (non-zero delta)                                    |
| `BuybackExecuted(tokenIn, amountIn, amountOut, router, comptroller)`  | Successful DEX swap; `amountIn` is the on-chain router consumption      |
| `BaseAssetForwarded(comptroller, amount)`                             | `BASE_ASSET` forwarded to `DESTINATION` without swap                    |
| `RouterAllowlisted(router, allowed)`                                  | Router added or removed from allowlist                                  |
| `SweepToken(token, to, amount)`                                       | Emergency token sweep                                                   |
| `AbnormalSlippage(tokenIn, actualAmountIn, amountOut, usdIn, usdOut)` | Swap returned less USD value than input by more than `slippageEventUsd` |
| `DailyCapUpdated(oldCap, newCap)`                                     | `setDailyCapUsd` succeeded                                              |
| `SlippageEventUsdUpdated(oldThreshold, newThreshold)`                 | `setSlippageEventUsd` succeeded                                         |

## Errors

| Error                                              | Cause                                                                         |
| -------------------------------------------------- | ----------------------------------------------------------------------------- |
| `UnauthorizedCaller(caller)`                       | `updateAssetsState` called by anyone other than `PROTOCOL_SHARE_RESERVE`      |
| `RouterNotAllowed(router)`                         | `executeBuyback` with a router not on the allowlist                           |
| `InvalidTokenIn(tokenIn)`                          | `executeBuyback` with `tokenIn == BASE_ASSET`                                 |
| `InsufficientBalance(token, requested, available)` | `executeBuyback` or `forwardBaseAsset` requested more than the contract holds |
| `SlippageExceeded(expected, actual)`               | Swap output fell below `minAmountOut`                                         |
| `DeadlineExpired(deadline, blockTimestamp)`        | `executeBuyback` after the supplied deadline                                  |
| `DailyCapExceeded(attempted, cap)`                 | `executeBuyback` would push cumulative USD usage past `dailyCapUsd`           |
| `ZeroAddressNotAllowed`                            | Constructor / `setAllowedRouter` / `sweepToken` with zero address             |
| `ZeroValueNotAllowed`                              | Setters or `sweepToken` invoked with zero                                     |

## Destinations

The `(DESTINATION, BASE_ASSET)` pair is fixed per instance. Common destinations across deployments:

* **`VTreasury`** — accumulates protocol-revenue tokens (U, BTCB, ETH, USDT, USDC, XVS) bought back from non-Prime, non-RiskFund income.
* **`PrimeLiquidityProvider`** — accumulates Prime rewards in USDT and U; later distributed to Prime users according to per-token speeds configured via VIP. See [Prime tokens](/technical-reference/reference-technical-articles/prime).
* **`RiskFundV2`** — accumulates USDT used by [Shortfall auctions](/technical-reference/reference-technical-articles/shortfall-and-auctions). Per-pool accounting was removed alongside the migration; `RiskFundV2` now draws against its raw balance.
* **`XVSVaultTreasury`** — accumulates XVS that funds `XVSVault` rewards via VIP.

See [deployed contracts](/deployed-contracts/token-converters) for per-chain proxy addresses and their `(base asset, destination)` mapping.

## Operator Notes

* Conversions run on a defined schedule rather than on every inflow. The cron decides when to call `executeBuyback`; the contract has no internal trigger.
* The oracle is consulted **only** for the cap and slippage signal — not for swap pricing. Swap economics are determined by the off-chain-built router calldata.
* The daily cap bounds blast radius if the operator key is compromised. It is not intended to throttle normal operation.
* Routers must be added to the allowlist by governance before the cron can route through them. Removing a router via `setAllowedRouter(router, false)` immediately blocks future swaps through it.
* Donations to the contract (tokens sent directly, outside the PSR flow) are not distinguished from authenticated PSR inflows on-chain. Use `sweepToken` to recover them if needed.


# Two Kinks Interest Rate Curve

## Overview

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.

## 2-Kink Interest Rate Model Architecture

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.

<figure><img src="/files/MTThDU9BUpnT3oVIP2m3" alt="Two Kinks Interest Rate Model"><figcaption><p>Two Kinks Interest Rate Model</p></figcaption></figure>

## Benefits of 2-Kink IR Curve

* **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.

## Smart Contract Reference

* [Two Kinks Rate Model contract (for the Core pool on BNB Chain)](/technical-reference/reference-core-pool/interestratemodels/twokinksinterestratemodel)
* [Two Kinks Rate Model contract (for the Isolated pools)](/technical-reference/reference-isolated-pools/interest-rate-models/two-kinks-interest-rate-model)
* [Jump Rate Model contract (used in the Core pool on BNB Chain)](/technical-reference/reference-core-pool/interestratemodels/jumpmodel)
* [Jump Rate Model V2 contract (used in the Isolated pools)](/technical-reference/reference-isolated-pools/interest-rate-models/jump-rate-model-v2)


# VenusERC4626 Vaults

## Overview

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.

### Key Benefits:

* **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

## Understanding ERC-4626

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.

#### Reference: <https://eips.ethereum.org/EIPS/eip-4626>

## The implementation of the Venus ERC-4626 vaults consists of two core smart contracts:

#### **1. VenusERC4626Factory.sol - The factory contract for deploying standardized vaults**

* Deploys individual vaults for individual vTokens via **BeaconProxy**
* Ensures deterministic addresses using **CREATE2**
* Managed by Venus Governance

#### **2. VenusERC4626.sol - The vault logic implementing ERC-4626 functionality**

* ERC-4626-compliant mint, deposit, redeem, and withdraw functions
* Integrates with Venus **vToken** interest accrual
* Handles reward distribution (e.g., XVS)

## Architecture

<figure><img src="/files/drzR9K8rrAIF5kGenH9u" alt="Flow of funds related to ERC4626 wrappers"><figcaption></figcaption></figure>

## **VenusERC4626Factory.sol: The Vault Factory**

### **Architecture Overview**

The factory contract implements a sophisticated deployment system using OpenZeppelin's upgradeability patterns:

```jsx
contract VenusERC4626Factory is AccessControlledV8, MaxLoopsLimitHelper {
    UpgradeableBeacon public beacon;
    mapping(address vToken => ERC4626Upgradeable vault) public createdVaults;

    function createERC4626(address vToken) external returns (ERC4626Upgradeable) {
        // Deployment logic...
    }
}
```

### **Core Components**

### **Beacon Proxy System**

* **UpgradeableBeacon**: Stores the current implementation address.
* **BeaconProxy**: Proxy delegates to beacon implementation.
* **CREATE2**: Deterministic deployment with fixed salt for beacon proxies.

#### Benefits:

* Single implementation contract shared by all vaults.
* Gas-efficient deployments.
* Centralized upgrade capability.

### **PoolRegistry Integration**

```jsx
function createERC4626(address vToken) external {
    // Validate vToken is registered in PoolRegistry
    if (vToken != poolRegistry.getVTokenForAsset(comptroller, underlying)) {
        revert VenusERC4626Factory__InvalidVToken();
    }
    // Proceed with deployment...
}
```

This ensures:

* Only legitimate Venus vTokens can create vaults.
* Proper asset/vToken pairing.
* Compliance with Venus's risk parameters.

### Key Features

* **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).

### Events

* **`CreateERC4626 (event)`**: Emitted when a new ERC-4626 vault is created for a vToken.
* **`RewardRecipientUpdated (event)`**: Emitted when the reward recipient address is updated.

### Constants

* **`SALT (bytes32)`**: Constant salt used for deterministic deployment of vaults.

### State variables

* **`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.

### Functions

* **`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).

### **Security Considerations**

### **1. Access Controls**

* **Admin-Only Functions** (via **AccessControlledV8**):
  * **setRewardRecipient()**
  * **setMaxLoopsLimit()**
  * **upgradeBeacon()** (for emergency fixes)

### **2. Input Validation**

* **ensureNonzeroAddress()** prevents invalid configurations.

### **Attack Surface Mitigation**

| **Threat Vector**  | **Mitigation Strategy**   |
| ------------------ | ------------------------- |
| Reentrancy         | `nonReentrant` modifiers  |
| Invalid vTokens    | PoolRegistry validation   |
| Governance attacks | ACM with timelocks        |
| Upgrade risks      | Beacon ownership controls |

***

## VenusERC4626.sol: The Vault Implementation

### Core Architecture

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:

```jsx
contract VenusERC4626 is
    ERC4626Upgradeable,
    AccessControlledV8,
    MaxLoopsLimitHelper,
    ReentrancyGuardUpgradeable {
    // Implementation...
}
```

### Key Features

* **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.

### Key Inherited Functionality:

* **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.

### Events

* **`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.

### State variables

* **`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.

### Functions

#### Core ERC-4626 Functions

* **`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.

#### Initialization

* **`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.

#### Reward Management

* **`claimRewards()`**: Claims all available rewards and sends them to the recipient.
* **`setRewardRecipient(address newRecipient)`**: Updates the reward recipient address (ACM-restricted).

#### Admin Functions

* **`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).

### Error Codes

* **`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.

### **Deposit Flow**

```jsx
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;
}
```

1. Validates input parameters.
2. Calculates shares to mint.
3. Transfers assets from the user.
4. Mints vTokens via Venus Protocol.
5. Issues vault shares to the receiver.

#### Example

**Scenario**: Alice deposits 100 USDC.

<figure><img src="/files/Elqwf8Unx9ZBPJ7ws8qS" alt="Flow of funds related to ERC4626 wrapper"><figcaption></figcaption></figure>

#### Result:

* Alice gets 100 vault shares.
* Vault holds 100 vUSDC (earning yield).

### **Withdrawal Flow**

```jsx
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;
}
```

1. Validates input parameters.
2. Calculates shares to burn.
3. Redeems underlying assets from Venus.
4. Transfers assets to the receiver.
5. Burns vault shares.

#### Example

**Scenario**: Alice withdraws 50 USDC (after interest accrual).

<figure><img src="/files/D2oKcxsbqRF03OANNpaU" alt="Flow of funds related to ERC4626 wrappers"><figcaption></figcaption></figure>

#### Result

Alice receives 50 USDC.

* Vault burns shares adjusted for interest (e.g., 48.54 shares at a 1.03 exchange rate).

### **Security Features**

1. **Reentrancy Protection**:
   * All state-changing functions use the **nonReentrant** modifier.
   * Critical Venus operations (mint/redeem) are atomic.
2. **Input Validation**:
   * Zero-address checks are performed via **ensureNonzeroAddress**.
   * Zero-amount validation for all operations.
   * Explicit error codes for Venus operations.
3. **Access Control**:
   * Sensitive functions are protected by Venus's ACM.
   * The reward recipient can only be changed by authorized accounts.

***


# XVS Bridge

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 [BNB chain](https://www.bnbchain.org) and multiple destination chains. The supported networks are as follows:

* [Arbitrum](https://arbitrum.io)
* [Base](https://www.base.org/)
* [BNB](https://www.bnbchain.org)
* [Ethereum](https://ethereum.org)
* [opBNB](https://opbnb.bnbchain.org)
* [Optimism](https://app.optimism.io)
* [ZKsync](https://zksync.io/)

## Supported Transfer Paths

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](https://github.com/VenusProtocol/token-bridge/blob/develop/contracts/Bridge/XVSBridgeAdmin.sol), [XVSProxySrc](https://github.com/VenusProtocol/token-bridge/blob/develop/contracts/Bridge/XVSProxyOFTSrc.sol), [XVSProxyDest](https://github.com/VenusProtocol/token-bridge/blob/develop/contracts/Bridge/XVSProxyOFTDest.sol), and [XVS](https://github.com/VenusProtocol/token-bridge/blob/develop/contracts/Bridge/token/XVS.sol) token contracts.

***The functionality of the bridge relies on*** [***LayerZero***](https://layerzero.network) ***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.***

## 1. Getting Started

To start using the XVS Cross-Chain Bridge, follow these steps:

### 1.1. Approving XVS Tokens

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:

1. 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.

### 1.2. Estimating Transaction Fees

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](https://layerzero.gitbook.io/docs/technical-reference/mainnet/supported-chain-ids) (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).

## 2. Transferring Tokens

The actual token transfer is performed using the `sendFrom` function of the `Bridge` contract. Follow these steps:

### 2.1. Sending Tokens

<figure><img src="/files/aU5TRDiC7PikC4R179Dz" alt="Assets bridging from src chain to dest chain"><figcaption></figcaption></figure>

1. 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](https://layerzero.gitbook.io/docs/technical-reference/mainnet/supported-chain-ids) (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)
     * `adapterParams`: `0x000100000000000000000000000000000000000000000000000000000000000493E0` (ethers.utils.solidityPack(\['uint16','uint256'],\[1, gasValue]) the gas value should be greater then minDestGas which is set to 300k).

## 3. Receiving Tokens on the Destination Chain

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.

## 4. Transferring Tokens Back to the BNB chain

<figure><img src="/files/ET1XmVHFiv2GaXA0GczS" alt="Assets bridging from dest chain to src chain"><figcaption></figcaption></figure>

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).

## 5. Monitoring Transaction Status

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](https://layerzeroscan.com) to monitor your cross-chain transactions.

## 6. Security and Risks

<figure><img src="/files/Zpa8rhlSCedtk2fyAAzG" alt="Risks and security"><figcaption></figcaption></figure>

### 6.1. Ownership Transfer

* 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.

### 6.2. Pause and Resume

* 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.

### 6.3. Limit the Amount of XVS Transfers

* 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.

### 6.4. Transfer Delays

* Configurable delay after XVS transfers to the target network by specifying a minimum number of blocks in the LayerZero endpoint configuration.

### 6.5. Token Controller Contract

* [Token Controller](https://github.com/VenusProtocol/token-bridge/blob/develop/contracts/Bridge/token/TokenController.sol) contract within the XVS token deployed on the target network to blacklist addresses, preventing them from transferring or receiving XVS. Integrated with the ACM.

### 6.6. Cap on Token Minting

* Cap on the amount of tokens that can be minted in the destination target network. This feature can be integrated in Token Controller.

### 6.7. Mitigation Plans for Mint Cap Reached

* 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.

### 6.8. Bridge Model

* 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:**

  ```
  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.
  ```

### 6.9. Bridge Replacement Scenario

In the event that a `Bridge` contract needs replacement, such as due to a security risk, the following steps will be taken:

1. **Pause the Bridge:**
   * Temporarily pause the `Bridge` contract to prevent further transactions.
2. **Token Evaluation:**
   * Evaluate whether pausing the XVS token is necessary during the replacement process.
3. **Migrate MinterToMintedAmount:**
   * Move the `minterToMintedAmount` value to a different `Bridge` contract address using the `migrateMintedTokens` function.
4. **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.

### 6.10. Default Downtime

* Currently, the `Bridge` relies on a single relayer, the [default](https://layerzero.gitbook.io/docs/technical-reference/mainnet/default-config) 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.

## 7. Contract Details

Here, we provide more details about the key contracts used in the XVS Cross-chain Bridge:

### 7.1. XVSBridgeAdmin

* [XVSBridgeAdmin](https://github.com/VenusProtocol/token-bridge/blob/develop/contracts/Bridge/XVSBridgeAdmin.sol) 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.

### 7.2. XVSProxySrc

* [XVSProxySrc](https://github.com/VenusProtocol/token-bridge/blob/develop/contracts/Bridge/XVSProxyOFTSrc.sol) extends the [BaseOFTV2](https://github.com/LayerZero-Labs/solidity-examples/blob/main/contracts/token/oft/v2/BaseOFTV2.sol) 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.

### 7.3. XVSProxyDest

* [XVSProxyDest](https://github.com/VenusProtocol/token-bridge/blob/develop/contracts/Bridge/XVSProxyOFTDest.sol) 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.

### 7.4. XVS Token

* The [XVS](https://github.com/VenusProtocol/token-bridge/blob/develop/contracts/Bridge/token/XVS.sol) 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](https://github.com/VenusProtocol/token-bridge/blob/develop/contracts/Bridge/token/TokenController.sol) 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.
* [ACM](https://github.com/VenusProtocol/governance-contracts/blob/develop/contracts/Governance/AccessControlManager.sol) integration is used for setting minting caps and blacklisting, and these settings can be configured via VIPs or Guardian.

## 8. Additional Features

In addition to the core functionality, the XVS Cross-chain Bridge includes additional features to enhance its capabilities:

### 8.1. Oracle Integration

* The contract incorporates an oracle integration through the `ResilientOracleInterface`. It allows the contract to fetch price data for the token using the `getPrice` function.

### 8.2. Whitelist Mechanism

* 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.

### 8.3. Transaction Limits

* 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)

  |          | BNB      | opBNB   | Arbitrum | Ethereum | ZKsync  | Optimism | Base    |
  | -------- | -------- | ------- | -------- | -------- | ------- | -------- | ------- |
  | 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 | $20,000  | $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  | -       |
* Daily Send Limit (source network in the first column, destination network in the first row)

  |          | BNB        | opBNB    | Arbitrum | Ethereum   | ZKsync   | Optimism | Base     |
  | -------- | ---------- | -------- | -------- | ---------- | -------- | -------- | -------- |
  | BNB      | -          | $50,000  | $100,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 | -        |
* 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.

### 8.4. Pause and Unpause Mechanism

* 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.

## 9. Possible Failures of Bridging XVS Tokens

### 9.1. Sending XVS tokens from the source chain

* 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.

### 9.2. Receiving XVS tokens on the destination chain

* 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.

### Retry Mechanism for Failed Transactions

In the event of a failed transaction, follow the below step-by-step process using block explorers and the [`retryMessage`](https://github.com/VenusProtocol/token-bridge/blob/main/contracts/Bridge/BaseXVSProxyOFT.sol#L368) function to retry transactions on the respective blockchain. Here's a detailed guide:

1. **Identify the Failed Transaction:**
   * Use [LayerZero scan](https://layerzeroscan.com) to identify the failed transaction within the target network by providing the transaction hash from the source network where the transaction was initiated.
2. **Examine the MessageFailed Log:**
   * Access the emitted events of the failed transaction and specifically examine the [`MessageFailed`](https://github.com/LayerZero-Labs/solidity-examples/blob/main/contracts/lzApp/NonblockingLzApp.sol#L20) log. This log contains essential function parameters needed for the retry.
3. **Extract Function Parameters:**
   * From the `MessageFailed` log, extract the following essential function parameters:
     * `_srcChainId`
     * `_srcAddress`
     * `_nonce`
     * `_payload`
4. **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.


# Core Pool


# Comptroller


# ComptrollerLens

## ComptrollerLens Contract

The ComptrollerLens contract has functions to get the number of tokens that can be seized through liquidation, hypothetical account liquidity and shortfall of an account.

## Solidity API

```solidity
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;
}
```

#### liquidateCalculateSeizeTokens

Computes the number of collateral tokens to be seized in a liquidation event

```solidity
function liquidateCalculateSeizeTokens(address comptroller, address vTokenBorrowed, address vTokenCollateral, uint256 actualRepayAmount) external view returns (uint256, uint256)
```

**Parameters**

| Name              | Type    | Description                                                       |
| ----------------- | ------- | ----------------------------------------------------------------- |
| 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**

| Name | Type    | Description                                |
| ---- | ------- | ------------------------------------------ |
| \[0] | uint256 | A tuple of error code, and tokens to seize |
| \[1] | uint256 |                                            |

***

#### liquidateCalculateSeizeTokens

Computes the number of collateral tokens to be seized in a liquidation event

```solidity
function liquidateCalculateSeizeTokens(address borrower, address comptroller, address vTokenBorrowed, address vTokenCollateral, uint256 actualRepayAmount) external view returns (uint256, uint256)
```

**Parameters**

| Name              | Type    | Description                                                       |
| ----------------- | ------- | ----------------------------------------------------------------- |
| borrower          | address | Address of borrower whose collateral is being seized              |
| 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**

| Name | Type    | Description                                |
| ---- | ------- | ------------------------------------------ |
| \[0] | uint256 | A tuple of error code, and tokens to seize |
| \[1] | uint256 |                                            |

***

#### liquidateVAICalculateSeizeTokens

Computes the number of VAI tokens to be seized in a liquidation event

```solidity
function liquidateVAICalculateSeizeTokens(address comptroller, address vTokenCollateral, uint256 actualRepayAmount) external view returns (uint256, uint256)
```

**Parameters**

| Name              | Type    | Description                                                           |
| ----------------- | ------- | --------------------------------------------------------------------- |
| 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**

| Name | Type    | Description                                |
| ---- | ------- | ------------------------------------------ |
| \[0] | uint256 | A tuple of error code, and tokens to seize |
| \[1] | uint256 |                                            |

***

#### getHypotheticalAccountLiquidity

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

```solidity
function getHypotheticalAccountLiquidity(address comptroller, address account, contract VToken vTokenModify, uint256 redeemTokens, uint256 borrowAmount, enum WeightFunction weightingStrategy) external view returns (uint256, uint256, uint256)
```

**Parameters**

| Name              | Type                | Description                                                                                                                                                                |
| ----------------- | ------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| comptroller       | address             | Address of comptroller                                                                                                                                                     |
| account           | address             | Address of the borrowed vToken                                                                                                                                             |
| vTokenModify      | contract VToken     | Address of collateral for vToken                                                                                                                                           |
| redeemTokens      | uint256             | 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 |

**Return Values**

| Name | Type    | Description                                             |
| ---- | ------- | ------------------------------------------------------- |
| \[0] | uint256 | Returns a tuple of error code, liquidity, and shortfall |
| \[1] | uint256 |                                                         |
| \[2] | uint256 |                                                         |

***


# Diamond


# Diamond

## Diamond

This contract contains functions related to facets

## Solidity API

```solidity
struct Facet {
  address facetAddress;
  bytes4[] functionSelectors;
}
```

#### \_become

Call \_acceptImplementation to accept the diamond proxy as new implementaion

```solidity
function _become(contract Unitroller unitroller) public
```

**Parameters**

| Name       | Type                | Description               |
| ---------- | ------------------- | ------------------------- |
| unitroller | contract Unitroller | Address of the unitroller |

***

#### diamondCut

To add function selectors to the facet's mapping

```solidity
function diamondCut(struct IDiamondCut.FacetCut[] diamondCut_) public
```

**Parameters**

| Name         | Type                           | Description                                                        |
| ------------ | ------------------------------ | ------------------------------------------------------------------ |
| diamondCut\_ | struct IDiamondCut.FacetCut\[] | IDiamondCut contains facets address, action and function selectors |

***

#### facetFunctionSelectors

Get all function selectors mapped to the facet address

```solidity
function facetFunctionSelectors(address facet) external view returns (bytes4[])
```

**Parameters**

| Name  | Type    | Description          |
| ----- | ------- | -------------------- |
| facet | address | Address of the facet |

**Return Values**

| Name | Type      | Description                           |
| ---- | --------- | ------------------------------------- |
| \[0] | bytes4\[] | selectors Array of function selectors |

***

#### facetPosition

Get facet position in the \_facetFunctionSelectors through facet address

```solidity
function facetPosition(address facet) external view returns (uint256)
```

**Parameters**

| Name  | Type    | Description          |
| ----- | ------- | -------------------- |
| facet | address | Address of the facet |

**Return Values**

| Name | Type    | Description           |
| ---- | ------- | --------------------- |
| \[0] | uint256 | Position of the facet |

***

#### facetAddresses

Get all facet addresses

```solidity
function facetAddresses() external view returns (address[])
```

**Return Values**

| Name | Type       | Description                             |
| ---- | ---------- | --------------------------------------- |
| \[0] | address\[] | facetAddresses Array of facet addresses |

***

#### facetAddress

Get facet address and position through function selector

```solidity
function facetAddress(bytes4 functionSelector) external view returns (struct ComptrollerV13Storage.FacetAddressAndPosition)
```

**Parameters**

| Name             | Type   | Description       |
| ---------------- | ------ | ----------------- |
| functionSelector | bytes4 | function selector |

**Return Values**

| Name | Type                                                 | Description                                        |
| ---- | ---------------------------------------------------- | -------------------------------------------------- |
| \[0] | struct ComptrollerV13Storage.FacetAddressAndPosition | FacetAddressAndPosition facet address and position |

***

#### facets

Get all facets address and their function selector

```solidity
function facets() external view returns (struct Diamond.Facet[])
```

**Return Values**

| Name | Type                    | Description             |
| ---- | ----------------------- | ----------------------- |
| \[0] | struct Diamond.Facet\[] | facets\_ Array of Facet |

***


# DiamondConsolidated

## DiamondConsolidated

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

## Solidity API


# Facets


# MarketFacet

## MarketFacet

This facet contract contains functions regarding markets

## Solidity API

#### isComptroller

Indicator that this is a Comptroller contract (for inspection)

```solidity
function isComptroller() public pure returns (bool)
```

***

#### getAssetsIn

Returns the vToken markets an account has entered in the Core Pool

```solidity
function getAssetsIn(address account) external view returns (contract VToken[])
```

**Parameters**

| Name    | Type    | Description                         |
| ------- | ------- | ----------------------------------- |
| account | address | The address of the account to query |

**Return Values**

| Name | Type               | Description                                                      |
| ---- | ------------------ | ---------------------------------------------------------------- |
| \[0] | contract VToken\[] | assets A dynamic array of vToken markets the account has entered |

***

#### getAllMarkets

Return all of the markets

```solidity
function getAllMarkets() external view returns (contract VToken[])
```

**Return Values**

| Name | Type               | Description                  |
| ---- | ------------------ | ---------------------------- |
| \[0] | contract VToken\[] | The list of market addresses |

***

#### liquidateCalculateSeizeTokens

Calculate number of tokens of collateral asset to seize given an underlying amount

```solidity
function liquidateCalculateSeizeTokens(address vTokenBorrowed, address vTokenCollateral, uint256 actualRepayAmount) external view returns (uint256, uint256)
```

**Parameters**

| Name              | Type    | Description                                                                     |
| ----------------- | ------- | ------------------------------------------------------------------------------- |
| 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 |

**Return Values**

| Name | Type    | Description                                                                  |
| ---- | ------- | ---------------------------------------------------------------------------- |
| \[0] | uint256 | (errorCode, number of vTokenCollateral tokens to be seized in a liquidation) |
| \[1] | uint256 |                                                                              |

***

#### liquidateCalculateSeizeTokens

Calculate number of tokens of collateral asset to seize given an underlying amount

```solidity
function liquidateCalculateSeizeTokens(address borrower, address vTokenBorrowed, address vTokenCollateral, uint256 actualRepayAmount) external view returns (uint256, uint256)
```

**Parameters**

| Name              | Type    | Description                                                                     |
| ----------------- | ------- | ------------------------------------------------------------------------------- |
| 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 | The amount of vTokenBorrowed underlying to convert into vTokenCollateral tokens |

**Return Values**

| Name | Type    | Description                                                                  |
| ---- | ------- | ---------------------------------------------------------------------------- |
| \[0] | uint256 | (errorCode, number of vTokenCollateral tokens to be seized in a liquidation) |
| \[1] | uint256 |                                                                              |

***

#### liquidateVAICalculateSeizeTokens

Calculate number of tokens of collateral asset to seize given an underlying amount

```solidity
function liquidateVAICalculateSeizeTokens(address vTokenCollateral, uint256 actualRepayAmount) external view returns (uint256, uint256)
```

**Parameters**

| Name              | Type    | Description                                                                     |
| ----------------- | ------- | ------------------------------------------------------------------------------- |
| vTokenCollateral  | address | The address of the collateral vToken                                            |
| actualRepayAmount | uint256 | The amount of vTokenBorrowed underlying to convert into vTokenCollateral tokens |

**Return Values**

| Name | Type    | Description                                                                  |
| ---- | ------- | ---------------------------------------------------------------------------- |
| \[0] | uint256 | (errorCode, number of vTokenCollateral tokens to be seized in a liquidation) |
| \[1] | uint256 |                                                                              |

***

#### checkMembership

Returns whether the given account has entered the specified vToken market in the Core Pool

```solidity
function checkMembership(address account, contract VToken vToken) external view returns (bool)
```

**Parameters**

| Name    | Type            | Description                         |
| ------- | --------------- | ----------------------------------- |
| account | address         | The address of the account to check |
| vToken  | contract VToken | The vToken to check                 |

**Return Values**

| Name | Type | Description                                          |
| ---- | ---- | ---------------------------------------------------- |
| \[0] | bool | True if the account is in the asset, otherwise false |

***

#### isMarketListed

Checks whether the given vToken market is listed in the Core Pool (`poolId = 0`)

```solidity
function isMarketListed(contract VToken vToken) external view returns (bool)
```

**Parameters**

| Name   | Type            | Description                               |
| ------ | --------------- | ----------------------------------------- |
| vToken | contract VToken | The vToken Address of the market to check |

**Return Values**

| Name | Type | Description                                                              |
| ---- | ---- | ------------------------------------------------------------------------ |
| \[0] | bool | listed True if the (Core Pool, vToken) market is listed, otherwise false |

***

#### enterMarkets

Add assets to be included in account liquidity calculation

```solidity
function enterMarkets(address[] vTokens) external returns (uint256[])
```

**Parameters**

| Name    | Type       | Description                                               |
| ------- | ---------- | --------------------------------------------------------- |
| vTokens | address\[] | The list of addresses of the vToken markets to be enabled |

**Return Values**

| Name | Type       | Description                                                         |
| ---- | ---------- | ------------------------------------------------------------------- |
| \[0] | uint256\[] | Success indicator for whether each corresponding market was entered |

***

#### enterMarketBehalf

Add assets to be included in account liquidity calculation

```solidity
function enterMarketBehalf(address onBehalf, address vToken) external returns (uint256)
```

**Parameters**

| Name     | Type    | Description                                                |
| -------- | ------- | ---------------------------------------------------------- |
| onBehalf | address | The address of the account entering the market             |
| vToken   | address | The address of the vToken market to enable for the account |

**Return Values**

| Name | Type    | Description                                                     |
| ---- | ------- | --------------------------------------------------------------- |
| \[0] | uint256 | uint256 indicating the result (0 = success, non-zero = failure) |

**❌ Errors**

* NotAnApprovedDelegate thrown if `msg.sender` is not the account itself or an approved delegate

***

#### unlistMarket

Unlists the given vToken market from the Core Pool (`poolId = 0`) by setting `isListed` to false

```solidity
function unlistMarket(address market) external returns (uint256)
```

**Parameters**

| Name   | Type    | Description                                  |
| ------ | ------- | -------------------------------------------- |
| market | address | The address of the market (vToken) to unlist |

**Return Values**

| Name | Type    | Description                                                         |
| ---- | ------- | ------------------------------------------------------------------- |
| \[0] | uint256 | uint256 0=success, otherwise a failure (See enum Error for details) |

***

#### exitMarket

Removes asset from sender's account liquidity calculation

```solidity
function exitMarket(address vTokenAddress) external returns (uint256)
```

**Parameters**

| Name          | Type    | Description                            |
| ------------- | ------- | -------------------------------------- |
| vTokenAddress | address | The address of the asset to be removed |

**Return Values**

| Name | Type    | Description                                               |
| ---- | ------- | --------------------------------------------------------- |
| \[0] | uint256 | Whether or not the account successfully exited the market |

***

#### supportMarket

Alias to \_supportMarket to support the Isolated Lending Comptroller Interface

```solidity
function supportMarket(contract VToken vToken) external returns (uint256)
```

**Parameters**

| Name   | Type            | Description                               |
| ------ | --------------- | ----------------------------------------- |
| vToken | contract VToken | The address of the market (token) to list |

**Return Values**

| Name | Type    | Description                                                          |
| ---- | ------- | -------------------------------------------------------------------- |
| \[0] | uint256 | uint256 0=success, otherwise a failure. (See enum Error for details) |

***

#### \_supportMarket

Adds the given vToken market to the Core Pool (`poolId = 0`) and marks it as listed

```solidity
function _supportMarket(contract VToken vToken) external returns (uint256)
```

**Parameters**

| Name   | Type            | Description                                               |
| ------ | --------------- | --------------------------------------------------------- |
| vToken | contract VToken | The address of the vToken market to list in the Core Pool |

**Return Values**

| Name | Type    | Description                                                          |
| ---- | ------- | -------------------------------------------------------------------- |
| \[0] | uint256 | uint256 0=success, otherwise a failure. (See enum Error for details) |

***

#### updateDelegate

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

```solidity
function updateDelegate(address delegate, bool approved) external
```

**Parameters**

| Name     | Type    | Description                                                                 |
| -------- | ------- | --------------------------------------------------------------------------- |
| delegate | address | The address to update the rights for                                        |
| approved | bool    | Whether to grant (true) or revoke (false) the borrowing or redeeming rights |

***

#### enterPool

Allows a user to switch to a new pool (e.g., e-mode).

```solidity
function enterPool(uint96 poolId) external
```

**Parameters**

| Name   | Type   | Description                                 |
| ------ | ------ | ------------------------------------------- |
| poolId | uint96 | The ID of the pool the user wants to enter. |

**📅 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.
* InactivePool The user is trying to enter inactive pool.

***

#### createPool

Creates a new pool with the given label.

```solidity
function createPool(string label) external returns (uint96)
```

**Parameters**

| Name  | Type   | Description                            |
| ----- | ------ | -------------------------------------- |
| label | string | name for the pool (must be non-empty). |

**Return Values**

| Name | Type   | Description                                                         |
| ---- | ------ | ------------------------------------------------------------------- |
| \[0] | uint96 | poolId The incremental unique identifier of the newly created pool. |

**📅 Events**

* PoolCreated Emitted after successfully creating a new pool.

**❌ Errors**

* EmptyPoolLabel Reverts if the provided label is an empty string.

***

#### addPoolMarkets

Batch initializes market entries with basic config.

```solidity
function addPoolMarkets(uint96[] poolIds, address[] vTokens) external
```

**Parameters**

| Name    | Type       | Description                         |
| ------- | ---------- | ----------------------------------- |
| poolIds | uint96\[]  | Array of pool IDs.                  |
| vTokens | address\[] | Array of market (vToken) addresses. |

**📅 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.
* MarketNotListedInCorePool Reverts if the market is not listed in the core 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.

***

#### removePoolMarket

Removes a market (vToken) from the specified pool.

```solidity
function removePoolMarket(uint96 poolId, address vToken) external
```

**Parameters**

| Name   | Type    | Description                                                 |
| ------ | ------- | ----------------------------------------------------------- |
| poolId | uint96  | The ID of the pool from which the market should be removed. |
| vToken | address | The address of the market token to remove.                  |

**📅 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.

***

#### getCollateralFactor

Get the core pool collateral factor for a vToken

```solidity
function getCollateralFactor(address vToken) external view returns (uint256)
```

**Parameters**

| Name   | Type    | Description                                                |
| ------ | ------- | ---------------------------------------------------------- |
| vToken | address | The address of the vToken to get the collateral factor for |

**Return Values**

| Name | Type    | Description                                          |
| ---- | ------- | ---------------------------------------------------- |
| \[0] | uint256 | The collateral factor for the vToken, scaled by 1e18 |

***

#### getLiquidationThreshold

Get the core pool liquidation threshold for a vToken

```solidity
function getLiquidationThreshold(address vToken) external view returns (uint256)
```

**Parameters**

| Name   | Type    | Description                                                    |
| ------ | ------- | -------------------------------------------------------------- |
| vToken | address | The address of the vToken to get the liquidation threshold for |

**Return Values**

| Name | Type    | Description                                              |
| ---- | ------- | -------------------------------------------------------- |
| \[0] | uint256 | The liquidation threshold for the vToken, scaled by 1e18 |

***

#### getLiquidationIncentive

Get the core pool liquidation Incentive for a vToken

```solidity
function getLiquidationIncentive(address vToken) external view returns (uint256)
```

**Parameters**

| Name   | Type    | Description                                                    |
| ------ | ------- | -------------------------------------------------------------- |
| vToken | address | The address of the vToken to get the liquidation Incentive for |

**Return Values**

| Name | Type    | Description                                                                   |
| ---- | ------- | ----------------------------------------------------------------------------- |
| \[0] | uint256 | liquidationIncentive The liquidation incentive for the vToken, scaled by 1e18 |

***

#### getEffectiveLtvFactor

Get the effective loan-to-value factor (collateral factor or liquidation threshold) for a given account and market.

```solidity
function getEffectiveLtvFactor(address account, address vToken, enum WeightFunction weightingStrategy) external view returns (uint256)
```

**Parameters**

| Name              | Type                | Description                                                                                                                                                                |
| ----------------- | ------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 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 |

**Return Values**

| Name | Type    | Description                                                |
| ---- | ------- | ---------------------------------------------------------- |
| \[0] | uint256 | factor The effective loan-to-value factor, scaled by 1e18. |

***

#### getEffectiveLiquidationIncentive

Get the Effective Liquidation Incentive for a given account and market

```solidity
function getEffectiveLiquidationIncentive(address account, address vToken) external view returns (uint256)
```

**Parameters**

| Name    | Type    | Description                                                              |
| ------- | ------- | ------------------------------------------------------------------------ |
| account | address | The account whose pool is used to determine the market's risk parameters |
| vToken  | address | The address of the vToken market                                         |

**Return Values**

| Name | Type    | Description                                              |
| ---- | ------- | -------------------------------------------------------- |
| \[0] | uint256 | The liquidation Incentive for the vToken, scaled by 1e18 |

***

#### getPoolVTokens

Returns the full list of vTokens for a given pool ID.

```solidity
function getPoolVTokens(uint96 poolId) external view returns (address[])
```

**Parameters**

| Name   | Type   | Description                                         |
| ------ | ------ | --------------------------------------------------- |
| poolId | uint96 | The ID of the pool whose vTokens are being queried. |

**Return Values**

| Name | Type       | Description                                            |
| ---- | ---------- | ------------------------------------------------------ |
| \[0] | address\[] | An array of vToken addresses associated with the pool. |

**❌ Errors**

* PoolDoesNotExist Reverts if the given pool ID do not exist.
* InvalidOperationForCorePool Reverts if called on the Core Pool.

***

#### markets

Returns the market configuration for a vToken in the core pool (poolId = 0).

```solidity
function markets(address vToken) external view returns (bool isListed, uint256 collateralFactorMantissa, bool isVenus, uint256 liquidationThresholdMantissa, uint256 liquidationIncentiveMantissa, uint96 marketPoolId, bool isBorrowAllowed)
```

**Parameters**

| Name   | Type    | Description                                                            |
| ------ | ------- | ---------------------------------------------------------------------- |
| vToken | address | The address of the vToken whose market configuration is to be fetched. |

**Return Values**

| Name                         | Type    | Description                                                         |
| ---------------------------- | ------- | ------------------------------------------------------------------- |
| 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 | The threshold at which liquidation is triggered, in mantissa.       |
| 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.                        |

***

#### poolMarkets

Returns the market configuration for a vToken from \_poolMarkets.

```solidity
function poolMarkets(uint96 poolId, address vToken) public view returns (bool isListed, uint256 collateralFactorMantissa, bool isVenus, uint256 liquidationThresholdMantissa, uint256 liquidationIncentiveMantissa, uint96 marketPoolId, bool isBorrowAllowed)
```

**Parameters**

| Name   | Type    | Description                                                            |
| ------ | ------- | ---------------------------------------------------------------------- |
| 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. |

**Return Values**

| Name                         | Type    | Description                                                     |
| ---------------------------- | ------- | --------------------------------------------------------------- |
| 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 | The threshold at which liquidation is triggered, in mantissa.   |
| 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.                    |

**❌ Errors**

* PoolDoesNotExist Reverts if the given pool ID do not exist.

***

#### hasValidPoolBorrows

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.

```solidity
function hasValidPoolBorrows(address account, uint96 targetPoolId) public view returns (bool)
```

**Parameters**

| Name         | Type    | Description                                         |
| ------------ | ------- | --------------------------------------------------- |
| account      | address | The address of the user attempting to switch pools. |
| targetPoolId | uint96  | The pool ID the user wants to switch into.          |

**Return Values**

| Name | Type | Description                                          |
| ---- | ---- | ---------------------------------------------------- |
| \[0] | bool | bool True if the switch is allowed, otherwise False. |

***


# PolicyFacet

## PolicyFacet

This facet contract contains all the external pre-hook functions related to vToken

## Solidity API

#### mintAllowed

Checks if the account should be allowed to mint tokens in the given market

```solidity
function mintAllowed(address vToken, address minter, uint256 mintAmount) external returns (uint256)
```

**Parameters**

| Name       | Type    | Description                                                                  |
| ---------- | ------- | ---------------------------------------------------------------------------- |
| 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**

| Name | Type    | Description                                                                          |
| ---- | ------- | ------------------------------------------------------------------------------------ |
| \[0] | uint256 | 0 if the mint is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol) |

***

#### mintVerify

Validates mint, accrues interest and updates score in prime. Reverts on rejection. May emit logs.

```solidity
function mintVerify(address vToken, address minter, uint256 actualMintAmount, uint256 mintTokens) external
```

**Parameters**

| Name             | Type    | Description                                     |
| ---------------- | ------- | ----------------------------------------------- |
| vToken           | address | Asset being minted                              |
| minter           | address | The address minting the tokens                  |
| actualMintAmount | uint256 | The amount of the underlying asset being minted |
| mintTokens       | uint256 | The number of tokens being minted               |

***

#### redeemAllowed

Checks if the account should be allowed to redeem tokens in the given market

```solidity
function redeemAllowed(address vToken, address redeemer, uint256 redeemTokens) external returns (uint256)
```

**Parameters**

| Name         | Type    | Description                                                              |
| ------------ | ------- | ------------------------------------------------------------------------ |
| 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**

| Name | Type    | Description                                                                            |
| ---- | ------- | -------------------------------------------------------------------------------------- |
| \[0] | uint256 | 0 if the redeem is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol) |

***

#### redeemVerify

Validates redeem, accrues interest and updates score in prime. Reverts on rejection. May emit logs.

```solidity
function redeemVerify(address vToken, address redeemer, uint256 redeemAmount, uint256 redeemTokens) external
```

**Parameters**

| Name         | Type    | Description                                       |
| ------------ | ------- | ------------------------------------------------- |
| vToken       | address | Asset being redeemed                              |
| redeemer     | address | The address redeeming the tokens                  |
| redeemAmount | uint256 | The amount of the underlying asset being redeemed |
| redeemTokens | uint256 | The number of tokens being redeemed               |

***

#### borrowAllowed

Checks if the account should be allowed to borrow the underlying asset of the given market

```solidity
function borrowAllowed(address vToken, address borrower, uint256 borrowAmount) external returns (uint256)
```

**Parameters**

| Name         | Type    | Description                                       |
| ------------ | ------- | ------------------------------------------------- |
| 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**

| Name | Type    | Description                                                                            |
| ---- | ------- | -------------------------------------------------------------------------------------- |
| \[0] | uint256 | 0 if the borrow is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol) |

***

#### borrowVerify

Validates borrow, accrues interest and updates score in prime. Reverts on rejection. May emit logs.

```solidity
function borrowVerify(address vToken, address borrower, uint256 borrowAmount) external
```

**Parameters**

| Name         | Type    | Description                                            |
| ------------ | ------- | ------------------------------------------------------ |
| 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 |

***

#### repayBorrowAllowed

Checks if the account should be allowed to repay a borrow in the given market

```solidity
function repayBorrowAllowed(address vToken, address payer, address borrower, uint256 repayAmount) external returns (uint256)
```

**Parameters**

| Name        | Type    | Description                                                |
| ----------- | ------- | ---------------------------------------------------------- |
| 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 | The amount of the underlying asset the account would repay |

**Return Values**

| Name | Type    | Description                                                                           |
| ---- | ------- | ------------------------------------------------------------------------------------- |
| \[0] | uint256 | 0 if the repay is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol) |

***

#### repayBorrowVerify

Validates repayBorrow, accrues interest and updates score in prime. Reverts on rejection. May emit logs.

```solidity
function repayBorrowVerify(address vToken, address payer, address borrower, uint256 actualRepayAmount, uint256 borrowerIndex) external
```

**Parameters**

| Name              | Type    | Description                           |
| ----------------- | ------- | ------------------------------------- |
| vToken            | address | Asset being repaid                    |
| payer             | address | The address repaying the borrow       |
| borrower          | address | The address of the borrower           |
| actualRepayAmount | uint256 | The amount of underlying being repaid |
| borrowerIndex     | uint256 |                                       |

***

#### liquidateBorrowAllowed

Checks if the liquidation should be allowed to occur

```solidity
function liquidateBorrowAllowed(address vTokenBorrowed, address vTokenCollateral, address liquidator, address borrower, uint256 repayAmount) external view returns (uint256)
```

**Parameters**

| Name             | Type    | Description                                                |
| ---------------- | ------- | ---------------------------------------------------------- |
| 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 | The address of the borrower                                |
| repayAmount      | uint256 | The amount of underlying being repaid                      |

***

#### liquidateBorrowVerify

Validates liquidateBorrow, accrues interest and updates score in prime. Reverts on rejection. May emit logs.

```solidity
function liquidateBorrowVerify(address vTokenBorrowed, address vTokenCollateral, address liquidator, address borrower, uint256 actualRepayAmount, uint256 seizeTokens) external
```

**Parameters**

| Name              | Type    | Description                                                |
| ----------------- | ------- | ---------------------------------------------------------- |
| 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 | The address of the borrower                                |
| actualRepayAmount | uint256 | The amount of underlying being repaid                      |
| seizeTokens       | uint256 | The amount of collateral token that will be seized         |

***

#### seizeAllowed

Checks if the seizing of assets should be allowed to occur

```solidity
function seizeAllowed(address vTokenCollateral, address vTokenBorrowed, address liquidator, address borrower, uint256 seizeTokens) external returns (uint256)
```

**Parameters**

| Name             | Type    | Description                                                |
| ---------------- | ------- | ---------------------------------------------------------- |
| 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 | The address of the borrower                                |
| seizeTokens      | uint256 | The number of collateral tokens to seize                   |

***

#### seizeVerify

Validates seize, accrues interest and updates score in prime. Reverts on rejection. May emit logs.

```solidity
function seizeVerify(address vTokenCollateral, address vTokenBorrowed, address liquidator, address borrower, uint256 seizeTokens) external
```

**Parameters**

| Name             | Type    | Description                                                |
| ---------------- | ------- | ---------------------------------------------------------- |
| 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 | The address of the borrower                                |
| seizeTokens      | uint256 | The number of collateral tokens to seize                   |

***

#### transferAllowed

Checks if the account should be allowed to transfer tokens in the given market

```solidity
function transferAllowed(address vToken, address src, address dst, uint256 transferTokens) external returns (uint256)
```

**Parameters**

| Name           | Type    | Description                               |
| -------------- | ------- | ----------------------------------------- |
| 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 | The number of vTokens to transfer         |

**Return Values**

| Name | Type    | Description                                                                              |
| ---- | ------- | ---------------------------------------------------------------------------------------- |
| \[0] | uint256 | 0 if the transfer is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol) |

***

#### transferVerify

Validates transfer, accrues interest and updates score in prime. Reverts on rejection. May emit logs.

```solidity
function transferVerify(address vToken, address src, address dst, uint256 transferTokens) external
```

**Parameters**

| Name           | Type    | Description                           |
| -------------- | ------- | ------------------------------------- |
| vToken         | address | Asset being transferred               |
| src            | address | The account which sources the tokens  |
| dst            | address | The account which receives the tokens |
| transferTokens | uint256 | The number of vTokens to transfer     |

***

#### getBorrowingPower

Alias to getAccountLiquidity to support the Isolated Lending Comptroller Interface

```solidity
function getBorrowingPower(address account) external view returns (uint256, uint256, uint256)
```

**Parameters**

| Name    | Type    | Description                   |
| ------- | ------- | ----------------------------- |
| account | address | The account get liquidity for |

**Return Values**

| Name | Type    | Description                                                                                                                                  |
| ---- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
| \[0] | uint256 | (possible error code (semi-opaque), account liquidity in excess of collateral requirements, account shortfall below collateral requirements) |
| \[1] | uint256 |                                                                                                                                              |
| \[2] | uint256 |                                                                                                                                              |

***

#### getAccountLiquidity

Determine the current account liquidity wrt liquidation threshold requirements

```solidity
function getAccountLiquidity(address account) external view returns (uint256, uint256, uint256)
```

**Parameters**

| Name    | Type    | Description                   |
| ------- | ------- | ----------------------------- |
| account | address | The account get liquidity for |

**Return Values**

| Name | Type    | Description                                                                                                                                                        |
| ---- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| \[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 |                                                                                                                                                                    |

***

#### getHypotheticalAccountLiquidity

Determine what the account liquidity would be if the given amounts were redeemed/borrowed

```solidity
function getHypotheticalAccountLiquidity(address account, address vTokenModify, uint256 redeemTokens, uint256 borrowAmount) external view returns (uint256, uint256, uint256)
```

**Parameters**

| Name         | Type    | Description                                       |
| ------------ | ------- | ------------------------------------------------- |
| 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 | The amount of underlying to hypothetically borrow |

**Return Values**

| Name | Type    | Description                                                                                                                                                            |
| ---- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| \[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 |                                                                                                                                                                        |

***

#### \_setVenusSpeeds

Set XVS speed for a single market

```solidity
function _setVenusSpeeds(contract VToken[] vTokens, uint256[] supplySpeeds, uint256[] borrowSpeeds) external
```

**Parameters**

| Name         | Type               | Description                          |
| ------------ | ------------------ | ------------------------------------ |
| vTokens      | contract VToken\[] | The market whose XVS speed to update |
| supplySpeeds | uint256\[]         | New XVS speed for supply             |
| borrowSpeeds | uint256\[]         | New XVS speed for borrow             |

***


# RewardFacet

## RewardFacet

This facet contract provides the external functions related to all claims and rewards of the protocol

## Solidity API

#### claimVenus

Claim all the xvs accrued by holder in all markets and VAI

```solidity
function claimVenus(address holder) public
```

**Parameters**

| Name   | Type    | Description                  |
| ------ | ------- | ---------------------------- |
| holder | address | The address to claim XVS for |

***

#### claimVenus

Claim all the xvs accrued by holder in the specified markets

```solidity
function claimVenus(address holder, contract VToken[] vTokens) public
```

**Parameters**

| Name    | Type               | Description                         |
| ------- | ------------------ | ----------------------------------- |
| holder  | address            | The address to claim XVS for        |
| vTokens | contract VToken\[] | The list of markets to claim XVS in |

***

#### claimVenus

Claim all xvs accrued by the holders

```solidity
function claimVenus(address[] holders, contract VToken[] vTokens, bool borrowers, bool suppliers) public
```

**Parameters**

| Name      | Type               | Description                                     |
| --------- | ------------------ | ----------------------------------------------- |
| 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               | Whether or not to claim XVS earned by supplying |

***

#### claimVenusAsCollateral

Claim all the xvs accrued by holder in all markets, a shorthand for `claimVenus` with collateral set to `true`

```solidity
function claimVenusAsCollateral(address holder) external
```

**Parameters**

| Name   | Type    | Description                  |
| ------ | ------- | ---------------------------- |
| holder | address | The address to claim XVS for |

***

#### \_grantXVS

Transfer XVS to the recipient

```solidity
function _grantXVS(address recipient, uint256 amount) external
```

**Parameters**

| Name      | Type    | Description                                     |
| --------- | ------- | ----------------------------------------------- |
| recipient | address | The address of the recipient to transfer XVS to |
| amount    | uint256 | The amount of XVS to (possibly) transfer        |

***

#### seizeVenus

Seize XVS rewards allocated to holders

```solidity
function seizeVenus(address[] holders, address recipient) external returns (uint256)
```

**Parameters**

| Name      | Type       | Description                        |
| --------- | ---------- | ---------------------------------- |
| holders   | address\[] | Addresses of the XVS holders       |
| recipient | address    | Address of the XVS token recipient |

**Return Values**

| Name | Type    | Description                                                        |
| ---- | ------- | ------------------------------------------------------------------ |
| \[0] | uint256 | The total amount of XVS tokens seized and transferred to recipient |

***

#### claimVenus

Claim all xvs accrued by the holders

```solidity
function claimVenus(address[] holders, contract VToken[] vTokens, bool borrowers, bool suppliers, bool collateral) public
```

**Parameters**

| Name       | Type               | Description                                                                                       |
| ---------- | ------------------ | ------------------------------------------------------------------------------------------------- |
| 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               | 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 |

***

#### getXVSVTokenAddress

Returns the XVS vToken address

```solidity
function getXVSVTokenAddress() external view returns (address)
```

**Return Values**

| Name | Type    | Description               |
| ---- | ------- | ------------------------- |
| \[0] | address | The address of XVS vToken |

***


# SetterFacet

## SetterFacet

This facet contract contains all the configurational setter functions

## Solidity API

#### setPriceOracle

Alias to \_setPriceOracle to support the Isolated Lending Comptroller Interface

```solidity
function setPriceOracle(contract ResilientOracleInterface newOracle) external returns (uint256)
```

**Parameters**

| Name      | Type                              | Description                 |
| --------- | --------------------------------- | --------------------------- |
| newOracle | contract ResilientOracleInterface | The new price oracle to set |

**Return Values**

| Name | Type    | Description                                                                |
| ---- | ------- | -------------------------------------------------------------------------- |
| \[0] | uint256 | uint256 0=success, otherwise a failure (see ErrorReporter.sol for details) |

***

#### \_setPriceOracle

Sets a new price oracle for the comptroller

```solidity
function _setPriceOracle(contract ResilientOracleInterface newOracle) external returns (uint256)
```

**Parameters**

| Name      | Type                              | Description                 |
| --------- | --------------------------------- | --------------------------- |
| newOracle | contract ResilientOracleInterface | The new price oracle to set |

**Return Values**

| Name | Type    | Description                                                                |
| ---- | ------- | -------------------------------------------------------------------------- |
| \[0] | uint256 | uint256 0=success, otherwise a failure (see ErrorReporter.sol for details) |

***

#### setCloseFactor

Alias to \_setCloseFactor to support the Isolated Lending Comptroller Interface

```solidity
function setCloseFactor(uint256 newCloseFactorMantissa) external returns (uint256)
```

**Parameters**

| Name                   | Type    | Description                      |
| ---------------------- | ------- | -------------------------------- |
| newCloseFactorMantissa | uint256 | New close factor, scaled by 1e18 |

**Return Values**

| Name | Type    | Description                              |
| ---- | ------- | ---------------------------------------- |
| \[0] | uint256 | uint256 0=success, otherwise will revert |

***

#### \_setCloseFactor

Sets the closeFactor used when liquidating borrows

```solidity
function _setCloseFactor(uint256 newCloseFactorMantissa) external returns (uint256)
```

**Parameters**

| Name                   | Type    | Description                      |
| ---------------------- | ------- | -------------------------------- |
| newCloseFactorMantissa | uint256 | New close factor, scaled by 1e18 |

**Return Values**

| Name | Type    | Description                              |
| ---- | ------- | ---------------------------------------- |
| \[0] | uint256 | uint256 0=success, otherwise will revert |

***

#### \_setAccessControl

Sets the address of the access control of this contract

```solidity
function _setAccessControl(address newAccessControlAddress) external returns (uint256)
```

**Parameters**

| Name                    | Type    | Description                        |
| ----------------------- | ------- | ---------------------------------- |
| newAccessControlAddress | address | New address for the access control |

**Return Values**

| Name | Type    | Description                              |
| ---- | ------- | ---------------------------------------- |
| \[0] | uint256 | uint256 0=success, otherwise will revert |

***

#### setCollateralFactor

Sets the collateral factor and liquidation threshold for a market in the Core Pool only.

```solidity
function setCollateralFactor(contract VToken vToken, uint256 newCollateralFactorMantissa, uint256 newLiquidationThresholdMantissa) external returns (uint256)
```

**Parameters**

| Name                            | Type            | Description                                   |
| ------------------------------- | --------------- | --------------------------------------------- |
| 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 |

**Return Values**

| Name | Type    | Description                                                             |
| ---- | ------- | ----------------------------------------------------------------------- |
| \[0] | uint256 | uint256 0=success, otherwise a failure. (See ErrorReporter for details) |

***

#### setLiquidationIncentive

Sets the liquidation incentive for a market in the Core Pool only.

```solidity
function setLiquidationIncentive(address vToken, uint256 newLiquidationIncentiveMantissa) external returns (uint256)
```

**Parameters**

| Name                            | Type    | Description                                    |
| ------------------------------- | ------- | ---------------------------------------------- |
| vToken                          | address | The market to set the liquidationIncentive for |
| newLiquidationIncentiveMantissa | uint256 | New liquidationIncentive scaled by 1e18        |

**Return Values**

| Name | Type    | Description                                                             |
| ---- | ------- | ----------------------------------------------------------------------- |
| \[0] | uint256 | uint256 0=success, otherwise a failure. (See ErrorReporter for details) |

***

#### setCollateralFactor

Sets the collateral factor and liquidation threshold for a market in the specified pool.

```solidity
function setCollateralFactor(uint96 poolId, contract VToken vToken, uint256 newCollateralFactorMantissa, uint256 newLiquidationThresholdMantissa) external returns (uint256)
```

**Parameters**

| Name                            | Type            | Description                                   |
| ------------------------------- | --------------- | --------------------------------------------- |
| 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         | The new liquidation threshold, scaled by 1e18 |

**Return Values**

| Name | Type    | Description                                                             |
| ---- | ------- | ----------------------------------------------------------------------- |
| \[0] | uint256 | uint256 0=success, otherwise a failure. (See ErrorReporter for details) |

***

#### setLiquidationIncentive

Sets the liquidation incentive for a market in the specified pool.

```solidity
function setLiquidationIncentive(uint96 poolId, address vToken, uint256 newLiquidationIncentiveMantissa) external returns (uint256)
```

**Parameters**

| Name                            | Type    | Description                                    |
| ------------------------------- | ------- | ---------------------------------------------- |
| poolId                          | uint96  | The ID of the pool.                            |
| vToken                          | address | The market to set the liquidationIncentive for |
| newLiquidationIncentiveMantissa | uint256 | New liquidationIncentive scaled by 1e18        |

**Return Values**

| Name | Type    | Description                                                             |
| ---- | ------- | ----------------------------------------------------------------------- |
| \[0] | uint256 | uint256 0=success, otherwise a failure. (See ErrorReporter for details) |

***

#### \_setLiquidatorContract

Update the address of the liquidator contract

```solidity
function _setLiquidatorContract(address newLiquidatorContract_) external
```

**Parameters**

| Name                    | Type    | Description                                |
| ----------------------- | ------- | ------------------------------------------ |
| newLiquidatorContract\_ | address | The new address of the liquidator contract |

***

#### \_setPauseGuardian

Admin function to change the Pause Guardian

```solidity
function _setPauseGuardian(address newPauseGuardian) external returns (uint256)
```

**Parameters**

| Name             | Type    | Description                           |
| ---------------- | ------- | ------------------------------------- |
| newPauseGuardian | address | The address of the new Pause Guardian |

**Return Values**

| Name | Type    | Description                                                          |
| ---- | ------- | -------------------------------------------------------------------- |
| \[0] | uint256 | uint256 0=success, otherwise a failure. (See enum Error for details) |

***

#### setMarketBorrowCaps

Alias to \_setMarketBorrowCaps to support the Isolated Lending Comptroller Interface

```solidity
function setMarketBorrowCaps(contract VToken[] vTokens, uint256[] newBorrowCaps) external
```

**Parameters**

| Name          | Type               | Description                                                                                       |
| ------------- | ------------------ | ------------------------------------------------------------------------------------------------- |
| 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 |

***

#### \_setMarketBorrowCaps

Set the given borrow caps for the given vToken market Borrowing that brings total borrows to or above borrow cap will revert

```solidity
function _setMarketBorrowCaps(contract VToken[] vTokens, uint256[] newBorrowCaps) external
```

**Parameters**

| Name          | Type               | Description                                                                                       |
| ------------- | ------------------ | ------------------------------------------------------------------------------------------------- |
| 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 |

***

#### setMarketSupplyCaps

Alias to \_setMarketSupplyCaps to support the Isolated Lending Comptroller Interface

```solidity
function setMarketSupplyCaps(contract VToken[] vTokens, uint256[] newSupplyCaps) external
```

**Parameters**

| Name          | Type               | Description                                                                                       |
| ------------- | ------------------ | ------------------------------------------------------------------------------------------------- |
| 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 |

***

#### \_setMarketSupplyCaps

Set the given supply caps for the given vToken market Supply that brings total Supply to or above supply cap will revert

```solidity
function _setMarketSupplyCaps(contract VToken[] vTokens, uint256[] newSupplyCaps) external
```

**Parameters**

| Name          | Type               | Description                                                                                       |
| ------------- | ------------------ | ------------------------------------------------------------------------------------------------- |
| 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 |

***

#### \_setProtocolPaused

Set whole protocol pause/unpause state

```solidity
function _setProtocolPaused(bool state) external returns (bool)
```

**Parameters**

| Name  | Type | Description                                 |
| ----- | ---- | ------------------------------------------- |
| state | bool | The new state (true=paused, false=unpaused) |

**Return Values**

| Name | Type | Description                            |
| ---- | ---- | -------------------------------------- |
| \[0] | bool | bool The updated state of the protocol |

***

#### setActionsPaused

Alias to \_setActionsPaused to support the Isolated Lending Comptroller Interface

```solidity
function setActionsPaused(address[] markets_, enum Action[] actions_, bool paused_) external
```

**Parameters**

| Name      | Type           | Description                                        |
| --------- | -------------- | -------------------------------------------------- |
| 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) |

***

#### \_setActionsPaused

Pause/unpause certain actions

```solidity
function _setActionsPaused(address[] markets_, enum Action[] actions_, bool paused_) external
```

**Parameters**

| Name      | Type           | Description                                        |
| --------- | -------------- | -------------------------------------------------- |
| 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) |

***

#### \_setVAIController

Sets a new VAI controller

```solidity
function _setVAIController(contract VAIControllerInterface vaiController_) external returns (uint256)
```

**Return Values**

| Name | Type    | Description                                                                |
| ---- | ------- | -------------------------------------------------------------------------- |
| \[0] | uint256 | uint256 0=success, otherwise a failure (see ErrorReporter.sol for details) |

***

#### \_setVAIMintRate

Set the VAI mint rate

```solidity
function _setVAIMintRate(uint256 newVAIMintRate) external returns (uint256)
```

**Parameters**

| Name           | Type    | Description                     |
| -------------- | ------- | ------------------------------- |
| newVAIMintRate | uint256 | The new VAI mint rate to be set |

**Return Values**

| Name | Type    | Description                                                                |
| ---- | ------- | -------------------------------------------------------------------------- |
| \[0] | uint256 | uint256 0=success, otherwise a failure (see ErrorReporter.sol for details) |

***

#### setMintedVAIOf

Set the minted VAI amount of the `owner`

```solidity
function setMintedVAIOf(address owner, uint256 amount) external returns (uint256)
```

**Parameters**

| Name   | Type    | Description                             |
| ------ | ------- | --------------------------------------- |
| owner  | address | The address of the account to set       |
| amount | uint256 | The amount of VAI to set to the account |

**Return Values**

| Name | Type    | Description                         |
| ---- | ------- | ----------------------------------- |
| \[0] | uint256 | The number of minted VAI by `owner` |

***

#### \_setTreasuryData

Set the treasury data.

```solidity
function _setTreasuryData(address newTreasuryGuardian, address newTreasuryAddress, uint256 newTreasuryPercent) external returns (uint256)
```

**Parameters**

| Name                | Type    | Description                                        |
| ------------------- | ------- | -------------------------------------------------- |
| 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                 |

**Return Values**

| Name | Type    | Description                                                                |
| ---- | ------- | -------------------------------------------------------------------------- |
| \[0] | uint256 | uint256 0=success, otherwise a failure (see ErrorReporter.sol for details) |

***

#### \_setVenusVAIVaultRate

Set the amount of XVS distributed per block to VAI Vault

```solidity
function _setVenusVAIVaultRate(uint256 venusVAIVaultRate_) external
```

**Parameters**

| Name                | Type    | Description                                                |
| ------------------- | ------- | ---------------------------------------------------------- |
| venusVAIVaultRate\_ | uint256 | The amount of XVS wei per block to distribute to VAI Vault |

***

#### \_setVAIVaultInfo

Set the VAI Vault infos

```solidity
function _setVAIVaultInfo(address vault_, uint256 releaseStartBlock_, uint256 minReleaseAmount_) external
```

**Parameters**

| Name                | Type    | Description                             |
| ------------------- | ------- | --------------------------------------- |
| 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 |

***

#### setPrimeToken

Alias to \_setPrimeToken to support the Isolated Lending Comptroller Interface

```solidity
function setPrimeToken(contract IPrime _prime) external returns (uint256)
```

**Parameters**

| Name    | Type            | Description                            |
| ------- | --------------- | -------------------------------------- |
| \_prime | contract IPrime | The new prime token contract to be set |

**Return Values**

| Name | Type    | Description                                                             |
| ---- | ------- | ----------------------------------------------------------------------- |
| \[0] | uint256 | uint 0=success, otherwise a failure (see ErrorReporter.sol for details) |

***

#### \_setPrimeToken

Sets the prime token contract for the comptroller

```solidity
function _setPrimeToken(contract IPrime _prime) external returns (uint256)
```

**Parameters**

| Name    | Type            | Description                            |
| ------- | --------------- | -------------------------------------- |
| \_prime | contract IPrime | The new prime token contract to be set |

**Return Values**

| Name | Type    | Description                                                             |
| ---- | ------- | ----------------------------------------------------------------------- |
| \[0] | uint256 | uint 0=success, otherwise a failure (see ErrorReporter.sol for details) |

***

#### setForcedLiquidation

Alias to \_setForcedLiquidation to support the Isolated Lending Comptroller Interface

```solidity
function setForcedLiquidation(address vTokenBorrowed, bool enable) external
```

**Parameters**

| Name           | Type    | Description                           |
| -------------- | ------- | ------------------------------------- |
| vTokenBorrowed | address | Borrowed vToken                       |
| enable         | bool    | Whether to enable forced liquidations |

***

#### \_setForcedLiquidation

Enables forced liquidations for a market. If forced liquidation is enabled, borrows in the market may be liquidated regardless of the account liquidity

```solidity
function _setForcedLiquidation(address vTokenBorrowed, bool enable) external
```

**Parameters**

| Name           | Type    | Description                           |
| -------------- | ------- | ------------------------------------- |
| vTokenBorrowed | address | Borrowed vToken                       |
| enable         | bool    | Whether to enable forced liquidations |

***

#### \_setForcedLiquidationForUser

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.

```solidity
function _setForcedLiquidationForUser(address borrower, address vTokenBorrowed, bool enable) external
```

**Parameters**

| Name           | Type    | Description                           |
| -------------- | ------- | ------------------------------------- |
| borrower       | address | The address of the borrower           |
| vTokenBorrowed | address | Borrowed vToken                       |
| enable         | bool    | Whether to enable forced liquidations |

***

#### setWhiteListFlashLoanAccount

```solidity
function setWhiteListFlashLoanAccount(address account, bool _isWhiteListed) external 
```

**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**

| Name            | Type    | Description                        |
| --------------- | ------- | ---------------------------------- |
| account         | address | The account to whitelist or remove |
| \_isWhiteListed | bool    | True to whitelist, false to remove |

**Return Values**

| Name | Type | Description |
| ---- | ---- | ----------- |
| None |      |             |

***

#### \_setXVSToken

Set the address of the XVS token

```solidity
function _setXVSToken(address xvs_) external
```

**Parameters**

| Name  | Type    | Description                  |
| ----- | ------- | ---------------------------- |
| xvs\_ | address | The address of the XVS token |

***

#### \_setXVSVToken

Set the address of the XVS vToken

```solidity
function _setXVSVToken(address xvsVToken_) external
```

**Parameters**

| Name        | Type    | Description                   |
| ----------- | ------- | ----------------------------- |
| xvsVToken\_ | address | The address of the XVS vToken |

***

#### setPoolActive

updates active status for a specific pool (excluding the Core Pool)

```solidity
function setPoolActive(uint96 poolId, bool active) external
```

**Parameters**

| Name   | Type   | Description                      |
| ------ | ------ | -------------------------------- |
| poolId | uint96 | id of the pool to update         |
| active | bool   | true to enable, false to disable |

**📅 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.

***

#### setIsBorrowAllowed

Updates the `isBorrowAllowed` flag for a market in a pool.

```solidity
function setIsBorrowAllowed(uint96 poolId, address vToken, bool borrowAllowed) external
```

**Parameters**

| Name          | Type    | Description                         |
| ------------- | ------- | ----------------------------------- |
| poolId        | uint96  | The ID of the pool.                 |
| vToken        | address | The address of the market (vToken). |
| borrowAllowed | bool    | The new borrow allowed status.      |

**📅 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.

***


# FlashLoanFacet

## FlashLoanFacet

This facet contract contains functions for flash loan operations

## Solidity API

#### executeFlashLoan

Executes a flashLoan operation with the requested assets

```solidity
function executeFlashLoan(
    address payable onBehalf,
    address payable receiver,
    VToken[] memory vTokens,
    uint256[] memory underlyingAmounts,
    bytes memory param
) external
```

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**

| Name              | Type            | Description                                                                                  |
| ----------------- | --------------- | -------------------------------------------------------------------------------------------- |
| 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                                           |
| param             | bytes           | The bytes passed in the executeOperation call                                                |

***


# VToken

## Venus's vToken Contract

Abstract base for vTokens

## Solidity API

```solidity
struct MintLocalVars {
  enum CarefulMath.MathError mathErr;
  uint256 exchangeRateMantissa;
  uint256 mintTokens;
  uint256 totalSupplyNew;
  uint256 accountTokensNew;
  uint256 actualMintAmount;
}
```

```solidity
struct RedeemLocalVars {
  enum CarefulMath.MathError mathErr;
  uint256 exchangeRateMantissa;
  uint256 redeemTokens;
  uint256 redeemAmount;
  uint256 totalSupplyNew;
  uint256 accountTokensNew;
}
```

```solidity
struct BorrowLocalVars {
  enum CarefulMath.MathError mathErr;
  uint256 accountBorrows;
  uint256 accountBorrowsNew;
  uint256 totalBorrowsNew;
}
```

```solidity
struct RepayBorrowLocalVars {
  enum TokenErrorReporter.Error err;
  enum CarefulMath.MathError mathErr;
  uint256 repayAmount;
  uint256 borrowerIndex;
  uint256 accountBorrows;
  uint256 accountBorrowsNew;
  uint256 totalBorrowsNew;
  uint256 actualRepayAmount;
}
```

#### transfer

Transfer `amount` tokens from `msg.sender` to `dst`

```solidity
function transfer(address dst, uint256 amount) external returns (bool)
```

**Parameters**

| Name   | Type    | Description                            |
| ------ | ------- | -------------------------------------- |
| dst    | address | The address of the destination account |
| amount | uint256 | The number of tokens to transfer       |

**Return Values**

| Name | Type | Description                           |
| ---- | ---- | ------------------------------------- |
| \[0] | bool | Whether or not the transfer succeeded |

***

#### transferFrom

Transfer `amount` tokens from `src` to `dst`

```solidity
function transferFrom(address src, address dst, uint256 amount) external returns (bool)
```

**Parameters**

| Name   | Type    | Description                            |
| ------ | ------- | -------------------------------------- |
| src    | address | The address of the source account      |
| dst    | address | The address of the destination account |
| amount | uint256 | The number of tokens to transfer       |

**Return Values**

| Name | Type | Description                           |
| ---- | ---- | ------------------------------------- |
| \[0] | bool | Whether or not the transfer succeeded |

***

#### approve

Approve `spender` to transfer up to `amount` from `src`

```solidity
function approve(address spender, uint256 amount) external returns (bool)
```

**Parameters**

| Name    | Type    | Description                                                               |
| ------- | ------- | ------------------------------------------------------------------------- |
| 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) |

**Return Values**

| Name | Type | Description                           |
| ---- | ---- | ------------------------------------- |
| \[0] | bool | Whether or not the approval succeeded |

***

#### balanceOfUnderlying

Get the underlying balance of the `owner`

```solidity
function balanceOfUnderlying(address owner) external returns (uint256)
```

**Parameters**

| Name  | Type    | Description                         |
| ----- | ------- | ----------------------------------- |
| owner | address | The address of the account to query |

**Return Values**

| Name | Type    | Description                               |
| ---- | ------- | ----------------------------------------- |
| \[0] | uint256 | The amount of underlying owned by `owner` |

***

#### totalBorrowsCurrent

Returns the current total borrows plus accrued interest

```solidity
function totalBorrowsCurrent() external returns (uint256)
```

**Return Values**

| Name | Type    | Description                     |
| ---- | ------- | ------------------------------- |
| \[0] | uint256 | The total borrows with interest |

***

#### borrowBalanceCurrent

Accrue interest to updated borrowIndex and then calculate account's borrow balance using the updated borrowIndex

```solidity
function borrowBalanceCurrent(address account) external returns (uint256)
```

**Parameters**

| Name    | Type    | Description                                                               |
| ------- | ------- | ------------------------------------------------------------------------- |
| account | address | The address whose balance should be calculated after updating borrowIndex |

**Return Values**

| Name | Type    | Description            |
| ---- | ------- | ---------------------- |
| \[0] | uint256 | The calculated balance |

***

#### seize

Transfers collateral tokens (this market) to the liquidator.

```solidity
function seize(address liquidator, address borrower, uint256 seizeTokens) external returns (uint256)
```

**Parameters**

| Name        | Type    | Description                             |
| ----------- | ------- | --------------------------------------- |
| liquidator  | address | The account receiving seized collateral |
| borrower    | address | The account having collateral seized    |
| seizeTokens | uint256 | The number of vTokens to seize          |

**Return Values**

| Name | Type    | Description                                                                                      |
| ---- | ------- | ------------------------------------------------------------------------------------------------ |
| \[0] | uint256 | uint Returns 0 on success, otherwise returns a failure code (see ErrorReporter.sol for details). |

***

#### \_setPendingAdmin

Begins transfer of admin rights. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer.

```solidity
function _setPendingAdmin(address payable newPendingAdmin) external returns (uint256)
```

**Parameters**

| Name            | Type            | Description        |
| --------------- | --------------- | ------------------ |
| newPendingAdmin | address payable | New pending admin. |

**Return Values**

| Name | Type    | Description                                                                                      |
| ---- | ------- | ------------------------------------------------------------------------------------------------ |
| \[0] | uint256 | uint Returns 0 on success, otherwise returns a failure code (see ErrorReporter.sol for details). |

***

#### \_acceptAdmin

Accepts transfer of admin rights. msg.sender must be pendingAdmin

```solidity
function _acceptAdmin() external returns (uint256)
```

**Return Values**

| Name | Type    | Description                                                                                      |
| ---- | ------- | ------------------------------------------------------------------------------------------------ |
| \[0] | uint256 | uint Returns 0 on success, otherwise returns a failure code (see ErrorReporter.sol for details). |

***

#### \_setReserveFactor

accrues interest and sets a new reserve factor for the protocol using `_setReserveFactorFresh`

```solidity
function _setReserveFactor(uint256 newReserveFactorMantissa_) external returns (uint256)
```

**Return Values**

| Name | Type    | Description                                                                                      |
| ---- | ------- | ------------------------------------------------------------------------------------------------ |
| \[0] | uint256 | uint Returns 0 on success, otherwise returns a failure code (see ErrorReporter.sol for details). |

***

#### setAccessControlManager

Sets the address of the access control manager of this contract

```solidity
function setAccessControlManager(address newAccessControlManagerAddress) external returns (uint256)
```

**Parameters**

| Name                           | Type    | Description                        |
| ------------------------------ | ------- | ---------------------------------- |
| newAccessControlManagerAddress | address | New address for the access control |

**Return Values**

| Name | Type    | Description                           |
| ---- | ------- | ------------------------------------- |
| \[0] | uint256 | uint 0=success, otherwise will revert |

***

#### \_reduceReserves

Accrues interest and reduces reserves by transferring to protocol share reserve

```solidity
function _reduceReserves(uint256 reduceAmount_) external virtual returns (uint256)
```

**Parameters**

| Name           | Type    | Description                     |
| -------------- | ------- | ------------------------------- |
| reduceAmount\_ | uint256 | Amount of reduction to reserves |

**Return Values**

| Name | Type    | Description                                                                                      |
| ---- | ------- | ------------------------------------------------------------------------------------------------ |
| \[0] | uint256 | uint Returns 0 on success, otherwise returns a failure code (see ErrorReporter.sol for details). |

***

#### allowance

Get the current allowance from `owner` for `spender`

```solidity
function allowance(address owner, address spender) external view returns (uint256)
```

**Parameters**

| Name    | Type    | Description                                                  |
| ------- | ------- | ------------------------------------------------------------ |
| 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         |

**Return Values**

| Name | Type    | Description                                                                 |
| ---- | ------- | --------------------------------------------------------------------------- |
| \[0] | uint256 | The number of tokens allowed to be spent (type(uint256).max means infinite) |

***

#### balanceOf

Get the token balance of the `owner`

```solidity
function balanceOf(address owner) external view returns (uint256)
```

**Parameters**

| Name  | Type    | Description                         |
| ----- | ------- | ----------------------------------- |
| owner | address | The address of the account to query |

**Return Values**

| Name | Type    | Description                           |
| ---- | ------- | ------------------------------------- |
| \[0] | uint256 | The number of tokens owned by `owner` |

***

#### getAccountSnapshot

Get a snapshot of the account's balances, and the cached exchange rate

```solidity
function getAccountSnapshot(address account) external view returns (uint256, uint256, uint256, uint256)
```

**Parameters**

| Name    | Type    | Description                        |
| ------- | ------- | ---------------------------------- |
| account | address | Address of the account to snapshot |

**Return Values**

| Name | Type    | Description                                                             |
| ---- | ------- | ----------------------------------------------------------------------- |
| \[0] | uint256 | (possible error, token balance, borrow balance, exchange rate mantissa) |
| \[1] | uint256 |                                                                         |
| \[2] | uint256 |                                                                         |
| \[3] | uint256 |                                                                         |

***

#### supplyRatePerBlock

Returns the current per-block supply interest rate for this vToken

```solidity
function supplyRatePerBlock() external view returns (uint256)
```

**Return Values**

| Name | Type    | Description                                        |
| ---- | ------- | -------------------------------------------------- |
| \[0] | uint256 | The supply interest rate per block, scaled by 1e18 |

***

#### borrowRatePerBlock

Returns the current per-block borrow interest rate for this vToken

```solidity
function borrowRatePerBlock() external view returns (uint256)
```

**Return Values**

| Name | Type    | Description                                        |
| ---- | ------- | -------------------------------------------------- |
| \[0] | uint256 | The borrow interest rate per block, scaled by 1e18 |

***

#### getCash

Get cash balance of this vToken in the underlying asset

```solidity
function getCash() external view returns (uint256)
```

**Return Values**

| Name | Type    | Description                                             |
| ---- | ------- | ------------------------------------------------------- |
| \[0] | uint256 | The quantity of underlying asset owned by this contract |

***

#### setReduceReservesBlockDelta

Governance function to set new threshold of block difference after which funds will be sent to the protocol share reserve

```solidity
function setReduceReservesBlockDelta(uint256 newReduceReservesBlockDelta_) external
```

**Parameters**

| Name                          | Type    | Description            |
| ----------------------------- | ------- | ---------------------- |
| newReduceReservesBlockDelta\_ | uint256 | block difference value |

***

#### setProtocolShareReserve

Sets protocol share reserve contract address

```solidity
function setProtocolShareReserve(address payable protcolShareReserve_) external
```

**Parameters**

| Name                  | Type            | Description                                    |
| --------------------- | --------------- | ---------------------------------------------- |
| protcolShareReserve\_ | address payable | The address of protocol share reserve contract |

***

#### initialize

Initialize the money market

```solidity
function initialize(contract ComptrollerInterface comptroller_, contract InterestRateModelV8 interestRateModel_, uint256 initialExchangeRateMantissa_, string name_, string symbol_, uint8 decimals_) public
```

**Parameters**

| Name                          | Type                          | Description                               |
| ----------------------------- | ----------------------------- | ----------------------------------------- |
| 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                        | EIP-20 name of this token                 |
| symbol\_                      | string                        | EIP-20 symbol of this token               |
| decimals\_                    | uint8                         | EIP-20 decimal precision of this token    |

***

#### exchangeRateCurrent

Accrue interest then return the up-to-date exchange rate

```solidity
function exchangeRateCurrent() public returns (uint256)
```

**Return Values**

| Name | Type    | Description                             |
| ---- | ------- | --------------------------------------- |
| \[0] | uint256 | Calculated exchange rate scaled by 1e18 |

***

#### accrueInterest

Applies accrued interest to total borrows and reserves

```solidity
function accrueInterest() public virtual returns (uint256)
```

***

#### \_setComptroller

Sets a new comptroller for the market

```solidity
function _setComptroller(contract ComptrollerInterface newComptroller) public returns (uint256)
```

**Return Values**

| Name | Type    | Description                                                                                      |
| ---- | ------- | ------------------------------------------------------------------------------------------------ |
| \[0] | uint256 | uint Returns 0 on success, otherwise returns a failure code (see ErrorReporter.sol for details). |

***

#### \_setInterestRateModel

Accrues interest and updates the interest rate model using \_setInterestRateModelFresh

```solidity
function _setInterestRateModel(contract InterestRateModelV8 newInterestRateModel_) public returns (uint256)
```

**Parameters**

| Name                   | Type                         | Description                        |
| ---------------------- | ---------------------------- | ---------------------------------- |
| newInterestRateModel\_ | contract InterestRateModelV8 | The new interest rate model to use |

**Return Values**

| Name | Type    | Description                                                                                      |
| ---- | ------- | ------------------------------------------------------------------------------------------------ |
| \[0] | uint256 | uint Returns 0 on success, otherwise returns a failure code (see ErrorReporter.sol for details). |

***

#### exchangeRateStored

Calculates the exchange rate from the underlying to the VToken

```solidity
function exchangeRateStored() public view returns (uint256)
```

**Return Values**

| Name | Type    | Description                             |
| ---- | ------- | --------------------------------------- |
| \[0] | uint256 | Calculated exchange rate scaled by 1e18 |

***

#### borrowBalanceStored

Return the borrow balance of account based on stored data

```solidity
function borrowBalanceStored(address account) public view returns (uint256)
```

**Parameters**

| Name    | Type    | Description                                    |
| ------- | ------- | ---------------------------------------------- |
| account | address | The address whose balance should be calculated |

**Return Values**

| Name | Type    | Description            |
| ---- | ------- | ---------------------- |
| \[0] | uint256 | The calculated balance |

***

#### transferOutUnderlyingFlashLoan

Transfers the underlying asset to the specified address for flash loan operations.

```solidity
function transferOutUnderlyingFlashLoan(address payable to, uint256 amount) external
```

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**

| Name   | Type            | Description                                              |
| ------ | --------------- | -------------------------------------------------------- |
| to     | address payable | The address to which the underlying asset is transferred |
| amount | uint256         | The amount of the underlying asset to transfer           |

***

#### transferInUnderlyingFlashLoan

Transfers the underlying asset from the specified address for flash loan repayment.

```solidity
function transferInUnderlyingFlashLoan(
    address payable from,
    uint256 repaymentAmount,
    uint256 totalFee,
    uint256 protocolFee
) external returns (uint256)
```

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**

| Name            | Type            | Description                                                             |
| --------------- | --------------- | ----------------------------------------------------------------------- |
| 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 |

**Return Values**

| Name | Type    | Description                      |
| ---- | ------- | -------------------------------- |
| \[0] | uint256 | The actual amount transferred in |

***

#### calculateFlashLoanFee

Calculates the total fee and protocol fee for a flash loan amount. Reverts if flash loans are disabled.

```solidity
function calculateFlashLoanFee(uint256 amount)
    public
    view
    returns (uint256, uint256);
```

**Parameters**

| Name   | Type    | Description                  |
| ------ | ------- | ---------------------------- |
| amount | uint256 | The amount of the flash loan |

**Return Values**

| Name | Type    | Description                                                           |
| ---- | ------- | --------------------------------------------------------------------- |
| \[0] | uint256 | The total fee for the flash loan                                      |
| \[1] | uint256 | The portion of the total fees that goes to the protocol share reserve |

***

#### setFlashLoanEnabled

Sets flash loan status for the market. Governance-restricted.

```solidity
function setFlashLoanEnabled(bool enabled) external returns (uint256)
```

**Parameters**

| Name    | Type | Description                                  |
| ------- | ---- | -------------------------------------------- |
| enabled | bool | True to enable flash loans, false to disable |

**Return Values**

| Name | Type    | Description                         |
| ---- | ------- | ----------------------------------- |
| \[0] | uint256 | Status code (e.g., success/failure) |

***

#### setFlashLoanFeeMantissa

Updates the flash loan fee parameters. Governance-restricted.

```solidity
function setFlashLoanFeeMantissa(
    uint256 flashLoanFeeMantissa_,
    uint256 flashLoanProtocolShare_
)
    external
    returns (uint256);
```

**Parameters**

| Name                     | Type    | Description                             |
| ------------------------ | ------- | --------------------------------------- |
| flashLoanFeeMantissa\_   | uint256 | New flash loan fee (scaled by 1e18)     |
| flashLoanProtocolShare\_ | uint256 | New protocol fee share (scaled by 1e18) |

**Return Values**

| Name | Type    | Description                         |
| ---- | ------- | ----------------------------------- |
| \[0] | uint256 | Status code (e.g., success/failure) |

***


# Prime

The Venus Prime program is implemented by three core contracts, plus a read-only lens:

* [PrimeV2](/technical-reference/reference-core-pool/prime/prime) — the Soulbound Prime token and boosted-reward engine.
* [PrimeLeaderboard](/technical-reference/reference-core-pool/prime/prime-leaderboard) — time-weighted XVS staking tracker that decides eligibility.
* [PrimeLiquidityProvider](/technical-reference/reference-core-pool/prime/prime-liquidity-provider) — funds PrimeV2 with the reward tokens.
* [PrimeLens](/technical-reference/reference-core-pool/prime/prime-lens) — read-only helper for off-chain APR queries against PrimeV2.

Storage layouts: [PrimeV2Storage](/technical-reference/reference-core-pool/prime/prime-storage), [PrimeLeaderboardStorage](/technical-reference/reference-core-pool/prime/prime-leaderboard-storage).

See the [Venus Prime technical article](/technical-reference/reference-technical-articles/prime) for how these fit together.


# Prime token

## PrimeV2

PrimeV2 is the Prime token contract with leaderboard-based distribution. Prime status is decided by the `PrimeLeaderboard` contract based on time-weighted XVS staking, and boosted rewards are distributed to Prime holders across supported markets.

## Solidity API

#### WRAPPED\_NATIVE\_TOKEN

Address of wrapped native token

```solidity
address WRAPPED_NATIVE_TOKEN
```

***

#### NATIVE\_MARKET

Address of native market vToken

```solidity
address NATIVE_MARKET
```

***

#### xvsVault

Address of XVSVault contract

```solidity
address xvsVault
```

***

#### xvsVaultRewardToken

Reward token address in XVSVault

```solidity
address xvsVaultRewardToken
```

***

#### xvsVaultPoolId

Pool ID in XVSVault

```solidity
uint256 xvsVaultPoolId
```

***

#### constructor

PrimeV2 constructor. Sets the immutable references above and disables further initialization of the implementation contract.

```solidity
constructor(address wrappedNativeToken_, address nativeMarket_, address xvsVault_, address xvsVaultRewardToken_, uint256 xvsVaultPoolId_, bool timeBased_, uint256 blocksPerYear_) public
```

**Parameters**

| Name                  | Type    | Description                                                         |
| --------------------- | ------- | ------------------------------------------------------------------- |
| wrappedNativeToken\_  | address | Address of wrapped native token                                     |
| nativeMarket\_        | address | Address of native market                                            |
| xvsVault\_            | address | Address of XVSVault contract                                        |
| xvsVaultRewardToken\_ | address | Reward token address in XVSVault                                    |
| xvsVaultPoolId\_      | uint256 | Pool ID in XVSVault                                                 |
| timeBased\_           | bool    | A boolean indicating whether the contract is based on time or block |
| blocksPerYear\_       | uint256 | Total blocks per year                                               |

**❌ Errors**

* Throw InvalidAddress if xvsVault\_ or xvsVaultRewardToken\_ is the zero address

***

#### initialize

PrimeV2 initializer

```solidity
function initialize(uint128 alphaNumerator_, uint128 alphaDenominator_, address accessControlManager_, address primeLiquidityProvider_, address corePoolComptroller_, address oracle_, uint256 loopsLimit_) external
```

**Parameters**

| Name                     | Type    | Description                                                 |
| ------------------------ | ------- | ----------------------------------------------------------- |
| alphaNumerator\_         | uint128 | numerator of alpha. If alpha is 0.5 then numerator is 1     |
| alphaDenominator\_       | uint128 | denominator of alpha. If alpha is 0.5 then denominator is 2 |
| accessControlManager\_   | address | Address of AccessControlManager                             |
| primeLiquidityProvider\_ | address | Address of PrimeLiquidityProvider                           |
| corePoolComptroller\_    | address | Address of core pool comptroller                            |
| oracle\_                 | address | Address of Oracle                                           |
| loopsLimit\_             | uint256 | Maximum number of loops allowed in a single transaction     |

**❌ Errors**

* Throw InvalidAddress if any of the address is zero
* Throw InvalidAlphaArguments if alpha arguments are invalid

***

#### claimPrime

Mint a Prime token for a user in a permissionless way. Checks the user's Prime Score (their effective stake, read via `PrimeLeaderboard.getEffectiveStake`) against `mintThreshold`. Anyone can call this on behalf of an eligible user; no ACM required. Reverts while the contract is paused.

```solidity
function claimPrime(address user) external
```

**Parameters**

| Name | Type    | Description              |
| ---- | ------- | ------------------------ |
| user | address | User address to mint for |

**📅 Events**

* Emits Mint event on new token issuance

**❌ Errors**

* Throw InvalidAddress if user is the zero address
* Throw ScoreUpdateInProgress if a score update round is active
* Throw UserAlreadyHasPrimeToken if user already has a token
* Throw LeaderboardNotSet if primeLeaderboard address is not configured
* Throw MintThresholdNotSet if mintThreshold is zero
* Throw EligibilityBelowThreshold if user's Prime Score < mintThreshold
* Throw InvalidLimit if mint limit would be exceeded
* Throw MintWindowClosed if the minting deadline has passed

***

#### claimPrimeBatch

Mint Prime tokens for multiple users in a permissionless way. Non-holders below `mintThreshold` are skipped with a `SkippedIneligibleUser` event (not reverted). Existing Prime holders are silently skipped. Anyone can call this; no ACM required. Reverts while the contract is paused.

```solidity
function claimPrimeBatch(address[] users) external
```

**Parameters**

| Name  | Type       | Description                         |
| ----- | ---------- | ----------------------------------- |
| users | address\[] | Array of user addresses to mint for |

**📅 Events**

* Emits Mint event for each new token issuance
* Emits SkippedIneligibleUser for each non-holder below threshold

**❌ Errors**

* Throw ScoreUpdateInProgress if a score update round is active
* Throw LeaderboardNotSet if primeLeaderboard address is not configured
* Throw MintThresholdNotSet if mintThreshold is zero
* Throw MintWindowClosed if the minting deadline has passed
* Throw InvalidLimit if mint limit would be exceeded
* Throw MaxLoopsLimitExceeded if the batch is larger than loopsLimit

***

#### issue

Issue a Prime token to a single user (admin function)

```solidity
function issue(address user) external
```

**Parameters**

| Name | Type    | Description  |
| ---- | ------- | ------------ |
| user | address | User address |

**📅 Events**

* Emits Mint event on new token issuance

**⛔️ Access Requirements**

* Controlled by ACM

**❌ Errors**

* Throw InvalidAddress if user is zero address
* Throw InvalidLimit if mint limit would be exceeded
* Throw UserAlreadyHasPrimeToken if user already has a token
* Throw ScoreUpdateInProgress if a score update round is active

***

#### issueBatch

Issue Prime tokens to multiple users (admin function)

```solidity
function issueBatch(address[] users) external
```

**Parameters**

| Name  | Type       | Description             |
| ----- | ---------- | ----------------------- |
| users | address\[] | Array of user addresses |

**📅 Events**

* Emits Mint event on new token issuance

**⛔️ Access Requirements**

* Controlled by ACM

**❌ Errors**

* Throw InvalidAddress if any user in the batch is zero address
* Throw InvalidLimit if mint limit would be exceeded
* Throw ScoreUpdateInProgress if a score update round is active
* Throw MaxLoopsLimitExceeded if the batch is larger than loopsLimit

***

#### burn

Burn a user's Prime token (admin function)

```solidity
function burn(address user) external
```

**Parameters**

| Name | Type    | Description  |
| ---- | ------- | ------------ |
| user | address | User address |

**📅 Events**

* Emits Burn event

**⛔️ Access Requirements**

* Controlled by ACM

**❌ Errors**

* Throw UserHasNoPrimeToken if user has no prime token
* Throw ScoreUpdateInProgress if a score update round is active

***

#### burnBatch

Burn Prime tokens for multiple users (admin function)

```solidity
function burnBatch(address[] users) external
```

**Parameters**

| Name  | Type       | Description             |
| ----- | ---------- | ----------------------- |
| users | address\[] | Array of user addresses |

**📅 Events**

* Emits Burn event for each user

**⛔️ Access Requirements**

* Controlled by ACM

**❌ Errors**

* Throw ScoreUpdateInProgress if a score update round is active
* Throw MaxLoopsLimitExceeded if the batch is larger than loopsLimit

***

#### isUserPrimeHolder

Check if a user has a Prime token

```solidity
function isUserPrimeHolder(address user) external view returns (bool)
```

**Parameters**

| Name | Type    | Description  |
| ---- | ------- | ------------ |
| user | address | User address |

**Return Values**

| Name | Type | Description                        |
| ---- | ---- | ---------------------------------- |
| \[0] | bool | whether the user has a Prime token |

***

#### claimInterest

Claim accrued interest for a market (to msg.sender). If the PrimeV2 balance is insufficient, funds are pulled from the PrimeLiquidityProvider in the same transaction; any remaining shortfall stays recorded as accrued and claimable later (partial claim, no revert). Residual accrued interest remains claimable even after a market is removed. Reverts while the contract is paused.

```solidity
function claimInterest(address vToken) external returns (uint256)
```

**Parameters**

| Name   | Type    | Description    |
| ------ | ------- | -------------- |
| vToken | address | Market address |

**Return Values**

| Name | Type    | Description    |
| ---- | ------- | -------------- |
| \[0] | uint256 | amount claimed |

**📅 Events**

* Emits InterestClaimed event

**❌ Errors**

* Throw MarketNotSupported if market is not supported (only when the vToken is not a current Prime market — never added, or since removed — and the user has no residual accrued balance)

***

#### claimInterest

Claim accrued interest for a market to a specific address. Permissionless: anyone can trigger a claim on behalf of a user. Tokens are always sent to the user address, never to msg.sender. Same shortfall behavior as the single-argument overload: partial claim with the remainder kept as accrued, no revert. Reverts while the contract is paused.

```solidity
function claimInterest(address vToken, address user) external returns (uint256)
```

**Parameters**

| Name   | Type    | Description       |
| ------ | ------- | ----------------- |
| vToken | address | Market address    |
| user   | address | Recipient address |

**Return Values**

| Name | Type    | Description    |
| ---- | ------- | -------------- |
| \[0] | uint256 | amount claimed |

**📅 Events**

* Emits InterestClaimed event

**❌ Errors**

* Throw MarketNotSupported if market is not supported (only when the vToken is not a current Prime market — never added, or since removed — and the user has no residual accrued balance)

***

#### accrueInterest

Accrue interest for a market. Intentionally not gated by the pause to ensure fair reward distribution during pauses.

```solidity
function accrueInterest(address vToken) public
```

**Parameters**

| Name   | Type    | Description    |
| ------ | ------- | -------------- |
| vToken | address | Market address |

**❌ Errors**

* Throw MarketNotSupported if market is not supported

***

#### accrueInterestAndUpdateScore

Accrue interest and update score for a user in a specific market. Called by the Comptroller hooks.

```solidity
function accrueInterestAndUpdateScore(address user, address market) external
```

**Parameters**

| Name   | Type    | Description    |
| ------ | ------- | -------------- |
| user   | address | User address   |
| market | address | Market address |

***

#### accrueInterestAndUpdateScore

Accrue interest and update score for a user across all markets. Called by `PrimeLeaderboard` when a user's XVS stake changes, so rewards are accrued at the old score before the score is recalculated.

```solidity
function accrueInterestAndUpdateScore(address user) external
```

**Parameters**

| Name | Type    | Description  |
| ---- | ------- | ------------ |
| user | address | User address |

**❌ Errors**

* Throw OnlyPrimeLeaderboard if caller is not the PrimeLeaderboard contract

***

#### getPendingRewards

Get pending rewards for a user (accrues first)

```solidity
function getPendingRewards(address user) external returns (struct PrimeV2StorageV1.PendingReward[] pendingRewards)
```

**Parameters**

| Name | Type    | Description  |
| ---- | ------- | ------------ |
| user | address | User address |

**Return Values**

| Name           | Type                                     | Description                         |
| -------------- | ---------------------------------------- | ----------------------------------- |
| pendingRewards | struct PrimeV2StorageV1.PendingReward\[] | Array of pending rewards per market |

***

#### getPendingRewardsStatic

Get pending rewards for a user (view-only, does not accrue). Returns rewards based on the last accrued state without triggering new accrual.

```solidity
function getPendingRewardsStatic(address user) external view returns (struct PrimeV2StorageV1.PendingReward[] pendingRewards)
```

**Parameters**

| Name | Type    | Description  |
| ---- | ------- | ------------ |
| user | address | User address |

**Return Values**

| Name           | Type                                     | Description                         |
| -------------- | ---------------------------------------- | ----------------------------------- |
| pendingRewards | struct PrimeV2StorageV1.PendingReward\[] | Array of pending rewards per market |

***

#### getLifetimeAccruedByMarket

Lifetime accrued rewards for many users in a single market. Pure view over the `lifetimeAccrued` field; intended for the off-chain cycle pipeline to snapshot per-(market, user) earnings without indexing events.

```solidity
function getLifetimeAccruedByMarket(address market, address[] users) external view returns (uint256[] amounts)
```

**Parameters**

| Name   | Type       | Description             |
| ------ | ---------- | ----------------------- |
| market | address    | vToken address          |
| users  | address\[] | Array of user addresses |

**Return Values**

| Name    | Type       | Description                                           |
| ------- | ---------- | ----------------------------------------------------- |
| amounts | uint256\[] | Lifetime accrued amounts, indexed parallel to `users` |

***

#### getLifetimeAccruedByUser

Lifetime accrued rewards for one user across many markets.

```solidity
function getLifetimeAccruedByUser(address user, address[] markets_) external view returns (uint256[] amounts)
```

**Parameters**

| Name      | Type       | Description               |
| --------- | ---------- | ------------------------- |
| user      | address    | User address              |
| markets\_ | address\[] | Array of vToken addresses |

**Return Values**

| Name    | Type       | Description                                              |
| ------- | ---------- | -------------------------------------------------------- |
| amounts | uint256\[] | Lifetime accrued amounts, indexed parallel to `markets_` |

***

#### updateScores

Update scores for a batch of users. Intentionally not gated by the pause — the keeper must complete rounds even during pauses.

```solidity
function updateScores(address[] users) external
```

**Parameters**

| Name  | Type       | Description             |
| ----- | ---------- | ----------------------- |
| users | address\[] | Array of user addresses |

**📅 Events**

* Emits UserScoreUpdated event

**❌ Errors**

* Throw NoScoreUpdatesRequired if no score updates are required
* Throw MaxLoopsLimitExceeded if the batch is larger than loopsLimit

***

#### getAllMarkets

Get all Prime markets

```solidity
function getAllMarkets() external view returns (address[])
```

**Return Values**

| Name | Type       | Description               |
| ---- | ---------- | ------------------------- |
| \[0] | address\[] | Array of market addresses |

***

#### xvsBalanceOfUser

Get a user's XVS balance from the vault (net of pending withdrawals)

```solidity
function xvsBalanceOfUser(address user) external view returns (uint256)
```

**Parameters**

| Name | Type    | Description  |
| ---- | ------- | ------------ |
| user | address | User address |

**Return Values**

| Name | Type    | Description        |
| ---- | ------- | ------------------ |
| \[0] | uint256 | User's XVS balance |

***

#### addMarket

Add a market to Prime. Opens a new score-update round: all Prime holders' scores must be recomputed via `updateScores` before issuing, burning and claiming Prime tokens are unblocked.

```solidity
function addMarket(address market, uint256 supplyMultiplier, uint256 borrowMultiplier) external
```

**Parameters**

| Name             | Type    | Description                       |
| ---------------- | ------- | --------------------------------- |
| market           | address | Market address                    |
| supplyMultiplier | uint256 | Supply multiplier, scaled by 1e18 |
| borrowMultiplier | uint256 | Borrow multiplier, scaled by 1e18 |

**📅 Events**

* Emits MarketAdded event
* Emits IncompleteRoundDiscarded if a previous score-update round was still in progress

**⛔️ Access Requirements**

* Controlled by ACM

**❌ Errors**

* Throw MarketAlreadyExists if market already exists
* Throw InvalidMultipliers if both multipliers are zero
* Throw InvalidVToken if market is not listed
* Throw AssetAlreadyExists if asset already has a market
* Throw MaxLoopsLimitExceeded if listing this market would exceed loopsLimit
* Throw UnsupportedUnderlyingDecimals if underlying token has decimals > 18

***

#### removeMarket

Remove a market from the Prime program

```solidity
function removeMarket(address market) external
```

**Parameters**

| Name   | Type    | Description                     |
| ------ | ------- | ------------------------------- |
| market | address | Market vToken address to remove |

**📅 Events**

* Emits MarketRemoved event

**⛔️ Access Requirements**

* Controlled by ACM

**❌ Errors**

* Throw MarketNotSupported if market doesn't exist
* Throw MarketHasActiveMembers if market still has members with scores

***

#### setLimit

Update mint limit (maximum Prime tokens)

```solidity
function setLimit(uint256 tokenLimit_) external
```

**Parameters**

| Name         | Type    | Description     |
| ------------ | ------- | --------------- |
| tokenLimit\_ | uint256 | New token limit |

**📅 Events**

* Emits MintLimitUpdated event

**⛔️ Access Requirements**

* Controlled by ACM

**❌ Errors**

* Throw InvalidLimit if limit is less than current count

***

#### updateAlpha

Update alpha parameter. Opens a new score-update round: all Prime holders' scores must be recomputed via `updateScores` before issuing, burning and claiming Prime tokens are unblocked.

```solidity
function updateAlpha(uint128 alphaNumerator_, uint128 alphaDenominator_) external
```

**Parameters**

| Name               | Type    | Description           |
| ------------------ | ------- | --------------------- |
| alphaNumerator\_   | uint128 | New alpha numerator   |
| alphaDenominator\_ | uint128 | New alpha denominator |

**📅 Events**

* Emits AlphaUpdated event
* Emits IncompleteRoundDiscarded if a previous score-update round was still in progress

**⛔️ Access Requirements**

* Controlled by ACM

**❌ Errors**

* Throw InvalidAlphaArguments if alpha arguments are invalid

***

#### updateMultipliers

Update market multipliers. Opens a new score-update round: all Prime holders' scores must be recomputed via `updateScores` before issuing, burning and claiming Prime tokens are unblocked.

```solidity
function updateMultipliers(address market, uint256 supplyMultiplier, uint256 borrowMultiplier) external
```

**Parameters**

| Name             | Type    | Description           |
| ---------------- | ------- | --------------------- |
| market           | address | Market address        |
| supplyMultiplier | uint256 | New supply multiplier |
| borrowMultiplier | uint256 | New borrow multiplier |

**📅 Events**

* Emits MultiplierUpdated event
* Emits IncompleteRoundDiscarded if a previous score-update round was still in progress

**⛔️ Access Requirements**

* Controlled by ACM

**❌ Errors**

* Throw MarketNotSupported if market is not supported
* Throw InvalidMultipliers if both multipliers are zero

***

#### pause

Pause the contract

```solidity
function pause() external
```

**📅 Events**

* Emits Paused event

**⛔️ Access Requirements**

* Controlled by ACM

***

#### unpause

Unpause the contract

```solidity
function unpause() external
```

**📅 Events**

* Emits Unpaused event

**⛔️ Access Requirements**

* Controlled by ACM

***

#### setMaxLoopsLimit

Set the max loops limit

```solidity
function setMaxLoopsLimit(uint256 loopsLimit) external
```

**Parameters**

| Name       | Type    | Description     |
| ---------- | ------- | --------------- |
| loopsLimit | uint256 | New loops limit |

**📅 Events**

* Emits MaxLoopsLimitUpdated event

**⛔️ Access Requirements**

* Controlled by ACM

***

#### setPrimeLeaderboard

Set the `PrimeLeaderboard` contract address used for permissionless mint eligibility

```solidity
function setPrimeLeaderboard(address primeLeaderboard_) external
```

**Parameters**

| Name               | Type    | Description                          |
| ------------------ | ------- | ------------------------------------ |
| primeLeaderboard\_ | address | Address of PrimeLeaderboard contract |

**📅 Events**

* Emits PrimeLeaderboardSet event

**⛔️ Access Requirements**

* Controlled by ACM

**❌ Errors**

* Throw InvalidAddress if address is zero

***

#### setMintThreshold

Set the minimum Prime Score threshold and minting deadline for permissionless Prime minting. Each epoch is one calendar month; governance typically calls this at end-of-epoch with the #500 user's Prime Score as the threshold. Pass `mintThreshold_ = 0` to disable the permissionless minting window immediately. Pass `mintDeadline_ = 0` for no expiry; otherwise the window auto-closes once `block.timestamp` exceeds it.

```solidity
function setMintThreshold(uint256 mintThreshold_, uint256 mintDeadline_) external
```

**Parameters**

| Name            | Type    | Description                                                    |
| --------------- | ------- | -------------------------------------------------------------- |
| mintThreshold\_ | uint256 | New mint threshold (set to 0 to close the window)              |
| mintDeadline\_  | uint256 | Unix timestamp after which minting is closed (0 = no deadline) |

**📅 Events**

* Emits MintThresholdUpdated event

**⛔️ Access Requirements**

* Controlled by ACM

**❌ Errors**

* Throw InvalidDeadline if mintDeadline\_ is non-zero and not strictly in the future

***

#### recordCycleSnapshot

Emit a cycle-start anchor event so the off-chain reward pipeline can recover cycle boundaries by indexing the event log. Operational hook, not a policy lever. Not idempotent on-chain: duplicate `cycleId`s emit duplicate events and must be de-duplicated by the indexer.

```solidity
function recordCycleSnapshot(uint256 cycleId) external
```

**Parameters**

| Name    | Type    | Description                                           |
| ------- | ------- | ----------------------------------------------------- |
| cycleId | uint256 | Identifier of the cycle whose start is being recorded |

**📅 Events**

* Emits CycleSnapshotRecorded(cycleId, block.number, block.timestamp)

**⛔️ Access Requirements**

* Controlled by ACM — grant `recordCycleSnapshot(uint256)` to a keeper EOA/bot, not the Timelock (cycles fire on a recurring schedule)

***

#### sweepUndistributed

Reclaim PLP income that accrued for a market while no scored members existed in it. Flushes any pending PLP delta via `accrueInterest` first, then transfers the recorded slice to the recipient.

```solidity
function sweepUndistributed(address vToken, address to) external
```

**Parameters**

| Name   | Type    | Description                                           |
| ------ | ------- | ----------------------------------------------------- |
| vToken | address | Market address whose underlying slice should be swept |
| to     | address | Recipient of the swept tokens                         |

**📅 Events**

* Emits UndistributedSwept on a non-zero transfer

**⛔️ Access Requirements**

* Controlled by ACM

**❌ Errors**

* Throw InvalidAddress if to is the zero address

Note: for a removed Prime market the call does not revert; it returns without transferring once the market's `undistributedReward` slice is zero. Passing an address that is not a vToken at all reverts when resolving its underlying token.

***


# Prime leaderboard

## PrimeLeaderboard

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

## Solidity API

#### xvsVault

Address of XVSVault contract

```solidity
address xvsVault
```

***

#### xvsVaultRewardToken

Reward token address in XVSVault

```solidity
address xvsVaultRewardToken
```

***

#### xvsVaultPoolId

Pool ID in XVSVault

```solidity
uint256 xvsVaultPoolId
```

***

#### initialize

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

```solidity
function initialize(address accessControlManager_, uint256 loopsLimit_) external
```

**Parameters**

| Name                   | Type    | Description                                             |
| ---------------------- | ------- | ------------------------------------------------------- |
| accessControlManager\_ | address | Address of AccessControlManager                         |
| loopsLimit\_           | uint256 | Maximum number of loops allowed in a single transaction |

***

#### initializeStakers

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

```solidity
function initializeStakers(address[] users, uint256[] amounts, uint64[] timestamps) external
```

**Parameters**

| Name       | Type       | Description                           |
| ---------- | ---------- | ------------------------------------- |
| users      | address\[] | Array of user addresses to initialize |
| amounts    | uint256\[] | Array of staked amounts (in XVS wei)  |
| timestamps | uint64\[]  | Array of deposit timestamps           |

**📅 Events**

* Emits StakerInitialized for each user successfully seeded

**⛔️ Access Requirements**

* Controlled by ACM

**❌ Errors**

* Throw StakersAlreadyInitialized if finalizeInitialization was already called
* Throw LengthMismatch if array lengths don't match
* Throw InvalidTimestamp if a seeded timestamp is zero or in the future

***

#### finalizeInitialization

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

```solidity
function finalizeInitialization() external
```

**📅 Events**

* Emits StakersInitializationFinalized

**⛔️ Access Requirements**

* Controlled by ACM

**❌ Errors**

* Throw StakersAlreadyInitialized if already finalized

***

#### xvsUpdated

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

```solidity
function xvsUpdated(address user) external
```

**Parameters**

| Name | Type    | Description                  |
| ---- | ------- | ---------------------------- |
| user | address | The user whose stake changed |

**📅 Events**

* Emits DepositRecorded event on deposit
* Emits WithdrawalRecorded event on withdrawal
* Emits DepositsCompacted event if deposits are compacted

**⛔️ Access Requirements**

* Only callable by XVSVault

**❌ Errors**

* Throw OnlyXVSVaultAllowed if caller is not XVSVault
* Throw ZeroAddress if user address is zero

***

#### getEffectiveStake

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

```solidity
function getEffectiveStake(address user) public view returns (uint256 effectiveStake)
```

**Parameters**

| Name | Type    | Description        |
| ---- | ------- | ------------------ |
| user | address | The user's address |

**Return Values**

| Name           | Type    | Description                            |
| -------------- | ------- | -------------------------------------- |
| effectiveStake | uint256 | The user's Prime Score (time-weighted) |

***

#### getEffectiveStakeBatch

Batch view to get Prime Scores for multiple users

```solidity
function getEffectiveStakeBatch(address[] users) external view returns (uint256[] scores)
```

**Parameters**

| Name  | Type       | Description             |
| ----- | ---------- | ----------------------- |
| users | address\[] | Array of user addresses |

**Return Values**

| Name   | Type       | Description           |
| ------ | ---------- | --------------------- |
| scores | uint256\[] | Array of Prime Scores |

***

#### getTotalStaked

Get a user's total staked amount

```solidity
function getTotalStaked(address user) external view returns (uint256)
```

**Parameters**

| Name | Type    | Description        |
| ---- | ------- | ------------------ |
| user | address | The user's address |

**Return Values**

| Name | Type    | Description          |
| ---- | ------- | -------------------- |
| \[0] | uint256 | The total XVS staked |

***

#### getDeposits

Get a user's deposit stack

```solidity
function getDeposits(address user) external view returns (struct IPrimeLeaderboard.Deposit[] deposits)
```

**Parameters**

| Name | Type    | Description        |
| ---- | ------- | ------------------ |
| user | address | The user's address |

**Return Values**

| Name     | Type                                | Description                          |
| -------- | ----------------------------------- | ------------------------------------ |
| deposits | struct IPrimeLeaderboard.Deposit\[] | Array of deposits (index 0 = oldest) |

***

#### getDepositCount

Get the number of deposit tranches for a user

```solidity
function getDepositCount(address user) external view returns (uint256 count)
```

**Parameters**

| Name | Type    | Description        |
| ---- | ------- | ------------------ |
| user | address | The user's address |

**Return Values**

| Name  | Type    | Description                |
| ----- | ------- | -------------------------- |
| count | uint256 | Number of deposit tranches |

***

#### getMultiplier

Calculate the multiplier for a given holding duration

```solidity
function getMultiplier(uint256 holdingDuration) external view returns (uint256 multiplier)
```

**Parameters**

| Name            | Type    | Description         |
| --------------- | ------- | ------------------- |
| holdingDuration | uint256 | Duration in seconds |

**Return Values**

| Name       | Type    | Description                     |
| ---------- | ------- | ------------------------------- |
| multiplier | uint256 | The multiplier (scaled by 1e18) |

***

#### getMultiplierTiers

Get the multiplier tier configuration

```solidity
function getMultiplierTiers() external view returns (uint256[] durations, uint256[] multipliers)
```

**Return Values**

| Name        | Type       | Description                  |
| ----------- | ---------- | ---------------------------- |
| durations   | uint256\[] | Array of duration thresholds |
| multipliers | uint256\[] | Array of multiplier values   |

***

#### setMultiplierTiers

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

```solidity
function setMultiplierTiers(uint256[] durations, uint256[] multipliers) external
```

**Parameters**

| Name        | Type       | Description                                 |
| ----------- | ---------- | ------------------------------------------- |
| durations   | uint256\[] | Array of duration thresholds in seconds     |
| multipliers | uint256\[] | Array of multiplier values (scaled by 1e18) |

**📅 Events**

* Emits MultiplierTiersUpdated event

**⛔️ Access Requirements**

* Controlled by ACM

**❌ Errors**

* Throw LengthMismatch if durations and multipliers arrays have different lengths
* Throw InvalidValue if durations array is empty
* Throw InvalidMultiplierTiers if tiers are not in ascending order or multipliers below base

***

#### setPrimeV2

Set the PrimeV2 contract address

```solidity
function setPrimeV2(address primeV2_) external
```

**Parameters**

| Name      | Type    | Description                 |
| --------- | ------- | --------------------------- |
| primeV2\_ | address | Address of PrimeV2 contract |

**📅 Events**

* Emits PrimeV2Set event

**⛔️ Access Requirements**

* Controlled by ACM

**❌ Errors**

* Throw ZeroAddress if address is zero

***

#### setMaxLoopsLimit

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

```solidity
function setMaxLoopsLimit(uint256 loopsLimit) external
```

**Parameters**

| Name       | Type    | Description                                        |
| ---------- | ------- | -------------------------------------------------- |
| loopsLimit | uint256 | Limit for the max loops that can execute at a time |

**📅 Events**

* Emits MaxLoopsLimitUpdated event

**⛔️ Access Requirements**

* Controlled by ACM

***


# Prime leaderboard storage

## PrimeLeaderboardStorageV1

Storage layout for the PrimeLeaderboard contract

## Solidity API

```solidity
// Individual deposit record for LIFO tracking (declared in IPrimeLeaderboard)
struct Deposit {
  uint128 amount;    // Amount deposited
  uint64 timestamp;  // Deposit timestamp
  uint64 _reserved;  // Reserved for future use
}
```

#### BASE\_MULTIPLIER

Base multiplier (1.0x) scaled by 1e18

```solidity
uint256 BASE_MULTIPLIER
```

***

#### MAX\_DEPOSITS\_PER\_USER

Maximum deposits per user (DoS protection). Constant, set to 30.

```solidity
uint256 MAX_DEPOSITS_PER_USER
```

***

#### EXP\_SCALE

Scaling factor for calculations (1e18)

```solidity
uint256 EXP_SCALE
```

***

#### \_depositStacks

User's deposit stack (LIFO order, index 0 = oldest). Holds the `Deposit` records described above.

```solidity
mapping(address => IPrimeLeaderboard.Deposit[]) _depositStacks
```

***

#### totalStaked

User's total staked XVS

```solidity
mapping(address => uint256) totalStaked
```

***

#### \_multiplierDurations

Multiplier tier duration thresholds, in seconds. Default `[30 days, 60 days, 90 days]`.

```solidity
uint256[] _multiplierDurations
```

***

#### \_multiplierValues

Multiplier values corresponding to each tier (scaled by 1e18). Default `[1.3e18, 1.6e18, 2.0e18]`.

```solidity
uint256[] _multiplierValues
```

***

#### primeV2

Address of the PrimeV2 contract

```solidity
address primeV2
```

***

#### stakersInitialized

Whether staker initialization is complete (prevents further initialization calls)

```solidity
bool stakersInitialized
```

***


# Prime lens

## PrimeLens

PrimeLens is a read-only helper contract for off-chain APR queries against PrimeV2. It is kept separate from PrimeV2 to stay within the EVM contract-size limit. It holds an immutable reference to a PrimeV2 instance and derives values from PrimeV2 and PrimeLiquidityProvider state.

## Solidity API

#### primeV2

The PrimeV2 instance this lens reads from (set in the constructor)

```solidity
contract IPrimeV2WithStorage primeV2
```

***

#### constructor

```solidity
constructor(address primeV2_)
```

**Parameters**

| Name      | Type    | Description                     |
| --------- | ------- | ------------------------------- |
| primeV2\_ | address | Address of the PrimeV2 contract |

**❌ Errors**

* Throw InvalidAddress if primeV2\_ is the zero address

***

#### calculateAPR

Returns supply and borrow APR for a user in a given market, based on current state.

```solidity
function calculateAPR(address market, address user) external view returns (struct IPrimeV2.APRInfo aprInfo)
```

**Parameters**

| Name   | Type    | Description                           |
| ------ | ------- | ------------------------------------- |
| market | address | The market for which to fetch the APR |
| user   | address | The account for which to get the APR  |

**Return Values**

| Name    | Type                    | Description                                      |
| ------- | ----------------------- | ------------------------------------------------ |
| aprInfo | struct IPrimeV2.APRInfo | APR information for the user in the given market |

The `APRInfo` struct contains:

```solidity
struct APRInfo {
  uint256 supplyAPR;          // supply APR of the user in BPS
  uint256 borrowAPR;          // borrow APR of the user in BPS
  uint256 totalScore;         // total score of the market
  uint256 userScore;          // score of the user
  uint256 xvsBalanceForScore; // XVS balance of the user used for score
  uint256 capital;            // capital of the user
  uint256 cappedSupply;       // capped supply of the user
  uint256 cappedBorrow;       // capped borrow of the user
  uint256 supplyCapUSD;       // supply cap of the user in USD
  uint256 borrowCapUSD;       // borrow cap of the user in USD
}
```

***

#### estimateAPR

Returns supply and borrow APR for a user in a given market based on hypothetical supply, borrow and XVS staked amounts. The user's score is recomputed from the supplied inputs (subtracting their existing market score and re-adding the estimated one), so the result reflects what the APR would be under the provided position.

```solidity
function estimateAPR(address market, address user, uint256 borrow, uint256 supply, uint256 xvsStaked) external view returns (struct IPrimeV2.APRInfo aprInfo)
```

**Parameters**

| Name      | Type    | Description                           |
| --------- | ------- | ------------------------------------- |
| 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 | Hypothetical supply amount            |
| xvsStaked | uint256 | Hypothetical staked XVS amount        |

**Return Values**

| Name    | Type                    | Description                                                                                |
| ------- | ----------------------- | ------------------------------------------------------------------------------------------ |
| aprInfo | struct IPrimeV2.APRInfo | APR information for the user in the given market (same `APRInfo` struct as `calculateAPR`) |

***

#### incomeDistributionYearly

The total income that will be distributed to Prime token holders for a market over a year. Computed as the PrimeLiquidityProvider effective distribution speed for the market's underlying multiplied by `blocksOrSecondsPerYear`.

```solidity
function incomeDistributionYearly(address vToken) public view returns (uint256 amount)
```

**Parameters**

| Name   | Type    | Description                                    |
| ------ | ------- | ---------------------------------------------- |
| vToken | address | The market for which to fetch the total income |

**Return Values**

| Name   | Type    | Description                        |
| ------ | ------- | ---------------------------------- |
| amount | uint256 | The annualized distribution income |

***


# Prime liquidity provider

## PrimeLiquidityProvider

PrimeLiquidityProvider is used to fund Prime

## Solidity API

#### DEFAULT\_MAX\_DISTRIBUTION\_SPEED

The default max token distribution speed

```solidity
uint256 DEFAULT_MAX_DISTRIBUTION_SPEED
```

***

#### prime

Address of the Prime contract

```solidity
address prime
```

***

#### tokenDistributionSpeeds

The rate at which token is distributed (per block)

```solidity
mapping(address => uint256) tokenDistributionSpeeds
```

***

#### maxTokenDistributionSpeeds

The max token distribution speed for token

```solidity
mapping(address => uint256) maxTokenDistributionSpeeds
```

***

#### lastAccruedBlock

The last block or second up to which rewards were accrued for the token (view getter over the `lastAccruedBlockOrSecond` storage mapping)

```solidity
function lastAccruedBlock(address token_) external view returns (uint256)
```

***

#### tokenAmountAccrued

The token accrued but not yet transferred to prime contract (view getter over the internal `_tokenAmountAccrued` mapping)

```solidity
function tokenAmountAccrued(address token_) external view returns (uint256)
```

***

#### initialize

PrimeLiquidityProvider initializer

```solidity
function initialize(address accessControlManager_, address[] tokens_, uint256[] distributionSpeeds_, uint256[] maxDistributionSpeeds_, uint256 loopsLimit_) external
```

**Parameters**

| Name                    | Type       | Description                                             |
| ----------------------- | ---------- | ------------------------------------------------------- |
| accessControlManager\_  | address    | AccessControlManager contract address                   |
| tokens\_                | address\[] | Array of addresses of the tokens                        |
| distributionSpeeds\_    | uint256\[] | New distribution speeds for tokens                      |
| maxDistributionSpeeds\_ | uint256\[] |                                                         |
| loopsLimit\_            | uint256    | Maximum number of loops allowed in a single transaction |

**❌ Errors**

* Throw InvalidArguments on different length of tokens and speeds array

***

#### initializeTokens

Initialize the distribution of the token

```solidity
function initializeTokens(address[] tokens_) external
```

**Parameters**

| Name     | Type       | Description                                       |
| -------- | ---------- | ------------------------------------------------- |
| tokens\_ | address\[] | Array of addresses of the tokens to be intialized |

**⛔️ Access Requirements**

* Only Governance

***

#### pauseFundsTransfer

Pause fund transfer of tokens to Prime contract

```solidity
function pauseFundsTransfer() external
```

**⛔️ Access Requirements**

* Controlled by ACM

***

#### resumeFundsTransfer

Resume fund transfer of tokens to Prime contract

```solidity
function resumeFundsTransfer() external
```

**⛔️ Access Requirements**

* Controlled by ACM

***

#### setTokensDistributionSpeed

Set distribution speed (amount of token distribute per block)

```solidity
function setTokensDistributionSpeed(address[] tokens_, uint256[] distributionSpeeds_) external
```

**Parameters**

| Name                 | Type       | Description                        |
| -------------------- | ---------- | ---------------------------------- |
| 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

***

#### setMaxTokensDistributionSpeed

Set max distribution speed for token (amount of maximum token distribute per block)

```solidity
function setMaxTokensDistributionSpeed(address[] tokens_, uint256[] maxDistributionSpeeds_) external
```

**Parameters**

| Name                    | Type       | Description                        |
| ----------------------- | ---------- | ---------------------------------- |
| 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

***

#### setPrimeToken

Set the prime token contract address

```solidity
function setPrimeToken(address prime_) external
```

**Parameters**

| Name    | Type    | Description                                 |
| ------- | ------- | ------------------------------------------- |
| prime\_ | address | The new address of the prime token contract |

**📅 Events**

* Emits PrimeTokenUpdated event

**⛔️ Access Requirements**

* Only owner

***

#### setMaxLoopsLimit

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

```solidity
function setMaxLoopsLimit(uint256 loopsLimit) external
```

**Parameters**

| Name       | Type    | Description                                   |
| ---------- | ------- | --------------------------------------------- |
| loopsLimit | uint256 | Limit for the max loops can execute at a time |

**📅 Events**

* Emits MaxLoopsLimitUpdated event on success

**⛔️ Access Requirements**

* Controlled by ACM

***

#### releaseFunds

Claim all the token accrued till last block

```solidity
function releaseFunds(address token_) external
```

**Parameters**

| Name    | Type    | Description                                |
| ------- | ------- | ------------------------------------------ |
| 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

***

#### sweepToken

A public function to sweep accidental ERC-20 transfers to this contract. Tokens are sent to user

```solidity
function sweepToken(contract IERC20Upgradeable token_, address to_, uint256 amount_) external
```

**Parameters**

| Name     | Type                       | Description                              |
| -------- | -------------------------- | ---------------------------------------- |
| 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

***

#### getEffectiveDistributionSpeed

Get rewards per block for token

```solidity
function getEffectiveDistributionSpeed(address token_) external view returns (uint256)
```

**Parameters**

| Name    | Type    | Description          |
| ------- | ------- | -------------------- |
| token\_ | address | Address of the token |

**Return Values**

| Name | Type    | Description                        |
| ---- | ------- | ---------------------------------- |
| \[0] | uint256 | speed returns the per block reward |

***

#### accrueTokens

Accrue token by updating the distribution state

```solidity
function accrueTokens(address token_) public
```

**Parameters**

| Name    | Type    | Description          |
| ------- | ------- | -------------------- |
| token\_ | address | Address of the token |

**📅 Events**

* Emits TokensAccrued event

***

#### getBlockNumberOrTimestamp

Get the current block number (block-based chains) or timestamp (time-based chains). Inherited from `TimeManagerV8`.

```solidity
function getBlockNumberOrTimestamp() public view virtual returns (uint256)
```

**Return Values**

| Name | Type    | Description                                                       |
| ---- | ------- | ----------------------------------------------------------------- |
| \[0] | uint256 | blockNumberOrSecond returns the current block number or timestamp |

***


# Prime storage

## PrimeV2StorageV1

Storage layout for the PrimeV2 contract with leaderboard-based Prime token distribution

## Solidity API

```solidity
struct Market {
  uint256 supplyMultiplier;
  uint256 borrowMultiplier;
  uint256 rewardIndex;
  uint256 sumOfMembersScore;
  bool exists;
}
```

```solidity
struct Interest {
  uint256 accrued;          // Accrued rewards pending claim (reset to 0 on claim)
  uint256 score;            // User's score in this market
  uint256 rewardIndex;      // Last recorded reward index
  uint256 lifetimeAccrued;  // Monotonic running total of all rewards ever accrued to this
                            // user in this market; never decremented on claim. Lets the
                            // off-chain cycle pipeline compute per-cycle earnings as the
                            // diff between two snapshots.
}
```

```solidity
struct PendingReward {
  address vToken;
  address rewardToken;
  uint256 amount;
}
```

#### isPrimeHolder

Whether a user holds a Prime token

```solidity
mapping(address => bool) isPrimeHolder
```

***

#### totalTokens

Total count of Prime tokens

```solidity
uint256 totalTokens
```

***

#### tokenLimit

Maximum number of Prime tokens allowed

```solidity
uint256 tokenLimit
```

***

#### markets

Mapping of vToken to its market configuration

```solidity
mapping(address => struct PrimeV2StorageV1.Market) markets
```

***

#### interests

Mapping of vToken -> user -> interest info

```solidity
mapping(address => mapping(address => struct PrimeV2StorageV1.Interest)) interests
```

***

#### vTokenForAsset

Mapping of underlying token to vToken address (used to check if an asset is part of Prime markets)

```solidity
mapping(address => address) vTokenForAsset
```

***

#### alphaNumerator

numerator of alpha. Ex: if alpha is 0.5 then this will be 1

```solidity
uint128 alphaNumerator
```

***

#### alphaDenominator

denominator of alpha. Ex: if alpha is 0.5 then this will be 2

```solidity
uint128 alphaDenominator
```

***

#### primeLiquidityProvider

The address of the PrimeLiquidityProvider contract

```solidity
address primeLiquidityProvider
```

***

#### oracle

The address of the ResilientOracle contract

```solidity
contract ResilientOracleInterface oracle
```

***

#### corePoolComptroller

Address of the core pool comptroller contract

```solidity
address corePoolComptroller
```

***

#### unreleasedPLPIncome

Unreleased income from the PLP per token that has already been accounted for — either indexed into `rewardIndex` for Prime holders, or recorded in `undistributedReward` while the market had no scored members

```solidity
mapping(address => uint256) unreleasedPLPIncome
```

***

#### undistributedReward

Income accrued while no scored members existed in the market. Tracked per underlying so governance can reclaim the slice via `sweepUndistributed` without touching user-owed funds.

```solidity
mapping(address => uint256) undistributedReward
```

***

#### isScoreUpdated

Mapping to check if an account's score was updated in a round

```solidity
mapping(uint256 => mapping(address => bool)) isScoreUpdated
```

***

#### nextScoreUpdateRoundId

Current score update round ID

```solidity
uint256 nextScoreUpdateRoundId
```

***

#### pendingScoreUpdates

Number of pending score updates in the current round

```solidity
uint256 pendingScoreUpdates
```

***

#### primeLeaderboard

Address of the PrimeLeaderboard contract for permissionless eligibility checks

```solidity
address primeLeaderboard
```

***

#### mintThreshold

Minimum Prime Score required for permissionless Prime minting

```solidity
uint256 mintThreshold
```

***

#### mintDeadline

Unix timestamp after which permissionless minting is closed (0 = no deadline)

```solidity
uint256 mintDeadline
```

***


# Vaults


# XVS


# XVSVault

## XVS Vault

The XVS Vault allows XVS holders to lock their XVS to recieve voting rights in Venus governance and are rewarded with XVS.

## Solidity API

#### pause

Pauses vault

```solidity
function pause() external
```

***

#### resume

Resume vault

```solidity
function resume() external
```

***

#### poolLength

Returns the number of pools with the specified reward token

```solidity
function poolLength(address rewardToken) external view returns (uint256)
```

**Parameters**

| Name        | Type    | Description          |
| ----------- | ------- | -------------------- |
| rewardToken | address | Reward token address |

**Return Values**

| Name | Type    | Description                                                     |
| ---- | ------- | --------------------------------------------------------------- |
| \[0] | uint256 | Number of pools that distribute the specified token as a reward |

***

#### add

Add a new token pool

```solidity
function add(address _rewardToken, uint256 _allocPoint, contract IBEP20 _token, uint256 _rewardPerBlock, uint256 _lockPeriod) external
```

**Parameters**

| Name             | Type            | Description                                                           |
| ---------------- | --------------- | --------------------------------------------------------------------- |
| \_rewardToken    | address         | Reward token address                                                  |
| \_allocPoint     | uint256         | Number of allocation points assigned to this pool                     |
| \_token          | contract IBEP20 | Staked token                                                          |
| \_rewardPerBlock | uint256         | Initial reward per block, in terms of \_rewardToken                   |
| \_lockPeriod     | uint256         | A period between withdrawal request and a moment when it's executable |

***

#### set

Update the given pool's reward allocation point

```solidity
function set(address _rewardToken, uint256 _pid, uint256 _allocPoint) external
```

**Parameters**

| Name          | Type    | Description                                       |
| ------------- | ------- | ------------------------------------------------- |
| \_rewardToken | address | Reward token address                              |
| \_pid         | uint256 | Pool index                                        |
| \_allocPoint  | uint256 | Number of allocation points assigned to this pool |

***

#### setRewardAmountPerBlock

Update the given reward token's amount per block

```solidity
function setRewardAmountPerBlock(address _rewardToken, uint256 _rewardAmount) external
```

**Parameters**

| Name           | Type    | Description                                       |
| -------------- | ------- | ------------------------------------------------- |
| \_rewardToken  | address | Reward token address                              |
| \_rewardAmount | uint256 | Number of allocation points assigned to this pool |

***

#### setWithdrawalLockingPeriod

Update the lock period after which a requested withdrawal can be executed

```solidity
function setWithdrawalLockingPeriod(address _rewardToken, uint256 _pid, uint256 _newPeriod) external
```

**Parameters**

| Name          | Type    | Description          |
| ------------- | ------- | -------------------- |
| \_rewardToken | address | Reward token address |
| \_pid         | uint256 | Pool index           |
| \_newPeriod   | uint256 | New lock period      |

***

#### deposit

Deposit XVSVault for XVS allocation

```solidity
function deposit(address _rewardToken, uint256 _pid, uint256 _amount) external
```

**Parameters**

| Name          | Type    | Description                    |
| ------------- | ------- | ------------------------------ |
| \_rewardToken | address | The Reward Token Address       |
| \_pid         | uint256 | The Pool Index                 |
| \_amount      | uint256 | The amount to deposit to vault |

***

#### claim

Claim rewards for pool

```solidity
function claim(address _account, address _rewardToken, uint256 _pid) external
```

**Parameters**

| Name          | Type    | Description                            |
| ------------- | ------- | -------------------------------------- |
| \_account     | address | The account for which to claim rewards |
| \_rewardToken | address | The Reward Token Address               |
| \_pid         | uint256 | The Pool Index                         |

***

#### executeWithdrawal

Execute withdrawal to XVSVault for XVS allocation

```solidity
function executeWithdrawal(address _rewardToken, uint256 _pid) external
```

**Parameters**

| Name          | Type    | Description              |
| ------------- | ------- | ------------------------ |
| \_rewardToken | address | The Reward Token Address |
| \_pid         | uint256 | The Pool Index           |

***

#### requestWithdrawal

Request withdrawal to XVSVault for XVS allocation

```solidity
function requestWithdrawal(address _rewardToken, uint256 _pid, uint256 _amount) external
```

**Parameters**

| Name          | Type    | Description                           |
| ------------- | ------- | ------------------------------------- |
| \_rewardToken | address | The Reward Token Address              |
| \_pid         | uint256 | The Pool Index                        |
| \_amount      | uint256 | The amount to withdraw from the vault |

***

#### getEligibleWithdrawalAmount

Get unlocked withdrawal amount

```solidity
function getEligibleWithdrawalAmount(address _rewardToken, uint256 _pid, address _user) external view returns (uint256 withdrawalAmount)
```

**Parameters**

| Name          | Type    | Description              |
| ------------- | ------- | ------------------------ |
| \_rewardToken | address | The Reward Token Address |
| \_pid         | uint256 | The Pool Index           |
| \_user        | address | The User Address         |

**Return Values**

| Name             | Type    | Description                       |
| ---------------- | ------- | --------------------------------- |
| withdrawalAmount | uint256 | Amount that the user can withdraw |

***

#### getRequestedAmount

Get requested amount

```solidity
function getRequestedAmount(address _rewardToken, uint256 _pid, address _user) external view returns (uint256)
```

**Parameters**

| Name          | Type    | Description              |
| ------------- | ------- | ------------------------ |
| \_rewardToken | address | The Reward Token Address |
| \_pid         | uint256 | The Pool Index           |
| \_user        | address | The User Address         |

**Return Values**

| Name | Type    | Description                                                                                            |
| ---- | ------- | ------------------------------------------------------------------------------------------------------ |
| \[0] | uint256 | Total amount of requested but not yet executed withdrawals (including both executable and locked ones) |

***

#### getWithdrawalRequests

Returns the array of withdrawal requests that have not been executed yet

```solidity
function getWithdrawalRequests(address _rewardToken, uint256 _pid, address _user) external view returns (struct XVSVaultStorageV1.WithdrawalRequest[])
```

**Parameters**

| Name          | Type    | Description              |
| ------------- | ------- | ------------------------ |
| \_rewardToken | address | The Reward Token Address |
| \_pid         | uint256 | The Pool Index           |
| \_user        | address | The User Address         |

**Return Values**

| Name | Type                                          | Description                     |
| ---- | --------------------------------------------- | ------------------------------- |
| \[0] | struct XVSVaultStorageV1.WithdrawalRequest\[] | An array of withdrawal requests |

***

#### pendingReward

View function to see pending XVSs on frontend

```solidity
function pendingReward(address _rewardToken, uint256 _pid, address _user) external view returns (uint256)
```

**Parameters**

| Name          | Type    | Description          |
| ------------- | ------- | -------------------- |
| \_rewardToken | address | Reward token address |
| \_pid         | uint256 | Pool index           |
| \_user        | address | User address         |

**Return Values**

| Name | Type    | Description                                                             |
| ---- | ------- | ----------------------------------------------------------------------- |
| \[0] | uint256 | Reward the user is eligible for in this pool, in terms of \_rewardToken |

***

#### updatePool

Update reward variables of the given pool to be up-to-date

```solidity
function updatePool(address _rewardToken, uint256 _pid) external
```

**Parameters**

| Name          | Type    | Description          |
| ------------- | ------- | -------------------- |
| \_rewardToken | address | Reward token address |
| \_pid         | uint256 | Pool index           |

***

#### getUserInfo

Get user info with reward token address and pid

```solidity
function getUserInfo(address _rewardToken, uint256 _pid, address _user) external view returns (uint256 amount, uint256 rewardDebt, uint256 pendingWithdrawals)
```

**Parameters**

| Name          | Type    | Description          |
| ------------- | ------- | -------------------- |
| \_rewardToken | address | Reward token address |
| \_pid         | uint256 | Pool index           |
| \_user        | address | User address         |

**Return Values**

| Name               | Type    | Description                                              |
| ------------------ | ------- | -------------------------------------------------------- |
| amount             | uint256 | Deposited amount                                         |
| rewardDebt         | uint256 | Reward debt (technical value used to track past payouts) |
| pendingWithdrawals | uint256 | Requested but not yet executed withdrawals               |

***

#### pendingWithdrawalsBeforeUpgrade

Gets the total pending withdrawal amount of a user before upgrade

```solidity
function pendingWithdrawalsBeforeUpgrade(address _rewardToken, uint256 _pid, address _user) public view returns (uint256 beforeUpgradeWithdrawalAmount)
```

**Parameters**

| Name          | Type    | Description              |
| ------------- | ------- | ------------------------ |
| \_rewardToken | address | The Reward Token Address |
| \_pid         | uint256 | The Pool Index           |
| \_user        | address | The address of the user  |

**Return Values**

| Name                          | Type    | Description                                                               |
| ----------------------------- | ------- | ------------------------------------------------------------------------- |
| beforeUpgradeWithdrawalAmount | uint256 | Total pending withdrawal amount in requests made before the vault upgrade |

***

#### delegate

Delegate votes from `msg.sender` to `delegatee`

```solidity
function delegate(address delegatee) external
```

**Parameters**

| Name      | Type    | Description                      |
| --------- | ------- | -------------------------------- |
| delegatee | address | The address to delegate votes to |

***

#### delegateBySig

Delegates votes from signatory to `delegatee`

```solidity
function delegateBySig(address delegatee, uint256 nonce, uint256 expiry, uint8 v, bytes32 r, bytes32 s) external
```

**Parameters**

| Name      | Type    | Description                                        |
| --------- | ------- | -------------------------------------------------- |
| 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   | The recovery byte of the signature                 |
| r         | bytes32 | Half of the ECDSA signature pair                   |
| s         | bytes32 | Half of the ECDSA signature pair                   |

***

#### getCurrentVotes

Gets the current votes balance for `account`

```solidity
function getCurrentVotes(address account) external view returns (uint96)
```

**Parameters**

| Name    | Type    | Description                      |
| ------- | ------- | -------------------------------- |
| account | address | The address to get votes balance |

**Return Values**

| Name | Type   | Description                               |
| ---- | ------ | ----------------------------------------- |
| \[0] | uint96 | The number of current votes for `account` |

***

#### getPriorVotes

Determine the xvs stake balance for an account

```solidity
function getPriorVotes(address account, uint256 blockNumber) external view returns (uint96)
```

**Parameters**

| Name        | Type    | Description                                 |
| ----------- | ------- | ------------------------------------------- |
| account     | address | The address of the account to check         |
| blockNumber | uint256 | The block number to get the vote balance at |

**Return Values**

| Name | Type   | Description                  |
| ---- | ------ | ---------------------------- |
| \[0] | uint96 | The balance that user staked |

***

#### \_become

* Admin Functions \*\*

```solidity
function _become(contract XVSVaultProxy xvsVaultProxy) external
```

***

#### setAccessControl

Sets the address of the access control of this contract

```solidity
function setAccessControl(address newAccessControlAddress) external
```

**Parameters**

| Name                    | Type    | Description                        |
| ----------------------- | ------- | ---------------------------------- |
| newAccessControlAddress | address | New address for the access control |

***


# XVSVaultProxy

## XVS Vault Proxy

XVS Vault Proxy contract

## Solidity API

#### \_setPendingImplementation

* Admin Functions \*\*

```solidity
function _setPendingImplementation(address newPendingImplementation) public returns (uint256)
```

***

#### \_acceptImplementation

Accepts new implementation of XVS Vault. msg.sender must be pendingImplementation

```solidity
function _acceptImplementation() public returns (uint256)
```

**Return Values**

| Name | Type    | Description                                                             |
| ---- | ------- | ----------------------------------------------------------------------- |
| \[0] | uint256 | uint 0=success, otherwise a failure (see ErrorReporter.sol for details) |

***

#### \_setPendingAdmin

Begins transfer of admin rights. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer.

```solidity
function _setPendingAdmin(address newPendingAdmin) public returns (uint256)
```

**Parameters**

| Name            | Type    | Description        |
| --------------- | ------- | ------------------ |
| newPendingAdmin | address | New pending admin. |

**Return Values**

| Name | Type    | Description                                                             |
| ---- | ------- | ----------------------------------------------------------------------- |
| \[0] | uint256 | uint 0=success, otherwise a failure (see ErrorReporter.sol for details) |

***

#### \_acceptAdmin

Accepts transfer of admin rights. msg.sender must be pendingAdmin

```solidity
function _acceptAdmin() public returns (uint256)
```

**Return Values**

| Name | Type    | Description                                                             |
| ---- | ------- | ----------------------------------------------------------------------- |
| \[0] | uint256 | uint 0=success, otherwise a failure (see ErrorReporter.sol for details) |

***


# XVSStore

## XVS Store

XVS Store responsible for distributing XVS rewards

## Solidity API

#### safeRewardTransfer

Safely transfer rewards. Only active reward tokens can be sent using this function. Only callable by owner

```solidity
function safeRewardTransfer(address token, address _to, uint256 _amount) external
```

**Parameters**

| Name     | Type    | Description                       |
| -------- | ------- | --------------------------------- |
| token    | address | Reward token to transfer          |
| \_to     | address | Destination address of the reward |
| \_amount | uint256 | Amount to transfer                |

***

#### setPendingAdmin

Allows the admin to propose a new admin Only callable admin

```solidity
function setPendingAdmin(address _admin) external
```

**Parameters**

| Name    | Type    | Description                                  |
| ------- | ------- | -------------------------------------------- |
| \_admin | address | Propose an account as admin of the XVS store |

***

#### acceptAdmin

Allows an account that is pending as admin to accept the role nly calllable by the pending admin

```solidity
function acceptAdmin() external
```

***

#### setNewOwner

Set the contract owner

```solidity
function setNewOwner(address _owner) external
```

**Parameters**

| Name    | Type    | Description                                         |
| ------- | ------- | --------------------------------------------------- |
| \_owner | address | The address of the owner to set Only callable admin |

***

#### setRewardToken

Set or disable a reward token

```solidity
function setRewardToken(address _tokenAddress, bool status) external
```

**Parameters**

| Name           | Type    | Description                                         |
| -------------- | ------- | --------------------------------------------------- |
| \_tokenAddress | address | The address of a token to set as active or inactive |
| status         | bool    | Set whether a reward token is active or not         |

***

#### emergencyRewardWithdraw

Security function to allow the owner of the contract to withdraw from the contract

```solidity
function emergencyRewardWithdraw(address _tokenAddress, uint256 _amount) external
```

**Parameters**

| Name           | Type    | Description                      |
| -------------- | ------- | -------------------------------- |
| \_tokenAddress | address | Reward token address to withdraw |
| \_amount       | uint256 | Amount of token to withdraw      |

***


# XVSVaultTreasury

## XVSVaultTreasury

This contract stores `XVS` received from `XVSBuyback` and funds `XVSVault`.

## Solidity API

#### XVS\_ADDRESS

The xvs token address

```solidity
address XVS_ADDRESS
```

***

#### xvsVault

The xvsvault address

```solidity
address xvsVault
```

***

#### fundXVSVault

This function transfers funds to the XVS vault

```solidity
function fundXVSVault(uint256 amountMantissa) external
```

**Parameters**

| Name           | Type    | Description                    |
| -------------- | ------- | ------------------------------ |
| amountMantissa | uint256 | Amount to be sent to XVS vault |

**📅 Events**

* FundsTransferredToXVSStore emits on success

**⛔️ Access Requirements**

* Restricted by ACM

**❌ Errors**

* InsufficientBalance is thrown when amount entered is greater than balance

#### sweepToken

This function sweep tokens from the contract

```solidity
function sweepToken(address tokenAddress, address to, uint256 amount) external
```

**Parameters**

| Name         | Type    | Description                                 |
| ------------ | ------- | ------------------------------------------- |
| 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      |

**📅 Events**

* SweepToken emits on success

**⛔️ Access Requirements**

* Restricted by ACM

***


# VAI


# VAIVault

## VAI Vault

The VAI Vault is configured for users to stake VAI And receive XVS as a reward.

## Solidity API

#### pause

Pause vault

```solidity
function pause() external
```

***

#### resume

Resume vault

```solidity
function resume() external
```

***

#### deposit

Deposit VAI to VAIVault for XVS allocation

```solidity
function deposit(uint256 _amount) external
```

**Parameters**

| Name     | Type    | Description                    |
| -------- | ------- | ------------------------------ |
| \_amount | uint256 | The amount to deposit to vault |

***

#### withdraw

Withdraw VAI from VAIVault

```solidity
function withdraw(uint256 _amount) external
```

**Parameters**

| Name     | Type    | Description                       |
| -------- | ------- | --------------------------------- |
| \_amount | uint256 | The amount to withdraw from vault |

***

#### claim

Claim XVS from VAIVault

```solidity
function claim() external
```

***

#### claim

Claim XVS from VAIVault

```solidity
function claim(address account) external
```

**Parameters**

| Name    | Type    | Description                        |
| ------- | ------- | ---------------------------------- |
| account | address | The account for which to claim XVS |

***

#### pendingXVS

View function to see pending XVS on frontend

```solidity
function pendingXVS(address _user) public view returns (uint256)
```

**Parameters**

| Name   | Type    | Description                 |
| ------ | ------- | --------------------------- |
| \_user | address | The user to see pending XVS |

**Return Values**

| Name | Type    | Description                      |
| ---- | ------- | -------------------------------- |
| \[0] | uint256 | Amount of XVS the user can claim |

***

#### updatePendingRewards

Function that updates pending rewards

```solidity
function updatePendingRewards() public
```

***

#### \_become

* Admin Functions \*\*

```solidity
function _become(contract VAIVaultProxy vaiVaultProxy) external
```

***

#### setAccessControl

Sets the address of the access control of this contract

```solidity
function setAccessControl(address newAccessControlAddress) external
```

**Parameters**

| Name                    | Type    | Description                        |
| ----------------------- | ------- | ---------------------------------- |
| newAccessControlAddress | address | New address for the access control |

***


# VAIVaultProxy

## VAI Vault Proxy

Proxy contract for the VAI Vault

## Solidity API

#### \_setPendingImplementation

* Admin Functions \*\*

```solidity
function _setPendingImplementation(address newPendingImplementation) public returns (uint256)
```

***

#### \_acceptImplementation

Accepts new implementation of VAI Vault. msg.sender must be pendingImplementation

```solidity
function _acceptImplementation() public returns (uint256)
```

**Return Values**

| Name | Type    | Description                                                             |
| ---- | ------- | ----------------------------------------------------------------------- |
| \[0] | uint256 | uint 0=success, otherwise a failure (see ErrorReporter.sol for details) |

***

#### \_setPendingAdmin

Begins transfer of admin rights. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer.

```solidity
function _setPendingAdmin(address newPendingAdmin) public returns (uint256)
```

**Parameters**

| Name            | Type    | Description        |
| --------------- | ------- | ------------------ |
| newPendingAdmin | address | New pending admin. |

**Return Values**

| Name | Type    | Description                                                             |
| ---- | ------- | ----------------------------------------------------------------------- |
| \[0] | uint256 | uint 0=success, otherwise a failure (see ErrorReporter.sol for details) |

***

#### \_acceptAdmin

Accepts transfer of admin rights. msg.sender must be pendingAdmin

```solidity
function _acceptAdmin() public returns (uint256)
```

**Return Values**

| Name | Type    | Description                                                             |
| ---- | ------- | ----------------------------------------------------------------------- |
| \[0] | uint256 | uint 0=success, otherwise a failure (see ErrorReporter.sol for details) |

***


# InterestRateModels


# JumpModel

## JumpRateModel

## Solidity API

#### constructor

Construct an interest rate model

```solidity
constructor(uint256 baseRatePerYear, uint256 multiplierPerYear, uint256 jumpMultiplierPerYear, uint256 kink_) public
```

**Parameters**

| Name                  | Type    | Description                                                            |
| --------------------- | ------- | ---------------------------------------------------------------------- |
| 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          |

***

#### utilizationRate

Calculates the utilization rate of the market: `borrows / (cash + borrows - reserves)`

```solidity
function utilizationRate(uint256 cash, uint256 borrows, uint256 reserves) public pure returns (uint256)
```

**Parameters**

| Name     | Type    | Description                                             |
| -------- | ------- | ------------------------------------------------------- |
| 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) |

**Return Values**

| Name | Type    | Description                                           |
| ---- | ------- | ----------------------------------------------------- |
| \[0] | uint256 | The utilization rate as a mantissa between \[0, 1e18] |

***

#### getBorrowRate

Calculates the current borrow rate per block, with the error code expected by the market

```solidity
function getBorrowRate(uint256 cash, uint256 borrows, uint256 reserves) public view returns (uint256)
```

**Parameters**

| Name     | Type    | Description                          |
| -------- | ------- | ------------------------------------ |
| 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**

| Name | Type    | Description                                                         |
| ---- | ------- | ------------------------------------------------------------------- |
| \[0] | uint256 | The borrow rate percentage per block as a mantissa (scaled by 1e18) |

***

#### getSupplyRate

Calculates the current supply rate per block

```solidity
function getSupplyRate(uint256 cash, uint256 borrows, uint256 reserves, uint256 reserveFactorMantissa) public view returns (uint256)
```

**Parameters**

| Name                  | Type    | Description                               |
| --------------------- | ------- | ----------------------------------------- |
| 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**

| Name | Type    | Description                                                         |
| ---- | ------- | ------------------------------------------------------------------- |
| \[0] | uint256 | The supply rate percentage per block as a mantissa (scaled by 1e18) |

***


# TwoKinksInterestRateModel

## TwoKinksInterestRateModel

An interest rate model with two different slope increase or decrease each after a certain utilization threshold called **kink** is reached.

## Solidity API

#### MULTIPLIER\_PER\_BLOCK

The multiplier of utilization rate per block that gives the slope 1 of the interest rate scaled by EXP\_SCALE

```solidity
int256 MULTIPLIER_PER_BLOCK
```

***

#### BASE\_RATE\_PER\_BLOCK

The base interest rate per block which is the y-intercept when utilization rate is 0 scaled by EXP\_SCALE

```solidity
int256 BASE_RATE_PER_BLOCK
```

***

#### KINK\_1

The utilization point at which the multiplier2 is applied

```solidity
int256 KINK_1
```

***

#### MULTIPLIER\_2\_PER\_BLOCK

The multiplier of utilization rate per block that gives the slope 2 of the interest rate scaled by EXP\_SCALE

```solidity
int256 MULTIPLIER_2_PER_BLOCK
```

***

#### BASE\_RATE\_2\_PER\_BLOCK

The base interest rate per block which is the y-intercept when utilization rate hits KINK\_1 scaled by EXP\_SCALE

```solidity
int256 BASE_RATE_2_PER_BLOCK
```

***

#### RATE\_1

The maximum kink interest rate scaled by EXP\_SCALE

```solidity
int256 RATE_1
```

***

#### KINK\_2

The utilization point at which the jump multiplier is applied

```solidity
int256 KINK_2
```

***

#### JUMP\_MULTIPLIER\_PER\_BLOCK

The multiplier of utilization rate per block that gives the slope 3 of interest rate scaled by EXP\_SCALE

```solidity
int256 JUMP_MULTIPLIER_PER_BLOCK
```

***

#### RATE\_2

The maximum kink interest rate scaled by EXP\_SCALE

```solidity
int256 RATE_2
```

***

#### constructor

Construct an interest rate model

```solidity
constructor(int256 baseRatePerYear_, int256 multiplierPerYear_, int256 kink1_, int256 multiplier2PerYear_, int256 baseRate2PerYear_, int256 kink2_, int256 jumpMultiplierPerYear_) public
```

**Parameters**

| Name                    | Type   | Description                                                                                                    |
| ----------------------- | ------ | -------------------------------------------------------------------------------------------------------------- |
| 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) |
| 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                                                                           |

***

#### getBorrowRate

Calculates the current borrow rate per slot (block)

```solidity
function getBorrowRate(uint256 cash, uint256 borrows, uint256 reserves) external view returns (uint256)
```

**Parameters**

| Name     | Type    | Description                          |
| -------- | ------- | ------------------------------------ |
| 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**

| Name | Type    | Description                                                                      |
| ---- | ------- | -------------------------------------------------------------------------------- |
| \[0] | uint256 | The borrow rate percentage per slot (block) as a mantissa (scaled by EXP\_SCALE) |

***

#### getSupplyRate

Calculates the current supply rate per slot (block)

```solidity
function getSupplyRate(uint256 cash, uint256 borrows, uint256 reserves, uint256 reserveFactorMantissa) public view virtual returns (uint256)
```

**Parameters**

| Name                  | Type    | Description                               |
| --------------------- | ------- | ----------------------------------------- |
| 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**

| Name | Type    | Description                                                                      |
| ---- | ------- | -------------------------------------------------------------------------------- |
| \[0] | uint256 | The supply rate percentage per slot (block) as a mantissa (scaled by EXP\_SCALE) |

***

#### utilizationRate

Calculates the utilization rate of the market: `borrows / (cash + borrows - reserves)`

```solidity
function utilizationRate(uint256 cash, uint256 borrows, uint256 reserves) public pure returns (uint256)
```

**Parameters**

| Name     | Type    | Description                          |
| -------- | ------- | ------------------------------------ |
| 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**

| Name | Type    | Description                                                 |
| ---- | ------- | ----------------------------------------------------------- |
| \[0] | uint256 | The utilization rate as a mantissa between \[0, EXP\_SCALE] |

***


# WhitePaperModel

## WhitePaperInterestRateModel

The parameterized model described in section 2.4 of the original Venus Protocol whitepaper

## Solidity API

#### constructor

Construct an interest rate model

```solidity
constructor(uint256 baseRatePerYear, uint256 multiplierPerYear) public
```

**Parameters**

| Name              | Type    | Description                                                            |
| ----------------- | ------- | ---------------------------------------------------------------------- |
| 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) |

***

#### utilizationRate

Calculates the utilization rate of the market: `borrows / (cash + borrows - reserves)`

```solidity
function utilizationRate(uint256 cash, uint256 borrows, uint256 reserves) public pure returns (uint256)
```

**Parameters**

| Name     | Type    | Description                                             |
| -------- | ------- | ------------------------------------------------------- |
| 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) |

**Return Values**

| Name | Type    | Description                                           |
| ---- | ------- | ----------------------------------------------------- |
| \[0] | uint256 | The utilization rate as a mantissa between \[0, 1e18] |

***

#### getBorrowRate

Calculates the current borrow rate per block, with the error code expected by the market

```solidity
function getBorrowRate(uint256 cash, uint256 borrows, uint256 reserves) public view returns (uint256)
```

**Parameters**

| Name     | Type    | Description                          |
| -------- | ------- | ------------------------------------ |
| 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**

| Name | Type    | Description                                                         |
| ---- | ------- | ------------------------------------------------------------------- |
| \[0] | uint256 | The borrow rate percentage per block as a mantissa (scaled by 1e18) |

***

#### getSupplyRate

Calculates the current supply rate per block

```solidity
function getSupplyRate(uint256 cash, uint256 borrows, uint256 reserves, uint256 reserveFactorMantissa) public view returns (uint256)
```

**Parameters**

| Name                  | Type    | Description                               |
| --------------------- | ------- | ----------------------------------------- |
| 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**

| Name | Type    | Description                                                         |
| ---- | ------- | ------------------------------------------------------------------- |
| \[0] | uint256 | The supply rate percentage per block as a mantissa (scaled by 1e18) |

***


# InterestRateModelLens

## InterestRateModelLens

Lens for querying interest rate model simulations

## Solidity API

```solidity
struct SimulationResponse {
  uint256[] borrowSimulation;
  uint256[] supplySimulation;
}
```

#### getSimulationResponse

Simulate interest rate curve fo a specific interest rate model given a reference borrow amount and reserve factor

```solidity
function getSimulationResponse(uint256 referenceAmountInWei, address interestRateModel, uint256 reserveFactorMantissa) external view returns (struct InterestRateModelLens.SimulationResponse)
```

**Parameters**

| Name                  | Type    | Description                                 |
| --------------------- | ------- | ------------------------------------------- |
| 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**

| Name | Type                                            | Description |
| ---- | ----------------------------------------------- | ----------- |
| \[0] | struct InterestRateModelLens.SimulationResponse |             |

***


# Liquidator

##

## Solidity API

#### vBnb

Address of vBNB contract.

```solidity
contract IVBNB vBnb
```

***

#### comptroller

Address of Venus Unitroller contract.

```solidity
contract IComptroller comptroller
```

***

#### vaiController

Address of VAIUnitroller contract.

```solidity
contract IVAIController vaiController
```

***

#### wBNB

Address of wBNB contract

```solidity
address wBNB
```

***

#### constructor

Constructor for the implementation contract. Sets immutable variables.

```solidity
constructor(address comptroller_, address payable vBnb_, address wBNB_) public
```

**Parameters**

| Name          | Type            | Description                             |
| ------------- | --------------- | --------------------------------------- |
| comptroller\_ | address         | The address of the Comptroller contract |
| vBnb\_        | address payable | The address of the VBNB                 |
| wBNB\_        | address         | The address of wBNB                     |

***

#### initialize

Initializer for the implementation contract.

```solidity
function initialize(uint256 treasuryPercentMantissa_, address accessControlManager_, address protocolShareReserve_) external virtual
```

**Parameters**

| Name                      | Type    | Description                                               |
| ------------------------- | ------- | --------------------------------------------------------- |
| 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        |

***

#### restrictLiquidation

An admin function to restrict liquidations to allowed addresses only.

```solidity
function restrictLiquidation(address borrower) external
```

**Parameters**

| Name     | Type    | Description                 |
| -------- | ------- | --------------------------- |
| borrower | address | The address of the borrower |

***

#### unrestrictLiquidation

An admin function to remove restrictions for liquidations.

```solidity
function unrestrictLiquidation(address borrower) external
```

**Parameters**

| Name     | Type    | Description                 |
| -------- | ------- | --------------------------- |
| borrower | address | The address of the borrower |

***

#### addToAllowlist

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.

```solidity
function addToAllowlist(address borrower, address liquidator) external
```

**Parameters**

| Name       | Type    | Description                 |
| ---------- | ------- | --------------------------- |
| borrower   | address | The address of the borrower |
| liquidator | address |                             |

***

#### removeFromAllowlist

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.

```solidity
function removeFromAllowlist(address borrower, address liquidator) external
```

**Parameters**

| Name       | Type    | Description                 |
| ---------- | ------- | --------------------------- |
| borrower   | address | The address of the borrower |
| liquidator | address |                             |

***

#### liquidateBorrow

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.

```solidity
function liquidateBorrow(address vToken, address borrower, uint256 repayAmount, contract IVToken vTokenCollateral) external payable
```

**Parameters**

| Name             | Type             | Description                                   |
| ---------------- | ---------------- | --------------------------------------------- |
| 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                       |

***

#### setTreasuryPercent

Sets the new percent of the seized amount that goes to treasury. Should be less than or equal to comptroller.liquidationIncentiveMantissa().sub(1e18).

```solidity
function setTreasuryPercent(uint256 newTreasuryPercentMantissa) external
```

**Parameters**

| Name                       | Type    | Description                             |
| -------------------------- | ------- | --------------------------------------- |
| newTreasuryPercentMantissa | uint256 | New treasury percent (scaled by 10^18). |

***

#### setProtocolShareReserve

Sets protocol share reserve contract address

```solidity
function setProtocolShareReserve(address payable protocolShareReserve_) external
```

**Parameters**

| Name                   | Type            | Description                                        |
| ---------------------- | --------------- | -------------------------------------------------- |
| protocolShareReserve\_ | address payable | The address of the protocol share reserve contract |

***

#### reduceReserves

Reduce the reserves of the pending accumulated reserves

```solidity
function reduceReserves() external
```

***

#### setMinLiquidatableVAI

Sets the threshold for minimum amount of vaiLiquidate

```solidity
function setMinLiquidatableVAI(uint256 minLiquidatableVAI_) external
```

**Parameters**

| Name                 | Type    | Description                        |
| -------------------- | ------- | ---------------------------------- |
| minLiquidatableVAI\_ | uint256 | New address for the access control |

***

#### setPendingRedeemChunkLength

Length of the pendingRedeem array to be consider while redeeming in Liquidation transaction

```solidity
function setPendingRedeemChunkLength(uint256 newLength_) external
```

**Parameters**

| Name        | Type    | Description         |
| ----------- | ------- | ------------------- |
| newLength\_ | uint256 | Length of the chunk |

***

#### pauseForceVAILiquidate

Pause Force Liquidation of VAI

```solidity
function pauseForceVAILiquidate() external
```

***

#### resumeForceVAILiquidate

Resume Force Liquidation of VAI

```solidity
function resumeForceVAILiquidate() external
```

***




---

[Next Page](/llms-full.txt/1)

