-
Notifications
You must be signed in to change notification settings - Fork 39
wad representation #498
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
wad representation #498
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #498 +/- ##
==========================================
+ Coverage 94.91% 95.02% +0.11%
==========================================
Files 76 77 +1
Lines 5187 5306 +119
==========================================
+ Hits 4923 5042 +119
Misses 264 264 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- Document truncation behavior consistently
Similarly toto_integer():- Add to to_token_amount(): "Truncates toward zero when scaling down (token_decimals < 18)."
- Add to from_token_amount(): "Truncates toward zero when scaling down (token_decimals > 18)."
- Add to checked_mul(): "Result is truncated toward zero after division by WAD_SCALE."
- Add to checked_div(): "Result is truncated toward zero."
- Negatives are supported so
abs()can be useful. - Can be helpful to provide:
impl Wad {
pub const ZERO: Wad = Wad(0);
pub const ONE: Wad = Wad(WAD_SCALE);
}
- Precision loss: is this inevitable?
#[test]
fn test_precision_loss_operation_order() {
let e = Env::default();
let principal = Wad::from_integer(&e, 1000);
let rate = Wad::from_raw(55_000_000_000_000_000);
let time_fraction = Wad::from_raw(8_333_333_333_333_333);
let interest_method1 = principal * rate * time_fraction;
let rate_time = rate * time_fraction;
let interest_method2 = principal * rate_time;
let diff = interest_method1.raw() - interest_method2.raw();
assert!(diff > 0);
}
#[test]
fn test_precision_loss_compound_interest() {
let e = Env::default();
let principal = Wad::from_integer(&e, 100);
let growth_factor = Wad::from_raw(1_010_000_000_000_000_000);
let mut amount = principal;
for _ in 0..10 {
amount = amount * growth_factor;
}
let expected = Wad::from_raw(110_462_212_541_000_000_000);
let diff = amount.raw() - expected.raw();
assert!(diff > 120_451_000);
}
#[test]
fn test_precision_loss_cross_multiplication() {
let a = Wad::from_raw(10_000_000_000_000_000_007);
let b = Wad::from_raw(3_000_000_000_000_000_000);
let quotient = a / b;
assert_eq!(quotient.raw(), 3_333_333_333_333_333_335);
let reconstructed = quotient * b;
assert_eq!(reconstructed.raw(), 10_000_000_000_000_000_005);
let lost = a.raw() - reconstructed.raw();
assert_eq!(lost, 2);
}
- Add additional checks for large decimals
#[test]
#[should_panic(expected = "attempt to multiply with overflow")]
fn test_token_decimals_not_validated() {
let e = Env::default();
let amount = 1_000_000;
let invalid_decimals = 57u8;
let _ = Wad::from_token_amount(&e, amount, invalid_decimals);
}
that's good, added the test
I had
Hmm, maybe
good advice, will do!
I think yes, but will spend more mental effort on it just in case. |
|
For any solution we will have for fixed point math, at some point, there will be precision errors. I think this is the innate unavoidable behavior of fixed points, because ultimately, we are using containers like The precision loss depicted by the tests above are negligible. Let me explain why. The purpose of any fixed-point math solution, is to not get rid of the precision errors altogether. The purpose is to get rid of the non-negligible, big precision errors. Or, in other words, make the precision errors negligible. For example, Right now, the precision error is I think this is VERY acceptable and expected behavior. |
brozorec
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm still not feeling 100% convinced about the operator overloading, but acknowledging the arguments about this design choice. One last thing, there's one miss from the test cov that can be easily covered.
Great job 🙌
Partially Fixes #438
PR Checklist