Skip to content

Commit 4068ad1

Browse files
bobthebuidlrpiobab
andauthored
Hc liquidation price (#350)
* Add liquidation price calculations * remove inline import * add liquidation price calc for debt + remove redundant node compilation for wasm * Fmt and schema. * Fix subtraction. * Fix yarn build. * Bump wasm for web. --------- Co-authored-by: piobab <[email protected]>
1 parent 6f43f25 commit 4068ad1

31 files changed

+146644
-2066
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/health-computer/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ wasm-bindgen = { workspace = true, optional = true }
3131
# all the `std::fmt` and `std::panicking` infrastructure, so isn't great for
3232
# code size when deploying.
3333
console_error_panic_hook = { version = "0.1.7", optional = true }
34+
web-sys = "0.3.64"
3435

3536
[dev-dependencies]
3637
proptest = { workspace = true }

packages/health-computer/src/health_computer.rs

Lines changed: 71 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
11
use std::cmp::min;
22

33
use cosmwasm_schema::cw_serde;
4-
use cosmwasm_std::{Coin, Decimal, Uint128};
4+
use cosmwasm_std::{Coin, Decimal, Fraction, Uint128};
55
use mars_types::{
66
credit_manager::Positions,
77
health::{
88
AccountKind, BorrowTarget, Health,
99
HealthError::{
10-
MissingHLSParams, MissingParams, MissingPrice, MissingVaultConfig, MissingVaultValues,
10+
MissingAmount, MissingHLSParams, MissingParams, MissingPrice, MissingVaultConfig,
11+
MissingVaultValues,
1112
},
12-
HealthResult, SwapKind,
13+
HealthResult, LiquidationPriceKind, SwapKind,
1314
},
1415
params::{AssetParams, CmSettings, VaultConfig},
1516
};
@@ -31,7 +32,7 @@ pub struct HealthComputer {
3132
}
3233

3334
impl HealthComputer {
34-
pub fn compute_health(&self) -> mars_types::health::HealthResult<Health> {
35+
pub fn compute_health(&self) -> HealthResult<Health> {
3536
let CollateralValue {
3637
total_collateral_value,
3738
max_ltv_adjusted_collateral,
@@ -403,6 +404,72 @@ impl HealthComputer {
403404
Ok(max_borrow_amount)
404405
}
405406

407+
pub fn liquidation_price(
408+
&self,
409+
denom: &str,
410+
kind: &LiquidationPriceKind,
411+
) -> HealthResult<Uint128> {
412+
let collateral_ltv_value = self.total_collateral_value()?.max_ltv_adjusted_collateral;
413+
let total_debt_value = self.total_debt_value()?;
414+
if total_debt_value.is_zero() {
415+
return Ok(Uint128::zero());
416+
}
417+
418+
let current_price =
419+
self.denoms_data.prices.get(denom).ok_or(MissingPrice(denom.to_string()))?;
420+
421+
if total_debt_value >= collateral_ltv_value {
422+
return Ok(Uint128::one() * *current_price);
423+
}
424+
425+
match kind {
426+
LiquidationPriceKind::Asset => {
427+
let asset_amount = self.get_coin_from_deposits_and_lends(denom)?.amount;
428+
if asset_amount.is_zero() {
429+
return Err(MissingAmount(denom.to_string()));
430+
}
431+
432+
let asset_ltv = self.get_coin_max_ltv(denom)?;
433+
434+
let asset_ltv_value =
435+
asset_amount.checked_mul_floor(current_price.checked_mul(asset_ltv)?)?;
436+
let debt_with_asset_ltv_value = total_debt_value.checked_add(asset_ltv_value)?;
437+
438+
if debt_with_asset_ltv_value <= collateral_ltv_value {
439+
return Ok(Uint128::zero());
440+
}
441+
442+
let debt_without = debt_with_asset_ltv_value - collateral_ltv_value;
443+
444+
// liquidation_price = (debt_value - collateral_ltv_value + asset_ltv_value) / (asset_amount * asset_ltv)
445+
Ok(Uint128::one()
446+
* Decimal::checked_from_ratio(debt_without, asset_amount)?.checked_mul(
447+
Decimal::from_ratio(asset_ltv.denominator(), asset_ltv.numerator()),
448+
)?)
449+
}
450+
451+
LiquidationPriceKind::Debt => {
452+
let debt_amount = self
453+
.positions
454+
.debts
455+
.iter()
456+
.find(|c| c.denom == denom)
457+
.ok_or(MissingAmount(denom.to_string()))?
458+
.amount;
459+
if debt_amount.is_zero() {
460+
return Err(MissingAmount(denom.to_string()));
461+
}
462+
463+
// Liquidation_price = (collateral_ltv_value - total_debt_value + debt_value_asset / asset_amount
464+
let debt_value = debt_amount.checked_mul_ceil(*current_price)?;
465+
let net_collateral_value_without_debt =
466+
collateral_ltv_value.checked_add(debt_value)?.checked_sub(total_debt_value)?;
467+
468+
Ok(net_collateral_value_without_debt / debt_amount)
469+
}
470+
}
471+
}
472+
406473
fn total_debt_value(&self) -> HealthResult<Uint128> {
407474
let mut total = Uint128::zero();
408475
for debt in &self.positions.debts {

packages/health-computer/src/javascript.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
use mars_types::health::{BorrowTarget, HealthValuesResponse, Slippage, SwapKind};
1+
use mars_types::health::{
2+
BorrowTarget, HealthValuesResponse, LiquidationPriceKind, Slippage, SwapKind,
3+
};
24
use wasm_bindgen::prelude::*;
35

46
use crate::HealthComputer;
@@ -39,3 +41,12 @@ pub fn max_swap_estimate_js(
3941
.unwrap()
4042
.to_string()
4143
}
44+
45+
#[wasm_bindgen]
46+
pub fn liquidation_price_js(
47+
c: HealthComputer,
48+
denom: String,
49+
kind: LiquidationPriceKind,
50+
) -> String {
51+
c.liquidation_price(&denom, &kind).unwrap().to_string()
52+
}

packages/types/src/health/account.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,3 +50,11 @@ impl Slippage {
5050
self.0
5151
}
5252
}
53+
54+
#[cw_serde]
55+
#[cfg_attr(feature = "javascript", derive(Tsify))]
56+
#[cfg_attr(feature = "javascript", tsify(into_wasm_abi, from_wasm_abi))]
57+
pub enum LiquidationPriceKind {
58+
Asset,
59+
Debt,
60+
}

packages/types/src/health/error.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@ pub enum HealthError {
1818
#[error("{0} address has not been set in config")]
1919
ContractNotSet(String),
2020

21+
#[error("{0} amount was not provided or is 0")]
22+
MissingAmount(String),
23+
2124
#[error(
2225
"Account is an HLS account, but {0} was not provided HLS params to compute health with"
2326
)]

scripts/health/DataFetcher.ts

Lines changed: 0 additions & 145 deletions
This file was deleted.

scripts/health/example-node.ts

Lines changed: 0 additions & 20 deletions
This file was deleted.

scripts/health/example-react/.gitignore

Lines changed: 0 additions & 25 deletions
This file was deleted.

0 commit comments

Comments
 (0)