Skip to content

Commit

Permalink
Allow passing decimals on low-level Kaspa parsing utilities
Browse files Browse the repository at this point in the history
  • Loading branch information
KaffinPX committed Sep 24, 2024
1 parent 255a235 commit 49ec7f5
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 11 deletions.
36 changes: 27 additions & 9 deletions wallet/core/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,14 @@ use kaspa_consensus_core::network::NetworkType;
use separator::{separated_float, separated_int, separated_uint_with_output, Separatable};
use workflow_log::style;

pub fn try_kaspa_str_to_sompi<S: Into<String>>(s: S) -> Result<Option<u64>> {
pub fn try_kaspa_str_to_sompi<S: Into<String>>(s: S, decimals: Option<u32>) -> Result<Option<u64>> {
let s: String = s.into();
let amount = s.trim();
if amount.is_empty() {
return Ok(None);
}

Ok(Some(str_to_sompi(amount)?))
Ok(Some(str_to_sompi(amount, decimals)?))
}

pub fn try_kaspa_str_to_sompi_i64<S: Into<String>>(s: S) -> Result<Option<i64>> {
Expand All @@ -35,6 +35,14 @@ pub fn sompi_to_kaspa(sompi: u64) -> f64 {
sompi as f64 / SOMPI_PER_KASPA as f64
}

#[inline]
pub fn sompi_to_kaspa_with_decimals(sompi: u64, decimals: Option<u32>) -> f64 {
let decimals = decimals.unwrap_or(8);
let sompi_per_unit = 10u64.pow(decimals);

sompi as f64 / sompi_per_unit as f64
}

#[inline]
pub fn kaspa_to_sompi(kaspa: f64) -> u64 {
(kaspa * SOMPI_PER_KASPA as f64) as u64
Expand Down Expand Up @@ -90,21 +98,31 @@ pub fn format_address_colors(address: &Address, range: Option<usize>) -> String
format!("{prefix}:{left}:{center}:{right}")
}

fn str_to_sompi(amount: &str) -> Result<u64> {
fn str_to_sompi(amount: &str, decimals: Option<u32>) -> Result<u64> {
let decimals = decimals.unwrap_or(8);
let sompi_per_unit = 10u64.pow(decimals);

// Check if the amount contains a decimal point, if doesn't return value directly.
let Some(dot_idx) = amount.find('.') else {
return Ok(amount.parse::<u64>()? * SOMPI_PER_KASPA);
return Ok(amount.parse::<u64>()? * sompi_per_unit);
};
let integer = amount[..dot_idx].parse::<u64>()? * SOMPI_PER_KASPA;

// Parse the integer part of the amount
let integer = amount[..dot_idx].parse::<u64>()? * sompi_per_unit;

let decimal = &amount[dot_idx + 1..];
let decimal_len = decimal.len();
let decimal = if decimal_len == 0 {
// If there are no digits after the decimal point, the fractional value is 0.
0
} else if decimal_len <= 8 {
decimal.parse::<u64>()? * 10u64.pow(8 - decimal_len as u32)
} else if decimal_len <= decimals as usize {
// If its within allowed decimals range, parse it as u64 and pad with zeros to the right to reach the correct precision.
decimal.parse::<u64>()? * 10u64.pow(decimals - decimal_len as u32)
} else {
// TODO - discuss how to handle values longer than 8 decimal places
// Truncate values longer than allowed decimal places.
// TODO - discuss how to handle values longer than supplied decimal places.
// (reject, truncate, ceil(), etc.)
decimal[..8].parse::<u64>()?
decimal[..decimals as usize].parse::<u64>()?
};
Ok(integer + decimal)
}
4 changes: 2 additions & 2 deletions wallet/core/src/wasm/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ extern "C" {
/// can be used to parse user input.
/// @category Wallet SDK
#[wasm_bindgen(js_name = "kaspaToSompi")]
pub fn kaspa_to_sompi(kaspa: String) -> Option<BigInt> {
crate::utils::try_kaspa_str_to_sompi(kaspa).ok().flatten().map(Into::into)
pub fn kaspa_to_sompi(kaspa: String, decimals: Option<u32>) -> Option<BigInt> {
crate::utils::try_kaspa_str_to_sompi(kaspa, decimals).ok().flatten().map(Into::into)
}

///
Expand Down

0 comments on commit 49ec7f5

Please sign in to comment.