Skip to content

Commit a86c523

Browse files
feat(platform): transfer to frozen account is allowed (#2478)
Co-authored-by: QuantumExplorer <quantum@dash.org>
1 parent 9032b11 commit a86c523

File tree

9 files changed

+308
-11
lines changed
  • packages
    • rs-dpp/src/data_contract/associated_token/token_configuration
    • rs-drive-abci
      • src/execution
        • platform_events/initialization/create_genesis_state/test
        • validation/state_transition/state_transitions/batch
          • action_validation/token
            • token_mint_transition_action/state_v0
            • token_transfer_transition_action/state_v0
          • tests/token
      • tests/strategy_tests

9 files changed

+308
-11
lines changed

packages/rs-dpp/src/data_contract/associated_token/token_configuration/accessors/mod.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,12 @@ impl TokenConfigurationV0Getters for TokenConfiguration {
5656
}
5757
}
5858

59+
fn is_allowed_transfer_to_frozen_balance(&self) -> bool {
60+
match self {
61+
TokenConfiguration::V0(v0) => v0.is_allowed_transfer_to_frozen_balance(),
62+
}
63+
}
64+
5965
/// Returns the maximum supply.
6066
fn max_supply(&self) -> Option<TokenAmount> {
6167
match self {
@@ -167,6 +173,13 @@ impl TokenConfigurationV0Setters for TokenConfiguration {
167173
}
168174
}
169175

176+
/// Allow or not a transfer and mint tokens to frozen identity token balances
177+
fn allow_transfer_to_frozen_balance(&mut self, allow: bool) {
178+
match self {
179+
TokenConfiguration::V0(v0) => v0.allow_transfer_to_frozen_balance(allow),
180+
}
181+
}
182+
170183
/// Sets the base supply.
171184
fn set_base_supply(&mut self, base_supply: u64) {
172185
match self {

packages/rs-dpp/src/data_contract/associated_token/token_configuration/accessors/v0/mod.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ pub trait TokenConfigurationV0Getters {
2727
/// Returns if we start as paused.
2828
fn start_as_paused(&self) -> bool;
2929

30+
/// Allow to transfer and mint tokens to frozen identity token balances
31+
fn is_allowed_transfer_to_frozen_balance(&self) -> bool;
32+
3033
/// Returns the maximum supply.
3134
fn max_supply(&self) -> Option<TokenAmount>;
3235

@@ -78,6 +81,9 @@ pub trait TokenConfigurationV0Setters {
7881
/// Sets the conventions change rules.
7982
fn set_conventions_change_rules(&mut self, rules: ChangeControlRules);
8083

84+
/// Allow or not a transfer and mint tokens to frozen identity token balances
85+
fn allow_transfer_to_frozen_balance(&mut self, allow: bool);
86+
8187
/// Sets the base supply.
8288
fn set_base_supply(&mut self, base_supply: TokenAmount);
8389

packages/rs-dpp/src/data_contract/associated_token/token_configuration/v0/accessors.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,11 @@ impl TokenConfigurationV0Getters for TokenConfigurationV0 {
4545
self.start_as_paused
4646
}
4747

48+
/// Allow to transfer and mint tokens to frozen identity token balances
49+
fn is_allowed_transfer_to_frozen_balance(&self) -> bool {
50+
self.allow_transfer_to_frozen_balance
51+
}
52+
4853
/// Returns the maximum supply.
4954
fn max_supply(&self) -> Option<TokenAmount> {
5055
self.max_supply
@@ -168,6 +173,11 @@ impl TokenConfigurationV0Setters for TokenConfigurationV0 {
168173
self.conventions_change_rules = rules;
169174
}
170175

176+
/// Allow or not a transfer and mint tokens to frozen identity token balances
177+
fn allow_transfer_to_frozen_balance(&mut self, allow: bool) {
178+
self.allow_transfer_to_frozen_balance = allow;
179+
}
180+
171181
/// Sets the base supply.
172182
fn set_base_supply(&mut self, base_supply: TokenAmount) {
173183
self.base_supply = base_supply;

packages/rs-dpp/src/data_contract/associated_token/token_configuration/v0/mod.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ pub struct TokenConfigurationV0 {
3434
/// Do we start off as paused, meaning that we can not transfer till we unpause.
3535
#[serde(default = "default_starts_as_paused")]
3636
pub start_as_paused: bool,
37+
/// Allow to transfer and mint tokens to frozen identity token balances
38+
#[serde(default = "default_allow_transfer_to_frozen_balance")]
39+
pub allow_transfer_to_frozen_balance: bool,
3740
/// Who can change the max supply
3841
/// Even if set no one can ever change this under the base supply
3942
#[serde(default = "default_change_control_rules")]
@@ -71,6 +74,11 @@ fn default_starts_as_paused() -> bool {
7174
false
7275
}
7376

77+
// Default function for `allow_transfer_to_frozen_balance`
78+
fn default_allow_transfer_to_frozen_balance() -> bool {
79+
true
80+
}
81+
7482
fn default_token_keeps_history_rules() -> TokenKeepsHistoryRules {
7583
TokenKeepsHistoryRules::V0(TokenKeepsHistoryRulesV0 {
7684
keeps_transfer_history: true,
@@ -143,13 +151,14 @@ impl fmt::Display for TokenConfigurationV0 {
143151
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
144152
write!(
145153
f,
146-
"TokenConfigurationV0 {{\n conventions: {:?},\n conventions_change_rules: {:?},\n base_supply: {},\n max_supply: {:?},\n keeps_history: {},\n start_as_paused: {},\n max_supply_change_rules: {:?},\n distribution_rules: {},\n manual_minting_rules: {:?},\n manual_burning_rules: {:?},\n freeze_rules: {:?},\n unfreeze_rules: {:?},\n destroy_frozen_funds_rules: {:?},\n emergency_action_rules: {:?},\n main_control_group: {:?},\n main_control_group_can_be_modified: {:?}\n}}",
154+
"TokenConfigurationV0 {{\n conventions: {:?},\n conventions_change_rules: {:?},\n base_supply: {},\n max_supply: {:?},\n keeps_history: {},\n start_as_paused: {},\n allow_transfer_to_frozen_balance: {},\n max_supply_change_rules: {:?},\n distribution_rules: {},\n manual_minting_rules: {:?},\n manual_burning_rules: {:?},\n freeze_rules: {:?},\n unfreeze_rules: {:?},\n destroy_frozen_funds_rules: {:?},\n emergency_action_rules: {:?},\n main_control_group: {:?},\n main_control_group_can_be_modified: {:?}\n}}",
147155
self.conventions,
148156
self.conventions_change_rules,
149157
self.base_supply,
150158
self.max_supply,
151159
self.keeps_history,
152160
self.start_as_paused,
161+
self.allow_transfer_to_frozen_balance,
153162
self.max_supply_change_rules,
154163
self.distribution_rules,
155164
self.manual_minting_rules,
@@ -190,6 +199,7 @@ impl TokenConfigurationV0 {
190199
keeps_direct_purchase_history: true,
191200
}),
192201
start_as_paused: false,
202+
allow_transfer_to_frozen_balance: true,
193203
max_supply_change_rules: ChangeControlRulesV0 {
194204
authorized_to_make_change: AuthorizedActionTakers::NoOne,
195205
admin_action_takers: AuthorizedActionTakers::NoOne,

packages/rs-drive-abci/src/execution/platform_events/initialization/create_genesis_state/test/tokens.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,7 @@ impl<C> Platform<C> {
240240
max_supply: None,
241241
keeps_history: TokenKeepsHistoryRulesV0::default().into(),
242242
start_as_paused: false,
243+
allow_transfer_to_frozen_balance: true,
243244
max_supply_change_rules: ChangeControlRulesV0::default().into(),
244245
distribution_rules: TokenDistributionRulesV0 {
245246
perpetual_distribution: None,

packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_mint_transition_action/state_v0/mod.rs

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,18 @@ use dpp::block::block_info::BlockInfo;
22
use dpp::consensus::ConsensusError;
33
use dpp::consensus::state::identity::RecipientIdentityDoesNotExistError;
44
use dpp::consensus::state::state_error::StateError;
5-
use dpp::consensus::state::token::TokenMintPastMaxSupplyError;
5+
use dpp::consensus::state::token::{IdentityTokenAccountFrozenError, TokenMintPastMaxSupplyError};
66
use dpp::data_contract::accessors::v0::DataContractV0Getters;
77
use dpp::data_contract::accessors::v1::DataContractV1Getters;
88
use dpp::data_contract::associated_token::token_configuration::accessors::v0::TokenConfigurationV0Getters;
99
use dpp::prelude::Identifier;
10+
use dpp::tokens::info::v0::IdentityTokenInfoV0Accessors;
1011
use dpp::validation::SimpleConsensusValidationResult;
1112
use drive::state_transition_action::batch::batched_transition::token_transition::token_mint_transition_action::{TokenMintTransitionAction, TokenMintTransitionActionAccessorsV0};
1213
use dpp::version::PlatformVersion;
1314
use drive::error::drive::DriveError;
1415
use drive::query::TransactionArg;
16+
use drive::state_transition_action::batch::batched_transition::token_transition::token_base_transition_action::TokenBaseTransitionActionAccessorsV0;
1517
use crate::error::Error;
1618
use crate::execution::types::execution_operation::{RetrieveIdentityInfo, ValidationOperation};
1719
use crate::execution::types::state_transition_execution_context::{StateTransitionExecutionContext, StateTransitionExecutionContextMethodsV0};
@@ -142,6 +144,39 @@ impl TokenMintTransitionActionStateValidationV0 for TokenMintTransitionAction {
142144
}
143145
}
144146

147+
// We need to verify that account we are transferring to not frozen
148+
if !self
149+
.base()
150+
.token_configuration()?
151+
.is_allowed_transfer_to_frozen_balance()
152+
{
153+
let (info, fee_result) = platform.drive.fetch_identity_token_info_with_costs(
154+
self.token_id().to_buffer(),
155+
recipient.to_buffer(),
156+
block_info,
157+
true,
158+
transaction,
159+
platform_version,
160+
)?;
161+
162+
execution_context
163+
.add_operation(ValidationOperation::PrecalculatedOperation(fee_result));
164+
165+
if let Some(info) = info {
166+
if info.frozen() {
167+
return Ok(SimpleConsensusValidationResult::new_with_error(
168+
ConsensusError::StateError(StateError::IdentityTokenAccountFrozenError(
169+
IdentityTokenAccountFrozenError::new(
170+
self.token_id(),
171+
recipient,
172+
"mint".to_string(),
173+
),
174+
)),
175+
));
176+
}
177+
};
178+
}
179+
145180
Ok(SimpleConsensusValidationResult::new())
146181
}
147182
}

packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_transfer_transition_action/state_v0/mod.rs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,15 @@ use dpp::block::block_info::BlockInfo;
22
use dpp::consensus::ConsensusError;
33
use dpp::consensus::state::state_error::StateError;
44
use dpp::consensus::state::token::{IdentityDoesNotHaveEnoughTokenBalanceError, IdentityTokenAccountFrozenError, TokenIsPausedError, TokenTransferRecipientIdentityNotExistError};
5+
use dpp::data_contract::associated_token::token_configuration::accessors::v0::TokenConfigurationV0Getters;
56
use dpp::prelude::Identifier;
67
use dpp::tokens::info::v0::IdentityTokenInfoV0Accessors;
78
use dpp::tokens::status::v0::TokenStatusV0Accessors;
89
use dpp::validation::SimpleConsensusValidationResult;
910
use drive::state_transition_action::batch::batched_transition::token_transition::token_transfer_transition_action::TokenTransferTransitionAction;
1011
use dpp::version::PlatformVersion;
1112
use drive::query::TransactionArg;
13+
use drive::state_transition_action::batch::batched_transition::token_transition::token_base_transition_action::TokenBaseTransitionActionAccessorsV0;
1214
use drive::state_transition_action::batch::batched_transition::token_transition::token_transfer_transition_action::v0::TokenTransferTransitionActionAccessorsV0;
1315
use crate::error::Error;
1416
use crate::execution::types::execution_operation::ValidationOperation;
@@ -78,6 +80,7 @@ impl TokenTransferTransitionActionStateValidationV0 for TokenTransferTransitionA
7880
}
7981

8082
// We need to verify that our token account is not frozen
83+
8184
let (info, fee_result) = platform.drive.fetch_identity_token_info_with_costs(
8285
self.token_id().to_buffer(),
8386
owner_id.to_buffer(),
@@ -103,6 +106,39 @@ impl TokenTransferTransitionActionStateValidationV0 for TokenTransferTransitionA
103106
}
104107
};
105108

109+
// We need to verify that account we are transferring to not frozen
110+
if !self
111+
.base()
112+
.token_configuration()?
113+
.is_allowed_transfer_to_frozen_balance()
114+
{
115+
let (info, fee_result) = platform.drive.fetch_identity_token_info_with_costs(
116+
self.token_id().to_buffer(),
117+
self.recipient_id().to_buffer(),
118+
block_info,
119+
true,
120+
transaction,
121+
platform_version,
122+
)?;
123+
124+
execution_context
125+
.add_operation(ValidationOperation::PrecalculatedOperation(fee_result));
126+
127+
if let Some(info) = info {
128+
if info.frozen() {
129+
return Ok(SimpleConsensusValidationResult::new_with_error(
130+
ConsensusError::StateError(StateError::IdentityTokenAccountFrozenError(
131+
IdentityTokenAccountFrozenError::new(
132+
self.token_id(),
133+
self.recipient_id(),
134+
"transfer".to_string(),
135+
),
136+
)),
137+
));
138+
}
139+
};
140+
}
141+
106142
// We need to verify that the token is not paused
107143
let (token_status, fee_result) = platform.drive.fetch_token_status_with_costs(
108144
self.token_id().to_buffer(),

0 commit comments

Comments
 (0)