From 9026669553f4e427cb6c820e4e3c6ad351c54ff3 Mon Sep 17 00:00:00 2001 From: pauldelucia Date: Thu, 13 Feb 2025 13:41:19 +0700 Subject: [PATCH 1/2] feat: check if token is paused on token transfers --- packages/rs-dpp/src/errors/consensus/codes.rs | 1 + .../src/errors/consensus/state/state_error.rs | 4 +++ .../src/errors/consensus/state/token/mod.rs | 2 ++ .../state/token/token_is_paused_error.rs | 32 +++++++++++++++++++ .../state_v0/mod.rs | 25 +++++++++++---- .../src/errors/consensus/consensus_error.rs | 3 +- 6 files changed, 60 insertions(+), 7 deletions(-) create mode 100644 packages/rs-dpp/src/errors/consensus/state/token/token_is_paused_error.rs diff --git a/packages/rs-dpp/src/errors/consensus/codes.rs b/packages/rs-dpp/src/errors/consensus/codes.rs index 9f1d7b7c626..fa1583ea088 100644 --- a/packages/rs-dpp/src/errors/consensus/codes.rs +++ b/packages/rs-dpp/src/errors/consensus/codes.rs @@ -254,6 +254,7 @@ impl ErrorWithCode for StateError { Self::NewAuthorizedActionTakerGroupDoesNotExistError(_) => 40158, Self::NewAuthorizedActionTakerMainGroupNotSetError(_) => 40159, Self::InvalidGroupPositionError(_) => 40160, + Self::TokenIsPausedError(_) => 40161, // Identity Errors: 40200-40299 Self::IdentityAlreadyExistsError(_) => 40200, diff --git a/packages/rs-dpp/src/errors/consensus/state/state_error.rs b/packages/rs-dpp/src/errors/consensus/state/state_error.rs index e76d6b2c5b3..d373725981b 100644 --- a/packages/rs-dpp/src/errors/consensus/state/state_error.rs +++ b/packages/rs-dpp/src/errors/consensus/state/state_error.rs @@ -52,6 +52,7 @@ use crate::consensus::state::voting::vote_poll_not_available_for_voting_error::V use crate::consensus::state::voting::vote_poll_not_found_error::VotePollNotFoundError; use super::document::document_timestamps_are_equal_error::DocumentTimestampsAreEqualError; +use super::token::TokenIsPausedError; #[derive( Error, Debug, PartialEq, Encode, Decode, PlatformSerialize, PlatformDeserialize, Clone, @@ -255,6 +256,9 @@ pub enum StateError { #[error(transparent)] InvalidGroupPositionError(InvalidGroupPositionError), + + #[error(transparent)] + TokenIsPausedError(TokenIsPausedError), } impl From for ConsensusError { diff --git a/packages/rs-dpp/src/errors/consensus/state/token/mod.rs b/packages/rs-dpp/src/errors/consensus/state/token/mod.rs index f28964addf7..9c2a5401ae8 100644 --- a/packages/rs-dpp/src/errors/consensus/state/token/mod.rs +++ b/packages/rs-dpp/src/errors/consensus/state/token/mod.rs @@ -6,6 +6,7 @@ mod new_authorized_action_taker_group_does_not_exist_error; mod new_authorized_action_taker_identity_does_not_exist_error; mod new_authorized_action_taker_main_group_not_set_error; mod new_tokens_destination_identity_does_not_exist_error; +mod token_is_paused_error; mod token_mint_past_max_supply_error; mod token_setting_max_supply_to_less_than_current_supply_error; mod unauthorized_token_action_error; @@ -18,6 +19,7 @@ pub use new_authorized_action_taker_group_does_not_exist_error::*; pub use new_authorized_action_taker_identity_does_not_exist_error::*; pub use new_authorized_action_taker_main_group_not_set_error::*; pub use new_tokens_destination_identity_does_not_exist_error::*; +pub use token_is_paused_error::*; pub use token_mint_past_max_supply_error::*; pub use token_setting_max_supply_to_less_than_current_supply_error::*; pub use unauthorized_token_action_error::*; diff --git a/packages/rs-dpp/src/errors/consensus/state/token/token_is_paused_error.rs b/packages/rs-dpp/src/errors/consensus/state/token/token_is_paused_error.rs new file mode 100644 index 00000000000..5681940847f --- /dev/null +++ b/packages/rs-dpp/src/errors/consensus/state/token/token_is_paused_error.rs @@ -0,0 +1,32 @@ +use crate::consensus::state::state_error::StateError; +use crate::consensus::ConsensusError; +use crate::ProtocolError; +use bincode::{Decode, Encode}; +use platform_serialization_derive::{PlatformDeserialize, PlatformSerialize}; +use platform_value::Identifier; +use thiserror::Error; + +#[derive( + Error, Debug, Clone, PartialEq, Eq, Encode, Decode, PlatformSerialize, PlatformDeserialize, +)] +#[error("Token {} is paused.", token_id)] +#[platform_serialize(unversioned)] +pub struct TokenIsPausedError { + token_id: Identifier, +} + +impl TokenIsPausedError { + pub fn new(token_id: Identifier) -> Self { + Self { token_id } + } + + pub fn token_id(&self) -> &Identifier { + &self.token_id + } +} + +impl From for ConsensusError { + fn from(err: TokenIsPausedError) -> Self { + Self::StateError(StateError::TokenIsPausedError(err)) + } +} diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_transfer_transition_action/state_v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_transfer_transition_action/state_v0/mod.rs index a40b0f30401..d35b018a405 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_transfer_transition_action/state_v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_transfer_transition_action/state_v0/mod.rs @@ -1,11 +1,12 @@ use dpp::block::block_info::BlockInfo; use dpp::consensus::ConsensusError; use dpp::consensus::state::state_error::StateError; -use dpp::consensus::state::token::{IdentityDoesNotHaveEnoughTokenBalanceError, IdentityTokenAccountFrozenError}; +use dpp::consensus::state::token::{IdentityDoesNotHaveEnoughTokenBalanceError, IdentityTokenAccountFrozenError, TokenIsPausedError}; use dpp::prelude::Identifier; use dpp::tokens::info::v0::IdentityTokenInfoV0Accessors; +use dpp::tokens::status::v0::TokenStatusV0Accessors; use dpp::validation::SimpleConsensusValidationResult; -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_transfer_transition_action::TokenTransferTransitionAction; use dpp::version::PlatformVersion; use drive::query::TransactionArg; use drive::state_transition_action::batch::batched_transition::token_transition::token_transfer_transition_action::v0::TokenTransferTransitionActionAccessorsV0; @@ -60,7 +61,6 @@ impl TokenTransferTransitionActionStateValidationV0 for TokenTransferTransitionA .unwrap_or_default(); execution_context.add_operation(ValidationOperation::RetrieveIdentityTokenBalance); if balance < self.amount() { - // The identity does not exist return Ok(SimpleConsensusValidationResult::new_with_error( ConsensusError::StateError(StateError::IdentityDoesNotHaveEnoughTokenBalanceError( IdentityDoesNotHaveEnoughTokenBalanceError::new( @@ -75,8 +75,6 @@ impl TokenTransferTransitionActionStateValidationV0 for TokenTransferTransitionA } // We need to verify that our token account is not frozen - - // We need to verify that we have enough of the token let info = platform.drive.fetch_identity_token_info( self.token_id().to_buffer(), owner_id.to_buffer(), @@ -84,7 +82,6 @@ impl TokenTransferTransitionActionStateValidationV0 for TokenTransferTransitionA platform_version, )?; if let Some(info) = info { - // We have an info, we need to check that we are not frozen if info.frozen() == true { return Ok(SimpleConsensusValidationResult::new_with_error( ConsensusError::StateError(StateError::IdentityTokenAccountFrozenError( @@ -98,6 +95,22 @@ impl TokenTransferTransitionActionStateValidationV0 for TokenTransferTransitionA } }; + // We need to verify that the token is not paused + let token_status = platform.drive.fetch_token_status( + self.token_id().to_buffer(), + transaction, + platform_version, + )?; + if let Some(status) = token_status { + if status.paused() { + return Ok(SimpleConsensusValidationResult::new_with_error( + ConsensusError::StateError(StateError::TokenIsPausedError( + TokenIsPausedError::new(self.token_id()), + )), + )); + } + } + Ok(SimpleConsensusValidationResult::new()) } } diff --git a/packages/wasm-dpp/src/errors/consensus/consensus_error.rs b/packages/wasm-dpp/src/errors/consensus/consensus_error.rs index 67cc9a39f27..936eb1c4e73 100644 --- a/packages/wasm-dpp/src/errors/consensus/consensus_error.rs +++ b/packages/wasm-dpp/src/errors/consensus/consensus_error.rs @@ -84,7 +84,7 @@ use dpp::consensus::state::identity::no_transfer_key_for_core_withdrawal_availab use dpp::consensus::state::identity::RecipientIdentityDoesNotExistError; use dpp::consensus::state::prefunded_specialized_balances::prefunded_specialized_balance_insufficient_error::PrefundedSpecializedBalanceInsufficientError; use dpp::consensus::state::prefunded_specialized_balances::prefunded_specialized_balance_not_found_error::PrefundedSpecializedBalanceNotFoundError; -use dpp::consensus::state::token::{IdentityDoesNotHaveEnoughTokenBalanceError, IdentityTokenAccountNotFrozenError, IdentityTokenAccountFrozenError, UnauthorizedTokenActionError, TokenSettingMaxSupplyToLessThanCurrentSupplyError, TokenMintPastMaxSupplyError, NewTokensDestinationIdentityDoesNotExistError, NewAuthorizedActionTakerIdentityDoesNotExistError, NewAuthorizedActionTakerGroupDoesNotExistError, NewAuthorizedActionTakerMainGroupNotSetError, InvalidGroupPositionError}; +use dpp::consensus::state::token::{IdentityDoesNotHaveEnoughTokenBalanceError, IdentityTokenAccountNotFrozenError, IdentityTokenAccountFrozenError, TokenIsPausedError, UnauthorizedTokenActionError, TokenSettingMaxSupplyToLessThanCurrentSupplyError, TokenMintPastMaxSupplyError, NewTokensDestinationIdentityDoesNotExistError, NewAuthorizedActionTakerIdentityDoesNotExistError, NewAuthorizedActionTakerGroupDoesNotExistError, NewAuthorizedActionTakerMainGroupNotSetError, InvalidGroupPositionError}; use dpp::consensus::state::voting::masternode_incorrect_voter_identity_id_error::MasternodeIncorrectVoterIdentityIdError; use dpp::consensus::state::voting::masternode_incorrect_voting_address_error::MasternodeIncorrectVotingAddressError; use dpp::consensus::state::voting::masternode_not_found_error::MasternodeNotFoundError; @@ -326,6 +326,7 @@ pub fn from_state_error(state_error: &StateError) -> JsValue { StateError::IdentityTokenAccountFrozenError(e) => { generic_consensus_error!(IdentityTokenAccountFrozenError, e).into() } + StateError::TokenIsPausedError(e) => generic_consensus_error!(TokenIsPausedError, e).into(), StateError::IdentityNotMemberOfGroupError(e) => { generic_consensus_error!(IdentityNotMemberOfGroupError, e).into() } From 4becf5f4b587e9a90b35ab284de6fc6d384e8a90 Mon Sep 17 00:00:00 2001 From: pauldelucia Date: Thu, 13 Feb 2025 18:34:24 +0700 Subject: [PATCH 2/2] add costs --- .../token_transfer_transition_action/state_v0/mod.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_transfer_transition_action/state_v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_transfer_transition_action/state_v0/mod.rs index d35b018a405..43d272522f1 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_transfer_transition_action/state_v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_transfer_transition_action/state_v0/mod.rs @@ -75,12 +75,15 @@ impl TokenTransferTransitionActionStateValidationV0 for TokenTransferTransitionA } // We need to verify that our token account is not frozen - let info = platform.drive.fetch_identity_token_info( + let (info, fee_result) = platform.drive.fetch_identity_token_info_with_costs( self.token_id().to_buffer(), owner_id.to_buffer(), + block_info, + true, transaction, platform_version, )?; + execution_context.add_operation(ValidationOperation::PrecalculatedOperation(fee_result)); if let Some(info) = info { if info.frozen() == true { return Ok(SimpleConsensusValidationResult::new_with_error( @@ -96,11 +99,14 @@ impl TokenTransferTransitionActionStateValidationV0 for TokenTransferTransitionA }; // We need to verify that the token is not paused - let token_status = platform.drive.fetch_token_status( + let (token_status, fee_result) = platform.drive.fetch_token_status_with_costs( self.token_id().to_buffer(), + block_info, + true, transaction, platform_version, )?; + execution_context.add_operation(ValidationOperation::PrecalculatedOperation(fee_result)); if let Some(status) = token_status { if status.paused() { return Ok(SimpleConsensusValidationResult::new_with_error(