Stability Pool

Inspired by Liquity's Stability Pool (https://docs.liquity.org/faq/stability-pool-and-liquidations)

The Stability Pool (SP) is the second line of defense in Positions contract liquidations. It acts as a pool of liquidity that can be used to repay insolvent positions in return for discounted collateral assets. When a position is liquidated, the pool repays its debt in exchange for assets sent by the Positions contract after successful repayments. In contrast to Liquity's pro rata model, this SP is First In First Out when it comes to rewarding liquidations to pool liquidity providers. Due to how the Liquidation Queue calculates liquidations, there will always be something for the SP to liquidate, meaning its advantageous for the first bidder at every liquidation and not just the one's the Liq Queue can't fulfill. This has the added benefit of filtering through spam deposits before large liquidatiosn. Pro-rata distributions, like the Liq Queue and Liquity's SP are better than FIFO at attracting large capital, but FIFO has direct incentives for competitive replenishes which is better for a pool that isn't prioritized but needs quick refills if the situation calls for it. We want this step of the liquidation mechanism to be reactive when low while not taking too much potential capital from the Liq Queue which will likely liquidate collateral for lower premiums a majority of the time, which is better for user solvency.

Key Points:

  • Any user funds in the Stability Pool will be used to repay said user's positions if liquidated. Meaning depositing in the SP doesn't increase liquidation risk for the user.

  • Unstaked deposits are still used to liquidate but accrue no incentives.

  • Withdrawals that would leave less than the minmum deposit amount will withdraw the remaining bid.

InstantiateMsg

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
pub struct InstantiateMsg {
    pub owner: Option<String>,
    pub asset_pool: Option<AssetPool>,
    pub incentive_rate: Option<Decimal>,
    pub max_incentives: Option<Uint128>,
    pub minimum_deposit_amount: Uint128,
    pub osmosis_proxy: String,
    pub positions_contract: String,
    pub oracle_contract: String,
    pub mbrn_denom: String,
}

pub struct AssetPool {
    pub credit_asset: Asset,
    pub liq_premium: Decimal,
    pub deposits: Vec<Deposit>
}

pub struct Asset {
    pub info: AssetInfo,
    pub amount: Uint128,
}
KeyTypeDescription

*asset_pool

AssetPool

Initial Asset Pool for the contract

*owner

String

Owner of the contract, defaults to info.sender

*incentive_rate

Decimal

Base MBRN incentive rate

*max_incentives

Uint128

Maximum MBRN the Pool can mint for incentives

*minimum_deposit_amount

Uint128

Minimum deposit amount

osmosis_proxy

String

Osmosis Proxy contract address

positions_contract

String

CDP contract

oracle_contract

String

Oracle contract

mbrn_denom

String

MBRN denom

* = optional

ExecuteMsg

UpdateConfig

Update Config if info.sender is config.owner

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum ExecuteMsg {
    UpdateConfig(UpdateConfig),
}

pub struct UpdateConfig {
    owner: Option<String>,
    incentive_rate: Option<Decimal>,
    max_incentives: Option<Uint128>,
    minimum_deposit_amount: Option<Uint128>,
    unstaking_period: Option<u64>,
    osmosis_proxy: Option<String>,
    positions_contract: Option<String>,
    pub oracle_contract: Option<String>,
    mbrn_denom: Option<String>,
}

Deposit

Deposit accepted credit assets to corresponding Asset Pools

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum ExecuteMsg {
    Deposit { 
        user: Option<String>
    }
}
KeyTypeDescription

*user

String

Address with claim over the deposit(s)

* = optional

Withdraw

Withdraw caller owned deposits from corresponding Asset Pools

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum ExecuteMsg {
    Withdraw { 
        amount: Uint128
    }
}
KeyTypeDescription

amount

Uint128

Amount to be withdrawn

Restake

Restake unstak(ed/ing) assets

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum ExecuteMsg {
    Restake { 
        restake_amount: Decimal,
    }
}
KeyTypeDescription

restake_amount

Decimal

Amount to restake

Liquidate

Use Asset Pool assets to repay for a Position and earn discounted assets

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum ExecuteMsg {
    Liquidate { 
        liq_amount: Decimal
    }
}
KeyTypeDescription

liq_amount

Decimal

Amount to be repaid

ClaimRewards

Claim all discounted assets received from liquidations for the calling address

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum ExecuteMsg {
    ClaimRewards { }
}

Distribute

Called by the Positions contract. Distributes liquidated funds to the users whose Deposits were used to repay the debt.

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum ExecuteMsg {
    Distribute { //Distributes liquidated funds to users
        distribution_assets: Vec<Asset>,
        distribution_asset_ratios: Vec<Decimal>,
        distribute_for: Uint128,
    }
}
KeyTypeDescription

distribution_assets

Vec<Asset>

Assets to be distributed to users

distribution-asset-ratios

Vec<Decimal>

Ratios of distribution assets

credit_price

Decimal

Redemption price of credit_asset

Repay

Allows the Positions contract to use user funds to repay for themselves

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum ExecuteMsg {
    Repay {
        user_info: UserInfo,
        repayment: Asset,
    }
}

pub struct UserInfo {
    pub position_id: Uint128,
    pub position_owner: String,
}
KeyTypeDescription

user_info

UserInfo

User's Position info

repayment

Asset

Asset to repay

QueryMsg

Config

Returns the current Config fields

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum QueryMsg {
    Config {}
}

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
pub struct Config {
    pub owner: Addr, //Positions contract address
    pub incentive_rate: Decimal,
    pub max_incentives: Uint128,
    pub unstaking_period: u64, // in days
    pub mbrn_denom: String,
    pub osmosis_proxy: Addr,
    pub positions_contract: Addr,
    pub oracle_contract: Addr,
}

CheckLiquidatible

Returns the amount of said asset that isn't liquidatible (i.e. leftover)

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum QueryMsg {
    CheckLiquidatible { 
        amount: Decimal  
    }
}

pub struct LiquidatibleResponse {
    pub leftover: Decimal,
}
KeyTypeDescription

amount

Decimal

Amount to check for

UserClaims

Returns the user's claimable assets

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum QueryMsg {
    UserClaims { 
        user: String 
    }
}

pub struct ClaimsResponse {
    pub claims: Vec<Coin>,
}
KeyTypeDescription

user

String

The user whose claims to check

AssetPool

Returns Asset Pool info

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum QueryMsg {
    AssetPool { 
        user: Option<String>,
        deposit_limit: Option<u32>,
        start_after: Option<u32>,        
    }
}

pub struct PoolResponse {
    pub credit_asset: Asset,
    pub liq_premium: Decimal,
    pub deposits: Vec<Deposit>
}
KeyTypeDescription

*user

String

User's deposits to return

*deposit_limit

u32

Deposit limit

*start_after

u32

Start after Deposit count

UnclaimedIncentives

Returns unclaimed incentives for a user in an AssetPool

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum QueryMsg {
    UnclaimedIncentives {
        user: String,
    }
}

//Returns Uint128
KeyTypeDescription

user

String

User address

CapitalAheadOfDeposit

Returns capital ahead of each user Deposit in an AssetPool

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum QueryMsg {
    CapitalAheadOfDeposit {
        user: String,
    }
}

pub struct DepositPositionResponse {
    pub deposit: Deposit,
    pub capital_ahead: Decimal,
}

pub struct Deposit {
    pub user: Addr,
    pub amount: Decimal,
    pub deposit_time: u64,
    pub last_accrued: u64,
    pub unstake_time: Option<u64>,
}
KeyTypeDescription

user

String

User address

Last updated