Skip to content
Merged
3 changes: 3 additions & 0 deletions packages/rs-dpp/src/errors/consensus/codes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,9 @@ impl ErrorWithCode for StateError {
Self::NewAuthorizedActionTakerMainGroupNotSetError(_) => 40159,
Self::InvalidGroupPositionError(_) => 40160,
Self::TokenIsPausedError(_) => 40161,
Self::IdentityTokenAccountAlreadyFrozenError(_) => 40162,
Self::TokenAlreadyPausedError(_) => 40163,
Self::TokenNotPausedError(_) => 40164,

// Identity Errors: 40200-40299
Self::IdentityAlreadyExistsError(_) => 40200,
Expand Down
14 changes: 12 additions & 2 deletions packages/rs-dpp/src/errors/consensus/state/state_error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,9 @@ use crate::consensus::state::identity::missing_transfer_key_error::MissingTransf
use crate::consensus::state::identity::no_transfer_key_for_core_withdrawal_available_error::NoTransferKeyForCoreWithdrawalAvailableError;
use crate::consensus::state::prefunded_specialized_balances::prefunded_specialized_balance_insufficient_error::PrefundedSpecializedBalanceInsufficientError;
use crate::consensus::state::prefunded_specialized_balances::prefunded_specialized_balance_not_found_error::PrefundedSpecializedBalanceNotFoundError;
use crate::consensus::state::token::{IdentityDoesNotHaveEnoughTokenBalanceError, IdentityTokenAccountFrozenError, IdentityTokenAccountNotFrozenError, InvalidGroupPositionError, NewAuthorizedActionTakerGroupDoesNotExistError, NewAuthorizedActionTakerIdentityDoesNotExistError, NewAuthorizedActionTakerMainGroupNotSetError, NewTokensDestinationIdentityDoesNotExistError, TokenMintPastMaxSupplyError, TokenSettingMaxSupplyToLessThanCurrentSupplyError, UnauthorizedTokenActionError};
use crate::consensus::state::token::{IdentityDoesNotHaveEnoughTokenBalanceError, IdentityTokenAccountFrozenError, IdentityTokenAccountNotFrozenError, InvalidGroupPositionError, NewAuthorizedActionTakerGroupDoesNotExistError, NewAuthorizedActionTakerIdentityDoesNotExistError, NewAuthorizedActionTakerMainGroupNotSetError, NewTokensDestinationIdentityDoesNotExistError, TokenMintPastMaxSupplyError, TokenSettingMaxSupplyToLessThanCurrentSupplyError, UnauthorizedTokenActionError, IdentityTokenAccountAlreadyFrozenError, TokenAlreadyPausedError, TokenIsPausedError,
TokenNotPausedError,
};
use crate::consensus::state::voting::masternode_incorrect_voter_identity_id_error::MasternodeIncorrectVoterIdentityIdError;
use crate::consensus::state::voting::masternode_incorrect_voting_address_error::MasternodeIncorrectVotingAddressError;
use crate::consensus::state::voting::masternode_not_found_error::MasternodeNotFoundError;
Expand All @@ -52,7 +54,6 @@ 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,
Expand Down Expand Up @@ -259,6 +260,15 @@ pub enum StateError {

#[error(transparent)]
TokenIsPausedError(TokenIsPausedError),

#[error(transparent)]
IdentityTokenAccountAlreadyFrozenError(IdentityTokenAccountAlreadyFrozenError),

#[error(transparent)]
TokenAlreadyPausedError(TokenAlreadyPausedError),

#[error(transparent)]
TokenNotPausedError(TokenNotPausedError),
}

impl From<StateError> for ConsensusError {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
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(
"Identity {} account is already frozen for token {}. Action attempted: {}",
identity_id,
token_id,
action
)]
#[platform_serialize(unversioned)]
pub struct IdentityTokenAccountAlreadyFrozenError {
token_id: Identifier,
identity_id: Identifier,
action: String,
}

impl IdentityTokenAccountAlreadyFrozenError {
pub fn new(token_id: Identifier, identity_id: Identifier, action: String) -> Self {
Self {
token_id,
identity_id,
action,
}
}

pub fn token_id(&self) -> &Identifier {
&self.token_id
}

pub fn identity_id(&self) -> &Identifier {
&self.identity_id
}

pub fn action(&self) -> &str {
&self.action
}
}

impl From<IdentityTokenAccountAlreadyFrozenError> for ConsensusError {
fn from(err: IdentityTokenAccountAlreadyFrozenError) -> Self {
Self::StateError(StateError::IdentityTokenAccountAlreadyFrozenError(err))
}
}
6 changes: 6 additions & 0 deletions packages/rs-dpp/src/errors/consensus/state/token/mod.rs
Original file line number Diff line number Diff line change
@@ -1,25 +1,31 @@
mod identity_does_not_have_enough_token_balance_error;
mod identity_token_account_already_frozen_error;
mod identity_token_account_frozen_error;
mod identity_token_account_not_frozen_error;
mod invalid_group_position_error;
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_already_paused_error;
mod token_is_paused_error;
mod token_mint_past_max_supply_error;
mod token_not_paused_error;
mod token_setting_max_supply_to_less_than_current_supply_error;
mod unauthorized_token_action_error;

pub use identity_does_not_have_enough_token_balance_error::*;
pub use identity_token_account_already_frozen_error::*;
pub use identity_token_account_frozen_error::*;
pub use identity_token_account_not_frozen_error::*;
pub use invalid_group_position_error::*;
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_already_paused_error::*;
pub use token_is_paused_error::*;
pub use token_mint_past_max_supply_error::*;
pub use token_not_paused_error::*;
pub use token_setting_max_supply_to_less_than_current_supply_error::*;
pub use unauthorized_token_action_error::*;
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
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 already paused. Action attempted: {}", token_id, action)]
#[platform_serialize(unversioned)]
pub struct TokenAlreadyPausedError {
token_id: Identifier,
action: String,
}

impl TokenAlreadyPausedError {
pub fn new(token_id: Identifier, action: String) -> Self {
Self { token_id, action }
}

pub fn token_id(&self) -> &Identifier {
&self.token_id
}

pub fn action(&self) -> &str {
&self.action
}
}

impl From<TokenAlreadyPausedError> for ConsensusError {
fn from(err: TokenAlreadyPausedError) -> Self {
Self::StateError(StateError::TokenAlreadyPausedError(err))
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
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 not paused. Action attempted: {}", token_id, action)]
#[platform_serialize(unversioned)]
pub struct TokenNotPausedError {
token_id: Identifier,
action: String,
}

impl TokenNotPausedError {
pub fn new(token_id: Identifier, action: String) -> Self {
Self { token_id, action }
}

pub fn token_id(&self) -> &Identifier {
&self.token_id
}

pub fn action(&self) -> &str {
&self.action
}
}

impl From<TokenNotPausedError> for ConsensusError {
fn from(err: TokenNotPausedError) -> Self {
Self::StateError(StateError::TokenNotPausedError(err))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ pub struct TokenFreezeTransitionV0 {
feature = "state-transition-serde-conversion",
serde(rename = "frozenIdentityId")
)]
pub frozen_identity_id: Identifier,
pub identity_to_freeze_id: Identifier,
/// The public note
#[cfg_attr(
feature = "state-transition-serde-conversion",
Expand All @@ -37,6 +37,10 @@ pub struct TokenFreezeTransitionV0 {
impl fmt::Display for TokenFreezeTransitionV0 {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
// Format the base transition (assuming `TokenBaseTransition` implements Display)
write!(f, "Base: {}, Froze: {}", self.base, self.frozen_identity_id)
write!(
f,
"Base: {}, Froze: {}",
self.base, self.identity_to_freeze_id
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -53,18 +53,18 @@ impl TokenFreezeTransitionV0Methods for TokenFreezeTransitionV0 {
}

fn frozen_identity_id(&self) -> Identifier {
self.frozen_identity_id
self.identity_to_freeze_id
}
fn set_frozen_identity_id(&mut self, frozen_identity_id: Identifier) {
self.frozen_identity_id = frozen_identity_id;
self.identity_to_freeze_id = frozen_identity_id;
}
}

impl AllowedAsMultiPartyAction for TokenFreezeTransitionV0 {
fn calculate_action_id(&self, owner_id: Identifier) -> Identifier {
let TokenFreezeTransitionV0 {
base,
frozen_identity_id,
identity_to_freeze_id: frozen_identity_id,
..
} = self;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -651,7 +651,7 @@ impl DocumentsBatchTransitionMethodsV1 for BatchTransitionV1 {
token_id,
using_group_info: None,
}),
frozen_identity_id,
identity_to_freeze_id: frozen_identity_id,
public_note,
});

Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,20 @@
use dpp::block::block_info::BlockInfo;
use dpp::consensus::state::state_error::StateError;
use dpp::consensus::state::token::{TokenAlreadyPausedError, TokenNotPausedError};
use dpp::consensus::ConsensusError;
use dpp::data_contract::accessors::v0::DataContractV0Getters;
use dpp::data_contract::accessors::v1::DataContractV1Getters;
use dpp::data_contract::associated_token::token_configuration::accessors::v0::TokenConfigurationV0Getters;
use dpp::prelude::Identifier;
use dpp::tokens::emergency_action::TokenEmergencyAction;
use dpp::tokens::status::v0::TokenStatusV0Accessors;
use dpp::validation::SimpleConsensusValidationResult;
use drive::state_transition_action::batch::batched_transition::token_transition::token_emergency_action_transition_action::{TokenEmergencyActionTransitionAction, TokenEmergencyActionTransitionActionAccessorsV0};
use dpp::version::PlatformVersion;
use drive::query::TransactionArg;
use crate::error::Error;
use crate::execution::types::state_transition_execution_context::StateTransitionExecutionContext;
use crate::execution::types::execution_operation::ValidationOperation;
use crate::execution::types::state_transition_execution_context::{StateTransitionExecutionContext, StateTransitionExecutionContextMethodsV0};
use crate::execution::validation::state_transition::batch::action_validation::token::token_base_transition_action::TokenBaseTransitionActionValidation;
use crate::platform_types::platform::PlatformStateRef;

Expand Down Expand Up @@ -66,6 +72,44 @@ impl TokenEmergencyActionTransitionActionStateValidationV0
return Ok(validation_result);
}

// Check if we are paused
let (maybe_token_status, fee_result) = platform.drive.fetch_token_status_with_costs(
Comment thread
shumkov marked this conversation as resolved.
self.token_id().to_buffer(),
block_info,
true,
transaction,
platform_version,
)?;
execution_context.add_operation(ValidationOperation::PrecalculatedOperation(fee_result));
if let Some(token_status) = maybe_token_status {
match self.emergency_action() {
TokenEmergencyAction::Pause => {
if token_status.paused() {
return Ok(SimpleConsensusValidationResult::new_with_error(
ConsensusError::StateError(StateError::TokenAlreadyPausedError(
TokenAlreadyPausedError::new(
self.token_id(),
"Pause Token".to_string(),
),
)),
));
}
}
TokenEmergencyAction::Resume => {
if !token_status.paused() {
return Ok(SimpleConsensusValidationResult::new_with_error(
ConsensusError::StateError(StateError::TokenNotPausedError(
TokenNotPausedError::new(
self.token_id(),
"Resume Token".to_string(),
),
)),
));
}
}
}
}

Ok(SimpleConsensusValidationResult::new())
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
use dpp::block::block_info::BlockInfo;
use dpp::consensus::state::state_error::StateError;
use dpp::consensus::state::token::IdentityTokenAccountAlreadyFrozenError;
use dpp::data_contract::accessors::v0::DataContractV0Getters;
use dpp::data_contract::accessors::v1::DataContractV1Getters;
use dpp::data_contract::associated_token::token_configuration::accessors::v0::TokenConfigurationV0Getters;
Expand All @@ -12,6 +14,11 @@ use crate::execution::types::state_transition_execution_context::StateTransition
use crate::execution::validation::state_transition::batch::action_validation::token::token_base_transition_action::TokenBaseTransitionActionValidation;
use crate::platform_types::platform::PlatformStateRef;

use crate::execution::types::execution_operation::ValidationOperation;
use crate::execution::types::state_transition_execution_context::StateTransitionExecutionContextMethodsV0;
use dpp::consensus::ConsensusError;
use dpp::tokens::info::v0::IdentityTokenInfoV0Accessors;

pub(in crate::execution::validation::state_transition::state_transitions::batch::action_validation) trait TokenFreezeTransitionActionStateValidationV0 {
fn validate_state_v0(
&self,
Expand All @@ -23,6 +30,7 @@ pub(in crate::execution::validation::state_transition::state_transitions::batch:
platform_version: &PlatformVersion,
) -> Result<SimpleConsensusValidationResult, Error>;
}

impl TokenFreezeTransitionActionStateValidationV0 for TokenFreezeTransitionAction {
fn validate_state_v0(
&self,
Expand Down Expand Up @@ -64,6 +72,30 @@ impl TokenFreezeTransitionActionStateValidationV0 for TokenFreezeTransitionActio
return Ok(validation_result);
}

// Check if the identity is already frozen
let (info, fee_result) = platform.drive.fetch_identity_token_info_with_costs(
Comment thread
shumkov marked this conversation as resolved.
self.token_id().to_buffer(),
self.identity_to_freeze_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() {
return Ok(SimpleConsensusValidationResult::new_with_error(
ConsensusError::StateError(StateError::IdentityTokenAccountAlreadyFrozenError(
IdentityTokenAccountAlreadyFrozenError::new(
self.token_id(),
owner_id,
"Freeze Identity Token Account".to_string(),
),
)),
));
}
};

Ok(SimpleConsensusValidationResult::new())
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ impl TokenTransferTransitionActionStateValidationV0 for TokenTransferTransitionA
)?;
execution_context.add_operation(ValidationOperation::PrecalculatedOperation(fee_result));
if let Some(info) = info {
if info.frozen() == true {
if info.frozen() {
return Ok(SimpleConsensusValidationResult::new_with_error(
ConsensusError::StateError(StateError::IdentityTokenAccountFrozenError(
IdentityTokenAccountFrozenError::new(
Expand Down
Loading