diff --git a/Cargo.lock b/Cargo.lock index bcdc53d40..b1e412877 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2737,7 +2737,7 @@ dependencies = [ [[package]] name = "sargon" -version = "1.1.42" +version = "1.1.43" dependencies = [ "actix-rt", "aes-gcm", @@ -2791,7 +2791,7 @@ dependencies = [ [[package]] name = "sargon-uniffi" -version = "1.1.42" +version = "1.1.43" dependencies = [ "actix-rt", "assert-json-diff", diff --git a/apple/Sources/Sargon/Extensions/Methods/Crypto/IntentDiscriminator+Wrap+Functions.swift b/apple/Sources/Sargon/Extensions/Methods/Crypto/IntentDiscriminator+Wrap+Functions.swift new file mode 100644 index 000000000..074c31d5d --- /dev/null +++ b/apple/Sources/Sargon/Extensions/Methods/Crypto/IntentDiscriminator+Wrap+Functions.swift @@ -0,0 +1,11 @@ +import SargonUniFFI + +extension IntentDiscriminator { + public static func secureRandom() -> Self { + newIntentDiscriminatorRandom() + } + + public var value: UInt64 { + intentDiscriminatorGetValue(intentDiscriminator: self) + } +} diff --git a/apple/Sources/Sargon/Extensions/Methods/RET/CompiledSubintent+Wrap+Functions.swift b/apple/Sources/Sargon/Extensions/Methods/RET/CompiledSubintent+Wrap+Functions.swift new file mode 100644 index 000000000..4e56b33a7 --- /dev/null +++ b/apple/Sources/Sargon/Extensions/Methods/RET/CompiledSubintent+Wrap+Functions.swift @@ -0,0 +1,8 @@ +import Foundation +import SargonUniFFI + +extension CompiledSubintent { + public var data: Data { + compiledSubintentBytes(compiledIntent: self) + } +} diff --git a/apple/Sources/Sargon/Extensions/Methods/RET/Subintent+Wrap+Functions.swift b/apple/Sources/Sargon/Extensions/Methods/RET/Subintent+Wrap+Functions.swift index 5c61ae4f6..d024320e1 100644 --- a/apple/Sources/Sargon/Extensions/Methods/RET/Subintent+Wrap+Functions.swift +++ b/apple/Sources/Sargon/Extensions/Methods/RET/Subintent+Wrap+Functions.swift @@ -3,7 +3,7 @@ import SargonUniFFI extension Subintent { public func hash() -> SubintentHash { - subintentHash(subintent: self) + subintentHash(subintent: self) } public func compile() -> CompiledSubintent { diff --git a/apple/Sources/Sargon/Extensions/SampleValues/Crypto/IntentDiscriminator+SampleValues.swift b/apple/Sources/Sargon/Extensions/SampleValues/Crypto/IntentDiscriminator+SampleValues.swift new file mode 100644 index 000000000..43a4be4d3 --- /dev/null +++ b/apple/Sources/Sargon/Extensions/SampleValues/Crypto/IntentDiscriminator+SampleValues.swift @@ -0,0 +1,8 @@ +import SargonUniFFI + +#if DEBUG +extension IntentDiscriminator { + public static let sample: Self = newIntentDiscriminatorSample() + public static let sampleOther: Self = newIntentDiscriminatorSampleOther() +} +#endif // DEBUG diff --git a/apple/Sources/Sargon/Extensions/Swiftified/Crypto/IntentDiscriminator+Swiftified.swift b/apple/Sources/Sargon/Extensions/Swiftified/Crypto/IntentDiscriminator+Swiftified.swift new file mode 100644 index 000000000..94f2f4078 --- /dev/null +++ b/apple/Sources/Sargon/Extensions/Swiftified/Crypto/IntentDiscriminator+Swiftified.swift @@ -0,0 +1,4 @@ +import Foundation +import SargonUniFFI + +extension IntentDiscriminator: SargonModel {} diff --git a/crates/sargon-uniffi/Cargo.toml b/crates/sargon-uniffi/Cargo.toml index 98072763c..37e20d6b6 100644 --- a/crates/sargon-uniffi/Cargo.toml +++ b/crates/sargon-uniffi/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "sargon-uniffi" # Don't forget to update version in crates/sargon/Cargo.toml -version = "1.1.42" +version = "1.1.43" edition = "2021" build = "build.rs" diff --git a/crates/sargon-uniffi/src/radix_connect/wallet_interaction/dapp_wallet_interaction/wallet_to_dapp/success_response/pre_authorization/pre_authorization.rs b/crates/sargon-uniffi/src/radix_connect/wallet_interaction/dapp_wallet_interaction/wallet_to_dapp/success_response/pre_authorization/pre_authorization.rs index 3011d724c..5f5d74ca7 100644 --- a/crates/sargon-uniffi/src/radix_connect/wallet_interaction/dapp_wallet_interaction/wallet_to_dapp/success_response/pre_authorization/pre_authorization.rs +++ b/crates/sargon-uniffi/src/radix_connect/wallet_interaction/dapp_wallet_interaction/wallet_to_dapp/success_response/pre_authorization/pre_authorization.rs @@ -6,3 +6,13 @@ pub struct WalletToDappInteractionPreAuthorizationResponseItems { /// A hex encoded signed partial transaction. pub encoded_signed_partial_transaction: String, } + +#[uniffi::export] +pub fn new_wallet_to_dapp_interaction_pre_authorization_response_items( + signed_subintent: SignedSubintent, +) -> WalletToDappInteractionPreAuthorizationResponseItems { + InternalWalletToDappInteractionPreAuthorizationResponseItems::new( + signed_subintent.into(), + ) + .into() +} diff --git a/crates/sargon-uniffi/src/wrapped_radix_engine_toolkit/low_level/v2/intent_core_v2.rs b/crates/sargon-uniffi/src/wrapped_radix_engine_toolkit/low_level/v2/intent_core_v2.rs deleted file mode 100644 index e14d84a77..000000000 --- a/crates/sargon-uniffi/src/wrapped_radix_engine_toolkit/low_level/v2/intent_core_v2.rs +++ /dev/null @@ -1,10 +0,0 @@ -use crate::prelude::*; -use sargon::IntentCoreV2 as InternalIntentCoreV2; - -/// Represents the core of an intent in V2, including the header, manifest, and message. -#[derive(Clone, PartialEq, Eq, InternalConversion, uniffi::Record)] -pub struct IntentCoreV2 { - pub header: IntentHeaderV2, - pub manifest: TransactionManifestV2, - pub message: MessageV2, -} diff --git a/crates/sargon-uniffi/src/wrapped_radix_engine_toolkit/low_level/v2/intent_signatures_v2.rs b/crates/sargon-uniffi/src/wrapped_radix_engine_toolkit/low_level/v2/intent_signatures_v2.rs deleted file mode 100644 index 16c1b04e0..000000000 --- a/crates/sargon-uniffi/src/wrapped_radix_engine_toolkit/low_level/v2/intent_signatures_v2.rs +++ /dev/null @@ -1,7 +0,0 @@ -use crate::prelude::*; -use sargon::IntentSignaturesV2 as InternalIntentSignaturesV2; - -#[derive(Clone, PartialEq, Eq, Hash, InternalConversion, uniffi::Record)] -pub struct IntentSignaturesV2 { - pub signatures: Vec, -} diff --git a/crates/sargon-uniffi/src/wrapped_radix_engine_toolkit/low_level/v2/mod.rs b/crates/sargon-uniffi/src/wrapped_radix_engine_toolkit/low_level/v2/mod.rs index 20a9b3146..2ac923426 100644 --- a/crates/sargon-uniffi/src/wrapped_radix_engine_toolkit/low_level/v2/mod.rs +++ b/crates/sargon-uniffi/src/wrapped_radix_engine_toolkit/low_level/v2/mod.rs @@ -1,15 +1,13 @@ mod compiled_subintent; -mod intent_core_v2; mod intent_header_v2; -mod intent_signatures_v2; mod message_v2; +mod signed_subintent; mod subintent; mod transaction_manifest_v2; pub use compiled_subintent::*; -pub use intent_core_v2::*; pub use intent_header_v2::*; -pub use intent_signatures_v2::*; pub use message_v2::*; +pub use signed_subintent::*; pub use subintent::*; pub use transaction_manifest_v2::*; diff --git a/crates/sargon-uniffi/src/wrapped_radix_engine_toolkit/low_level/v2/signed_subintent.rs b/crates/sargon-uniffi/src/wrapped_radix_engine_toolkit/low_level/v2/signed_subintent.rs new file mode 100644 index 000000000..e3cc5ef00 --- /dev/null +++ b/crates/sargon-uniffi/src/wrapped_radix_engine_toolkit/low_level/v2/signed_subintent.rs @@ -0,0 +1,8 @@ +use crate::prelude::*; +use sargon::SignedSubintent as InternalSignedSubintent; + +#[derive(Clone, PartialEq, Eq, InternalConversion, uniffi::Record)] +pub struct SignedSubintent { + pub subintent: Subintent, + pub subintent_signatures: IntentSignatures, +} diff --git a/crates/sargon-uniffi/src/wrapped_radix_engine_toolkit/low_level/v2/subintent.rs b/crates/sargon-uniffi/src/wrapped_radix_engine_toolkit/low_level/v2/subintent.rs index 7b0f09fcb..1cc24c2eb 100644 --- a/crates/sargon-uniffi/src/wrapped_radix_engine_toolkit/low_level/v2/subintent.rs +++ b/crates/sargon-uniffi/src/wrapped_radix_engine_toolkit/low_level/v2/subintent.rs @@ -3,7 +3,19 @@ use sargon::Subintent as InternalSubintent; #[derive(Clone, PartialEq, Eq, InternalConversion, uniffi::Record)] pub struct Subintent { - pub intent_core: IntentCoreV2, + pub header: IntentHeaderV2, + pub manifest: SubintentManifest, + pub message: MessageV2, +} + +#[uniffi::export] +pub fn new_subintent( + header: IntentHeaderV2, + manifest: SubintentManifest, + message: MessageV2, +) -> Result { + InternalSubintent::new(header.into(), manifest.into(), message.into()) + .into_result() } #[uniffi::export] diff --git a/crates/sargon-uniffi/src/wrapped_radix_engine_toolkit/low_level/v2/transaction_manifest_v2/child_intents.rs b/crates/sargon-uniffi/src/wrapped_radix_engine_toolkit/low_level/v2/transaction_manifest_v2/child_intents.rs deleted file mode 100644 index ce26be249..000000000 --- a/crates/sargon-uniffi/src/wrapped_radix_engine_toolkit/low_level/v2/transaction_manifest_v2/child_intents.rs +++ /dev/null @@ -1,14 +0,0 @@ -use crate::prelude::*; -use sargon::ChildIntents as InternalChildIntents; - -/// Represents a collection of child subintents. -/// -/// This struct is used to manage a list of `ChildSubintent` instances, providing -/// methods for creation, conversion, and sample values for testing purposes. -/// -/// # Fields -/// - `children`: A vector of `ChildSubintent` instances. -#[derive(Clone, PartialEq, Eq, InternalConversion, uniffi::Record)] -pub struct ChildIntents { - pub children: Vec, -} diff --git a/crates/sargon-uniffi/src/wrapped_radix_engine_toolkit/low_level/v2/transaction_manifest_v2/child_subintent.rs b/crates/sargon-uniffi/src/wrapped_radix_engine_toolkit/low_level/v2/transaction_manifest_v2/child_subintent.rs deleted file mode 100644 index 8f676524e..000000000 --- a/crates/sargon-uniffi/src/wrapped_radix_engine_toolkit/low_level/v2/transaction_manifest_v2/child_subintent.rs +++ /dev/null @@ -1,7 +0,0 @@ -use crate::prelude::*; -use sargon::ChildSubintent as InternalChildSubintent; - -#[derive(Clone, PartialEq, Eq, InternalConversion, uniffi::Record)] -pub struct ChildSubintent { - pub hash: SubintentHash, -} diff --git a/crates/sargon-uniffi/src/wrapped_radix_engine_toolkit/low_level/v2/transaction_manifest_v2/instructions_v2/instructions_v2.rs b/crates/sargon-uniffi/src/wrapped_radix_engine_toolkit/low_level/v2/transaction_manifest_v2/instructions_v2/instructions_v2.rs deleted file mode 100644 index 3d0847072..000000000 --- a/crates/sargon-uniffi/src/wrapped_radix_engine_toolkit/low_level/v2/transaction_manifest_v2/instructions_v2/instructions_v2.rs +++ /dev/null @@ -1,32 +0,0 @@ -use crate::prelude::*; -use sargon::InstructionsV2 as InternalInstructionsV2; - -#[derive(Clone, PartialEq, Eq, uniffi::Record)] -pub struct InstructionsV2 { - pub secret_magic: String, - pub network_id: NetworkID, -} - -impl InstructionsV2 { - pub fn into_internal(&self) -> InternalInstructionsV2 { - self.clone().into() - } -} - -impl From for InstructionsV2 { - fn from(value: InternalInstructionsV2) -> Self { - Self { - secret_magic: value.instructions_string(), - network_id: value.network_id.into(), - } - } -} - -impl From for InternalInstructionsV2 { - fn from(val: InstructionsV2) -> Self { - InternalInstructionsV2::new(val.secret_magic, val.network_id.into()) - .unwrap() - } -} - -decl_conversion_tests_for!(InstructionsV2); diff --git a/crates/sargon-uniffi/src/wrapped_radix_engine_toolkit/low_level/v2/transaction_manifest_v2/instructions_v2/mod.rs b/crates/sargon-uniffi/src/wrapped_radix_engine_toolkit/low_level/v2/transaction_manifest_v2/instructions_v2/mod.rs deleted file mode 100644 index 8320e0597..000000000 --- a/crates/sargon-uniffi/src/wrapped_radix_engine_toolkit/low_level/v2/transaction_manifest_v2/instructions_v2/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -mod instructions_v2; - -pub use instructions_v2::*; diff --git a/crates/sargon-uniffi/src/wrapped_radix_engine_toolkit/low_level/v2/transaction_manifest_v2/mod.rs b/crates/sargon-uniffi/src/wrapped_radix_engine_toolkit/low_level/v2/transaction_manifest_v2/mod.rs index 9fab7c24e..f76a6b2be 100644 --- a/crates/sargon-uniffi/src/wrapped_radix_engine_toolkit/low_level/v2/transaction_manifest_v2/mod.rs +++ b/crates/sargon-uniffi/src/wrapped_radix_engine_toolkit/low_level/v2/transaction_manifest_v2/mod.rs @@ -1,11 +1,5 @@ -mod child_intents; -mod child_subintent; -mod instructions_v2; mod subintent_manifest; mod transaction_manifest_v2; -pub use child_intents::*; -pub use child_subintent::*; -pub use instructions_v2::*; pub use subintent_manifest::*; pub use transaction_manifest_v2::*; diff --git a/crates/sargon/Cargo.toml b/crates/sargon/Cargo.toml index 245a5ee09..ad8b97f2f 100644 --- a/crates/sargon/Cargo.toml +++ b/crates/sargon/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "sargon" # Don't forget to update version in crates/sargon-uniffi/Cargo.toml -version = "1.1.42" +version = "1.1.43" edition = "2021" build = "build.rs" diff --git a/crates/sargon/src/core/types/keys/is_private_key.rs b/crates/sargon/src/core/types/keys/is_private_key.rs index 0e89c906c..71bbfbc99 100644 --- a/crates/sargon/src/core/types/keys/is_private_key.rs +++ b/crates/sargon/src/core/types/keys/is_private_key.rs @@ -24,6 +24,19 @@ pub trait IsPrivateKey>: Sized { tuple.into() } + fn sign_subintent_hash( + &self, + subintent_hash: &SubintentHash, + ) -> IntentSignature + where + (P, Self::Signature): Into, + { + let public_key: P = self.public_key(); + let signature = self.sign(&subintent_hash.hash); + let tuple: SignatureWithPublicKey = (public_key, signature).into(); + tuple.into() + } + fn notarize_hash( &self, signed_transaction_intent_hash: &SignedTransactionIntentHash, diff --git a/crates/sargon/src/radix_connect/wallet_interaction/dapp_wallet_interaction/wallet_to_dapp/success_response/pre_authorization/pre_authorization.rs b/crates/sargon/src/radix_connect/wallet_interaction/dapp_wallet_interaction/wallet_to_dapp/success_response/pre_authorization/pre_authorization.rs index 2096a3cde..7cd9abdec 100644 --- a/crates/sargon/src/radix_connect/wallet_interaction/dapp_wallet_interaction/wallet_to_dapp/success_response/pre_authorization/pre_authorization.rs +++ b/crates/sargon/src/radix_connect/wallet_interaction/dapp_wallet_interaction/wallet_to_dapp/success_response/pre_authorization/pre_authorization.rs @@ -9,28 +9,12 @@ pub struct WalletToDappInteractionPreAuthorizationResponseItems { } impl WalletToDappInteractionPreAuthorizationResponseItems { - pub fn new( - signed_partial_transaction: ScryptoSignedPartialTransaction, - ) -> Result { - let bytes = signed_partial_transaction - .to_raw() - .map_err(|e| match e { - sbor::EncodeError::MaxDepthExceeded(max) => { - CommonError::InvalidTransactionMaxSBORDepthExceeded { - max: max as u16, - } - } - _ => { - CommonError::InvalidSignedPartialTransactionFailedToEncode { - underlying: format!("{:?}", e), - } - } - })? - .to_vec(); + pub fn new(signed_subintent: SignedSubintent) -> Self { + let bytes = signed_subintent.compiled(); let encoded_signed_partial_transaction = hex_encode(&bytes); - Ok(Self { + Self { encoded_signed_partial_transaction, - }) + } } } @@ -38,14 +22,14 @@ impl HasSampleValues for WalletToDappInteractionPreAuthorizationResponseItems { fn sample() -> Self { Self { encoded_signed_partial_transaction: - "replace_actual_encoded_string_here".to_owned(), + "4d220e03210221012105210607010a872c0100000000000a912c01000000000022010105008306670000000022010105e8860667000000000a15cd5b070000000020200022010121020c0a746578742f706c61696e2200010c0c48656c6c6f205261646978212020002022054103800051c9a978fb5bfa066a3e5658251ee3304fb9bf58c35b61f8c10e0e7b91840c086c6f636b5f6665652101850000fda0c4277708000000000000000000000000000000004103800051c9a978fb5bfa066a3e5658251ee3304fb9bf58c35b61f8c10e0e7b91840c087769746864726177210280005da66318c6318c61f5a61b4c6318c6318cf794aa8d295f14e6318c6318c6850000443945309a7a48000000000000000000000000000000000280005da66318c6318c61f5a61b4c6318c6318cf794aa8d295f14e6318c6318c6850000443945309a7a480000000000000000000000000000004103800051ac224ee242c339b5ea5f1ae567f0520a6ffa24b52a10b8e6cd96a8347f0c147472795f6465706f7369745f6f725f61626f727421028100000000220000600121002021002022030001210120074101069ff73da4b2c861c340558d0d7ee44bfb8f221f4ba7f8d74a9e9d82c1acd2f951afd718faddb24a11062a508ad6edf31c519f88973688eaf04fc0cd944bebdc00012101200741007a324555c61268211c4dae7c63a5f94f3be523d7b0b93426685c8767d74907fb348775142bb6e1ac6d236acf795b672b7c94114e4198caec995d86d1327d5c060001210120074100fb65235bc47969a6b4421b8495641e9bec403103df5fa4ed7a123df0dc97f1734822bc9e609e00aa13698ba3227a61a8aff23fcc0f188eed9f29da155aa5c894202000".to_owned(), } } fn sample_other() -> Self { Self { encoded_signed_partial_transaction: - "replace_other_encoded_string_here".to_owned(), + "4d220e03210221012105210607f20a00000000000000000a0a000000000000002200002200000ab168de3a00000000202000220000202000202200202100202201000121012007410001598e989470d125dafac276b95bb1ba21e2ee8e0beb0547599335f83b48a0a830cd6a956a54421039cef5fb7e492ebaa315f751a2dd5b74bd9cebbda997ec12202000".to_owned(), } } } @@ -67,4 +51,11 @@ mod tests { fn inequality() { assert_ne!(SUT::sample(), SUT::sample_other()); } + + #[test] + fn new() { + let signed_subintent = SignedSubintent::sample(); + let sut = SUT::new(signed_subintent); + assert_eq!(sut, SUT::sample()); + } } diff --git a/crates/sargon/src/signing/signables/signable_subintent.rs b/crates/sargon/src/signing/signables/signable_subintent.rs index f408be56f..42bd48e4c 100644 --- a/crates/sargon/src/signing/signables/signable_subintent.rs +++ b/crates/sargon/src/signing/signables/signable_subintent.rs @@ -10,7 +10,7 @@ impl Signable for Subintent { &self, profile: &Profile, ) -> Result> { - let summary = self.intent_core.manifest.summary().unwrap(); + let summary = self.manifest.summary().unwrap(); ExtractorOfEntitiesRequiringAuth::extract(profile, summary) } @@ -22,7 +22,7 @@ impl Signable for Subintent { )>, network_id: Option, ) -> Self { - let mut builder = TransactionManifestV2Builder::new_v2(); + let mut builder = ScryptoSubintentManifestV2Builder::new_subintent_v2(); let network_id = network_id.unwrap_or_default(); for (address, hash) in all_addresses_with_hashes { @@ -33,7 +33,9 @@ impl Signable for Subintent { ); } - let manifest = TransactionManifestV2::sargon_built(builder, network_id); + builder = builder.yield_to_parent(()); + + let manifest = SubintentManifest::sargon_built(builder, network_id); Self::new(IntentHeaderV2::sample(), manifest, MessageV2::None).unwrap() } @@ -55,7 +57,7 @@ mod test { identities.clone(), ); - let summary = intent.intent_core.manifest.summary().unwrap(); + let summary = intent.manifest.summary().unwrap(); assert_eq!( accounts.iter().sorted().collect_vec(), diff --git a/crates/sargon/src/wrapped_radix_engine_toolkit/low_level/v1/transaction_manifest/instructions/instructions.rs b/crates/sargon/src/wrapped_radix_engine_toolkit/low_level/v1/transaction_manifest/instructions/instructions.rs index 6c175b1e0..69c0060e9 100644 --- a/crates/sargon/src/wrapped_radix_engine_toolkit/low_level/v1/transaction_manifest/instructions/instructions.rs +++ b/crates/sargon/src/wrapped_radix_engine_toolkit/low_level/v1/transaction_manifest/instructions/instructions.rs @@ -426,4 +426,10 @@ mod tests { }) ); } + + #[test] + fn test_man() { + let instructions = TransactionManifest::sample_other(); + instructions.summary().unwrap(); + } } diff --git a/crates/sargon/src/wrapped_radix_engine_toolkit/low_level/v2/compiled_subintent.rs b/crates/sargon/src/wrapped_radix_engine_toolkit/low_level/v2/compiled_subintent.rs index a67d8e0b5..623638ad2 100644 --- a/crates/sargon/src/wrapped_radix_engine_toolkit/low_level/v2/compiled_subintent.rs +++ b/crates/sargon/src/wrapped_radix_engine_toolkit/low_level/v2/compiled_subintent.rs @@ -90,7 +90,7 @@ mod tests { #[test] fn from_str() { assert_eq!( - "4d220b012105210607010a872c0100000000000a912c01000000000022010105008306670000000022010105e8860667000000000a15cd5b070000000020200022010121020c0a746578742f706c61696e2200010c0c48656c6c6f205261646978212020002022044103800051c9a978fb5bfa066a3e5658251ee3304fb9bf58c35b61f8c10e0e7b91840c086c6f636b5f6665652101850000fda0c4277708000000000000000000000000000000004103800051c9a978fb5bfa066a3e5658251ee3304fb9bf58c35b61f8c10e0e7b91840c087769746864726177210280005da66318c6318c61f5a61b4c6318c6318cf794aa8d295f14e6318c6318c6850000443945309a7a48000000000000000000000000000000000280005da66318c6318c61f5a61b4c6318c6318cf794aa8d295f14e6318c6318c6850000443945309a7a480000000000000000000000000000004103800051ac224ee242c339b5ea5f1ae567f0520a6ffa24b52a10b8e6cd96a8347f0c147472795f6465706f7369745f6f725f61626f727421028100000000220000".parse::().unwrap(), + "4d220b012105210607010a872c0100000000000a912c01000000000022010105008306670000000022010105e8860667000000000a15cd5b070000000020200022010121020c0a746578742f706c61696e2200010c0c48656c6c6f205261646978212020002022054103800051c9a978fb5bfa066a3e5658251ee3304fb9bf58c35b61f8c10e0e7b91840c086c6f636b5f6665652101850000fda0c4277708000000000000000000000000000000004103800051c9a978fb5bfa066a3e5658251ee3304fb9bf58c35b61f8c10e0e7b91840c087769746864726177210280005da66318c6318c61f5a61b4c6318c6318cf794aa8d295f14e6318c6318c6850000443945309a7a48000000000000000000000000000000000280005da66318c6318c61f5a61b4c6318c6318cf794aa8d295f14e6318c6318c6850000443945309a7a480000000000000000000000000000004103800051ac224ee242c339b5ea5f1ae567f0520a6ffa24b52a10b8e6cd96a8347f0c147472795f6465706f7369745f6f725f61626f72742102810000000022000060012100".parse::().unwrap(), SUT::sample() ); } diff --git a/crates/sargon/src/wrapped_radix_engine_toolkit/low_level/v2/intent_core_v2.rs b/crates/sargon/src/wrapped_radix_engine_toolkit/low_level/v2/intent_core_v2.rs deleted file mode 100644 index ce99f731f..000000000 --- a/crates/sargon/src/wrapped_radix_engine_toolkit/low_level/v2/intent_core_v2.rs +++ /dev/null @@ -1,197 +0,0 @@ -use crate::prelude::*; - -/// Represents the core of an intent in V2, including the header, manifest, and message. -#[derive(Clone, PartialEq, Eq, derive_more::Debug)] -#[debug("header:\n{:?}\n\nmessage:\n{:?}\n\nmanifest:\n{}\n\n", self.header, self.message, self.manifest.manifest_string())] -pub struct IntentCoreV2 { - pub header: IntentHeaderV2, - pub manifest: TransactionManifestV2, - pub message: MessageV2, -} - -impl IntentCoreV2 { - pub fn new( - header: IntentHeaderV2, - manifest: TransactionManifestV2, - message: MessageV2, - ) -> Self { - Self { - header, - manifest, - message, - } - } - - pub fn network_id(&self) -> NetworkID { - self.header.network_id - } - - pub fn manifest_string(&self) -> String { - self.manifest.manifest_string() - } - - pub fn blobs(&self) -> &Blobs { - &self.manifest.blobs - } -} - -impl From for ScryptoIntentCoreV2 { - fn from(value: IntentCoreV2) -> Self { - into_scrypto(&value.header, &value.manifest, &value.message) - } -} - -fn into_scrypto( - header: &IntentHeaderV2, - manifest: &TransactionManifestV2, - message: &MessageV2, -) -> ScryptoIntentCoreV2 { - ScryptoIntentCoreV2 { - header: (*header).into(), - blobs: manifest.blobs.clone().into(), - message: message.clone().into(), - children: manifest.children.clone().into(), - instructions: ScryptoInstructionsV2(manifest.instructions().clone()), - } -} - -impl TryFrom for IntentCoreV2 { - type Error = crate::CommonError; - - fn try_from(value: ScryptoIntentCoreV2) -> Result { - let message: MessageV2 = value.message.try_into()?; - let header: IntentHeaderV2 = value.header.try_into()?; - let network_id = header.network_id; - let instructions = InstructionsV2::try_from(( - value.instructions.0.as_ref(), - network_id, - ))?; - let blobs: Blobs = value.blobs.into(); - let children: ChildIntents = - (value.children.children, network_id).into(); - let manifest = - TransactionManifestV2::with_instructions_and_blobs_and_children( - instructions, - blobs, - children, - ); - - Ok(Self::new(header, manifest, message)) - } -} - -impl HasSampleValues for IntentCoreV2 { - fn sample() -> Self { - Self::new( - IntentHeaderV2::sample(), - TransactionManifestV2::sample(), - MessageV2::sample(), - ) - } - - fn sample_other() -> Self { - Self::new( - IntentHeaderV2::sample_other(), - TransactionManifestV2::empty(NetworkID::Simulator), - MessageV2::None, - ) - } -} - -#[cfg(test)] -impl IntentCoreV2 { - /// Utility function which uses `IntentCoreV2::new(, , )` - /// and SHOULD return `Err` if `depth > IntentCoreV2::MAX_SBOR_DEPTH`, which - /// we can assert in unit tests. - pub(crate) fn test_with_sbor_depth( - depth: usize, - network_id: NetworkID, - ) -> Result { - InstructionsV2::test_with_sbor_depth(depth, network_id) - .and_then(|instructions| { - TransactionManifestV2::new( - instructions.instructions_string(), - network_id, - Blobs::default(), - ChildIntents::empty(), - ) - }) - .map(|manifest| { - Self::new( - IntentHeaderV2::sample(), - manifest, - MessageV2::sample(), - ) - }) - } - - pub(crate) const MAX_SBOR_DEPTH: usize = InstructionsV2::MAX_SBOR_DEPTH; -} - -#[cfg(test)] -mod tests { - use super::*; - use radix_transactions::manifest::CallMethod; - use sbor::ValueKind as ScryptoValueKind; - - #[allow(clippy::upper_case_acronyms)] - type SUT = IntentCoreV2; - - #[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 manifest_string() { - let sut = SUT::sample(); - let manifest_string = SUT::sample().manifest_string(); - assert_eq!(manifest_string, sut.manifest.manifest_string()) - } - - #[test] - fn blobs() { - let sut = SUT::sample(); - assert_eq!(sut.blobs().clone(), Blobs::default()); - } - - #[test] - fn network_id() { - assert_eq!(SUT::sample().network_id(), NetworkID::Mainnet); - assert_eq!(SUT::sample_other().network_id(), NetworkID::Simulator); - } - - #[test] - fn to_from_scrypto() { - let roundtrip = - |s: SUT| SUT::try_from(ScryptoIntentCoreV2::from(s)).unwrap(); - roundtrip(SUT::sample()); - roundtrip(SUT::sample_other()); - } - - #[test] - fn intent_with_max_sbor_depth_is_ok() { - let sut = - SUT::test_with_sbor_depth(SUT::MAX_SBOR_DEPTH, NetworkID::Stokenet); - assert!(sut.is_ok()); - } - - #[test] - fn intent_with_sbor_depth_greater_than_max_is_err() { - assert_eq!( - SUT::test_with_sbor_depth( - SUT::MAX_SBOR_DEPTH + 1, - NetworkID::Stokenet - ), - Err(CommonError::InvalidTransactionMaxSBORDepthExceeded { - max: 20_u16 - }) - ); - } -} diff --git a/crates/sargon/src/wrapped_radix_engine_toolkit/low_level/v2/intent_signatures_v2.rs b/crates/sargon/src/wrapped_radix_engine_toolkit/low_level/v2/intent_signatures_v2.rs deleted file mode 100644 index daf20e388..000000000 --- a/crates/sargon/src/wrapped_radix_engine_toolkit/low_level/v2/intent_signatures_v2.rs +++ /dev/null @@ -1,141 +0,0 @@ -use crate::prelude::*; - -#[derive(Clone, Debug, PartialEq, Eq, Default, Hash)] -pub struct IntentSignaturesV2 { - pub signatures: Vec, -} - -impl IntentSignaturesV2 { - pub fn new(signatures: I) -> Self - where - I: IntoIterator, - { - Self { - signatures: signatures.into_iter().collect(), - } - } - - pub fn validate(&self, hash: impl Into) -> bool { - let hash = hash.into(); - - self.signatures.iter().all(|s| s.validate(hash)) - } -} - -impl From for ScryptoIntentSignaturesV2 { - fn from(value: IntentSignaturesV2) -> Self { - Self { - signatures: value - .signatures - .into_iter() - .map(|s| s.into()) - .collect(), - } - } -} - -impl TryFrom<(ScryptoIntentSignaturesV2, Hash)> for IntentSignaturesV2 { - type Error = crate::CommonError; - - fn try_from( - value: (ScryptoIntentSignaturesV2, Hash), - ) -> Result { - value - .clone() - .0 - .signatures - .into_iter() - .map(|s| { - TryInto::::try_into((s, value.1.to_owned())) - }) - .collect::>>() - .map(|signatures| Self { signatures }) - } -} - -impl HasSampleValues for IntentSignaturesV2 { - fn sample() -> Self { - let intent = Subintent::sample(); - let mut signatures = Vec::::new(); - for n in 1..4 { - let private_key: Secp256k1PrivateKey = - ScryptoSecp256k1PrivateKey::from_u64(n).unwrap().into(); - - signatures.push(private_key.sign_transaction_intent_hash( - &TransactionIntentHash::new( - intent.hash().hash, - intent.network_id(), - ), - )) - } - - IntentSignaturesV2::new(signatures) - } - - fn sample_other() -> Self { - let intent = Subintent::sample_other(); - let mut signatures = Vec::::new(); - for n in 1..4 { - let private_key: Secp256k1PrivateKey = - ScryptoSecp256k1PrivateKey::from_u64(n).unwrap().into(); - - signatures.push(private_key.sign_transaction_intent_hash( - &TransactionIntentHash::new( - intent.hash().hash, - intent.network_id(), - ), - )) - } - - IntentSignaturesV2::new(signatures) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[allow(clippy::upper_case_acronyms)] - type SUT = IntentSignaturesV2; - - #[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_validate() { - let valid_hash = SignatureWithPublicKey::sample_hash(); - let invalid_hash = Hash::sample(); - let valid_signature = IntentSignature::sample(); - let valid_signatures = IntentSignaturesV2::new(vec![valid_signature]); - - assert!(valid_signatures.validate(valid_hash)); - assert!(!valid_signatures.validate(invalid_hash)); - } - - #[test] - fn to_from_scrypto() { - let roundtrip = |s: SUT, hash: Hash| { - let scrypto: ScryptoIntentSignaturesV2 = s.clone().into(); - SUT::try_from((scrypto, hash)).unwrap() - }; - assert_eq!( - SUT::sample(), - roundtrip(SUT::sample(), Subintent::sample().hash().hash) - ); - assert_eq!( - SUT::sample_other(), - roundtrip( - SUT::sample_other(), - Subintent::sample_other().hash().hash - ) - ); - } -} diff --git a/crates/sargon/src/wrapped_radix_engine_toolkit/low_level/v2/mod.rs b/crates/sargon/src/wrapped_radix_engine_toolkit/low_level/v2/mod.rs index 54ce9f2c0..7c71049ad 100644 --- a/crates/sargon/src/wrapped_radix_engine_toolkit/low_level/v2/mod.rs +++ b/crates/sargon/src/wrapped_radix_engine_toolkit/low_level/v2/mod.rs @@ -1,17 +1,15 @@ mod compiled_subintent; -mod intent_core_v2; mod intent_header_v2; -mod intent_signatures_v2; mod message_v2; mod signed_partial_transaction; +mod signed_subintent; mod subintent; mod transaction_manifest_v2; pub use compiled_subintent::*; -pub use intent_core_v2::*; pub use intent_header_v2::*; -pub use intent_signatures_v2::*; pub use message_v2::*; pub use signed_partial_transaction::*; +pub use signed_subintent::*; pub use subintent::*; pub use transaction_manifest_v2::*; diff --git a/crates/sargon/src/wrapped_radix_engine_toolkit/low_level/v2/signed_partial_transaction.rs b/crates/sargon/src/wrapped_radix_engine_toolkit/low_level/v2/signed_partial_transaction.rs index 8beaaac5c..d472aa89a 100644 --- a/crates/sargon/src/wrapped_radix_engine_toolkit/low_level/v2/signed_partial_transaction.rs +++ b/crates/sargon/src/wrapped_radix_engine_toolkit/low_level/v2/signed_partial_transaction.rs @@ -1,17 +1,17 @@ use crate::prelude::*; pub fn build_signed_partial_transaction( - intent_core: IntentCoreV2, - signatures: IntentSignaturesV2, + subintent: Subintent, + signatures: Vec, ) -> ScryptoSignedPartialTransaction { ScryptoSignedPartialTransaction { partial_transaction: ScryptoPartialTransaction { - root_subintent: ScryptoSubintent { - intent_core: intent_core.into(), - }, + root_subintent: ScryptoSubintent::from(subintent), non_root_subintents: ScryptoNonRootSubintents(vec![]), }, - root_subintent_signatures: signatures.into(), + root_subintent_signatures: ScryptoIntentSignaturesV2 { + signatures: signatures.into_iter().map(|s| s.into()).collect(), + }, non_root_subintent_signatures: ScryptoNonRootSubintentSignatures { by_subintent: vec![], }, diff --git a/crates/sargon/src/wrapped_radix_engine_toolkit/low_level/v2/signed_subintent.rs b/crates/sargon/src/wrapped_radix_engine_toolkit/low_level/v2/signed_subintent.rs new file mode 100644 index 000000000..29bfe4766 --- /dev/null +++ b/crates/sargon/src/wrapped_radix_engine_toolkit/low_level/v2/signed_subintent.rs @@ -0,0 +1,209 @@ +use crate::prelude::*; + +#[derive(Clone, PartialEq, Eq, derive_more::Debug)] +pub struct SignedSubintent { + pub subintent: Subintent, + pub subintent_signatures: IntentSignatures, +} + +impl SignedSubintent { + pub fn new( + subintent: Subintent, + subintent_signatures: IntentSignatures, + ) -> Result { + if !subintent_signatures.validate(subintent.hash()) { + return Err(CommonError::InvalidSignaturesForIntentSomeDidNotValidateIntentHash); + } + + // Verify that this SignedSubintent has acceptable depth and is compatible + _ = compile_signed_subintent_with(&subintent, &subintent_signatures)?; + + Ok(Self { + subintent, + subintent_signatures, + }) + } + + pub fn compiled(&self) -> Vec { + compile_signed_subintent_with( + &self.subintent, + &self.subintent_signatures, + ) + .expect("Compiling after initialization is always valid") + } +} + +fn into_scrypto( + subintent: &Subintent, + subintent_signatures: &IntentSignatures, +) -> ScryptoSignedPartialTransaction { + ScryptoSignedPartialTransaction { + partial_transaction: ScryptoPartialTransaction { + root_subintent: ScryptoSubintent::from(subintent.clone()), + non_root_subintents: ScryptoNonRootSubintents(vec![]), + }, + root_subintent_signatures: ScryptoIntentSignaturesV2 { + signatures: subintent_signatures + .clone() + .signatures + .into_iter() + .map(|s| s.into()) + .collect(), + }, + non_root_subintent_signatures: ScryptoNonRootSubintentSignatures { + by_subintent: vec![], + }, + } +} + +fn compile_signed_subintent_with( + subintent: &Subintent, + subintent_signatures: &IntentSignatures, +) -> Result> { + compile_signed_subintent(into_scrypto(subintent, subintent_signatures)) +} + +fn compile_signed_subintent( + signed_partial_transaction: ScryptoSignedPartialTransaction, +) -> Result> { + RET_compile_signed_partial_tx(&signed_partial_transaction).map_err(|e| { + match e { + sbor::EncodeError::MaxDepthExceeded(max) => { + CommonError::InvalidTransactionMaxSBORDepthExceeded { + max: max as u16, + } + } + _ => CommonError::InvalidSignedIntentFailedToEncode { + underlying: format!("{:?}", e), + }, + } + }) +} + +impl From for ScryptoSignedPartialTransaction { + fn from(val: SignedSubintent) -> Self { + into_scrypto(&val.subintent, &val.subintent_signatures) + } +} + +impl HasSampleValues for SignedSubintent { + fn sample() -> Self { + let intent = Subintent::sample(); + + let mut signatures = Vec::::new(); + for n in 1..4 { + let private_key: Secp256k1PrivateKey = + ScryptoSecp256k1PrivateKey::from_u64(n).unwrap().into(); + + let intent_signature = + private_key.sign_subintent_hash(&intent.hash()); + signatures.push(intent_signature) + } + + let intent_signatures = IntentSignatures::new(signatures); + + Self::new(intent, intent_signatures).unwrap() + } + + fn sample_other() -> Self { + Self::new(Subintent::sample_other(), IntentSignatures::default()) + .unwrap() + } +} + +#[cfg(test)] +mod tests { + + use super::*; + use crate::prelude::*; + + #[allow(clippy::upper_case_acronyms)] + type SUT = SignedSubintent; + + #[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 many_intent_signatures_all_valid() { + let intent = Subintent::sample_other(); + + let mut signatures = Vec::::new(); + for n in 1..4 { + let private_key: Secp256k1PrivateKey = + ScryptoSecp256k1PrivateKey::from_u64(n).unwrap().into(); + + let intent_signature = + private_key.sign_subintent_hash(&intent.hash()); + signatures.push(intent_signature) + } + + let intent_signatures = IntentSignatures::new(signatures); + assert_eq!( + intent_signatures.clone().signatures.into_iter().map(|s| s.signature().to_string()).collect_vec(), + [ + "014f6e14706f07aaa632ed83a4df6ee76c3bfb0693af6bd0c010a49dd2071b1c910c26143e501f7cca5c7aba6e8db8b4221a0a9b3703d38a20257fdbb38eb2920e", + "00c23163dd81b1648d101b69c571bc0cad9e9da3ac9309f1dc0f40b01c02fb17dc5b77a2bd569f98fea088c419cd9d3b1a27f094817da6b08f420d9d36777b0b84", + "00d50da65a9423f14bfda39589c8ccd1cce7c191e064918a92b82891e8e7aaa4853ede0a8ce659ce63f5c0160f72b34b77ca52ba7b519db48da51f7bd8f470ae6e", + ] + ); + + assert_eq!( + SUT::new(intent, intent_signatures.clone()) + .unwrap() + .subintent_signatures, + intent_signatures + ); + } + + #[test] + fn many_intent_signatures_one_invalid() { + let intent = Subintent::sample_other(); + + let mut signatures = Vec::::new(); + for n in 1..4 { + let private_key: Secp256k1PrivateKey = + ScryptoSecp256k1PrivateKey::from_u64(n).unwrap().into(); + + let intent_signature = + private_key.sign_subintent_hash(&intent.hash()); + signatures.push(intent_signature) + } + + signatures.push(IntentSignature::sample()); + + assert_eq!( + SUT::new(intent, IntentSignatures::new(signatures)), + Err(CommonError::InvalidSignaturesForIntentSomeDidNotValidateIntentHash) + ); + } + + #[test] + fn many_intent_signatures_invalid_because_mismatching_intent() { + let intent = Subintent::sample_other(); + + let mut signatures = Vec::::new(); + for n in 1..4 { + let private_key: Secp256k1PrivateKey = + ScryptoSecp256k1PrivateKey::from_u64(n).unwrap().into(); + let hash = intent.hash(); + let intent_signature = private_key.sign_subintent_hash(&hash); + signatures.push(intent_signature) + } + + assert_eq!( + SUT::new( + Subintent::sample(), // <-- WRONG Intent, not was signed. + IntentSignatures::new(signatures) + ), + Err(CommonError::InvalidSignaturesForIntentSomeDidNotValidateIntentHash) + ); + } +} diff --git a/crates/sargon/src/wrapped_radix_engine_toolkit/low_level/v2/subintent.rs b/crates/sargon/src/wrapped_radix_engine_toolkit/low_level/v2/subintent.rs index d048ec0fb..f04ad375d 100644 --- a/crates/sargon/src/wrapped_radix_engine_toolkit/low_level/v2/subintent.rs +++ b/crates/sargon/src/wrapped_radix_engine_toolkit/low_level/v2/subintent.rs @@ -3,20 +3,24 @@ use delegate::delegate; use std::hash::Hasher; #[derive(Clone, PartialEq, Eq, derive_more::Debug)] -#[debug("{:?}", self.intent_core)] +#[debug("header:\n{:?}\n\nmessage:\n{:?}\n\nmanifest:\n{}\n\n", self.header, self.message, self.manifest.manifest_string())] pub struct Subintent { - pub intent_core: IntentCoreV2, + pub header: IntentHeaderV2, + pub manifest: SubintentManifest, + pub message: MessageV2, } impl Subintent { pub fn new( header: IntentHeaderV2, - manifest: TransactionManifestV2, + manifest: SubintentManifest, message: MessageV2, ) -> Result { _ = compile_intent_with(&header, &manifest, &message)?; Ok(Self { - intent_core: IntentCoreV2::new(header, manifest, message), + header, + manifest, + message, }) } @@ -29,11 +33,23 @@ impl Subintent { self.network_id(), ) } + + pub fn network_id(&self) -> NetworkID { + self.header.network_id + } + + pub fn manifest_string(&self) -> String { + self.manifest.manifest_string() + } + + pub fn blobs(&self) -> &Blobs { + &self.manifest.blobs + } } fn into_scrypto( header: &IntentHeaderV2, - manifest: &TransactionManifestV2, + manifest: &SubintentManifest, message: &MessageV2, ) -> ScryptoSubintent { ScryptoSubintent { @@ -51,7 +67,7 @@ fn into_scrypto( fn compile_intent_with( header: &IntentHeaderV2, - manifest: &TransactionManifestV2, + manifest: &SubintentManifest, message: &MessageV2, ) -> Result { compile_intent(into_scrypto(header, manifest, message)) @@ -67,9 +83,7 @@ fn compile_intent(scrypto_intent: ScryptoSubintent) -> Result { impl From for ScryptoSubintent { fn from(value: Subintent) -> Self { - ScryptoSubintent { - intent_core: value.intent_core.into(), - } + into_scrypto(&value.header, &value.manifest, &value.message) } } @@ -83,8 +97,8 @@ impl TryFrom for Subintent { NetworkID::try_from(value.intent_core.header.network_id)?; let manifest = - TryFrom::<(ScryptoTransactionManifestV2, NetworkID)>::try_from(( - ScryptoTransactionManifestV2::from_intent_core( + TryFrom::<(ScryptoSubintentManifestV2, NetworkID)>::try_from(( + ScryptoSubintentManifestV2::from_intent_core( &value.intent_core, ), network_id, @@ -105,21 +119,11 @@ impl std::hash::Hash for Subintent { } } -impl Subintent { - delegate! { - to self.intent_core{ - pub fn network_id(&self) -> NetworkID; - pub fn manifest_string(&self) -> String; - pub fn blobs(&self) -> &Blobs; - } - } -} - impl HasSampleValues for Subintent { fn sample() -> Self { Self::new( IntentHeaderV2::sample(), - TransactionManifestV2::sample(), + SubintentManifest::sample(), MessageV2::sample(), ) .unwrap() @@ -128,7 +132,7 @@ impl HasSampleValues for Subintent { fn sample_other() -> Self { Self::new( IntentHeaderV2::sample_other(), - TransactionManifestV2::empty(NetworkID::Simulator), + SubintentManifest::empty(NetworkID::Simulator), MessageV2::None, ) .unwrap() @@ -159,12 +163,33 @@ mod tests { #[test] fn compile() { - assert_eq!(SUT::sample().compile().to_string(), "4d220b012105210607010a872c0100000000000a912c01000000000022010105008306670000000022010105e8860667000000000a15cd5b070000000020200022010121020c0a746578742f706c61696e2200010c0c48656c6c6f205261646978212020002022044103800051c9a978fb5bfa066a3e5658251ee3304fb9bf58c35b61f8c10e0e7b91840c086c6f636b5f6665652101850000fda0c4277708000000000000000000000000000000004103800051c9a978fb5bfa066a3e5658251ee3304fb9bf58c35b61f8c10e0e7b91840c087769746864726177210280005da66318c6318c61f5a61b4c6318c6318cf794aa8d295f14e6318c6318c6850000443945309a7a48000000000000000000000000000000000280005da66318c6318c61f5a61b4c6318c6318cf794aa8d295f14e6318c6318c6850000443945309a7a480000000000000000000000000000004103800051ac224ee242c339b5ea5f1ae567f0520a6ffa24b52a10b8e6cd96a8347f0c147472795f6465706f7369745f6f725f61626f727421028100000000220000"); + assert_eq!(SUT::sample().compile().to_string(), "4d220b012105210607010a872c0100000000000a912c01000000000022010105008306670000000022010105e8860667000000000a15cd5b070000000020200022010121020c0a746578742f706c61696e2200010c0c48656c6c6f205261646978212020002022054103800051c9a978fb5bfa066a3e5658251ee3304fb9bf58c35b61f8c10e0e7b91840c086c6f636b5f6665652101850000fda0c4277708000000000000000000000000000000004103800051c9a978fb5bfa066a3e5658251ee3304fb9bf58c35b61f8c10e0e7b91840c087769746864726177210280005da66318c6318c61f5a61b4c6318c6318cf794aa8d295f14e6318c6318c6850000443945309a7a48000000000000000000000000000000000280005da66318c6318c61f5a61b4c6318c6318cf794aa8d295f14e6318c6318c6850000443945309a7a480000000000000000000000000000004103800051ac224ee242c339b5ea5f1ae567f0520a6ffa24b52a10b8e6cd96a8347f0c147472795f6465706f7369745f6f725f61626f72742102810000000022000060012100"); } #[test] fn subintent_hash() { let hash = SUT::sample().hash(); - assert_eq!(hash.to_string(), "subtxid_rdx1e95452vfay89t46gtw2jgfagw6p9uee3m2harsppwdhzprdjn8vsmkg88c") + assert_eq!(hash.to_string(), "subtxid_rdx1xput628m2l7jjweefd70gnq3t3a5x2gjeljduwm7vwly94s8ullql92sa0") + } + + #[test] + fn network_id() { + assert_eq!(SUT::sample().network_id(), NetworkID::Mainnet); + } + + #[test] + fn manifest_string() { + assert_eq!( + SUT::sample().manifest_string(), + "CALL_METHOD\n Address(\"account_rdx128y6j78mt0aqv6372evz28hrxp8mn06ccddkr7xppc88hyvynvjdwr\")\n \"lock_fee\"\n Decimal(\"0.61\")\n;\nCALL_METHOD\n Address(\"account_rdx128y6j78mt0aqv6372evz28hrxp8mn06ccddkr7xppc88hyvynvjdwr\")\n \"withdraw\"\n Address(\"resource_rdx1tknxxxxxxxxxradxrdxxxxxxxxx009923554798xxxxxxxxxradxrd\")\n Decimal(\"1337\")\n;\nTAKE_FROM_WORKTOP\n Address(\"resource_rdx1tknxxxxxxxxxradxrdxxxxxxxxx009923554798xxxxxxxxxradxrd\")\n Decimal(\"1337\")\n Bucket(\"bucket1\")\n;\nCALL_METHOD\n Address(\"account_rdx12xkzynhzgtpnnd02tudw2els2g9xl73yk54ppw8xekt2sdrlaer264\")\n \"try_deposit_or_abort\"\n Bucket(\"bucket1\")\n Enum<0u8>()\n;\nYIELD_TO_PARENT;\n" + ); + } + + #[test] + fn to_from_scrypto() { + let roundtrip = + |s: SUT| SUT::try_from(ScryptoSubintent::from(s)).unwrap(); + roundtrip(SUT::sample()); + roundtrip(SUT::sample_other()); } } diff --git a/jvm/sargon-android/src/main/java/com/radixdlt/sargon/extensions/CompiledSubintent.kt b/jvm/sargon-android/src/main/java/com/radixdlt/sargon/extensions/CompiledSubintent.kt new file mode 100644 index 000000000..479ce92c6 --- /dev/null +++ b/jvm/sargon-android/src/main/java/com/radixdlt/sargon/extensions/CompiledSubintent.kt @@ -0,0 +1,13 @@ +package com.radixdlt.sargon.extensions + +import com.radixdlt.sargon.BagOfBytes +import com.radixdlt.sargon.CompiledSubintent +import com.radixdlt.sargon.Subintent +import com.radixdlt.sargon.compiledSubintentBytes +import com.radixdlt.sargon.compiledSubintentDecompile + +fun CompiledSubintent.decompile(): Subintent = + compiledSubintentDecompile(compiledIntent = this) + +val CompiledSubintent.bytes: BagOfBytes + get() = compiledSubintentBytes(compiledIntent = this) \ No newline at end of file diff --git a/jvm/sargon-android/src/main/java/com/radixdlt/sargon/samples/CompiledSubintentSample.kt b/jvm/sargon-android/src/main/java/com/radixdlt/sargon/samples/CompiledSubintentSample.kt new file mode 100644 index 000000000..c2f04be19 --- /dev/null +++ b/jvm/sargon-android/src/main/java/com/radixdlt/sargon/samples/CompiledSubintentSample.kt @@ -0,0 +1,14 @@ +package com.radixdlt.sargon.samples + +import com.radixdlt.sargon.CompiledSubintent +import com.radixdlt.sargon.annotation.UsesSampleValues +import com.radixdlt.sargon.newCompiledSubintentSample +import com.radixdlt.sargon.newCompiledSubintentSampleOther + +@UsesSampleValues +val CompiledSubintent.Companion.sample + get() = object : Sample { + override fun invoke(): CompiledSubintent = newCompiledSubintentSample() + + override fun other(): CompiledSubintent = newCompiledSubintentSampleOther() + } \ No newline at end of file diff --git a/jvm/sargon-android/src/test/java/com/radixdlt/sargon/CompiledSubintentTest.kt b/jvm/sargon-android/src/test/java/com/radixdlt/sargon/CompiledSubintentTest.kt new file mode 100644 index 000000000..19dac2869 --- /dev/null +++ b/jvm/sargon-android/src/test/java/com/radixdlt/sargon/CompiledSubintentTest.kt @@ -0,0 +1,32 @@ +package com.radixdlt.sargon + +import com.radixdlt.sargon.extensions.bytes +import com.radixdlt.sargon.extensions.compile +import com.radixdlt.sargon.extensions.decompile +import com.radixdlt.sargon.extensions.hex +import com.radixdlt.sargon.samples.Sample +import com.radixdlt.sargon.samples.sample +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Test + +class CompiledSubintentTest: SampleTestable { + override val samples: List> + get() = listOf(CompiledSubintent.sample) + + @Test + fun testDecompile() { + val expectedSubintent = Subintent.sample() + assertEquals( + expectedSubintent, + expectedSubintent.compile().decompile() + ) + } + + @Test + fun testBytes() { + assertEquals( + CompiledSubintent.sample().bytes.hex, + "4d220b012105210607010a872c0100000000000a912c01000000000022010105008306670000000022010105e8860667000000000a15cd5b070000000020200022010121020c0a746578742f706c61696e2200010c0c48656c6c6f205261646978212020002022054103800051c9a978fb5bfa066a3e5658251ee3304fb9bf58c35b61f8c10e0e7b91840c086c6f636b5f6665652101850000fda0c4277708000000000000000000000000000000004103800051c9a978fb5bfa066a3e5658251ee3304fb9bf58c35b61f8c10e0e7b91840c087769746864726177210280005da66318c6318c61f5a61b4c6318c6318cf794aa8d295f14e6318c6318c6850000443945309a7a48000000000000000000000000000000000280005da66318c6318c61f5a61b4c6318c6318cf794aa8d295f14e6318c6318c6850000443945309a7a480000000000000000000000000000004103800051ac224ee242c339b5ea5f1ae567f0520a6ffa24b52a10b8e6cd96a8347f0c147472795f6465706f7369745f6f725f61626f72742102810000000022000060012100" + ) + } +} \ No newline at end of file