Health token adjustment: Deal with odd I80F48 behavior
The identity a * b = -((-a) * b) does not hold for I80F48, probably it's rounding to -inf. This meant that withdrawing the full native token balance could fail because the magnitude of -position * price was bigger than position * price.
This commit is contained in:
parent
3b93a38395
commit
511db72f8e
|
@ -652,7 +652,12 @@ impl HealthCache {
|
|||
pub fn adjust_token_balance(&mut self, token_index: TokenIndex, change: I80F48) -> Result<()> {
|
||||
let entry_index = self.token_entry_index(token_index)?;
|
||||
let mut entry = &mut self.token_infos[entry_index];
|
||||
entry.balance = cm!(entry.balance + change * entry.oracle_price);
|
||||
|
||||
// Work around the fact that -((-x) * y) == x * y does not hold for I80F48:
|
||||
// We need to make sure that if balance is before * price, then change = -before
|
||||
// brings it to exactly zero.
|
||||
let removed_contribution = (-change) * entry.oracle_price;
|
||||
entry.balance = cm!(entry.balance - removed_contribution);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
|
@ -38,3 +38,17 @@ pub fn format_zero_terminated_utf8_bytes(
|
|||
.trim_matches(char::from(0)),
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use fixed::types::I80F48;
|
||||
|
||||
#[test]
|
||||
pub fn test_i80f48_mul_rounding() {
|
||||
// It's not desired, but I80F48 seems to round to -inf
|
||||
let price = I80F48::from_num(0.04);
|
||||
let x = I80F48::from_bits(96590783907000000);
|
||||
assert_eq!((x * price).to_string(), "13.726375969298193");
|
||||
assert_eq!(((-x) * price).to_string(), "-13.726375969298196");
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue