I have a u128 total and a u128 user_total. I also have a balance and want the user to be able to withdraw (balance * user_total) / (total * multiplier)
What is the best way to do this to avoid overflow, since balance is a u64 and both totals are u128s?
I still want the calculation to happen in the case of an overflow as shown by u64::MAX
Currently, I have:
// user_total: u128, total: u128, balance: u64, multiplier: u8 ; multiplier > 0 and user_total < total
let divisor: Option<u128> = total.checked_mul(multiplier as u128);
let amount_won = match (balance as u128).checked_mul(user_total) {
Some(result) => match divisor {
Some(div) => result.checked_div(div).ok_or(StakeError::Overflow)?,
None => {
let intermediate = result.checked_div(multiplier as u128).ok_or(StakeError::Overflow)?;
intermediate.checked_div(total).ok_or(StakeError::Overflow)?
}
},
None => {
let fallback_result = (balance as u128).checked_mul(u64::MAX as u128).unwrap_or_default();
match divisor {
Some(div) => fallback_result.checked_div(div).ok_or(StakeError::Overflow)?,
None => {
let intermediate = fallback_result.checked_div(multiplier as u128).ok_or(StakeError::Overflow)?;
intermediate.checked_div(total).ok_or(StakeError::Overflow)?
}
}
}
} as u64;
It's a bit complicated and I haven't tested all edge cases of this piece of code, but am wondering if there is just a better way to do this.