diff --git a/packages/rs-dpp/schema/meta_schemas/document/v0/document-meta.json b/packages/rs-dpp/schema/meta_schemas/document/v0/document-meta.json index 80d20a3f775..5570d74da3c 100644 --- a/packages/rs-dpp/schema/meta_schemas/document/v0/document-meta.json +++ b/packages/rs-dpp/schema/meta_schemas/document/v0/document-meta.json @@ -287,6 +287,50 @@ } } ] + }, + "documentActionTokenCost": { + "type": "object", + "properties": { + "contractId": { + "type": "array", + "contentMediaType": "application/x.dash.dpp.identifier", + "byteArray": true, + "minItems": 32, + "maxItems": 32 + }, + "tokenPosition": { + "type": "integer", + "minimum": 0, + "maximum": 65535 + }, + "amount": { + "type": "integer", + "minimum": 1, + "maximum": 281474976710655 + }, + "effect": { + "type": "integer", + "enum": [ + 0, + 1 + ], + "description": "0 - TransferTokenToContractOwner (default), 1 - Burn" + }, + "gasFeesPaidBy": { + "type": "integer", + "enum": [ + 0, + 1, + 2 + ], + "description": "0 - DocumentOwner (default), 1 - ContractOwner, 2 - PreferContractOwner" + } + }, + "required": [ + "tokenPosition", + "amount" + ], + "additionalProperties": false } }, "properties": { @@ -453,6 +497,30 @@ ], "description": "Key requirements. 0 - Unique Non Replaceable, 1 - Multiple, 2 - Multiple with reference to latest key." }, + "tokenCost": { + "type": "object", + "properties": { + "create": { + "$ref": "#/$defs/documentActionTokenCost" + }, + "replace": { + "$ref": "#/$defs/documentActionTokenCost" + }, + "delete": { + "$ref": "#/$defs/documentActionTokenCost" + }, + "transfer": { + "$ref": "#/$defs/documentActionTokenCost" + }, + "update_price": { + "$ref": "#/$defs/documentActionTokenCost" + }, + "purchase": { + "$ref": "#/$defs/documentActionTokenCost" + } + }, + "additionalProperties": false + }, "properties": { "type": "object", "additionalProperties": { diff --git a/packages/rs-dpp/src/core_types/validator_set/v0/mod.rs b/packages/rs-dpp/src/core_types/validator_set/v0/mod.rs index 0774fe8c74c..8366ab31932 100644 --- a/packages/rs-dpp/src/core_types/validator_set/v0/mod.rs +++ b/packages/rs-dpp/src/core_types/validator_set/v0/mod.rs @@ -9,6 +9,7 @@ use bincode::error::EncodeError; #[cfg(feature = "core-types-serialization")] use bincode::{BorrowDecode, Decode, Encode}; use dashcore::blsful::Bls12381G2Impl; +#[cfg(feature = "core-types-serialization")] use dashcore::hashes::Hash; use dashcore::{ProTxHash, QuorumHash}; use itertools::Itertools; @@ -18,7 +19,7 @@ use std::collections::BTreeMap; use std::fmt; use std::fmt::{Debug, Display, Formatter}; -/// The validator set is only slightly different from a quorum as it does not contain non valid +/// The validator set is only slightly different from a quorum as it does not contain non-valid /// members #[derive(Clone, Eq, PartialEq)] #[cfg_attr( diff --git a/packages/rs-dpp/src/data_contract/document_type/accessors/mod.rs b/packages/rs-dpp/src/data_contract/document_type/accessors/mod.rs index 60cac67e1b9..652439075b6 100644 --- a/packages/rs-dpp/src/data_contract/document_type/accessors/mod.rs +++ b/packages/rs-dpp/src/data_contract/document_type/accessors/mod.rs @@ -8,20 +8,28 @@ use crate::data_contract::document_type::{DocumentType, DocumentTypeMutRef, Docu use platform_value::{Identifier, Value}; -use crate::balances::credits::TokenAmount; use crate::data_contract::document_type::restricted_creation::CreationRestrictionMode; #[cfg(feature = "validation")] use crate::data_contract::document_type::validator::StatelessJsonSchemaLazyValidator; use crate::data_contract::storage_requirements::keys_for_document_type::StorageKeyRequirements; -use crate::data_contract::TokenContractPosition; use crate::document::transfer::Transferable; use crate::identity::SecurityLevel; use crate::nft::TradeMode; +use crate::tokens::token_amount_on_contract_token::DocumentActionTokenCost; use indexmap::IndexMap; use std::collections::{BTreeMap, BTreeSet}; pub use v0::*; pub use v1::*; +impl DocumentTypeV0MutGetters for DocumentType { + fn schema_mut(&mut self) -> &mut Value { + match self { + DocumentType::V0(v0) => v0.schema_mut(), + DocumentType::V1(v1) => v1.schema_mut(), + } + } +} + impl DocumentTypeV0Getters for DocumentType { fn name(&self) -> &String { match self { @@ -195,6 +203,50 @@ impl DocumentTypeV0Setters for DocumentType { } } +impl DocumentTypeV1Setters for DocumentType { + fn set_document_creation_token_cost(&mut self, cost: Option) { + match self { + DocumentType::V0(_) => { /* no-op */ } + DocumentType::V1(v1) => v1.set_document_creation_token_cost(cost), + } + } + + fn set_document_replacement_token_cost(&mut self, cost: Option) { + match self { + DocumentType::V0(_) => { /* no-op */ } + DocumentType::V1(v1) => v1.set_document_replacement_token_cost(cost), + } + } + + fn set_document_deletion_token_cost(&mut self, cost: Option) { + match self { + DocumentType::V0(_) => { /* no-op */ } + DocumentType::V1(v1) => v1.set_document_deletion_token_cost(cost), + } + } + + fn set_document_transfer_token_cost(&mut self, cost: Option) { + match self { + DocumentType::V0(_) => { /* no-op */ } + DocumentType::V1(v1) => v1.set_document_transfer_token_cost(cost), + } + } + + fn set_document_price_update_token_cost(&mut self, cost: Option) { + match self { + DocumentType::V0(_) => { /* no-op */ } + DocumentType::V1(v1) => v1.set_document_price_update_token_cost(cost), + } + } + + fn set_document_purchase_token_cost(&mut self, cost: Option) { + match self { + DocumentType::V0(_) => { /* no-op */ } + DocumentType::V1(v1) => v1.set_document_purchase_token_cost(cost), + } + } +} + impl DocumentTypeV0Getters for DocumentTypeRef<'_> { fn name(&self) -> &String { match self { @@ -532,42 +584,42 @@ impl DocumentTypeV0Setters for DocumentTypeMutRef<'_> { } impl DocumentTypeV1Getters for DocumentType { - fn document_creation_token_cost(&self) -> Option<(TokenContractPosition, TokenAmount)> { + fn document_creation_token_cost(&self) -> Option { match self { DocumentType::V0(_) => None, DocumentType::V1(v1) => v1.document_creation_token_cost(), } } - fn document_replacement_token_cost(&self) -> Option<(TokenContractPosition, TokenAmount)> { + fn document_replacement_token_cost(&self) -> Option { match self { DocumentType::V0(_) => None, DocumentType::V1(v1) => v1.document_replacement_token_cost(), } } - fn document_deletion_token_cost(&self) -> Option<(TokenContractPosition, TokenAmount)> { + fn document_deletion_token_cost(&self) -> Option { match self { DocumentType::V0(_) => None, DocumentType::V1(v1) => v1.document_deletion_token_cost(), } } - fn document_transfer_token_cost(&self) -> Option<(TokenContractPosition, TokenAmount)> { + fn document_transfer_token_cost(&self) -> Option { match self { DocumentType::V0(_) => None, DocumentType::V1(v1) => v1.document_transfer_token_cost(), } } - fn document_update_price_token_cost(&self) -> Option<(TokenContractPosition, TokenAmount)> { + fn document_update_price_token_cost(&self) -> Option { match self { DocumentType::V0(_) => None, DocumentType::V1(v1) => v1.document_update_price_token_cost(), } } - fn document_purchase_token_cost(&self) -> Option<(TokenContractPosition, TokenAmount)> { + fn document_purchase_token_cost(&self) -> Option { match self { DocumentType::V0(_) => None, DocumentType::V1(v1) => v1.document_purchase_token_cost(), @@ -576,42 +628,42 @@ impl DocumentTypeV1Getters for DocumentType { } impl DocumentTypeV1Getters for DocumentTypeRef<'_> { - fn document_creation_token_cost(&self) -> Option<(TokenContractPosition, TokenAmount)> { + fn document_creation_token_cost(&self) -> Option { match self { DocumentTypeRef::V0(_) => None, DocumentTypeRef::V1(v1) => v1.document_creation_token_cost(), } } - fn document_replacement_token_cost(&self) -> Option<(TokenContractPosition, TokenAmount)> { + fn document_replacement_token_cost(&self) -> Option { match self { DocumentTypeRef::V0(_) => None, DocumentTypeRef::V1(v1) => v1.document_replacement_token_cost(), } } - fn document_deletion_token_cost(&self) -> Option<(TokenContractPosition, TokenAmount)> { + fn document_deletion_token_cost(&self) -> Option { match self { DocumentTypeRef::V0(_) => None, DocumentTypeRef::V1(v1) => v1.document_deletion_token_cost(), } } - fn document_transfer_token_cost(&self) -> Option<(TokenContractPosition, TokenAmount)> { + fn document_transfer_token_cost(&self) -> Option { match self { DocumentTypeRef::V0(_) => None, DocumentTypeRef::V1(v1) => v1.document_transfer_token_cost(), } } - fn document_update_price_token_cost(&self) -> Option<(TokenContractPosition, TokenAmount)> { + fn document_update_price_token_cost(&self) -> Option { match self { DocumentTypeRef::V0(_) => None, DocumentTypeRef::V1(v1) => v1.document_update_price_token_cost(), } } - fn document_purchase_token_cost(&self) -> Option<(TokenContractPosition, TokenAmount)> { + fn document_purchase_token_cost(&self) -> Option { match self { DocumentTypeRef::V0(_) => None, DocumentTypeRef::V1(v1) => v1.document_purchase_token_cost(), @@ -620,42 +672,42 @@ impl DocumentTypeV1Getters for DocumentTypeRef<'_> { } impl DocumentTypeV1Getters for DocumentTypeMutRef<'_> { - fn document_creation_token_cost(&self) -> Option<(TokenContractPosition, TokenAmount)> { + fn document_creation_token_cost(&self) -> Option { match self { DocumentTypeMutRef::V0(_) => None, DocumentTypeMutRef::V1(v1) => v1.document_creation_token_cost(), } } - fn document_replacement_token_cost(&self) -> Option<(TokenContractPosition, TokenAmount)> { + fn document_replacement_token_cost(&self) -> Option { match self { DocumentTypeMutRef::V0(_) => None, DocumentTypeMutRef::V1(v1) => v1.document_replacement_token_cost(), } } - fn document_deletion_token_cost(&self) -> Option<(TokenContractPosition, TokenAmount)> { + fn document_deletion_token_cost(&self) -> Option { match self { DocumentTypeMutRef::V0(_) => None, DocumentTypeMutRef::V1(v1) => v1.document_deletion_token_cost(), } } - fn document_transfer_token_cost(&self) -> Option<(TokenContractPosition, TokenAmount)> { + fn document_transfer_token_cost(&self) -> Option { match self { DocumentTypeMutRef::V0(_) => None, DocumentTypeMutRef::V1(v1) => v1.document_transfer_token_cost(), } } - fn document_update_price_token_cost(&self) -> Option<(TokenContractPosition, TokenAmount)> { + fn document_update_price_token_cost(&self) -> Option { match self { DocumentTypeMutRef::V0(_) => None, DocumentTypeMutRef::V1(v1) => v1.document_update_price_token_cost(), } } - fn document_purchase_token_cost(&self) -> Option<(TokenContractPosition, TokenAmount)> { + fn document_purchase_token_cost(&self) -> Option { match self { DocumentTypeMutRef::V0(_) => None, DocumentTypeMutRef::V1(v1) => v1.document_purchase_token_cost(), diff --git a/packages/rs-dpp/src/data_contract/document_type/accessors/v0/mod.rs b/packages/rs-dpp/src/data_contract/document_type/accessors/v0/mod.rs index 5769860f1ae..7aa1da24bfe 100644 --- a/packages/rs-dpp/src/data_contract/document_type/accessors/v0/mod.rs +++ b/packages/rs-dpp/src/data_contract/document_type/accessors/v0/mod.rs @@ -14,6 +14,11 @@ use crate::nft::TradeMode; use indexmap::IndexMap; use std::collections::{BTreeMap, BTreeSet}; +pub trait DocumentTypeV0MutGetters { + /// Gets the schema as mut + fn schema_mut(&mut self) -> &mut Value; +} + pub trait DocumentTypeV0Getters { /// Returns the name of the document type. fn name(&self) -> &String; diff --git a/packages/rs-dpp/src/data_contract/document_type/accessors/v1/mod.rs b/packages/rs-dpp/src/data_contract/document_type/accessors/v1/mod.rs index c05f3a498b4..d908adec2f5 100644 --- a/packages/rs-dpp/src/data_contract/document_type/accessors/v1/mod.rs +++ b/packages/rs-dpp/src/data_contract/document_type/accessors/v1/mod.rs @@ -1,47 +1,85 @@ -use crate::balances::credits::TokenAmount; -use crate::data_contract::TokenContractPosition; +use crate::tokens::token_amount_on_contract_token::DocumentActionTokenCost; /// Trait providing getters for retrieving token costs associated with different document operations. pub trait DocumentTypeV1Getters { /// Returns the token cost associated with document creation, if applicable. /// /// # Returns - /// - `Some((TokenContractPosition, TokenAmount))` if a creation cost exists. + /// - `Some(TokenActionCost)` if a creation cost exists. /// - `None` if no cost is set for document creation. - fn document_creation_token_cost(&self) -> Option<(TokenContractPosition, TokenAmount)>; + fn document_creation_token_cost(&self) -> Option; /// Returns the token cost associated with document replacement (updating), if applicable. /// /// # Returns - /// - `Some((TokenContractPosition, TokenAmount))` if a replacement cost exists. + /// - `Some(TokenActionCost)` if a replacement cost exists. /// - `None` if no cost is set for document replacement. - fn document_replacement_token_cost(&self) -> Option<(TokenContractPosition, TokenAmount)>; + fn document_replacement_token_cost(&self) -> Option; /// Returns the token cost associated with document deletion, if applicable. /// /// # Returns - /// - `Some((TokenContractPosition, TokenAmount))` if a deletion cost exists. + /// - `Some(TokenActionCost)` if a deletion cost exists. /// - `None` if no cost is set for document deletion. - fn document_deletion_token_cost(&self) -> Option<(TokenContractPosition, TokenAmount)>; + fn document_deletion_token_cost(&self) -> Option; /// Returns the token cost associated with document transfer, if applicable. /// /// # Returns - /// - `Some((TokenContractPosition, TokenAmount))` if a transfer cost exists. + /// - `Some(TokenActionCost)` if a transfer cost exists. /// - `None` if no cost is set for document transfer. - fn document_transfer_token_cost(&self) -> Option<(TokenContractPosition, TokenAmount)>; + fn document_transfer_token_cost(&self) -> Option; /// Returns the token cost associated with updating the price of a document, if applicable. /// /// # Returns - /// - `Some((TokenContractPosition, TokenAmount))` if an update price cost exists. + /// - `Some(TokenActionCost)` if an update price cost exists. /// - `None` if no cost is set for updating the price. - fn document_update_price_token_cost(&self) -> Option<(TokenContractPosition, TokenAmount)>; + fn document_update_price_token_cost(&self) -> Option; /// Returns the token cost associated with document purchase, if applicable. /// /// # Returns - /// - `Some((TokenContractPosition, TokenAmount))` if a purchase cost exists. + /// - `Some(TokenActionCost)` if a purchase cost exists. /// - `None` if no cost is set for document purchase. - fn document_purchase_token_cost(&self) -> Option<(TokenContractPosition, TokenAmount)>; + fn document_purchase_token_cost(&self) -> Option; +} + +/// Trait providing setters for assigning token costs to different document operations. +pub trait DocumentTypeV1Setters { + /// Sets the token cost for document creation. + /// + /// # Arguments + /// - `cost`: `Some(DocumentActionTokenCost)` to set a cost, or `None` to clear it. + fn set_document_creation_token_cost(&mut self, cost: Option); + + /// Sets the token cost for document replacement (updating). + /// + /// # Arguments + /// - `cost`: `Some(DocumentActionTokenCost)` to set a cost, or `None` to clear it. + fn set_document_replacement_token_cost(&mut self, cost: Option); + + /// Sets the token cost for document deletion. + /// + /// # Arguments + /// - `cost`: `Some(DocumentActionTokenCost)` to set a cost, or `None` to clear it. + fn set_document_deletion_token_cost(&mut self, cost: Option); + + /// Sets the token cost for document transfer. + /// + /// # Arguments + /// - `cost`: `Some(DocumentActionTokenCost)` to set a cost, or `None` to clear it. + fn set_document_transfer_token_cost(&mut self, cost: Option); + + /// Sets the token cost for updating the price of a document. + /// + /// # Arguments + /// - `cost`: `Some(DocumentActionTokenCost)` to set a cost, or `None` to clear it. + fn set_document_price_update_token_cost(&mut self, cost: Option); + + /// Sets the token cost for document purchase. + /// + /// # Arguments + /// - `cost`: `Some(DocumentActionTokenCost)` to set a cost, or `None` to clear it. + fn set_document_purchase_token_cost(&mut self, cost: Option); } diff --git a/packages/rs-dpp/src/data_contract/document_type/class_methods/mod.rs b/packages/rs-dpp/src/data_contract/document_type/class_methods/mod.rs index 1a38953a784..77a2dca60c6 100644 --- a/packages/rs-dpp/src/data_contract/document_type/class_methods/mod.rs +++ b/packages/rs-dpp/src/data_contract/document_type/class_methods/mod.rs @@ -34,6 +34,6 @@ fn consensus_or_protocol_value_error(platform_value_error: platform_value::Error } #[cfg(not(feature = "validation"))] { - ProtocolError::ValueError(platform_value_error.into()) + ProtocolError::ValueError(platform_value_error) } } diff --git a/packages/rs-dpp/src/data_contract/document_type/class_methods/try_from_schema/v0/mod.rs b/packages/rs-dpp/src/data_contract/document_type/class_methods/try_from_schema/v0/mod.rs index 120493f020a..7915f665844 100644 --- a/packages/rs-dpp/src/data_contract/document_type/class_methods/try_from_schema/v0/mod.rs +++ b/packages/rs-dpp/src/data_contract/document_type/class_methods/try_from_schema/v0/mod.rs @@ -8,7 +8,9 @@ use crate::consensus::basic::data_contract::{ use crate::consensus::ConsensusError; use crate::data_contract::document_type::index::Index; use crate::data_contract::document_type::index_level::IndexLevel; -use crate::data_contract::document_type::property::{DocumentProperty, DocumentPropertyType}; +use crate::data_contract::document_type::property::DocumentProperty; +#[cfg(feature = "validation")] +use crate::data_contract::document_type::property::DocumentPropertyType; #[cfg(feature = "validation")] use crate::data_contract::document_type::schema::validate_max_depth; use crate::data_contract::document_type::v0::DocumentTypeV0; @@ -32,6 +34,7 @@ use crate::consensus::basic::document::MissingPositionsInDocumentTypePropertiesE use crate::consensus::basic::BasicError; use crate::data_contract::config::v0::DataContractConfigGettersV0; use crate::data_contract::config::DataContractConfig; +#[cfg(feature = "validation")] use crate::data_contract::document_type::class_methods::try_from_schema::{ MAX_INDEXED_BYTE_ARRAY_PROPERTY_LENGTH, MAX_INDEXED_STRING_PROPERTY_LENGTH, NOT_ALLOWED_SYSTEM_PROPERTIES, SYSTEM_PROPERTIES, diff --git a/packages/rs-dpp/src/data_contract/document_type/class_methods/try_from_schema/v1/mod.rs b/packages/rs-dpp/src/data_contract/document_type/class_methods/try_from_schema/v1/mod.rs index 7d66082c209..6a6087aed2a 100644 --- a/packages/rs-dpp/src/data_contract/document_type/class_methods/try_from_schema/v1/mod.rs +++ b/packages/rs-dpp/src/data_contract/document_type/class_methods/try_from_schema/v1/mod.rs @@ -8,7 +8,9 @@ use crate::consensus::basic::data_contract::{ use crate::consensus::ConsensusError; use crate::data_contract::document_type::index::Index; use crate::data_contract::document_type::index_level::IndexLevel; -use crate::data_contract::document_type::property::{DocumentProperty, DocumentPropertyType}; +use crate::data_contract::document_type::property::DocumentProperty; +#[cfg(feature = "validation")] +use crate::data_contract::document_type::property::DocumentPropertyType; #[cfg(feature = "validation")] use crate::data_contract::document_type::schema::validate_max_depth; #[cfg(feature = "validation")] @@ -27,14 +29,20 @@ use crate::consensus::basic::data_contract::ContestedUniqueIndexWithUniqueIndexE #[cfg(any(test, feature = "validation"))] use crate::consensus::basic::data_contract::InvalidDocumentTypeNameError; #[cfg(feature = "validation")] +use crate::consensus::basic::data_contract::TokenPaymentByBurningOnlyAllowedOnInternalTokenError; +#[cfg(feature = "validation")] use crate::consensus::basic::document::MissingPositionsInDocumentTypePropertiesError; #[cfg(feature = "validation")] use crate::consensus::basic::BasicError; use crate::data_contract::config::v0::DataContractConfigGettersV0; use crate::data_contract::config::DataContractConfig; use crate::data_contract::document_type::class_methods::try_from_schema::{ - insert_values, insert_values_nested, MAX_INDEXED_BYTE_ARRAY_PROPERTY_LENGTH, - MAX_INDEXED_STRING_PROPERTY_LENGTH, NOT_ALLOWED_SYSTEM_PROPERTIES, SYSTEM_PROPERTIES, + insert_values, insert_values_nested, +}; +#[cfg(feature = "validation")] +use crate::data_contract::document_type::class_methods::try_from_schema::{ + MAX_INDEXED_BYTE_ARRAY_PROPERTY_LENGTH, MAX_INDEXED_STRING_PROPERTY_LENGTH, + NOT_ALLOWED_SYSTEM_PROPERTIES, SYSTEM_PROPERTIES, }; use crate::data_contract::document_type::class_methods::{ consensus_or_protocol_data_contract_error, consensus_or_protocol_value_error, @@ -50,6 +58,10 @@ use crate::data_contract::errors::DataContractError; use crate::data_contract::storage_requirements::keys_for_document_type::StorageKeyRequirements; use crate::data_contract::TokenContractPosition; use crate::identity::SecurityLevel; +use crate::tokens::gas_fees_paid_by::GasFeesPaidBy; +use crate::tokens::token_amount_on_contract_token::{ + DocumentActionTokenCost, DocumentActionTokenEffect, +}; #[cfg(feature = "validation")] use crate::validation::meta_validators::DOCUMENT_META_SCHEMA_V0; use crate::validation::operations::ProtocolValidationOperation; @@ -544,19 +556,64 @@ impl DocumentTypeV1 { let token_costs_value = schema.get_optional_value("tokenCost")?; - let extract_cost = - |key: &str| -> Result, ProtocolError> { - token_costs_value - .and_then(|v| v.get_optional_value(key).transpose()) - .transpose()? - .map(|action_cost| { - Ok(( - action_cost.get_integer::("tokenPosition")?, - action_cost.get_integer::("amount")?, - )) + let extract_cost = |key: &str| -> Result, ProtocolError> { + token_costs_value + .and_then(|v| v.get_optional_value(key).transpose()) + .transpose()? + .map(|action_cost| { + // Extract an optional contract_id. Adjust the key if necessary. + let contract_id = action_cost.get_optional_identifier("contractId")?; + // Extract token_contract_position as an integer, then convert it. + let token_contract_position = + action_cost.get_integer::("tokenPosition")?; + // Extract the token amount. + let token_amount = action_cost.get_integer::("amount")?; + // Extract the token effect + let effect = action_cost + .get_optional_integer::("effect")? + .map(|int| int.try_into()) + .transpose()? + .unwrap_or(DocumentActionTokenEffect::TransferTokenToContractOwner); + + #[cfg(feature = "validation")] + if full_validation { + + // If contractId is present and user tries to burn, bail out: + if let Some(contract_id) = contract_id { + if effect == DocumentActionTokenEffect::BurnToken { + return Err(ProtocolError::ConsensusError( + ConsensusError::BasicError( + BasicError::TokenPaymentByBurningOnlyAllowedOnInternalTokenError( + TokenPaymentByBurningOnlyAllowedOnInternalTokenError::new( + contract_id, + token_contract_position, + key.to_string(), + ), + ), + ) + .into(), + )); + } + } + } + + // Extract an optional string and map it to the enum, defaulting if missing or unrecognized. + let gas_fees_paid_by = action_cost + .get_optional_integer::("gasFeesPaidBy")? + .map(|int| int.try_into()) + .transpose()? + .unwrap_or(GasFeesPaidBy::DocumentOwner); + + Ok(DocumentActionTokenCost { + contract_id, + token_contract_position, + token_amount, + effect, + gas_fees_paid_by, }) - .transpose() - }; + }) + .transpose() + }; let token_costs = TokenCostsV0 { create: extract_cost("create")?, diff --git a/packages/rs-dpp/src/data_contract/document_type/token_costs/accessors.rs b/packages/rs-dpp/src/data_contract/document_type/token_costs/accessors.rs index 25482cae5ee..4ae870ed0d2 100644 --- a/packages/rs-dpp/src/data_contract/document_type/token_costs/accessors.rs +++ b/packages/rs-dpp/src/data_contract/document_type/token_costs/accessors.rs @@ -1,62 +1,43 @@ -use crate::balances::credits::TokenAmount; -use crate::data_contract::TokenContractPosition; +use crate::tokens::token_amount_on_contract_token::DocumentActionTokenCost; /// Trait providing getters for retrieving token costs associated with different operations. pub trait TokenCostGettersV0 { /// Returns the token cost associated with document creation, if applicable. - fn document_creation_token_cost(&self) -> Option<(TokenContractPosition, TokenAmount)>; + fn document_creation_token_cost(&self) -> Option; /// Returns the token cost associated with document replacement (updating), if applicable. - fn document_replacement_token_cost(&self) -> Option<(TokenContractPosition, TokenAmount)>; + fn document_replacement_token_cost(&self) -> Option; /// Returns the token cost associated with document deletion, if applicable. - fn document_deletion_token_cost(&self) -> Option<(TokenContractPosition, TokenAmount)>; + fn document_deletion_token_cost(&self) -> Option; /// Returns the token cost associated with document transfer, if applicable. - fn document_transfer_token_cost(&self) -> Option<(TokenContractPosition, TokenAmount)>; + fn document_transfer_token_cost(&self) -> Option; /// Returns the token cost associated with updating the price of a document, if applicable. - fn document_price_update_token_cost(&self) -> Option<(TokenContractPosition, TokenAmount)>; + fn document_price_update_token_cost(&self) -> Option; /// Returns the token cost associated with document purchase, if applicable. - fn document_purchase_token_cost(&self) -> Option<(TokenContractPosition, TokenAmount)>; + fn document_purchase_token_cost(&self) -> Option; } /// Trait providing setters for modifying token costs associated with different operations. pub trait TokenCostSettersV0 { /// Sets the token cost for document creation. - fn set_document_creation_token_cost( - &mut self, - cost: Option<(TokenContractPosition, TokenAmount)>, - ); + fn set_document_creation_token_cost(&mut self, cost: Option); /// Sets the token cost for document replacement (updating). - fn set_document_replacement_token_cost( - &mut self, - cost: Option<(TokenContractPosition, TokenAmount)>, - ); + fn set_document_replacement_token_cost(&mut self, cost: Option); /// Sets the token cost for document deletion. - fn set_document_deletion_token_cost( - &mut self, - cost: Option<(TokenContractPosition, TokenAmount)>, - ); + fn set_document_deletion_token_cost(&mut self, cost: Option); /// Sets the token cost for document transfer. - fn set_document_transfer_token_cost( - &mut self, - cost: Option<(TokenContractPosition, TokenAmount)>, - ); + fn set_document_transfer_token_cost(&mut self, cost: Option); /// Sets the token cost for updating the price of a document. - fn set_document_price_update_token_cost( - &mut self, - cost: Option<(TokenContractPosition, TokenAmount)>, - ); + fn set_document_price_update_token_cost(&mut self, cost: Option); /// Sets the token cost for document purchase. - fn set_document_purchase_token_cost( - &mut self, - cost: Option<(TokenContractPosition, TokenAmount)>, - ); + fn set_document_purchase_token_cost(&mut self, cost: Option); } diff --git a/packages/rs-dpp/src/data_contract/document_type/token_costs/mod.rs b/packages/rs-dpp/src/data_contract/document_type/token_costs/mod.rs index 7d1158c3119..70a68a94a9d 100644 --- a/packages/rs-dpp/src/data_contract/document_type/token_costs/mod.rs +++ b/packages/rs-dpp/src/data_contract/document_type/token_costs/mod.rs @@ -1,9 +1,8 @@ -use crate::balances::credits::TokenAmount; use crate::data_contract::document_type::token_costs::accessors::{ TokenCostGettersV0, TokenCostSettersV0, }; use crate::data_contract::document_type::token_costs::v0::TokenCostsV0; -use crate::data_contract::TokenContractPosition; +use crate::tokens::token_amount_on_contract_token::DocumentActionTokenCost; use derive_more::From; pub(crate) mod accessors; @@ -18,37 +17,37 @@ pub enum TokenCosts { /// Implementation of the `TokenCostGettersV0` trait for `TokenCosts` enum. impl TokenCostGettersV0 for TokenCosts { - fn document_creation_token_cost(&self) -> Option<(TokenContractPosition, TokenAmount)> { + fn document_creation_token_cost(&self) -> Option { match self { TokenCosts::V0(inner) => inner.document_creation_token_cost(), } } - fn document_replacement_token_cost(&self) -> Option<(TokenContractPosition, TokenAmount)> { + fn document_replacement_token_cost(&self) -> Option { match self { TokenCosts::V0(inner) => inner.document_replacement_token_cost(), } } - fn document_deletion_token_cost(&self) -> Option<(TokenContractPosition, TokenAmount)> { + fn document_deletion_token_cost(&self) -> Option { match self { TokenCosts::V0(inner) => inner.document_deletion_token_cost(), } } - fn document_transfer_token_cost(&self) -> Option<(TokenContractPosition, TokenAmount)> { + fn document_transfer_token_cost(&self) -> Option { match self { TokenCosts::V0(inner) => inner.document_transfer_token_cost(), } } - fn document_price_update_token_cost(&self) -> Option<(TokenContractPosition, TokenAmount)> { + fn document_price_update_token_cost(&self) -> Option { match self { TokenCosts::V0(inner) => inner.document_price_update_token_cost(), } } - fn document_purchase_token_cost(&self) -> Option<(TokenContractPosition, TokenAmount)> { + fn document_purchase_token_cost(&self) -> Option { match self { TokenCosts::V0(inner) => inner.document_purchase_token_cost(), } @@ -56,55 +55,37 @@ impl TokenCostGettersV0 for TokenCosts { } impl TokenCostSettersV0 for TokenCosts { - fn set_document_creation_token_cost( - &mut self, - cost: Option<(TokenContractPosition, TokenAmount)>, - ) { + fn set_document_creation_token_cost(&mut self, cost: Option) { match self { TokenCosts::V0(inner) => inner.set_document_creation_token_cost(cost), } } - fn set_document_replacement_token_cost( - &mut self, - cost: Option<(TokenContractPosition, TokenAmount)>, - ) { + fn set_document_replacement_token_cost(&mut self, cost: Option) { match self { TokenCosts::V0(inner) => inner.set_document_replacement_token_cost(cost), } } - fn set_document_deletion_token_cost( - &mut self, - cost: Option<(TokenContractPosition, TokenAmount)>, - ) { + fn set_document_deletion_token_cost(&mut self, cost: Option) { match self { TokenCosts::V0(inner) => inner.set_document_deletion_token_cost(cost), } } - fn set_document_transfer_token_cost( - &mut self, - cost: Option<(TokenContractPosition, TokenAmount)>, - ) { + fn set_document_transfer_token_cost(&mut self, cost: Option) { match self { TokenCosts::V0(inner) => inner.set_document_transfer_token_cost(cost), } } - fn set_document_price_update_token_cost( - &mut self, - cost: Option<(TokenContractPosition, TokenAmount)>, - ) { + fn set_document_price_update_token_cost(&mut self, cost: Option) { match self { TokenCosts::V0(inner) => inner.set_document_price_update_token_cost(cost), } } - fn set_document_purchase_token_cost( - &mut self, - cost: Option<(TokenContractPosition, TokenAmount)>, - ) { + fn set_document_purchase_token_cost(&mut self, cost: Option) { match self { TokenCosts::V0(inner) => inner.set_document_purchase_token_cost(cost), } diff --git a/packages/rs-dpp/src/data_contract/document_type/token_costs/v0/mod.rs b/packages/rs-dpp/src/data_contract/document_type/token_costs/v0/mod.rs index 3f05636e695..345663540b3 100644 --- a/packages/rs-dpp/src/data_contract/document_type/token_costs/v0/mod.rs +++ b/packages/rs-dpp/src/data_contract/document_type/token_costs/v0/mod.rs @@ -1,99 +1,80 @@ -use crate::balances::credits::TokenAmount; use crate::data_contract::document_type::token_costs::accessors::{ TokenCostGettersV0, TokenCostSettersV0, }; -use crate::data_contract::TokenContractPosition; +use crate::tokens::token_amount_on_contract_token::DocumentActionTokenCost; /// Token costs for various document operations. #[derive(Debug, PartialEq, Clone, Default)] pub struct TokenCostsV0 { /// Cost of creating a document. - pub create: Option<(TokenContractPosition, TokenAmount)>, + pub create: Option, /// Cost of replacing a document. - pub replace: Option<(TokenContractPosition, TokenAmount)>, + pub replace: Option, /// Cost of deleting a document. - pub delete: Option<(TokenContractPosition, TokenAmount)>, + pub delete: Option, /// Cost of transferring a document. - pub transfer: Option<(TokenContractPosition, TokenAmount)>, + pub transfer: Option, /// Cost of updating the price of a document. - pub update_price: Option<(TokenContractPosition, TokenAmount)>, + pub update_price: Option, /// Cost of purchasing a document. - pub purchase: Option<(TokenContractPosition, TokenAmount)>, + pub purchase: Option, } /// Implementation of the `TokenCostGettersV0` trait for `TokenCostsV0`. impl TokenCostGettersV0 for TokenCostsV0 { - fn document_creation_token_cost(&self) -> Option<(TokenContractPosition, TokenAmount)> { + fn document_creation_token_cost(&self) -> Option { self.create } - fn document_replacement_token_cost(&self) -> Option<(TokenContractPosition, TokenAmount)> { + fn document_replacement_token_cost(&self) -> Option { self.replace } - fn document_deletion_token_cost(&self) -> Option<(TokenContractPosition, TokenAmount)> { + fn document_deletion_token_cost(&self) -> Option { self.delete } - fn document_transfer_token_cost(&self) -> Option<(TokenContractPosition, TokenAmount)> { + fn document_transfer_token_cost(&self) -> Option { self.transfer } - fn document_price_update_token_cost(&self) -> Option<(TokenContractPosition, TokenAmount)> { + fn document_price_update_token_cost(&self) -> Option { self.update_price } - fn document_purchase_token_cost(&self) -> Option<(TokenContractPosition, TokenAmount)> { + fn document_purchase_token_cost(&self) -> Option { self.purchase } } /// Implementation of the `TokenCostSettersV0` trait for `TokenCostsV0`. impl TokenCostSettersV0 for TokenCostsV0 { - fn set_document_creation_token_cost( - &mut self, - cost: Option<(TokenContractPosition, TokenAmount)>, - ) { + fn set_document_creation_token_cost(&mut self, cost: Option) { self.create = cost; } - fn set_document_replacement_token_cost( - &mut self, - cost: Option<(TokenContractPosition, TokenAmount)>, - ) { + fn set_document_replacement_token_cost(&mut self, cost: Option) { self.replace = cost; } - fn set_document_deletion_token_cost( - &mut self, - cost: Option<(TokenContractPosition, TokenAmount)>, - ) { + fn set_document_deletion_token_cost(&mut self, cost: Option) { self.delete = cost; } - fn set_document_transfer_token_cost( - &mut self, - cost: Option<(TokenContractPosition, TokenAmount)>, - ) { + fn set_document_transfer_token_cost(&mut self, cost: Option) { self.transfer = cost; } - fn set_document_price_update_token_cost( - &mut self, - cost: Option<(TokenContractPosition, TokenAmount)>, - ) { + fn set_document_price_update_token_cost(&mut self, cost: Option) { self.update_price = cost; } - fn set_document_purchase_token_cost( - &mut self, - cost: Option<(TokenContractPosition, TokenAmount)>, - ) { + fn set_document_purchase_token_cost(&mut self, cost: Option) { self.purchase = cost; } } diff --git a/packages/rs-dpp/src/data_contract/document_type/v0/accessors.rs b/packages/rs-dpp/src/data_contract/document_type/v0/accessors.rs index f04b9fa39fe..efc5da11ac8 100644 --- a/packages/rs-dpp/src/data_contract/document_type/v0/accessors.rs +++ b/packages/rs-dpp/src/data_contract/document_type/v0/accessors.rs @@ -1,5 +1,5 @@ use crate::data_contract::document_type::accessors::{ - DocumentTypeV0Getters, DocumentTypeV0Setters, + DocumentTypeV0Getters, DocumentTypeV0MutGetters, DocumentTypeV0Setters, }; use crate::data_contract::document_type::index::Index; use crate::data_contract::document_type::index_level::IndexLevel; @@ -18,6 +18,12 @@ use crate::nft::TradeMode; use indexmap::IndexMap; use std::collections::{BTreeMap, BTreeSet}; +impl DocumentTypeV0MutGetters for DocumentTypeV0 { + fn schema_mut(&mut self) -> &mut Value { + &mut self.schema + } +} + impl DocumentTypeV0Getters for DocumentTypeV0 { fn name(&self) -> &String { &self.name diff --git a/packages/rs-dpp/src/data_contract/document_type/v0/mod.rs b/packages/rs-dpp/src/data_contract/document_type/v0/mod.rs index a2f2a28b991..69c62729fba 100644 --- a/packages/rs-dpp/src/data_contract/document_type/v0/mod.rs +++ b/packages/rs-dpp/src/data_contract/document_type/v0/mod.rs @@ -66,10 +66,3 @@ pub struct DocumentTypeV0 { impl DocumentTypeBasicMethods for DocumentTypeV0 {} impl DocumentTypeV0Methods for DocumentTypeV0 {} - -impl DocumentTypeV0 { - // Public method to set the data_contract_id - pub fn set_data_contract_id(&mut self, new_id: Identifier) { - self.data_contract_id = new_id; - } -} diff --git a/packages/rs-dpp/src/data_contract/document_type/v1/accessors.rs b/packages/rs-dpp/src/data_contract/document_type/v1/accessors.rs index 54caaa1fa8d..100224a3ebd 100644 --- a/packages/rs-dpp/src/data_contract/document_type/v1/accessors.rs +++ b/packages/rs-dpp/src/data_contract/document_type/v1/accessors.rs @@ -1,5 +1,5 @@ use crate::data_contract::document_type::accessors::{ - DocumentTypeV0Getters, DocumentTypeV0Setters, DocumentTypeV1Getters, + DocumentTypeV0Getters, DocumentTypeV0MutGetters, DocumentTypeV0Setters, DocumentTypeV1Getters, }; use crate::data_contract::document_type::index::Index; use crate::data_contract::document_type::index_level::IndexLevel; @@ -7,20 +7,25 @@ use crate::data_contract::document_type::property::DocumentProperty; use platform_value::{Identifier, Value}; -use crate::balances::credits::TokenAmount; use crate::data_contract::document_type::restricted_creation::CreationRestrictionMode; use crate::data_contract::document_type::token_costs::accessors::TokenCostGettersV0; use crate::data_contract::document_type::v1::DocumentTypeV1; #[cfg(feature = "validation")] use crate::data_contract::document_type::validator::StatelessJsonSchemaLazyValidator; use crate::data_contract::storage_requirements::keys_for_document_type::StorageKeyRequirements; -use crate::data_contract::TokenContractPosition; use crate::document::transfer::Transferable; use crate::identity::SecurityLevel; use crate::nft::TradeMode; +use crate::tokens::token_amount_on_contract_token::DocumentActionTokenCost; use indexmap::IndexMap; use std::collections::{BTreeMap, BTreeSet}; +impl DocumentTypeV0MutGetters for DocumentTypeV1 { + fn schema_mut(&mut self) -> &mut Value { + &mut self.schema + } +} + impl DocumentTypeV0Getters for DocumentTypeV1 { fn name(&self) -> &String { &self.name @@ -125,27 +130,27 @@ impl DocumentTypeV0Setters for DocumentTypeV1 { } impl DocumentTypeV1Getters for DocumentTypeV1 { - fn document_creation_token_cost(&self) -> Option<(TokenContractPosition, TokenAmount)> { + fn document_creation_token_cost(&self) -> Option { self.token_costs.document_creation_token_cost() } - fn document_replacement_token_cost(&self) -> Option<(TokenContractPosition, TokenAmount)> { + fn document_replacement_token_cost(&self) -> Option { self.token_costs.document_replacement_token_cost() } - fn document_deletion_token_cost(&self) -> Option<(TokenContractPosition, TokenAmount)> { + fn document_deletion_token_cost(&self) -> Option { self.token_costs.document_deletion_token_cost() } - fn document_transfer_token_cost(&self) -> Option<(TokenContractPosition, TokenAmount)> { + fn document_transfer_token_cost(&self) -> Option { self.token_costs.document_transfer_token_cost() } - fn document_update_price_token_cost(&self) -> Option<(TokenContractPosition, TokenAmount)> { + fn document_update_price_token_cost(&self) -> Option { self.token_costs.document_price_update_token_cost() } - fn document_purchase_token_cost(&self) -> Option<(TokenContractPosition, TokenAmount)> { + fn document_purchase_token_cost(&self) -> Option { self.token_costs.document_purchase_token_cost() } } diff --git a/packages/rs-dpp/src/data_contract/document_type/v1/mod.rs b/packages/rs-dpp/src/data_contract/document_type/v1/mod.rs index 1ca0be47843..ce7a0dd4f3f 100644 --- a/packages/rs-dpp/src/data_contract/document_type/v1/mod.rs +++ b/packages/rs-dpp/src/data_contract/document_type/v1/mod.rs @@ -6,19 +6,22 @@ use crate::data_contract::document_type::index_level::IndexLevel; use crate::data_contract::document_type::property::DocumentProperty; use crate::data_contract::storage_requirements::keys_for_document_type::StorageKeyRequirements; +use crate::data_contract::document_type::accessors::DocumentTypeV1Setters; use crate::data_contract::document_type::methods::{ DocumentTypeBasicMethods, DocumentTypeV0Methods, }; use crate::data_contract::document_type::restricted_creation::CreationRestrictionMode; +use crate::data_contract::document_type::token_costs::accessors::TokenCostSettersV0; use crate::data_contract::document_type::token_costs::TokenCosts; use crate::data_contract::document_type::v0::DocumentTypeV0; +#[cfg(feature = "validation")] +use crate::data_contract::document_type::validator::StatelessJsonSchemaLazyValidator; use crate::document::transfer::Transferable; use crate::identity::SecurityLevel; use crate::nft::TradeMode; +use crate::tokens::token_amount_on_contract_token::DocumentActionTokenCost; use platform_value::{Identifier, Value}; -#[cfg(feature = "validation")] -use crate::data_contract::document_type::validator::StatelessJsonSchemaLazyValidator; mod accessors; #[cfg(feature = "random-document-types")] pub mod random_document_type; @@ -71,10 +74,29 @@ impl DocumentTypeBasicMethods for DocumentTypeV1 {} impl DocumentTypeV0Methods for DocumentTypeV1 {} -impl DocumentTypeV1 { - // Public method to set the data_contract_id - pub fn set_data_contract_id(&mut self, new_id: Identifier) { - self.data_contract_id = new_id; +impl DocumentTypeV1Setters for DocumentTypeV1 { + fn set_document_creation_token_cost(&mut self, cost: Option) { + self.token_costs.set_document_creation_token_cost(cost) + } + + fn set_document_replacement_token_cost(&mut self, cost: Option) { + self.token_costs.set_document_replacement_token_cost(cost) + } + + fn set_document_deletion_token_cost(&mut self, cost: Option) { + self.token_costs.set_document_deletion_token_cost(cost) + } + + fn set_document_transfer_token_cost(&mut self, cost: Option) { + self.token_costs.set_document_transfer_token_cost(cost) + } + + fn set_document_price_update_token_cost(&mut self, cost: Option) { + self.token_costs.set_document_price_update_token_cost(cost) + } + + fn set_document_purchase_token_cost(&mut self, cost: Option) { + self.token_costs.set_document_purchase_token_cost(cost) } } diff --git a/packages/rs-dpp/src/document/document_factory/mod.rs b/packages/rs-dpp/src/document/document_factory/mod.rs index 158daf9488f..2d958c7eb8d 100644 --- a/packages/rs-dpp/src/document/document_factory/mod.rs +++ b/packages/rs-dpp/src/document/document_factory/mod.rs @@ -17,6 +17,7 @@ use crate::state_transition::batch_transition::{ batched_transition::document_transition_action_type::DocumentTransitionActionType, BatchTransition, }; +use crate::tokens::token_payment_info::TokenPaymentInfo; use crate::util::entropy_generator::EntropyGenerator; pub use v0::DocumentFactoryV0; @@ -117,7 +118,12 @@ impl DocumentFactory { documents_iter: impl IntoIterator< Item = ( DocumentTransitionActionType, - Vec<(Document, DocumentTypeRef<'a>, Bytes32)>, + Vec<( + Document, + DocumentTypeRef<'a>, + Bytes32, + Option, + )>, ), >, nonce_counter: &mut BTreeMap<(Identifier, Identifier), u64>, //IdentityID/ContractID -> nonce diff --git a/packages/rs-dpp/src/document/document_factory/v0/mod.rs b/packages/rs-dpp/src/document/document_factory/v0/mod.rs index 503192c2f18..7cfbfed6757 100644 --- a/packages/rs-dpp/src/document/document_factory/v0/mod.rs +++ b/packages/rs-dpp/src/document/document_factory/v0/mod.rs @@ -34,6 +34,7 @@ use crate::state_transition::batch_transition::{ use itertools::Itertools; #[cfg(feature = "state-transitions")] use crate::state_transition::state_transitions::document::batch_transition::batched_transition::document_transition::DocumentTransition; +use crate::tokens::token_payment_info::TokenPaymentInfo; const PROPERTY_FEATURE_VERSION: &str = "$version"; const PROPERTY_ENTROPY: &str = "$entropy"; @@ -191,6 +192,7 @@ impl DocumentFactoryV0 { data_contract: data_contract.clone(), metadata: None, entropy: Bytes32::new(document_entropy), + token_payment_info: None, } .into()), version => Err(ProtocolError::UnknownVersionMismatch { @@ -208,7 +210,12 @@ impl DocumentFactoryV0 { documents_iter: impl IntoIterator< Item = ( DocumentTransitionActionType, - Vec<(Document, DocumentTypeRef<'a>, Bytes32)>, + Vec<( + Document, + DocumentTypeRef<'a>, + Bytes32, + Option, + )>, ), >, nonce_counter: &mut BTreeMap<(Identifier, Identifier), u64>, //IdentityID/ContractID -> nonce @@ -218,25 +225,25 @@ impl DocumentFactoryV0 { #[allow(clippy::type_complexity)] let documents: Vec<( DocumentTransitionActionType, - Vec<(Document, DocumentTypeRef, Bytes32)>, + Vec<(Document, DocumentTypeRef, Bytes32, Option)>, )> = documents_iter.into_iter().collect(); let mut flattened_documents_iter = documents.iter().flat_map(|(_, v)| v).peekable(); - let Some((first_document, _, _)) = flattened_documents_iter.peek() else { + let Some((first_document, _, _, _)) = flattened_documents_iter.peek() else { return Err(DocumentError::NoDocumentsSuppliedError.into()); }; let owner_id = first_document.owner_id(); let is_the_same_owner = - flattened_documents_iter.all(|(document, _, _)| document.owner_id() == owner_id); + flattened_documents_iter.all(|(document, _, _, _)| document.owner_id() == owner_id); if !is_the_same_owner { return Err(DocumentError::MismatchOwnerIdsError { documents: documents .into_iter() .flat_map(|(_, v)| { v.into_iter() - .map(|(document, _, _)| document) + .map(|(document, _, _, _)| document) .collect::>() }) .collect(), @@ -253,7 +260,9 @@ impl DocumentFactoryV0 { DocumentTransitionActionType::Delete => Self::document_delete_transitions( documents .into_iter() - .map(|(document, document_type, _)| (document, document_type)) + .map(|(document, document_type, _, token_payment_info)| { + (document, document_type, token_payment_info) + }) .collect(), nonce_counter, platform_version, @@ -261,7 +270,9 @@ impl DocumentFactoryV0 { DocumentTransitionActionType::Replace => Self::document_replace_transitions( documents .into_iter() - .map(|(document, document_type, _)| (document, document_type)) + .map(|(document, document_type, _, token_payment_info)| { + (document, document_type, token_payment_info) + }) .collect(), nonce_counter, platform_version, @@ -313,6 +324,7 @@ impl DocumentFactoryV0 { data_contract: data_contract.clone(), metadata: None, entropy: Bytes32::default(), + token_payment_info: None, } .into()), version => Err(ProtocolError::UnknownVersionMismatch { @@ -384,13 +396,13 @@ impl DocumentFactoryV0 { // #[cfg(feature = "state-transitions")] fn document_create_transitions( - documents: Vec<(Document, DocumentTypeRef, Bytes32)>, + documents: Vec<(Document, DocumentTypeRef, Bytes32, Option)>, nonce_counter: &mut BTreeMap<(Identifier, Identifier), u64>, //IdentityID/ContractID -> nonce platform_version: &PlatformVersion, ) -> Result, ProtocolError> { documents .into_iter() - .map(|(document, document_type, entropy)| { + .map(|(document, document_type, entropy, token_payment_info)| { if document_type.documents_mutable() { //we need to have revisions let Some(revision) = document.revision() else { @@ -414,6 +426,7 @@ impl DocumentFactoryV0 { document, document_type, entropy.to_buffer(), + token_payment_info, *nonce, platform_version, None, @@ -429,13 +442,13 @@ impl DocumentFactoryV0 { #[cfg(feature = "state-transitions")] fn document_replace_transitions( - documents: Vec<(Document, DocumentTypeRef)>, + documents: Vec<(Document, DocumentTypeRef, Option)>, nonce_counter: &mut BTreeMap<(Identifier, Identifier), u64>, //IdentityID/ContractID -> nonce platform_version: &PlatformVersion, ) -> Result, ProtocolError> { documents .into_iter() - .map(|(mut document, document_type)| { + .map(|(mut document, document_type, token_payment_info)| { if !document_type.documents_mutable() { return Err(DocumentError::TryingToReplaceImmutableDocument { document: Box::new(document), @@ -459,6 +472,7 @@ impl DocumentFactoryV0 { let transition = DocumentReplaceTransition::from_document( document, document_type, + token_payment_info, *nonce, platform_version, None, @@ -513,13 +527,13 @@ impl DocumentFactoryV0 { #[cfg(feature = "state-transitions")] fn document_delete_transitions( - documents: Vec<(Document, DocumentTypeRef)>, + documents: Vec<(Document, DocumentTypeRef, Option)>, nonce_counter: &mut BTreeMap<(Identifier, Identifier), u64>, //IdentityID/ContractID -> nonce platform_version: &PlatformVersion, ) -> Result, ProtocolError> { documents .into_iter() - .map(|(document, document_type)| { + .map(|(document, document_type, token_payment_info)| { if !document_type.documents_can_be_deleted() { return Err(DocumentError::TryingToDeleteIndelibleDocument { document: Box::new(document), @@ -539,6 +553,7 @@ impl DocumentFactoryV0 { let transition = DocumentDeleteTransition::from_document( document, document_type, + token_payment_info, *nonce, platform_version, None, @@ -606,7 +621,7 @@ mod test { let document = Document::V0(document_v0); // This will be passed to the factory - let documents = vec![(document, document_type_ref)]; + let documents = vec![(document, document_type_ref, None)]; let mut nonce_counter = BTreeMap::new(); let platform_version = PlatformVersion::latest(); diff --git a/packages/rs-dpp/src/document/extended_document/accessors.rs b/packages/rs-dpp/src/document/extended_document/accessors.rs index a471124d21f..c20951f83ac 100644 --- a/packages/rs-dpp/src/document/extended_document/accessors.rs +++ b/packages/rs-dpp/src/document/extended_document/accessors.rs @@ -4,6 +4,7 @@ use crate::document::{Document, ExtendedDocument}; use crate::identity::TimestampMillis; use crate::metadata::Metadata; use crate::prelude::{BlockHeight, CoreBlockHeight, Revision}; +use crate::tokens::token_payment_info::TokenPaymentInfo; use crate::ProtocolError; use platform_value::{Bytes32, Identifier, Value}; use std::collections::BTreeMap; @@ -152,6 +153,13 @@ impl ExtendedDocument { } } + /// Returns a reference to the actual document object containing the data. + pub fn token_payment_info(&self) -> Option { + match self { + ExtendedDocument::V0(v0) => v0.token_payment_info, + } + } + /// Returns a reference to the data contract associated with the document. pub fn data_contract(&self) -> &DataContract { match self { diff --git a/packages/rs-dpp/src/document/extended_document/fields.rs b/packages/rs-dpp/src/document/extended_document/fields.rs index 09400b60edd..4f1351c4045 100644 --- a/packages/rs-dpp/src/document/extended_document/fields.rs +++ b/packages/rs-dpp/src/document/extended_document/fields.rs @@ -2,6 +2,7 @@ pub mod property_names { pub const FEATURE_VERSION: &str = "$version"; pub const ID: &str = "$id"; pub const DOCUMENT_TYPE_NAME: &str = "$type"; + pub const TOKEN_PAYMENT_INFO: &str = "$tokenPaymentInfo"; pub const REVISION: &str = "$revision"; pub const DATA_CONTRACT: &str = "$dataContract"; pub const DATA_CONTRACT_ID: &str = "$dataContractId"; diff --git a/packages/rs-dpp/src/document/extended_document/mod.rs b/packages/rs-dpp/src/document/extended_document/mod.rs index 2901850d30b..83f1eb3c3df 100644 --- a/packages/rs-dpp/src/document/extended_document/mod.rs +++ b/packages/rs-dpp/src/document/extended_document/mod.rs @@ -20,6 +20,7 @@ use crate::document::extended_document::v0::ExtendedDocumentV0; use crate::document::serialization_traits::DocumentJsonMethodsV0; #[cfg(feature = "validation")] use crate::validation::SimpleConsensusValidationResult; +use derive_more::From; use platform_value::Value; use platform_version::version::PlatformVersion; use platform_versioning::PlatformVersioned; @@ -28,7 +29,7 @@ use serde_json::Value as JsonValue; #[cfg(feature = "document-value-conversion")] use std::collections::BTreeMap; -#[derive(Debug, Clone, PlatformVersioned)] +#[derive(Debug, Clone, PlatformVersioned, From)] pub enum ExtendedDocument { V0(ExtendedDocumentV0), } @@ -642,6 +643,7 @@ mod test { metadata: None, data_contract_id, entropy: Default::default(), + token_payment_info: None, } .into() } diff --git a/packages/rs-dpp/src/document/extended_document/serde_serialize.rs b/packages/rs-dpp/src/document/extended_document/serde_serialize.rs index 799e5d9deb4..00c6741ebe6 100644 --- a/packages/rs-dpp/src/document/extended_document/serde_serialize.rs +++ b/packages/rs-dpp/src/document/extended_document/serde_serialize.rs @@ -81,6 +81,7 @@ impl<'de> Visitor<'de> for ExtendedDocumentVisitor { data_contract, metadata: None, entropy: Bytes32::default(), + token_payment_info: None, })), _ => Err(serde::de::Error::unknown_variant( &format!("{}", version), diff --git a/packages/rs-dpp/src/document/extended_document/v0/mod.rs b/packages/rs-dpp/src/document/extended_document/v0/mod.rs index d048b97a3ac..597a8165cb3 100644 --- a/packages/rs-dpp/src/document/extended_document/v0/mod.rs +++ b/packages/rs-dpp/src/document/extended_document/v0/mod.rs @@ -11,7 +11,7 @@ use crate::data_contract::DataContract; feature = "document-json-conversion" ))] use crate::document::extended_document::fields::property_names; -use crate::document::{Document, DocumentV0Getters, ExtendedDocument}; +use crate::document::{Document, DocumentV0Getters}; use crate::identity::TimestampMillis; use crate::metadata::Metadata; use crate::prelude::{BlockHeight, CoreBlockHeight, Revision}; @@ -27,6 +27,10 @@ use platform_value::btreemap_extensions::{ BTreeValueMapReplacementPathHelper, BTreeValueRemoveFromMapHelper, }; use platform_value::{Bytes32, Identifier, ReplacementType, Value}; +#[cfg(all( + feature = "document-serde-conversion", + feature = "data-contract-serde-conversion" +))] use serde::{Deserialize, Serialize}; use std::collections::BTreeMap; @@ -40,6 +44,7 @@ use crate::document::serialization_traits::DocumentJsonMethodsV0; #[cfg(feature = "document-value-conversion")] use crate::document::serialization_traits::DocumentPlatformValueMethodsV0; use crate::document::serialization_traits::ExtendedDocumentPlatformConversionMethodsV0; +use crate::tokens::token_payment_info::TokenPaymentInfo; #[cfg(feature = "validation")] use crate::validation::SimpleConsensusValidationResult; #[cfg(feature = "document-json-conversion")] @@ -119,6 +124,15 @@ pub struct ExtendedDocumentV0 { serde(rename = "$entropy") )] pub entropy: Bytes32, + /// A field representing the token payment info. + #[cfg_attr( + all( + feature = "document-serde-conversion", + feature = "data-contract-serde-conversion" + ), + serde(rename = "$tokenPaymentInfo") + )] + pub token_payment_info: Option, } impl ExtendedDocumentV0 { @@ -218,6 +232,7 @@ impl ExtendedDocumentV0 { document: Document, data_contract: DataContract, document_type_name: String, + token_payment_info: Option, ) -> Self { Self { document_type_name, @@ -226,6 +241,7 @@ impl ExtendedDocumentV0 { data_contract, metadata: None, entropy: Default::default(), + token_payment_info, } } @@ -291,6 +307,16 @@ impl ExtendedDocumentV0 { .clone() .into_btree_string_map() .map_err(ProtocolError::ValueError)?; + + let token_payment_info = properties + .remove_optional_map_as_btree_map_keep_values_as_platform_value( + property_names::TOKEN_PAYMENT_INFO, + ) + .ok() + .flatten() + .map(|map| map.try_into()) + .transpose()?; + let document_type_name = properties .remove_string(property_names::DOCUMENT_TYPE_NAME) .map_err(ProtocolError::ValueError)?; @@ -305,6 +331,7 @@ impl ExtendedDocumentV0 { data_contract_id, metadata: None, entropy: Default::default(), + token_payment_info, }; extended_document.data_contract_id = Identifier::new( @@ -340,6 +367,15 @@ impl ExtendedDocumentV0 { .remove_string(property_names::DOCUMENT_TYPE_NAME) .map_err(ProtocolError::ValueError)?; + let token_payment_info = properties + .remove_optional_map_as_btree_map_keep_values_as_platform_value( + property_names::TOKEN_PAYMENT_INFO, + ) + .ok() + .flatten() + .map(|map| map.try_into()) + .transpose()?; + let document_type = data_contract.document_type_for_name(document_type_name.as_str())?; let identifiers = document_type.identifier_paths().to_owned(); @@ -364,6 +400,7 @@ impl ExtendedDocumentV0 { data_contract_id, metadata: None, entropy: Default::default(), + token_payment_info, }; extended_document.data_contract_id = properties @@ -396,6 +433,13 @@ impl ExtendedDocumentV0 { property_names::DATA_CONTRACT_ID.to_string(), JsonValue::String(bs58::encode(self.data_contract_id.to_buffer()).into_string()), ); + if let Some(token_payment_info) = self.token_payment_info { + let value: Value = token_payment_info.try_into()?; + value_mut.insert( + property_names::TOKEN_PAYMENT_INFO.to_string(), + value.try_into_validating_json()?, + ); + } Ok(value) } @@ -410,6 +454,12 @@ impl ExtendedDocumentV0 { property_names::DATA_CONTRACT_ID.to_string(), Value::Identifier(self.data_contract_id.to_buffer()), ); + if let Some(token_payment_info) = self.token_payment_info { + object.insert( + property_names::TOKEN_PAYMENT_INFO.to_string(), + token_payment_info.try_into()?, + ); + } Ok(object) } @@ -419,6 +469,7 @@ impl ExtendedDocumentV0 { document_type_name, data_contract_id, document, + token_payment_info, .. } = self; @@ -432,6 +483,12 @@ impl ExtendedDocumentV0 { property_names::DATA_CONTRACT_ID.to_string(), Value::Identifier(data_contract_id.to_buffer()), ); + if let Some(token_payment_info) = token_payment_info { + object.insert( + property_names::TOKEN_PAYMENT_INFO.to_string(), + token_payment_info.try_into()?, + ); + } Ok(object) } @@ -510,9 +567,3 @@ impl ExtendedDocumentV0 { ) } } - -impl From for ExtendedDocument { - fn from(value: ExtendedDocumentV0) -> Self { - ExtendedDocument::V0(value) - } -} diff --git a/packages/rs-dpp/src/document/extended_document/v0/serialize.rs b/packages/rs-dpp/src/document/extended_document/v0/serialize.rs index 255d49bd960..0cecc57ba5a 100644 --- a/packages/rs-dpp/src/document/extended_document/v0/serialize.rs +++ b/packages/rs-dpp/src/document/extended_document/v0/serialize.rs @@ -125,6 +125,7 @@ impl ExtendedDocumentPlatformDeserializationMethodsV0 for ExtendedDocumentV0 { metadata: None, entropy: Default::default(), + token_payment_info: None, }) } } diff --git a/packages/rs-dpp/src/document/specialized_document_factory/mod.rs b/packages/rs-dpp/src/document/specialized_document_factory/mod.rs index 0d7a25b3dcd..f006f3f2712 100644 --- a/packages/rs-dpp/src/document/specialized_document_factory/mod.rs +++ b/packages/rs-dpp/src/document/specialized_document_factory/mod.rs @@ -17,6 +17,7 @@ use crate::state_transition::batch_transition::{ batched_transition::document_transition_action_type::DocumentTransitionActionType, BatchTransition, }; +use crate::tokens::token_payment_info::TokenPaymentInfo; use crate::util::entropy_generator::EntropyGenerator; pub use v0::SpecializedDocumentFactoryV0; @@ -120,7 +121,12 @@ impl SpecializedDocumentFactory { documents_iter: impl IntoIterator< Item = ( DocumentTransitionActionType, - Vec<(Document, DocumentTypeRef<'a>, Bytes32)>, + Vec<( + Document, + DocumentTypeRef<'a>, + Bytes32, + Option, + )>, ), >, nonce_counter: &mut BTreeMap<(Identifier, Identifier), u64>, //IdentityID/ContractID -> nonce diff --git a/packages/rs-dpp/src/document/specialized_document_factory/v0/mod.rs b/packages/rs-dpp/src/document/specialized_document_factory/v0/mod.rs index 77ec8ad7bad..6e6ace91043 100644 --- a/packages/rs-dpp/src/document/specialized_document_factory/v0/mod.rs +++ b/packages/rs-dpp/src/document/specialized_document_factory/v0/mod.rs @@ -33,6 +33,7 @@ use crate::state_transition::batch_transition::{ use itertools::Itertools; #[cfg(feature = "state-transitions")] use crate::state_transition::state_transitions::document::batch_transition::batched_transition::document_transition::DocumentTransition; +use crate::tokens::token_payment_info::TokenPaymentInfo; const PROPERTY_FEATURE_VERSION: &str = "$version"; const PROPERTY_ENTROPY: &str = "$entropy"; @@ -199,6 +200,7 @@ impl SpecializedDocumentFactoryV0 { data_contract: self.data_contract.clone(), metadata: None, entropy: Bytes32::new(document_entropy), + token_payment_info: None, } .into()), version => Err(ProtocolError::UnknownVersionMismatch { @@ -216,7 +218,12 @@ impl SpecializedDocumentFactoryV0 { documents_iter: impl IntoIterator< Item = ( DocumentTransitionActionType, - Vec<(Document, DocumentTypeRef<'a>, Bytes32)>, + Vec<( + Document, + DocumentTypeRef<'a>, + Bytes32, + Option, + )>, ), >, nonce_counter: &mut BTreeMap<(Identifier, Identifier), u64>, //IdentityID/ContractID -> nonce @@ -226,25 +233,25 @@ impl SpecializedDocumentFactoryV0 { #[allow(clippy::type_complexity)] let documents: Vec<( DocumentTransitionActionType, - Vec<(Document, DocumentTypeRef, Bytes32)>, + Vec<(Document, DocumentTypeRef, Bytes32, Option)>, )> = documents_iter.into_iter().collect(); let mut flattened_documents_iter = documents.iter().flat_map(|(_, v)| v).peekable(); - let Some((first_document, _, _)) = flattened_documents_iter.peek() else { + let Some((first_document, _, _, _)) = flattened_documents_iter.peek() else { return Err(DocumentError::NoDocumentsSuppliedError.into()); }; let owner_id = first_document.owner_id(); let is_the_same_owner = - flattened_documents_iter.all(|(document, _, _)| document.owner_id() == owner_id); + flattened_documents_iter.all(|(document, _, _, _)| document.owner_id() == owner_id); if !is_the_same_owner { return Err(DocumentError::MismatchOwnerIdsError { documents: documents .into_iter() .flat_map(|(_, v)| { v.into_iter() - .map(|(document, _, _)| document) + .map(|(document, _, _, _)| document) .collect::>() }) .collect(), @@ -261,7 +268,9 @@ impl SpecializedDocumentFactoryV0 { DocumentTransitionActionType::Delete => Self::document_delete_transitions( documents .into_iter() - .map(|(document, document_type, _)| (document, document_type)) + .map(|(document, document_type, _, token_payment_info)| { + (document, document_type, token_payment_info) + }) .collect(), nonce_counter, platform_version, @@ -269,7 +278,9 @@ impl SpecializedDocumentFactoryV0 { DocumentTransitionActionType::Replace => Self::document_replace_transitions( documents .into_iter() - .map(|(document, document_type, _)| (document, document_type)) + .map(|(document, document_type, _, token_payment_info)| { + (document, document_type, token_payment_info) + }) .collect(), nonce_counter, platform_version, @@ -322,6 +333,7 @@ impl SpecializedDocumentFactoryV0 { data_contract: self.data_contract.clone(), metadata: None, entropy: Bytes32::default(), + token_payment_info: None, } .into()), version => Err(ProtocolError::UnknownVersionMismatch { @@ -393,13 +405,13 @@ impl SpecializedDocumentFactoryV0 { // #[cfg(feature = "state-transitions")] fn document_create_transitions( - documents: Vec<(Document, DocumentTypeRef, Bytes32)>, + documents: Vec<(Document, DocumentTypeRef, Bytes32, Option)>, nonce_counter: &mut BTreeMap<(Identifier, Identifier), u64>, //IdentityID/ContractID -> nonce platform_version: &PlatformVersion, ) -> Result, ProtocolError> { documents .into_iter() - .map(|(document, document_type, entropy)| { + .map(|(document, document_type, entropy, token_payment_info)| { if document_type.documents_mutable() { //we need to have revisions let Some(revision) = document.revision() else { @@ -423,6 +435,7 @@ impl SpecializedDocumentFactoryV0 { document, document_type, entropy.to_buffer(), + token_payment_info, *nonce, platform_version, None, @@ -438,13 +451,13 @@ impl SpecializedDocumentFactoryV0 { #[cfg(feature = "state-transitions")] fn document_replace_transitions( - documents: Vec<(Document, DocumentTypeRef)>, + documents: Vec<(Document, DocumentTypeRef, Option)>, nonce_counter: &mut BTreeMap<(Identifier, Identifier), u64>, //IdentityID/ContractID -> nonce platform_version: &PlatformVersion, ) -> Result, ProtocolError> { documents .into_iter() - .map(|(mut document, document_type)| { + .map(|(mut document, document_type, token_payment_info)| { if !document_type.documents_mutable() { return Err(DocumentError::TryingToReplaceImmutableDocument { document: Box::new(document), @@ -468,6 +481,7 @@ impl SpecializedDocumentFactoryV0 { let transition = DocumentReplaceTransition::from_document( document, document_type, + token_payment_info, *nonce, platform_version, None, @@ -522,13 +536,13 @@ impl SpecializedDocumentFactoryV0 { #[cfg(feature = "state-transitions")] fn document_delete_transitions( - documents: Vec<(Document, DocumentTypeRef)>, + documents: Vec<(Document, DocumentTypeRef, Option)>, nonce_counter: &mut BTreeMap<(Identifier, Identifier), u64>, //IdentityID/ContractID -> nonce platform_version: &PlatformVersion, ) -> Result, ProtocolError> { documents .into_iter() - .map(|(document, document_type)| { + .map(|(document, document_type, token_payment_info)| { if !document_type.documents_can_be_deleted() { return Err(DocumentError::TryingToDeleteIndelibleDocument { document: Box::new(document), @@ -547,6 +561,7 @@ impl SpecializedDocumentFactoryV0 { let transition = DocumentDeleteTransition::from_document( document, document_type, + token_payment_info, *nonce, platform_version, None, 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..9c883845be4 100644 --- a/packages/rs-dpp/src/errors/consensus/basic/basic_error.rs +++ b/packages/rs-dpp/src/errors/consensus/basic/basic_error.rs @@ -4,7 +4,6 @@ use platform_serialization_derive::{PlatformDeserialize, PlatformSerialize}; use thiserror::Error; use crate::consensus::basic::data_contract::data_contract_max_depth_exceed_error::DataContractMaxDepthExceedError; -use crate::consensus::basic::data_contract::InvalidJsonSchemaRefError; use crate::consensus::basic::data_contract::{ ContestedUniqueIndexOnMutableDocumentTypeError, ContestedUniqueIndexWithUniqueIndexError, DataContractHaveNewUniqueIndexError, DataContractImmutablePropertiesUpdateError, @@ -24,8 +23,12 @@ use crate::consensus::basic::data_contract::{ NonContiguousContractGroupPositionsError, NonContiguousContractTokenPositionsError, SystemPropertyIndexAlreadyPresentError, UndefinedIndexPropertyError, UniqueIndicesLimitReachedError, UnknownDocumentCreationRestrictionModeError, - UnknownSecurityLevelError, UnknownStorageKeyRequirementsError, UnknownTradeModeError, - UnknownTransferableTypeError, + UnknownGasFeesPaidByError, UnknownSecurityLevelError, UnknownStorageKeyRequirementsError, + UnknownTradeModeError, UnknownTransferableTypeError, +}; +use crate::consensus::basic::data_contract::{ + InvalidJsonSchemaRefError, TokenPaymentByBurningOnlyAllowedOnInternalTokenError, + UnknownDocumentActionTokenEffectError, }; use crate::consensus::basic::decode::{ ProtocolVersionParsingError, SerializedObjectParsingError, VersionError, @@ -501,6 +504,17 @@ pub enum BasicError { #[error(transparent)] MissingDefaultLocalizationError(MissingDefaultLocalizationError), + + #[error(transparent)] + UnknownGasFeesPaidByError(UnknownGasFeesPaidByError), + + #[error(transparent)] + UnknownDocumentActionTokenEffectError(UnknownDocumentActionTokenEffectError), + + #[error(transparent)] + TokenPaymentByBurningOnlyAllowedOnInternalTokenError( + TokenPaymentByBurningOnlyAllowedOnInternalTokenError, + ), } impl From for ConsensusError { diff --git a/packages/rs-dpp/src/errors/consensus/basic/data_contract/mod.rs b/packages/rs-dpp/src/errors/consensus/basic/data_contract/mod.rs index 37ad0e0a929..cb59f46d74d 100644 --- a/packages/rs-dpp/src/errors/consensus/basic/data_contract/mod.rs +++ b/packages/rs-dpp/src/errors/consensus/basic/data_contract/mod.rs @@ -34,9 +34,12 @@ mod invalid_token_distribution_function_invalid_parameter_tuple_error; mod non_contiguous_contract_group_positions_error; mod non_contiguous_contract_token_positions_error; mod system_property_index_already_present_error; +mod token_payment_by_burning_only_allowed_on_internal_token_error; mod undefined_index_property_error; mod unique_indices_limit_reached_error; +mod unknown_document_action_token_effect_error; mod unknown_document_creation_restriction_mode_error; +mod unknown_gas_fees_paid_by_error; mod unknown_security_level_error; mod unknown_storage_key_requirements_error; mod unknown_trade_mode_error; @@ -81,7 +84,10 @@ pub use invalid_token_distribution_function_invalid_parameter_error::*; pub use invalid_token_distribution_function_invalid_parameter_tuple_error::*; pub use non_contiguous_contract_group_positions_error::*; pub use non_contiguous_contract_token_positions_error::*; +pub use token_payment_by_burning_only_allowed_on_internal_token_error::*; +pub use unknown_document_action_token_effect_error::*; pub use unknown_document_creation_restriction_mode_error::*; +pub use unknown_gas_fees_paid_by_error::*; pub use unknown_security_level_error::*; pub use unknown_storage_key_requirements_error::*; pub use unknown_trade_mode_error::*; diff --git a/packages/rs-dpp/src/errors/consensus/basic/data_contract/token_payment_by_burning_only_allowed_on_internal_token_error.rs b/packages/rs-dpp/src/errors/consensus/basic/data_contract/token_payment_by_burning_only_allowed_on_internal_token_error.rs new file mode 100644 index 00000000000..65fcd8ed0a7 --- /dev/null +++ b/packages/rs-dpp/src/errors/consensus/basic/data_contract/token_payment_by_burning_only_allowed_on_internal_token_error.rs @@ -0,0 +1,76 @@ +use crate::consensus::basic::BasicError; +use crate::consensus::ConsensusError; +use crate::data_contract::TokenContractPosition; +use crate::tokens::calculate_token_id; +use crate::ProtocolError; +use bincode::{Decode, Encode}; +use platform_serialization_derive::{PlatformDeserialize, PlatformSerialize}; +use platform_value::Identifier; +use std::fmt; +use thiserror::Error; + +#[derive( + Error, Debug, Clone, PartialEq, Eq, Encode, Decode, PlatformSerialize, PlatformDeserialize, +)] +#[platform_serialize(unversioned)] +pub struct TokenPaymentByBurningOnlyAllowedOnInternalTokenError { + external_token_contract_id: Identifier, + external_token_contract_token_position: TokenContractPosition, + action: String, +} + +impl TokenPaymentByBurningOnlyAllowedOnInternalTokenError { + pub fn new( + external_token_contract_id: Identifier, + external_token_contract_token_position: TokenContractPosition, + action: String, + ) -> Self { + Self { + external_token_contract_id, + external_token_contract_token_position, + action, + } + } + + pub fn external_token_contract_id(&self) -> Identifier { + self.external_token_contract_id + } + + pub fn external_token_id(&self) -> Identifier { + calculate_token_id( + self.external_token_contract_id.as_bytes(), + self.external_token_contract_token_position, + ) + .into() + } + + pub fn external_token_contract_token_position(&self) -> TokenContractPosition { + self.external_token_contract_token_position + } + + pub fn action(&self) -> &str { + self.action.as_str() + } +} + +// Custom Display implementation to include external_token_id +impl fmt::Display for TokenPaymentByBurningOnlyAllowedOnInternalTokenError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "Token payments by burning only allowed on internal tokens. \ +Trying to register a contract that burns tokens with id {} from contract {} \ +at position {} for action '{}'.", + self.external_token_id(), + self.external_token_contract_id, + self.external_token_contract_token_position, + self.action + ) + } +} + +impl From for ConsensusError { + fn from(err: TokenPaymentByBurningOnlyAllowedOnInternalTokenError) -> Self { + Self::BasicError(BasicError::TokenPaymentByBurningOnlyAllowedOnInternalTokenError(err)) + } +} diff --git a/packages/rs-dpp/src/errors/consensus/basic/data_contract/unknown_document_action_token_effect_error.rs b/packages/rs-dpp/src/errors/consensus/basic/data_contract/unknown_document_action_token_effect_error.rs new file mode 100644 index 00000000000..f7820172795 --- /dev/null +++ b/packages/rs-dpp/src/errors/consensus/basic/data_contract/unknown_document_action_token_effect_error.rs @@ -0,0 +1,43 @@ +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( + "Unrecognized document action token effect: allowed {:?}, got {}", + allowed_values, + received +)] +#[platform_serialize(unversioned)] +pub struct UnknownDocumentActionTokenEffectError { + allowed_values: Vec, + received: u64, +} + +impl UnknownDocumentActionTokenEffectError { + pub fn new(allowed_values: Vec, received: u64) -> Self { + Self { + allowed_values, + received, + } + } + + pub fn allowed_values(&self) -> &[u8] { + &self.allowed_values + } + + pub fn received(&self) -> u64 { + self.received + } +} + +impl From for ConsensusError { + fn from(err: UnknownDocumentActionTokenEffectError) -> Self { + Self::BasicError(BasicError::UnknownDocumentActionTokenEffectError(err)) + } +} diff --git a/packages/rs-dpp/src/errors/consensus/basic/data_contract/unknown_gas_fees_paid_by_error.rs b/packages/rs-dpp/src/errors/consensus/basic/data_contract/unknown_gas_fees_paid_by_error.rs new file mode 100644 index 00000000000..bd9dbbd4e4f --- /dev/null +++ b/packages/rs-dpp/src/errors/consensus/basic/data_contract/unknown_gas_fees_paid_by_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( + "Unrecognized gas fees paid by mode: allowed {:?}, got {}", + allowed_values, + received +)] +#[platform_serialize(unversioned)] +pub struct UnknownGasFeesPaidByError { + /* + DO NOT CHANGE ORDER OF FIELDS WITHOUT INTRODUCING A NEW VERSION + */ + allowed_values: Vec, + received: u64, +} + +impl UnknownGasFeesPaidByError { + pub fn new(allowed_values: Vec, received: u64) -> Self { + Self { + allowed_values, + received, + } + } + + pub fn allowed_values(&self) -> Vec { + self.allowed_values.clone() + } + + pub fn received(&self) -> u64 { + self.received + } +} + +impl From for ConsensusError { + fn from(err: UnknownGasFeesPaidByError) -> Self { + Self::BasicError(BasicError::UnknownGasFeesPaidByError(err)) + } +} diff --git a/packages/rs-dpp/src/errors/consensus/basic/json_schema_error/error.rs b/packages/rs-dpp/src/errors/consensus/basic/json_schema_error/error.rs index cdfdb081046..780998dc297 100644 --- a/packages/rs-dpp/src/errors/consensus/basic/json_schema_error/error.rs +++ b/packages/rs-dpp/src/errors/consensus/basic/json_schema_error/error.rs @@ -1,3 +1,4 @@ +#[cfg(feature = "json-schema-validation")] use crate::consensus::basic::json_schema_error::error_data::JsonSchemaErrorData; use crate::consensus::basic::BasicError; use crate::consensus::ConsensusError; @@ -7,6 +8,7 @@ use bincode::{Decode, Encode}; use jsonschema::ValidationError; use platform_serialization_derive::{PlatformDeserialize, PlatformSerialize}; use platform_value::Value; +#[cfg(feature = "json-schema-validation")] use serde_json::Value as JsonValue; use thiserror::Error; diff --git a/packages/rs-dpp/src/errors/consensus/basic/json_schema_error/error_data.rs b/packages/rs-dpp/src/errors/consensus/basic/json_schema_error/error_data.rs index a8468aec37f..ad654612356 100644 --- a/packages/rs-dpp/src/errors/consensus/basic/json_schema_error/error_data.rs +++ b/packages/rs-dpp/src/errors/consensus/basic/json_schema_error/error_data.rs @@ -6,7 +6,9 @@ use jsonschema::paths::PathChunk; use jsonschema::ValidationError; use serde::{Deserialize, Serialize}; use serde_json::Value; +#[cfg(feature = "json-schema-validation")] use std::fmt::Write; +#[cfg(feature = "json-schema-validation")] use std::ops::Deref; #[derive(Debug, Serialize, Default, Deserialize)] diff --git a/packages/rs-dpp/src/errors/consensus/codes.rs b/packages/rs-dpp/src/errors/consensus/codes.rs index b6e6b84b738..f58b0f07ccb 100644 --- a/packages/rs-dpp/src/errors/consensus/codes.rs +++ b/packages/rs-dpp/src/errors/consensus/codes.rs @@ -103,6 +103,9 @@ impl ErrorWithCode for BasicError { Self::InvalidTokenDistributionFunctionInvalidParameterTupleError(_) => 10256, Self::InvalidTokenDistributionFunctionIncoherenceError(_) => 10257, Self::MissingDefaultLocalizationError(_) => 10258, + Self::UnknownGasFeesPaidByError(_) => 10259, + Self::UnknownDocumentActionTokenEffectError(_) => 10260, + Self::TokenPaymentByBurningOnlyAllowedOnInternalTokenError(_) => 10261, // Group Errors: 10350-10399 Self::GroupPositionDoesNotExistError(_) => 10350, @@ -245,6 +248,9 @@ impl ErrorWithCode for StateError { Self::DocumentContestIdentityAlreadyContestantError(_) => 40112, Self::DocumentContestDocumentWithSameIdAlreadyPresentError(_) => 40113, Self::DocumentContestNotPaidForError(_) => 40114, + Self::RequiredTokenPaymentInfoNotSetError(_) => 40115, + Self::IdentityHasNotAgreedToPayRequiredTokenAmountError(_) => 40116, + Self::IdentityTryingToPayWithWrongTokenError(_) => 40117, // 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 5fae0f8e0eb..e4b23ef0eb9 100644 --- a/packages/rs-dpp/src/errors/consensus/state/state_error.rs +++ b/packages/rs-dpp/src/errors/consensus/state/state_error.rs @@ -41,7 +41,7 @@ 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, IdentityTokenAccountAlreadyFrozenError, TokenAlreadyPausedError, TokenIsPausedError, TokenNotPausedError, InvalidTokenClaimPropertyMismatch, InvalidTokenClaimNoCurrentRewards, InvalidTokenClaimWrongClaimant, PreProgrammedDistributionTimestampInPastError, TokenTransferRecipientIdentityNotExistError}; +use crate::consensus::state::token::{IdentityDoesNotHaveEnoughTokenBalanceError, IdentityTokenAccountFrozenError, IdentityTokenAccountNotFrozenError, InvalidGroupPositionError, NewAuthorizedActionTakerGroupDoesNotExistError, NewAuthorizedActionTakerIdentityDoesNotExistError, NewAuthorizedActionTakerMainGroupNotSetError, NewTokensDestinationIdentityDoesNotExistError, TokenMintPastMaxSupplyError, TokenSettingMaxSupplyToLessThanCurrentSupplyError, UnauthorizedTokenActionError, IdentityTokenAccountAlreadyFrozenError, TokenAlreadyPausedError, TokenIsPausedError, TokenNotPausedError, InvalidTokenClaimPropertyMismatch, InvalidTokenClaimNoCurrentRewards, InvalidTokenClaimWrongClaimant, PreProgrammedDistributionTimestampInPastError, TokenTransferRecipientIdentityNotExistError, IdentityHasNotAgreedToPayRequiredTokenAmountError, RequiredTokenPaymentInfoNotSetError, IdentityTryingToPayWithWrongTokenError}; 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; @@ -278,6 +278,17 @@ pub enum StateError { #[error(transparent)] PreProgrammedDistributionTimestampInPastError(PreProgrammedDistributionTimestampInPastError), + + #[error(transparent)] + IdentityHasNotAgreedToPayRequiredTokenAmountError( + IdentityHasNotAgreedToPayRequiredTokenAmountError, + ), + + #[error(transparent)] + RequiredTokenPaymentInfoNotSetError(RequiredTokenPaymentInfoNotSetError), + + #[error(transparent)] + IdentityTryingToPayWithWrongTokenError(IdentityTryingToPayWithWrongTokenError), } impl From for ConsensusError { diff --git a/packages/rs-dpp/src/errors/consensus/state/token/identity_has_not_agreed_to_pay_required_token_amount_error.rs b/packages/rs-dpp/src/errors/consensus/state/token/identity_has_not_agreed_to_pay_required_token_amount_error.rs new file mode 100644 index 00000000000..1096cbf929e --- /dev/null +++ b/packages/rs-dpp/src/errors/consensus/state/token/identity_has_not_agreed_to_pay_required_token_amount_error.rs @@ -0,0 +1,73 @@ +use crate::balances::credits::TokenAmount; +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 has not agreed to pay the required token amount for token {}: required {}, min offer {:?}, max offer {:?}, action: {}", + token_id, + required_amount, + identity_min_offer, + identity_max_offer, + action +)] +#[platform_serialize(unversioned)] +pub struct IdentityHasNotAgreedToPayRequiredTokenAmountError { + token_id: Identifier, + required_amount: u64, + identity_min_offer: Option, + identity_max_offer: Option, + action: String, +} + +impl IdentityHasNotAgreedToPayRequiredTokenAmountError { + #[allow(clippy::too_many_arguments)] + pub fn new( + token_id: Identifier, + required_amount: u64, + identity_min_offer: Option, + identity_max_offer: Option, + action: String, + ) -> Self { + Self { + token_id, + required_amount, + identity_min_offer, + identity_max_offer, + action, + } + } + + pub fn token_id(&self) -> &Identifier { + &self.token_id + } + + pub fn required_amount(&self) -> u64 { + self.required_amount + } + + pub fn identity_min_offer(&self) -> Option { + self.identity_min_offer + } + + pub fn identity_max_offer(&self) -> Option { + self.identity_max_offer + } + + pub fn action(&self) -> &str { + &self.action + } +} + +impl From for ConsensusError { + fn from(err: IdentityHasNotAgreedToPayRequiredTokenAmountError) -> Self { + Self::StateError(StateError::IdentityHasNotAgreedToPayRequiredTokenAmountError(err)) + } +} diff --git a/packages/rs-dpp/src/errors/consensus/state/token/identity_trying_to_pay_with_wrong_token_error.rs b/packages/rs-dpp/src/errors/consensus/state/token/identity_trying_to_pay_with_wrong_token_error.rs new file mode 100644 index 00000000000..89e2e730562 --- /dev/null +++ b/packages/rs-dpp/src/errors/consensus/state/token/identity_trying_to_pay_with_wrong_token_error.rs @@ -0,0 +1,99 @@ +use crate::consensus::state::state_error::StateError; +use crate::consensus::ConsensusError; +use crate::data_contract::TokenContractPosition; +use crate::ProtocolError; +use bincode::{Decode, Encode}; +use platform_serialization_derive::{PlatformDeserialize, PlatformSerialize}; +use platform_value::Identifier; + +#[derive(Debug, Clone, PartialEq, Eq, Encode, Decode, PlatformSerialize, PlatformDeserialize)] +#[platform_serialize(unversioned)] +pub struct IdentityTryingToPayWithWrongTokenError { + expected_contract_id: Option, + expected_token_contract_position: TokenContractPosition, + expected_token_id: Identifier, + + actual_contract_id: Option, + actual_token_contract_position: TokenContractPosition, + actual_token_id: Identifier, +} + +impl IdentityTryingToPayWithWrongTokenError { + #[allow(clippy::too_many_arguments)] + pub fn new( + expected_contract_id: Option, + expected_token_contract_position: TokenContractPosition, + expected_token_id: Identifier, + actual_contract_id: Option, + actual_token_contract_position: TokenContractPosition, + actual_token_id: Identifier, + ) -> Self { + Self { + expected_contract_id, + expected_token_contract_position, + expected_token_id, + actual_contract_id, + actual_token_contract_position, + actual_token_id, + } + } + + pub fn expected_contract_id(&self) -> Option { + self.expected_contract_id + } + + pub fn expected_token_contract_position(&self) -> TokenContractPosition { + self.expected_token_contract_position + } + + pub fn expected_token_id(&self) -> &Identifier { + &self.expected_token_id + } + + pub fn actual_contract_id(&self) -> Option { + self.actual_contract_id + } + + pub fn actual_token_contract_position(&self) -> TokenContractPosition { + self.actual_token_contract_position + } + + pub fn actual_token_id(&self) -> &Identifier { + &self.actual_token_id + } +} + +impl std::fmt::Display for IdentityTryingToPayWithWrongTokenError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let expected_contract_display = match &self.expected_contract_id { + Some(id) => format!("{}", id), + None => "Not Expected".to_string(), + }; + + let actual_contract_display = match &self.actual_contract_id { + Some(id) => format!("{}", id), + None => "Not Set".to_string(), + }; + + write!( + f, + "Identity is trying to pay with the wrong token: \ +expected contract ID: {}, position: {}, token ID: {}; \ +actual contract ID: {}, position: {}, token ID: {}", + expected_contract_display, + self.expected_token_contract_position, + self.expected_token_id, + actual_contract_display, + self.actual_token_contract_position, + self.actual_token_id, + ) + } +} + +impl std::error::Error for IdentityTryingToPayWithWrongTokenError {} + +impl From for ConsensusError { + fn from(err: IdentityTryingToPayWithWrongTokenError) -> Self { + Self::StateError(StateError::IdentityTryingToPayWithWrongTokenError(err)) + } +} 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 f1f45d675a4..bd63f021a6c 100644 --- a/packages/rs-dpp/src/errors/consensus/state/token/mod.rs +++ b/packages/rs-dpp/src/errors/consensus/state/token/mod.rs @@ -1,7 +1,9 @@ mod identity_does_not_have_enough_token_balance_error; +mod identity_has_not_agreed_to_pay_required_token_amount_error; mod identity_token_account_already_frozen_error; mod identity_token_account_frozen_error; mod identity_token_account_not_frozen_error; +mod identity_trying_to_pay_with_wrong_token_error; mod invalid_group_position_error; mod invalid_token_claim_no_current_rewards; mod invalid_token_claim_property_mismatch; @@ -11,6 +13,7 @@ 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 pre_programmed_distribution_timestamp_in_past_error; +mod required_token_payment_info_not_set_error; mod token_already_paused_error; mod token_is_paused_error; mod token_mint_past_max_supply_error; @@ -20,9 +23,11 @@ mod token_transfer_recipient_identity_not_exist_error; mod unauthorized_token_action_error; pub use identity_does_not_have_enough_token_balance_error::*; +pub use identity_has_not_agreed_to_pay_required_token_amount_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 identity_trying_to_pay_with_wrong_token_error::*; pub use invalid_group_position_error::*; pub use invalid_token_claim_no_current_rewards::*; pub use invalid_token_claim_property_mismatch::*; @@ -32,6 +37,7 @@ 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 pre_programmed_distribution_timestamp_in_past_error::*; +pub use required_token_payment_info_not_set_error::*; pub use token_already_paused_error::*; pub use token_is_paused_error::*; pub use token_mint_past_max_supply_error::*; diff --git a/packages/rs-dpp/src/errors/consensus/state/token/required_token_payment_info_not_set_error.rs b/packages/rs-dpp/src/errors/consensus/state/token/required_token_payment_info_not_set_error.rs new file mode 100644 index 00000000000..f1a76fe8ab1 --- /dev/null +++ b/packages/rs-dpp/src/errors/consensus/state/token/required_token_payment_info_not_set_error.rs @@ -0,0 +1,41 @@ +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( + "Required token payment info not set on token {} (action: {})", + token_id, + action +)] +#[platform_serialize(unversioned)] +pub struct RequiredTokenPaymentInfoNotSetError { + token_id: Identifier, + action: String, +} + +impl RequiredTokenPaymentInfoNotSetError { + 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 for ConsensusError { + fn from(err: RequiredTokenPaymentInfoNotSetError) -> Self { + Self::StateError(StateError::RequiredTokenPaymentInfoNotSetError(err)) + } +} diff --git a/packages/rs-dpp/src/errors/protocol_error.rs b/packages/rs-dpp/src/errors/protocol_error.rs index 9e358de2df7..e9acd8d26a3 100644 --- a/packages/rs-dpp/src/errors/protocol_error.rs +++ b/packages/rs-dpp/src/errors/protocol_error.rs @@ -284,6 +284,12 @@ pub enum ProtocolError { #[error("missing epoch info: {0}")] MissingEpochInfo(String), + + #[error("Invalid BatchedTransitionAction variant: expected {expected}, found {found}")] + InvalidBatchedTransitionActionVariant { + expected: &'static str, + found: &'static str, + }, } impl From<&str> for ProtocolError { diff --git a/packages/rs-dpp/src/identity/identity_factory.rs b/packages/rs-dpp/src/identity/identity_factory.rs index 48f73698181..2ec10511c20 100644 --- a/packages/rs-dpp/src/identity/identity_factory.rs +++ b/packages/rs-dpp/src/identity/identity_factory.rs @@ -23,8 +23,11 @@ use crate::consensus::basic::BasicError; use crate::consensus::ConsensusError; #[cfg(all(feature = "state-transitions", feature = "client"))] use crate::identity::accessors::IdentityGettersV0; - -#[cfg(all(feature = "validation", feature = "identity-value-conversion"))] +#[cfg(all( + feature = "identity-serialization", + feature = "client", + feature = "validation" +))] use crate::identity::conversion::platform_value::IdentityPlatformValueConversionMethodsV0; #[cfg(all(feature = "state-transitions", feature = "client"))] use crate::identity::core_script::CoreScript; diff --git a/packages/rs-dpp/src/state_transition/serialization.rs b/packages/rs-dpp/src/state_transition/serialization.rs index ff55d2653ab..998c0e017c7 100644 --- a/packages/rs-dpp/src/state_transition/serialization.rs +++ b/packages/rs-dpp/src/state_transition/serialization.rs @@ -335,6 +335,7 @@ mod tests { .document_type_for_name(extended_document.document_type_name()) .unwrap(), *extended_document.entropy(), + None, ) }) .collect::>(); diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_base_transition/fields.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_base_transition/fields.rs index df730f10f96..8ba3d4b2441 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_base_transition/fields.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_base_transition/fields.rs @@ -4,6 +4,7 @@ pub(in crate::state_transition::state_transitions::document::batch_transition) m pub const DOCUMENT_TYPE: &str = "$type"; pub const ACTION: &str = "$action"; pub const IDENTITY_CONTRACT_NONCE: &str = "$identityContractNonce"; + pub const TOKEN_PAYMENT_INFO: &str = "$tokenPaymentInfo"; } pub const IDENTIFIER_FIELDS: [&str; 2] = [property_names::ID, property_names::DATA_CONTRACT_ID]; diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_base_transition/from_document.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_base_transition/from_document.rs index 88c136d585c..d394d50727d 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_base_transition/from_document.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_base_transition/from_document.rs @@ -2,14 +2,18 @@ use crate::data_contract::document_type::DocumentTypeRef; use crate::document::Document; use crate::prelude::IdentityNonce; use crate::state_transition::batch_transition::document_base_transition::v0::DocumentBaseTransitionV0; +use crate::state_transition::batch_transition::document_base_transition::v1::DocumentBaseTransitionV1; use crate::state_transition::batch_transition::document_base_transition::DocumentBaseTransition; +use crate::tokens::token_payment_info::TokenPaymentInfo; use crate::ProtocolError; use platform_version::version::{FeatureVersion, PlatformVersion}; impl DocumentBaseTransition { + #[allow(clippy::too_many_arguments)] pub fn from_document( document: &Document, document_type: DocumentTypeRef, + token_payment_info: Option, identity_contract_nonce: IdentityNonce, platform_version: &PlatformVersion, feature_version: Option, @@ -27,6 +31,13 @@ impl DocumentBaseTransition { identity_contract_nonce, ) .into()), + 1 => Ok(DocumentBaseTransitionV1::from_document( + document, + document_type, + token_payment_info, + identity_contract_nonce, + ) + .into()), version => Err(ProtocolError::UnknownVersionMismatch { method: "DocumentBaseTransition::from_document".to_string(), known_versions: vec![0], diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_base_transition/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_base_transition/mod.rs index d430a12ba79..9f1ed77111c 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_base_transition/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_base_transition/mod.rs @@ -3,6 +3,8 @@ mod fields; mod from_document; pub mod v0; mod v0_methods; +pub mod v1; +mod v1_methods; #[cfg(any( feature = "state-transition-value-conversion", @@ -12,6 +14,7 @@ use crate::data_contract::DataContract; use crate::state_transition::batch_transition::document_base_transition::v0::{ DocumentBaseTransitionV0, DocumentTransitionObjectLike, }; +use crate::state_transition::batch_transition::document_base_transition::v1::DocumentBaseTransitionV1; #[cfg(any( feature = "state-transition-value-conversion", feature = "state-transition-json-conversion" @@ -40,6 +43,8 @@ use std::collections::BTreeMap; pub enum DocumentBaseTransition { #[display("V0({})", "_0")] V0(DocumentBaseTransitionV0), + #[display("V1({})", "_1")] + V1(DocumentBaseTransitionV1), } impl Default for DocumentBaseTransition { diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_base_transition/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_base_transition/v0/mod.rs index 9477075d480..919450b3e30 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_base_transition/v0/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_base_transition/v0/mod.rs @@ -46,7 +46,7 @@ pub struct DocumentBaseTransitionV0 { pub id: Identifier, #[cfg_attr( feature = "state-transition-serde-conversion", - serde(rename = "$identity-contract-nonce") + serde(rename = "$identityContractNonce") )] pub identity_contract_nonce: IdentityNonce, /// Name of document type found int the data contract associated with the `data_contract_id` @@ -68,17 +68,11 @@ impl DocumentBaseTransitionV0 { identity_contract_nonce: IdentityNonce, ) -> Result { Ok(DocumentBaseTransitionV0 { - id: Identifier::from( - map.remove_hash256_bytes(property_names::ID) - .map_err(ProtocolError::ValueError)?, - ), + id: Identifier::from(map.remove_hash256_bytes(property_names::ID)?), identity_contract_nonce, - document_type_name: map - .remove_string(property_names::DOCUMENT_TYPE) - .map_err(ProtocolError::ValueError)?, + document_type_name: map.remove_string(property_names::DOCUMENT_TYPE)?, data_contract_id: Identifier::new( - map.remove_optional_hash256_bytes(property_names::DATA_CONTRACT_ID) - .map_err(ProtocolError::ValueError)? + map.remove_optional_hash256_bytes(property_names::DATA_CONTRACT_ID)? .unwrap_or(data_contract.id().to_buffer()), ), }) @@ -94,7 +88,7 @@ pub trait DocumentTransitionObjectLike { data_contract: DataContract, ) -> Result where - Self: std::marker::Sized; + Self: Sized; #[cfg(feature = "state-transition-value-conversion")] /// Creates the document transition from Raw Object fn from_object( @@ -102,14 +96,14 @@ pub trait DocumentTransitionObjectLike { data_contract: DataContract, ) -> Result where - Self: std::marker::Sized; + Self: Sized; #[cfg(feature = "state-transition-value-conversion")] fn from_value_map( map: BTreeMap, data_contract: DataContract, ) -> Result where - Self: std::marker::Sized; + Self: Sized; #[cfg(feature = "state-transition-value-conversion")] /// Object is an [`platform::Value`] instance that preserves the `Vec` representation diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_base_transition/v0/v0_methods.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_base_transition/v0/v0_methods.rs index f3c6beb7ee1..6047dcf6586 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_base_transition/v0/v0_methods.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_base_transition/v0/v0_methods.rs @@ -14,6 +14,9 @@ pub trait DocumentBaseTransitionV0Methods { /// Returns the document type name. fn document_type_name(&self) -> &String; + /// Returns the document type name as owned. + fn document_type_name_owned(self) -> String; + /// Sets the document type name. fn set_document_type_name(&mut self, document_type_name: String); @@ -40,6 +43,10 @@ impl DocumentBaseTransitionV0Methods for DocumentBaseTransitionV0 { &self.document_type_name } + fn document_type_name_owned(self) -> String { + self.document_type_name + } + fn set_document_type_name(&mut self, document_type_name: String) { self.document_type_name = document_type_name; } diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_base_transition/v0_methods.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_base_transition/v0_methods.rs index 053865b0568..b556e2fee80 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_base_transition/v0_methods.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_base_transition/v0_methods.rs @@ -9,54 +9,69 @@ impl DocumentBaseTransitionV0Methods for DocumentBaseTransition { fn id(&self) -> Identifier { match self { DocumentBaseTransition::V0(v0) => v0.id(), + DocumentBaseTransition::V1(v1) => v1.id(), } } fn set_id(&mut self, id: Identifier) { match self { DocumentBaseTransition::V0(v0) => v0.set_id(id), + DocumentBaseTransition::V1(v1) => v1.set_id(id), } } fn document_type_name(&self) -> &String { match self { DocumentBaseTransition::V0(v0) => v0.document_type_name(), + DocumentBaseTransition::V1(v1) => v1.document_type_name(), + } + } + fn document_type_name_owned(self) -> String { + match self { + DocumentBaseTransition::V0(v0) => v0.document_type_name_owned(), + DocumentBaseTransition::V1(v1) => v1.document_type_name_owned(), } } fn set_document_type_name(&mut self, document_type_name: String) { match self { DocumentBaseTransition::V0(v0) => v0.set_document_type_name(document_type_name), + DocumentBaseTransition::V1(v1) => v1.set_document_type_name(document_type_name), } } fn data_contract_id(&self) -> Identifier { match self { DocumentBaseTransition::V0(v0) => v0.data_contract_id(), + DocumentBaseTransition::V1(v1) => v1.data_contract_id(), } } fn data_contract_id_ref(&self) -> &Identifier { match self { DocumentBaseTransition::V0(v0) => v0.data_contract_id_ref(), + DocumentBaseTransition::V1(v1) => v1.data_contract_id_ref(), } } fn set_data_contract_id(&mut self, data_contract_id: Identifier) { match self { DocumentBaseTransition::V0(v0) => v0.set_data_contract_id(data_contract_id), + DocumentBaseTransition::V1(v1) => v1.set_data_contract_id(data_contract_id), } } fn identity_contract_nonce(&self) -> IdentityNonce { match self { DocumentBaseTransition::V0(v0) => v0.identity_contract_nonce, + DocumentBaseTransition::V1(v1) => v1.identity_contract_nonce, } } fn set_identity_contract_nonce(&mut self, identity_contract_nonce: IdentityNonce) { match self { DocumentBaseTransition::V0(v0) => v0.identity_contract_nonce = identity_contract_nonce, + DocumentBaseTransition::V1(v1) => v1.identity_contract_nonce = identity_contract_nonce, } } } diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_base_transition/v1/from_document.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_base_transition/v1/from_document.rs new file mode 100644 index 00000000000..69c4fd49bfb --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_base_transition/v1/from_document.rs @@ -0,0 +1,23 @@ +use crate::data_contract::document_type::accessors::DocumentTypeV0Getters; +use crate::data_contract::document_type::DocumentTypeRef; +use crate::document::{Document, DocumentV0Getters}; +use crate::prelude::IdentityNonce; +use crate::state_transition::batch_transition::document_base_transition::v1::DocumentBaseTransitionV1; +use crate::tokens::token_payment_info::TokenPaymentInfo; + +impl DocumentBaseTransitionV1 { + pub(in crate::state_transition::state_transitions::document::batch_transition::batched_transition::document_base_transition) fn from_document( + document: &Document, + document_type: DocumentTypeRef, + token_payment_info: Option, + identity_contract_nonce: IdentityNonce, + ) -> Self { + DocumentBaseTransitionV1 { + id: document.id(), + identity_contract_nonce, + document_type_name: document_type.name().to_string(), + data_contract_id: document_type.data_contract_id(), + token_payment_info, + } + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_base_transition/v1/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_base_transition/v1/mod.rs new file mode 100644 index 00000000000..b4e9106422c --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_base_transition/v1/mod.rs @@ -0,0 +1,93 @@ +pub mod from_document; +pub mod v1_methods; + +#[cfg(feature = "state-transition-value-conversion")] +use std::collections::BTreeMap; + +use bincode::{Decode, Encode}; +use derive_more::Display; + +#[cfg(feature = "state-transition-value-conversion")] +use crate::data_contract::accessors::v0::DataContractV0Getters; +use crate::identifier::Identifier; +use crate::prelude::IdentityNonce; +#[cfg(feature = "state-transition-value-conversion")] +use crate::state_transition::batch_transition::document_base_transition::property_names; +use crate::tokens::token_payment_info::TokenPaymentInfo; +#[cfg(any( + feature = "state-transition-json-conversion", + feature = "state-transition-value-conversion" +))] +use crate::{data_contract::DataContract, errors::ProtocolError}; +#[cfg(feature = "state-transition-value-conversion")] +use platform_value::btreemap_extensions::BTreeValueRemoveFromMapHelper; +#[cfg(feature = "state-transition-value-conversion")] +use platform_value::Value; +#[cfg(feature = "state-transition-serde-conversion")] +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Clone, Encode, Decode, Default, PartialEq, Display)] +#[cfg_attr( + feature = "state-transition-serde-conversion", + derive(Serialize, Deserialize), + serde(rename_all = "camelCase") +)] +#[display( + "ID: {}, Type: {}, Contract ID: {}", + "id", + "document_type_name", + "data_contract_id" +)] +pub struct DocumentBaseTransitionV1 { + /// The document ID + #[cfg_attr(feature = "state-transition-serde-conversion", serde(rename = "$id"))] + pub id: Identifier, + #[cfg_attr( + feature = "state-transition-serde-conversion", + serde(rename = "$identityContractNonce") + )] + pub identity_contract_nonce: IdentityNonce, + /// Name of document type found int the data contract associated with the `data_contract_id` + #[cfg_attr(feature = "state-transition-serde-conversion", serde(rename = "$type"))] + pub document_type_name: String, + /// Data contract ID generated from the data contract's `owner_id` and `entropy` + #[cfg_attr( + feature = "state-transition-serde-conversion", + serde(rename = "$dataContractId") + )] + pub data_contract_id: Identifier, + /// An optional Token Payment Info + #[cfg_attr( + feature = "state-transition-serde-conversion", + serde(default, rename = "$tokenPaymentInfo") + )] + pub token_payment_info: Option, +} + +#[cfg(feature = "state-transition-value-conversion")] +impl DocumentBaseTransitionV1 { + pub fn from_value_map_consume( + map: &mut BTreeMap, + data_contract: DataContract, + identity_contract_nonce: IdentityNonce, + ) -> Result { + let inner_token_payment_info_map: Option> = map + .remove_optional_map_as_btree_map_keep_values_as_platform_value( + property_names::TOKEN_PAYMENT_INFO, + ) + .ok() + .flatten(); + Ok(DocumentBaseTransitionV1 { + id: Identifier::from(map.remove_hash256_bytes(property_names::ID)?), + identity_contract_nonce, + document_type_name: map.remove_string(property_names::DOCUMENT_TYPE)?, + data_contract_id: Identifier::new( + map.remove_optional_hash256_bytes(property_names::DATA_CONTRACT_ID)? + .unwrap_or(data_contract.id().to_buffer()), + ), + token_payment_info: inner_token_payment_info_map + .map(|map| map.try_into()) + .transpose()?, + }) + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_base_transition/v1/v1_methods.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_base_transition/v1/v1_methods.rs new file mode 100644 index 00000000000..1d185790619 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_base_transition/v1/v1_methods.rs @@ -0,0 +1,80 @@ +use crate::prelude::IdentityNonce; +use crate::state_transition::batch_transition::document_base_transition::v0::v0_methods::DocumentBaseTransitionV0Methods; +use crate::state_transition::batch_transition::document_base_transition::v1::DocumentBaseTransitionV1; +use crate::tokens::token_payment_info::TokenPaymentInfo; +use platform_value::Identifier; + +/// A trait that contains getter and setter methods for `DocumentBaseTransitionV0` +pub trait DocumentBaseTransitionV1Methods: DocumentBaseTransitionV0Methods { + /// Returns the token payment info. + fn token_payment_info(&self) -> Option; + + /// Returns the token payment info. + fn token_payment_info_ref(&self) -> &Option; + + /// Sets the token payment info. + fn set_token_payment_info(&mut self, token_payment_info: TokenPaymentInfo); + + /// Clears the token payment info. + fn clear_token_payment_info(&mut self); +} + +impl DocumentBaseTransitionV1Methods for DocumentBaseTransitionV1 { + fn token_payment_info(&self) -> Option { + self.token_payment_info + } + + fn token_payment_info_ref(&self) -> &Option { + &self.token_payment_info + } + + fn set_token_payment_info(&mut self, token_payment_info: TokenPaymentInfo) { + self.token_payment_info = Some(token_payment_info); + } + + fn clear_token_payment_info(&mut self) { + self.token_payment_info = None; + } +} + +impl DocumentBaseTransitionV0Methods for DocumentBaseTransitionV1 { + fn id(&self) -> Identifier { + self.id + } + + fn set_id(&mut self, id: Identifier) { + self.id = id; + } + + fn document_type_name(&self) -> &String { + &self.document_type_name + } + + fn document_type_name_owned(self) -> String { + self.document_type_name + } + + fn set_document_type_name(&mut self, document_type_name: String) { + self.document_type_name = document_type_name; + } + + fn data_contract_id(&self) -> Identifier { + self.data_contract_id + } + + fn data_contract_id_ref(&self) -> &Identifier { + &self.data_contract_id + } + + fn set_data_contract_id(&mut self, data_contract_id: Identifier) { + self.data_contract_id = data_contract_id; + } + + fn identity_contract_nonce(&self) -> IdentityNonce { + self.identity_contract_nonce + } + + fn set_identity_contract_nonce(&mut self, identity_contract_nonce: IdentityNonce) { + self.identity_contract_nonce = identity_contract_nonce; + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_base_transition/v1_methods.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_base_transition/v1_methods.rs new file mode 100644 index 00000000000..bc4538dccba --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_base_transition/v1_methods.rs @@ -0,0 +1,33 @@ +use crate::state_transition::batch_transition::document_base_transition::v1::v1_methods::DocumentBaseTransitionV1Methods; +use crate::state_transition::batch_transition::document_base_transition::DocumentBaseTransition; +use crate::tokens::token_payment_info::TokenPaymentInfo; + +impl DocumentBaseTransitionV1Methods for DocumentBaseTransition { + fn token_payment_info(&self) -> Option { + match self { + DocumentBaseTransition::V0(_) => None, + DocumentBaseTransition::V1(v1) => v1.token_payment_info, + } + } + + fn token_payment_info_ref(&self) -> &Option { + match self { + DocumentBaseTransition::V0(_) => &None, + DocumentBaseTransition::V1(v1) => v1.token_payment_info_ref(), + } + } + + fn set_token_payment_info(&mut self, token_payment_info: TokenPaymentInfo) { + match self { + DocumentBaseTransition::V0(_) => {} + DocumentBaseTransition::V1(v1) => v1.set_token_payment_info(token_payment_info), + } + } + + fn clear_token_payment_info(&mut self) { + match self { + DocumentBaseTransition::V0(_) => {} + DocumentBaseTransition::V1(v1) => v1.clear_token_payment_info(), + } + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_create_transition/convertible.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_create_transition/convertible.rs index b1d5a81ed0e..bfa829a274a 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_create_transition/convertible.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_create_transition/convertible.rs @@ -34,8 +34,10 @@ use crate::ProtocolError; feature = "state-transition-json-conversion", feature = "state-transition-value-conversion" ))] +use platform_value::btreemap_extensions::BTreeValueRemoveFromMapHelper; +#[cfg(feature = "state-transition-json-conversion")] use platform_value::btreemap_extensions::{ - BTreeValueMapHelper, BTreeValueMapReplacementPathHelper, BTreeValueRemoveFromMapHelper, + BTreeValueMapHelper, BTreeValueMapReplacementPathHelper, }; #[cfg(feature = "state-transition-json-conversion")] use platform_value::ReplacementType; 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..1916f706032 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 @@ -3,14 +3,17 @@ use crate::document::Document; use crate::prelude::IdentityNonce; use crate::state_transition::batch_transition::batched_transition::DocumentCreateTransition; use crate::state_transition::batch_transition::document_create_transition::DocumentCreateTransitionV0; +use crate::tokens::token_payment_info::TokenPaymentInfo; use crate::ProtocolError; use platform_version::version::{FeatureVersion, PlatformVersion}; impl DocumentCreateTransition { + #[allow(clippy::too_many_arguments)] pub fn from_document( document: Document, document_type: DocumentTypeRef, entropy: [u8; 32], + token_payment_info: Option, identity_contract_nonce: IdentityNonce, platform_version: &PlatformVersion, feature_version: Option, @@ -28,6 +31,7 @@ impl DocumentCreateTransition { document, document_type, entropy, + token_payment_info, identity_contract_nonce, platform_version, base_feature_version, 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..126062a1659 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 @@ -4,6 +4,7 @@ use crate::document::{Document, DocumentV0Getters}; use crate::prelude::IdentityNonce; use crate::state_transition::batch_transition::document_base_transition::DocumentBaseTransition; use crate::state_transition::batch_transition::document_create_transition::DocumentCreateTransitionV0; +use crate::tokens::token_payment_info::TokenPaymentInfo; use crate::ProtocolError; use platform_version::version::{FeatureVersion, PlatformVersion}; @@ -12,6 +13,7 @@ impl DocumentCreateTransitionV0 { document: Document, document_type: DocumentTypeRef, entropy: [u8; 32], + token_payment_info: Option, identity_contract_nonce: IdentityNonce, platform_version: &PlatformVersion, base_feature_version: Option, @@ -22,6 +24,7 @@ impl DocumentCreateTransitionV0 { base: DocumentBaseTransition::from_document( &document, document_type, + token_payment_info, identity_contract_nonce, platform_version, base_feature_version, 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..e9e2643caf4 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 @@ -24,6 +24,7 @@ use crate::data_contract::document_type::methods::DocumentTypeBasicMethods; use crate::data_contract::document_type::DocumentTypeRef; use crate::document::{Document, DocumentV0}; use crate::fee::Credits; +#[cfg(feature = "state-transition-value-conversion")] use crate::state_transition::batch_transition::document_base_transition::v0::DocumentBaseTransitionV0; #[cfg(feature = "state-transition-value-conversion")] use crate::state_transition::batch_transition::document_base_transition::v0::DocumentTransitionObjectLike; @@ -35,6 +36,7 @@ use platform_version::version::PlatformVersion; #[cfg(feature = "state-transition-value-conversion")] use crate::state_transition::batch_transition; +use crate::state_transition::batch_transition::document_base_transition::v0::v0_methods::DocumentBaseTransitionV0Methods; mod property_names { pub const ENTROPY: &str = "$entropy"; @@ -195,92 +197,86 @@ impl DocumentFromCreateTransitionV0 for Document { { let DocumentCreateTransitionV0 { base, data, .. } = v0; - match base { - DocumentBaseTransition::V0(base_v0) => { - let DocumentBaseTransitionV0 { id, .. } = base_v0; - - let requires_created_at = document_type - .required_fields() - .contains(document::property_names::CREATED_AT); - let requires_updated_at = document_type - .required_fields() - .contains(document::property_names::UPDATED_AT); - - let requires_created_at_block_height = document_type - .required_fields() - .contains(document::property_names::CREATED_AT_BLOCK_HEIGHT); - let requires_updated_at_block_height = document_type - .required_fields() - .contains(document::property_names::UPDATED_AT_BLOCK_HEIGHT); - - let requires_created_at_core_block_height = document_type - .required_fields() - .contains(document::property_names::CREATED_AT_CORE_BLOCK_HEIGHT); - let requires_updated_at_core_block_height = document_type - .required_fields() - .contains(document::property_names::UPDATED_AT_CORE_BLOCK_HEIGHT); - - let created_at = if requires_created_at { - Some(block_info.time_ms) - } else { - None - }; - let updated_at = if requires_updated_at { - Some(block_info.time_ms) - } else { - None - }; - - let created_at_block_height = if requires_created_at_block_height { - Some(block_info.height) - } else { - None - }; - let updated_at_block_height = if requires_updated_at_block_height { - Some(block_info.height) - } else { - None - }; - - let created_at_core_block_height = if requires_created_at_core_block_height { - Some(block_info.core_height) - } else { - None - }; - let updated_at_core_block_height = if requires_updated_at_core_block_height { - Some(block_info.core_height) - } else { - None - }; - - match platform_version - .dpp - .document_versions - .document_structure_version - { - 0 => Ok(DocumentV0 { - id, - owner_id, - properties: data, - revision: document_type.initial_revision(), - created_at, - updated_at, - transferred_at: None, - created_at_block_height, - updated_at_block_height, - transferred_at_block_height: None, - created_at_core_block_height, - updated_at_core_block_height, - transferred_at_core_block_height: None, - } - .into()), - version => Err(ProtocolError::UnknownVersionMismatch { - method: "Document::try_from_create_transition_v0".to_string(), - known_versions: vec![0], - received: version, - }), - } + let requires_created_at = document_type + .required_fields() + .contains(document::property_names::CREATED_AT); + let requires_updated_at = document_type + .required_fields() + .contains(document::property_names::UPDATED_AT); + + let requires_created_at_block_height = document_type + .required_fields() + .contains(document::property_names::CREATED_AT_BLOCK_HEIGHT); + let requires_updated_at_block_height = document_type + .required_fields() + .contains(document::property_names::UPDATED_AT_BLOCK_HEIGHT); + + let requires_created_at_core_block_height = document_type + .required_fields() + .contains(document::property_names::CREATED_AT_CORE_BLOCK_HEIGHT); + let requires_updated_at_core_block_height = document_type + .required_fields() + .contains(document::property_names::UPDATED_AT_CORE_BLOCK_HEIGHT); + + let created_at = if requires_created_at { + Some(block_info.time_ms) + } else { + None + }; + let updated_at = if requires_updated_at { + Some(block_info.time_ms) + } else { + None + }; + + let created_at_block_height = if requires_created_at_block_height { + Some(block_info.height) + } else { + None + }; + let updated_at_block_height = if requires_updated_at_block_height { + Some(block_info.height) + } else { + None + }; + + let created_at_core_block_height = if requires_created_at_core_block_height { + Some(block_info.core_height) + } else { + None + }; + let updated_at_core_block_height = if requires_updated_at_core_block_height { + Some(block_info.core_height) + } else { + None + }; + + match platform_version + .dpp + .document_versions + .document_structure_version + { + 0 => Ok(DocumentV0 { + id: base.id(), + owner_id, + properties: data, + revision: document_type.initial_revision(), + created_at, + updated_at, + transferred_at: None, + created_at_block_height, + updated_at_block_height, + transferred_at_block_height: None, + created_at_core_block_height, + updated_at_core_block_height, + transferred_at_core_block_height: None, } + .into()), + version => Err(ProtocolError::UnknownVersionMismatch { + method: "Document::try_from_create_transition_v0".to_string(), + known_versions: vec![0], + received: version, + }), } } @@ -296,92 +292,86 @@ impl DocumentFromCreateTransitionV0 for Document { { let DocumentCreateTransitionV0 { base, data, .. } = v0; - match base { - DocumentBaseTransition::V0(base_v0) => { - let DocumentBaseTransitionV0 { id, .. } = base_v0; - - let requires_created_at = document_type - .required_fields() - .contains(document::property_names::CREATED_AT); - let requires_updated_at = document_type - .required_fields() - .contains(document::property_names::UPDATED_AT); - - let requires_created_at_block_height = document_type - .required_fields() - .contains(document::property_names::CREATED_AT_BLOCK_HEIGHT); - let requires_updated_at_block_height = document_type - .required_fields() - .contains(document::property_names::UPDATED_AT_BLOCK_HEIGHT); - - let requires_created_at_core_block_height = document_type - .required_fields() - .contains(document::property_names::CREATED_AT_CORE_BLOCK_HEIGHT); - let requires_updated_at_core_block_height = document_type - .required_fields() - .contains(document::property_names::UPDATED_AT_CORE_BLOCK_HEIGHT); - - let created_at = if requires_created_at { - Some(block_info.time_ms) - } else { - None - }; - let updated_at = if requires_updated_at { - Some(block_info.time_ms) - } else { - None - }; - - let created_at_block_height = if requires_created_at_block_height { - Some(block_info.height) - } else { - None - }; - let updated_at_block_height = if requires_updated_at_block_height { - Some(block_info.height) - } else { - None - }; - - let created_at_core_block_height = if requires_created_at_core_block_height { - Some(block_info.core_height) - } else { - None - }; - let updated_at_core_block_height = if requires_updated_at_core_block_height { - Some(block_info.core_height) - } else { - None - }; - - match platform_version - .dpp - .document_versions - .document_structure_version - { - 0 => Ok(DocumentV0 { - id: *id, - owner_id, - properties: data.clone(), - revision: document_type.initial_revision(), - created_at, - updated_at, - transferred_at: None, - created_at_block_height, - updated_at_block_height, - transferred_at_block_height: None, - created_at_core_block_height, - updated_at_core_block_height, - transferred_at_core_block_height: None, - } - .into()), - version => Err(ProtocolError::UnknownVersionMismatch { - method: "Document::try_from_owned_create_transition_v0".to_string(), - known_versions: vec![0], - received: version, - }), - } + let requires_created_at = document_type + .required_fields() + .contains(document::property_names::CREATED_AT); + let requires_updated_at = document_type + .required_fields() + .contains(document::property_names::UPDATED_AT); + + let requires_created_at_block_height = document_type + .required_fields() + .contains(document::property_names::CREATED_AT_BLOCK_HEIGHT); + let requires_updated_at_block_height = document_type + .required_fields() + .contains(document::property_names::UPDATED_AT_BLOCK_HEIGHT); + + let requires_created_at_core_block_height = document_type + .required_fields() + .contains(document::property_names::CREATED_AT_CORE_BLOCK_HEIGHT); + let requires_updated_at_core_block_height = document_type + .required_fields() + .contains(document::property_names::UPDATED_AT_CORE_BLOCK_HEIGHT); + + let created_at = if requires_created_at { + Some(block_info.time_ms) + } else { + None + }; + let updated_at = if requires_updated_at { + Some(block_info.time_ms) + } else { + None + }; + + let created_at_block_height = if requires_created_at_block_height { + Some(block_info.height) + } else { + None + }; + let updated_at_block_height = if requires_updated_at_block_height { + Some(block_info.height) + } else { + None + }; + + let created_at_core_block_height = if requires_created_at_core_block_height { + Some(block_info.core_height) + } else { + None + }; + let updated_at_core_block_height = if requires_updated_at_core_block_height { + Some(block_info.core_height) + } else { + None + }; + + match platform_version + .dpp + .document_versions + .document_structure_version + { + 0 => Ok(DocumentV0 { + id: base.id(), + owner_id, + properties: data.clone(), + revision: document_type.initial_revision(), + created_at, + updated_at, + transferred_at: None, + created_at_block_height, + updated_at_block_height, + transferred_at_block_height: None, + created_at_core_block_height, + updated_at_core_block_height, + transferred_at_core_block_height: None, } + .into()), + version => Err(ProtocolError::UnknownVersionMismatch { + method: "Document::try_from_owned_create_transition_v0".to_string(), + known_versions: vec![0], + received: version, + }), } } } diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_delete_transition/from_document.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_delete_transition/from_document.rs index a3eafe8c329..4af388b6b76 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_delete_transition/from_document.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_delete_transition/from_document.rs @@ -6,11 +6,14 @@ use platform_version::version::{FeatureVersion, PlatformVersion}; use crate::state_transition::batch_transition::batched_transition::document_delete_transition::DocumentDeleteTransitionV0; use crate::state_transition::batch_transition::batched_transition::DocumentDeleteTransition; +use crate::tokens::token_payment_info::TokenPaymentInfo; impl DocumentDeleteTransition { + #[allow(clippy::too_many_arguments)] pub fn from_document( document: Document, document_type: DocumentTypeRef, + token_payment_info: Option, identity_contract_nonce: IdentityNonce, platform_version: &PlatformVersion, feature_version: Option, @@ -27,6 +30,7 @@ impl DocumentDeleteTransition { 0 => Ok(DocumentDeleteTransitionV0::from_document( document, document_type, + token_payment_info, identity_contract_nonce, platform_version, base_feature_version, diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_delete_transition/v0/from_document.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_delete_transition/v0/from_document.rs index 9a939350289..df7b4d2d77a 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_delete_transition/v0/from_document.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_delete_transition/v0/from_document.rs @@ -3,6 +3,7 @@ use crate::document::Document; use crate::prelude::IdentityNonce; use crate::state_transition::batch_transition::batched_transition::document_delete_transition::DocumentDeleteTransitionV0; use crate::state_transition::batch_transition::document_base_transition::DocumentBaseTransition; +use crate::tokens::token_payment_info::TokenPaymentInfo; use crate::ProtocolError; use platform_version::version::{FeatureVersion, PlatformVersion}; @@ -10,6 +11,7 @@ impl DocumentDeleteTransitionV0 { pub(crate) fn from_document( document: Document, document_type: DocumentTypeRef, + token_payment_info: Option, identity_contract_nonce: IdentityNonce, platform_version: &PlatformVersion, base_feature_version: Option, @@ -18,6 +20,7 @@ impl DocumentDeleteTransitionV0 { base: DocumentBaseTransition::from_document( &document, document_type, + token_payment_info, identity_contract_nonce, platform_version, base_feature_version, diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_purchase_transition/from_document.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_purchase_transition/from_document.rs index b7f24dc3d1e..5c92946a2fb 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_purchase_transition/from_document.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_purchase_transition/from_document.rs @@ -7,12 +7,15 @@ use platform_version::version::{FeatureVersion, PlatformVersion}; use crate::state_transition::batch_transition::batched_transition::document_purchase_transition::DocumentPurchaseTransitionV0; use crate::state_transition::batch_transition::batched_transition::DocumentPurchaseTransition; +use crate::tokens::token_payment_info::TokenPaymentInfo; impl DocumentPurchaseTransition { + #[allow(clippy::too_many_arguments)] pub fn from_document( document: Document, document_type: DocumentTypeRef, price: Credits, + token_payment_info: Option, identity_contract_nonce: IdentityNonce, platform_version: &PlatformVersion, feature_version: Option, @@ -30,6 +33,7 @@ impl DocumentPurchaseTransition { document, document_type, price, + token_payment_info, identity_contract_nonce, platform_version, base_feature_version, diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_purchase_transition/v0/from_document.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_purchase_transition/v0/from_document.rs index 9c2eb59f76e..d25745fa30b 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_purchase_transition/v0/from_document.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_purchase_transition/v0/from_document.rs @@ -5,6 +5,7 @@ use crate::fee::Credits; use crate::prelude::IdentityNonce; use crate::state_transition::batch_transition::batched_transition::document_purchase_transition::DocumentPurchaseTransitionV0; use crate::state_transition::batch_transition::document_base_transition::DocumentBaseTransition; +use crate::tokens::token_payment_info::TokenPaymentInfo; use crate::ProtocolError; use platform_version::version::{FeatureVersion, PlatformVersion}; @@ -13,6 +14,7 @@ impl DocumentPurchaseTransitionV0 { document: Document, document_type: DocumentTypeRef, price: Credits, + token_payment_info: Option, identity_contract_nonce: IdentityNonce, platform_version: &PlatformVersion, base_feature_version: Option, @@ -29,6 +31,7 @@ impl DocumentPurchaseTransitionV0 { base: DocumentBaseTransition::from_document( &document, document_type, + token_payment_info, identity_contract_nonce, platform_version, base_feature_version, diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_replace_transition/from_document.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_replace_transition/from_document.rs index 1d2923a1f34..373ccf4aa00 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_replace_transition/from_document.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_replace_transition/from_document.rs @@ -3,13 +3,16 @@ use crate::document::Document; use crate::prelude::IdentityNonce; use crate::state_transition::batch_transition::batched_transition::document_replace_transition::DocumentReplaceTransitionV0; use crate::state_transition::batch_transition::batched_transition::DocumentReplaceTransition; +use crate::tokens::token_payment_info::TokenPaymentInfo; use crate::ProtocolError; use platform_version::version::{FeatureVersion, PlatformVersion}; impl DocumentReplaceTransition { + #[allow(clippy::too_many_arguments)] pub fn from_document( document: Document, document_type: DocumentTypeRef, + token_payment_info: Option, identity_contract_nonce: IdentityNonce, platform_version: &PlatformVersion, feature_version: Option, @@ -26,6 +29,7 @@ impl DocumentReplaceTransition { 0 => Ok(DocumentReplaceTransitionV0::from_document( document, document_type, + token_payment_info, identity_contract_nonce, platform_version, base_feature_version, diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_replace_transition/v0/from_document.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_replace_transition/v0/from_document.rs index 4b5903c87ab..c51afdfceb4 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_replace_transition/v0/from_document.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_replace_transition/v0/from_document.rs @@ -4,6 +4,7 @@ use crate::document::{Document, DocumentV0Getters}; use crate::prelude::IdentityNonce; use crate::state_transition::batch_transition::batched_transition::document_replace_transition::DocumentReplaceTransitionV0; use crate::state_transition::batch_transition::document_base_transition::DocumentBaseTransition; +use crate::tokens::token_payment_info::TokenPaymentInfo; use crate::ProtocolError; use platform_version::version::{FeatureVersion, PlatformVersion}; @@ -11,6 +12,7 @@ impl DocumentReplaceTransitionV0 { pub(crate) fn from_document( document: Document, document_type: DocumentTypeRef, + token_payment_info: Option, identity_contract_nonce: IdentityNonce, platform_version: &PlatformVersion, base_feature_version: Option, @@ -19,6 +21,7 @@ impl DocumentReplaceTransitionV0 { base: DocumentBaseTransition::from_document( &document, document_type, + token_payment_info, identity_contract_nonce, platform_version, base_feature_version, diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_transfer_transition/from_document.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_transfer_transition/from_document.rs index 17d0166f09f..5b16c302d6c 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_transfer_transition/from_document.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_transfer_transition/from_document.rs @@ -4,14 +4,17 @@ use crate::prelude::IdentityNonce; use crate::state_transition::batch_transition::batched_transition::document_transfer_transition::{ DocumentTransferTransition, DocumentTransferTransitionV0, }; +use crate::tokens::token_payment_info::TokenPaymentInfo; use crate::ProtocolError; use platform_value::Identifier; use platform_version::version::{FeatureVersion, PlatformVersion}; impl DocumentTransferTransition { + #[allow(clippy::too_many_arguments)] pub fn from_document( document: Document, document_type: DocumentTypeRef, + token_payment_info: Option, identity_contract_nonce: IdentityNonce, recipient_owner_id: Identifier, platform_version: &PlatformVersion, @@ -29,6 +32,7 @@ impl DocumentTransferTransition { 0 => Ok(DocumentTransferTransitionV0::from_document( document, document_type, + token_payment_info, identity_contract_nonce, recipient_owner_id, platform_version, diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_transfer_transition/v0/from_document.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_transfer_transition/v0/from_document.rs index 7f182eb46a6..bed0d5dba00 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_transfer_transition/v0/from_document.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_transfer_transition/v0/from_document.rs @@ -4,6 +4,7 @@ use crate::document::{Document, DocumentV0Getters}; use crate::prelude::IdentityNonce; use crate::state_transition::batch_transition::batched_transition::document_transfer_transition::DocumentTransferTransitionV0; use crate::state_transition::batch_transition::document_base_transition::DocumentBaseTransition; +use crate::tokens::token_payment_info::TokenPaymentInfo; use crate::ProtocolError; use platform_value::Identifier; use platform_version::version::{FeatureVersion, PlatformVersion}; @@ -12,6 +13,7 @@ impl DocumentTransferTransitionV0 { pub(crate) fn from_document( document: Document, document_type: DocumentTypeRef, + token_payment_info: Option, identity_contract_nonce: IdentityNonce, recipient_owner_id: Identifier, platform_version: &PlatformVersion, @@ -21,6 +23,7 @@ impl DocumentTransferTransitionV0 { base: DocumentBaseTransition::from_document( &document, document_type, + token_payment_info, identity_contract_nonce, platform_version, base_feature_version, diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_update_price_transition/from_document.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_update_price_transition/from_document.rs index 39e2877d601..331f2c677cb 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_update_price_transition/from_document.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_update_price_transition/from_document.rs @@ -6,12 +6,15 @@ use crate::prelude::IdentityNonce; use crate::ProtocolError; use crate::state_transition::batch_transition::batched_transition::DocumentUpdatePriceTransition; use crate::state_transition::batch_transition::batched_transition::document_update_price_transition::DocumentUpdatePriceTransitionV0; +use crate::tokens::token_payment_info::TokenPaymentInfo; impl DocumentUpdatePriceTransition { + #[allow(clippy::too_many_arguments)] pub fn from_document( document: Document, document_type: DocumentTypeRef, price: Credits, + token_payment_info: Option, identity_contract_nonce: IdentityNonce, platform_version: &PlatformVersion, feature_version: Option, @@ -29,6 +32,7 @@ impl DocumentUpdatePriceTransition { document, document_type, price, + token_payment_info, identity_contract_nonce, platform_version, base_feature_version, diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_update_price_transition/v0/from_document.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_update_price_transition/v0/from_document.rs index 2a6c7785872..d190ca6ffdb 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_update_price_transition/v0/from_document.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_update_price_transition/v0/from_document.rs @@ -7,12 +7,14 @@ use crate::prelude::IdentityNonce; use crate::ProtocolError; use crate::state_transition::batch_transition::document_base_transition::DocumentBaseTransition; use crate::state_transition::batch_transition::batched_transition::document_update_price_transition::DocumentUpdatePriceTransitionV0; +use crate::tokens::token_payment_info::TokenPaymentInfo; impl DocumentUpdatePriceTransitionV0 { pub(crate) fn from_document( document: Document, document_type: DocumentTypeRef, price: Credits, + token_payment_info: Option, identity_contract_nonce: IdentityNonce, platform_version: &PlatformVersion, base_feature_version: Option, @@ -21,6 +23,7 @@ impl DocumentUpdatePriceTransitionV0 { base: DocumentBaseTransition::from_document( &document, document_type, + token_payment_info, identity_contract_nonce, platform_version, base_feature_version, diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/methods/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/methods/mod.rs index afe15fccbb4..7404683fd53 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/methods/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/methods/mod.rs @@ -31,6 +31,8 @@ use crate::state_transition::StateTransition; #[cfg(feature = "state-transition-signing")] use crate::tokens::emergency_action::TokenEmergencyAction; #[cfg(feature = "state-transition-signing")] +use crate::tokens::token_payment_info::TokenPaymentInfo; +#[cfg(feature = "state-transition-signing")] use crate::tokens::{PrivateEncryptedNote, SharedEncryptedNote}; use crate::ProtocolError; #[cfg(feature = "state-transition-signing")] @@ -80,6 +82,7 @@ impl DocumentsBatchTransitionMethodsV0 for BatchTransition { identity_public_key: &IdentityPublicKey, identity_contract_nonce: IdentityNonce, user_fee_increase: UserFeeIncrease, + token_payment_info: Option, signer: &S, platform_version: &PlatformVersion, batch_feature_version: Option, @@ -101,6 +104,7 @@ impl DocumentsBatchTransitionMethodsV0 for BatchTransition { identity_public_key, identity_contract_nonce, user_fee_increase, + token_payment_info, signer, platform_version, batch_feature_version, @@ -116,6 +120,7 @@ impl DocumentsBatchTransitionMethodsV0 for BatchTransition { identity_public_key, identity_contract_nonce, user_fee_increase, + token_payment_info, signer, platform_version, batch_feature_version, @@ -138,6 +143,7 @@ impl DocumentsBatchTransitionMethodsV0 for BatchTransition { identity_public_key: &IdentityPublicKey, identity_contract_nonce: IdentityNonce, user_fee_increase: UserFeeIncrease, + token_payment_info: Option, signer: &S, platform_version: &PlatformVersion, batch_feature_version: Option, @@ -158,6 +164,7 @@ impl DocumentsBatchTransitionMethodsV0 for BatchTransition { identity_public_key, identity_contract_nonce, user_fee_increase, + token_payment_info, signer, platform_version, batch_feature_version, @@ -172,6 +179,7 @@ impl DocumentsBatchTransitionMethodsV0 for BatchTransition { identity_public_key, identity_contract_nonce, user_fee_increase, + token_payment_info, signer, platform_version, batch_feature_version, @@ -197,6 +205,7 @@ impl DocumentsBatchTransitionMethodsV0 for BatchTransition { identity_public_key: &IdentityPublicKey, identity_contract_nonce: IdentityNonce, user_fee_increase: UserFeeIncrease, + token_payment_info: Option, signer: &S, platform_version: &PlatformVersion, batch_feature_version: Option, @@ -218,6 +227,7 @@ impl DocumentsBatchTransitionMethodsV0 for BatchTransition { identity_public_key, identity_contract_nonce, user_fee_increase, + token_payment_info, signer, platform_version, batch_feature_version, @@ -233,6 +243,7 @@ impl DocumentsBatchTransitionMethodsV0 for BatchTransition { identity_public_key, identity_contract_nonce, user_fee_increase, + token_payment_info, signer, platform_version, batch_feature_version, @@ -257,6 +268,7 @@ impl DocumentsBatchTransitionMethodsV0 for BatchTransition { identity_public_key: &IdentityPublicKey, identity_contract_nonce: IdentityNonce, user_fee_increase: UserFeeIncrease, + token_payment_info: Option, signer: &S, platform_version: &PlatformVersion, batch_feature_version: Option, @@ -277,6 +289,7 @@ impl DocumentsBatchTransitionMethodsV0 for BatchTransition { identity_public_key, identity_contract_nonce, user_fee_increase, + token_payment_info, signer, platform_version, batch_feature_version, @@ -291,6 +304,7 @@ impl DocumentsBatchTransitionMethodsV0 for BatchTransition { identity_public_key, identity_contract_nonce, user_fee_increase, + token_payment_info, signer, platform_version, batch_feature_version, @@ -315,6 +329,7 @@ impl DocumentsBatchTransitionMethodsV0 for BatchTransition { identity_public_key: &IdentityPublicKey, identity_contract_nonce: IdentityNonce, user_fee_increase: UserFeeIncrease, + token_payment_info: Option, signer: &S, platform_version: &PlatformVersion, batch_feature_version: Option, @@ -336,6 +351,7 @@ impl DocumentsBatchTransitionMethodsV0 for BatchTransition { identity_public_key, identity_contract_nonce, user_fee_increase, + token_payment_info, signer, platform_version, batch_feature_version, @@ -351,6 +367,7 @@ impl DocumentsBatchTransitionMethodsV0 for BatchTransition { identity_public_key, identity_contract_nonce, user_fee_increase, + token_payment_info, signer, platform_version, batch_feature_version, @@ -377,6 +394,7 @@ impl DocumentsBatchTransitionMethodsV0 for BatchTransition { identity_public_key: &IdentityPublicKey, identity_contract_nonce: IdentityNonce, user_fee_increase: UserFeeIncrease, + token_payment_info: Option, signer: &S, platform_version: &PlatformVersion, batch_feature_version: Option, @@ -399,6 +417,7 @@ impl DocumentsBatchTransitionMethodsV0 for BatchTransition { identity_public_key, identity_contract_nonce, user_fee_increase, + token_payment_info, signer, platform_version, batch_feature_version, @@ -415,6 +434,7 @@ impl DocumentsBatchTransitionMethodsV0 for BatchTransition { identity_public_key, identity_contract_nonce, user_fee_increase, + token_payment_info, signer, platform_version, batch_feature_version, diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/methods/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/methods/v0/mod.rs index b24df10e050..acb26f272ac 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/methods/v0/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/methods/v0/mod.rs @@ -22,6 +22,8 @@ use platform_version::version::{FeatureVersion, PlatformVersion}; use std::convert::TryFrom; use crate::state_transition::batch_transition::batched_transition::{BatchedTransition, BatchedTransitionRef}; use crate::state_transition::state_transitions::document::batch_transition::batched_transition::document_transition::DocumentTransitionV0Methods; +#[cfg(feature = "state-transition-signing")] +use crate::tokens::token_payment_info::TokenPaymentInfo; pub trait DocumentsBatchTransitionMethodsV0: DocumentsBatchTransitionAccessorsV0 { #[cfg(feature = "state-transition-signing")] @@ -33,6 +35,7 @@ pub trait DocumentsBatchTransitionMethodsV0: DocumentsBatchTransitionAccessorsV0 identity_public_key: &IdentityPublicKey, identity_contract_nonce: IdentityNonce, user_fee_increase: UserFeeIncrease, + token_payment_info: Option, signer: &S, platform_version: &PlatformVersion, batch_feature_version: Option, @@ -48,6 +51,7 @@ pub trait DocumentsBatchTransitionMethodsV0: DocumentsBatchTransitionAccessorsV0 identity_public_key: &IdentityPublicKey, identity_contract_nonce: IdentityNonce, user_fee_increase: UserFeeIncrease, + token_payment_info: Option, signer: &S, platform_version: &PlatformVersion, _batch_feature_version: Option, @@ -63,6 +67,7 @@ pub trait DocumentsBatchTransitionMethodsV0: DocumentsBatchTransitionAccessorsV0 identity_public_key: &IdentityPublicKey, identity_contract_nonce: IdentityNonce, user_fee_increase: UserFeeIncrease, + token_payment_info: Option, signer: &S, platform_version: &PlatformVersion, _batch_feature_version: Option, @@ -79,6 +84,7 @@ pub trait DocumentsBatchTransitionMethodsV0: DocumentsBatchTransitionAccessorsV0 identity_public_key: &IdentityPublicKey, identity_contract_nonce: IdentityNonce, user_fee_increase: UserFeeIncrease, + token_payment_info: Option, signer: &S, platform_version: &PlatformVersion, _batch_feature_version: Option, @@ -95,6 +101,7 @@ pub trait DocumentsBatchTransitionMethodsV0: DocumentsBatchTransitionAccessorsV0 identity_public_key: &IdentityPublicKey, identity_contract_nonce: IdentityNonce, user_fee_increase: UserFeeIncrease, + token_payment_info: Option, signer: &S, platform_version: &PlatformVersion, batch_feature_version: Option, @@ -112,6 +119,7 @@ pub trait DocumentsBatchTransitionMethodsV0: DocumentsBatchTransitionAccessorsV0 identity_public_key: &IdentityPublicKey, identity_contract_nonce: IdentityNonce, user_fee_increase: UserFeeIncrease, + token_payment_info: Option, signer: &S, platform_version: &PlatformVersion, batch_feature_version: Option, diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/v0/v0_methods.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/v0/v0_methods.rs index b39b5e0f36e..cbdd6fa1cd9 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/v0/v0_methods.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/v0/v0_methods.rs @@ -39,6 +39,8 @@ use crate::state_transition::batch_transition::batched_transition::document_purc use crate::state_transition::batch_transition::batched_transition::document_transition::DocumentTransition; use crate::state_transition::batch_transition::resolvers::v0::BatchTransitionResolversV0; use crate::state_transition::state_transitions::document::batch_transition::batched_transition::document_transition::DocumentTransitionV0Methods; +#[cfg(feature = "state-transition-signing")] +use crate::tokens::token_payment_info::TokenPaymentInfo; impl DocumentsBatchTransitionAccessorsV0 for BatchTransitionV0 { type IterType<'a> @@ -85,6 +87,7 @@ impl DocumentsBatchTransitionMethodsV0 for BatchTransitionV0 { identity_public_key: &IdentityPublicKey, identity_contract_nonce: IdentityNonce, user_fee_increase: UserFeeIncrease, + token_payment_info: Option, signer: &S, platform_version: &PlatformVersion, _batch_feature_version: Option, @@ -96,6 +99,7 @@ impl DocumentsBatchTransitionMethodsV0 for BatchTransitionV0 { document, document_type, entropy, + token_payment_info, identity_contract_nonce, platform_version, create_feature_version, @@ -125,6 +129,7 @@ impl DocumentsBatchTransitionMethodsV0 for BatchTransitionV0 { identity_public_key: &IdentityPublicKey, identity_contract_nonce: IdentityNonce, user_fee_increase: UserFeeIncrease, + token_payment_info: Option, signer: &S, platform_version: &PlatformVersion, _batch_feature_version: Option, @@ -135,6 +140,7 @@ impl DocumentsBatchTransitionMethodsV0 for BatchTransitionV0 { let replace_transition = DocumentReplaceTransition::from_document( document, document_type, + token_payment_info, identity_contract_nonce, platform_version, replace_feature_version, @@ -165,6 +171,7 @@ impl DocumentsBatchTransitionMethodsV0 for BatchTransitionV0 { identity_public_key: &IdentityPublicKey, identity_contract_nonce: IdentityNonce, user_fee_increase: UserFeeIncrease, + token_payment_info: Option, signer: &S, platform_version: &PlatformVersion, _batch_feature_version: Option, @@ -175,6 +182,7 @@ impl DocumentsBatchTransitionMethodsV0 for BatchTransitionV0 { let transfer_transition = DocumentTransferTransition::from_document( document, document_type, + token_payment_info, identity_contract_nonce, recipient_owner_id, platform_version, @@ -205,6 +213,7 @@ impl DocumentsBatchTransitionMethodsV0 for BatchTransitionV0 { identity_public_key: &IdentityPublicKey, identity_contract_nonce: IdentityNonce, user_fee_increase: UserFeeIncrease, + token_payment_info: Option, signer: &S, platform_version: &PlatformVersion, _batch_feature_version: Option, @@ -215,6 +224,7 @@ impl DocumentsBatchTransitionMethodsV0 for BatchTransitionV0 { let delete_transition = DocumentDeleteTransition::from_document( document, document_type, + token_payment_info, identity_contract_nonce, platform_version, delete_feature_version, @@ -245,6 +255,7 @@ impl DocumentsBatchTransitionMethodsV0 for BatchTransitionV0 { identity_public_key: &IdentityPublicKey, identity_contract_nonce: IdentityNonce, user_fee_increase: UserFeeIncrease, + token_payment_info: Option, signer: &S, platform_version: &PlatformVersion, _batch_feature_version: Option, @@ -256,6 +267,7 @@ impl DocumentsBatchTransitionMethodsV0 for BatchTransitionV0 { document, document_type, price, + token_payment_info, identity_contract_nonce, platform_version, update_price_feature_version, @@ -287,6 +299,7 @@ impl DocumentsBatchTransitionMethodsV0 for BatchTransitionV0 { identity_public_key: &IdentityPublicKey, identity_contract_nonce: IdentityNonce, user_fee_increase: UserFeeIncrease, + token_payment_info: Option, signer: &S, platform_version: &PlatformVersion, _batch_feature_version: Option, @@ -297,6 +310,7 @@ impl DocumentsBatchTransitionMethodsV0 for BatchTransitionV0 { document, document_type, price, + token_payment_info, identity_contract_nonce, platform_version, purchase_feature_version, diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/v1/v0_methods.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/v1/v0_methods.rs index 854847c717b..833f1e43727 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/v1/v0_methods.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/v1/v0_methods.rs @@ -85,6 +85,8 @@ use crate::state_transition::batch_transition::token_unfreeze_transition::TokenU use crate::tokens::emergency_action::TokenEmergencyAction; #[cfg(feature = "state-transition-signing")] use crate::tokens::{PrivateEncryptedNote, SharedEncryptedNote}; +#[cfg(feature = "state-transition-signing")] +use crate::tokens::token_payment_info::TokenPaymentInfo; impl DocumentsBatchTransitionAccessorsV0 for BatchTransitionV1 { type IterType<'a> @@ -133,6 +135,7 @@ impl DocumentsBatchTransitionMethodsV0 for BatchTransitionV1 { identity_public_key: &IdentityPublicKey, identity_contract_nonce: IdentityNonce, user_fee_increase: UserFeeIncrease, + token_payment_info: Option, signer: &S, platform_version: &PlatformVersion, _batch_feature_version: Option, @@ -144,6 +147,7 @@ impl DocumentsBatchTransitionMethodsV0 for BatchTransitionV1 { document, document_type, entropy, + token_payment_info, identity_contract_nonce, platform_version, create_feature_version, @@ -173,6 +177,7 @@ impl DocumentsBatchTransitionMethodsV0 for BatchTransitionV1 { identity_public_key: &IdentityPublicKey, identity_contract_nonce: IdentityNonce, user_fee_increase: UserFeeIncrease, + token_payment_info: Option, signer: &S, platform_version: &PlatformVersion, _batch_feature_version: Option, @@ -183,6 +188,7 @@ impl DocumentsBatchTransitionMethodsV0 for BatchTransitionV1 { let replace_transition = DocumentReplaceTransition::from_document( document, document_type, + token_payment_info, identity_contract_nonce, platform_version, replace_feature_version, @@ -213,6 +219,7 @@ impl DocumentsBatchTransitionMethodsV0 for BatchTransitionV1 { identity_public_key: &IdentityPublicKey, identity_contract_nonce: IdentityNonce, user_fee_increase: UserFeeIncrease, + token_payment_info: Option, signer: &S, platform_version: &PlatformVersion, _batch_feature_version: Option, @@ -223,6 +230,7 @@ impl DocumentsBatchTransitionMethodsV0 for BatchTransitionV1 { let transfer_transition = DocumentTransferTransition::from_document( document, document_type, + token_payment_info, identity_contract_nonce, recipient_owner_id, platform_version, @@ -253,6 +261,7 @@ impl DocumentsBatchTransitionMethodsV0 for BatchTransitionV1 { identity_public_key: &IdentityPublicKey, identity_contract_nonce: IdentityNonce, user_fee_increase: UserFeeIncrease, + token_payment_info: Option, signer: &S, platform_version: &PlatformVersion, _batch_feature_version: Option, @@ -263,6 +272,7 @@ impl DocumentsBatchTransitionMethodsV0 for BatchTransitionV1 { let delete_transition = DocumentDeleteTransition::from_document( document, document_type, + token_payment_info, identity_contract_nonce, platform_version, delete_feature_version, @@ -293,6 +303,7 @@ impl DocumentsBatchTransitionMethodsV0 for BatchTransitionV1 { identity_public_key: &IdentityPublicKey, identity_contract_nonce: IdentityNonce, user_fee_increase: UserFeeIncrease, + token_payment_info: Option, signer: &S, platform_version: &PlatformVersion, _batch_feature_version: Option, @@ -304,6 +315,7 @@ impl DocumentsBatchTransitionMethodsV0 for BatchTransitionV1 { document, document_type, price, + token_payment_info, identity_contract_nonce, platform_version, update_price_feature_version, @@ -335,6 +347,7 @@ impl DocumentsBatchTransitionMethodsV0 for BatchTransitionV1 { identity_public_key: &IdentityPublicKey, identity_contract_nonce: IdentityNonce, user_fee_increase: UserFeeIncrease, + token_payment_info: Option, signer: &S, platform_version: &PlatformVersion, _batch_feature_version: Option, @@ -345,6 +358,7 @@ impl DocumentsBatchTransitionMethodsV0 for BatchTransitionV1 { document, document_type, price, + token_payment_info, identity_contract_nonce, platform_version, purchase_feature_version, diff --git a/packages/rs-dpp/src/tests/fixtures/get_document_transitions_fixture.rs b/packages/rs-dpp/src/tests/fixtures/get_document_transitions_fixture.rs index d50516c4400..8942b86d7de 100644 --- a/packages/rs-dpp/src/tests/fixtures/get_document_transitions_fixture.rs +++ b/packages/rs-dpp/src/tests/fixtures/get_document_transitions_fixture.rs @@ -8,11 +8,18 @@ use crate::document::Document; use crate::state_transition::batch_transition::accessors::DocumentsBatchTransitionAccessorsV0; use crate::state_transition::batch_transition::batched_transition::BatchedTransition; use crate::state_transition::batch_transition::batched_transition::document_transition_action_type::DocumentTransitionActionType; +use crate::tokens::token_payment_info::TokenPaymentInfo; + pub fn get_batched_transitions_fixture<'a>( documents: impl IntoIterator< Item = ( DocumentTransitionActionType, - Vec<(Document, DocumentTypeRef<'a>, Bytes32)>, + Vec<( + Document, + DocumentTypeRef<'a>, + Bytes32, + Option, + )>, ), >, nonce_counter: &mut BTreeMap<(Identifier, Identifier), u64>, //IdentityID/ContractID -> nonce diff --git a/packages/rs-dpp/src/tokens/gas_fees_paid_by.rs b/packages/rs-dpp/src/tokens/gas_fees_paid_by.rs new file mode 100644 index 00000000000..72d8e1fd565 --- /dev/null +++ b/packages/rs-dpp/src/tokens/gas_fees_paid_by.rs @@ -0,0 +1,81 @@ +use crate::consensus::basic::data_contract::UnknownGasFeesPaidByError; +use crate::consensus::basic::BasicError; +use crate::consensus::ConsensusError; +use crate::ProtocolError; +use bincode_derive::{Decode, Encode}; +use derive_more::Display; +#[cfg(any( + feature = "state-transition-serde-conversion", + all( + feature = "document-serde-conversion", + feature = "data-contract-serde-conversion" + ), +))] +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Clone, Copy, Encode, Decode, Default, PartialEq, Display)] +#[cfg_attr( + any( + feature = "state-transition-serde-conversion", + all( + feature = "document-serde-conversion", + feature = "data-contract-serde-conversion" + ), + ), + derive(Serialize, Deserialize) +)] +pub enum GasFeesPaidBy { + /// The user pays the gas fees + #[default] + DocumentOwner = 0, + /// The contract owner pays the gas fees + ContractOwner = 1, + /// The user is stating his willingness to pay the gas fee if the Contract owner's balance is + /// insufficient. + PreferContractOwner = 2, +} + +impl From for u8 { + fn from(value: GasFeesPaidBy) -> Self { + match value { + GasFeesPaidBy::DocumentOwner => 0, + GasFeesPaidBy::ContractOwner => 1, + GasFeesPaidBy::PreferContractOwner => 2, + } + } +} + +impl TryFrom for GasFeesPaidBy { + type Error = ProtocolError; + + fn try_from(value: u8) -> Result { + match value { + 0 => Ok(GasFeesPaidBy::DocumentOwner), + 1 => Ok(GasFeesPaidBy::ContractOwner), + 2 => Ok(GasFeesPaidBy::PreferContractOwner), + value => Err(ProtocolError::ConsensusError( + ConsensusError::BasicError(BasicError::UnknownGasFeesPaidByError( + UnknownGasFeesPaidByError::new(vec![0, 1, 2], value as u64), + )) + .into(), + )), + } + } +} + +impl TryFrom for GasFeesPaidBy { + type Error = ProtocolError; + + fn try_from(value: u64) -> Result { + u8::try_from(value) + .map_err(|_| { + ProtocolError::ConsensusError( + ConsensusError::BasicError(BasicError::UnknownGasFeesPaidByError( + UnknownGasFeesPaidByError::new(vec![0, 1, 2], value), + )) + .into(), + ) + })? + .try_into() + } +} diff --git a/packages/rs-dpp/src/tokens/mod.rs b/packages/rs-dpp/src/tokens/mod.rs index 7ef624e086f..c6da28ccd0b 100644 --- a/packages/rs-dpp/src/tokens/mod.rs +++ b/packages/rs-dpp/src/tokens/mod.rs @@ -7,9 +7,12 @@ use crate::util::hash::hash_double; pub mod allowed_currency; pub mod emergency_action; pub mod errors; +pub mod gas_fees_paid_by; pub mod info; pub mod status; +pub mod token_amount_on_contract_token; pub mod token_event; +pub mod token_payment_info; pub const MAX_TOKEN_NOTE_LEN: usize = 2048; pub type SharedEncryptedNote = (SenderKeyIndex, RecipientKeyIndex, Vec); diff --git a/packages/rs-dpp/src/tokens/token_amount_on_contract_token.rs b/packages/rs-dpp/src/tokens/token_amount_on_contract_token.rs new file mode 100644 index 00000000000..4a8100f1207 --- /dev/null +++ b/packages/rs-dpp/src/tokens/token_amount_on_contract_token.rs @@ -0,0 +1,75 @@ +use crate::balances::credits::TokenAmount; +use crate::consensus::basic::data_contract::UnknownDocumentActionTokenEffectError; +use crate::consensus::basic::BasicError; +use crate::consensus::ConsensusError; +use crate::data_contract::TokenContractPosition; +use crate::tokens::gas_fees_paid_by::GasFeesPaidBy; +use crate::ProtocolError; +use platform_value::Identifier; + +#[derive(Debug, PartialEq, Clone, Copy, Default)] +pub enum DocumentActionTokenEffect { + /// When the document action occurs the token is transferred to the balance of the contract owner + #[default] + TransferTokenToContractOwner, + /// When the document action occurs the token is burned + /// This option is not available for external tokens. + BurnToken, +} + +impl From for u8 { + fn from(value: DocumentActionTokenEffect) -> Self { + match value { + DocumentActionTokenEffect::TransferTokenToContractOwner => 0, + DocumentActionTokenEffect::BurnToken => 1, + } + } +} + +impl TryFrom for DocumentActionTokenEffect { + type Error = ProtocolError; + + fn try_from(value: u8) -> Result { + match value { + 0 => Ok(DocumentActionTokenEffect::TransferTokenToContractOwner), + 1 => Ok(DocumentActionTokenEffect::BurnToken), + other => Err(ProtocolError::ConsensusError( + ConsensusError::BasicError(BasicError::UnknownDocumentActionTokenEffectError( + UnknownDocumentActionTokenEffectError::new(vec![0, 1], other as u64), + )) + .into(), + )), + } + } +} + +impl TryFrom for DocumentActionTokenEffect { + type Error = ProtocolError; + + fn try_from(value: u64) -> Result { + u8::try_from(value) + .map_err(|_| { + ProtocolError::ConsensusError( + ConsensusError::BasicError(BasicError::UnknownDocumentActionTokenEffectError( + UnknownDocumentActionTokenEffectError::new(vec![0, 1], value), + )) + .into(), + ) + })? + .try_into() + } +} + +#[derive(Debug, PartialEq, Clone, Copy, Default)] +pub struct DocumentActionTokenCost { + /// If this is not set, it means that we are using our own contract id + pub contract_id: Option, + /// Token contract position + pub token_contract_position: TokenContractPosition, + /// The amount + pub token_amount: TokenAmount, + /// The amount + pub effect: DocumentActionTokenEffect, + /// Who is paying for gas fees for this action + pub gas_fees_paid_by: GasFeesPaidBy, +} diff --git a/packages/rs-dpp/src/tokens/token_payment_info/methods/mod.rs b/packages/rs-dpp/src/tokens/token_payment_info/methods/mod.rs new file mode 100644 index 00000000000..2d24cd45f58 --- /dev/null +++ b/packages/rs-dpp/src/tokens/token_payment_info/methods/mod.rs @@ -0,0 +1 @@ +pub mod v0; diff --git a/packages/rs-dpp/src/tokens/token_payment_info/methods/v0/mod.rs b/packages/rs-dpp/src/tokens/token_payment_info/methods/v0/mod.rs new file mode 100644 index 00000000000..a827088ce74 --- /dev/null +++ b/packages/rs-dpp/src/tokens/token_payment_info/methods/v0/mod.rs @@ -0,0 +1,42 @@ +use crate::balances::credits::TokenAmount; +use crate::data_contract::TokenContractPosition; +use crate::tokens::calculate_token_id; +use crate::tokens::token_payment_info::v0::v0_accessors::TokenPaymentInfoAccessorsV0; +use platform_value::Identifier; + +pub trait TokenPaymentInfoMethodsV0: TokenPaymentInfoAccessorsV0 { + fn is_valid_for_required_cost(&self, required_cost: TokenAmount) -> bool { + if let Some(min_cost) = self.minimum_token_cost() { + if required_cost < min_cost { + return false; + } + } + + if let Some(max_cost) = self.maximum_token_cost() { + if required_cost > max_cost { + return false; + } + } + + true + } + + fn matches_token_contract( + &self, + contract_id: &Option, + token_contract_position: TokenContractPosition, + ) -> bool { + self.payment_token_contract_id_ref() == contract_id + && self.token_contract_position() == token_contract_position + } + + fn token_id(&self, current_contract_id: Identifier) -> Identifier { + calculate_token_id( + self.payment_token_contract_id() + .unwrap_or(current_contract_id) + .as_bytes(), + self.token_contract_position(), + ) + .into() + } +} diff --git a/packages/rs-dpp/src/tokens/token_payment_info/mod.rs b/packages/rs-dpp/src/tokens/token_payment_info/mod.rs new file mode 100644 index 00000000000..db3df38dcff --- /dev/null +++ b/packages/rs-dpp/src/tokens/token_payment_info/mod.rs @@ -0,0 +1,155 @@ +use crate::balances::credits::TokenAmount; +use crate::data_contract::TokenContractPosition; +use crate::tokens::gas_fees_paid_by::GasFeesPaidBy; +use crate::tokens::token_payment_info::methods::v0::TokenPaymentInfoMethodsV0; +use crate::tokens::token_payment_info::v0::v0_accessors::TokenPaymentInfoAccessorsV0; +use crate::tokens::token_payment_info::v0::TokenPaymentInfoV0; +use crate::ProtocolError; +use bincode_derive::{Decode, Encode}; +use derive_more::{Display, From}; +use platform_serialization_derive::{PlatformDeserialize, PlatformSerialize}; +use platform_value::btreemap_extensions::BTreeValueMapHelper; +#[cfg(feature = "state-transition-value-conversion")] +use platform_value::Error; +use platform_value::{Identifier, Value}; +#[cfg(any( + feature = "state-transition-serde-conversion", + all( + feature = "document-serde-conversion", + feature = "data-contract-serde-conversion" + ), +))] +use serde::{Deserialize, Serialize}; +use std::collections::BTreeMap; + +pub mod methods; +pub mod v0; + +#[derive( + Debug, + Clone, + Copy, + Encode, + Decode, + PlatformDeserialize, + PlatformSerialize, + PartialEq, + Display, + From, +)] +#[cfg_attr( + any( + feature = "state-transition-serde-conversion", + all( + feature = "document-serde-conversion", + feature = "data-contract-serde-conversion" + ), + ), + derive(Serialize, Deserialize) +)] +pub enum TokenPaymentInfo { + #[display("V0({})", "_0")] + V0(TokenPaymentInfoV0), +} + +impl TokenPaymentInfoMethodsV0 for TokenPaymentInfo {} + +impl TokenPaymentInfoAccessorsV0 for TokenPaymentInfo { + // Getters + fn payment_token_contract_id(&self) -> Option { + match self { + TokenPaymentInfo::V0(v0) => v0.payment_token_contract_id(), + } + } + + fn payment_token_contract_id_ref(&self) -> &Option { + match self { + TokenPaymentInfo::V0(v0) => v0.payment_token_contract_id_ref(), + } + } + + fn token_contract_position(&self) -> TokenContractPosition { + match self { + TokenPaymentInfo::V0(v0) => v0.token_contract_position(), + } + } + + fn minimum_token_cost(&self) -> Option { + match self { + TokenPaymentInfo::V0(v0) => v0.minimum_token_cost(), + } + } + + fn maximum_token_cost(&self) -> Option { + match self { + TokenPaymentInfo::V0(v0) => v0.maximum_token_cost(), + } + } + + // Setters + fn set_payment_token_contract_id(&mut self, id: Option) { + match self { + TokenPaymentInfo::V0(v0) => v0.set_payment_token_contract_id(id), + } + } + + fn set_token_contract_position(&mut self, position: TokenContractPosition) { + match self { + TokenPaymentInfo::V0(v0) => v0.set_token_contract_position(position), + } + } + + fn set_minimum_token_cost(&mut self, cost: Option) { + match self { + TokenPaymentInfo::V0(v0) => v0.set_minimum_token_cost(cost), + } + } + + fn set_maximum_token_cost(&mut self, cost: Option) { + match self { + TokenPaymentInfo::V0(v0) => v0.set_maximum_token_cost(cost), + } + } + + fn gas_fees_paid_by(&self) -> GasFeesPaidBy { + match self { + TokenPaymentInfo::V0(v0) => v0.gas_fees_paid_by(), + } + } + + fn set_gas_fees_paid_by(&mut self, payer: GasFeesPaidBy) { + match self { + TokenPaymentInfo::V0(v0) => v0.set_gas_fees_paid_by(payer), + } + } +} + +impl TryFrom> for TokenPaymentInfo { + type Error = ProtocolError; + + fn try_from(map: BTreeMap) -> Result { + let format_version = map.get_str("$format_version")?; + match format_version { + "0" => { + let token_payment_info: TokenPaymentInfoV0 = map.try_into()?; + + Ok(token_payment_info.into()) + } + version => Err(ProtocolError::UnknownVersionMismatch { + method: "TokenPaymentInfo::from_value".to_string(), + known_versions: vec![0], + received: version + .parse() + .map_err(|_| ProtocolError::Generic("Conversion error".to_string()))?, + }), + } + } +} + +#[cfg(feature = "state-transition-value-conversion")] +impl TryFrom for Value { + type Error = Error; + fn try_from(value: TokenPaymentInfo) -> Result { + platform_value::to_value(value) + } +} diff --git a/packages/rs-dpp/src/tokens/token_payment_info/v0/mod.rs b/packages/rs-dpp/src/tokens/token_payment_info/v0/mod.rs new file mode 100644 index 00000000000..8719cba8b26 --- /dev/null +++ b/packages/rs-dpp/src/tokens/token_payment_info/v0/mod.rs @@ -0,0 +1,137 @@ +pub mod v0_accessors; + +use crate::balances::credits::TokenAmount; +use crate::data_contract::TokenContractPosition; +use crate::tokens::gas_fees_paid_by::GasFeesPaidBy; +use crate::tokens::token_payment_info::v0::v0_accessors::TokenPaymentInfoAccessorsV0; +use crate::ProtocolError; +use bincode_derive::{Decode, Encode}; +use derive_more::Display; +use platform_value::btreemap_extensions::BTreeValueRemoveFromMapHelper; +use platform_value::{Identifier, Value}; +#[cfg(any( + feature = "state-transition-serde-conversion", + all( + feature = "document-serde-conversion", + feature = "data-contract-serde-conversion" + ), +))] +use serde::{Deserialize, Serialize}; +use std::collections::BTreeMap; + +#[derive(Debug, Clone, Copy, Encode, Decode, Default, PartialEq, Display)] +#[cfg_attr( + any( + feature = "state-transition-serde-conversion", + all( + feature = "document-serde-conversion", + feature = "data-contract-serde-conversion" + ), + ), + derive(Serialize, Deserialize) +)] +#[display( + "Contract ID: {:?}, Token Position: {:?}, Min Cost: {:?}, Max Cost: {:?}, Gas Fees Paid By: {}", + payment_token_contract_id, + token_contract_position, + minimum_token_cost, + maximum_token_cost, + gas_fees_paid_by +)] +pub struct TokenPaymentInfoV0 { + /// By default, we use a token in the same contract, this field must be set if the document + /// requires payment using another contracts token. + pub payment_token_contract_id: Option, + /// If we are expecting to pay with a token in a contract, which token are we expecting + /// to pay with? + /// We have this set so contract owners can't switch out to more valuable token. + /// For example if my Data contract + pub token_contract_position: TokenContractPosition, + /// Minimum token cost, this most often should not be set + pub minimum_token_cost: Option, + /// Maximum token cost, this most often should be set + /// If: + /// - a client does not have this set + /// - and the data contract allows the price of NFTs to be changed by the data contract's owner or allowed party. + /// Then: + /// - The user could see the cost changed on them + pub maximum_token_cost: Option, + /// Who pays the gas fees, this needs to match what the contract allows + pub gas_fees_paid_by: GasFeesPaidBy, +} + +impl TokenPaymentInfoAccessorsV0 for TokenPaymentInfoV0 { + // Getters + fn payment_token_contract_id(&self) -> Option { + self.payment_token_contract_id + } + + fn payment_token_contract_id_ref(&self) -> &Option { + &self.payment_token_contract_id + } + + fn token_contract_position(&self) -> TokenContractPosition { + self.token_contract_position + } + + fn minimum_token_cost(&self) -> Option { + self.minimum_token_cost + } + + fn maximum_token_cost(&self) -> Option { + self.maximum_token_cost + } + + // Setters + fn set_payment_token_contract_id(&mut self, id: Option) { + self.payment_token_contract_id = id; + } + + fn set_token_contract_position(&mut self, position: TokenContractPosition) { + self.token_contract_position = position; + } + + fn set_minimum_token_cost(&mut self, cost: Option) { + self.minimum_token_cost = cost; + } + + fn set_maximum_token_cost(&mut self, cost: Option) { + self.maximum_token_cost = cost; + } + + fn gas_fees_paid_by(&self) -> GasFeesPaidBy { + self.gas_fees_paid_by + } + + fn set_gas_fees_paid_by(&mut self, payer: GasFeesPaidBy) { + self.gas_fees_paid_by = payer; + } +} + +impl TryFrom> for TokenPaymentInfoV0 { + type Error = ProtocolError; + + fn try_from(mut map: BTreeMap) -> Result { + Ok(TokenPaymentInfoV0 { + payment_token_contract_id: map.remove_optional_identifier("paymentTokenContractId")?, + + token_contract_position: map + .remove_optional_integer("tokenContractPosition")? + .unwrap_or_default(), + + minimum_token_cost: map.remove_optional_integer("minimumTokenCost")?, + + maximum_token_cost: map.remove_optional_integer("maximumTokenCost")?, + + gas_fees_paid_by: map + .remove_optional_string("gasFeesPaidBy")? + .map(|v| match v.as_str() { + "DocumentOwner" => GasFeesPaidBy::DocumentOwner, + "ContractOwner" => GasFeesPaidBy::ContractOwner, + "PreferContractOwner" => GasFeesPaidBy::PreferContractOwner, + _ => GasFeesPaidBy::default(), + }) + .unwrap_or_default(), + }) + } +} diff --git a/packages/rs-dpp/src/tokens/token_payment_info/v0/v0_accessors.rs b/packages/rs-dpp/src/tokens/token_payment_info/v0/v0_accessors.rs new file mode 100644 index 00000000000..b2c03b84290 --- /dev/null +++ b/packages/rs-dpp/src/tokens/token_payment_info/v0/v0_accessors.rs @@ -0,0 +1,42 @@ +use crate::balances::credits::TokenAmount; +use crate::data_contract::TokenContractPosition; +use crate::tokens::gas_fees_paid_by::GasFeesPaidBy; +use platform_value::Identifier; + +/// Trait providing accessor and mutator methods for `TokenPaymentInfoV0`. +pub trait TokenPaymentInfoAccessorsV0 { + /// Returns a cloned copy of the `payment_token_contract_id` field. + fn payment_token_contract_id(&self) -> Option; + + /// Returns a reference to the `payment_token_contract_id` field. + /// + /// This method avoids copying and can be used when only read access is needed. + fn payment_token_contract_id_ref(&self) -> &Option; + + /// Returns the `token_contract_position` field. + fn token_contract_position(&self) -> TokenContractPosition; + + /// Returns a copy of the `minimum_token_cost` field. + fn minimum_token_cost(&self) -> Option; + + /// Returns a copy of the `maximum_token_cost` field. + fn maximum_token_cost(&self) -> Option; + + /// Sets the `payment_token_contract_id` field to the given value. + fn set_payment_token_contract_id(&mut self, id: Option); + + /// Sets the `token_contract_position` field to the given value. + fn set_token_contract_position(&mut self, position: TokenContractPosition); + + /// Sets the `minimum_token_cost` field to the given value. + fn set_minimum_token_cost(&mut self, cost: Option); + + /// Sets the `maximum_token_cost` field to the given value. + fn set_maximum_token_cost(&mut self, cost: Option); + + /// Returns the `gas_fees_paid_by` strategy. + fn gas_fees_paid_by(&self) -> GasFeesPaidBy; + + /// Sets the `gas_fees_paid_by` strategy. + fn set_gas_fees_paid_by(&mut self, payer: GasFeesPaidBy); +} diff --git a/packages/rs-drive-abci/src/execution/check_tx/v0/mod.rs b/packages/rs-drive-abci/src/execution/check_tx/v0/mod.rs index 28002dd8c73..496136cd309 100644 --- a/packages/rs-drive-abci/src/execution/check_tx/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/check_tx/v0/mod.rs @@ -2355,6 +2355,7 @@ mod tests { &key, 2, 0, + None, &signer, platform_version, None, @@ -2374,6 +2375,7 @@ mod tests { &key, 3, 0, + None, &signer, platform_version, None, diff --git a/packages/rs-drive-abci/src/execution/platform_events/block_processing_end_events/tests.rs b/packages/rs-drive-abci/src/execution/platform_events/block_processing_end_events/tests.rs index a00a26083eb..a81ca9b5a49 100644 --- a/packages/rs-drive-abci/src/execution/platform_events/block_processing_end_events/tests.rs +++ b/packages/rs-drive-abci/src/execution/platform_events/block_processing_end_events/tests.rs @@ -79,6 +79,7 @@ mod refund_tests { key, 2, 0, + None, signer, platform_version, None, @@ -186,6 +187,7 @@ mod refund_tests { key, 3, 0, + None, signer, platform_version, None, @@ -306,6 +308,7 @@ mod refund_tests { &key, 4, 0, + None, &signer, platform_version, None, @@ -405,6 +408,7 @@ mod refund_tests { &key, 4, 0, + None, &signer, platform_version, None, @@ -507,6 +511,7 @@ mod refund_tests { &key, 4, 0, + None, &signer, platform_version, None, @@ -605,6 +610,7 @@ mod refund_tests { &key, 4, 0, + None, &signer, platform_version, None, @@ -703,6 +709,7 @@ mod refund_tests { &key, 4, 0, + None, &signer, platform_version, None, @@ -802,6 +809,7 @@ mod refund_tests { &key, 4, 0, + None, &signer, &platform_version_with_higher_fees, None, diff --git a/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_masternode_list/mod.rs b/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_masternode_list/mod.rs index e542bc7e8c4..f0de44e4709 100644 --- a/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_masternode_list/mod.rs +++ b/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_masternode_list/mod.rs @@ -129,7 +129,7 @@ mod test { platform .core_rpc .expect_get_protx_diff_with_masternodes() - .returning(move |base_block, block| { + .returning(move |_base_block, block| { if block == 2128896 { let file_path = adjust_path_based_on_current_dir( "tests/supporting_files/mainnet_protx_list_diffs/1-2128896.json", diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document/document_base_transaction_action/state_v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document/document_base_transaction_action/state_v0/mod.rs index 33df1dcc541..d2485c577a7 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document/document_base_transaction_action/state_v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document/document_base_transaction_action/state_v0/mod.rs @@ -1,8 +1,9 @@ use dpp::block::block_info::BlockInfo; use dpp::consensus::ConsensusError; use dpp::consensus::state::state_error::StateError; -use dpp::consensus::state::token::IdentityDoesNotHaveEnoughTokenBalanceError; +use dpp::consensus::state::token::{IdentityDoesNotHaveEnoughTokenBalanceError, IdentityTokenAccountFrozenError}; use dpp::identifier::Identifier; +use dpp::tokens::info::v0::IdentityTokenInfoV0Accessors; use dpp::validation::SimpleConsensusValidationResult; use drive::grovedb::TransactionArg; use drive::state_transition_action::batch::batched_transition::document_transition::document_base_transition_action::{DocumentBaseTransitionAction, DocumentBaseTransitionActionAccessorsV0}; @@ -39,7 +40,35 @@ impl DocumentBaseTransitionActionStateValidationV0 for DocumentBaseTransitionAct // The following was introduced with tokens, since there are no token costs before v9 there was no reason to // create a new version for state verification - if let Some((token_id, cost_in_tokens)) = self.token_cost() { + if let Some((token_id, _, cost_in_tokens)) = self.token_cost() { + let (maybe_identity_token_info, fee_result) = + platform.drive.fetch_identity_token_info_with_costs( + 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(identity_token_info) = maybe_identity_token_info { + // if we have an info we need to make sure we are not frozen for this identity + if identity_token_info.frozen() { + return Ok(SimpleConsensusValidationResult::new_with_error( + ConsensusError::StateError(StateError::IdentityTokenAccountFrozenError( + IdentityTokenAccountFrozenError::new( + token_id, + owner_id, + format!("Document {} token payment", transition_type), + ), + )), + )); + } + } + let (maybe_identity_token_balance, fee_result) = platform.drive.fetch_identity_token_balance_with_costs( token_id.to_buffer(), diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/data_triggers/triggers/dashpay/v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/data_triggers/triggers/dashpay/v0/mod.rs index d3cdf285133..ad43302fbba 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/data_triggers/triggers/dashpay/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/data_triggers/triggers/dashpay/v0/mod.rs @@ -154,7 +154,12 @@ mod test { let document_transitions = get_batched_transitions_fixture( [( DocumentTransitionActionType::Create, - vec![(contact_request_document, document_type, Bytes32::default())], + vec![( + contact_request_document, + document_type, + Bytes32::default(), + None, + )], )], &mut nonce_counter, ); @@ -180,9 +185,9 @@ mod test { }; let result = create_contact_request_data_trigger( - &DocumentCreateTransitionAction::try_from_document_borrowed_create_transition_with_contract_lookup(&platform.drive, None, document_create_transition, &BlockInfo::default(), |_identifier| { + &DocumentCreateTransitionAction::try_from_document_borrowed_create_transition_with_contract_lookup(&platform.drive, *owner_id, None, document_create_transition, &BlockInfo::default(), 0, |_identifier| { Ok(Arc::new(DataContractFetchInfo::dashpay_contract_fixture(protocol_version))) - }, platform_version).expect("expected to create action").0.into(), + }, platform_version).expect("expected to create action").0.into_data().expect("expected to be a valid transition").as_document_action().expect("expected document action"), &data_trigger_context, platform_version, ) @@ -257,7 +262,12 @@ mod test { let document_transitions = get_batched_transitions_fixture( [( DocumentTransitionActionType::Create, - vec![(contact_request_document, document_type, Bytes32::default())], + vec![( + contact_request_document, + document_type, + Bytes32::default(), + None, + )], )], &mut nonce_counter, ); @@ -298,9 +308,9 @@ mod test { let _dashpay_identity_id = data_trigger_context.owner_id.to_owned(); let result = create_contact_request_data_trigger( - &DocumentCreateTransitionAction::try_from_document_borrowed_create_transition_with_contract_lookup(&platform.drive, None, document_create_transition, &BlockInfo::default(), |_identifier| { + &DocumentCreateTransitionAction::try_from_document_borrowed_create_transition_with_contract_lookup(&platform.drive, owner_id, None, document_create_transition, &BlockInfo::default(), 0, |_identifier| { Ok(Arc::new(DataContractFetchInfo::dashpay_contract_fixture(protocol_version))) - }, platform_version).expect("expected to create action").0.into(), + }, platform_version).expect("expected to create action").0.into_data().expect("expected to be a valid transition").as_document_action().expect("expected document action"), &data_trigger_context, platform_version, ) @@ -385,7 +395,12 @@ mod test { let document_transitions = get_batched_transitions_fixture( [( DocumentTransitionActionType::Create, - vec![(contact_request_document, document_type, Bytes32::default())], + vec![( + contact_request_document, + document_type, + Bytes32::default(), + None, + )], )], &mut nonce_counter, ); @@ -411,9 +426,9 @@ mod test { let _dashpay_identity_id = data_trigger_context.owner_id.to_owned(); let result = create_contact_request_data_trigger( - &DocumentCreateTransitionAction::try_from_document_borrowed_create_transition_with_contract_lookup(&platform.drive, None, document_create_transition, &BlockInfo::default(), |_identifier| { + &DocumentCreateTransitionAction::try_from_document_borrowed_create_transition_with_contract_lookup(&platform.drive, owner_id, None, document_create_transition, &BlockInfo::default(), 0, |_identifier| { Ok(Arc::new(DataContractFetchInfo::dashpay_contract_fixture(protocol_version))) - }, platform_version).expect("expected to create action").0.into(), + }, platform_version).expect("expected to create action").0.into_data().expect("expected to be a valid transition").as_document_action().expect("expected document action"), &data_trigger_context, platform_version, ) diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/data_triggers/triggers/dpns/v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/data_triggers/triggers/dpns/v0/mod.rs index 55ffa746720..e94ab7595b5 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/data_triggers/triggers/dpns/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/data_triggers/triggers/dpns/v0/mod.rs @@ -425,7 +425,7 @@ mod test { let transitions = get_batched_transitions_fixture( [( DocumentTransitionActionType::Create, - vec![(document, document_type, Bytes32::default())], + vec![(document, document_type, Bytes32::default(), None)], )], &mut nonce_counter, ); @@ -445,10 +445,10 @@ mod test { }; let result = create_domain_data_trigger_v0( - &DocumentCreateTransitionAction::try_from_document_borrowed_create_transition_with_contract_lookup(&platform.drive, None, - document_create_transition, &BlockInfo::default(), |_identifier| { + &DocumentCreateTransitionAction::try_from_document_borrowed_create_transition_with_contract_lookup(&platform.drive, owner_id, None, + document_create_transition, &BlockInfo::default(), 0, |_identifier| { Ok(Arc::new(DataContractFetchInfo::dpns_contract_fixture(platform_version.protocol_version))) - }, platform_version).expect("expected to create action").0.into(), + }, platform_version).expect("expected to create action").0.into_data().expect("expected to be a valid transition").as_document_action().expect("expected document action"), &data_trigger_context, platform_version, ) diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/data_triggers/triggers/withdrawals/v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/data_triggers/triggers/withdrawals/v0/mod.rs index edc0ca1ddf8..f6e6e07bc1c 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/data_triggers/triggers/withdrawals/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/data_triggers/triggers/withdrawals/v0/mod.rs @@ -136,6 +136,7 @@ mod tests { use drive::state_transition_action::batch::batched_transition::document_transition::document_delete_transition_action::v0::DocumentDeleteTransitionActionV0; use dpp::system_data_contracts::{load_system_data_contract, SystemDataContract}; use dpp::tests::fixtures::{get_data_contract_fixture, get_withdrawal_document_fixture}; + use dpp::tokens::gas_fees_paid_by::GasFeesPaidBy; use dpp::version::PlatformVersion; use drive::util::object_size_info::DocumentInfo::DocumentRefInfo; use drive::util::object_size_info::{DocumentAndContractInfo, OwnedDocumentInfo}; @@ -169,6 +170,7 @@ mod tests { document_type_name: "".to_string(), data_contract: Arc::new(DataContractFetchInfo::dpns_contract_fixture(1)), token_cost: None, + gas_fees_paid_by: GasFeesPaidBy::DocumentOwner, } .into(); @@ -312,6 +314,7 @@ mod tests { platform_version.protocol_version, )), token_cost: None, + gas_fees_paid_by: GasFeesPaidBy::DocumentOwner, }), }), ); diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/tests/document/creation.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/tests/document/creation.rs index c228b55a526..5b413b56e07 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/tests/document/creation.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/tests/document/creation.rs @@ -32,14 +32,20 @@ mod creation_tests { use dpp::consensus::state::state_error::StateError; use dpp::dashcore::Network; use dpp::dashcore::Network::Testnet; - use dpp::data_contract::DataContract; + use dpp::data_contract::{DataContract, TokenConfiguration}; use dpp::identity::SecurityLevel; use dpp::state_transition::batch_transition::document_base_transition::DocumentBaseTransition; use dpp::state_transition::batch_transition::document_create_transition::DocumentCreateTransitionV0; use dpp::state_transition::batch_transition::{DocumentCreateTransition, BatchTransitionV0}; use dpp::state_transition::StateTransition; use dpp::data_contract::accessors::v1::DataContractV1Getters; + use dpp::data_contract::document_type::accessors::DocumentTypeV1Getters; + use dpp::tokens::gas_fees_paid_by::GasFeesPaidBy; + use dpp::tokens::token_amount_on_contract_token::DocumentActionTokenCost; + use dpp::tokens::token_payment_info::TokenPaymentInfo; + use dpp::tokens::token_payment_info::v0::TokenPaymentInfoV0; use crate::config::PlatformConfig; + use crate::execution::validation::state_transition::tests::{create_card_game_external_token_contract_with_owner_identity, create_card_game_internal_token_contract_with_owner_identity_transfer_tokens, create_token_contract_with_owner_identity}; #[test] fn test_document_creation() { @@ -87,6 +93,7 @@ mod creation_tests { &key, 2, 0, + None, &signer, platform_version, None, @@ -173,6 +180,7 @@ mod creation_tests { &key, 2, 0, + None, &signer, platform_version, None, @@ -235,6 +243,7 @@ mod creation_tests { &key, 3, 0, + None, &signer, platform_version, None, @@ -343,6 +352,7 @@ mod creation_tests { &key, 2, 0, + None, &signer, platform_version, None, @@ -523,6 +533,7 @@ mod creation_tests { &key_1, 2, 0, + None, &signer_1, platform_version, None, @@ -544,6 +555,7 @@ mod creation_tests { &key_2, 2, 0, + None, &signer_2, platform_version, None, @@ -565,6 +577,7 @@ mod creation_tests { &key_1, 3, 0, + None, &signer_1, platform_version, None, @@ -585,6 +598,7 @@ mod creation_tests { &key_2, 3, 0, + None, &signer_2, platform_version, None, @@ -943,6 +957,7 @@ mod creation_tests { &key_1, 2, 0, + None, &signer_1, platform_version, None, @@ -961,6 +976,7 @@ mod creation_tests { base: DocumentBaseTransition::from_document( &document_1, domain, + None, 3, platform_version, None, @@ -1215,6 +1231,7 @@ mod creation_tests { &key_1, 2, 0, + None, &signer_1, platform_version, None, @@ -1233,6 +1250,7 @@ mod creation_tests { base: DocumentBaseTransition::from_document( &document_1, domain, + None, 3, platform_version, None, @@ -1561,6 +1579,7 @@ mod creation_tests { &key_1, 2, 0, + None, &signer_1, platform_version, None, @@ -1582,6 +1601,7 @@ mod creation_tests { &key_2, 2, 0, + None, &signer_2, platform_version, None, @@ -1603,6 +1623,7 @@ mod creation_tests { &key_1, 3, 0, + None, &signer_1, platform_version, None, @@ -1624,6 +1645,7 @@ mod creation_tests { &key_1, 4, 0, + None, &signer_1, platform_version, None, @@ -1644,6 +1666,7 @@ mod creation_tests { &key_2, 3, 0, + None, &signer_2, platform_version, None, @@ -1664,6 +1687,7 @@ mod creation_tests { &key_1, 5, 0, + None, &signer_1, platform_version, None, @@ -2102,6 +2126,7 @@ mod creation_tests { &contender_1_key, 4, 0, + None, &contender_1_signer, platform_version, None, @@ -2333,6 +2358,7 @@ mod creation_tests { &key, 2, 0, + None, &signer, platform_version, None, @@ -2395,6 +2421,7 @@ mod creation_tests { &another_identity_key, 2, 0, + None, &another_identity_signer, platform_version, None, @@ -2442,7 +2469,7 @@ mod creation_tests { } #[test] - fn test_document_creation_paid_with_a_token() { + fn test_document_creation_paid_with_a_token_burn() { let platform_version = PlatformVersion::latest(); let mut platform = TestPlatformBuilder::new() .with_latest_protocol_version() @@ -2457,11 +2484,12 @@ mod creation_tests { let (buyer, signer, key) = setup_identity(&mut platform, 234, dash_to_credits!(0.1)); - let (contract, gold_token_id, _) = create_card_game_token_contract_with_owner_identity( - &mut platform, - contract_owner_id.id(), - platform_version, - ); + let (contract, gold_token_id, _) = + create_card_game_internal_token_contract_with_owner_identity_burn_tokens( + &mut platform, + contract_owner_id.id(), + platform_version, + ); let token_supply = platform .drive @@ -2509,6 +2537,13 @@ mod creation_tests { &key, 2, 0, + Some(TokenPaymentInfo::V0(TokenPaymentInfoV0 { + payment_token_contract_id: None, + token_contract_position: 0, + minimum_token_cost: None, + maximum_token_cost: Some(10), + gas_fees_paid_by: GasFeesPaidBy::DocumentOwner, + })), &signer, platform_version, None, @@ -2560,10 +2595,24 @@ mod creation_tests { // He had 15, but spent 10 assert_eq!(token_balance, Some(5)); + + // There was a burn so the contract owner shouldn't have gotten more tokens + let contract_owner_token_balance = platform + .drive + .fetch_identity_token_balance( + gold_token_id.to_buffer(), + contract_owner_id.id().to_buffer(), + None, + platform_version, + ) + .expect("expected to fetch token balance"); + + // He started with None, so should have None + assert_eq!(contract_owner_token_balance, None); } #[test] - fn test_document_creation_not_enough_token_balance_to_create_document() { + fn test_document_creation_paid_with_a_token_transfer() { let platform_version = PlatformVersion::latest(); let mut platform = TestPlatformBuilder::new() .with_latest_protocol_version() @@ -2578,12 +2627,155 @@ mod creation_tests { let (buyer, signer, key) = setup_identity(&mut platform, 234, dash_to_credits!(0.1)); - let (contract, gold_token_id, _) = create_card_game_token_contract_with_owner_identity( - &mut platform, - contract_owner_id.id(), - platform_version, + let (contract, gold_token_id, _) = + create_card_game_internal_token_contract_with_owner_identity_transfer_tokens( + &mut platform, + contract_owner_id.id(), + platform_version, + ); + + let token_supply = platform + .drive + .fetch_token_total_supply(gold_token_id.to_buffer(), None, platform_version) + .expect("expected to fetch total supply"); + + assert_eq!(token_supply, Some(0)); + + assert_eq!(contract.tokens().len(), 2); + + add_tokens_to_identity(&mut platform, gold_token_id, buyer.id(), 15); + + let token_supply = platform + .drive + .fetch_token_total_supply(gold_token_id.to_buffer(), None, platform_version) + .expect("expected to fetch total supply"); + + assert_eq!(token_supply, Some(15)); + + let card_document_type = contract + .document_type_for_name("card") + .expect("expected a profile document type"); + + let entropy = Bytes32::random_with_rng(&mut rng); + + let mut document = card_document_type + .random_document_with_identifier_and_entropy( + &mut rng, + buyer.id(), + entropy, + DocumentFieldFillType::DoNotFillIfNotRequired, + DocumentFieldFillSize::AnyDocumentFillSize, + platform_version, + ) + .expect("expected a random document"); + + document.set("attack", 4.into()); + document.set("defense", 7.into()); + + let documents_batch_create_transition = + BatchTransition::new_document_creation_transition_from_document( + document.clone(), + card_document_type, + entropy.0, + &key, + 2, + 0, + Some(TokenPaymentInfo::V0(TokenPaymentInfoV0 { + payment_token_contract_id: None, + token_contract_position: 0, + minimum_token_cost: None, + maximum_token_cost: Some(10), + gas_fees_paid_by: GasFeesPaidBy::DocumentOwner, + })), + &signer, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition"); + + let documents_batch_create_serialized_transition = documents_batch_create_transition + .serialize_to_bytes() + .expect("expected documents batch serialized state transition"); + + let transaction = platform.drive.grove.start_transaction(); + + let processing_result = platform + .platform + .process_raw_state_transitions( + &vec![documents_batch_create_serialized_transition.clone()], + &platform_state, + &BlockInfo::default(), + &transaction, + platform_version, + false, + None, + ) + .expect("expected to process state transition"); + + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::SuccessfulExecution(_, _)] ); + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit transaction"); + + let token_balance = platform + .drive + .fetch_identity_token_balance( + gold_token_id.to_buffer(), + buyer.id().to_buffer(), + None, + platform_version, + ) + .expect("expected to fetch token balance"); + + // The buyer had 15, but spent 10 + assert_eq!(token_balance, Some(5)); + + let contract_owner_token_balance = platform + .drive + .fetch_identity_token_balance( + gold_token_id.to_buffer(), + contract_owner_id.id().to_buffer(), + None, + platform_version, + ) + .expect("expected to fetch token balance"); + + // He was paid 10 + assert_eq!(contract_owner_token_balance, Some(10)); + } + + #[test] + fn test_document_creation_paid_with_a_token_not_spending_enough() { + let platform_version = PlatformVersion::latest(); + let mut platform = TestPlatformBuilder::new() + .with_latest_protocol_version() + .build_with_mock_rpc() + .set_genesis_state(); + + let mut rng = StdRng::seed_from_u64(433); + + let platform_state = platform.state.load(); + + let (contract_owner_id, _, _) = setup_identity(&mut platform, 958, dash_to_credits!(0.1)); + + let (buyer, signer, key) = setup_identity(&mut platform, 234, dash_to_credits!(0.1)); + + let (contract, gold_token_id, _) = + create_card_game_internal_token_contract_with_owner_identity_burn_tokens( + &mut platform, + contract_owner_id.id(), + platform_version, + ); + let token_supply = platform .drive .fetch_token_total_supply(gold_token_id.to_buffer(), None, platform_version) @@ -2593,15 +2785,14 @@ mod creation_tests { assert_eq!(contract.tokens().len(), 2); - // We need 10 tokens, we have 8. - add_tokens_to_identity(&mut platform, gold_token_id, buyer.id(), 8); + add_tokens_to_identity(&mut platform, gold_token_id.into(), buyer.id(), 15); let token_supply = platform .drive .fetch_token_total_supply(gold_token_id.to_buffer(), None, platform_version) .expect("expected to fetch total supply"); - assert_eq!(token_supply, Some(8)); + assert_eq!(token_supply, Some(15)); let card_document_type = contract .document_type_for_name("card") @@ -2631,6 +2822,13 @@ mod creation_tests { &key, 2, 0, + Some(TokenPaymentInfo::V0(TokenPaymentInfoV0 { + payment_token_contract_id: None, + token_contract_position: 0, + minimum_token_cost: None, + maximum_token_cost: Some(9), + gas_fees_paid_by: GasFeesPaidBy::DocumentOwner, + })), &signer, platform_version, None, @@ -2661,9 +2859,9 @@ mod creation_tests { assert_matches!( processing_result.execution_results().as_slice(), [PaidConsensusError( - ConsensusError::StateError(StateError::IdentityDoesNotHaveEnoughTokenBalanceError( - _ - )), + ConsensusError::StateError( + StateError::IdentityHasNotAgreedToPayRequiredTokenAmountError(_) + ), _ )] ); @@ -2685,7 +2883,712 @@ mod creation_tests { ) .expect("expected to fetch token balance"); - // We should still have 8 - assert_eq!(token_balance, Some(8)); + // He should still have 15 + assert_eq!(token_balance, Some(15)); + } + + #[test] + fn test_document_creation_paid_with_a_token_minimum_cost_set_rare_scenario() { + let platform_version = PlatformVersion::latest(); + let mut platform = TestPlatformBuilder::new() + .with_latest_protocol_version() + .build_with_mock_rpc() + .set_genesis_state(); + + let mut rng = StdRng::seed_from_u64(433); + + let platform_state = platform.state.load(); + + let (contract_owner_id, _, _) = setup_identity(&mut platform, 958, dash_to_credits!(0.1)); + + let (buyer, signer, key) = setup_identity(&mut platform, 234, dash_to_credits!(0.1)); + + let (contract, gold_token_id, _) = + create_card_game_internal_token_contract_with_owner_identity_burn_tokens( + &mut platform, + contract_owner_id.id(), + platform_version, + ); + + let token_supply = platform + .drive + .fetch_token_total_supply(gold_token_id.to_buffer(), None, platform_version) + .expect("expected to fetch total supply"); + + assert_eq!(token_supply, Some(0)); + + assert_eq!(contract.tokens().len(), 2); + + add_tokens_to_identity(&mut platform, gold_token_id.into(), buyer.id(), 15); + + let token_supply = platform + .drive + .fetch_token_total_supply(gold_token_id.to_buffer(), None, platform_version) + .expect("expected to fetch total supply"); + + assert_eq!(token_supply, Some(15)); + + let card_document_type = contract + .document_type_for_name("card") + .expect("expected a profile document type"); + + let entropy = Bytes32::random_with_rng(&mut rng); + + let mut document = card_document_type + .random_document_with_identifier_and_entropy( + &mut rng, + buyer.id(), + entropy, + DocumentFieldFillType::DoNotFillIfNotRequired, + DocumentFieldFillSize::AnyDocumentFillSize, + platform_version, + ) + .expect("expected a random document"); + + document.set("attack", 4.into()); + document.set("defense", 7.into()); + + let documents_batch_create_transition = + BatchTransition::new_document_creation_transition_from_document( + document.clone(), + card_document_type, + entropy.0, + &key, + 2, + 0, + Some(TokenPaymentInfo::V0(TokenPaymentInfoV0 { + payment_token_contract_id: None, + token_contract_position: 0, + minimum_token_cost: Some(12), + maximum_token_cost: None, + gas_fees_paid_by: GasFeesPaidBy::DocumentOwner, + })), + &signer, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition"); + + let documents_batch_create_serialized_transition = documents_batch_create_transition + .serialize_to_bytes() + .expect("expected documents batch serialized state transition"); + + let transaction = platform.drive.grove.start_transaction(); + + let processing_result = platform + .platform + .process_raw_state_transitions( + &vec![documents_batch_create_serialized_transition.clone()], + &platform_state, + &BlockInfo::default(), + &transaction, + platform_version, + false, + None, + ) + .expect("expected to process state transition"); + + assert_matches!( + processing_result.execution_results().as_slice(), + [PaidConsensusError( + ConsensusError::StateError( + StateError::IdentityHasNotAgreedToPayRequiredTokenAmountError(_) + ), + _ + )] + ); + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit transaction"); + + let token_balance = platform + .drive + .fetch_identity_token_balance( + gold_token_id.to_buffer(), + buyer.id().to_buffer(), + None, + platform_version, + ) + .expect("expected to fetch token balance"); + + // He should still have 15 + assert_eq!(token_balance, Some(15)); + } + + #[test] + fn test_document_creation_paid_with_a_token_agreeing_to_too_much() { + let platform_version = PlatformVersion::latest(); + let mut platform = TestPlatformBuilder::new() + .with_latest_protocol_version() + .build_with_mock_rpc() + .set_genesis_state(); + + let mut rng = StdRng::seed_from_u64(433); + + let platform_state = platform.state.load(); + + let (contract_owner_id, _, _) = setup_identity(&mut platform, 958, dash_to_credits!(0.1)); + + let (buyer, signer, key) = setup_identity(&mut platform, 234, dash_to_credits!(0.1)); + + let (contract, gold_token_id, _) = + create_card_game_internal_token_contract_with_owner_identity_burn_tokens( + &mut platform, + contract_owner_id.id(), + platform_version, + ); + + let token_supply = platform + .drive + .fetch_token_total_supply(gold_token_id.to_buffer(), None, platform_version) + .expect("expected to fetch total supply"); + + assert_eq!(token_supply, Some(0)); + + assert_eq!(contract.tokens().len(), 2); + + add_tokens_to_identity(&mut platform, gold_token_id.into(), buyer.id(), 15); + + let token_supply = platform + .drive + .fetch_token_total_supply(gold_token_id.to_buffer(), None, platform_version) + .expect("expected to fetch total supply"); + + assert_eq!(token_supply, Some(15)); + + let card_document_type = contract + .document_type_for_name("card") + .expect("expected a profile document type"); + + let entropy = Bytes32::random_with_rng(&mut rng); + + let mut document = card_document_type + .random_document_with_identifier_and_entropy( + &mut rng, + buyer.id(), + entropy, + DocumentFieldFillType::DoNotFillIfNotRequired, + DocumentFieldFillSize::AnyDocumentFillSize, + platform_version, + ) + .expect("expected a random document"); + + document.set("attack", 4.into()); + document.set("defense", 7.into()); + + let documents_batch_create_transition = + BatchTransition::new_document_creation_transition_from_document( + document.clone(), + card_document_type, + entropy.0, + &key, + 2, + 0, + Some(TokenPaymentInfo::V0(TokenPaymentInfoV0 { + payment_token_contract_id: None, + token_contract_position: 0, + minimum_token_cost: None, + maximum_token_cost: Some(12), + gas_fees_paid_by: GasFeesPaidBy::DocumentOwner, + })), + &signer, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition"); + + let documents_batch_create_serialized_transition = documents_batch_create_transition + .serialize_to_bytes() + .expect("expected documents batch serialized state transition"); + + let transaction = platform.drive.grove.start_transaction(); + + let processing_result = platform + .platform + .process_raw_state_transitions( + &vec![documents_batch_create_serialized_transition.clone()], + &platform_state, + &BlockInfo::default(), + &transaction, + platform_version, + false, + None, + ) + .expect("expected to process state transition"); + + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::SuccessfulExecution(_, _)] + ); + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit transaction"); + + let token_balance = platform + .drive + .fetch_identity_token_balance( + gold_token_id.to_buffer(), + buyer.id().to_buffer(), + None, + platform_version, + ) + .expect("expected to fetch token balance"); + + // He had 15, but only spent 10 + assert_eq!(token_balance, Some(5)); + } + + #[test] + fn test_document_creation_paid_with_a_token_token_info_not_set() { + let platform_version = PlatformVersion::latest(); + let mut platform = TestPlatformBuilder::new() + .with_latest_protocol_version() + .build_with_mock_rpc() + .set_genesis_state(); + + let mut rng = StdRng::seed_from_u64(433); + + let platform_state = platform.state.load(); + + let (contract_owner_id, _, _) = setup_identity(&mut platform, 958, dash_to_credits!(0.1)); + + let (buyer, signer, key) = setup_identity(&mut platform, 234, dash_to_credits!(0.1)); + + let (contract, gold_token_id, _) = + create_card_game_internal_token_contract_with_owner_identity_burn_tokens( + &mut platform, + contract_owner_id.id(), + platform_version, + ); + + let token_supply = platform + .drive + .fetch_token_total_supply(gold_token_id.to_buffer(), None, platform_version) + .expect("expected to fetch total supply"); + + assert_eq!(token_supply, Some(0)); + + assert_eq!(contract.tokens().len(), 2); + + add_tokens_to_identity(&mut platform, gold_token_id.into(), buyer.id(), 15); + + let token_supply = platform + .drive + .fetch_token_total_supply(gold_token_id.to_buffer(), None, platform_version) + .expect("expected to fetch total supply"); + + assert_eq!(token_supply, Some(15)); + + let card_document_type = contract + .document_type_for_name("card") + .expect("expected a profile document type"); + + let entropy = Bytes32::random_with_rng(&mut rng); + + let mut document = card_document_type + .random_document_with_identifier_and_entropy( + &mut rng, + buyer.id(), + entropy, + DocumentFieldFillType::DoNotFillIfNotRequired, + DocumentFieldFillSize::AnyDocumentFillSize, + platform_version, + ) + .expect("expected a random document"); + + document.set("attack", 4.into()); + document.set("defense", 7.into()); + + let documents_batch_create_transition = + BatchTransition::new_document_creation_transition_from_document( + document.clone(), + card_document_type, + entropy.0, + &key, + 2, + 0, + None, + &signer, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition"); + + let documents_batch_create_serialized_transition = documents_batch_create_transition + .serialize_to_bytes() + .expect("expected documents batch serialized state transition"); + + let transaction = platform.drive.grove.start_transaction(); + + let processing_result = platform + .platform + .process_raw_state_transitions( + &vec![documents_batch_create_serialized_transition.clone()], + &platform_state, + &BlockInfo::default(), + &transaction, + platform_version, + false, + None, + ) + .expect("expected to process state transition"); + + assert_matches!( + processing_result.execution_results().as_slice(), + [PaidConsensusError( + ConsensusError::StateError(StateError::RequiredTokenPaymentInfoNotSetError(_)), + _ + )] + ); + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit transaction"); + + let token_balance = platform + .drive + .fetch_identity_token_balance( + gold_token_id.to_buffer(), + buyer.id().to_buffer(), + None, + platform_version, + ) + .expect("expected to fetch token balance"); + + // Nothing should have happened + assert_eq!(token_balance, Some(15)); + } + + #[test] + fn test_document_creation_not_enough_token_balance_to_create_document() { + let platform_version = PlatformVersion::latest(); + let mut platform = TestPlatformBuilder::new() + .with_latest_protocol_version() + .build_with_mock_rpc() + .set_genesis_state(); + + let mut rng = StdRng::seed_from_u64(433); + + let platform_state = platform.state.load(); + + let (contract_owner_id, _, _) = setup_identity(&mut platform, 958, dash_to_credits!(0.1)); + + let (buyer, signer, key) = setup_identity(&mut platform, 234, dash_to_credits!(0.1)); + + let (contract, gold_token_id, _) = + create_card_game_internal_token_contract_with_owner_identity_burn_tokens( + &mut platform, + contract_owner_id.id(), + platform_version, + ); + + let token_supply = platform + .drive + .fetch_token_total_supply(gold_token_id.to_buffer(), None, platform_version) + .expect("expected to fetch total supply"); + + assert_eq!(token_supply, Some(0)); + + assert_eq!(contract.tokens().len(), 2); + + // We need 10 tokens, we have 8. + add_tokens_to_identity(&mut platform, gold_token_id, buyer.id(), 8); + + let token_supply = platform + .drive + .fetch_token_total_supply(gold_token_id.to_buffer(), None, platform_version) + .expect("expected to fetch total supply"); + + assert_eq!(token_supply, Some(8)); + + let card_document_type = contract + .document_type_for_name("card") + .expect("expected a profile document type"); + + let entropy = Bytes32::random_with_rng(&mut rng); + + let mut document = card_document_type + .random_document_with_identifier_and_entropy( + &mut rng, + buyer.id(), + entropy, + DocumentFieldFillType::DoNotFillIfNotRequired, + DocumentFieldFillSize::AnyDocumentFillSize, + platform_version, + ) + .expect("expected a random document"); + + document.set("attack", 4.into()); + document.set("defense", 7.into()); + + let documents_batch_create_transition = + BatchTransition::new_document_creation_transition_from_document( + document.clone(), + card_document_type, + entropy.0, + &key, + 2, + 0, + Some(TokenPaymentInfo::V0(TokenPaymentInfoV0 { + payment_token_contract_id: None, // This contract + token_contract_position: 0, + minimum_token_cost: None, + maximum_token_cost: None, // We'll pay whatever + gas_fees_paid_by: GasFeesPaidBy::DocumentOwner, + })), + &signer, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition"); + + let documents_batch_create_serialized_transition = documents_batch_create_transition + .serialize_to_bytes() + .expect("expected documents batch serialized state transition"); + + let transaction = platform.drive.grove.start_transaction(); + + let processing_result = platform + .platform + .process_raw_state_transitions( + &vec![documents_batch_create_serialized_transition.clone()], + &platform_state, + &BlockInfo::default(), + &transaction, + platform_version, + false, + None, + ) + .expect("expected to process state transition"); + + assert_matches!( + processing_result.execution_results().as_slice(), + [PaidConsensusError( + ConsensusError::StateError(StateError::IdentityDoesNotHaveEnoughTokenBalanceError( + _ + )), + _ + )] + ); + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit transaction"); + + let token_balance = platform + .drive + .fetch_identity_token_balance( + gold_token_id.to_buffer(), + buyer.id().to_buffer(), + None, + platform_version, + ) + .expect("expected to fetch token balance"); + + // We should still have 8 + assert_eq!(token_balance, Some(8)); + } + + #[test] + fn test_document_creation_paid_with_an_external_token() { + let platform_version = PlatformVersion::latest(); + let mut platform = TestPlatformBuilder::new() + .with_latest_protocol_version() + .build_with_mock_rpc() + .set_genesis_state(); + + let mut rng = StdRng::seed_from_u64(433); + + let platform_state = platform.state.load(); + + let (document_contract_owner_id, _, _) = + setup_identity(&mut platform, 958, dash_to_credits!(0.1)); + + let (token_contract_owner_id, _, _) = + setup_identity(&mut platform, 11, dash_to_credits!(0.1)); + + let (buyer, signer, key) = setup_identity(&mut platform, 234, dash_to_credits!(0.1)); + + let (token_contract, token_id) = create_token_contract_with_owner_identity( + &mut platform, + token_contract_owner_id.id(), + None::, + None, + None, + platform_version, + ); + + let document_contract = create_card_game_external_token_contract_with_owner_identity( + &mut platform, + token_contract.id(), + 0, + 5, + GasFeesPaidBy::DocumentOwner, + document_contract_owner_id.id(), + platform_version, + ); + + let token_supply = platform + .drive + .fetch_token_total_supply(token_id.to_buffer(), None, platform_version) + .expect("expected to fetch total supply"); + + assert_eq!(token_supply, Some(100000)); + + assert_eq!(token_contract.tokens().len(), 1); + + add_tokens_to_identity(&mut platform, token_id.into(), buyer.id(), 15); + + let token_supply = platform + .drive + .fetch_token_total_supply(token_id.to_buffer(), None, platform_version) + .expect("expected to fetch total supply"); + + assert_eq!(token_supply, Some(100015)); + + let card_document_type = document_contract + .document_type_for_name("card") + .expect("expected a profile document type"); + + assert_eq!( + card_document_type.document_creation_token_cost(), + Some(DocumentActionTokenCost { + contract_id: Some(token_contract.id()), + token_contract_position: 0, + token_amount: 5, + effect: Default::default(), + gas_fees_paid_by: GasFeesPaidBy::DocumentOwner, + }) + ); + + let entropy = Bytes32::random_with_rng(&mut rng); + + let mut document = card_document_type + .random_document_with_identifier_and_entropy( + &mut rng, + buyer.id(), + entropy, + DocumentFieldFillType::DoNotFillIfNotRequired, + DocumentFieldFillSize::AnyDocumentFillSize, + platform_version, + ) + .expect("expected a random document"); + + document.set("attack", 4.into()); + document.set("defense", 7.into()); + + let documents_batch_create_transition = + BatchTransition::new_document_creation_transition_from_document( + document.clone(), + card_document_type, + entropy.0, + &key, + 2, + 0, + Some(TokenPaymentInfo::V0(TokenPaymentInfoV0 { + payment_token_contract_id: Some(token_contract.id()), + token_contract_position: 0, + minimum_token_cost: None, + maximum_token_cost: Some(5), + gas_fees_paid_by: GasFeesPaidBy::DocumentOwner, + })), + &signer, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition"); + + assert_matches!( + documents_batch_create_transition, + StateTransition::Batch(BatchTransition::V1(_)) + ); + + let documents_batch_create_serialized_transition = documents_batch_create_transition + .serialize_to_bytes() + .expect("expected documents batch serialized state transition"); + + let transaction = platform.drive.grove.start_transaction(); + + let processing_result = platform + .platform + .process_raw_state_transitions( + &vec![documents_batch_create_serialized_transition.clone()], + &platform_state, + &BlockInfo::default(), + &transaction, + platform_version, + false, + None, + ) + .expect("expected to process state transition"); + + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::SuccessfulExecution(_, _)] + ); + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit transaction"); + + let token_balance = platform + .drive + .fetch_identity_token_balance( + token_id.to_buffer(), + buyer.id().to_buffer(), + None, + platform_version, + ) + .expect("expected to fetch token balance"); + + // He had 15, but spent 5 + assert_eq!(token_balance, Some(10)); + + let token_supply = platform + .drive + .fetch_token_total_supply(token_id.to_buffer(), None, platform_version) + .expect("expected to fetch total supply"); + + assert_eq!(token_supply, Some(100015)); + + let token_balance = platform + .drive + .fetch_identity_token_balance( + token_id.to_buffer(), + document_contract_owner_id.id().to_buffer(), + None, + platform_version, + ) + .expect("expected to fetch token balance"); + + // He was paid 5 + assert_eq!(token_balance, Some(5)); } } diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/tests/document/deletion.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/tests/document/deletion.rs index aea536eb86c..d5d511abb30 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/tests/document/deletion.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/tests/document/deletion.rs @@ -2,7 +2,9 @@ use super::*; mod deletion_tests { use super::*; - use crate::execution::validation::state_transition::tests::create_card_game_token_contract_with_owner_identity; + use crate::execution::validation::state_transition::tests::create_card_game_internal_token_contract_with_owner_identity_burn_tokens; + use dpp::tokens::token_payment_info::v0::TokenPaymentInfoV0; + use dpp::tokens::token_payment_info::TokenPaymentInfo; #[test] fn test_document_delete_on_document_type_that_is_mutable_and_can_be_deleted() { @@ -58,6 +60,7 @@ mod deletion_tests { &key, 2, 0, + None, &signer, platform_version, None, @@ -101,6 +104,7 @@ mod deletion_tests { &key, 3, 0, + None, &signer, platform_version, None, @@ -239,6 +243,7 @@ mod deletion_tests { &key, 2, 0, + None, &signer, platform_version, None, @@ -282,6 +287,7 @@ mod deletion_tests { &key, 3, 0, + None, &signer, platform_version, None, @@ -403,6 +409,7 @@ mod deletion_tests { &key, 2, 0, + None, &signer, platform_version, None, @@ -446,6 +453,7 @@ mod deletion_tests { &key, 3, 0, + None, &signer, platform_version, None, @@ -567,6 +575,7 @@ mod deletion_tests { &key, 2, 0, + None, &signer, platform_version, None, @@ -610,6 +619,7 @@ mod deletion_tests { &key, 3, 0, + None, &signer, platform_version, None, @@ -702,6 +712,7 @@ mod deletion_tests { &key, 3, 0, + None, &signer, platform_version, None, @@ -761,7 +772,7 @@ mod deletion_tests { let (buyer, signer, key) = setup_identity(&mut platform, 234, dash_to_credits!(0.1)); let (contract, gold_token_id, gas_token_id) = - create_card_game_token_contract_with_owner_identity( + create_card_game_internal_token_contract_with_owner_identity_burn_tokens( &mut platform, contract_owner_id.id(), platform_version, @@ -800,6 +811,13 @@ mod deletion_tests { &key, 2, 0, + Some(TokenPaymentInfo::V0(TokenPaymentInfoV0 { + payment_token_contract_id: None, + token_contract_position: 0, + minimum_token_cost: None, + maximum_token_cost: Some(10), + gas_fees_paid_by: Default::default(), + })), &signer, platform_version, None, @@ -859,6 +877,13 @@ mod deletion_tests { &key, 3, 0, + Some(TokenPaymentInfo::V0(TokenPaymentInfoV0 { + payment_token_contract_id: None, + token_contract_position: 1, + minimum_token_cost: None, + maximum_token_cost: Some(1), + gas_fees_paid_by: Default::default(), + })), &signer, platform_version, None, @@ -929,7 +954,7 @@ mod deletion_tests { let (buyer, signer, key) = setup_identity(&mut platform, 234, dash_to_credits!(0.1)); let (contract, gold_token_id, gas_token_id) = - create_card_game_token_contract_with_owner_identity( + create_card_game_internal_token_contract_with_owner_identity_burn_tokens( &mut platform, contract_owner_id.id(), platform_version, @@ -967,6 +992,13 @@ mod deletion_tests { &key, 2, 0, + Some(TokenPaymentInfo::V0(TokenPaymentInfoV0 { + payment_token_contract_id: None, + token_contract_position: 0, + minimum_token_cost: None, + maximum_token_cost: Some(10), + gas_fees_paid_by: Default::default(), + })), &signer, platform_version, None, @@ -1026,6 +1058,13 @@ mod deletion_tests { &key, 3, 0, + Some(TokenPaymentInfo::V0(TokenPaymentInfoV0 { + payment_token_contract_id: None, + token_contract_position: 1, + minimum_token_cost: None, + maximum_token_cost: Some(10), + gas_fees_paid_by: Default::default(), + })), &signer, platform_version, None, diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/tests/document/dpns.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/tests/document/dpns.rs index 770831858bf..427d39348fd 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/tests/document/dpns.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/tests/document/dpns.rs @@ -214,6 +214,7 @@ mod dpns_tests { &key_1, 2, 0, + None, &signer_1, platform_version, None, @@ -235,6 +236,7 @@ mod dpns_tests { &key_2, 2, 0, + None, &signer_2, platform_version, None, @@ -256,6 +258,7 @@ mod dpns_tests { &key_3, 2, 0, + None, &signer_3, platform_version, None, @@ -277,6 +280,7 @@ mod dpns_tests { &key_1, 3, 0, + None, &signer_1, platform_version, None, @@ -297,6 +301,7 @@ mod dpns_tests { &key_2, 3, 0, + None, &signer_2, platform_version, None, @@ -317,6 +322,7 @@ mod dpns_tests { &key_3, 3, 0, + None, &signer_3, platform_version, None, @@ -669,6 +675,7 @@ mod dpns_tests { &key_1, 2, 0, + None, &signer_1, platform_version, None, @@ -690,6 +697,7 @@ mod dpns_tests { &key_2, 2, 0, + None, &signer_2, platform_version, None, @@ -711,6 +719,7 @@ mod dpns_tests { &key_3, 2, 0, + None, &signer_3, platform_version, None, @@ -732,6 +741,7 @@ mod dpns_tests { &key_1, 3, 0, + None, &signer_1, platform_version, None, @@ -752,6 +762,7 @@ mod dpns_tests { &key_2, 3, 0, + None, &signer_2, platform_version, None, @@ -772,6 +783,7 @@ mod dpns_tests { &key_3, 3, 0, + None, &signer_3, platform_version, None, diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/tests/document/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/tests/document/mod.rs index c318efd8104..d073097768c 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/tests/document/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/tests/document/mod.rs @@ -7,4 +7,4 @@ mod transfer; use super::*; -use crate::execution::validation::state_transition::tests::create_card_game_token_contract_with_owner_identity; +use crate::execution::validation::state_transition::tests::create_card_game_internal_token_contract_with_owner_identity_burn_tokens; diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/tests/document/nft.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/tests/document/nft.rs index 9b28a656024..d90c717889a 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/tests/document/nft.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/tests/document/nft.rs @@ -3,6 +3,8 @@ use super::*; mod nft_tests { use super::*; use crate::test::helpers::fast_forward_to_block::fast_forward_to_block; + use dpp::tokens::token_payment_info::v0::TokenPaymentInfoV0; + use dpp::tokens::token_payment_info::TokenPaymentInfo; #[test] fn test_document_set_price_on_document_without_ability_to_purchase() { let platform_version = PlatformVersion::latest(); @@ -47,6 +49,7 @@ mod nft_tests { &key, 2, 0, + None, &signer, platform_version, None, @@ -117,6 +120,7 @@ mod nft_tests { &key, 3, 0, + None, &signer, platform_version, None, @@ -206,6 +210,7 @@ mod nft_tests { &key, 2, 0, + None, &signer, platform_version, None, @@ -299,6 +304,7 @@ mod nft_tests { &key, 3, 0, + None, &signer, platform_version, None, @@ -426,6 +432,7 @@ mod nft_tests { &key, 2, 0, + None, &signer, platform_version, None, @@ -545,6 +552,7 @@ mod nft_tests { &key, 3, 0, + None, &signer, platform_version, None, @@ -661,6 +669,7 @@ mod nft_tests { &recipient_key, 1, // 1 because he's never done anything 0, + None, &recipient_signer, platform_version, None, @@ -821,6 +830,7 @@ mod nft_tests { &key, 2, 0, + None, &signer, platform_version, None, @@ -944,6 +954,7 @@ mod nft_tests { &key, 3, 0, + None, &signer, platform_version, None, @@ -1039,6 +1050,7 @@ mod nft_tests { &key, 4, 0, + None, &signer, platform_version, None, @@ -1167,6 +1179,7 @@ mod nft_tests { &recipient_key, 1, // 1 because he's never done anything 0, + None, &recipient_signer, platform_version, None, @@ -1326,6 +1339,7 @@ mod nft_tests { &key, 2, 0, + None, &signer, platform_version, None, @@ -1449,6 +1463,7 @@ mod nft_tests { &key, 3, 0, + None, &signer, platform_version, None, @@ -1567,6 +1582,7 @@ mod nft_tests { &recipient_key, 1, // 1 because he's never done anything 0, + None, &recipient_signer, platform_version, None, @@ -1711,6 +1727,7 @@ mod nft_tests { &key, 2, 0, + None, &signer, platform_version, None, @@ -1757,6 +1774,7 @@ mod nft_tests { &key, 3, 0, + None, &signer, platform_version, None, @@ -1807,6 +1825,7 @@ mod nft_tests { &recipient_key, 1, // 1 because he's never done anything 0, + None, &recipient_signer, platform_version, None, @@ -1903,6 +1922,7 @@ mod nft_tests { &key, 2, 0, + None, &signer, platform_version, None, @@ -1949,6 +1969,7 @@ mod nft_tests { &key, 3, 0, + None, &signer, platform_version, None, @@ -1999,6 +2020,7 @@ mod nft_tests { &key, 1, // 1 because he's never done anything 0, + None, &signer, platform_version, None, @@ -2100,6 +2122,7 @@ mod nft_tests { &key, 2, 0, + None, &signer, platform_version, None, @@ -2146,6 +2169,7 @@ mod nft_tests { &key, 3, 0, + None, &signer, platform_version, None, @@ -2196,6 +2220,7 @@ mod nft_tests { &recipient_key, 1, // 1 because he's never done anything 0, + None, &recipient_signer, platform_version, None, @@ -2307,6 +2332,7 @@ mod nft_tests { &key, 4, // 1 because he's never done anything 0, + None, &signer, platform_version, None, @@ -2402,6 +2428,7 @@ mod nft_tests { &key, 2, 0, + None, &signer, platform_version, None, @@ -2495,6 +2522,7 @@ mod nft_tests { &key, 3, 0, + None, &signer, platform_version, None, @@ -2589,6 +2617,7 @@ mod nft_tests { &recipient_key, 1, // 1 because he's never done anything 0, + None, &recipient_signer, platform_version, None, @@ -2681,6 +2710,7 @@ mod nft_tests { &key, 2, 0, + None, &signer, platform_version, None, @@ -2729,6 +2759,7 @@ mod nft_tests { &other_identity_key, 1, 0, + None, &other_identity_signer, platform_version, None, @@ -2820,7 +2851,7 @@ mod nft_tests { setup_identity(&mut platform, 450, dash_to_credits!(1.0)); let (contract, gold_token_id, gas_token_id) = - create_card_game_token_contract_with_owner_identity( + create_card_game_internal_token_contract_with_owner_identity_burn_tokens( &mut platform, contract_owner_id.id(), platform_version, @@ -2874,6 +2905,13 @@ mod nft_tests { &key, 2, 0, + Some(TokenPaymentInfo::V0(TokenPaymentInfoV0 { + payment_token_contract_id: None, + token_contract_position: 0, + minimum_token_cost: Some(10), + maximum_token_cost: Some(10), + gas_fees_paid_by: Default::default(), + })), &signer, platform_version, None, @@ -2970,6 +3008,13 @@ mod nft_tests { &key, 3, 0, + Some(TokenPaymentInfo::V0(TokenPaymentInfoV0 { + payment_token_contract_id: None, + token_contract_position: 1, + minimum_token_cost: None, + maximum_token_cost: Some(1), + gas_fees_paid_by: Default::default(), + })), &signer, platform_version, None, @@ -3061,6 +3106,13 @@ mod nft_tests { &recipient_key, 1, // 1 because he's never done anything 0, + Some(TokenPaymentInfo::V0(TokenPaymentInfoV0 { + payment_token_contract_id: None, + token_contract_position: 0, + minimum_token_cost: Some(2), + maximum_token_cost: Some(3), + gas_fees_paid_by: Default::default(), + })), &recipient_signer, platform_version, None, diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/tests/document/replacement.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/tests/document/replacement.rs index 780682c9cf1..ed72f0c583b 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/tests/document/replacement.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/tests/document/replacement.rs @@ -5,6 +5,8 @@ mod replacement_tests { use crate::test::helpers::fast_forward_to_block::fast_forward_to_block; use dpp::identifier::Identifier; use dpp::prelude::IdentityNonce; + use dpp::tokens::token_payment_info::v0::TokenPaymentInfoV0; + use dpp::tokens::token_payment_info::TokenPaymentInfo; use std::collections::BTreeMap; #[test] @@ -61,6 +63,7 @@ mod replacement_tests { &key, 2, 0, + None, &signer, platform_version, None, @@ -104,6 +107,7 @@ mod replacement_tests { &key, 3, 0, + None, &signer, platform_version, None, @@ -213,6 +217,7 @@ mod replacement_tests { &key, 2, 0, + None, &signer, platform_version, None, @@ -269,6 +274,7 @@ mod replacement_tests { &key, 3 + i as IdentityNonce, 0, + None, &signer, platform_version, None, @@ -559,6 +565,7 @@ mod replacement_tests { &key, 2, 0, + None, &signer, platform_version, None, @@ -602,6 +609,7 @@ mod replacement_tests { &key, 3, 0, + None, &signer, platform_version, None, @@ -689,6 +697,7 @@ mod replacement_tests { &key, 2, 0, + None, &signer, platform_version, None, @@ -784,6 +793,7 @@ mod replacement_tests { &key, 3, 0, + None, &signer, platform_version, None, @@ -891,6 +901,7 @@ mod replacement_tests { &key, 3, 0, + None, &signer, platform_version, None, @@ -994,6 +1005,7 @@ mod replacement_tests { &key, 2, 0, + None, &signer, platform_version, None, @@ -1058,6 +1070,7 @@ mod replacement_tests { &key, 3, 0, + None, &signer, platform_version, None, @@ -1077,6 +1090,7 @@ mod replacement_tests { &key, 4, 0, + None, &signer, platform_version, None, @@ -1210,6 +1224,7 @@ mod replacement_tests { &key, 2, 0, + None, &signer, platform_version, None, @@ -1278,6 +1293,7 @@ mod replacement_tests { &key, 3, 0, + None, &signer, platform_version, None, @@ -1297,6 +1313,7 @@ mod replacement_tests { &key, 4, 0, + None, &signer, platform_version, None, @@ -1467,6 +1484,7 @@ mod replacement_tests { &key, 2, 0, + None, &signer, platform_version, None, @@ -1535,6 +1553,7 @@ mod replacement_tests { &key, 3, 0, + None, &signer, platform_version, None, @@ -1554,6 +1573,7 @@ mod replacement_tests { &key, 4, 0, + None, &signer, platform_version, None, @@ -1728,6 +1748,7 @@ mod replacement_tests { &key, 2, 0, + None, &signer, platform_version, None, @@ -1796,6 +1817,7 @@ mod replacement_tests { &key, 3, 0, + None, &signer, platform_version, None, @@ -1815,6 +1837,7 @@ mod replacement_tests { &key, 4, 0, + None, &signer, platform_version, None, @@ -1946,7 +1969,7 @@ mod replacement_tests { let (creator, signer, key) = setup_identity(&mut platform, 234, dash_to_credits!(0.1)); let (contract, gold_token_id, gas_token_id) = - create_card_game_token_contract_with_owner_identity( + create_card_game_internal_token_contract_with_owner_identity_burn_tokens( &mut platform, contract_owner_id.id(), platform_version, @@ -1997,6 +2020,13 @@ mod replacement_tests { &key, 2, 0, + Some(TokenPaymentInfo::V0(TokenPaymentInfoV0 { + payment_token_contract_id: None, + token_contract_position: 0, + minimum_token_cost: None, + maximum_token_cost: Some(10), + gas_fees_paid_by: Default::default(), + })), &signer, platform_version, None, @@ -2043,6 +2073,13 @@ mod replacement_tests { &key, 3, 0, + Some(TokenPaymentInfo::V0(TokenPaymentInfoV0 { + payment_token_contract_id: None, + token_contract_position: 1, + minimum_token_cost: None, + maximum_token_cost: Some(2), + gas_fees_paid_by: Default::default(), + })), &signer, platform_version, None, diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/tests/document/transfer.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/tests/document/transfer.rs index 12637581e35..8a0e7ea99fd 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/tests/document/transfer.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/tests/document/transfer.rs @@ -2,6 +2,8 @@ use super::*; mod transfer_tests { use super::*; + use dpp::tokens::token_payment_info::v0::TokenPaymentInfoV0; + use dpp::tokens::token_payment_info::TokenPaymentInfo; #[test] fn test_document_transfer_on_document_type_that_is_transferable_that_has_no_owner_indices() { @@ -69,6 +71,7 @@ mod transfer_tests { &key, 2, 0, + None, &signer, platform_version, None, @@ -115,6 +118,7 @@ mod transfer_tests { &key, 3, 0, + None, &signer, platform_version, None, @@ -223,6 +227,7 @@ mod transfer_tests { &key, 2, 0, + None, &signer, platform_version, None, @@ -316,6 +321,7 @@ mod transfer_tests { &key, 3, 0, + None, &signer, platform_version, None, @@ -447,6 +453,7 @@ mod transfer_tests { &key, 2, 0, + None, &signer, platform_version, None, @@ -540,6 +547,7 @@ mod transfer_tests { &key, 3, 0, + None, &signer, platform_version, None, @@ -691,6 +699,7 @@ mod transfer_tests { &key, 3, 0, + None, &signer, platform_version, None, @@ -796,6 +805,7 @@ mod transfer_tests { &key, 2, 0, + None, &signer, platform_version, None, @@ -889,6 +899,7 @@ mod transfer_tests { &key, 3, 0, + None, &signer, platform_version, None, @@ -957,6 +968,7 @@ mod transfer_tests { &recipient_key, 2, 0, + None, &recipient_signer, platform_version, None, @@ -1035,7 +1047,7 @@ mod transfer_tests { let (receiver, _, _) = setup_identity(&mut platform, 450, dash_to_credits!(0.1)); let (contract, gold_token_id, gas_token_id) = - create_card_game_token_contract_with_owner_identity( + create_card_game_internal_token_contract_with_owner_identity_burn_tokens( &mut platform, contract_owner_id.id(), platform_version, @@ -1088,6 +1100,13 @@ mod transfer_tests { &key, 2, 0, + Some(TokenPaymentInfo::V0(TokenPaymentInfoV0 { + payment_token_contract_id: None, + token_contract_position: 0, + minimum_token_cost: None, + maximum_token_cost: Some(10), + gas_fees_paid_by: Default::default(), + })), &signer, platform_version, None, @@ -1181,6 +1200,13 @@ mod transfer_tests { &key, 3, 0, + Some(TokenPaymentInfo::V0(TokenPaymentInfoV0 { + payment_token_contract_id: None, + token_contract_position: 1, + minimum_token_cost: None, + maximum_token_cost: Some(10), + gas_fees_paid_by: Default::default(), + })), &signer, platform_version, None, 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..9540f6a5e79 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 @@ -33,7 +33,6 @@ use dpp::state_transition::StateTransitionLike; use drive::state_transition_action::batch::batched_transition::document_transition::document_create_transition_action::DocumentCreateTransitionAction; use drive::state_transition_action::batch::batched_transition::document_transition::document_delete_transition_action::DocumentDeleteTransitionAction; use drive::state_transition_action::batch::batched_transition::document_transition::document_replace_transition_action::DocumentReplaceTransitionAction; -use drive::state_transition_action::batch::batched_transition::document_transition::DocumentTransitionAction; use drive::state_transition_action::batch::BatchTransitionAction; use drive::state_transition_action::batch::v0::BatchTransitionActionV0; @@ -90,6 +89,7 @@ trait BatchTransitionInternalTransformerV0 { data_contract_id: &Identifier, owner_id: Identifier, document_transitions: &BTreeMap<&String, Vec<&DocumentTransition>>, + user_fee_increase: UserFeeIncrease, execution_context: &mut StateTransitionExecutionContext, transaction: TransactionArg, platform_version: &PlatformVersion, @@ -103,6 +103,7 @@ trait BatchTransitionInternalTransformerV0 { document_type_name: &str, owner_id: Identifier, document_transitions: &[&DocumentTransition], + user_fee_increase: UserFeeIncrease, execution_context: &mut StateTransitionExecutionContext, transaction: TransactionArg, platform_version: &PlatformVersion, @@ -144,6 +145,7 @@ trait BatchTransitionInternalTransformerV0 { data_contract_fetch_info: Arc, transition: &DocumentTransition, replaced_documents: &[Document], + user_fee_increase: UserFeeIncrease, owner_id: Identifier, execution_context: &mut StateTransitionExecutionContext, platform_version: &PlatformVersion, @@ -236,6 +238,7 @@ impl BatchTransitionTransformerV0 for BatchTransition { data_contract_id, owner_id, document_transitions_by_document_type, + user_fee_increase, execution_context, transaction, platform_version, @@ -350,6 +353,7 @@ impl BatchTransitionInternalTransformerV0 for BatchTransition { data_contract_id: &Identifier, owner_id: Identifier, document_transitions: &BTreeMap<&String, Vec<&DocumentTransition>>, + user_fee_increase: UserFeeIncrease, execution_context: &mut StateTransitionExecutionContext, transaction: TransactionArg, platform_version: &PlatformVersion, @@ -385,6 +389,7 @@ impl BatchTransitionInternalTransformerV0 for BatchTransition { document_type_name, owner_id, document_transitions, + user_fee_increase, execution_context, transaction, platform_version, @@ -403,6 +408,7 @@ impl BatchTransitionInternalTransformerV0 for BatchTransition { document_type_name: &str, owner_id: Identifier, document_transitions: &[&DocumentTransition], + user_fee_increase: UserFeeIncrease, execution_context: &mut StateTransitionExecutionContext, transaction: TransactionArg, platform_version: &PlatformVersion, @@ -476,6 +482,7 @@ impl BatchTransitionInternalTransformerV0 for BatchTransition { data_contract_fetch_info.clone(), transition, &replaced_documents, + user_fee_increase, owner_id, execution_context, platform_version, @@ -617,6 +624,7 @@ impl BatchTransitionInternalTransformerV0 for BatchTransition { data_contract_fetch_info: Arc, transition: &DocumentTransition, replaced_documents: &[Document], + user_fee_increase: UserFeeIncrease, owner_id: Identifier, execution_context: &mut StateTransitionExecutionContext, platform_version: &PlatformVersion, @@ -624,18 +632,14 @@ impl BatchTransitionInternalTransformerV0 for BatchTransition { match transition { DocumentTransition::Create(document_create_transition) => { let (document_create_action, fee_result) = DocumentCreateTransitionAction::try_from_document_borrowed_create_transition_with_contract_lookup( - drive, transaction, - document_create_transition, block_info, |_identifier| { + drive, owner_id, transaction, + document_create_transition, block_info, user_fee_increase, |_identifier| { Ok(data_contract_fetch_info.clone()) }, platform_version)?; execution_context .add_operation(ValidationOperation::PrecalculatedOperation(fee_result)); - - let batched_action = BatchedTransitionAction::DocumentAction( - DocumentTransitionAction::CreateAction(document_create_action), - ); - Ok(batched_action.into()) + Ok(document_create_action) } DocumentTransition::Replace(document_replace_transition) => { let mut result = ConsensusValidationResult::::new(); @@ -707,9 +711,10 @@ impl BatchTransitionInternalTransformerV0 for BatchTransition { } } - let document_replace_action = + let (document_replace_action, fee_result) = DocumentReplaceTransitionAction::try_from_borrowed_document_replace_transition( document_replace_transition, + owner_id, original_document_created_at, original_document_created_at_block_height, original_document_created_at_core_block_height, @@ -717,26 +722,28 @@ impl BatchTransitionInternalTransformerV0 for BatchTransition { original_document_transferred_at_block_height, original_document_transferred_at_core_block_height, block_info, + user_fee_increase, |_identifier| Ok(data_contract_fetch_info.clone()), )?; + execution_context + .add_operation(ValidationOperation::PrecalculatedOperation(fee_result)); + if result.is_valid() { - let batched_action = BatchedTransitionAction::DocumentAction( - DocumentTransitionAction::ReplaceAction(document_replace_action), - ); - Ok(batched_action.into()) + Ok(document_replace_action) } else { Ok(result) } } DocumentTransition::Delete(document_delete_transition) => { - let action = DocumentDeleteTransitionAction::try_from_document_borrowed_create_transition_with_contract_lookup(document_delete_transition, |_identifier| { + let (batched_action, fee_result) = DocumentDeleteTransitionAction::try_from_document_borrowed_delete_transition_with_contract_lookup(document_delete_transition, owner_id, user_fee_increase, |_identifier| { Ok(data_contract_fetch_info.clone()) })?; - let batched_action = BatchedTransitionAction::DocumentAction( - DocumentTransitionAction::DeleteAction(action), - ); - Ok(batched_action.into()) + + execution_context + .add_operation(ValidationOperation::PrecalculatedOperation(fee_result)); + + Ok(batched_action) } DocumentTransition::Transfer(document_transfer_transition) => { let mut result = ConsensusValidationResult::::new(); @@ -778,19 +785,21 @@ impl BatchTransitionInternalTransformerV0 for BatchTransition { } } - let document_transfer_action = + let (document_transfer_action, fee_result) = DocumentTransferTransitionAction::try_from_borrowed_document_transfer_transition( document_transfer_transition, + owner_id, original_document.clone(), //todo: remove clone block_info, + user_fee_increase, |_identifier| Ok(data_contract_fetch_info.clone()), )?; + execution_context + .add_operation(ValidationOperation::PrecalculatedOperation(fee_result)); + if result.is_valid() { - let batched_action = BatchedTransitionAction::DocumentAction( - DocumentTransitionAction::TransferAction(document_transfer_action), - ); - Ok(batched_action.into()) + Ok(document_transfer_action) } else { Ok(result) } @@ -835,19 +844,21 @@ impl BatchTransitionInternalTransformerV0 for BatchTransition { } } - let document_update_price_action = + let (document_update_price_action, fee_result) = DocumentUpdatePriceTransitionAction::try_from_borrowed_document_update_price_transition( document_update_price_transition, + owner_id, original_document.clone(), //todo: find a way to not have to use cloning block_info, + user_fee_increase, |_identifier| Ok(data_contract_fetch_info.clone()), )?; + execution_context + .add_operation(ValidationOperation::PrecalculatedOperation(fee_result)); + if result.is_valid() { - let batched_action = BatchedTransitionAction::DocumentAction( - DocumentTransitionAction::UpdatePriceAction(document_update_price_action), - ); - Ok(batched_action.into()) + Ok(document_update_price_action) } else { Ok(result) } @@ -902,20 +913,22 @@ impl BatchTransitionInternalTransformerV0 for BatchTransition { } } - let document_purchase_action = + let (document_purchase_action, fee_result) = DocumentPurchaseTransitionAction::try_from_borrowed_document_purchase_transition( document_purchase_transition, + owner_id, original_document.clone(), //todo: find a way to not have to use cloning owner_id, block_info, + user_fee_increase, |_identifier| Ok(data_contract_fetch_info.clone()), )?; + execution_context + .add_operation(ValidationOperation::PrecalculatedOperation(fee_result)); + if result.is_valid() { - let batched_action = BatchedTransitionAction::DocumentAction( - DocumentTransitionAction::PurchaseAction(document_purchase_action), - ); - Ok(batched_action.into()) + Ok(document_purchase_action) } else { Ok(result) } diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/data_contract_create/advanced_structure/v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/data_contract_create/advanced_structure/v0/mod.rs index cb0983a8109..5f2db600793 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/data_contract_create/advanced_structure/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/data_contract_create/advanced_structure/v0/mod.rs @@ -9,7 +9,7 @@ use dpp::consensus::basic::data_contract::{ }; use dpp::consensus::basic::BasicError; use dpp::data_contract::associated_token::token_configuration::accessors::v0::TokenConfigurationV0Getters; -use dpp::data_contract::INITIAL_DATA_CONTRACT_VERSION; +use dpp::data_contract::{TokenContractPosition, INITIAL_DATA_CONTRACT_VERSION}; use dpp::prelude::DataContract; use dpp::state_transition::data_contract_create_transition::accessors::DataContractCreateTransitionAccessorsV0; use dpp::state_transition::data_contract_create_transition::DataContractCreateTransition; @@ -87,10 +87,10 @@ impl DataContractCreatedStateTransitionAdvancedStructureValidationV0 } } - let expected_position = 0; - - for (token_contract_position, token_configuration) in self.data_contract().tokens() { - if expected_position != *token_contract_position { + for (expected_position, (token_contract_position, token_configuration)) in + self.data_contract().tokens().iter().enumerate() + { + if expected_position as TokenContractPosition != *token_contract_position { let bump_action = StateTransitionAction::BumpIdentityNonceAction( BumpIdentityNonceAction::from_borrowed_data_contract_create_transition(self), ); @@ -98,7 +98,7 @@ impl DataContractCreatedStateTransitionAdvancedStructureValidationV0 return Ok(ConsensusValidationResult::new_with_data_and_errors( bump_action, vec![NonContiguousContractTokenPositionsError::new( - expected_position, + expected_position as TokenContractPosition, *token_contract_position, ) .into()], diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/data_contract_create/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/data_contract_create/mod.rs index b411f716051..b8b2a41aa6e 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/data_contract_create/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/data_contract_create/mod.rs @@ -143,6 +143,7 @@ impl StateTransitionStateValidationV0 for DataContractCreateTransition { #[cfg(test)] mod tests { use crate::execution::validation::state_transition::state_transitions::tests::setup_identity; + use crate::execution::validation::state_transition::tests::create_token_contract_with_owner_identity; use crate::platform_types::state_transitions_processing_result::StateTransitionExecutionResult; use crate::test::helpers::setup::TestPlatformBuilder; use assert_matches::assert_matches; @@ -151,23 +152,33 @@ mod tests { use dpp::consensus::basic::BasicError; use dpp::consensus::ConsensusError; use dpp::dash_to_credits; + use dpp::data_contract::accessors::v0::DataContractV0Getters; use dpp::data_contract::accessors::v1::DataContractV1Getters; use dpp::data_contract::associated_token::token_configuration::accessors::v0::TokenConfigurationV0Setters; use dpp::data_contract::change_control_rules::authorized_action_takers::AuthorizedActionTakers; use dpp::data_contract::change_control_rules::v0::ChangeControlRulesV0; use dpp::data_contract::change_control_rules::ChangeControlRules; + use dpp::data_contract::document_type::accessors::{ + DocumentTypeV0MutGetters, DocumentTypeV1Setters, + }; use dpp::data_contract::group::v0::GroupV0; use dpp::data_contract::group::Group; use dpp::data_contract::DataContract; + use dpp::data_contract::TokenConfiguration; use dpp::identity::accessors::IdentityGettersV0; use dpp::identity::identity_public_key::accessors::v0::IdentityPublicKeyGettersV0; use dpp::identity::TimestampMillis; + use dpp::platform_value::Value; use dpp::prelude::Identifier; use dpp::serialization::PlatformSerializable; use dpp::state_transition::data_contract_create_transition::methods::DataContractCreateTransitionMethodsV0; use dpp::state_transition::data_contract_create_transition::DataContractCreateTransition; use dpp::tests::json_document::json_document_to_contract_with_ids; use dpp::tokens::calculate_token_id; + use dpp::tokens::gas_fees_paid_by::GasFeesPaidBy; + use dpp::tokens::token_amount_on_contract_token::{ + DocumentActionTokenCost, DocumentActionTokenEffect, + }; use platform_version::version::PlatformVersion; use std::collections::BTreeMap; @@ -683,6 +694,342 @@ mod tests { .expect("expected to fetch token balance"); assert_eq!(token_balance, Some(base_supply_start_amount)); } + + #[test] + fn test_data_contract_creation_with_single_token_setting_burn_of_internal_token_on_nft_purchase_should_be_allowed( + ) { + let platform_version = PlatformVersion::latest(); + let mut platform = TestPlatformBuilder::new() + .build_with_mock_rpc() + .set_genesis_state(); + + let platform_state = platform.state.load(); + + let (identity, contract_signer, contract_key) = + setup_identity(&mut platform, 958, dash_to_credits!(0.1)); + + let mut data_contract = json_document_to_contract_with_ids( + "tests/supporting_files/contract/crypto-card-game/crypto-card-game-in-game-currency.json", + None, + None, + false, //no need to validate the data contracts in tests for drive + platform_version, + ) + .expect("expected to get json based contract"); + + { + let document_type = data_contract + .document_types_mut() + .get_mut("card") + .expect("expected a document type with name card"); + document_type.set_document_creation_token_cost(Some(DocumentActionTokenCost { + contract_id: None, + token_contract_position: 0, + token_amount: 5, + effect: DocumentActionTokenEffect::BurnToken, + gas_fees_paid_by: GasFeesPaidBy::DocumentOwner, + })); + let gas_fees_paid_by_int: u8 = GasFeesPaidBy::DocumentOwner.into(); + let schema = document_type.schema_mut(); + let token_cost = schema + .get_mut("tokenCost") + .expect("expected to get token cost") + .expect("expected token cost to be set"); + let creation_token_cost = token_cost + .get_mut("create") + .expect("expected to get creation token cost") + .expect("expected creation token cost to be set"); + creation_token_cost + .set_value("tokenPosition", 0.into()) + .expect("expected to set token position"); + creation_token_cost + .set_value("amount", 5.into()) + .expect("expected to set token amount"); + creation_token_cost + .set_value( + "effect", + Value::U8(DocumentActionTokenEffect::BurnToken.into()), + ) + .expect("expected to set token pay effect"); + creation_token_cost + .set_value("gasFeesPaidBy", gas_fees_paid_by_int.into()) + .expect("expected to set token amount"); + } + + let data_contract_create_transition = + DataContractCreateTransition::new_from_data_contract( + data_contract, + 1, + &identity.into_partial_identity_info(), + contract_key.id(), + &contract_signer, + platform_version, + None, + ) + .expect("expect to create data contract create batch transition"); + + let data_contract_create_serialized_transition = data_contract_create_transition + .serialize_to_bytes() + .expect("expected documents batch serialized state transition"); + + let transaction = platform.drive.grove.start_transaction(); + + let processing_result = platform + .platform + .process_raw_state_transitions( + &vec![data_contract_create_serialized_transition.clone()], + &platform_state, + &BlockInfo::default(), + &transaction, + platform_version, + false, + None, + ) + .expect("expected to process state transition"); + + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::SuccessfulExecution(_, _)] + ); + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit transaction"); + } + + #[test] + fn test_data_contract_creation_with_single_tokensetting_transfer_on_nft_purchase_with_internal_token_should_be_allowed( + ) { + let platform_version = PlatformVersion::latest(); + let mut platform = TestPlatformBuilder::new() + .build_with_mock_rpc() + .set_genesis_state(); + + let platform_state = platform.state.load(); + + let (identity, contract_signer, contract_key) = + setup_identity(&mut platform, 958, dash_to_credits!(0.1)); + + let mut data_contract = json_document_to_contract_with_ids( + "tests/supporting_files/contract/crypto-card-game/crypto-card-game-in-game-currency.json", + None, + None, + false, //no need to validate the data contracts in tests for drive + platform_version, + ) + .expect("expected to get json based contract"); + + { + let document_type = data_contract + .document_types_mut() + .get_mut("card") + .expect("expected a document type with name card"); + document_type.set_document_creation_token_cost(Some(DocumentActionTokenCost { + contract_id: None, + token_contract_position: 0, + token_amount: 5, + effect: DocumentActionTokenEffect::TransferTokenToContractOwner, + gas_fees_paid_by: GasFeesPaidBy::DocumentOwner, + })); + let gas_fees_paid_by_int: u8 = GasFeesPaidBy::DocumentOwner.into(); + let schema = document_type.schema_mut(); + let token_cost = schema + .get_mut("tokenCost") + .expect("expected to get token cost") + .expect("expected token cost to be set"); + let creation_token_cost = token_cost + .get_mut("create") + .expect("expected to get creation token cost") + .expect("expected creation token cost to be set"); + creation_token_cost + .set_value("tokenPosition", 0.into()) + .expect("expected to set token position"); + creation_token_cost + .set_value("amount", 5.into()) + .expect("expected to set token amount"); + creation_token_cost + .set_value( + "effect", + Value::U8( + DocumentActionTokenEffect::TransferTokenToContractOwner.into(), + ), + ) + .expect("expected to set token pay effect"); + creation_token_cost + .set_value("gasFeesPaidBy", gas_fees_paid_by_int.into()) + .expect("expected to set token amount"); + } + + let data_contract_create_transition = + DataContractCreateTransition::new_from_data_contract( + data_contract, + 1, + &identity.into_partial_identity_info(), + contract_key.id(), + &contract_signer, + platform_version, + None, + ) + .expect("expect to create data contract create batch transition"); + + let data_contract_create_serialized_transition = data_contract_create_transition + .serialize_to_bytes() + .expect("expected documents batch serialized state transition"); + + let transaction = platform.drive.grove.start_transaction(); + + let processing_result = platform + .platform + .process_raw_state_transitions( + &vec![data_contract_create_serialized_transition.clone()], + &platform_state, + &BlockInfo::default(), + &transaction, + platform_version, + false, + None, + ) + .expect("expected to process state transition"); + + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::SuccessfulExecution(_, _)] + ); + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit transaction"); + } + + #[test] + fn test_data_contract_creation_with_single_token_setting_transfer_on_nft_purchase_with_external_token_should_be_allowed( + ) { + let platform_version = PlatformVersion::latest(); + let mut platform = TestPlatformBuilder::new() + .build_with_mock_rpc() + .set_genesis_state(); + + let platform_state = platform.state.load(); + + let (identity, contract_signer, contract_key) = + setup_identity(&mut platform, 958, dash_to_credits!(0.1)); + + let (token_contract_owner_id, _, _) = + setup_identity(&mut platform, 11, dash_to_credits!(0.1)); + + let (token_contract, _) = create_token_contract_with_owner_identity( + &mut platform, + token_contract_owner_id.id(), + None::, + None, + None, + platform_version, + ); + + let token_contract_id = token_contract.id(); + + let mut data_contract = json_document_to_contract_with_ids( + "tests/supporting_files/contract/crypto-card-game/crypto-card-game-in-game-currency.json", + None, + None, + false, //no need to validate the data contracts in tests for drive + platform_version, + ) + .expect("expected to get json based contract"); + + { + let document_type = data_contract + .document_types_mut() + .get_mut("card") + .expect("expected a document type with name card"); + document_type.set_document_creation_token_cost(Some(DocumentActionTokenCost { + contract_id: Some(token_contract_id), + token_contract_position: 0, + token_amount: 5, + effect: DocumentActionTokenEffect::TransferTokenToContractOwner, + gas_fees_paid_by: GasFeesPaidBy::DocumentOwner, + })); + let gas_fees_paid_by_int: u8 = GasFeesPaidBy::DocumentOwner.into(); + let schema = document_type.schema_mut(); + let token_cost = schema + .get_mut("tokenCost") + .expect("expected to get token cost") + .expect("expected token cost to be set"); + let creation_token_cost = token_cost + .get_mut("create") + .expect("expected to get creation token cost") + .expect("expected creation token cost to be set"); + creation_token_cost + .set_value("contractId", token_contract_id.into()) + .expect("expected to set token contract id"); + creation_token_cost + .set_value("tokenPosition", 0.into()) + .expect("expected to set token position"); + creation_token_cost + .set_value("amount", 5.into()) + .expect("expected to set token amount"); + creation_token_cost + .set_value( + "effect", + Value::U8( + DocumentActionTokenEffect::TransferTokenToContractOwner.into(), + ), + ) + .expect("expected to set token pay effect"); + creation_token_cost + .set_value("gasFeesPaidBy", gas_fees_paid_by_int.into()) + .expect("expected to set token amount"); + } + + let data_contract_create_transition = + DataContractCreateTransition::new_from_data_contract( + data_contract, + 1, + &identity.into_partial_identity_info(), + contract_key.id(), + &contract_signer, + platform_version, + None, + ) + .expect("expect to create data contract create batch transition"); + + let data_contract_create_serialized_transition = data_contract_create_transition + .serialize_to_bytes() + .expect("expected documents batch serialized state transition"); + + let transaction = platform.drive.grove.start_transaction(); + + let processing_result = platform + .platform + .process_raw_state_transitions( + &vec![data_contract_create_serialized_transition.clone()], + &platform_state, + &BlockInfo::default(), + &transaction, + platform_version, + false, + None, + ) + .expect("expected to process state transition"); + + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::SuccessfulExecution(_, _)] + ); + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit transaction"); + } } mod pre_programmed_distribution { @@ -1188,6 +1535,133 @@ mod tests { .expect("expected to fetch token balance"); assert_eq!(token_balance, None); } + + #[test] + fn test_data_contract_creation_with_single_token_setting_burn_of_external_token_not_allowed( + ) { + let platform_version = PlatformVersion::latest(); + let mut platform = TestPlatformBuilder::new() + .build_with_mock_rpc() + .set_genesis_state(); + + let platform_state = platform.state.load(); + + let (identity, contract_signer, contract_key) = + setup_identity(&mut platform, 958, dash_to_credits!(0.1)); + + let (token_contract_owner_id, _, _) = + setup_identity(&mut platform, 11, dash_to_credits!(0.1)); + + let (token_contract, _) = create_token_contract_with_owner_identity( + &mut platform, + token_contract_owner_id.id(), + None::, + None, + None, + platform_version, + ); + + let token_contract_id = token_contract.id(); + + let mut data_contract = json_document_to_contract_with_ids( + "tests/supporting_files/contract/crypto-card-game/crypto-card-game-use-external-currency.json", + None, + None, + false, //no need to validate the data contracts in tests for drive + platform_version, + ) + .expect("expected to get json based contract"); + + { + let document_type = data_contract + .document_types_mut() + .get_mut("card") + .expect("expected a document type with name card"); + document_type.set_document_creation_token_cost(Some(DocumentActionTokenCost { + contract_id: Some(token_contract_id), + token_contract_position: 0, + token_amount: 5, + effect: DocumentActionTokenEffect::BurnToken, + gas_fees_paid_by: GasFeesPaidBy::DocumentOwner, + })); + let gas_fees_paid_by_int: u8 = GasFeesPaidBy::DocumentOwner.into(); + let schema = document_type.schema_mut(); + let token_cost = schema + .get_mut("tokenCost") + .expect("expected to get token cost") + .expect("expected token cost to be set"); + let creation_token_cost = token_cost + .get_mut("create") + .expect("expected to get creation token cost") + .expect("expected creation token cost to be set"); + creation_token_cost + .set_value("contractId", token_contract_id.into()) + .expect("expected to set token contract id"); + creation_token_cost + .set_value("tokenPosition", 0.into()) + .expect("expected to set token position"); + creation_token_cost + .set_value("amount", 5.into()) + .expect("expected to set token amount"); + creation_token_cost + .set_value( + "effect", + Value::U8(DocumentActionTokenEffect::BurnToken.into()), + ) + .expect("expected to set token pay effect"); + creation_token_cost + .set_value("gasFeesPaidBy", gas_fees_paid_by_int.into()) + .expect("expected to set token amount"); + } + + let data_contract_create_transition = + DataContractCreateTransition::new_from_data_contract( + data_contract, + 1, + &identity.into_partial_identity_info(), + contract_key.id(), + &contract_signer, + platform_version, + None, + ) + .expect("expect to create data contract create batch transition"); + + let data_contract_create_serialized_transition = data_contract_create_transition + .serialize_to_bytes() + .expect("expected documents batch serialized state transition"); + + let transaction = platform.drive.grove.start_transaction(); + + let processing_result = platform + .platform + .process_raw_state_transitions( + &vec![data_contract_create_serialized_transition.clone()], + &platform_state, + &BlockInfo::default(), + &transaction, + platform_version, + false, + None, + ) + .expect("expected to process state transition"); + + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::PaidConsensusError( + ConsensusError::BasicError( + BasicError::TokenPaymentByBurningOnlyAllowedOnInternalTokenError(_) + ), + _ + )] + ); + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit transaction"); + } } } diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/mod.rs index de56c7c4b3a..868de9b9e3b 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/mod.rs @@ -74,13 +74,14 @@ pub(in crate::execution) mod tests { use dapi_grpc::platform::v0::get_contested_resource_vote_state_request::{get_contested_resource_vote_state_request_v0, GetContestedResourceVoteStateRequestV0}; use dapi_grpc::platform::v0::get_contested_resource_vote_state_response::{get_contested_resource_vote_state_response_v0, GetContestedResourceVoteStateResponseV0}; use dapi_grpc::platform::v0::get_contested_resource_vote_state_response::get_contested_resource_vote_state_response_v0::FinishedVoteInfo; + use dpp::balances::credits::TokenAmount; use dpp::dash_to_credits; use dpp::dashcore::{ProTxHash, Txid}; use dpp::dashcore::hashes::Hash; use dpp::data_contract::accessors::v0::DataContractV0Getters; use dpp::data_contract::accessors::v1::{DataContractV1Getters, DataContractV1Setters}; - use dpp::data_contract::{DataContract, GroupContractPosition}; - use dpp::data_contract::document_type::accessors::DocumentTypeV0Getters; + use dpp::data_contract::{DataContract, GroupContractPosition, TokenContractPosition}; + use dpp::data_contract::document_type::accessors::{DocumentTypeV0Getters, DocumentTypeV1Setters}; use dpp::data_contract::document_type::random_document::{CreateRandomDocument, DocumentFieldFillSize, DocumentFieldFillType}; use dpp::document::{Document, DocumentV0Getters, DocumentV0Setters}; use dpp::document::serialization_traits::DocumentPlatformConversionMethodsV0; @@ -127,6 +128,9 @@ pub(in crate::execution) mod tests { use crate::execution::types::processed_block_fees_outcome::v0::ProcessedBlockFeesOutcome; use dpp::data_contract::associated_token::token_configuration::TokenConfiguration; use dpp::data_contract::group::Group; + use dpp::tokens::gas_fees_paid_by::GasFeesPaidBy; + use dpp::tokens::token_amount_on_contract_token::{DocumentActionTokenCost, DocumentActionTokenEffect}; + use dpp::data_contract::document_type::accessors::DocumentTypeV0MutGetters; /// We add an identity, but we also add the same amount to system credits pub(in crate::execution) fn setup_identity_with_system_credits( @@ -1093,6 +1097,7 @@ pub(in crate::execution) mod tests { key_1, 2 + nonce_offset.unwrap_or_default(), 0, + None, signer_1, platform_version, None, @@ -1114,6 +1119,7 @@ pub(in crate::execution) mod tests { key_2, 2 + nonce_offset.unwrap_or_default(), 0, + None, signer_2, platform_version, None, @@ -1135,6 +1141,7 @@ pub(in crate::execution) mod tests { key_1, 3 + nonce_offset.unwrap_or_default(), 0, + None, signer_1, platform_version, None, @@ -1155,6 +1162,7 @@ pub(in crate::execution) mod tests { key_2, 3 + nonce_offset.unwrap_or_default(), 0, + None, signer_2, platform_version, None, @@ -1406,6 +1414,7 @@ pub(in crate::execution) mod tests { key_1, 2, 0, + None, signer_1, platform_version, None, @@ -1427,6 +1436,7 @@ pub(in crate::execution) mod tests { key_2, 2, 0, + None, signer_2, platform_version, None, @@ -1448,6 +1458,7 @@ pub(in crate::execution) mod tests { key_1, 3, 0, + None, signer_1, platform_version, None, @@ -1468,6 +1479,7 @@ pub(in crate::execution) mod tests { key_2, 3, 0, + None, signer_2, platform_version, None, @@ -1628,6 +1640,7 @@ pub(in crate::execution) mod tests { &key_1, 2, 0, + None, &signer_1, platform_version, None, @@ -1649,6 +1662,7 @@ pub(in crate::execution) mod tests { &key_1, 3, 0, + None, &signer_1, platform_version, None, @@ -2358,7 +2372,34 @@ pub(in crate::execution) mod tests { (basic_token_contract, token_id.into()) } - pub(in crate::execution) fn create_card_game_token_contract_with_owner_identity( + pub(in crate::execution) fn create_card_game_internal_token_contract_with_owner_identity_burn_tokens( + platform: &mut TempPlatform, + identity_id: Identifier, + platform_version: &PlatformVersion, + ) -> (DataContract, Identifier, Identifier) { + let data_contract_id = DataContract::generate_data_contract_id_v0(identity_id, 1); + + let basic_token_contract = setup_contract( + &platform.drive, + "tests/supporting_files/contract/crypto-card-game/crypto-card-game-in-game-currency-burn-tokens.json", + Some(data_contract_id.to_buffer()), + Some(identity_id.to_buffer()), + Some(|data_contract: &mut DataContract| { + data_contract.set_created_at_epoch(Some(0)); + data_contract.set_created_at(Some(0)); + data_contract.set_created_at_block_height(Some(0)); + }), + None, + Some(platform_version), + ); + + let token_id = calculate_token_id(data_contract_id.as_bytes(), 0); + let token_id_2 = calculate_token_id(data_contract_id.as_bytes(), 1); + + (basic_token_contract, token_id.into(), token_id_2.into()) + } + + pub(in crate::execution) fn create_card_game_internal_token_contract_with_owner_identity_transfer_tokens( platform: &mut TempPlatform, identity_id: Identifier, platform_version: &PlatformVersion, @@ -2384,4 +2425,48 @@ pub(in crate::execution) mod tests { (basic_token_contract, token_id.into(), token_id_2.into()) } + + pub(in crate::execution) fn create_card_game_external_token_contract_with_owner_identity( + platform: &mut TempPlatform, + token_contract_id: Identifier, + token_contract_position: TokenContractPosition, + token_cost_amount: TokenAmount, + gas_fees_paid_by: GasFeesPaidBy, + identity_id: Identifier, + platform_version: &PlatformVersion, + ) -> DataContract { + let data_contract_id = DataContract::generate_data_contract_id_v0(identity_id, 1); + + let basic_token_contract = setup_contract( + &platform.drive, + "tests/supporting_files/contract/crypto-card-game/crypto-card-game-use-external-currency.json", + Some(data_contract_id.to_buffer()), + Some(identity_id.to_buffer()), + Some(|data_contract: &mut DataContract| { + data_contract.set_created_at_epoch(Some(0)); + data_contract.set_created_at(Some(0)); + data_contract.set_created_at_block_height(Some(0)); + let document_type = data_contract.document_types_mut().get_mut("card").expect("expected a document type with name card"); + document_type.set_document_creation_token_cost(Some(DocumentActionTokenCost { + contract_id: Some(token_contract_id), + token_contract_position, + token_amount: token_cost_amount, + effect: DocumentActionTokenEffect::TransferTokenToContractOwner, + gas_fees_paid_by, + })); + let gas_fees_paid_by_int: u8 = gas_fees_paid_by.into(); + let schema = document_type.schema_mut(); + let token_cost = schema.get_mut("tokenCost").expect("expected to get token cost").expect("expected token cost to be set"); + let creation_token_cost = token_cost.get_mut("create").expect("expected to get creation token cost").expect("expected creation token cost to be set"); + creation_token_cost.set_value("contractId", token_contract_id.into()).expect("expected to set token contract id"); + creation_token_cost.set_value("tokenPosition", token_contract_position.into()).expect("expected to set token position"); + creation_token_cost.set_value("amount", token_cost_amount.into()).expect("expected to set token amount"); + creation_token_cost.set_value("gasFeesPaidBy", gas_fees_paid_by_int.into()).expect("expected to set token amount"); + }), + None, + Some(platform_version), + ); + + basic_token_contract + } } diff --git a/packages/rs-drive-abci/tests/supporting_files/contract/crypto-card-game/crypto-card-game-in-game-currency-burn-tokens.json b/packages/rs-drive-abci/tests/supporting_files/contract/crypto-card-game/crypto-card-game-in-game-currency-burn-tokens.json new file mode 100644 index 00000000000..719d2b6e352 --- /dev/null +++ b/packages/rs-drive-abci/tests/supporting_files/contract/crypto-card-game/crypto-card-game-in-game-currency-burn-tokens.json @@ -0,0 +1,178 @@ +{ + "$format_version": "1", + "id": "86LHvdC1Tqx5P97LQUSibGFqf2vnKFpB6VkqQ7oso86e", + "ownerId": "2QjL594djCH2NyDsn45vd6yQjEDHupMKo7CEGVTHtQxU", + "version": 1, + "documentSchemas": { + "card": { + "type": "object", + "documentsMutable": true, + "canBeDeleted": true, + "transferable": 1, + "tradeMode": 1, + "tokenCost": { + "create": { "tokenPosition": 0, "amount": 10, + "effect": 1 + }, + "delete": { "tokenPosition": 1, "amount": 1, "effect": 1 }, + "replace": { "tokenPosition": 1, "amount": 2, "effect": 1 }, + "transfer": { "tokenPosition": 1, "amount": 1, "effect": 1 }, + "update_price": { "tokenPosition": 1, "amount": 1, "effect": 1 }, + "purchase": { "tokenPosition": 0, "amount": 3, "effect": 1 } + }, + "properties": { + "name": { + "type": "string", + "description": "Name of the card", + "maxLength": 63, + "position": 0 + }, + "description": { + "type": "string", + "description": "Description of the card", + "maxLength": 256, + "position": 1 + }, + "imageUrl": { + "type": "string", + "description": "URL of the image associated with the card", + "maxLength": 2048, + "format": "uri", + "position": 2 + }, + "imageHash": { + "type": "array", + "description": "SHA256 hash of the bytes of the image specified by imageUrl", + "byteArray": true, + "minItems": 32, + "maxItems": 32, + "position": 3 + }, + "imageFingerprint": { + "type": "array", + "description": "dHash of the image specified by imageUrl", + "byteArray": true, + "minItems": 8, + "maxItems": 8, + "position": 4 + }, + "attack": { + "type": "integer", + "description": "Attack power of the card", + "minimum": 0, + "position": 5 + }, + "defense": { + "type": "integer", + "description": "Defense level of the card", + "minimum": 0, + "position": 6 + } + }, + "indices": [ + { + "name": "owner", + "properties": [ + { + "$ownerId": "asc" + } + ] + }, + { + "name": "attack", + "properties": [ + { + "attack": "asc" + } + ] + }, + { + "name": "defense", + "properties": [ + { + "defense": "asc" + } + ] + }, + { + "name": "transferredAt", + "properties": [ + { + "$transferredAt": "asc" + } + ] + }, + { + "name": "ownerTransferredAt", + "properties": [ + { + "$ownerId": "asc" + }, + { + "$transferredAt": "asc" + } + ] + }, + { + "name": "transferredAtBlockHeight", + "properties": [ + { + "$transferredAtBlockHeight": "asc" + } + ] + }, + { + "name": "transferredAtCoreBlockHeight", + "properties": [ + { + "$transferredAtCoreBlockHeight": "asc" + } + ] + } + ], + "required": [ + "name", + "$transferredAt", + "$transferredAtBlockHeight", + "$transferredAtCoreBlockHeight", + "attack", + "defense" + ], + "additionalProperties": false + } + }, + "tokens": { + "0": { + "$format_version": "0", + "conventions": { + "$format_version": "0", + "localizations": { + "en": { + "$format_version": "0", + "shouldCapitalize": true, + "pluralForm": "gold", + "singularForm": "gold" + } + }, + "decimals": 0 + }, + "maxSupply": null + }, + "1": { + "$format_version": "0", + "conventions": { + "$format_version": "0", + "localizations": { + "en": { + "$format_version": "0", + "shouldCapitalize": true, + "pluralForm": "gas", + "singularForm": "gas" + } + }, + "decimals": 0 + }, + "maxSupply": null + } + } +} \ No newline at end of file diff --git a/packages/rs-drive-abci/tests/supporting_files/contract/crypto-card-game/crypto-card-game-use-external-currency.json b/packages/rs-drive-abci/tests/supporting_files/contract/crypto-card-game/crypto-card-game-use-external-currency.json new file mode 100644 index 00000000000..f12d9dc73da --- /dev/null +++ b/packages/rs-drive-abci/tests/supporting_files/contract/crypto-card-game/crypto-card-game-use-external-currency.json @@ -0,0 +1,137 @@ +{ + "$format_version": "1", + "id": "86LHvdC1Tqx5P97LQUSibGFqf2vnKFpB6VkqQ7oso86e", + "ownerId": "2QjL594djCH2NyDsn45vd6yQjEDHupMKo7CEGVTHtQxU", + "version": 1, + "documentSchemas": { + "card": { + "type": "object", + "documentsMutable": true, + "canBeDeleted": true, + "transferable": 1, + "tradeMode": 1, + "tokenCost": { + "create": { "contractId": "86LHvdC1Tqx5P97LQUSibGFqf2vnKFpB6VkqQ7oso86e", "tokenPosition": 0, "amount": 10, "effect": 0, "gasFeesPaidBy": 1 } + }, + "properties": { + "name": { + "type": "string", + "description": "Name of the card", + "maxLength": 63, + "position": 0 + }, + "description": { + "type": "string", + "description": "Description of the card", + "maxLength": 256, + "position": 1 + }, + "imageUrl": { + "type": "string", + "description": "URL of the image associated with the card", + "maxLength": 2048, + "format": "uri", + "position": 2 + }, + "imageHash": { + "type": "array", + "description": "SHA256 hash of the bytes of the image specified by imageUrl", + "byteArray": true, + "minItems": 32, + "maxItems": 32, + "position": 3 + }, + "imageFingerprint": { + "type": "array", + "description": "dHash of the image specified by imageUrl", + "byteArray": true, + "minItems": 8, + "maxItems": 8, + "position": 4 + }, + "attack": { + "type": "integer", + "description": "Attack power of the card", + "minimum": 0, + "position": 5 + }, + "defense": { + "type": "integer", + "description": "Defense level of the card", + "minimum": 0, + "position": 6 + } + }, + "indices": [ + { + "name": "owner", + "properties": [ + { + "$ownerId": "asc" + } + ] + }, + { + "name": "attack", + "properties": [ + { + "attack": "asc" + } + ] + }, + { + "name": "defense", + "properties": [ + { + "defense": "asc" + } + ] + }, + { + "name": "transferredAt", + "properties": [ + { + "$transferredAt": "asc" + } + ] + }, + { + "name": "ownerTransferredAt", + "properties": [ + { + "$ownerId": "asc" + }, + { + "$transferredAt": "asc" + } + ] + }, + { + "name": "transferredAtBlockHeight", + "properties": [ + { + "$transferredAtBlockHeight": "asc" + } + ] + }, + { + "name": "transferredAtCoreBlockHeight", + "properties": [ + { + "$transferredAtCoreBlockHeight": "asc" + } + ] + } + ], + "required": [ + "name", + "$transferredAt", + "$transferredAtBlockHeight", + "$transferredAtCoreBlockHeight", + "attack", + "defense" + ], + "additionalProperties": false + } + } +} \ No newline at end of file diff --git a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/document/document_create_transition.rs b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/document/document_create_transition.rs index 92e4364028c..d3807a5ea2c 100644 --- a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/document/document_create_transition.rs +++ b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/document/document_create_transition.rs @@ -12,6 +12,8 @@ use dpp::block::epoch::Epoch; use dpp::document::Document; use dpp::prelude::Identifier; use std::borrow::Cow; +use dpp::data_contract::accessors::v0::DataContractV0Getters; +use dpp::tokens::token_amount_on_contract_token::DocumentActionTokenEffect; use crate::state_transition_action::batch::batched_transition::document_transition::document_base_transition_action::DocumentBaseTransitionActionAccessorsV0; use crate::state_transition_action::batch::batched_transition::document_transition::document_create_transition_action::{DocumentCreateTransitionAction, DocumentCreateTransitionActionAccessorsV0, DocumentFromCreateTransitionAction}; use dpp::version::PlatformVersion; @@ -65,12 +67,24 @@ impl DriveHighLevelBatchOperationConverter for DocumentCreateTransitionAction { }, )]; - if let Some((token_id, cost)) = document_creation_token_cost { - ops.push(TokenOperation(TokenOperationType::TokenBurn { - token_id, - identity_balance_holder_id: owner_id, - burn_amount: cost, - })); + if let Some((token_id, effect, cost)) = document_creation_token_cost { + match effect { + DocumentActionTokenEffect::TransferTokenToContractOwner => { + ops.push(TokenOperation(TokenOperationType::TokenTransfer { + token_id, + sender_id: owner_id, + recipient_id: contract_fetch_info.contract.owner_id(), + amount: cost, + })); + } + DocumentActionTokenEffect::BurnToken => { + ops.push(TokenOperation(TokenOperationType::TokenBurn { + token_id, + identity_balance_holder_id: owner_id, + burn_amount: cost, + })); + } + } } if let Some((contested_document_resource_vote_poll, credits)) = diff --git a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/document/document_delete_transition.rs b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/document/document_delete_transition.rs index d82f1af2e17..3a2df2af44f 100644 --- a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/document/document_delete_transition.rs +++ b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/document/document_delete_transition.rs @@ -5,7 +5,9 @@ use crate::util::batch::{DocumentOperationType, DriveOperation, IdentityOperatio use crate::error::Error; use dpp::block::epoch::Epoch; +use dpp::data_contract::accessors::v0::DataContractV0Getters; use dpp::identifier::Identifier; +use dpp::tokens::token_amount_on_contract_token::DocumentActionTokenEffect; use crate::state_transition_action::batch::batched_transition::document_transition::document_base_transition_action::DocumentBaseTransitionActionAccessorsV0; use crate::state_transition_action::batch::batched_transition::document_transition::document_delete_transition_action::DocumentDeleteTransitionAction; use crate::state_transition_action::batch::batched_transition::document_transition::document_delete_transition_action::v0::DocumentDeleteTransitionActionAccessorsV0; @@ -31,6 +33,8 @@ impl DriveHighLevelBatchOperationConverter for DocumentDeleteTransitionAction { 0 => { let base = self.base_owned(); + let contract_fetch_info = base.data_contract_fetch_info(); + let data_contract_id = base.data_contract_id(); let identity_contract_nonce = base.identity_contract_nonce(); @@ -54,12 +58,24 @@ impl DriveHighLevelBatchOperationConverter for DocumentDeleteTransitionAction { }), ]; - if let Some((token_id, cost)) = document_deletion_token_cost { - ops.push(TokenOperation(TokenOperationType::TokenBurn { - token_id, - identity_balance_holder_id: owner_id, - burn_amount: cost, - })); + if let Some((token_id, effect, cost)) = document_deletion_token_cost { + match effect { + DocumentActionTokenEffect::TransferTokenToContractOwner => { + ops.push(TokenOperation(TokenOperationType::TokenTransfer { + token_id, + sender_id: owner_id, + recipient_id: contract_fetch_info.contract.owner_id(), + amount: cost, + })); + } + DocumentActionTokenEffect::BurnToken => { + ops.push(TokenOperation(TokenOperationType::TokenBurn { + token_id, + identity_balance_holder_id: owner_id, + burn_amount: cost, + })); + } + } } Ok(ops) diff --git a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/document/document_purchase_transition.rs b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/document/document_purchase_transition.rs index 15af66ab529..b2fe6465f30 100644 --- a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/document/document_purchase_transition.rs +++ b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/document/document_purchase_transition.rs @@ -9,6 +9,8 @@ use dpp::block::epoch::Epoch; use dpp::prelude::Identifier; use std::borrow::Cow; +use dpp::data_contract::accessors::v0::DataContractV0Getters; +use dpp::tokens::token_amount_on_contract_token::DocumentActionTokenEffect; use crate::state_transition_action::batch::batched_transition::document_transition::document_base_transition_action::DocumentBaseTransitionActionAccessorsV0; use crate::state_transition_action::batch::batched_transition::document_transition::document_purchase_transition_action::{DocumentPurchaseTransitionAction, DocumentPurchaseTransitionActionAccessorsV0}; use dpp::version::PlatformVersion; @@ -37,6 +39,8 @@ impl DriveHighLevelBatchOperationConverter for DocumentPurchaseTransitionAction let purchase_amount = self.price(); let contract_fetch_info = self.base().data_contract_fetch_info(); + let contract_owner_id = contract_fetch_info.contract.owner_id(); + let document_purchase_token_cost = self.base().token_cost(); let document = self.document_owned(); @@ -77,12 +81,24 @@ impl DriveHighLevelBatchOperationConverter for DocumentPurchaseTransitionAction }), ]; - if let Some((token_id, cost)) = document_purchase_token_cost { - ops.push(TokenOperation(TokenOperationType::TokenBurn { - token_id, - identity_balance_holder_id: owner_id, - burn_amount: cost, - })); + if let Some((token_id, effect, cost)) = document_purchase_token_cost { + match effect { + DocumentActionTokenEffect::TransferTokenToContractOwner => { + ops.push(TokenOperation(TokenOperationType::TokenTransfer { + token_id, + sender_id: owner_id, + recipient_id: contract_owner_id, + amount: cost, + })); + } + DocumentActionTokenEffect::BurnToken => { + ops.push(TokenOperation(TokenOperationType::TokenBurn { + token_id, + identity_balance_holder_id: owner_id, + burn_amount: cost, + })); + } + } } Ok(ops) diff --git a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/document/document_replace_transition.rs b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/document/document_replace_transition.rs index 18f7efe15ae..c967f532204 100644 --- a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/document/document_replace_transition.rs +++ b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/document/document_replace_transition.rs @@ -10,6 +10,8 @@ use dpp::block::epoch::Epoch; use dpp::document::Document; use dpp::prelude::Identifier; use std::borrow::Cow; +use dpp::data_contract::accessors::v0::DataContractV0Getters; +use dpp::tokens::token_amount_on_contract_token::DocumentActionTokenEffect; use crate::state_transition_action::batch::batched_transition::document_transition::document_base_transition_action::DocumentBaseTransitionActionAccessorsV0; use crate::state_transition_action::batch::batched_transition::document_transition::document_replace_transition_action::{DocumentFromReplaceTransitionAction, DocumentReplaceTransitionAction, DocumentReplaceTransitionActionAccessorsV0}; use dpp::version::PlatformVersion; @@ -35,6 +37,8 @@ impl DriveHighLevelBatchOperationConverter for DocumentReplaceTransitionAction { let document_type_name = self.base().document_type_name().clone(); let identity_contract_nonce = self.base().identity_contract_nonce(); let contract_fetch_info = self.base().data_contract_fetch_info(); + let contract_owner_id = contract_fetch_info.contract.owner_id(); + let document_replacement_token_cost = self.base().token_cost(); let document = Document::try_from_owned_replace_transition_action( self, @@ -64,12 +68,24 @@ impl DriveHighLevelBatchOperationConverter for DocumentReplaceTransitionAction { }), ]; - if let Some((token_id, cost)) = document_replacement_token_cost { - ops.push(TokenOperation(TokenOperationType::TokenBurn { - token_id, - identity_balance_holder_id: owner_id, - burn_amount: cost, - })); + if let Some((token_id, effect, cost)) = document_replacement_token_cost { + match effect { + DocumentActionTokenEffect::TransferTokenToContractOwner => { + ops.push(TokenOperation(TokenOperationType::TokenTransfer { + token_id, + sender_id: owner_id, + recipient_id: contract_owner_id, + amount: cost, + })); + } + DocumentActionTokenEffect::BurnToken => { + ops.push(TokenOperation(TokenOperationType::TokenBurn { + token_id, + identity_balance_holder_id: owner_id, + burn_amount: cost, + })); + } + } } Ok(ops) diff --git a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/document/document_transfer_transition.rs b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/document/document_transfer_transition.rs index 55e0dec6117..8239e71d232 100644 --- a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/document/document_transfer_transition.rs +++ b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/document/document_transfer_transition.rs @@ -10,6 +10,8 @@ use dpp::block::epoch::Epoch; use dpp::document::DocumentV0Getters; use dpp::prelude::Identifier; use std::borrow::Cow; +use dpp::data_contract::accessors::v0::DataContractV0Getters; +use dpp::tokens::token_amount_on_contract_token::DocumentActionTokenEffect; use crate::state_transition_action::batch::batched_transition::document_transition::document_base_transition_action::DocumentBaseTransitionActionAccessorsV0; use crate::state_transition_action::batch::batched_transition::document_transition::document_transfer_transition_action::{DocumentTransferTransitionAction, DocumentTransferTransitionActionAccessorsV0}; use dpp::version::PlatformVersion; @@ -35,6 +37,8 @@ impl DriveHighLevelBatchOperationConverter for DocumentTransferTransitionAction let document_type_name = self.base().document_type_name().clone(); let identity_contract_nonce = self.base().identity_contract_nonce(); let contract_fetch_info = self.base().data_contract_fetch_info(); + let contract_owner_id = contract_fetch_info.contract.owner_id(); + let document_transfer_token_cost = self.base().token_cost(); let document = self.document_owned(); @@ -66,12 +70,24 @@ impl DriveHighLevelBatchOperationConverter for DocumentTransferTransitionAction }), ]; - if let Some((token_id, cost)) = document_transfer_token_cost { - ops.push(TokenOperation(TokenOperationType::TokenBurn { - token_id, - identity_balance_holder_id: owner_id, - burn_amount: cost, - })); + if let Some((token_id, effect, cost)) = document_transfer_token_cost { + match effect { + DocumentActionTokenEffect::TransferTokenToContractOwner => { + ops.push(TokenOperation(TokenOperationType::TokenTransfer { + token_id, + sender_id: owner_id, + recipient_id: contract_owner_id, + amount: cost, + })); + } + DocumentActionTokenEffect::BurnToken => { + ops.push(TokenOperation(TokenOperationType::TokenBurn { + token_id, + identity_balance_holder_id: owner_id, + burn_amount: cost, + })); + } + } } Ok(ops) diff --git a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/document/document_update_price_transition.rs b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/document/document_update_price_transition.rs index b3d08472c1a..44b74ac809d 100644 --- a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/document/document_update_price_transition.rs +++ b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/document/document_update_price_transition.rs @@ -9,6 +9,8 @@ use dpp::block::epoch::Epoch; use dpp::prelude::Identifier; use std::borrow::Cow; +use dpp::data_contract::accessors::v0::DataContractV0Getters; +use dpp::tokens::token_amount_on_contract_token::DocumentActionTokenEffect; use crate::state_transition_action::batch::batched_transition::document_transition::document_base_transition_action::DocumentBaseTransitionActionAccessorsV0; use crate::state_transition_action::batch::batched_transition::document_transition::document_update_price_transition_action::{DocumentUpdatePriceTransitionAction, DocumentUpdatePriceTransitionActionAccessorsV0}; use dpp::version::PlatformVersion; @@ -35,6 +37,8 @@ impl DriveHighLevelBatchOperationConverter for DocumentUpdatePriceTransitionActi let identity_contract_nonce = self.base().identity_contract_nonce(); let fetch_info = self.base().data_contract_fetch_info(); let document_update_price_token_cost = self.base().token_cost(); + let contract_owner_id = fetch_info.contract.owner_id(); + let document = self.document_owned(); let storage_flags = @@ -59,12 +63,24 @@ impl DriveHighLevelBatchOperationConverter for DocumentUpdatePriceTransitionActi }), ]; - if let Some((token_id, cost)) = document_update_price_token_cost { - ops.push(TokenOperation(TokenOperationType::TokenBurn { - token_id, - identity_balance_holder_id: owner_id, - burn_amount: cost, - })); + if let Some((token_id, effect, cost)) = document_update_price_token_cost { + match effect { + DocumentActionTokenEffect::TransferTokenToContractOwner => { + ops.push(TokenOperation(TokenOperationType::TokenTransfer { + token_id, + sender_id: owner_id, + recipient_id: contract_owner_id, + amount: cost, + })); + } + DocumentActionTokenEffect::BurnToken => { + ops.push(TokenOperation(TokenOperationType::TokenBurn { + token_id, + identity_balance_holder_id: owner_id, + burn_amount: cost, + })); + } + } } Ok(ops) diff --git a/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_base_transition_action/mod.rs b/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_base_transition_action/mod.rs index 3aa64620368..9ed7cb26286 100644 --- a/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_base_transition_action/mod.rs +++ b/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_base_transition_action/mod.rs @@ -6,6 +6,7 @@ use dpp::balances::credits::TokenAmount; use dpp::data_contract::document_type::accessors::DocumentTypeV0Getters; use dpp::data_contract::document_type::DocumentTypeRef; use dpp::prelude::IdentityNonce; +use dpp::tokens::token_amount_on_contract_token::DocumentActionTokenEffect; use dpp::ProtocolError; use std::sync::Arc; @@ -77,7 +78,7 @@ impl DocumentBaseTransitionActionAccessorsV0 for DocumentBaseTransitionAction { } } - fn token_cost(&self) -> Option<(Identifier, TokenAmount)> { + fn token_cost(&self) -> Option<(Identifier, DocumentActionTokenEffect, TokenAmount)> { match self { DocumentBaseTransitionAction::V0(v0) => v0.token_cost, } diff --git a/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_base_transition_action/transformer.rs b/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_base_transition_action/transformer.rs index cbd1b23c2c5..84fb5fcf744 100644 --- a/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_base_transition_action/transformer.rs +++ b/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_base_transition_action/transformer.rs @@ -1,40 +1,30 @@ use dpp::platform_value::Identifier; use std::sync::Arc; -use dpp::balances::credits::TokenAmount; use dpp::data_contract::document_type::DocumentType; -use dpp::data_contract::TokenContractPosition; +use dpp::prelude::ConsensusValidationResult; use dpp::ProtocolError; use dpp::state_transition::batch_transition::document_base_transition::DocumentBaseTransition; +use dpp::tokens::token_amount_on_contract_token::DocumentActionTokenCost; use crate::drive::contract::DataContractFetchInfo; +use crate::error::Error; use crate::state_transition_action::batch::batched_transition::document_transition::document_base_transition_action::{DocumentBaseTransitionAction, DocumentBaseTransitionActionV0}; impl DocumentBaseTransitionAction { - /// from base transition with contract lookup - pub fn try_from_base_transition_with_contract_lookup( - value: DocumentBaseTransition, - get_data_contract: impl Fn(Identifier) -> Result, ProtocolError>, - get_token_cost: impl Fn(&DocumentType) -> Option<(TokenContractPosition, TokenAmount)>, - ) -> Result { - match value { - DocumentBaseTransition::V0(v0) => Ok( - DocumentBaseTransitionActionV0::try_from_base_transition_with_contract_lookup( - v0, - get_data_contract, - get_token_cost, - )? - .into(), - ), - } - } - /// from borrowed base transition with contract lookup pub fn try_from_borrowed_base_transition_with_contract_lookup( value: &DocumentBaseTransition, get_data_contract: impl Fn(Identifier) -> Result, ProtocolError>, - get_token_cost: impl Fn(&DocumentType) -> Option<(TokenContractPosition, TokenAmount)>, - ) -> Result { - match value { - DocumentBaseTransition::V0(v0) => Ok(DocumentBaseTransitionActionV0::try_from_borrowed_base_transition_with_contract_lookup(v0, get_data_contract, get_token_cost)?.into()), - } + get_token_cost: impl Fn(&DocumentType) -> Option, + action: &str, + ) -> Result, Error> { + Ok( + DocumentBaseTransitionActionV0::try_from_borrowed_base_transition_with_contract_lookup( + value, + get_data_contract, + get_token_cost, + action, + )? + .map(|v0| v0.into()), + ) } } diff --git a/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_base_transition_action/v0/mod.rs b/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_base_transition_action/v0/mod.rs index 5f51a3030fa..4d7a8327015 100644 --- a/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_base_transition_action/v0/mod.rs +++ b/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_base_transition_action/v0/mod.rs @@ -1,19 +1,20 @@ /// transformer pub mod transformer; +use crate::drive::contract::DataContractFetchInfo; use dpp::balances::credits::TokenAmount; use dpp::data_contract::document_type::DocumentTypeRef; use dpp::identifier::Identifier; use dpp::prelude::IdentityNonce; +use dpp::tokens::gas_fees_paid_by::GasFeesPaidBy; +use dpp::tokens::token_amount_on_contract_token::DocumentActionTokenEffect; use dpp::ProtocolError; use std::sync::Arc; -use crate::drive::contract::DataContractFetchInfo; - #[derive(Debug, Clone)] /// document base transition action v0 pub struct DocumentBaseTransitionActionV0 { - /// The document Id + /// The document ID pub id: Identifier, /// The identity contract nonce, this is used to stop replay attacks pub identity_contract_nonce: IdentityNonce, @@ -22,12 +23,14 @@ pub struct DocumentBaseTransitionActionV0 { /// A potential data contract pub data_contract: Arc, /// Token cost with the token_id coming first - pub token_cost: Option<(Identifier, TokenAmount)>, + pub token_cost: Option<(Identifier, DocumentActionTokenEffect, TokenAmount)>, + /// Who pays the gas fees + pub gas_fees_paid_by: GasFeesPaidBy, } /// document base transition action accessors v0 pub trait DocumentBaseTransitionActionAccessorsV0 { - /// The document Id + /// The document ID fn id(&self) -> Identifier; /// The document type @@ -51,5 +54,5 @@ pub trait DocumentBaseTransitionActionAccessorsV0 { fn identity_contract_nonce(&self) -> IdentityNonce; /// Token cost - fn token_cost(&self) -> Option<(Identifier, TokenAmount)>; + fn token_cost(&self) -> Option<(Identifier, DocumentActionTokenEffect, TokenAmount)>; } diff --git a/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_base_transition_action/v0/transformer.rs b/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_base_transition_action/v0/transformer.rs index 05dc364dd99..a4bbfc86333 100644 --- a/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_base_transition_action/v0/transformer.rs +++ b/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_base_transition_action/v0/transformer.rs @@ -1,78 +1,118 @@ -use dpp::balances::credits::TokenAmount; use dpp::data_contract::accessors::v0::DataContractV0Getters; use dpp::data_contract::document_type::DocumentType; -use dpp::data_contract::TokenContractPosition; use dpp::platform_value::Identifier; use std::sync::Arc; - +use dpp::consensus::ConsensusError; +use dpp::consensus::state::state_error::StateError; +use dpp::consensus::state::token::{IdentityHasNotAgreedToPayRequiredTokenAmountError, IdentityTryingToPayWithWrongTokenError, RequiredTokenPaymentInfoNotSetError}; +use dpp::prelude::ConsensusValidationResult; use dpp::ProtocolError; -use dpp::state_transition::batch_transition::document_base_transition::v0::DocumentBaseTransitionV0; +use dpp::state_transition::batch_transition::document_base_transition::DocumentBaseTransition; +use dpp::state_transition::batch_transition::document_base_transition::v0::v0_methods::DocumentBaseTransitionV0Methods; +use dpp::state_transition::batch_transition::document_base_transition::v1::v1_methods::DocumentBaseTransitionV1Methods; use dpp::tokens::calculate_token_id; +use dpp::tokens::gas_fees_paid_by::GasFeesPaidBy; +use dpp::tokens::token_amount_on_contract_token::DocumentActionTokenCost; +use dpp::tokens::token_payment_info::v0::v0_accessors::TokenPaymentInfoAccessorsV0; +use dpp::tokens::token_payment_info::methods::v0::TokenPaymentInfoMethodsV0; use crate::drive::contract::DataContractFetchInfo; +use crate::error::Error; use crate::state_transition_action::batch::batched_transition::document_transition::document_base_transition_action::DocumentBaseTransitionActionV0; impl DocumentBaseTransitionActionV0 { - /// try from base transition with contract lookup - pub fn try_from_base_transition_with_contract_lookup( - value: DocumentBaseTransitionV0, - get_data_contract: impl Fn(Identifier) -> Result, ProtocolError>, - get_token_cost: impl Fn(&DocumentType) -> Option<(TokenContractPosition, TokenAmount)>, - ) -> Result { - let DocumentBaseTransitionV0 { - id, - document_type_name, - data_contract_id, - identity_contract_nonce, - } = value; - let data_contract = get_data_contract(data_contract_id)?; - let document_type = data_contract - .contract - .document_type_borrowed_for_name(document_type_name.as_str())?; - let token_cost = - get_token_cost(document_type).map(|(token_contract_position, token_amount)| { - ( - calculate_token_id(data_contract_id.as_bytes(), token_contract_position).into(), - token_amount, - ) - }); - Ok(DocumentBaseTransitionActionV0 { - id, - identity_contract_nonce, - document_type_name, - data_contract, - token_cost, - }) - } - /// try from borrowed base transition with contract lookup pub fn try_from_borrowed_base_transition_with_contract_lookup( - value: &DocumentBaseTransitionV0, + value: &DocumentBaseTransition, get_data_contract: impl Fn(Identifier) -> Result, ProtocolError>, - get_token_cost: impl Fn(&DocumentType) -> Option<(TokenContractPosition, TokenAmount)>, - ) -> Result { - let DocumentBaseTransitionV0 { - id, - document_type_name, - data_contract_id, - identity_contract_nonce, - } = value; - let data_contract = get_data_contract(*data_contract_id)?; + get_token_cost: impl Fn(&DocumentType) -> Option, + action: &str, + ) -> Result, Error> { + let data_contract_id = value.data_contract_id(); + let data_contract = get_data_contract(data_contract_id)?; let document_type = data_contract .contract - .document_type_borrowed_for_name(document_type_name)?; - let token_cost = - get_token_cost(document_type).map(|(token_contract_position, token_amount)| { + .document_type_borrowed_for_name(value.document_type_name().as_str())?; + let document_action_token_cost = get_token_cost(document_type); + let token_cost = document_action_token_cost.map( + |DocumentActionTokenCost { + contract_id, + token_contract_position, + token_amount, + effect, + .. + }| { ( - calculate_token_id(data_contract_id.as_bytes(), token_contract_position).into(), + calculate_token_id( + contract_id.unwrap_or(data_contract_id).as_bytes(), + token_contract_position, + ) + .into(), + effect, token_amount, ) - }); + }, + ); + if let Some(document_action_token_cost) = document_action_token_cost { + let Some(token_payment_info) = value.token_payment_info_ref() else { + return Ok(ConsensusValidationResult::new_with_error( + ConsensusError::StateError(StateError::RequiredTokenPaymentInfoNotSetError( + RequiredTokenPaymentInfoNotSetError::new( + token_cost.expect("expected token cost").0, + action.to_string(), + ), + )), + )); + }; + // Let's see that the user agreed to pay using the correct token + if !token_payment_info.matches_token_contract( + &document_action_token_cost.contract_id, + document_action_token_cost.token_contract_position, + ) { + return Ok(ConsensusValidationResult::new_with_error( + ConsensusError::StateError(StateError::IdentityTryingToPayWithWrongTokenError( + IdentityTryingToPayWithWrongTokenError::new( + document_action_token_cost.contract_id, + document_action_token_cost.token_contract_position, + token_cost.expect("expected token cost").0, + token_payment_info.payment_token_contract_id(), + token_payment_info.token_contract_position(), + token_payment_info.token_id(data_contract_id), + ), + )), + )); + } + // Let's see that the user agreed to pay the required amount + if !token_payment_info + .is_valid_for_required_cost(document_action_token_cost.token_amount) + { + return Ok(ConsensusValidationResult::new_with_error( + ConsensusError::StateError( + StateError::IdentityHasNotAgreedToPayRequiredTokenAmountError( + IdentityHasNotAgreedToPayRequiredTokenAmountError::new( + token_cost.expect("expected token cost").0, + document_action_token_cost.token_amount, + token_payment_info.minimum_token_cost(), + token_payment_info.maximum_token_cost(), + action.to_string(), + ), + ), + ), + )); + } + } + let gas_fees_paid_by = value + .token_payment_info_ref() + .as_ref() + .map(|token_payment_info| token_payment_info.gas_fees_paid_by()) + .unwrap_or(GasFeesPaidBy::DocumentOwner); Ok(DocumentBaseTransitionActionV0 { - id: *id, - identity_contract_nonce: *identity_contract_nonce, - document_type_name: document_type_name.clone(), + id: value.id(), + identity_contract_nonce: value.identity_contract_nonce(), + document_type_name: value.document_type_name().clone(), data_contract, token_cost, - }) + gas_fees_paid_by, + } + .into()) } } diff --git a/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_create_transition_action/transformer.rs b/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_create_transition_action/transformer.rs index dab39d6d725..cce4ec18856 100644 --- a/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_create_transition_action/transformer.rs +++ b/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_create_transition_action/transformer.rs @@ -3,46 +3,38 @@ use dpp::fee::fee_result::FeeResult; use dpp::platform_value::Identifier; use grovedb::TransactionArg; use std::sync::Arc; - +use dpp::prelude::{ConsensusValidationResult, UserFeeIncrease}; use dpp::ProtocolError; use dpp::state_transition::batch_transition::document_create_transition::DocumentCreateTransition; use platform_version::version::PlatformVersion; use crate::drive::contract::DataContractFetchInfo; 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::document_transition::document_create_transition_action::{DocumentCreateTransitionAction, DocumentCreateTransitionActionV0}; impl DocumentCreateTransitionAction { - /// from_document_create_transition_with_contract_lookup - pub fn try_from_document_create_transition_with_contract_lookup( - drive: &Drive, - transaction: TransactionArg, - value: DocumentCreateTransition, - block_info: &BlockInfo, - get_data_contract: impl Fn(Identifier) -> Result, ProtocolError>, - platform_version: &PlatformVersion, - ) -> Result<(Self, FeeResult), Error> { - match value { - DocumentCreateTransition::V0(v0) => { - let (v0, fee) = DocumentCreateTransitionActionV0::try_from_document_create_transition_with_contract_lookup(drive, transaction, v0, block_info, get_data_contract, platform_version)?; - Ok((v0.into(), fee)) - } - } - } - /// from_document_borrowed_create_transition_with_contract_lookup + #[allow(clippy::too_many_arguments)] pub fn try_from_document_borrowed_create_transition_with_contract_lookup( drive: &Drive, + owner_id: Identifier, transaction: TransactionArg, value: &DocumentCreateTransition, block_info: &BlockInfo, + user_fee_increase: UserFeeIncrease, get_data_contract: impl Fn(Identifier) -> Result, ProtocolError>, platform_version: &PlatformVersion, - ) -> Result<(Self, FeeResult), Error> { + ) -> Result< + ( + ConsensusValidationResult, + FeeResult, + ), + Error, + > { match value { DocumentCreateTransition::V0(v0) => { - let (v0, fee) = DocumentCreateTransitionActionV0::try_from_borrowed_document_create_transition_with_contract_lookup(drive, transaction, v0, block_info, get_data_contract, platform_version)?; - Ok((v0.into(), fee)) + DocumentCreateTransitionActionV0::try_from_borrowed_document_create_transition_with_contract_lookup(drive, owner_id, transaction, v0, block_info, user_fee_increase, get_data_contract, platform_version) } } } diff --git a/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_create_transition_action/v0/transformer.rs b/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_create_transition_action/v0/transformer.rs index da79d89a73a..7fdbaba02e9 100644 --- a/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_create_transition_action/v0/transformer.rs +++ b/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_create_transition_action/v0/transformer.rs @@ -4,7 +4,7 @@ use dpp::fee::fee_result::FeeResult; use dpp::platform_value::Identifier; use grovedb::TransactionArg; use std::sync::Arc; - +use dpp::prelude::{ConsensusValidationResult, UserFeeIncrease}; use dpp::ProtocolError; use dpp::state_transition::batch_transition::document_create_transition::v0::DocumentCreateTransitionV0; use dpp::voting::vote_info_storage::contested_document_vote_poll_stored_info::ContestedDocumentVotePollStoredInfo; @@ -15,128 +15,67 @@ use crate::drive::Drive; use crate::drive::votes::resolved::vote_polls::contested_document_resource_vote_poll::resolve::ContestedDocumentResourceVotePollResolver; use crate::error::drive::DriveError; use crate::error::Error; +use crate::state_transition_action::batch::batched_transition::BatchedTransitionAction; use crate::state_transition_action::batch::batched_transition::document_transition::document_base_transition_action::{DocumentBaseTransitionAction, DocumentBaseTransitionActionAccessorsV0}; use crate::state_transition_action::batch::batched_transition::document_transition::document_create_transition_action::DocumentCreateTransitionActionV0; +use crate::state_transition_action::batch::batched_transition::document_transition::DocumentTransitionAction; +use crate::state_transition_action::system::bump_identity_data_contract_nonce_action::BumpIdentityDataContractNonceAction; impl DocumentCreateTransitionActionV0 { - /// try from document create transition with contract lookup - pub fn try_from_document_create_transition_with_contract_lookup( - drive: &Drive, - transaction: TransactionArg, - value: DocumentCreateTransitionV0, - block_info: &BlockInfo, - get_data_contract: impl Fn(Identifier) -> Result, ProtocolError>, - platform_version: &PlatformVersion, - ) -> Result<(Self, FeeResult), Error> { - let DocumentCreateTransitionV0 { - base, - data, - prefunded_voting_balance, - .. - } = value; - let base = DocumentBaseTransitionAction::try_from_base_transition_with_contract_lookup( - base, - get_data_contract, - |document_type| document_type.document_creation_token_cost(), - )?; - - let document_type = base.document_type()?; - - let document_type_indexes = document_type.indexes(); - - let prefunded_voting_balances_by_vote_poll = prefunded_voting_balance - .map(|(index_name, credits)| { - let index = document_type_indexes.get(&index_name).ok_or( - ProtocolError::UnknownContestedIndexResolution(format!( - "index {} not found on document type {}", - index_name.clone(), - document_type.name() - )), - )?; - let index_values = index.extract_values(&data); - - let vote_poll = ContestedDocumentResourceVotePoll { - contract_id: base.data_contract_id(), - document_type_name: base.document_type_name().clone(), - index_name, - index_values, - }; - - let resolved_vote_poll = vote_poll - .resolve_owned_with_provided_arc_contract_fetch_info( - base.data_contract_fetch_info(), - )?; - - Ok::<_, Error>((resolved_vote_poll, credits)) - }) - .transpose()?; - - let mut fee_result = FeeResult::default(); - - let (current_store_contest_info, should_store_contest_info) = - if let Some((contested_document_resource_vote_poll, _)) = - &prefunded_voting_balances_by_vote_poll - { - let (fetch_fee_result, maybe_current_store_contest_info) = drive - .fetch_contested_document_vote_poll_stored_info( - contested_document_resource_vote_poll, - Some(&block_info.epoch), - transaction, - platform_version, - )?; - - fee_result = fetch_fee_result.ok_or(Error::Drive( - DriveError::CorruptedCodeExecution("expected fee result"), - ))?; - let should_store_contest_info = if maybe_current_store_contest_info.is_none() { - // We are starting a new contest - Some(ContestedDocumentVotePollStoredInfo::new( - *block_info, - platform_version, - )?) - } else { - None - }; - (maybe_current_store_contest_info, should_store_contest_info) - } else { - (None, None) - }; - - Ok(( - DocumentCreateTransitionActionV0 { - base, - block_info: *block_info, - data, - prefunded_voting_balance: prefunded_voting_balances_by_vote_poll, - current_store_contest_info, - should_store_contest_info, - }, - fee_result, - )) - } - /// try from borrowed document create transition with contract lookup + #[allow(clippy::too_many_arguments)] pub fn try_from_borrowed_document_create_transition_with_contract_lookup( drive: &Drive, + owner_id: Identifier, transaction: TransactionArg, value: &DocumentCreateTransitionV0, block_info: &BlockInfo, + user_fee_increase: UserFeeIncrease, get_data_contract: impl Fn(Identifier) -> Result, ProtocolError>, platform_version: &PlatformVersion, - ) -> Result<(Self, FeeResult), Error> { + ) -> Result< + ( + ConsensusValidationResult, + FeeResult, + ), + Error, + > { let DocumentCreateTransitionV0 { base, data, prefunded_voting_balance, .. } = value; - let base = + let base_action_validation_result = DocumentBaseTransitionAction::try_from_borrowed_base_transition_with_contract_lookup( base, get_data_contract, |document_type| document_type.document_creation_token_cost(), + "create", )?; + let base = match base_action_validation_result.is_valid() { + true => base_action_validation_result.into_data()?, + false => { + let bump_action = + BumpIdentityDataContractNonceAction::from_borrowed_document_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, + ), + FeeResult::default(), + )); + } + }; + let document_type = base.document_type()?; let document_type_indexes = document_type.indexes(); @@ -201,14 +140,18 @@ impl DocumentCreateTransitionActionV0 { }; Ok(( - DocumentCreateTransitionActionV0 { - base, - block_info: *block_info, - data: data.clone(), - prefunded_voting_balance: prefunded_voting_balances_by_vote_poll, - current_store_contest_info, - should_store_contest_info, - }, + BatchedTransitionAction::DocumentAction(DocumentTransitionAction::CreateAction( + DocumentCreateTransitionActionV0 { + base, + block_info: *block_info, + data: data.clone(), + prefunded_voting_balance: prefunded_voting_balances_by_vote_poll, + current_store_contest_info, + should_store_contest_info, + } + .into(), + )) + .into(), fee_result, )) } diff --git a/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_delete_transition_action/transformer.rs b/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_delete_transition_action/transformer.rs index ede80bd6f0b..30e506013b7 100644 --- a/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_delete_transition_action/transformer.rs +++ b/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_delete_transition_action/transformer.rs @@ -1,29 +1,30 @@ use dpp::platform_value::Identifier; use std::sync::Arc; - +use dpp::fee::fee_result::FeeResult; +use dpp::prelude::{ConsensusValidationResult, UserFeeIncrease}; use dpp::ProtocolError; use dpp::state_transition::batch_transition::batched_transition::DocumentDeleteTransition; use crate::drive::contract::DataContractFetchInfo; +use crate::error::Error; +use crate::state_transition_action::batch::batched_transition::BatchedTransitionAction; use crate::state_transition_action::batch::batched_transition::document_transition::document_delete_transition_action::{DocumentDeleteTransitionAction, DocumentDeleteTransitionActionV0}; impl DocumentDeleteTransitionAction { - /// from - pub fn try_from_document_create_transition_with_contract_lookup( - value: DocumentDeleteTransition, - get_data_contract: impl Fn(Identifier) -> Result, ProtocolError>, - ) -> Result { - match value { - DocumentDeleteTransition::V0(v0) => Ok(DocumentDeleteTransitionActionV0::try_from_document_delete_transition_with_contract_lookup(v0, get_data_contract)?.into()), - } - } - /// from borrowed - pub fn try_from_document_borrowed_create_transition_with_contract_lookup( + pub fn try_from_document_borrowed_delete_transition_with_contract_lookup( value: &DocumentDeleteTransition, + owner_id: Identifier, + user_fee_increase: UserFeeIncrease, get_data_contract: impl Fn(Identifier) -> Result, ProtocolError>, - ) -> Result { + ) -> Result< + ( + ConsensusValidationResult, + FeeResult, + ), + Error, + > { match value { - DocumentDeleteTransition::V0(v0) => Ok(DocumentDeleteTransitionActionV0::try_from_borrowed_document_delete_transition_with_contract_lookup(v0, get_data_contract)?.into()), + DocumentDeleteTransition::V0(v0) => DocumentDeleteTransitionActionV0::try_from_borrowed_document_delete_transition_with_contract_lookup(v0, owner_id, user_fee_increase, get_data_contract), } } } diff --git a/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_delete_transition_action/v0/transformer.rs b/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_delete_transition_action/v0/transformer.rs index 33e9f5ec023..ec815461626 100644 --- a/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_delete_transition_action/v0/transformer.rs +++ b/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_delete_transition_action/v0/transformer.rs @@ -1,42 +1,70 @@ use dpp::platform_value::Identifier; use std::sync::Arc; use dpp::data_contract::document_type::accessors::DocumentTypeV1Getters; +use dpp::fee::fee_result::FeeResult; +use dpp::prelude::{ConsensusValidationResult, UserFeeIncrease}; use dpp::ProtocolError; use dpp::state_transition::batch_transition::batched_transition::document_delete_transition::DocumentDeleteTransitionV0; use crate::drive::contract::DataContractFetchInfo; +use crate::error::Error; +use crate::state_transition_action::batch::batched_transition::BatchedTransitionAction; use crate::state_transition_action::batch::batched_transition::document_transition::document_base_transition_action::DocumentBaseTransitionAction; use crate::state_transition_action::batch::batched_transition::document_transition::document_delete_transition_action::v0::DocumentDeleteTransitionActionV0; +use crate::state_transition_action::batch::batched_transition::document_transition::DocumentTransitionAction; +use crate::state_transition_action::system::bump_identity_data_contract_nonce_action::BumpIdentityDataContractNonceAction; impl DocumentDeleteTransitionActionV0 { - /// try from - pub fn try_from_document_delete_transition_with_contract_lookup( - value: DocumentDeleteTransitionV0, - get_data_contract: impl Fn(Identifier) -> Result, ProtocolError>, - ) -> Result { - let DocumentDeleteTransitionV0 { base, .. } = value; - Ok(DocumentDeleteTransitionActionV0 { - base: DocumentBaseTransitionAction::try_from_base_transition_with_contract_lookup( - base, - get_data_contract, - |document_type| document_type.document_deletion_token_cost(), - )?, - }) - } - /// try from borrowed pub fn try_from_borrowed_document_delete_transition_with_contract_lookup( value: &DocumentDeleteTransitionV0, + owner_id: Identifier, + user_fee_increase: UserFeeIncrease, get_data_contract: impl Fn(Identifier) -> Result, ProtocolError>, - ) -> Result { + ) -> Result< + ( + ConsensusValidationResult, + FeeResult, + ), + Error, + > { let DocumentDeleteTransitionV0 { base, .. } = value; - Ok(DocumentDeleteTransitionActionV0 { - base: DocumentBaseTransitionAction::try_from_borrowed_base_transition_with_contract_lookup( + + let base_action_validation_result = + DocumentBaseTransitionAction::try_from_borrowed_base_transition_with_contract_lookup( base, get_data_contract, - |document_type| { - document_type.document_deletion_token_cost() - } - )?, - }) + |document_type| document_type.document_deletion_token_cost(), + "delete", + )?; + + let base = match base_action_validation_result.is_valid() { + true => base_action_validation_result.into_data()?, + false => { + let bump_action = + BumpIdentityDataContractNonceAction::from_borrowed_document_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, + ), + FeeResult::default(), + )); + } + }; + + Ok(( + BatchedTransitionAction::DocumentAction(DocumentTransitionAction::DeleteAction( + DocumentDeleteTransitionActionV0 { base }.into(), + )) + .into(), + FeeResult::default(), + )) } } diff --git a/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_purchase_transition_action/transformer.rs b/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_purchase_transition_action/transformer.rs index 7f591c601f6..d6082362fc6 100644 --- a/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_purchase_transition_action/transformer.rs +++ b/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_purchase_transition_action/transformer.rs @@ -2,32 +2,44 @@ use dpp::block::block_info::BlockInfo; use dpp::document::Document; use dpp::platform_value::Identifier; use std::sync::Arc; - +use dpp::fee::fee_result::FeeResult; +use dpp::prelude::{ConsensusValidationResult, UserFeeIncrease}; use dpp::ProtocolError; use dpp::state_transition::batch_transition::batched_transition::DocumentPurchaseTransition; use crate::drive::contract::DataContractFetchInfo; +use crate::error::Error; +use crate::state_transition_action::batch::batched_transition::BatchedTransitionAction; use crate::state_transition_action::batch::batched_transition::document_transition::document_purchase_transition_action::{DocumentPurchaseTransitionAction, DocumentPurchaseTransitionActionV0}; impl DocumentPurchaseTransitionAction { /// try from borrowed pub fn try_from_borrowed_document_purchase_transition( document_purchase_transition: &DocumentPurchaseTransition, + owner_id: Identifier, original_document: Document, purchaser_id: Identifier, block_info: &BlockInfo, + user_fee_increase: UserFeeIncrease, get_data_contract: impl Fn(Identifier) -> Result, ProtocolError>, - ) -> Result { + ) -> Result< + ( + ConsensusValidationResult, + FeeResult, + ), + Error, + > { match document_purchase_transition { - DocumentPurchaseTransition::V0(v0) => Ok( + DocumentPurchaseTransition::V0(v0) => { DocumentPurchaseTransitionActionV0::try_from_borrowed_document_purchase_transition( v0, + owner_id, original_document, purchaser_id, block_info, + user_fee_increase, get_data_contract, - )? - .into(), - ), + ) + } } } } diff --git a/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_purchase_transition_action/v0/transformer.rs b/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_purchase_transition_action/v0/transformer.rs index b9380c6b48d..c0a706aa30c 100644 --- a/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_purchase_transition_action/v0/transformer.rs +++ b/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_purchase_transition_action/v0/transformer.rs @@ -4,29 +4,65 @@ use dpp::document::{property_names, Document, DocumentV0Getters, DocumentV0Sette use dpp::platform_value::Identifier; use std::sync::Arc; use dpp::data_contract::document_type::accessors::DocumentTypeV1Getters; +use dpp::fee::fee_result::FeeResult; +use dpp::prelude::{ConsensusValidationResult, UserFeeIncrease}; use dpp::ProtocolError; use dpp::state_transition::batch_transition::batched_transition::document_purchase_transition::DocumentPurchaseTransitionV0; use crate::drive::contract::DataContractFetchInfo; +use crate::error::Error; +use crate::state_transition_action::batch::batched_transition::BatchedTransitionAction; use crate::state_transition_action::batch::batched_transition::document_transition::document_purchase_transition_action::v0::DocumentPurchaseTransitionActionV0; use crate::state_transition_action::batch::batched_transition::document_transition::document_base_transition_action::{DocumentBaseTransitionAction, DocumentBaseTransitionActionAccessorsV0}; +use crate::state_transition_action::batch::batched_transition::document_transition::DocumentTransitionAction; +use crate::state_transition_action::system::bump_identity_data_contract_nonce_action::BumpIdentityDataContractNonceAction; impl DocumentPurchaseTransitionActionV0 { /// try from borrowed pub fn try_from_borrowed_document_purchase_transition( document_purchase_transition: &DocumentPurchaseTransitionV0, + owner_id: Identifier, original_document: Document, purchaser_id: Identifier, block_info: &BlockInfo, + user_fee_increase: UserFeeIncrease, get_data_contract: impl Fn(Identifier) -> Result, ProtocolError>, - ) -> Result { + ) -> Result< + ( + ConsensusValidationResult, + FeeResult, + ), + Error, + > { let DocumentPurchaseTransitionV0 { base, price, .. } = document_purchase_transition; - let base = + let base_action_validation_result = DocumentBaseTransitionAction::try_from_borrowed_base_transition_with_contract_lookup( base, get_data_contract, |document_type| document_type.document_purchase_token_cost(), + "purchase", )?; + let base = match base_action_validation_result.is_valid() { + true => base_action_validation_result.into_data()?, + false => { + let bump_action = + BumpIdentityDataContractNonceAction::from_borrowed_document_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, + ), + FeeResult::default(), + )); + } + }; let original_owner_id = original_document.owner_id(); let mut modified_document = original_document; @@ -50,11 +86,18 @@ impl DocumentPurchaseTransitionActionV0 { modified_document.set_transferred_at_core_block_height(Some(block_info.core_height)); } - Ok(DocumentPurchaseTransitionActionV0 { - base, - document: modified_document, - original_owner_id, - price: *price, - }) + Ok(( + BatchedTransitionAction::DocumentAction(DocumentTransitionAction::PurchaseAction( + DocumentPurchaseTransitionActionV0 { + base, + document: modified_document, + original_owner_id, + price: *price, + } + .into(), + )) + .into(), + FeeResult::default(), + )) } } diff --git a/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_replace_transition_action/transformer.rs b/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_replace_transition_action/transformer.rs index a4d5d3eb861..7cd6cfb39bc 100644 --- a/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_replace_transition_action/transformer.rs +++ b/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_replace_transition_action/transformer.rs @@ -1,12 +1,14 @@ use dpp::block::block_info::BlockInfo; use dpp::platform_value::Identifier; use std::sync::Arc; - +use dpp::fee::fee_result::FeeResult; use dpp::identity::TimestampMillis; -use dpp::prelude::{BlockHeight, CoreBlockHeight}; +use dpp::prelude::{BlockHeight, ConsensusValidationResult, CoreBlockHeight, UserFeeIncrease}; use dpp::ProtocolError; use dpp::state_transition::batch_transition::batched_transition::DocumentReplaceTransition; use crate::drive::contract::DataContractFetchInfo; +use crate::error::Error; +use crate::state_transition_action::batch::batched_transition::BatchedTransitionAction; use crate::state_transition_action::batch::batched_transition::document_transition::document_replace_transition_action::{DocumentReplaceTransitionAction, DocumentReplaceTransitionActionV0}; impl DocumentReplaceTransitionAction { @@ -14,6 +16,7 @@ impl DocumentReplaceTransitionAction { #[allow(clippy::too_many_arguments)] pub fn try_from_borrowed_document_replace_transition( document_replace_transition: &DocumentReplaceTransition, + owner_id: Identifier, originally_created_at: Option, originally_created_at_block_height: Option, originally_created_at_core_block_height: Option, @@ -21,12 +24,20 @@ impl DocumentReplaceTransitionAction { originally_transferred_at_block_height: Option, originally_transferred_at_core_block_height: Option, block_info: &BlockInfo, + user_fee_increase: UserFeeIncrease, get_data_contract: impl Fn(Identifier) -> Result, ProtocolError>, - ) -> Result { + ) -> Result< + ( + ConsensusValidationResult, + FeeResult, + ), + Error, + > { match document_replace_transition { - DocumentReplaceTransition::V0(v0) => Ok( + DocumentReplaceTransition::V0(v0) => { DocumentReplaceTransitionActionV0::try_from_borrowed_document_replace_transition( v0, + owner_id, originally_created_at, originally_created_at_block_height, originally_created_at_core_block_height, @@ -34,10 +45,10 @@ impl DocumentReplaceTransitionAction { originally_transferred_at_block_height, originally_transferred_at_core_block_height, block_info, + user_fee_increase, get_data_contract, - )? - .into(), - ), + ) + } } } } diff --git a/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_replace_transition_action/v0/transformer.rs b/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_replace_transition_action/v0/transformer.rs index 5e3bbfb8c04..8642bc34221 100644 --- a/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_replace_transition_action/v0/transformer.rs +++ b/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_replace_transition_action/v0/transformer.rs @@ -3,19 +3,25 @@ use dpp::document::property_names; use dpp::platform_value::Identifier; use std::sync::Arc; use dpp::data_contract::document_type::accessors::DocumentTypeV1Getters; +use dpp::fee::fee_result::FeeResult; use dpp::identity::TimestampMillis; -use dpp::prelude::{BlockHeight, CoreBlockHeight}; +use dpp::prelude::{BlockHeight, ConsensusValidationResult, CoreBlockHeight, UserFeeIncrease}; use dpp::ProtocolError; use dpp::state_transition::batch_transition::batched_transition::document_replace_transition::DocumentReplaceTransitionV0; use crate::drive::contract::DataContractFetchInfo; +use crate::error::Error; +use crate::state_transition_action::batch::batched_transition::BatchedTransitionAction; use crate::state_transition_action::batch::batched_transition::document_transition::document_replace_transition_action::v0::DocumentReplaceTransitionActionV0; use crate::state_transition_action::batch::batched_transition::document_transition::document_base_transition_action::{DocumentBaseTransitionAction, DocumentBaseTransitionActionAccessorsV0}; +use crate::state_transition_action::batch::batched_transition::document_transition::DocumentTransitionAction; +use crate::state_transition_action::system::bump_identity_data_contract_nonce_action::BumpIdentityDataContractNonceAction; impl DocumentReplaceTransitionActionV0 { /// try from borrowed #[allow(clippy::too_many_arguments)] pub fn try_from_borrowed_document_replace_transition( document_replace_transition: &DocumentReplaceTransitionV0, + owner_id: Identifier, originally_created_at: Option, originally_created_at_block_height: Option, originally_created_at_core_block_height: Option, @@ -23,20 +29,50 @@ impl DocumentReplaceTransitionActionV0 { originally_transferred_at_block_height: Option, originally_transferred_at_core_block_height: Option, block_info: &BlockInfo, + user_fee_increase: UserFeeIncrease, get_data_contract: impl Fn(Identifier) -> Result, ProtocolError>, - ) -> Result { + ) -> Result< + ( + ConsensusValidationResult, + FeeResult, + ), + Error, + > { let DocumentReplaceTransitionV0 { base, revision, data, .. } = document_replace_transition; - let base = + let base_action_validation_result = DocumentBaseTransitionAction::try_from_borrowed_base_transition_with_contract_lookup( base, get_data_contract, |document_type| document_type.document_replacement_token_cost(), + "replace", )?; + + let base = match base_action_validation_result.is_valid() { + true => base_action_validation_result.into_data()?, + false => { + let bump_action = + BumpIdentityDataContractNonceAction::from_borrowed_document_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, + ), + FeeResult::default(), + )); + } + }; let updated_at = if base.document_type_field_is_required(property_names::UPDATED_AT)? { Some(block_info.time_ms) } else { @@ -58,19 +94,26 @@ impl DocumentReplaceTransitionActionV0 { None }; - Ok(DocumentReplaceTransitionActionV0 { - base, - revision: *revision, - created_at: originally_created_at, - updated_at, - transferred_at: originally_transferred_at, - created_at_block_height: originally_created_at_block_height, - updated_at_block_height, - transferred_at_block_height: originally_transferred_at_block_height, - created_at_core_block_height: originally_created_at_core_block_height, - updated_at_core_block_height, - transferred_at_core_block_height: originally_transferred_at_core_block_height, - data: data.clone(), - }) + Ok(( + BatchedTransitionAction::DocumentAction(DocumentTransitionAction::ReplaceAction( + DocumentReplaceTransitionActionV0 { + base, + revision: *revision, + created_at: originally_created_at, + updated_at, + transferred_at: originally_transferred_at, + created_at_block_height: originally_created_at_block_height, + updated_at_block_height, + transferred_at_block_height: originally_transferred_at_block_height, + created_at_core_block_height: originally_created_at_core_block_height, + updated_at_core_block_height, + transferred_at_core_block_height: originally_transferred_at_core_block_height, + data: data.clone(), + } + .into(), + )) + .into(), + FeeResult::default(), + )) } } diff --git a/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_transfer_transition_action/transformer.rs b/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_transfer_transition_action/transformer.rs index 736d414f17c..a5035f8951e 100644 --- a/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_transfer_transition_action/transformer.rs +++ b/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_transfer_transition_action/transformer.rs @@ -2,30 +2,42 @@ use dpp::block::block_info::BlockInfo; use dpp::document::Document; use dpp::platform_value::Identifier; use std::sync::Arc; - +use dpp::fee::fee_result::FeeResult; +use dpp::prelude::{ConsensusValidationResult, UserFeeIncrease}; use dpp::ProtocolError; use dpp::state_transition::batch_transition::batched_transition::DocumentTransferTransition; use crate::drive::contract::DataContractFetchInfo; +use crate::error::Error; +use crate::state_transition_action::batch::batched_transition::BatchedTransitionAction; use crate::state_transition_action::batch::batched_transition::document_transition::document_transfer_transition_action::{DocumentTransferTransitionAction, DocumentTransferTransitionActionV0}; impl DocumentTransferTransitionAction { /// try from borrowed pub fn try_from_borrowed_document_transfer_transition( document_transfer_transition: &DocumentTransferTransition, + owner_id: Identifier, original_document: Document, block_info: &BlockInfo, + user_fee_increase: UserFeeIncrease, get_data_contract: impl Fn(Identifier) -> Result, ProtocolError>, - ) -> Result { + ) -> Result< + ( + ConsensusValidationResult, + FeeResult, + ), + Error, + > { match document_transfer_transition { - DocumentTransferTransition::V0(v0) => Ok( + DocumentTransferTransition::V0(v0) => { DocumentTransferTransitionActionV0::try_from_borrowed_document_transfer_transition( v0, + owner_id, original_document, block_info, + user_fee_increase, get_data_contract, - )? - .into(), - ), + ) + } } } } diff --git a/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_transfer_transition_action/v0/transformer.rs b/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_transfer_transition_action/v0/transformer.rs index 6103bfe58f0..17264725946 100644 --- a/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_transfer_transition_action/v0/transformer.rs +++ b/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_transfer_transition_action/v0/transformer.rs @@ -4,32 +4,69 @@ use dpp::document::{property_names, Document, DocumentV0Getters, DocumentV0Sette use dpp::platform_value::Identifier; use std::sync::Arc; use dpp::data_contract::document_type::accessors::DocumentTypeV1Getters; +use dpp::fee::fee_result::FeeResult; +use dpp::prelude::{ConsensusValidationResult, UserFeeIncrease}; use dpp::ProtocolError; use dpp::state_transition::batch_transition::batched_transition::document_transfer_transition::DocumentTransferTransitionV0; use crate::drive::contract::DataContractFetchInfo; +use crate::error::Error; +use crate::state_transition_action::batch::batched_transition::BatchedTransitionAction; use crate::state_transition_action::batch::batched_transition::document_transition::document_transfer_transition_action::v0::DocumentTransferTransitionActionV0; use crate::state_transition_action::batch::batched_transition::document_transition::document_base_transition_action::{DocumentBaseTransitionAction, DocumentBaseTransitionActionAccessorsV0}; +use crate::state_transition_action::batch::batched_transition::document_transition::DocumentTransitionAction; +use crate::state_transition_action::system::bump_identity_data_contract_nonce_action::BumpIdentityDataContractNonceAction; impl DocumentTransferTransitionActionV0 { /// try from borrowed pub fn try_from_borrowed_document_transfer_transition( document_transfer_transition: &DocumentTransferTransitionV0, + owner_id: Identifier, original_document: Document, block_info: &BlockInfo, + user_fee_increase: UserFeeIncrease, get_data_contract: impl Fn(Identifier) -> Result, ProtocolError>, - ) -> Result { + ) -> Result< + ( + ConsensusValidationResult, + FeeResult, + ), + Error, + > { let DocumentTransferTransitionV0 { base, recipient_owner_id, .. } = document_transfer_transition; - let base = + let base_action_validation_result = DocumentBaseTransitionAction::try_from_borrowed_base_transition_with_contract_lookup( base, get_data_contract, |document_type| document_type.document_transfer_token_cost(), + "transfer", )?; + let base = match base_action_validation_result.is_valid() { + true => base_action_validation_result.into_data()?, + false => { + let bump_action = + BumpIdentityDataContractNonceAction::from_borrowed_document_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, + ), + FeeResult::default(), + )); + } + }; + let mut modified_document = original_document; modified_document.set_owner_id(*recipient_owner_id); @@ -51,9 +88,16 @@ impl DocumentTransferTransitionActionV0 { modified_document.set_transferred_at_core_block_height(Some(block_info.core_height)); } - Ok(DocumentTransferTransitionActionV0 { - base, - document: modified_document, - }) + Ok(( + BatchedTransitionAction::DocumentAction(DocumentTransitionAction::TransferAction( + DocumentTransferTransitionActionV0 { + base, + document: modified_document, + } + .into(), + )) + .into(), + FeeResult::default(), + )) } } diff --git a/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_update_price_transition_action/transformer.rs b/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_update_price_transition_action/transformer.rs index 524ff7e6c1a..03b1e93d597 100644 --- a/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_update_price_transition_action/transformer.rs +++ b/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_update_price_transition_action/transformer.rs @@ -2,30 +2,40 @@ use dpp::block::block_info::BlockInfo; use dpp::document::Document; use dpp::platform_value::Identifier; use std::sync::Arc; - +use dpp::fee::fee_result::FeeResult; +use dpp::prelude::{ConsensusValidationResult, UserFeeIncrease}; use dpp::ProtocolError; use dpp::state_transition::batch_transition::batched_transition::DocumentUpdatePriceTransition; use crate::drive::contract::DataContractFetchInfo; +use crate::error::Error; +use crate::state_transition_action::batch::batched_transition::BatchedTransitionAction; use crate::state_transition_action::batch::batched_transition::document_transition::document_update_price_transition_action::{DocumentUpdatePriceTransitionAction, DocumentUpdatePriceTransitionActionV0}; impl DocumentUpdatePriceTransitionAction { /// try from borrowed pub fn try_from_borrowed_document_update_price_transition( document_update_price_transition: &DocumentUpdatePriceTransition, + owner_id: Identifier, original_document: Document, block_info: &BlockInfo, + user_fee_increase: UserFeeIncrease, get_data_contract: impl Fn(Identifier) -> Result, ProtocolError>, - ) -> Result { + ) -> Result< + ( + ConsensusValidationResult, + FeeResult, + ), + Error, + > { match document_update_price_transition { - DocumentUpdatePriceTransition::V0(v0) => Ok( - DocumentUpdatePriceTransitionActionV0::try_from_borrowed_document_update_price_transition( + DocumentUpdatePriceTransition::V0(v0) => DocumentUpdatePriceTransitionActionV0::try_from_borrowed_document_update_price_transition( v0, + owner_id, original_document, block_info, + user_fee_increase, get_data_contract, - )? - .into(), - ), + ), } } } diff --git a/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_update_price_transition_action/v0/transformer.rs b/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_update_price_transition_action/v0/transformer.rs index ffe82035d3f..f18dca6085d 100644 --- a/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_update_price_transition_action/v0/transformer.rs +++ b/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_update_price_transition_action/v0/transformer.rs @@ -4,28 +4,65 @@ use dpp::document::{property_names, Document, DocumentV0Setters}; use dpp::platform_value::Identifier; use std::sync::Arc; use dpp::data_contract::document_type::accessors::DocumentTypeV1Getters; +use dpp::fee::fee_result::FeeResult; +use dpp::prelude::{ConsensusValidationResult, UserFeeIncrease}; use dpp::ProtocolError; use dpp::state_transition::batch_transition::batched_transition::document_update_price_transition::DocumentUpdatePriceTransitionV0; use crate::drive::contract::DataContractFetchInfo; +use crate::error::Error; +use crate::state_transition_action::batch::batched_transition::BatchedTransitionAction; use crate::state_transition_action::batch::batched_transition::document_transition::document_update_price_transition_action::v0::DocumentUpdatePriceTransitionActionV0; use crate::state_transition_action::batch::batched_transition::document_transition::document_base_transition_action::{DocumentBaseTransitionAction, DocumentBaseTransitionActionAccessorsV0}; +use crate::state_transition_action::batch::batched_transition::document_transition::DocumentTransitionAction; +use crate::state_transition_action::system::bump_identity_data_contract_nonce_action::BumpIdentityDataContractNonceAction; impl DocumentUpdatePriceTransitionActionV0 { /// try from borrowed pub fn try_from_borrowed_document_update_price_transition( document_update_price_transition: &DocumentUpdatePriceTransitionV0, + owner_id: Identifier, original_document: Document, block_info: &BlockInfo, + user_fee_increase: UserFeeIncrease, get_data_contract: impl Fn(Identifier) -> Result, ProtocolError>, - ) -> Result { + ) -> Result< + ( + ConsensusValidationResult, + FeeResult, + ), + Error, + > { let DocumentUpdatePriceTransitionV0 { base, price, .. } = document_update_price_transition; - let base = + let base_action_validation_result = DocumentBaseTransitionAction::try_from_borrowed_base_transition_with_contract_lookup( base, get_data_contract, |document_type| document_type.document_update_price_token_cost(), + "update_price", )?; + let base = match base_action_validation_result.is_valid() { + true => base_action_validation_result.into_data()?, + false => { + let bump_action = + BumpIdentityDataContractNonceAction::from_borrowed_document_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, + ), + FeeResult::default(), + )); + } + }; + let mut modified_document = original_document; modified_document.set_u64(PRICE, *price); @@ -44,9 +81,16 @@ impl DocumentUpdatePriceTransitionActionV0 { modified_document.set_updated_at_core_block_height(Some(block_info.core_height)); } - Ok(DocumentUpdatePriceTransitionActionV0 { - base, - document: modified_document, - }) + Ok(( + BatchedTransitionAction::DocumentAction(DocumentTransitionAction::UpdatePriceAction( + DocumentUpdatePriceTransitionActionV0 { + base, + document: modified_document, + } + .into(), + )) + .into(), + FeeResult::default(), + )) } } diff --git a/packages/rs-drive/src/state_transition_action/batch/batched_transition/mod.rs b/packages/rs-drive/src/state_transition_action/batch/batched_transition/mod.rs index 4ba839bd84f..d0c45c1ac86 100644 --- a/packages/rs-drive/src/state_transition_action/batch/batched_transition/mod.rs +++ b/packages/rs-drive/src/state_transition_action/batch/batched_transition/mod.rs @@ -1,5 +1,6 @@ use derive_more::From; use dpp::identifier::Identifier; +use dpp::ProtocolError; use crate::state_transition_action::batch::batched_transition::document_transition::document_base_transition_action::DocumentBaseTransitionActionAccessorsV0; use crate::state_transition_action::batch::batched_transition::document_transition::DocumentTransitionAction; use crate::state_transition_action::batch::batched_transition::token_transition::token_base_transition_action::TokenBaseTransitionActionAccessorsV0; @@ -37,4 +38,49 @@ impl BatchedTransitionAction { } } } + /// as_document_action + pub fn as_document_action(&self) -> Result<&DocumentTransitionAction, ProtocolError> { + match self { + BatchedTransitionAction::DocumentAction(action) => Ok(action), + other => Err(ProtocolError::InvalidBatchedTransitionActionVariant { + expected: "DocumentAction", + found: other.variant_name(), + }), + } + } + + /// as_token_action + pub fn as_token_action(&self) -> Result<&TokenTransitionAction, ProtocolError> { + match self { + BatchedTransitionAction::TokenAction(action) => Ok(action), + other => Err(ProtocolError::InvalidBatchedTransitionActionVariant { + expected: "TokenAction", + found: other.variant_name(), + }), + } + } + + /// as_bump_identity_nonce_action + pub fn as_bump_identity_nonce_action( + &self, + ) -> Result<&BumpIdentityDataContractNonceAction, ProtocolError> { + match self { + BatchedTransitionAction::BumpIdentityDataContractNonce(action) => Ok(action), + other => Err(ProtocolError::InvalidBatchedTransitionActionVariant { + expected: "BumpIdentityDataContractNonce", + found: other.variant_name(), + }), + } + } + + /// Helper method to get the variant name for diagnostics. + fn variant_name(&self) -> &'static str { + match self { + BatchedTransitionAction::DocumentAction(_) => "DocumentAction", + BatchedTransitionAction::TokenAction(_) => "TokenAction", + BatchedTransitionAction::BumpIdentityDataContractNonce(_) => { + "BumpIdentityDataContractNonce" + } + } + } } diff --git a/packages/rs-drive/src/state_transition_action/system/bump_identity_data_contract_nonce_action/transformer.rs b/packages/rs-drive/src/state_transition_action/system/bump_identity_data_contract_nonce_action/transformer.rs index e0691b16e68..7e9b021b171 100644 --- a/packages/rs-drive/src/state_transition_action/system/bump_identity_data_contract_nonce_action/transformer.rs +++ b/packages/rs-drive/src/state_transition_action/system/bump_identity_data_contract_nonce_action/transformer.rs @@ -101,16 +101,12 @@ impl BumpIdentityDataContractNonceAction { identity_id: Identifier, user_fee_increase: UserFeeIncrease, ) -> Self { - match value { - DocumentBaseTransition::V0(v0) => { - BumpIdentityDataContractNonceActionV0::from_document_base_transition( - v0, - identity_id, - user_fee_increase, - ) - .into() - } - } + BumpIdentityDataContractNonceActionV0::from_document_base_transition( + value, + identity_id, + user_fee_increase, + ) + .into() } /// from borrowed base transition @@ -119,16 +115,12 @@ impl BumpIdentityDataContractNonceAction { identity_id: Identifier, user_fee_increase: UserFeeIncrease, ) -> Self { - match value { - DocumentBaseTransition::V0(v0) => { - BumpIdentityDataContractNonceActionV0::from_borrowed_document_base_transition( - v0, - identity_id, - user_fee_increase, - ) - .into() - } - } + BumpIdentityDataContractNonceActionV0::from_borrowed_document_base_transition( + value, + identity_id, + user_fee_increase, + ) + .into() } /// from base transition @@ -137,16 +129,12 @@ impl BumpIdentityDataContractNonceAction { identity_id: Identifier, user_fee_increase: UserFeeIncrease, ) -> Self { - match value { - DocumentBaseTransitionAction::V0(v0) => { - BumpIdentityDataContractNonceActionV0::from_document_base_transition_action( - v0, - identity_id, - user_fee_increase, - ) - .into() - } - } + BumpIdentityDataContractNonceActionV0::from_document_base_transition_action( + value, + identity_id, + user_fee_increase, + ) + .into() } /// from borrowed base transition @@ -155,16 +143,12 @@ impl BumpIdentityDataContractNonceAction { identity_id: Identifier, user_fee_increase: UserFeeIncrease, ) -> Self { - match value { - DocumentBaseTransitionAction::V0(v0) => { - BumpIdentityDataContractNonceActionV0::from_borrowed_document_base_transition_action( - v0, - identity_id, - user_fee_increase, - ) - .into() - } - } + BumpIdentityDataContractNonceActionV0::from_borrowed_document_base_transition_action( + value, + identity_id, + user_fee_increase, + ) + .into() } /// from base transition @@ -173,16 +157,12 @@ impl BumpIdentityDataContractNonceAction { identity_id: Identifier, user_fee_increase: UserFeeIncrease, ) -> Self { - match value { - TokenBaseTransition::V0(v0) => { - BumpIdentityDataContractNonceActionV0::from_token_base_transition( - v0, - identity_id, - user_fee_increase, - ) - .into() - } - } + BumpIdentityDataContractNonceActionV0::from_token_base_transition( + value, + identity_id, + user_fee_increase, + ) + .into() } /// from borrowed base transition @@ -191,16 +171,12 @@ impl BumpIdentityDataContractNonceAction { identity_id: Identifier, user_fee_increase: UserFeeIncrease, ) -> Self { - match value { - TokenBaseTransition::V0(v0) => { - BumpIdentityDataContractNonceActionV0::from_borrowed_token_base_transition( - v0, - identity_id, - user_fee_increase, - ) - .into() - } - } + BumpIdentityDataContractNonceActionV0::from_borrowed_token_base_transition( + value, + identity_id, + user_fee_increase, + ) + .into() } /// from base transition @@ -209,16 +185,12 @@ impl BumpIdentityDataContractNonceAction { identity_id: Identifier, user_fee_increase: UserFeeIncrease, ) -> Self { - match value { - TokenBaseTransitionAction::V0(v0) => { - BumpIdentityDataContractNonceActionV0::from_token_base_transition_action( - v0, - identity_id, - user_fee_increase, - ) - .into() - } - } + BumpIdentityDataContractNonceActionV0::from_token_base_transition_action( + value, + identity_id, + user_fee_increase, + ) + .into() } /// from borrowed base transition @@ -227,16 +199,12 @@ impl BumpIdentityDataContractNonceAction { identity_id: Identifier, user_fee_increase: UserFeeIncrease, ) -> Self { - match value { - TokenBaseTransitionAction::V0(v0) => { - BumpIdentityDataContractNonceActionV0::from_borrowed_token_base_transition_action( - v0, - identity_id, - user_fee_increase, - ) - .into() - } - } + BumpIdentityDataContractNonceActionV0::from_borrowed_token_base_transition_action( + value, + identity_id, + user_fee_increase, + ) + .into() } /// from data contract update diff --git a/packages/rs-drive/src/state_transition_action/system/bump_identity_data_contract_nonce_action/v0/transformer.rs b/packages/rs-drive/src/state_transition_action/system/bump_identity_data_contract_nonce_action/v0/transformer.rs index c87a865a70c..d9b2bf74e96 100644 --- a/packages/rs-drive/src/state_transition_action/system/bump_identity_data_contract_nonce_action/v0/transformer.rs +++ b/packages/rs-drive/src/state_transition_action/system/bump_identity_data_contract_nonce_action/v0/transformer.rs @@ -1,164 +1,125 @@ use dpp::data_contract::accessors::v0::DataContractV0Getters; use dpp::platform_value::Identifier; use dpp::prelude::UserFeeIncrease; - +use dpp::state_transition::batch_transition::document_base_transition::DocumentBaseTransition; use dpp::state_transition::data_contract_update_transition::DataContractUpdateTransitionV0; -use dpp::state_transition::batch_transition::document_base_transition::v0::DocumentBaseTransitionV0; -use dpp::state_transition::batch_transition::token_base_transition::v0::TokenBaseTransitionV0; +use dpp::state_transition::batch_transition::document_base_transition::v0::v0_methods::DocumentBaseTransitionV0Methods; +use dpp::state_transition::batch_transition::token_base_transition::TokenBaseTransition; +use dpp::state_transition::batch_transition::token_base_transition::v0::v0_methods::TokenBaseTransitionV0Methods; use crate::state_transition_action::contract::data_contract_update::v0::DataContractUpdateTransitionActionV0; -use crate::state_transition_action::batch::batched_transition::document_transition::document_base_transition_action::DocumentBaseTransitionActionV0; -use crate::state_transition_action::batch::batched_transition::token_transition::token_base_transition_action::TokenBaseTransitionActionV0; +use crate::state_transition_action::batch::batched_transition::document_transition::document_base_transition_action::{DocumentBaseTransitionAction, DocumentBaseTransitionActionAccessorsV0}; +use crate::state_transition_action::batch::batched_transition::token_transition::token_base_transition_action::{TokenBaseTransitionAction, TokenBaseTransitionActionAccessorsV0}; use crate::state_transition_action::system::bump_identity_data_contract_nonce_action::BumpIdentityDataContractNonceActionV0; impl BumpIdentityDataContractNonceActionV0 { /// from base transition pub fn from_document_base_transition( - value: DocumentBaseTransitionV0, + value: DocumentBaseTransition, identity_id: Identifier, user_fee_increase: UserFeeIncrease, ) -> Self { - let DocumentBaseTransitionV0 { - data_contract_id, - identity_contract_nonce, - .. - } = value; BumpIdentityDataContractNonceActionV0 { identity_id, - data_contract_id, - identity_contract_nonce, + data_contract_id: value.data_contract_id(), + identity_contract_nonce: value.identity_contract_nonce(), user_fee_increase, } } /// from borrowed base transition pub fn from_borrowed_document_base_transition( - value: &DocumentBaseTransitionV0, + value: &DocumentBaseTransition, identity_id: Identifier, user_fee_increase: UserFeeIncrease, ) -> Self { - let DocumentBaseTransitionV0 { - data_contract_id, - identity_contract_nonce, - .. - } = value; BumpIdentityDataContractNonceActionV0 { identity_id, - data_contract_id: *data_contract_id, - identity_contract_nonce: *identity_contract_nonce, + data_contract_id: value.data_contract_id(), + identity_contract_nonce: value.identity_contract_nonce(), user_fee_increase, } } /// from base transition pub fn from_document_base_transition_action( - value: DocumentBaseTransitionActionV0, + value: DocumentBaseTransitionAction, identity_id: Identifier, user_fee_increase: UserFeeIncrease, ) -> Self { - let DocumentBaseTransitionActionV0 { - data_contract, - identity_contract_nonce, - .. - } = value; BumpIdentityDataContractNonceActionV0 { identity_id, - data_contract_id: data_contract.contract.id(), - identity_contract_nonce, + data_contract_id: value.data_contract_id(), + identity_contract_nonce: value.identity_contract_nonce(), user_fee_increase, } } /// from borrowed base transition pub fn from_borrowed_document_base_transition_action( - value: &DocumentBaseTransitionActionV0, + value: &DocumentBaseTransitionAction, identity_id: Identifier, user_fee_increase: UserFeeIncrease, ) -> Self { - let DocumentBaseTransitionActionV0 { - data_contract, - identity_contract_nonce, - .. - } = value; BumpIdentityDataContractNonceActionV0 { identity_id, - data_contract_id: data_contract.contract.id(), - identity_contract_nonce: *identity_contract_nonce, + data_contract_id: value.data_contract_id(), + identity_contract_nonce: value.identity_contract_nonce(), user_fee_increase, } } /// from base transition pub fn from_token_base_transition( - value: TokenBaseTransitionV0, + value: TokenBaseTransition, identity_id: Identifier, user_fee_increase: UserFeeIncrease, ) -> Self { - let TokenBaseTransitionV0 { - data_contract_id, - identity_contract_nonce, - .. - } = value; BumpIdentityDataContractNonceActionV0 { identity_id, - data_contract_id, - identity_contract_nonce, + data_contract_id: value.data_contract_id(), + identity_contract_nonce: value.identity_contract_nonce(), user_fee_increase, } } /// from borrowed base transition pub fn from_borrowed_token_base_transition( - value: &TokenBaseTransitionV0, + value: &TokenBaseTransition, identity_id: Identifier, user_fee_increase: UserFeeIncrease, ) -> Self { - let TokenBaseTransitionV0 { - data_contract_id, - identity_contract_nonce, - .. - } = value; BumpIdentityDataContractNonceActionV0 { identity_id, - data_contract_id: *data_contract_id, - identity_contract_nonce: *identity_contract_nonce, + data_contract_id: value.data_contract_id(), + identity_contract_nonce: value.identity_contract_nonce(), user_fee_increase, } } /// from base transition pub fn from_token_base_transition_action( - value: TokenBaseTransitionActionV0, + value: TokenBaseTransitionAction, identity_id: Identifier, user_fee_increase: UserFeeIncrease, ) -> Self { - let TokenBaseTransitionActionV0 { - data_contract, - identity_contract_nonce, - .. - } = value; BumpIdentityDataContractNonceActionV0 { identity_id, - data_contract_id: data_contract.contract.id(), - identity_contract_nonce, + data_contract_id: value.data_contract_id(), + identity_contract_nonce: value.identity_contract_nonce(), user_fee_increase, } } /// from borrowed base transition pub fn from_borrowed_token_base_transition_action( - value: &TokenBaseTransitionActionV0, + value: &TokenBaseTransitionAction, identity_id: Identifier, user_fee_increase: UserFeeIncrease, ) -> Self { - let TokenBaseTransitionActionV0 { - data_contract, - identity_contract_nonce, - .. - } = value; BumpIdentityDataContractNonceActionV0 { identity_id, - data_contract_id: data_contract.contract.id(), - identity_contract_nonce: *identity_contract_nonce, + data_contract_id: value.data_contract_id(), + identity_contract_nonce: value.identity_contract_nonce(), user_fee_increase, } } diff --git a/packages/rs-platform-value/src/btreemap_extensions/btreemap_removal_extensions.rs b/packages/rs-platform-value/src/btreemap_extensions/btreemap_removal_extensions.rs index 8b2b2daa250..d9a4b4acf95 100644 --- a/packages/rs-platform-value/src/btreemap_extensions/btreemap_removal_extensions.rs +++ b/packages/rs-platform-value/src/btreemap_extensions/btreemap_removal_extensions.rs @@ -59,6 +59,20 @@ pub trait BTreeValueRemoveFromMapHelper { where K: TryFrom + Ord, V: TryFrom; + + fn remove_map_as_btree_map_keep_values_as_platform_value( + &mut self, + key: &str, + ) -> Result, Error> + where + K: TryFrom + Ord; + + fn remove_optional_map_as_btree_map_keep_values_as_platform_value( + &mut self, + key: &str, + ) -> Result>, Error> + where + K: TryFrom + Ord; } pub trait BTreeValueRemoveTupleFromMapHelper { @@ -341,6 +355,41 @@ impl BTreeValueRemoveFromMapHelper for BTreeMap { }) .transpose() } + + fn remove_map_as_btree_map_keep_values_as_platform_value( + &mut self, + key: &str, + ) -> Result, Error> + where + K: TryFrom + Ord, + { + self.remove_optional_map_as_btree_map_keep_values_as_platform_value(key)? + .ok_or_else(|| Error::StructureError(format!("unable to remove map property {key}"))) + } + + fn remove_optional_map_as_btree_map_keep_values_as_platform_value( + &mut self, + key: &str, + ) -> Result>, Error> + where + K: TryFrom + Ord, + { + self.remove(key) + .and_then(|v| { + if v.is_null() { + None + } else if let Value::Map(map) = v { + Some( + map.iter() + .map(|(key, value)| Ok((key.clone().try_into()?, value.clone()))) + .collect(), + ) + } else { + None + } + }) + .transpose() + } } impl BTreeValueRemoveFromMapHelper for BTreeMap { @@ -621,6 +670,41 @@ impl BTreeValueRemoveFromMapHelper for BTreeMap { }) .transpose() } + + fn remove_map_as_btree_map_keep_values_as_platform_value( + &mut self, + key: &str, + ) -> Result, Error> + where + K: TryFrom + Ord, + { + self.remove_optional_map_as_btree_map_keep_values_as_platform_value(key)? + .ok_or_else(|| Error::StructureError(format!("unable to remove map property {key}"))) + } + + fn remove_optional_map_as_btree_map_keep_values_as_platform_value( + &mut self, + key: &str, + ) -> Result>, Error> + where + K: TryFrom + Ord, + { + self.remove(key) + .and_then(|v| { + if v.is_null() { + None + } else if let Value::Map(map) = v { + Some( + map.into_iter() + .map(|(key, value)| Ok((key.try_into()?, value))) + .collect(), + ) + } else { + None + } + }) + .transpose() + } } impl BTreeValueRemoveTupleFromMapHelper for BTreeMap { diff --git a/packages/rs-platform-version/src/version/dpp_versions/dpp_state_transition_serialization_versions/v2.rs b/packages/rs-platform-version/src/version/dpp_versions/dpp_state_transition_serialization_versions/v2.rs index 1df489c45e7..a6ad26bfa26 100644 --- a/packages/rs-platform-version/src/version/dpp_versions/dpp_state_transition_serialization_versions/v2.rs +++ b/packages/rs-platform-version/src/version/dpp_versions/dpp_state_transition_serialization_versions/v2.rs @@ -58,7 +58,7 @@ pub const STATE_TRANSITION_SERIALIZATION_VERSIONS_V2: DPPStateTransitionSerializ document_base_state_transition: FeatureVersionBounds { min_version: 0, max_version: 0, - default_current_version: 0, + default_current_version: 1, }, document_create_state_transition: DocumentFeatureVersionBounds { bounds: FeatureVersionBounds { diff --git a/packages/rs-sdk/src/platform/transition/purchase_document.rs b/packages/rs-sdk/src/platform/transition/purchase_document.rs index c119bcc149f..11ea6488426 100644 --- a/packages/rs-sdk/src/platform/transition/purchase_document.rs +++ b/packages/rs-sdk/src/platform/transition/purchase_document.rs @@ -12,6 +12,7 @@ use dpp::prelude::Identifier; use dpp::state_transition::batch_transition::methods::v0::DocumentsBatchTransitionMethodsV0; use dpp::state_transition::batch_transition::BatchTransition; use dpp::state_transition::StateTransition; +use dpp::tokens::token_payment_info::TokenPaymentInfo; #[async_trait::async_trait] /// A trait for purchasing a document on Platform @@ -26,6 +27,7 @@ pub trait PurchaseDocument: Waitable { document_type: DocumentType, purchaser_id: Identifier, identity_public_key: IdentityPublicKey, + token_payment_info: Option, signer: &S, settings: Option, ) -> Result; @@ -39,6 +41,7 @@ pub trait PurchaseDocument: Waitable { document_type: DocumentType, purchaser_id: Identifier, identity_public_key: IdentityPublicKey, + token_payment_info: Option, signer: &S, settings: Option, ) -> Result; @@ -53,6 +56,7 @@ impl PurchaseDocument for Document { document_type: DocumentType, purchaser_id: Identifier, identity_public_key: IdentityPublicKey, + token_payment_info: Option, signer: &S, settings: Option, ) -> Result { @@ -75,6 +79,7 @@ impl PurchaseDocument for Document { &identity_public_key, new_identity_contract_nonce, settings.user_fee_increase.unwrap_or_default(), + token_payment_info, signer, sdk.version(), None, @@ -94,6 +99,7 @@ impl PurchaseDocument for Document { document_type: DocumentType, purchaser_id: Identifier, identity_public_key: IdentityPublicKey, + token_payment_info: Option, signer: &S, settings: Option, ) -> Result { @@ -104,6 +110,7 @@ impl PurchaseDocument for Document { document_type, purchaser_id, identity_public_key, + token_payment_info, signer, settings, ) diff --git a/packages/rs-sdk/src/platform/transition/put_document.rs b/packages/rs-sdk/src/platform/transition/put_document.rs index a18b9143ea4..a61d978d2f6 100644 --- a/packages/rs-sdk/src/platform/transition/put_document.rs +++ b/packages/rs-sdk/src/platform/transition/put_document.rs @@ -67,6 +67,7 @@ impl PutDocument for Document { &identity_public_key, new_identity_contract_nonce, settings.user_fee_increase.unwrap_or_default(), + None, signer, sdk.version(), None, diff --git a/packages/rs-sdk/src/platform/transition/transfer_document.rs b/packages/rs-sdk/src/platform/transition/transfer_document.rs index bd4a87e2dd6..0dae7f03fd9 100644 --- a/packages/rs-sdk/src/platform/transition/transfer_document.rs +++ b/packages/rs-sdk/src/platform/transition/transfer_document.rs @@ -11,6 +11,7 @@ use dpp::identity::IdentityPublicKey; use dpp::state_transition::batch_transition::methods::v0::DocumentsBatchTransitionMethodsV0; use dpp::state_transition::batch_transition::BatchTransition; use dpp::state_transition::StateTransition; +use dpp::tokens::token_payment_info::TokenPaymentInfo; use rs_dapi_client::{DapiRequest, IntoInner}; #[async_trait::async_trait] @@ -18,23 +19,27 @@ use rs_dapi_client::{DapiRequest, IntoInner}; pub trait TransferDocument: Waitable { /// Transfers a document on platform /// Setting settings to `None` sets default connection behavior + #[allow(clippy::too_many_arguments)] async fn transfer_document_to_identity( &self, recipient_id: Identifier, sdk: &Sdk, document_type: DocumentType, identity_public_key: IdentityPublicKey, + token_payment_info: Option, signer: &S, settings: Option, ) -> Result; /// Transfers a document on platform and waits for the response + #[allow(clippy::too_many_arguments)] async fn transfer_document_to_identity_and_wait_for_response( &self, recipient_id: Identifier, sdk: &Sdk, document_type: DocumentType, identity_public_key: IdentityPublicKey, + token_payment_info: Option, signer: &S, settings: Option, ) -> Result; @@ -48,6 +53,7 @@ impl TransferDocument for Document { sdk: &Sdk, document_type: DocumentType, identity_public_key: IdentityPublicKey, + token_payment_info: Option, signer: &S, settings: Option, ) -> Result { @@ -69,6 +75,7 @@ impl TransferDocument for Document { &identity_public_key, new_identity_contract_nonce, settings.user_fee_increase.unwrap_or_default(), + token_payment_info, signer, sdk.version(), None, @@ -95,6 +102,7 @@ impl TransferDocument for Document { sdk: &Sdk, document_type: DocumentType, identity_public_key: IdentityPublicKey, + token_payment_info: Option, signer: &S, settings: Option, ) -> Result { @@ -104,6 +112,7 @@ impl TransferDocument for Document { sdk, document_type, identity_public_key, + token_payment_info, signer, settings, ) diff --git a/packages/rs-sdk/src/platform/transition/update_price_of_document.rs b/packages/rs-sdk/src/platform/transition/update_price_of_document.rs index b6e651d5eec..c3c362bfc86 100644 --- a/packages/rs-sdk/src/platform/transition/update_price_of_document.rs +++ b/packages/rs-sdk/src/platform/transition/update_price_of_document.rs @@ -12,29 +12,34 @@ use dpp::identity::IdentityPublicKey; use dpp::state_transition::batch_transition::methods::v0::DocumentsBatchTransitionMethodsV0; use dpp::state_transition::batch_transition::BatchTransition; use dpp::state_transition::StateTransition; +use dpp::tokens::token_payment_info::TokenPaymentInfo; #[async_trait::async_trait] /// A trait for updating the price of a document on Platform pub trait UpdatePriceOfDocument: Waitable { /// Updates the price of a document on platform /// Setting settings to `None` sets default connection behavior + #[allow(clippy::too_many_arguments)] async fn update_price_of_document( &self, price: Credits, sdk: &Sdk, document_type: DocumentType, identity_public_key: IdentityPublicKey, + token_payment_info: Option, signer: &S, settings: Option, ) -> Result; /// Updates the price of a document on platform and waits for the response + #[allow(clippy::too_many_arguments)] async fn update_price_of_document_and_wait_for_response( &self, price: Credits, sdk: &Sdk, document_type: DocumentType, identity_public_key: IdentityPublicKey, + token_payment_info: Option, signer: &S, settings: Option, ) -> Result; @@ -48,6 +53,7 @@ impl UpdatePriceOfDocument for Document { sdk: &Sdk, document_type: DocumentType, identity_public_key: IdentityPublicKey, + token_payment_info: Option, signer: &S, settings: Option, ) -> Result { @@ -69,6 +75,7 @@ impl UpdatePriceOfDocument for Document { &identity_public_key, new_identity_contract_nonce, settings.user_fee_increase.unwrap_or_default(), + token_payment_info, signer, sdk.version(), None, @@ -87,11 +94,20 @@ impl UpdatePriceOfDocument for Document { sdk: &Sdk, document_type: DocumentType, identity_public_key: IdentityPublicKey, + token_payment_info: Option, signer: &S, settings: Option, ) -> Result { let state_transition = self - .update_price_of_document(price, sdk, document_type, identity_public_key, signer, None) + .update_price_of_document( + price, + sdk, + document_type, + identity_public_key, + token_payment_info, + signer, + None, + ) .await?; Self::wait_for_response(sdk, state_transition, settings).await diff --git a/packages/wasm-dpp/src/document/factory.rs b/packages/wasm-dpp/src/document/factory.rs index 74b397ca41e..4d954c4287f 100644 --- a/packages/wasm-dpp/src/document/factory.rs +++ b/packages/wasm-dpp/src/document/factory.rs @@ -22,6 +22,7 @@ use crate::{ }; use dpp::identifier::Identifier; use dpp::state_transition::batch_transition::batched_transition::document_transition_action_type::DocumentTransitionActionType; +use dpp::tokens::token_payment_info::TokenPaymentInfo; use dpp::version::PlatformVersion; use std::convert::TryFrom; @@ -158,11 +159,16 @@ impl DocumentFactoryWASM { #[allow(clippy::type_complexity)] let documents: Vec<( DocumentTransitionActionType, - Vec<(Document, DocumentTypeRef, Bytes32)>, + Vec<(Document, DocumentTypeRef, Bytes32, Option)>, )> = documents_by_action .iter() .map(|(action_type, documents)| { - let documents_with_refs: Vec<(Document, DocumentTypeRef, Bytes32)> = documents + let documents_with_refs: Vec<( + Document, + DocumentTypeRef, + Bytes32, + Option, + )> = documents .iter() .map(|extended_document| { ( @@ -172,6 +178,7 @@ impl DocumentFactoryWASM { .document_type_for_name(extended_document.document_type_name()) .expect("should be able to get document type"), extended_document.entropy().to_owned(), + extended_document.token_payment_info(), ) }) .collect(); diff --git a/packages/wasm-dpp/src/document/state_transition/batch_transition/document_transition/mod.rs b/packages/wasm-dpp/src/document/state_transition/batch_transition/document_transition/mod.rs index d7080c5da83..dee9cb76b95 100644 --- a/packages/wasm-dpp/src/document/state_transition/batch_transition/document_transition/mod.rs +++ b/packages/wasm-dpp/src/document/state_transition/batch_transition/document_transition/mod.rs @@ -19,11 +19,11 @@ use wasm_bindgen::prelude::*; use dpp::fee::Credits; use dpp::platform_value::converter::serde_json::BTreeValueJsonConverter; use dpp::prelude::Revision; -use dpp::state_transition::batch_transition::document_base_transition::DocumentBaseTransition; use dpp::state_transition::batch_transition::document_replace_transition::v0::v0_methods::DocumentReplaceTransitionV0Methods; use dpp::state_transition::batch_transition::batched_transition::document_purchase_transition::v0::v0_methods::DocumentPurchaseTransitionV0Methods; use dpp::state_transition::batch_transition::batched_transition::document_transfer_transition::v0::v0_methods::DocumentTransferTransitionV0Methods; use dpp::state_transition::batch_transition::batched_transition::document_update_price_transition::v0::v0_methods::DocumentUpdatePriceTransitionV0Methods; +use dpp::state_transition::batch_transition::document_base_transition::v0::v0_methods::DocumentBaseTransitionV0Methods; use crate::{ buffer::Buffer, identifier::{identifier_from_js_value, IdentifierWrapper}, @@ -89,9 +89,7 @@ impl DocumentTransitionWasm { #[wasm_bindgen(js_name=getIdentityContractNonce)] pub fn get_identity_contract_nonce(&self) -> JsValue { - match self.0.base() { - DocumentBaseTransition::V0(v0) => JsValue::from(v0.identity_contract_nonce), - } + JsValue::from(self.0.base().identity_contract_nonce()) } #[wasm_bindgen(js_name=getRevision)] diff --git a/packages/wasm-dpp/src/errors/consensus/consensus_error.rs b/packages/wasm-dpp/src/errors/consensus/consensus_error.rs index 90a642897b0..33d3d1b2d13 100644 --- a/packages/wasm-dpp/src/errors/consensus/consensus_error.rs +++ b/packages/wasm-dpp/src/errors/consensus/consensus_error.rs @@ -61,7 +61,7 @@ use dpp::consensus::state::data_trigger::DataTriggerError::{ DataTriggerConditionError, DataTriggerExecutionError, DataTriggerInvalidResultError, }; use wasm_bindgen::{JsError, JsValue}; -use dpp::consensus::basic::data_contract::{ContestedUniqueIndexOnMutableDocumentTypeError, ContestedUniqueIndexWithUniqueIndexError, DataContractTokenConfigurationUpdateError, GroupExceedsMaxMembersError, GroupMemberHasPowerOfZeroError, GroupMemberHasPowerOverLimitError, GroupNonUnilateralMemberPowerHasLessThanRequiredPowerError, GroupPositionDoesNotExistError, GroupTotalPowerLessThanRequiredError, InvalidDocumentTypeRequiredSecurityLevelError, InvalidTokenBaseSupplyError, InvalidTokenDistributionFunctionDivideByZeroError, InvalidTokenDistributionFunctionIncoherenceError, InvalidTokenDistributionFunctionInvalidParameterError, InvalidTokenDistributionFunctionInvalidParameterTupleError, NonContiguousContractGroupPositionsError, NonContiguousContractTokenPositionsError, UnknownDocumentCreationRestrictionModeError, UnknownSecurityLevelError, UnknownStorageKeyRequirementsError, UnknownTradeModeError, UnknownTransferableTypeError}; +use dpp::consensus::basic::data_contract::{ContestedUniqueIndexOnMutableDocumentTypeError, ContestedUniqueIndexWithUniqueIndexError, DataContractTokenConfigurationUpdateError, GroupExceedsMaxMembersError, GroupMemberHasPowerOfZeroError, GroupMemberHasPowerOverLimitError, GroupNonUnilateralMemberPowerHasLessThanRequiredPowerError, GroupPositionDoesNotExistError, GroupTotalPowerLessThanRequiredError, InvalidDocumentTypeRequiredSecurityLevelError, InvalidTokenBaseSupplyError, InvalidTokenDistributionFunctionDivideByZeroError, InvalidTokenDistributionFunctionIncoherenceError, InvalidTokenDistributionFunctionInvalidParameterError, InvalidTokenDistributionFunctionInvalidParameterTupleError, NonContiguousContractGroupPositionsError, NonContiguousContractTokenPositionsError, TokenPaymentByBurningOnlyAllowedOnInternalTokenError, UnknownDocumentActionTokenEffectError, UnknownDocumentCreationRestrictionModeError, UnknownGasFeesPaidByError, UnknownSecurityLevelError, UnknownStorageKeyRequirementsError, UnknownTradeModeError, UnknownTransferableTypeError}; use dpp::consensus::basic::document::{ContestedDocumentsTemporarilyNotAllowedError, DocumentCreationNotAllowedError, DocumentFieldMaxSizeExceededError, MaxDocumentsTransitionsExceededError, MissingPositionsInDocumentTypePropertiesError}; use dpp::consensus::basic::group::GroupActionNotAllowedOnTransitionError; use dpp::consensus::basic::identity::{DataContractBoundsNotPresentError, DisablingKeyIdAlsoBeingAddedInSameTransitionError, InvalidIdentityCreditWithdrawalTransitionAmountError, InvalidIdentityUpdateTransitionDisableKeysError, InvalidIdentityUpdateTransitionEmptyError, TooManyMasterPublicKeyError, WithdrawalOutputScriptNotAllowedWhenSigningWithOwnerKeyError}; @@ -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, TokenIsPausedError, IdentityTokenAccountAlreadyFrozenError, UnauthorizedTokenActionError, TokenSettingMaxSupplyToLessThanCurrentSupplyError, TokenMintPastMaxSupplyError, NewTokensDestinationIdentityDoesNotExistError, NewAuthorizedActionTakerIdentityDoesNotExistError, NewAuthorizedActionTakerGroupDoesNotExistError, NewAuthorizedActionTakerMainGroupNotSetError, InvalidGroupPositionError, TokenAlreadyPausedError, TokenNotPausedError, InvalidTokenClaimPropertyMismatch, InvalidTokenClaimNoCurrentRewards, InvalidTokenClaimWrongClaimant, TokenTransferRecipientIdentityNotExistError, PreProgrammedDistributionTimestampInPastError}; +use dpp::consensus::state::token::{IdentityDoesNotHaveEnoughTokenBalanceError, IdentityTokenAccountNotFrozenError, IdentityTokenAccountFrozenError, TokenIsPausedError, IdentityTokenAccountAlreadyFrozenError, UnauthorizedTokenActionError, TokenSettingMaxSupplyToLessThanCurrentSupplyError, TokenMintPastMaxSupplyError, NewTokensDestinationIdentityDoesNotExistError, NewAuthorizedActionTakerIdentityDoesNotExistError, NewAuthorizedActionTakerGroupDoesNotExistError, NewAuthorizedActionTakerMainGroupNotSetError, InvalidGroupPositionError, TokenAlreadyPausedError, TokenNotPausedError, InvalidTokenClaimPropertyMismatch, InvalidTokenClaimNoCurrentRewards, InvalidTokenClaimWrongClaimant, TokenTransferRecipientIdentityNotExistError, PreProgrammedDistributionTimestampInPastError, IdentityHasNotAgreedToPayRequiredTokenAmountError, RequiredTokenPaymentInfoNotSetError, IdentityTryingToPayWithWrongTokenError}; 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; @@ -390,6 +390,15 @@ pub fn from_state_error(state_error: &StateError) -> JsValue { StateError::PreProgrammedDistributionTimestampInPastError(e) => { generic_consensus_error!(PreProgrammedDistributionTimestampInPastError, e).into() } + StateError::IdentityHasNotAgreedToPayRequiredTokenAmountError(e) => { + generic_consensus_error!(IdentityHasNotAgreedToPayRequiredTokenAmountError, e).into() + } + StateError::RequiredTokenPaymentInfoNotSetError(e) => { + generic_consensus_error!(RequiredTokenPaymentInfoNotSetError, e).into() + } + StateError::IdentityTryingToPayWithWrongTokenError(e) => { + generic_consensus_error!(IdentityTryingToPayWithWrongTokenError, e).into() + } } } @@ -743,6 +752,15 @@ fn from_basic_error(basic_error: &BasicError) -> JsValue { BasicError::MissingDefaultLocalizationError(e) => { generic_consensus_error!(MissingDefaultLocalizationError, e).into() } + BasicError::UnknownGasFeesPaidByError(e) => { + generic_consensus_error!(UnknownGasFeesPaidByError, e).into() + } + BasicError::UnknownDocumentActionTokenEffectError(e) => { + generic_consensus_error!(UnknownDocumentActionTokenEffectError, e).into() + } + BasicError::TokenPaymentByBurningOnlyAllowedOnInternalTokenError(e) => { + generic_consensus_error!(TokenPaymentByBurningOnlyAllowedOnInternalTokenError, e).into() + } } }