diff --git a/fixtures/vector/wallet_interactions_dapp_to_wallet.json b/fixtures/vector/wallet_interactions_dapp_to_wallet.json new file mode 100644 index 000000000..8f1e2b084 --- /dev/null +++ b/fixtures/vector/wallet_interactions_dapp_to_wallet.json @@ -0,0 +1,155 @@ +[ + { + "interactionId" : "d59590ea-d50b-4e8d-a5e1-da3a2574ae5c", + "items" : { + "discriminator" : "authorizedRequest", + "auth" : { + "discriminator" : "loginWithChallenge", + "challenge" : "e280cfa39e1499f2862e59759cc2fc990cce28b70a7989324fe91c47814d0630" + }, + "reset" : { + "accounts" : true, + "personaData" : true + }, + "ongoingAccounts" : { + "numberOfAccounts" : { + "quantifier" : "atLeast", + "quantity" : 4 + }, + "challenge" : "e280cfa39e1499f2862e59759cc2fc990cce28b70a7989324fe91c47814d0630" + }, + "ongoingPersonaData" : { + "isRequestingName" : true, + "numberOfRequestedEmailAddresses" : { + "quantifier" : "exactly", + "quantity" : 1 + }, + "numberOfRequestedPhoneNumbers" : { + "quantifier" : "exactly", + "quantity" : 1 + } + } + }, + "metadata" : { + "version" : 2, + "networkId" : 2, + "origin" : "https://dev-sandbox.rdx-works-main.extratools.works/", + "dAppDefinitionAddress" : "account_tdx_2_12xd46c22d6m696lv565t9afn088htudtq275px3qs925ywwty8axze" + } + }, + { + "interactionId" : "d59590ea-d50b-4e8d-a5e1-da3a2574ae5c", + "items" : { + "discriminator" : "authorizedRequest", + "auth" : { + "discriminator" : "loginWithoutChallenge" + }, + "reset" : { + "accounts" : true, + "personaData" : true + }, + "ongoingAccounts" : { + "numberOfAccounts" : { + "quantifier" : "exactly", + "quantity" : 4 + }, + "challenge" : "e280cfa39e1499f2862e59759cc2fc990cce28b70a7989324fe91c47814d0630" + }, + "ongoingPersonaData" : { + "isRequestingName" : true, + "numberOfRequestedEmailAddresses" : { + "quantifier" : "atLeast", + "quantity" : 1 + }, + "numberOfRequestedPhoneNumbers" : { + "quantifier" : "atLeast", + "quantity" : 1 + } + } + }, + "metadata" : { + "version" : 2, + "networkId" : 2, + "origin" : "https://dev-sandbox.rdx-works-main.extratools.works/", + "dAppDefinitionAddress" : "account_tdx_2_12xd46c22d6m696lv565t9afn088htudtq275px3qs925ywwty8axze" + } + }, + { + "interactionId" : "4051ff20-03b0-4a48-8205-0e8e8c673289", + "items" : { + "discriminator" : "transaction", + "send" : { + "version" : 1, + "message" : "test message", + "blobs": ["0061736d0100000001c8011c60037f7f7f0060027f7f0060027f7f017f60017f0060037f7f7f017f60017f017f60047f7f7f7f0060017f017e60037f7f7f017e60057f7f7f7f7f0060057f7f7f7f7f017f60027f7e017f60037f7f7e0"], + "transactionManifest" : "CALL_FUNCTION Address(\"package_tdx_2_1pkgxxxxxxxxxplxxxxxxxxxxxxx020379220524xxxxxxxxxe4r780\") \n \"OneResourcePool\"\n \"instantiate\"\n Enum(Enum())\n Enum() \n Address(\"resource_tdx_2_1tknxxxxxxxxxradxrdxxxxxxxxx009923554798xxxxxxxxxtfd2jc\")\n None;" + } + }, + "metadata" : { + "version" : 2, + "networkId" : 2, + "origin" : "https://dev-sandbox.rdx-works-main.extratools.works/", + "dAppDefinitionAddress" : "account_tdx_2_12xd46c22d6m696lv565t9afn088htudtq275px3qs925ywwty8axze" + } + }, + { + "interactionId" : "51a720a5-9f80-4d0f-8264-704d1645f0af", + "items" : { + "discriminator" : "unauthorizedRequest", + "oneTimeAccounts" : { + "numberOfAccounts" : { + "quantifier" : "atLeast", + "quantity" : 1 + }, + "challenge" : "84a5234f14a50dee062dc7a6a51f4bdab7cab5faadea05542af2040688d8fb6c" + }, + "oneTimePersonaData" : { + "isRequestingName" : true, + "numberOfRequestedEmailAddresses" : { + "quantifier" : "exactly", + "quantity" : 1 + }, + "numberOfRequestedPhoneNumbers" : { + "quantifier" : "exactly", + "quantity" : 1 + } + } + }, + "metadata" : { + "version" : 2, + "networkId" : 2, + "origin" : "https://dev-sandbox.rdx-works-main.extratools.works/", + "dAppDefinitionAddress" : "account_tdx_2_12xd46c22d6m696lv565t9afn088htudtq275px3qs925ywwty8axze" + } + }, + { + "interactionId" : "51a720a5-9f80-4d0f-8264-704d1645f0af", + "items" : { + "discriminator" : "unauthorizedRequest", + "oneTimeAccounts" : { + "numberOfAccounts" : { + "quantifier" : "exactly", + "quantity" : 1 + }, + "challenge" : "84a5234f14a50dee062dc7a6a51f4bdab7cab5faadea05542af2040688d8fb6c" + }, + "oneTimePersonaData" : { + "isRequestingName" : true, + "numberOfRequestedEmailAddresses" : { + "quantifier" : "atLeast", + "quantity" : 1 + }, + "numberOfRequestedPhoneNumbers" : { + "quantifier" : "atLeast", + "quantity" : 1 + } + } + }, + "metadata" : { + "version" : 2, + "networkId" : 2, + "origin" : "https://dev-sandbox.rdx-works-main.extratools.works/", + "dAppDefinitionAddress" : "account_tdx_2_12xd46c22d6m696lv565t9afn088htudtq275px3qs925ywwty8axze" + } + } +] \ No newline at end of file diff --git a/fixtures/vector/wallet_interactions_wallet_to_dapp.json b/fixtures/vector/wallet_interactions_wallet_to_dapp.json new file mode 100644 index 000000000..97ab6ab59 --- /dev/null +++ b/fixtures/vector/wallet_interactions_wallet_to_dapp.json @@ -0,0 +1,115 @@ +[ + { + "discriminator" : "success", + "interactionId" : "06f00fbc-67ed-4a22-a122-1da719b25b6f", + "items" : { + "discriminator" : "authorizedRequest", + "auth" : { + "discriminator" : "loginWithChallenge", + "persona" : { + "identityAddress" : "identity_tdx_2_12twas58v4sthsmuky5653dup0drez3vcfwsfm6kp40qu9qyt8fgts6", + "label" : "Usdudh" + }, + "challenge" : "069ef236486d4cd5706b5e5b168e19f750ffd1b4876529a0a9de966d50a15ab7", + "proof" : { + "publicKey" : "ff8aee4c625738e35d837edb11e33b8abe0d6f40849ca1451edaba84d04d0699", + "curve" : "curve25519", + "signature" : "10177ac7d486691777133ffe59d46d55529d86cb1c4ce66aa82f432372f33e24d803d8498f42e26fe113c030fce68c526aeacff94334ba5a7f7ef84c2936eb05" + } + }, + "ongoingAccounts" : { + "accounts" : [ + { + "address" : "account_tdx_2_129qeystv8tufmkmjrry2g6kadhhfh4f7rd0x3t9yagcvfhspt62paz", + "label" : "Dff", + "appearanceId" : 0 + }, + { + "address" : "account_tdx_2_128928hvf6pjr3rx2xvdw6ulf7pc8g88ya8ma3j8dtjmntckz09fr3n", + "label" : "Ghhvgfvf", + "appearanceId" : 1 + } + ], + "challenge" : "069ef236486d4cd5706b5e5b168e19f750ffd1b4876529a0a9de966d50a15ab7", + "proofs" : [ + { + "proof" : { + "publicKey" : "11b162e3343ce770b6e9ed8a29d125b5580d1272b0dc4e2bd0fcae33320d9566", + "curve" : "curve25519", + "signature" : "e18617b527d4d33607a8adb6a040c26ca97642ec89dd8a6fe7a41fa724473e4cc69b0729c1df57aba77455801f2eef6f28848a5d206e3739de29ca2288957502" + }, + "accountAddress" : "account_tdx_2_129qeystv8tufmkmjrry2g6kadhhfh4f7rd0x3t9yagcvfhspt62paz" + }, + { + "proof" : { + "publicKey" : "5386353e4cc27e3d27d064d777d811e242a16ba7aefd425062ed46631739619d", + "curve" : "curve25519", + "signature" : "0143fd941d51f531c8265b0f6b24f4cfcdfd24b40aac47dee6fb3386ce0d400563c892e3894a33840d1c7af2dd43ecd0729fd209171003765d109a04d7485605" + }, + "accountAddress" : "account_tdx_2_128928hvf6pjr3rx2xvdw6ulf7pc8g88ya8ma3j8dtjmntckz09fr3n" + } + ] + }, + "ongoingPersonaData" : { + "name" : { + "variant" : "western", + "familyName" : "Family", + "givenNames" : "Given", + "nickname" : "Nick" + }, + "emailAddresses" : [ + "some@gmail.com" + ], + "phoneNumbers" : [ + "071234579" + ] + } + } + }, + { + "discriminator" : "success", + "interactionId" : "278608e0-e5ca-416e-8339-f2d2695651c4", + "items" : { + "oneTimeAccounts" : { + "accounts" : [ + { + "address" : "account_tdx_2_129qeystv8tufmkmjrry2g6kadhhfh4f7rd0x3t9yagcvfhspt62paz", + "label" : "Dff", + "appearanceId" : 0 + } + ] + }, + "discriminator" : "unauthorizedRequest", + "oneTimePersonaData" : { + "name" : { + "variant" : "western", + "familyName" : "Family", + "givenNames" : "Given", + "nickname" : "Nick" + }, + "emailAddresses" : [ + "some@gmail.com" + ], + "phoneNumbers" : [ + "071234579" + ] + } + } + }, + { + "discriminator" : "failure", + "interactionId" : "278608e0-e5ca-416e-8339-f2d2695651c4", + "error" : "rejectedByUser", + "message" : "User rejected the request" + }, + { + "discriminator" : "success", + "interactionId" : "c42f8825-4bbb-4ce2-a646-776b529e2f51", + "items" : { + "send" : { + "transactionIntentHash" : "txid_tdx_2_1mwuvufnewv6qkxdaesx0gcwap7n79knhkn0crsc8dg9g9k7qknjs6vkd3n" + }, + "discriminator" : "transaction" + } + } +] \ No newline at end of file diff --git a/src/core/error/common_error.rs b/src/core/error/common_error.rs index bdec5d1fc..fdbe42ecd 100644 --- a/src/core/error/common_error.rs +++ b/src/core/error/common_error.rs @@ -451,6 +451,18 @@ pub enum CommonError { #[error("Invalid LedgerHardwareWalletModel, bad value: {bad_value}")] InvalidLedgerHardwareWalletModel { bad_value: String } = 10126, + + #[error("RadixConnectMobile invalid URL, bad value: {bad_value}")] + RadixConnectMobileInvalidRequestUrl { bad_value: String } = 10127, + + #[error("RadixConnectMobile invalid origin, bad value: {bad_value}")] + RadixConnectMobileInvalidOrigin { bad_value: String } = 10128, + + #[error("Failed to create Session (UUID) from string: {bad_value}")] + RadixConnectMobileInvalidSessionID { bad_value: String } = 10129, + + #[error("Failed to create InteractionID (UUID) from string: {bad_value}")] + RadixMobileInvalidInteractionID { bad_value: String } = 10130, } #[uniffi::export] diff --git a/src/profile/v100/entity/account/appearance_id.rs b/src/core/types/appearance_id.rs similarity index 100% rename from src/profile/v100/entity/account/appearance_id.rs rename to src/core/types/appearance_id.rs diff --git a/src/profile/v100/entity/account/appearance_id_uniffi_fn.rs b/src/core/types/appearance_id_uniffi_fn.rs similarity index 100% rename from src/profile/v100/entity/account/appearance_id_uniffi_fn.rs rename to src/core/types/appearance_id_uniffi_fn.rs diff --git a/src/core/types/mod.rs b/src/core/types/mod.rs index abd73959f..76da0841a 100644 --- a/src/core/types/mod.rs +++ b/src/core/types/mod.rs @@ -1,3 +1,5 @@ +mod appearance_id; +mod appearance_id_uniffi_fn; mod bag_of_bytes; mod bag_of_bytes_uniffi_fn; mod decimal192; @@ -12,10 +14,15 @@ mod logged_result; mod non_empty_max_n_bytes; mod nonce; mod nonce_uniffi_fn; +mod requested_number_quantifier; +mod requested_quantity; +mod requested_quantity_uniffi_fn; mod rounding_mode; mod safe_to_log; mod signatures; +pub use appearance_id::*; +pub use appearance_id_uniffi_fn::*; #[macro_use] mod secret_bytes; @@ -33,6 +40,9 @@ pub use logged_result::*; pub use non_empty_max_n_bytes::*; pub use nonce::*; pub use nonce_uniffi_fn::*; +pub use requested_number_quantifier::*; +pub use requested_quantity::*; +pub use requested_quantity_uniffi_fn::*; pub use rounding_mode::*; pub use safe_to_log::*; pub use secret_bytes::*; diff --git a/src/profile/v100/networks/network/authorized_dapp/requested_number_quantifier.rs b/src/core/types/requested_number_quantifier.rs similarity index 100% rename from src/profile/v100/networks/network/authorized_dapp/requested_number_quantifier.rs rename to src/core/types/requested_number_quantifier.rs diff --git a/src/profile/v100/networks/network/authorized_dapp/requested_quantity.rs b/src/core/types/requested_quantity.rs similarity index 100% rename from src/profile/v100/networks/network/authorized_dapp/requested_quantity.rs rename to src/core/types/requested_quantity.rs diff --git a/src/profile/v100/networks/network/authorized_dapp/requested_quantity_uniffi_fn.rs b/src/core/types/requested_quantity_uniffi_fn.rs similarity index 100% rename from src/profile/v100/networks/network/authorized_dapp/requested_quantity_uniffi_fn.rs rename to src/core/types/requested_quantity_uniffi_fn.rs diff --git a/src/core/utils/string_utils.rs b/src/core/utils/string_utils.rs index b465b1fb7..1d7b09e5b 100644 --- a/src/core/utils/string_utils.rs +++ b/src/core/utils/string_utils.rs @@ -1,3 +1,6 @@ +use crate::CommonError; +use url::Url; + /// Returns the last `n` chars of the &str `s`. If `s` is shorter than `n` /// we panic. pub fn suffix_str(n: usize, s: impl AsRef) -> String { @@ -27,6 +30,12 @@ impl StrExt for str { } } +pub fn parse_url(s: impl AsRef) -> Result { + Url::try_from(s.as_ref()).map_err(|_| CommonError::InvalidURL { + bad_value: s.as_ref().to_owned(), + }) +} + #[cfg(test)] mod tests { use super::*; @@ -58,4 +67,14 @@ mod tests { assert_eq!("fo".remove_last(), "f"); assert_eq!("Foobar".remove_last(), "Fooba"); } + + #[test] + fn test_parse_url() { + assert!(parse_url("https://radixdlt.com").is_ok()); + } + + #[test] + fn test_parse_url_invalid() { + assert!(parse_url("https/radixdlt").is_err()); + } } diff --git a/src/lib.rs b/src/lib.rs index 49676c92e..71bd0284c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,6 +4,7 @@ mod core; mod gateway_api; mod hierarchical_deterministic; mod profile; +mod radix_connect; mod wallet; mod wrapped_radix_engine_toolkit; @@ -13,6 +14,7 @@ pub mod prelude { pub use crate::gateway_api::*; pub use crate::hierarchical_deterministic::*; pub use crate::profile::*; + pub use crate::radix_connect::*; pub use crate::wallet::*; pub use crate::wrapped_radix_engine_toolkit::*; diff --git a/src/profile/v100/app_preferences/gateways/gateway.rs b/src/profile/v100/app_preferences/gateways/gateway.rs index 8e8ab0106..c588b83eb 100644 --- a/src/profile/v100/app_preferences/gateways/gateway.rs +++ b/src/profile/v100/app_preferences/gateways/gateway.rs @@ -61,8 +61,7 @@ impl From for Gateway { impl Gateway { pub fn new(url: String, id: NetworkID) -> Result { - let url = Url::try_from(url.as_str()) - .map_err(|_| CommonError::InvalidURL { bad_value: url })?; + let url = parse_url(url)?; let network = NetworkDefinition::lookup_by_id(id)?; Ok(Self { url, network }) } diff --git a/src/profile/v100/entity/account/mod.rs b/src/profile/v100/entity/account/mod.rs index a464c60d5..313d97c6a 100644 --- a/src/profile/v100/entity/account/mod.rs +++ b/src/profile/v100/entity/account/mod.rs @@ -1,11 +1,7 @@ mod account; mod account_uniffi_fn; -mod appearance_id; -mod appearance_id_uniffi_fn; mod on_ledger_settings; pub use account::*; pub use account_uniffi_fn::*; -pub use appearance_id::*; -pub use appearance_id_uniffi_fn::*; pub use on_ledger_settings::*; diff --git a/src/profile/v100/networks/network/authorized_dapp/mod.rs b/src/profile/v100/networks/network/authorized_dapp/mod.rs index 7f21a05ea..abce6e0af 100644 --- a/src/profile/v100/networks/network/authorized_dapp/mod.rs +++ b/src/profile/v100/networks/network/authorized_dapp/mod.rs @@ -3,9 +3,6 @@ mod authorized_dapp_uniffi_fn; mod authorized_persona_simple; mod authorized_persona_simple_uniffi_fn; mod references_to_authorized_personas; -mod requested_number_quantifier; -mod requested_quantity; -mod requested_quantity_uniffi_fn; mod shared_persona_data; mod shared_persona_data_uniffi_fn; mod shared_with_dapp; @@ -15,9 +12,6 @@ pub use authorized_dapp_uniffi_fn::*; pub use authorized_persona_simple::*; pub use authorized_persona_simple_uniffi_fn::*; pub use references_to_authorized_personas::*; -pub use requested_number_quantifier::*; -pub use requested_quantity::*; -pub use requested_quantity_uniffi_fn::*; pub use shared_persona_data::*; pub use shared_persona_data_uniffi_fn::*; pub use shared_with_dapp::*; diff --git a/src/radix_connect/app_link_parser.rs b/src/radix_connect/app_link_parser.rs new file mode 100644 index 000000000..67875c514 --- /dev/null +++ b/src/radix_connect/app_link_parser.rs @@ -0,0 +1,174 @@ +use crate::prelude::*; +use url::form_urlencoded; +use url::Url; + +use super::interaction_id; + +const CONNECT_URL_PARAM_SESSION_ID: &str = "sessionId"; +const CONNECT_URL_PARAM_ORIGIN: &str = "origin"; +const CONNECT_URL_PARAM_INTERACTION_ID: &str = "interactionId"; +const CONNECT_URL: &str = "https://d1rxdfxrfmemlj.cloudfront.net"; + +pub fn parse_mobile_connect_request( + url: impl AsRef, +) -> Result { + let url = url.as_ref(); + let connect_url = parse_url(CONNECT_URL).unwrap(); + let parsed_url = parse_url(url).map_err(|_| { + CommonError::RadixConnectMobileInvalidRequestUrl { + bad_value: url.to_owned(), + } + })?; + if parsed_url.host_str() != connect_url.host_str() + || parsed_url.scheme() != connect_url.scheme() + { + return Err(CommonError::RadixConnectMobileInvalidRequestUrl { + bad_value: url.to_owned(), + }); + } + + let query_parameters = parsed_url + .query_pairs() + .into_owned() + .collect::>(); + let session_id_string = query_parameters + .get(CONNECT_URL_PARAM_SESSION_ID) + .ok_or(CommonError::RadixConnectMobileInvalidRequestUrl { + bad_value: url.to_owned(), + })?; + let Some(origin) = query_parameters.get(CONNECT_URL_PARAM_ORIGIN) else { + return query_parameters + .get(CONNECT_URL_PARAM_INTERACTION_ID) + .ok_or(CommonError::RadixConnectMobileInvalidRequestUrl { + bad_value: url.to_owned(), + }) + .and_then(|interaction_id| { + DappRequest::try_with_interaction_id_and_session_id( + interaction_id, + session_id_string, + ) + }) + .map(MobileConnectRequest::DappInteraction); + }; + + LinkRequest::try_with_origin_and_session_id(origin, session_id_string) + .map(MobileConnectRequest::Link) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn parse_url_into_link_request_origin() { + let session_id = Uuid::new_v4().to_string(); + let connect_url = CONNECT_URL.to_owned() + + format!("/?sessionId={}&origin=radix%3A%2F%2Fapp", session_id) + .as_str(); + let result = parse_mobile_connect_request(connect_url); + assert!(result.is_ok()); + match result.unwrap() { + MobileConnectRequest::Link(link_request) => { + assert_eq!(link_request.session_id.0.to_string(), session_id); + assert_eq!( + link_request.origin, + parse_url("radix://app").unwrap() + ); + } + _ => { + panic!("Expected LinkRequest"); + } + } + } + + #[test] + fn parse_url_wrong_session_id() { + let connect_url = + CONNECT_URL.to_owned() + "/?sessionId=123&origin=radix%3A%2F%2Fapp"; + let err = parse_mobile_connect_request(connect_url.clone()) + .err() + .unwrap(); + assert_eq!( + err, + CommonError::RadixConnectMobileInvalidSessionID { + bad_value: "123".to_owned() + } + ); + } + + #[test] + fn parse_url_into_dapp_interaction() { + let session_id = Uuid::new_v4().to_string(); + let interaction_id = Uuid::new_v4().to_string(); + let url = CONNECT_URL.to_owned() + + format!( + "/?sessionId={}&interactionId={}", + session_id, interaction_id + ) + .as_str(); + let result = parse_mobile_connect_request(url); + assert!(result.is_ok()); + match result.unwrap() { + MobileConnectRequest::DappInteraction(dapp_request) => { + assert_eq!(dapp_request.session_id.0.to_string(), session_id); + assert_eq!( + dapp_request.interaction_id.0.to_string(), + interaction_id + ); + } + _ => { + panic!("Expected DappRequest"); + } + } + } + + #[test] + fn url_does_not_match_expected() { + let url = "https://example.com"; + let err = parse_mobile_connect_request(url).err().unwrap(); + assert_eq!( + err, + CommonError::RadixConnectMobileInvalidRequestUrl { + bad_value: url.to_owned() + } + ); + } + + #[test] + fn url_invalid() { + let url = "http/invalid_url"; + let err = parse_mobile_connect_request(url).err().unwrap(); + assert_eq!( + err, + CommonError::RadixConnectMobileInvalidRequestUrl { + bad_value: url.to_owned() + } + ); + } + + #[test] + fn url_with_invalid_origin() { + let session_id = Uuid::new_v4().to_string(); + let connect_url = CONNECT_URL.to_owned() + + format!("/?sessionId={}&origin=invalid", session_id).as_str(); + let err = parse_mobile_connect_request(connect_url).err().unwrap(); + assert_eq!( + err, + CommonError::RadixConnectMobileInvalidOrigin { + bad_value: "invalid".to_owned() + } + ); + } + + #[test] + fn url_does_not_match_any_request() { + let url = "https://d1rxdfxrfmemlj.cloudfront.net/?invalid=1"; + let err = parse_mobile_connect_request(url).err().unwrap(); + assert_eq!( + err, + CommonError::RadixConnectMobileInvalidRequestUrl { + bad_value: url.to_owned() + } + ); + } +} diff --git a/src/radix_connect/dapp_request.rs b/src/radix_connect/dapp_request.rs new file mode 100644 index 000000000..b053b0e6a --- /dev/null +++ b/src/radix_connect/dapp_request.rs @@ -0,0 +1,125 @@ +use crate::prelude::*; + +#[derive(Debug, Serialize, Deserialize, PartialEq, uniffi::Record)] +pub struct DappRequest { + pub interaction_id: WalletInteractionId, + pub session_id: SessionID, +} + +impl DappRequest { + pub fn new( + interaction_id: WalletInteractionId, + session_id: SessionID, + ) -> Self { + Self { + interaction_id, + session_id, + } + } + + pub(crate) fn try_with_interaction_id_and_session_id( + interaction_id: impl AsRef, + session_id: impl AsRef, + ) -> Result { + let interaction_id = WalletInteractionId::from_str( + interaction_id.as_ref(), + ) + .map_err(|_| CommonError::RadixMobileInvalidInteractionID { + bad_value: interaction_id.as_ref().to_owned(), + })?; + let session_id = + SessionID::from_str(session_id.as_ref()).map_err(|_| { + CommonError::RadixConnectMobileInvalidSessionID { + bad_value: session_id.as_ref().to_owned(), + } + })?; + Ok(DappRequest::new(interaction_id, session_id)) + } +} + +impl HasSampleValues for DappRequest { + fn sample() -> Self { + Self { + interaction_id: WalletInteractionId::sample(), + session_id: SessionID::sample(), + } + } + + fn sample_other() -> Self { + Self { + interaction_id: WalletInteractionId::sample_other(), + session_id: SessionID::sample_other(), + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[allow(clippy::upper_case_acronyms)] + type SUT = DappRequest; + + #[test] + fn equality() { + assert_eq!(SUT::sample(), SUT::sample()); + assert_eq!(SUT::sample_other(), SUT::sample_other()); + } + + #[test] + fn inequality() { + assert_ne!(SUT::sample(), SUT::sample_other()); + } + + #[test] + fn try_with_interaction_id_and_session_id() { + let session_id = Uuid::new_v4().to_string(); + let interaction_id = Uuid::new_v4().to_string(); + let sut = SUT::try_with_interaction_id_and_session_id( + interaction_id.clone(), + session_id.clone(), + ) + .unwrap(); + assert_eq!(sut.interaction_id.0.to_string(), interaction_id); + assert_eq!(sut.session_id.0.to_string(), session_id); + } + + #[test] + fn try_with_invalid_interaction_id() { + let session_id = Uuid::new_v4().to_string(); + let interaction_id = "bad"; + assert_eq!( + SUT::try_with_interaction_id_and_session_id( + interaction_id, + session_id.clone() + ), + Err(CommonError::RadixMobileInvalidInteractionID { + bad_value: interaction_id.to_owned() + }) + ); + } + + #[test] + fn try_with_invalid_session_id() { + let session_id = "bad"; + let interaction_id = Uuid::new_v4().to_string(); + assert_eq!( + SUT::try_with_interaction_id_and_session_id( + interaction_id.clone(), + session_id + ), + Err(CommonError::RadixConnectMobileInvalidSessionID { + bad_value: session_id.to_owned() + }) + ); + } + + #[test] + fn test_new() { + let session_id = SessionID::sample(); + let interaction_id = WalletInteractionId::sample(); + let sut = SUT::new(interaction_id.clone(), session_id.clone()); + assert_eq!(sut.interaction_id, interaction_id); + assert_eq!(sut.session_id, session_id); + } +} diff --git a/src/radix_connect/interaction_id.rs b/src/radix_connect/interaction_id.rs new file mode 100644 index 000000000..2801d8205 --- /dev/null +++ b/src/radix_connect/interaction_id.rs @@ -0,0 +1,53 @@ +use crate::prelude::*; + +uniffi::custom_newtype!(WalletInteractionId, Uuid); + +#[derive( + Debug, Serialize, Deserialize, Clone, PartialEq, Eq, Ord, PartialOrd, Hash, +)] +pub struct WalletInteractionId(pub(crate) Uuid); + +impl FromStr for WalletInteractionId { + type Err = CommonError; + fn from_str(s: &str) -> Result { + Uuid::from_str(s).map(WalletInteractionId).map_err(|_| { + CommonError::RadixMobileInvalidInteractionID { + bad_value: s.to_owned(), + } + }) + } +} + +impl HasSampleValues for WalletInteractionId { + fn sample() -> Self { + WalletInteractionId(Uuid::from_bytes([0xff; 16])) + } + + fn sample_other() -> Self { + WalletInteractionId(Uuid::from_bytes([0xde; 16])) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[allow(clippy::upper_case_acronyms)] + type SUT = WalletInteractionId; + + #[test] + fn equality() { + assert_eq!(SUT::sample(), SUT::sample()); + assert_eq!(SUT::sample_other(), SUT::sample_other()); + } + + #[test] + fn inequafrom_invalid_str() { + assert_eq!( + "bad".parse::(), + Err(CommonError::RadixMobileInvalidInteractionID { + bad_value: "bad".to_owned() + }) + ); + } +} diff --git a/src/radix_connect/interaction_version.rs b/src/radix_connect/interaction_version.rs new file mode 100644 index 000000000..e8741937f --- /dev/null +++ b/src/radix_connect/interaction_version.rs @@ -0,0 +1,52 @@ +use crate::prelude::*; + +uniffi::custom_newtype!(WalletInteractionVersion, u64); + +#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)] +pub struct WalletInteractionVersion(pub u64); + +impl From for WalletInteractionVersion { + fn from(value: u64) -> Self { + Self(value) + } +} + +impl WalletInteractionVersion { + pub fn current() -> Self { + Self(1) + } +} + +impl HasSampleValues for WalletInteractionVersion { + fn sample() -> Self { + Self(1) + } + + fn sample_other() -> Self { + Self(2) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[allow(clippy::upper_case_acronyms)] + type SUT = WalletInteractionVersion; + + #[test] + fn equality() { + assert_eq!(SUT::sample(), SUT::sample()); + assert_eq!(SUT::sample_other(), SUT::sample_other()); + } + + #[test] + fn inequality() { + assert_ne!(SUT::sample(), SUT::sample_other()); + } + + #[test] + fn current() { + assert_eq!(SUT::current(), 1.into()); + } +} diff --git a/src/radix_connect/link_request.rs b/src/radix_connect/link_request.rs new file mode 100644 index 000000000..43ae6716a --- /dev/null +++ b/src/radix_connect/link_request.rs @@ -0,0 +1,77 @@ +use crate::prelude::*; + +use super::session_id; + +#[derive(Debug, Serialize, Deserialize, PartialEq, uniffi::Record)] +pub struct LinkRequest { + pub origin: Url, + pub session_id: SessionID, +} + +impl LinkRequest { + pub fn new(origin: Url, session_id: SessionID) -> Self { + Self { origin, session_id } + } + + pub(crate) fn try_with_origin_and_session_id( + origin: impl AsRef, + session_id: impl AsRef, + ) -> Result { + let origin = parse_url(origin.as_ref()).map_err(|_| { + CommonError::RadixConnectMobileInvalidOrigin { + bad_value: origin.as_ref().to_owned(), + } + })?; + let session_id = + SessionID::from_str(session_id.as_ref()).map_err(|_| { + CommonError::RadixConnectMobileInvalidSessionID { + bad_value: session_id.as_ref().to_owned(), + } + })?; + Ok(LinkRequest::new(origin, session_id)) + } +} + +impl HasSampleValues for LinkRequest { + fn sample() -> Self { + LinkRequest::new( + parse_url("radix://app1").unwrap(), + SessionID::sample(), + ) + } + + fn sample_other() -> Self { + LinkRequest::new( + parse_url("radix://app2").unwrap(), + SessionID::sample_other(), + ) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[allow(clippy::upper_case_acronyms)] + type SUT = LinkRequest; + + #[test] + fn equality() { + assert_eq!(SUT::sample(), SUT::sample()); + assert_eq!(SUT::sample_other(), SUT::sample_other()); + } + + #[test] + fn inequality() { + assert_ne!(SUT::sample(), SUT::sample_other()); + } + + #[test] + fn test_new() { + let origin = parse_url("radix://app").unwrap(); + let session_id = SessionID::sample(); + let sut = SUT::new(origin.clone(), session_id.clone()); + assert_eq!(sut.origin, origin); + assert_eq!(sut.session_id, session_id); + } +} diff --git a/src/radix_connect/mobile_connect_request.rs b/src/radix_connect/mobile_connect_request.rs new file mode 100644 index 000000000..36bacb725 --- /dev/null +++ b/src/radix_connect/mobile_connect_request.rs @@ -0,0 +1,56 @@ +use crate::prelude::*; + +#[derive(Debug, Serialize, Deserialize, PartialEq, uniffi::Enum)] +pub enum MobileConnectRequest { + Link(LinkRequest), + DappInteraction(DappRequest), +} + +impl FromStr for MobileConnectRequest { + type Err = CommonError; + + fn from_str(s: &str) -> Result { + parse_mobile_connect_request(s) + } +} + +#[uniffi::export] +pub fn new_mobile_connect_request(url: String) -> Result { + MobileConnectRequest::from_str(url.as_str()) +} + +impl HasSampleValues for MobileConnectRequest { + fn sample() -> Self { + MobileConnectRequest::Link(LinkRequest::sample()) + } + + fn sample_other() -> Self { + MobileConnectRequest::DappInteraction(DappRequest::sample()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[allow(clippy::upper_case_acronyms)] + type SUT = MobileConnectRequest; + + #[test] + fn equality() { + assert_eq!(SUT::sample(), SUT::sample()); + assert_eq!(SUT::sample_other(), SUT::sample_other()); + } + + #[test] + fn inequality() { + assert_ne!(SUT::sample(), SUT::sample_other()); + } + + #[test] + fn test_new_mobile_connect_request() { + let uuid = Uuid::new_v4().to_string(); + let connect_url = format!("https://d1rxdfxrfmemlj.cloudfront.net/?sessionId={}&origin=radix%3A%2F%2Fapp", uuid); + assert!(new_mobile_connect_request(connect_url).is_ok()); + } +} diff --git a/src/radix_connect/mod.rs b/src/radix_connect/mod.rs new file mode 100644 index 000000000..f5b5d0d26 --- /dev/null +++ b/src/radix_connect/mod.rs @@ -0,0 +1,21 @@ +mod app_link_parser; +mod dapp_request; +mod interaction_id; +mod interaction_version; +mod link_request; +mod mobile_connect_request; +mod session_id; +mod wallet_account; +mod wallet_interaction; +mod wallet_persona; + +pub use app_link_parser::*; +pub use dapp_request::*; +pub use interaction_id::*; +pub use interaction_version::*; +pub use link_request::*; +pub use mobile_connect_request::*; +pub use session_id::*; +pub use wallet_account::*; +pub use wallet_interaction::*; +pub use wallet_persona::*; diff --git a/src/radix_connect/session_id.rs b/src/radix_connect/session_id.rs new file mode 100644 index 000000000..5f3734f57 --- /dev/null +++ b/src/radix_connect/session_id.rs @@ -0,0 +1,53 @@ +use crate::prelude::*; + +uniffi::custom_newtype!(SessionID, Uuid); + +#[derive( + Debug, Serialize, Deserialize, Clone, PartialEq, Eq, Ord, PartialOrd, Hash, +)] +pub struct SessionID(pub(crate) Uuid); + +impl FromStr for SessionID { + type Err = CommonError; + fn from_str(s: &str) -> Result { + Uuid::from_str(s).map(SessionID).map_err(|_| { + CommonError::RadixConnectMobileInvalidSessionID { + bad_value: s.to_owned(), + } + }) + } +} + +impl HasSampleValues for SessionID { + fn sample() -> Self { + SessionID(Uuid::from_bytes([0xff; 16])) + } + + fn sample_other() -> Self { + SessionID(Uuid::from_bytes([0xde; 16])) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[allow(clippy::upper_case_acronyms)] + type SUT = SessionID; + + #[test] + fn equality() { + assert_eq!(SUT::sample(), SUT::sample()); + assert_eq!(SUT::sample_other(), SUT::sample_other()); + } + + #[test] + fn inequafrom_invalid_str() { + assert_eq!( + "bad".parse::(), + Err(CommonError::RadixConnectMobileInvalidSessionID { + bad_value: "bad".to_owned() + }) + ); + } +} diff --git a/src/radix_connect/wallet_account.rs b/src/radix_connect/wallet_account.rs new file mode 100644 index 000000000..4741f2983 --- /dev/null +++ b/src/radix_connect/wallet_account.rs @@ -0,0 +1,56 @@ +use crate::prelude::*; + +#[derive(Debug, Serialize, Deserialize, PartialEq, Clone, uniffi::Record)] +#[serde(rename_all = "camelCase")] +pub struct WalletInteractionWalletAccount { + pub address: AccountAddress, + pub label: String, + pub appearance_id: AppearanceID, +} + +impl WalletInteractionWalletAccount { + pub fn new( + address: impl Into, + label: impl AsRef, + appearance_id: impl Into, + ) -> Self { + Self { + address: address.into(), + label: label.as_ref().to_owned(), + appearance_id: appearance_id.into(), + } + } +} + +impl HasSampleValues for WalletInteractionWalletAccount { + fn sample() -> Self { + Self::new(AccountAddress::sample(), "sample1", AppearanceID::sample()) + } + + fn sample_other() -> Self { + Self::new( + AccountAddress::sample_other(), + "sample2", + AppearanceID::sample_other(), + ) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[allow(clippy::upper_case_acronyms)] + type SUT = WalletInteractionWalletAccount; + + #[test] + fn equality() { + assert_eq!(SUT::sample(), SUT::sample()); + assert_eq!(SUT::sample_other(), SUT::sample_other()); + } + + #[test] + fn inequality() { + assert_ne!(SUT::sample(), SUT::sample_other()); + } +} diff --git a/src/radix_connect/wallet_interaction/dapp_wallet_interaction/dapp_to_wallet/dapp_metadata/interaction_metadata.rs b/src/radix_connect/wallet_interaction/dapp_wallet_interaction/dapp_to_wallet/dapp_metadata/interaction_metadata.rs new file mode 100644 index 000000000..912e100ff --- /dev/null +++ b/src/radix_connect/wallet_interaction/dapp_wallet_interaction/dapp_to_wallet/dapp_metadata/interaction_metadata.rs @@ -0,0 +1,66 @@ +use crate::prelude::*; + +#[derive(Debug, Deserialize, Serialize, PartialEq, uniffi::Record, Clone)] +#[serde(rename_all = "camelCase")] +pub struct DappToWalletInteractionMetadata { + pub version: WalletInteractionVersion, + pub network_id: NetworkID, + pub origin: Url, + #[serde(rename = "dAppDefinitionAddress")] + pub dapp_definition_address: DappDefinitionAddress, +} + +impl DappToWalletInteractionMetadata { + pub fn new( + version: impl Into, + network_id: impl Into, + origin: impl Into, + dapp_definition_address: impl Into, + ) -> Self { + Self { + version: version.into(), + network_id: network_id.into(), + origin: origin.into(), + dapp_definition_address: dapp_definition_address.into(), + } + } +} + +impl HasSampleValues for DappToWalletInteractionMetadata { + fn sample() -> Self { + Self::new( + WalletInteractionVersion::sample(), + NetworkID::Stokenet, + Url::from_str("https://example.com").unwrap(), + DappDefinitionAddress::sample(), + ) + } + + fn sample_other() -> Self { + Self::new( + WalletInteractionVersion::sample_other(), + NetworkID::Stokenet, + Url::from_str("https://example.org").unwrap(), + DappDefinitionAddress::sample_other(), + ) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[allow(clippy::upper_case_acronyms)] + type SUT = DappToWalletInteractionMetadata; + + #[test] + fn equality() { + assert_eq!(SUT::sample(), SUT::sample()); + assert_eq!(SUT::sample_other(), SUT::sample_other()); + } + + #[test] + fn inequality() { + assert_ne!(SUT::sample(), SUT::sample_other()); + } +} diff --git a/src/radix_connect/wallet_interaction/dapp_wallet_interaction/dapp_to_wallet/dapp_metadata/interaction_metadata_unvalidated.rs b/src/radix_connect/wallet_interaction/dapp_wallet_interaction/dapp_to_wallet/dapp_metadata/interaction_metadata_unvalidated.rs new file mode 100644 index 000000000..12696dc41 --- /dev/null +++ b/src/radix_connect/wallet_interaction/dapp_wallet_interaction/dapp_to_wallet/dapp_metadata/interaction_metadata_unvalidated.rs @@ -0,0 +1,68 @@ +use crate::prelude::*; + +#[derive(Debug, Deserialize, Serialize, PartialEq, uniffi::Record, Clone)] +#[serde(rename_all = "camelCase")] +pub struct DappToWalletInteractionMetadataUnvalidated { + pub version: WalletInteractionVersion, + pub network_id: NetworkID, + pub origin: Url, + #[serde(rename = "dAppDefinitionAddress")] + pub dapp_definition_address: String, +} + +impl DappToWalletInteractionMetadataUnvalidated { + pub fn new( + version: impl Into, + network_id: impl Into, + origin: impl Into, + dapp_definition_address: impl AsRef, + ) -> Self { + Self { + version: version.into(), + network_id: network_id.into(), + origin: origin.into(), + dapp_definition_address: dapp_definition_address + .as_ref() + .to_owned(), + } + } +} + +impl HasSampleValues for DappToWalletInteractionMetadataUnvalidated { + fn sample() -> Self { + Self::new( + WalletInteractionVersion::sample(), + NetworkID::Stokenet, + Url::from_str("https://example.com").unwrap(), + DappDefinitionAddress::sample().to_string(), + ) + } + + fn sample_other() -> Self { + Self::new( + WalletInteractionVersion::sample_other(), + NetworkID::Stokenet, + Url::from_str("https://example.org").unwrap(), + DappDefinitionAddress::sample_other().to_string(), + ) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[allow(clippy::upper_case_acronyms)] + type SUT = DappToWalletInteractionMetadataUnvalidated; + + #[test] + fn equality() { + assert_eq!(SUT::sample(), SUT::sample()); + assert_eq!(SUT::sample_other(), SUT::sample_other()); + } + + #[test] + fn inequality() { + assert_ne!(SUT::sample(), SUT::sample_other()); + } +} diff --git a/src/radix_connect/wallet_interaction/dapp_wallet_interaction/dapp_to_wallet/dapp_metadata/mod.rs b/src/radix_connect/wallet_interaction/dapp_wallet_interaction/dapp_to_wallet/dapp_metadata/mod.rs new file mode 100644 index 000000000..96dbc1f7f --- /dev/null +++ b/src/radix_connect/wallet_interaction/dapp_wallet_interaction/dapp_to_wallet/dapp_metadata/mod.rs @@ -0,0 +1,5 @@ +mod interaction_metadata; +mod interaction_metadata_unvalidated; + +pub use interaction_metadata::*; +pub use interaction_metadata_unvalidated::*; diff --git a/src/radix_connect/wallet_interaction/dapp_wallet_interaction/dapp_to_wallet/interaction.rs b/src/radix_connect/wallet_interaction/dapp_wallet_interaction/dapp_to_wallet/interaction.rs new file mode 100644 index 000000000..f452df45d --- /dev/null +++ b/src/radix_connect/wallet_interaction/dapp_wallet_interaction/dapp_to_wallet/interaction.rs @@ -0,0 +1,60 @@ +use crate::prelude::*; + +#[derive(Debug, Deserialize, Serialize, PartialEq, uniffi::Record)] +#[serde(rename_all = "camelCase")] +pub struct DappToWalletInteraction { + pub interaction_id: WalletInteractionId, + pub items: DappToWalletInteractionItems, + pub metadata: DappToWalletInteractionMetadata, +} + +impl DappToWalletInteraction { + pub fn new( + interaction_id: WalletInteractionId, + items: DappToWalletInteractionItems, + metadata: DappToWalletInteractionMetadata, + ) -> Self { + Self { + interaction_id, + items, + metadata, + } + } +} + +impl HasSampleValues for DappToWalletInteraction { + fn sample() -> Self { + Self::new( + WalletInteractionId::sample(), + DappToWalletInteractionItems::sample(), + DappToWalletInteractionMetadata::sample(), + ) + } + + fn sample_other() -> Self { + Self::new( + WalletInteractionId::sample_other(), + DappToWalletInteractionItems::sample_other(), + DappToWalletInteractionMetadata::sample_other(), + ) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[allow(clippy::upper_case_acronyms)] + type SUT = DappToWalletInteraction; + + #[test] + fn equality() { + assert_eq!(SUT::sample(), SUT::sample()); + assert_eq!(SUT::sample_other(), SUT::sample_other()); + } + + #[test] + fn inequality() { + assert_ne!(SUT::sample(), SUT::sample_other()); + } +} diff --git a/src/radix_connect/wallet_interaction/dapp_wallet_interaction/dapp_to_wallet/interaction_items/items.rs b/src/radix_connect/wallet_interaction/dapp_wallet_interaction/dapp_to_wallet/interaction_items/items.rs new file mode 100644 index 000000000..21d479e50 --- /dev/null +++ b/src/radix_connect/wallet_interaction/dapp_wallet_interaction/dapp_to_wallet/interaction_items/items.rs @@ -0,0 +1,43 @@ +use crate::prelude::*; + +#[derive(Debug, Deserialize, Serialize, PartialEq, uniffi::Enum)] +#[serde(tag = "discriminator")] +pub enum DappToWalletInteractionItems { + #[serde(rename = "unauthorizedRequest")] + UnauthorizedRequest(DappToWalletInteractionUnauthorizedRequestItems), + #[serde(rename = "authorizedRequest")] + AuthorizedRequest(DappToWalletInteractionAuthorizedRequestItems), + #[serde(rename = "transaction")] + Transaction(DappToWalletInteractionTransactionItems), +} + +impl HasSampleValues for DappToWalletInteractionItems { + fn sample() -> Self { + Self::UnauthorizedRequest( + DappToWalletInteractionUnauthorizedRequestItems::sample(), + ) + } + + fn sample_other() -> Self { + Self::Transaction(DappToWalletInteractionTransactionItems::sample()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[allow(clippy::upper_case_acronyms)] + type SUT = DappToWalletInteractionItems; + + #[test] + fn equality() { + assert_eq!(SUT::sample(), SUT::sample()); + assert_eq!(SUT::sample_other(), SUT::sample_other()); + } + + #[test] + fn inequality() { + assert_ne!(SUT::sample(), SUT::sample_other()); + } +} diff --git a/src/radix_connect/wallet_interaction/dapp_wallet_interaction/dapp_to_wallet/interaction_items/mod.rs b/src/radix_connect/wallet_interaction/dapp_wallet_interaction/dapp_to_wallet/interaction_items/mod.rs new file mode 100644 index 000000000..5f2ff6ad8 --- /dev/null +++ b/src/radix_connect/wallet_interaction/dapp_wallet_interaction/dapp_to_wallet/interaction_items/mod.rs @@ -0,0 +1,7 @@ +mod items; +mod request; +mod transaction; + +pub use items::*; +pub use request::*; +pub use transaction::*; diff --git a/src/radix_connect/wallet_interaction/dapp_wallet_interaction/dapp_to_wallet/interaction_items/request/auth/auth.rs b/src/radix_connect/wallet_interaction/dapp_wallet_interaction/dapp_to_wallet/interaction_items/request/auth/auth.rs new file mode 100644 index 000000000..91ba1173e --- /dev/null +++ b/src/radix_connect/wallet_interaction/dapp_wallet_interaction/dapp_to_wallet/interaction_items/request/auth/auth.rs @@ -0,0 +1,47 @@ +use crate::prelude::*; + +#[derive(Debug, Deserialize, Serialize, PartialEq, uniffi::Enum)] +#[serde(tag = "discriminator")] +pub enum DappToWalletInteractionAuthRequestItem { + #[serde(rename = "loginWithChallenge")] + LoginWithChallenge( + DappToWalletInteractionAuthLoginWithChallengeRequestItem, + ), + #[serde(rename = "loginWithoutChallenge")] + LoginWithoutChallenge, + #[serde(rename = "usePersona")] + UsePersona(DappToWalletInteractionAuthUsePersonaRequestItem), +} + +impl HasSampleValues for DappToWalletInteractionAuthRequestItem { + fn sample() -> Self { + Self::LoginWithChallenge( + DappToWalletInteractionAuthLoginWithChallengeRequestItem::sample(), + ) + } + + fn sample_other() -> Self { + Self::UsePersona( + DappToWalletInteractionAuthUsePersonaRequestItem::sample(), + ) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[allow(clippy::upper_case_acronyms)] + type SUT = DappToWalletInteractionAuthRequestItem; + + #[test] + fn equality() { + assert_eq!(SUT::sample(), SUT::sample()); + assert_eq!(SUT::sample_other(), SUT::sample_other()); + } + + #[test] + fn inequality() { + assert_ne!(SUT::sample(), SUT::sample_other()); + } +} diff --git a/src/radix_connect/wallet_interaction/dapp_wallet_interaction/dapp_to_wallet/interaction_items/request/auth/login_with_challenge.rs b/src/radix_connect/wallet_interaction/dapp_wallet_interaction/dapp_to_wallet/interaction_items/request/auth/login_with_challenge.rs new file mode 100644 index 000000000..1a17723cd --- /dev/null +++ b/src/radix_connect/wallet_interaction/dapp_wallet_interaction/dapp_to_wallet/interaction_items/request/auth/login_with_challenge.rs @@ -0,0 +1,45 @@ +use crate::prelude::*; + +#[derive(Debug, Deserialize, Serialize, PartialEq, uniffi::Record)] +pub struct DappToWalletInteractionAuthLoginWithChallengeRequestItem { + pub challenge: Exactly32Bytes, +} + +impl DappToWalletInteractionAuthLoginWithChallengeRequestItem { + pub fn new(challenge: impl Into) -> Self { + Self { + challenge: challenge.into(), + } + } +} + +impl HasSampleValues + for DappToWalletInteractionAuthLoginWithChallengeRequestItem +{ + fn sample() -> Self { + Self::new(Exactly32Bytes::sample()) + } + + fn sample_other() -> Self { + Self::new(Exactly32Bytes::sample_other()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[allow(clippy::upper_case_acronyms)] + type SUT = DappToWalletInteractionAuthLoginWithChallengeRequestItem; + + #[test] + fn equality() { + assert_eq!(SUT::sample(), SUT::sample()); + assert_eq!(SUT::sample_other(), SUT::sample_other()); + } + + #[test] + fn inequality() { + assert_ne!(SUT::sample(), SUT::sample_other()); + } +} diff --git a/src/radix_connect/wallet_interaction/dapp_wallet_interaction/dapp_to_wallet/interaction_items/request/auth/mod.rs b/src/radix_connect/wallet_interaction/dapp_wallet_interaction/dapp_to_wallet/interaction_items/request/auth/mod.rs new file mode 100644 index 000000000..088fc9cbe --- /dev/null +++ b/src/radix_connect/wallet_interaction/dapp_wallet_interaction/dapp_to_wallet/interaction_items/request/auth/mod.rs @@ -0,0 +1,7 @@ +mod auth; +mod login_with_challenge; +mod use_persona; + +pub use auth::*; +pub use login_with_challenge::*; +pub use use_persona::*; diff --git a/src/radix_connect/wallet_interaction/dapp_wallet_interaction/dapp_to_wallet/interaction_items/request/auth/use_persona.rs b/src/radix_connect/wallet_interaction/dapp_wallet_interaction/dapp_to_wallet/interaction_items/request/auth/use_persona.rs new file mode 100644 index 000000000..6c4e6f7a3 --- /dev/null +++ b/src/radix_connect/wallet_interaction/dapp_wallet_interaction/dapp_to_wallet/interaction_items/request/auth/use_persona.rs @@ -0,0 +1,44 @@ +use crate::prelude::*; + +#[derive(Debug, Deserialize, Serialize, PartialEq, uniffi::Record)] +#[serde(rename_all = "camelCase")] +pub struct DappToWalletInteractionAuthUsePersonaRequestItem { + pub identity_address: IdentityAddress, +} + +impl DappToWalletInteractionAuthUsePersonaRequestItem { + pub fn new(identity_address: impl Into) -> Self { + Self { + identity_address: identity_address.into(), + } + } +} + +impl HasSampleValues for DappToWalletInteractionAuthUsePersonaRequestItem { + fn sample() -> Self { + Self::new(IdentityAddress::sample()) + } + + fn sample_other() -> Self { + Self::new(IdentityAddress::sample_other()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[allow(clippy::upper_case_acronyms)] + type SUT = DappToWalletInteractionAuthUsePersonaRequestItem; + + #[test] + fn equality() { + assert_eq!(SUT::sample(), SUT::sample()); + assert_eq!(SUT::sample_other(), SUT::sample_other()); + } + + #[test] + fn inequality() { + assert_ne!(SUT::sample(), SUT::sample_other()); + } +} diff --git a/src/radix_connect/wallet_interaction/dapp_wallet_interaction/dapp_to_wallet/interaction_items/request/authorized_request.rs b/src/radix_connect/wallet_interaction/dapp_wallet_interaction/dapp_to_wallet/interaction_items/request/authorized_request.rs new file mode 100644 index 000000000..efd87a8e2 --- /dev/null +++ b/src/radix_connect/wallet_interaction/dapp_wallet_interaction/dapp_to_wallet/interaction_items/request/authorized_request.rs @@ -0,0 +1,89 @@ +use crate::prelude::*; + +#[derive(Debug, Deserialize, Serialize, PartialEq, uniffi::Record)] +#[serde(rename_all = "camelCase")] +pub struct DappToWalletInteractionAuthorizedRequestItems { + pub auth: DappToWalletInteractionAuthRequestItem, + pub reset: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub ongoing_accounts: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub ongoing_persona_data: + Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub one_time_accounts: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub one_time_persona_data: + Option, +} + +impl DappToWalletInteractionAuthorizedRequestItems { + pub fn new( + auth: DappToWalletInteractionAuthRequestItem, + reset: impl Into>, + ongoing_accounts: impl Into< + Option, + >, + ongoing_persona_data: impl Into< + Option, + >, + one_time_accounts: impl Into< + Option, + >, + one_time_persona_data: impl Into< + Option, + >, + ) -> Self { + Self { + auth, + reset: reset.into(), + ongoing_accounts: ongoing_accounts.into(), + ongoing_persona_data: ongoing_persona_data.into(), + one_time_accounts: one_time_accounts.into(), + one_time_persona_data: one_time_persona_data.into(), + } + } +} + +impl HasSampleValues for DappToWalletInteractionAuthorizedRequestItems { + fn sample() -> Self { + Self::new( + DappToWalletInteractionAuthRequestItem::sample(), + DappToWalletInteractionResetRequestItem::sample(), + DappToWalletInteractionAccountsRequestItem::sample(), + DappToWalletInteractionPersonaDataRequestItem::sample(), + DappToWalletInteractionAccountsRequestItem::sample(), + DappToWalletInteractionPersonaDataRequestItem::sample(), + ) + } + + fn sample_other() -> Self { + Self::new( + DappToWalletInteractionAuthRequestItem::sample_other(), + DappToWalletInteractionResetRequestItem::sample_other(), + DappToWalletInteractionAccountsRequestItem::sample_other(), + DappToWalletInteractionPersonaDataRequestItem::sample_other(), + DappToWalletInteractionAccountsRequestItem::sample_other(), + DappToWalletInteractionPersonaDataRequestItem::sample_other(), + ) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[allow(clippy::upper_case_acronyms)] + type SUT = DappToWalletInteractionAuthorizedRequestItems; + + #[test] + fn equality() { + assert_eq!(SUT::sample(), SUT::sample()); + assert_eq!(SUT::sample_other(), SUT::sample_other()); + } + + #[test] + fn inequality() { + assert_ne!(SUT::sample(), SUT::sample_other()); + } +} diff --git a/src/radix_connect/wallet_interaction/dapp_wallet_interaction/dapp_to_wallet/interaction_items/request/entity/accounts.rs b/src/radix_connect/wallet_interaction/dapp_wallet_interaction/dapp_to_wallet/interaction_items/request/entity/accounts.rs new file mode 100644 index 000000000..ef4b0e53f --- /dev/null +++ b/src/radix_connect/wallet_interaction/dapp_wallet_interaction/dapp_to_wallet/interaction_items/request/entity/accounts.rs @@ -0,0 +1,53 @@ +use crate::prelude::*; + +#[derive(Debug, Deserialize, Serialize, PartialEq, uniffi::Record)] +#[serde(rename_all = "camelCase")] +pub struct DappToWalletInteractionAccountsRequestItem { + pub number_of_accounts: RequestedQuantity, + #[serde(skip_serializing_if = "Option::is_none")] + pub challenge: Option, +} + +impl DappToWalletInteractionAccountsRequestItem { + pub fn new( + number_of_accounts: RequestedQuantity, + challenge: impl Into>, + ) -> Self { + Self { + number_of_accounts, + challenge: challenge.into(), + } + } +} + +impl HasSampleValues for DappToWalletInteractionAccountsRequestItem { + fn sample() -> Self { + Self::new(RequestedQuantity::sample(), Exactly32Bytes::sample()) + } + + fn sample_other() -> Self { + Self::new( + RequestedQuantity::sample_other(), + Exactly32Bytes::sample_other(), + ) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[allow(clippy::upper_case_acronyms)] + type SUT = DappToWalletInteractionAccountsRequestItem; + + #[test] + fn equality() { + assert_eq!(SUT::sample(), SUT::sample()); + assert_eq!(SUT::sample_other(), SUT::sample_other()); + } + + #[test] + fn inequality() { + assert_ne!(SUT::sample(), SUT::sample_other()); + } +} diff --git a/src/radix_connect/wallet_interaction/dapp_wallet_interaction/dapp_to_wallet/interaction_items/request/entity/mod.rs b/src/radix_connect/wallet_interaction/dapp_wallet_interaction/dapp_to_wallet/interaction_items/request/entity/mod.rs new file mode 100644 index 000000000..16b7d403c --- /dev/null +++ b/src/radix_connect/wallet_interaction/dapp_wallet_interaction/dapp_to_wallet/interaction_items/request/entity/mod.rs @@ -0,0 +1,7 @@ +mod accounts; +mod persona_data; +mod reset; + +pub use accounts::*; +pub use persona_data::*; +pub use reset::*; diff --git a/src/radix_connect/wallet_interaction/dapp_wallet_interaction/dapp_to_wallet/interaction_items/request/entity/persona_data.rs b/src/radix_connect/wallet_interaction/dapp_wallet_interaction/dapp_to_wallet/interaction_items/request/entity/persona_data.rs new file mode 100644 index 000000000..e4c693c1d --- /dev/null +++ b/src/radix_connect/wallet_interaction/dapp_wallet_interaction/dapp_to_wallet/interaction_items/request/entity/persona_data.rs @@ -0,0 +1,65 @@ +use crate::prelude::*; + +#[derive(Debug, Deserialize, Serialize, PartialEq, uniffi::Record)] +#[serde(rename_all = "camelCase")] +pub struct DappToWalletInteractionPersonaDataRequestItem { + #[serde(skip_serializing_if = "Option::is_none")] + pub is_requesting_name: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub number_of_requested_email_addresses: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub number_of_requested_phone_numbers: Option, +} + +impl DappToWalletInteractionPersonaDataRequestItem { + pub fn new( + is_requesting_name: impl Into>, + number_of_requested_email_addresses: impl Into>, + number_of_requested_phone_numbers: impl Into>, + ) -> Self { + Self { + is_requesting_name: is_requesting_name.into(), + number_of_requested_email_addresses: + number_of_requested_email_addresses.into(), + number_of_requested_phone_numbers: + number_of_requested_phone_numbers.into(), + } + } +} + +impl HasSampleValues for DappToWalletInteractionPersonaDataRequestItem { + fn sample() -> Self { + Self::new( + true, + RequestedQuantity::sample(), + RequestedQuantity::sample(), + ) + } + + fn sample_other() -> Self { + Self::new( + false, + RequestedQuantity::sample_other(), + RequestedQuantity::sample_other(), + ) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[allow(clippy::upper_case_acronyms)] + type SUT = DappToWalletInteractionPersonaDataRequestItem; + + #[test] + fn equality() { + assert_eq!(SUT::sample(), SUT::sample()); + assert_eq!(SUT::sample_other(), SUT::sample_other()); + } + + #[test] + fn inequality() { + assert_ne!(SUT::sample(), SUT::sample_other()); + } +} diff --git a/src/radix_connect/wallet_interaction/dapp_wallet_interaction/dapp_to_wallet/interaction_items/request/entity/reset.rs b/src/radix_connect/wallet_interaction/dapp_wallet_interaction/dapp_to_wallet/interaction_items/request/entity/reset.rs new file mode 100644 index 000000000..636914600 --- /dev/null +++ b/src/radix_connect/wallet_interaction/dapp_wallet_interaction/dapp_to_wallet/interaction_items/request/entity/reset.rs @@ -0,0 +1,46 @@ +use crate::prelude::*; + +#[derive(Debug, Deserialize, Serialize, PartialEq, uniffi::Record)] +#[serde(rename_all = "camelCase")] +pub struct DappToWalletInteractionResetRequestItem { + pub accounts: bool, + pub persona_data: bool, +} + +impl DappToWalletInteractionResetRequestItem { + pub fn new(accounts: bool, persona_data: bool) -> Self { + Self { + accounts, + persona_data, + } + } +} + +impl HasSampleValues for DappToWalletInteractionResetRequestItem { + fn sample() -> Self { + Self::new(true, true) + } + + fn sample_other() -> Self { + Self::new(false, false) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[allow(clippy::upper_case_acronyms)] + type SUT = DappToWalletInteractionResetRequestItem; + + #[test] + fn equality() { + assert_eq!(SUT::sample(), SUT::sample()); + assert_eq!(SUT::sample_other(), SUT::sample_other()); + } + + #[test] + fn inequality() { + assert_ne!(SUT::sample(), SUT::sample_other()); + } +} diff --git a/src/radix_connect/wallet_interaction/dapp_wallet_interaction/dapp_to_wallet/interaction_items/request/mod.rs b/src/radix_connect/wallet_interaction/dapp_wallet_interaction/dapp_to_wallet/interaction_items/request/mod.rs new file mode 100644 index 000000000..9e9d85188 --- /dev/null +++ b/src/radix_connect/wallet_interaction/dapp_wallet_interaction/dapp_to_wallet/interaction_items/request/mod.rs @@ -0,0 +1,9 @@ +mod auth; +mod authorized_request; +mod entity; +mod unauthorized_request; + +pub use auth::*; +pub use authorized_request::*; +pub use entity::*; +pub use unauthorized_request::*; diff --git a/src/radix_connect/wallet_interaction/dapp_wallet_interaction/dapp_to_wallet/interaction_items/request/unauthorized_request.rs b/src/radix_connect/wallet_interaction/dapp_wallet_interaction/dapp_to_wallet/interaction_items/request/unauthorized_request.rs new file mode 100644 index 000000000..ca8a696ae --- /dev/null +++ b/src/radix_connect/wallet_interaction/dapp_wallet_interaction/dapp_to_wallet/interaction_items/request/unauthorized_request.rs @@ -0,0 +1,62 @@ +use crate::prelude::*; + +#[derive(Debug, Deserialize, Serialize, PartialEq, uniffi::Record)] +#[serde(rename_all = "camelCase")] +pub struct DappToWalletInteractionUnauthorizedRequestItems { + #[serde(skip_serializing_if = "Option::is_none")] + pub one_time_accounts: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub one_time_persona_data: + Option, +} + +impl DappToWalletInteractionUnauthorizedRequestItems { + pub fn new( + one_time_accounts: impl Into< + Option, + >, + one_time_persona_data: impl Into< + Option, + >, + ) -> Self { + Self { + one_time_accounts: one_time_accounts.into(), + one_time_persona_data: one_time_persona_data.into(), + } + } +} + +impl HasSampleValues for DappToWalletInteractionUnauthorizedRequestItems { + fn sample() -> Self { + Self::new( + DappToWalletInteractionAccountsRequestItem::sample(), + DappToWalletInteractionPersonaDataRequestItem::sample(), + ) + } + + fn sample_other() -> Self { + Self::new( + DappToWalletInteractionAccountsRequestItem::sample_other(), + DappToWalletInteractionPersonaDataRequestItem::sample_other(), + ) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[allow(clippy::upper_case_acronyms)] + type SUT = DappToWalletInteractionUnauthorizedRequestItems; + + #[test] + fn equality() { + assert_eq!(SUT::sample(), SUT::sample()); + assert_eq!(SUT::sample_other(), SUT::sample_other()); + } + + #[test] + fn inequality() { + assert_ne!(SUT::sample(), SUT::sample_other()); + } +} diff --git a/src/radix_connect/wallet_interaction/dapp_wallet_interaction/dapp_to_wallet/interaction_items/transaction/mod.rs b/src/radix_connect/wallet_interaction/dapp_wallet_interaction/dapp_to_wallet/interaction_items/transaction/mod.rs new file mode 100644 index 000000000..8db2af7a8 --- /dev/null +++ b/src/radix_connect/wallet_interaction/dapp_wallet_interaction/dapp_to_wallet/interaction_items/transaction/mod.rs @@ -0,0 +1,5 @@ +mod transaction; +mod transaction_version; + +pub use transaction::*; +pub use transaction_version::*; diff --git a/src/radix_connect/wallet_interaction/dapp_wallet_interaction/dapp_to_wallet/interaction_items/transaction/transaction.rs b/src/radix_connect/wallet_interaction/dapp_wallet_interaction/dapp_to_wallet/interaction_items/transaction/transaction.rs new file mode 100644 index 000000000..3439ddfdd --- /dev/null +++ b/src/radix_connect/wallet_interaction/dapp_wallet_interaction/dapp_to_wallet/interaction_items/transaction/transaction.rs @@ -0,0 +1,88 @@ +use crate::prelude::*; + +#[derive(Debug, Deserialize, Serialize, PartialEq, uniffi::Record)] +pub struct DappToWalletInteractionTransactionItems { + pub send: DappToWalletInteractionSendTransactionItem, +} + +impl DappToWalletInteractionTransactionItems { + pub fn new(send: DappToWalletInteractionSendTransactionItem) -> Self { + Self { send } + } +} + +#[derive(Debug, Deserialize, Serialize, PartialEq, uniffi::Record)] +#[serde(rename_all = "camelCase")] +pub struct DappToWalletInteractionSendTransactionItem { + pub transaction_manifest: String, + pub version: TXVersion, + #[serde(skip_serializing_if = "Option::is_none")] + pub blobs: Option>, + #[serde(skip_serializing_if = "Option::is_none")] + pub message: Option, +} + +impl DappToWalletInteractionSendTransactionItem { + pub fn new( + transaction_manifest: impl AsRef, + version: impl Into, + blobs: impl Into>>, + message: impl Into>, + ) -> Self { + Self { + transaction_manifest: transaction_manifest.as_ref().to_owned(), + version: version.into(), + blobs: blobs.into(), + message: message.into(), + } + } +} + +impl HasSampleValues for DappToWalletInteractionTransactionItems { + fn sample() -> Self { + Self::new(DappToWalletInteractionSendTransactionItem::sample()) + } + + fn sample_other() -> Self { + Self::new(DappToWalletInteractionSendTransactionItem::sample_other()) + } +} + +impl HasSampleValues for DappToWalletInteractionSendTransactionItem { + fn sample() -> Self { + Self::new( + "transaction_manifest", + TXVersion::sample(), + vec!["blob".to_owned()], + "message".to_owned(), + ) + } + + fn sample_other() -> Self { + Self::new( + "transaction_manifest_other", + TXVersion::sample_other(), + vec!["blob_other".to_owned()], + "message_other".to_owned(), + ) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[allow(clippy::upper_case_acronyms)] + type SUT = DappToWalletInteractionTransactionItems; + + #[test] + fn equality() { + assert_eq!(SUT::sample(), SUT::sample()); + assert_eq!(SUT::sample_other(), SUT::sample_other()); + } + + #[test] + fn inequality() { + assert_ne!(SUT::sample(), SUT::sample_other()); + } +} diff --git a/src/radix_connect/wallet_interaction/dapp_wallet_interaction/dapp_to_wallet/interaction_items/transaction/transaction_version.rs b/src/radix_connect/wallet_interaction/dapp_wallet_interaction/dapp_to_wallet/interaction_items/transaction/transaction_version.rs new file mode 100644 index 000000000..1fb326d52 --- /dev/null +++ b/src/radix_connect/wallet_interaction/dapp_wallet_interaction/dapp_to_wallet/interaction_items/transaction/transaction_version.rs @@ -0,0 +1,21 @@ +use crate::prelude::*; + +uniffi::custom_newtype!(TXVersion, u64); +#[derive(Debug, Deserialize, Serialize, PartialEq)] +pub struct TXVersion(u64); + +impl From for TXVersion { + fn from(value: u64) -> Self { + Self(value) + } +} + +impl HasSampleValues for TXVersion { + fn sample() -> Self { + Self(1) + } + + fn sample_other() -> Self { + Self(2) + } +} diff --git a/src/radix_connect/wallet_interaction/dapp_wallet_interaction/dapp_to_wallet/interaction_uniffi_fn.rs b/src/radix_connect/wallet_interaction/dapp_wallet_interaction/dapp_to_wallet/interaction_uniffi_fn.rs new file mode 100644 index 000000000..594146211 --- /dev/null +++ b/src/radix_connect/wallet_interaction/dapp_wallet_interaction/dapp_to_wallet/interaction_uniffi_fn.rs @@ -0,0 +1,4 @@ +use crate::prelude::*; + +json_data_convertible!(DappToWalletInteractionUnvalidated); +json_data_convertible!(WalletToDappInteractionResponse); diff --git a/src/radix_connect/wallet_interaction/dapp_wallet_interaction/dapp_to_wallet/interaction_unvalidated.rs b/src/radix_connect/wallet_interaction/dapp_wallet_interaction/dapp_to_wallet/interaction_unvalidated.rs new file mode 100644 index 000000000..117019f49 --- /dev/null +++ b/src/radix_connect/wallet_interaction/dapp_wallet_interaction/dapp_to_wallet/interaction_unvalidated.rs @@ -0,0 +1,60 @@ +use crate::prelude::*; + +#[derive(Debug, Deserialize, Serialize, PartialEq, uniffi::Record)] +#[serde(rename_all = "camelCase")] +pub struct DappToWalletInteractionUnvalidated { + pub interaction_id: WalletInteractionId, + pub items: DappToWalletInteractionItems, + pub metadata: DappToWalletInteractionMetadataUnvalidated, +} + +impl DappToWalletInteractionUnvalidated { + pub fn new( + interaction_id: WalletInteractionId, + items: DappToWalletInteractionItems, + metadata: DappToWalletInteractionMetadataUnvalidated, + ) -> Self { + Self { + interaction_id, + items, + metadata, + } + } +} + +impl HasSampleValues for DappToWalletInteractionUnvalidated { + fn sample() -> Self { + Self::new( + WalletInteractionId::sample(), + DappToWalletInteractionItems::sample(), + DappToWalletInteractionMetadataUnvalidated::sample(), + ) + } + + fn sample_other() -> Self { + Self::new( + WalletInteractionId::sample_other(), + DappToWalletInteractionItems::sample_other(), + DappToWalletInteractionMetadataUnvalidated::sample_other(), + ) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[allow(clippy::upper_case_acronyms)] + type SUT = DappToWalletInteractionUnvalidated; + + #[test] + fn equality() { + assert_eq!(SUT::sample(), SUT::sample()); + assert_eq!(SUT::sample_other(), SUT::sample_other()); + } + + #[test] + fn inequality() { + assert_ne!(SUT::sample(), SUT::sample_other()); + } +} diff --git a/src/radix_connect/wallet_interaction/dapp_wallet_interaction/dapp_to_wallet/mod.rs b/src/radix_connect/wallet_interaction/dapp_wallet_interaction/dapp_to_wallet/mod.rs new file mode 100644 index 000000000..055e2b016 --- /dev/null +++ b/src/radix_connect/wallet_interaction/dapp_wallet_interaction/dapp_to_wallet/mod.rs @@ -0,0 +1,11 @@ +mod dapp_metadata; +mod interaction; +mod interaction_items; +mod interaction_uniffi_fn; +mod interaction_unvalidated; + +pub use dapp_metadata::*; +pub use interaction::*; +pub use interaction_items::*; +pub use interaction_uniffi_fn::*; +pub use interaction_unvalidated::*; diff --git a/src/radix_connect/wallet_interaction/dapp_wallet_interaction/mod.rs b/src/radix_connect/wallet_interaction/dapp_wallet_interaction/mod.rs new file mode 100644 index 000000000..bc33a207d --- /dev/null +++ b/src/radix_connect/wallet_interaction/dapp_wallet_interaction/mod.rs @@ -0,0 +1,5 @@ +mod dapp_to_wallet; +mod wallet_to_dapp; + +pub use dapp_to_wallet::*; +pub use wallet_to_dapp::*; diff --git a/src/radix_connect/wallet_interaction/dapp_wallet_interaction/wallet_to_dapp/failure_response/error_type.rs b/src/radix_connect/wallet_interaction/dapp_wallet_interaction/wallet_to_dapp/failure_response/error_type.rs new file mode 100644 index 000000000..da670bd7b --- /dev/null +++ b/src/radix_connect/wallet_interaction/dapp_wallet_interaction/wallet_to_dapp/failure_response/error_type.rs @@ -0,0 +1,56 @@ +use crate::prelude::*; + +#[derive(Debug, Serialize, Deserialize, PartialEq, uniffi::Enum)] +#[serde(rename_all = "camelCase")] +pub enum DappWalletInteractionErrorType { + RejectedByUser, + WrongNetwork, + FailedToPrepareTransaction, + FailedToCompileTransaction, + FailedToSignTransaction, + FailedToSubmitTransaction, + FailedToPollSubmittedTransaction, + FailedToFindAccountWithEnoughFundsToLockFee, + SubmittedTransactionWasDuplicate, + SubmittedTransactionHasFailedTransactionStatus, + SubmittedTransactionHasRejectedTransactionStatus, + WrongAccountType, + UnknownWebsite, + InvalidOriginURL, + RadixJsonNotFound, + RadixJsonUnknownFileFormat, + UnknownDappDefinitionAddress, + InvalidPersona, + InvalidRequest, + IncompatibleVersion, + FailedToSignAuthChallenge, +} + +impl HasSampleValues for DappWalletInteractionErrorType { + fn sample() -> Self { + DappWalletInteractionErrorType::FailedToPrepareTransaction + } + + fn sample_other() -> Self { + DappWalletInteractionErrorType::FailedToCompileTransaction + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[allow(clippy::upper_case_acronyms)] + type SUT = DappWalletInteractionErrorType; + + #[test] + fn equality() { + assert_eq!(SUT::sample(), SUT::sample()); + assert_eq!(SUT::sample_other(), SUT::sample_other()); + } + + #[test] + fn inequality() { + assert_ne!(SUT::sample(), SUT::sample_other()); + } +} diff --git a/src/radix_connect/wallet_interaction/dapp_wallet_interaction/wallet_to_dapp/failure_response/failure.rs b/src/radix_connect/wallet_interaction/dapp_wallet_interaction/wallet_to_dapp/failure_response/failure.rs new file mode 100644 index 000000000..dcc40dc10 --- /dev/null +++ b/src/radix_connect/wallet_interaction/dapp_wallet_interaction/wallet_to_dapp/failure_response/failure.rs @@ -0,0 +1,61 @@ +use crate::prelude::*; + +#[derive(Debug, Serialize, Deserialize, PartialEq, uniffi::Record)] +#[serde(rename_all = "camelCase")] +pub struct WalletToDappInteractionFailureResponse { + pub interaction_id: WalletInteractionId, + pub error: DappWalletInteractionErrorType, + #[serde(skip_serializing_if = "Option::is_none")] + pub message: Option, +} + +impl WalletToDappInteractionFailureResponse { + pub fn new( + interaction_id: WalletInteractionId, + error: DappWalletInteractionErrorType, + message: impl Into>, + ) -> Self { + Self { + interaction_id, + error, + message: message.into(), + } + } +} + +impl HasSampleValues for WalletToDappInteractionFailureResponse { + fn sample() -> Self { + Self::new( + WalletInteractionId::sample(), + DappWalletInteractionErrorType::sample(), + "sample1".to_owned(), + ) + } + + fn sample_other() -> Self { + Self::new( + WalletInteractionId::sample_other(), + DappWalletInteractionErrorType::sample_other(), + "sample2".to_owned(), + ) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[allow(clippy::upper_case_acronyms)] + type SUT = WalletToDappInteractionFailureResponse; + + #[test] + fn equality() { + assert_eq!(SUT::sample(), SUT::sample()); + assert_eq!(SUT::sample_other(), SUT::sample_other()); + } + + #[test] + fn inequality() { + assert_ne!(SUT::sample(), SUT::sample_other()); + } +} diff --git a/src/radix_connect/wallet_interaction/dapp_wallet_interaction/wallet_to_dapp/failure_response/mod.rs b/src/radix_connect/wallet_interaction/dapp_wallet_interaction/wallet_to_dapp/failure_response/mod.rs new file mode 100644 index 000000000..a310785a4 --- /dev/null +++ b/src/radix_connect/wallet_interaction/dapp_wallet_interaction/wallet_to_dapp/failure_response/mod.rs @@ -0,0 +1,5 @@ +mod error_type; +mod failure; + +pub use error_type::*; +pub use failure::*; diff --git a/src/radix_connect/wallet_interaction/dapp_wallet_interaction/wallet_to_dapp/mod.rs b/src/radix_connect/wallet_interaction/dapp_wallet_interaction/wallet_to_dapp/mod.rs new file mode 100644 index 000000000..cddd897f4 --- /dev/null +++ b/src/radix_connect/wallet_interaction/dapp_wallet_interaction/wallet_to_dapp/mod.rs @@ -0,0 +1,7 @@ +mod failure_response; +mod response; +mod success_response; + +pub use failure_response::*; +pub use response::*; +pub use success_response::*; diff --git a/src/radix_connect/wallet_interaction/dapp_wallet_interaction/wallet_to_dapp/response.rs b/src/radix_connect/wallet_interaction/dapp_wallet_interaction/wallet_to_dapp/response.rs new file mode 100644 index 000000000..37b9b9360 --- /dev/null +++ b/src/radix_connect/wallet_interaction/dapp_wallet_interaction/wallet_to_dapp/response.rs @@ -0,0 +1,43 @@ +use crate::prelude::*; + +#[derive(Debug, Serialize, Deserialize, PartialEq, uniffi::Enum)] +#[serde(tag = "discriminator")] +#[allow(clippy::large_enum_variant)] +pub enum WalletToDappInteractionResponse { + #[serde(rename = "success")] + Success(WalletToDappInteractionSuccessResponse), + #[serde(rename = "failure")] + Failure(WalletToDappInteractionFailureResponse), +} + +impl HasSampleValues for WalletToDappInteractionResponse { + fn sample() -> Self { + WalletToDappInteractionResponse::Success( + WalletToDappInteractionSuccessResponse::sample(), + ) + } + fn sample_other() -> Self { + WalletToDappInteractionResponse::Failure( + WalletToDappInteractionFailureResponse::sample(), + ) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[allow(clippy::upper_case_acronyms)] + type SUT = WalletToDappInteractionResponse; + + #[test] + fn equality() { + assert_eq!(SUT::sample(), SUT::sample()); + assert_eq!(SUT::sample_other(), SUT::sample_other()); + } + + #[test] + fn inequality() { + assert_ne!(SUT::sample(), SUT::sample_other()); + } +} diff --git a/src/radix_connect/wallet_interaction/dapp_wallet_interaction/wallet_to_dapp/success_response/account/account_proof.rs b/src/radix_connect/wallet_interaction/dapp_wallet_interaction/wallet_to_dapp/success_response/account/account_proof.rs new file mode 100644 index 000000000..13ebb45cb --- /dev/null +++ b/src/radix_connect/wallet_interaction/dapp_wallet_interaction/wallet_to_dapp/success_response/account/account_proof.rs @@ -0,0 +1,55 @@ +use crate::prelude::*; + +#[derive(Debug, Serialize, Deserialize, PartialEq, uniffi::Record)] +#[serde(rename_all = "camelCase")] +pub struct WalletToDappInteractionAccountProof { + pub account_address: AccountAddress, + pub proof: WalletToDappInteractionAuthProof, +} + +impl WalletToDappInteractionAccountProof { + pub fn new( + account_address: impl Into, + proof: WalletToDappInteractionAuthProof, + ) -> Self { + Self { + account_address: account_address.into(), + proof, + } + } +} + +impl HasSampleValues for WalletToDappInteractionAccountProof { + fn sample() -> Self { + Self::new( + AccountAddress::sample(), + WalletToDappInteractionAuthProof::sample(), + ) + } + + fn sample_other() -> Self { + Self::new( + AccountAddress::sample_other(), + WalletToDappInteractionAuthProof::sample_other(), + ) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[allow(clippy::upper_case_acronyms)] + type SUT = WalletToDappInteractionAccountProof; + + #[test] + fn equality() { + assert_eq!(SUT::sample(), SUT::sample()); + assert_eq!(SUT::sample_other(), SUT::sample_other()); + } + + #[test] + fn inequality() { + assert_ne!(SUT::sample(), SUT::sample_other()); + } +} diff --git a/src/radix_connect/wallet_interaction/dapp_wallet_interaction/wallet_to_dapp/success_response/account/accounts.rs b/src/radix_connect/wallet_interaction/dapp_wallet_interaction/wallet_to_dapp/success_response/account/accounts.rs new file mode 100644 index 000000000..045a3a171 --- /dev/null +++ b/src/radix_connect/wallet_interaction/dapp_wallet_interaction/wallet_to_dapp/success_response/account/accounts.rs @@ -0,0 +1,61 @@ +use crate::prelude::*; + +#[derive(Debug, Serialize, Deserialize, PartialEq, uniffi::Record)] +pub struct WalletToDappInteractionAccountsRequestResponseItem { + pub accounts: Vec, + #[serde(skip_serializing_if = "Option::is_none")] + pub challenge: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub proofs: Option>, +} + +impl WalletToDappInteractionAccountsRequestResponseItem { + pub fn new( + accounts: Vec, + challenge: impl Into>, + proofs: impl Into>>, + ) -> Self { + Self { + accounts, + challenge: challenge.into(), + proofs: proofs.into(), + } + } +} + +impl HasSampleValues for WalletToDappInteractionAccountsRequestResponseItem { + fn sample() -> Self { + Self::new( + vec![WalletInteractionWalletAccount::sample()], + Exactly32Bytes::sample(), + vec![WalletToDappInteractionAccountProof::sample()], + ) + } + + fn sample_other() -> Self { + Self::new( + vec![WalletInteractionWalletAccount::sample_other()], + Exactly32Bytes::sample_other(), + vec![WalletToDappInteractionAccountProof::sample_other()], + ) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[allow(clippy::upper_case_acronyms)] + type SUT = WalletToDappInteractionAccountsRequestResponseItem; + + #[test] + fn equality() { + assert_eq!(SUT::sample(), SUT::sample()); + assert_eq!(SUT::sample_other(), SUT::sample_other()); + } + + #[test] + fn inequality() { + assert_ne!(SUT::sample(), SUT::sample_other()); + } +} diff --git a/src/radix_connect/wallet_interaction/dapp_wallet_interaction/wallet_to_dapp/success_response/account/mod.rs b/src/radix_connect/wallet_interaction/dapp_wallet_interaction/wallet_to_dapp/success_response/account/mod.rs new file mode 100644 index 000000000..c490ce075 --- /dev/null +++ b/src/radix_connect/wallet_interaction/dapp_wallet_interaction/wallet_to_dapp/success_response/account/mod.rs @@ -0,0 +1,5 @@ +mod account_proof; +mod accounts; + +pub use account_proof::*; +pub use accounts::*; diff --git a/src/radix_connect/wallet_interaction/dapp_wallet_interaction/wallet_to_dapp/success_response/auth/auth.rs b/src/radix_connect/wallet_interaction/dapp_wallet_interaction/wallet_to_dapp/success_response/auth/auth.rs new file mode 100644 index 000000000..fe857b939 --- /dev/null +++ b/src/radix_connect/wallet_interaction/dapp_wallet_interaction/wallet_to_dapp/success_response/auth/auth.rs @@ -0,0 +1,49 @@ +use crate::prelude::*; + +#[derive(Debug, Serialize, Deserialize, PartialEq, uniffi::Enum)] +#[serde(tag = "discriminator")] +pub enum WalletToDappInteractionAuthRequestResponseItem { + #[serde(rename = "usePersona")] + UsePersona(WalletToDappInteractionAuthUsePersonaRequestResponseItem), + #[serde(rename = "loginWithoutChallenge")] + LoginWithoutChallenge( + WalletToDappInteractionAuthLoginWithoutChallengeRequestResponseItem, + ), + #[serde(rename = "loginWithChallenge")] + LoginWithChallenge( + WalletToDappInteractionAuthLoginWithChallengeRequestResponseItem, + ), +} + +impl HasSampleValues for WalletToDappInteractionAuthRequestResponseItem { + fn sample() -> Self { + WalletToDappInteractionAuthRequestResponseItem::UsePersona( + WalletToDappInteractionAuthUsePersonaRequestResponseItem::sample(), + ) + } + + fn sample_other() -> Self { + WalletToDappInteractionAuthRequestResponseItem::LoginWithChallenge( + WalletToDappInteractionAuthLoginWithChallengeRequestResponseItem::sample_other(), + ) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[allow(clippy::upper_case_acronyms)] + type SUT = WalletToDappInteractionAuthRequestResponseItem; + + #[test] + fn equality() { + assert_eq!(SUT::sample(), SUT::sample()); + assert_eq!(SUT::sample_other(), SUT::sample_other()); + } + + #[test] + fn inequality() { + assert_ne!(SUT::sample(), SUT::sample_other()); + } +} diff --git a/src/radix_connect/wallet_interaction/dapp_wallet_interaction/wallet_to_dapp/success_response/auth/auth_login_with_challenge.rs b/src/radix_connect/wallet_interaction/dapp_wallet_interaction/wallet_to_dapp/success_response/auth/auth_login_with_challenge.rs new file mode 100644 index 000000000..99dc4fecc --- /dev/null +++ b/src/radix_connect/wallet_interaction/dapp_wallet_interaction/wallet_to_dapp/success_response/auth/auth_login_with_challenge.rs @@ -0,0 +1,61 @@ +use crate::prelude::*; + +#[derive(Debug, Serialize, Deserialize, PartialEq, uniffi::Record)] +pub struct WalletToDappInteractionAuthLoginWithChallengeRequestResponseItem { + pub persona: DappWalletInteractionPersona, + pub challenge: Exactly32Bytes, + pub proof: WalletToDappInteractionAuthProof, +} + +impl WalletToDappInteractionAuthLoginWithChallengeRequestResponseItem { + pub fn new( + persona: DappWalletInteractionPersona, + challenge: impl Into, + proof: WalletToDappInteractionAuthProof, + ) -> Self { + Self { + persona, + challenge: challenge.into(), + proof, + } + } +} + +impl HasSampleValues + for WalletToDappInteractionAuthLoginWithChallengeRequestResponseItem +{ + fn sample() -> Self { + Self::new( + DappWalletInteractionPersona::sample(), + Exactly32Bytes::sample(), + WalletToDappInteractionAuthProof::sample(), + ) + } + + fn sample_other() -> Self { + Self::new( + DappWalletInteractionPersona::sample_other(), + Exactly32Bytes::sample_other(), + WalletToDappInteractionAuthProof::sample_other(), + ) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[allow(clippy::upper_case_acronyms)] + type SUT = WalletToDappInteractionAuthLoginWithChallengeRequestResponseItem; + + #[test] + fn equality() { + assert_eq!(SUT::sample(), SUT::sample()); + assert_eq!(SUT::sample_other(), SUT::sample_other()); + } + + #[test] + fn inequality() { + assert_ne!(SUT::sample(), SUT::sample_other()); + } +} diff --git a/src/radix_connect/wallet_interaction/dapp_wallet_interaction/wallet_to_dapp/success_response/auth/auth_login_without_challenge.rs b/src/radix_connect/wallet_interaction/dapp_wallet_interaction/wallet_to_dapp/success_response/auth/auth_login_without_challenge.rs new file mode 100644 index 000000000..66ac26a84 --- /dev/null +++ b/src/radix_connect/wallet_interaction/dapp_wallet_interaction/wallet_to_dapp/success_response/auth/auth_login_without_challenge.rs @@ -0,0 +1,44 @@ +use crate::prelude::*; + +#[derive(Debug, Serialize, Deserialize, PartialEq, uniffi::Record)] +pub struct WalletToDappInteractionAuthLoginWithoutChallengeRequestResponseItem { + pub persona: DappWalletInteractionPersona, +} + +impl WalletToDappInteractionAuthLoginWithoutChallengeRequestResponseItem { + pub fn new(persona: DappWalletInteractionPersona) -> Self { + Self { persona } + } +} + +impl HasSampleValues + for WalletToDappInteractionAuthLoginWithoutChallengeRequestResponseItem +{ + fn sample() -> Self { + Self::new(DappWalletInteractionPersona::sample()) + } + + fn sample_other() -> Self { + Self::new(DappWalletInteractionPersona::sample_other()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[allow(clippy::upper_case_acronyms)] + type SUT = + WalletToDappInteractionAuthLoginWithoutChallengeRequestResponseItem; + + #[test] + fn equality() { + assert_eq!(SUT::sample(), SUT::sample()); + assert_eq!(SUT::sample_other(), SUT::sample_other()); + } + + #[test] + fn inequality() { + assert_ne!(SUT::sample(), SUT::sample_other()); + } +} diff --git a/src/radix_connect/wallet_interaction/dapp_wallet_interaction/wallet_to_dapp/success_response/auth/auth_proof.rs b/src/radix_connect/wallet_interaction/dapp_wallet_interaction/wallet_to_dapp/success_response/auth/auth_proof.rs new file mode 100644 index 000000000..d1d9f4761 --- /dev/null +++ b/src/radix_connect/wallet_interaction/dapp_wallet_interaction/wallet_to_dapp/success_response/auth/auth_proof.rs @@ -0,0 +1,63 @@ +use crate::prelude::*; + +#[serde_as] +#[derive(Debug, Serialize, Deserialize, PartialEq, uniffi::Record)] +#[serde(rename_all = "camelCase")] +pub struct WalletToDappInteractionAuthProof { + #[serde_as(as = "DisplayFromStr")] + pub public_key: PublicKey, + pub curve: SLIP10Curve, + #[serde_as(as = "DisplayFromStr")] + pub signature: Signature, +} + +impl WalletToDappInteractionAuthProof { + pub fn new( + public_key: impl Into, + curve: SLIP10Curve, + signature: impl Into, + ) -> Self { + Self { + public_key: public_key.into(), + curve, + signature: signature.into(), + } + } +} + +impl HasSampleValues for WalletToDappInteractionAuthProof { + fn sample() -> Self { + Self::new( + PublicKey::sample(), + SLIP10Curve::sample(), + Signature::sample(), + ) + } + + fn sample_other() -> Self { + Self::new( + PublicKey::sample_other(), + SLIP10Curve::sample_other(), + Signature::sample_other(), + ) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[allow(clippy::upper_case_acronyms)] + type SUT = WalletToDappInteractionAuthProof; + + #[test] + fn equality() { + assert_eq!(SUT::sample(), SUT::sample()); + assert_eq!(SUT::sample_other(), SUT::sample_other()); + } + + #[test] + fn inequality() { + assert_ne!(SUT::sample(), SUT::sample_other()); + } +} diff --git a/src/radix_connect/wallet_interaction/dapp_wallet_interaction/wallet_to_dapp/success_response/auth/auth_use_persona.rs b/src/radix_connect/wallet_interaction/dapp_wallet_interaction/wallet_to_dapp/success_response/auth/auth_use_persona.rs new file mode 100644 index 000000000..93b39edb2 --- /dev/null +++ b/src/radix_connect/wallet_interaction/dapp_wallet_interaction/wallet_to_dapp/success_response/auth/auth_use_persona.rs @@ -0,0 +1,43 @@ +use crate::prelude::*; + +#[derive(Debug, Serialize, Deserialize, PartialEq, uniffi::Record)] +pub struct WalletToDappInteractionAuthUsePersonaRequestResponseItem { + pub persona: DappWalletInteractionPersona, +} + +impl WalletToDappInteractionAuthUsePersonaRequestResponseItem { + pub fn new(persona: DappWalletInteractionPersona) -> Self { + Self { persona } + } +} + +impl HasSampleValues + for WalletToDappInteractionAuthUsePersonaRequestResponseItem +{ + fn sample() -> Self { + Self::new(DappWalletInteractionPersona::sample()) + } + + fn sample_other() -> Self { + Self::new(DappWalletInteractionPersona::sample_other()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[allow(clippy::upper_case_acronyms)] + type SUT = WalletToDappInteractionAuthUsePersonaRequestResponseItem; + + #[test] + fn equality() { + assert_eq!(SUT::sample(), SUT::sample()); + assert_eq!(SUT::sample_other(), SUT::sample_other()); + } + + #[test] + fn inequality() { + assert_ne!(SUT::sample(), SUT::sample_other()); + } +} diff --git a/src/radix_connect/wallet_interaction/dapp_wallet_interaction/wallet_to_dapp/success_response/auth/mod.rs b/src/radix_connect/wallet_interaction/dapp_wallet_interaction/wallet_to_dapp/success_response/auth/mod.rs new file mode 100644 index 000000000..273066c82 --- /dev/null +++ b/src/radix_connect/wallet_interaction/dapp_wallet_interaction/wallet_to_dapp/success_response/auth/mod.rs @@ -0,0 +1,11 @@ +mod auth; +mod auth_login_with_challenge; +mod auth_login_without_challenge; +mod auth_proof; +mod auth_use_persona; + +pub use auth::*; +pub use auth_login_with_challenge::*; +pub use auth_login_without_challenge::*; +pub use auth_proof::*; +pub use auth_use_persona::*; diff --git a/src/radix_connect/wallet_interaction/dapp_wallet_interaction/wallet_to_dapp/success_response/authorized_request.rs b/src/radix_connect/wallet_interaction/dapp_wallet_interaction/wallet_to_dapp/success_response/authorized_request.rs new file mode 100644 index 000000000..5401b938b --- /dev/null +++ b/src/radix_connect/wallet_interaction/dapp_wallet_interaction/wallet_to_dapp/success_response/authorized_request.rs @@ -0,0 +1,88 @@ +use crate::prelude::*; + +#[derive(Debug, Serialize, Deserialize, PartialEq, uniffi::Record)] +#[serde(rename_all = "camelCase")] +pub struct WalletToDappInteractionAuthorizedRequestResponseItems { + pub auth: WalletToDappInteractionAuthRequestResponseItem, + #[serde(skip_serializing_if = "Option::is_none")] + pub ongoing_accounts: + Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub ongoing_persona_data: + Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub one_time_accounts: + Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub one_time_persona_data: + Option, +} + +impl WalletToDappInteractionAuthorizedRequestResponseItems { + pub fn new( + auth: WalletToDappInteractionAuthRequestResponseItem, + ongoing_accounts: impl Into< + Option, + >, + ongoing_persona_data: impl Into< + Option, + >, + one_time_accounts: impl Into< + Option, + >, + one_time_persona_data: impl Into< + Option, + >, + ) -> Self { + Self { + auth, + ongoing_accounts: ongoing_accounts.into(), + ongoing_persona_data: ongoing_persona_data.into(), + one_time_accounts: one_time_accounts.into(), + one_time_persona_data: one_time_persona_data.into(), + } + } +} + +impl HasSampleValues for WalletToDappInteractionAuthorizedRequestResponseItems { + fn sample() -> Self { + Self::new( + WalletToDappInteractionAuthRequestResponseItem::sample(), + WalletToDappInteractionAccountsRequestResponseItem::sample(), + WalletToDappInteractionPersonaDataRequestResponseItem::sample(), + WalletToDappInteractionAccountsRequestResponseItem::sample(), + WalletToDappInteractionPersonaDataRequestResponseItem::sample(), + ) + } + + fn sample_other() -> Self { + Self::new( + WalletToDappInteractionAuthRequestResponseItem::sample_other(), + WalletToDappInteractionAccountsRequestResponseItem::sample_other(), + WalletToDappInteractionPersonaDataRequestResponseItem::sample_other( + ), + WalletToDappInteractionAccountsRequestResponseItem::sample_other(), + WalletToDappInteractionPersonaDataRequestResponseItem::sample_other( + ), + ) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[allow(clippy::upper_case_acronyms)] + type SUT = WalletToDappInteractionAuthorizedRequestResponseItems; + + #[test] + fn equality() { + assert_eq!(SUT::sample(), SUT::sample()); + assert_eq!(SUT::sample_other(), SUT::sample_other()); + } + + #[test] + fn inequality() { + assert_ne!(SUT::sample(), SUT::sample_other()); + } +} diff --git a/src/radix_connect/wallet_interaction/dapp_wallet_interaction/wallet_to_dapp/success_response/items.rs b/src/radix_connect/wallet_interaction/dapp_wallet_interaction/wallet_to_dapp/success_response/items.rs new file mode 100644 index 000000000..6ac9af4ef --- /dev/null +++ b/src/radix_connect/wallet_interaction/dapp_wallet_interaction/wallet_to_dapp/success_response/items.rs @@ -0,0 +1,47 @@ +use crate::prelude::*; + +#[derive(Debug, Serialize, Deserialize, PartialEq, uniffi::Enum)] +#[serde(tag = "discriminator")] +#[allow(clippy::large_enum_variant)] +pub enum WalletToDappInteractionResponseItems { + #[serde(rename = "authorizedRequest")] + AuthorizedRequest(WalletToDappInteractionAuthorizedRequestResponseItems), + #[serde(rename = "unauthorizedRequest")] + UnauthorizedRequest( + WalletToDappInteractionUnauthorizedRequestResponseItems, + ), + #[serde(rename = "transaction")] + Transaction(WalletToDappInteractionTransactionResponseItems), +} + +impl HasSampleValues for WalletToDappInteractionResponseItems { + fn sample() -> Self { + WalletToDappInteractionResponseItems::AuthorizedRequest( + WalletToDappInteractionAuthorizedRequestResponseItems::sample(), + ) + } + fn sample_other() -> Self { + WalletToDappInteractionResponseItems::Transaction( + WalletToDappInteractionTransactionResponseItems::sample_other(), + ) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[allow(clippy::upper_case_acronyms)] + type SUT = WalletToDappInteractionResponseItems; + + #[test] + fn equality() { + assert_eq!(SUT::sample(), SUT::sample()); + assert_eq!(SUT::sample_other(), SUT::sample_other()); + } + + #[test] + fn inequality() { + assert_ne!(SUT::sample(), SUT::sample_other()); + } +} diff --git a/src/radix_connect/wallet_interaction/dapp_wallet_interaction/wallet_to_dapp/success_response/mod.rs b/src/radix_connect/wallet_interaction/dapp_wallet_interaction/wallet_to_dapp/success_response/mod.rs new file mode 100644 index 000000000..aa3a3bfeb --- /dev/null +++ b/src/radix_connect/wallet_interaction/dapp_wallet_interaction/wallet_to_dapp/success_response/mod.rs @@ -0,0 +1,17 @@ +mod account; +mod auth; +mod authorized_request; +mod items; +mod persona_data; +mod success; +mod transaction; +mod unauthorized_request; + +pub use account::*; +pub use auth::*; +pub use authorized_request::*; +pub use items::*; +pub use persona_data::*; +pub use success::*; +pub use transaction::*; +pub use unauthorized_request::*; diff --git a/src/radix_connect/wallet_interaction/dapp_wallet_interaction/wallet_to_dapp/success_response/persona_data/mod.rs b/src/radix_connect/wallet_interaction/dapp_wallet_interaction/wallet_to_dapp/success_response/persona_data/mod.rs new file mode 100644 index 000000000..8bf469146 --- /dev/null +++ b/src/radix_connect/wallet_interaction/dapp_wallet_interaction/wallet_to_dapp/success_response/persona_data/mod.rs @@ -0,0 +1,2 @@ +mod persona_data; +pub use persona_data::*; diff --git a/src/radix_connect/wallet_interaction/dapp_wallet_interaction/wallet_to_dapp/success_response/persona_data/persona_data.rs b/src/radix_connect/wallet_interaction/dapp_wallet_interaction/wallet_to_dapp/success_response/persona_data/persona_data.rs new file mode 100644 index 000000000..400907828 --- /dev/null +++ b/src/radix_connect/wallet_interaction/dapp_wallet_interaction/wallet_to_dapp/success_response/persona_data/persona_data.rs @@ -0,0 +1,63 @@ +use crate::prelude::*; + +#[derive(Debug, Serialize, Deserialize, PartialEq, Clone, uniffi::Record)] +#[serde(rename_all = "camelCase")] +pub struct WalletToDappInteractionPersonaDataRequestResponseItem { + #[serde(skip_serializing_if = "Option::is_none")] + pub name: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub email_addresses: Option>, + #[serde(skip_serializing_if = "Option::is_none")] + pub phone_numbers: Option>, +} + +impl WalletToDappInteractionPersonaDataRequestResponseItem { + pub fn new( + name: impl Into>, + email_addresses: impl Into>>, + phone_numbers: impl Into>>, + ) -> Self { + Self { + name: name.into(), + email_addresses: email_addresses.into(), + phone_numbers: phone_numbers.into(), + } + } +} + +impl HasSampleValues for WalletToDappInteractionPersonaDataRequestResponseItem { + fn sample() -> Self { + Self::new( + PersonaDataEntryName::sample(), + vec![PersonaDataEntryEmailAddress::sample()], + vec![PersonaDataEntryPhoneNumber::sample()], + ) + } + + fn sample_other() -> Self { + Self::new( + PersonaDataEntryName::sample_other(), + vec![PersonaDataEntryEmailAddress::sample_other()], + vec![PersonaDataEntryPhoneNumber::sample_other()], + ) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[allow(clippy::upper_case_acronyms)] + type SUT = WalletToDappInteractionPersonaDataRequestResponseItem; + + #[test] + fn equality() { + assert_eq!(SUT::sample(), SUT::sample()); + assert_eq!(SUT::sample_other(), SUT::sample_other()); + } + + #[test] + fn inequality() { + assert_ne!(SUT::sample(), SUT::sample_other()); + } +} diff --git a/src/radix_connect/wallet_interaction/dapp_wallet_interaction/wallet_to_dapp/success_response/success.rs b/src/radix_connect/wallet_interaction/dapp_wallet_interaction/wallet_to_dapp/success_response/success.rs new file mode 100644 index 000000000..b3ce8876e --- /dev/null +++ b/src/radix_connect/wallet_interaction/dapp_wallet_interaction/wallet_to_dapp/success_response/success.rs @@ -0,0 +1,55 @@ +use crate::prelude::*; + +#[derive(Debug, Serialize, Deserialize, PartialEq, uniffi::Record)] +#[serde(rename_all = "camelCase")] +pub struct WalletToDappInteractionSuccessResponse { + pub interaction_id: WalletInteractionId, + pub items: WalletToDappInteractionResponseItems, +} + +impl WalletToDappInteractionSuccessResponse { + pub fn new( + interaction_id: WalletInteractionId, + items: WalletToDappInteractionResponseItems, + ) -> Self { + Self { + interaction_id, + items, + } + } +} + +impl HasSampleValues for WalletToDappInteractionSuccessResponse { + fn sample() -> Self { + Self::new( + WalletInteractionId::sample(), + WalletToDappInteractionResponseItems::sample(), + ) + } + + fn sample_other() -> Self { + Self::new( + WalletInteractionId::sample_other(), + WalletToDappInteractionResponseItems::sample_other(), + ) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[allow(clippy::upper_case_acronyms)] + type SUT = WalletToDappInteractionSuccessResponse; + + #[test] + fn equality() { + assert_eq!(SUT::sample(), SUT::sample()); + assert_eq!(SUT::sample_other(), SUT::sample_other()); + } + + #[test] + fn inequality() { + assert_ne!(SUT::sample(), SUT::sample_other()); + } +} diff --git a/src/radix_connect/wallet_interaction/dapp_wallet_interaction/wallet_to_dapp/success_response/transaction/mod.rs b/src/radix_connect/wallet_interaction/dapp_wallet_interaction/wallet_to_dapp/success_response/transaction/mod.rs new file mode 100644 index 000000000..653d08017 --- /dev/null +++ b/src/radix_connect/wallet_interaction/dapp_wallet_interaction/wallet_to_dapp/success_response/transaction/mod.rs @@ -0,0 +1,3 @@ +mod transaction; + +pub use transaction::*; diff --git a/src/radix_connect/wallet_interaction/dapp_wallet_interaction/wallet_to_dapp/success_response/transaction/transaction.rs b/src/radix_connect/wallet_interaction/dapp_wallet_interaction/wallet_to_dapp/success_response/transaction/transaction.rs new file mode 100644 index 000000000..2d3e3a191 --- /dev/null +++ b/src/radix_connect/wallet_interaction/dapp_wallet_interaction/wallet_to_dapp/success_response/transaction/transaction.rs @@ -0,0 +1,58 @@ +use crate::prelude::*; + +#[derive(Debug, Serialize, Deserialize, PartialEq, uniffi::Record)] +pub struct WalletToDappInteractionTransactionResponseItems { + pub send: WalletToDappInteractionSendTransactionResponseItem, +} + +impl WalletToDappInteractionTransactionResponseItems { + pub fn new(transaction_intent_hash: IntentHash) -> Self { + Self { + send: WalletToDappInteractionSendTransactionResponseItem::new( + transaction_intent_hash, + ), + } + } +} + +#[derive(Debug, Serialize, Deserialize, PartialEq, uniffi::Record)] +pub struct WalletToDappInteractionSendTransactionResponseItem { + #[serde(rename = "transactionIntentHash")] + bech32_encoded_tx_id: String, +} + +impl WalletToDappInteractionSendTransactionResponseItem { + pub fn new(transaction_intent_hash: IntentHash) -> Self { + Self { + bech32_encoded_tx_id: transaction_intent_hash.bech32_encoded_tx_id, + } + } +} + +impl HasSampleValues for WalletToDappInteractionTransactionResponseItems { + fn sample() -> Self { + Self::new(IntentHash::sample()) + } + fn sample_other() -> Self { + Self::new(IntentHash::sample_other()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[allow(clippy::upper_case_acronyms)] + type SUT = WalletToDappInteractionTransactionResponseItems; + + #[test] + fn equality() { + assert_eq!(SUT::sample(), SUT::sample()); + assert_eq!(SUT::sample_other(), SUT::sample_other()); + } + + #[test] + fn inequality() { + assert_ne!(SUT::sample(), SUT::sample_other()); + } +} diff --git a/src/radix_connect/wallet_interaction/dapp_wallet_interaction/wallet_to_dapp/success_response/unauthorized_request.rs b/src/radix_connect/wallet_interaction/dapp_wallet_interaction/wallet_to_dapp/success_response/unauthorized_request.rs new file mode 100644 index 000000000..9bc354dd7 --- /dev/null +++ b/src/radix_connect/wallet_interaction/dapp_wallet_interaction/wallet_to_dapp/success_response/unauthorized_request.rs @@ -0,0 +1,66 @@ +use crate::prelude::*; + +#[derive(Debug, Serialize, Deserialize, PartialEq, uniffi::Record)] +#[serde(rename_all = "camelCase")] +pub struct WalletToDappInteractionUnauthorizedRequestResponseItems { + #[serde(skip_serializing_if = "Option::is_none")] + pub one_time_accounts: + Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub one_time_persona_data: + Option, +} + +impl WalletToDappInteractionUnauthorizedRequestResponseItems { + pub fn new( + one_time_accounts: impl Into< + Option, + >, + one_time_persona_data: impl Into< + Option, + >, + ) -> Self { + Self { + one_time_accounts: one_time_accounts.into(), + one_time_persona_data: one_time_persona_data.into(), + } + } +} + +impl HasSampleValues + for WalletToDappInteractionUnauthorizedRequestResponseItems +{ + fn sample() -> Self { + Self::new( + WalletToDappInteractionAccountsRequestResponseItem::sample(), + WalletToDappInteractionPersonaDataRequestResponseItem::sample(), + ) + } + + fn sample_other() -> Self { + Self::new( + WalletToDappInteractionAccountsRequestResponseItem::sample_other(), + WalletToDappInteractionPersonaDataRequestResponseItem::sample_other( + ), + ) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[allow(clippy::upper_case_acronyms)] + type SUT = WalletToDappInteractionUnauthorizedRequestResponseItems; + + #[test] + fn equality() { + assert_eq!(SUT::sample(), SUT::sample()); + assert_eq!(SUT::sample_other(), SUT::sample_other()); + } + + #[test] + fn inequality() { + assert_ne!(SUT::sample(), SUT::sample_other()); + } +} diff --git a/src/radix_connect/wallet_interaction/mod.rs b/src/radix_connect/wallet_interaction/mod.rs new file mode 100644 index 000000000..fae159a84 --- /dev/null +++ b/src/radix_connect/wallet_interaction/mod.rs @@ -0,0 +1,3 @@ +mod dapp_wallet_interaction; + +pub use dapp_wallet_interaction::*; diff --git a/src/radix_connect/wallet_persona.rs b/src/radix_connect/wallet_persona.rs new file mode 100644 index 000000000..ecf57e106 --- /dev/null +++ b/src/radix_connect/wallet_persona.rs @@ -0,0 +1,49 @@ +use crate::prelude::*; + +#[derive(Debug, Serialize, Deserialize, PartialEq, uniffi::Record)] +#[serde(rename_all = "camelCase")] +pub struct DappWalletInteractionPersona { + pub identity_address: IdentityAddress, + pub label: String, +} + +impl DappWalletInteractionPersona { + pub fn new( + identity_address: impl Into, + label: impl AsRef, + ) -> Self { + Self { + identity_address: identity_address.into(), + label: label.as_ref().to_owned(), + } + } +} + +impl HasSampleValues for DappWalletInteractionPersona { + fn sample() -> Self { + Self::new(IdentityAddress::sample(), "sample1") + } + + fn sample_other() -> Self { + Self::new(IdentityAddress::sample_other(), "sample2") + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[allow(clippy::upper_case_acronyms)] + type SUT = DappWalletInteractionPersona; + + #[test] + fn equality() { + assert_eq!(SUT::sample(), SUT::sample()); + assert_eq!(SUT::sample_other(), SUT::sample_other()); + } + + #[test] + fn inequality() { + assert_ne!(SUT::sample(), SUT::sample_other()); + } +} diff --git a/tests/vectors/main.rs b/tests/vectors/main.rs index d57142ef0..22a8810ec 100644 --- a/tests/vectors/main.rs +++ b/tests/vectors/main.rs @@ -334,7 +334,6 @@ mod slip10_tests { } } -#[cfg(test)] mod encrypted_profile_tests { use std::collections::HashSet; @@ -498,3 +497,352 @@ mod encrypted_profile_tests { fixture.test(); } } + +#[cfg(test)] +mod dapp_to_wallet_interaction_tests { + use super::*; + use serde_json::Value; + use url::Url; + + #[test] + fn test_vector() { + let decoded_wallet_interactions = + fixture::>(include_str!(concat!( + env!("FIXTURES_VECTOR"), + "wallet_interactions_dapp_to_wallet.json" + ))) + .expect("wallet_interactions_dapp_to_wallet fixture"); + + let metadata = DappToWalletInteractionMetadata::new( + 2, + NetworkID::Stokenet, + Url::from_str("https://dev-sandbox.rdx-works-main.extratools.works").unwrap(), + DappDefinitionAddress::from_str( + "account_tdx_2_12xd46c22d6m696lv565t9afn088htudtq275px3qs925ywwty8axze", + ) + .unwrap(), + ); + + let authorized_request_with_challenge_items = DappToWalletInteractionItems::AuthorizedRequest( + DappToWalletInteractionAuthorizedRequestItems::new( + DappToWalletInteractionAuthRequestItem::LoginWithChallenge( + DappToWalletInteractionAuthLoginWithChallengeRequestItem::new( + Exactly32Bytes::from_hex("e280cfa39e1499f2862e59759cc2fc990cce28b70a7989324fe91c47814d0630").unwrap(), + ) + ), + DappToWalletInteractionResetRequestItem::new( + true, + true, + ), + DappToWalletInteractionAccountsRequestItem::new( + RequestedQuantity::at_least(4), + Exactly32Bytes::from_hex("e280cfa39e1499f2862e59759cc2fc990cce28b70a7989324fe91c47814d0630").unwrap(), + ), + DappToWalletInteractionPersonaDataRequestItem::new( + true, + RequestedQuantity::exactly(1), + RequestedQuantity::exactly(1), + ), + None, + None, + ) + ); + + let authorized_request_with_challenge = DappToWalletInteraction::new( + WalletInteractionId::from_str( + "d59590ea-d50b-4e8d-a5e1-da3a2574ae5c", + ) + .unwrap(), + authorized_request_with_challenge_items, + metadata.clone(), + ); + + let authorized_request_without_challenge_items = DappToWalletInteractionItems::AuthorizedRequest( + DappToWalletInteractionAuthorizedRequestItems::new( + DappToWalletInteractionAuthRequestItem::LoginWithoutChallenge, + DappToWalletInteractionResetRequestItem::new( + true, + true, + ), + DappToWalletInteractionAccountsRequestItem::new( + RequestedQuantity::exactly(4), + Exactly32Bytes::from_hex("e280cfa39e1499f2862e59759cc2fc990cce28b70a7989324fe91c47814d0630").unwrap(), + ), + DappToWalletInteractionPersonaDataRequestItem::new( + true, + RequestedQuantity::at_least(1), + RequestedQuantity::at_least(1), + ), + None, + None, + ) + ); + + let authorized_request_without_challenge = DappToWalletInteraction::new( + WalletInteractionId::from_str( + "d59590ea-d50b-4e8d-a5e1-da3a2574ae5c", + ) + .unwrap(), + authorized_request_without_challenge_items, + metadata.clone(), + ); + + let transaction = DappToWalletInteraction::new( + WalletInteractionId::from_str("4051ff20-03b0-4a48-8205-0e8e8c673289").unwrap(), + DappToWalletInteractionItems::Transaction( + DappToWalletInteractionTransactionItems::new( + DappToWalletInteractionSendTransactionItem::new( + "CALL_FUNCTION Address(\"package_tdx_2_1pkgxxxxxxxxxplxxxxxxxxxxxxx020379220524xxxxxxxxxe4r780\") \n \"OneResourcePool\"\n \"instantiate\"\n Enum(Enum())\n Enum() \n Address(\"resource_tdx_2_1tknxxxxxxxxxradxrdxxxxxxxxx009923554798xxxxxxxxxtfd2jc\")\n None;", + 1, + vec!["0061736d0100000001c8011c60037f7f7f0060027f7f0060027f7f017f60017f0060037f7f7f017f60017f017f60047f7f7f7f0060017f017e60037f7f7f017e60057f7f7f7f7f0060057f7f7f7f7f017f60027f7e017f60037f7f7e0".into()], + "test message".to_owned(), + ) + ) + ), + metadata.clone(), + ); + + let unauthorized_request_1_items = DappToWalletInteractionItems::UnauthorizedRequest( + DappToWalletInteractionUnauthorizedRequestItems::new( + DappToWalletInteractionAccountsRequestItem::new( + RequestedQuantity::at_least(1), + Exactly32Bytes::from_hex("84a5234f14a50dee062dc7a6a51f4bdab7cab5faadea05542af2040688d8fb6c").unwrap() + ), + DappToWalletInteractionPersonaDataRequestItem::new( + true, + RequestedQuantity::exactly(1), + RequestedQuantity::exactly(1), + ) + ) + ); + + let unauthorized_request_1 = DappToWalletInteraction::new( + WalletInteractionId::from_str( + "51a720a5-9f80-4d0f-8264-704d1645f0af", + ) + .unwrap(), + unauthorized_request_1_items, + metadata.clone(), + ); + + let unauthorized_request_2_items = DappToWalletInteractionItems::UnauthorizedRequest( + DappToWalletInteractionUnauthorizedRequestItems::new( + DappToWalletInteractionAccountsRequestItem::new( + RequestedQuantity::exactly(1), + Exactly32Bytes::from_hex("84a5234f14a50dee062dc7a6a51f4bdab7cab5faadea05542af2040688d8fb6c").unwrap() + ), + DappToWalletInteractionPersonaDataRequestItem::new( + true, + RequestedQuantity::at_least(1), + RequestedQuantity::at_least(1), + ) + ) + ); + + let unauthorized_request_2 = DappToWalletInteraction::new( + WalletInteractionId::from_str( + "51a720a5-9f80-4d0f-8264-704d1645f0af", + ) + .unwrap(), + unauthorized_request_2_items, + metadata.clone(), + ); + + let interactions = vec![ + authorized_request_with_challenge, + authorized_request_without_challenge, + transaction, + unauthorized_request_1, + unauthorized_request_2, + ]; + + for (fixture, expected) in + decoded_wallet_interactions.iter().zip(interactions.iter()) + { + pretty_assertions::assert_eq!(fixture, expected); + } + + let raw_wallet_interactions = + fixture::>(include_str!(concat!( + env!("FIXTURES_VECTOR"), + "wallet_interactions_dapp_to_wallet.json" + ))) + .expect("wallet_interactions_dapp_to_wallet fixture"); + + let encoded_interactions = + serde_json::to_string(&interactions).unwrap(); + let serde_value: Vec = + serde_json::from_str(&encoded_interactions).unwrap(); + + for (fixture, expected) in + raw_wallet_interactions.iter().zip(serde_value.iter()) + { + pretty_assertions::assert_eq!(fixture, expected); + } + } +} + +#[cfg(test)] +mod wallet_to_dapp_interaction_tests { + use super::*; + use serde_json::Value; + + #[test] + fn test_vector() { + let persona_data = + WalletToDappInteractionPersonaDataRequestResponseItem::new( + PersonaDataEntryName::new( + PersonaDataNameVariant::Western, + "Family", + "Given", + "Nick", + ) + .unwrap(), + vec![PersonaDataEntryEmailAddress::new("some@gmail.com") + .unwrap()], + vec![PersonaDataEntryPhoneNumber::new("071234579").unwrap()], + ); + + let account_1 = WalletInteractionWalletAccount::new( + AccountAddress::from_str("account_tdx_2_129qeystv8tufmkmjrry2g6kadhhfh4f7rd0x3t9yagcvfhspt62paz") + .unwrap(), + "Dff", + AppearanceID::gradient0(), + ); + + let account_2 = WalletInteractionWalletAccount::new( + AccountAddress::from_str("account_tdx_2_128928hvf6pjr3rx2xvdw6ulf7pc8g88ya8ma3j8dtjmntckz09fr3n") + .unwrap(), + "Ghhvgfvf", + AppearanceID::gradient1(), + ); + + let authorized_request_response_items = WalletToDappInteractionResponseItems::AuthorizedRequest( + WalletToDappInteractionAuthorizedRequestResponseItems::new( + WalletToDappInteractionAuthRequestResponseItem::LoginWithChallenge( + WalletToDappInteractionAuthLoginWithChallengeRequestResponseItem::new( + DappWalletInteractionPersona::new( + IdentityAddress::from_str("identity_tdx_2_12twas58v4sthsmuky5653dup0drez3vcfwsfm6kp40qu9qyt8fgts6") + .unwrap(), + "Usdudh", + ), + Exactly32Bytes::from_hex("069ef236486d4cd5706b5e5b168e19f750ffd1b4876529a0a9de966d50a15ab7") + .unwrap(), + WalletToDappInteractionAuthProof::new( + PublicKey::from_str("ff8aee4c625738e35d837edb11e33b8abe0d6f40849ca1451edaba84d04d0699") + .unwrap(), + SLIP10Curve::Curve25519, + Signature::from_str("10177ac7d486691777133ffe59d46d55529d86cb1c4ce66aa82f432372f33e24d803d8498f42e26fe113c030fce68c526aeacff94334ba5a7f7ef84c2936eb05") + .unwrap() + ), + ) + ), + WalletToDappInteractionAccountsRequestResponseItem::new( + vec![account_1.clone(), account_2.clone()], + Exactly32Bytes::from_hex("069ef236486d4cd5706b5e5b168e19f750ffd1b4876529a0a9de966d50a15ab7") + .unwrap(), + vec![ + WalletToDappInteractionAccountProof::new( + account_1.address, + WalletToDappInteractionAuthProof::new( + PublicKey::from_str("11b162e3343ce770b6e9ed8a29d125b5580d1272b0dc4e2bd0fcae33320d9566") + .unwrap(), + SLIP10Curve::Curve25519, + Signature::from_str("e18617b527d4d33607a8adb6a040c26ca97642ec89dd8a6fe7a41fa724473e4cc69b0729c1df57aba77455801f2eef6f28848a5d206e3739de29ca2288957502") + .unwrap(), + ), + ), + WalletToDappInteractionAccountProof::new( + account_2.address, + WalletToDappInteractionAuthProof::new( + PublicKey::from_str("5386353e4cc27e3d27d064d777d811e242a16ba7aefd425062ed46631739619d") + .unwrap(), + SLIP10Curve::Curve25519, + Signature::from_str("0143fd941d51f531c8265b0f6b24f4cfcdfd24b40aac47dee6fb3386ce0d400563c892e3894a33840d1c7af2dd43ecd0729fd209171003765d109a04d7485605") + .unwrap(), + ), + ), + ], + ), + persona_data.clone(), + None, + None, + ) + ); + + let authorized_request_response = + WalletToDappInteractionResponse::Success( + WalletToDappInteractionSuccessResponse::new( + WalletInteractionId::from_str( + "06f00fbc-67ed-4a22-a122-1da719b25b6f", + ) + .unwrap(), + authorized_request_response_items, + ), + ); + + let unauthorized_request_response_items = + WalletToDappInteractionResponseItems::UnauthorizedRequest( + WalletToDappInteractionUnauthorizedRequestResponseItems::new( + WalletToDappInteractionAccountsRequestResponseItem::new( + vec![account_1.clone()], + None, + None, + ), + persona_data.clone(), + ), + ); + + let unauthorized_request_response = + WalletToDappInteractionResponse::Success( + WalletToDappInteractionSuccessResponse::new( + WalletInteractionId::from_str( + "278608e0-e5ca-416e-8339-f2d2695651c4", + ) + .unwrap(), + unauthorized_request_response_items, + ), + ); + + let failure_response = WalletToDappInteractionResponse::Failure( + WalletToDappInteractionFailureResponse::new( + WalletInteractionId::from_str( + "278608e0-e5ca-416e-8339-f2d2695651c4", + ) + .unwrap(), + DappWalletInteractionErrorType::RejectedByUser, + "User rejected the request".to_owned(), + ), + ); + + let transaction_response = WalletToDappInteractionResponse::Success( + WalletToDappInteractionSuccessResponse::new( + WalletInteractionId::from_str("c42f8825-4bbb-4ce2-a646-776b529e2f51").unwrap(), + WalletToDappInteractionResponseItems::Transaction( + WalletToDappInteractionTransactionResponseItems::new( + IntentHash::from_str("txid_tdx_2_1mwuvufnewv6qkxdaesx0gcwap7n79knhkn0crsc8dg9g9k7qknjs6vkd3n") + .unwrap(), + ), + ) + )); + + let responses = vec![ + authorized_request_response, + unauthorized_request_response, + failure_response, + transaction_response, + ]; + + let encoded = serde_json::to_string(&responses).unwrap(); + let serde_value: Vec = serde_json::from_str(&encoded).unwrap(); + let fixture = fixture::>(include_str!(concat!( + env!("FIXTURES_VECTOR"), + "wallet_interactions_wallet_to_dapp.json" + ))) + .expect("wallet_interactions_wallet_to_dapp fixture"); + + for (serde_value, fixture) in serde_value.iter().zip(fixture.iter()) { + pretty_assertions::assert_eq!(serde_value, fixture); + } + } +}