Only this pageAll pages
Powered by GitBook
1 of 17

Unstable Protocol

Loading...

Users

Loading...

Loading...

Loading...

Loading...

Loading...

Developers

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Mint nUSD

Minting nUSD is the process of creating a secured debt position by depositing approved collateral into the Unstable Protocol.

How to Mint nUSD

To mint nUSD, you need to deposit approved yield-bearing collateral into one of Unstable's vaults:

  1. Connect your wallet to the Unstable Protocol dApp

  2. Navigate to the "Mint" section

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

  4. Enter the amount of collateral you want to deposit

  5. The system will calculate how much nUSD you can mint based on the current collateralization ratio for that asset type

  6. Confirm the transaction

Collateralization Ratio

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.

Interest and Fees

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.

Collateralization and Liquidation

The Unstable Protocol uses overcollateralization to ensure the stability of nUSD. This page explains how collateralization works and what happens during liquidation.

Collateralization

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

Position Management

The Position Management component handles user collateral positions, deposits, and nUSD minting/burning operations.

Action
Description
Function

Repay nUSD

Repaying your nUSD debt allows you to unlock your collateral from the Unstable Protocol.

How to Repay nUSD

You can repay nUSD anytime to unlock your collateral (fully or partially):

  1. Connect your wallet to the Unstable Protocol dApp

Interest and Fees

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.

Interest Model

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

Supported Collateral Types

Unstable accepts multiple types of high-quality collateral across different asset classes:

  • stS

  • scETH

  • scUSD

  • wstkscUSD: Wrapped staked scUSD

  • [REDACTED]

  • [REDACTED]

Monitoring Your Collateral Health

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

Liquidation is the mechanism that ensures the protocol remains solvent even when collateral values drop.

When Liquidation Happens

If a vault's collateral falls below the safe threshold (e.g., 125%), it becomes eligible for liquidation. This can happen due to:

  1. A decrease in the market value of your collateral

  2. A depeg of the collateral asset (for stablecoin collaterals)

The Liquidation Process

When liquidation occurs:

  1. The system detects that a position has fallen below the minimum collateralization ratio

  2. The Stability Pool provides nUSD to cover the debt

  3. The liquidated collateral (minus a penalty) is distributed to Stability Pool depositors

  4. The user's debt is cleared, and any remaining collateral is returned to the user

Liquidation Penalty

A liquidation fee is applied when positions fall below the minimum collateralization ratio. The exact fee varies by collateral type.

How to Avoid Liquidation

To prevent liquidation:

  1. Monitor your position regularly

  2. Add more collateral when your ratio approaches the minimum threshold

  3. Partially repay your debt to improve your collateralization ratio

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

  • Partial Repayments

    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.

    Withdrawal After Repayment

    After repaying your nUSD debt, you can withdraw your collateral:

    1. Navigate to the "Withdraw" section

    2. Select the vault containing your collateral

    3. Enter the amount of collateral you want to withdraw

    4. Confirm the transaction

    No Fixed Terms

    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.

    Introduction

    Unlocking Liquidity While Preserving Yield

    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.

    Capital Efficiency

    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

    Robust Stability Mechanisms

    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)

    Example: Deposit and Mint

    Example: Withdraw After Repaying

    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)

    Origination Fee

    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:

    1. Ensure protocol sustainability

    2. Promote responsible borrowing

    3. Balance supply and demand for different collateral types

    Fee Calculation

    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

    Redemption Fees

    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

    Flash Loan Fees

    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 / 10000
    Fee Percentage = Min Fee + (Max Fee - Min Fee) * Utilization / Max Utilization

    Architecture

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

    Core Components

    • 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

    Component Implementation

    Each functional component in the Unstable Protocol is implemented through specific contracts:

    Component
    Primary Contracts
    Integration Purpose

    Vault Types

    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

    Core Tokens

    • 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 --> E

    Redemption 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

    Redemption System

    The Redemption System component handles redemption of nUSD for collateral.

    Action
    Description
    Function

    Redeem

    Redeem nUSD for collateral

    redemption(address debtor, uint256 nusdAmount, uint256 minReceiveAmount)

    Calculate Redemption

    Calculate redemption amounts

    calculateRedemption(address provider, uint256 nusdAmount)

    Example: Redeem nUSD for Collateral

    Interest and Fees

    The Interest and Fees component handles fee calculations and interest accumulation.

    Action
    Description
    Function

    Update Fees

    Force interest accumulation update

    updateFeeAccumulator()

    Calculate Interest

    Calculate interest on a position

    Internal operation, automatic

    Example: Get Origination Fee

    Liquidation System

    The Liquidation System component handles the liquidation of unhealthy positions.

    Action
    Description
    Function

    Liquidate Position

    Liquidate an unhealthy position

    liquidation(address provider, address debtor, uint256 assetAmount)

    Check Liquidation Status

    Check if position is liquidatable

    getLiquidateableAmount(address user)

    Example: Check and Liquidate Position

    Deployments

    Contract Addresses

    Sonic Mainnet

    Contract
    Address

    Emergency Controls

    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.

    Purpose

    The configurator serves several key functions:

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

  • Action
    Description
    Function

    Pause

    Pause protocol functions

    toggleVaultMintPause(address vault)

    Unpause

    Unpause protocol functions

    toggleVaultMintPause(address vault)

    Access Control

    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.

    Example Usage

    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

    0x21f36a432a028769ec2bfda7a1e8cfc96d06339f

    nUSD

    0xd229ff67806d6037e6dfc9eeb2f331cb74e8c79e

    stSOracle

    0x522ff9a972c67f5885c52b77b77e0e030eb02534

    scUSDOracle

    0x898386189002d960980a85258c8661b9f2e741bb

    scETHOracle

    0x65f5e4a515461a64d484ad46272da3756af3275a

    wstkscUSDOracle

    0x27de6e2300afa0a01c1f9ecfe8a2033d0262be32

    StakedStableVault1

    0x53d2698cd284aef101e9257341170e2e2b7833a5

    StakedStableVault2

    0x2edc98820d688ce51dc2825d1e96ad28e9d45289

    Security & Audits

    Audits & Testing

    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.

    Safety & Risk Management

    Protocol Safety Features

    Access Control

    • 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

    Vault & Oracle Safety

    • 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 Onboarding Framework

    • 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

    Price Oracle

    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.

    Oracle Interface

    All oracles in the Unstable Protocol implement the IZkOracle interface:

    Action
    Description
    Function

    Example: Get Asset Prices

    Redemption Rate vs. Market Rate

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

    Depeg Detection

    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.

    Oracle Implementation

    Oracles can be implemented in various ways:

    1. Direct Integration: For assets with on-chain price data

    2. Chainlink Oracles: For reliable, decentralized price feeds

    3. 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);
    }
    Volatile/other-denominated wrappers (e.g. stS): conservative LTVs (e.g. 75%) due to higher volatility, complex redemption mechanics, and oracle fragility
  • 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

  • 0xc24889314cb4ba854f5079d70371632a4feeabcd
    0x9a8ac0dfe8e7b0682727d1e29c9c587c1da11856

    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

    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.

    How Redemption Works

    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 Process

    Key Components:

    1. Redemption Function: Located in the vault contracts (BaseVault.sol), the main function is:

    2. How it works:

      • Users can redeem nUSD by targeting a specific debtor's position

      • The redeemer pays nUSD and receives the debtor's collateral

    Checking if Redemption is Enabled/Disabled

    You can check redemption status using these functions:

    1. Check if redemption is enabled for a vault:

    2. Check how much you can redeem from a specific provider:

    From BaseVault.sol:

    How to Execute Redemption

    1. Calculate redemption first:

    2. Execute the redemption:

    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)

    Redemption Process Flow:

    1. Validation:

      • Ensures you can't redeem against your own position

      • Checks if the debtor has enough debt

      • Verifies redemption is enabled for the vault

    Example Usage:

    Notes:

    • 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

    Redemption Fees

    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:

    1. Incentivize users to become redemption providers

    2. Provide an arbitrage opportunity when nUSD trades below its peg

    3. Ensure the system maintains sufficient redemption capacity

    How Redeemability Status Works:

    Vault-Level Configuration

    Redemption is enabled/disabled at the vault level by the protocol owner:

    Redemption Provider Status

    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:

    Redeemability Criteria

    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
    }