Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Minting nUSD is the process of creating a secured debt position by depositing approved collateral into the Unstable Protocol.
To mint nUSD, you need to deposit approved yield-bearing collateral into one of Unstable's vaults:
Connect your wallet to the Unstable Protocol dApp
Navigate to the "Mint" section
Select the type of collateral you want to deposit:
ETH-based assets (scETH, etc.)
S-based assets (stS, etc.)
USD-pegged assets (scUSD, wstkscUSD, etc.)
Enter the amount of collateral you want to deposit
The system will calculate how much nUSD you can mint based on the current collateralization ratio for that asset type
Confirm the transaction
Each collateral type has a required minimum collateralization ratio (e.g., 125%), which means you must always maintain that buffer. For example, if your collateral is worth $1,250, you could borrow up to $1,000 nUSD at a 125% ratio.
Unstable charges interest on nUSD loans based on the specific vault and collateral type. The interest rate is determined by the protocol parameters and may vary over time.
Your collateral's yield continues to accumulate, which can help offset the interest costs and improve your loan health over time.
The Unstable Protocol uses overcollateralization to ensure the stability of nUSD. This page explains how collateralization works and what happens during liquidation.
Every nUSD in circulation is backed by more than $1 worth of collateral. The protocol requires users to maintain a minimum collateralization ratio for their positions. This ratio varies by collateral type but is typically at least 125%.
The Position Management component handles user collateral positions, deposits, and nUSD minting/burning operations.
The Unstable Protocol uses a unique fee structure that differs from traditional lending platforms. Instead of ongoing interest charges, Unstable implements a one-time fee model that makes borrowing costs predictable.
Unstable charges interest on nUSD loans based on the specific vault and collateral type. The interest rate varies based on market conditions and protocol parameters.
Other supported tokens with price feeds
Unstable accepts multiple types of high-quality collateral across different asset classes:
stS
scETH
scUSD
wstkscUSD: Wrapped staked scUSD
[REDACTED]
[REDACTED]
Your position's health is determined by the ratio between your collateral's value and your debt. To calculate this:
Collateralization Ratio = (Collateral Value) / (nUSD Debt)
You can monitor your collateral health on the Unstable Protocol dashboard. It's important to maintain a healthy buffer above the minimum required ratio to protect against market volatility.
Liquidation is the mechanism that ensures the protocol remains solvent even when collateral values drop.
If a vault's collateral falls below the safe threshold (e.g., 125%), it becomes eligible for liquidation. This can happen due to:
A decrease in the market value of your collateral
A depeg of the collateral asset (for stablecoin collaterals)
When liquidation occurs:
The system detects that a position has fallen below the minimum collateralization ratio
The Stability Pool provides nUSD to cover the debt
The liquidated collateral (minus a penalty) is distributed to Stability Pool depositors
The user's debt is cleared, and any remaining collateral is returned to the user
A liquidation fee is applied when positions fall below the minimum collateralization ratio. The exact fee varies by collateral type.
To prevent liquidation:
Monitor your position regularly
Add more collateral when your ratio approaches the minimum threshold
Partially repay your debt to improve your collateralization ratio
Maintain a healthy buffer above the minimum required ratio
Navigate to the "Repay" section
Select the vault containing your collateral
Enter the amount of nUSD you want to repay
Confirm the transaction
You can make partial repayments of your nUSD debt. When you do this, a proportional amount of your collateral will be unlocked and available for withdrawal.
After repaying your nUSD debt, you can withdraw your collateral:
Navigate to the "Withdraw" section
Select the vault containing your collateral
Enter the amount of collateral you want to withdraw
Confirm the transaction
There are no fixed terms for nUSD loans – you manage your position as needed. By keeping a healthy safety margin above the minimum ratio, you can borrow long-term without worrying about immediate liquidation risk.
Unstable Protocol enables users to borrow against yield-bearing assets without sacrificing their staking rewards. The protocol's stablecoin, nUSD, is overcollateralized by productive assets like liquid staking derivatives that continue generating returns while serving as collateral, creating a unique capital efficiency advantage.
By enabling users to maintain exposure to staking rewards while accessing liquidity, Unstable creates a powerful capital efficiency multiplier effect:
Dual-purpose assets: Collateral simultaneously secures loans and generates yield
Self-improving collateral ratios: As yield accumulates, position health naturally strengthens
Reduced liquidation risk: Growing collateral value provides increasing protection against market volatility
Every nUSD is backed by more than $1 of high-quality collateral:
Overcollateralization: Minimum 1XX% collateral ratio (varies by asset)
Yield-bearing collateral: Assets like stETH, rETH, and other LSDs that grow in value over time
Automated liquidations: Swift protection against undercollateralization
Redemption mechanism: Direct 1:1 USD value redemption for underlying collateral
Mint Only
Mint nUSD against existing collateral
mint(address onBehalfOf, uint256 amount)
Repay
Burn nUSD without withdrawing
burn(address onBehalfOf, uint256 amount)
Deposit and Mint
Deposit collateral and mint nUSD
depositAssetToMint(uint256 assetAmount, uint256 mintAmount)
Withdraw
Withdraw collateral after repaying
withdraw(address onBehalfOf, uint256 amount)
Deposit Only
Deposit collateral without minting
depositAssetToMint(uint256 assetAmount, 0)
When you mint nUSD, you pay a one-time origination fee. This fee is calculated as a percentage of the borrowed amount and is deducted from the nUSD you receive.
The origination fee varies based on several factors:
Vault utilization: Higher utilization rates result in higher fees
Collateral type: Different collateral types may have different fee structures
Protocol parameters: The fee is adjusted based on market conditions
The fee structure is designed to:
Ensure protocol sustainability
Promote responsible borrowing
Balance supply and demand for different collateral types
The origination fee is calculated using the following formula:
Where the Fee Percentage is determined by:
Min Fee: The minimum fee percentage (in basis points) at 0% utilization
Max Fee: The maximum fee percentage (in basis points) at max utilization
Utilization: Current vault utilization (total borrowed / max supply)
Max Utilization: The utilization level at which the maximum fee applies
When redeeming nUSD for collateral, a redemption fee is applied. This fee varies based on:
Base fee: Minimum fee for redemption
Collateral ratio: Higher collateral ratios may result in higher fees
Provider share: Portion of the fee that goes to the redemption provider
The protocol also supports flash loans of nUSD with an associated fee. Flash loans allow you to borrow nUSD without collateral, as long as you repay the loan within the same transaction.
// Approve collateral for deposit
IERC20(collateralToken).approve(vaultAddress, collateralAmount);
// Deposit collateral and mint nUSD in one transaction
IVault(vaultAddress).depositAssetToMint(collateralAmount, nusdAmount);
// Check updated position
(uint256 collateral, uint256 debt) = IVault(vaultAddress).positions(userAddress);// Approve nUSD for burning
IERC20(nUSDAddress).approve(vaultAddress, debtAmount);
// Burn nUSD to reduce debt
IVault(vaultAddress).burn(userAddress, debtAmount);
// Withdraw collateral
IVault(vaultAddress).withdraw(userAddress, collateralAmount);Fee = Borrowed Amount * Fee Percentage / 10000Fee Percentage = Min Fee + (Max Fee - Min Fee) * Utilization / Max UtilizationThe Unstable Protocol is designed with a flexible architecture to support different collateral types and provide adaptability for future upgrades. It organizes protocol functions into logical components with clear responsibilities, creating a cohesive system.
UnstableConfigurator: Central configuration contract that manages system parameters
Vaults (BaseVault and implementations): Manage collateral and debt positions
nUSD: The protocol's USD-pegged stablecoin
Oracles: Provide price data for collateral assets
Each functional component in the Unstable Protocol is implemented through specific contracts:
The protocol supports multiple vault types for different collateral assets:
ETH-based vaults: For scETH and other yield-bearing ETH wrappers
Sonic-based vaults: For staked S-based collateral
Stablecoin vaults: For USD-pegged assets
Token vaults: For other tokens with reliable price feeds
nUSD: The protocol's USD-pegged stablecoin
Collateral tokens: Various yield-bearing assets accepted by vaults
graph TD
A[Position Management] <--> B[Interest & Fees]
A <--> C[Price Oracle]
A <--> D[Liquidation System]
A <--> E[Redemption System]
F[Emergency Controls] --> A
F --> B
F --> D
F --> E
C --> D
C --> ERedemption System
BaseVault (redemption methods)
Convert nUSD to collateral
Emergency Controls
UnstableConfigurator
Emergency controls and pauses
Position Management
BaseVault, StakedEthVault, etc.
Manage user positions and collateral
Interest and Fees
UnstableConfigurator
Handle origination fees
Price Oracle
Chainlink, zkOracle
Provide price data
Liquidation System
BaseVault (liquidation methods)
Manage position health
The Redemption System component handles redemption of nUSD for collateral.
Redeem
Redeem nUSD for collateral
redemption(address debtor, uint256 nusdAmount, uint256 minReceiveAmount)
Calculate Redemption
Calculate redemption amounts
calculateRedemption(address provider, uint256 nusdAmount)
The Liquidation System component handles the liquidation of unhealthy positions.
Liquidate Position
Liquidate an unhealthy position
liquidation(address provider, address debtor, uint256 assetAmount)
Check Liquidation Status
Check if position is liquidatable
getLiquidateableAmount(address user)
The Emergency Controls component provides safety mechanisms and pause functions for the protocol through the UnstableConfigurator contract, which is the central registry that manages protocol parameters and access control.
The configurator serves several key functions:
Stores the mapping between collateral assets and their oracles
// Calculate redemption details
(uint256 providerFee, uint256 protocolFee, uint256 nusdToProtocol, uint256 nusdToRepay, uint256 nusdToConvert, uint256 collateralReceived) =
IVault(vaultAddress).calculateRedemption(userAddress, nusdAmount);
// Approve nUSD for redemption
IERC20(nUSDAddress).approve(vaultAddress, nusdAmount);
// Execute redemption with minimum amount check
IVault(vaultAddress).redemption(userAddress, nusdAmount, minCollateralAmount);// Get the origination fee percentage for a vault
uint256 originationFee = IVault(vaultAddress).getOriginationFee();
// Calculate the fee amount for a specific mint amount
uint256 feeAmount = (mintAmount * originationFee) / 10000; // Fee is in basis points// Check if a position is liquidatable
uint256 liquidateableAmount = IVault(vaultAddress).getLiquidateableAmount(userAddress);
// If liquidateable, execute liquidation
if (liquidateableAmount > 0) {
IVault(vaultAddress).liquidation(
liquidatorAddress, // Provider of nUSD for liquidation
userAddress, // Debtor whose position is being liquidated
liquidateableAmount // Amount of collateral to liquidate
);
}Maintains a list of vaults that are enabled to mint nUSD
Configures settings for each vault (fees, collateral ratios, etc.)
Manages access control for privileged operations
Provides emergency pause functionality for protocol operations
Pause
Pause protocol functions
toggleVaultMintPause(address vault)
Unpause
Unpause protocol functions
toggleVaultMintPause(address vault)
The configurator has two levels of access:
Owner: Higher level privilege, typically a multisig wallet with timelock. Can add vaults capable of minting nUSD and make other critical changes.
Admin: Lower level privilege for emergency pauses and low-risk parameter adjustments.
To configure emergency controls:
Note: Emergency functions are only accessible to protocol administrators and not available through standard integration.
// Pause minting for a vault in case of emergency
configurator.toggleVaultMintPause(vaultAddress);
// Unpause minting for a vault after emergency is resolved
configurator.toggleVaultMintPause(vaultAddress);StakedEthVault
StakedTokenVault
UnstableConfigurator
nUSD
stSOracle
scUSDOracle
scETHOracle
wstkscUSDOracle
StakedStableVault1
StakedStableVault2
Unstable Protocol shares its core CDP architecture with Lybra V2, a battle-tested system that has undergone multiple audits by Consensys, Halborn, and Code4rena.
Unstable Protocol was audited by KALOS Security in May 2024. The audit report can be found here.
Additionally, Unstable Protocol engaged Alberto Cuesta Cañada—co-author of ERC4626 (Tokenized Vaults), ERC3156 (Flash Loans), and ERC7266 (Oracles); former CTO of Yield Protocol; current judge for Code4rena, Cantina and engineer at Optimism —as a consultant. Alberto contributed to both protocol mechanics and the design of our testing framework, which applies the Branching Tree Technique (BTT) to exhaustively map edge cases and protocol invariants.
Multi-tier access control scheme separates critical functions (Owner) from operational functions (Admin), enabling rapid emergency responses while protecting high-impact changes
Vault-level pause switches for mint, burn, and redemption
Supply caps per vault to limit risk exposure
Multiple oracle types with ability to update if compromised
Toggle between redemption rate and market pricing modes
Depeg thresholds to auto-pause minting during market instability
Collateral types are classified as stable-denominated, ETH-denominated, and volatile/other-denominated wrappers
Stable-denominated wrappers (e.g. scUSD, wstkscUSD): high initial LTVs (up to 97%) with strict peg stability, liquidity, and oracle integrity requirements
ETH-denominated wrappers (e.g. scETH): moderate LTVs (e.g. 80%) with risk buffers for slashing, withdrawal delays, and price tracking deviations
The Price Oracle component is a critical part of the Unstable Protocol, providing price data for collateral assets that is used to calculate collateralization ratios, determine liquidation events, and facilitate redemptions.
All oracles in the Unstable Protocol implement the IZkOracle interface:
Redemption Rate: The contract rate at which the collateral can be redeemed for the underlying asset.
Market Rate: The current market price of the collateral, which may differ from the redemption rate.
The protocol can be configured to use either rate through the useMarketRate setting in the UnstableConfigurator.
The oracle system includes a mechanism to detect when a collateral asset has depegged from its expected value:
Depeg Threshold: A parameter that determines the maximum allowed divergence between redemption and market rates.
If the divergence exceeds this threshold, minting with that collateral can be automatically paused.
Oracles can be implemented in various ways:
Direct Integration: For assets with on-chain price data
Chainlink Oracles: For reliable, decentralized price feeds
Custom ZkOracles: For assets requiring more complex verification
interface IZkOracle {
// Returns the address of the asset
function assetAddress() external view returns (address);
// Returns the redemption rate (contract rate) in underlying terms
function getRedemptionRate() external view returns (uint256);
// Returns the market rate in underlying terms
function getMarketRate() external view returns (uint256);
}All assets must meet minimum on-chain liquidity thresholds
Initial debt ceilings are capped per asset; borrowing is limited until stability and liquidity are proven over time
Timelock delay is enforced for onboarding and parameter changes
Parameters are scaled gradually with protocol adoption; risk settings tighten as TVL grows to preserve solvency
Get Market Rate
Get current market rate
getMarketRate()
Get Redemption Rate
Get redemption rate
getRedemptionRate()
Check Depeg Status
Check if asset is depegged
isDepegged()
// Get the market price of the collateral
uint256 marketPrice = IVault(vaultAddress).getMarketRate();
// Get the redemption rate (typically lower than market)
uint256 redemptionRate = IVault(vaultAddress).getRedemptionRate();
// Check if asset is depegged
bool depegged = IVault(vaultAddress).isDepegged();Redemption is a mechanism that allows nUSD holders to exchange their nUSD directly for collateral from the protocol at a slight discount. This feature helps maintain the peg of nUSD to $1 and provides an exit mechanism for nUSD holders.
For example, if you redeem 1,000 nUSD and the redemption fee is 0.5%, you would receive collateral worth 995 nUSD (1,000 nUSD minus the 0.5% fee).
Redemption allows you to exchange nUSD for underlying collateral at face value (minus fees), providing an arbitrage opportunity when nUSD trades below its peg.
Redemption Function: Located in the vault contracts (BaseVault.sol), the main function is:
How it works:
Users can redeem nUSD by targeting a specific debtor's position
The redeemer pays nUSD and receives the debtor's collateral
You can check redemption status using these functions:
From BaseVault.sol:
Parameters:
debtor: Address of the position you want to redeem against
nusdAmount: Amount of nUSD you want to redeem
minReceiveAmount: Minimum collateral you expect to receive (slippage protection)
Validation:
Ensures you can't redeem against your own position
Checks if the debtor has enough debt
Verifies redemption is enabled for the vault
Redemption provides an arbitrage mechanism to maintain nUSD's peg
Users with higher collateral ratios are more attractive redemption targets (lower fees)
The system prevents self-redemption
Redemption fees benefit both the protocol and the position provider being redeemed against
A redemption fee is applied when you redeem nUSD for collateral. In the Unstable Protocol:
The standard redemption fee is 0.5% of the redeemed amount
This fee is paid directly to the redemption provider whose collateral you're redeeming
The fee compensates providers for offering their collateral for redemption
For example, if you redeem 1,000 nUSD:
5 nUSD (0.5%) goes to the redemption provider as a fee
You receive collateral worth 995 nUSD
The fee structure is designed to:
Incentivize users to become redemption providers
Provide an arbitrage opportunity when nUSD trades below its peg
Ensure the system maintains sufficient redemption capacity
Redemption is enabled/disabled at the vault level by the protocol owner:
Once redemption is enabled for a vault, any user with a debt position automatically becomes a potential redemption target. This is evident from the getRedeemableAmount function:
A user automatically becomes a redemption provider if:
The vault has redemption enabled (config.enabled = true)
They have an outstanding debt position (getBorrowedOf(provider) > 0)
Their collateral ratio is within the allowed range (between 100% and maxCollateralRatio)
A fee structure applies based on the debtor's collateral ratio
The debtor's debt is reduced by the redeemed amount
Fee Calculation: Based on the debtor's collateral ratio:
Below bad collateral ratio: Base fee goes to protocol, no provider fee
Between bad and safe ratios: Proportional provider fee based on proximity to safe ratio
Above safe ratio: Higher fees with linear multiplier up to max collateral ratio
Execution:
Protocol fee (if any) is sent to the configurator
Remaining nUSD repays the debtor's debt
Collateral is transferred to the redeemer
Debtor's position is updated
function redemption(address debtor, uint256 nusdAmount, uint256 minReceiveAmount) external// From UnstableConfigurator.sol
function getRedemptionConfig(address vault) public view returns(RedemptionConfig memory) function getRedemptionConfig(address vault) public view returns(RedemptionConfig memory) {
RedemptionConfig memory config = vaultRedemptionConfig[vault];
if(config.enabled == false && config.providerShare == 0 && config.baseFee == 0 && config.maxCollateralRatio == 0 && config.maxMultiplier == 0) {
return defaultRedemptionConfig;
}
else return config;
}// From vault contracts
function getRedeemableAmount(address provider) public view returns(uint256)function getRedeemableAmount(address provider) public view returns(uint256) {
IConfigurator.RedemptionConfig memory config = configurator.getRedemptionConfig(address(this));
if(!config.enabled) return 0;
if(getBorrowedOf(provider) == 0) return 0;
if(getCollateralRatio(provider) > config.maxCollateralRatio || getCollateralRatio(provider) < 10_000) return 0;
return getBorrowedOf(provider);
}function calculateRedemption(address debtor, uint256 nusdAmount) public view returns (
uint256 providerFee,
uint256 protocolFee,
uint256 nusdToProtocol,
uint256 nusdToRepay,
uint256 nusdToConvert,
uint256 collateralReceived
)function redemption(address debtor, uint256 nusdAmount, uint256 minReceiveAmount) external// 1. Check if redemption is enabled
RedemptionConfig memory config = configurator.getRedemptionConfig(vaultAddress);
require(config.enabled, "Redemption not enabled");
// 2. Check redeemable amount for a specific debtor
uint256 maxRedeemable = vault.getRedeemableAmount(debtorAddress);
// 3. Calculate redemption details
(,, uint256 nusdToProtocol, uint256 nusdToRepay,, uint256 collateralReceived) =
vault.calculateRedemption(debtorAddress, nusdAmount);
// 4. Execute redemption (requires nUSD approval first)
nUSD.approve(vaultAddress, nusdAmount);
vault.redemption(debtorAddress, nusdAmount, minCollateralReceived);function getRedemptionConfig(address vault) public view returns(RedemptionConfig memory) {
RedemptionConfig memory config = vaultRedemptionConfig[vault];
if(config.enabled == false && config.providerShare == 0 && config.baseFee == 0 && config.maxCollateralRatio == 0 && config.maxMultiplier == 0) {
return defaultRedemptionConfig;
}
else return config;
}function getRedeemableAmount(address provider) public view returns(uint256) {
IConfigurator.RedemptionConfig memory config = configurator.getRedemptionConfig(address(this));
if(!config.enabled) return 0; // Vault-level check
if(getBorrowedOf(provider) == 0) return 0; // Must have debt
if(getCollateralRatio(provider) > config.maxCollateralRatio || getCollateralRatio(provider) < 10_000) return 0;
return getBorrowedOf(provider); // Can redeem up to full debt amount
}