From 64c03d3ddb0406c3a2dcebb3af5cc8f4757ed544 Mon Sep 17 00:00:00 2001 From: GitGuru7 Date: Wed, 27 May 2026 18:42:59 +0530 Subject: [PATCH 01/25] docs: add reference docs for fixed rate vaults --- SUMMARY.md | 6 + deployed-contracts/fixed-rate-vaults.md | 19 + guides/fixed-rate-vaults/README.md | 19 + guides/fixed-rate-vaults/institution-guide.md | 86 ++++ guides/fixed-rate-vaults/supplier-guide.md | 84 ++++ .../fixed-rate-vaults.md | 421 ++++++++++++++++++ whats-new/fixed-rate-vaults.md | 48 ++ 7 files changed, 683 insertions(+) create mode 100644 deployed-contracts/fixed-rate-vaults.md create mode 100644 guides/fixed-rate-vaults/README.md create mode 100644 guides/fixed-rate-vaults/institution-guide.md create mode 100644 guides/fixed-rate-vaults/supplier-guide.md create mode 100644 technical-reference/reference-technical-articles/fixed-rate-vaults.md create mode 100644 whats-new/fixed-rate-vaults.md diff --git a/SUMMARY.md b/SUMMARY.md index 4a92bac..4f44fe6 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -18,6 +18,7 @@ * [Automatic Income Allocation](whats-new/automatic-income-allocation.md) * [TokenBuyback Contract](whats-new/token-converter.md) * [Venus Prime](whats-new/prime-yield.md) +* [Fixed Rate Vaults](whats-new/fixed-rate-vaults.md) ## Governance @@ -59,6 +60,9 @@ * [Isolated E-mode](guides/isolated-e-mode.md) * [Boost and Repay with Collateral](guides/leveraged-positions.md) * [Trade](guides/trade.md) +* [Fixed Rate Vaults](guides/fixed-rate-vaults/README.md) + * [Institution Guide](guides/fixed-rate-vaults/institution-guide.md) + * [Supplier Guide](guides/fixed-rate-vaults/supplier-guide.md) ## Technical reference @@ -70,6 +74,7 @@ * [Diamond Comptroller in the Core pool](technical-reference/reference-technical-articles/diamond-comptroller.md) * [E-Mode](technical-reference/reference-technical-articles/e-mode.md) * [Trade](technical-reference/reference-technical-articles/trade.md) + * [Fixed Rate Vaults](technical-reference/reference-technical-articles/fixed-rate-vaults.md) * [Native Token Gateway](technical-reference/reference-technical-articles/native-token-gateway.md) * [Omnichain Governance](technical-reference/reference-technical-articles/omnichain-governance.md) * [Prime tokens](technical-reference/reference-technical-articles/prime.md) @@ -209,6 +214,7 @@ * [Token Converters](deployed-contracts/token-converters.md) * [VenusERC4626](deployed-contracts/venus-erc4626.md) * [Periphery](deployed-contracts/periphery.md) +* [Fixed Rate Vaults](deployed-contracts/fixed-rate-vaults.md) ## Services diff --git a/deployed-contracts/fixed-rate-vaults.md b/deployed-contracts/fixed-rate-vaults.md new file mode 100644 index 0000000..8456f74 --- /dev/null +++ b/deployed-contracts/fixed-rate-vaults.md @@ -0,0 +1,19 @@ +# Fixed Rate Vaults + +Core contracts for the Fixed Rate Vaults system. Each institution's vault is deployed as an EIP-1167 clone by governance via `createVault(...)` on `InstitutionalVaultController`, so individual vault instances are not enumerated here — query the controller's `allVaults` array (or the `VaultCreated` event log) to enumerate deployed vaults. + +## BNB Chain Mainnet + +### Fixed Rate Vaults Contracts + +* InstitutionalVaultController (proxy): [`0x6D9e91cB766259af42619c14c994E694E57e6E85`](https://bscscan.com/address/0x6D9e91cB766259af42619c14c994E694E57e6E85) +* InstitutionPositionToken: [`0x3Ed56f6937fc8549f9325405d1e8E650739647Fa`](https://bscscan.com/address/0x3Ed56f6937fc8549f9325405d1e8E650739647Fa) +* LiquidationAdapter (proxy): [`0x17A6222fB8b4b6D852cA54f5bc376a6A2c6224Bd`](https://bscscan.com/address/0x17A6222fB8b4b6D852cA54f5bc376a6A2c6224Bd) + +## BNB Chain Testnet + +### Fixed Rate Vaults Contracts + +* InstitutionalVaultController (proxy): [`0xf77dED2A00F94e33C392126238360D4642c16Ba2`](https://testnet.bscscan.com/address/0xf77dED2A00F94e33C392126238360D4642c16Ba2) +* InstitutionPositionToken: [`0x71dA473257a96e975558C8edD8491AD0880EFCe5`](https://testnet.bscscan.com/address/0x71dA473257a96e975558C8edD8491AD0880EFCe5) +* LiquidationAdapter (proxy): [`0x4b302b56315Ca16A0A4565108e62404496916491`](https://testnet.bscscan.com/address/0x4b302b56315Ca16A0A4565108e62404496916491) diff --git a/guides/fixed-rate-vaults/README.md b/guides/fixed-rate-vaults/README.md new file mode 100644 index 0000000..d02ce53 --- /dev/null +++ b/guides/fixed-rate-vaults/README.md @@ -0,0 +1,19 @@ +# Fixed Rate Vaults + +Fixed Rate 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 headline APY 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) — deposits the loan asset during fundraising, holds through the lock period, and redeems principal plus the fixed 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](institution-guide.md) | +| **Supplier** — you want to deposit during fundraising and earn the fixed yield at maturity | [Supplier Guide](supplier-guide.md) | + +For the contract-level details, see the [Fixed Rate Vaults Technical Reference](../../technical-reference/reference-technical-articles/fixed-rate-vaults.md). diff --git a/guides/fixed-rate-vaults/institution-guide.md b/guides/fixed-rate-vaults/institution-guide.md new file mode 100644 index 0000000..e14e857 --- /dev/null +++ b/guides/fixed-rate-vaults/institution-guide.md @@ -0,0 +1,86 @@ +# Institution Guide + +This guide walks through the institution's lifecycle in a Fixed Rate 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. + +## 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. + +## Step 2: Wait for the Vault to Open + +After the margin lands, Venus opens the vault and starts the fundraising window. Suppliers can now deposit the loan asset. No action is required from you in this step. + +## 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. + +{% 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. + +**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. + +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. + +{% 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 Rate 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** + + Fixed APY, 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 Rate Vaults Technical Reference](../../technical-reference/reference-technical-articles/fixed-rate-vaults.md). diff --git a/guides/fixed-rate-vaults/supplier-guide.md b/guides/fixed-rate-vaults/supplier-guide.md new file mode 100644 index 0000000..cf8f105 --- /dev/null +++ b/guides/fixed-rate-vaults/supplier-guide.md @@ -0,0 +1,84 @@ +# Supplier Guide + +This guide walks through how to participate in a Fixed Rate Vault as a supplier. You deposit the loan asset during the fundraising window, hold through the lock period, and redeem principal plus the fixed yield at maturity. + +## Before You Deposit + +Each vault has a published set of terms set at deployment. Before committing funds, review: + +* **Fixed APY** — the annualized rate paid on your deposit. +* **Lock duration** — how long your funds are locked after fundraising closes. +* **Minimum and maximum raise** — the minimum needed to actually fund the loan, and the ceiling beyond which deposits are rejected. +* **Minimum deposit** — the floor for a single deposit. +* **Supply asset** — the asset you deposit. +* **Fundraising window** — when deposits close. + + +## Step 1: Deposit During Fundraising + +While fundraising is open, deposit the supply asset into the vault. You receive vault share tokens representing your claim. The shares are freely transferable, so you can hold them in any wallet. + +**Minimum deposit floor** applies unless you're filling the final residual capacity, in which case the floor is waived so the cap can actually be reached. + + +## Step 2: Hold Through the Lock Period + +When the fundraising window closes with the raise above the minimum, the vault enters the lock period. At this point: + +* **Deposits and withdrawals 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. + + +## 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. Burn your shares to receive principal plus your share of the interest. + +Redeem as soon as possible. If funds remain unclaimed for too long, Venus may sweep the remaining assets and close the vault. + +### Worked Example + +A vault raises 100,000 USDC at 8% fixed APY for a 90-day lock. You deposit 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 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's a return of ~1.78% over the 90-day term on your 10,000 USDC principal. + +## Key Risks You Must Understand + +A Fixed Rate 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 headline yield. + +## Best Practices + +* **Read the vault terms carefully.** APY, 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. + +## Recovering Your Funds + +When the vault reaches a terminal state, redemption is available. Burn your shares to claim your portion of the remaining balance. + +| Outcome | What you receive | +| --- | --- | +| **Loan matured** | Principal + your share of the interest | +| **Vault failed — raise short** | Full principal, no interest | +| **Vault failed — collateral underdelivered** | Full principal + pro-rata share of the confiscated margin | +| **Vault liquidated** | Pro-rata share of the remaining supply asset; may be less than full principal if collateral didn't cover the debt | + +--- + +For the on-chain details, including the full state machine, function signatures, math, and liquidation paths, see the [Fixed Rate Vaults Technical Reference](../../technical-reference/reference-technical-articles/fixed-rate-vaults.md). diff --git a/technical-reference/reference-technical-articles/fixed-rate-vaults.md b/technical-reference/reference-technical-articles/fixed-rate-vaults.md new file mode 100644 index 0000000..d55cae4 --- /dev/null +++ b/technical-reference/reference-technical-articles/fixed-rate-vaults.md @@ -0,0 +1,421 @@ +# Fixed Rate Vaults + +**Fixed Rate Vaults** are a new lending product on Venus Protocol. 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 headline APY at maturity. + +The system is deployed as a clone factory. The **InstitutionalVaultController** is the orchestration surface. It deploys a fresh **InstitutionalLoanVault** clone per institution, mints a position NFT to the nominated operator, and proxies governance operations to the vault. Suppliers interact with the vault directly via the standard ERC-4626 interface. + +| Component | Description | +| --- | --- | +| **BaseVault** | Abstract ERC-4626 base providing shared fundraising, interest computation, state machine, settlement waterfall, and pause logic | +| **InstitutionalLoanVault** | Concrete vault deployed as an EIP-1167 clone. Extends `BaseVault` with collateral, borrowing, risk checks, and liquidation hooks | +| **InstitutionalVaultController** | Orchestrator. Deploys clones, mints position NFTs, holds the AccessControlManager reference, and proxies governance calls | +| **InstitutionPositionToken** | Non-upgradeable singleton ERC-721. One token per vault, minted to the institution's nominated operator. Transfer-gated by governance approval | +| **LiquidationAdapter** | Routes both health-based and overdue liquidations. Holds liquidator/settler whitelists, the global `closeFactor`, and the protocol liquidation share | + +--- + +## Architecture + +The Fixed Rate Vaults system consists of four contracts plus the shared ERC-4626 base: + +| Contract | Role | +| --- | --- | +| **InstitutionalVaultController** | Central governance surface. Validates configurations, deploys vault clones, maintains the vault registry, and exposes ACM-gated admin functions. Deployed behind a transparent proxy. | +| **InstitutionalLoanVault** | Per-loan vault. Holds collateral, raised funds, and debt; enforces the state machine; exposes institution and supplier entrypoints. Deployed as a minimal EIP-1167 clone | +| **InstitutionPositionToken** | Singleton ERC-721. Mints one token per vault; gates transfers behind a single-use governance approval; provides the on-chain ownership credential for institution-side actions. Deployed once and cannot be upgraded. | +| **LiquidationAdapter** | Routes liquidation calls. Enforces liquidator/settler whitelists, calculates seize amounts using either `liquidationIncentive` (health-based) or `latePenaltyRate` (overdue), and accrues the protocol share for periodic sweeps to PSR | + +### Per-Vault Isolation + +Each vault is an entirely independent contract. Collateral, supplier deposits, debt, settlement, and risk thresholds are scoped to a single vault, so one vault cannot affect another. Even institutions running multiple loans concurrently receive a fresh clone per loan. + +| Layer | Mechanism | +| --- | --- | +| **Fund custody** | Each vault holds its own balance of the supply asset (ERC-4626 underlying) and collateral asset. | +| **State machine** | Each vault advances through its own `VaultState` independently. Lifecycle timers (`openStartTime`, `lockEndTime`, `settlementDeadline`) are recorded on the vault itself | +| **Access control** | Institution operations are gated by `onlyPositionHolder` which is checked against `positionToken.ownerOf(positionTokenId)` at call time. Governance operations are proxied through the controller and gated by Venus AccessControlManager | +| **Deterministic deployment** | Clones are deployed with `Clones.cloneDeterministic(impl, salt)` using `keccak256(institution, nonce)` as salt. Per-institution nonce ensures uniqueness across deployments | + +## State Machine + +Vault lifecycle is encoded as the `VaultState` enum (defined in `IVaultTypes.sol`). A vault advances through these states in a single direction; there is no rollback. + +```solidity +enum VaultState { + WaitingForMargin, // 0 — awaiting institution margin deposit + MarginDeposited, // 1 — margin in, awaiting governance to open + Fundraising, // 2 — suppliers depositing supply asset + InstitutionConfirmation, // 3 — reserved for subcontract use; unused here + Lock, // 4 — funds committed, interest accruing + PendingSettlement, // 5 — maturity reached, awaiting repayment + SettlementDeadlineExceeded, // 6 — deadline passed with outstanding debt + Matured, // 7 — repayment settled, shares redeemable + Failed, // 8 — fundraising shortfall or institution default + Liquidated, // 9 — bad-debt rescue path + Closed // 10 — governance delisted; all actions blocked +} +``` + +The diagram below shows how a vault moves between states, with each arrow labelled by the condition that triggers the transition. + +``` + +------------------------+ + | WaitingForMargin |-- cancelVault() (governance) --+ + +-----------+------------+ | + | depositCollateral() | + | (collateral >= required margin) | + v | + +------------------------+-- cancelVault() (governance) ---+ + | MarginDeposited | | + +-----------+------------+ | + | openVault() (governance) | + v | + +------------------------+ raise short OR | + | Fundraising |--> collateral underdelivered --+ + | (suppliers supply) | | + +-----------+------------+ v + | raised >= minBorrowCap +--------+ +--------+ + | and collateral met | Failed |-- closeVault() -> | Closed | + v +--------+ +--------+ + +------------------------+ LT shortfall > 0 + | Lock |--> (health-based +------------+ +--------+ + | (borrowing) | liquidation) ---------> | Liquidated |-- closeVault() -> | Closed | + +-----------+------------+ +------------+ +--------+ + | ^ + | lockDuration elapsed | + | (repaid in full early ------> Matured) | + v | + +------------------------+ | + | PendingSettlement | | + +-----------+------------+ | + | settlementDeadline expired + debt > 0 | + | (repaid ------> Matured) | + v | + +----------------------------+ liquidateOverdueVault() | + | SettlementDeadlineExceeded |------------------------------+ + +-------------+--------------+ + | repaid + v + +---------+ + | Matured | + +----+----+ + | closeVault() (governance) + v + +--------+ + | Closed | + +--------+ +``` + +| State | Meaning | Allowed transitions | +| --- | --- | --- | +| **WaitingForMargin** | Vault deployed; institution must deposit the margin in a single transaction | → `MarginDeposited` (margin met), or → `Failed` (cancelled by governance) | +| **MarginDeposited** | Margin in. Lifecycle timelines pre-computed but not started | → `Fundraising` (via `openVault`), or → `Failed` (cancelled) | +| **Fundraising** | Suppliers deposit the supply asset; institution tops up to `idealCollateralAmount` | → `Lock` (raised ≥ minBorrowCap, collateral met), → `Failed` (raise short OR collateral underdelivered) | +| **Lock** | Funds committed; full interest fixed; institution may claim funds, repay, top up collateral | → `PendingSettlement` (lock duration elapsed), → `Matured` (repaid in full early), → `Liquidated` (HF-based liquidation completed) | +| **PendingSettlement** | Maturity reached; awaiting institution repayment | → `Matured` (debt cleared), → `SettlementDeadlineExceeded` (deadline passed with debt outstanding) | +| **SettlementDeadlineExceeded** | Deadline breached with debt outstanding. Liquidatable at late-penalty rate | → `Matured` (repaid), → `Liquidated` (overdue liquidation completed) | +| **Matured** | Settlement complete. Suppliers redeem pro-rata against `settlementAmount` | → `Closed` (governance delists) | +| **Failed** | Two sub-scenarios — see below. Suppliers redeem; institution recovers residual collateral | → `Closed` | +| **Liquidated** | Debt was cleared via liquidation. Suppliers redeem pro-rata against the leftover supply asset balance | → `Closed` | +| **Closed** | Terminal. All entrypoints revert | — | + +### Happy Path + +`WaitingForMargin` → `MarginDeposited` → `Fundraising` → `Lock` → `PendingSettlement` → `Matured` → `Closed` + +### Failed Sub-Scenarios + +The `Failed` state covers two distinct outcomes, distinguished by the `institutionDefaulted` flag in `InstitutionalRuntime`: + +* **Scenario A (raise shortfall).** `totalRaised < minBorrowCap` at the end of the open window. `institutionDefaulted = false`, `confiscatedMarginRemaining = 0`. Suppliers redeem principal only; institution recovers all collateral including the margin. +* **Scenario B (collateral underdelivery).** `totalRaised ≥ minBorrowCap` but `totalCollateralDeposited < idealCollateralAmount` at the end of the open window. The margin (`idealCollateralAmount × marginRate`) is confiscated; `institutionDefaulted = true`. Suppliers redeem principal plus a pro-rata share of the confiscated margin in the collateral asset; institution recovers `totalCollateralDeposited − confiscatedMargin`. + +## Lifecycle Parameters + +All vault configuration is set once at deployment via `createVault` and cannot be changed afterwards (except `RiskConfig` fields, which are governance-mutable post-deployment). + +### Shared Vault Configuration (`VaultConfig`) + +| Field | Type | Meaning | +| --- | --- | --- | +| `supplyAsset` | `IERC20` | The loan asset suppliers deposit and the institution borrows | +| `fixedAPY` | `uint256` | Annualized interest rate. | +| `reserveFactor` | `uint256` | Protocol share of interest.| +| `minBorrowCap` | `uint256` | Minimum fundraise required to enter `Lock`. Below this, vault enters `Failed`| +| `maxBorrowCap` | `uint256` | Hard ceiling on fundraising. Deposits clamp to remaining capacity | +| `minSupplierDeposit` | `uint256` | Floor for a single deposit. Waived only when filling the final residual capacity | +| `openDuration` | `uint40` | Length of the fundraising window in seconds | +| `lockDuration` | `uint40` | Length of the locked-loan period in seconds. Used to compute total interest | +| `settlementWindow` | `uint40` | Grace period after lock end before the vault becomes overdue | + +### Institutional Configuration (`InstitutionalConfig`) + +| Field | Type | Meaning | +| --- | --- | --- | +| `collateralAsset` | `IERC20` | Asset the institution posts as collateral | +| `idealCollateralAmount` | `uint256` | Target collateral the institution should post. Computed off-chain by applying a collateral factor to `maxBorrowCap` | +| `marginRate` | `uint256` | Margin percentage of `idealCollateralAmount`. | +| `institutionOperator` | `address` | Initial recipient of the position NFT | +| `positionTokenId` | `uint256` | NFT id assigned at vault creation | + +### Risk Configuration (`RiskConfig`) + +| Field | Type | Meaning | Mutable | +| --- | --- | --- | --- | +| `liquidationThreshold` | `uint256` | Maximum debt-to-collateral ratio before liquidation. | Yes | +| `liquidationIncentive` | `uint256` | Health-based liquidator bonus. | Yes | +| `latePenaltyRate` | `uint256` | Overdue liquidation bonus. Same range as `liquidationIncentive` | Yes | + +All risk parameter updates flow through `InstitutionalVaultController.setLiquidationThreshold` / `setLiquidationIncentive` / `setLatePenaltyRate`, each gated by AccessControlManager. + + +## Function Reference + +### Governance (on `InstitutionalVaultController`) + +All controller entrypoints are gated by Venus AccessControlManager via the `_checkAccessAllowed` modifier. + +| Function | Effect | +| --- | --- | +| `createVault(...)` | Deploys a fresh `InstitutionalLoanVault` clone, mints the position NFT, registers the vault, and applies its `VaultConfig` / `InstitutionalConfig` / `RiskConfig`. Vault starts in `WaitingForMargin`. Emits `VaultCreated` | +| `openVault(vault)` | `MarginDeposited` → `Fundraising`; fixes all lifecycle timers | +| `cancelVault(vault)` | Cancels a pre-launch vault (`WaitingForMargin` / `MarginDeposited`) and refunds all collateral, including the margin; transitions to `Failed` with `institutionDefaulted = false` | +| `approvePositionTransfer(vault, recipient)` / `revokePositionTransfer(vault)` | Grant or revoke a single-use approval for a position-NFT transfer | +| `partialPauseVault` / `completePauseVault` / `unpauseVault` | Two-level pause control — see [Pause System](#pause-system) under Security Model | +| `closeVault(vault)` | Terminal: transitions a settled vault to `Closed` | +| `setLiquidationThreshold` / `setLiquidationIncentive` / `setLatePenaltyRate` | Update the mutable `RiskConfig` fields post-deployment | + +### Institution (on the vault) + +The `onlyPositionHolder` modifier checks `positionToken.ownerOf(positionTokenId) == msg.sender` at call time. Transferring the NFT immediately transfers control of these functions. + +#### depositCollateral + +```solidity +function depositCollateral(uint256 amount) external; +``` + +Pulls the collateral asset from the caller. Allowed in `WaitingForMargin`, `Fundraising`, and `Lock`. In `WaitingForMargin`, the deposit must bring `totalCollateralDeposited` to at least `idealCollateralAmount × marginRate` in a single transaction. Partial deposits below the margin threshold revert with `InsufficientCollateral`. On success in `WaitingForMargin`, the vault transitions to `MarginDeposited`. Emits `CollateralDeposited(amount, totalCollateralDeposited)`. + +#### withdrawCollateral + +```solidity +function withdrawCollateral(uint256 amount) external; +``` + +Releases collateral to the caller. Allowed in `Lock`, `Matured`, and `Failed`; blocked in all other states. During `Lock`, two checks gate the call: + +1. **Floor check.** `totalCollateralDeposited − amount ≥ minimumCollateralRequired`, where the floor is recalculated at Lock entry as `idealCollateralAmount × totalRaised / maxBorrowCap`. Withdrawals cannot touch the locked portion. +2. **LT health check.** `_getHypotheticalVaultLiquidity(amount, 0)` simulates the post-withdrawal balance; if it would breach the liquidation threshold, the call reverts with `WithdrawalWouldBreachLT`. + +In `Failed` (`institutionDefaulted = true`), the withdrawable amount is capped at `totalCollateralDeposited − confiscatedMarginRemaining`. + +#### claimRaisedFunds + +```solidity +function claimRaisedFunds() external; +``` + +One-shot transfer of the entire raised supply asset balance to the caller. Allowed only in `Lock`, gated by `fundsWithdrawn` (set true on success). Pre-call health check: simulating the resulting debt (`_runtime.totalRaised`) against current collateral must not produce a shortfall, otherwise reverts with `ClaimWouldBreachLT`. Emits `RaisedFundsClaimed(amount)`. + +#### repay + +```solidity +function repay(uint256 amount) external; +``` + +Anyone can call. Pulls supply asset from the caller and reduces `totalDebt`. Allowed in `Lock`, `PendingSettlement`, and `SettlementDeadlineExceeded`. Overpayment is automatically clamped to `outstandingDebt`. Emits `Repaid(amount, remainingDebt)`. + +### Supplier (on the vault, ERC-4626 interface) + +All supplier functions are permissionless. Anyone can supply. + +```solidity +function deposit(uint256 assets, address receiver) external returns (uint256 shares); +function mint(uint256 shares, address receiver) external returns (uint256 assets); +function withdraw(uint256 assets, address receiver, address owner) external returns (uint256 shares); +function redeem(uint256 shares, address receiver, address owner) external returns (uint256 assets); +``` + +* `deposit` and `mint` are allowed only in `Fundraising`. Both clamp to remaining capacity (`maxBorrowCap − totalRaised`); exceeding capacity does not revert unless capacity is zero, in which case `ExceedsMaxCap` is raised. `minSupplierDeposit` is enforced unless the deposit fills the final residual slot. + +* `withdraw` and `redeem` are allowed in `Matured`, `Failed`, and `Liquidated` only. Both follow standard ERC-4626 semantics, computing the supply-asset payout from `settlementAmount` and `totalSupply()`. In `Failed`, the `_afterWithdrawHook` additionally transfers a pro-rata slice of the confiscated margin in the collateral asset. + +Shares are standard ERC-20s, freely transferable at all times. Suppliers track their position through the share balance, not through any per-user NFT. + +### Liquidator (via `LiquidationAdapter`) + +Two liquidation paths exist on the vault, each gated by the `onlyLiquidationAdapter` modifier: + +```solidity +function liquidate(uint256 repayAmount) external returns (uint256 actualRepay); +function liquidateOverdueVault(uint256 repayAmount) external returns (uint256 actualRepay); +``` + +* `liquidate` (health-based) requires a current LT shortfall. Allowed in `Lock`, `PendingSettlement`, or `SettlementDeadlineExceeded`. The liquidator (via the adapter) repays up to `min(repayAmount, outstandingDebt × closeFactor)` and seizes collateral at the `liquidationIncentive` rate. + +* `liquidateOverdueVault` (deadline-based) requires the vault to be in `SettlementDeadlineExceeded`. No collateral shortfall is required; the time breach alone qualifies. Seize amount is computed at the `latePenaltyRate`. + +In both cases, seized collateral is split between the caller and the protocol per `LiquidationAdapter.protocolLiquidationShare`; the protocol share is accrued inside the adapter and periodically swept to PSR via `sweepProtocolShareToReserve`. + +### Read-Only Views + +```solidity +function state() external view returns (VaultState); +function config() external view returns (VaultConfig memory); // BaseVault — shared config +function runtime() external view returns (VaultRuntime memory); // BaseVault — shared runtime +function institutionalConfig() external view returns (InstitutionalConfig memory); +function institutionalRuntime() external view returns (InstitutionalRuntime memory); +function riskConfig() external view returns (RiskConfig memory); +function outstandingDebt() external view returns (uint256); +function totalAssets() external view returns (uint256); +function maxDeposit(address) external view returns (uint256); +function maxWithdraw(address) external view returns (uint256); +function maxRedeem(address) external view returns (uint256); +function previewDeposit(uint256) external view returns (uint256); +function previewRedeem(uint256) external view returns (uint256); +``` + +`totalAssets()` returns `totalRaised` until shares become redeemable. Once the vault settles (`Matured`, `Failed`, or `Liquidated`) it returns `settlementAmount`. + +## Math + +### Required Margin + +The margin the institution must deposit to advance from `WaitingForMargin` to `MarginDeposited`: + +$$ +\text{requiredMargin} = \text{idealCollateralAmount} \times \frac{\text{marginRate}}{10^{18}} +$$ + +### Minimum Collateral Floor (at Lock Entry) + +When the vault transitions to `Lock`, the locked-collateral floor is recalculated proportionally to the actual raise: + +$$ +\text{minimumCollateralRequired} = \text{idealCollateralAmount} \times \frac{\text{totalRaised}}{\text{maxBorrowCap}} +$$ + +This frees the excess collateral above the floor for withdrawal during `Lock` when the raise underfills the cap. + +### Total Interest + +Fixed interest is computed once at Lock entry and is owed in full at maturity, regardless of when the institution repays: + +$$ +\text{totalInterest} = \frac{\text{totalRaised} \times \text{fixedAPY} \times \text{lockDuration}}{\text{BPS} \times \text{YEAR}} +$$ + +Where `BPS = 10000` and `YEAR = 365 days`. The result is stored as `totalDebt` at Lock entry; `claimRaisedFunds` adds `totalRaised` to `totalDebt`. + +### Protocol Fee at Settlement + +`_settleProtocolShare` runs the settlement waterfall once on entry to `Matured` or `Liquidated`. Three branches: + +| Branch | Condition | Protocol fee | Settlement amount | +| --- | --- | --- | --- | +| **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` | + +Any surplus above `totalRaised + totalInterest` is also forwarded to PSR. `ShortfallDetected(expected, available)` fires in the partial and principal-shortfall branches. + +### Per-Supplier Payout + +Standard ERC-4626 pro-rata against the post-settlement `settlementAmount`: + +$$ +\text{payout} = \text{shares} \times \frac{\text{settlementAmount}}{\text{totalSupply}} +$$ + +### Margin Compensation per Redeem + +When the institution defaults on collateral delivery, the margin is distributed pro-rata to suppliers as they redeem: + +$$ +\text{compensation} = \text{confiscatedMarginRemaining} \times \frac{\text{shares}}{\text{totalSupplyBeforeBurn}} +$$ + +Compensation is paid in the collateral asset, not the supply asset. Integer division means the last supplier to redeem may receive a marginally smaller compensation than the proportional share suggests; the dust amount is negligible in practice. + +## Liquidation + +### Standard (Health-Based) Liquidation + +Triggered when the vault's debt exceeds its LT-capped collateral value. The liquidator (whitelisted on `LiquidationAdapter`) repays up to a fraction of the outstanding debt, capped by the global `closeFactor`, and seizes collateral at the `liquidationIncentive` rate. + +* **Eligibility**: the vault has a non-zero shortfall. +* **Allowed states**: `Lock`, `PendingSettlement`, `SettlementDeadlineExceeded`. +* **Repay cap**: `min(repayAmount, outstandingDebt × closeFactor)`. `closeFactor` lives on `LiquidationAdapter`, shared across all vaults. +* **Seize amount**: computed from oracle-priced collateral and the supply asset, scaled by `liquidationIncentive`. + +When the resulting repayment clears the debt, the vault transitions to `Matured` if collateral remains, or to `Liquidated` if the settlement is bad-debt (collateral insufficient to fully cover principal + interest). + +### Overdue (Deadline-Based) Liquidation + +Triggered when the settlement deadline passes with debt outstanding, irrespective of collateral health. + +* **Eligibility**: `state == SettlementDeadlineExceeded` and `outstandingDebt > 0`. +* **No collateral shortfall required.** The time breach alone qualifies. +* **Seize amount**: scaled by `latePenaltyRate` instead of `liquidationIncentive`. + +A vault that breaches both the LT cap **and** the settlement deadline can be liquidated through either path; the chosen path determines the bonus rate applied to the seize. + +### Bad-Debt Rescue + +If a liquidation completes but leaves the vault unable to repay suppliers in full, `repayBadDebt` is the path for governance or a sponsoring party to inject supply asset and transition the vault to `Matured` cleanly. Without this rescue, the vault remains in `Liquidated` and suppliers redeem against whatever the seized + remaining balance allows. + +## Events + +The events suppliers, institutions, and indexers will care about: + +| Event | Emitted by | Meaning | +| --- | --- | --- | +| `StateTransition(from, to, timestamp)` | `BaseVault` | Every state change. The canonical lifecycle hook | +| `Deposit(caller, owner, assets, shares)` | ERC-4626 standard | Supplier deposited | +| `Withdraw(caller, receiver, owner, assets, shares)` | ERC-4626 standard | Supplier redeemed | +| `CollateralDeposited(amount, total)` | `InstitutionalLoanVault` | Institution posted collateral | +| `CollateralWithdrawn(positionHolder, amount, remaining)` | `InstitutionalLoanVault` | Institution withdrew collateral | +| `RaisedFundsClaimed(amount)` | `BaseVault` | Institution claimed the raised funds | +| `Repaid(amount, remainingDebt)` | `BaseVault` | Any repayment toward `totalDebt` | +| `VaultLocked(totalRaised, lockEndTime)` | `InstitutionalLoanVault` | Vault entered `Lock` | +| `VaultFailed(totalRaised, minBorrowCap)` | `InstitutionalLoanVault` | Vault entered `Failed` | +| `MarginConfiscated(marginAmount)` | `InstitutionalLoanVault` | Failed — margin reserved for suppliers | +| `MarginCompensationClaimed(receiver, amount)` | `InstitutionalLoanVault` | Per-supplier margin payout on redeem | +| `LiquidationExecuted(liquidator, repayAmount, collateralSeized)` | `InstitutionalLoanVault` | Health-based liquidation | +| `OverdueLiquidationExecuted(settler, repayAmount, collateralSeized)` | `InstitutionalLoanVault` | Deadline-based liquidation | +| `SettlementConfirmed(settlementAmount, protocolFee, surplus)` | `BaseVault` | Settlement waterfall completed | +| `ShortfallDetected(totalOwed, available)` | `BaseVault` | Available balance < expected repayment at settlement | +| `VaultClosed(state)` | `BaseVault` | Vault terminated by governance | + +## Security Model + +### Access Boundaries + +| Surface | Gate | Notes | +| --- | --- | --- | +| Governance operations (create, open, cancel, pause, close, risk updates) | Venus AccessControlManager via `_checkAccessAllowed` on `InstitutionalVaultController` | Each function is independently gated by its selector signature | +| Institution operations (collateral, claim) | `onlyPositionHolder` on the vault — checks `positionToken.ownerOf(tokenId)` at call time | NFT transfer immediately reassigns control | +| Liquidation entrypoints on the vault | `onlyLiquidationAdapter` | Only the configured adapter address can call `liquidate` / `liquidateOverdueVault` | +| Liquidator/settler whitelists | ACM-gated `updateLiquidatorWhitelist` / `updateSettlerWhitelist` on the adapter | Separate whitelists for the two liquidation paths | +| Supplier deposits and redemptions | Permissionless | Standard ERC-4626; no allowlist | + +### Pause System + +A two-level pause governs all operations: + +* `Unpaused` (0): normal operation. +* `Partial` (1): blocks deposits, collateral operations, fund claim, and the institution's repay path. Liquidation entrypoints and supplier withdrawals remain available. +* `Complete` (2): blocks everything, including repayment and liquidation. Supplier withdrawals are still permitted via the `whenNotCompletelyPaused` guard, providing a safety valve to ensure suppliers can exit terminal-state vaults even during a complete pause. + +### Position NFT Transfer + +`InstitutionPositionToken` is a singleton ERC-721 deployed once and owned by the controller. Transfers are blocked unless governance has approved a specific recipient via `approveTransfer(tokenId, recipient)`. The approval is single-use. This prevents institutions from silently transferring control without governance review. + +### One-Shot Lifecycle + +The state machine is monotonic; no state can re-enter `Fundraising` once it has been left. This eliminates classes of issues around re-initialization, ensures that interest cannot be compounded across cycles, and keeps the per-vault accounting bounded. + +## Source + +Source contracts live in the [VenusProtocol fixed-rate-vaults repository](https://github.com/VenusProtocol/fixed-rate-vaults). diff --git a/whats-new/fixed-rate-vaults.md b/whats-new/fixed-rate-vaults.md new file mode 100644 index 0000000..5d8db53 --- /dev/null +++ b/whats-new/fixed-rate-vaults.md @@ -0,0 +1,48 @@ +# Fixed Rate Vaults + +**Fixed Rate Vaults** are a new lending product on Venus Protocol. 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 headline APY at maturity. + +## What's New + +| Component | Description | +| --- | --- | +| **BaseVault** | Abstract ERC-4626 base providing shared fundraising, interest computation, state machine, and settlement logic | +| **InstitutionalLoanVault** | Concrete vault deployed as an EIP-1167 clone per institution. Adds collateral management, fund claim, repayment, and liquidation hooks | +| **InstitutionalVaultController** | Central orchestrator. Deploys vault clones, mints position NFTs, and proxies governance operations | +| **InstitutionPositionToken** | Singleton ERC-721 representing institution ownership of a vault. One token per vault, transfer-gated by governance approval | +| **LiquidationAdapter** | Routes both health-based and overdue liquidations. Holds liquidator/settler whitelists, the global close factor, and the protocol liquidation share | + +## For Institutions + +* **Predictable borrowing cost.** The APY is fixed at vault creation. There are no variable-rate surprises over the loan term. +* **Retain collateral exposure.** You borrow against the asset without selling it, keeping your position intact if it appreciates during the loan term. +* **Known repayment from day one.** The total amount owed is calculable at lock entry, making debt service straightforward to plan. + +## For Suppliers + +* **Fixed, known yield.** The APY and lock duration are set upfront — you know exactly what you'll earn before you deposit. +* **Isolated risk.** Each vault is independent. A default in one vault has no impact on any other vault or the Venus core markets. +* **Liquid position.** Share tokens are freely transferable ERC-20s. You can transfer or sell your shares to another party. + +## How It Works + +Each vault is an independent ERC-4626 contract, deployed as a clone of the `InstitutionalLoanVault` implementation. Collateral, supplier deposits, debt, and settlement are scoped to the single vault. + +Venus deploys the vault and mints a position NFT to the institution's nominated operator. The NFT is the credential for all institution-side actions: posting collateral, claiming the raised funds, repaying, and withdrawing collateral at the end. Suppliers interact via the standard ERC-4626 interface: deposit during fundraising, then redeem once the vault reaches a terminal state. + +The lifecycle is one-shot. A vault advances monotonically through fundraising, lock, settlement, and a terminal state (matured, failed, or liquidated). There is no re-entry and no second fundraise. + +## Failure Modes + +Two paths can lead to a failed vault during fundraising: + +* **Raise shortfall.** Fundraising never crosses the minimum threshold. Suppliers receive full principal back, with no interest. The institution recovers all collateral including the margin. +* **Collateral underdelivery.** The raise succeeded but the institution didn't top up collateral in time. The margin is confiscated and distributed to suppliers as compensation. + +If the institution misses the settlement deadline after the lock period, the vault becomes liquidatable at the late-penalty rate regardless of collateral health. + +## Documentation + +* [Institution Guide](../guides/fixed-rate-vaults/institution-guide.md): walkthrough for borrowers. +* [Supplier Guide](../guides/fixed-rate-vaults/supplier-guide.md): walkthrough for lenders. +* [Fixed Rate Vaults Technical Reference](../technical-reference/reference-technical-articles/fixed-rate-vaults.md): contract architecture, math, and liquidation paths. From 8322f690bbeb9368d0326ed93a49374ac9122ad9 Mon Sep 17 00:00:00 2001 From: GitGuru7 Date: Thu, 28 May 2026 02:39:02 +0530 Subject: [PATCH 02/25] docs: improve fixed rate vaults docs --- .../assets/fixed-rate-vault-architecture.svg | 168 +++++++ .gitbook/assets/fixed-rate-vault-flow.svg | 115 +++++ .../assets/fixed-rate-vault-state-machine.svg | 182 +++++++ .../fixed-rate-vaults.md | 470 ++++++------------ whats-new/fixed-rate-vaults.md | 73 +-- 5 files changed, 661 insertions(+), 347 deletions(-) create mode 100644 .gitbook/assets/fixed-rate-vault-architecture.svg create mode 100644 .gitbook/assets/fixed-rate-vault-flow.svg create mode 100644 .gitbook/assets/fixed-rate-vault-state-machine.svg diff --git a/.gitbook/assets/fixed-rate-vault-architecture.svg b/.gitbook/assets/fixed-rate-vault-architecture.svg new file mode 100644 index 0000000..a889fd1 --- /dev/null +++ b/.gitbook/assets/fixed-rate-vault-architecture.svg @@ -0,0 +1,168 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + FIXED RATE VAULTS — CONTRACT ARCHITECTURE + + + + + + + + Liquidation + Adapter + + UPGRADEABLE + + + + + + InstitutionalVaultController + + governance surface · vault configuration · admin call proxy + UPGRADEABLE · transparent proxy + + + + + + + Institution + PositionToken + + ERC-721 + + + + + + VAULT INSTANCES + + + + + InstitutionalLoanVault + + per-loan ERC-4626 + collateral · debt · shares + + clone + + + + + + InstitutionalLoanVault + + per-loan ERC-4626 + collateral · debt · shares + + clone + + + + + + + × N + InstitutionalLoanVault + + per-loan ERC-4626 + collateral · debt · shares + + clone + + + + + + + deploys clones + + + + + mints NFT + + + + + liquidate() + + + + + ownerOf() + + diff --git a/.gitbook/assets/fixed-rate-vault-flow.svg b/.gitbook/assets/fixed-rate-vault-flow.svg new file mode 100644 index 0000000..8362c10 --- /dev/null +++ b/.gitbook/assets/fixed-rate-vault-flow.svg @@ -0,0 +1,115 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + FIXED RATE VAULT — FUND FLOW + + + + + + VAULT + ERC-4626 + + + collateral locked + debt tracked + shares issued + + + + + + + Supplier 1 + stablecoin holder + + + + + Supplier 2 + stablecoin holder + + + + + Supplier 3 + stablecoin holder + + + + + + Institution + borrower + posts collateral + + + + ① FUNDRAISING + ② LOCK + ③ SETTLEMENT + ④ MATURITY + + + + + + + + + + + deposit stablecoin + + + + ① COLLATERAL POSTED + posts collateral + + + + loan disbursed + + + + principal + interest + + + + + + + + + + + principal + yield + + diff --git a/.gitbook/assets/fixed-rate-vault-state-machine.svg b/.gitbook/assets/fixed-rate-vault-state-machine.svg new file mode 100644 index 0000000..6e10c87 --- /dev/null +++ b/.gitbook/assets/fixed-rate-vault-state-machine.svg @@ -0,0 +1,182 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + FIXED RATE VAULT — STATE MACHINE + + + + + + + WaitingForMargin + institution posts collateral margin + + + + + + MarginDeposited + governance calls openVault() + + + + + + Fundraising + suppliers deposit · institution tops up collateral + within fundraising window + + + + + + Lock + loan active · APY and totalDebt fixed + + + + + + PendingSettlement + institution repays before deadline + + + + + + SettlementDeadlineExceeded + deadline passed · debt still outstanding + + + + + + + + Failed + principal + margin returned + + + + + + Matured + suppliers redeem principal + yield + + + + + + Liquidated + settlement waterfall runs + + + + + + Closed + governance calls closeVault() + + + + + + + depositCollateral() + + + + openVault() + + + + raised ≥ minBorrowCap + + + + lockDuration elapsed + + + + totalDebt == 0 + + + + deadline + debt > 0 + + + + liquidateOverdueVault() + + + + repaid + + + + raise shortfall / + collateral underdelivery + + + + + + + + cancelVault() + (governance) + + + + + + + + + + closeVault() + + + + + LEGEND + + Normal progression + + Successful settlement + + Overdue / late path + + Failure / cancel path + + closeVault() to Closed + + + diff --git a/technical-reference/reference-technical-articles/fixed-rate-vaults.md b/technical-reference/reference-technical-articles/fixed-rate-vaults.md index d55cae4..613e5d6 100644 --- a/technical-reference/reference-technical-articles/fixed-rate-vaults.md +++ b/technical-reference/reference-technical-articles/fixed-rate-vaults.md @@ -1,421 +1,257 @@ # Fixed Rate Vaults -**Fixed Rate Vaults** are a new lending product on Venus Protocol. 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 headline APY at maturity. +A Fixed Rate 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. -The system is deployed as a clone factory. The **InstitutionalVaultController** is the orchestration surface. It deploys a fresh **InstitutionalLoanVault** clone per institution, mints a position NFT to the nominated operator, and proxies governance operations to the vault. Suppliers interact with the vault directly via the standard ERC-4626 interface. +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. -| Component | Description | -| --- | --- | -| **BaseVault** | Abstract ERC-4626 base providing shared fundraising, interest computation, state machine, settlement waterfall, and pause logic | -| **InstitutionalLoanVault** | Concrete vault deployed as an EIP-1167 clone. Extends `BaseVault` with collateral, borrowing, risk checks, and liquidation hooks | -| **InstitutionalVaultController** | Orchestrator. Deploys clones, mints position NFTs, holds the AccessControlManager reference, and proxies governance calls | -| **InstitutionPositionToken** | Non-upgradeable singleton ERC-721. One token per vault, minted to the institution's nominated operator. Transfer-gated by governance approval | -| **LiquidationAdapter** | Routes both health-based and overdue liquidations. Holds liquidator/settler whitelists, the global `closeFactor`, and the protocol liquidation share | +## Architecture ---- +### Contracts -## Architecture +The system is composed of four contracts. Each vault is an independent clone deployed by the controller — there is no shared state between loans. -The Fixed Rate Vaults system consists of four contracts plus the shared ERC-4626 base: - -| Contract | Role | -| --- | --- | -| **InstitutionalVaultController** | Central governance surface. Validates configurations, deploys vault clones, maintains the vault registry, and exposes ACM-gated admin functions. Deployed behind a transparent proxy. | -| **InstitutionalLoanVault** | Per-loan vault. Holds collateral, raised funds, and debt; enforces the state machine; exposes institution and supplier entrypoints. Deployed as a minimal EIP-1167 clone | -| **InstitutionPositionToken** | Singleton ERC-721. Mints one token per vault; gates transfers behind a single-use governance approval; provides the on-chain ownership credential for institution-side actions. Deployed once and cannot be upgraded. | -| **LiquidationAdapter** | Routes liquidation calls. Enforces liquidator/settler whitelists, calculates seize amounts using either `liquidationIncentive` (health-based) or `latePenaltyRate` (overdue), and accrues the protocol share for periodic sweeps to PSR | - -### Per-Vault Isolation - -Each vault is an entirely independent contract. Collateral, supplier deposits, debt, settlement, and risk thresholds are scoped to a single vault, so one vault cannot affect another. Even institutions running multiple loans concurrently receive a fresh clone per loan. - -| Layer | Mechanism | -| --- | --- | -| **Fund custody** | Each vault holds its own balance of the supply asset (ERC-4626 underlying) and collateral asset. | -| **State machine** | Each vault advances through its own `VaultState` independently. Lifecycle timers (`openStartTime`, `lockEndTime`, `settlementDeadline`) are recorded on the vault itself | -| **Access control** | Institution operations are gated by `onlyPositionHolder` which is checked against `positionToken.ownerOf(positionTokenId)` at call time. Governance operations are proxied through the controller and gated by Venus AccessControlManager | -| **Deterministic deployment** | Clones are deployed with `Clones.cloneDeterministic(impl, salt)` using `keccak256(institution, nonce)` as salt. Per-institution nonce ensures uniqueness across deployments | - -## State Machine - -Vault lifecycle is encoded as the `VaultState` enum (defined in `IVaultTypes.sol`). A vault advances through these states in a single direction; there is no rollback. - -```solidity -enum VaultState { - WaitingForMargin, // 0 — awaiting institution margin deposit - MarginDeposited, // 1 — margin in, awaiting governance to open - Fundraising, // 2 — suppliers depositing supply asset - InstitutionConfirmation, // 3 — reserved for subcontract use; unused here - Lock, // 4 — funds committed, interest accruing - PendingSettlement, // 5 — maturity reached, awaiting repayment - SettlementDeadlineExceeded, // 6 — deadline passed with outstanding debt - Matured, // 7 — repayment settled, shares redeemable - Failed, // 8 — fundraising shortfall or institution default - Liquidated, // 9 — bad-debt rescue path - Closed // 10 — governance delisted; all actions blocked -} -``` +
Fixed Rate Vault contract architecture diagram

The controller deploys a fresh vault clone and mints a position NFT per loan; all liquidation calls are routed through the LiquidationAdapter

-The diagram below shows how a vault moves between states, with each arrow labelled by the condition that triggers the transition. +**InstitutionalVaultController** 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. -``` - +------------------------+ - | WaitingForMargin |-- cancelVault() (governance) --+ - +-----------+------------+ | - | depositCollateral() | - | (collateral >= required margin) | - v | - +------------------------+-- cancelVault() (governance) ---+ - | MarginDeposited | | - +-----------+------------+ | - | openVault() (governance) | - v | - +------------------------+ raise short OR | - | Fundraising |--> collateral underdelivered --+ - | (suppliers supply) | | - +-----------+------------+ v - | raised >= minBorrowCap +--------+ +--------+ - | and collateral met | Failed |-- closeVault() -> | Closed | - v +--------+ +--------+ - +------------------------+ LT shortfall > 0 - | Lock |--> (health-based +------------+ +--------+ - | (borrowing) | liquidation) ---------> | Liquidated |-- closeVault() -> | Closed | - +-----------+------------+ +------------+ +--------+ - | ^ - | lockDuration elapsed | - | (repaid in full early ------> Matured) | - v | - +------------------------+ | - | PendingSettlement | | - +-----------+------------+ | - | settlementDeadline expired + debt > 0 | - | (repaid ------> Matured) | - v | - +----------------------------+ liquidateOverdueVault() | - | SettlementDeadlineExceeded |------------------------------+ - +-------------+--------------+ - | repaid - v - +---------+ - | Matured | - +----+----+ - | closeVault() (governance) - v - +--------+ - | Closed | - +--------+ -``` +**InstitutionalLoanVault** 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. -| State | Meaning | Allowed transitions | -| --- | --- | --- | -| **WaitingForMargin** | Vault deployed; institution must deposit the margin in a single transaction | → `MarginDeposited` (margin met), or → `Failed` (cancelled by governance) | -| **MarginDeposited** | Margin in. Lifecycle timelines pre-computed but not started | → `Fundraising` (via `openVault`), or → `Failed` (cancelled) | -| **Fundraising** | Suppliers deposit the supply asset; institution tops up to `idealCollateralAmount` | → `Lock` (raised ≥ minBorrowCap, collateral met), → `Failed` (raise short OR collateral underdelivered) | -| **Lock** | Funds committed; full interest fixed; institution may claim funds, repay, top up collateral | → `PendingSettlement` (lock duration elapsed), → `Matured` (repaid in full early), → `Liquidated` (HF-based liquidation completed) | -| **PendingSettlement** | Maturity reached; awaiting institution repayment | → `Matured` (debt cleared), → `SettlementDeadlineExceeded` (deadline passed with debt outstanding) | -| **SettlementDeadlineExceeded** | Deadline breached with debt outstanding. Liquidatable at late-penalty rate | → `Matured` (repaid), → `Liquidated` (overdue liquidation completed) | -| **Matured** | Settlement complete. Suppliers redeem pro-rata against `settlementAmount` | → `Closed` (governance delists) | -| **Failed** | Two sub-scenarios — see below. Suppliers redeem; institution recovers residual collateral | → `Closed` | -| **Liquidated** | Debt was cleared via liquidation. Suppliers redeem pro-rata against the leftover supply asset balance | → `Closed` | -| **Closed** | Terminal. All entrypoints revert | — | +**InstitutionPositionToken** 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`. -### Happy Path +**LiquidationAdapter** 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)`. -`WaitingForMargin` → `MarginDeposited` → `Fundraising` → `Lock` → `PendingSettlement` → `Matured` → `Closed` +### BaseVault, ERC-4626, and extensibility -### Failed Sub-Scenarios +`InstitutionalLoanVault` inherits `BaseVault`, an abstract contract built on top of ERC-4626 that was designed to be reusable across different kinds of fixed-rate 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. -The `Failed` state covers two distinct outcomes, distinguished by the `institutionDefaulted` flag in `InstitutionalRuntime`: +ERC-4626 is used as the supplier-facing API, but several methods deviate from the specification to enforce lifecycle constraints: -* **Scenario A (raise shortfall).** `totalRaised < minBorrowCap` at the end of the open window. `institutionDefaulted = false`, `confiscatedMarginRemaining = 0`. Suppliers redeem principal only; institution recovers all collateral including the margin. -* **Scenario B (collateral underdelivery).** `totalRaised ≥ minBorrowCap` but `totalCollateralDeposited < idealCollateralAmount` at the end of the open window. The margin (`idealCollateralAmount × marginRate`) is confiscated; `institutionDefaulted = true`. Suppliers redeem principal plus a pro-rata share of the confiscated margin in the collateral asset; institution recovers `totalCollateralDeposited − confiscatedMargin`. +| 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 | -## Lifecycle Parameters +`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. -All vault configuration is set once at deployment via `createVault` and cannot be changed afterwards (except `RiskConfig` fields, which are governance-mutable post-deployment). +`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. -### Shared Vault Configuration (`VaultConfig`) +### Oracle -| Field | Type | Meaning | -| --- | --- | --- | -| `supplyAsset` | `IERC20` | The loan asset suppliers deposit and the institution borrows | -| `fixedAPY` | `uint256` | Annualized interest rate. | -| `reserveFactor` | `uint256` | Protocol share of interest.| -| `minBorrowCap` | `uint256` | Minimum fundraise required to enter `Lock`. Below this, vault enters `Failed`| -| `maxBorrowCap` | `uint256` | Hard ceiling on fundraising. Deposits clamp to remaining capacity | -| `minSupplierDeposit` | `uint256` | Floor for a single deposit. Waived only when filling the final residual capacity | -| `openDuration` | `uint40` | Length of the fundraising window in seconds | -| `lockDuration` | `uint40` | Length of the locked-loan period in seconds. Used to compute total interest | -| `settlementWindow` | `uint40` | Grace period after lock end before the vault becomes overdue | - -### Institutional Configuration (`InstitutionalConfig`) - -| Field | Type | Meaning | -| --- | --- | --- | -| `collateralAsset` | `IERC20` | Asset the institution posts as collateral | -| `idealCollateralAmount` | `uint256` | Target collateral the institution should post. Computed off-chain by applying a collateral factor to `maxBorrowCap` | -| `marginRate` | `uint256` | Margin percentage of `idealCollateralAmount`. | -| `institutionOperator` | `address` | Initial recipient of the position NFT | -| `positionTokenId` | `uint256` | NFT id assigned at vault creation | +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`. -### Risk Configuration (`RiskConfig`) +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. -| Field | Type | Meaning | Mutable | -| --- | --- | --- | --- | -| `liquidationThreshold` | `uint256` | Maximum debt-to-collateral ratio before liquidation. | Yes | -| `liquidationIncentive` | `uint256` | Health-based liquidator bonus. | Yes | -| `latePenaltyRate` | `uint256` | Overdue liquidation bonus. Same range as `liquidationIncentive` | Yes | +## State machine -All risk parameter updates flow through `InstitutionalVaultController.setLiquidationThreshold` / `setLiquidationIncentive` / `setLatePenaltyRate`, each gated by AccessControlManager. +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. +
Fixed Rate Vault state machine diagram

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 closeVault()

-## Function Reference +## Core mechanics -### Governance (on `InstitutionalVaultController`) +### Margin deposit -All controller entrypoints are gated by Venus AccessControlManager via the `_checkAccessAllowed` modifier. +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: -| Function | Effect | -| --- | --- | -| `createVault(...)` | Deploys a fresh `InstitutionalLoanVault` clone, mints the position NFT, registers the vault, and applies its `VaultConfig` / `InstitutionalConfig` / `RiskConfig`. Vault starts in `WaitingForMargin`. Emits `VaultCreated` | -| `openVault(vault)` | `MarginDeposited` → `Fundraising`; fixes all lifecycle timers | -| `cancelVault(vault)` | Cancels a pre-launch vault (`WaitingForMargin` / `MarginDeposited`) and refunds all collateral, including the margin; transitions to `Failed` with `institutionDefaulted = false` | -| `approvePositionTransfer(vault, recipient)` / `revokePositionTransfer(vault)` | Grant or revoke a single-use approval for a position-NFT transfer | -| `partialPauseVault` / `completePauseVault` / `unpauseVault` | Two-level pause control — see [Pause System](#pause-system) under Security Model | -| `closeVault(vault)` | Terminal: transitions a settled vault to `Closed` | -| `setLiquidationThreshold` / `setLiquidationIncentive` / `setLatePenaltyRate` | Update the mutable `RiskConfig` fields post-deployment | +$$\text{requiredMargin} = \text{idealCollateralAmount} \times \frac{\text{marginRate}}{10^{18}}$$ -### Institution (on the vault) +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. -The `onlyPositionHolder` modifier checks `positionToken.ownerOf(positionTokenId) == msg.sender` at call time. Transferring the NFT immediately transfers control of these functions. +### Fundraising -#### depositCollateral +`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. -```solidity -function depositCollateral(uint256 amount) external; -``` +At `fundraisingEndTime` both sides are evaluated simultaneously. If `totalRaised ≥ minBorrowCap` and `totalCollateralDeposited ≥ idealCollateralAmount` the vault transitions to `Lock` and the loan begins. -Pulls the collateral asset from the caller. Allowed in `WaitingForMargin`, `Fundraising`, and `Lock`. In `WaitingForMargin`, the deposit must bring `totalCollateralDeposited` to at least `idealCollateralAmount × marginRate` in a single transaction. Partial deposits below the margin threshold revert with `InsufficientCollateral`. On success in `WaitingForMargin`, the vault transitions to `MarginDeposited`. Emits `CollateralDeposited(amount, totalCollateralDeposited)`. +If either condition is not met, the vault transitions to `Failed`. Two distinct failure modes are possible, distinguished by `InstitutionalRuntime.institutionDefaulted`: -#### withdrawCollateral +**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. -```solidity -function withdrawCollateral(uint256 amount) external; -``` +**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`: -Releases collateral to the caller. Allowed in `Lock`, `Matured`, and `Failed`; blocked in all other states. During `Lock`, two checks gate the call: +$$\text{requiredMargin} = \text{idealCollateralAmount} \times \frac{\text{marginRate}}{10^{18}}$$ -1. **Floor check.** `totalCollateralDeposited − amount ≥ minimumCollateralRequired`, where the floor is recalculated at Lock entry as `idealCollateralAmount × totalRaised / maxBorrowCap`. Withdrawals cannot touch the locked portion. -2. **LT health check.** `_getHypotheticalVaultLiquidity(amount, 0)` simulates the post-withdrawal balance; if it would breach the liquidation threshold, the call reverts with `WithdrawalWouldBreachLT`. +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`. -In `Failed` (`institutionDefaulted = true`), the withdrawable amount is capped at `totalCollateralDeposited − confiscatedMarginRemaining`. +#### Margin confiscation: collateral underdelivery -#### claimRaisedFunds +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: -```solidity -function claimRaisedFunds() external; -``` +$$\text{compensation} = \text{confiscatedMarginRemaining} \times \frac{\text{shares}}{\text{totalSupplyBeforeBurn}}$$ -One-shot transfer of the entire raised supply asset balance to the caller. Allowed only in `Lock`, gated by `fundsWithdrawn` (set true on success). Pre-call health check: simulating the resulting debt (`_runtime.totalRaised`) against current collateral must not produce a shortfall, otherwise reverts with `ClaimWouldBreachLT`. Emits `RaisedFundsClaimed(amount)`. +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. -#### repay +### Lock entry and borrowing -```solidity -function repay(uint256 amount) external; -``` +When the vault transitions to `Lock`, two values are fixed for the lifetime of the loan: -Anyone can call. Pulls supply asset from the caller and reduces `totalDebt`. Allowed in `Lock`, `PendingSettlement`, and `SettlementDeadlineExceeded`. Overpayment is automatically clamped to `outstandingDebt`. Emits `Repaid(amount, remainingDebt)`. +**Total interest** is stored immediately as `totalDebt` and is owed in full regardless of when the institution repays — there is no early-repayment discount: -### Supplier (on the vault, ERC-4626 interface) +$$\text{totalInterest} = \frac{\text{totalRaised} \times \text{fixedAPY} \times \text{lockDuration}}{\text{BPS} \times \text{YEAR}}$$ -All supplier functions are permissionless. Anyone can supply. +`BPS = 10000`, `YEAR = 365 days`. `totalDebt = totalInterest` at lock entry; after `claimRaisedFunds` it becomes `totalInterest + totalRaised`. -```solidity -function deposit(uint256 assets, address receiver) external returns (uint256 shares); -function mint(uint256 shares, address receiver) external returns (uint256 assets); -function withdraw(uint256 assets, address receiver, address owner) external returns (uint256 shares); -function redeem(uint256 shares, address receiver, address owner) external returns (uint256 assets); -``` +**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`: -* `deposit` and `mint` are allowed only in `Fundraising`. Both clamp to remaining capacity (`maxBorrowCap − totalRaised`); exceeding capacity does not revert unless capacity is zero, in which case `ExceedsMaxCap` is raised. `minSupplierDeposit` is enforced unless the deposit fills the final residual slot. +$$\text{minimumCollateralRequired} = \text{idealCollateralAmount} \times \frac{\text{totalRaised}}{\text{maxBorrowCap}}$$ -* `withdraw` and `redeem` are allowed in `Matured`, `Failed`, and `Liquidated` only. Both follow standard ERC-4626 semantics, computing the supply-asset payout from `settlementAmount` and `totalSupply()`. In `Failed`, the `_afterWithdrawHook` additionally transfers a pro-rata slice of the confiscated margin in the collateral asset. +#### Claiming raised funds -Shares are standard ERC-20s, freely transferable at all times. Suppliers track their position through the share balance, not through any per-user NFT. +`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. -### Liquidator (via `LiquidationAdapter`) +After a successful claim, `totalDebt = totalInterest + totalRaised` — the full lifetime obligation. -Two liquidation paths exist on the vault, each gated by the `onlyLiquidationAdapter` modifier: +#### Repaying -```solidity -function liquidate(uint256 repayAmount) external returns (uint256 actualRepay); -function liquidateOverdueVault(uint256 repayAmount) external returns (uint256 actualRepay); -``` +`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()`. -* `liquidate` (health-based) requires a current LT shortfall. Allowed in `Lock`, `PendingSettlement`, or `SettlementDeadlineExceeded`. The liquidator (via the adapter) repays up to `min(repayAmount, outstandingDebt × closeFactor)` and seizes collateral at the `liquidationIncentive` rate. +#### Collateral during Lock -* `liquidateOverdueVault` (deadline-based) requires the vault to be in `SettlementDeadlineExceeded`. No collateral shortfall is required; the time breach alone qualifies. Seize amount is computed at the `latePenaltyRate`. +The institution may add or withdraw collateral during `Lock`. Withdrawal requires both checks to pass: -In both cases, seized collateral is split between the caller and the protocol per `LiquidationAdapter.protocolLiquidationShare`; the protocol share is accrued inside the adapter and periodically swept to PSR via `sweepProtocolShareToReserve`. +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. -### Read-Only Views +The tighter of the two determines how much can be withdrawn. -```solidity -function state() external view returns (VaultState); -function config() external view returns (VaultConfig memory); // BaseVault — shared config -function runtime() external view returns (VaultRuntime memory); // BaseVault — shared runtime -function institutionalConfig() external view returns (InstitutionalConfig memory); -function institutionalRuntime() external view returns (InstitutionalRuntime memory); -function riskConfig() external view returns (RiskConfig memory); -function outstandingDebt() external view returns (uint256); -function totalAssets() external view returns (uint256); -function maxDeposit(address) external view returns (uint256); -function maxWithdraw(address) external view returns (uint256); -function maxRedeem(address) external view returns (uint256); -function previewDeposit(uint256) external view returns (uint256); -function previewRedeem(uint256) external view returns (uint256); -``` +### Settlement window -`totalAssets()` returns `totalRaised` until shares become redeemable. Once the vault settles (`Matured`, `Failed`, or `Liquidated`) it returns `settlementAmount`. +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`. -## Math +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)). -### Required Margin +### Settlement waterfall -The margin the institution must deposit to advance from `WaitingForMargin` to `MarginDeposited`: +On entry to `Matured` or `Liquidated`, `_settleProtocolShare` runs once and distributes the supply asset balance: -$$ -\text{requiredMargin} = \text{idealCollateralAmount} \times \frac{\text{marginRate}}{10^{18}} -$$ +| 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` | -### Minimum Collateral Floor (at Lock Entry) +Surplus above `totalRaised + totalInterest` is forwarded to PSR. `ShortfallDetected(expected, available)` fires in the shortfall branches. -When the vault transitions to `Lock`, the locked-collateral floor is recalculated proportionally to the actual raise: +`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{minimumCollateralRequired} = \text{idealCollateralAmount} \times \frac{\text{totalRaised}}{\text{maxBorrowCap}} -$$ +$$\text{payout} = \text{shares} \times \frac{\text{settlementAmount}}{\text{totalSupply}}$$ -This frees the excess collateral above the floor for withdrawal during `Lock` when the raise underfills the cap. +### Liquidation -### Total Interest +#### Health factor -Fixed interest is computed once at Lock entry and is owed in full at maturity, regardless of when the institution repays: +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{totalInterest} = \frac{\text{totalRaised} \times \text{fixedAPY} \times \text{lockDuration}}{\text{BPS} \times \text{YEAR}} -$$ +$$\text{LT-cap} = \frac{\text{collateralUSD} \times \text{liquidationThreshold}}{10^{18}}$$ -Where `BPS = 10000` and `YEAR = 365 days`. The result is stored as `totalDebt` at Lock entry; `claimRaisedFunds` adds `totalRaised` to `totalDebt`. +$$\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}$$ -### Protocol Fee at Settlement +`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. -`_settleProtocolShare` runs the settlement waterfall once on entry to `Matured` or `Liquidated`. Three branches: +#### Seize calculation and Compound V2 lineage -| Branch | Condition | Protocol fee | Settlement amount | -| --- | --- | --- | --- | -| **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` | +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. -Any surplus above `totalRaised + totalInterest` is also forwarded to PSR. `ShortfallDetected(expected, available)` fires in the partial and principal-shortfall branches. +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: -### Per-Supplier Payout +``` +repayEquivalent = totalSeized × MANTISSA_ONE / incentive +incentiveAmount = totalSeized − repayEquivalent +protocolAmount = incentiveAmount × protocolLiquidationShare / MANTISSA_ONE +callerAmount = totalSeized − protocolAmount +``` -Standard ERC-4626 pro-rata against the post-settlement `settlementAmount`: +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. -$$ -\text{payout} = \text{shares} \times \frac{\text{settlementAmount}}{\text{totalSupply}} -$$ +#### Health-based -### Margin Compensation per Redeem +Available in `Lock`, `PendingSettlement`, and `SettlementDeadlineExceeded` when the vault has a non-zero shortfall (see [Health factor](#health-factor) above). -When the institution defaults on collateral delivery, the margin is distributed pro-rata to suppliers as they redeem: +Whitelisted liquidators call `LiquidationAdapter.liquidate(vault, repayAmount)`. The adapter verifies the shortfall and forwards to `vault.liquidate(repayAmount)` through the `onlyLiquidationAdapter` modifier. Inside the vault, `_executeLiquidation` enforces the close factor: if `repayAmount > outstandingDebt × closeFactor` the call reverts with `ExceedsCloseFactor` — it is a hard revert, not a silent cap. Seized collateral is split between the caller and the protocol per the formula above. -$$ -\text{compensation} = \text{confiscatedMarginRemaining} \times \frac{\text{shares}}{\text{totalSupplyBeforeBurn}} -$$ +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. -Compensation is paid in the collateral asset, not the supply asset. Integer division means the last supplier to redeem may receive a marginally smaller compensation than the proportional share suggests; the dust amount is negligible in practice. +#### Overdue -## Liquidation +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`. -### Standard (Health-Based) Liquidation +#### Bad-debt rescue -Triggered when the vault's debt exceeds its LT-capped collateral value. The liquidator (whitelisted on `LiquidationAdapter`) repays up to a fraction of the outstanding debt, capped by the global `closeFactor`, and seizes collateral at the `liquidationIncentive` rate. +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. -* **Eligibility**: the vault has a non-zero shortfall. -* **Allowed states**: `Lock`, `PendingSettlement`, `SettlementDeadlineExceeded`. -* **Repay cap**: `min(repayAmount, outstandingDebt × closeFactor)`. `closeFactor` lives on `LiquidationAdapter`, shared across all vaults. -* **Seize amount**: computed from oracle-priced collateral and the supply asset, scaled by `liquidationIncentive`. +## Risk parameters -When the resulting repayment clears the debt, the vault transitions to `Matured` if collateral remains, or to `Liquidated` if the settlement is bad-debt (collateral insufficient to fully cover principal + interest). +All tunable parameters grouped by contract, mutability, and who sets them. -### Overdue (Deadline-Based) Liquidation +**Set once at vault creation via `createVault` — fixed for the life of the vault:** -Triggered when the settlement deadline passes with debt outstanding, irrespective of collateral health. +| 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 | +| Fixed APY | `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` | -* **Eligibility**: `state == SettlementDeadlineExceeded` and `outstandingDebt > 0`. -* **No collateral shortfall required.** The time breach alone qualifies. -* **Seize amount**: scaled by `latePenaltyRate` instead of `liquidationIncentive`. +**Held on `LiquidationAdapter` — global across all vaults, mutable by governance:** -A vault that breaches both the LT cap **and** the settlement deadline can be liquidated through either path; the chosen path determines the bonus rate applied to the seize. +| Parameter | Field | Constraint | +| --- | --- | --- | +| Close factor | `closeFactor` | 0 < CF ≤ `1e18` | +| Protocol liquidation share | `protocolLiquidationShare` | ≤ `1e18` | -### Bad-Debt Rescue +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. -If a liquidation completes but leaves the vault unable to repay suppliers in full, `repayBadDebt` is the path for governance or a sponsoring party to inject supply asset and transition the vault to `Matured` cleanly. Without this rescue, the vault remains in `Liquidated` and suppliers redeem against whatever the seized + remaining balance allows. +## Governance and access control -## Events +### Pause system -The events suppliers, institutions, and indexers will care about: +A two-level pause is controlled by governance via `partialPauseVault` / `completePauseVault`: -| Event | Emitted by | Meaning | -| --- | --- | --- | -| `StateTransition(from, to, timestamp)` | `BaseVault` | Every state change. The canonical lifecycle hook | -| `Deposit(caller, owner, assets, shares)` | ERC-4626 standard | Supplier deposited | -| `Withdraw(caller, receiver, owner, assets, shares)` | ERC-4626 standard | Supplier redeemed | -| `CollateralDeposited(amount, total)` | `InstitutionalLoanVault` | Institution posted collateral | -| `CollateralWithdrawn(positionHolder, amount, remaining)` | `InstitutionalLoanVault` | Institution withdrew collateral | -| `RaisedFundsClaimed(amount)` | `BaseVault` | Institution claimed the raised funds | -| `Repaid(amount, remainingDebt)` | `BaseVault` | Any repayment toward `totalDebt` | -| `VaultLocked(totalRaised, lockEndTime)` | `InstitutionalLoanVault` | Vault entered `Lock` | -| `VaultFailed(totalRaised, minBorrowCap)` | `InstitutionalLoanVault` | Vault entered `Failed` | -| `MarginConfiscated(marginAmount)` | `InstitutionalLoanVault` | Failed — margin reserved for suppliers | -| `MarginCompensationClaimed(receiver, amount)` | `InstitutionalLoanVault` | Per-supplier margin payout on redeem | -| `LiquidationExecuted(liquidator, repayAmount, collateralSeized)` | `InstitutionalLoanVault` | Health-based liquidation | -| `OverdueLiquidationExecuted(settler, repayAmount, collateralSeized)` | `InstitutionalLoanVault` | Deadline-based liquidation | -| `SettlementConfirmed(settlementAmount, protocolFee, surplus)` | `BaseVault` | Settlement waterfall completed | -| `ShortfallDetected(totalOwed, available)` | `BaseVault` | Available balance < expected repayment at settlement | -| `VaultClosed(state)` | `BaseVault` | Vault terminated by governance | - -## Security Model - -### Access Boundaries - -| Surface | Gate | Notes | +| Level | Blocked | Live | | --- | --- | --- | -| Governance operations (create, open, cancel, pause, close, risk updates) | Venus AccessControlManager via `_checkAccessAllowed` on `InstitutionalVaultController` | Each function is independently gated by its selector signature | -| Institution operations (collateral, claim) | `onlyPositionHolder` on the vault — checks `positionToken.ownerOf(tokenId)` at call time | NFT transfer immediately reassigns control | -| Liquidation entrypoints on the vault | `onlyLiquidationAdapter` | Only the configured adapter address can call `liquidate` / `liquidateOverdueVault` | -| Liquidator/settler whitelists | ACM-gated `updateLiquidatorWhitelist` / `updateSettlerWhitelist` on the adapter | Separate whitelists for the two liquidation paths | -| Supplier deposits and redemptions | Permissionless | Standard ERC-4626; no allowlist | - -### Pause System +| **Partial** | `deposit`, `mint`, `depositCollateral`, `claimRaisedFunds` | `repay`, `liquidate`, `withdraw`, `redeem` | +| **Complete** | All vault interactions | — | -A two-level pause governs all operations: +By design, governance can freeze new supply and collateral operations without interrupting active debt service or liquidations. -* `Unpaused` (0): normal operation. -* `Partial` (1): blocks deposits, collateral operations, fund claim, and the institution's repay path. Liquidation entrypoints and supplier withdrawals remain available. -* `Complete` (2): blocks everything, including repayment and liquidation. Supplier withdrawals are still permitted via the `whenNotCompletelyPaused` guard, providing a safety valve to ensure suppliers can exit terminal-state vaults even during a complete pause. +### Position NFT -### Position NFT Transfer +`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. -`InstitutionPositionToken` is a singleton ERC-721 deployed once and owned by the controller. Transfers are blocked unless governance has approved a specific recipient via `approveTransfer(tokenId, recipient)`. The approval is single-use. This prevents institutions from silently transferring control without governance review. +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. -### One-Shot Lifecycle +### ACM permissions -The state machine is monotonic; no state can re-enter `Fundraising` once it has been left. This eliminates classes of issues around re-initialization, ensures that interest cannot be compounded across cycles, and keeps the per-vault accounting bounded. +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. -## Source +## Further reading -Source contracts live in the [VenusProtocol fixed-rate-vaults repository](https://github.com/VenusProtocol/fixed-rate-vaults). +- [Supplier Guide](../../guides/fixed-rate-vaults/supplier-guide.md) +- [Institution Guide](../../guides/fixed-rate-vaults/institution-guide.md) +- [Repository](https://github.com/VenusProtocol/fixed-rate-vaults) diff --git a/whats-new/fixed-rate-vaults.md b/whats-new/fixed-rate-vaults.md index 5d8db53..67fd82c 100644 --- a/whats-new/fixed-rate-vaults.md +++ b/whats-new/fixed-rate-vaults.md @@ -1,48 +1,61 @@ # Fixed Rate Vaults -**Fixed Rate Vaults** are a new lending product on Venus Protocol. 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 headline APY at maturity. +Venus Protocol is introducing a new way to earn and borrow: **Fixed Rate Vaults**. -## What's New +Instead of the variable rates and shared liquidity pools of Venus core markets, Fixed Rate 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 fixed APY, and get their principal back at maturity. No rate fluctuations, no surprises — just a clear term with a clear outcome. -| Component | Description | -| --- | --- | -| **BaseVault** | Abstract ERC-4626 base providing shared fundraising, interest computation, state machine, and settlement logic | -| **InstitutionalLoanVault** | Concrete vault deployed as an EIP-1167 clone per institution. Adds collateral management, fund claim, repayment, and liquidation hooks | -| **InstitutionalVaultController** | Central orchestrator. Deploys vault clones, mints position NFTs, and proxies governance operations | -| **InstitutionPositionToken** | Singleton ERC-721 representing institution ownership of a vault. One token per vault, transfer-gated by governance approval | -| **LiquidationAdapter** | Routes both health-based and overdue liquidations. Holds liquidator/settler whitelists, the global close factor, and the protocol liquidation share | +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. -## For Institutions +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. -* **Predictable borrowing cost.** The APY is fixed at vault creation. There are no variable-rate surprises over the loan term. -* **Retain collateral exposure.** You borrow against the asset without selling it, keeping your position intact if it appreciates during the loan term. -* **Known repayment from day one.** The total amount owed is calculable at lock entry, making debt service straightforward to plan. +
Fixed Rate Vault fund flow diagram

Suppliers deposit stablecoin into the vault, the institution receives the loan and repays with interest, and suppliers redeem principal plus yield at maturity

-## For Suppliers +## How a Vault Progresses -* **Fixed, known yield.** The APY and lock duration are set upfront — you know exactly what you'll earn before you deposit. -* **Isolated risk.** Each vault is independent. A default in one vault has no impact on any other vault or the Venus core markets. -* **Liquid position.** Share tokens are freely transferable ERC-20s. You can transfer or sell your shares to another party. +
Fixed Rate Vault state machine diagram

Fixed Rate Vault state transitions

-## How It Works +Every vault follows the same journey from creation to close. States move in one direction only — there's no going back. -Each vault is an independent ERC-4626 contract, deployed as a clone of the `InstitutionalLoanVault` implementation. Collateral, supplier deposits, debt, and settlement are scoped to the single vault. +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 deposit. 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. -Venus deploys the vault and mints a position NFT to the institution's nominated operator. The NFT is the credential for all institution-side actions: posting collateral, claiming the raised funds, repaying, and withdrawing collateral at the end. Suppliers interact via the standard ERC-4626 interface: deposit during fundraising, then redeem once the vault reaches a terminal state. +## Participants -The lifecycle is one-shot. A vault advances monotonically through fundraising, lock, settlement, and a terminal state (matured, failed, or liquidated). There is no re-entry and no second fundraise. +### Suppliers -## Failure Modes +Fixed Rate Vaults are designed to give lenders certainty: -Two paths can lead to a failed vault during fundraising: +- **You know your yield upfront.** The APY and lock duration are fixed before fundraising opens — there's nothing to guess or monitor. +- **Collateral is posted before you can deposit.** 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. -* **Raise shortfall.** Fundraising never crosses the minimum threshold. Suppliers receive full principal back, with no interest. The institution recovers all collateral including the margin. -* **Collateral underdelivery.** The raise succeeded but the institution didn't top up collateral in time. The margin is confiscated and distributed to suppliers as compensation. +### Institutions -If the institution misses the settlement deadline after the lock period, the vault becomes liquidatable at the late-penalty rate regardless of collateral health. +Fixed Rate Vaults give borrowers control over their cost of capital: -## Documentation +- **Predictable cost.** The APY 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. -* [Institution Guide](../guides/fixed-rate-vaults/institution-guide.md): walkthrough for borrowers. -* [Supplier Guide](../guides/fixed-rate-vaults/supplier-guide.md): walkthrough for lenders. -* [Fixed Rate Vaults Technical Reference](../technical-reference/reference-technical-articles/fixed-rate-vaults.md): contract architecture, math, and liquidation paths. +## Liquidations + +Fixed Rate 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.md) — step-by-step walkthrough for lenders. +- [Institution Guide](../guides/fixed-rate-vaults/institution-guide.md) — step-by-step walkthrough for borrowers. +- [Fixed Rate Vaults Technical Reference](../technical-reference/reference-technical-articles/fixed-rate-vaults.md) — contract architecture, math, and liquidation paths in full detail. From 4f1616093634ecad54eee8ce3987103bbffa903d Mon Sep 17 00:00:00 2001 From: GitGuru7 Date: Thu, 28 May 2026 09:04:23 +0530 Subject: [PATCH 03/25] docs: add Solidity API reference for Fixed Rate Vaults --- SUMMARY.md | 6 + .../reference-fixed-rate-vaults/README.md | 13 + .../reference-fixed-rate-vaults/base-vault.md | 549 ++++++++++++++ .../institution-position-token.md | 165 +++++ .../institutional-loan-vault.md | 639 +++++++++++++++++ .../institutional-vault-controller.md | 675 ++++++++++++++++++ .../liquidation-adapter.md | 320 +++++++++ .../fixed-rate-vaults.md | 11 +- whats-new/fixed-rate-vaults.md | 1 + 9 files changed, 2374 insertions(+), 5 deletions(-) create mode 100644 technical-reference/reference-fixed-rate-vaults/README.md create mode 100644 technical-reference/reference-fixed-rate-vaults/base-vault.md create mode 100644 technical-reference/reference-fixed-rate-vaults/institution-position-token.md create mode 100644 technical-reference/reference-fixed-rate-vaults/institutional-loan-vault.md create mode 100644 technical-reference/reference-fixed-rate-vaults/institutional-vault-controller.md create mode 100644 technical-reference/reference-fixed-rate-vaults/liquidation-adapter.md diff --git a/SUMMARY.md b/SUMMARY.md index 4f44fe6..3a8b233 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -153,6 +153,12 @@ * [MaxLoopsLimitHelper](technical-reference/reference-isolated-pools/utility/max-loops-limit-helper.md) * [ErrorReporter](technical-reference/reference-isolated-pools/utility/error-reporter.md) * [ExponentialNoError](technical-reference/reference-isolated-pools/utility/exponential-no-error.md) +* [Fixed Rate Vaults](technical-reference/reference-fixed-rate-vaults/README.md) + * [InstitutionalVaultController](technical-reference/reference-fixed-rate-vaults/institutional-vault-controller.md) + * [InstitutionalLoanVault](technical-reference/reference-fixed-rate-vaults/institutional-loan-vault.md) + * [LiquidationAdapter](technical-reference/reference-fixed-rate-vaults/liquidation-adapter.md) + * [InstitutionPositionToken](technical-reference/reference-fixed-rate-vaults/institution-position-token.md) + * [BaseVault](technical-reference/reference-fixed-rate-vaults/base-vault.md) * [Oracle](technical-reference/reference-oracle/README.md) * [ResilientOracle](technical-reference/reference-oracle/resilient-oracle.md) * [DeviationBoundedOracle](technical-reference/reference-oracle/deviation-bounded-oracle.md) diff --git a/technical-reference/reference-fixed-rate-vaults/README.md b/technical-reference/reference-fixed-rate-vaults/README.md new file mode 100644 index 0000000..c217f61 --- /dev/null +++ b/technical-reference/reference-fixed-rate-vaults/README.md @@ -0,0 +1,13 @@ +# Fixed Rate Vaults + +Solidity API reference for the Fixed Rate Vault system, generated from NatSpec. + +The system has three singleton contracts, one vault implementation contract (cloned per loan by the controller), and one abstract base: + +| Contract | Description | +| --- | --- | +| [InstitutionalVaultController](institutional-vault-controller.md) | Factory and governance proxy. Deploys vault clones, maintains the registry, and proxies all ACM-gated lifecycle calls. | +| [InstitutionalLoanVault](institutional-loan-vault.md) | Core execution contract for a single loan. Holds collateral and supply assets, enforces the state machine, and exposes ERC-4626 supplier and institution-side entry points. | +| [LiquidationAdapter](liquidation-adapter.md) | The sole address permitted to call `vault.liquidate()`. Manages liquidator/settler whitelists, enforces the close factor, and splits seized collateral between the caller and the protocol. | +| [InstitutionPositionToken](institution-position-token.md) | Singleton ERC-721. One token per vault; the holder controls all institution-side operations on that vault. | +| [BaseVault](base-vault.md) | Abstract base inherited by `InstitutionalLoanVault`. Provides shared ERC-4626 mechanics, fundraising, interest computation, settlement waterfall, and the pause system. | diff --git a/technical-reference/reference-fixed-rate-vaults/base-vault.md b/technical-reference/reference-fixed-rate-vaults/base-vault.md new file mode 100644 index 0000000..1701a16 --- /dev/null +++ b/technical-reference/reference-fixed-rate-vaults/base-vault.md @@ -0,0 +1,549 @@ +# BaseVault + +**Inherits:** ERC4626Upgradeable, ReentrancyGuardUpgradeable + +**Title:** BaseVault + +Abstract base ERC-4626 vault providing shared mechanics for all Venus fixed-rate vault types: +fundraising (time-bounded deposit window), interest computation, settlement (protocol fee waterfall), +and core state machine transitions. + +Subcontracts ([InstitutionalLoanVault](institutional-loan-vault.md)) inherit this and add type-specific logic. +Deployed as EIP-1167 minimal proxy clones by the respective VaultController. + +## Solidity API + +## State Variables + +### BPS + +```solidity +uint256 public constant BPS = 10_000 +``` + +### MANTISSA_ONE + +```solidity +uint256 public constant MANTISSA_ONE = 1e18 +``` + +### YEAR + +```solidity +uint256 public constant YEAR = 365 days +``` + +### _config + +Immutable vault configuration set at initialization. + +```solidity +VaultConfig internal _config +``` + +### _runtime + +Runtime state that changes during the vault lifecycle. + +```solidity +VaultRuntime internal _runtime +``` + +### vaultController + +VaultController address — set to msg.sender during initialize. + +```solidity +address public vaultController +``` + +### pauseLevel + +Current pause level (Unpaused, Partial, Complete). + +```solidity +PauseLevel public pauseLevel +``` + +## Functions + +### onlyController + +Reverts if caller is not the VaultController. + +```solidity +modifier onlyController(); +``` + +### whenNotPaused + +Reverts on any pause level (Partial or Complete). Used for general operations. + +```solidity +modifier whenNotPaused(); +``` + +### whenNotCompletelyPaused + +Reverts only on Complete pause. Repay and liquidation remain available during Partial pause. + +```solidity +modifier whenNotCompletelyPaused(); +``` + +### closeVault + +Transitions vault to Closed state. All operations are blocked after this point. +Governance should only call this once all suppliers have withdrawn their funds. + +**Notes:** +- error: InvalidState If vault is not in a terminal state (Matured/Failed/Liquidated). +- event: StateTransition Emitted for the terminal state -> Closed transition. +- event: VaultClosed Emitted with the previous terminal state. + +```solidity +function closeVault() external onlyController; +``` + +### partialPause + +Partial pause — blocks general operations (deposits, collateral, borrowing). +Repay and liquidation remain available so positions can still be defended/resolved. + +**Note:** event: PauseLevelSet + +```solidity +function partialPause() external onlyController; +``` + +### completePause + +Complete pause — blocks all operations including repay and liquidation. + +**Note:** event: PauseLevelSet + +```solidity +function completePause() external onlyController; +``` + +### unpause + +Removes all pause restrictions. + +**Note:** event: PauseLevelSet + +```solidity +function unpause() external onlyController; +``` + +### sweep + +Recovers any tokens stuck in the vault. Full balance is transferred. + +**Notes:** +- error: NothingToSweep If the token balance is zero. +- event: TokensSwept + +```solidity +function sweep(address token) external onlyController; +``` + +**Parameters** + +| Name | Type | Description | +| ---- | ---- | ----------- | +| `token` | `address` | Token address to sweep. | + +### updateVaultState + +Permissionless vault finalizer. Triggers state transitions and settlement. + +```solidity +function updateVaultState() external; +``` + +### outstandingDebt + +Total remaining debt. Decremented by repayments; zero when fully repaid. + +```solidity +function outstandingDebt() external view returns (uint256); +``` + +**Returns** + +| Name | Type | Description | +| ---- | ---- | ----------- | +| `` | `uint256` | Outstanding debt in supply asset units. | + +### config + +Returns the vault configuration. + +```solidity +function config() external view returns (VaultConfig memory); +``` + +**Returns** + +| Name | Type | Description | +| ---- | ---- | ----------- | +| `` | `VaultConfig` | Immutable VaultConfig struct set at initialization. | + +### runtime + +Returns the runtime state. + +```solidity +function runtime() external view returns (VaultRuntime memory); +``` + +**Returns** + +| Name | Type | Description | +| ---- | ---- | ----------- | +| `` | `VaultRuntime` | Mutable VaultRuntime struct tracking lifecycle progress. | + +### state + +Current vault lifecycle state. + +```solidity +function state() external view returns (VaultState); +``` + +**Returns** + +| Name | Type | Description | +| ---- | ---- | ----------- | +| `` | `VaultState` | Current VaultState enum value. | + +### deposit + +Deposits supply assets during the Fundraising window. +Clamps to remaining capacity instead of reverting on excess. + +**Notes:** +- error: InvalidState If vault is not in Fundraising state. +- error: ExceedsMaxCap If clamped deposit amount is zero (vault at capacity). + +```solidity +function deposit(uint256 assets, address receiver) public override returns (uint256 shares); +``` + +**Parameters** + +| Name | Type | Description | +| ---- | ---- | ----------- | +| `assets` | `uint256` | Requested deposit amount in supply asset units. | +| `receiver` | `address` | Address to receive minted shares. | + +**Returns** + +| Name | Type | Description | +| ---- | ---- | ----------- | +| `shares` | `uint256` | Actual shares minted (may be less than requested if cap approached). | + +### mint + +Mints shares during the Fundraising window. +Clamps to remaining capacity instead of reverting on excess. + +**Notes:** +- error: InvalidState If vault is not in Fundraising state. +- error: ExceedsMaxCap If clamped share amount is zero (vault at capacity). + +```solidity +function mint(uint256 shares, address receiver) public override returns (uint256 assets); +``` + +**Parameters** + +| Name | Type | Description | +| ---- | ---- | ----------- | +| `shares` | `uint256` | Requested shares to mint. | +| `receiver` | `address` | Address to receive minted shares. | + +**Returns** + +| Name | Type | Description | +| ---- | ---- | ----------- | +| `assets` | `uint256` | Actual supply assets pulled (may be less than requested if cap approached). | + +### withdraw + +Withdraws supply assets in terminal states. +Advances state before checking max, enabling single-tx withdrawals +when the vault is ready to transition (e.g. PendingSettlement -> Matured). + +**Notes:** +- error: InvalidState If vault is not in a terminal state (Matured/Failed/Liquidated). +- error: ExceedsMaxCap If requested assets exceed the caller's withdrawable balance. + +```solidity +function withdraw( + uint256 assets, + address receiver, + address owner +) public override returns (uint256 shares); +``` + +**Parameters** + +| Name | Type | Description | +| ---- | ---- | ----------- | +| `assets` | `uint256` | Amount of supply assets to withdraw. | +| `receiver` | `address` | Address to receive the assets. | +| `owner` | `address` | Share holder address. | + +**Returns** + +| Name | Type | Description | +| ---- | ---- | ----------- | +| `shares` | `uint256` | Shares burned. | + +### redeem + +Redeems shares for supply assets in terminal states. +Advances state before checking max, enabling single-tx redemptions +when the vault is ready to transition (e.g. PendingSettlement -> Matured). + +**Notes:** +- error: InvalidState If vault is not in a terminal state (Matured/Failed/Liquidated). +- error: ExceedsMaxCap If requested shares exceed the caller's redeemable balance. + +```solidity +function redeem( + uint256 shares, + address receiver, + address owner +) public override returns (uint256 assets); +``` + +**Parameters** + +| Name | Type | Description | +| ---- | ---- | ----------- | +| `shares` | `uint256` | Shares to redeem. | +| `receiver` | `address` | Address to receive the assets. | +| `owner` | `address` | Share holder address. | + +**Returns** + +| Name | Type | Description | +| ---- | ---- | ----------- | +| `assets` | `uint256` | Supply assets returned. | + +### totalAssets + +State-dependent total assets backing outstanding shares. + +Matured/Failed/Liquidated: settlementAmount (decremented on each withdrawal). All other states: totalRaised. + +```solidity +function totalAssets() public view override returns (uint256); +``` + +**Returns** + +| Name | Type | Description | +| ---- | ---- | ----------- | +| `` | `uint256` | Total assets in supply asset units. | + +### maxDeposit + +Remaining deposit capacity in supply asset units. Zero outside Fundraising state. + +```solidity +function maxDeposit(address /* receiver */) public view override returns (uint256); +``` + +**Returns** + +| Name | Type | Description | +| ---- | ---- | ----------- | +| `` | `uint256` | Maximum depositable amount. | + +### maxMint + +Share equivalent of maxDeposit. + +```solidity +function maxMint(address receiver) public view override returns (uint256); +``` + +**Parameters** + +| Name | Type | Description | +| ---- | ---- | ----------- | +| `receiver` | `address` | Receiver address (passed through to maxDeposit). | + +**Returns** + +| Name | Type | Description | +| ---- | ---- | ----------- | +| `` | `uint256` | Maximum mintable shares. | + +### maxWithdraw + +Withdrawable supply asset amount for a supplier. Zero outside terminal states. + +```solidity +function maxWithdraw(address owner) public view override returns (uint256); +``` + +**Parameters** + +| Name | Type | Description | +| ---- | ---- | ----------- | +| `owner` | `address` | Share holder address. | + +**Returns** + +| Name | Type | Description | +| ---- | ---- | ----------- | +| `` | `uint256` | Maximum withdrawable supply asset amount. | + +### maxRedeem + +Redeemable share amount for a supplier. Zero outside terminal states. + +```solidity +function maxRedeem(address owner) public view override returns (uint256); +``` + +**Parameters** + +| Name | Type | Description | +| ---- | ---- | ----------- | +| `owner` | `address` | Share holder address. | + +**Returns** + +| Name | Type | Description | +| ---- | ---- | ----------- | +| `` | `uint256` | Maximum redeemable share amount. | + +## Events + +### StateTransition + +```solidity +event StateTransition(VaultState indexed from, VaultState indexed to, uint256 timestamp); +``` + +### VaultClosed + +```solidity +event VaultClosed(VaultState state); +``` + +### SettlementConfirmed + +```solidity +event SettlementConfirmed(uint256 settlementAmount, uint256 protocolFee, uint256 surplus); +``` + +### ShortfallDetected + +```solidity +event ShortfallDetected(uint256 totalOwed, uint256 available); +``` + +### PSRNotificationFailed + +```solidity +event PSRNotificationFailed(address indexed psr, bytes reason); +``` + +### RaisedFundsClaimed + +```solidity +event RaisedFundsClaimed(uint256 amount); +``` + +### Repaid + +```solidity +event Repaid(uint256 amount, uint256 remainingDebt); +``` + +### PauseLevelSet + +```solidity +event PauseLevelSet(PauseLevel oldLevel, PauseLevel newLevel); +``` + +### TokensSwept + +```solidity +event TokensSwept(address indexed token, address indexed recipient, uint256 amount); +``` + +## Errors + +### InvalidState + +```solidity +error InvalidState(); +``` + +### SameStateTransition + +```solidity +error SameStateTransition(); +``` + +### BelowMinimumDepositAmount + +```solidity +error BelowMinimumDepositAmount(); +``` + +### ExceedsMaxCap + +```solidity +error ExceedsMaxCap(); +``` + +### Unauthorized + +```solidity +error Unauthorized(); +``` + +### AlreadyWithdrawn + +```solidity +error AlreadyWithdrawn(); +``` + +### NoOutstandingDebt + +```solidity +error NoOutstandingDebt(); +``` + +### ZeroRepayAmount + +```solidity +error ZeroRepayAmount(); +``` + +### NothingToSweep + +```solidity +error NothingToSweep(); +``` + +### PartiallyPaused + +```solidity +error PartiallyPaused(); +``` + +### CompletelyPaused + +```solidity +error CompletelyPaused(); +``` diff --git a/technical-reference/reference-fixed-rate-vaults/institution-position-token.md b/technical-reference/reference-fixed-rate-vaults/institution-position-token.md new file mode 100644 index 0000000..12a6624 --- /dev/null +++ b/technical-reference/reference-fixed-rate-vaults/institution-position-token.md @@ -0,0 +1,165 @@ +# InstitutionPositionToken + +**Inherits:** ERC721, Ownable2Step + +**Title:** InstitutionPositionToken + +Singleton ERC-721 representing institution positions in Institutional Vaults. +One token per vault. Holder = institution operator. Governance-gated transfers. + +Owner is VaultController (sole minter, transfer governance gateway). +Not upgradeable — logic is minimal and immutable. +Deployed with msg.sender as owner, then ownership transferred to VaultController. + +## Solidity API + +## State Variables + +### nextTokenId + +Auto-incrementing token ID counter (starts at 1). + +```solidity +uint256 public nextTokenId +``` + +### tokenIdToVault + +Maps token ID to its vault address. + +```solidity +mapping(uint256 => address) public tokenIdToVault +``` + +### vaultToTokenId + +Maps vault address to its token ID. + +```solidity +mapping(address => uint256) public vaultToTokenId +``` + +### approvedRecipient + +Recipient governance has approved to receive a specific token (one-shot). +Cleared back to address(0) once the matching transfer is consumed. + +```solidity +mapping(uint256 => address) public approvedRecipient +``` + +## Functions + +### constructor + +```solidity +constructor() ERC721("Venus Institution Position", "vINST"); +``` + +### renounceOwnership + +Disabled — renouncing ownership would permanently brick minting and transfer governance. + +**Note:** error: OwnershipCannotBeRenounced Always reverts. + +```solidity +function renounceOwnership() public pure override; +``` + +### mint + +Mints a new token to `to` for the given vault. + +**Note:** event: PositionTokenMinted + +```solidity +function mint(address to, address vault) external onlyOwner returns (uint256 tokenId); +``` + +**Parameters** + +| Name | Type | Description | +| ---- | ---- | ----------- | +| `to` | `address` | The initial institution operator address. | +| `vault` | `address` | The vault address this token represents. | + +**Returns** + +| Name | Type | Description | +| ---- | ---- | ----------- | +| `tokenId` | `uint256` | The minted token ID. | + +### approveTransfer + +Approves `recipient` to receive `tokenId` on the next transfer. One-shot — cleared after use. + +**Notes:** +- error: ZeroAddress If recipient is address(0). +- event: PositionTransferApproved + +```solidity +function approveTransfer(uint256 tokenId, address recipient) external onlyOwner; +``` + +**Parameters** + +| Name | Type | Description | +| ---- | ---- | ----------- | +| `tokenId` | `uint256` | The token ID to approve for transfer. | +| `recipient` | `address` | The address that must be the destination of the next transfer. | + +### revokeTransferApproval + +Revokes a previously granted transfer approval. + +**Note:** event: PositionTransferRevoked + +```solidity +function revokeTransferApproval(uint256 tokenId) external onlyOwner; +``` + +**Parameters** + +| Name | Type | Description | +| ---- | ---- | ----------- | +| `tokenId` | `uint256` | The token ID to revoke approval for. | + +## Events + +### PositionTokenMinted + +```solidity +event PositionTokenMinted(address indexed vault, uint256 indexed tokenId, address indexed institution); +``` + +### PositionTransferApproved + +```solidity +event PositionTransferApproved(uint256 indexed tokenId, address indexed recipient); +``` + +### PositionTransferRevoked + +```solidity +event PositionTransferRevoked(uint256 indexed tokenId); +``` + +## Errors + +### TransferNotApproved + +```solidity +error TransferNotApproved(uint256 tokenId); +``` + +### OwnershipCannotBeRenounced + +```solidity +error OwnershipCannotBeRenounced(); +``` + +### ZeroAddress + +```solidity +error ZeroAddress(); +``` diff --git a/technical-reference/reference-fixed-rate-vaults/institutional-loan-vault.md b/technical-reference/reference-fixed-rate-vaults/institutional-loan-vault.md new file mode 100644 index 0000000..3627429 --- /dev/null +++ b/technical-reference/reference-fixed-rate-vaults/institutional-loan-vault.md @@ -0,0 +1,639 @@ +# InstitutionalLoanVault + +**Inherits:** [BaseVault](base-vault.md) + +**Title:** InstitutionalLoanVault + +ERC-4626 vault for institutional fixed-rate lending with on-chain collateral, +borrowing, and liquidation support. Deployed as EIP-1167 minimal proxy clones. + +Inherits BaseVault for shared ERC-4626 mechanics, fundraising, interest, settlement, +and core state machine. Adds: collateral deposit/withdraw, borrowing, risk checks, +liquidation entry points, and pre-fundraising states (WaitingForMargin, MarginDeposited). +No ACM — all governance calls are proxied through VaultController. +Position-holder gated functions (collateral ops, claimRaisedFunds) are restricted to the +current owner of the vault's PositionToken — not the original institution address. The +institution can transfer vault ownership by transferring the token to another address. +Fee-on-transfer tokens are NOT supported for either the underlying asset or collateral. + +## Solidity API + +## State Variables + +### _instConfig + +Institutional-specific configuration — collateral, sizing, position identity. + +```solidity +InstitutionalConfig internal _instConfig +``` + +### _instRuntime + +Institutional-specific runtime — collateral accounting, margin confiscation. + +```solidity +InstitutionalRuntime internal _instRuntime +``` + +### _riskConfig + +Risk parameters — LT/LI/latePenaltyRate mutable via controller. + +```solidity +RiskConfig internal _riskConfig +``` + +### positionToken + +InstitutionPositionToken contract — from controller storage. + +```solidity +IInstitutionPositionToken public positionToken +``` + +## Functions + +### onlyPositionHolder + +Restricts to the current owner of the vault's PositionToken. Ownership is transferable — +if the institution transfers the token, the new holder gains access to position-holder gated functions. + +```solidity +modifier onlyPositionHolder(); +``` + +### onlyLiquidationAdapter + +Restricts to the LiquidationAdapter contract stored on the controller. + +```solidity +modifier onlyLiquidationAdapter(); +``` + +### constructor + +**Note:** oz-upgrades-unsafe-allow: constructor + +```solidity +constructor(); +``` + +### initialize + +Initializes the vault clone. Called once by VaultController. + +```solidity +function initialize( + VaultConfig calldata config_, + InstitutionalConfig calldata instConfig_, + RiskConfig calldata riskConfig_, + IInstitutionPositionToken positionToken_, + string calldata name_, + string calldata symbol_ +) external initializer; +``` + +**Parameters** + +| Name | Type | Description | +| ---- | ---- | ----------- | +| `config_` | `VaultConfig` | Shared vault configuration (asset, rates, caps, timing). | +| `instConfig_` | `InstitutionalConfig` | Institutional-specific configuration (collateral, sizing, position identity). | +| `riskConfig_` | `RiskConfig` | Risk parameters. | +| `positionToken_` | `IInstitutionPositionToken` | InstitutionPositionToken contract reference. | +| `name_` | `string` | ERC-20 share token name. | +| `symbol_` | `string` | ERC-20 share token symbol. | + +### openVault + +Transitions MarginDeposited -> Fundraising. Controller only. + +**Notes:** +- error: InvalidState If vault is not in MarginDeposited state. +- event: VaultOpened Emitted with the open end time. +- event: StateTransition Emitted for MarginDeposited -> Fundraising. + +```solidity +function openVault() external onlyController; +``` + +### cancelVault + +Cancels a vault that has not yet launched and refunds any deposited collateral +to the NFT position holder. Restricted to the two pre-launch states: +WaitingForMargin (no collateral yet) or MarginDeposited (margin in escrow). +Uses positionToken.ownerOf so any approved NFT transfer is honoured. + +**Notes:** +- error: InvalidState If vault is not in WaitingForMargin or MarginDeposited. +- event: VaultCancelled Emitted with the position-holder recipient and refunded collateral amount. +- event: StateTransition Emitted by _stateTransition for WaitingForMargin/MarginDeposited -> Failed. + +```solidity +function cancelVault() external onlyController nonReentrant; +``` + +### repayBadDebt + +Permissionless bad-debt rescue. Anyone may repay to settle a vault where collateral < debt. + +**Notes:** +- error: InvalidState If vault is not in Lock, PendingSettlement, or SettlementDeadlineExceeded. +- error: ZeroRepayAmount If repayAmount is zero. +- error: NoOutstandingDebt If there is no debt to repay. +- error: NotBadDebt If collateral value >= debt value. +- error: InsufficientRepayment If outstanding debt after repay still exceeds total interest (principal not fully returned). + +```solidity +function repayBadDebt(uint256 repayAmount) external nonReentrant whenNotCompletelyPaused; +``` + +**Parameters** + +| Name | Type | Description | +| ---- | ---- | ----------- | +| `repayAmount` | `uint256` | Amount of supply asset to pull from caller. | + +### setLiquidationThreshold + +Updates liquidation threshold. Controller only. + +**Note:** event: LiquidationThresholdUpdated + +```solidity +function setLiquidationThreshold(uint256 newLT) external onlyController; +``` + +**Parameters** + +| Name | Type | Description | +| ---- | ---- | ----------- | +| `newLT` | `uint256` | New liquidation threshold (mantissa). | + +### setLiquidationIncentive + +Updates liquidation incentive. Controller only. + +**Note:** event: LiquidationIncentiveUpdated + +```solidity +function setLiquidationIncentive(uint256 newLI) external onlyController; +``` + +**Parameters** + +| Name | Type | Description | +| ---- | ---- | ----------- | +| `newLI` | `uint256` | New liquidation incentive (mantissa). | + +### setLatePenaltyRate + +Updates late penalty rate. Controller only. + +**Note:** event: LatePenaltyRateUpdated + +```solidity +function setLatePenaltyRate(uint256 newRate) external onlyController; +``` + +**Parameters** + +| Name | Type | Description | +| ---- | ---- | ----------- | +| `newRate` | `uint256` | New late penalty rate (mantissa). | + +### liquidate + +HF-based liquidation. LiquidationAdapter only. + +**Notes:** +- error: ZeroRepayAmount If repayAmount is zero. +- error: InvalidState If vault is not in Lock, PendingSettlement, or SettlementDeadlineExceeded. +- error: NoOutstandingDebt If there is no debt to repay. +- error: NotLiquidatable If vault has no LT shortfall. +- event: LiquidationExecuted Emitted with liquidator, repay amount, and collateral seized. + +```solidity +function liquidate( + uint256 repayAmount +) external onlyLiquidationAdapter nonReentrant whenNotCompletelyPaused returns (uint256 actualRepay); +``` + +**Parameters** + +| Name | Type | Description | +| ---- | ---- | ----------- | +| `repayAmount` | `uint256` | Amount of supply asset to repay. | + +**Returns** + +| Name | Type | Description | +| ---- | ---- | ----------- | +| `actualRepay` | `uint256` | Actual amount repaid after clamping to outstanding debt. | + +### liquidateOverdueVault + +Deadline-based liquidation. LiquidationAdapter only. + +**Notes:** +- error: ZeroRepayAmount If repayAmount is zero. +- error: InvalidStateForOverdueLiquidation If not in SettlementDeadlineExceeded. +- error: NoOutstandingDebt If there is no debt to repay. +- error: ExceedsCloseFactor If actualRepay exceeds the close factor limit (via _executeLiquidation). +- error: InsufficientCollateralForSeize If seize amount exceeds collateral balance (via _executeLiquidation). +- event: OverdueLiquidationExecuted Emitted with settler, repay amount, and collateral seized. + +```solidity +function liquidateOverdueVault( + uint256 repayAmount +) external onlyLiquidationAdapter nonReentrant whenNotCompletelyPaused returns (uint256 actualRepay); +``` + +**Parameters** + +| Name | Type | Description | +| ---- | ---- | ----------- | +| `repayAmount` | `uint256` | Amount of supply asset to repay. | + +**Returns** + +| Name | Type | Description | +| ---- | ---- | ----------- | +| `actualRepay` | `uint256` | Actual amount repaid after clamping to outstanding debt. | + +### depositCollateral + +Deposits collateral into the vault. Fee-on-transfer / rebasing collateral tokens are NOT supported. + +- WaitingForMargin: the full margin amount must be deposited in a single transaction to transition to MarginDeposited; partial deposits revert. +- Fundraising: institution deposits remaining collateral alongside lender fundraising. +- Lock: top-up collateral. + +**Notes:** +- error: InvalidState If vault is not in WaitingForMargin, Fundraising, or Lock. +- error: InsufficientCollateral If deposit in WaitingForMargin does not meet margin threshold. +- event: CollateralDeposited Emitted with actual deposited amount and total collateral. + +```solidity +function depositCollateral(uint256 amount) external onlyPositionHolder nonReentrant whenNotPaused; +``` + +**Parameters** + +| Name | Type | Description | +| ---- | ---- | ----------- | +| `amount` | `uint256` | Amount of collateral tokens to deposit. | + +### withdrawCollateral + +Withdraws collateral. + +- Lock: floor-checked (minimumCollateralRequired) + LT-checked. +- Failed (Scenario A — raised < minCap): withdraw all deposited collateral. +- Failed (Scenario B — institution default): withdraw deposited minus confiscated margin. +- Matured: capped at totalCollateralDeposited, unrestricted. +- Liquidated: blocked — collateral is recoverable by governance via sweep(). + +**Notes:** +- error: InvalidState If vault is not in Lock, Matured, or Failed. +- error: InsufficientCollateral If withdrawal would breach floor or exceed available amount. +- error: WithdrawalWouldBreachLT If withdrawal would cause LT shortfall during Lock. +- event: CollateralWithdrawn Emitted with position holder, amount, and remaining collateral. + +```solidity +function withdrawCollateral(uint256 amount) external onlyPositionHolder nonReentrant whenNotPaused; +``` + +**Parameters** + +| Name | Type | Description | +| ---- | ---- | ----------- | +| `amount` | `uint256` | Amount of collateral tokens to withdraw. | + +### claimRaisedFunds + +One-time fund withdrawal. Transfers all raised supply assets to institution. + +**Notes:** +- error: AlreadyWithdrawn if funds already claimed. +- error: ClaimWouldBreachLT if post-claim debt would exceed LT cap. +- event: RaisedFundsClaimed + +```solidity +function claimRaisedFunds() external onlyPositionHolder nonReentrant whenNotPaused; +``` + +### repay + +Repays outstanding debt. Anyone may call. Clamped to outstandingDebt. + +**Notes:** +- error: InvalidState If vault is not in Lock, PendingSettlement, or SettlementDeadlineExceeded. +- error: ZeroRepayAmount if amount is zero. +- error: NoOutstandingDebt if there is no debt to repay. +- event: Repaid + +```solidity +function repay(uint256 amount) external nonReentrant whenNotCompletelyPaused; +``` + +**Parameters** + +| Name | Type | Description | +| ---- | ---- | ----------- | +| `amount` | `uint256` | Amount of supply asset to repay. | + +### getCollateralValueUSD + +Current collateral value in USD via oracle. + +```solidity +function getCollateralValueUSD() external view returns (uint256); +``` + +**Returns** + +| Name | Type | Description | +| ---- | ---- | ----------- | +| `` | `uint256` | Collateral value in 18-decimal USD. | + +### getDebtValueUSD + +Current outstanding debt value in USD via oracle. + +```solidity +function getDebtValueUSD() external view returns (uint256); +``` + +**Returns** + +| Name | Type | Description | +| ---- | ---- | ----------- | +| `` | `uint256` | Debt value in 18-decimal USD. | + +### institutionalConfig + +Returns the institutional-specific configuration. + +```solidity +function institutionalConfig() external view returns (InstitutionalConfig memory); +``` + +**Returns** + +| Name | Type | Description | +| ---- | ---- | ----------- | +| `` | `InstitutionalConfig` | Institutional config struct. | + +### riskConfig + +Returns the risk configuration. + +```solidity +function riskConfig() external view returns (RiskConfig memory); +``` + +**Returns** + +| Name | Type | Description | +| ---- | ---- | ----------- | +| `` | `RiskConfig` | Risk parameters struct. | + +### institutionalRuntime + +Returns the institutional-specific runtime state. + +```solidity +function institutionalRuntime() external view returns (InstitutionalRuntime memory); +``` + +**Returns** + +| Name | Type | Description | +| ---- | ---- | ----------- | +| `` | `InstitutionalRuntime` | Institutional runtime struct. | + +### getVaultLiquidity + +Returns current liquidity and shortfall for the vault. + +```solidity +function getVaultLiquidity() external view returns (uint256 liquidity, uint256 shortfall); +``` + +**Returns** + +| Name | Type | Description | +| ---- | ---- | ----------- | +| `liquidity` | `uint256` | Excess liquidity (0 if shortfall). | +| `shortfall` | `uint256` | LT shortfall (0 if healthy). | + +### getHypotheticalVaultLiquidity + +Returns hypothetical liquidity/shortfall after a simulated withdrawal and/or debt increase. + +```solidity +function getHypotheticalVaultLiquidity( + uint256 withdrawAmount, + uint256 additionalDebt +) external view returns (uint256 liquidity, uint256 shortfall); +``` + +**Parameters** + +| Name | Type | Description | +| ---- | ---- | ----------- | +| `withdrawAmount` | `uint256` | Simulated collateral withdrawal amount. | +| `additionalDebt` | `uint256` | Simulated additional debt on top of outstanding. | + +**Returns** + +| Name | Type | Description | +| ---- | ---- | ----------- | +| `liquidity` | `uint256` | Excess liquidity (0 if shortfall). | +| `shortfall` | `uint256` | LT shortfall (0 if healthy). | + +### calculateSeizeAmount + +Preview seize amount for a given repay and liquidation type. + +```solidity +function calculateSeizeAmount( + uint256 repayAmount, + LiquidationType liquidationType +) external view returns (uint256); +``` + +**Parameters** + +| Name | Type | Description | +| ---- | ---- | ----------- | +| `repayAmount` | `uint256` | Amount being repaid. | +| `liquidationType` | `LiquidationType` | HF_BASED or DEADLINE. | + +**Returns** + +| Name | Type | Description | +| ---- | ---- | ----------- | +| `` | `uint256` | Collateral seize amount. | + +## Events + +### VaultOpened + +```solidity +event VaultOpened(uint256 openEndTime); +``` + +### VaultLocked + +```solidity +event VaultLocked(uint256 totalRaised, uint256 lockEndTime); +``` + +### VaultFailed + +```solidity +event VaultFailed(uint256 totalRaised, uint256 minBorrowCap); +``` + +### VaultLiquidated + +```solidity +event VaultLiquidated(uint256 available); +``` + +### CollateralDeposited + +```solidity +event CollateralDeposited(uint256 amount, uint256 totalCollateral); +``` + +### CollateralWithdrawn + +```solidity +event CollateralWithdrawn(address indexed positionHolder, uint256 amount, uint256 remaining); +``` + +### LiquidationExecuted + +```solidity +event LiquidationExecuted(address indexed liquidator, uint256 repayAmount, uint256 collateralSeized); +``` + +### OverdueLiquidationExecuted + +```solidity +event OverdueLiquidationExecuted(address indexed settler, uint256 repayAmount, uint256 collateralSeized); +``` + +### MarginConfiscated + +```solidity +event MarginConfiscated(uint256 marginAmount); +``` + +### MarginCompensationClaimed + +```solidity +event MarginCompensationClaimed(address indexed receiver, uint256 amount); +``` + +### VaultCancelled + +```solidity +event VaultCancelled(address indexed recipient, uint256 collateralAmount); +``` + +### LiquidationThresholdUpdated + +```solidity +event LiquidationThresholdUpdated(uint256 oldLT, uint256 newLT); +``` + +### LiquidationIncentiveUpdated + +```solidity +event LiquidationIncentiveUpdated(uint256 oldLI, uint256 newLI); +``` + +### LatePenaltyRateUpdated + +```solidity +event LatePenaltyRateUpdated(uint256 oldRate, uint256 newRate); +``` + +## Errors + +### InsufficientCollateral + +```solidity +error InsufficientCollateral(); +``` + +### NotPositionHolder + +```solidity +error NotPositionHolder(); +``` + +### InvalidStateForOverdueLiquidation + +```solidity +error InvalidStateForOverdueLiquidation(); +``` + +### NotBadDebt + +```solidity +error NotBadDebt(); +``` + +### InsufficientRepayment + +```solidity +error InsufficientRepayment(); +``` + +### NotLiquidatable + +```solidity +error NotLiquidatable(); +``` + +### ExceedsCloseFactor + +```solidity +error ExceedsCloseFactor(); +``` + +### InsufficientCollateralForSeize + +```solidity +error InsufficientCollateralForSeize(uint256 seizeAmount, uint256 availableCollateral); +``` + +### WithdrawalWouldBreachLT + +```solidity +error WithdrawalWouldBreachLT(); +``` + +### WithdrawExceedsCollateral + +```solidity +error WithdrawExceedsCollateral(); +``` + +### ClaimWouldBreachLT + +```solidity +error ClaimWouldBreachLT(); +``` + +### InvalidOraclePrice + +```solidity +error InvalidOraclePrice(); +``` diff --git a/technical-reference/reference-fixed-rate-vaults/institutional-vault-controller.md b/technical-reference/reference-fixed-rate-vaults/institutional-vault-controller.md new file mode 100644 index 0000000..fd1388d --- /dev/null +++ b/technical-reference/reference-fixed-rate-vaults/institutional-vault-controller.md @@ -0,0 +1,675 @@ +# InstitutionalVaultController + +**Inherits:** Initializable, AccessControlledV8 + +**Title:** InstitutionalVaultController + +Central orchestrator for the Institutional Vault system. Deploys vault clones, maintains the registry, +holds the Venus ACM reference, and proxies governance operations to vaults. + +Deployed as a transparent proxy (upgradeable via ProxyAdmin). + +## Solidity API + +## State Variables + +### MANTISSA_ONE + +```solidity +uint256 public constant MANTISSA_ONE = 1e18 +``` + +### MANTISSA_ONE_AND_HALF + +Maximum allowed multiplier for rate parameters (LI, LP). Caps bonus/penalty at 50% above mantissa. + +```solidity +uint256 public constant MANTISSA_ONE_AND_HALF = 1.5e18 +``` + +### MAX_APY_BPS + +Maximum allowed fixed APY in basis points (100% = 10 000 bps). +Interest is calculated as: totalRaised * fixedAPY * lockDuration / (BPS * YEAR). + +```solidity +uint256 public constant MAX_APY_BPS = 10_000 +``` + +### vaultImplementation + +InstitutionalLoanVault implementation address for cloning. + +```solidity +address public vaultImplementation +``` + +### liquidationAdapter + +LiquidationAdapter contract address. + +```solidity +address public liquidationAdapter +``` + +### oracle + +Venus ResilientOracle address. + +```solidity +address public oracle +``` + +### protocolShareReserve + +Venus ProtocolShareReserve (PSR) address. + +```solidity +address public protocolShareReserve +``` + +### comptroller + +Comptroller address for PSR integration. + +```solidity +address public comptroller +``` + +### treasury + +Treasury address — recipient for swept tokens. + +```solidity +address public treasury +``` + +### positionToken + +InstitutionPositionToken contract address. + +```solidity +IInstitutionPositionToken public positionToken +``` + +### allVaults + +Array of all deployed vault addresses. + +```solidity +address[] public allVaults +``` + +### isRegistered + +Whether a vault is registered. + +```solidity +mapping(address => bool) public isRegistered +``` + +### institutionNonce + +Per-institution deploy counter (for CREATE2 salt). + +```solidity +mapping(address => uint256) public institutionNonce +``` + +## Functions + +### constructor + +**Note:** oz-upgrades-unsafe-allow: constructor + +```solidity +constructor(); +``` + +### initialize + +Initializes the controller proxy. + +```solidity +function initialize( + address vaultImplementation_, + address oracle_, + address protocolShareReserve_, + address comptroller_, + address treasury_, + address positionToken_, + address acm_ +) external initializer; +``` + +**Parameters** + +| Name | Type | Description | +| ---- | ---- | ----------- | +| `vaultImplementation_` | `address` | InstitutionalLoanVault implementation for cloning. | +| `oracle_` | `address` | Venus ResilientOracle address. | +| `protocolShareReserve_` | `address` | PSR address. | +| `comptroller_` | `address` | Comptroller address for PSR. | +| `treasury_` | `address` | Treasury address — recipient for swept tokens. | +| `positionToken_` | `address` | InstitutionPositionToken address. | +| `acm_` | `address` | Venus AccessControlManager address. | + +### acceptPositionTokenOwnership + +Accepts pending ownership of the InstitutionPositionToken. +Required because PositionToken uses Ownable2Step. Call after transferOwnership. + +```solidity +function acceptPositionTokenOwnership() external; +``` + +### createVault + +Deploys a new vault clone via deterministic CREATE2. + +**Note:** event: VaultCreated + +```solidity +function createVault( + VaultConfig calldata _vaultConfig, + InstitutionalConfig calldata _instConfig, + RiskConfig calldata _riskConfig, + string calldata _name, + string calldata _symbol +) external returns (address vault); +``` + +**Parameters** + +| Name | Type | Description | +| ---- | ---- | ----------- | +| `_vaultConfig` | `VaultConfig` | Shared vault configuration (asset, rates, caps, timing). | +| `_instConfig` | `InstitutionalConfig` | Institutional-specific configuration (collateral, sizing, position identity). | +| `_riskConfig` | `RiskConfig` | Risk parameters. | +| `_name` | `string` | ERC-20 share token name for the deployed vault. | +| `_symbol` | `string` | ERC-20 share token symbol for the deployed vault. | + +**Returns** + +| Name | Type | Description | +| ---- | ---- | ----------- | +| `vault` | `address` | Deployed vault address. | + +### openVault + +Transitions MarginDeposited -> Fundraising on a vault. + +**Note:** error: VaultNotRegistered If vault is not in the registry. + +```solidity +function openVault(address vault) external; +``` + +**Parameters** + +| Name | Type | Description | +| ---- | ---- | ----------- | +| `vault` | `address` | Vault address. | + +### cancelVault + +Cancels a pre-launch vault and refunds any deposited collateral to the NFT position holder. +Callable only on a vault still in WaitingForMargin or MarginDeposited. + +**Note:** error: VaultNotRegistered If vault is not in the registry. + +```solidity +function cancelVault(address vault) external; +``` + +**Parameters** + +| Name | Type | Description | +| ---- | ---- | ----------- | +| `vault` | `address` | Vault address. | + +### partialPauseVault + +Partial pause — blocks general operations; repay and liquidation remain available. + +**Note:** error: VaultNotRegistered If vault is not in the registry. + +```solidity +function partialPauseVault(address vault) external; +``` + +**Parameters** + +| Name | Type | Description | +| ---- | ---- | ----------- | +| `vault` | `address` | Vault address. | + +### completePauseVault + +Complete pause — blocks all operations including repay and liquidation. + +**Note:** error: VaultNotRegistered If vault is not in the registry. + +```solidity +function completePauseVault(address vault) external; +``` + +**Parameters** + +| Name | Type | Description | +| ---- | ---- | ----------- | +| `vault` | `address` | Vault address. | + +### unpauseVault + +Unpause vault — removes all pause restrictions. + +**Note:** error: VaultNotRegistered If vault is not in the registry. + +```solidity +function unpauseVault(address vault) external; +``` + +**Parameters** + +| Name | Type | Description | +| ---- | ---- | ----------- | +| `vault` | `address` | Vault address. | + +### closeVault + +Transitions vault to Closed state. All operations are blocked after this point. + +**Note:** error: VaultNotRegistered If vault is not in the registry. + +```solidity +function closeVault(address vault) external; +``` + +**Parameters** + +| Name | Type | Description | +| ---- | ---- | ----------- | +| `vault` | `address` | Vault address. | + +### sweep + +Recovers stuck tokens from a vault to treasury. + +**Note:** error: VaultNotRegistered If vault is not in the registry. + +```solidity +function sweep(address vault, address token) external; +``` + +**Parameters** + +| Name | Type | Description | +| ---- | ---- | ----------- | +| `vault` | `address` | Vault address. | +| `token` | `address` | Token address to sweep. | + +### approvePositionTransfer + +Approves transfer of the vault's position token to a specific recipient. + +**Note:** error: VaultNotRegistered If vault is not in the registry. + +```solidity +function approvePositionTransfer(address vault, address recipient) external; +``` + +**Parameters** + +| Name | Type | Description | +| ---- | ---- | ----------- | +| `vault` | `address` | Vault address. | +| `recipient` | `address` | The address that must be the destination of the next transfer. | + +### revokePositionTransfer + +Revokes a previously granted approval. + +**Note:** error: VaultNotRegistered If vault is not in the registry. + +```solidity +function revokePositionTransfer(address vault) external; +``` + +**Parameters** + +| Name | Type | Description | +| ---- | ---- | ----------- | +| `vault` | `address` | Vault address. | + +### setLiquidationThreshold + +Updates liquidation threshold on a vault. + +**Notes:** +- error: VaultNotRegistered If vault is not in the registry. +- error: InvalidLiquidationThreshold If newLT == 0 or newLT > MANTISSA_ONE. +- event: LiquidationThresholdUpdated + +```solidity +function setLiquidationThreshold(address vault, uint256 newLT) external; +``` + +**Parameters** + +| Name | Type | Description | +| ---- | ---- | ----------- | +| `vault` | `address` | Vault address. | +| `newLT` | `uint256` | New liquidation threshold (mantissa). | + +### setLiquidationIncentive + +Updates liquidation incentive on a vault. + +**Notes:** +- error: VaultNotRegistered If vault is not in the registry. +- error: InvalidLiquidationIncentive If newLI <= MANTISSA_ONE or newLI > MANTISSA_ONE_AND_HALF. +- event: LiquidationIncentiveUpdated + +```solidity +function setLiquidationIncentive(address vault, uint256 newLI) external; +``` + +**Parameters** + +| Name | Type | Description | +| ---- | ---- | ----------- | +| `vault` | `address` | Vault address. | +| `newLI` | `uint256` | New liquidation incentive (mantissa). Must be in range (MANTISSA_ONE, MANTISSA_ONE_AND_HALF]. | + +### setLatePenaltyRate + +Updates late penalty rate on a vault. + +**Notes:** +- error: VaultNotRegistered If vault is not in the registry. +- error: InvalidLatePenaltyRate If newRate <= MANTISSA_ONE or newRate > MANTISSA_ONE_AND_HALF. +- event: LatePenaltyRateUpdated + +```solidity +function setLatePenaltyRate(address vault, uint256 newRate) external; +``` + +**Parameters** + +| Name | Type | Description | +| ---- | ---- | ----------- | +| `vault` | `address` | Vault address. | +| `newRate` | `uint256` | New late penalty rate (mantissa). Must be in range (MANTISSA_ONE, MANTISSA_ONE_AND_HALF]. | + +### setVaultImplementation + +Update clone source. Only affects future vaults. + +**Notes:** +- error: InvalidAddress if zero address. +- event: VaultImplementationUpdated + +```solidity +function setVaultImplementation(address impl) external; +``` + +**Parameters** + +| Name | Type | Description | +| ---- | ---- | ----------- | +| `impl` | `address` | New implementation address. | + +### setLiquidationAdapter + +Update LiquidationAdapter address. + +**Notes:** +- error: InvalidAddress if zero address. +- event: LiquidationAdapterUpdated + +```solidity +function setLiquidationAdapter(address adapter) external; +``` + +**Parameters** + +| Name | Type | Description | +| ---- | ---- | ----------- | +| `adapter` | `address` | New adapter address. | + +### setOracle + +Update ResilientOracle reference. + +**Notes:** +- error: InvalidAddress if zero address. +- event: OracleUpdated + +```solidity +function setOracle(address oracle_) external; +``` + +**Parameters** + +| Name | Type | Description | +| ---- | ---- | ----------- | +| `oracle_` | `address` | New oracle address. | + +### setProtocolShareReserve + +Update ProtocolShareReserve address. + +**Notes:** +- error: InvalidAddress if zero address. +- event: ProtocolShareReserveUpdated + +```solidity +function setProtocolShareReserve(address psr) external; +``` + +**Parameters** + +| Name | Type | Description | +| ---- | ---- | ----------- | +| `psr` | `address` | New PSR address. | + +### setComptroller + +Update comptroller address for PSR. + +**Notes:** +- error: InvalidAddress if zero address. +- event: ComptrollerUpdated + +```solidity +function setComptroller(address comptroller_) external; +``` + +**Parameters** + +| Name | Type | Description | +| ---- | ---- | ----------- | +| `comptroller_` | `address` | New comptroller address. | + +### setTreasury + +Update treasury address for swept tokens. + +**Notes:** +- error: InvalidAddress if zero address. +- event: TreasuryUpdated + +```solidity +function setTreasury(address treasury_) external; +``` + +**Parameters** + +| Name | Type | Description | +| ---- | ---- | ----------- | +| `treasury_` | `address` | New treasury address. | + +### predictVaultAddress + +Predicts the next vault address for a given institution. + +```solidity +function predictVaultAddress(address institution) external view returns (address); +``` + +**Parameters** + +| Name | Type | Description | +| ---- | ---- | ----------- | +| `institution` | `address` | Institution operator address. | + +**Returns** + +| Name | Type | Description | +| ---- | ---- | ----------- | +| `` | `address` | Predicted vault address. | + +### getAggregatedVaultStates + +Returns state summary for all registered vaults. + +```solidity +function getAggregatedVaultStates() external view returns (VaultStateInfo[] memory); +``` + +**Returns** + +| Name | Type | Description | +| ---- | ---- | ----------- | +| `` | `VaultStateInfo[]` | Array of VaultStateInfo structs. | + +### allVaultsLength + +Returns total number of deployed vaults. + +```solidity +function allVaultsLength() external view returns (uint256); +``` + +**Returns** + +| Name | Type | Description | +| ---- | ---- | ----------- | +| `` | `uint256` | Number of vaults in registry. | + +### renounceOwnership + +Disabled — renouncing ownership would permanently brick ACM-gated vault governance. + +**Note:** error: OwnershipCannotBeRenounced Always reverts. + +```solidity +function renounceOwnership() public pure override; +``` + +## Events + +### VaultCreated + +```solidity +event VaultCreated(address indexed vault, address indexed institution); +``` + +### VaultImplementationUpdated + +```solidity +event VaultImplementationUpdated(address indexed oldImpl, address indexed newImpl); +``` + +### LiquidationAdapterUpdated + +```solidity +event LiquidationAdapterUpdated(address indexed oldAdapter, address indexed newAdapter); +``` + +### OracleUpdated + +```solidity +event OracleUpdated(address indexed oldOracle, address indexed newOracle); +``` + +### ProtocolShareReserveUpdated + +```solidity +event ProtocolShareReserveUpdated(address indexed oldPSR, address indexed newPSR); +``` + +### ComptrollerUpdated + +```solidity +event ComptrollerUpdated(address indexed oldComptroller, address indexed newComptroller); +``` + +### TreasuryUpdated + +```solidity +event TreasuryUpdated(address indexed oldTreasury, address indexed newTreasury); +``` + +### LiquidationThresholdUpdated + +```solidity +event LiquidationThresholdUpdated(address indexed vault, uint256 newLT); +``` + +### LiquidationIncentiveUpdated + +```solidity +event LiquidationIncentiveUpdated(address indexed vault, uint256 newLI); +``` + +### LatePenaltyRateUpdated + +```solidity +event LatePenaltyRateUpdated(address indexed vault, uint256 newRate); +``` + +## Errors + +### VaultNotRegistered + +```solidity +error VaultNotRegistered(); +``` + +### InvalidConfig + +```solidity +error InvalidConfig(); +``` + +### InvalidLiquidationThreshold + +```solidity +error InvalidLiquidationThreshold(); +``` + +### InvalidLiquidationIncentive + +```solidity +error InvalidLiquidationIncentive(); +``` + +### InvalidLatePenaltyRate + +```solidity +error InvalidLatePenaltyRate(); +``` + +### InvalidAddress + +```solidity +error InvalidAddress(); +``` + +### OwnershipCannotBeRenounced + +```solidity +error OwnershipCannotBeRenounced(); +``` diff --git a/technical-reference/reference-fixed-rate-vaults/liquidation-adapter.md b/technical-reference/reference-fixed-rate-vaults/liquidation-adapter.md new file mode 100644 index 0000000..f1e0410 --- /dev/null +++ b/technical-reference/reference-fixed-rate-vaults/liquidation-adapter.md @@ -0,0 +1,320 @@ +# LiquidationAdapter + +**Inherits:** Initializable, AccessControlledV8, ReentrancyGuardUpgradeable + +**Title:** LiquidationAdapter + +Manages whitelisted liquidators/settlers, routes liquidation calls to Institutional Vault vaults, +receives seized collateral, and splits incentive between protocol and caller. + +Deployed as a transparent proxy (upgradeable). Holds ACM for whitelist and config management. + +## Solidity API + +## State Variables + +### MANTISSA_ONE + +```solidity +uint256 public constant MANTISSA_ONE = 1e18 +``` + +### vaultController + +InstitutionalVaultController address (vaults are validated via controller). + +```solidity +address public vaultController +``` + +### isWhitelistedLiquidator + +HF-based liquidators — can call liquidate() when LT shortfall > 0. + +```solidity +mapping(address => bool) public isWhitelistedLiquidator +``` + +### isWhitelistedSettler + +Deadline-based settlers — can call liquidateOverdueVault() in SettlementDeadlineExceeded. + +```solidity +mapping(address => bool) public isWhitelistedSettler +``` + +### protocolLiquidationShare + +Fraction of incentive portion to protocol (mantissa). + +```solidity +uint256 public protocolLiquidationShare +``` + +### closeFactor + +Max fraction of debt repayable per liquidation (mantissa). Global for all vaults. + +```solidity +uint256 public closeFactor +``` + +### protocolShareAccrued + +Accrued protocol share per collateral token. Swept to PSR via governance. + +```solidity +mapping(address => uint256) public protocolShareAccrued +``` + +## Functions + +### constructor + +**Note:** oz-upgrades-unsafe-allow: constructor + +```solidity +constructor(); +``` + +### initialize + +Initializes the adapter proxy. + +```solidity +function initialize( + address vaultController_, + uint256 protocolLiquidationShare_, + uint256 closeFactor_, + address acm_ +) external initializer; +``` + +**Parameters** + +| Name | Type | Description | +| ---- | ---- | ----------- | +| `vaultController_` | `address` | VaultController address. | +| `protocolLiquidationShare_` | `uint256` | Initial protocol share of incentive (mantissa). | +| `closeFactor_` | `uint256` | Initial close factor (mantissa). | +| `acm_` | `address` | Venus AccessControlManager address. | + +### setLiquidatorWhitelist + +Add or remove a liquidator from the whitelist. + +**Note:** event: LiquidatorWhitelistUpdated + +```solidity +function setLiquidatorWhitelist(address liquidator, bool approved) external; +``` + +**Parameters** + +| Name | Type | Description | +| ---- | ---- | ----------- | +| `liquidator` | `address` | Address to update. | +| `approved` | `bool` | Whether to approve or remove. | + +### setSettlerWhitelist + +Add or remove a settler from the whitelist. + +**Note:** event: SettlerWhitelistUpdated + +```solidity +function setSettlerWhitelist(address settler, bool approved) external; +``` + +**Parameters** + +| Name | Type | Description | +| ---- | ---- | ----------- | +| `settler` | `address` | Address to update. | +| `approved` | `bool` | Whether to approve or remove. | + +### setProtocolLiquidationShare + +Set the protocol share of the liquidation incentive (mantissa). + +**Notes:** +- error: InvalidShare if share > 1e18. +- event: ProtocolLiquidationShareUpdated + +```solidity +function setProtocolLiquidationShare(uint256 share) external; +``` + +**Parameters** + +| Name | Type | Description | +| ---- | ---- | ----------- | +| `share` | `uint256` | New share (0 <= share <= 1e18). | + +### setCloseFactor + +Set max fraction of debt repayable per liquidation. + +**Notes:** +- error: InvalidCloseFactor if zero or > 1e18. +- event: CloseFactorUpdated + +```solidity +function setCloseFactor(uint256 newCF) external; +``` + +**Parameters** + +| Name | Type | Description | +| ---- | ---- | ----------- | +| `newCF` | `uint256` | New close factor (0 < newCF <= 1e18). | + +### sweepProtocolShareToReserve + +Transfer accrued protocol share for the given collateral token to PSR. + +**Note:** event: ProtocolShareSweptToReserve + +```solidity +function sweepProtocolShareToReserve(address collateral) external; +``` + +**Parameters** + +| Name | Type | Description | +| ---- | ---- | ----------- | +| `collateral` | `address` | Collateral token address. | + +### liquidate + +HF-based liquidation. Whitelisted liquidator only. + +```solidity +function liquidate( + address vault, + uint256 repayAmount +) external onlyWhitelistedLiquidator nonReentrant; +``` + +**Parameters** + +| Name | Type | Description | +| ---- | ---- | ----------- | +| `vault` | `address` | Vault address to liquidate. | +| `repayAmount` | `uint256` | Amount of supply asset to repay. | + +### liquidateOverdueVault + +Deadline-based liquidation. Whitelisted settler only. + +```solidity +function liquidateOverdueVault( + address vault, + uint256 repayAmount +) external onlyWhitelistedSettler nonReentrant; +``` + +**Parameters** + +| Name | Type | Description | +| ---- | ---- | ----------- | +| `vault` | `address` | Vault address to liquidate. | +| `repayAmount` | `uint256` | Amount of supply asset to repay. | + +### renounceOwnership + +Disabled — renouncing ownership would permanently brick ACM-gated liquidation governance. + +**Note:** error: OwnershipCannotBeRenounced Always reverts. + +```solidity +function renounceOwnership() public pure override; +``` + +## Events + +### LiquidatorWhitelistUpdated + +```solidity +event LiquidatorWhitelistUpdated(address indexed liquidator, bool approved); +``` + +### SettlerWhitelistUpdated + +```solidity +event SettlerWhitelistUpdated(address indexed settler, bool approved); +``` + +### ProtocolLiquidationShareUpdated + +```solidity +event ProtocolLiquidationShareUpdated(uint256 oldShare, uint256 newShare); +``` + +### CloseFactorUpdated + +```solidity +event CloseFactorUpdated(uint256 oldCloseFactor, uint256 newCloseFactor); +``` + +### LiquidationCollateralSplit + +```solidity +event LiquidationCollateralSplit(uint256 totalSeized, uint256 protocolAmount, uint256 callerAmount); +``` + +### ProtocolShareSweptToReserve + +```solidity +event ProtocolShareSweptToReserve(address indexed collateral, uint256 amount); +``` + +## Errors + +### NotWhitelistedLiquidator + +```solidity +error NotWhitelistedLiquidator(); +``` + +### NotWhitelistedSettler + +```solidity +error NotWhitelistedSettler(); +``` + +### VaultNotRegistered + +```solidity +error VaultNotRegistered(); +``` + +### InvalidShare + +```solidity +error InvalidShare(); +``` + +### InvalidCloseFactor + +```solidity +error InvalidCloseFactor(); +``` + +### InvalidAddress + +```solidity +error InvalidAddress(); +``` + +### ZeroRepayAmount + +```solidity +error ZeroRepayAmount(); +``` + +### OwnershipCannotBeRenounced + +```solidity +error OwnershipCannotBeRenounced(); +``` diff --git a/technical-reference/reference-technical-articles/fixed-rate-vaults.md b/technical-reference/reference-technical-articles/fixed-rate-vaults.md index 613e5d6..b3044a3 100644 --- a/technical-reference/reference-technical-articles/fixed-rate-vaults.md +++ b/technical-reference/reference-technical-articles/fixed-rate-vaults.md @@ -12,13 +12,13 @@ The system is composed of four contracts. Each vault is an independent clone dep
Fixed Rate Vault contract architecture diagram

The controller deploys a fresh vault clone and mints a position NFT per loan; all liquidation calls are routed through the LiquidationAdapter

-**InstitutionalVaultController** 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. +**[InstitutionalVaultController](../reference-fixed-rate-vaults/institutional-vault-controller.md)** 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** 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. +**[InstitutionalLoanVault](../reference-fixed-rate-vaults/institutional-loan-vault.md)** 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** 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`. +**[InstitutionPositionToken](../reference-fixed-rate-vaults/institution-position-token.md)** 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** 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)`. +**[LiquidationAdapter](../reference-fixed-rate-vaults/liquidation-adapter.md)** 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 @@ -177,7 +177,7 @@ This mirrors Compound V2's `liquidationIncentiveMantissa` accounting: the protoc 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 verifies the shortfall and forwards to `vault.liquidate(repayAmount)` through the `onlyLiquidationAdapter` modifier. Inside the vault, `_executeLiquidation` enforces the close factor: if `repayAmount > outstandingDebt × closeFactor` the call reverts with `ExceedsCloseFactor` — it is a hard revert, not a silent cap. Seized collateral is split between the caller and the protocol per the formula 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. @@ -254,4 +254,5 @@ Governance operations (create, open, cancel, pause, close, risk-parameter update - [Supplier Guide](../../guides/fixed-rate-vaults/supplier-guide.md) - [Institution Guide](../../guides/fixed-rate-vaults/institution-guide.md) +- [Solidity API Reference](../reference-fixed-rate-vaults/README.md) - [Repository](https://github.com/VenusProtocol/fixed-rate-vaults) diff --git a/whats-new/fixed-rate-vaults.md b/whats-new/fixed-rate-vaults.md index 67fd82c..7f02d85 100644 --- a/whats-new/fixed-rate-vaults.md +++ b/whats-new/fixed-rate-vaults.md @@ -59,3 +59,4 @@ Both paths route through the `LiquidationAdapter`, which maintains separate ACM- - [Supplier Guide](../guides/fixed-rate-vaults/supplier-guide.md) — step-by-step walkthrough for lenders. - [Institution Guide](../guides/fixed-rate-vaults/institution-guide.md) — step-by-step walkthrough for borrowers. - [Fixed Rate Vaults Technical Reference](../technical-reference/reference-technical-articles/fixed-rate-vaults.md) — contract architecture, math, and liquidation paths in full detail. +- [Solidity API Reference](../technical-reference/reference-fixed-rate-vaults/README.md) — full function-level reference for all contracts. From ecd099b2c4379aff8d43f754654c4c72308ff607 Mon Sep 17 00:00:00 2001 From: GitGuru7 Date: Thu, 28 May 2026 09:16:09 +0530 Subject: [PATCH 04/25] docs: pin Fixed Rate Vaults to top of What's New --- SUMMARY.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SUMMARY.md b/SUMMARY.md index 3a8b233..f2eede7 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -8,6 +8,7 @@ ## What's New? +* [Fixed Rate Vaults](whats-new/fixed-rate-vaults.md) * [Trade](whats-new/trade.md) * [Leveraged Positions](whats-new/leveraged-positions.md) * [E-Mode](whats-new/e-mode.md) @@ -18,7 +19,6 @@ * [Automatic Income Allocation](whats-new/automatic-income-allocation.md) * [TokenBuyback Contract](whats-new/token-converter.md) * [Venus Prime](whats-new/prime-yield.md) -* [Fixed Rate Vaults](whats-new/fixed-rate-vaults.md) ## Governance From d96d3f685dc58737d9b216444b36d95540a14e3f Mon Sep 17 00:00:00 2001 From: GitGuru7 Date: Thu, 28 May 2026 09:26:18 +0530 Subject: [PATCH 05/25] docs: improve institution-guide --- guides/fixed-rate-vaults/institution-guide.md | 29 +++++++++++++++++-- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/guides/fixed-rate-vaults/institution-guide.md b/guides/fixed-rate-vaults/institution-guide.md index e14e857..fdb9760 100644 --- a/guides/fixed-rate-vaults/institution-guide.md +++ b/guides/fixed-rate-vaults/institution-guide.md @@ -8,11 +8,13 @@ To get started, reach out to the Venus team. Once the terms are agreed upon off- After deployment, you receive two things: -* The **vault address** — the target of every later action. +* 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. @@ -20,18 +22,28 @@ Deposit the margin into the vault in a single transaction. Partial deposits belo 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 deposit 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. +* **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. @@ -41,8 +53,15 @@ If fundraising succeeds but you don't top up the collateral in time, the margin 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 @@ -51,6 +70,10 @@ When the lock period ends, repayment is due. You have until the settlement deadl 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 %} From 136695411047c3fc08c707671cfc79e698fcfee0 Mon Sep 17 00:00:00 2001 From: Fred Date: Thu, 28 May 2026 17:29:05 +0800 Subject: [PATCH 06/25] Update SUMMARY.md Co-authored-by: zed-venus --- SUMMARY.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SUMMARY.md b/SUMMARY.md index f2eede7..89684d2 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -8,7 +8,7 @@ ## What's New? -* [Fixed Rate Vaults](whats-new/fixed-rate-vaults.md) +* [Fixed Term Vaults](whats-new/fixed-rate-vaults.md) * [Trade](whats-new/trade.md) * [Leveraged Positions](whats-new/leveraged-positions.md) * [E-Mode](whats-new/e-mode.md) From 2643f838dacb2355c86c3332aceebc3b5dc66763 Mon Sep 17 00:00:00 2001 From: Fred Date: Thu, 28 May 2026 17:29:25 +0800 Subject: [PATCH 07/25] Update SUMMARY.md Co-authored-by: zed-venus --- SUMMARY.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SUMMARY.md b/SUMMARY.md index 89684d2..8df3b3f 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -60,7 +60,7 @@ * [Isolated E-mode](guides/isolated-e-mode.md) * [Boost and Repay with Collateral](guides/leveraged-positions.md) * [Trade](guides/trade.md) -* [Fixed Rate Vaults](guides/fixed-rate-vaults/README.md) +* [Fixed Term Vaults](guides/fixed-rate-vaults/README.md) * [Institution Guide](guides/fixed-rate-vaults/institution-guide.md) * [Supplier Guide](guides/fixed-rate-vaults/supplier-guide.md) From 50c61998e4aa93efc895d20768d24c33acf7bc49 Mon Sep 17 00:00:00 2001 From: Fred Date: Thu, 28 May 2026 17:29:39 +0800 Subject: [PATCH 08/25] Update whats-new/fixed-rate-vaults.md Co-authored-by: zed-venus --- whats-new/fixed-rate-vaults.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/whats-new/fixed-rate-vaults.md b/whats-new/fixed-rate-vaults.md index 7f02d85..ffd29f6 100644 --- a/whats-new/fixed-rate-vaults.md +++ b/whats-new/fixed-rate-vaults.md @@ -58,5 +58,5 @@ Both paths route through the `LiquidationAdapter`, which maintains separate ACM- - [Supplier Guide](../guides/fixed-rate-vaults/supplier-guide.md) — step-by-step walkthrough for lenders. - [Institution Guide](../guides/fixed-rate-vaults/institution-guide.md) — step-by-step walkthrough for borrowers. -- [Fixed Rate Vaults Technical Reference](../technical-reference/reference-technical-articles/fixed-rate-vaults.md) — contract architecture, math, and liquidation paths in full detail. +- [Fixed Term Vaults Technical Reference](../technical-reference/reference-technical-articles/fixed-rate-vaults.md) — contract architecture, math, and liquidation paths in full detail. - [Solidity API Reference](../technical-reference/reference-fixed-rate-vaults/README.md) — full function-level reference for all contracts. From 5e6cf1096a1dd4547644559eed6a380382288f68 Mon Sep 17 00:00:00 2001 From: Fred Date: Thu, 28 May 2026 17:29:51 +0800 Subject: [PATCH 09/25] Update whats-new/fixed-rate-vaults.md Co-authored-by: zed-venus --- whats-new/fixed-rate-vaults.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/whats-new/fixed-rate-vaults.md b/whats-new/fixed-rate-vaults.md index ffd29f6..070b8f9 100644 --- a/whats-new/fixed-rate-vaults.md +++ b/whats-new/fixed-rate-vaults.md @@ -41,7 +41,7 @@ Fixed Rate Vaults are designed to give lenders certainty: Fixed Rate Vaults give borrowers control over their cost of capital: -- **Predictable cost.** The APY is fixed at vault creation — no variable-rate exposure over the loan term. +- **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. From 05f3e7c93e52ac98f42b9040fbfb9fbd421e621c Mon Sep 17 00:00:00 2001 From: Fred Date: Thu, 28 May 2026 17:30:08 +0800 Subject: [PATCH 10/25] Update whats-new/fixed-rate-vaults.md Co-authored-by: zed-venus --- whats-new/fixed-rate-vaults.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/whats-new/fixed-rate-vaults.md b/whats-new/fixed-rate-vaults.md index 070b8f9..efa27e3 100644 --- a/whats-new/fixed-rate-vaults.md +++ b/whats-new/fixed-rate-vaults.md @@ -47,7 +47,7 @@ Fixed Rate Vaults give borrowers control over their cost of capital: ## Liquidations -Fixed Rate Vaults run their own liquidation system, independent of Venus core. Two paths exist: +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. From 1ca3c2c80737607b122afb1ce6a5f54ba352c783 Mon Sep 17 00:00:00 2001 From: Fred Date: Thu, 28 May 2026 17:30:19 +0800 Subject: [PATCH 11/25] Update whats-new/fixed-rate-vaults.md Co-authored-by: zed-venus --- whats-new/fixed-rate-vaults.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/whats-new/fixed-rate-vaults.md b/whats-new/fixed-rate-vaults.md index efa27e3..992046e 100644 --- a/whats-new/fixed-rate-vaults.md +++ b/whats-new/fixed-rate-vaults.md @@ -39,7 +39,7 @@ Fixed Rate Vaults are designed to give lenders certainty: ### Institutions -Fixed Rate Vaults give borrowers control over their cost of capital: +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. From 67ba6ee83b225ee8d8b65cb7f261cdc914d0ae3b Mon Sep 17 00:00:00 2001 From: Fred Date: Thu, 28 May 2026 17:38:28 +0800 Subject: [PATCH 12/25] Update whats-new/fixed-rate-vaults.md Co-authored-by: zed-venus --- whats-new/fixed-rate-vaults.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/whats-new/fixed-rate-vaults.md b/whats-new/fixed-rate-vaults.md index 992046e..f35cae6 100644 --- a/whats-new/fixed-rate-vaults.md +++ b/whats-new/fixed-rate-vaults.md @@ -33,8 +33,8 @@ Every vault follows the same journey from creation to close. States move in one Fixed Rate Vaults are designed to give lenders certainty: -- **You know your yield upfront.** The APY and lock duration are fixed before fundraising opens — there's nothing to guess or monitor. -- **Collateral is posted before you can deposit.** 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. +- **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 From 18e8ab14fd1f31f6afa23f0e8ed75b10a79a45fb Mon Sep 17 00:00:00 2001 From: Fred Date: Thu, 28 May 2026 17:38:41 +0800 Subject: [PATCH 13/25] Update SUMMARY.md Co-authored-by: zed-venus --- SUMMARY.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SUMMARY.md b/SUMMARY.md index 8df3b3f..9cef3ef 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -220,7 +220,7 @@ * [Token Converters](deployed-contracts/token-converters.md) * [VenusERC4626](deployed-contracts/venus-erc4626.md) * [Periphery](deployed-contracts/periphery.md) -* [Fixed Rate Vaults](deployed-contracts/fixed-rate-vaults.md) +* [Fixed Term Vaults](deployed-contracts/fixed-rate-vaults.md) ## Services From 08a791bedc0aed605ca2cc18c25ddb18eb91a26e Mon Sep 17 00:00:00 2001 From: Fred Date: Thu, 28 May 2026 17:38:52 +0800 Subject: [PATCH 14/25] Update SUMMARY.md Co-authored-by: zed-venus --- SUMMARY.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SUMMARY.md b/SUMMARY.md index 9cef3ef..f5a06ce 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -153,7 +153,7 @@ * [MaxLoopsLimitHelper](technical-reference/reference-isolated-pools/utility/max-loops-limit-helper.md) * [ErrorReporter](technical-reference/reference-isolated-pools/utility/error-reporter.md) * [ExponentialNoError](technical-reference/reference-isolated-pools/utility/exponential-no-error.md) -* [Fixed Rate Vaults](technical-reference/reference-fixed-rate-vaults/README.md) +* [Fixed Term Vaults](technical-reference/reference-fixed-rate-vaults/README.md) * [InstitutionalVaultController](technical-reference/reference-fixed-rate-vaults/institutional-vault-controller.md) * [InstitutionalLoanVault](technical-reference/reference-fixed-rate-vaults/institutional-loan-vault.md) * [LiquidationAdapter](technical-reference/reference-fixed-rate-vaults/liquidation-adapter.md) From c46028d5988ce3dbb2265f0341eeb68932878b7f Mon Sep 17 00:00:00 2001 From: Fred Date: Thu, 28 May 2026 17:39:15 +0800 Subject: [PATCH 15/25] Update SUMMARY.md Co-authored-by: zed-venus --- SUMMARY.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SUMMARY.md b/SUMMARY.md index f5a06ce..c680c98 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -74,7 +74,7 @@ * [Diamond Comptroller in the Core pool](technical-reference/reference-technical-articles/diamond-comptroller.md) * [E-Mode](technical-reference/reference-technical-articles/e-mode.md) * [Trade](technical-reference/reference-technical-articles/trade.md) - * [Fixed Rate Vaults](technical-reference/reference-technical-articles/fixed-rate-vaults.md) + * [Fixed Term Vaults](technical-reference/reference-technical-articles/fixed-rate-vaults.md) * [Native Token Gateway](technical-reference/reference-technical-articles/native-token-gateway.md) * [Omnichain Governance](technical-reference/reference-technical-articles/omnichain-governance.md) * [Prime tokens](technical-reference/reference-technical-articles/prime.md) From c80ccc0c04121745502c36f72668971d191d3533 Mon Sep 17 00:00:00 2001 From: zed-venus Date: Thu, 28 May 2026 17:51:21 +0800 Subject: [PATCH 16/25] Apply suggestions from code review Co-authored-by: zed-venus --- guides/fixed-rate-vaults/supplier-guide.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/guides/fixed-rate-vaults/supplier-guide.md b/guides/fixed-rate-vaults/supplier-guide.md index cf8f105..155cd5c 100644 --- a/guides/fixed-rate-vaults/supplier-guide.md +++ b/guides/fixed-rate-vaults/supplier-guide.md @@ -1,8 +1,12 @@ # Supplier Guide -This guide walks through how to participate in a Fixed Rate Vault as a supplier. You deposit the loan asset during the fundraising window, hold through the lock period, and redeem principal plus the fixed yield at maturity. +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. -## Before You Deposit +{% 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 %} + +## Before You Supply Each vault has a published set of terms set at deployment. Before committing funds, review: From 65daa6412946e6b29517a3901df0cdd3f4304173 Mon Sep 17 00:00:00 2001 From: zed-venus Date: Thu, 28 May 2026 17:53:19 +0800 Subject: [PATCH 17/25] Apply suggestions from code review wording revision Co-authored-by: zed-venus --- deployed-contracts/fixed-rate-vaults.md | 8 ++++---- guides/fixed-rate-vaults/README.md | 10 +++++----- guides/fixed-rate-vaults/institution-guide.md | 10 +++++----- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/deployed-contracts/fixed-rate-vaults.md b/deployed-contracts/fixed-rate-vaults.md index 8456f74..10ee93c 100644 --- a/deployed-contracts/fixed-rate-vaults.md +++ b/deployed-contracts/fixed-rate-vaults.md @@ -1,10 +1,10 @@ -# Fixed Rate Vaults +# Fixed Term Vaults -Core contracts for the Fixed Rate Vaults system. Each institution's vault is deployed as an EIP-1167 clone by governance via `createVault(...)` on `InstitutionalVaultController`, so individual vault instances are not enumerated here — query the controller's `allVaults` array (or the `VaultCreated` event log) to enumerate deployed vaults. +Core contracts for the Fixed Term Vaults system. Each institution's vault is deployed as an EIP-1167 clone by governance via `createVault(...)` on `InstitutionalVaultController`, so individual vault instances are not enumerated here — query the controller's `allVaults` array (or the `VaultCreated` event log) to enumerate deployed vaults. ## BNB Chain Mainnet -### Fixed Rate Vaults Contracts +### Fixed Term Vaults Contracts * InstitutionalVaultController (proxy): [`0x6D9e91cB766259af42619c14c994E694E57e6E85`](https://bscscan.com/address/0x6D9e91cB766259af42619c14c994E694E57e6E85) * InstitutionPositionToken: [`0x3Ed56f6937fc8549f9325405d1e8E650739647Fa`](https://bscscan.com/address/0x3Ed56f6937fc8549f9325405d1e8E650739647Fa) @@ -12,7 +12,7 @@ Core contracts for the Fixed Rate Vaults system. Each institution's vault is dep ## BNB Chain Testnet -### Fixed Rate Vaults Contracts +### Fixed Term Vaults Contracts * InstitutionalVaultController (proxy): [`0xf77dED2A00F94e33C392126238360D4642c16Ba2`](https://testnet.bscscan.com/address/0xf77dED2A00F94e33C392126238360D4642c16Ba2) * InstitutionPositionToken: [`0x71dA473257a96e975558C8edD8491AD0880EFCe5`](https://testnet.bscscan.com/address/0x71dA473257a96e975558C8edD8491AD0880EFCe5) diff --git a/guides/fixed-rate-vaults/README.md b/guides/fixed-rate-vaults/README.md index d02ce53..8578bf4 100644 --- a/guides/fixed-rate-vaults/README.md +++ b/guides/fixed-rate-vaults/README.md @@ -1,11 +1,11 @@ -# Fixed Rate Vaults +# Fixed Term Vaults -Fixed Rate 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 headline APY at maturity. Each vault funds a single loan and closes once settlement is complete. +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) — deposits the loan asset during fundraising, holds through the lock period, and redeems principal plus the fixed yield once the institution has repaid. +* **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. @@ -14,6 +14,6 @@ Available on BNB Chain. | 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](institution-guide.md) | -| **Supplier** — you want to deposit during fundraising and earn the fixed yield at maturity | [Supplier Guide](supplier-guide.md) | +| **Supplier** — you want to supply during fundraising and earn the target yield at maturity | [Supplier Guide](supplier-guide.md) | -For the contract-level details, see the [Fixed Rate Vaults Technical Reference](../../technical-reference/reference-technical-articles/fixed-rate-vaults.md). +For the contract-level details, see the [Fixed Term Vaults Technical Reference](../../technical-reference/reference-technical-articles/fixed-rate-vaults.md). diff --git a/guides/fixed-rate-vaults/institution-guide.md b/guides/fixed-rate-vaults/institution-guide.md index fdb9760..53790cb 100644 --- a/guides/fixed-rate-vaults/institution-guide.md +++ b/guides/fixed-rate-vaults/institution-guide.md @@ -1,6 +1,6 @@ # Institution Guide -This guide walks through the institution's lifecycle in a Fixed Rate 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. +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 @@ -28,7 +28,7 @@ If you never deposit the margin, the vault simply sits idle. Venus can cancel an ## Step 2: Wait for the Vault to Open -After the margin lands, Venus opens the vault and starts the fundraising window. Suppliers can now deposit the loan asset. No action is required from you in this step. +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.) @@ -80,7 +80,7 @@ Missing the settlement deadline makes the vault liquidatable at the late-penalty ## Key Risks You Must Understand -A Fixed Rate Vault is a fixed-term commitment with a few timing-sensitive obligations. Be aware of the following before participating: +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** @@ -96,7 +96,7 @@ A Fixed Rate Vault is a fixed-term commitment with a few timing-sensitive obliga 4. **No early changes to terms** - Fixed APY, 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. + 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 @@ -106,4 +106,4 @@ A Fixed Rate Vault is a fixed-term commitment with a few timing-sensitive obliga * **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 Rate Vaults Technical Reference](../../technical-reference/reference-technical-articles/fixed-rate-vaults.md). +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.md). From 39664d564405de0586a100f83ed698ee0f2696b5 Mon Sep 17 00:00:00 2001 From: zed-venus Date: Thu, 28 May 2026 17:55:48 +0800 Subject: [PATCH 18/25] Apply suggestions from code review Co-authored-by: zed-venus --- guides/fixed-rate-vaults/supplier-guide.md | 26 +++++++++++----------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/guides/fixed-rate-vaults/supplier-guide.md b/guides/fixed-rate-vaults/supplier-guide.md index 155cd5c..bda3a62 100644 --- a/guides/fixed-rate-vaults/supplier-guide.md +++ b/guides/fixed-rate-vaults/supplier-guide.md @@ -10,26 +10,26 @@ This guide walks through how to participate in a Fixed Term Vault as a supplier. Each vault has a published set of terms set at deployment. Before committing funds, review: -* **Fixed APY** — the annualized rate paid on your deposit. +* **Target APR** — the annualized target rate this vault aims to deliver. Actual return is variable and depends on counterparty performance; capital is at risk. * **Lock duration** — how long your funds are locked after fundraising closes. -* **Minimum and maximum raise** — the minimum needed to actually fund the loan, and the ceiling beyond which deposits are rejected. -* **Minimum deposit** — the floor for a single deposit. -* **Supply asset** — the asset you deposit. -* **Fundraising window** — when deposits close. +* **Minimum and maximum raise** — the minimum needed to actually fund the loan, and the ceiling above which the vault stops accepting supplies. +* **Minimum supply** — the floor for a single supply. +* **Supply asset** — the asset you supply. +* **Fundraising window** — when supplying closes. -## Step 1: Deposit During Fundraising +## Step 1: Supply During Fundraising -While fundraising is open, deposit the supply asset into the vault. You receive vault share tokens representing your claim. The shares are freely transferable, so you can hold them in any wallet. +While fundraising is open, supply your assets into the vault. You receive vault share tokens representing your claim. The shares are freely transferable, so you can hold them in any wallet. -**Minimum deposit floor** applies unless you're filling the final residual capacity, in which case the floor is waived so the cap can actually be reached. +**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. ## Step 2: Hold Through the Lock Period When the fundraising window closes with the raise above the minimum, the vault enters the lock period. At this point: -* **Deposits and withdrawals are blocked.** There is no early exit. +* **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. @@ -49,7 +49,7 @@ Redeem as soon as possible. If funds remain unclaimed for too long, Venus may sw ### Worked Example -A vault raises 100,000 USDC at 8% fixed APY for a 90-day lock. You deposit 10,000 USDC and receive shares representing 10% of the vault. +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}$$ @@ -59,7 +59,7 @@ A vault raises 100,000 USDC at 8% fixed APY for a 90-day lock. You deposit 10,00 ## Key Risks You Must Understand -A Fixed Rate Vault is a fixed-term commitment. Be aware of the following before participating: +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. @@ -69,7 +69,7 @@ A Fixed Rate Vault is a fixed-term commitment. Be aware of the following before ## Best Practices -* **Read the vault terms carefully.** APY, lock duration, and the minimum-raise threshold determine your worst-case outcome. +* **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. ## Recovering Your Funds @@ -85,4 +85,4 @@ When the vault reaches a terminal state, redemption is available. Burn your shar --- -For the on-chain details, including the full state machine, function signatures, math, and liquidation paths, see the [Fixed Rate Vaults Technical Reference](../../technical-reference/reference-technical-articles/fixed-rate-vaults.md). +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.md). From 8f2adbf19870b74e1503180e55c3ee323b3465ff Mon Sep 17 00:00:00 2001 From: zed-venus Date: Thu, 28 May 2026 17:57:24 +0800 Subject: [PATCH 19/25] Apply suggestions from code review Co-authored-by: zed-venus --- .../reference-fixed-rate-vaults/README.md | 4 ++-- .../reference-fixed-rate-vaults/base-vault.md | 2 +- .../institutional-loan-vault.md | 2 +- .../fixed-rate-vaults.md | 12 ++++++------ whats-new/fixed-rate-vaults.md | 4 ++-- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/technical-reference/reference-fixed-rate-vaults/README.md b/technical-reference/reference-fixed-rate-vaults/README.md index c217f61..3a48813 100644 --- a/technical-reference/reference-fixed-rate-vaults/README.md +++ b/technical-reference/reference-fixed-rate-vaults/README.md @@ -1,6 +1,6 @@ -# Fixed Rate Vaults +# Fixed Term Vaults -Solidity API reference for the Fixed Rate Vault system, generated from NatSpec. +Solidity API reference for the Fixed Term Vault system, generated from NatSpec. The system has three singleton contracts, one vault implementation contract (cloned per loan by the controller), and one abstract base: diff --git a/technical-reference/reference-fixed-rate-vaults/base-vault.md b/technical-reference/reference-fixed-rate-vaults/base-vault.md index 1701a16..2f9b4ad 100644 --- a/technical-reference/reference-fixed-rate-vaults/base-vault.md +++ b/technical-reference/reference-fixed-rate-vaults/base-vault.md @@ -4,7 +4,7 @@ **Title:** BaseVault -Abstract base ERC-4626 vault providing shared mechanics for all Venus fixed-rate vault types: +Abstract base ERC-4626 vault providing shared mechanics for all Venus fixed-term vault types: fundraising (time-bounded deposit window), interest computation, settlement (protocol fee waterfall), and core state machine transitions. diff --git a/technical-reference/reference-fixed-rate-vaults/institutional-loan-vault.md b/technical-reference/reference-fixed-rate-vaults/institutional-loan-vault.md index 3627429..cafa4bf 100644 --- a/technical-reference/reference-fixed-rate-vaults/institutional-loan-vault.md +++ b/technical-reference/reference-fixed-rate-vaults/institutional-loan-vault.md @@ -4,7 +4,7 @@ **Title:** InstitutionalLoanVault -ERC-4626 vault for institutional fixed-rate lending with on-chain collateral, +ERC-4626 vault for institutional fixed-term lending with on-chain collateral, borrowing, and liquidation support. Deployed as EIP-1167 minimal proxy clones. Inherits BaseVault for shared ERC-4626 mechanics, fundraising, interest, settlement, diff --git a/technical-reference/reference-technical-articles/fixed-rate-vaults.md b/technical-reference/reference-technical-articles/fixed-rate-vaults.md index b3044a3..8aa2c26 100644 --- a/technical-reference/reference-technical-articles/fixed-rate-vaults.md +++ b/technical-reference/reference-technical-articles/fixed-rate-vaults.md @@ -1,6 +1,6 @@ -# Fixed Rate Vaults +# Fixed Term Vaults -A Fixed Rate 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. +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. @@ -10,7 +10,7 @@ Each vault is a fully isolated contract clone — its own collateral, its own de The system is composed of four contracts. Each vault is an independent clone deployed by the controller — there is no shared state between loans. -
Fixed Rate Vault contract architecture diagram

The controller deploys a fresh vault clone and mints a position NFT per loan; all liquidation calls are routed through the LiquidationAdapter

+
Fixed Term Vault contract architecture diagram

The controller deploys a fresh vault clone and mints a position NFT per loan; all liquidation calls are routed through the LiquidationAdapter

**[InstitutionalVaultController](../reference-fixed-rate-vaults/institutional-vault-controller.md)** 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. @@ -22,7 +22,7 @@ The system is composed of four contracts. Each vault is an independent clone dep ### 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-rate 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. +`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: @@ -51,7 +51,7 @@ Both the supply asset and the collateral asset must have a non-zero oracle price 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. -
Fixed Rate Vault state machine diagram

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 closeVault()

+
Fixed Term Vault state machine diagram

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 closeVault()

## Core mechanics @@ -199,7 +199,7 @@ All tunable parameters grouped by contract, mutability, and who sets them. | --- | --- | --- | --- | | 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 | -| Fixed APY | `VaultConfig.fixedAPY` | basis points | 1 – 10 000 | +| 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` | diff --git a/whats-new/fixed-rate-vaults.md b/whats-new/fixed-rate-vaults.md index f35cae6..dbbd77a 100644 --- a/whats-new/fixed-rate-vaults.md +++ b/whats-new/fixed-rate-vaults.md @@ -1,6 +1,6 @@ -# Fixed Rate Vaults +# Fixed Term Vaults -Venus Protocol is introducing a new way to earn and borrow: **Fixed Rate 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 Rate 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 fixed APY, and get their principal back at maturity. No rate fluctuations, no surprises — just a clear term with a clear outcome. From 770b291b6ee4a84d1002a28c3ff041fabcac06d5 Mon Sep 17 00:00:00 2001 From: zed-venus Date: Thu, 28 May 2026 17:58:19 +0800 Subject: [PATCH 20/25] Apply suggestions from code review Co-authored-by: zed-venus --- whats-new/fixed-rate-vaults.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/whats-new/fixed-rate-vaults.md b/whats-new/fixed-rate-vaults.md index dbbd77a..b94f278 100644 --- a/whats-new/fixed-rate-vaults.md +++ b/whats-new/fixed-rate-vaults.md @@ -2,23 +2,23 @@ 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 Rate 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 fixed APY, and get their principal back at maturity. No rate fluctuations, no surprises — just a clear term with a clear outcome. +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. -
Fixed Rate Vault fund flow diagram

Suppliers deposit stablecoin into the vault, the institution receives the loan and repays with interest, and suppliers redeem principal plus yield at maturity

+
Fixed Term Vault fund flow diagram

Suppliers supply stablecoins into the vault, the institution receives the loan and repays with interest, and suppliers redeem principal plus target yield at maturity

## How a Vault Progresses -
Fixed Rate Vault state machine diagram

Fixed Rate Vault state transitions

+
Fixed Term Vault state machine diagram

Fixed Term Vault state transitions

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 deposit. 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. +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. @@ -31,7 +31,7 @@ Every vault follows the same journey from creation to close. States move in one ### Suppliers -Fixed Rate Vaults are designed to give lenders certainty: +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. From 4a1bbad62aa09477f76b52989ad90ab1c47bd819 Mon Sep 17 00:00:00 2001 From: zed-venus Date: Thu, 28 May 2026 18:00:41 +0800 Subject: [PATCH 21/25] Update guides/fixed-rate-vaults/supplier-guide.md --- guides/fixed-rate-vaults/supplier-guide.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/guides/fixed-rate-vaults/supplier-guide.md b/guides/fixed-rate-vaults/supplier-guide.md index bda3a62..8c503ad 100644 --- a/guides/fixed-rate-vaults/supplier-guide.md +++ b/guides/fixed-rate-vaults/supplier-guide.md @@ -53,7 +53,7 @@ A vault raises 100,000 USDC at an 8% target APR for a 90-day lock. You supply 10 * 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 interest paid to suppliers: $$1{,}972.60 - 197.26 \approx 1{,}775.34 \text{ USDC}$$ +* Target net 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's a return of ~1.78% over the 90-day term on your 10,000 USDC principal. From e9c42f5085fca49be98c9261a37f22a034c3e63f Mon Sep 17 00:00:00 2001 From: zed-venus Date: Thu, 28 May 2026 18:00:51 +0800 Subject: [PATCH 22/25] Update guides/fixed-rate-vaults/supplier-guide.md --- guides/fixed-rate-vaults/supplier-guide.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/guides/fixed-rate-vaults/supplier-guide.md b/guides/fixed-rate-vaults/supplier-guide.md index 8c503ad..72dcbe2 100644 --- a/guides/fixed-rate-vaults/supplier-guide.md +++ b/guides/fixed-rate-vaults/supplier-guide.md @@ -55,7 +55,7 @@ A vault raises 100,000 USDC at an 8% target APR for a 90-day lock. You supply 10 * Assume a 10% protocol fee on interest: $$1{,}972.60 \times 0.10 \approx 197.26 \text{ USDC}$$ * Target net 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's a return of ~1.78% over the 90-day term on your 10,000 USDC principal. +* Your share (10%): **~10,177.53 USDC**. That's should be a return of ~1.78% over the 90-day term on your 10,000 USDC principal. ## Key Risks You Must Understand From 1b8df7cecc5cf8128b3d3914619cec80caf03690 Mon Sep 17 00:00:00 2001 From: zed-venus Date: Thu, 28 May 2026 21:11:29 +0800 Subject: [PATCH 23/25] Update guides/fixed-rate-vaults/supplier-guide.md --- guides/fixed-rate-vaults/supplier-guide.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/guides/fixed-rate-vaults/supplier-guide.md b/guides/fixed-rate-vaults/supplier-guide.md index 72dcbe2..5d4c4ca 100644 --- a/guides/fixed-rate-vaults/supplier-guide.md +++ b/guides/fixed-rate-vaults/supplier-guide.md @@ -65,7 +65,7 @@ A Fixed Term Vault is a fixed-term commitment. Be aware of the following before * **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 headline yield. +* **Liquidation may reduce recovery.** If collateral didn't fully cover the debt, your payout may be less than the target rewards. ## Best Practices From b75c2eb513b5d1f0341a4e77280d627cfa343dcf Mon Sep 17 00:00:00 2001 From: zed-venus Date: Thu, 28 May 2026 21:11:43 +0800 Subject: [PATCH 24/25] Update guides/fixed-rate-vaults/supplier-guide.md --- guides/fixed-rate-vaults/supplier-guide.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/guides/fixed-rate-vaults/supplier-guide.md b/guides/fixed-rate-vaults/supplier-guide.md index 5d4c4ca..b16f3c6 100644 --- a/guides/fixed-rate-vaults/supplier-guide.md +++ b/guides/fixed-rate-vaults/supplier-guide.md @@ -55,7 +55,7 @@ A vault raises 100,000 USDC at an 8% target APR for a 90-day lock. You supply 10 * Assume a 10% protocol fee on interest: $$1{,}972.60 \times 0.10 \approx 197.26 \text{ USDC}$$ * Target net 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's should be a return of ~1.78% over the 90-day term on your 10,000 USDC principal. +* 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 From 1bd0c11d051b67385170cb0744da4d004d3f2cab Mon Sep 17 00:00:00 2001 From: zed-venus Date: Thu, 28 May 2026 21:11:56 +0800 Subject: [PATCH 25/25] Update guides/fixed-rate-vaults/supplier-guide.md --- guides/fixed-rate-vaults/supplier-guide.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/guides/fixed-rate-vaults/supplier-guide.md b/guides/fixed-rate-vaults/supplier-guide.md index b16f3c6..aeb1d37 100644 --- a/guides/fixed-rate-vaults/supplier-guide.md +++ b/guides/fixed-rate-vaults/supplier-guide.md @@ -53,7 +53,7 @@ A vault raises 100,000 USDC at an 8% target APR for a 90-day lock. You supply 10 * 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}$$ -* Target net interest paid to suppliers: $$1{,}972.60 - 197.26 \approx 1{,}775.34 \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.