Skip to content
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

TransactionRecord: isCoinbase and hasAddress by string + Utils: Unit-parsing functions + Address: verify with network #102

Open
wants to merge 14 commits into
base: gamma-dev
Choose a base branch
from
Open
14 changes: 12 additions & 2 deletions crypto/addresses/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -230,8 +230,18 @@ impl Address {
}

#[wasm_bindgen(js_name=validate)]
pub fn validate(address: &str) -> bool {
Self::try_from(address).is_ok()
pub fn validate(address: &str, prefix: Option<String>) -> bool {
let address = Self::try_from(address).ok();

if let Some(address) = address {
if let Some(prefix) = prefix {
let prefix = Prefix::try_from(prefix.as_str()).expect("Address::verify() - invalid network prefix");
return address.prefix == prefix;
}
return true;
}

false
}

/// Convert an address to a string.
Expand Down
12 changes: 10 additions & 2 deletions wallet/core/src/storage/transaction/record.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use super::*;
use crate::imports::*;
use crate::storage::{Binding, BindingT};
use crate::tx::PendingTransactionInner;
use kaspa_addresses::AddressT;
use workflow_core::time::{unixtime_as_millis_u64, unixtime_to_locale_string};
use workflow_wasm::utils::try_get_js_value_prop;

Expand Down Expand Up @@ -814,8 +815,15 @@ impl TransactionRecord {

/// Check if the transaction record has the given address within the associated UTXO set.
#[wasm_bindgen(js_name = hasAddress)]
pub fn has_address(&self, address: &Address) -> bool {
self.transaction_data.has_address(address)
pub fn has_address(&self, address: &AddressT) -> Result<bool> {
let address = Address::try_cast_from(address)?;
Ok(self.transaction_data.has_address(address.as_ref()))
}

/// Check if the transaction record is coinbase sourced.
#[wasm_bindgen(getter, js_name = "isCoinbase")]
pub fn is_coinbase_sourced(&self) -> bool {
self.is_coinbase()
}

/// Serialize the transaction record to a JavaScript object.
Expand Down
50 changes: 50 additions & 0 deletions wallet/core/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,16 @@ pub fn try_kaspa_str_to_sompi<S: Into<String>>(s: S) -> Result<Option<u64>> {
Ok(Some(str_to_sompi(amount)?))
}

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

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

pub fn try_kaspa_str_to_sompi_i64<S: Into<String>>(s: S) -> Result<Option<i64>> {
let s: String = s.into();
let amount = s.trim();
Expand All @@ -45,6 +55,18 @@ pub fn sompi_to_kaspa_string(sompi: u64) -> String {
sompi_to_kaspa(sompi).separated_string()
}

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

sompi as f64 / sompi_per_unit as f64
}

#[inline]
pub fn sompi_to_unit_string(sompi: u64, decimals: u32) -> String {
sompi_to_unit(sompi, decimals).separated_string()
}

#[inline]
pub fn sompi_to_kaspa_string_with_trailing_zeroes(sompi: u64) -> String {
separated_float!(format!("{:.8}", sompi_to_kaspa(sompi)))
Expand Down Expand Up @@ -108,3 +130,31 @@ fn str_to_sompi(amount: &str) -> Result<u64> {
};
Ok(integer + decimal)
}

fn str_to_unit(amount: &str, decimals: u32) -> Result<u64> {
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_unit);
};

// 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 <= 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 {
// Truncate values longer than allowed decimal places.
// TODO - discuss how to handle values longer than supplied decimal places.
// (reject, truncate, ceil(), etc.)
decimal[..decimals as usize].parse::<u64>()?
};
Ok(integer + decimal)
}
20 changes: 20 additions & 0 deletions wallet/core/src/wasm/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,15 @@ pub fn kaspa_to_sompi(kaspa: String) -> Option<BigInt> {
crate::utils::try_kaspa_str_to_sompi(kaspa).ok().flatten().map(Into::into)
}

/// Convert a Kaspa string to a specific unit represented by bigint.
/// This function provides correct precision handling and
/// can be used to parse user input.
/// @category Wallet SDK
#[wasm_bindgen(js_name = "kaspaToUnit")]
pub fn kaspa_to_unit(kaspa: String, decimals: u32) -> Option<BigInt> {
crate::utils::try_kaspa_str_to_unit(kaspa, decimals).ok().flatten().map(Into::into)
}

///
/// Convert Sompi to a string representation of the amount in Kaspa.
///
Expand All @@ -31,6 +40,17 @@ pub fn sompi_to_kaspa_string(sompi: ISompiToKaspa) -> Result<String> {
Ok(crate::utils::sompi_to_kaspa_string(sompi))
}

///
/// Convert Sompi to a string representation of an unit in Kaspa.
///
/// @category Wallet SDK
///
#[wasm_bindgen(js_name = "sompiToUnitString")]
pub fn sompi_to_unit_string(sompi: ISompiToKaspa, decimals: u32) -> Result<String> {
let sompi = sompi.try_as_u64()?;
Ok(crate::utils::sompi_to_unit_string(sompi, decimals))
}

///
/// Format a Sompi amount to a string representation of the amount in Kaspa with a suffix
/// based on the network type (e.g. `KAS` for mainnet, `TKAS` for testnet,
Expand Down
Loading