From 244f5f902d6220de9fa3f6e7e60cf4c8c22ed524 Mon Sep 17 00:00:00 2001 From: QuantumExplorer Date: Tue, 29 Oct 2024 19:38:54 +0700 Subject: [PATCH] feat(sdk): added transfer transition to rs-sdk (#2289) --- .../methods/mod.rs | 54 ++++++++++++- .../methods/v0/mod.rs | 24 ++++++ .../v0/v0_methods.rs | 78 ++++++++++++++++++- .../mod.rs | 1 + .../v1.rs | 1 + .../v2.rs | 1 + packages/rs-sdk/src/platform/transition.rs | 1 + .../src/platform/transition/transfer.rs | 67 ++++++++++++++++ 8 files changed, 224 insertions(+), 3 deletions(-) create mode 100644 packages/rs-sdk/src/platform/transition/transfer.rs diff --git a/packages/rs-dpp/src/state_transition/state_transitions/identity/identity_credit_transfer_transition/methods/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/identity/identity_credit_transfer_transition/methods/mod.rs index 2bea2328d7..43790f371d 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/identity/identity_credit_transfer_transition/methods/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/identity/identity_credit_transfer_transition/methods/mod.rs @@ -1,7 +1,57 @@ mod v0; - pub use v0::*; use crate::state_transition::identity_credit_transfer_transition::IdentityCreditTransferTransition; +#[cfg(feature = "state-transition-signing")] +use crate::{ + identity::{signer::Signer, Identity, IdentityPublicKey}, + prelude::{IdentityNonce, UserFeeIncrease}, + state_transition::{ + identity_credit_transfer_transition::v0::IdentityCreditTransferTransitionV0, + StateTransition, + }, + ProtocolError, +}; +#[cfg(feature = "state-transition-signing")] +use platform_value::Identifier; +#[cfg(feature = "state-transition-signing")] +use platform_version::version::{FeatureVersion, PlatformVersion}; -impl IdentityCreditTransferTransitionMethodsV0 for IdentityCreditTransferTransition {} +impl IdentityCreditTransferTransitionMethodsV0 for IdentityCreditTransferTransition { + #[cfg(feature = "state-transition-signing")] + fn try_from_identity( + identity: &Identity, + to_identity_with_identifier: Identifier, + amount: u64, + user_fee_increase: UserFeeIncrease, + signer: S, + signing_withdrawal_key_to_use: Option<&IdentityPublicKey>, + nonce: IdentityNonce, + platform_version: &PlatformVersion, + version: Option, + ) -> Result { + match version.unwrap_or( + platform_version + .dpp + .state_transition_conversion_versions + .identity_to_identity_transfer_transition, + ) { + 0 => Ok(IdentityCreditTransferTransitionV0::try_from_identity( + identity, + to_identity_with_identifier, + amount, + user_fee_increase, + signer, + signing_withdrawal_key_to_use, + nonce, + platform_version, + version, + )?), + version => Err(ProtocolError::UnknownVersionMismatch { + method: "IdentityCreditTransferTransition::try_from_identity".to_string(), + known_versions: vec![0], + received: version, + }), + } + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/identity/identity_credit_transfer_transition/methods/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/identity/identity_credit_transfer_transition/methods/v0/mod.rs index caa6ad6560..eeb7104420 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/identity/identity_credit_transfer_transition/methods/v0/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/identity/identity_credit_transfer_transition/methods/v0/mod.rs @@ -1,6 +1,30 @@ +#[cfg(feature = "state-transition-signing")] +use crate::{ + identity::{signer::Signer, Identity, IdentityPublicKey}, + prelude::{IdentityNonce, UserFeeIncrease}, + state_transition::StateTransition, + ProtocolError, +}; +use platform_value::Identifier; +#[cfg(feature = "state-transition-signing")] +use platform_version::version::{FeatureVersion, PlatformVersion}; + use crate::state_transition::StateTransitionType; pub trait IdentityCreditTransferTransitionMethodsV0 { + #[cfg(feature = "state-transition-signing")] + fn try_from_identity( + identity: &Identity, + to_identity_with_identifier: Identifier, + amount: u64, + user_fee_increase: UserFeeIncrease, + signer: S, + signing_withdrawal_key_to_use: Option<&IdentityPublicKey>, + nonce: IdentityNonce, + platform_version: &PlatformVersion, + version: Option, + ) -> Result; + /// Get State Transition Type fn get_type() -> StateTransitionType { StateTransitionType::IdentityCreditTransfer diff --git a/packages/rs-dpp/src/state_transition/state_transitions/identity/identity_credit_transfer_transition/v0/v0_methods.rs b/packages/rs-dpp/src/state_transition/state_transitions/identity/identity_credit_transfer_transition/v0/v0_methods.rs index 0060a25a2c..e04e061f67 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/identity/identity_credit_transfer_transition/v0/v0_methods.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/identity/identity_credit_transfer_transition/v0/v0_methods.rs @@ -1,4 +1,80 @@ +#[cfg(feature = "state-transition-signing")] +use crate::{ + identity::{ + accessors::IdentityGettersV0, signer::Signer, Identity, IdentityPublicKey, KeyType, + Purpose, SecurityLevel, + }, + prelude::{IdentityNonce, UserFeeIncrease}, + state_transition::StateTransition, + ProtocolError, +}; +use platform_value::Identifier; + use crate::state_transition::identity_credit_transfer_transition::methods::IdentityCreditTransferTransitionMethodsV0; use crate::state_transition::identity_credit_transfer_transition::v0::IdentityCreditTransferTransitionV0; +use crate::state_transition::GetDataContractSecurityLevelRequirementFn; +#[cfg(feature = "state-transition-signing")] +use platform_version::version::{FeatureVersion, PlatformVersion}; + +impl IdentityCreditTransferTransitionMethodsV0 for IdentityCreditTransferTransitionV0 { + #[cfg(feature = "state-transition-signing")] + fn try_from_identity( + identity: &Identity, + to_identity_with_identifier: Identifier, + amount: u64, + user_fee_increase: UserFeeIncrease, + signer: S, + signing_withdrawal_key_to_use: Option<&IdentityPublicKey>, + nonce: IdentityNonce, + _platform_version: &PlatformVersion, + _version: Option, + ) -> Result { + let mut transition: StateTransition = IdentityCreditTransferTransitionV0 { + identity_id: identity.id(), + recipient_id: to_identity_with_identifier, + amount, + nonce, + user_fee_increase, + signature_public_key_id: 0, + signature: Default::default(), + } + .into(); + + let identity_public_key = match signing_withdrawal_key_to_use { + Some(key) => { + if signer.can_sign_with(key) { + key + } else { + return Err( + ProtocolError::DesiredKeyWithTypePurposeSecurityLevelMissing( + "specified transfer public key cannot be used for signing".to_string(), + ), + ); + } + } + None => { + let key = identity + .get_first_public_key_matching( + Purpose::TRANSFER, + SecurityLevel::full_range().into(), + KeyType::all_key_types().into(), + true, + ) + .ok_or_else(|| { + ProtocolError::DesiredKeyWithTypePurposeSecurityLevelMissing( + "no transfer public key".to_string(), + ) + })?; + key + } + }; + + transition.sign_external( + identity_public_key, + &signer, + None::, + )?; -impl IdentityCreditTransferTransitionMethodsV0 for IdentityCreditTransferTransitionV0 {} + Ok(transition) + } +} diff --git a/packages/rs-platform-version/src/version/dpp_versions/dpp_state_transition_conversion_versions/mod.rs b/packages/rs-platform-version/src/version/dpp_versions/dpp_state_transition_conversion_versions/mod.rs index 4c2e0a22a3..74d2b39661 100644 --- a/packages/rs-platform-version/src/version/dpp_versions/dpp_state_transition_conversion_versions/mod.rs +++ b/packages/rs-platform-version/src/version/dpp_versions/dpp_state_transition_conversion_versions/mod.rs @@ -7,6 +7,7 @@ pub mod v2; pub struct DPPStateTransitionConversionVersions { pub identity_to_identity_create_transition: FeatureVersion, pub identity_to_identity_top_up_transition: FeatureVersion, + pub identity_to_identity_transfer_transition: FeatureVersion, pub identity_to_identity_withdrawal_transition: FeatureVersion, pub identity_to_identity_create_transition_with_signer: FeatureVersion, } diff --git a/packages/rs-platform-version/src/version/dpp_versions/dpp_state_transition_conversion_versions/v1.rs b/packages/rs-platform-version/src/version/dpp_versions/dpp_state_transition_conversion_versions/v1.rs index d465374250..a6ce094346 100644 --- a/packages/rs-platform-version/src/version/dpp_versions/dpp_state_transition_conversion_versions/v1.rs +++ b/packages/rs-platform-version/src/version/dpp_versions/dpp_state_transition_conversion_versions/v1.rs @@ -4,6 +4,7 @@ pub const STATE_TRANSITION_CONVERSION_VERSIONS_V1: DPPStateTransitionConversionV DPPStateTransitionConversionVersions { identity_to_identity_create_transition: 0, identity_to_identity_top_up_transition: 0, + identity_to_identity_transfer_transition: 0, identity_to_identity_withdrawal_transition: 0, identity_to_identity_create_transition_with_signer: 0, }; diff --git a/packages/rs-platform-version/src/version/dpp_versions/dpp_state_transition_conversion_versions/v2.rs b/packages/rs-platform-version/src/version/dpp_versions/dpp_state_transition_conversion_versions/v2.rs index 17fd17bd94..fb38e3ebd7 100644 --- a/packages/rs-platform-version/src/version/dpp_versions/dpp_state_transition_conversion_versions/v2.rs +++ b/packages/rs-platform-version/src/version/dpp_versions/dpp_state_transition_conversion_versions/v2.rs @@ -4,6 +4,7 @@ pub const STATE_TRANSITION_CONVERSION_VERSIONS_V2: DPPStateTransitionConversionV DPPStateTransitionConversionVersions { identity_to_identity_create_transition: 0, identity_to_identity_top_up_transition: 0, + identity_to_identity_transfer_transition: 0, identity_to_identity_withdrawal_transition: 1, identity_to_identity_create_transition_with_signer: 0, }; diff --git a/packages/rs-sdk/src/platform/transition.rs b/packages/rs-sdk/src/platform/transition.rs index 490bc40090..6bd51a3b2e 100644 --- a/packages/rs-sdk/src/platform/transition.rs +++ b/packages/rs-sdk/src/platform/transition.rs @@ -9,6 +9,7 @@ pub mod put_document; pub mod put_identity; pub mod put_settings; pub mod top_up_identity; +pub mod transfer; pub mod transfer_document; mod txid; pub mod update_price_of_document; diff --git a/packages/rs-sdk/src/platform/transition/transfer.rs b/packages/rs-sdk/src/platform/transition/transfer.rs new file mode 100644 index 0000000000..bf330a1024 --- /dev/null +++ b/packages/rs-sdk/src/platform/transition/transfer.rs @@ -0,0 +1,67 @@ +use dpp::identifier::Identifier; +use dpp::identity::accessors::IdentityGettersV0; + +use crate::platform::transition::broadcast::BroadcastStateTransition; +use crate::platform::transition::put_settings::PutSettings; +use crate::{Error, Sdk}; +use dpp::identity::signer::Signer; +use dpp::identity::{Identity, IdentityPublicKey}; +use dpp::state_transition::identity_credit_transfer_transition::methods::IdentityCreditTransferTransitionMethodsV0; +use dpp::state_transition::identity_credit_transfer_transition::IdentityCreditTransferTransition; +use dpp::state_transition::proof_result::StateTransitionProofResult; + +#[async_trait::async_trait] +pub trait TransferToIdentity { + /// Function to transfer credits from an identity to another identity. Returns the final + /// identity balance. + /// + /// If signing_transfer_key_to_use is not set, we will try to use one in the signer that is + /// available for the transfer. + async fn transfer_credits( + &self, + sdk: &Sdk, + to_identity_id: Identifier, + amount: u64, + signing_transfer_key_to_use: Option<&IdentityPublicKey>, + signer: S, + settings: Option, + ) -> Result; +} + +#[async_trait::async_trait] +impl TransferToIdentity for Identity { + async fn transfer_credits( + &self, + sdk: &Sdk, + to_identity_id: Identifier, + amount: u64, + signing_transfer_key_to_use: Option<&IdentityPublicKey>, + signer: S, + settings: Option, + ) -> Result { + let new_identity_nonce = sdk.get_identity_nonce(self.id(), true, settings).await?; + let user_fee_increase = settings.and_then(|settings| settings.user_fee_increase); + let state_transition = IdentityCreditTransferTransition::try_from_identity( + self, + to_identity_id, + amount, + user_fee_increase.unwrap_or_default(), + signer, + signing_transfer_key_to_use, + new_identity_nonce, + sdk.version(), + None, + )?; + + let result = state_transition.broadcast_and_wait(sdk, None).await?; + + match result { + StateTransitionProofResult::VerifiedPartialIdentity(identity) => { + identity.balance.ok_or(Error::DapiClientError( + "expected an identity balance after transfer".to_string(), + )) + } + _ => Err(Error::DapiClientError("proved a non identity".to_string())), + } + } +}