Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions packages/health-computer/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ wasm-bindgen = { workspace = true, optional = true }
# all the `std::fmt` and `std::panicking` infrastructure, so isn't great for
# code size when deploying.
console_error_panic_hook = { version = "0.1.7", optional = true }
web-sys = "0.3.64"

[dev-dependencies]
proptest = { workspace = true }
Expand Down
75 changes: 71 additions & 4 deletions packages/health-computer/src/health_computer.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
use std::cmp::min;

use cosmwasm_schema::cw_serde;
use cosmwasm_std::{Coin, Decimal, Uint128};
use cosmwasm_std::{Coin, Decimal, Fraction, Uint128};
use mars_types::{
credit_manager::Positions,
health::{
AccountKind, BorrowTarget, Health,
HealthError::{
MissingHLSParams, MissingParams, MissingPrice, MissingVaultConfig, MissingVaultValues,
MissingAmount, MissingHLSParams, MissingParams, MissingPrice, MissingVaultConfig,
MissingVaultValues,
},
HealthResult, SwapKind,
HealthResult, LiquidationPriceKind, SwapKind,
},
params::{AssetParams, CmSettings, VaultConfig},
};
Expand All @@ -31,7 +32,7 @@ pub struct HealthComputer {
}

impl HealthComputer {
pub fn compute_health(&self) -> mars_types::health::HealthResult<Health> {
pub fn compute_health(&self) -> HealthResult<Health> {
let CollateralValue {
total_collateral_value,
max_ltv_adjusted_collateral,
Expand Down Expand Up @@ -403,6 +404,72 @@ impl HealthComputer {
Ok(max_borrow_amount)
}

pub fn liquidation_price(
&self,
denom: &str,
kind: &LiquidationPriceKind,
) -> HealthResult<Uint128> {
let collateral_ltv_value = self.total_collateral_value()?.max_ltv_adjusted_collateral;
let total_debt_value = self.total_debt_value()?;
if total_debt_value.is_zero() {
return Ok(Uint128::zero());
}

let current_price =
self.denoms_data.prices.get(denom).ok_or(MissingPrice(denom.to_string()))?;

if total_debt_value >= collateral_ltv_value {
return Ok(Uint128::one() * *current_price);
}

match kind {
LiquidationPriceKind::Asset => {
let asset_amount = self.get_coin_from_deposits_and_lends(denom)?.amount;
if asset_amount.is_zero() {
return Err(MissingAmount(denom.to_string()));
}

let asset_ltv = self.get_coin_max_ltv(denom)?;

let asset_ltv_value =
asset_amount.checked_mul_floor(current_price.checked_mul(asset_ltv)?)?;
let debt_with_asset_ltv_value = total_debt_value.checked_add(asset_ltv_value)?;

if debt_with_asset_ltv_value <= collateral_ltv_value {
return Ok(Uint128::zero());
}

let debt_without = debt_with_asset_ltv_value - collateral_ltv_value;

// liquidation_price = (debt_value - collateral_ltv_value + asset_ltv_value) / (asset_amount * asset_ltv)
Ok(Uint128::one()
* Decimal::checked_from_ratio(debt_without, asset_amount)?.checked_mul(
Decimal::from_ratio(asset_ltv.denominator(), asset_ltv.numerator()),
)?)
}

LiquidationPriceKind::Debt => {
let debt_amount = self
.positions
.debts
.iter()
.find(|c| c.denom == denom)
.ok_or(MissingAmount(denom.to_string()))?
.amount;
if debt_amount.is_zero() {
return Err(MissingAmount(denom.to_string()));
}

// Liquidation_price = (collateral_ltv_value - total_debt_value + debt_value_asset / asset_amount
let debt_value = debt_amount.checked_mul_ceil(*current_price)?;
let net_collateral_value_without_debt =
collateral_ltv_value.checked_add(debt_value)?.checked_sub(total_debt_value)?;

Ok(net_collateral_value_without_debt / debt_amount)
}
}
}

fn total_debt_value(&self) -> HealthResult<Uint128> {
let mut total = Uint128::zero();
for debt in &self.positions.debts {
Expand Down
13 changes: 12 additions & 1 deletion packages/health-computer/src/javascript.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
use mars_types::health::{BorrowTarget, HealthValuesResponse, Slippage, SwapKind};
use mars_types::health::{
BorrowTarget, HealthValuesResponse, LiquidationPriceKind, Slippage, SwapKind,
};
use wasm_bindgen::prelude::*;

use crate::HealthComputer;
Expand Down Expand Up @@ -39,3 +41,12 @@ pub fn max_swap_estimate_js(
.unwrap()
.to_string()
}

#[wasm_bindgen]
pub fn liquidation_price_js(
c: HealthComputer,
denom: String,
kind: LiquidationPriceKind,
) -> String {
c.liquidation_price(&denom, &kind).unwrap().to_string()
}
8 changes: 8 additions & 0 deletions packages/types/src/health/account.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,11 @@ impl Slippage {
self.0
}
}

#[cw_serde]
#[cfg_attr(feature = "javascript", derive(Tsify))]
#[cfg_attr(feature = "javascript", tsify(into_wasm_abi, from_wasm_abi))]
pub enum LiquidationPriceKind {
Asset,
Debt,
}
3 changes: 3 additions & 0 deletions packages/types/src/health/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ pub enum HealthError {
#[error("{0} address has not been set in config")]
ContractNotSet(String),

#[error("{0} amount was not provided or is 0")]
MissingAmount(String),

#[error(
"Account is an HLS account, but {0} was not provided HLS params to compute health with"
)]
Expand Down
145 changes: 0 additions & 145 deletions scripts/health/DataFetcher.ts

This file was deleted.

20 changes: 0 additions & 20 deletions scripts/health/example-node.ts

This file was deleted.

25 changes: 0 additions & 25 deletions scripts/health/example-react/.gitignore

This file was deleted.

Loading