Skip to content

Commit 965fc06

Browse files
Merge pull request #4 from waves-rust/0.3.1
0.3.1
2 parents bdf10de + 8602c7e commit 965fc06

6 files changed

Lines changed: 209 additions & 5 deletions

File tree

Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "wavesplatform"
3-
version = "0.3.0"
3+
version = "0.3.1"
44
authors = ["peterz <peterz@rambler.ru>", "DEADBLACKCLOVER <deadblackclover@protonmail.com>"]
55
description = "Library to work with Waves blockchain (https://waves.tech/)"
66
edition = "2018"
@@ -13,6 +13,7 @@ keywords = ["waves", "blockchain"]
1313
[dependencies]
1414
base58 = "0.2.0"
1515
rand = "0.8.5"
16+
regex = "1.6.0"
1617
tiny-bip39 = "1.0.0"
1718

1819
blake2 = "0.9.2"

examples/get_balance.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use wavesplatform::node::{Node, MAINNET_URL};
2+
use wavesplatform::util::Amount;
23

34
#[tokio::main]
45
async fn main() -> Result<(), Box<dyn std::error::Error>> {
@@ -9,13 +10,17 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
910
.get_balance("3PEktVux2RhchSN63DsDo4b4mz4QqzKSeDv")
1011
.await?;
1112

12-
println!("Balance: {} WAVES", result.balance());
13+
let balance = Amount::from_wavelet(result.balance());
14+
15+
println!("Balance: {} WAVES", balance);
1316

1417
let result = node
1518
.get_balance_details("3PEktVux2RhchSN63DsDo4b4mz4QqzKSeDv")
1619
.await?;
1720

18-
println!("Regular balance: {} WAVES", result.regular());
21+
let balance = Amount::from_wavelet(result.regular());
22+
23+
println!("Regular balance: {} WAVES", balance);
1924

2025
Ok(())
2126
}

src/node.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ impl<'a> Node<'a> {
3434
/// Get the regular balance in WAVES at a given address
3535
/// ```no_run
3636
/// use wavesplatform::node::{Node, MAINNET_URL};
37+
/// use wavesplatform::util::Amount;
3738
///
3839
/// #[tokio::main]
3940
/// async fn main() -> Result<(), Box<dyn std::error::Error>> {
@@ -43,7 +44,9 @@ impl<'a> Node<'a> {
4344
/// .get_balance("3PEktVux2RhchSN63DsDo4b4mz4QqzKSeDv")
4445
/// .await?;
4546
///
46-
/// println!("Balance: {} WAVES", result.balance());
47+
/// let balance = Amount::from_wavelet(result.balance());
48+
///
49+
/// println!("Balance: {} WAVES", balance);
4750
///
4851
/// Ok(())
4952
/// }
@@ -62,6 +65,7 @@ impl<'a> Node<'a> {
6265
/// Get the available, regular, generating, and effective balance
6366
/// ```no_run
6467
/// use wavesplatform::node::{Node, MAINNET_URL};
68+
/// use wavesplatform::util::Amount;
6569
///
6670
/// #[tokio::main]
6771
/// async fn main() -> Result<(), Box<dyn std::error::Error>> {
@@ -71,7 +75,9 @@ impl<'a> Node<'a> {
7175
/// .get_balance_details("3PEktVux2RhchSN63DsDo4b4mz4QqzKSeDv")
7276
/// .await?;
7377
///
74-
/// println!("Regular balance: {} WAVES", result.regular());
78+
/// let balance = Amount::from_wavelet(result.regular());
79+
///
80+
/// println!("Regular balance: {} WAVES", balance);
7581
///
7682
/// Ok(())
7783
/// }

src/util.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
1+
mod alias;
2+
mod amount;
3+
14
use curve25519_dalek::montgomery::MontgomeryPoint;
25
use ed25519_dalek::*;
36

7+
pub use alias::*;
8+
pub use amount::*;
9+
410
/// Signature verify function
511
pub fn sig_verify(
612
message: &[u8],

src/util/alias.rs

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
use regex::Regex;
2+
use std::fmt;
3+
4+
/// Regular expression for the definition of alias
5+
const REGEXP: &str = "^[-.0-9@_a-z]{4,30}$";
6+
/// Regular expression for the definition of alias with prefix
7+
const REGEXP_WITH_PREFIX: &str = "^alias:[A-Z]{1}:[-.0-9@_a-z]{4,30}$";
8+
9+
/// List of errors in processing [`Alias`]
10+
#[derive(Debug, PartialEq, Eq)]
11+
pub enum AliasError {
12+
InvalidAlias,
13+
RegexError,
14+
}
15+
16+
/// The [`Alias`] type on working with aliases in the Waves blockchain and presenting it in a format with or without the network prefix
17+
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
18+
pub struct Alias(String);
19+
20+
impl Alias {
21+
/// Create an [`Alias`] from the string
22+
pub fn new(alias: &str) -> Result<Alias, AliasError> {
23+
if Self::is_valid(REGEXP, alias)? {
24+
Ok(Alias(format!("{}", alias)))
25+
} else if Self::is_valid(REGEXP_WITH_PREFIX, alias)? {
26+
let value = Self::replace_prefix(alias)?;
27+
Ok(Alias(value))
28+
} else {
29+
Err(AliasError::InvalidAlias)
30+
}
31+
}
32+
33+
/// Representing [`Alias`] as a string with a prefix
34+
pub fn to_string_with_prefix(&self, chain_id: u8) -> String {
35+
format!("alias:{}:{}", chain_id as char, self.0)
36+
}
37+
38+
/// Validation of alias using regular expressions
39+
fn is_valid(regexp: &str, alias: &str) -> Result<bool, AliasError> {
40+
match Regex::new(regexp) {
41+
Ok(r) => Ok(r.is_match(alias)),
42+
Err(_) => Err(AliasError::RegexError),
43+
}
44+
}
45+
46+
/// Removing the prefix with regular expressions
47+
fn replace_prefix(alias: &str) -> Result<String, AliasError> {
48+
match Regex::new("^alias:[A-Z]{1}:") {
49+
Ok(r) => Ok(r.replace(alias, "").to_string()),
50+
Err(_) => Err(AliasError::RegexError),
51+
}
52+
}
53+
}
54+
55+
impl fmt::Display for Alias {
56+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
57+
write!(f, "{}", self.0)
58+
}
59+
}
60+
61+
#[cfg(test)]
62+
mod tests {
63+
use super::*;
64+
use crate::account::TESTNET;
65+
66+
#[test]
67+
fn test_alias() {
68+
let result = Alias::new("test");
69+
assert!(result.is_ok());
70+
71+
let alias = result.unwrap();
72+
73+
assert_eq!(alias.to_string(), "test");
74+
assert_eq!(alias.to_string_with_prefix(TESTNET), "alias:T:test");
75+
76+
let result = Alias::new("a");
77+
assert_eq!(result, Err(AliasError::InvalidAlias));
78+
79+
let result = Alias::new("3MzGEv9wnaqrYFYujAXSH5RQfHaVKNQvx3D");
80+
assert_eq!(result, Err(AliasError::InvalidAlias));
81+
}
82+
83+
#[test]
84+
fn test_alias_with_prefix() {
85+
let result = Alias::new("alias:T:test");
86+
assert!(result.is_ok());
87+
88+
let alias = result.unwrap();
89+
90+
assert_eq!(alias.to_string(), "test");
91+
assert_eq!(alias.to_string_with_prefix(TESTNET), "alias:T:test");
92+
}
93+
}

src/util/amount.rs

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
use std::fmt;
2+
use std::str::FromStr;
3+
4+
/// The number of decimal places (decimals) for WAVES is 8.
5+
const DECIMALS: usize = 8;
6+
7+
/// The [`Amount`] type can be used to express Waves amounts that supports conversion to various denominations.
8+
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
9+
pub struct Amount(u64);
10+
11+
impl Amount {
12+
/// The zero amount.
13+
pub const ZERO: Amount = Amount(0);
14+
/// Exactly one WAVELET.
15+
pub const ONE_WAVELET: Amount = Amount(1);
16+
/// Exactly one WAVES.
17+
pub const ONE_WAVES: Amount = Amount(100_000_000);
18+
19+
/// Create an [`Amount`] with WAVELET precision and the given number of WAVELET.
20+
pub fn from_wavelet(wavelet: u64) -> Amount {
21+
Amount(wavelet)
22+
}
23+
24+
/// The maximum value of an [`Amount`].
25+
pub fn max_value() -> Amount {
26+
Amount(u64::max_value())
27+
}
28+
29+
/// The minimum value of an [`Amount`].
30+
pub fn min_value() -> Amount {
31+
Amount(u64::min_value())
32+
}
33+
34+
/// Get the number of WAVELET in this [`Amount`].
35+
pub fn as_wavelet(self) -> u64 {
36+
self.0
37+
}
38+
39+
/// Express this [`Amount`] as a floating-point value in WAVES.
40+
pub fn as_waves(self) -> f64 {
41+
let real = format!("{:0width$}", self.0, width = DECIMALS);
42+
43+
if real.len() == DECIMALS {
44+
let result = format!("0.{}", &real[real.len() - DECIMALS..]);
45+
f64::from_str(&result).unwrap()
46+
} else {
47+
let result = format!(
48+
"{}.{}",
49+
&real[0..(real.len() - DECIMALS)],
50+
&real[real.len() - DECIMALS..]
51+
);
52+
f64::from_str(&result).unwrap()
53+
}
54+
}
55+
}
56+
57+
impl Default for Amount {
58+
fn default() -> Self {
59+
Amount::ZERO
60+
}
61+
}
62+
63+
impl fmt::Display for Amount {
64+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
65+
write!(f, "{}", self.as_waves())
66+
}
67+
}
68+
69+
#[cfg(test)]
70+
mod tests {
71+
use super::*;
72+
73+
#[test]
74+
fn test() {
75+
let wavelet = 1_000;
76+
let balance = Amount::from_wavelet(wavelet);
77+
assert_eq!(balance.as_waves(), 0.00001);
78+
79+
let wavelet = 1_000_000;
80+
let balance = Amount::from_wavelet(wavelet);
81+
assert_eq!(balance.as_waves(), 0.01);
82+
83+
let wavelet = 1_000_000_000;
84+
let balance = Amount::from_wavelet(wavelet);
85+
assert_eq!(balance.as_waves(), 10.0);
86+
}
87+
88+
#[test]
89+
fn test_one_waves() {
90+
let one_waves = Amount::ONE_WAVES;
91+
assert_eq!(one_waves.as_waves(), 1.0);
92+
}
93+
}

0 commit comments

Comments
 (0)