1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
use crate::scrt::cosmwasm_std::StdResult;
use super::uint256::Uint256;
/// Convert between tokens with different decimals.
///
/// # Arguments
///
/// * `amount` - the amount of input token to convert
/// * `rate` - corresponds to the output token decimals. E.g: If we want 1:1 rate and the output token has 6 decimals, then rate = 1_000_000
/// * `input_decimals` - the number of decimals of the input token
/// * `output_decimals` - the number of decimals of the output token
pub fn convert_token(
amount: impl Into<Uint256>,
rate: impl Into<Uint256>,
input_decimals: u8,
output_decimals: u8
) -> StdResult<Uint256> {
// result = amount * rate / one whole output token
let amount = amount.into();
let rate = rate.into();
let result = (amount * rate)?;
// But, if tokens have different number of decimals, we need to compensate either by
// dividing or multiplying (depending on which token has more decimals) by the difference.
// However, we can combine this and the last operation by simply dividing by the input decimals
// if there is a difference.
let compensation = if input_decimals == output_decimals {
output_decimals
} else {
input_decimals
};
let whole_token = Uint256::from(one_token(compensation));
let result = Uint256::from(result.0 / whole_token.0);
Ok(result)
}
/// Get the amount needed to represent 1 whole token given its decimals.
/// Ex. Given token A that has 3 decimals, 1 A == 1000
#[inline]
pub fn one_token(decimals: u8) -> u128 {
1 * 10u128.pow(decimals.into())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_convert_token() {
// Assuming the user friendly (in the UI) exchange rate has been set to
// 1 swapped_token (9 decimals) == 1.5 input_token (9 decimals):
// the rate would be 1 / 1.5 = 0.(6) or 666666666 (0.(6) ** 10 * 9)
// meaning the price for 1 whole swapped_token is
// 1500000000 (1.5 * 10 ** 9 decimals) of input_token.
// If we want to get 2 of swapped_token, we need to send 3 input_token
// i.e. amount = 3000000000 (3 * 10 ** 9 decimals)
let rate = 666_666_666;
let amount = 3_000_000_000u128;
let result = convert_token(amount, rate, 9, 9).unwrap();
assert_eq!(result, 1_999_999_998u128.into());
// Should work the same even if input_token has less decimals (ex. 6)
// Here amount has 3 zeroes less because input_token now has 6 decimals, so
// 1 input_token = 3000000 (3 * 10 ** 6)
let rate = 666_666_666;
let amount = 3_000_000;
let result = convert_token(amount, rate, 6, 9).unwrap();
assert_eq!(result, 1_999_999_998.into());
// And the other way around - when swap_token has 6 decimals.
// Here the rate and result have 3 less digits - to account for the less decimals
let rate = 666_666;
let amount = 3_000_000_000u64;
let result = convert_token(amount, rate, 9, 6).unwrap();
assert_eq!(result, 1_999_998.into());
let rate = 150000000;
let amount = 5 * one_token(18);
let result = convert_token(amount, rate, 18, 8).unwrap();
assert_eq!(result, 7_5_000_000_0.into());
let rate = 15 * one_token(17); // 1.5
let amount = 5 * one_token(8);
let result = convert_token(amount, rate, 8, 18).unwrap();
assert_eq!(result, (75 * one_token(17)).into()); // 7.5
}
}