3

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.

1
  • Or is there a way to cast u128 as a higher data type? That would make things much easier.
    – Varun Siva
    Commented Apr 21 at 20:27

1 Answer 1

1

You can certainly do something like this, or use a 256-bit number using a crate like uint https://github.com/paritytech/parity-common/tree/master/uint, ie:

construct_uint! {
    /// 256-bit unsigned integer.
    pub struct U256(4);
}

And then perform math on it as you need.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.