@@ -31,7 +31,7 @@ pub struct HealthComputer {
31
31
}
32
32
33
33
impl HealthComputer {
34
- pub fn compute_health ( & self ) -> HealthResult < Health > {
34
+ pub fn compute_health ( & self ) -> mars_types :: health :: HealthResult < Health > {
35
35
let CollateralValue {
36
36
total_collateral_value,
37
37
max_ltv_adjusted_collateral,
@@ -138,6 +138,7 @@ impl HealthComputer {
138
138
from_denom : & str ,
139
139
to_denom : & str ,
140
140
kind : & SwapKind ,
141
+ slippage : Decimal ,
141
142
) -> HealthResult < Uint128 > {
142
143
// Both deposits and lends should be considered, as the funds can automatically be un-lent and
143
144
// and also used to swap.
@@ -172,22 +173,29 @@ impl HealthComputer {
172
173
// Swapping that asset for an asset with the same price, but 0.8 max ltv results in a collateral_value of 0.8.
173
174
// Therefore, when the asset that is swapped to has a higher or equal max ltv than the asset swapped from,
174
175
// the collateral value will increase and we can allow the full balance to be swapped.
175
- let swappable_amount = if to_ltv >= from_ltv {
176
+ // The ltv_out is adjusted for slippage, as the swap_out_value can drop by the slippage.
177
+ let to_ltv_slippage_corrected = to_ltv. checked_mul ( Decimal :: one ( ) - slippage) ?;
178
+ let swappable_amount = if to_ltv_slippage_corrected >= from_ltv {
176
179
from_coin. amount
177
180
} else {
178
181
// In order to calculate the output of the swap, the formula looks like this:
179
182
// 1 = (collateral_value + to_amount * to_price * to_ltv - from_amount * from_price * from_ltv) / debt_value
180
183
// The unknown variables here are to_amount and from_amount. In order to only have 1 unknown variable, from_amount,
181
184
// to_amount can be replaced by:
182
- // to_amount = from_amount * from_price / to_price
185
+ // to_amount = slippage * from_amount * from_price / to_price
183
186
// This results in the following formula:
184
- // 1 = (collateral_value + from_amount * from_price / to_price * to_price * to_ltv - from_amount * from_price * from_ltv) / debt_value
187
+ // 1 = (collateral_value + slippage * from_amount * from_price / to_price * to_price * to_ltv - from_amount * from_price * from_ltv) / debt_value
188
+ // debt_value = collateral_value + slippage * from_amount * from_price * to_ltv - from_amount * from_price * from_ltv
189
+ // slippage * from_amount * from_price * to_ltv - from_amount * from_price * from_ltv = debt_value - collateral_value
190
+ // from_amount * (slippage * from_price * to_ltv - from_price * from_ltv) = debt_value - collateral_value
185
191
// Rearranging this formula to isolate from_amount results in the following formula:
186
- // from_amount = (collateral_value - debt_value) / (from_price * ( from_ltv - to_ltv))
192
+ // from_amount = (debt_value - collateral_value) / (from_price * (slippage * to_ltv - from_ltv))
193
+ // Rearranging to avoid negative numbers for the denominator (to_ltv_slippage_corrected < from_ltv):
194
+ // from_amount = (collateral_value - debt_value) / (from_price * (from_ltv - slippage * to_ltv)
187
195
let amount = total_max_ltv_adjusted_value
188
196
. checked_sub ( debt_value) ?
189
197
. checked_sub ( Uint128 :: one ( ) ) ?
190
- . checked_div_floor ( from_price. checked_mul ( from_ltv - to_ltv ) ?) ?;
198
+ . checked_div_floor ( from_price. checked_mul ( from_ltv - to_ltv_slippage_corrected ) ?) ?;
191
199
192
200
// Cap the swappable amount at the current balance of the coin
193
201
min ( amount, from_coin. amount )
@@ -219,14 +227,19 @@ impl HealthComputer {
219
227
// The total swappable amount for margin is represented by the available coin balance + the
220
228
// the maximum amount that can be borrowed (and then swapped).
221
229
// This is represented by the formula:
222
- // 1 = (collateral_after_swap + borrow_amount * borrow_price * to_ltv) / (debt + borrow_amount * borrow_price)
230
+ // 1 = (collateral_after_swap + slippage * borrow_amount * borrow_price * to_ltv) / (debt + borrow_amount * borrow_price)
231
+ // debt + borrow_amount * borrow_price = collateral_after_swap + slippage * borrow_amount * borrow_price * to_ltv
232
+ // borrow_amount * borrow_price - slippage * borrow_amount * borrow_price * to_ltv = collateral_after_swap - debt
233
+ // borrow_amount * borrow_price * (1 - slippage * to_ltv) = collateral_after_swap - debt
223
234
// Rearranging this results in:
224
- // borrow_amount = (collateral_after_swap - debt) / ((1 - to_ltv) * borrow_price )
235
+ // borrow_amount = (collateral_after_swap - debt) / (borrow_price * (1 - slippage * to_ltv) )
225
236
let borrow_amount = total_max_ltv_adjust_value_after_swap
226
237
. checked_sub ( debt_value) ?
227
238
. checked_sub ( Uint128 :: one ( ) ) ?
228
239
. checked_div_floor (
229
- Decimal :: one ( ) . checked_sub ( to_ltv) ?. checked_mul ( * from_price) ?,
240
+ Decimal :: one ( )
241
+ . checked_sub ( to_ltv_slippage_corrected) ?
242
+ . checked_mul ( * from_price) ?,
230
243
) ?;
231
244
232
245
// The total amount that can be swapped is then the balance of the coin + the additional amount
@@ -359,6 +372,32 @@ impl HealthComputer {
359
372
. checked_mul ( Decimal :: one ( ) . checked_sub ( checked_vault_max_ltv) ?) ?,
360
373
) ?
361
374
}
375
+
376
+ BorrowTarget :: Swap {
377
+ slippage,
378
+ denom_out,
379
+ } => {
380
+ let denom_out_ltv = self . get_coin_max_ltv ( denom_out) . unwrap ( ) ;
381
+
382
+ // The max borrow for swap can be calculated as:
383
+ // 1 = (total_max_ltv_adjusted_value + (denom_amount_out * denom_price_out * denom_out_ltv)) / (debt_value + (max_borrow_denom_amount * borrow_denom_price))
384
+ // denom_amount_out can be replaced by:
385
+ // denom_amount_out = slippage * max_borrow_denom_amount * borrow_denom_price / denom_price_out
386
+ // This results in the following formula:
387
+ // 1 = (total_max_ltv_adjusted_value + (slippage * max_borrow_denom_amount * borrow_denom_price * denom_out_ltv)) / (debt_value + (max_borrow_denom_amount * borrow_denom_price))
388
+ // Re-arranging this to isolate borrow denom amount renders:
389
+ // max_borrow_denom_amount = (total_max_ltv_adjusted_value - debt_value) / (borrow_denom_price * (1 - slippage * denom_out_ltv))
390
+ let out_ltv_slippage_corrected =
391
+ denom_out_ltv. checked_mul ( Decimal :: one ( ) - slippage) ?;
392
+ total_max_ltv_adjusted_value
393
+ . checked_sub ( debt_value) ?
394
+ . checked_sub ( Uint128 :: one ( ) ) ?
395
+ . checked_div_floor (
396
+ Decimal :: one ( )
397
+ . checked_sub ( out_ltv_slippage_corrected) ?
398
+ . checked_mul ( borrow_denom_price) ?,
399
+ ) ?
400
+ }
362
401
} ;
363
402
364
403
Ok ( max_borrow_amount)
0 commit comments