Skip to content

Commit

Permalink
WIP wrapping addresses with macro
Browse files Browse the repository at this point in the history
  • Loading branch information
Sajjon committed Feb 20, 2024
1 parent c21494b commit 0623404
Show file tree
Hide file tree
Showing 27 changed files with 1,044 additions and 486 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ time-util = { version = "0.3.4", features = ["chrono"] }
assert-json-diff = "2.0.2"
url = { version = "2.5.0", features = ["serde"] }
num-format = "0.4.4"
paste = "1.0.14"

[build-dependencies]
uniffi = { version = "0.26.0", features = ["build"] }
Expand Down
6 changes: 6 additions & 0 deletions src/core/error/common_error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,12 @@ pub enum CommonError {

#[error("Unrecognized Locale Identifier: {bad_value}")]
UnrecognizedLocaleIdentifier { bad_value: String } = 10087,

#[error("Failed to create Address (via RetAddress) from node_id (hex): {node_id_as_hex}, network_id: {network_id}")]
FailedToCreateAddressViaRetAddressFromNodeIdAndNetworkID {
node_id_as_hex: String,
network_id: NetworkID,
} = 10088,
}

/*
Expand Down
105 changes: 105 additions & 0 deletions src/profile/v100/address/access_controller_address.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
use crate::prelude::*;

#[derive(
Clone,
Debug,
PartialEq,
Eq,
Hash,
derive_more::FromStr,
derive_more::Display,
SerializeDisplay,
DeserializeFromStr,
uniffi::Record,
)]
#[display("{__inner}")]
pub struct AccessControllerAddress {
pub(crate) __inner: InnerAccessControllerAddress,
}

#[uniffi::export]
pub fn new_access_controller_address(
bech32: String,
) -> Result<AccessControllerAddress> {
AccessControllerAddress::try_from_bech32(bech32.as_str())
}

#[cfg(test)]
mod tests {
use crate::prelude::*;

#[test]
fn display() {
let s = "resource_rdx1tknxxxxxxxxxradxrdxxxxxxxxx009923554798xxxxxxxxxradxrd";
let a = AccessControllerAddress::try_from_bech32(s).unwrap();
assert_eq!(format!("{a}"), s);
}

#[test]
fn json_roundtrip() {
let a: AccessControllerAddress =
"resource_rdx1tknxxxxxxxxxradxrdxxxxxxxxx009923554798xxxxxxxxxradxrd"
.parse()
.unwrap();

assert_json_value_eq_after_roundtrip(
&a,
json!("resource_rdx1tknxxxxxxxxxradxrdxxxxxxxxx009923554798xxxxxxxxxradxrd"),
);
assert_json_roundtrip(&a);
assert_json_value_ne_after_roundtrip(
&a,
json!("resource_rdx1tkk83magp3gjyxrpskfsqwkg4g949rmcjee4tu2xmw93ltw2cz94sq"),
);
}

#[test]
fn json_roundtrip_fails_for_invalid() {
assert_json_value_fails::<AccessControllerAddress>(
json!("resource_rdx1tknxxxxxxxxxradxrdxxxxxxxxx009923554798xxxxxxxxxradxxx")
);
assert_json_value_fails::<AccessControllerAddress>(
json!("account_rdx1tknxxxxxxxxxradxrdxxxxxxxxx009923554798xxxxxxxxxradxrd")
);
assert_json_value_fails::<AccessControllerAddress>(json!(
"super invalid"
));
}

#[test]
fn network_id_stokenet() {
let a: AccessControllerAddress =
"resource_tdx_2_1tkckx9fynl9f7756z8wxphq7wce6vk874nuq4f2nnxgh3nzrwhjdlp"
.parse()
.unwrap();
assert_eq!(a.network_id(), NetworkID::Stokenet);
}

#[test]
fn network_id_mainnet() {
let a: AccessControllerAddress =
"resource_rdx1tknxxxxxxxxxradxrdxxxxxxxxx009923554798xxxxxxxxxradxrd"
.parse()
.unwrap();
assert_eq!(a.network_id(), NetworkID::Mainnet);
}
}

#[cfg(test)]
mod uniffi_tests {
use crate::{new_resource_address, EntityAddress};

use super::*;

#[allow(clippy::upper_case_acronyms)]
type SUT = AccessControllerAddress;

#[test]
fn new() {
let s = "resource_rdx1tknxxxxxxxxxradxrdxxxxxxxxx009923554798xxxxxxxxxradxrd";
let a = AccessControllerAddress::try_from_bech32(s).unwrap();
let b = new_access_controller_address(s.to_string()).unwrap();
assert_eq!(b.address(), s);
assert_eq!(a, b);
}
}
147 changes: 31 additions & 116 deletions src/profile/v100/address/account_address.rs
Original file line number Diff line number Diff line change
@@ -1,103 +1,39 @@
use radix_engine_toolkit::models::canonical_address_types::{
CanonicalAccountAddress as RetAccountAddress,
CanonicalAddress as RetIsAddressTrait,
};
pub use crate::prelude::*;
// use crate::InnerAccountAddress;

use crate::prelude::*;

pub trait RetStringType:
RetIsAddressTrait + std::fmt::Display + FromStr
{
}

/// UniFFI conversion for RET types which are DisplayFromStr using String as builtin.
impl<U: RetStringType> crate::UniffiCustomTypeConverter for U {
type Builtin = String;

#[cfg(not(tarpaulin_include))] // false negative, tested in bindgen tests
fn into_custom(val: Self::Builtin) -> uniffi::Result<Self> {
val.parse::<U>().map_err(|e| e.into())
}

#[cfg(not(tarpaulin_include))] // false negative, tested in bindgen tests
fn from_custom(obj: Self) -> Self::Builtin {
obj.to_string()
}
}

pub trait WrappingRetStringType: From<Self::Inner> + Into<Self::Inner> + std::fmt::Display + FromStr<Err = CommonError> {
type Inner: RetStringType;
}

impl RetStringType for RetAccountAddress {}

pub struct InnerAccountAddress {}

/// The address of an Account, a bech32 encoding of a public key hash
/// that starts with the prefix `"account_"`, dependent on NetworkID, meaning the same
/// public key used for two AccountAddresses on two different networks will not have
/// the same address.
/// Human readable address of an account. Always starts with `"account_"``, for example:
///
/// `account_rdx16xlfcpp0vf7e3gqnswv8j9k58n6rjccu58vvspmdva22kf3aplease`
///
/// Most commonly the user will see this address in its abbreviated
/// form which is:
///
/// `acco...please`
///
/// Addresses are checksummed, as per Bech32. **Only** *Account* addresses starts with
/// the prefix `account_`.
#[derive(
Clone,
Debug,
Default,
PartialEq,
Eq,
Hash,
// SerializeDisplay,
// DeserializeFromStr,
derive_more::FromStr,
derive_more::Display,
uniffi::Record,
)]
#[display("{__inner}")]
struct AccountAddress2 {
__inner: RetAccountAddress,
}

impl WrappingRetStringType for AccountAddress2 {
type Inner = RetAccountAddress;
}

/// The address of an Account, a bech32 encoding of a public key hash
/// that starts with the prefix `"account_"`, dependent on NetworkID, meaning the same
/// public key used for two AccountAddresses on two different networks will not have
/// the same address.
#[derive(
Clone,
Debug,
Default,
PartialEq,
Eq,
Hash,
SerializeDisplay,
DeserializeFromStr,
derive_more::Display,
uniffi::Record,
)]
#[display("{address}")]
#[display("{__inner}")]
pub struct AccountAddress {
/// Human readable address of an account. Always starts with `"account_"``, for example:
///
/// `account_rdx16xlfcpp0vf7e3gqnswv8j9k58n6rjccu58vvspmdva22kf3aplease`
///
/// Most commonly the user will see this address in its abbreviated
/// form which is:
///
/// `acco...please`
///
/// Addresses are checksummed, as per Bech32. **Only** *Account* addresses starts with
/// the prefix `account_`.
pub address: String,

/// The network this account address is tied to, i.e. which was used when a public key
/// hash was used to bech32 encode it. This means that two public key hashes will result
/// in two different account address on two different networks.
pub network_id: NetworkID,
pub(crate) __inner: InnerAccountAddress,
}

#[uniffi::export]
pub fn new_account_address(bech32: String) -> Result<AccountAddress> {
AccountAddress::try_from_bech32(bech32.as_str())
// AccountAddress::try_from_bech32(bech32.as_str())
todo!()
}

#[uniffi::export]
Expand Down Expand Up @@ -127,7 +63,8 @@ pub fn account_address_to_short(address: &AccountAddress) -> String {

impl AccountAddress {
pub fn new(public_key: PublicKey, network_id: NetworkID) -> Self {
<Self as EntityAddress>::from_public_key(public_key, network_id)
// <Self as EntityAddress>::from_public_key(public_key, network_id)
todo!();
}

/// Formats the AccountAddress to its abbreviated form which is what the user
Expand All @@ -143,16 +80,8 @@ impl AccountAddress {
/// `account_rdx16xlfcpp0vf7e3gqnswv8j9k58n6rjccu58vvspmdva22kf3aplease`
///
pub fn short(&self) -> String {
let suffix = suffix_str(6, &self.address);
format!("{}...{}", &self.address[0..4], suffix)
}
}

impl FromStr for AccountAddress {
type Err = CommonError;

fn from_str(s: &str) -> Result<Self, Self::Err> {
AccountAddress::try_from_bech32(s)
let suffix = suffix_str(6, &self.address());
format!("{}...{}", &self.address()[0..4], suffix)
}
}

Expand All @@ -163,20 +92,6 @@ impl EntityAddress for AccountAddress {
fn entity_type() -> AbstractEntityType {
AbstractEntityType::Account
}

// Underscored to decrease visibility. You SHOULD NOT call this function directly,
// instead use `try_from_bech32` which performs proper validation. Impl types SHOULD
// `panic` if `address` does not start with `Self::entity_type().hrp()`
fn __with_address_and_network_id(
address: &str,
network_id: NetworkID,
) -> Self {
assert!(address.starts_with(&Self::entity_type().hrp()), "Invalid address, you SHOULD NOT call this function directly, you should use `try_from_bech32` instead.");
Self {
address: address.to_string(),
network_id,
}
}
}

impl HasPlaceholder for AccountAddress {
Expand All @@ -198,7 +113,7 @@ impl AccountAddress {
"account_rdx16xlfcpp0vf7e3gqnswv8j9k58n6rjccu58vvspmdva22kf3aplease",
)
.unwrap();
assert_eq!(address.network_id, NetworkID::Mainnet);
assert_eq!(address.network_id(), NetworkID::Mainnet);
address
}

Expand All @@ -208,7 +123,7 @@ impl AccountAddress {
"account_rdx16yf8jxxpdtcf4afpj5ddeuazp2evep7quuhgtq28vjznee08master",
)
.unwrap();
assert_eq!(address.network_id, NetworkID::Mainnet);
assert_eq!(address.network_id(), NetworkID::Mainnet);
address
}

Expand All @@ -218,7 +133,7 @@ impl AccountAddress {
"account_tdx_2_1289zm062j788dwrjefqkfgfeea5tkkdnh8htqhdrzdvjkql4kxceql",
)
.unwrap();
assert_eq!(address.network_id, NetworkID::Stokenet);
assert_eq!(address.network_id(), NetworkID::Stokenet);
address
}

Expand All @@ -228,7 +143,7 @@ impl AccountAddress {
"account_tdx_2_129663ef7fj8azge3y6sl73lf9vyqt53ewzlf7ul2l76mg5wyqlqlpr",
)
.unwrap();
assert_eq!(address.network_id, NetworkID::Stokenet);
assert_eq!(address.network_id(), NetworkID::Stokenet);
address
}
}
Expand Down Expand Up @@ -297,7 +212,7 @@ mod tests {

assert_eq!(
AccountAddress::from_public_key::<PublicKey>(public_key.into(), NetworkID::Mainnet)
.address,
.address(),
"account_rdx129qdd2yp9vs8jkkn2uwn6sw0ejwmcwr3r4c3usr2hp0nau67m2kzdm"
)
}
Expand All @@ -310,7 +225,7 @@ mod tests {
.unwrap();

assert_eq!(
AccountAddress::new(public_key.into(), NetworkID::Mainnet).address,
AccountAddress::new(public_key.into(), NetworkID::Mainnet).address(),
"account_rdx129qdd2yp9vs8jkkn2uwn6sw0ejwmcwr3r4c3usr2hp0nau67m2kzdm"
)
}
Expand All @@ -321,7 +236,7 @@ mod tests {
"account_tdx_b_1286wrrqrfcrfhthfrtdywe8alney8zu0ja5xrhcq2475ej08m9raqq",
)
.unwrap();
assert_eq!(address.network_id, NetworkID::Nebunet)
assert_eq!(address.network_id(), NetworkID::Nebunet)
}

#[test]
Expand All @@ -330,7 +245,7 @@ mod tests {
"account_rdx16xlfcpp0vf7e3gqnswv8j9k58n6rjccu58vvspmdva22kf3aplease",
)
.unwrap();
assert_eq!(sut.network_id, NetworkID::Mainnet);
assert_eq!(sut.network_id(), NetworkID::Mainnet);
}

#[test]
Expand Down Expand Up @@ -443,6 +358,6 @@ mod uniffi_tests {
AccountAddress::try_from_bech32(bech32).unwrap(),
from_bech32.clone()
);
assert_eq!(from_bech32.address, bech32)
assert_eq!(from_bech32.address(), bech32)
}
}
Loading

0 comments on commit 0623404

Please sign in to comment.