From d2a1ba5bca4641d7d87ed2a98415848140f6c39a Mon Sep 17 00:00:00 2001 From: Ivan Shumkov Date: Sat, 29 Mar 2025 13:37:05 +0700 Subject: [PATCH 1/6] feat: add token order transitions --- packages/rs-dpp/src/balances/credits.rs | 6 +- .../src/errors/consensus/basic/basic_error.rs | 7 ++ .../src/errors/consensus/basic/token/mod.rs | 4 ++ .../basic/token/zero_token_amount_error.rs | 32 +++++++++ .../basic/token/zero_token_price_error.rs | 32 +++++++++ packages/rs-dpp/src/errors/consensus/codes.rs | 2 + .../from_document.rs | 6 +- .../v0/from_document.rs | 3 +- .../document_create_transition/v0/mod.rs | 3 +- .../v0/v0_methods.rs | 9 +-- .../document_create_transition/v0_methods.rs | 5 +- .../batched_transition/mod.rs | 8 +++ .../validate_structure/v0/mod.rs | 16 +++-- .../validate_structure/v0/mod.rs | 16 +++-- .../accessors.rs | 65 ++++++++++++++++++ .../mod.rs | 4 ++ .../transition.rs | 22 +++++++ .../v0/accessors.rs | 66 +++++++++++++++++++ .../v0/mod.rs | 9 +++ .../v0/transition.rs | 29 ++++++++ .../validate_structure.rs | 36 ++++++++++ .../validate_structure/v0.rs | 21 ++++++ .../accessors.rs | 59 +++++++++++++++++ .../token_order_buy_limit_transition/mod.rs | 4 ++ .../transition.rs | 22 +++++++ .../v0/accessors.rs | 59 +++++++++++++++++ .../v0/mod.rs | 9 +++ .../v0/transition.rs | 39 +++++++++++ .../validate_structure.rs | 36 ++++++++++ .../validate_structure/v0.rs | 32 +++++++++ .../accessors.rs | 52 +++++++++++++++ .../token_order_cancel_transition/mod.rs | 3 + .../transition.rs | 22 +++++++ .../v0/accessors.rs | 53 +++++++++++++++ .../token_order_cancel_transition/v0/mod.rs | 9 +++ .../v0/transition.rs | 24 +++++++ .../accessors.rs | 52 +++++++++++++++ .../token_order_sell_limit_transition/mod.rs | 4 ++ .../transition.rs | 22 +++++++ .../v0/accessors.rs | 51 ++++++++++++++ .../v0/mod.rs | 9 +++ .../v0/transition.rs | 41 ++++++++++++ .../validate_structure.rs | 36 ++++++++++ .../validate_structure/v0.rs | 32 +++++++++ .../validate_structure/v0/mod.rs | 16 +++-- .../validate_token_amount.rs | 17 +++++ .../drive_abci_validation_versions/mod.rs | 3 + .../drive_abci_validation_versions/v1.rs | 3 + .../drive_abci_validation_versions/v2.rs | 3 + .../drive_abci_validation_versions/v3.rs | 3 + .../drive_abci_validation_versions/v4.rs | 3 + .../drive_abci_validation_versions/v5.rs | 3 + .../src/errors/consensus/consensus_error.rs | 8 ++- 53 files changed, 1100 insertions(+), 30 deletions(-) create mode 100644 packages/rs-dpp/src/errors/consensus/basic/token/zero_token_amount_error.rs create mode 100644 packages/rs-dpp/src/errors/consensus/basic/token/zero_token_price_error.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_adjust_price_transition/accessors.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_adjust_price_transition/mod.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_adjust_price_transition/transition.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_adjust_price_transition/v0/accessors.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_adjust_price_transition/v0/mod.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_adjust_price_transition/v0/transition.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_adjust_price_transition/validate_structure.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_adjust_price_transition/validate_structure/v0.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_buy_limit_transition/accessors.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_buy_limit_transition/mod.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_buy_limit_transition/transition.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_buy_limit_transition/v0/accessors.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_buy_limit_transition/v0/mod.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_buy_limit_transition/v0/transition.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_buy_limit_transition/validate_structure.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_buy_limit_transition/validate_structure/v0.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_cancel_transition/accessors.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_cancel_transition/mod.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_cancel_transition/transition.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_cancel_transition/v0/accessors.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_cancel_transition/v0/mod.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_cancel_transition/v0/transition.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_sell_limit_transition/accessors.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_sell_limit_transition/mod.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_sell_limit_transition/transition.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_sell_limit_transition/v0/accessors.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_sell_limit_transition/v0/mod.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_sell_limit_transition/v0/transition.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_sell_limit_transition/validate_structure.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_sell_limit_transition/validate_structure/v0.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/validate_token_amount.rs diff --git a/packages/rs-dpp/src/balances/credits.rs b/packages/rs-dpp/src/balances/credits.rs index 02f2479f045..2e7ca3d8bed 100644 --- a/packages/rs-dpp/src/balances/credits.rs +++ b/packages/rs-dpp/src/balances/credits.rs @@ -32,8 +32,12 @@ pub type SumTokenAmount = i128; pub type SignedCredits = i64; /// Maximum value of credits -pub const MAX_CREDITS: Credits = 9223372036854775807 as Credits; //i64 Max +pub const MAX_CREDITS: Credits = i64::MAX as Credits; //i64 Max +/// Maximum token amount +pub const TOKEN_MAX_AMOUNT: TokenAmount = i64::MAX as TokenAmount; + +/// Number of credits in 1 duff pub const CREDITS_PER_DUFF: Credits = 1000; /// Trait for signed and unsigned credits diff --git a/packages/rs-dpp/src/errors/consensus/basic/basic_error.rs b/packages/rs-dpp/src/errors/consensus/basic/basic_error.rs index 6b3cc992cfa..645b7f0f35b 100644 --- a/packages/rs-dpp/src/errors/consensus/basic/basic_error.rs +++ b/packages/rs-dpp/src/errors/consensus/basic/basic_error.rs @@ -79,6 +79,7 @@ use crate::consensus::basic::token::{ DestinationIdentityForTokenMintingNotSetError, InvalidActionIdError, InvalidTokenAmountError, InvalidTokenConfigUpdateNoChangeError, InvalidTokenIdError, InvalidTokenNoteTooBigError, InvalidTokenPositionError, MissingDefaultLocalizationError, TokenTransferToOurselfError, + ZeroTokenAmountError, ZeroTokenPriceError, }; use crate::consensus::basic::unsupported_version_error::UnsupportedVersionError; use crate::consensus::basic::value_error::ValueError; @@ -501,6 +502,12 @@ pub enum BasicError { #[error(transparent)] MissingDefaultLocalizationError(MissingDefaultLocalizationError), + + #[error(transparent)] + ZeroTokenAmountError(ZeroTokenAmountError), + + #[error(transparent)] + ZeroTokenPriceError(ZeroTokenPriceError), } impl From for ConsensusError { diff --git a/packages/rs-dpp/src/errors/consensus/basic/token/mod.rs b/packages/rs-dpp/src/errors/consensus/basic/token/mod.rs index 79ad589ee41..f7cef9e3824 100644 --- a/packages/rs-dpp/src/errors/consensus/basic/token/mod.rs +++ b/packages/rs-dpp/src/errors/consensus/basic/token/mod.rs @@ -9,6 +9,8 @@ mod invalid_token_note_too_big_error; mod invalid_token_position_error; mod missing_default_localization; mod token_transfer_to_ourselves_error; +mod zero_token_amount_error; +mod zero_token_price_error; pub use choosing_token_mint_recipient_not_allowed_error::*; pub use contract_has_no_tokens_error::*; @@ -21,3 +23,5 @@ pub use invalid_token_note_too_big_error::*; pub use invalid_token_position_error::*; pub use missing_default_localization::*; pub use token_transfer_to_ourselves_error::*; +pub use zero_token_amount_error::*; +pub use zero_token_price_error::*; diff --git a/packages/rs-dpp/src/errors/consensus/basic/token/zero_token_amount_error.rs b/packages/rs-dpp/src/errors/consensus/basic/token/zero_token_amount_error.rs new file mode 100644 index 00000000000..77adb97e166 --- /dev/null +++ b/packages/rs-dpp/src/errors/consensus/basic/token/zero_token_amount_error.rs @@ -0,0 +1,32 @@ +use crate::consensus::basic::BasicError; +use crate::consensus::ConsensusError; +use crate::ProtocolError; +use bincode::{Decode, Encode}; +use platform_serialization_derive::{PlatformDeserialize, PlatformSerialize}; +use thiserror::Error; + +#[derive( + Error, Debug, Clone, PartialEq, Eq, Encode, Decode, PlatformSerialize, PlatformDeserialize, +)] +#[error("Token amount can't be 0")] +#[platform_serialize(unversioned)] +pub struct ZeroTokenAmountError {} + +impl Default for ZeroTokenAmountError { + fn default() -> Self { + Self::new() + } +} + +impl ZeroTokenAmountError { + /// Creates a new `ZeroTokenAmountError`. + pub fn new() -> Self { + Self {} + } +} + +impl From for ConsensusError { + fn from(err: ZeroTokenAmountError) -> Self { + Self::BasicError(BasicError::ZeroTokenAmountError(err)) + } +} diff --git a/packages/rs-dpp/src/errors/consensus/basic/token/zero_token_price_error.rs b/packages/rs-dpp/src/errors/consensus/basic/token/zero_token_price_error.rs new file mode 100644 index 00000000000..27cfa1b23b5 --- /dev/null +++ b/packages/rs-dpp/src/errors/consensus/basic/token/zero_token_price_error.rs @@ -0,0 +1,32 @@ +use crate::consensus::basic::BasicError; +use crate::consensus::ConsensusError; +use crate::ProtocolError; +use bincode::{Decode, Encode}; +use platform_serialization_derive::{PlatformDeserialize, PlatformSerialize}; +use thiserror::Error; + +#[derive( + Error, Debug, Clone, PartialEq, Eq, Encode, Decode, PlatformSerialize, PlatformDeserialize, +)] +#[error("Token price can't be 0")] +#[platform_serialize(unversioned)] +pub struct ZeroTokenPriceError {} + +impl Default for ZeroTokenPriceError { + fn default() -> Self { + Self::new() + } +} + +impl ZeroTokenPriceError { + /// Creates a new `ZeroTokenPriceError`. + pub fn new() -> Self { + Self {} + } +} + +impl From for ConsensusError { + fn from(err: ZeroTokenPriceError) -> Self { + Self::BasicError(BasicError::ZeroTokenPriceError(err)) + } +} diff --git a/packages/rs-dpp/src/errors/consensus/codes.rs b/packages/rs-dpp/src/errors/consensus/codes.rs index b6e6b84b738..15d796d2e4d 100644 --- a/packages/rs-dpp/src/errors/consensus/codes.rs +++ b/packages/rs-dpp/src/errors/consensus/codes.rs @@ -145,6 +145,8 @@ impl ErrorWithCode for BasicError { Self::InvalidTokenConfigUpdateNoChangeError(_) => 10457, Self::InvalidTokenAmountError(_) => 10458, Self::InvalidTokenNoteTooBigError(_) => 10459, + Self::ZeroTokenAmountError(_) => 10460, + Self::ZeroTokenPriceError(_) => 10461, // Identity Errors: 10500-10599 Self::DuplicatedIdentityPublicKeyBasicError(_) => 10500, diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_create_transition/from_document.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_create_transition/from_document.rs index 7ade005e6cf..acc5e8e8a91 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_create_transition/from_document.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_create_transition/from_document.rs @@ -1,7 +1,9 @@ use crate::data_contract::document_type::DocumentTypeRef; use crate::document::Document; use crate::prelude::IdentityNonce; -use crate::state_transition::batch_transition::batched_transition::DocumentCreateTransition; +use crate::state_transition::batch_transition::batched_transition::{ + DocumentCreateTransition, Entropy, +}; use crate::state_transition::batch_transition::document_create_transition::DocumentCreateTransitionV0; use crate::ProtocolError; use platform_version::version::{FeatureVersion, PlatformVersion}; @@ -10,7 +12,7 @@ impl DocumentCreateTransition { pub fn from_document( document: Document, document_type: DocumentTypeRef, - entropy: [u8; 32], + entropy: Entropy, identity_contract_nonce: IdentityNonce, platform_version: &PlatformVersion, feature_version: Option, diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_create_transition/v0/from_document.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_create_transition/v0/from_document.rs index 633c72ffccd..8b0914ecb59 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_create_transition/v0/from_document.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_create_transition/v0/from_document.rs @@ -2,6 +2,7 @@ use crate::data_contract::document_type::methods::DocumentTypeV0Methods; use crate::data_contract::document_type::DocumentTypeRef; use crate::document::{Document, DocumentV0Getters}; use crate::prelude::IdentityNonce; +use crate::state_transition::batch_transition::batched_transition::Entropy; use crate::state_transition::batch_transition::document_base_transition::DocumentBaseTransition; use crate::state_transition::batch_transition::document_create_transition::DocumentCreateTransitionV0; use crate::ProtocolError; @@ -11,7 +12,7 @@ impl DocumentCreateTransitionV0 { pub(crate) fn from_document( document: Document, document_type: DocumentTypeRef, - entropy: [u8; 32], + entropy: Entropy, identity_contract_nonce: IdentityNonce, platform_version: &PlatformVersion, base_feature_version: Option, diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_create_transition/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_create_transition/v0/mod.rs index 14b5313cf1e..dc10cf0618f 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_create_transition/v0/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_create_transition/v0/mod.rs @@ -35,6 +35,7 @@ use platform_version::version::PlatformVersion; #[cfg(feature = "state-transition-value-conversion")] use crate::state_transition::batch_transition; +use crate::state_transition::batch_transition::batched_transition::Entropy; mod property_names { pub const ENTROPY: &str = "$entropy"; @@ -63,7 +64,7 @@ pub struct DocumentCreateTransitionV0 { feature = "state-transition-serde-conversion", serde(rename = "$entropy") )] - pub entropy: [u8; 32], + pub entropy: Entropy, #[cfg_attr(feature = "state-transition-serde-conversion", serde(flatten))] pub data: BTreeMap, diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_create_transition/v0/v0_methods.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_create_transition/v0/v0_methods.rs index e19bcb8ec8b..7c4dda123c2 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_create_transition/v0/v0_methods.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_create_transition/v0/v0_methods.rs @@ -5,18 +5,19 @@ use platform_value::Value; use crate::fee::Credits; use std::collections::BTreeMap; +use crate::state_transition::batch_transition::batched_transition::Entropy; use crate::state_transition::batch_transition::document_base_transition::document_base_transition_trait::DocumentBaseTransitionAccessors; pub trait DocumentCreateTransitionV0Methods: DocumentBaseTransitionAccessors { /// Returns a reference to the `entropy` field of the `DocumentCreateTransitionV0`. - fn entropy(&self) -> [u8; 32]; + fn entropy(&self) -> Entropy; /// Sets the value of the `entropy` field in the `DocumentCreateTransitionV0`. /// /// # Arguments /// /// * `entropy` - An array of 32 bytes to set. - fn set_entropy(&mut self, entropy: [u8; 32]); + fn set_entropy(&mut self, entropy: Entropy); /// Returns an optional reference to the `data` field of the `DocumentCreateTransitionV0`. fn data(&self) -> &BTreeMap; @@ -51,11 +52,11 @@ impl DocumentBaseTransitionAccessors for DocumentCreateTransitionV0 { } impl DocumentCreateTransitionV0Methods for DocumentCreateTransitionV0 { - fn entropy(&self) -> [u8; 32] { + fn entropy(&self) -> Entropy { self.entropy } - fn set_entropy(&mut self, entropy: [u8; 32]) { + fn set_entropy(&mut self, entropy: Entropy) { self.entropy = entropy; } diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_create_transition/v0_methods.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_create_transition/v0_methods.rs index da248d53934..e9823dccefa 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_create_transition/v0_methods.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_create_transition/v0_methods.rs @@ -1,6 +1,7 @@ use std::collections::BTreeMap; use platform_value::{Value}; use crate::fee::Credits; +use crate::state_transition::batch_transition::batched_transition::Entropy; use crate::state_transition::batch_transition::document_base_transition::document_base_transition_trait::DocumentBaseTransitionAccessors; use crate::state_transition::batch_transition::document_base_transition::DocumentBaseTransition; use crate::state_transition::batch_transition::document_create_transition::DocumentCreateTransition; @@ -27,13 +28,13 @@ impl DocumentBaseTransitionAccessors for DocumentCreateTransition { } impl DocumentCreateTransitionV0Methods for DocumentCreateTransition { - fn entropy(&self) -> [u8; 32] { + fn entropy(&self) -> Entropy { match self { DocumentCreateTransition::V0(v0) => v0.entropy, } } - fn set_entropy(&mut self, entropy: [u8; 32]) { + fn set_entropy(&mut self, entropy: Entropy) { match self { DocumentCreateTransition::V0(v0) => v0.entropy = entropy, } diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/mod.rs index 910572b72f9..d6ce8e95638 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/mod.rs @@ -22,10 +22,15 @@ pub mod token_destroy_frozen_funds_transition; pub mod token_emergency_action_transition; pub mod token_freeze_transition; pub mod token_mint_transition; +pub mod token_order_adjust_price_transition; +pub mod token_order_buy_limit_transition; +pub mod token_order_cancel_transition; +pub mod token_order_sell_limit_transition; pub mod token_transfer_transition; pub mod token_transition; pub mod token_transition_action_type; pub mod token_unfreeze_transition; +mod validate_token_amount; use crate::prelude::IdentityNonce; use crate::state_transition::batch_transition::batched_transition::document_transition::DocumentTransitionV0Methods; @@ -43,6 +48,9 @@ use token_transition::TokenTransition; pub const PROPERTY_ACTION: &str = "$action"; +/// Entropy used for creating unique identifiers +pub type Entropy = [u8; 32]; + #[derive(Debug, Clone, Encode, Decode, From, PartialEq, Display)] #[cfg_attr( feature = "state-transition-serde-conversion", diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_burn_transition/validate_structure/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_burn_transition/validate_structure/v0/mod.rs index e56c21e06e1..9755b5dcd94 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_burn_transition/validate_structure/v0/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_burn_transition/validate_structure/v0/mod.rs @@ -1,22 +1,26 @@ -use crate::consensus::basic::token::{InvalidTokenAmountError, InvalidTokenNoteTooBigError}; +use crate::consensus::basic::token::InvalidTokenNoteTooBigError; use crate::consensus::basic::BasicError; use crate::consensus::ConsensusError; +use crate::state_transition::batch_transition::batched_transition::validate_token_amount::ValidateTokenAmountV0; use crate::state_transition::batch_transition::token_burn_transition::v0::v0_methods::TokenBurnTransitionV0Methods; use crate::state_transition::batch_transition::TokenBurnTransition; use crate::tokens::MAX_TOKEN_NOTE_LEN; use crate::validation::SimpleConsensusValidationResult; use crate::ProtocolError; -pub(super) trait TokenBurnTransitionActionStructureValidationV0 { +pub(super) trait TokenBurnTransitionActionStructureValidationV0: + ValidateTokenAmountV0 +{ fn validate_structure_v0(&self) -> Result; } + +impl ValidateTokenAmountV0 for TokenBurnTransition {} + impl TokenBurnTransitionActionStructureValidationV0 for TokenBurnTransition { fn validate_structure_v0(&self) -> Result { - if self.burn_amount() > i64::MAX as u64 { + if let Some(consensus_error) = self.validate_token_amount_v0(self.burn_amount()) { return Ok(SimpleConsensusValidationResult::new_with_error( - ConsensusError::BasicError(BasicError::InvalidTokenAmountError( - InvalidTokenAmountError::new(i64::MAX as u64, self.burn_amount()), - )), + consensus_error, )); } diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_mint_transition/validate_structure/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_mint_transition/validate_structure/v0/mod.rs index 8c4fe050de8..85d319ae1ff 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_mint_transition/validate_structure/v0/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_mint_transition/validate_structure/v0/mod.rs @@ -1,22 +1,26 @@ -use crate::consensus::basic::token::{InvalidTokenAmountError, InvalidTokenNoteTooBigError}; +use crate::consensus::basic::token::InvalidTokenNoteTooBigError; use crate::consensus::basic::BasicError; use crate::consensus::ConsensusError; +use crate::state_transition::batch_transition::batched_transition::validate_token_amount::ValidateTokenAmountV0; use crate::state_transition::batch_transition::token_mint_transition::v0::v0_methods::TokenMintTransitionV0Methods; use crate::state_transition::batch_transition::TokenMintTransition; use crate::tokens::MAX_TOKEN_NOTE_LEN; use crate::validation::SimpleConsensusValidationResult; use crate::ProtocolError; -pub(super) trait TokenMintTransitionActionStructureValidationV0 { +pub(super) trait TokenMintTransitionActionStructureValidationV0: + ValidateTokenAmountV0 +{ fn validate_structure_v0(&self) -> Result; } + +impl ValidateTokenAmountV0 for TokenMintTransition {} + impl TokenMintTransitionActionStructureValidationV0 for TokenMintTransition { fn validate_structure_v0(&self) -> Result { - if self.amount() > i64::MAX as u64 { + if let Some(consensus_error) = self.validate_token_amount_v0(self.amount()) { return Ok(SimpleConsensusValidationResult::new_with_error( - ConsensusError::BasicError(BasicError::InvalidTokenAmountError( - InvalidTokenAmountError::new(i64::MAX as u64, self.amount()), - )), + consensus_error, )); } diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_adjust_price_transition/accessors.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_adjust_price_transition/accessors.rs new file mode 100644 index 00000000000..29c966a9314 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_adjust_price_transition/accessors.rs @@ -0,0 +1,65 @@ +use platform_value::Identifier; +use crate::fee::Credits; +use crate::prelude::Revision; +use crate::state_transition::batch_transition::batched_transition::token_order_adjust_price_transition::transition::TokenOrderAdjustPriceTransition; +use crate::state_transition::batch_transition::batched_transition::token_order_adjust_price_transition::v0::accessors::TokenOrderAdjustPriceTransitionV0Methods; +use crate::state_transition::batch_transition::token_base_transition::token_base_transition_accessors::TokenBaseTransitionAccessors; +use crate::state_transition::batch_transition::token_base_transition::TokenBaseTransition; + +impl TokenBaseTransitionAccessors for TokenOrderAdjustPriceTransition { + fn base(&self) -> &TokenBaseTransition { + match self { + Self::V0(v0) => &v0.base(), + } + } + + fn base_mut(&mut self) -> &mut TokenBaseTransition { + match self { + Self::V0(v0) => v0.base_mut(), + } + } + + fn set_base(&mut self, base: TokenBaseTransition) { + match self { + Self::V0(v0) => v0.set_base(base), + } + } +} + +impl TokenOrderAdjustPriceTransitionV0Methods for TokenOrderAdjustPriceTransition { + fn order_id(&self) -> Identifier { + match self { + Self::V0(v0) => v0.order_id(), + } + } + + fn set_order_id(&mut self, id: Identifier) { + match self { + Self::V0(v0) => v0.set_order_id(id), + } + } + + fn order_revision(&self) -> Revision { + match self { + Self::V0(v0) => v0.order_revision(), + } + } + + fn set_order_revision(&mut self, revision: Revision) { + match self { + Self::V0(v0) => v0.set_order_revision(revision), + } + } + + fn token_price(&self) -> Credits { + match self { + Self::V0(v0) => v0.token_price(), + } + } + + fn set_token_price(&mut self, price: Credits) { + match self { + Self::V0(v0) => v0.set_token_price(price), + } + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_adjust_price_transition/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_adjust_price_transition/mod.rs new file mode 100644 index 00000000000..633e00a1f0c --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_adjust_price_transition/mod.rs @@ -0,0 +1,4 @@ +pub mod accessors; +pub mod transition; +pub mod v0; +pub mod validate_structure; diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_adjust_price_transition/transition.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_adjust_price_transition/transition.rs new file mode 100644 index 00000000000..3283f08af53 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_adjust_price_transition/transition.rs @@ -0,0 +1,22 @@ +use bincode::{Decode, Encode}; +use derive_more::{Display, From}; +#[cfg(feature = "state-transition-serde-conversion")] +use serde::{Deserialize, Serialize}; +use crate::state_transition::batch_transition::batched_transition::token_order_adjust_price_transition::v0::transition::TokenOrderAdjustPriceTransitionV0; + +#[derive(Debug, Clone, Encode, Decode, PartialEq, Display, From)] +#[cfg_attr( + feature = "state-transition-serde-conversion", + derive(Serialize, Deserialize) +)] +pub enum TokenOrderAdjustPriceTransition { + #[display("V0({})", "_0")] + V0(TokenOrderAdjustPriceTransitionV0), +} + +impl Default for TokenOrderAdjustPriceTransition { + fn default() -> Self { + TokenOrderAdjustPriceTransition::V0(TokenOrderAdjustPriceTransitionV0::default()) + // since only v0 + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_adjust_price_transition/v0/accessors.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_adjust_price_transition/v0/accessors.rs new file mode 100644 index 00000000000..f2569a540d3 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_adjust_price_transition/v0/accessors.rs @@ -0,0 +1,66 @@ +use platform_value::Identifier; +use crate::fee::Credits; +use crate::prelude::Revision; +use crate::state_transition::batch_transition::batched_transition::token_order_adjust_price_transition::v0::transition::TokenOrderAdjustPriceTransitionV0; +use crate::state_transition::batch_transition::token_base_transition::token_base_transition_accessors::TokenBaseTransitionAccessors; +use crate::state_transition::batch_transition::token_base_transition::TokenBaseTransition; + +impl TokenBaseTransitionAccessors for TokenOrderAdjustPriceTransitionV0 { + fn base(&self) -> &TokenBaseTransition { + &self.base + } + + fn base_mut(&mut self) -> &mut TokenBaseTransition { + &mut self.base + } + + fn set_base(&mut self, base: TokenBaseTransition) { + self.base = base; + } +} + +pub trait TokenOrderAdjustPriceTransitionV0Methods: TokenBaseTransitionAccessors { + /// Order ID to adjust price for + fn order_id(&self) -> Identifier; + + /// Set order ID to adjust price for + fn set_order_id(&mut self, id: Identifier); + + /// Order revision to adjust price for + fn order_revision(&self) -> Revision; + + /// Set order revision to adjust price for + fn set_order_revision(&mut self, revision: Revision); + + /// New price for specified order + fn token_price(&self) -> Credits; + + /// Set new price for specified order + fn set_token_price(&mut self, price: Credits); +} + +impl TokenOrderAdjustPriceTransitionV0Methods for TokenOrderAdjustPriceTransitionV0 { + fn order_id(&self) -> Identifier { + self.order_id + } + + fn set_order_id(&mut self, id: Identifier) { + self.order_id = id; + } + + fn order_revision(&self) -> Revision { + self.order_revision + } + + fn set_order_revision(&mut self, revision: Revision) { + self.order_revision = revision; + } + + fn token_price(&self) -> Credits { + self.token_price + } + + fn set_token_price(&mut self, price: Credits) { + self.token_price = price; + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_adjust_price_transition/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_adjust_price_transition/v0/mod.rs new file mode 100644 index 00000000000..2dbb416ecb3 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_adjust_price_transition/v0/mod.rs @@ -0,0 +1,9 @@ +pub mod accessors; +pub mod transition; + +mod property_names { + pub const AMOUNT: &str = "amount"; +} + +/// The Identifier fields in [`TokenBurnTransition`] +pub use super::super::document_base_transition::IDENTIFIER_FIELDS; diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_adjust_price_transition/v0/transition.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_adjust_price_transition/v0/transition.rs new file mode 100644 index 00000000000..53efc2d3b47 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_adjust_price_transition/v0/transition.rs @@ -0,0 +1,29 @@ +use crate::fee::Credits; +use crate::prelude::Revision; +use crate::state_transition::batch_transition::token_base_transition::TokenBaseTransition; +use bincode_derive::{Decode, Encode}; +use derive_more::Display; +use platform_value::Identifier; +#[cfg(feature = "state-transition-serde-conversion")] +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Clone, Default, Encode, Decode, PartialEq, Display)] +#[cfg_attr( + feature = "state-transition-serde-conversion", + derive(Serialize, Deserialize), + serde(rename_all = "camelCase") +)] +#[display( + "Base: {base}, Order ID: {order_id}, Order Revision: {order_revision}, Price: {token_price} credits" +)] +pub struct TokenOrderAdjustPriceTransitionV0 { + /// Document Base Transition + #[cfg_attr(feature = "state-transition-serde-conversion", serde(flatten))] + pub(super) base: TokenBaseTransition, + /// Order ID + pub(super) order_id: Identifier, + /// Order revision + pub(super) order_revision: Revision, + /// New price for specified order and revision + pub(super) token_price: Credits, +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_adjust_price_transition/validate_structure.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_adjust_price_transition/validate_structure.rs new file mode 100644 index 00000000000..df5953e5735 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_adjust_price_transition/validate_structure.rs @@ -0,0 +1,36 @@ +use crate::validation::SimpleConsensusValidationResult; +use crate::ProtocolError; +use platform_version::version::PlatformVersion; +use crate::state_transition::batch_transition::batched_transition::token_order_adjust_price_transition::validate_structure::v0::TokenOrderAdjustPriceTransitionStructureValidationV0; +use crate::state_transition::batch_transition::batched_transition::token_order_adjust_price_transition::transition::TokenOrderAdjustPriceTransition; + +mod v0; + +pub trait TokenOrderAdjustPriceTransitionStructureValidation { + fn validate_structure( + &self, + platform_version: &PlatformVersion, + ) -> Result; +} + +impl TokenOrderAdjustPriceTransitionStructureValidation for TokenOrderAdjustPriceTransition { + fn validate_structure( + &self, + platform_version: &PlatformVersion, + ) -> Result { + match platform_version + .drive_abci + .validation_and_processing + .state_transitions + .batch_state_transition + .token_order_adjust_price_transition_structure_validation + { + 0 => self.validate_structure_v0(), + version => Err(ProtocolError::UnknownVersionMismatch { + method: "TokenOrderAdjustPriceTransition::validate_structure".to_string(), + known_versions: vec![0], + received: version, + }), + } + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_adjust_price_transition/validate_structure/v0.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_adjust_price_transition/validate_structure/v0.rs new file mode 100644 index 00000000000..2aff0277ba2 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_adjust_price_transition/validate_structure/v0.rs @@ -0,0 +1,21 @@ +use crate::consensus::basic::token::ZeroTokenPriceError; +use crate::validation::SimpleConsensusValidationResult; +use crate::ProtocolError; +use crate::state_transition::batch_transition::batched_transition::token_order_adjust_price_transition::transition::TokenOrderAdjustPriceTransition; +use crate::state_transition::batch_transition::batched_transition::token_order_adjust_price_transition::v0::accessors::TokenOrderAdjustPriceTransitionV0Methods; + +pub(super) trait TokenOrderAdjustPriceTransitionStructureValidationV0 { + fn validate_structure_v0(&self) -> Result; +} + +impl TokenOrderAdjustPriceTransitionStructureValidationV0 for TokenOrderAdjustPriceTransition { + fn validate_structure_v0(&self) -> Result { + if self.token_price() == 0 { + return Ok(SimpleConsensusValidationResult::new_with_error( + ZeroTokenPriceError::new().into(), + )); + } + + Ok(SimpleConsensusValidationResult::default()) + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_buy_limit_transition/accessors.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_buy_limit_transition/accessors.rs new file mode 100644 index 00000000000..3981100db26 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_buy_limit_transition/accessors.rs @@ -0,0 +1,59 @@ +use crate::balances::credits::TokenAmount; +use crate::fee::Credits; +use crate::state_transition::batch_transition::batched_transition::Entropy; +use crate::state_transition::batch_transition::batched_transition::token_order_buy_limit_transition::transition::TokenOrderBuyLimitTransition; +use crate::state_transition::batch_transition::batched_transition::token_order_buy_limit_transition::v0::accessors::TokenOrderBuyLimitTransitionV0Methods; +use crate::state_transition::batch_transition::token_base_transition::token_base_transition_accessors::TokenBaseTransitionAccessors; +use crate::state_transition::batch_transition::token_base_transition::TokenBaseTransition; + +impl TokenBaseTransitionAccessors for TokenOrderBuyLimitTransition { + fn base(&self) -> &TokenBaseTransition { + match self { + Self::V0(v0) => v0.base(), + } + } + + fn base_mut(&mut self) -> &mut TokenBaseTransition { + match self { + Self::V0(v0) => v0.base_mut(), + } + } + + fn set_base(&mut self, base: TokenBaseTransition) { + match self { + Self::V0(v0) => v0.set_base(base), + } + } +} + +impl TokenOrderBuyLimitTransitionV0Methods for TokenOrderBuyLimitTransition { + fn order_id_entropy(&self) -> Entropy { + match self { + Self::V0(v0) => v0.order_id_entropy(), + } + } + + fn token_amount(&self) -> TokenAmount { + match self { + Self::V0(v0) => v0.token_amount(), + } + } + + fn set_token_amount(&mut self, amount: TokenAmount) { + match self { + Self::V0(v0) => v0.set_token_amount(amount), + } + } + + fn token_max_price(&self) -> Credits { + match self { + Self::V0(v0) => v0.token_max_price(), + } + } + + fn set_token_max_price(&mut self, max_price: Credits) { + match self { + Self::V0(v0) => v0.set_token_max_price(max_price), + } + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_buy_limit_transition/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_buy_limit_transition/mod.rs new file mode 100644 index 00000000000..633e00a1f0c --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_buy_limit_transition/mod.rs @@ -0,0 +1,4 @@ +pub mod accessors; +pub mod transition; +pub mod v0; +pub mod validate_structure; diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_buy_limit_transition/transition.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_buy_limit_transition/transition.rs new file mode 100644 index 00000000000..6d47bb73ba4 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_buy_limit_transition/transition.rs @@ -0,0 +1,22 @@ +use bincode::{Decode, Encode}; +use derive_more::{Display, From}; +#[cfg(feature = "state-transition-serde-conversion")] +use serde::{Deserialize, Serialize}; +use crate::state_transition::batch_transition::batched_transition::token_order_buy_limit_transition::v0::transition::TokenOrderBuyLimitTransitionV0; + +#[derive(Debug, Clone, Encode, Decode, PartialEq, Display, From)] +#[cfg_attr( + feature = "state-transition-serde-conversion", + derive(Serialize, Deserialize) +)] +pub enum TokenOrderBuyLimitTransition { + #[display("V0({})", "_0")] + V0(TokenOrderBuyLimitTransitionV0), +} + +impl Default for TokenOrderBuyLimitTransition { + fn default() -> Self { + TokenOrderBuyLimitTransition::V0(TokenOrderBuyLimitTransitionV0::default()) + // since only v0 + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_buy_limit_transition/v0/accessors.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_buy_limit_transition/v0/accessors.rs new file mode 100644 index 00000000000..9277f9cf9a7 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_buy_limit_transition/v0/accessors.rs @@ -0,0 +1,59 @@ +use crate::balances::credits::TokenAmount; +use crate::fee::Credits; +use crate::state_transition::batch_transition::batched_transition::Entropy; +use crate::state_transition::batch_transition::batched_transition::token_order_buy_limit_transition::v0::transition::TokenOrderBuyLimitTransitionV0; +use crate::state_transition::batch_transition::token_base_transition::token_base_transition_accessors::TokenBaseTransitionAccessors; +use crate::state_transition::batch_transition::token_base_transition::TokenBaseTransition; + +impl TokenBaseTransitionAccessors for TokenOrderBuyLimitTransitionV0 { + fn base(&self) -> &TokenBaseTransition { + &self.base + } + + fn base_mut(&mut self) -> &mut TokenBaseTransition { + &mut self.base + } + + fn set_base(&mut self, base: TokenBaseTransition) { + self.base = base; + } +} + +pub trait TokenOrderBuyLimitTransitionV0Methods: TokenBaseTransitionAccessors { + /// Entropy generated to create order ID + fn order_id_entropy(&self) -> Entropy; + + /// How many tokens to buy + fn token_amount(&self) -> TokenAmount; + + /// Set how many tokens to buy + fn set_token_amount(&mut self, amount: TokenAmount); + + /// Max price to pay for token's amount + fn token_max_price(&self) -> Credits; + + /// Set max price to pay for token's amount + fn set_token_max_price(&mut self, max_price: Credits); +} + +impl TokenOrderBuyLimitTransitionV0Methods for TokenOrderBuyLimitTransitionV0 { + fn order_id_entropy(&self) -> Entropy { + self.order_id_entropy + } + + fn token_amount(&self) -> TokenAmount { + self.token_amount + } + + fn set_token_amount(&mut self, amount: TokenAmount) { + self.token_amount = amount; + } + + fn token_max_price(&self) -> Credits { + self.token_max_price + } + + fn set_token_max_price(&mut self, max_price: Credits) { + self.token_max_price = max_price; + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_buy_limit_transition/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_buy_limit_transition/v0/mod.rs new file mode 100644 index 00000000000..2dbb416ecb3 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_buy_limit_transition/v0/mod.rs @@ -0,0 +1,9 @@ +pub mod accessors; +pub mod transition; + +mod property_names { + pub const AMOUNT: &str = "amount"; +} + +/// The Identifier fields in [`TokenBurnTransition`] +pub use super::super::document_base_transition::IDENTIFIER_FIELDS; diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_buy_limit_transition/v0/transition.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_buy_limit_transition/v0/transition.rs new file mode 100644 index 00000000000..5b87476f651 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_buy_limit_transition/v0/transition.rs @@ -0,0 +1,39 @@ +use crate::balances::credits::TokenAmount; +use crate::fee::Credits; +use crate::state_transition::batch_transition::batched_transition::Entropy; +use crate::state_transition::batch_transition::token_base_transition::TokenBaseTransition; +use bincode_derive::{Decode, Encode}; +#[cfg(feature = "state-transition-serde-conversion")] +use serde::{Deserialize, Serialize}; +use std::fmt; + +#[derive(Debug, Clone, Default, Encode, Decode, PartialEq)] +#[cfg_attr( + feature = "state-transition-serde-conversion", + derive(Serialize, Deserialize), + serde(rename_all = "camelCase") +)] +pub struct TokenOrderBuyLimitTransitionV0 { + /// Document Base Transition + #[cfg_attr(feature = "state-transition-serde-conversion", serde(flatten))] + pub(super) base: TokenBaseTransition, + /// Entropy generated to create order ID + pub(super) order_id_entropy: Entropy, + /// How many tokens to buy + pub(super) token_amount: TokenAmount, + /// What is the maximum price to pay for the tokens + pub(super) token_max_price: Credits, +} + +impl fmt::Display for TokenOrderBuyLimitTransitionV0 { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "Base: {}, Order ID Entropy: {}, Token Amount to Buy: {}, Max Price: {} credits", + self.base, + hex::encode(&self.order_id_entropy), + self.token_amount, + self.token_max_price + ) + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_buy_limit_transition/validate_structure.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_buy_limit_transition/validate_structure.rs new file mode 100644 index 00000000000..b5b1203e27d --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_buy_limit_transition/validate_structure.rs @@ -0,0 +1,36 @@ +use crate::validation::SimpleConsensusValidationResult; +use crate::ProtocolError; +use platform_version::version::PlatformVersion; +use crate::state_transition::batch_transition::batched_transition::token_order_buy_limit_transition::transition::TokenOrderBuyLimitTransition; +use crate::state_transition::batch_transition::batched_transition::token_order_buy_limit_transition::validate_structure::v0::TokenOrderBuyLimitTransitionStructureValidationV0; + +mod v0; + +pub trait TokenOrderBuyLimitTransitionStructureValidation { + fn validate_structure( + &self, + platform_version: &PlatformVersion, + ) -> Result; +} + +impl TokenOrderBuyLimitTransitionStructureValidation for TokenOrderBuyLimitTransition { + fn validate_structure( + &self, + platform_version: &PlatformVersion, + ) -> Result { + match platform_version + .drive_abci + .validation_and_processing + .state_transitions + .batch_state_transition + .token_order_buy_limit_transition_structure_validation + { + 0 => self.validate_structure_v0(), + version => Err(ProtocolError::UnknownVersionMismatch { + method: "TokenOrderBuyLimitTransition::validate_structure".to_string(), + known_versions: vec![0], + received: version, + }), + } + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_buy_limit_transition/validate_structure/v0.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_buy_limit_transition/validate_structure/v0.rs new file mode 100644 index 00000000000..94da730d41f --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_buy_limit_transition/validate_structure/v0.rs @@ -0,0 +1,32 @@ +use crate::consensus::basic::token::ZeroTokenPriceError; +use crate::validation::SimpleConsensusValidationResult; +use crate::ProtocolError; +use crate::state_transition::batch_transition::batched_transition::token_order_buy_limit_transition::transition::TokenOrderBuyLimitTransition; +use crate::state_transition::batch_transition::batched_transition::token_order_buy_limit_transition::v0::accessors::TokenOrderBuyLimitTransitionV0Methods; +use crate::state_transition::batch_transition::batched_transition::validate_token_amount::ValidateTokenAmountV0; + +pub(super) trait TokenOrderBuyLimitTransitionStructureValidationV0: + ValidateTokenAmountV0 +{ + fn validate_structure_v0(&self) -> Result; +} + +impl ValidateTokenAmountV0 for TokenOrderBuyLimitTransition {} + +impl TokenOrderBuyLimitTransitionStructureValidationV0 for TokenOrderBuyLimitTransition { + fn validate_structure_v0(&self) -> Result { + if let Some(consensus_error) = self.validate_token_amount_v0(self.token_amount()) { + return Ok(SimpleConsensusValidationResult::new_with_error( + consensus_error, + )); + } + + if self.token_max_price() == 0 { + return Ok(SimpleConsensusValidationResult::new_with_error( + ZeroTokenPriceError::new().into(), + )); + } + + Ok(SimpleConsensusValidationResult::default()) + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_cancel_transition/accessors.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_cancel_transition/accessors.rs new file mode 100644 index 00000000000..71044dff35a --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_cancel_transition/accessors.rs @@ -0,0 +1,52 @@ +use platform_value::Identifier; +use crate::prelude::Revision; +use crate::state_transition::batch_transition::batched_transition::token_order_cancel_transition::transition::TokenOrderCancelLimitTransition; +use crate::state_transition::batch_transition::batched_transition::token_order_cancel_transition::v0::accessors::TokenOrderCancelLimitTransitionV0Methods; +use crate::state_transition::batch_transition::token_base_transition::token_base_transition_accessors::TokenBaseTransitionAccessors; +use crate::state_transition::batch_transition::token_base_transition::TokenBaseTransition; + +impl TokenBaseTransitionAccessors for TokenOrderCancelLimitTransition { + fn base(&self) -> &TokenBaseTransition { + match self { + Self::V0(v0) => v0.base(), + } + } + + fn base_mut(&mut self) -> &mut TokenBaseTransition { + match self { + Self::V0(v0) => v0.base_mut(), + } + } + + fn set_base(&mut self, base: TokenBaseTransition) { + match self { + Self::V0(v0) => v0.set_base(base), + } + } +} + +impl TokenOrderCancelLimitTransitionV0Methods for TokenOrderCancelLimitTransition { + fn order_id(&self) -> Identifier { + match self { + TokenOrderCancelLimitTransition::V0(v0) => v0.order_id(), + } + } + + fn set_order_id(&mut self, id: Identifier) { + match self { + TokenOrderCancelLimitTransition::V0(v0) => v0.set_order_id(id), + } + } + + fn order_revision(&self) -> Revision { + match self { + TokenOrderCancelLimitTransition::V0(v0) => v0.order_revision(), + } + } + + fn set_order_revision(&mut self, revision: Revision) { + match self { + TokenOrderCancelLimitTransition::V0(v0) => v0.set_order_revision(revision), + } + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_cancel_transition/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_cancel_transition/mod.rs new file mode 100644 index 00000000000..b1807e62b27 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_cancel_transition/mod.rs @@ -0,0 +1,3 @@ +pub mod accessors; +pub mod transition; +pub mod v0; diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_cancel_transition/transition.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_cancel_transition/transition.rs new file mode 100644 index 00000000000..357b2c67af9 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_cancel_transition/transition.rs @@ -0,0 +1,22 @@ +use bincode::{Decode, Encode}; +use derive_more::{Display, From}; +#[cfg(feature = "state-transition-serde-conversion")] +use serde::{Deserialize, Serialize}; +use crate::state_transition::batch_transition::batched_transition::token_order_cancel_transition::v0::transition::TokenOrderCancelLimitTransitionV0; + +#[derive(Debug, Clone, Encode, Decode, PartialEq, Display, From)] +#[cfg_attr( + feature = "state-transition-serde-conversion", + derive(Serialize, Deserialize) +)] +pub enum TokenOrderCancelLimitTransition { + #[display("V0({})", "_0")] + V0(TokenOrderCancelLimitTransitionV0), +} + +impl Default for TokenOrderCancelLimitTransition { + fn default() -> Self { + TokenOrderCancelLimitTransition::V0(TokenOrderCancelLimitTransitionV0::default()) + // since only v0 + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_cancel_transition/v0/accessors.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_cancel_transition/v0/accessors.rs new file mode 100644 index 00000000000..d8a59269349 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_cancel_transition/v0/accessors.rs @@ -0,0 +1,53 @@ +use platform_value::Identifier; +use crate::balances::credits::TokenAmount; +use crate::fee::Credits; +use crate::prelude::Revision; +use crate::state_transition::batch_transition::batched_transition::token_order_cancel_transition::v0::transition::TokenOrderCancelLimitTransitionV0; +use crate::state_transition::batch_transition::token_base_transition::token_base_transition_accessors::TokenBaseTransitionAccessors; +use crate::state_transition::batch_transition::token_base_transition::TokenBaseTransition; + +impl TokenBaseTransitionAccessors for TokenOrderCancelLimitTransitionV0 { + fn base(&self) -> &TokenBaseTransition { + &self.base + } + + fn base_mut(&mut self) -> &mut TokenBaseTransition { + &mut self.base + } + + fn set_base(&mut self, base: TokenBaseTransition) { + self.base = base; + } +} + +pub trait TokenOrderCancelLimitTransitionV0Methods: TokenBaseTransitionAccessors { + /// Order ID to cancel + fn order_id(&self) -> Identifier; + + /// Set order ID to cancel + fn set_order_id(&mut self, id: Identifier); + + /// Order revision to cancel + fn order_revision(&self) -> Revision; + + /// Set order revision + fn set_order_revision(&mut self, revision: Revision); +} + +impl TokenOrderCancelLimitTransitionV0Methods for TokenOrderCancelLimitTransitionV0 { + fn order_id(&self) -> Identifier { + self.order_id + } + + fn set_order_id(&mut self, id: Identifier) { + self.order_id = id; + } + + fn order_revision(&self) -> Revision { + self.order_revision + } + + fn set_order_revision(&mut self, revision: Revision) { + self.order_revision = revision; + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_cancel_transition/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_cancel_transition/v0/mod.rs new file mode 100644 index 00000000000..2dbb416ecb3 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_cancel_transition/v0/mod.rs @@ -0,0 +1,9 @@ +pub mod accessors; +pub mod transition; + +mod property_names { + pub const AMOUNT: &str = "amount"; +} + +/// The Identifier fields in [`TokenBurnTransition`] +pub use super::super::document_base_transition::IDENTIFIER_FIELDS; diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_cancel_transition/v0/transition.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_cancel_transition/v0/transition.rs new file mode 100644 index 00000000000..48a61cbbb01 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_cancel_transition/v0/transition.rs @@ -0,0 +1,24 @@ +use crate::prelude::Revision; +use crate::state_transition::batch_transition::token_base_transition::TokenBaseTransition; +use bincode_derive::{Decode, Encode}; +use derive_more::Display; +use platform_value::Identifier; +#[cfg(feature = "state-transition-serde-conversion")] +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Clone, Default, Encode, Decode, PartialEq, Display)] +#[cfg_attr( + feature = "state-transition-serde-conversion", + derive(Serialize, Deserialize), + serde(rename_all = "camelCase") +)] +#[display("Base: {base}, Order ID: {order_id}, Order Revision: {order_revision} credits")] +pub struct TokenOrderCancelLimitTransitionV0 { + /// Document Base Transition + #[cfg_attr(feature = "state-transition-serde-conversion", serde(flatten))] + pub(super) base: TokenBaseTransition, + /// Order ID to cancel + pub(super) order_id: Identifier, + /// Order revision to cancel + pub(super) order_revision: Revision, +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_sell_limit_transition/accessors.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_sell_limit_transition/accessors.rs new file mode 100644 index 00000000000..a162d8dad71 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_sell_limit_transition/accessors.rs @@ -0,0 +1,52 @@ +use crate::balances::credits::TokenAmount; +use crate::fee::Credits; +use crate::state_transition::batch_transition::batched_transition::token_order_sell_limit_transition::transition::TokenOrderSellLimitTransition; +use crate::state_transition::batch_transition::batched_transition::token_order_sell_limit_transition::v0::accessors::TokenOrderSellLimitTransitionV0Methods; +use crate::state_transition::batch_transition::token_base_transition::token_base_transition_accessors::TokenBaseTransitionAccessors; +use crate::state_transition::batch_transition::token_base_transition::TokenBaseTransition; + +impl TokenBaseTransitionAccessors for TokenOrderSellLimitTransition { + fn base(&self) -> &TokenBaseTransition { + match self { + Self::V0(v0) => &v0.base(), + } + } + + fn base_mut(&mut self) -> &mut TokenBaseTransition { + match self { + Self::V0(v0) => v0.base_mut(), + } + } + + fn set_base(&mut self, base: TokenBaseTransition) { + match self { + Self::V0(v0) => v0.set_base(base), + } + } +} + +impl TokenOrderSellLimitTransitionV0Methods for TokenOrderSellLimitTransition { + fn token_amount(&self) -> TokenAmount { + match self { + Self::V0(v0) => v0.token_amount(), + } + } + + fn set_token_amount(&mut self, amount: TokenAmount) { + match self { + Self::V0(v0) => v0.set_token_amount(amount), + } + } + + fn token_min_price(&self) -> Credits { + match self { + Self::V0(v0) => v0.token_min_price(), + } + } + + fn set_token_min_price(&mut self, min_price: Credits) { + match self { + Self::V0(v0) => v0.set_token_min_price(min_price), + } + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_sell_limit_transition/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_sell_limit_transition/mod.rs new file mode 100644 index 00000000000..633e00a1f0c --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_sell_limit_transition/mod.rs @@ -0,0 +1,4 @@ +pub mod accessors; +pub mod transition; +pub mod v0; +pub mod validate_structure; diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_sell_limit_transition/transition.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_sell_limit_transition/transition.rs new file mode 100644 index 00000000000..a60fe60c099 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_sell_limit_transition/transition.rs @@ -0,0 +1,22 @@ +use bincode::{Decode, Encode}; +use derive_more::{Display, From}; +#[cfg(feature = "state-transition-serde-conversion")] +use serde::{Deserialize, Serialize}; +use crate::state_transition::batch_transition::batched_transition::token_order_sell_limit_transition::v0::transition::TokenOrderSellLimitTransitionV0; + +#[derive(Debug, Clone, Encode, Decode, PartialEq, Display, From)] +#[cfg_attr( + feature = "state-transition-serde-conversion", + derive(Serialize, Deserialize) +)] +pub enum TokenOrderSellLimitTransition { + #[display("V0({})", "_0")] + V0(TokenOrderSellLimitTransitionV0), +} + +impl Default for TokenOrderSellLimitTransition { + fn default() -> Self { + TokenOrderSellLimitTransition::V0(TokenOrderSellLimitTransitionV0::default()) + // since only v0 + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_sell_limit_transition/v0/accessors.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_sell_limit_transition/v0/accessors.rs new file mode 100644 index 00000000000..bdc02bba07d --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_sell_limit_transition/v0/accessors.rs @@ -0,0 +1,51 @@ +use crate::balances::credits::TokenAmount; +use crate::fee::Credits; +use crate::state_transition::batch_transition::batched_transition::token_order_sell_limit_transition::v0::transition::TokenOrderSellLimitTransitionV0; +use crate::state_transition::batch_transition::token_base_transition::token_base_transition_accessors::TokenBaseTransitionAccessors; +use crate::state_transition::batch_transition::token_base_transition::TokenBaseTransition; + +impl TokenBaseTransitionAccessors for TokenOrderSellLimitTransitionV0 { + fn base(&self) -> &TokenBaseTransition { + &self.base + } + + fn base_mut(&mut self) -> &mut TokenBaseTransition { + &mut self.base + } + + fn set_base(&mut self, base: TokenBaseTransition) { + self.base = base; + } +} + +pub trait TokenOrderSellLimitTransitionV0Methods: TokenBaseTransitionAccessors { + /// How many tokens to sell + fn token_amount(&self) -> TokenAmount; + + /// Set how many tokens to sell + fn set_token_amount(&mut self, amount: TokenAmount); + + /// Min price to pay for token's amount + fn token_min_price(&self) -> Credits; + + /// Set min price to be paid for specified token's amount + fn set_token_min_price(&mut self, min_price: Credits); +} + +impl TokenOrderSellLimitTransitionV0Methods for TokenOrderSellLimitTransitionV0 { + fn token_amount(&self) -> TokenAmount { + self.token_amount + } + + fn set_token_amount(&mut self, amount: TokenAmount) { + self.token_amount = amount; + } + + fn token_min_price(&self) -> Credits { + self.token_min_price + } + + fn set_token_min_price(&mut self, min_price: Credits) { + self.token_min_price = min_price; + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_sell_limit_transition/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_sell_limit_transition/v0/mod.rs new file mode 100644 index 00000000000..2dbb416ecb3 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_sell_limit_transition/v0/mod.rs @@ -0,0 +1,9 @@ +pub mod accessors; +pub mod transition; + +mod property_names { + pub const AMOUNT: &str = "amount"; +} + +/// The Identifier fields in [`TokenBurnTransition`] +pub use super::super::document_base_transition::IDENTIFIER_FIELDS; diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_sell_limit_transition/v0/transition.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_sell_limit_transition/v0/transition.rs new file mode 100644 index 00000000000..fb14de39854 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_sell_limit_transition/v0/transition.rs @@ -0,0 +1,41 @@ +use std::fmt; +use crate::balances::credits::TokenAmount; +use crate::fee::Credits; +use crate::state_transition::batch_transition::batched_transition::Entropy; +use crate::state_transition::batch_transition::token_base_transition::TokenBaseTransition; +use bincode_derive::{Decode, Encode}; +use platform_value::Identifier; +#[cfg(feature = "state-transition-serde-conversion")] +use serde::{Deserialize, Serialize}; +use crate::state_transition::batch_transition::batched_transition::token_order_buy_limit_transition::v0::transition::TokenOrderBuyLimitTransitionV0; + +#[derive(Debug, Clone, Default, Encode, Decode, PartialEq)] +#[cfg_attr( + feature = "state-transition-serde-conversion", + derive(Serialize, Deserialize), + serde(rename_all = "camelCase") +)] +pub struct TokenOrderSellLimitTransitionV0 { + /// Document Base Transition + #[cfg_attr(feature = "state-transition-serde-conversion", serde(flatten))] + pub base: TokenBaseTransition, + /// Entropy generated to create order ID + pub order_id_entropy: Entropy, + /// How many tokens to sell + pub token_amount: TokenAmount, + /// What is the minimum price to be paid for the tokens + pub token_min_price: Credits, +} + +impl fmt::Display for TokenOrderSellLimitTransitionV0 { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "Base: {}, Order ID Entropy: {}, Token Amount to Sell: {}, Min Price: {} credits", + self.base, + hex::encode(&self.order_id_entropy), + self.token_amount, + self.token_min_price + ) + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_sell_limit_transition/validate_structure.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_sell_limit_transition/validate_structure.rs new file mode 100644 index 00000000000..3239dc627c6 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_sell_limit_transition/validate_structure.rs @@ -0,0 +1,36 @@ +use crate::validation::SimpleConsensusValidationResult; +use crate::ProtocolError; +use platform_version::version::PlatformVersion; +use crate::state_transition::batch_transition::batched_transition::token_order_sell_limit_transition::validate_structure::v0::TokenOrderSellLimitTransitionStructureValidationV0; +use crate::state_transition::batch_transition::batched_transition::token_order_sell_limit_transition::transition::TokenOrderSellLimitTransition; + +mod v0; + +pub trait TokenOrderSellLimitTransitionStructureValidation { + fn validate_structure( + &self, + platform_version: &PlatformVersion, + ) -> Result; +} + +impl TokenOrderSellLimitTransitionStructureValidation for TokenOrderSellLimitTransition { + fn validate_structure( + &self, + platform_version: &PlatformVersion, + ) -> Result { + match platform_version + .drive_abci + .validation_and_processing + .state_transitions + .batch_state_transition + .token_order_sell_limit_transition_structure_validation + { + 0 => self.validate_structure_v0(), + version => Err(ProtocolError::UnknownVersionMismatch { + method: "TokenOrderSellLimitTransition::validate_structure".to_string(), + known_versions: vec![0], + received: version, + }), + } + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_sell_limit_transition/validate_structure/v0.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_sell_limit_transition/validate_structure/v0.rs new file mode 100644 index 00000000000..fb7f93a1d51 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_sell_limit_transition/validate_structure/v0.rs @@ -0,0 +1,32 @@ +use crate::consensus::basic::token::ZeroTokenPriceError; +use crate::validation::SimpleConsensusValidationResult; +use crate::ProtocolError; +use crate::state_transition::batch_transition::batched_transition::token_order_sell_limit_transition::transition::TokenOrderSellLimitTransition; +use crate::state_transition::batch_transition::batched_transition::token_order_sell_limit_transition::v0::accessors::TokenOrderSellLimitTransitionV0Methods; +use crate::state_transition::batch_transition::batched_transition::validate_token_amount::ValidateTokenAmountV0; + +pub(super) trait TokenOrderSellLimitTransitionStructureValidationV0: + ValidateTokenAmountV0 +{ + fn validate_structure_v0(&self) -> Result; +} + +impl ValidateTokenAmountV0 for TokenOrderSellLimitTransition {} + +impl TokenOrderSellLimitTransitionStructureValidationV0 for TokenOrderSellLimitTransition { + fn validate_structure_v0(&self) -> Result { + if let Some(consensus_error) = self.validate_token_amount_v0(self.token_amount()) { + return Ok(SimpleConsensusValidationResult::new_with_error( + consensus_error, + )); + } + + if self.token_min_price() == 0 { + return Ok(SimpleConsensusValidationResult::new_with_error( + ZeroTokenPriceError::new().into(), + )); + } + + Ok(SimpleConsensusValidationResult::default()) + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_transfer_transition/validate_structure/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_transfer_transition/validate_structure/v0/mod.rs index dc5ebb70621..02209ffa593 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_transfer_transition/validate_structure/v0/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_transfer_transition/validate_structure/v0/mod.rs @@ -1,8 +1,9 @@ use platform_value::Identifier; use crate::consensus::basic::BasicError; -use crate::consensus::basic::token::{InvalidTokenAmountError, InvalidTokenNoteTooBigError, TokenTransferToOurselfError}; +use crate::consensus::basic::token::{InvalidTokenAmountError, InvalidTokenNoteTooBigError, TokenTransferToOurselfError, ZeroTokenAmountError}; use crate::consensus::ConsensusError; use crate::ProtocolError; +use crate::state_transition::batch_transition::batched_transition::validate_token_amount::{ValidateTokenAmountV0}; use crate::state_transition::batch_transition::token_base_transition::token_base_transition_accessors::TokenBaseTransitionAccessors; use crate::state_transition::batch_transition::token_base_transition::v0::v0_methods::TokenBaseTransitionV0Methods; use crate::state_transition::batch_transition::token_transfer_transition::v0::v0_methods::TokenTransferTransitionV0Methods; @@ -10,22 +11,25 @@ use crate::state_transition::batch_transition::TokenTransferTransition; use crate::tokens::MAX_TOKEN_NOTE_LEN; use crate::validation::SimpleConsensusValidationResult; -pub(super) trait TokenTransferTransitionActionStructureValidationV0 { +pub(super) trait TokenTransferTransitionActionStructureValidationV0: + ValidateTokenAmountV0 +{ fn validate_structure_v0( &self, owner_id: Identifier, ) -> Result; } + +impl ValidateTokenAmountV0 for TokenTransferTransition {} + impl TokenTransferTransitionActionStructureValidationV0 for TokenTransferTransition { fn validate_structure_v0( &self, owner_id: Identifier, ) -> Result { - if self.amount() > i64::MAX as u64 { + if let Some(consensus_error) = self.validate_token_amount_v0(self.amount()) { return Ok(SimpleConsensusValidationResult::new_with_error( - ConsensusError::BasicError(BasicError::InvalidTokenAmountError( - InvalidTokenAmountError::new(i64::MAX as u64, self.amount()), - )), + consensus_error, )); } diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/validate_token_amount.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/validate_token_amount.rs new file mode 100644 index 00000000000..b7cb7f26403 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/validate_token_amount.rs @@ -0,0 +1,17 @@ +use crate::balances::credits::{TokenAmount, TOKEN_MAX_AMOUNT}; +use crate::consensus::basic::token::{InvalidTokenAmountError, ZeroTokenAmountError}; +use crate::consensus::ConsensusError; + +pub(super) trait ValidateTokenAmountV0 { + fn validate_token_amount_v0(&self, amount: TokenAmount) -> Option { + if amount == 0 { + return Some(ZeroTokenAmountError::new().into()); + } + + if amount > TOKEN_MAX_AMOUNT { + return Some(InvalidTokenAmountError::new(TOKEN_MAX_AMOUNT, amount).into()); + }; + + None + } +} diff --git a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/mod.rs b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/mod.rs index 8ceadd2f9f6..63fd315d88b 100644 --- a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/mod.rs +++ b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/mod.rs @@ -120,6 +120,9 @@ pub struct DriveAbciDocumentsStateTransitionValidationVersions { pub token_base_transition_group_action_validation: FeatureVersion, pub token_claim_transition_structure_validation: FeatureVersion, pub token_claim_transition_state_validation: FeatureVersion, + pub token_order_buy_limit_transition_structure_validation: FeatureVersion, + pub token_order_sell_limit_transition_structure_validation: FeatureVersion, + pub token_order_adjust_price_transition_structure_validation: FeatureVersion, } #[derive(Clone, Debug, Default)] diff --git a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v1.rs b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v1.rs index 2ea70f9c38c..da6d3074b03 100644 --- a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v1.rs +++ b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v1.rs @@ -151,6 +151,9 @@ pub const DRIVE_ABCI_VALIDATION_VERSIONS_V1: DriveAbciValidationVersions = token_base_transition_group_action_validation: 0, token_claim_transition_structure_validation: 0, token_claim_transition_state_validation: 0, + token_order_buy_limit_transition_structure_validation: 0, + token_order_sell_limit_transition_structure_validation: 0, + token_order_adjust_price_transition_structure_validation: 0, }, }, has_nonce_validation: 0, diff --git a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v2.rs b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v2.rs index c5f280b3b17..cec5204b566 100644 --- a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v2.rs +++ b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v2.rs @@ -151,6 +151,9 @@ pub const DRIVE_ABCI_VALIDATION_VERSIONS_V2: DriveAbciValidationVersions = token_base_transition_group_action_validation: 0, token_claim_transition_structure_validation: 0, token_claim_transition_state_validation: 0, + token_order_buy_limit_transition_structure_validation: 0, + token_order_sell_limit_transition_structure_validation: 0, + token_order_adjust_price_transition_structure_validation: 0, }, }, has_nonce_validation: 0, diff --git a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v3.rs b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v3.rs index 758e340218d..52b2cea35ab 100644 --- a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v3.rs +++ b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v3.rs @@ -151,6 +151,9 @@ pub const DRIVE_ABCI_VALIDATION_VERSIONS_V3: DriveAbciValidationVersions = token_base_transition_group_action_validation: 0, token_claim_transition_structure_validation: 0, token_claim_transition_state_validation: 0, + token_order_buy_limit_transition_structure_validation: 0, + token_order_sell_limit_transition_structure_validation: 0, + token_order_adjust_price_transition_structure_validation: 0, }, }, has_nonce_validation: 0, diff --git a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v4.rs b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v4.rs index 7b1ed68b745..37afb48d380 100644 --- a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v4.rs +++ b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v4.rs @@ -154,6 +154,9 @@ pub const DRIVE_ABCI_VALIDATION_VERSIONS_V4: DriveAbciValidationVersions = token_base_transition_group_action_validation: 0, token_claim_transition_structure_validation: 0, token_claim_transition_state_validation: 0, + token_order_buy_limit_transition_structure_validation: 0, + token_order_sell_limit_transition_structure_validation: 0, + token_order_adjust_price_transition_structure_validation: 0, }, }, has_nonce_validation: 1, // <---- changed this diff --git a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v5.rs b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v5.rs index 41946b98be5..3022ce399dc 100644 --- a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v5.rs +++ b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v5.rs @@ -155,6 +155,9 @@ pub const DRIVE_ABCI_VALIDATION_VERSIONS_V5: DriveAbciValidationVersions = token_base_transition_group_action_validation: 0, token_claim_transition_structure_validation: 0, token_claim_transition_state_validation: 0, + token_order_buy_limit_transition_structure_validation: 0, + token_order_sell_limit_transition_structure_validation: 0, + token_order_adjust_price_transition_structure_validation: 0, }, }, has_nonce_validation: 1, diff --git a/packages/wasm-dpp/src/errors/consensus/consensus_error.rs b/packages/wasm-dpp/src/errors/consensus/consensus_error.rs index 90a642897b0..d93a43ddaa8 100644 --- a/packages/wasm-dpp/src/errors/consensus/consensus_error.rs +++ b/packages/wasm-dpp/src/errors/consensus/consensus_error.rs @@ -66,7 +66,7 @@ use dpp::consensus::basic::document::{ContestedDocumentsTemporarilyNotAllowedErr use dpp::consensus::basic::group::GroupActionNotAllowedOnTransitionError; use dpp::consensus::basic::identity::{DataContractBoundsNotPresentError, DisablingKeyIdAlsoBeingAddedInSameTransitionError, InvalidIdentityCreditWithdrawalTransitionAmountError, InvalidIdentityUpdateTransitionDisableKeysError, InvalidIdentityUpdateTransitionEmptyError, TooManyMasterPublicKeyError, WithdrawalOutputScriptNotAllowedWhenSigningWithOwnerKeyError}; use dpp::consensus::basic::overflow_error::OverflowError; -use dpp::consensus::basic::token::{ChoosingTokenMintRecipientNotAllowedError, ContractHasNoTokensError, DestinationIdentityForTokenMintingNotSetError, InvalidActionIdError, InvalidTokenAmountError, InvalidTokenConfigUpdateNoChangeError, InvalidTokenIdError, InvalidTokenNoteTooBigError, InvalidTokenPositionError, MissingDefaultLocalizationError, TokenTransferToOurselfError}; +use dpp::consensus::basic::token::{ChoosingTokenMintRecipientNotAllowedError, ContractHasNoTokensError, DestinationIdentityForTokenMintingNotSetError, InvalidActionIdError, InvalidTokenAmountError, InvalidTokenConfigUpdateNoChangeError, InvalidTokenIdError, InvalidTokenNoteTooBigError, InvalidTokenPositionError, MissingDefaultLocalizationError, TokenTransferToOurselfError, ZeroTokenAmountError, ZeroTokenPriceError}; use dpp::consensus::state::data_contract::data_contract_update_action_not_allowed_error::DataContractUpdateActionNotAllowedError; use dpp::consensus::state::data_contract::document_type_update_error::DocumentTypeUpdateError; use dpp::consensus::state::document::document_contest_currently_locked_error::DocumentContestCurrentlyLockedError; @@ -740,6 +740,12 @@ fn from_basic_error(basic_error: &BasicError) -> JsValue { BasicError::InvalidTokenNoteTooBigError(e) => { generic_consensus_error!(InvalidTokenNoteTooBigError, e).into() } + BasicError::ZeroTokenPriceError(e) => { + generic_consensus_error!(ZeroTokenPriceError, e).into() + } + BasicError::ZeroTokenAmountError(e) => { + generic_consensus_error!(ZeroTokenAmountError, e).into() + } BasicError::MissingDefaultLocalizationError(e) => { generic_consensus_error!(MissingDefaultLocalizationError, e).into() } From 9df654f1b36eaa1aed860e562207024a6da3f3d9 Mon Sep 17 00:00:00 2001 From: Ivan Shumkov Date: Sat, 29 Mar 2025 13:45:54 +0700 Subject: [PATCH 2/6] refactor: rename TokenOrderCancelLimitTransition --- .../token_order_cancel_transition/accessors.rs | 16 ++++++++-------- .../token_order_cancel_transition/transition.rs | 10 +++++----- .../v0/accessors.rs | 8 ++++---- .../v0/transition.rs | 2 +- 4 files changed, 18 insertions(+), 18 deletions(-) diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_cancel_transition/accessors.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_cancel_transition/accessors.rs index 71044dff35a..f611dae57ab 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_cancel_transition/accessors.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_cancel_transition/accessors.rs @@ -1,11 +1,11 @@ use platform_value::Identifier; use crate::prelude::Revision; -use crate::state_transition::batch_transition::batched_transition::token_order_cancel_transition::transition::TokenOrderCancelLimitTransition; -use crate::state_transition::batch_transition::batched_transition::token_order_cancel_transition::v0::accessors::TokenOrderCancelLimitTransitionV0Methods; +use crate::state_transition::batch_transition::batched_transition::token_order_cancel_transition::transition::TokenOrderCancelTransition; +use crate::state_transition::batch_transition::batched_transition::token_order_cancel_transition::v0::accessors::TokenOrderCancelTransitionV0Methods; use crate::state_transition::batch_transition::token_base_transition::token_base_transition_accessors::TokenBaseTransitionAccessors; use crate::state_transition::batch_transition::token_base_transition::TokenBaseTransition; -impl TokenBaseTransitionAccessors for TokenOrderCancelLimitTransition { +impl TokenBaseTransitionAccessors for TokenOrderCancelTransition { fn base(&self) -> &TokenBaseTransition { match self { Self::V0(v0) => v0.base(), @@ -25,28 +25,28 @@ impl TokenBaseTransitionAccessors for TokenOrderCancelLimitTransition { } } -impl TokenOrderCancelLimitTransitionV0Methods for TokenOrderCancelLimitTransition { +impl TokenOrderCancelTransitionV0Methods for TokenOrderCancelTransition { fn order_id(&self) -> Identifier { match self { - TokenOrderCancelLimitTransition::V0(v0) => v0.order_id(), + TokenOrderCancelTransition::V0(v0) => v0.order_id(), } } fn set_order_id(&mut self, id: Identifier) { match self { - TokenOrderCancelLimitTransition::V0(v0) => v0.set_order_id(id), + TokenOrderCancelTransition::V0(v0) => v0.set_order_id(id), } } fn order_revision(&self) -> Revision { match self { - TokenOrderCancelLimitTransition::V0(v0) => v0.order_revision(), + TokenOrderCancelTransition::V0(v0) => v0.order_revision(), } } fn set_order_revision(&mut self, revision: Revision) { match self { - TokenOrderCancelLimitTransition::V0(v0) => v0.set_order_revision(revision), + TokenOrderCancelTransition::V0(v0) => v0.set_order_revision(revision), } } } diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_cancel_transition/transition.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_cancel_transition/transition.rs index 357b2c67af9..35447485080 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_cancel_transition/transition.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_cancel_transition/transition.rs @@ -2,21 +2,21 @@ use bincode::{Decode, Encode}; use derive_more::{Display, From}; #[cfg(feature = "state-transition-serde-conversion")] use serde::{Deserialize, Serialize}; -use crate::state_transition::batch_transition::batched_transition::token_order_cancel_transition::v0::transition::TokenOrderCancelLimitTransitionV0; +use crate::state_transition::batch_transition::batched_transition::token_order_cancel_transition::v0::transition::TokenOrderCancelTransitionV0; #[derive(Debug, Clone, Encode, Decode, PartialEq, Display, From)] #[cfg_attr( feature = "state-transition-serde-conversion", derive(Serialize, Deserialize) )] -pub enum TokenOrderCancelLimitTransition { +pub enum TokenOrderCancelTransition { #[display("V0({})", "_0")] - V0(TokenOrderCancelLimitTransitionV0), + V0(TokenOrderCancelTransitionV0), } -impl Default for TokenOrderCancelLimitTransition { +impl Default for TokenOrderCancelTransition { fn default() -> Self { - TokenOrderCancelLimitTransition::V0(TokenOrderCancelLimitTransitionV0::default()) + TokenOrderCancelTransition::V0(TokenOrderCancelTransitionV0::default()) // since only v0 } } diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_cancel_transition/v0/accessors.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_cancel_transition/v0/accessors.rs index d8a59269349..435d9edf07e 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_cancel_transition/v0/accessors.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_cancel_transition/v0/accessors.rs @@ -2,11 +2,11 @@ use platform_value::Identifier; use crate::balances::credits::TokenAmount; use crate::fee::Credits; use crate::prelude::Revision; -use crate::state_transition::batch_transition::batched_transition::token_order_cancel_transition::v0::transition::TokenOrderCancelLimitTransitionV0; +use crate::state_transition::batch_transition::batched_transition::token_order_cancel_transition::v0::transition::TokenOrderCancelTransitionV0; use crate::state_transition::batch_transition::token_base_transition::token_base_transition_accessors::TokenBaseTransitionAccessors; use crate::state_transition::batch_transition::token_base_transition::TokenBaseTransition; -impl TokenBaseTransitionAccessors for TokenOrderCancelLimitTransitionV0 { +impl TokenBaseTransitionAccessors for TokenOrderCancelTransitionV0 { fn base(&self) -> &TokenBaseTransition { &self.base } @@ -20,7 +20,7 @@ impl TokenBaseTransitionAccessors for TokenOrderCancelLimitTransitionV0 { } } -pub trait TokenOrderCancelLimitTransitionV0Methods: TokenBaseTransitionAccessors { +pub trait TokenOrderCancelTransitionV0Methods: TokenBaseTransitionAccessors { /// Order ID to cancel fn order_id(&self) -> Identifier; @@ -34,7 +34,7 @@ pub trait TokenOrderCancelLimitTransitionV0Methods: TokenBaseTransitionAccessors fn set_order_revision(&mut self, revision: Revision); } -impl TokenOrderCancelLimitTransitionV0Methods for TokenOrderCancelLimitTransitionV0 { +impl TokenOrderCancelTransitionV0Methods for TokenOrderCancelTransitionV0 { fn order_id(&self) -> Identifier { self.order_id } diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_cancel_transition/v0/transition.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_cancel_transition/v0/transition.rs index 48a61cbbb01..7501934870f 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_cancel_transition/v0/transition.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_cancel_transition/v0/transition.rs @@ -13,7 +13,7 @@ use serde::{Deserialize, Serialize}; serde(rename_all = "camelCase") )] #[display("Base: {base}, Order ID: {order_id}, Order Revision: {order_revision} credits")] -pub struct TokenOrderCancelLimitTransitionV0 { +pub struct TokenOrderCancelTransitionV0 { /// Document Base Transition #[cfg_attr(feature = "state-transition-serde-conversion", serde(flatten))] pub(super) base: TokenBaseTransition, From c8a99c8f85b7867ac45df266173de4c7e4d090e5 Mon Sep 17 00:00:00 2001 From: Ivan Shumkov Date: Sat, 29 Mar 2025 17:43:43 +0700 Subject: [PATCH 3/6] refactor: deduplicate validation logic a bit --- .../src/errors/consensus/basic/basic_error.rs | 7 +- .../basic/token/invalid_token_price_error.rs | 46 +++++ .../src/errors/consensus/basic/token/mod.rs | 2 + packages/rs-dpp/src/errors/consensus/codes.rs | 1 + packages/rs-dpp/src/state_transition/mod.rs | 12 ++ .../batched_transition/document_transition.rs | 20 ++ .../batched_transition/mod.rs | 2 +- .../batched_transition/resolvers.rs | 60 ++++++ .../validate_structure/v0/mod.rs | 32 +-- .../validate_structure/v0/mod.rs | 22 +-- .../validate_structure/v0/mod.rs | 23 +-- .../validate_structure/v0/mod.rs | 17 +- .../validate_structure/v0/mod.rs | 17 +- .../validate_structure/v0/mod.rs | 17 +- .../validate_structure/v0/mod.rs | 33 +--- .../validate_structure/v0.rs | 10 +- .../validate_structure/v0.rs | 23 +-- .../validate_structure/v0.rs | 23 +-- .../validate_structure/v0/mod.rs | 61 ++---- .../batched_transition/token_transition.rs | 183 ++++++++++++------ .../token_transition_action_type.rs | 12 ++ .../validate_structure/v0/mod.rs | 17 +- .../validate_token_amount.rs | 17 -- .../batched_transition/validation.rs | 50 +++++ .../batch_transition/resolvers/v0/mod.rs | 12 ++ .../validate_basic_structure/v0/mod.rs | 13 ++ packages/rs-dpp/src/tokens/token_event.rs | 2 + 27 files changed, 442 insertions(+), 292 deletions(-) create mode 100644 packages/rs-dpp/src/errors/consensus/basic/token/invalid_token_price_error.rs delete mode 100644 packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/validate_token_amount.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/validation.rs diff --git a/packages/rs-dpp/src/errors/consensus/basic/basic_error.rs b/packages/rs-dpp/src/errors/consensus/basic/basic_error.rs index 645b7f0f35b..8a9c08fca58 100644 --- a/packages/rs-dpp/src/errors/consensus/basic/basic_error.rs +++ b/packages/rs-dpp/src/errors/consensus/basic/basic_error.rs @@ -78,8 +78,8 @@ use crate::consensus::basic::token::{ ChoosingTokenMintRecipientNotAllowedError, ContractHasNoTokensError, DestinationIdentityForTokenMintingNotSetError, InvalidActionIdError, InvalidTokenAmountError, InvalidTokenConfigUpdateNoChangeError, InvalidTokenIdError, InvalidTokenNoteTooBigError, - InvalidTokenPositionError, MissingDefaultLocalizationError, TokenTransferToOurselfError, - ZeroTokenAmountError, ZeroTokenPriceError, + InvalidTokenPositionError, InvalidTokenPriceError, MissingDefaultLocalizationError, + TokenTransferToOurselfError, ZeroTokenAmountError, ZeroTokenPriceError, }; use crate::consensus::basic::unsupported_version_error::UnsupportedVersionError; use crate::consensus::basic::value_error::ValueError; @@ -508,6 +508,9 @@ pub enum BasicError { #[error(transparent)] ZeroTokenPriceError(ZeroTokenPriceError), + + #[error(transparent)] + InvalidTokenPriceError(InvalidTokenPriceError), } impl From for ConsensusError { diff --git a/packages/rs-dpp/src/errors/consensus/basic/token/invalid_token_price_error.rs b/packages/rs-dpp/src/errors/consensus/basic/token/invalid_token_price_error.rs new file mode 100644 index 00000000000..545c5e872e7 --- /dev/null +++ b/packages/rs-dpp/src/errors/consensus/basic/token/invalid_token_price_error.rs @@ -0,0 +1,46 @@ +use crate::consensus::basic::BasicError; +use crate::consensus::ConsensusError; +use crate::ProtocolError; +use bincode::{Decode, Encode}; +use platform_serialization_derive::{PlatformDeserialize, PlatformSerialize}; +use thiserror::Error; + +#[derive( + Error, Debug, Clone, PartialEq, Eq, Encode, Decode, PlatformSerialize, PlatformDeserialize, +)] +#[error( + "Invalid token price {}, exceeds maximum allowed {}", + token_price, + max_token_price +)] +#[platform_serialize(unversioned)] +pub struct InvalidTokenPriceError { + max_token_price: u64, + token_price: u64, +} + +impl InvalidTokenPriceError { + /// Creates a new `InvalidTokenPriceError`. + pub fn new(max_token_price: u64, token_price: u64) -> Self { + Self { + max_token_price, + token_price, + } + } + + /// Returns the maximum allowed token price. + pub fn max_token_price(&self) -> u64 { + self.max_token_price + } + + /// Returns the invalid token price that was provided. + pub fn token_price(&self) -> u64 { + self.token_price + } +} + +impl From for ConsensusError { + fn from(err: InvalidTokenPriceError) -> Self { + Self::BasicError(BasicError::InvalidTokenPriceError(err)) + } +} diff --git a/packages/rs-dpp/src/errors/consensus/basic/token/mod.rs b/packages/rs-dpp/src/errors/consensus/basic/token/mod.rs index f7cef9e3824..da72e87bb65 100644 --- a/packages/rs-dpp/src/errors/consensus/basic/token/mod.rs +++ b/packages/rs-dpp/src/errors/consensus/basic/token/mod.rs @@ -7,6 +7,7 @@ mod invalid_token_config_update_no_change_error; mod invalid_token_id_error; mod invalid_token_note_too_big_error; mod invalid_token_position_error; +mod invalid_token_price_error; mod missing_default_localization; mod token_transfer_to_ourselves_error; mod zero_token_amount_error; @@ -21,6 +22,7 @@ pub use invalid_token_config_update_no_change_error::*; pub use invalid_token_id_error::*; pub use invalid_token_note_too_big_error::*; pub use invalid_token_position_error::*; +pub use invalid_token_price_error::*; pub use missing_default_localization::*; pub use token_transfer_to_ourselves_error::*; pub use zero_token_amount_error::*; diff --git a/packages/rs-dpp/src/errors/consensus/codes.rs b/packages/rs-dpp/src/errors/consensus/codes.rs index 15d796d2e4d..75d96e204e8 100644 --- a/packages/rs-dpp/src/errors/consensus/codes.rs +++ b/packages/rs-dpp/src/errors/consensus/codes.rs @@ -147,6 +147,7 @@ impl ErrorWithCode for BasicError { Self::InvalidTokenNoteTooBigError(_) => 10459, Self::ZeroTokenAmountError(_) => 10460, Self::ZeroTokenPriceError(_) => 10461, + Self::InvalidTokenPriceError(_) => 10462, // Identity Errors: 10500-10599 Self::DuplicatedIdentityPublicKeyBasicError(_) => 10500, diff --git a/packages/rs-dpp/src/state_transition/mod.rs b/packages/rs-dpp/src/state_transition/mod.rs index 782c970aa04..d02f566289d 100644 --- a/packages/rs-dpp/src/state_transition/mod.rs +++ b/packages/rs-dpp/src/state_transition/mod.rs @@ -362,6 +362,18 @@ impl StateTransition { "TokenConfigUpdate" } BatchedTransitionRef::Token(TokenTransition::Claim(_)) => "TokenClaim", + BatchedTransitionRef::Token(TokenTransition::OrderBuyLimit(_)) => { + "TokenOrderBuyLimit" + } + BatchedTransitionRef::Token(TokenTransition::OrderSellLimit(_)) => { + "TokenOrderSellLimit" + } + BatchedTransitionRef::Token(TokenTransition::OrderCancel(_)) => { + "TokenOrderCancel" + } + BatchedTransitionRef::Token(TokenTransition::OrderAdjustPrice(_)) => { + "TokenOrderAdjustPrice" + } }; document_transition_types.push(document_transition_name); } diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_transition.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_transition.rs index ed63c8524a7..53a9fed59a1 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_transition.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_transition.rs @@ -10,6 +10,10 @@ use crate::state_transition::batch_transition::batched_transition::{DocumentPurc use crate::state_transition::batch_transition::batched_transition::document_purchase_transition::v0::v0_methods::DocumentPurchaseTransitionV0Methods; use crate::state_transition::batch_transition::batched_transition::document_transfer_transition::v0::v0_methods::DocumentTransferTransitionV0Methods; use crate::state_transition::batch_transition::batched_transition::document_update_price_transition::v0::v0_methods::DocumentUpdatePriceTransitionV0Methods; +use crate::state_transition::batch_transition::batched_transition::token_order_adjust_price_transition::transition::TokenOrderAdjustPriceTransition; +use crate::state_transition::batch_transition::batched_transition::token_order_buy_limit_transition::transition::TokenOrderBuyLimitTransition; +use crate::state_transition::batch_transition::batched_transition::token_order_cancel_transition::transition::TokenOrderCancelTransition; +use crate::state_transition::batch_transition::batched_transition::token_order_sell_limit_transition::transition::TokenOrderSellLimitTransition; use crate::state_transition::batch_transition::document_base_transition::document_base_transition_trait::DocumentBaseTransitionAccessors; use crate::state_transition::batch_transition::document_base_transition::DocumentBaseTransition; use crate::state_transition::batch_transition::document_base_transition::v0::v0_methods::DocumentBaseTransitionV0Methods; @@ -119,6 +123,22 @@ impl BatchTransitionResolversV0 for DocumentTransition { fn as_transition_token_config_update(&self) -> Option<&TokenConfigUpdateTransition> { None } + + fn as_transition_token_order_buy_limit(&self) -> Option<&TokenOrderBuyLimitTransition> { + None + } + + fn as_transition_token_order_sell_limit(&self) -> Option<&TokenOrderSellLimitTransition> { + None + } + + fn as_transition_token_order_cancel(&self) -> Option<&TokenOrderCancelTransition> { + None + } + + fn as_transition_token_order_adjust_price(&self) -> Option<&TokenOrderAdjustPriceTransition> { + None + } } pub trait DocumentTransitionV0Methods { diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/mod.rs index d6ce8e95638..c19c080b4c8 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/mod.rs @@ -30,7 +30,7 @@ pub mod token_transfer_transition; pub mod token_transition; pub mod token_transition_action_type; pub mod token_unfreeze_transition; -mod validate_token_amount; +mod validation; use crate::prelude::IdentityNonce; use crate::state_transition::batch_transition::batched_transition::document_transition::DocumentTransitionV0Methods; diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/resolvers.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/resolvers.rs index 83ead62c008..e6981f1e930 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/resolvers.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/resolvers.rs @@ -8,6 +8,10 @@ use crate::state_transition::batch_transition::{ TokenDestroyFrozenFundsTransition, TokenEmergencyActionTransition, TokenFreezeTransition, TokenMintTransition, TokenTransferTransition, TokenUnfreezeTransition, }; +use crate::state_transition::batch_transition::batched_transition::token_order_adjust_price_transition::transition::TokenOrderAdjustPriceTransition; +use crate::state_transition::batch_transition::batched_transition::token_order_buy_limit_transition::transition::TokenOrderBuyLimitTransition; +use crate::state_transition::batch_transition::batched_transition::token_order_cancel_transition::transition::TokenOrderCancelTransition; +use crate::state_transition::batch_transition::batched_transition::token_order_sell_limit_transition::transition::TokenOrderSellLimitTransition; impl BatchTransitionResolversV0 for BatchedTransition { fn as_transition_create(&self) -> Option<&DocumentCreateTransition> { @@ -109,6 +113,34 @@ impl BatchTransitionResolversV0 for BatchedTransition { BatchedTransition::Token(token) => token.as_transition_token_config_update(), } } + + fn as_transition_token_order_buy_limit(&self) -> Option<&TokenOrderBuyLimitTransition> { + match self { + BatchedTransition::Document(_) => None, + BatchedTransition::Token(token) => token.as_transition_token_order_buy_limit(), + } + } + + fn as_transition_token_order_sell_limit(&self) -> Option<&TokenOrderSellLimitTransition> { + match self { + BatchedTransition::Document(_) => None, + BatchedTransition::Token(token) => token.as_transition_token_order_sell_limit(), + } + } + + fn as_transition_token_order_cancel(&self) -> Option<&TokenOrderCancelTransition> { + match self { + BatchedTransition::Document(_) => None, + BatchedTransition::Token(token) => token.as_transition_token_order_cancel(), + } + } + + fn as_transition_token_order_adjust_price(&self) -> Option<&TokenOrderAdjustPriceTransition> { + match self { + BatchedTransition::Document(_) => None, + BatchedTransition::Token(token) => token.as_transition_token_order_adjust_price(), + } + } } impl BatchTransitionResolversV0 for BatchedTransitionRef<'_> { @@ -211,4 +243,32 @@ impl BatchTransitionResolversV0 for BatchedTransitionRef<'_> { BatchedTransitionRef::Token(token) => token.as_transition_token_config_update(), } } + + fn as_transition_token_order_buy_limit(&self) -> Option<&TokenOrderBuyLimitTransition> { + match self { + BatchedTransitionRef::Document(_) => None, + BatchedTransitionRef::Token(token) => token.as_transition_token_order_buy_limit(), + } + } + + fn as_transition_token_order_sell_limit(&self) -> Option<&TokenOrderSellLimitTransition> { + match self { + BatchedTransitionRef::Document(_) => None, + BatchedTransitionRef::Token(token) => token.as_transition_token_order_sell_limit(), + } + } + + fn as_transition_token_order_cancel(&self) -> Option<&TokenOrderCancelTransition> { + match self { + BatchedTransitionRef::Document(_) => None, + BatchedTransitionRef::Token(token) => token.as_transition_token_order_cancel(), + } + } + + fn as_transition_token_order_adjust_price(&self) -> Option<&TokenOrderAdjustPriceTransition> { + match self { + BatchedTransitionRef::Document(_) => None, + BatchedTransitionRef::Token(token) => token.as_transition_token_order_adjust_price(), + } + } } diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_burn_transition/validate_structure/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_burn_transition/validate_structure/v0/mod.rs index 9755b5dcd94..0730ee4c170 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_burn_transition/validate_structure/v0/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_burn_transition/validate_structure/v0/mod.rs @@ -1,43 +1,27 @@ use crate::consensus::basic::token::InvalidTokenNoteTooBigError; use crate::consensus::basic::BasicError; use crate::consensus::ConsensusError; -use crate::state_transition::batch_transition::batched_transition::validate_token_amount::ValidateTokenAmountV0; +use crate::state_transition::batch_transition::batched_transition::validation::{ + validate_public_note, validate_token_amount_v0, +}; use crate::state_transition::batch_transition::token_burn_transition::v0::v0_methods::TokenBurnTransitionV0Methods; use crate::state_transition::batch_transition::TokenBurnTransition; use crate::tokens::MAX_TOKEN_NOTE_LEN; use crate::validation::SimpleConsensusValidationResult; use crate::ProtocolError; -pub(super) trait TokenBurnTransitionActionStructureValidationV0: - ValidateTokenAmountV0 -{ +pub(super) trait TokenBurnTransitionActionStructureValidationV0 { fn validate_structure_v0(&self) -> Result; } -impl ValidateTokenAmountV0 for TokenBurnTransition {} - impl TokenBurnTransitionActionStructureValidationV0 for TokenBurnTransition { fn validate_structure_v0(&self) -> Result { - if let Some(consensus_error) = self.validate_token_amount_v0(self.burn_amount()) { - return Ok(SimpleConsensusValidationResult::new_with_error( - consensus_error, - )); - } + let mut result = validate_token_amount_v0(self.burn_amount()); if let Some(public_note) = self.public_note() { - if public_note.len() > MAX_TOKEN_NOTE_LEN { - return Ok(SimpleConsensusValidationResult::new_with_error( - ConsensusError::BasicError(BasicError::InvalidTokenNoteTooBigError( - InvalidTokenNoteTooBigError::new( - MAX_TOKEN_NOTE_LEN as u32, - "public_note", - public_note.len() as u32, - ), - )), - )); - } - } + result.merge(validate_public_note(public_note)); + }; - Ok(SimpleConsensusValidationResult::default()) + Ok(result) } } diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_claim_transition/validate_structure/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_claim_transition/validate_structure/v0/mod.rs index 6bd29b50c81..794bcd3ac8e 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_claim_transition/validate_structure/v0/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_claim_transition/validate_structure/v0/mod.rs @@ -1,9 +1,6 @@ -use crate::consensus::basic::token::InvalidTokenNoteTooBigError; -use crate::consensus::basic::BasicError; -use crate::consensus::ConsensusError; +use crate::state_transition::batch_transition::batched_transition::validation::validate_public_note; use crate::state_transition::batch_transition::token_claim_transition::v0::v0_methods::TokenClaimTransitionV0Methods; use crate::state_transition::batch_transition::TokenClaimTransition; -use crate::tokens::MAX_TOKEN_NOTE_LEN; use crate::validation::SimpleConsensusValidationResult; use crate::ProtocolError; @@ -12,19 +9,12 @@ pub(super) trait TokenClaimTransitionActionStructureValidationV0 { } impl TokenClaimTransitionActionStructureValidationV0 for TokenClaimTransition { fn validate_structure_v0(&self) -> Result { + let mut result = SimpleConsensusValidationResult::new(); + if let Some(public_note) = self.public_note() { - if public_note.len() > MAX_TOKEN_NOTE_LEN { - return Ok(SimpleConsensusValidationResult::new_with_error( - ConsensusError::BasicError(BasicError::InvalidTokenNoteTooBigError( - InvalidTokenNoteTooBigError::new( - MAX_TOKEN_NOTE_LEN as u32, - "public_note", - public_note.len() as u32, - ), - )), - )); - } + result.merge(validate_public_note(public_note)); } - Ok(SimpleConsensusValidationResult::default()) + + Ok(result) } } diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_config_update_transition/validate_structure/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_config_update_transition/validate_structure/v0/mod.rs index 85b7eafd98d..e1c05cda52f 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_config_update_transition/validate_structure/v0/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_config_update_transition/validate_structure/v0/mod.rs @@ -4,6 +4,7 @@ use crate::consensus::basic::token::{ use crate::consensus::basic::BasicError; use crate::consensus::ConsensusError; use crate::data_contract::associated_token::token_configuration_item::TokenConfigurationChangeItem; +use crate::state_transition::batch_transition::batched_transition::validation::validate_public_note; use crate::state_transition::batch_transition::token_config_update_transition::v0::v0_methods::TokenConfigUpdateTransitionV0Methods; use crate::state_transition::batch_transition::TokenConfigUpdateTransition; use crate::tokens::MAX_TOKEN_NOTE_LEN; @@ -15,31 +16,19 @@ pub(super) trait TokenConfigUpdateTransitionStructureValidationV0 { } impl TokenConfigUpdateTransitionStructureValidationV0 for TokenConfigUpdateTransition { fn validate_structure_v0(&self) -> Result { + let mut result = SimpleConsensusValidationResult::new(); + if matches!( self.update_token_configuration_item(), TokenConfigurationChangeItem::TokenConfigurationNoChange ) { - return Ok(SimpleConsensusValidationResult::new_with_error( - ConsensusError::BasicError(BasicError::InvalidTokenConfigUpdateNoChangeError( - InvalidTokenConfigUpdateNoChangeError::new(), - )), - )); + result.add_error(InvalidTokenConfigUpdateNoChangeError::new()); } if let Some(public_note) = self.public_note() { - if public_note.len() > MAX_TOKEN_NOTE_LEN { - return Ok(SimpleConsensusValidationResult::new_with_error( - ConsensusError::BasicError(BasicError::InvalidTokenNoteTooBigError( - InvalidTokenNoteTooBigError::new( - MAX_TOKEN_NOTE_LEN as u32, - "public_note", - public_note.len() as u32, - ), - )), - )); - } + result.merge(validate_public_note(public_note)); } - Ok(SimpleConsensusValidationResult::default()) + Ok(result) } } diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_destroy_frozen_funds_transition/validate_structure/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_destroy_frozen_funds_transition/validate_structure/v0/mod.rs index e9eee6c1df9..0cc1885ed8a 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_destroy_frozen_funds_transition/validate_structure/v0/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_destroy_frozen_funds_transition/validate_structure/v0/mod.rs @@ -4,6 +4,7 @@ use crate::validation::SimpleConsensusValidationResult; use crate::consensus::basic::BasicError; use crate::consensus::basic::token::InvalidTokenNoteTooBigError; use crate::consensus::ConsensusError; +use crate::state_transition::batch_transition::batched_transition::validation::validate_public_note; use crate::state_transition::batch_transition::token_destroy_frozen_funds_transition::v0::v0_methods::TokenDestroyFrozenFundsTransitionV0Methods; use crate::tokens::MAX_TOKEN_NOTE_LEN; @@ -12,20 +13,12 @@ pub(super) trait TokenDestroyFrozenFundsTransitionStructureValidationV0 { } impl TokenDestroyFrozenFundsTransitionStructureValidationV0 for TokenDestroyFrozenFundsTransition { fn validate_structure_v0(&self) -> Result { + let mut result = SimpleConsensusValidationResult::new(); + if let Some(public_note) = self.public_note() { - if public_note.len() > MAX_TOKEN_NOTE_LEN { - return Ok(SimpleConsensusValidationResult::new_with_error( - ConsensusError::BasicError(BasicError::InvalidTokenNoteTooBigError( - InvalidTokenNoteTooBigError::new( - MAX_TOKEN_NOTE_LEN as u32, - "public_note", - public_note.len() as u32, - ), - )), - )); - } + result.merge(validate_public_note(public_note)); } - Ok(SimpleConsensusValidationResult::default()) + Ok(result) } } diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_emergency_action_transition/validate_structure/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_emergency_action_transition/validate_structure/v0/mod.rs index eb20e22b3b1..a90771d6299 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_emergency_action_transition/validate_structure/v0/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_emergency_action_transition/validate_structure/v0/mod.rs @@ -1,6 +1,7 @@ use crate::consensus::basic::token::InvalidTokenNoteTooBigError; use crate::consensus::basic::BasicError; use crate::consensus::ConsensusError; +use crate::state_transition::batch_transition::batched_transition::validation::validate_public_note; use crate::state_transition::batch_transition::token_emergency_action_transition::v0::v0_methods::TokenEmergencyActionTransitionV0Methods; use crate::state_transition::batch_transition::TokenEmergencyActionTransition; use crate::tokens::MAX_TOKEN_NOTE_LEN; @@ -12,20 +13,12 @@ pub(super) trait TokenEmergencyActionTransitionStructureValidationV0 { } impl TokenEmergencyActionTransitionStructureValidationV0 for TokenEmergencyActionTransition { fn validate_structure_v0(&self) -> Result { + let mut result = SimpleConsensusValidationResult::new(); + if let Some(public_note) = self.public_note() { - if public_note.len() > MAX_TOKEN_NOTE_LEN { - return Ok(SimpleConsensusValidationResult::new_with_error( - ConsensusError::BasicError(BasicError::InvalidTokenNoteTooBigError( - InvalidTokenNoteTooBigError::new( - MAX_TOKEN_NOTE_LEN as u32, - "public_note", - public_note.len() as u32, - ), - )), - )); - } + result.merge(validate_public_note(public_note)); } - Ok(SimpleConsensusValidationResult::default()) + Ok(result) } } diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_freeze_transition/validate_structure/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_freeze_transition/validate_structure/v0/mod.rs index d17507f87b7..2c71a861bb8 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_freeze_transition/validate_structure/v0/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_freeze_transition/validate_structure/v0/mod.rs @@ -1,6 +1,7 @@ use crate::consensus::basic::token::InvalidTokenNoteTooBigError; use crate::consensus::basic::BasicError; use crate::consensus::ConsensusError; +use crate::state_transition::batch_transition::batched_transition::validation::validate_public_note; use crate::state_transition::batch_transition::token_freeze_transition::v0::v0_methods::TokenFreezeTransitionV0Methods; use crate::state_transition::batch_transition::TokenFreezeTransition; use crate::tokens::MAX_TOKEN_NOTE_LEN; @@ -12,20 +13,12 @@ pub(super) trait TokenFreezeTransitionStructureValidationV0 { } impl TokenFreezeTransitionStructureValidationV0 for TokenFreezeTransition { fn validate_structure_v0(&self) -> Result { + let mut result = SimpleConsensusValidationResult::new(); + if let Some(public_note) = self.public_note() { - if public_note.len() > MAX_TOKEN_NOTE_LEN { - return Ok(SimpleConsensusValidationResult::new_with_error( - ConsensusError::BasicError(BasicError::InvalidTokenNoteTooBigError( - InvalidTokenNoteTooBigError::new( - MAX_TOKEN_NOTE_LEN as u32, - "public_note", - public_note.len() as u32, - ), - )), - )); - } + result.merge(validate_public_note(public_note)); } - Ok(SimpleConsensusValidationResult::default()) + Ok(result) } } diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_mint_transition/validate_structure/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_mint_transition/validate_structure/v0/mod.rs index 85d319ae1ff..86920822754 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_mint_transition/validate_structure/v0/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_mint_transition/validate_structure/v0/mod.rs @@ -1,42 +1,27 @@ use crate::consensus::basic::token::InvalidTokenNoteTooBigError; use crate::consensus::basic::BasicError; use crate::consensus::ConsensusError; -use crate::state_transition::batch_transition::batched_transition::validate_token_amount::ValidateTokenAmountV0; +use crate::state_transition::batch_transition::batched_transition::validation::{ + validate_public_note, validate_token_amount_v0, +}; use crate::state_transition::batch_transition::token_mint_transition::v0::v0_methods::TokenMintTransitionV0Methods; use crate::state_transition::batch_transition::TokenMintTransition; use crate::tokens::MAX_TOKEN_NOTE_LEN; use crate::validation::SimpleConsensusValidationResult; use crate::ProtocolError; -pub(super) trait TokenMintTransitionActionStructureValidationV0: - ValidateTokenAmountV0 -{ +pub(super) trait TokenMintTransitionActionStructureValidationV0 { fn validate_structure_v0(&self) -> Result; } -impl ValidateTokenAmountV0 for TokenMintTransition {} - impl TokenMintTransitionActionStructureValidationV0 for TokenMintTransition { fn validate_structure_v0(&self) -> Result { - if let Some(consensus_error) = self.validate_token_amount_v0(self.amount()) { - return Ok(SimpleConsensusValidationResult::new_with_error( - consensus_error, - )); - } + let mut result = validate_token_amount_v0(self.amount()); if let Some(public_note) = self.public_note() { - if public_note.len() > MAX_TOKEN_NOTE_LEN { - return Ok(SimpleConsensusValidationResult::new_with_error( - ConsensusError::BasicError(BasicError::InvalidTokenNoteTooBigError( - InvalidTokenNoteTooBigError::new( - MAX_TOKEN_NOTE_LEN as u32, - "public_note", - public_note.len() as u32, - ), - )), - )); - } - } - Ok(SimpleConsensusValidationResult::default()) + result.merge(validate_public_note(public_note)); + }; + + Ok(result) } } diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_adjust_price_transition/validate_structure/v0.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_adjust_price_transition/validate_structure/v0.rs index 2aff0277ba2..a029ce57094 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_adjust_price_transition/validate_structure/v0.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_adjust_price_transition/validate_structure/v0.rs @@ -1,8 +1,8 @@ -use crate::consensus::basic::token::ZeroTokenPriceError; use crate::validation::SimpleConsensusValidationResult; use crate::ProtocolError; use crate::state_transition::batch_transition::batched_transition::token_order_adjust_price_transition::transition::TokenOrderAdjustPriceTransition; use crate::state_transition::batch_transition::batched_transition::token_order_adjust_price_transition::v0::accessors::TokenOrderAdjustPriceTransitionV0Methods; +use crate::state_transition::batch_transition::batched_transition::validation::validate_token_price_v0; pub(super) trait TokenOrderAdjustPriceTransitionStructureValidationV0 { fn validate_structure_v0(&self) -> Result; @@ -10,12 +10,8 @@ pub(super) trait TokenOrderAdjustPriceTransitionStructureValidationV0 { impl TokenOrderAdjustPriceTransitionStructureValidationV0 for TokenOrderAdjustPriceTransition { fn validate_structure_v0(&self) -> Result { - if self.token_price() == 0 { - return Ok(SimpleConsensusValidationResult::new_with_error( - ZeroTokenPriceError::new().into(), - )); - } + let result = validate_token_price_v0(self.token_price()); - Ok(SimpleConsensusValidationResult::default()) + Ok(result) } } diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_buy_limit_transition/validate_structure/v0.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_buy_limit_transition/validate_structure/v0.rs index 94da730d41f..7d73f622b67 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_buy_limit_transition/validate_structure/v0.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_buy_limit_transition/validate_structure/v0.rs @@ -1,32 +1,19 @@ -use crate::consensus::basic::token::ZeroTokenPriceError; use crate::validation::SimpleConsensusValidationResult; use crate::ProtocolError; use crate::state_transition::batch_transition::batched_transition::token_order_buy_limit_transition::transition::TokenOrderBuyLimitTransition; use crate::state_transition::batch_transition::batched_transition::token_order_buy_limit_transition::v0::accessors::TokenOrderBuyLimitTransitionV0Methods; -use crate::state_transition::batch_transition::batched_transition::validate_token_amount::ValidateTokenAmountV0; +use crate::state_transition::batch_transition::batched_transition::validation::{validate_token_amount_v0, validate_token_price_v0}; -pub(super) trait TokenOrderBuyLimitTransitionStructureValidationV0: - ValidateTokenAmountV0 -{ +pub(super) trait TokenOrderBuyLimitTransitionStructureValidationV0 { fn validate_structure_v0(&self) -> Result; } -impl ValidateTokenAmountV0 for TokenOrderBuyLimitTransition {} - impl TokenOrderBuyLimitTransitionStructureValidationV0 for TokenOrderBuyLimitTransition { fn validate_structure_v0(&self) -> Result { - if let Some(consensus_error) = self.validate_token_amount_v0(self.token_amount()) { - return Ok(SimpleConsensusValidationResult::new_with_error( - consensus_error, - )); - } + let mut result = validate_token_amount_v0(self.token_amount()); - if self.token_max_price() == 0 { - return Ok(SimpleConsensusValidationResult::new_with_error( - ZeroTokenPriceError::new().into(), - )); - } + result.merge(validate_token_price_v0(self.token_max_price())); - Ok(SimpleConsensusValidationResult::default()) + Ok(result) } } diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_sell_limit_transition/validate_structure/v0.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_sell_limit_transition/validate_structure/v0.rs index fb7f93a1d51..a0b0c42dfc4 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_sell_limit_transition/validate_structure/v0.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_sell_limit_transition/validate_structure/v0.rs @@ -1,32 +1,19 @@ -use crate::consensus::basic::token::ZeroTokenPriceError; use crate::validation::SimpleConsensusValidationResult; use crate::ProtocolError; use crate::state_transition::batch_transition::batched_transition::token_order_sell_limit_transition::transition::TokenOrderSellLimitTransition; use crate::state_transition::batch_transition::batched_transition::token_order_sell_limit_transition::v0::accessors::TokenOrderSellLimitTransitionV0Methods; -use crate::state_transition::batch_transition::batched_transition::validate_token_amount::ValidateTokenAmountV0; +use crate::state_transition::batch_transition::batched_transition::validation::{validate_token_amount_v0, validate_token_price_v0}; -pub(super) trait TokenOrderSellLimitTransitionStructureValidationV0: - ValidateTokenAmountV0 -{ +pub(super) trait TokenOrderSellLimitTransitionStructureValidationV0 { fn validate_structure_v0(&self) -> Result; } -impl ValidateTokenAmountV0 for TokenOrderSellLimitTransition {} - impl TokenOrderSellLimitTransitionStructureValidationV0 for TokenOrderSellLimitTransition { fn validate_structure_v0(&self) -> Result { - if let Some(consensus_error) = self.validate_token_amount_v0(self.token_amount()) { - return Ok(SimpleConsensusValidationResult::new_with_error( - consensus_error, - )); - } + let mut result = validate_token_amount_v0(self.token_amount()); - if self.token_min_price() == 0 { - return Ok(SimpleConsensusValidationResult::new_with_error( - ZeroTokenPriceError::new().into(), - )); - } + result.merge(validate_token_price_v0(self.token_min_price())); - Ok(SimpleConsensusValidationResult::default()) + Ok(result) } } diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_transfer_transition/validate_structure/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_transfer_transition/validate_structure/v0/mod.rs index 02209ffa593..165ef0732a6 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_transfer_transition/validate_structure/v0/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_transfer_transition/validate_structure/v0/mod.rs @@ -1,9 +1,9 @@ use platform_value::Identifier; use crate::consensus::basic::BasicError; -use crate::consensus::basic::token::{InvalidTokenAmountError, InvalidTokenNoteTooBigError, TokenTransferToOurselfError, ZeroTokenAmountError}; +use crate::consensus::basic::token::{InvalidTokenNoteTooBigError, TokenTransferToOurselfError}; use crate::consensus::ConsensusError; use crate::ProtocolError; -use crate::state_transition::batch_transition::batched_transition::validate_token_amount::{ValidateTokenAmountV0}; +use crate::state_transition::batch_transition::batched_transition::validation::{validate_public_note, validate_token_amount_v0}; use crate::state_transition::batch_transition::token_base_transition::token_base_transition_accessors::TokenBaseTransitionAccessors; use crate::state_transition::batch_transition::token_base_transition::v0::v0_methods::TokenBaseTransitionV0Methods; use crate::state_transition::batch_transition::token_transfer_transition::v0::v0_methods::TokenTransferTransitionV0Methods; @@ -11,78 +11,51 @@ use crate::state_transition::batch_transition::TokenTransferTransition; use crate::tokens::MAX_TOKEN_NOTE_LEN; use crate::validation::SimpleConsensusValidationResult; -pub(super) trait TokenTransferTransitionActionStructureValidationV0: - ValidateTokenAmountV0 -{ +pub(super) trait TokenTransferTransitionActionStructureValidationV0 { fn validate_structure_v0( &self, owner_id: Identifier, ) -> Result; } -impl ValidateTokenAmountV0 for TokenTransferTransition {} - impl TokenTransferTransitionActionStructureValidationV0 for TokenTransferTransition { fn validate_structure_v0( &self, owner_id: Identifier, ) -> Result { - if let Some(consensus_error) = self.validate_token_amount_v0(self.amount()) { - return Ok(SimpleConsensusValidationResult::new_with_error( - consensus_error, - )); - } + let mut result = validate_token_amount_v0(self.amount()); if self.recipient_id() == owner_id { - return Ok(SimpleConsensusValidationResult::new_with_error( - ConsensusError::BasicError(BasicError::TokenTransferToOurselfError( - TokenTransferToOurselfError::new(self.base().token_id(), owner_id), - )), + result.add_error(TokenTransferToOurselfError::new( + self.base().token_id(), + owner_id, )); } if let Some(public_note) = self.public_note() { - if public_note.len() > MAX_TOKEN_NOTE_LEN { - return Ok(SimpleConsensusValidationResult::new_with_error( - ConsensusError::BasicError(BasicError::InvalidTokenNoteTooBigError( - InvalidTokenNoteTooBigError::new( - MAX_TOKEN_NOTE_LEN as u32, - "public_note", - public_note.len() as u32, - ), - )), - )); - } + result.merge(validate_public_note(public_note)); } if let Some(shared_encrypted_note) = self.shared_encrypted_note() { if shared_encrypted_note.2.len() > MAX_TOKEN_NOTE_LEN { - return Ok(SimpleConsensusValidationResult::new_with_error( - ConsensusError::BasicError(BasicError::InvalidTokenNoteTooBigError( - InvalidTokenNoteTooBigError::new( - MAX_TOKEN_NOTE_LEN as u32, - "shared_encrypted_note", - shared_encrypted_note.2.len() as u32, - ), - )), + result.add_error(InvalidTokenNoteTooBigError::new( + MAX_TOKEN_NOTE_LEN as u32, + "shared_encrypted_note", + shared_encrypted_note.2.len() as u32, )); } } if let Some(private_encrypted_note) = self.private_encrypted_note() { if private_encrypted_note.2.len() > MAX_TOKEN_NOTE_LEN { - return Ok(SimpleConsensusValidationResult::new_with_error( - ConsensusError::BasicError(BasicError::InvalidTokenNoteTooBigError( - InvalidTokenNoteTooBigError::new( - MAX_TOKEN_NOTE_LEN as u32, - "private_encrypted_note", - private_encrypted_note.2.len() as u32, - ), - )), + result.add_error(InvalidTokenNoteTooBigError::new( + MAX_TOKEN_NOTE_LEN as u32, + "private_encrypted_note", + private_encrypted_note.2.len() as u32, )); } } - Ok(SimpleConsensusValidationResult::default()) + Ok(result) } } diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_transition.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_transition.rs index 0e96fba13b5..5ea1d9a697b 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_transition.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_transition.rs @@ -21,6 +21,10 @@ use crate::ProtocolError; use crate::state_transition::batch_transition::{DocumentCreateTransition, DocumentDeleteTransition, DocumentReplaceTransition, TokenBurnTransition, TokenConfigUpdateTransition, TokenDestroyFrozenFundsTransition, TokenEmergencyActionTransition, TokenFreezeTransition, TokenMintTransition, TokenClaimTransition, TokenTransferTransition}; use crate::state_transition::batch_transition::batched_transition::{DocumentPurchaseTransition, DocumentTransferTransition}; use crate::state_transition::batch_transition::batched_transition::multi_party_action::AllowedAsMultiPartyAction; +use crate::state_transition::batch_transition::batched_transition::token_order_adjust_price_transition::transition::TokenOrderAdjustPriceTransition; +use crate::state_transition::batch_transition::batched_transition::token_order_buy_limit_transition::transition::TokenOrderBuyLimitTransition; +use crate::state_transition::batch_transition::batched_transition::token_order_cancel_transition::transition::TokenOrderCancelTransition; +use crate::state_transition::batch_transition::batched_transition::token_order_sell_limit_transition::transition::TokenOrderSellLimitTransition; use crate::state_transition::batch_transition::batched_transition::token_unfreeze_transition::TokenUnfreezeTransition; use crate::state_transition::batch_transition::resolvers::v0::BatchTransitionResolversV0; use crate::state_transition::batch_transition::token_base_transition::token_base_transition_accessors::TokenBaseTransitionAccessors; @@ -74,6 +78,18 @@ pub enum TokenTransition { #[display("TokenConfigUpdateTransition({})", "_0")] ConfigUpdate(TokenConfigUpdateTransition), + + #[display("TokenOrderBuyLimitTransition({})", "_0")] + OrderBuyLimit(TokenOrderBuyLimitTransition), + + #[display("TokenOrderSellLimitTransition({})", "_0")] + OrderSellLimit(TokenOrderSellLimitTransition), + + #[display("TokenOrderCancelTransition({})", "_0")] + OrderCancel(TokenOrderCancelTransition), + + #[display("TokenOrderAdjustPriceTransition({})", "_0")] + OrderAdjustPrice(TokenOrderAdjustPriceTransition), } impl BatchTransitionResolversV0 for TokenTransition { @@ -168,6 +184,38 @@ impl BatchTransitionResolversV0 for TokenTransition { None } } + + fn as_transition_token_order_buy_limit(&self) -> Option<&TokenOrderBuyLimitTransition> { + if let Self::OrderBuyLimit(ref t) = self { + Some(t) + } else { + None + } + } + + fn as_transition_token_order_sell_limit(&self) -> Option<&TokenOrderSellLimitTransition> { + if let Self::OrderSellLimit(ref t) = self { + Some(t) + } else { + None + } + } + + fn as_transition_token_order_cancel(&self) -> Option<&TokenOrderCancelTransition> { + if let Self::OrderCancel(ref t) = self { + Some(t) + } else { + None + } + } + + fn as_transition_token_order_adjust_price(&self) -> Option<&TokenOrderAdjustPriceTransition> { + if let Self::OrderAdjustPrice(ref t) = self { + Some(t) + } else { + None + } + } } pub trait TokenTransitionV0Methods { @@ -205,17 +253,7 @@ pub trait TokenTransitionV0Methods { &self, token_configuration: &TokenConfiguration, contract_owner_id: Identifier, - ) -> Result; - /// Historical document id - fn build_historical_document( - &self, - token_id: Identifier, - owner_id: Identifier, - owner_nonce: IdentityNonce, - block_info: &BlockInfo, - token_configuration: &TokenConfiguration, - platform_version: &PlatformVersion, - ) -> Result; + ) -> Result, ProtocolError>; } impl TokenTransitionV0Methods for TokenTransition { @@ -230,6 +268,10 @@ impl TokenTransitionV0Methods for TokenTransition { TokenTransition::Claim(t) => t.base(), TokenTransition::EmergencyAction(t) => t.base(), TokenTransition::ConfigUpdate(t) => t.base(), + TokenTransition::OrderBuyLimit(t) => t.base(), + TokenTransition::OrderSellLimit(t) => t.base(), + TokenTransition::OrderCancel(t) => t.base(), + TokenTransition::OrderAdjustPrice(t) => t.base(), } } @@ -244,6 +286,10 @@ impl TokenTransitionV0Methods for TokenTransition { TokenTransition::Claim(t) => t.base_mut(), TokenTransition::EmergencyAction(t) => t.base_mut(), TokenTransition::ConfigUpdate(t) => t.base_mut(), + TokenTransition::OrderBuyLimit(t) => t.base_mut(), + TokenTransition::OrderSellLimit(t) => t.base_mut(), + TokenTransition::OrderCancel(t) => t.base_mut(), + TokenTransition::OrderAdjustPrice(t) => t.base_mut(), } } @@ -262,6 +308,10 @@ impl TokenTransitionV0Methods for TokenTransition { TokenTransition::Claim(_) => None, TokenTransition::EmergencyAction(t) => Some(t.calculate_action_id(owner_id)), TokenTransition::ConfigUpdate(t) => Some(t.calculate_action_id(owner_id)), + TokenTransition::OrderBuyLimit(_) => None, + TokenTransition::OrderSellLimit(_) => None, + TokenTransition::OrderCancel(_) => None, + TokenTransition::OrderAdjustPrice(_) => None, } } @@ -274,7 +324,12 @@ impl TokenTransitionV0Methods for TokenTransition { | TokenTransition::DestroyFrozenFunds(_) | TokenTransition::EmergencyAction(_) | TokenTransition::ConfigUpdate(_) => true, - TokenTransition::Transfer(_) | TokenTransition::Claim(_) => false, + TokenTransition::Transfer(_) + | TokenTransition::Claim(_) + | TokenTransition::OrderBuyLimit(_) + | TokenTransition::OrderSellLimit(_) + | TokenTransition::OrderCancel(_) + | TokenTransition::OrderAdjustPrice(_) => false, } } @@ -310,6 +365,11 @@ impl TokenTransitionV0Methods for TokenTransition { TokenTransition::DestroyFrozenFunds(_) => "destroyFrozenFunds", TokenTransition::ConfigUpdate(_) => "configUpdate", TokenTransition::Claim(_) => "claim", + // TODO: Decide should it use historical contract or own + TokenTransition::OrderBuyLimit(_) => "", + TokenTransition::OrderSellLimit(_) => "", + TokenTransition::OrderCancel(_) => "", + TokenTransition::OrderAdjustPrice(_) => "", } } @@ -334,74 +394,77 @@ impl TokenTransitionV0Methods for TokenTransition { ) } - /// Historical document id - fn build_historical_document( - &self, - token_id: Identifier, - owner_id: Identifier, - owner_nonce: IdentityNonce, - block_info: &BlockInfo, - token_configuration: &TokenConfiguration, - platform_version: &PlatformVersion, - ) -> Result { - self.associated_token_event(token_configuration, owner_id)? - .build_historical_document_owned( - token_id, - owner_id, - owner_nonce, - block_info, - platform_version, - ) - } - fn associated_token_event( &self, token_configuration: &TokenConfiguration, owner_id: Identifier, - ) -> Result { - Ok(match self { + ) -> Result, ProtocolError> { + let event = match self { TokenTransition::Burn(burn) => { - TokenEvent::Burn(burn.burn_amount(), burn.public_note().cloned()) + let event = TokenEvent::Burn(burn.burn_amount(), burn.public_note().cloned()); + + Some(event) } TokenTransition::Mint(mint) => { let recipient = match mint.issued_to_identity_id() { None => token_configuration.distribution_rules().new_tokens_destination_identity().copied().ok_or(ProtocolError::NotSupported("either the mint destination must be set or the contract must have a destination set for new tokens".to_string()))?, Some(recipient) => recipient, }; - TokenEvent::Mint(mint.amount(), recipient, mint.public_note().cloned()) + let event = TokenEvent::Mint(mint.amount(), recipient, mint.public_note().cloned()); + + Some(event) } TokenTransition::Transfer(transfer) => { let (public_note, shared_encrypted_note, private_encrypted_note) = transfer.notes(); - TokenEvent::Transfer( + let event = TokenEvent::Transfer( transfer.recipient_id(), public_note, shared_encrypted_note, private_encrypted_note, transfer.amount(), - ) + ); + + Some(event) } TokenTransition::Freeze(freeze) => { - TokenEvent::Freeze(freeze.frozen_identity_id(), freeze.public_note().cloned()) + let event = + TokenEvent::Freeze(freeze.frozen_identity_id(), freeze.public_note().cloned()); + + Some(event) + } + TokenTransition::Unfreeze(unfreeze) => { + let event = TokenEvent::Unfreeze( + unfreeze.frozen_identity_id(), + unfreeze.public_note().cloned(), + ); + + Some(event) + } + TokenTransition::EmergencyAction(emergency_action) => { + let event = TokenEvent::EmergencyAction( + emergency_action.emergency_action(), + emergency_action.public_note().cloned(), + ); + + Some(event) } - TokenTransition::Unfreeze(unfreeze) => TokenEvent::Unfreeze( - unfreeze.frozen_identity_id(), - unfreeze.public_note().cloned(), - ), - TokenTransition::EmergencyAction(emergency_action) => TokenEvent::EmergencyAction( - emergency_action.emergency_action(), - emergency_action.public_note().cloned(), - ), TokenTransition::DestroyFrozenFunds(destroy_frozen_funds) => { - TokenEvent::DestroyFrozenFunds( + let event = TokenEvent::DestroyFrozenFunds( destroy_frozen_funds.frozen_identity_id(), TokenAmount::MAX, // we do not know how much will be destroyed destroy_frozen_funds.public_note().cloned(), - ) + ); + + Some(event) + } + TokenTransition::ConfigUpdate(config_update) => { + let event = TokenEvent::ConfigUpdate( + config_update.update_token_configuration_item().clone(), + config_update.public_note().cloned(), + ); + + Some(event) } - TokenTransition::ConfigUpdate(config_update) => TokenEvent::ConfigUpdate( - config_update.update_token_configuration_item().clone(), - config_update.public_note().cloned(), - ), TokenTransition::Claim(claim) => { let distribution_rules = token_configuration.distribution_rules(); let distribution_recipient = match claim.distribution_type() { @@ -434,12 +497,20 @@ impl TokenTransitionV0Methods for TokenTransition { } }; - TokenEvent::Claim( + let event = TokenEvent::Claim( distribution_recipient, TokenAmount::MAX, // we do not know how much will be released claim.public_note().cloned(), - ) + ); + + Some(event) } - }) + TokenTransition::OrderBuyLimit(_) => None, + TokenTransition::OrderSellLimit(_) => None, + TokenTransition::OrderCancel(_) => None, + TokenTransition::OrderAdjustPrice(_) => None, + }; + + Ok(event) } } diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_transition_action_type.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_transition_action_type.rs index ea464d5e88d..cc77ae73d64 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_transition_action_type.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_transition_action_type.rs @@ -14,6 +14,10 @@ pub enum TokenTransitionActionType { Claim, EmergencyAction, ConfigUpdate, + OrderBuyLimit, + OrderSellLimit, + OrderCancel, + OrderAdjustPrice, } impl fmt::Display for TokenTransitionActionType { @@ -28,6 +32,10 @@ impl fmt::Display for TokenTransitionActionType { TokenTransitionActionType::Claim => "Claim", TokenTransitionActionType::EmergencyAction => "EmergencyAction", TokenTransitionActionType::ConfigUpdate => "ConfigUpdate", + TokenTransitionActionType::OrderBuyLimit => "OrderBuyLimit", + TokenTransitionActionType::OrderSellLimit => "OrderSellLimit", + TokenTransitionActionType::OrderCancel => "OrderCancel", + TokenTransitionActionType::OrderAdjustPrice => "OrderAdjustPrice", }; write!(f, "{}", action_str) } @@ -49,6 +57,10 @@ impl TokenTransitionActionTypeGetter for TokenTransition { TokenTransition::Claim(_) => TokenTransitionActionType::Claim, TokenTransition::EmergencyAction(_) => TokenTransitionActionType::EmergencyAction, TokenTransition::ConfigUpdate(_) => TokenTransitionActionType::ConfigUpdate, + TokenTransition::OrderBuyLimit(_) => TokenTransitionActionType::OrderBuyLimit, + TokenTransition::OrderSellLimit(_) => TokenTransitionActionType::OrderSellLimit, + TokenTransition::OrderCancel(_) => TokenTransitionActionType::OrderCancel, + TokenTransition::OrderAdjustPrice(_) => TokenTransitionActionType::OrderAdjustPrice, } } } diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_unfreeze_transition/validate_structure/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_unfreeze_transition/validate_structure/v0/mod.rs index d02ab5e0dd1..237e989f65f 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_unfreeze_transition/validate_structure/v0/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_unfreeze_transition/validate_structure/v0/mod.rs @@ -1,6 +1,7 @@ use crate::consensus::basic::token::InvalidTokenNoteTooBigError; use crate::consensus::basic::BasicError; use crate::consensus::ConsensusError; +use crate::state_transition::batch_transition::batched_transition::validation::validate_public_note; use crate::state_transition::batch_transition::token_unfreeze_transition::v0::v0_methods::TokenUnfreezeTransitionV0Methods; use crate::state_transition::batch_transition::TokenUnfreezeTransition; use crate::tokens::MAX_TOKEN_NOTE_LEN; @@ -12,20 +13,12 @@ pub(super) trait TokenUnfreezeTransitionStructureValidationV0 { } impl TokenUnfreezeTransitionStructureValidationV0 for TokenUnfreezeTransition { fn validate_structure_v0(&self) -> Result { + let mut result = SimpleConsensusValidationResult::new(); + if let Some(public_note) = self.public_note() { - if public_note.len() > MAX_TOKEN_NOTE_LEN { - return Ok(SimpleConsensusValidationResult::new_with_error( - ConsensusError::BasicError(BasicError::InvalidTokenNoteTooBigError( - InvalidTokenNoteTooBigError::new( - MAX_TOKEN_NOTE_LEN as u32, - "public_note", - public_note.len() as u32, - ), - )), - )); - } + result.merge(validate_public_note(public_note)); } - Ok(SimpleConsensusValidationResult::default()) + Ok(result) } } diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/validate_token_amount.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/validate_token_amount.rs deleted file mode 100644 index b7cb7f26403..00000000000 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/validate_token_amount.rs +++ /dev/null @@ -1,17 +0,0 @@ -use crate::balances::credits::{TokenAmount, TOKEN_MAX_AMOUNT}; -use crate::consensus::basic::token::{InvalidTokenAmountError, ZeroTokenAmountError}; -use crate::consensus::ConsensusError; - -pub(super) trait ValidateTokenAmountV0 { - fn validate_token_amount_v0(&self, amount: TokenAmount) -> Option { - if amount == 0 { - return Some(ZeroTokenAmountError::new().into()); - } - - if amount > TOKEN_MAX_AMOUNT { - return Some(InvalidTokenAmountError::new(TOKEN_MAX_AMOUNT, amount).into()); - }; - - None - } -} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/validation.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/validation.rs new file mode 100644 index 00000000000..4aa9f26b391 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/validation.rs @@ -0,0 +1,50 @@ +use crate::balances::credits::{TokenAmount, MAX_CREDITS, TOKEN_MAX_AMOUNT}; +use crate::consensus::basic::token::{ + InvalidTokenAmountError, InvalidTokenNoteTooBigError, InvalidTokenPriceError, + ZeroTokenAmountError, ZeroTokenPriceError, +}; +use crate::fee::Credits; +use crate::tokens::MAX_TOKEN_NOTE_LEN; +use crate::validation::SimpleConsensusValidationResult; + +pub(super) fn validate_token_amount_v0(amount: TokenAmount) -> SimpleConsensusValidationResult { + let mut result = SimpleConsensusValidationResult::default(); + + if amount == 0 { + result.add_error(ZeroTokenAmountError::new()); + } + + if amount > TOKEN_MAX_AMOUNT { + result.add_error(InvalidTokenAmountError::new(TOKEN_MAX_AMOUNT, amount)); + }; + + result +} + +pub(super) fn validate_token_price_v0(price: Credits) -> SimpleConsensusValidationResult { + let mut result = SimpleConsensusValidationResult::default(); + + if price == 0 { + result.add_error(ZeroTokenPriceError::new()); + }; + + if price > MAX_CREDITS { + result.add_error(InvalidTokenPriceError::new(MAX_CREDITS, price)); + } + + result +} + +pub(super) fn validate_public_note(public_note: &str) -> SimpleConsensusValidationResult { + let mut result = SimpleConsensusValidationResult::default(); + + if public_note.len() > MAX_TOKEN_NOTE_LEN { + result.add_error(InvalidTokenNoteTooBigError::new( + MAX_TOKEN_NOTE_LEN as u32, + "public_note", + public_note.len() as u32, + )); + } + + result +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/resolvers/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/resolvers/v0/mod.rs index 687ece25889..02e2663ddb4 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/resolvers/v0/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/resolvers/v0/mod.rs @@ -8,6 +8,10 @@ use crate::state_transition::batch_transition::{ TokenDestroyFrozenFundsTransition, TokenEmergencyActionTransition, TokenFreezeTransition, TokenMintTransition, TokenTransferTransition, }; +use crate::state_transition::batch_transition::batched_transition::token_order_adjust_price_transition::transition::TokenOrderAdjustPriceTransition; +use crate::state_transition::batch_transition::batched_transition::token_order_buy_limit_transition::transition::TokenOrderBuyLimitTransition; +use crate::state_transition::batch_transition::batched_transition::token_order_cancel_transition::transition::TokenOrderCancelTransition; +use crate::state_transition::batch_transition::batched_transition::token_order_sell_limit_transition::transition::TokenOrderSellLimitTransition; pub trait BatchTransitionResolversV0 { fn as_transition_create(&self) -> Option<&DocumentCreateTransition>; @@ -28,4 +32,12 @@ pub trait BatchTransitionResolversV0 { fn as_transition_token_emergency_action(&self) -> Option<&TokenEmergencyActionTransition>; fn as_transition_token_config_update(&self) -> Option<&TokenConfigUpdateTransition>; + + fn as_transition_token_order_buy_limit(&self) -> Option<&TokenOrderBuyLimitTransition>; + + fn as_transition_token_order_sell_limit(&self) -> Option<&TokenOrderSellLimitTransition>; + + fn as_transition_token_order_cancel(&self) -> Option<&TokenOrderCancelTransition>; + + fn as_transition_token_order_adjust_price(&self) -> Option<&TokenOrderAdjustPriceTransition>; } diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/validation/validate_basic_structure/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/validation/validate_basic_structure/v0/mod.rs index 3ab68d5219b..a1d755eec61 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/validation/validate_basic_structure/v0/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/validation/validate_basic_structure/v0/mod.rs @@ -18,6 +18,9 @@ use std::collections::BTreeMap; use crate::consensus::basic::group::GroupActionNotAllowedOnTransitionError; use crate::consensus::basic::token::{InvalidActionIdError, InvalidTokenIdError}; use crate::state_transition::batch_transition::batched_transition::BatchedTransitionRef; +use crate::state_transition::batch_transition::batched_transition::token_order_adjust_price_transition::validate_structure::TokenOrderAdjustPriceTransitionStructureValidation; +use crate::state_transition::batch_transition::batched_transition::token_order_buy_limit_transition::validate_structure::TokenOrderBuyLimitTransitionStructureValidation; +use crate::state_transition::batch_transition::batched_transition::token_order_sell_limit_transition::validate_structure::TokenOrderSellLimitTransitionStructureValidation; use crate::state_transition::batch_transition::batched_transition::token_transition::{TokenTransition, TokenTransitionV0Methods}; use crate::state_transition::batch_transition::batched_transition::token_transition_action_type::TokenTransitionActionTypeGetter; use crate::state_transition::batch_transition::token_base_transition::v0::v0_methods::TokenBaseTransitionV0Methods; @@ -170,6 +173,16 @@ impl BatchTransition { TokenTransition::Claim(release_transition) => { release_transition.validate_structure(platform_version)? } + TokenTransition::OrderBuyLimit(transition) => { + transition.validate_structure(platform_version)? + } + TokenTransition::OrderSellLimit(transition) => { + transition.validate_structure(platform_version)? + } + TokenTransition::OrderCancel(_) => SimpleConsensusValidationResult::default(), + TokenTransition::OrderAdjustPrice(transition) => { + transition.validate_structure(platform_version)? + } }; if !consensus_result.is_valid() { diff --git a/packages/rs-dpp/src/tokens/token_event.rs b/packages/rs-dpp/src/tokens/token_event.rs index 618daaa2355..19a503d4c5c 100644 --- a/packages/rs-dpp/src/tokens/token_event.rs +++ b/packages/rs-dpp/src/tokens/token_event.rs @@ -6,6 +6,7 @@ use crate::data_contract::associated_token::token_distribution_key::TokenDistrib use crate::data_contract::associated_token::token_perpetual_distribution::distribution_recipient::TokenDistributionResolvedRecipient; use crate::data_contract::document_type::DocumentTypeRef; use crate::document::{Document, DocumentV0}; +use crate::fee::Credits; use crate::prelude::{ DataContract, DerivationEncryptionKeyIndex, IdentityNonce, RootEncryptionKeyIndex, }; @@ -54,6 +55,7 @@ pub enum TokenEvent { ), EmergencyAction(TokenEmergencyAction, TokenEventPublicNote), ConfigUpdate(TokenConfigurationChangeItem, TokenEventPublicNote), + // TODO: Add token trade event } impl TokenEvent { From 427b460ec2c3cbd6a7bb248404e33b65289067b1 Mon Sep 17 00:00:00 2001 From: Ivan Shumkov Date: Sun, 30 Mar 2025 12:34:44 +0700 Subject: [PATCH 4/6] feat: integrate new state transitions --- .../validate_structure/v0.rs | 2 + .../batched_transition/token_transition.rs | 50 ----- packages/rs-dpp/src/tokens/token_event.rs | 23 ++- .../batch/action_validation/token/mod.rs | 4 + .../mod.rs | 59 ++++++ .../state_v0/mod.rs | 57 ++++++ .../mod.rs | 59 ++++++ .../state_v0/mod.rs | 55 ++++++ .../mod.rs | 59 ++++++ .../state_v0/mod.rs | 55 ++++++ .../mod.rs | 59 ++++++ .../state_v0/mod.rs | 55 ++++++ .../state_transitions/batch/state/v0/mod.rs | 37 ++++ .../batch/transformer/v0/mod.rs | 44 +++++ .../verify_state_transitions.rs | 93 +++++---- .../v0/mod.rs | 2 +- .../batch/token/mod.rs | 4 + .../token_order_adjust_price_transition.rs | 55 ++++++ .../token/token_order_buy_limit_transition.rs | 55 ++++++ .../token/token_order_cancel_transition.rs | 55 ++++++ .../token_order_sell_limit_transition.rs | 55 ++++++ .../batch/token/token_transition.rs | 113 +++++++---- .../token_transition/mod.rs | 101 ++++------ .../action.rs | 38 ++++ .../mod.rs | 7 + .../transformer.rs | 120 +++++++++++ .../v0/action.rs | 79 ++++++++ .../v0/mod.rs | 5 + .../v0/transformer.rs | 182 +++++++++++++++++ .../action.rs | 45 +++++ .../mod.rs | 7 + .../transformer.rs | 120 +++++++++++ .../v0/action.rs | 85 ++++++++ .../v0/mod.rs | 5 + .../v0/transformer.rs | 182 +++++++++++++++++ .../action.rs | 38 ++++ .../mod.rs | 7 + .../transformer.rs | 120 +++++++++++ .../v0/action.rs | 74 +++++++ .../v0/mod.rs | 5 + .../v0/transformer.rs | 181 +++++++++++++++++ .../action.rs | 45 +++++ .../mod.rs | 7 + .../transformer.rs | 120 +++++++++++ .../v0/action.rs | 85 ++++++++ .../v0/mod.rs | 5 + .../v0/transformer.rs | 187 ++++++++++++++++++ .../token_transition_action_type.rs | 10 + .../v0/mod.rs | 170 ++++++++++------ .../drive_abci_validation_versions/mod.rs | 4 + .../drive_abci_validation_versions/v1.rs | 4 + .../drive_abci_validation_versions/v2.rs | 4 + .../drive_abci_validation_versions/v3.rs | 4 + .../drive_abci_validation_versions/v4.rs | 4 + .../drive_abci_validation_versions/v5.rs | 4 + .../batch_transition/token_transition/mod.rs | 28 +++ .../token_transition/order_adjust_price.rs | 12 ++ .../token_transition/order_buy_limit.rs | 12 ++ .../token_transition/order_cancel.rs | 12 ++ .../token_transition/order_sell_limit.rs | 12 ++ .../src/errors/consensus/consensus_error.rs | 5 +- 61 files changed, 2930 insertions(+), 255 deletions(-) create mode 100644 packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_order_adjust_price_transition_action/mod.rs create mode 100644 packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_order_adjust_price_transition_action/state_v0/mod.rs create mode 100644 packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_order_buy_limit_transition_action/mod.rs create mode 100644 packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_order_buy_limit_transition_action/state_v0/mod.rs create mode 100644 packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_order_cancel_transition_action/mod.rs create mode 100644 packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_order_cancel_transition_action/state_v0/mod.rs create mode 100644 packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_order_sell_limit_transition_action/mod.rs create mode 100644 packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_order_sell_limit_transition_action/state_v0/mod.rs create mode 100644 packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/token/token_order_adjust_price_transition.rs create mode 100644 packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/token/token_order_buy_limit_transition.rs create mode 100644 packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/token/token_order_cancel_transition.rs create mode 100644 packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/token/token_order_sell_limit_transition.rs create mode 100644 packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_order_adjust_price_transition_action/action.rs create mode 100644 packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_order_adjust_price_transition_action/mod.rs create mode 100644 packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_order_adjust_price_transition_action/transformer.rs create mode 100644 packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_order_adjust_price_transition_action/v0/action.rs create mode 100644 packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_order_adjust_price_transition_action/v0/mod.rs create mode 100644 packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_order_adjust_price_transition_action/v0/transformer.rs create mode 100644 packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_order_buy_limit_transition_action/action.rs create mode 100644 packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_order_buy_limit_transition_action/mod.rs create mode 100644 packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_order_buy_limit_transition_action/transformer.rs create mode 100644 packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_order_buy_limit_transition_action/v0/action.rs create mode 100644 packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_order_buy_limit_transition_action/v0/mod.rs create mode 100644 packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_order_buy_limit_transition_action/v0/transformer.rs create mode 100644 packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_order_cancel_transition_action/action.rs create mode 100644 packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_order_cancel_transition_action/mod.rs create mode 100644 packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_order_cancel_transition_action/transformer.rs create mode 100644 packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_order_cancel_transition_action/v0/action.rs create mode 100644 packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_order_cancel_transition_action/v0/mod.rs create mode 100644 packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_order_cancel_transition_action/v0/transformer.rs create mode 100644 packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_order_sell_limit_transition_action/action.rs create mode 100644 packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_order_sell_limit_transition_action/mod.rs create mode 100644 packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_order_sell_limit_transition_action/transformer.rs create mode 100644 packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_order_sell_limit_transition_action/v0/action.rs create mode 100644 packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_order_sell_limit_transition_action/v0/mod.rs create mode 100644 packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_order_sell_limit_transition_action/v0/transformer.rs create mode 100644 packages/wasm-dpp/src/document/state_transition/batch_transition/token_transition/order_adjust_price.rs create mode 100644 packages/wasm-dpp/src/document/state_transition/batch_transition/token_transition/order_buy_limit.rs create mode 100644 packages/wasm-dpp/src/document/state_transition/batch_transition/token_transition/order_cancel.rs create mode 100644 packages/wasm-dpp/src/document/state_transition/batch_transition/token_transition/order_sell_limit.rs diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_buy_limit_transition/validate_structure/v0.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_buy_limit_transition/validate_structure/v0.rs index 7d73f622b67..d655eed84fd 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_buy_limit_transition/validate_structure/v0.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_order_buy_limit_transition/validate_structure/v0.rs @@ -10,6 +10,8 @@ pub(super) trait TokenOrderBuyLimitTransitionStructureValidationV0 { impl TokenOrderBuyLimitTransitionStructureValidationV0 for TokenOrderBuyLimitTransition { fn validate_structure_v0(&self) -> Result { + // TODO: We shouldn't allow group actions? + let mut result = validate_token_amount_v0(self.token_amount()); result.merge(validate_token_price_v0(self.token_max_price())); diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_transition.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_transition.rs index 5ea1d9a697b..af672ad8945 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_transition.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_transition.rs @@ -240,15 +240,6 @@ pub trait TokenTransitionV0Methods { fn calculate_action_id(&self, owner_id: Identifier) -> Option; fn can_calculate_action_id(&self) -> bool; - /// Historical document type name for the token history contract - fn historical_document_type_name(&self) -> &str; - /// Historical document type for the token history contract - fn historical_document_type<'a>( - &self, - token_history_contract: &'a DataContract, - ) -> Result, ProtocolError>; - /// Historical document id - fn historical_document_id(&self, owner_id: Identifier) -> Identifier; fn associated_token_event( &self, token_configuration: &TokenConfiguration, @@ -353,47 +344,6 @@ impl TokenTransitionV0Methods for TokenTransition { self.base_mut().set_identity_contract_nonce(nonce); } - /// Historical document type name for the token history contract - fn historical_document_type_name(&self) -> &str { - match self { - TokenTransition::Burn(_) => "burn", - TokenTransition::Mint(_) => "mint", - TokenTransition::Transfer(_) => "transfer", - TokenTransition::Freeze(_) => "freeze", - TokenTransition::Unfreeze(_) => "unfreeze", - TokenTransition::EmergencyAction(_) => "emergencyAction", - TokenTransition::DestroyFrozenFunds(_) => "destroyFrozenFunds", - TokenTransition::ConfigUpdate(_) => "configUpdate", - TokenTransition::Claim(_) => "claim", - // TODO: Decide should it use historical contract or own - TokenTransition::OrderBuyLimit(_) => "", - TokenTransition::OrderSellLimit(_) => "", - TokenTransition::OrderCancel(_) => "", - TokenTransition::OrderAdjustPrice(_) => "", - } - } - - /// Historical document type for the token history contract - fn historical_document_type<'a>( - &self, - token_history_contract: &'a DataContract, - ) -> Result, ProtocolError> { - Ok(token_history_contract.document_type_for_name(self.historical_document_type_name())?) - } - - /// Historical document id - fn historical_document_id(&self, owner_id: Identifier) -> Identifier { - let token_id = self.token_id(); - let name = self.historical_document_type_name(); - let owner_nonce = self.identity_contract_nonce(); - Document::generate_document_id_v0( - &token_id, - &owner_id, - format!("history_{}", name).as_str(), - owner_nonce.to_be_bytes().as_slice(), - ) - } - fn associated_token_event( &self, token_configuration: &TokenConfiguration, diff --git a/packages/rs-dpp/src/tokens/token_event.rs b/packages/rs-dpp/src/tokens/token_event.rs index 19a503d4c5c..ee9c0377d3d 100644 --- a/packages/rs-dpp/src/tokens/token_event.rs +++ b/packages/rs-dpp/src/tokens/token_event.rs @@ -80,20 +80,29 @@ impl TokenEvent { Ok(token_history_contract.document_type_for_name(self.associated_document_type_name())?) } - pub fn build_historical_document_owned( - self, + pub fn associated_document_id( + &self, token_id: Identifier, owner_id: Identifier, owner_nonce: IdentityNonce, - block_info: &BlockInfo, - platform_version: &PlatformVersion, - ) -> Result { - let document_id = Document::generate_document_id_v0( + ) -> Identifier { + Document::generate_document_id_v0( &token_id, &owner_id, format!("history_{}", self.associated_document_type_name()).as_str(), owner_nonce.to_be_bytes().as_slice(), - ); + ) + } + + pub fn build_associated_historical_document_owned( + self, + token_id: Identifier, + owner_id: Identifier, + owner_nonce: IdentityNonce, + block_info: &BlockInfo, + platform_version: &PlatformVersion, + ) -> Result { + let document_id = self.associated_document_id(token_id, owner_id, owner_nonce); let properties = match self { TokenEvent::Mint(mint_amount, recipient_id, public_note) => { diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/mod.rs index 49646315c67..ec20f9d8a25 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/mod.rs @@ -6,5 +6,9 @@ pub(crate) mod token_destroy_frozen_funds_transition_action; pub(crate) mod token_emergency_action_transition_action; pub(crate) mod token_freeze_transition_action; pub(crate) mod token_mint_transition_action; +pub(crate) mod token_order_adjust_price_transition_action; +pub(crate) mod token_order_buy_limit_transition_action; +pub(crate) mod token_order_cancel_transition_action; +pub(crate) mod token_order_sell_limit_transition_action; pub(crate) mod token_transfer_transition_action; pub(crate) mod token_unfreeze_transition_action; diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_order_adjust_price_transition_action/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_order_adjust_price_transition_action/mod.rs new file mode 100644 index 00000000000..5f347dc34ea --- /dev/null +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_order_adjust_price_transition_action/mod.rs @@ -0,0 +1,59 @@ +use dpp::block::block_info::BlockInfo; +use dpp::identifier::Identifier; +use dpp::validation::SimpleConsensusValidationResult; +use dpp::version::PlatformVersion; +use drive::grovedb::TransactionArg; +use drive::state_transition_action::batch::batched_transition::token_transition::token_order_adjust_price_transition_action::action::TokenOrderAdjustPriceTransitionAction; +use crate::error::Error; +use crate::error::execution::ExecutionError; +use crate::execution::types::state_transition_execution_context::StateTransitionExecutionContext; +use crate::execution::validation::state_transition::batch::action_validation::token::token_order_adjust_price_transition_action::state_v0::TokenOrderAdjustPriceTransitionActionStateValidationV0; +use crate::platform_types::platform::PlatformStateRef; + +mod state_v0; + +pub trait TokenOrderAdjustPriceTransitionActionValidation { + fn validate_state( + &self, + platform: &PlatformStateRef, + owner_id: Identifier, + block_info: &BlockInfo, + execution_context: &mut StateTransitionExecutionContext, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result; +} + +impl TokenOrderAdjustPriceTransitionActionValidation for TokenOrderAdjustPriceTransitionAction { + fn validate_state( + &self, + platform: &PlatformStateRef, + owner_id: Identifier, + block_info: &BlockInfo, + execution_context: &mut StateTransitionExecutionContext, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result { + match platform_version + .drive_abci + .validation_and_processing + .state_transitions + .batch_state_transition + .token_order_sell_limit_transition_state_validation + { + 0 => self.validate_state_v0( + platform, + owner_id, + block_info, + execution_context, + transaction, + platform_version, + ), + version => Err(Error::Execution(ExecutionError::UnknownVersionMismatch { + method: "TokenOrderAdjustPriceTransitionAction::validate_state".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_order_adjust_price_transition_action/state_v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_order_adjust_price_transition_action/state_v0/mod.rs new file mode 100644 index 00000000000..ab62dedbcaf --- /dev/null +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_order_adjust_price_transition_action/state_v0/mod.rs @@ -0,0 +1,57 @@ +use dpp::block::block_info::BlockInfo; +use dpp::data_contract::accessors::v1::DataContractV1Getters; +use dpp::prelude::Identifier; +use dpp::validation::SimpleConsensusValidationResult; +use dpp::version::PlatformVersion; +use drive::query::TransactionArg; +use drive::state_transition_action::batch::batched_transition::token_transition::token_order_adjust_price_transition_action::action::TokenOrderAdjustPriceTransitionAction; +use drive::state_transition_action::batch::batched_transition::token_transition::token_order_adjust_price_transition_action::TokenOrderAdjustPriceTransitionActionAccessorsV0; +use crate::error::Error; +use crate::execution::types::state_transition_execution_context::{StateTransitionExecutionContext}; +use crate::execution::validation::state_transition::batch::action_validation::token::token_base_transition_action::TokenBaseTransitionActionValidation; +use crate::platform_types::platform::PlatformStateRef; + +pub(in crate::execution::validation::state_transition::state_transitions::batch::action_validation) trait TokenOrderAdjustPriceTransitionActionStateValidationV0 { + fn validate_state_v0( + &self, + platform: &PlatformStateRef, + owner_id: Identifier, + block_info: &BlockInfo, + execution_context: &mut StateTransitionExecutionContext, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result; +} +impl TokenOrderAdjustPriceTransitionActionStateValidationV0 + for TokenOrderAdjustPriceTransitionAction +{ + fn validate_state_v0( + &self, + platform: &PlatformStateRef, + owner_id: Identifier, + block_info: &BlockInfo, + execution_context: &mut StateTransitionExecutionContext, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result { + let validation_result = self.base().validate_state( + platform, + owner_id, + block_info, + execution_context, + transaction, + platform_version, + )?; + if !validation_result.is_valid() { + return Ok(validation_result); + } + + // Let's first check to see if we are authorized to perform this action + let contract = &self.data_contract_fetch_info_ref().contract; + let token_configuration = contract.expected_token_configuration(self.token_position())?; + + // TODO: Implement validation + + Ok(SimpleConsensusValidationResult::new()) + } +} diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_order_buy_limit_transition_action/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_order_buy_limit_transition_action/mod.rs new file mode 100644 index 00000000000..9d6a1c6fd84 --- /dev/null +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_order_buy_limit_transition_action/mod.rs @@ -0,0 +1,59 @@ +use dpp::block::block_info::BlockInfo; +use dpp::identifier::Identifier; +use dpp::validation::SimpleConsensusValidationResult; +use dpp::version::PlatformVersion; +use drive::grovedb::TransactionArg; +use drive::state_transition_action::batch::batched_transition::token_transition::token_order_buy_limit_transition_action::action::TokenOrderBuyLimitTransitionAction; +use crate::error::Error; +use crate::error::execution::ExecutionError; +use crate::execution::types::state_transition_execution_context::StateTransitionExecutionContext; +use crate::execution::validation::state_transition::batch::action_validation::token::token_order_buy_limit_transition_action::state_v0::TokenOrderBuyLimitTransitionActionStateValidationV0; +use crate::platform_types::platform::PlatformStateRef; + +mod state_v0; + +pub trait TokenOrderBuyLimitTransitionActionValidation { + fn validate_state( + &self, + platform: &PlatformStateRef, + owner_id: Identifier, + block_info: &BlockInfo, + execution_context: &mut StateTransitionExecutionContext, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result; +} + +impl TokenOrderBuyLimitTransitionActionValidation for TokenOrderBuyLimitTransitionAction { + fn validate_state( + &self, + platform: &PlatformStateRef, + owner_id: Identifier, + block_info: &BlockInfo, + execution_context: &mut StateTransitionExecutionContext, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result { + match platform_version + .drive_abci + .validation_and_processing + .state_transitions + .batch_state_transition + .token_order_buy_limit_transition_state_validation + { + 0 => self.validate_state_v0( + platform, + owner_id, + block_info, + execution_context, + transaction, + platform_version, + ), + version => Err(Error::Execution(ExecutionError::UnknownVersionMismatch { + method: "TokenOrderBuyLimitTransitionAction::validate_state".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_order_buy_limit_transition_action/state_v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_order_buy_limit_transition_action/state_v0/mod.rs new file mode 100644 index 00000000000..40acf17fa7a --- /dev/null +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_order_buy_limit_transition_action/state_v0/mod.rs @@ -0,0 +1,55 @@ +use dpp::block::block_info::BlockInfo; +use dpp::data_contract::accessors::v1::DataContractV1Getters; +use dpp::prelude::Identifier; +use dpp::validation::SimpleConsensusValidationResult; +use drive::state_transition_action::batch::batched_transition::token_transition::token_order_buy_limit_transition_action::TokenOrderBuyLimitTransitionActionAccessorsV0; +use dpp::version::PlatformVersion; +use drive::query::TransactionArg; +use drive::state_transition_action::batch::batched_transition::token_transition::token_order_buy_limit_transition_action::action::TokenOrderBuyLimitTransitionAction; +use crate::error::Error; +use crate::execution::types::state_transition_execution_context::{StateTransitionExecutionContext}; +use crate::execution::validation::state_transition::batch::action_validation::token::token_base_transition_action::TokenBaseTransitionActionValidation; +use crate::platform_types::platform::PlatformStateRef; + +pub(in crate::execution::validation::state_transition::state_transitions::batch::action_validation) trait TokenOrderBuyLimitTransitionActionStateValidationV0 { + fn validate_state_v0( + &self, + platform: &PlatformStateRef, + owner_id: Identifier, + block_info: &BlockInfo, + execution_context: &mut StateTransitionExecutionContext, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result; +} +impl TokenOrderBuyLimitTransitionActionStateValidationV0 for TokenOrderBuyLimitTransitionAction { + fn validate_state_v0( + &self, + platform: &PlatformStateRef, + owner_id: Identifier, + block_info: &BlockInfo, + execution_context: &mut StateTransitionExecutionContext, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result { + let validation_result = self.base().validate_state( + platform, + owner_id, + block_info, + execution_context, + transaction, + platform_version, + )?; + if !validation_result.is_valid() { + return Ok(validation_result); + } + + // Let's first check to see if we are authorized to perform this action + let contract = &self.data_contract_fetch_info_ref().contract; + let token_configuration = contract.expected_token_configuration(self.token_position())?; + + // TODO: Implement validation + + Ok(SimpleConsensusValidationResult::new()) + } +} diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_order_cancel_transition_action/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_order_cancel_transition_action/mod.rs new file mode 100644 index 00000000000..71f4dfba447 --- /dev/null +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_order_cancel_transition_action/mod.rs @@ -0,0 +1,59 @@ +use dpp::block::block_info::BlockInfo; +use dpp::identifier::Identifier; +use dpp::validation::SimpleConsensusValidationResult; +use dpp::version::PlatformVersion; +use drive::grovedb::TransactionArg; +use drive::state_transition_action::batch::batched_transition::token_transition::token_order_cancel_transition_action::action::TokenOrderCancelTransitionAction; +use crate::error::Error; +use crate::error::execution::ExecutionError; +use crate::execution::types::state_transition_execution_context::StateTransitionExecutionContext; +use crate::execution::validation::state_transition::batch::action_validation::token::token_order_cancel_transition_action::state_v0::TokenOrderCancelTransitionActionStateValidationV0; +use crate::platform_types::platform::PlatformStateRef; + +mod state_v0; + +pub trait TokenOrderCancelTransitionActionValidation { + fn validate_state( + &self, + platform: &PlatformStateRef, + owner_id: Identifier, + block_info: &BlockInfo, + execution_context: &mut StateTransitionExecutionContext, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result; +} + +impl TokenOrderCancelTransitionActionValidation for TokenOrderCancelTransitionAction { + fn validate_state( + &self, + platform: &PlatformStateRef, + owner_id: Identifier, + block_info: &BlockInfo, + execution_context: &mut StateTransitionExecutionContext, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result { + match platform_version + .drive_abci + .validation_and_processing + .state_transitions + .batch_state_transition + .token_order_sell_limit_transition_state_validation + { + 0 => self.validate_state_v0( + platform, + owner_id, + block_info, + execution_context, + transaction, + platform_version, + ), + version => Err(Error::Execution(ExecutionError::UnknownVersionMismatch { + method: "TokenOrderCancelTransitionAction::validate_state".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_order_cancel_transition_action/state_v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_order_cancel_transition_action/state_v0/mod.rs new file mode 100644 index 00000000000..bb06c053971 --- /dev/null +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_order_cancel_transition_action/state_v0/mod.rs @@ -0,0 +1,55 @@ +use dpp::block::block_info::BlockInfo; +use dpp::data_contract::accessors::v1::DataContractV1Getters; +use dpp::prelude::Identifier; +use dpp::validation::SimpleConsensusValidationResult; +use dpp::version::PlatformVersion; +use drive::query::TransactionArg; +use drive::state_transition_action::batch::batched_transition::token_transition::token_order_cancel_transition_action::action::TokenOrderCancelTransitionAction; +use drive::state_transition_action::batch::batched_transition::token_transition::token_order_cancel_transition_action::TokenOrderCancelTransitionActionAccessorsV0; +use crate::error::Error; +use crate::execution::types::state_transition_execution_context::{StateTransitionExecutionContext}; +use crate::execution::validation::state_transition::batch::action_validation::token::token_base_transition_action::TokenBaseTransitionActionValidation; +use crate::platform_types::platform::PlatformStateRef; + +pub(in crate::execution::validation::state_transition::state_transitions::batch::action_validation) trait TokenOrderCancelTransitionActionStateValidationV0 { + fn validate_state_v0( + &self, + platform: &PlatformStateRef, + owner_id: Identifier, + block_info: &BlockInfo, + execution_context: &mut StateTransitionExecutionContext, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result; +} +impl TokenOrderCancelTransitionActionStateValidationV0 for TokenOrderCancelTransitionAction { + fn validate_state_v0( + &self, + platform: &PlatformStateRef, + owner_id: Identifier, + block_info: &BlockInfo, + execution_context: &mut StateTransitionExecutionContext, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result { + let validation_result = self.base().validate_state( + platform, + owner_id, + block_info, + execution_context, + transaction, + platform_version, + )?; + if !validation_result.is_valid() { + return Ok(validation_result); + } + + // Let's first check to see if we are authorized to perform this action + let contract = &self.data_contract_fetch_info_ref().contract; + let token_configuration = contract.expected_token_configuration(self.token_position())?; + + // TODO: Implement validation + + Ok(SimpleConsensusValidationResult::new()) + } +} diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_order_sell_limit_transition_action/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_order_sell_limit_transition_action/mod.rs new file mode 100644 index 00000000000..c1911294169 --- /dev/null +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_order_sell_limit_transition_action/mod.rs @@ -0,0 +1,59 @@ +use dpp::block::block_info::BlockInfo; +use dpp::identifier::Identifier; +use dpp::validation::SimpleConsensusValidationResult; +use dpp::version::PlatformVersion; +use drive::grovedb::TransactionArg; +use drive::state_transition_action::batch::batched_transition::token_transition::token_order_sell_limit_transition_action::action::TokenOrderSellLimitTransitionAction; +use crate::error::Error; +use crate::error::execution::ExecutionError; +use crate::execution::types::state_transition_execution_context::StateTransitionExecutionContext; +use crate::execution::validation::state_transition::batch::action_validation::token::token_order_sell_limit_transition_action::state_v0::TokenOrderSellLimitTransitionActionStateValidationV0; +use crate::platform_types::platform::PlatformStateRef; + +mod state_v0; + +pub trait TokenOrderSellLimitTransitionActionValidation { + fn validate_state( + &self, + platform: &PlatformStateRef, + owner_id: Identifier, + block_info: &BlockInfo, + execution_context: &mut StateTransitionExecutionContext, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result; +} + +impl TokenOrderSellLimitTransitionActionValidation for TokenOrderSellLimitTransitionAction { + fn validate_state( + &self, + platform: &PlatformStateRef, + owner_id: Identifier, + block_info: &BlockInfo, + execution_context: &mut StateTransitionExecutionContext, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result { + match platform_version + .drive_abci + .validation_and_processing + .state_transitions + .batch_state_transition + .token_order_cancel_transition_state_validation + { + 0 => self.validate_state_v0( + platform, + owner_id, + block_info, + execution_context, + transaction, + platform_version, + ), + version => Err(Error::Execution(ExecutionError::UnknownVersionMismatch { + method: "TokenOrderSellLimitTransitionAction::validate_state".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_order_sell_limit_transition_action/state_v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_order_sell_limit_transition_action/state_v0/mod.rs new file mode 100644 index 00000000000..6546f88d344 --- /dev/null +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_order_sell_limit_transition_action/state_v0/mod.rs @@ -0,0 +1,55 @@ +use dpp::block::block_info::BlockInfo; +use dpp::data_contract::accessors::v1::DataContractV1Getters; +use dpp::prelude::Identifier; +use dpp::validation::SimpleConsensusValidationResult; +use dpp::version::PlatformVersion; +use drive::query::TransactionArg; +use drive::state_transition_action::batch::batched_transition::token_transition::token_order_sell_limit_transition_action::action::TokenOrderSellLimitTransitionAction; +use drive::state_transition_action::batch::batched_transition::token_transition::token_order_sell_limit_transition_action::TokenOrderSellLimitTransitionActionAccessorsV0; +use crate::error::Error; +use crate::execution::types::state_transition_execution_context::{StateTransitionExecutionContext}; +use crate::execution::validation::state_transition::batch::action_validation::token::token_base_transition_action::TokenBaseTransitionActionValidation; +use crate::platform_types::platform::PlatformStateRef; + +pub(in crate::execution::validation::state_transition::state_transitions::batch::action_validation) trait TokenOrderSellLimitTransitionActionStateValidationV0 { + fn validate_state_v0( + &self, + platform: &PlatformStateRef, + owner_id: Identifier, + block_info: &BlockInfo, + execution_context: &mut StateTransitionExecutionContext, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result; +} +impl TokenOrderSellLimitTransitionActionStateValidationV0 for TokenOrderSellLimitTransitionAction { + fn validate_state_v0( + &self, + platform: &PlatformStateRef, + owner_id: Identifier, + block_info: &BlockInfo, + execution_context: &mut StateTransitionExecutionContext, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result { + let validation_result = self.base().validate_state( + platform, + owner_id, + block_info, + execution_context, + transaction, + platform_version, + )?; + if !validation_result.is_valid() { + return Ok(validation_result); + } + + // Let's first check to see if we are authorized to perform this action + let contract = &self.data_contract_fetch_info_ref().contract; + let token_configuration = contract.expected_token_configuration(self.token_position())?; + + // TODO: Implement validation + + Ok(SimpleConsensusValidationResult::new()) + } +} diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/state/v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/state/v0/mod.rs index bf28e8c9e16..8ed66adacb0 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/state/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/state/v0/mod.rs @@ -28,6 +28,10 @@ use crate::execution::validation::state_transition::batch::action_validation::to use crate::execution::validation::state_transition::batch::action_validation::token::token_emergency_action_transition_action::TokenEmergencyActionTransitionActionValidation; use crate::execution::validation::state_transition::batch::action_validation::token::token_freeze_transition_action::TokenFreezeTransitionActionValidation; use crate::execution::validation::state_transition::batch::action_validation::token::token_mint_transition_action::TokenMintTransitionActionValidation; +use crate::execution::validation::state_transition::batch::action_validation::token::token_order_adjust_price_transition_action::TokenOrderAdjustPriceTransitionActionValidation; +use crate::execution::validation::state_transition::batch::action_validation::token::token_order_buy_limit_transition_action::TokenOrderBuyLimitTransitionActionValidation; +use crate::execution::validation::state_transition::batch::action_validation::token::token_order_cancel_transition_action::TokenOrderCancelTransitionActionValidation; +use crate::execution::validation::state_transition::batch::action_validation::token::token_order_sell_limit_transition_action::TokenOrderSellLimitTransitionActionValidation; use crate::execution::validation::state_transition::batch::action_validation::token::token_transfer_transition_action::TokenTransferTransitionActionValidation; use crate::execution::validation::state_transition::batch::action_validation::token::token_unfreeze_transition_action::TokenUnfreezeTransitionActionValidation; use crate::execution::validation::state_transition::batch::data_triggers::{data_trigger_bindings_list, DataTriggerExecutionContext, DataTriggerExecutor}; @@ -229,6 +233,39 @@ impl DocumentsBatchStateTransitionStateValidationV0 for BatchTransition { transaction, platform_version, )?, + TokenTransitionAction::OrderBuyLimitAction(action) => action.validate_state( + platform, + owner_id, + block_info, + execution_context, + transaction, + platform_version, + )?, + TokenTransitionAction::OrderSellLimitAction(action) => action.validate_state( + platform, + owner_id, + block_info, + execution_context, + transaction, + platform_version, + )?, + TokenTransitionAction::OrderCancelAction(action) => action.validate_state( + platform, + owner_id, + block_info, + execution_context, + transaction, + platform_version, + )?, + TokenTransitionAction::OrderAdjustPriceAction(action) => action + .validate_state( + platform, + owner_id, + block_info, + execution_context, + transaction, + platform_version, + )?, }, BatchedTransitionAction::BumpIdentityDataContractNonce(_) => { return Err(Error::Execution(ExecutionError::CorruptedCodeExecution( diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/transformer/v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/transformer/v0/mod.rs index 837f80215a4..6f9561c6dec 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/transformer/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/transformer/v0/mod.rs @@ -61,6 +61,10 @@ use drive::state_transition_action::batch::batched_transition::token_transition: use drive::state_transition_action::batch::batched_transition::token_transition::token_freeze_transition_action::TokenFreezeTransitionAction; use drive::state_transition_action::batch::batched_transition::token_transition::token_mint_transition_action::TokenMintTransitionAction; use drive::state_transition_action::batch::batched_transition::token_transition::token_claim_transition_action::TokenClaimTransitionAction; +use drive::state_transition_action::batch::batched_transition::token_transition::token_order_adjust_price_transition_action::action::TokenOrderAdjustPriceTransitionAction; +use drive::state_transition_action::batch::batched_transition::token_transition::token_order_buy_limit_transition_action::action::TokenOrderBuyLimitTransitionAction; +use drive::state_transition_action::batch::batched_transition::token_transition::token_order_cancel_transition_action::action::TokenOrderCancelTransitionAction; +use drive::state_transition_action::batch::batched_transition::token_transition::token_order_sell_limit_transition_action::action::TokenOrderSellLimitTransitionAction; use drive::state_transition_action::batch::batched_transition::token_transition::token_transfer_transition_action::TokenTransferTransitionAction; use drive::state_transition_action::batch::batched_transition::token_transition::token_unfreeze_transition_action::TokenUnfreezeTransitionAction; use drive::state_transition_action::batch::batched_transition::token_transition::TokenTransitionAction; @@ -600,6 +604,46 @@ impl BatchTransitionInternalTransformerV0 for BatchTransition { Ok(data_contract_fetch_info.clone()) }, platform_version)?; + execution_context + .add_operation(ValidationOperation::PrecalculatedOperation(fee_result)); + + Ok(batched_action) + } + TokenTransition::OrderBuyLimit(transition) => { + let (batched_action, fee_result) = TokenOrderBuyLimitTransitionAction::try_from_borrowed_token_order_buy_limit_transition_with_contract_lookup(drive, owner_id, transition, approximate_for_costs, transaction, block_info, user_fee_increase, |_identifier| { + Ok(data_contract_fetch_info.clone()) + }, platform_version)?; + + execution_context + .add_operation(ValidationOperation::PrecalculatedOperation(fee_result)); + + Ok(batched_action) + } + TokenTransition::OrderSellLimit(transition) => { + let (batched_action, fee_result) = TokenOrderSellLimitTransitionAction::try_from_borrowed_token_order_sell_limit_transition_with_contract_lookup(drive, owner_id, transition, approximate_for_costs, transaction, block_info, user_fee_increase, |_identifier| { + Ok(data_contract_fetch_info.clone()) + }, platform_version)?; + + execution_context + .add_operation(ValidationOperation::PrecalculatedOperation(fee_result)); + + Ok(batched_action) + } + TokenTransition::OrderCancel(transition) => { + let (batched_action, fee_result) = TokenOrderCancelTransitionAction::try_from_borrowed_token_order_cancel_transition_with_contract_lookup(drive, owner_id, transition, approximate_for_costs, transaction, block_info, user_fee_increase, |_identifier| { + Ok(data_contract_fetch_info.clone()) + }, platform_version)?; + + execution_context + .add_operation(ValidationOperation::PrecalculatedOperation(fee_result)); + + Ok(batched_action) + } + TokenTransition::OrderAdjustPrice(transition) => { + let (batched_action, fee_result) = TokenOrderAdjustPriceTransitionAction::try_from_borrowed_token_order_adjust_price_transition_with_contract_lookup(drive, owner_id, transition, approximate_for_costs, transaction, block_info, user_fee_increase, |_identifier| { + Ok(data_contract_fetch_info.clone()) + }, platform_version)?; + execution_context .add_operation(ValidationOperation::PrecalculatedOperation(fee_result)); diff --git a/packages/rs-drive-abci/tests/strategy_tests/verify_state_transitions.rs b/packages/rs-drive-abci/tests/strategy_tests/verify_state_transitions.rs index 5b9114e9ee1..461fd7c340d 100644 --- a/packages/rs-drive-abci/tests/strategy_tests/verify_state_transitions.rs +++ b/packages/rs-drive-abci/tests/strategy_tests/verify_state_transitions.rs @@ -267,23 +267,30 @@ pub(crate) fn verify_state_transitions_were_or_were_not_executed( }, ); } - BatchedTransitionAction::TokenAction(token_transition_action) => { - if token_transition_action + BatchedTransitionAction::TokenAction(transition_action) => { + if transition_action .keeps_history() .expect("expected no error in token action keeps history") { + let Some(token_event) = transition_action.associated_token_event() else { + unreachable!("token event must be defined if keep history is enabled for token action"); + }; + + let token_id = transition_action.base().token_id(); + let owner_id = batch_transition.owner_id(); + let owner_nonce = transition_action.base().identity_contract_nonce(); + // if we keep history we just need to check the historical document proofs_request.documents.push( get_proofs_request_v0::DocumentRequest { contract_id: SystemDataContract::TokenHistory .id() .to_vec(), - document_type: token_transition_action - .historical_document_type_name() + document_type: token_event.associated_document_type_name() .to_string(), document_type_keeps_history: false, - document_id: token_transition_action - .historical_document_id(batch_transition.owner_id()) + document_id: token_event + .associated_document_id(token_id, owner_id, owner_nonce) .to_vec(), document_contested_status: 0, }, @@ -507,10 +514,21 @@ pub(crate) fn verify_state_transitions_were_or_were_not_executed( .keeps_history() .expect("expected no error in token action keeps history") { + let Some(token_event) = + token_transition_action.associated_token_event() + else { + unreachable!("token event must be defined if keep history is enabled for token action"); + }; + let token_id = token_transition_action.base().token_id(); - let document_type_name = token_transition_action - .historical_document_type_name() - .to_string(); + let owner_id = batch_transition.owner_id(); + let owner_nonce = + token_transition_action.base().identity_contract_nonce(); + let document_type_name = + token_event.associated_document_type_name().to_string(); + let document_id = token_event + .associated_document_id(token_id, owner_id, owner_nonce) + .to_buffer(); let token_history = platform .drive @@ -518,15 +536,17 @@ pub(crate) fn verify_state_transitions_were_or_were_not_executed( .system_data_contracts .load_token_history(); + let document_type = token_event + .associated_document_type(&token_history) + .expect("expected document type"); + let query = SingleDocumentDriveQuery { contract_id: SystemDataContract::TokenHistory .id() .to_buffer(), document_type_name, document_type_keeps_history: false, - document_id: token_transition_action - .historical_document_id(batch_transition.owner_id()) - .to_buffer(), + document_id, block_time_ms: None, //None because we want latest contested_status: SingleDocumentDriveQueryContestedStatus::NotContested, @@ -552,30 +572,25 @@ pub(crate) fn verify_state_transitions_were_or_were_not_executed( "we expect a token history document" ); - let expected_document = token_transition_action - .build_historical_document( + let basic_info = platform + .state + .last_committed_block_info() + .as_ref() + .expect("expected last commited block info") + .basic_info(); + + let expected_document = token_event + .build_associated_historical_document_owned( token_id, batch_transition.owner_id(), - token_transition_action - .base() - .identity_contract_nonce(), - platform - .state - .last_committed_block_info() - .as_ref() - .expect("expected last commited block info") - .basic_info(), + owner_nonce, + basic_info, platform_version, ) .expect("expected to build historical document"); let serialized_expected_document = expected_document - .serialize( - token_transition_action - .historical_document_type(&token_history) - .expect("expected document type"), - platform_version, - ) + .serialize(document_type, platform_version) .expect("expected to serialize"); assert_eq!( @@ -881,16 +896,16 @@ pub(crate) fn verify_state_transitions_were_or_were_not_executed( .collect(); proofs_request - .votes - .push(get_proofs_request_v0::VoteStatusRequest{ - request_type: Some(RequestType::ContestedResourceVoteStatusRequest(vote_status_request::ContestedResourceVoteStatusRequest { - contract_id: contested_document_resource_vote_poll.contract.id().to_vec(), - document_type_name: contested_document_resource_vote_poll.document_type_name.clone(), - index_name: contested_document_resource_vote_poll.index_name.clone(), - voter_identifier: masternode_vote_action.pro_tx_hash().to_vec(), - index_values: serialized_index_values, - })) - }); + .votes + .push(get_proofs_request_v0::VoteStatusRequest { + request_type: Some(RequestType::ContestedResourceVoteStatusRequest(vote_status_request::ContestedResourceVoteStatusRequest { + contract_id: contested_document_resource_vote_poll.contract.id().to_vec(), + document_type_name: contested_document_resource_vote_poll.document_type_name.clone(), + index_name: contested_document_resource_vote_poll.index_name.clone(), + voter_identifier: masternode_vote_action.pro_tx_hash().to_vec(), + index_values: serialized_index_values, + })) + }); contested_document_resource_vote_poll.contract.as_ref() } }, diff --git a/packages/rs-drive/src/drive/tokens/add_transaction_history_operations/v0/mod.rs b/packages/rs-drive/src/drive/tokens/add_transaction_history_operations/v0/mod.rs index bfcec28b150..c75935015ae 100644 --- a/packages/rs-drive/src/drive/tokens/add_transaction_history_operations/v0/mod.rs +++ b/packages/rs-drive/src/drive/tokens/add_transaction_history_operations/v0/mod.rs @@ -32,7 +32,7 @@ impl Drive { let document_type = event.associated_document_type(&contract)?; - let document = event.build_historical_document_owned( + let document = event.build_associated_historical_document_owned( token_id, owner_id, owner_nonce, diff --git a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/token/mod.rs b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/token/mod.rs index d805cdc4b87..26e16f539bf 100644 --- a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/token/mod.rs +++ b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/token/mod.rs @@ -5,6 +5,10 @@ mod token_destroy_frozen_funds_transition; mod token_emergency_action_transition; mod token_freeze_transition; mod token_mint_transition; +mod token_order_adjust_price_transition; +mod token_order_buy_limit_transition; +mod token_order_cancel_transition; +mod token_order_sell_limit_transition; mod token_transfer_transition; mod token_transition; mod token_unfreeze_transition; diff --git a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/token/token_order_adjust_price_transition.rs b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/token/token_order_adjust_price_transition.rs new file mode 100644 index 00000000000..29e2f6820f5 --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/token/token_order_adjust_price_transition.rs @@ -0,0 +1,55 @@ +use dpp::block::epoch::Epoch; +use dpp::identifier::Identifier; +use platform_version::version::PlatformVersion; +use crate::error::drive::DriveError; +use crate::error::Error; +use crate::state_transition_action::action_convert_to_operations::batch::DriveHighLevelBatchOperationConverter; +use crate::state_transition_action::batch::batched_transition::token_transition::token_base_transition_action::TokenBaseTransitionActionAccessorsV0; +use crate::state_transition_action::batch::batched_transition::token_transition::token_order_adjust_price_transition_action::action::TokenOrderAdjustPriceTransitionAction; +use crate::state_transition_action::batch::batched_transition::token_transition::token_order_adjust_price_transition_action::TokenOrderAdjustPriceTransitionActionAccessorsV0; +use crate::util::batch::{DriveOperation, IdentityOperationType}; +use crate::util::batch::DriveOperation::{IdentityOperation}; + +impl DriveHighLevelBatchOperationConverter for TokenOrderAdjustPriceTransitionAction { + fn into_high_level_batch_drive_operations<'b>( + self, + _epoch: &Epoch, + owner_id: Identifier, + platform_version: &PlatformVersion, + ) -> Result>, Error> { + match platform_version + .drive + .methods + .state_transitions + .convert_to_high_level_operations + .token_mint_transition + { + 0 => { + let data_contract_id = self.base().data_contract_id(); + + let identity_contract_nonce = self.base().identity_contract_nonce(); + + let mut ops = vec![IdentityOperation( + IdentityOperationType::UpdateIdentityContractNonce { + identity_id: owner_id.into_buffer(), + contract_id: data_contract_id.into_buffer(), + nonce: identity_contract_nonce, + }, + )]; + + // TODO: Token Event? + + // TODO: Add operation + + Ok(ops) + } + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: + "TokenOrderAdjustPriceTransitionAction::into_high_level_document_drive_operations" + .to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/token/token_order_buy_limit_transition.rs b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/token/token_order_buy_limit_transition.rs new file mode 100644 index 00000000000..77c5dcd51dc --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/token/token_order_buy_limit_transition.rs @@ -0,0 +1,55 @@ +use dpp::block::epoch::Epoch; +use dpp::identifier::Identifier; +use platform_version::version::PlatformVersion; +use crate::error::drive::DriveError; +use crate::error::Error; +use crate::state_transition_action::action_convert_to_operations::batch::DriveHighLevelBatchOperationConverter; +use crate::state_transition_action::batch::batched_transition::token_transition::token_base_transition_action::TokenBaseTransitionActionAccessorsV0; +use crate::state_transition_action::batch::batched_transition::token_transition::token_order_buy_limit_transition_action::action::TokenOrderBuyLimitTransitionAction; +use crate::state_transition_action::batch::batched_transition::token_transition::token_order_buy_limit_transition_action::TokenOrderBuyLimitTransitionActionAccessorsV0; +use crate::util::batch::{DriveOperation, IdentityOperationType}; +use crate::util::batch::DriveOperation::{IdentityOperation}; + +impl DriveHighLevelBatchOperationConverter for TokenOrderBuyLimitTransitionAction { + fn into_high_level_batch_drive_operations<'b>( + self, + _epoch: &Epoch, + owner_id: Identifier, + platform_version: &PlatformVersion, + ) -> Result>, Error> { + match platform_version + .drive + .methods + .state_transitions + .convert_to_high_level_operations + .token_mint_transition + { + 0 => { + let data_contract_id = self.base().data_contract_id(); + + let identity_contract_nonce = self.base().identity_contract_nonce(); + + let mut ops = vec![IdentityOperation( + IdentityOperationType::UpdateIdentityContractNonce { + identity_id: owner_id.into_buffer(), + contract_id: data_contract_id.into_buffer(), + nonce: identity_contract_nonce, + }, + )]; + + // TODO: Token Event? + + // TODO: Add operation + + Ok(ops) + } + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: + "TokenOrderBuyLimitTransitionAction::into_high_level_document_drive_operations" + .to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/token/token_order_cancel_transition.rs b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/token/token_order_cancel_transition.rs new file mode 100644 index 00000000000..288bcfb4f53 --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/token/token_order_cancel_transition.rs @@ -0,0 +1,55 @@ +use dpp::block::epoch::Epoch; +use dpp::identifier::Identifier; +use platform_version::version::PlatformVersion; +use crate::error::drive::DriveError; +use crate::error::Error; +use crate::state_transition_action::action_convert_to_operations::batch::DriveHighLevelBatchOperationConverter; +use crate::state_transition_action::batch::batched_transition::token_transition::token_base_transition_action::TokenBaseTransitionActionAccessorsV0; +use crate::state_transition_action::batch::batched_transition::token_transition::token_order_cancel_transition_action::action::TokenOrderCancelTransitionAction; +use crate::state_transition_action::batch::batched_transition::token_transition::token_order_cancel_transition_action::TokenOrderCancelTransitionActionAccessorsV0; +use crate::util::batch::{DriveOperation, IdentityOperationType}; +use crate::util::batch::DriveOperation::{IdentityOperation}; + +impl DriveHighLevelBatchOperationConverter for TokenOrderCancelTransitionAction { + fn into_high_level_batch_drive_operations<'b>( + self, + _epoch: &Epoch, + owner_id: Identifier, + platform_version: &PlatformVersion, + ) -> Result>, Error> { + match platform_version + .drive + .methods + .state_transitions + .convert_to_high_level_operations + .token_mint_transition + { + 0 => { + let data_contract_id = self.base().data_contract_id(); + + let identity_contract_nonce = self.base().identity_contract_nonce(); + + let mut ops = vec![IdentityOperation( + IdentityOperationType::UpdateIdentityContractNonce { + identity_id: owner_id.into_buffer(), + contract_id: data_contract_id.into_buffer(), + nonce: identity_contract_nonce, + }, + )]; + + // TODO: Token Event? + + // TODO: Add operation + + Ok(ops) + } + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: + "TokenOrderCancelTransitionAction::into_high_level_document_drive_operations" + .to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/token/token_order_sell_limit_transition.rs b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/token/token_order_sell_limit_transition.rs new file mode 100644 index 00000000000..5b7ae611eab --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/token/token_order_sell_limit_transition.rs @@ -0,0 +1,55 @@ +use dpp::block::epoch::Epoch; +use dpp::identifier::Identifier; +use platform_version::version::PlatformVersion; +use crate::error::drive::DriveError; +use crate::error::Error; +use crate::state_transition_action::action_convert_to_operations::batch::DriveHighLevelBatchOperationConverter; +use crate::state_transition_action::batch::batched_transition::token_transition::token_base_transition_action::TokenBaseTransitionActionAccessorsV0; +use crate::state_transition_action::batch::batched_transition::token_transition::token_order_sell_limit_transition_action::action::TokenOrderSellLimitTransitionAction; +use crate::state_transition_action::batch::batched_transition::token_transition::token_order_sell_limit_transition_action::TokenOrderSellLimitTransitionActionAccessorsV0; +use crate::util::batch::{DriveOperation, IdentityOperationType}; +use crate::util::batch::DriveOperation::{IdentityOperation}; + +impl DriveHighLevelBatchOperationConverter for TokenOrderSellLimitTransitionAction { + fn into_high_level_batch_drive_operations<'b>( + self, + _epoch: &Epoch, + owner_id: Identifier, + platform_version: &PlatformVersion, + ) -> Result>, Error> { + match platform_version + .drive + .methods + .state_transitions + .convert_to_high_level_operations + .token_mint_transition + { + 0 => { + let data_contract_id = self.base().data_contract_id(); + + let identity_contract_nonce = self.base().identity_contract_nonce(); + + let mut ops = vec![IdentityOperation( + IdentityOperationType::UpdateIdentityContractNonce { + identity_id: owner_id.into_buffer(), + contract_id: data_contract_id.into_buffer(), + nonce: identity_contract_nonce, + }, + )]; + + // TODO: Token Event? + + // TODO: Add operation + + Ok(ops) + } + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: + "TokenOrderSellLimitTransitionAction::into_high_level_document_drive_operations" + .to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/token/token_transition.rs b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/token/token_transition.rs index 691674d9f34..d3a96eba305 100644 --- a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/token/token_transition.rs +++ b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/token/token_transition.rs @@ -57,64 +57,111 @@ impl DriveHighLevelBatchOperationConverter for TokenTransitionAction { } TokenTransitionAction::ConfigUpdateAction(token_config_update) => token_config_update .into_high_level_batch_drive_operations(epoch, owner_id, platform_version), + TokenTransitionAction::OrderBuyLimitAction(action) => { + action.into_high_level_batch_drive_operations(epoch, owner_id, platform_version) + } + TokenTransitionAction::OrderSellLimitAction(action) => { + action.into_high_level_batch_drive_operations(epoch, owner_id, platform_version) + } + TokenTransitionAction::OrderCancelAction(action) => { + action.into_high_level_batch_drive_operations(epoch, owner_id, platform_version) + } + TokenTransitionAction::OrderAdjustPriceAction(action) => { + action.into_high_level_batch_drive_operations(epoch, owner_id, platform_version) + } } } } impl TokenTransitionAction { /// Gets the associated token event for the transition action - pub fn associated_token_event(&self) -> TokenEvent { + pub fn associated_token_event(&self) -> Option { match self { - TokenTransitionAction::BurnAction(burn_action) => TokenEvent::Burn( - burn_action.burn_amount(), - burn_action.public_note().cloned(), - ), - TokenTransitionAction::MintAction(mint_action) => TokenEvent::Mint( - mint_action.mint_amount(), - mint_action.identity_balance_holder_id(), - mint_action.public_note().cloned(), - ), + TokenTransitionAction::BurnAction(burn_action) => { + let event = TokenEvent::Burn( + burn_action.burn_amount(), + burn_action.public_note().cloned(), + ); + + Some(event) + } + TokenTransitionAction::MintAction(mint_action) => { + let event = TokenEvent::Mint( + mint_action.mint_amount(), + mint_action.identity_balance_holder_id(), + mint_action.public_note().cloned(), + ); + + Some(event) + } TokenTransitionAction::TransferAction(transfer_action) => { let (public_note, shared_encrypted_note, private_encrypted_note) = transfer_action.notes(); - TokenEvent::Transfer( + + let event = TokenEvent::Transfer( transfer_action.recipient_id(), public_note, shared_encrypted_note, private_encrypted_note, transfer_action.amount(), - ) + ); + + Some(event) + } + TokenTransitionAction::FreezeAction(freeze_action) => { + let event = TokenEvent::Freeze( + freeze_action.identity_to_freeze_id(), + freeze_action.public_note().cloned(), + ); + + Some(event) + } + TokenTransitionAction::UnfreezeAction(unfreeze_action) => { + let event = TokenEvent::Unfreeze( + unfreeze_action.frozen_identity_id(), + unfreeze_action.public_note().cloned(), + ); + + Some(event) + } + TokenTransitionAction::ClaimAction(release_action) => { + let event = TokenEvent::Claim( + release_action.distribution_info().into(), + release_action.amount(), + release_action.public_note().cloned(), + ); + + Some(event) } - TokenTransitionAction::FreezeAction(freeze_action) => TokenEvent::Freeze( - freeze_action.identity_to_freeze_id(), - freeze_action.public_note().cloned(), - ), - TokenTransitionAction::UnfreezeAction(unfreeze_action) => TokenEvent::Unfreeze( - unfreeze_action.frozen_identity_id(), - unfreeze_action.public_note().cloned(), - ), - TokenTransitionAction::ClaimAction(release_action) => TokenEvent::Claim( - release_action.distribution_info().into(), - release_action.amount(), - release_action.public_note().cloned(), - ), TokenTransitionAction::EmergencyActionAction(emergency_action) => { - TokenEvent::EmergencyAction( + let event = TokenEvent::EmergencyAction( emergency_action.emergency_action(), emergency_action.public_note().cloned(), - ) + ); + + Some(event) } TokenTransitionAction::DestroyFrozenFundsAction(destroy_action) => { - TokenEvent::DestroyFrozenFunds( + let event = TokenEvent::DestroyFrozenFunds( destroy_action.frozen_identity_id(), destroy_action.amount(), destroy_action.public_note().cloned(), - ) + ); + + Some(event) + } + TokenTransitionAction::ConfigUpdateAction(config_update) => { + let event = TokenEvent::ConfigUpdate( + config_update.update_token_configuration_item().clone(), + config_update.public_note().cloned(), + ); + + Some(event) } - TokenTransitionAction::ConfigUpdateAction(config_update) => TokenEvent::ConfigUpdate( - config_update.update_token_configuration_item().clone(), - config_update.public_note().cloned(), - ), + TokenTransitionAction::OrderBuyLimitAction(_) => None, + TokenTransitionAction::OrderSellLimitAction(_) => None, + TokenTransitionAction::OrderCancelAction(_) => None, + TokenTransitionAction::OrderAdjustPriceAction(_) => None, } } } diff --git a/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/mod.rs b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/mod.rs index 12e4da46ce8..8eb6e747493 100644 --- a/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/mod.rs +++ b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/mod.rs @@ -22,18 +22,18 @@ pub mod token_emergency_action_transition_action; /// token_claim_transition_action pub mod token_claim_transition_action; +/// token_order_adjust_price_transition_action +pub mod token_order_adjust_price_transition_action; +/// token_order_buy_limit_transition_action +pub mod token_order_buy_limit_transition_action; +/// token_order_cancel_transition_action +pub mod token_order_cancel_transition_action; +/// token_order_sell_limit_transition_action +pub mod token_order_sell_limit_transition_action; use derive_more::From; -use dpp::block::block_info::BlockInfo; -use dpp::data_contract::accessors::v0::DataContractV0Getters; use dpp::data_contract::associated_token::token_configuration::accessors::v0::TokenConfigurationV0Getters; use dpp::data_contract::associated_token::token_keeps_history_rules::accessors::v0::TokenKeepsHistoryRulesV0Getters; -use dpp::data_contract::document_type::DocumentTypeRef; -use dpp::document::Document; -use dpp::identifier::Identifier; -use dpp::prelude::{DataContract, IdentityNonce}; -use dpp::ProtocolError; -use platform_version::version::PlatformVersion; use crate::error::Error; use crate::state_transition_action::batch::batched_transition::token_transition::token_base_transition_action::{TokenBaseTransitionAction, TokenBaseTransitionActionAccessorsV0}; use crate::state_transition_action::batch::batched_transition::token_transition::token_burn_transition_action::{TokenBurnTransitionAction, TokenBurnTransitionActionAccessorsV0}; @@ -48,6 +48,14 @@ use crate::state_transition_action::batch::batched_transition::token_transition: use crate::state_transition_action::batch::batched_transition::token_transition::token_destroy_frozen_funds_transition_action::TokenDestroyFrozenFundsTransitionAction; use crate::state_transition_action::batch::batched_transition::token_transition::token_destroy_frozen_funds_transition_action::TokenDestroyFrozenFundsTransitionActionAccessorsV0; use crate::state_transition_action::batch::batched_transition::token_transition::token_claim_transition_action::{TokenClaimTransitionAction, TokenClaimTransitionActionAccessorsV0}; +use crate::state_transition_action::batch::batched_transition::token_transition::token_order_adjust_price_transition_action::action::TokenOrderAdjustPriceTransitionAction; +use crate::state_transition_action::batch::batched_transition::token_transition::token_order_adjust_price_transition_action::TokenOrderAdjustPriceTransitionActionAccessorsV0; +use crate::state_transition_action::batch::batched_transition::token_transition::token_order_buy_limit_transition_action::action::TokenOrderBuyLimitTransitionAction; +use crate::state_transition_action::batch::batched_transition::token_transition::token_order_buy_limit_transition_action::TokenOrderBuyLimitTransitionActionAccessorsV0; +use crate::state_transition_action::batch::batched_transition::token_transition::token_order_cancel_transition_action::action::TokenOrderCancelTransitionAction; +use crate::state_transition_action::batch::batched_transition::token_transition::token_order_cancel_transition_action::TokenOrderCancelTransitionActionAccessorsV0; +use crate::state_transition_action::batch::batched_transition::token_transition::token_order_sell_limit_transition_action::action::TokenOrderSellLimitTransitionAction; +use crate::state_transition_action::batch::batched_transition::token_transition::token_order_sell_limit_transition_action::TokenOrderSellLimitTransitionActionAccessorsV0; /// token action #[derive(Debug, Clone, From)] @@ -70,6 +78,14 @@ pub enum TokenTransitionAction { DestroyFrozenFundsAction(TokenDestroyFrozenFundsTransitionAction), /// update the token configuration ConfigUpdateAction(TokenConfigUpdateTransitionAction), + /// order buy limit + OrderBuyLimitAction(TokenOrderBuyLimitTransitionAction), + /// order sell limit + OrderSellLimitAction(TokenOrderSellLimitTransitionAction), + /// order cancel + OrderCancelAction(TokenOrderCancelTransitionAction), + /// order adjust price + OrderAdjustPriceAction(TokenOrderAdjustPriceTransitionAction), } impl TokenTransitionAction { @@ -85,6 +101,10 @@ impl TokenTransitionAction { TokenTransitionAction::EmergencyActionAction(action) => action.base(), TokenTransitionAction::DestroyFrozenFundsAction(action) => action.base(), TokenTransitionAction::ConfigUpdateAction(action) => action.base(), + TokenTransitionAction::OrderBuyLimitAction(action) => action.base(), + TokenTransitionAction::OrderSellLimitAction(action) => action.base(), + TokenTransitionAction::OrderCancelAction(action) => action.base(), + TokenTransitionAction::OrderAdjustPriceAction(action) => action.base(), } } @@ -100,65 +120,13 @@ impl TokenTransitionAction { TokenTransitionAction::EmergencyActionAction(action) => action.base_owned(), TokenTransitionAction::DestroyFrozenFundsAction(action) => action.base_owned(), TokenTransitionAction::ConfigUpdateAction(action) => action.base_owned(), + TokenTransitionAction::OrderBuyLimitAction(action) => action.base_owned(), + TokenTransitionAction::OrderSellLimitAction(action) => action.base_owned(), + TokenTransitionAction::OrderCancelAction(action) => action.base_owned(), + TokenTransitionAction::OrderAdjustPriceAction(action) => action.base_owned(), } } - /// Historical document type name for the token history contract - pub fn historical_document_type_name(&self) -> &str { - match self { - TokenTransitionAction::BurnAction(_) => "burn", - TokenTransitionAction::MintAction(_) => "mint", - TokenTransitionAction::TransferAction(_) => "transfer", - TokenTransitionAction::FreezeAction(_) => "freeze", - TokenTransitionAction::UnfreezeAction(_) => "unfreeze", - TokenTransitionAction::ClaimAction(_) => "claim", - TokenTransitionAction::EmergencyActionAction(_) => "emergencyAction", - TokenTransitionAction::DestroyFrozenFundsAction(_) => "destroyFrozenFunds", - TokenTransitionAction::ConfigUpdateAction(_) => "configUpdate", - } - } - - /// Historical document type for the token history contract - pub fn historical_document_type<'a>( - &self, - token_history_contract: &'a DataContract, - ) -> Result, ProtocolError> { - Ok(token_history_contract.document_type_for_name(self.historical_document_type_name())?) - } - - /// Historical document id - pub fn historical_document_id(&self, owner_id: Identifier) -> Identifier { - let token_id = self.base().token_id(); - let name = self.historical_document_type_name(); - let owner_nonce = self.base().identity_contract_nonce(); - Document::generate_document_id_v0( - &token_id, - &owner_id, - format!("history_{}", name).as_str(), - owner_nonce.to_be_bytes().as_slice(), - ) - } - - /// Historical document id - pub fn build_historical_document( - &self, - token_id: Identifier, - owner_id: Identifier, - owner_nonce: IdentityNonce, - block_info: &BlockInfo, - platform_version: &PlatformVersion, - ) -> Result { - self.associated_token_event() - .build_historical_document_owned( - token_id, - owner_id, - owner_nonce, - block_info, - platform_version, - ) - .map_err(Error::Protocol) - } - /// Do we keep history for this action pub fn keeps_history(&self) -> Result { let keeps_history = self.base().token_configuration()?.keeps_history(); @@ -172,6 +140,11 @@ impl TokenTransitionAction { TokenTransitionAction::EmergencyActionAction(_) => Ok(true), TokenTransitionAction::DestroyFrozenFundsAction(_) => Ok(true), TokenTransitionAction::ConfigUpdateAction(_) => Ok(true), + // TODO: Back to it + TokenTransitionAction::OrderBuyLimitAction(_) => Ok(false), + TokenTransitionAction::OrderSellLimitAction(_) => Ok(false), + TokenTransitionAction::OrderCancelAction(_) => Ok(false), + TokenTransitionAction::OrderAdjustPriceAction(_) => Ok(false), } } } diff --git a/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_order_adjust_price_transition_action/action.rs b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_order_adjust_price_transition_action/action.rs new file mode 100644 index 00000000000..9afe9acc06d --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_order_adjust_price_transition_action/action.rs @@ -0,0 +1,38 @@ +use derive_more::From; +use dpp::identifier::Identifier; +use dpp::prelude::Revision; +use crate::state_transition_action::batch::batched_transition::token_transition::token_base_transition_action::TokenBaseTransitionAction; +use crate::state_transition_action::batch::batched_transition::token_transition::token_order_adjust_price_transition_action::v0::action::{TokenOrderAdjustPriceTransitionActionAccessorsV0, TokenOrderAdjustPriceTransitionActionV0}; + +/// Token release transition action +#[derive(Debug, Clone, From)] +pub enum TokenOrderAdjustPriceTransitionAction { + /// v0 + V0(TokenOrderAdjustPriceTransitionActionV0), +} + +impl TokenOrderAdjustPriceTransitionActionAccessorsV0 for TokenOrderAdjustPriceTransitionAction { + fn base(&self) -> &TokenBaseTransitionAction { + match self { + TokenOrderAdjustPriceTransitionAction::V0(v0) => &v0.base, + } + } + + fn base_owned(self) -> TokenBaseTransitionAction { + match self { + TokenOrderAdjustPriceTransitionAction::V0(v0) => v0.base, + } + } + + fn order_id(&self) -> Identifier { + match self { + TokenOrderAdjustPriceTransitionAction::V0(v0) => v0.order_id, + } + } + + fn order_revision(&self) -> Revision { + match self { + TokenOrderAdjustPriceTransitionAction::V0(v0) => v0.order_revision, + } + } +} diff --git a/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_order_adjust_price_transition_action/mod.rs b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_order_adjust_price_transition_action/mod.rs new file mode 100644 index 00000000000..6a9bce80de1 --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_order_adjust_price_transition_action/mod.rs @@ -0,0 +1,7 @@ +/// token order adjust price transition action module +pub mod action; +/// transformer module for token release transition action +pub mod transformer; +mod v0; + +pub use v0::*; // re-export the v0 module items (including TokenIssuanceTransitionActionV0) diff --git a/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_order_adjust_price_transition_action/transformer.rs b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_order_adjust_price_transition_action/transformer.rs new file mode 100644 index 00000000000..1014e91fae7 --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_order_adjust_price_transition_action/transformer.rs @@ -0,0 +1,120 @@ +use dpp::platform_value::Identifier; +use dpp::ProtocolError; +use grovedb::TransactionArg; +use std::sync::Arc; +use dpp::block::block_info::BlockInfo; +use dpp::fee::fee_result::FeeResult; +use dpp::prelude::{ConsensusValidationResult, UserFeeIncrease}; +use dpp::state_transition::batch_transition::batched_transition::token_order_adjust_price_transition::transition::TokenOrderAdjustPriceTransition; +use crate::drive::contract::DataContractFetchInfo; +use platform_version::version::PlatformVersion; +use crate::drive::Drive; +use crate::error::Error; +use crate::state_transition_action::batch::batched_transition::token_transition::token_order_adjust_price_transition_action::action::TokenOrderAdjustPriceTransitionAction; +use crate::state_transition_action::batch::batched_transition::token_transition::token_order_adjust_price_transition_action::v0::action::TokenOrderAdjustPriceTransitionActionV0; +use crate::state_transition_action::batch::BatchedTransitionAction; + +/// Implement methods to transform a `TokenOrderAdjustPriceTransition` into a `TokenOrderAdjustPriceTransitionAction`. +impl TokenOrderAdjustPriceTransitionAction { + /// Transform a `TokenOrderAdjustPriceTransition` into a `TokenOrderAdjustPriceTransitionAction` using the provided data contract lookup. + /// + /// # Arguments + /// + /// * `drive` - A reference to the `Drive` instance used for accessing the system. + /// * `owner_id` - The identifier of the owner initiating the release transition. + /// * `transaction` - The transaction argument used for state changes. + /// * `value` - A `TokenOrderAdjustPriceTransition` instance. + /// * `approximate_without_state_for_costs` - A flag indicating whether to approximate state costs without full state. + /// * `drive_operations` - A mutable reference to the vector of low-level operations that need to be performed. + /// * `get_data_contract` - A closure that fetches the `DataContractFetchInfo` given a contract ID. + /// * `platform_version` - The platform version for the context in which the transition is being executed. + /// + /// # Returns + /// + /// * `Result<(ConsensusValidationResult, FeeResult), Error>` - A `TokenOrderAdjustPriceTransitionAction` if successful, otherwise `ProtocolError`. + #[allow(clippy::too_many_arguments)] + pub fn try_from_token_order_adjust_price_transition_with_contract_lookup( + drive: &Drive, + owner_id: Identifier, + value: TokenOrderAdjustPriceTransition, + approximate_without_state_for_costs: bool, + transaction: TransactionArg, + block_info: &BlockInfo, + user_fee_increase: UserFeeIncrease, + get_data_contract: impl Fn(Identifier) -> Result, ProtocolError>, + platform_version: &PlatformVersion, + ) -> Result< + ( + ConsensusValidationResult, + FeeResult, + ), + Error, + > { + match value { + TokenOrderAdjustPriceTransition::V0(v0) => { + TokenOrderAdjustPriceTransitionActionV0::try_from_token_order_adjust_price_transition_with_contract_lookup( + drive, + owner_id, + v0, + approximate_without_state_for_costs, + transaction, + block_info, + user_fee_increase, + get_data_contract, + platform_version, + ) + } + } + } + + /// Transform a borrowed `TokenOrderAdjustPriceTransition` into a `TokenOrderAdjustPriceTransitionAction` using the provided data contract lookup. + /// + /// # Arguments + /// + /// * `drive` - A reference to the `Drive` instance used for accessing the system. + /// * `owner_id` - The identifier of the owner initiating the release transition. + /// * `transaction` - The transaction argument used for state changes. + /// * `value` - A reference to a `TokenOrderAdjustPriceTransition`. + /// * `approximate_without_state_for_costs` - A flag indicating whether to approximate state costs without full state. + /// * `drive_operations` - A mutable reference to the vector of low-level operations that need to be performed. + /// * `get_data_contract` - A closure that fetches the `DataContractFetchInfo` given a contract ID. + /// * `platform_version` - The platform version for the context in which the transition is being executed. + /// + /// # Returns + /// + #[allow(clippy::too_many_arguments)] + /// * `Result<(ConsensusValidationResult, FeeResult), Error>` - A `TokenOrderAdjustPriceTransitionAction` if successful, otherwise `ProtocolError`. + pub fn try_from_borrowed_token_order_adjust_price_transition_with_contract_lookup( + drive: &Drive, + owner_id: Identifier, + value: &TokenOrderAdjustPriceTransition, + approximate_without_state_for_costs: bool, + transaction: TransactionArg, + block_info: &BlockInfo, + user_fee_increase: UserFeeIncrease, + get_data_contract: impl Fn(Identifier) -> Result, ProtocolError>, + platform_version: &PlatformVersion, + ) -> Result< + ( + ConsensusValidationResult, + FeeResult, + ), + Error, + > { + match value { + TokenOrderAdjustPriceTransition::V0(v0) => { + TokenOrderAdjustPriceTransitionActionV0::try_from_borrowed_token_order_adjust_price_transition_with_contract_lookup( + drive, + owner_id, + v0, + approximate_without_state_for_costs, + transaction, + block_info, + user_fee_increase, + get_data_contract, + platform_version, + ) + } + } + } +} diff --git a/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_order_adjust_price_transition_action/v0/action.rs b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_order_adjust_price_transition_action/v0/action.rs new file mode 100644 index 00000000000..6bcc758f36b --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_order_adjust_price_transition_action/v0/action.rs @@ -0,0 +1,79 @@ +use std::sync::Arc; +use dpp::balances::credits::TokenAmount; +use dpp::fee::Credits; +use dpp::identifier::Identifier; +use dpp::prelude::Revision; +use dpp::state_transition::batch_transition::batched_transition::Entropy; +use crate::drive::contract::DataContractFetchInfo; +use crate::state_transition_action::batch::batched_transition::token_transition::token_base_transition_action::{TokenBaseTransitionAction, TokenBaseTransitionActionAccessorsV0}; + +/// Token order cancel transition action v0 +#[derive(Debug, Clone)] +pub struct TokenOrderAdjustPriceTransitionActionV0 { + /// Base token transition action + pub base: TokenBaseTransitionAction, + /// Entropy generated to create order ID + pub order_id: Identifier, + /// Token amount to sell + pub order_revision: Revision, + /// + pub token_price: Credits, +} + +/// Accessors for `TokenOrderAdjustPriceTransitionActionV0` +pub trait TokenOrderAdjustPriceTransitionActionAccessorsV0 { + /// Returns a reference to the base token transition action + fn base(&self) -> &TokenBaseTransitionAction; + + /// Consumes self and returns the base token transition action + fn base_owned(self) -> TokenBaseTransitionAction; + + /// Returns the token position in the contract + fn token_position(&self) -> u16 { + self.base().token_position() + } + + /// Returns the token ID + fn token_id(&self) -> Identifier { + self.base().token_id() + } + + /// Returns the data contract ID + fn data_contract_id(&self) -> Identifier { + self.base().data_contract_id() + } + + /// Returns a reference to the data contract fetch info + fn data_contract_fetch_info_ref(&self) -> &Arc { + self.base().data_contract_fetch_info_ref() + } + + /// Returns the data contract fetch info + fn data_contract_fetch_info(&self) -> Arc { + self.base().data_contract_fetch_info() + } + + /// Order ID to cancel + fn order_id(&self) -> Identifier; + + /// Order Revision to cancel + fn order_revision(&self) -> Revision; +} + +impl TokenOrderAdjustPriceTransitionActionAccessorsV0 for TokenOrderAdjustPriceTransitionActionV0 { + fn base(&self) -> &TokenBaseTransitionAction { + &self.base + } + + fn base_owned(self) -> TokenBaseTransitionAction { + self.base + } + + fn order_id(&self) -> Identifier { + self.order_id + } + + fn order_revision(&self) -> Revision { + self.order_revision + } +} diff --git a/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_order_adjust_price_transition_action/v0/mod.rs b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_order_adjust_price_transition_action/v0/mod.rs new file mode 100644 index 00000000000..ac3b822b6c5 --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_order_adjust_price_transition_action/v0/mod.rs @@ -0,0 +1,5 @@ +pub mod action; +pub mod transformer; + +pub use action::*; +pub use transformer::*; diff --git a/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_order_adjust_price_transition_action/v0/transformer.rs b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_order_adjust_price_transition_action/v0/transformer.rs new file mode 100644 index 00000000000..7d1f7e7aff4 --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_order_adjust_price_transition_action/v0/transformer.rs @@ -0,0 +1,182 @@ +use std::sync::Arc; +use grovedb::TransactionArg; +use dpp::block::block_info::BlockInfo; +use dpp::identifier::Identifier; +use dpp::ProtocolError; +use crate::drive::contract::DataContractFetchInfo; +use crate::state_transition_action::batch::batched_transition::token_transition::token_base_transition_action::{TokenBaseTransitionAction}; +use dpp::fee::fee_result::FeeResult; +use dpp::prelude::{ConsensusValidationResult, UserFeeIncrease}; +use dpp::state_transition::batch_transition::batched_transition::token_order_adjust_price_transition::v0::accessors::TokenOrderAdjustPriceTransitionV0Methods; +use dpp::state_transition::batch_transition::batched_transition::token_order_adjust_price_transition::v0::transition::TokenOrderAdjustPriceTransitionV0; +use dpp::state_transition::batch_transition::token_base_transition::token_base_transition_accessors::TokenBaseTransitionAccessors; +use platform_version::version::PlatformVersion; +use crate::drive::Drive; +use crate::error::Error; +use crate::state_transition_action::batch::batched_transition::BatchedTransitionAction; +use crate::state_transition_action::batch::batched_transition::token_transition::token_order_adjust_price_transition_action::v0::action::TokenOrderAdjustPriceTransitionActionV0; +use crate::state_transition_action::batch::batched_transition::token_transition::TokenTransitionAction; +use crate::state_transition_action::system::bump_identity_data_contract_nonce_action::BumpIdentityDataContractNonceAction; + +impl TokenOrderAdjustPriceTransitionActionV0 { + /// Converts a `TokenOrderAdjustPriceTransitionV0` into a `TokenOrderAdjustPriceTransitionActionV0` using the provided contract lookup. + /// + /// This method processes the token releasing transition and returns the corresponding transition action + /// while looking up necessary data contracts and applying the relevant logic for releasing. + /// + /// # Arguments + /// + /// * `drive` - A reference to the `Drive` instance which handles data storage and retrieval. + /// * `owner_id` - The identifier of the owner initiating the releasing transition. This is typically the identity + /// performing the transaction, such as the user's ID. + /// * `transaction` - A transaction context that includes the necessary state and other details for the transition. + /// * `value` - The `TokenOrderAdjustPriceTransitionV0` struct containing the transition data, including token amount and recipient. + /// * `approximate_without_state_for_costs` - A flag to determine if costs should be approximated without considering + /// the full state for the operation. Useful for optimizing the transaction cost calculations. + /// * `block_info` - Information about the current block to calculate fees. + /// * `get_data_contract` - A closure function that takes a contract identifier and returns a `DataContractFetchInfo` + /// containing the data contract details, including token configurations. + /// * `platform_version` - A reference to the platform version, ensuring the transition respects version-specific logic. + /// + /// # Returns + /// + /// * `Result, Error>` - Returns the constructed `TokenOrderAdjustPriceTransitionActionV0` if successful, + /// or an error if any issue arises, such as missing data or an invalid state transition. + #[allow(clippy::too_many_arguments)] + pub fn try_from_token_order_adjust_price_transition_with_contract_lookup( + drive: &Drive, + owner_id: Identifier, + value: TokenOrderAdjustPriceTransitionV0, + approximate_without_state_for_costs: bool, + transaction: TransactionArg, + block_info: &BlockInfo, + user_fee_increase: UserFeeIncrease, + get_data_contract: impl Fn(Identifier) -> Result, ProtocolError>, + platform_version: &PlatformVersion, + ) -> Result< + ( + ConsensusValidationResult, + FeeResult, + ), + Error, + > { + Self::try_from_borrowed_token_order_adjust_price_transition_with_contract_lookup( + drive, + owner_id, + &value, + approximate_without_state_for_costs, + transaction, + block_info, + user_fee_increase, + get_data_contract, + platform_version, + ) + } + + /// Converts a borrowed `TokenOrderAdjustPriceTransitionV0` into a `TokenOrderAdjustPriceTransitionActionV0` using the provided contract lookup. + /// + /// This method processes the token releasing transition and constructs the corresponding transition action while + /// looking up necessary data contracts and applying the relevant releasing logic. It does not require `drive_operations` + /// to be passed as a parameter, but it manages them internally. + /// + /// # Arguments + /// + /// * `drive` - A reference to the `Drive` instance that handles data storage and retrieval. + /// * `owner_id` - The identifier of the owner initiating the releasing transition. This is typically the identity + /// performing the transaction, such as the user's ID. + /// * `value` - A reference to the `TokenOrderAdjustPriceTransitionV0` struct containing the transition data, including token + /// amount and recipient. + /// * `approximate_without_state_for_costs` - A flag to indicate whether costs should be approximated without full + /// state consideration. Useful for optimizing transaction cost calculations in scenarios where full state is not needed. + /// * `transaction` - The transaction context, which includes the necessary state and other details for the transition. + /// * `block_info` - Information about the current block (e.g., epoch) to help calculate transaction fees. + /// * `get_data_contract` - A closure function that takes a contract identifier and returns a `DataContractFetchInfo` + /// containing the data contract details, including token configurations. + /// * `platform_version` - A reference to the platform version to ensure the transition respects version-specific logic. + /// + //// # Returns + /// + /// * `Result<(ConsensusValidationResult, FeeResult), Error>` - Returns a tuple containing the constructed + /// `TokenOrderAdjustPriceTransitionActionV0` and a `FeeResult` if successful. If an error occurs (e.g., missing data or + /// invalid state transition), it returns an `Error`. + /// + #[allow(clippy::too_many_arguments)] + pub fn try_from_borrowed_token_order_adjust_price_transition_with_contract_lookup( + drive: &Drive, + owner_id: Identifier, + value: &TokenOrderAdjustPriceTransitionV0, + approximate_without_state_for_costs: bool, + transaction: TransactionArg, + block_info: &BlockInfo, + user_fee_increase: UserFeeIncrease, + get_data_contract: impl Fn(Identifier) -> Result, ProtocolError>, + platform_version: &PlatformVersion, + ) -> Result< + ( + ConsensusValidationResult, + FeeResult, + ), + Error, + > { + let mut drive_operations = vec![]; + + let base_action_validation_result = + TokenBaseTransitionAction::try_from_borrowed_base_transition_with_contract_lookup( + drive, + owner_id, + value.base(), + approximate_without_state_for_costs, + transaction, + &mut drive_operations, + get_data_contract, + platform_version, + )?; + + let mut fee_result = Drive::calculate_fee( + None, + Some(drive_operations), + &block_info.epoch, + drive.config.epochs_per_era, + platform_version, + None, + )?; + + let base = match base_action_validation_result.is_valid() { + true => base_action_validation_result.into_data()?, + false => { + let bump_action = + BumpIdentityDataContractNonceAction::from_borrowed_token_base_transition( + value.base(), + owner_id, + user_fee_increase, + ); + let batched_action = + BatchedTransitionAction::BumpIdentityDataContractNonce(bump_action); + + return Ok(( + ConsensusValidationResult::new_with_data_and_errors( + batched_action, + base_action_validation_result.errors, + ), + fee_result, + )); + } + }; + + // TODO: Consider to add some validation here + + Ok(( + BatchedTransitionAction::TokenAction(TokenTransitionAction::OrderAdjustPriceAction( + Self { + base, + order_id: value.order_id(), + order_revision: value.order_revision(), + token_price: value.token_price(), + } + .into(), + )) + .into(), + fee_result, + )) + } +} diff --git a/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_order_buy_limit_transition_action/action.rs b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_order_buy_limit_transition_action/action.rs new file mode 100644 index 00000000000..387f2ef9dc6 --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_order_buy_limit_transition_action/action.rs @@ -0,0 +1,45 @@ +use derive_more::From; +use dpp::balances::credits::TokenAmount; +use dpp::fee::Credits; +use dpp::state_transition::batch_transition::batched_transition::Entropy; +use crate::state_transition_action::batch::batched_transition::token_transition::token_base_transition_action::TokenBaseTransitionAction; +use crate::state_transition_action::batch::batched_transition::token_transition::token_order_buy_limit_transition_action::v0::action::{TokenOrderBuyLimitTransitionActionAccessorsV0, TokenOrderBuyLimitTransitionActionV0}; + +/// Token release transition action +#[derive(Debug, Clone, From)] +pub enum TokenOrderBuyLimitTransitionAction { + /// v0 + V0(TokenOrderBuyLimitTransitionActionV0), +} + +impl TokenOrderBuyLimitTransitionActionAccessorsV0 for TokenOrderBuyLimitTransitionAction { + fn base(&self) -> &TokenBaseTransitionAction { + match self { + TokenOrderBuyLimitTransitionAction::V0(v0) => &v0.base, + } + } + + fn base_owned(self) -> TokenBaseTransitionAction { + match self { + TokenOrderBuyLimitTransitionAction::V0(v0) => v0.base, + } + } + + fn order_id_entropy(&self) -> Entropy { + match self { + TokenOrderBuyLimitTransitionAction::V0(v0) => v0.order_id_entropy, + } + } + + fn token_amount(&self) -> TokenAmount { + match self { + TokenOrderBuyLimitTransitionAction::V0(v0) => v0.token_amount, + } + } + + fn token_max_price(&self) -> Credits { + match self { + TokenOrderBuyLimitTransitionAction::V0(v0) => v0.token_max_price, + } + } +} diff --git a/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_order_buy_limit_transition_action/mod.rs b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_order_buy_limit_transition_action/mod.rs new file mode 100644 index 00000000000..1a1e985d2bf --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_order_buy_limit_transition_action/mod.rs @@ -0,0 +1,7 @@ +/// token order buy limit transition action module +pub mod action; +/// transformer module for token release transition action +pub mod transformer; +mod v0; + +pub use v0::*; // re-export the v0 module items (including TokenIssuanceTransitionActionV0) diff --git a/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_order_buy_limit_transition_action/transformer.rs b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_order_buy_limit_transition_action/transformer.rs new file mode 100644 index 00000000000..69b238a8943 --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_order_buy_limit_transition_action/transformer.rs @@ -0,0 +1,120 @@ +use dpp::platform_value::Identifier; +use dpp::ProtocolError; +use grovedb::TransactionArg; +use std::sync::Arc; +use dpp::block::block_info::BlockInfo; +use dpp::fee::fee_result::FeeResult; +use dpp::prelude::{ConsensusValidationResult, UserFeeIncrease}; +use dpp::state_transition::batch_transition::batched_transition::token_order_buy_limit_transition::transition::TokenOrderBuyLimitTransition; +use crate::drive::contract::DataContractFetchInfo; +use platform_version::version::PlatformVersion; +use crate::drive::Drive; +use crate::error::Error; +use crate::state_transition_action::batch::batched_transition::token_transition::token_order_buy_limit_transition_action::action::TokenOrderBuyLimitTransitionAction; +use crate::state_transition_action::batch::batched_transition::token_transition::token_order_buy_limit_transition_action::v0::action::TokenOrderBuyLimitTransitionActionV0; +use crate::state_transition_action::batch::BatchedTransitionAction; + +/// Implement methods to transform a `TokenOrderBuyLimitTransition` into a `TokenOrderBuyLimitTransitionAction`. +impl TokenOrderBuyLimitTransitionAction { + /// Transform a `TokenOrderBuyLimitTransition` into a `TokenOrderBuyLimitTransitionAction` using the provided data contract lookup. + /// + /// # Arguments + /// + /// * `drive` - A reference to the `Drive` instance used for accessing the system. + /// * `owner_id` - The identifier of the owner initiating the release transition. + /// * `transaction` - The transaction argument used for state changes. + /// * `value` - A `TokenOrderBuyLimitTransition` instance. + /// * `approximate_without_state_for_costs` - A flag indicating whether to approximate state costs without full state. + /// * `drive_operations` - A mutable reference to the vector of low-level operations that need to be performed. + /// * `get_data_contract` - A closure that fetches the `DataContractFetchInfo` given a contract ID. + /// * `platform_version` - The platform version for the context in which the transition is being executed. + /// + /// # Returns + /// + /// * `Result<(ConsensusValidationResult, FeeResult), Error>` - A `TokenOrderBuyLimitTransitionAction` if successful, otherwise `ProtocolError`. + #[allow(clippy::too_many_arguments)] + pub fn try_from_token_order_buy_limit_transition_with_contract_lookup( + drive: &Drive, + owner_id: Identifier, + value: TokenOrderBuyLimitTransition, + approximate_without_state_for_costs: bool, + transaction: TransactionArg, + block_info: &BlockInfo, + user_fee_increase: UserFeeIncrease, + get_data_contract: impl Fn(Identifier) -> Result, ProtocolError>, + platform_version: &PlatformVersion, + ) -> Result< + ( + ConsensusValidationResult, + FeeResult, + ), + Error, + > { + match value { + TokenOrderBuyLimitTransition::V0(v0) => { + TokenOrderBuyLimitTransitionActionV0::try_from_token_order_buy_limit_transition_with_contract_lookup( + drive, + owner_id, + v0, + approximate_without_state_for_costs, + transaction, + block_info, + user_fee_increase, + get_data_contract, + platform_version, + ) + } + } + } + + /// Transform a borrowed `TokenOrderBuyLimitTransition` into a `TokenOrderBuyLimitTransitionAction` using the provided data contract lookup. + /// + /// # Arguments + /// + /// * `drive` - A reference to the `Drive` instance used for accessing the system. + /// * `owner_id` - The identifier of the owner initiating the release transition. + /// * `transaction` - The transaction argument used for state changes. + /// * `value` - A reference to a `TokenOrderBuyLimitTransition`. + /// * `approximate_without_state_for_costs` - A flag indicating whether to approximate state costs without full state. + /// * `drive_operations` - A mutable reference to the vector of low-level operations that need to be performed. + /// * `get_data_contract` - A closure that fetches the `DataContractFetchInfo` given a contract ID. + /// * `platform_version` - The platform version for the context in which the transition is being executed. + /// + /// # Returns + /// + #[allow(clippy::too_many_arguments)] + /// * `Result<(ConsensusValidationResult, FeeResult), Error>` - A `TokenOrderBuyLimitTransitionAction` if successful, otherwise `ProtocolError`. + pub fn try_from_borrowed_token_order_buy_limit_transition_with_contract_lookup( + drive: &Drive, + owner_id: Identifier, + value: &TokenOrderBuyLimitTransition, + approximate_without_state_for_costs: bool, + transaction: TransactionArg, + block_info: &BlockInfo, + user_fee_increase: UserFeeIncrease, + get_data_contract: impl Fn(Identifier) -> Result, ProtocolError>, + platform_version: &PlatformVersion, + ) -> Result< + ( + ConsensusValidationResult, + FeeResult, + ), + Error, + > { + match value { + TokenOrderBuyLimitTransition::V0(v0) => { + TokenOrderBuyLimitTransitionActionV0::try_from_borrowed_token_order_buy_limit_transition_with_contract_lookup( + drive, + owner_id, + v0, + approximate_without_state_for_costs, + transaction, + block_info, + user_fee_increase, + get_data_contract, + platform_version, + ) + } + } + } +} diff --git a/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_order_buy_limit_transition_action/v0/action.rs b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_order_buy_limit_transition_action/v0/action.rs new file mode 100644 index 00000000000..78652d9e434 --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_order_buy_limit_transition_action/v0/action.rs @@ -0,0 +1,85 @@ +use std::sync::Arc; +use dpp::balances::credits::TokenAmount; +use dpp::fee::Credits; +use dpp::identifier::Identifier; +use dpp::state_transition::batch_transition::batched_transition::Entropy; +use crate::drive::contract::DataContractFetchInfo; +use crate::state_transition_action::batch::batched_transition::token_transition::token_base_transition_action::{TokenBaseTransitionAction, TokenBaseTransitionActionAccessorsV0}; + +/// Token order buy limit transition action v0 +#[derive(Debug, Clone)] +pub struct TokenOrderBuyLimitTransitionActionV0 { + /// Base token transition action + pub base: TokenBaseTransitionAction, + /// Entropy generated to create order ID + pub order_id_entropy: Entropy, + /// Token amount to buy + pub token_amount: TokenAmount, + /// Max price to pay for the tokens + pub token_max_price: Credits, +} + +/// Accessors for `TokenOrderBuyLimitTransitionActionV0` +pub trait TokenOrderBuyLimitTransitionActionAccessorsV0 { + /// Returns a reference to the base token transition action + fn base(&self) -> &TokenBaseTransitionAction; + + /// Consumes self and returns the base token transition action + fn base_owned(self) -> TokenBaseTransitionAction; + + /// Returns the token position in the contract + fn token_position(&self) -> u16 { + self.base().token_position() + } + + /// Returns the token ID + fn token_id(&self) -> Identifier { + self.base().token_id() + } + + /// Returns the data contract ID + fn data_contract_id(&self) -> Identifier { + self.base().data_contract_id() + } + + /// Returns a reference to the data contract fetch info + fn data_contract_fetch_info_ref(&self) -> &Arc { + self.base().data_contract_fetch_info_ref() + } + + /// Returns the data contract fetch info + fn data_contract_fetch_info(&self) -> Arc { + self.base().data_contract_fetch_info() + } + + /// Returns entropy generated to create order ID + fn order_id_entropy(&self) -> Entropy; + + /// Returns the token amount to buy + fn token_amount(&self) -> TokenAmount; + + /// Returns the max price to pay for the tokens + fn token_max_price(&self) -> Credits; +} + +impl TokenOrderBuyLimitTransitionActionAccessorsV0 for TokenOrderBuyLimitTransitionActionV0 { + fn base(&self) -> &TokenBaseTransitionAction { + &self.base + } + + fn base_owned(self) -> TokenBaseTransitionAction { + self.base + } + + fn order_id_entropy(&self) -> Entropy { + self.order_id_entropy + } + + fn token_amount(&self) -> TokenAmount { + self.token_amount + } + + fn token_max_price(&self) -> Credits { + self.token_max_price + } +} diff --git a/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_order_buy_limit_transition_action/v0/mod.rs b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_order_buy_limit_transition_action/v0/mod.rs new file mode 100644 index 00000000000..ac3b822b6c5 --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_order_buy_limit_transition_action/v0/mod.rs @@ -0,0 +1,5 @@ +pub mod action; +pub mod transformer; + +pub use action::*; +pub use transformer::*; diff --git a/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_order_buy_limit_transition_action/v0/transformer.rs b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_order_buy_limit_transition_action/v0/transformer.rs new file mode 100644 index 00000000000..c7ce29749cb --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_order_buy_limit_transition_action/v0/transformer.rs @@ -0,0 +1,182 @@ +use std::sync::Arc; +use grovedb::TransactionArg; +use dpp::block::block_info::BlockInfo; +use dpp::identifier::Identifier; +use dpp::ProtocolError; +use crate::drive::contract::DataContractFetchInfo; +use crate::state_transition_action::batch::batched_transition::token_transition::token_base_transition_action::{TokenBaseTransitionAction}; +use dpp::fee::fee_result::FeeResult; +use dpp::prelude::{ConsensusValidationResult, UserFeeIncrease}; +use dpp::state_transition::batch_transition::batched_transition::token_order_buy_limit_transition::v0::accessors::TokenOrderBuyLimitTransitionV0Methods; +use dpp::state_transition::batch_transition::batched_transition::token_order_buy_limit_transition::v0::transition::TokenOrderBuyLimitTransitionV0; +use dpp::state_transition::batch_transition::token_base_transition::token_base_transition_accessors::TokenBaseTransitionAccessors; +use platform_version::version::PlatformVersion; +use crate::drive::Drive; +use crate::error::Error; +use crate::state_transition_action::batch::batched_transition::BatchedTransitionAction; +use crate::state_transition_action::batch::batched_transition::token_transition::token_order_buy_limit_transition_action::v0::action::TokenOrderBuyLimitTransitionActionV0; +use crate::state_transition_action::batch::batched_transition::token_transition::TokenTransitionAction; +use crate::state_transition_action::system::bump_identity_data_contract_nonce_action::BumpIdentityDataContractNonceAction; + +impl TokenOrderBuyLimitTransitionActionV0 { + /// Converts a `TokenOrderBuyLimitTransitionV0` into a `TokenOrderBuyLimitTransitionActionV0` using the provided contract lookup. + /// + /// This method processes the token releasing transition and returns the corresponding transition action + /// while looking up necessary data contracts and applying the relevant logic for releasing. + /// + /// # Arguments + /// + /// * `drive` - A reference to the `Drive` instance which handles data storage and retrieval. + /// * `owner_id` - The identifier of the owner initiating the releasing transition. This is typically the identity + /// performing the transaction, such as the user's ID. + /// * `transaction` - A transaction context that includes the necessary state and other details for the transition. + /// * `value` - The `TokenOrderBuyLimitTransitionV0` struct containing the transition data, including token amount and recipient. + /// * `approximate_without_state_for_costs` - A flag to determine if costs should be approximated without considering + /// the full state for the operation. Useful for optimizing the transaction cost calculations. + /// * `block_info` - Information about the current block to calculate fees. + /// * `get_data_contract` - A closure function that takes a contract identifier and returns a `DataContractFetchInfo` + /// containing the data contract details, including token configurations. + /// * `platform_version` - A reference to the platform version, ensuring the transition respects version-specific logic. + /// + /// # Returns + /// + /// * `Result, Error>` - Returns the constructed `TokenOrderBuyLimitTransitionActionV0` if successful, + /// or an error if any issue arises, such as missing data or an invalid state transition. + #[allow(clippy::too_many_arguments)] + pub fn try_from_token_order_buy_limit_transition_with_contract_lookup( + drive: &Drive, + owner_id: Identifier, + value: TokenOrderBuyLimitTransitionV0, + approximate_without_state_for_costs: bool, + transaction: TransactionArg, + block_info: &BlockInfo, + user_fee_increase: UserFeeIncrease, + get_data_contract: impl Fn(Identifier) -> Result, ProtocolError>, + platform_version: &PlatformVersion, + ) -> Result< + ( + ConsensusValidationResult, + FeeResult, + ), + Error, + > { + Self::try_from_borrowed_token_order_buy_limit_transition_with_contract_lookup( + drive, + owner_id, + &value, + approximate_without_state_for_costs, + transaction, + block_info, + user_fee_increase, + get_data_contract, + platform_version, + ) + } + + /// Converts a borrowed `TokenOrderBuyLimitTransitionV0` into a `TokenOrderBuyLimitTransitionActionV0` using the provided contract lookup. + /// + /// This method processes the token releasing transition and constructs the corresponding transition action while + /// looking up necessary data contracts and applying the relevant releasing logic. It does not require `drive_operations` + /// to be passed as a parameter, but it manages them internally. + /// + /// # Arguments + /// + /// * `drive` - A reference to the `Drive` instance that handles data storage and retrieval. + /// * `owner_id` - The identifier of the owner initiating the releasing transition. This is typically the identity + /// performing the transaction, such as the user's ID. + /// * `value` - A reference to the `TokenOrderBuyLimitTransitionV0` struct containing the transition data, including token + /// amount and recipient. + /// * `approximate_without_state_for_costs` - A flag to indicate whether costs should be approximated without full + /// state consideration. Useful for optimizing transaction cost calculations in scenarios where full state is not needed. + /// * `transaction` - The transaction context, which includes the necessary state and other details for the transition. + /// * `block_info` - Information about the current block (e.g., epoch) to help calculate transaction fees. + /// * `get_data_contract` - A closure function that takes a contract identifier and returns a `DataContractFetchInfo` + /// containing the data contract details, including token configurations. + /// * `platform_version` - A reference to the platform version to ensure the transition respects version-specific logic. + /// + //// # Returns + /// + /// * `Result<(ConsensusValidationResult, FeeResult), Error>` - Returns a tuple containing the constructed + /// `TokenOrderBuyLimitTransitionActionV0` and a `FeeResult` if successful. If an error occurs (e.g., missing data or + /// invalid state transition), it returns an `Error`. + /// + #[allow(clippy::too_many_arguments)] + pub fn try_from_borrowed_token_order_buy_limit_transition_with_contract_lookup( + drive: &Drive, + owner_id: Identifier, + value: &TokenOrderBuyLimitTransitionV0, + approximate_without_state_for_costs: bool, + transaction: TransactionArg, + block_info: &BlockInfo, + user_fee_increase: UserFeeIncrease, + get_data_contract: impl Fn(Identifier) -> Result, ProtocolError>, + platform_version: &PlatformVersion, + ) -> Result< + ( + ConsensusValidationResult, + FeeResult, + ), + Error, + > { + let mut drive_operations = vec![]; + + let base_action_validation_result = + TokenBaseTransitionAction::try_from_borrowed_base_transition_with_contract_lookup( + drive, + owner_id, + value.base(), + approximate_without_state_for_costs, + transaction, + &mut drive_operations, + get_data_contract, + platform_version, + )?; + + let mut fee_result = Drive::calculate_fee( + None, + Some(drive_operations), + &block_info.epoch, + drive.config.epochs_per_era, + platform_version, + None, + )?; + + let base = match base_action_validation_result.is_valid() { + true => base_action_validation_result.into_data()?, + false => { + let bump_action = + BumpIdentityDataContractNonceAction::from_borrowed_token_base_transition( + value.base(), + owner_id, + user_fee_increase, + ); + let batched_action = + BatchedTransitionAction::BumpIdentityDataContractNonce(bump_action); + + return Ok(( + ConsensusValidationResult::new_with_data_and_errors( + batched_action, + base_action_validation_result.errors, + ), + fee_result, + )); + } + }; + + // TODO: Consider to add some validation here + + Ok(( + BatchedTransitionAction::TokenAction(TokenTransitionAction::OrderBuyLimitAction( + Self { + base, + order_id_entropy: value.order_id_entropy(), + token_amount: value.token_amount(), + token_max_price: value.token_max_price(), + } + .into(), + )) + .into(), + fee_result, + )) + } +} diff --git a/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_order_cancel_transition_action/action.rs b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_order_cancel_transition_action/action.rs new file mode 100644 index 00000000000..71df37ec197 --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_order_cancel_transition_action/action.rs @@ -0,0 +1,38 @@ +use derive_more::From; +use dpp::identifier::Identifier; +use dpp::prelude::Revision; +use crate::state_transition_action::batch::batched_transition::token_transition::token_base_transition_action::TokenBaseTransitionAction; +use crate::state_transition_action::batch::batched_transition::token_transition::token_order_cancel_transition_action::v0::action::{TokenOrderCancelTransitionActionAccessorsV0, TokenOrderCancelTransitionActionV0}; + +/// Token release transition action +#[derive(Debug, Clone, From)] +pub enum TokenOrderCancelTransitionAction { + /// v0 + V0(TokenOrderCancelTransitionActionV0), +} + +impl TokenOrderCancelTransitionActionAccessorsV0 for TokenOrderCancelTransitionAction { + fn base(&self) -> &TokenBaseTransitionAction { + match self { + TokenOrderCancelTransitionAction::V0(v0) => &v0.base, + } + } + + fn base_owned(self) -> TokenBaseTransitionAction { + match self { + TokenOrderCancelTransitionAction::V0(v0) => v0.base, + } + } + + fn order_id(&self) -> Identifier { + match self { + TokenOrderCancelTransitionAction::V0(v0) => v0.order_id, + } + } + + fn order_revision(&self) -> Revision { + match self { + TokenOrderCancelTransitionAction::V0(v0) => v0.order_revision, + } + } +} diff --git a/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_order_cancel_transition_action/mod.rs b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_order_cancel_transition_action/mod.rs new file mode 100644 index 00000000000..9132c656364 --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_order_cancel_transition_action/mod.rs @@ -0,0 +1,7 @@ +/// token order cancel transition action module +pub mod action; +/// transformer module for token release transition action +pub mod transformer; +mod v0; + +pub use v0::*; // re-export the v0 module items (including TokenIssuanceTransitionActionV0) diff --git a/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_order_cancel_transition_action/transformer.rs b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_order_cancel_transition_action/transformer.rs new file mode 100644 index 00000000000..76db38d14dd --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_order_cancel_transition_action/transformer.rs @@ -0,0 +1,120 @@ +use dpp::platform_value::Identifier; +use dpp::ProtocolError; +use grovedb::TransactionArg; +use std::sync::Arc; +use dpp::block::block_info::BlockInfo; +use dpp::fee::fee_result::FeeResult; +use dpp::prelude::{ConsensusValidationResult, UserFeeIncrease}; +use dpp::state_transition::batch_transition::batched_transition::token_order_cancel_transition::transition::TokenOrderCancelTransition; +use crate::drive::contract::DataContractFetchInfo; +use platform_version::version::PlatformVersion; +use crate::drive::Drive; +use crate::error::Error; +use crate::state_transition_action::batch::batched_transition::token_transition::token_order_cancel_transition_action::action::TokenOrderCancelTransitionAction; +use crate::state_transition_action::batch::batched_transition::token_transition::token_order_cancel_transition_action::v0::action::TokenOrderCancelTransitionActionV0; +use crate::state_transition_action::batch::BatchedTransitionAction; + +/// Implement methods to transform a `TokenOrderCancelTransition` into a `TokenOrderCancelTransitionAction`. +impl TokenOrderCancelTransitionAction { + /// Transform a `TokenOrderCancelTransition` into a `TokenOrderCancelTransitionAction` using the provided data contract lookup. + /// + /// # Arguments + /// + /// * `drive` - A reference to the `Drive` instance used for accessing the system. + /// * `owner_id` - The identifier of the owner initiating the release transition. + /// * `transaction` - The transaction argument used for state changes. + /// * `value` - A `TokenOrderCancelTransition` instance. + /// * `approximate_without_state_for_costs` - A flag indicating whether to approximate state costs without full state. + /// * `drive_operations` - A mutable reference to the vector of low-level operations that need to be performed. + /// * `get_data_contract` - A closure that fetches the `DataContractFetchInfo` given a contract ID. + /// * `platform_version` - The platform version for the context in which the transition is being executed. + /// + /// # Returns + /// + /// * `Result<(ConsensusValidationResult, FeeResult), Error>` - A `TokenOrderCancelTransitionAction` if successful, otherwise `ProtocolError`. + #[allow(clippy::too_many_arguments)] + pub fn try_from_token_order_cancel_limit_transition_with_contract_lookup( + drive: &Drive, + owner_id: Identifier, + value: TokenOrderCancelTransition, + approximate_without_state_for_costs: bool, + transaction: TransactionArg, + block_info: &BlockInfo, + user_fee_increase: UserFeeIncrease, + get_data_contract: impl Fn(Identifier) -> Result, ProtocolError>, + platform_version: &PlatformVersion, + ) -> Result< + ( + ConsensusValidationResult, + FeeResult, + ), + Error, + > { + match value { + TokenOrderCancelTransition::V0(v0) => { + TokenOrderCancelTransitionActionV0::try_from_token_order_cancel_transition_with_contract_lookup( + drive, + owner_id, + v0, + approximate_without_state_for_costs, + transaction, + block_info, + user_fee_increase, + get_data_contract, + platform_version, + ) + } + } + } + + /// Transform a borrowed `TokenOrderCancelTransition` into a `TokenOrderCancelTransitionAction` using the provided data contract lookup. + /// + /// # Arguments + /// + /// * `drive` - A reference to the `Drive` instance used for accessing the system. + /// * `owner_id` - The identifier of the owner initiating the release transition. + /// * `transaction` - The transaction argument used for state changes. + /// * `value` - A reference to a `TokenOrderCancelTransition`. + /// * `approximate_without_state_for_costs` - A flag indicating whether to approximate state costs without full state. + /// * `drive_operations` - A mutable reference to the vector of low-level operations that need to be performed. + /// * `get_data_contract` - A closure that fetches the `DataContractFetchInfo` given a contract ID. + /// * `platform_version` - The platform version for the context in which the transition is being executed. + /// + /// # Returns + /// + #[allow(clippy::too_many_arguments)] + /// * `Result<(ConsensusValidationResult, FeeResult), Error>` - A `TokenOrderCancelTransitionAction` if successful, otherwise `ProtocolError`. + pub fn try_from_borrowed_token_order_cancel_transition_with_contract_lookup( + drive: &Drive, + owner_id: Identifier, + value: &TokenOrderCancelTransition, + approximate_without_state_for_costs: bool, + transaction: TransactionArg, + block_info: &BlockInfo, + user_fee_increase: UserFeeIncrease, + get_data_contract: impl Fn(Identifier) -> Result, ProtocolError>, + platform_version: &PlatformVersion, + ) -> Result< + ( + ConsensusValidationResult, + FeeResult, + ), + Error, + > { + match value { + TokenOrderCancelTransition::V0(v0) => { + TokenOrderCancelTransitionActionV0::try_from_borrowed_token_order_cancel_transition_with_contract_lookup( + drive, + owner_id, + v0, + approximate_without_state_for_costs, + transaction, + block_info, + user_fee_increase, + get_data_contract, + platform_version, + ) + } + } + } +} diff --git a/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_order_cancel_transition_action/v0/action.rs b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_order_cancel_transition_action/v0/action.rs new file mode 100644 index 00000000000..3d1f6a1268d --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_order_cancel_transition_action/v0/action.rs @@ -0,0 +1,74 @@ +use std::sync::Arc; +use dpp::identifier::Identifier; +use dpp::prelude::Revision; +use crate::drive::contract::DataContractFetchInfo; +use crate::state_transition_action::batch::batched_transition::token_transition::token_base_transition_action::{TokenBaseTransitionAction, TokenBaseTransitionActionAccessorsV0}; + +/// Token order cancel transition action v0 +#[derive(Debug, Clone)] +pub struct TokenOrderCancelTransitionActionV0 { + /// Base token transition action + pub base: TokenBaseTransitionAction, + /// Entropy generated to create order ID + pub order_id: Identifier, + /// Token amount to sell + pub order_revision: Revision, +} + +/// Accessors for `TokenOrderCancelTransitionActionV0` +pub trait TokenOrderCancelTransitionActionAccessorsV0 { + /// Returns a reference to the base token transition action + fn base(&self) -> &TokenBaseTransitionAction; + + /// Consumes self and returns the base token transition action + fn base_owned(self) -> TokenBaseTransitionAction; + + /// Returns the token position in the contract + fn token_position(&self) -> u16 { + self.base().token_position() + } + + /// Returns the token ID + fn token_id(&self) -> Identifier { + self.base().token_id() + } + + /// Returns the data contract ID + fn data_contract_id(&self) -> Identifier { + self.base().data_contract_id() + } + + /// Returns a reference to the data contract fetch info + fn data_contract_fetch_info_ref(&self) -> &Arc { + self.base().data_contract_fetch_info_ref() + } + + /// Returns the data contract fetch info + fn data_contract_fetch_info(&self) -> Arc { + self.base().data_contract_fetch_info() + } + + /// Order ID to cancel + fn order_id(&self) -> Identifier; + + /// Order Revision to cancel + fn order_revision(&self) -> Revision; +} + +impl TokenOrderCancelTransitionActionAccessorsV0 for TokenOrderCancelTransitionActionV0 { + fn base(&self) -> &TokenBaseTransitionAction { + &self.base + } + + fn base_owned(self) -> TokenBaseTransitionAction { + self.base + } + + fn order_id(&self) -> Identifier { + self.order_id + } + + fn order_revision(&self) -> Revision { + self.order_revision + } +} diff --git a/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_order_cancel_transition_action/v0/mod.rs b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_order_cancel_transition_action/v0/mod.rs new file mode 100644 index 00000000000..ac3b822b6c5 --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_order_cancel_transition_action/v0/mod.rs @@ -0,0 +1,5 @@ +pub mod action; +pub mod transformer; + +pub use action::*; +pub use transformer::*; diff --git a/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_order_cancel_transition_action/v0/transformer.rs b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_order_cancel_transition_action/v0/transformer.rs new file mode 100644 index 00000000000..be819496610 --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_order_cancel_transition_action/v0/transformer.rs @@ -0,0 +1,181 @@ +use std::sync::Arc; +use grovedb::TransactionArg; +use dpp::block::block_info::BlockInfo; +use dpp::identifier::Identifier; +use dpp::ProtocolError; +use crate::drive::contract::DataContractFetchInfo; +use crate::state_transition_action::batch::batched_transition::token_transition::token_base_transition_action::{TokenBaseTransitionAction}; +use dpp::fee::fee_result::FeeResult; +use dpp::prelude::{ConsensusValidationResult, UserFeeIncrease}; +use dpp::state_transition::batch_transition::batched_transition::token_order_cancel_transition::v0::accessors::TokenOrderCancelTransitionV0Methods; +use dpp::state_transition::batch_transition::batched_transition::token_order_cancel_transition::v0::transition::TokenOrderCancelTransitionV0; +use dpp::state_transition::batch_transition::token_base_transition::token_base_transition_accessors::TokenBaseTransitionAccessors; +use platform_version::version::PlatformVersion; +use crate::drive::Drive; +use crate::error::Error; +use crate::state_transition_action::batch::batched_transition::BatchedTransitionAction; +use crate::state_transition_action::batch::batched_transition::token_transition::token_order_cancel_transition_action::v0::action::TokenOrderCancelTransitionActionV0; +use crate::state_transition_action::batch::batched_transition::token_transition::TokenTransitionAction; +use crate::state_transition_action::system::bump_identity_data_contract_nonce_action::BumpIdentityDataContractNonceAction; + +impl TokenOrderCancelTransitionActionV0 { + /// Converts a `TokenOrderCancelTransitionV0` into a `TokenOrderCancelTransitionActionV0` using the provided contract lookup. + /// + /// This method processes the token releasing transition and returns the corresponding transition action + /// while looking up necessary data contracts and applying the relevant logic for releasing. + /// + /// # Arguments + /// + /// * `drive` - A reference to the `Drive` instance which handles data storage and retrieval. + /// * `owner_id` - The identifier of the owner initiating the releasing transition. This is typically the identity + /// performing the transaction, such as the user's ID. + /// * `transaction` - A transaction context that includes the necessary state and other details for the transition. + /// * `value` - The `TokenOrderCancelTransitionV0` struct containing the transition data, including token amount and recipient. + /// * `approximate_without_state_for_costs` - A flag to determine if costs should be approximated without considering + /// the full state for the operation. Useful for optimizing the transaction cost calculations. + /// * `block_info` - Information about the current block to calculate fees. + /// * `get_data_contract` - A closure function that takes a contract identifier and returns a `DataContractFetchInfo` + /// containing the data contract details, including token configurations. + /// * `platform_version` - A reference to the platform version, ensuring the transition respects version-specific logic. + /// + /// # Returns + /// + /// * `Result, Error>` - Returns the constructed `TokenOrderCancelTransitionActionV0` if successful, + /// or an error if any issue arises, such as missing data or an invalid state transition. + #[allow(clippy::too_many_arguments)] + pub fn try_from_token_order_cancel_transition_with_contract_lookup( + drive: &Drive, + owner_id: Identifier, + value: TokenOrderCancelTransitionV0, + approximate_without_state_for_costs: bool, + transaction: TransactionArg, + block_info: &BlockInfo, + user_fee_increase: UserFeeIncrease, + get_data_contract: impl Fn(Identifier) -> Result, ProtocolError>, + platform_version: &PlatformVersion, + ) -> Result< + ( + ConsensusValidationResult, + FeeResult, + ), + Error, + > { + Self::try_from_borrowed_token_order_cancel_transition_with_contract_lookup( + drive, + owner_id, + &value, + approximate_without_state_for_costs, + transaction, + block_info, + user_fee_increase, + get_data_contract, + platform_version, + ) + } + + /// Converts a borrowed `TokenOrderCancelTransitionV0` into a `TokenOrderCancelTransitionActionV0` using the provided contract lookup. + /// + /// This method processes the token releasing transition and constructs the corresponding transition action while + /// looking up necessary data contracts and applying the relevant releasing logic. It does not require `drive_operations` + /// to be passed as a parameter, but it manages them internally. + /// + /// # Arguments + /// + /// * `drive` - A reference to the `Drive` instance that handles data storage and retrieval. + /// * `owner_id` - The identifier of the owner initiating the releasing transition. This is typically the identity + /// performing the transaction, such as the user's ID. + /// * `value` - A reference to the `TokenOrderCancelTransitionV0` struct containing the transition data, including token + /// amount and recipient. + /// * `approximate_without_state_for_costs` - A flag to indicate whether costs should be approximated without full + /// state consideration. Useful for optimizing transaction cost calculations in scenarios where full state is not needed. + /// * `transaction` - The transaction context, which includes the necessary state and other details for the transition. + /// * `block_info` - Information about the current block (e.g., epoch) to help calculate transaction fees. + /// * `get_data_contract` - A closure function that takes a contract identifier and returns a `DataContractFetchInfo` + /// containing the data contract details, including token configurations. + /// * `platform_version` - A reference to the platform version to ensure the transition respects version-specific logic. + /// + //// # Returns + /// + /// * `Result<(ConsensusValidationResult, FeeResult), Error>` - Returns a tuple containing the constructed + /// `TokenOrderCancelTransitionActionV0` and a `FeeResult` if successful. If an error occurs (e.g., missing data or + /// invalid state transition), it returns an `Error`. + /// + #[allow(clippy::too_many_arguments)] + pub fn try_from_borrowed_token_order_cancel_transition_with_contract_lookup( + drive: &Drive, + owner_id: Identifier, + value: &TokenOrderCancelTransitionV0, + approximate_without_state_for_costs: bool, + transaction: TransactionArg, + block_info: &BlockInfo, + user_fee_increase: UserFeeIncrease, + get_data_contract: impl Fn(Identifier) -> Result, ProtocolError>, + platform_version: &PlatformVersion, + ) -> Result< + ( + ConsensusValidationResult, + FeeResult, + ), + Error, + > { + let mut drive_operations = vec![]; + + let base_action_validation_result = + TokenBaseTransitionAction::try_from_borrowed_base_transition_with_contract_lookup( + drive, + owner_id, + value.base(), + approximate_without_state_for_costs, + transaction, + &mut drive_operations, + get_data_contract, + platform_version, + )?; + + let mut fee_result = Drive::calculate_fee( + None, + Some(drive_operations), + &block_info.epoch, + drive.config.epochs_per_era, + platform_version, + None, + )?; + + let base = match base_action_validation_result.is_valid() { + true => base_action_validation_result.into_data()?, + false => { + let bump_action = + BumpIdentityDataContractNonceAction::from_borrowed_token_base_transition( + value.base(), + owner_id, + user_fee_increase, + ); + let batched_action = + BatchedTransitionAction::BumpIdentityDataContractNonce(bump_action); + + return Ok(( + ConsensusValidationResult::new_with_data_and_errors( + batched_action, + base_action_validation_result.errors, + ), + fee_result, + )); + } + }; + + // TODO: Consider to add some validation here + + Ok(( + BatchedTransitionAction::TokenAction(TokenTransitionAction::OrderCancelAction( + Self { + base, + order_id: value.order_id(), + order_revision: value.order_revision(), + } + .into(), + )) + .into(), + fee_result, + )) + } +} diff --git a/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_order_sell_limit_transition_action/action.rs b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_order_sell_limit_transition_action/action.rs new file mode 100644 index 00000000000..5dfed2c2f65 --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_order_sell_limit_transition_action/action.rs @@ -0,0 +1,45 @@ +use derive_more::From; +use dpp::balances::credits::TokenAmount; +use dpp::fee::Credits; +use dpp::state_transition::batch_transition::batched_transition::Entropy; +use crate::state_transition_action::batch::batched_transition::token_transition::token_base_transition_action::TokenBaseTransitionAction; +use crate::state_transition_action::batch::batched_transition::token_transition::token_order_sell_limit_transition_action::v0::action::{TokenOrderSellLimitTransitionActionAccessorsV0, TokenOrderSellLimitTransitionActionV0}; + +/// Token release transition action +#[derive(Debug, Clone, From)] +pub enum TokenOrderSellLimitTransitionAction { + /// v0 + V0(TokenOrderSellLimitTransitionActionV0), +} + +impl TokenOrderSellLimitTransitionActionAccessorsV0 for TokenOrderSellLimitTransitionAction { + fn base(&self) -> &TokenBaseTransitionAction { + match self { + TokenOrderSellLimitTransitionAction::V0(v0) => &v0.base, + } + } + + fn base_owned(self) -> TokenBaseTransitionAction { + match self { + TokenOrderSellLimitTransitionAction::V0(v0) => v0.base, + } + } + + fn order_id_entropy(&self) -> Entropy { + match self { + TokenOrderSellLimitTransitionAction::V0(v0) => v0.order_id_entropy, + } + } + + fn token_amount(&self) -> TokenAmount { + match self { + TokenOrderSellLimitTransitionAction::V0(v0) => v0.token_amount, + } + } + + fn token_min_price(&self) -> Credits { + match self { + TokenOrderSellLimitTransitionAction::V0(v0) => v0.token_min_price, + } + } +} diff --git a/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_order_sell_limit_transition_action/mod.rs b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_order_sell_limit_transition_action/mod.rs new file mode 100644 index 00000000000..5333a41f8a7 --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_order_sell_limit_transition_action/mod.rs @@ -0,0 +1,7 @@ +/// token order sell limit transition action module +pub mod action; +/// transformer module for token release transition action +pub mod transformer; +mod v0; + +pub use v0::*; // re-export the v0 module items (including TokenIssuanceTransitionActionV0) diff --git a/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_order_sell_limit_transition_action/transformer.rs b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_order_sell_limit_transition_action/transformer.rs new file mode 100644 index 00000000000..c040209fa11 --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_order_sell_limit_transition_action/transformer.rs @@ -0,0 +1,120 @@ +use dpp::platform_value::Identifier; +use dpp::ProtocolError; +use grovedb::TransactionArg; +use std::sync::Arc; +use dpp::block::block_info::BlockInfo; +use dpp::fee::fee_result::FeeResult; +use dpp::prelude::{ConsensusValidationResult, UserFeeIncrease}; +use dpp::state_transition::batch_transition::batched_transition::token_order_sell_limit_transition::transition::TokenOrderSellLimitTransition; +use crate::drive::contract::DataContractFetchInfo; +use platform_version::version::PlatformVersion; +use crate::drive::Drive; +use crate::error::Error; +use crate::state_transition_action::batch::batched_transition::token_transition::token_order_sell_limit_transition_action::action::TokenOrderSellLimitTransitionAction; +use crate::state_transition_action::batch::batched_transition::token_transition::token_order_sell_limit_transition_action::v0::action::TokenOrderSellLimitTransitionActionV0; +use crate::state_transition_action::batch::BatchedTransitionAction; + +/// Implement methods to transform a `TokenOrderSellLimitTransition` into a `TokenOrderSellLimitTransitionAction`. +impl TokenOrderSellLimitTransitionAction { + /// Transform a `TokenOrderSellLimitTransition` into a `TokenOrderSellLimitTransitionAction` using the provided data contract lookup. + /// + /// # Arguments + /// + /// * `drive` - A reference to the `Drive` instance used for accessing the system. + /// * `owner_id` - The identifier of the owner initiating the release transition. + /// * `transaction` - The transaction argument used for state changes. + /// * `value` - A `TokenOrderSellLimitTransition` instance. + /// * `approximate_without_state_for_costs` - A flag indicating whether to approximate state costs without full state. + /// * `drive_operations` - A mutable reference to the vector of low-level operations that need to be performed. + /// * `get_data_contract` - A closure that fetches the `DataContractFetchInfo` given a contract ID. + /// * `platform_version` - The platform version for the context in which the transition is being executed. + /// + /// # Returns + /// + /// * `Result<(ConsensusValidationResult, FeeResult), Error>` - A `TokenOrderSellLimitTransitionAction` if successful, otherwise `ProtocolError`. + #[allow(clippy::too_many_arguments)] + pub fn try_from_token_order_sell_limit_transition_with_contract_lookup( + drive: &Drive, + owner_id: Identifier, + value: TokenOrderSellLimitTransition, + approximate_without_state_for_costs: bool, + transaction: TransactionArg, + block_info: &BlockInfo, + user_fee_increase: UserFeeIncrease, + get_data_contract: impl Fn(Identifier) -> Result, ProtocolError>, + platform_version: &PlatformVersion, + ) -> Result< + ( + ConsensusValidationResult, + FeeResult, + ), + Error, + > { + match value { + TokenOrderSellLimitTransition::V0(v0) => { + TokenOrderSellLimitTransitionActionV0::try_from_token_order_sell_limit_transition_with_contract_lookup( + drive, + owner_id, + v0, + approximate_without_state_for_costs, + transaction, + block_info, + user_fee_increase, + get_data_contract, + platform_version, + ) + } + } + } + + /// Transform a borrowed `TokenOrderSellLimitTransition` into a `TokenOrderSellLimitTransitionAction` using the provided data contract lookup. + /// + /// # Arguments + /// + /// * `drive` - A reference to the `Drive` instance used for accessing the system. + /// * `owner_id` - The identifier of the owner initiating the release transition. + /// * `transaction` - The transaction argument used for state changes. + /// * `value` - A reference to a `TokenOrderSellLimitTransition`. + /// * `approximate_without_state_for_costs` - A flag indicating whether to approximate state costs without full state. + /// * `drive_operations` - A mutable reference to the vector of low-level operations that need to be performed. + /// * `get_data_contract` - A closure that fetches the `DataContractFetchInfo` given a contract ID. + /// * `platform_version` - The platform version for the context in which the transition is being executed. + /// + /// # Returns + /// + #[allow(clippy::too_many_arguments)] + /// * `Result<(ConsensusValidationResult, FeeResult), Error>` - A `TokenOrderSellLimitTransitionAction` if successful, otherwise `ProtocolError`. + pub fn try_from_borrowed_token_order_sell_limit_transition_with_contract_lookup( + drive: &Drive, + owner_id: Identifier, + value: &TokenOrderSellLimitTransition, + approximate_without_state_for_costs: bool, + transaction: TransactionArg, + block_info: &BlockInfo, + user_fee_increase: UserFeeIncrease, + get_data_contract: impl Fn(Identifier) -> Result, ProtocolError>, + platform_version: &PlatformVersion, + ) -> Result< + ( + ConsensusValidationResult, + FeeResult, + ), + Error, + > { + match value { + TokenOrderSellLimitTransition::V0(v0) => { + TokenOrderSellLimitTransitionActionV0::try_from_borrowed_token_order_sell_limit_transition_with_contract_lookup( + drive, + owner_id, + v0, + approximate_without_state_for_costs, + transaction, + block_info, + user_fee_increase, + get_data_contract, + platform_version, + ) + } + } + } +} diff --git a/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_order_sell_limit_transition_action/v0/action.rs b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_order_sell_limit_transition_action/v0/action.rs new file mode 100644 index 00000000000..52bc5c9804c --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_order_sell_limit_transition_action/v0/action.rs @@ -0,0 +1,85 @@ +use std::sync::Arc; +use dpp::balances::credits::TokenAmount; +use dpp::fee::Credits; +use dpp::identifier::Identifier; +use dpp::state_transition::batch_transition::batched_transition::Entropy; +use crate::drive::contract::DataContractFetchInfo; +use crate::state_transition_action::batch::batched_transition::token_transition::token_base_transition_action::{TokenBaseTransitionAction, TokenBaseTransitionActionAccessorsV0}; + +/// Token order sell limit transition action v0 +#[derive(Debug, Clone)] +pub struct TokenOrderSellLimitTransitionActionV0 { + /// Base token transition action + pub base: TokenBaseTransitionAction, + /// Entropy generated to create order ID + pub order_id_entropy: Entropy, + /// Token amount to sell + pub token_amount: TokenAmount, + /// Min price to sell the tokens + pub token_min_price: Credits, +} + +/// Accessors for `TokenOrderSellLimitTransitionActionV0` +pub trait TokenOrderSellLimitTransitionActionAccessorsV0 { + /// Returns a reference to the base token transition action + fn base(&self) -> &TokenBaseTransitionAction; + + /// Consumes self and returns the base token transition action + fn base_owned(self) -> TokenBaseTransitionAction; + + /// Returns the token position in the contract + fn token_position(&self) -> u16 { + self.base().token_position() + } + + /// Returns the token ID + fn token_id(&self) -> Identifier { + self.base().token_id() + } + + /// Returns the data contract ID + fn data_contract_id(&self) -> Identifier { + self.base().data_contract_id() + } + + /// Returns a reference to the data contract fetch info + fn data_contract_fetch_info_ref(&self) -> &Arc { + self.base().data_contract_fetch_info_ref() + } + + /// Returns the data contract fetch info + fn data_contract_fetch_info(&self) -> Arc { + self.base().data_contract_fetch_info() + } + + /// Returns entropy generated to create order ID + fn order_id_entropy(&self) -> Entropy; + + /// Returns the token amount to sell + fn token_amount(&self) -> TokenAmount; + + /// Returns the min price to sell the tokens + fn token_min_price(&self) -> Credits; +} + +impl TokenOrderSellLimitTransitionActionAccessorsV0 for TokenOrderSellLimitTransitionActionV0 { + fn base(&self) -> &TokenBaseTransitionAction { + &self.base + } + + fn base_owned(self) -> TokenBaseTransitionAction { + self.base + } + + fn order_id_entropy(&self) -> Entropy { + self.order_id_entropy + } + + fn token_amount(&self) -> TokenAmount { + self.token_amount + } + + fn token_min_price(&self) -> Credits { + self.token_min_price + } +} diff --git a/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_order_sell_limit_transition_action/v0/mod.rs b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_order_sell_limit_transition_action/v0/mod.rs new file mode 100644 index 00000000000..ac3b822b6c5 --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_order_sell_limit_transition_action/v0/mod.rs @@ -0,0 +1,5 @@ +pub mod action; +pub mod transformer; + +pub use action::*; +pub use transformer::*; diff --git a/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_order_sell_limit_transition_action/v0/transformer.rs b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_order_sell_limit_transition_action/v0/transformer.rs new file mode 100644 index 00000000000..23d375cdd15 --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_order_sell_limit_transition_action/v0/transformer.rs @@ -0,0 +1,187 @@ +use std::sync::Arc; +use grovedb::TransactionArg; +use dpp::block::block_info::BlockInfo; +use dpp::identifier::Identifier; +use dpp::ProtocolError; +use crate::drive::contract::DataContractFetchInfo; +use crate::state_transition_action::batch::batched_transition::token_transition::token_base_transition_action::{TokenBaseTransitionAction}; +use dpp::fee::fee_result::FeeResult; +use dpp::prelude::{ConsensusValidationResult, UserFeeIncrease}; +use dpp::state_transition::batch_transition::batched_transition::token_order_sell_limit_transition::v0::transition::TokenOrderSellLimitTransitionV0; +use platform_version::version::PlatformVersion; +use crate::drive::Drive; +use crate::error::Error; +use crate::state_transition_action::batch::batched_transition::BatchedTransitionAction; +use crate::state_transition_action::batch::batched_transition::token_transition::token_order_sell_limit_transition_action::v0::action::TokenOrderSellLimitTransitionActionV0; +use crate::state_transition_action::batch::batched_transition::token_transition::TokenTransitionAction; +use crate::state_transition_action::system::bump_identity_data_contract_nonce_action::BumpIdentityDataContractNonceAction; + +impl TokenOrderSellLimitTransitionActionV0 { + /// Converts a `TokenOrderSellLimitTransitionV0` into a `TokenOrderSellLimitTransitionActionV0` using the provided contract lookup. + /// + /// This method processes the token releasing transition and returns the corresponding transition action + /// while looking up necessary data contracts and applying the relevant logic for releasing. + /// + /// # Arguments + /// + /// * `drive` - A reference to the `Drive` instance which handles data storage and retrieval. + /// * `owner_id` - The identifier of the owner initiating the releasing transition. This is typically the identity + /// performing the transaction, such as the user's ID. + /// * `transaction` - A transaction context that includes the necessary state and other details for the transition. + /// * `value` - The `TokenOrderSellLimitTransitionV0` struct containing the transition data, including token amount and recipient. + /// * `approximate_without_state_for_costs` - A flag to determine if costs should be approximated without considering + /// the full state for the operation. Useful for optimizing the transaction cost calculations. + /// * `block_info` - Information about the current block to calculate fees. + /// * `get_data_contract` - A closure function that takes a contract identifier and returns a `DataContractFetchInfo` + /// containing the data contract details, including token configurations. + /// * `platform_version` - A reference to the platform version, ensuring the transition respects version-specific logic. + /// + /// # Returns + /// + /// * `Result, Error>` - Returns the constructed `TokenOrderSellLimitTransitionActionV0` if successful, + /// or an error if any issue arises, such as missing data or an invalid state transition. + #[allow(clippy::too_many_arguments)] + pub fn try_from_token_order_sell_limit_transition_with_contract_lookup( + drive: &Drive, + owner_id: Identifier, + value: TokenOrderSellLimitTransitionV0, + approximate_without_state_for_costs: bool, + transaction: TransactionArg, + block_info: &BlockInfo, + user_fee_increase: UserFeeIncrease, + get_data_contract: impl Fn(Identifier) -> Result, ProtocolError>, + platform_version: &PlatformVersion, + ) -> Result< + ( + ConsensusValidationResult, + FeeResult, + ), + Error, + > { + Self::try_from_borrowed_token_order_sell_limit_transition_with_contract_lookup( + drive, + owner_id, + &value, + approximate_without_state_for_costs, + transaction, + block_info, + user_fee_increase, + get_data_contract, + platform_version, + ) + } + + /// Converts a borrowed `TokenOrderSellLimitTransitionV0` into a `TokenOrderSellLimitTransitionActionV0` using the provided contract lookup. + /// + /// This method processes the token releasing transition and constructs the corresponding transition action while + /// looking up necessary data contracts and applying the relevant releasing logic. It does not require `drive_operations` + /// to be passed as a parameter, but it manages them internally. + /// + /// # Arguments + /// + /// * `drive` - A reference to the `Drive` instance that handles data storage and retrieval. + /// * `owner_id` - The identifier of the owner initiating the releasing transition. This is typically the identity + /// performing the transaction, such as the user's ID. + /// * `value` - A reference to the `TokenOrderSellLimitTransitionV0` struct containing the transition data, including token + /// amount and recipient. + /// * `approximate_without_state_for_costs` - A flag to indicate whether costs should be approximated without full + /// state consideration. Useful for optimizing transaction cost calculations in scenarios where full state is not needed. + /// * `transaction` - The transaction context, which includes the necessary state and other details for the transition. + /// * `block_info` - Information about the current block (e.g., epoch) to help calculate transaction fees. + /// * `get_data_contract` - A closure function that takes a contract identifier and returns a `DataContractFetchInfo` + /// containing the data contract details, including token configurations. + /// * `platform_version` - A reference to the platform version to ensure the transition respects version-specific logic. + /// + //// # Returns + /// + /// * `Result<(ConsensusValidationResult, FeeResult), Error>` - Returns a tuple containing the constructed + /// `TokenOrderSellLimitTransitionActionV0` and a `FeeResult` if successful. If an error occurs (e.g., missing data or + /// invalid state transition), it returns an `Error`. + /// + #[allow(clippy::too_many_arguments)] + pub fn try_from_borrowed_token_order_sell_limit_transition_with_contract_lookup( + drive: &Drive, + owner_id: Identifier, + value: &TokenOrderSellLimitTransitionV0, + approximate_without_state_for_costs: bool, + transaction: TransactionArg, + block_info: &BlockInfo, + user_fee_increase: UserFeeIncrease, + get_data_contract: impl Fn(Identifier) -> Result, ProtocolError>, + platform_version: &PlatformVersion, + ) -> Result< + ( + ConsensusValidationResult, + FeeResult, + ), + Error, + > { + let TokenOrderSellLimitTransitionV0 { + base, + order_id_entropy, + token_amount, + token_min_price, + } = value; + + let mut drive_operations = vec![]; + + let base_action_validation_result = + TokenBaseTransitionAction::try_from_borrowed_base_transition_with_contract_lookup( + drive, + owner_id, + base, + approximate_without_state_for_costs, + transaction, + &mut drive_operations, + get_data_contract, + platform_version, + )?; + + let mut fee_result = Drive::calculate_fee( + None, + Some(drive_operations), + &block_info.epoch, + drive.config.epochs_per_era, + platform_version, + None, + )?; + + let base = match base_action_validation_result.is_valid() { + true => base_action_validation_result.into_data()?, + false => { + let bump_action = + BumpIdentityDataContractNonceAction::from_borrowed_token_base_transition( + base, + owner_id, + user_fee_increase, + ); + let batched_action = + BatchedTransitionAction::BumpIdentityDataContractNonce(bump_action); + + return Ok(( + ConsensusValidationResult::new_with_data_and_errors( + batched_action, + base_action_validation_result.errors, + ), + fee_result, + )); + } + }; + + // TODO: Consider to add some validation here + + Ok(( + BatchedTransitionAction::TokenAction(TokenTransitionAction::OrderSellLimitAction( + Self { + base, + order_id_entropy: *order_id_entropy, + token_amount: *token_amount, + token_min_price: *token_min_price, + } + .into(), + )) + .into(), + fee_result, + )) + } +} diff --git a/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_transition_action_type.rs b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_transition_action_type.rs index 75f617670a4..c6ce709861c 100644 --- a/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_transition_action_type.rs +++ b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_transition_action_type.rs @@ -19,6 +19,16 @@ impl TokenTransitionActionTypeGetter for TokenTransitionAction { TokenTransitionActionType::DestroyFrozenFunds } TokenTransitionAction::ConfigUpdateAction(_) => TokenTransitionActionType::ConfigUpdate, + TokenTransitionAction::OrderBuyLimitAction(_) => { + TokenTransitionActionType::OrderBuyLimit + } + TokenTransitionAction::OrderSellLimitAction(_) => { + TokenTransitionActionType::OrderSellLimit + } + TokenTransitionAction::OrderCancelAction(_) => TokenTransitionActionType::OrderCancel, + TokenTransitionAction::OrderAdjustPriceAction(_) => { + TokenTransitionActionType::OrderAdjustPrice + } } } } diff --git a/packages/rs-drive/src/verify/state_transition/verify_state_transition_was_executed_with_proof/v0/mod.rs b/packages/rs-drive/src/verify/state_transition/verify_state_transition_was_executed_with_proof/v0/mod.rs index 693bb8eae9d..a1d569e8eee 100644 --- a/packages/rs-drive/src/verify/state_transition/verify_state_transition_was_executed_with_proof/v0/mod.rs +++ b/packages/rs-drive/src/verify/state_transition/verify_state_transition_was_executed_with_proof/v0/mod.rs @@ -7,6 +7,7 @@ use dpp::data_contract::associated_token::token_configuration::accessors::v0::To use dpp::data_contract::associated_token::token_keeps_history_rules::accessors::v0::TokenKeepsHistoryRulesV0Getters; use dpp::data_contract::document_type::accessors::DocumentTypeV0Getters; use dpp::data_contract::serialized_version::DataContractInSerializationFormat; +use dpp::data_contract::TokenConfiguration; use dpp::document::{Document, DocumentV0Getters}; use dpp::document::document_methods::DocumentMethodsV0; use dpp::document::property_names::PRICE; @@ -306,69 +307,22 @@ impl Drive { ))), )?; - let identity_contract_nonce = - token_transition.base().identity_contract_nonce(); - - let token_history_document_type_name = - token_transition.historical_document_type_name().to_string(); - - let token_history_contract = load_system_data_contract( - SystemDataContract::TokenHistory, - platform_version, - )?; - - let token_history_document_type = - token_transition.historical_document_type(&token_history_contract)?; - let token_config = contract.expected_token_configuration( token_transition.base().token_contract_position(), )?; - let keeps_historical_document = token_config.keeps_history(); - - let historical_query = || { - let query = SingleDocumentDriveQuery { - contract_id: token_history_contract.id().into_buffer(), - document_type_name: token_history_document_type_name, - document_type_keeps_history: false, - document_id: token_transition - .historical_document_id(owner_id) - .to_buffer(), - block_time_ms: None, //None because we want latest - contested_status: - SingleDocumentDriveQueryContestedStatus::NotContested, - }; - - let (root_hash, document) = query.verify_proof( - false, - proof, - token_history_document_type, - platform_version, - )?; - - let document = document.ok_or(Error::Proof(ProofError::IncorrectProof(format!("proof did not contain document with id {} expected to exist because the token keeps historical documents", token_transition.historical_document_type_name()))))?; - let expected_document = token_transition.build_historical_document( - token_id, - owner_id, - identity_contract_nonce, - &BlockInfo::default(), - token_config, - platform_version, - )?; + let keeps_historical_document = token_config.keeps_history(); - if !document.is_equal_ignoring_time_based_fields( - &expected_document, - Some(vec!["destroyedAmount"]), - platform_version, - )? { - return Err(Error::Proof(ProofError::IncorrectProof(format!("proof of state transition execution did not show the correct historical document {}, {}", document, expected_document)))); - } - Ok((root_hash, VerifiedTokenActionWithDocument(document))) - }; match token_transition { TokenTransition::Burn(_) => { if keeps_historical_document.keeps_burning_history() { - historical_query() + verify_token_historical_document( + proof, + token_transition, + token_config, + owner_id, + platform_version, + ) } else { let (root_hash, Some(balance)) = Drive::verify_token_balance_for_identity_id( @@ -387,7 +341,13 @@ impl Drive { } TokenTransition::Mint(token_mint_transition) => { if keeps_historical_document.keeps_minting_history() { - historical_query() + verify_token_historical_document( + proof, + token_transition, + token_config, + owner_id, + platform_version, + ) } else { let recipient_id = token_mint_transition.recipient_id(token_config)?; @@ -408,7 +368,13 @@ impl Drive { } TokenTransition::Transfer(token_transfer_transition) => { if keeps_historical_document.keeps_transfer_history() { - historical_query() + verify_token_historical_document( + proof, + token_transition, + token_config, + owner_id, + platform_version, + ) } else { let recipient_id = token_transfer_transition.recipient_id(); let identity_ids = @@ -435,7 +401,13 @@ impl Drive { } TokenTransition::Freeze(token_freeze_transition) => { if keeps_historical_document.keeps_freezing_history() { - historical_query() + verify_token_historical_document( + proof, + token_transition, + token_config, + owner_id, + platform_version, + ) } else { let (root_hash, Some(identity_token_info)) = Drive::verify_token_info_for_identity_id( @@ -463,7 +435,13 @@ impl Drive { } TokenTransition::Unfreeze(token_unfreeze_transition) => { if keeps_historical_document.keeps_freezing_history() { - historical_query() + verify_token_historical_document( + proof, + token_transition, + token_config, + owner_id, + platform_version, + ) } else { let (root_hash, Some(identity_token_info)) = Drive::verify_token_info_for_identity_id( @@ -492,7 +470,17 @@ impl Drive { TokenTransition::DestroyFrozenFunds(_) | TokenTransition::EmergencyAction(_) | TokenTransition::ConfigUpdate(_) - | TokenTransition::Claim(_) => historical_query(), + | TokenTransition::Claim(_) => verify_token_historical_document( + proof, + token_transition, + token_config, + owner_id, + platform_version, + ), + TokenTransition::OrderBuyLimit(_) => verify_token_order(), + TokenTransition::OrderSellLimit(_) => verify_token_order(), + TokenTransition::OrderCancel(_) => verify_token_order(), + TokenTransition::OrderAdjustPrice(_) => verify_token_order(), } } } @@ -654,3 +642,65 @@ impl Drive { } } } + +fn verify_token_order() -> Result<(RootHash, StateTransitionProofResult), Error> { + // TODO: Implement this + + Ok((RootHash::default(), VerifiedDocuments(Default::default()))) +} + +fn verify_token_historical_document( + proof: &[u8], + token_transition: &TokenTransition, + token_config: &TokenConfiguration, + owner_id: Identifier, + platform_version: &PlatformVersion, +) -> Result<(RootHash, StateTransitionProofResult), Error> { + let token_history_contract = + load_system_data_contract(SystemDataContract::TokenHistory, platform_version)?; + + let Some(token_event) = token_transition.associated_token_event(token_config, owner_id)? else { + unreachable!("verify_token_historical_event must be called only for token transitions that have an associated token event"); + }; + + let token_id = token_transition.token_id(); + let owner_nonce = token_transition.base().identity_contract_nonce(); + + let query = SingleDocumentDriveQuery { + contract_id: token_history_contract.id().into_buffer(), + document_type_name: token_event.associated_document_type_name().to_string(), + document_type_keeps_history: false, + document_id: token_event + .associated_document_id(token_id, owner_id, owner_nonce) + .to_buffer(), + block_time_ms: None, //None because we want latest + contested_status: SingleDocumentDriveQueryContestedStatus::NotContested, + }; + + let token_history_document_type = token_history_contract + .document_type_for_name(token_event.associated_document_type_name())?; + + let (root_hash, Some(document)) = + query.verify_proof(false, proof, token_history_document_type, platform_version)? + else { + return Err(Error::Proof(ProofError::IncorrectProof(format!("proof did not contain document with id {} expected to exist because the token keeps historical documents", token_event.associated_document_type_name())))); + }; + + let expected_document = token_event.build_associated_historical_document_owned( + token_id, + owner_id, + owner_nonce, + &BlockInfo::default(), + platform_version, + )?; + + if !document.is_equal_ignoring_time_based_fields( + &expected_document, + Some(vec!["destroyedAmount"]), + platform_version, + )? { + return Err(Error::Proof(ProofError::IncorrectProof(format!("proof of state transition execution did not show the correct historical document {}, {}", document, expected_document)))); + } + + Ok((root_hash, VerifiedTokenActionWithDocument(document))) +} diff --git a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/mod.rs b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/mod.rs index 63fd315d88b..2ba1029268f 100644 --- a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/mod.rs +++ b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/mod.rs @@ -121,8 +121,12 @@ pub struct DriveAbciDocumentsStateTransitionValidationVersions { pub token_claim_transition_structure_validation: FeatureVersion, pub token_claim_transition_state_validation: FeatureVersion, pub token_order_buy_limit_transition_structure_validation: FeatureVersion, + pub token_order_buy_limit_transition_state_validation: FeatureVersion, pub token_order_sell_limit_transition_structure_validation: FeatureVersion, + pub token_order_sell_limit_transition_state_validation: FeatureVersion, + pub token_order_cancel_transition_state_validation: FeatureVersion, pub token_order_adjust_price_transition_structure_validation: FeatureVersion, + pub token_order_adjust_price_transition_state_validation: FeatureVersion, } #[derive(Clone, Debug, Default)] diff --git a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v1.rs b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v1.rs index da6d3074b03..4194b1f1648 100644 --- a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v1.rs +++ b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v1.rs @@ -152,8 +152,12 @@ pub const DRIVE_ABCI_VALIDATION_VERSIONS_V1: DriveAbciValidationVersions = token_claim_transition_structure_validation: 0, token_claim_transition_state_validation: 0, token_order_buy_limit_transition_structure_validation: 0, + token_order_buy_limit_transition_state_validation: 0, token_order_sell_limit_transition_structure_validation: 0, + token_order_sell_limit_transition_state_validation: 0, + token_order_cancel_transition_state_validation: 0, token_order_adjust_price_transition_structure_validation: 0, + token_order_adjust_price_transition_state_validation: 0, }, }, has_nonce_validation: 0, diff --git a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v2.rs b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v2.rs index cec5204b566..ecabde37639 100644 --- a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v2.rs +++ b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v2.rs @@ -152,8 +152,12 @@ pub const DRIVE_ABCI_VALIDATION_VERSIONS_V2: DriveAbciValidationVersions = token_claim_transition_structure_validation: 0, token_claim_transition_state_validation: 0, token_order_buy_limit_transition_structure_validation: 0, + token_order_buy_limit_transition_state_validation: 0, token_order_sell_limit_transition_structure_validation: 0, + token_order_sell_limit_transition_state_validation: 0, + token_order_cancel_transition_state_validation: 0, token_order_adjust_price_transition_structure_validation: 0, + token_order_adjust_price_transition_state_validation: 0, }, }, has_nonce_validation: 0, diff --git a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v3.rs b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v3.rs index 52b2cea35ab..c374bb66941 100644 --- a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v3.rs +++ b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v3.rs @@ -152,8 +152,12 @@ pub const DRIVE_ABCI_VALIDATION_VERSIONS_V3: DriveAbciValidationVersions = token_claim_transition_structure_validation: 0, token_claim_transition_state_validation: 0, token_order_buy_limit_transition_structure_validation: 0, + token_order_buy_limit_transition_state_validation: 0, token_order_sell_limit_transition_structure_validation: 0, + token_order_sell_limit_transition_state_validation: 0, + token_order_cancel_transition_state_validation: 0, token_order_adjust_price_transition_structure_validation: 0, + token_order_adjust_price_transition_state_validation: 0, }, }, has_nonce_validation: 0, diff --git a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v4.rs b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v4.rs index 37afb48d380..5f13e30852e 100644 --- a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v4.rs +++ b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v4.rs @@ -155,8 +155,12 @@ pub const DRIVE_ABCI_VALIDATION_VERSIONS_V4: DriveAbciValidationVersions = token_claim_transition_structure_validation: 0, token_claim_transition_state_validation: 0, token_order_buy_limit_transition_structure_validation: 0, + token_order_buy_limit_transition_state_validation: 0, token_order_sell_limit_transition_structure_validation: 0, + token_order_sell_limit_transition_state_validation: 0, + token_order_cancel_transition_state_validation: 0, token_order_adjust_price_transition_structure_validation: 0, + token_order_adjust_price_transition_state_validation: 0, }, }, has_nonce_validation: 1, // <---- changed this diff --git a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v5.rs b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v5.rs index 3022ce399dc..5def0960a26 100644 --- a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v5.rs +++ b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v5.rs @@ -156,8 +156,12 @@ pub const DRIVE_ABCI_VALIDATION_VERSIONS_V5: DriveAbciValidationVersions = token_claim_transition_structure_validation: 0, token_claim_transition_state_validation: 0, token_order_buy_limit_transition_structure_validation: 0, + token_order_buy_limit_transition_state_validation: 0, token_order_sell_limit_transition_structure_validation: 0, + token_order_sell_limit_transition_state_validation: 0, + token_order_cancel_transition_state_validation: 0, token_order_adjust_price_transition_structure_validation: 0, + token_order_adjust_price_transition_state_validation: 0, }, }, has_nonce_validation: 1, diff --git a/packages/wasm-dpp/src/document/state_transition/batch_transition/token_transition/mod.rs b/packages/wasm-dpp/src/document/state_transition/batch_transition/token_transition/mod.rs index 15e9a4a52e5..5316055577f 100644 --- a/packages/wasm-dpp/src/document/state_transition/batch_transition/token_transition/mod.rs +++ b/packages/wasm-dpp/src/document/state_transition/batch_transition/token_transition/mod.rs @@ -5,6 +5,10 @@ pub mod destroy; pub mod emergency_action; pub mod freeze; pub mod mint; +pub mod order_adjust_price; +pub mod order_buy_limit; +pub mod order_cancel; +pub mod order_sell_limit; pub mod transfer; pub mod unfreeze; @@ -15,6 +19,10 @@ use crate::batch_transition::token_transition::destroy::TokenDestroyFrozenFundsT use crate::batch_transition::token_transition::emergency_action::TokenEmergencyActionTransitionWasm; use crate::batch_transition::token_transition::freeze::TokenFreezeTransitionWasm; use crate::batch_transition::token_transition::mint::TokenMintTransitionWasm; +use crate::batch_transition::token_transition::order_adjust_price::TokenOrderAdjustPriceTransitionWasm; +use crate::batch_transition::token_transition::order_buy_limit::TokenOrderBuyLimitTransitionWasm; +use crate::batch_transition::token_transition::order_cancel::TokenOrderCancelTransitionWasm; +use crate::batch_transition::token_transition::order_sell_limit::TokenOrderSellLimitTransitionWasm; use crate::batch_transition::token_transition::transfer::TokenTransferTransitionWasm; use crate::batch_transition::token_transition::unfreeze::TokenUnfreezeTransitionWasm; use crate::identifier::IdentifierWrapper; @@ -38,6 +46,10 @@ pub enum TokenTransitionType { Claim, EmergencyAction, ConfigUpdate, + OrderBuyLimit, + OrderSellLimit, + OrderCancel, + OrderAdjustPrice, } impl From<&TokenTransition> for TokenTransitionType { @@ -52,6 +64,10 @@ impl From<&TokenTransition> for TokenTransitionType { TokenTransition::EmergencyAction(_) => TokenTransitionType::EmergencyAction, TokenTransition::ConfigUpdate(_) => TokenTransitionType::ConfigUpdate, TokenTransition::Claim(_) => TokenTransitionType::Claim, + TokenTransition::OrderBuyLimit(_) => TokenTransitionType::OrderBuyLimit, + TokenTransition::OrderSellLimit(_) => TokenTransitionType::OrderSellLimit, + TokenTransition::OrderCancel(_) => TokenTransitionType::OrderCancel, + TokenTransition::OrderAdjustPrice(_) => TokenTransitionType::OrderAdjustPrice, } } } @@ -133,6 +149,18 @@ impl TokenTransitionWasm { TokenConfigUpdateTransitionWasm::from(config_update.clone()).into() } TokenTransition::Claim(claim) => TokenClaimTransitionWasm::from(claim.clone()).into(), + TokenTransition::OrderBuyLimit(transition) => { + TokenOrderBuyLimitTransitionWasm::from(transition.clone()).into() + } + TokenTransition::OrderSellLimit(transition) => { + TokenOrderSellLimitTransitionWasm::from(transition.clone()).into() + } + TokenTransition::OrderCancel(transition) => { + TokenOrderCancelTransitionWasm::from(transition.clone()).into() + } + TokenTransition::OrderAdjustPrice(transition) => { + TokenOrderAdjustPriceTransitionWasm::from(transition.clone()).into() + } } } } diff --git a/packages/wasm-dpp/src/document/state_transition/batch_transition/token_transition/order_adjust_price.rs b/packages/wasm-dpp/src/document/state_transition/batch_transition/token_transition/order_adjust_price.rs new file mode 100644 index 00000000000..9dd08cfec2c --- /dev/null +++ b/packages/wasm-dpp/src/document/state_transition/batch_transition/token_transition/order_adjust_price.rs @@ -0,0 +1,12 @@ +use wasm_bindgen::prelude::wasm_bindgen; +use dpp::state_transition::batch_transition::batched_transition::token_order_adjust_price_transition::transition::TokenOrderAdjustPriceTransition; + +#[wasm_bindgen(js_name=TokenOrderAdjustPriceTransition)] +#[derive(Debug, Clone)] +pub struct TokenOrderAdjustPriceTransitionWasm(TokenOrderAdjustPriceTransition); + +impl From for TokenOrderAdjustPriceTransitionWasm { + fn from(value: TokenOrderAdjustPriceTransition) -> Self { + Self(value) + } +} diff --git a/packages/wasm-dpp/src/document/state_transition/batch_transition/token_transition/order_buy_limit.rs b/packages/wasm-dpp/src/document/state_transition/batch_transition/token_transition/order_buy_limit.rs new file mode 100644 index 00000000000..23043cf0a42 --- /dev/null +++ b/packages/wasm-dpp/src/document/state_transition/batch_transition/token_transition/order_buy_limit.rs @@ -0,0 +1,12 @@ +use wasm_bindgen::prelude::wasm_bindgen; +use dpp::state_transition::batch_transition::batched_transition::token_order_buy_limit_transition::transition::TokenOrderBuyLimitTransition; + +#[wasm_bindgen(js_name=TokenOrderBuyLimitTransition)] +#[derive(Debug, Clone)] +pub struct TokenOrderBuyLimitTransitionWasm(TokenOrderBuyLimitTransition); + +impl From for TokenOrderBuyLimitTransitionWasm { + fn from(value: TokenOrderBuyLimitTransition) -> Self { + Self(value) + } +} diff --git a/packages/wasm-dpp/src/document/state_transition/batch_transition/token_transition/order_cancel.rs b/packages/wasm-dpp/src/document/state_transition/batch_transition/token_transition/order_cancel.rs new file mode 100644 index 00000000000..0b8ed7d41f0 --- /dev/null +++ b/packages/wasm-dpp/src/document/state_transition/batch_transition/token_transition/order_cancel.rs @@ -0,0 +1,12 @@ +use wasm_bindgen::prelude::wasm_bindgen; +use dpp::state_transition::batch_transition::batched_transition::token_order_cancel_transition::transition::TokenOrderCancelTransition; + +#[wasm_bindgen(js_name=TokenOrderCancelTransition)] +#[derive(Debug, Clone)] +pub struct TokenOrderCancelTransitionWasm(TokenOrderCancelTransition); + +impl From for TokenOrderCancelTransitionWasm { + fn from(value: TokenOrderCancelTransition) -> Self { + Self(value) + } +} diff --git a/packages/wasm-dpp/src/document/state_transition/batch_transition/token_transition/order_sell_limit.rs b/packages/wasm-dpp/src/document/state_transition/batch_transition/token_transition/order_sell_limit.rs new file mode 100644 index 00000000000..0a55f3822be --- /dev/null +++ b/packages/wasm-dpp/src/document/state_transition/batch_transition/token_transition/order_sell_limit.rs @@ -0,0 +1,12 @@ +use wasm_bindgen::prelude::wasm_bindgen; +use dpp::state_transition::batch_transition::batched_transition::token_order_sell_limit_transition::transition::TokenOrderSellLimitTransition; + +#[wasm_bindgen(js_name=TokenOrderSellLimitTransition)] +#[derive(Debug, Clone)] +pub struct TokenOrderSellLimitTransitionWasm(TokenOrderSellLimitTransition); + +impl From for TokenOrderSellLimitTransitionWasm { + fn from(value: TokenOrderSellLimitTransition) -> Self { + Self(value) + } +} diff --git a/packages/wasm-dpp/src/errors/consensus/consensus_error.rs b/packages/wasm-dpp/src/errors/consensus/consensus_error.rs index d93a43ddaa8..cf432dab28e 100644 --- a/packages/wasm-dpp/src/errors/consensus/consensus_error.rs +++ b/packages/wasm-dpp/src/errors/consensus/consensus_error.rs @@ -66,7 +66,7 @@ use dpp::consensus::basic::document::{ContestedDocumentsTemporarilyNotAllowedErr use dpp::consensus::basic::group::GroupActionNotAllowedOnTransitionError; use dpp::consensus::basic::identity::{DataContractBoundsNotPresentError, DisablingKeyIdAlsoBeingAddedInSameTransitionError, InvalidIdentityCreditWithdrawalTransitionAmountError, InvalidIdentityUpdateTransitionDisableKeysError, InvalidIdentityUpdateTransitionEmptyError, TooManyMasterPublicKeyError, WithdrawalOutputScriptNotAllowedWhenSigningWithOwnerKeyError}; use dpp::consensus::basic::overflow_error::OverflowError; -use dpp::consensus::basic::token::{ChoosingTokenMintRecipientNotAllowedError, ContractHasNoTokensError, DestinationIdentityForTokenMintingNotSetError, InvalidActionIdError, InvalidTokenAmountError, InvalidTokenConfigUpdateNoChangeError, InvalidTokenIdError, InvalidTokenNoteTooBigError, InvalidTokenPositionError, MissingDefaultLocalizationError, TokenTransferToOurselfError, ZeroTokenAmountError, ZeroTokenPriceError}; +use dpp::consensus::basic::token::{ChoosingTokenMintRecipientNotAllowedError, ContractHasNoTokensError, DestinationIdentityForTokenMintingNotSetError, InvalidActionIdError, InvalidTokenAmountError, InvalidTokenConfigUpdateNoChangeError, InvalidTokenIdError, InvalidTokenNoteTooBigError, InvalidTokenPositionError, InvalidTokenPriceError, MissingDefaultLocalizationError, TokenTransferToOurselfError, ZeroTokenAmountError, ZeroTokenPriceError}; use dpp::consensus::state::data_contract::data_contract_update_action_not_allowed_error::DataContractUpdateActionNotAllowedError; use dpp::consensus::state::data_contract::document_type_update_error::DocumentTypeUpdateError; use dpp::consensus::state::document::document_contest_currently_locked_error::DocumentContestCurrentlyLockedError; @@ -746,6 +746,9 @@ fn from_basic_error(basic_error: &BasicError) -> JsValue { BasicError::ZeroTokenAmountError(e) => { generic_consensus_error!(ZeroTokenAmountError, e).into() } + BasicError::InvalidTokenPriceError(e) => { + generic_consensus_error!(InvalidTokenPriceError, e).into() + } BasicError::MissingDefaultLocalizationError(e) => { generic_consensus_error!(MissingDefaultLocalizationError, e).into() } From dea79bc51a7873ae205380928853db275b1b344a Mon Sep 17 00:00:00 2001 From: Ivan Shumkov Date: Sun, 30 Mar 2025 15:59:40 +0700 Subject: [PATCH 5/6] feat: add token marketplace contract --- .github/package-filters/js-packages.yml | 6 + .github/package-filters/rs-packages.yml | 5 + Cargo.lock | 11 + Cargo.toml | 3 +- package.json | 3 +- packages/data-contracts/Cargo.toml | 1 + packages/data-contracts/src/error.rs | 17 + packages/data-contracts/src/lib.rs | 13 +- .../system_data_contract_versions/mod.rs | 2 + .../system_data_contract_versions/v1.rs | 2 + packages/token-history-contract/src/lib.rs | 8 +- packages/token-marketplace-contract/.eslintrc | 18 + .../token-marketplace-contract/.mocharc.yml | 2 + .../token-marketplace-contract/Cargo.toml | 13 + packages/token-marketplace-contract/LICENSE | 20 + packages/token-marketplace-contract/README.md | 26 ++ .../lib/systemIds.js | 4 + .../token-marketplace-contract/package.json | 29 ++ .../schema/v1/documents.json | 100 +++++ .../token-marketplace-contract/src/error.rs | 17 + .../token-marketplace-contract/src/lib.rs | 37 ++ .../token-marketplace-contract/src/v1/mod.rs | 7 + .../token-marketplace-contract/test/.eslintrc | 12 + .../test/bootstrap.js | 30 ++ .../unit/tokenMarketplaceContract.spec.js | 412 ++++++++++++++++++ 25 files changed, 791 insertions(+), 7 deletions(-) create mode 100644 packages/token-marketplace-contract/.eslintrc create mode 100644 packages/token-marketplace-contract/.mocharc.yml create mode 100644 packages/token-marketplace-contract/Cargo.toml create mode 100644 packages/token-marketplace-contract/LICENSE create mode 100644 packages/token-marketplace-contract/README.md create mode 100644 packages/token-marketplace-contract/lib/systemIds.js create mode 100644 packages/token-marketplace-contract/package.json create mode 100644 packages/token-marketplace-contract/schema/v1/documents.json create mode 100644 packages/token-marketplace-contract/src/error.rs create mode 100644 packages/token-marketplace-contract/src/lib.rs create mode 100644 packages/token-marketplace-contract/src/v1/mod.rs create mode 100644 packages/token-marketplace-contract/test/.eslintrc create mode 100644 packages/token-marketplace-contract/test/bootstrap.js create mode 100644 packages/token-marketplace-contract/test/unit/tokenMarketplaceContract.spec.js diff --git a/.github/package-filters/js-packages.yml b/.github/package-filters/js-packages.yml index 0c4e0260fa7..33c55c16a70 100644 --- a/.github/package-filters/js-packages.yml +++ b/.github/package-filters/js-packages.yml @@ -6,6 +6,10 @@ - .github/workflows/tests* - packages/token-history-contract/** +'@dashevo/token-marketplace-contract': &token-marketplace-contract + - .github/workflows/tests* + - packages/token-marketplace-contract/** + '@dashevo/dashpay-contract': &dashpay-contract - .github/workflows/tests* - packages/dashpay-contract/** @@ -35,6 +39,7 @@ - *withdrawals-contract - *wallet-utils-contract - *token-history-contract + - *token-marketplace-contract - packages/rs-platform-serialization/** - packages/rs-platform-serialization-derive/** - packages/rs-platform-value/** @@ -86,6 +91,7 @@ dashmate: - *dpns-contract - *withdrawals-contract - *token-history-contract + - *token-marketplace-contract - *wallet-lib - *dapi-client diff --git a/.github/package-filters/rs-packages.yml b/.github/package-filters/rs-packages.yml index 7e31bd9992f..e34571505e7 100644 --- a/.github/package-filters/rs-packages.yml +++ b/.github/package-filters/rs-packages.yml @@ -6,6 +6,10 @@ token-history-contract: &token-history-contract - .github/workflows/tests* - packages/token-history-contract/** +token-marketplace-contract: &token-marketplace-contract + - .github/workflows/tests* + - packages/token-marketplace-contract/** + dashpay-contract: &dashpay-contract - .github/workflows/tests* - packages/dashpay-contract/** @@ -35,6 +39,7 @@ dpp: &dpp - *withdrawals-contract - *wallet-utils-contract - *token-history-contract + - *token-marketplace-contract - *json-schema-compatibility-validator - packages/rs-platform-serialization/** - packages/rs-platform-serialization-derive/** diff --git a/Cargo.lock b/Cargo.lock index 0fb070fb49d..36968a01b6a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1329,6 +1329,7 @@ dependencies = [ "serde_json", "thiserror 1.0.64", "token-history-contract", + "token-marketplace-contract", "wallet-utils-contract", "withdrawals-contract", ] @@ -5068,6 +5069,16 @@ dependencies = [ "thiserror 1.0.64", ] +[[package]] +name = "token-marketplace-contract" +version = "2.0.0-dev.1" +dependencies = [ + "platform-value", + "platform-version", + "serde_json", + "thiserror 1.0.64", +] + [[package]] name = "tokio" version = "1.40.0" diff --git a/Cargo.toml b/Cargo.toml index 1dd2d2ecdbf..e824d1a8ab9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,7 +29,8 @@ members = [ "packages/rs-json-schema-compatibility-validator", "packages/check-features", "packages/wallet-utils-contract", - "packages/token-history-contract" + "packages/token-history-contract", + "packages/token-marketplace-contract" ] exclude = ["packages/wasm-sdk"] # This one is experimental and not ready for use diff --git a/package.json b/package.json index 091c572b30d..9df60afb643 100644 --- a/package.json +++ b/package.json @@ -67,7 +67,8 @@ "packages/dash-spv", "packages/wasm-dpp", "packages/withdrawals-contract", - "packages/token-history-contract" + "packages/token-history-contract", + "packages/token-marketplace-contract" ], "resolutions": { "elliptic": "6.5.7", diff --git a/packages/data-contracts/Cargo.toml b/packages/data-contracts/Cargo.toml index f10d5785838..6fb72122b8a 100644 --- a/packages/data-contracts/Cargo.toml +++ b/packages/data-contracts/Cargo.toml @@ -18,3 +18,4 @@ feature-flags-contract = { path = "../feature-flags-contract" } platform-value = { path = "../rs-platform-value" } wallet-utils-contract = { path = "../wallet-utils-contract" } token-history-contract = { path = "../token-history-contract" } +token-marketplace-contract = { path = "../token-marketplace-contract" } diff --git a/packages/data-contracts/src/error.rs b/packages/data-contracts/src/error.rs index 7c0c802b71e..8b8939cd32b 100644 --- a/packages/data-contracts/src/error.rs +++ b/packages/data-contracts/src/error.rs @@ -136,3 +136,20 @@ impl From for Error { } } } + +impl From for Error { + fn from(e: token_marketplace_contract::Error) -> Self { + match e { + token_marketplace_contract::Error::UnknownVersionMismatch { + method, + known_versions, + received, + } => Error::UnknownVersionMismatch { + method, + known_versions, + received, + }, + token_marketplace_contract::Error::InvalidSchemaJson(e) => Error::InvalidSchemaJson(e), + } + } +} diff --git a/packages/data-contracts/src/lib.rs b/packages/data-contracts/src/lib.rs index a78ffefc373..a4af5263f4e 100644 --- a/packages/data-contracts/src/lib.rs +++ b/packages/data-contracts/src/lib.rs @@ -23,6 +23,7 @@ pub enum SystemDataContract { Dashpay = 4, WalletUtils = 5, TokenHistory = 6, + TokenMarket = 7, } pub struct DataContractSource { @@ -43,6 +44,7 @@ impl SystemDataContract { SystemDataContract::Dashpay => dashpay_contract::ID_BYTES, SystemDataContract::WalletUtils => wallet_utils_contract::ID_BYTES, SystemDataContract::TokenHistory => token_history_contract::ID_BYTES, + SystemDataContract::TokenMarket => token_marketplace_contract::ID_BYTES, }; Identifier::new(bytes) } @@ -98,10 +100,19 @@ impl SystemDataContract { SystemDataContract::TokenHistory => DataContractSource { id_bytes: token_history_contract::ID_BYTES, owner_id_bytes: token_history_contract::OWNER_ID_BYTES, - version: platform_version.system_data_contracts.wallet as u32, + version: platform_version.system_data_contracts.token_history as u32, definitions: token_history_contract::load_definitions(platform_version)?, document_schemas: token_history_contract::load_documents_schemas(platform_version)?, }, + SystemDataContract::TokenMarket => DataContractSource { + id_bytes: token_marketplace_contract::ID_BYTES, + owner_id_bytes: token_marketplace_contract::OWNER_ID_BYTES, + version: platform_version.system_data_contracts.token_marketplace as u32, + definitions: token_marketplace_contract::load_definitions(platform_version)?, + document_schemas: token_marketplace_contract::load_documents_schemas( + platform_version, + )?, + }, }; Ok(data) diff --git a/packages/rs-platform-version/src/version/system_data_contract_versions/mod.rs b/packages/rs-platform-version/src/version/system_data_contract_versions/mod.rs index cc444b25e9d..b44c3f70309 100644 --- a/packages/rs-platform-version/src/version/system_data_contract_versions/mod.rs +++ b/packages/rs-platform-version/src/version/system_data_contract_versions/mod.rs @@ -10,4 +10,6 @@ pub struct SystemDataContractVersions { pub masternode_reward_shares: FeatureVersion, pub feature_flags: FeatureVersion, pub wallet: FeatureVersion, + pub token_history: FeatureVersion, + pub token_marketplace: FeatureVersion, } diff --git a/packages/rs-platform-version/src/version/system_data_contract_versions/v1.rs b/packages/rs-platform-version/src/version/system_data_contract_versions/v1.rs index a55db9a296b..e73fece4489 100644 --- a/packages/rs-platform-version/src/version/system_data_contract_versions/v1.rs +++ b/packages/rs-platform-version/src/version/system_data_contract_versions/v1.rs @@ -8,4 +8,6 @@ pub const SYSTEM_DATA_CONTRACT_VERSIONS_V1: SystemDataContractVersions = masternode_reward_shares: 1, feature_flags: 1, wallet: 1, + token_history: 1, + token_marketplace: 1, }; diff --git a/packages/token-history-contract/src/lib.rs b/packages/token-history-contract/src/lib.rs index 3bf08b2e25b..d89375dc9db 100644 --- a/packages/token-history-contract/src/lib.rs +++ b/packages/token-history-contract/src/lib.rs @@ -16,20 +16,20 @@ pub const OWNER_ID_BYTES: [u8; 32] = [0; 32]; pub const ID: Identifier = Identifier(IdentifierBytes32(ID_BYTES)); pub const OWNER_ID: Identifier = Identifier(IdentifierBytes32(OWNER_ID_BYTES)); pub fn load_definitions(platform_version: &PlatformVersion) -> Result, Error> { - match platform_version.system_data_contracts.withdrawals { + match platform_version.system_data_contracts.token_history { 1 => Ok(None), version => Err(Error::UnknownVersionMismatch { - method: "wallet_contract::load_definitions".to_string(), + method: "token_history::load_definitions".to_string(), known_versions: vec![1], received: version, }), } } pub fn load_documents_schemas(platform_version: &PlatformVersion) -> Result { - match platform_version.system_data_contracts.withdrawals { + match platform_version.system_data_contracts.token_history { 1 => v1::load_documents_schemas(), version => Err(Error::UnknownVersionMismatch { - method: "wallet_contract::load_documents_schemas".to_string(), + method: "token_history::load_documents_schemas".to_string(), known_versions: vec![1], received: version, }), diff --git a/packages/token-marketplace-contract/.eslintrc b/packages/token-marketplace-contract/.eslintrc new file mode 100644 index 00000000000..cb6c7636b60 --- /dev/null +++ b/packages/token-marketplace-contract/.eslintrc @@ -0,0 +1,18 @@ +{ + "extends": "airbnb-base", + "rules": { + "no-plusplus": 0, + "eol-last": [ + "error", + "always" + ], + "class-methods-use-this": "off", + "curly": [ + "error", + "all" + ] + }, + "globals": { + "BigInt": true + } +} diff --git a/packages/token-marketplace-contract/.mocharc.yml b/packages/token-marketplace-contract/.mocharc.yml new file mode 100644 index 00000000000..164b941c1b6 --- /dev/null +++ b/packages/token-marketplace-contract/.mocharc.yml @@ -0,0 +1,2 @@ +require: test/bootstrap.js +recursive: true diff --git a/packages/token-marketplace-contract/Cargo.toml b/packages/token-marketplace-contract/Cargo.toml new file mode 100644 index 00000000000..715888660ec --- /dev/null +++ b/packages/token-marketplace-contract/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "token-marketplace-contract" +description = "Token marketplace system contract to store orders" +version = "2.0.0-dev.1" +edition = "2021" +rust-version.workspace = true +license = "MIT" + +[dependencies] +thiserror = "1.0.64" +platform-version = { path = "../rs-platform-version" } +serde_json = { version = "1.0" } +platform-value = { path = "../rs-platform-value" } diff --git a/packages/token-marketplace-contract/LICENSE b/packages/token-marketplace-contract/LICENSE new file mode 100644 index 00000000000..3be95833750 --- /dev/null +++ b/packages/token-marketplace-contract/LICENSE @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2019 Dash Core Group, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/packages/token-marketplace-contract/README.md b/packages/token-marketplace-contract/README.md new file mode 100644 index 00000000000..54f2789f849 --- /dev/null +++ b/packages/token-marketplace-contract/README.md @@ -0,0 +1,26 @@ +# Token Marketplace Contract + +[![Build Status](https://github.com/dashpay/platform/actions/workflows/release.yml/badge.svg)](https://github.com/dashpay/platform/actions/workflows/release.yml) +[![NPM version](https://img.shields.io/npm/v/@dashevo/wallet-contract.svg?style=flat-square)](https://npmjs.org/package/@dashevo/wallet-contract) + +JSON Contracts for Token marketplace orders + +## Table of Contents + +- [Install](#install) +- [Contributing](#contributing) +- [License](#license) + +## Install + +```sh +npm install @dashevo/token-marketplace-contract +``` + +## Contributing + +Feel free to dive in! [Open an issue](https://github.com/dashpay/platform/issues/new/choose) or submit PRs. + +## License + +[MIT](LICENSE) © Dash Core Group, Inc. diff --git a/packages/token-marketplace-contract/lib/systemIds.js b/packages/token-marketplace-contract/lib/systemIds.js new file mode 100644 index 00000000000..156f81eed4b --- /dev/null +++ b/packages/token-marketplace-contract/lib/systemIds.js @@ -0,0 +1,4 @@ +module.exports = { + ownerId: '11111111111111111111111111111111', + contractId: 'Bz2DTBaPsCpgS6cvJA2SswDJxqi2JpTCF1ugcF7DMK3Q', +}; diff --git a/packages/token-marketplace-contract/package.json b/packages/token-marketplace-contract/package.json new file mode 100644 index 00000000000..20f9c2c9cba --- /dev/null +++ b/packages/token-marketplace-contract/package.json @@ -0,0 +1,29 @@ +{ + "name": "@dashevo/token-marketplace-contract", + "version": "2.0.0-dev.1", + "description": "The token marketplace contract to store orders", + "scripts": { + "lint": "eslint .", + "test": "yarn run test:unit", + "test:unit": "mocha 'test/unit/**/*.spec.js'" + }, + "contributors": [ + { + "name": "Ivan Shumkov", + "email": "shumkov@dash.org", + "url": "https://github.com/shumkov" + } + ], + "license": "MIT", + "devDependencies": { + "@dashevo/wasm-dpp": "workspace:*", + "chai": "^4.3.10", + "dirty-chai": "^2.0.1", + "eslint": "^8.53.0", + "eslint-config-airbnb-base": "^15.0.0", + "eslint-plugin-import": "^2.29.0", + "mocha": "^11.1.0", + "sinon": "^17.0.1", + "sinon-chai": "^3.7.0" + } +} diff --git a/packages/token-marketplace-contract/schema/v1/documents.json b/packages/token-marketplace-contract/schema/v1/documents.json new file mode 100644 index 00000000000..912adbacb20 --- /dev/null +++ b/packages/token-marketplace-contract/schema/v1/documents.json @@ -0,0 +1,100 @@ +{ + "order": { + "description": "// TODO: Fill it", + "type": "object", + "creationRestrictionMode": 2, + "indices": [ + { + "name": "byDate", + "properties": [ + { + "tokenId": "asc" + }, + { + "$createdAt": "asc" + } + ] + }, + { + "name": "byAmount", + "properties": [ + { + "tokenId": "asc" + }, + { + "amount": "asc" + } + ] + }, + { + "name": "byOwnerId", + "properties": [ + { + "tokenId": "asc" + }, + { + "$ownerId": "asc" + }, + { + "$createdAt": "asc" + } + ] + } + ], + "properties": { + "type": { + "type": "integer", + "description": "The type of order: 0 - buy, 1 - sell", + "enum": [ + 0, + 1 + ], + "position": 0 + }, + "status": { + "type": "integer", + "description": "The status of order: 0 - open, 1 - complete, 2 - canceled", + "enum": [ + 0, + 1, + 2, + ], + "position": 1 + }, + "tokenId": { + "type": "array", + "byteArray": true, + "minItems": 32, + "maxItems": 32, + "description": "The token ID", + "position": 2, + "contentMediaType": "application/x.dash.dpp.identifier" + }, + "initialTokenAmount": { + "type": "integer", + "minimum": 0, + "description": "The amount of tokens to buy/sell", + "position": 3 + }, + "processedTokenAmount": { + "type": "integer", + "minimum": 0, + "description": "Already processed amount of tokens", + "position": 3 + }, + "tokenPrice": { + "type": "integer", + "minimum": 0, + "description": "Max/min price for buy/sell specified amount of tokens", + "position": 4 + } + }, + "required": [ + "tokenId", + "amount", + "$createdAt", + "$updatedAt" + ], + "additionalProperties": false + } +} diff --git a/packages/token-marketplace-contract/src/error.rs b/packages/token-marketplace-contract/src/error.rs new file mode 100644 index 00000000000..d01bbcc91cf --- /dev/null +++ b/packages/token-marketplace-contract/src/error.rs @@ -0,0 +1,17 @@ +use platform_version::version::FeatureVersion; + +#[derive(thiserror::Error, Debug)] +pub enum Error { + /// Platform expected some specific versions + #[error("platform unknown version on {method}, received: {received}")] + UnknownVersionMismatch { + /// method + method: String, + /// the allowed versions for this method + known_versions: Vec, + /// requested core height + received: FeatureVersion, + }, + #[error("schema deserialize error: {0}")] + InvalidSchemaJson(#[from] serde_json::Error), +} diff --git a/packages/token-marketplace-contract/src/lib.rs b/packages/token-marketplace-contract/src/lib.rs new file mode 100644 index 00000000000..606918fbb9d --- /dev/null +++ b/packages/token-marketplace-contract/src/lib.rs @@ -0,0 +1,37 @@ +mod error; +pub mod v1; + +pub use crate::error::Error; +use platform_value::{Identifier, IdentifierBytes32}; +use platform_version::version::PlatformVersion; +use serde_json::Value; + +pub const ID_BYTES: [u8; 32] = [ + 163, 48, 89, 76, 126, 133, 229, 211, 173, 53, 218, 112, 77, 231, 72, 107, 107, 127, 225, 220, + 84, 165, 134, 59, 133, 4, 111, 198, 239, 243, 236, 179, +]; + +pub const OWNER_ID_BYTES: [u8; 32] = [0; 32]; + +pub const ID: Identifier = Identifier(IdentifierBytes32(ID_BYTES)); +pub const OWNER_ID: Identifier = Identifier(IdentifierBytes32(OWNER_ID_BYTES)); +pub fn load_definitions(platform_version: &PlatformVersion) -> Result, Error> { + match platform_version.system_data_contracts.token_marketplace { + 1 => Ok(None), + version => Err(Error::UnknownVersionMismatch { + method: "token_marketplace::load_definitions".to_string(), + known_versions: vec![1], + received: version, + }), + } +} +pub fn load_documents_schemas(platform_version: &PlatformVersion) -> Result { + match platform_version.system_data_contracts.token_marketplace { + 1 => v1::load_documents_schemas(), + version => Err(Error::UnknownVersionMismatch { + method: "token_marketplace::load_documents_schemas".to_string(), + known_versions: vec![1], + received: version, + }), + } +} diff --git a/packages/token-marketplace-contract/src/v1/mod.rs b/packages/token-marketplace-contract/src/v1/mod.rs new file mode 100644 index 00000000000..f3b7db17562 --- /dev/null +++ b/packages/token-marketplace-contract/src/v1/mod.rs @@ -0,0 +1,7 @@ +use crate::Error; +use serde_json::Value; + +pub fn load_documents_schemas() -> Result { + serde_json::from_str(include_str!("../../schema/v1/documents.json")) + .map_err(Error::InvalidSchemaJson) +} diff --git a/packages/token-marketplace-contract/test/.eslintrc b/packages/token-marketplace-contract/test/.eslintrc new file mode 100644 index 00000000000..720ced73852 --- /dev/null +++ b/packages/token-marketplace-contract/test/.eslintrc @@ -0,0 +1,12 @@ +{ + "env": { + "node": true, + "mocha": true + }, + "rules": { + "import/no-extraneous-dependencies": "off" + }, + "globals": { + "expect": true + } +} diff --git a/packages/token-marketplace-contract/test/bootstrap.js b/packages/token-marketplace-contract/test/bootstrap.js new file mode 100644 index 00000000000..7af04f464d7 --- /dev/null +++ b/packages/token-marketplace-contract/test/bootstrap.js @@ -0,0 +1,30 @@ +const sinon = require('sinon'); +const sinonChai = require('sinon-chai'); + +const { expect, use } = require('chai'); +const dirtyChai = require('dirty-chai'); + +const { + default: loadWasmDpp, +} = require('@dashevo/wasm-dpp'); + +use(dirtyChai); +use(sinonChai); + +exports.mochaHooks = { + beforeAll: loadWasmDpp, + + beforeEach() { + if (!this.sinon) { + this.sinon = sinon.createSandbox(); + } else { + this.sinon.restore(); + } + }, + + afterEach() { + this.sinon.restore(); + }, +}; + +global.expect = expect; diff --git a/packages/token-marketplace-contract/test/unit/tokenMarketplaceContract.spec.js b/packages/token-marketplace-contract/test/unit/tokenMarketplaceContract.spec.js new file mode 100644 index 00000000000..59cda32200b --- /dev/null +++ b/packages/token-marketplace-contract/test/unit/tokenMarketplaceContract.spec.js @@ -0,0 +1,412 @@ +const crypto = require('crypto'); +const { + DashPlatformProtocol, + JsonSchemaError, +} = require('@dashevo/wasm-dpp'); +const generateRandomIdentifier = require('@dashevo/wasm-dpp/lib/test/utils/generateRandomIdentifierAsync'); +const { expect } = require('chai'); +const tokenHistoryContractDocumentsSchema = require('../../schema/v1/token-marketplace-contract-documents.json'); + +const expectJsonSchemaError = (validationResult, errorCount = 1) => { + const errors = validationResult.getErrors(); + expect(errors).to.have.length(errorCount); + + const error = validationResult.getErrors()[0]; + expect(error).to.be.instanceof(JsonSchemaError); + + return error; +}; + +describe('Token History Contract', () => { + let dpp; + let dataContract; + let identityId; + + beforeEach(async () => { + dpp = new DashPlatformProtocol({ generate: () => crypto.randomBytes(32) }); + identityId = await generateRandomIdentifier(); + dataContract = dpp.dataContract.create( + identityId, + BigInt(1), + tokenHistoryContractDocumentsSchema, + ); + }); + + it('should have a valid contract definition', async () => { + const createContract = () => dpp.dataContract.create( + identityId, + BigInt(1), + tokenHistoryContractDocumentsSchema, + ); + + expect(createContract).to.not.throw(); + }); + + describe('documents', () => { + describe('burn', () => { + let rawBurnDocument; + + beforeEach(() => { + rawBurnDocument = { + tokenId: crypto.randomBytes(32), + amount: 100, + note: 'Burning tokens', + }; + }); + + describe('tokenId', () => { + it('should be defined', async () => { + delete rawBurnDocument.tokenId; + const document = dpp.document.create(dataContract, identityId, 'burn', rawBurnDocument); + const validationResult = document.validate(dpp.protocolVersion); + const error = expectJsonSchemaError(validationResult); + expect(error.keyword).to.equal('required'); + expect(error.params.missingProperty).to.equal('tokenId'); + }); + }); + + describe('amount', () => { + it('should be defined', async () => { + delete rawBurnDocument.amount; + const document = dpp.document.create(dataContract, identityId, 'burn', rawBurnDocument); + const validationResult = document.validate(dpp.protocolVersion); + const error = expectJsonSchemaError(validationResult); + expect(error.keyword).to.equal('required'); + expect(error.params.missingProperty).to.equal('amount'); + }); + + it('should be a non-negative integer', async () => { + rawBurnDocument.amount = -1; + const document = dpp.document.create(dataContract, identityId, 'burn', rawBurnDocument); + const validationResult = document.validate(dpp.protocolVersion); + const error = expectJsonSchemaError(validationResult); + expect(error.keyword).to.equal('minimum'); + }); + }); + + it('should not have additional properties', async () => { + rawBurnDocument.extraProp = 123; + const document = dpp.document.create(dataContract, identityId, 'burn', rawBurnDocument); + const validationResult = document.validate(dpp.protocolVersion); + const error = expectJsonSchemaError(validationResult); + + expect(error.keyword).to.equal('additionalProperties'); + expect(error.params.additionalProperties).to.deep.equal([ + 'extraProp', + ]); + }); + + it('should be valid', async () => { + const document = dpp.document.create(dataContract, identityId, 'burn', rawBurnDocument); + const validationResult = await document.validate(dpp.protocolVersion); + expect(validationResult.isValid()).to.be.true(); + }); + }); + + describe('mint', () => { + let rawMintDocument; + + beforeEach(() => { + rawMintDocument = { + tokenId: crypto.randomBytes(32), + recipientId: crypto.randomBytes(32), + amount: 1000, + note: 'Minting tokens', + }; + }); + + describe('tokenId', () => { + it('should be defined', async () => { + delete rawMintDocument.tokenId; + const document = dpp.document.create(dataContract, identityId, 'mint', rawMintDocument); + const validationResult = document.validate(dpp.protocolVersion); + const error = expectJsonSchemaError(validationResult); + expect(error.keyword).to.equal('required'); + expect(error.params.missingProperty).to.equal('tokenId'); + }); + }); + + describe('recipientId', () => { + it('should be defined', async () => { + delete rawMintDocument.recipientId; + const document = dpp.document.create(dataContract, identityId, 'mint', rawMintDocument); + const validationResult = document.validate(dpp.protocolVersion); + const error = expectJsonSchemaError(validationResult); + expect(error.keyword).to.equal('required'); + expect(error.params.missingProperty).to.equal('recipientId'); + }); + }); + + describe('amount', () => { + it('should be a non-negative integer', async () => { + rawMintDocument.amount = -1; + const document = dpp.document.create(dataContract, identityId, 'mint', rawMintDocument); + const validationResult = document.validate(dpp.protocolVersion); + const error = expectJsonSchemaError(validationResult); + expect(error.keyword).to.equal('minimum'); + }); + }); + + it('should not have additional properties', async () => { + rawMintDocument.extraField = 'foo'; + const document = dpp.document.create(dataContract, identityId, 'mint', rawMintDocument); + const validationResult = document.validate(dpp.protocolVersion); + const error = expectJsonSchemaError(validationResult); + expect(error.keyword).to.equal('additionalProperties'); + expect(error.params.additionalProperties).to.deep.equal(['extraField']); + }); + + it('should be valid', async () => { + const document = dpp.document.create(dataContract, identityId, 'mint', rawMintDocument); + const validationResult = await document.validate(dpp.protocolVersion); + expect(validationResult.isValid()).to.be.true(); + }); + }); + + describe('transfer', () => { + let rawTransferDocument; + + beforeEach(() => { + rawTransferDocument = { + tokenId: crypto.randomBytes(32), + amount: 10, + toIdentityId: crypto.randomBytes(32), + publicNote: 'Transfer tokens', + encryptedPersonalNote: crypto.randomBytes(32), + encryptedSharedNote: crypto.randomBytes(32), + senderKeyIndex: 0, + recipientKeyIndex: 1, + rootEncryptionKeyIndex: 2, + derivationEncryptionKeyIndex: 3, + }; + }); + + describe('tokenId', () => { + it('should be defined', async () => { + delete rawTransferDocument.tokenId; + const document = dpp.document.create(dataContract, identityId, 'transfer', rawTransferDocument); + const validationResult = document.validate(dpp.protocolVersion); + const error = expectJsonSchemaError(validationResult); + expect(error.keyword).to.equal('required'); + expect(error.params.missingProperty).to.equal('tokenId'); + }); + }); + + describe('amount', () => { + it('should be a non-negative integer', async () => { + rawTransferDocument.amount = -1; + const document = dpp.document.create(dataContract, identityId, 'transfer', rawTransferDocument); + const validationResult = document.validate(dpp.protocolVersion); + const error = expectJsonSchemaError(validationResult); + expect(error.keyword).to.equal('minimum'); + }); + }); + + describe('toIdentityId', () => { + it('should be defined', async () => { + delete rawTransferDocument.toIdentityId; + const document = dpp.document.create(dataContract, identityId, 'transfer', rawTransferDocument); + const validationResult = document.validate(dpp.protocolVersion); + const error = expectJsonSchemaError(validationResult); + expect(error.keyword).to.equal('required'); + expect(error.params.missingProperty).to.equal('toIdentityId'); + }); + }); + + it('should not have additional properties', async () => { + rawTransferDocument.foo = 'bar'; + const document = dpp.document.create(dataContract, identityId, 'transfer', rawTransferDocument); + const validationResult = document.validate(dpp.protocolVersion); + const error = expectJsonSchemaError(validationResult); + expect(error.keyword).to.equal('additionalProperties'); + expect(error.params.additionalProperties).to.deep.equal(['foo']); + }); + + it('should be valid', async () => { + const document = dpp.document.create(dataContract, identityId, 'transfer', rawTransferDocument); + const validationResult = await document.validate(dpp.protocolVersion); + expect(validationResult.isValid()).to.be.true(); + }); + }); + + describe('freeze', () => { + let rawFreezeDocument; + + beforeEach(() => { + rawFreezeDocument = { + tokenId: crypto.randomBytes(32), + frozenIdentityId: crypto.randomBytes(32), + }; + }); + + describe('tokenId', () => { + it('should be defined', async () => { + delete rawFreezeDocument.tokenId; + const document = dpp.document.create(dataContract, identityId, 'freeze', rawFreezeDocument); + const validationResult = document.validate(dpp.protocolVersion); + const error = expectJsonSchemaError(validationResult); + expect(error.keyword).to.equal('required'); + expect(error.params.missingProperty).to.equal('tokenId'); + }); + }); + + describe('frozenIdentityId', () => { + it('should be defined', async () => { + delete rawFreezeDocument.frozenIdentityId; + const document = dpp.document.create(dataContract, identityId, 'freeze', rawFreezeDocument); + const validationResult = document.validate(dpp.protocolVersion); + const error = expectJsonSchemaError(validationResult); + expect(error.keyword).to.equal('required'); + expect(error.params.missingProperty).to.equal('frozenIdentityId'); + }); + }); + + it('should not have additional properties', async () => { + rawFreezeDocument.something = true; + const document = dpp.document.create(dataContract, identityId, 'freeze', rawFreezeDocument); + const validationResult = document.validate(dpp.protocolVersion); + const error = expectJsonSchemaError(validationResult); + expect(error.keyword).to.equal('additionalProperties'); + expect(error.params.additionalProperties).to.deep.equal(['something']); + }); + + it('should be valid', async () => { + const document = dpp.document.create(dataContract, identityId, 'freeze', rawFreezeDocument); + const validationResult = await document.validate(dpp.protocolVersion); + expect(validationResult.isValid()).to.be.true(); + }); + }); + + describe('unfreeze', () => { + let rawUnfreezeDocument; + + beforeEach(() => { + rawUnfreezeDocument = { + tokenId: crypto.randomBytes(32), + frozenIdentityId: crypto.randomBytes(32), + }; + }); + + describe('tokenId', () => { + it('should be defined', async () => { + delete rawUnfreezeDocument.tokenId; + const document = dpp.document.create(dataContract, identityId, 'unfreeze', rawUnfreezeDocument); + const validationResult = document.validate(dpp.protocolVersion); + const error = expectJsonSchemaError(validationResult); + expect(error.keyword).to.equal('required'); + expect(error.params.missingProperty).to.equal('tokenId'); + }); + }); + + it('should not have additional properties', async () => { + rawUnfreezeDocument.foo = 'bar'; + const document = dpp.document.create(dataContract, identityId, 'unfreeze', rawUnfreezeDocument); + const validationResult = document.validate(dpp.protocolVersion); + const error = expectJsonSchemaError(validationResult); + expect(error.keyword).to.equal('additionalProperties'); + expect(error.params.additionalProperties).to.deep.equal(['foo']); + }); + + it('should be valid', async () => { + const document = dpp.document.create(dataContract, identityId, 'unfreeze', rawUnfreezeDocument); + const validationResult = await document.validate(dpp.protocolVersion); + expect(validationResult.isValid()).to.be.true(); + }); + }); + + describe('destroyFrozenFunds', () => { + let rawDestroyFrozenFundsDocument; + + beforeEach(() => { + rawDestroyFrozenFundsDocument = { + tokenId: crypto.randomBytes(32), + frozenIdentityId: crypto.randomBytes(32), + destroyedAmount: 500, + }; + }); + + describe('frozenIdentityId', () => { + it('should be defined', async () => { + delete rawDestroyFrozenFundsDocument.frozenIdentityId; + const document = dpp.document.create(dataContract, identityId, 'destroyFrozenFunds', rawDestroyFrozenFundsDocument); + const validationResult = document.validate(dpp.protocolVersion); + const error = expectJsonSchemaError(validationResult); + expect(error.keyword).to.equal('required'); + expect(error.params.missingProperty).to.equal('frozenIdentityId'); + }); + }); + + describe('destroyedAmount', () => { + it('should be non-negative', async () => { + rawDestroyFrozenFundsDocument.destroyedAmount = -1; + const document = dpp.document.create(dataContract, identityId, 'destroyFrozenFunds', rawDestroyFrozenFundsDocument); + const validationResult = document.validate(dpp.protocolVersion); + const error = expectJsonSchemaError(validationResult); + expect(error.keyword).to.equal('minimum'); + }); + }); + + it('should not have additional properties', async () => { + rawDestroyFrozenFundsDocument.bar = 123; + const document = dpp.document.create(dataContract, identityId, 'destroyFrozenFunds', rawDestroyFrozenFundsDocument); + const validationResult = document.validate(dpp.protocolVersion); + const error = expectJsonSchemaError(validationResult); + expect(error.keyword).to.equal('additionalProperties'); + expect(error.params.additionalProperties).to.deep.equal(['bar']); + }); + + it('should be valid', async () => { + const document = dpp.document.create(dataContract, identityId, 'destroyFrozenFunds', rawDestroyFrozenFundsDocument); + const validationResult = await document.validate(dpp.protocolVersion); + expect(validationResult.isValid()).to.be.true(); + }); + }); + + describe('emergencyAction', () => { + let rawEmergencyActionDocument; + + beforeEach(() => { + rawEmergencyActionDocument = { + tokenId: crypto.randomBytes(32), + action: 1, + }; + }); + + describe('tokenId', () => { + it('should be defined', async () => { + delete rawEmergencyActionDocument.tokenId; + const document = dpp.document.create(dataContract, identityId, 'emergencyAction', rawEmergencyActionDocument); + const validationResult = document.validate(dpp.protocolVersion); + const error = expectJsonSchemaError(validationResult); + expect(error.keyword).to.equal('required'); + expect(error.params.missingProperty).to.equal('tokenId'); + }); + }); + + describe('action', () => { + it('should be non-negative', async () => { + rawEmergencyActionDocument.action = -5; + const document = dpp.document.create(dataContract, identityId, 'emergencyAction', rawEmergencyActionDocument); + const validationResult = document.validate(dpp.protocolVersion); + const error = expectJsonSchemaError(validationResult); + expect(error.keyword).to.equal('enum'); + }); + }); + + it('should not have additional properties', async () => { + rawEmergencyActionDocument.xyz = 999; + const document = dpp.document.create(dataContract, identityId, 'emergencyAction', rawEmergencyActionDocument); + const validationResult = document.validate(dpp.protocolVersion); + const error = expectJsonSchemaError(validationResult); + expect(error.keyword).to.equal('additionalProperties'); + expect(error.params.additionalProperties).to.deep.equal(['xyz']); + }); + + it('should be valid', async () => { + const document = dpp.document.create(dataContract, identityId, 'emergencyAction', rawEmergencyActionDocument); + const validationResult = await document.validate(dpp.protocolVersion); + expect(validationResult.isValid()).to.be.true(); + }); + }); + }); +}); From 5a28c54cdcff9ab3a79550505d60b76e3b91af77 Mon Sep 17 00:00:00 2001 From: Ivan Shumkov Date: Sun, 30 Mar 2025 18:32:56 +0700 Subject: [PATCH 6/6] chore: remove canceled status --- packages/token-marketplace-contract/schema/v1/documents.json | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/token-marketplace-contract/schema/v1/documents.json b/packages/token-marketplace-contract/schema/v1/documents.json index 912adbacb20..b1b63395c15 100644 --- a/packages/token-marketplace-contract/schema/v1/documents.json +++ b/packages/token-marketplace-contract/schema/v1/documents.json @@ -53,11 +53,10 @@ }, "status": { "type": "integer", - "description": "The status of order: 0 - open, 1 - complete, 2 - canceled", + "description": "The status of order: 0 - open, 1 - complete", "enum": [ 0, - 1, - 2, + 1 ], "position": 1 },