1mod address_funds;
2mod contract_group_queries;
3mod contract_moderation_queries;
4mod data_contract_based_queries;
5mod document_history;
6mod document_query;
7mod group_queries;
8mod identity_based_queries;
9mod prefunded_specialized_balances;
10mod proofs;
11mod response_metadata;
12mod service;
13mod shielded;
14mod system;
15mod token_queries;
16mod validator_queries;
17mod voting;
18
19use crate::error::query::QueryError;
20
21use dpp::validation::ValidationResult;
22
23pub use service::QueryService;
24
25pub type QueryValidationResult<TData> = ValidationResult<TData, QueryError>;
27
28#[cfg(test)]
29pub(crate) mod tests {
30 use crate::error::query::QueryError;
31 use crate::error::Error;
32 use crate::platform_types::platform::Platform;
33 use crate::platform_types::platform_state::PlatformState;
34 use crate::platform_types::platform_state::PlatformStateV0Methods;
35 use crate::query::service::query_result_into_response;
36 use crate::query::QueryValidationResult;
37 use crate::rpc::core::MockCoreRPCLike;
38 use crate::test::helpers::setup::{TempPlatform, TestPlatformBuilder};
39 use dapi_grpc::tonic::{Code, Status};
40 use dpp::block::block_info::BlockInfo;
41 use dpp::data_contract::{DataContract, TokenConfiguration};
42 use drive::config::DEFAULT_QUERY_LIMIT;
43 use drive_proof_verifier::{ContextProvider, ContextProviderError};
44
45 use crate::config::PlatformConfig;
46 use dpp::dashcore::Network;
47 use dpp::data_contract::accessors::v0::{DataContractV0Getters, DataContractV0Setters};
48 use dpp::data_contract::config::moderation::{
49 ContractDocumentRemoval, ContractModerationConfig, ContractModerationReason,
50 ContractModerators,
51 };
52 use dpp::data_contract::document_type::DocumentTypeRef;
53 use dpp::data_contract::schema::DataContractSchemaMethodsV0;
54 use dpp::document::Document;
55 use dpp::identifier::Identifier;
56 use dpp::platform_value::Value;
57 use dpp::prelude::{CoreBlockHeight, TimestampMillis};
58 use drive::util::batch::DriveOperation::{
59 ContractModerationOperation, DataContractOperation, DocumentOperation,
60 };
61 use drive::util::batch::{
62 ContractModerationOperationType, DataContractOperationType, DocumentOperationType,
63 };
64 use drive::util::object_size_info::{
65 DataContractInfo, DocumentInfo, DocumentTypeInfo, OwnedDocumentInfo,
66 };
67 use drive::util::storage_flags::StorageFlags;
68 use platform_version::version::{PlatformVersion, ProtocolVersion};
69 use std::borrow::Cow;
70 use std::collections::BTreeMap;
71 use std::sync::Arc;
72
73 pub fn setup_platform<'a>(
74 with_genesis_state: Option<(TimestampMillis, CoreBlockHeight)>,
75 network: Network,
76 initial_protocol_version: Option<ProtocolVersion>,
77 ) -> (
78 TempPlatform<MockCoreRPCLike>,
79 Arc<PlatformState>,
80 &'a PlatformVersion,
81 ) {
82 setup_platform_with_config(
83 with_genesis_state,
84 PlatformConfig::default_for_network(network),
85 initial_protocol_version,
86 )
87 }
88
89 pub fn setup_platform_with_default_query_limit<'a>(
92 with_genesis_state: Option<(TimestampMillis, CoreBlockHeight)>,
93 default_query_limit: u16,
94 ) -> (
95 TempPlatform<MockCoreRPCLike>,
96 Arc<PlatformState>,
97 &'a PlatformVersion,
98 ) {
99 let mut config = PlatformConfig::default_for_network(Network::Testnet);
100 config.drive.default_query_limit = default_query_limit;
101 setup_platform_with_config(with_genesis_state, config, None)
102 }
103
104 fn setup_platform_with_config<'a>(
105 with_genesis_state: Option<(TimestampMillis, CoreBlockHeight)>,
106 config: PlatformConfig,
107 initial_protocol_version: Option<ProtocolVersion>,
108 ) -> (
109 TempPlatform<MockCoreRPCLike>,
110 Arc<PlatformState>,
111 &'a PlatformVersion,
112 ) {
113 let mut platform_builder = TestPlatformBuilder::new().with_config(config);
114
115 if let Some(initial_protocol_version) = initial_protocol_version {
116 platform_builder =
117 platform_builder.with_initial_protocol_version(initial_protocol_version);
118 }
119
120 let platform = platform_builder.build_with_mock_rpc();
121 let platform = if let Some((timestamp, activation_core_block_height)) = with_genesis_state {
122 platform.set_genesis_state_with_activation_info(timestamp, activation_core_block_height)
123 } else {
124 platform.set_initial_state_structure()
125 };
126
127 let platform_state = platform.platform.state.load_full();
130
131 let platform_version = platform_state.current_platform_version().unwrap();
132
133 (platform, platform_state, platform_version)
134 }
135
136 pub fn store_data_contract(
137 platform: &Platform<MockCoreRPCLike>,
138 data_contract: &DataContract,
139 platform_version: &PlatformVersion,
140 ) {
141 let operation = DataContractOperation(DataContractOperationType::ApplyContract {
142 contract: Cow::Owned(data_contract.to_owned()),
143 storage_flags: None,
144 });
145
146 let block_info = BlockInfo::genesis();
147
148 platform
149 .drive
150 .apply_drive_operations(
151 vec![operation],
152 true,
153 &block_info,
154 None,
155 platform_version,
156 None,
157 )
158 .expect("expected to apply drive operations");
159 }
160
161 pub fn with_moderated_posts(
166 mut contract: DataContract,
167 platform_version: &PlatformVersion,
168 ) -> DataContract {
169 contract.set_config(contract.config().clone().with_moderation(Some(
170 ContractModerationConfig {
171 banlist: false,
172 suspensions: false,
173 warnings: false,
174 moderators: ContractModerators::ContractOwner,
175 },
176 )));
177 let mut schemas = BTreeMap::new();
178 for (name, schema) in contract.document_schemas() {
179 let mut json: serde_json::Value = schema.clone().try_into().expect("a JSON schema");
180 if name == "post" {
181 json["canBeDeleted"] = false.into();
182 json["moderatorAbilities"] = serde_json::json!({ "delete": true });
183 }
184 if let Some(properties) = json
185 .get_mut("properties")
186 .and_then(|properties| properties.as_object_mut())
187 {
188 for property in properties.values_mut() {
189 if property["refersTo"]["documentType"] == "post" {
190 property["refersTo"]["type"] = "moderatedDocument".into();
191 }
192 }
193 }
194 if let Some(indices) = json
195 .get_mut("indices")
196 .and_then(|indices| indices.as_array_mut())
197 {
198 for index in indices {
199 if let Some(index) = index.as_object_mut() {
200 index.remove("preallocated");
201 }
202 }
203 }
204 schemas.insert(name, Value::from(json));
205 }
206 let defs = contract.schema_defs().cloned();
207 contract
208 .set_document_schemas(schemas, defs, true, &mut vec![], platform_version)
209 .expect("expected the moderated variant to parse");
210 contract
211 }
212
213 pub fn removal_of(id: [u8; 32], owner: [u8; 32]) -> ContractDocumentRemoval {
215 ContractDocumentRemoval {
216 document_owner_id: Identifier::from(owner),
217 moderator_id: Identifier::from([0x77; 32]),
218 reason: ContractModerationReason::from_text("spam"),
219 removed_at: 1_000 + id[0] as u64,
220 document_hash: id,
221 restoration: None,
222 kept_fields: Default::default(),
223 }
224 }
225
226 pub fn remove_post_by_moderator(
229 platform: &Platform<MockCoreRPCLike>,
230 data_contract: &DataContract,
231 id: [u8; 32],
232 removal: ContractDocumentRemoval,
233 platform_version: &PlatformVersion,
234 ) {
235 let moderator_id = removal.moderator_id;
236 let operations = vec![
237 DocumentOperation(DocumentOperationType::ForceDeleteDocument {
238 document_id: Identifier::from(id),
239 contract_info: DataContractInfo::BorrowedDataContract(data_contract),
240 document_type_info: DocumentTypeInfo::DocumentTypeName("post".to_string()),
241 }),
242 ContractModerationOperation(ContractModerationOperationType::AddDocumentRemoval {
243 contract_id: data_contract.id(),
244 document_type_name: "post".to_string(),
245 document_id: Identifier::from(id),
246 removal: Box::new(removal),
247 replaced_record_size: None,
248 estimated_kept_fields_size: 0,
249 moderator_id,
250 }),
251 ContractModerationOperation(ContractModerationOperationType::ForfeitStorageRefunds),
252 ];
253 platform
254 .drive
255 .apply_drive_operations(
256 operations,
257 true,
258 &BlockInfo::genesis(),
259 None,
260 platform_version,
261 None,
262 )
263 .expect("expected to remove the post");
264 }
265
266 pub fn store_document(
267 platform: &Platform<MockCoreRPCLike>,
268 data_contract: &DataContract,
269 document_type: DocumentTypeRef,
270 document: &Document,
271 platform_version: &PlatformVersion,
272 ) {
273 let storage_flags = Some(Cow::Owned(StorageFlags::SingleEpoch(0)));
274
275 let operation = DocumentOperation(DocumentOperationType::AddDocument {
276 owned_document_info: OwnedDocumentInfo {
277 document_info: DocumentInfo::DocumentRefInfo((document, storage_flags)),
278 owner_id: None,
279 },
280 contract_info: DataContractInfo::BorrowedDataContract(data_contract),
281 document_type_info: DocumentTypeInfo::DocumentTypeRef(document_type),
282 override_document: false,
283 });
284
285 let block_info = BlockInfo::genesis();
286
287 platform
288 .drive
289 .apply_drive_operations(
290 vec![operation],
291 true,
292 &block_info,
293 None,
294 platform_version,
295 None,
296 )
297 .expect("expected to apply drive operations");
298 }
299
300 pub fn assert_invalid_argument_status<TData: Clone>(
303 result: Result<QueryValidationResult<TData>, Error>,
304 ) -> Status {
305 let status = query_result_into_response(result)
306 .err()
307 .expect("expected the request to be refused");
308 assert_eq!(status.code(), Code::InvalidArgument, "{}", status.message());
309 status
310 }
311
312 pub fn assert_invalid_identifier<TData: Clone>(
313 validation_result: QueryValidationResult<TData>,
314 ) {
315 assert!(matches!(
316 validation_result.errors.as_slice(),
317 [QueryError::InvalidArgument(msg)] if msg.contains("id must be a valid identifier (32 bytes long)")
318 ));
319 }
320
321 pub struct NoQuorumKeysContextProvider;
325
326 impl ContextProvider for NoQuorumKeysContextProvider {
327 fn get_data_contract(
328 &self,
329 _id: &Identifier,
330 _platform_version: &PlatformVersion,
331 ) -> Result<Option<Arc<DataContract>>, ContextProviderError> {
332 Ok(None)
333 }
334
335 fn get_token_configuration(
336 &self,
337 _token_id: &Identifier,
338 ) -> Result<Option<TokenConfiguration>, ContextProviderError> {
339 Ok(None)
340 }
341
342 fn get_quorum_public_key(
343 &self,
344 _quorum_type: u32,
345 _quorum_hash: [u8; 32],
346 _core_chain_locked_height: u32,
347 ) -> Result<[u8; 48], ContextProviderError> {
348 Err(ContextProviderError::Config(
349 "no quorum keys in this test".to_string(),
350 ))
351 }
352
353 fn get_platform_activation_height(&self) -> Result<CoreBlockHeight, ContextProviderError> {
354 Ok(1)
355 }
356 }
357
358 pub const NO_LIMIT_PROOF_CASES: [(u16, u16); 2] = [
362 (DEFAULT_QUERY_LIMIT, DEFAULT_QUERY_LIMIT + 1),
363 (
364 2 * DEFAULT_QUERY_LIMIT,
365 DEFAULT_QUERY_LIMIT + DEFAULT_QUERY_LIMIT / 2,
366 ),
367 ];
368
369 pub fn assert_drive_part_of_proof_verified(error: drive_proof_verifier::Error) {
372 assert!(
373 matches!(
374 error,
375 drive_proof_verifier::Error::QuorumKeyUnavailable { .. }
376 ),
377 "expected the Drive part of the proof to verify and the signature check to stop at \
378 the quorum key, got {error:?}"
379 );
380 }
381
382 #[allow(clippy::type_complexity)]
392 pub fn setup_platform_with_token_state<'a>() -> (
393 TempPlatform<MockCoreRPCLike>,
394 Arc<PlatformState>,
395 &'a PlatformVersion,
396 [u8; 32],
397 [[u8; 32]; 3],
398 [[u8; 32]; 3],
399 ) {
400 use dpp::data_contract::associated_token::token_configuration::v0::TokenConfigurationV0;
401 use dpp::data_contract::associated_token::token_configuration_convention::v0::TokenConfigurationConventionV0;
402 use dpp::data_contract::associated_token::token_distribution_rules::v0::TokenDistributionRulesV0;
403 use dpp::data_contract::associated_token::token_distribution_rules::TokenDistributionRules;
404 use dpp::data_contract::associated_token::token_keeps_history_rules::v0::TokenKeepsHistoryRulesV0;
405 use dpp::data_contract::associated_token::token_marketplace_rules::v0::TokenMarketplaceRulesV0;
406 use dpp::data_contract::associated_token::token_perpetual_distribution::distribution_function::DistributionFunction;
407 use dpp::data_contract::associated_token::token_perpetual_distribution::distribution_recipient::TokenDistributionRecipient;
408 use dpp::data_contract::associated_token::token_perpetual_distribution::reward_distribution_type::RewardDistributionType;
409 use dpp::data_contract::associated_token::token_perpetual_distribution::v0::TokenPerpetualDistributionV0;
410 use dpp::data_contract::associated_token::token_perpetual_distribution::TokenPerpetualDistribution;
411 use dpp::data_contract::associated_token::token_pre_programmed_distribution::v0::TokenPreProgrammedDistributionV0;
412 use dpp::data_contract::associated_token::token_pre_programmed_distribution::TokenPreProgrammedDistribution;
413 use dpp::data_contract::change_control_rules::authorized_action_takers::AuthorizedActionTakers;
414 use dpp::data_contract::change_control_rules::v0::ChangeControlRulesV0;
415 use dpp::data_contract::config::DataContractConfig;
416 use dpp::data_contract::group::v0::GroupV0;
417 use dpp::data_contract::group::Group;
418 use dpp::data_contract::v1::DataContractV1;
419 use dpp::data_contract::{TokenConfiguration, INITIAL_DATA_CONTRACT_VERSION};
420 use dpp::identifier::Identifier;
421 use dpp::identity::accessors::IdentitySettersV0;
422 use dpp::identity::Identity;
423 use dpp::prelude::IdentityPublicKey;
424 use dpp::tokens::calculate_token_id;
425 use dpp::tokens::status::v0::TokenStatusV0;
426 use dpp::tokens::status::TokenStatus;
427 use dpp::tokens::token_pricing_schedule::TokenPricingSchedule;
428 use rand::rngs::StdRng;
429 use rand::SeedableRng;
430 use std::collections::BTreeMap;
431 use dpp::identity::identity_public_key::accessors::v0::IdentityPublicKeyGettersV0;
432
433 let (platform, state, version) = setup_platform(Some((1, 1)), Network::Testnet, None);
434
435 let identity_id_1 = [1u8; 32];
436 let identity_id_2 = [2u8; 32];
437 let identity_id_3 = [3u8; 32];
438 let contract_id = [3u8; 32];
439
440 let token_id_0 = calculate_token_id(&contract_id, 0);
441 let token_id_1 = calculate_token_id(&contract_id, 1);
442 let token_id_2 = calculate_token_id(&contract_id, 2);
443
444 let credits_per_identity: u64 = 10_000_000_000_000;
446 let total_credits = credits_per_identity * 3;
447 platform
448 .platform
449 .drive
450 .add_to_system_credits(total_credits, None, version)
451 .expect("expected to add system credits");
452
453 let mut rng = StdRng::seed_from_u64(0u64);
454 let non_unique_key = IdentityPublicKey::random_voting_key_with_rng(11, &mut rng, version)
455 .expect("expected to create voting key");
456
457 for id_bytes in [identity_id_1, identity_id_2, identity_id_3] {
458 let id = Identifier::new(id_bytes);
459 let mut identity =
460 Identity::create_basic_identity(id, version).expect("expected to create identity");
461 identity.set_balance(credits_per_identity);
462
463 let seed = id_bytes[0];
464 let mut rng = StdRng::seed_from_u64(seed as u64);
465 let mut keys =
466 IdentityPublicKey::main_keys_with_random_authentication_keys_with_private_keys_with_rng(
467 3, &mut rng, version,
468 )
469 .expect("expected to create keys");
470
471 let transfer_key =
472 IdentityPublicKey::random_masternode_transfer_key_with_rng(3, &mut rng, version)
473 .expect("expected to create transfer key");
474 keys.push(transfer_key);
475 keys.push(non_unique_key.clone());
476
477 identity.set_public_keys(keys.into_iter().map(|(key, _)| (key.id(), key)).collect());
478
479 platform
480 .platform
481 .drive
482 .add_new_identity(identity, false, &BlockInfo::genesis(), true, None, version)
483 .expect("expected to add identity");
484 }
485
486 let groups = [
488 (
489 0,
490 Group::V0(GroupV0 {
491 members: [
492 (Identifier::new(identity_id_1), 1),
493 (Identifier::new(identity_id_2), 1),
494 ]
495 .into(),
496 required_power: 1,
497 }),
498 ),
499 (
500 1,
501 Group::V0(GroupV0 {
502 members: [
503 (Identifier::new(identity_id_1), 1),
504 (Identifier::new(identity_id_2), 1),
505 (Identifier::new(identity_id_3), 1),
506 ]
507 .into(),
508 required_power: 3,
509 }),
510 ),
511 (
512 2,
513 Group::V0(GroupV0 {
514 members: [
515 (Identifier::new(identity_id_1), 1),
516 (Identifier::new(identity_id_3), 1),
517 ]
518 .into(),
519 required_power: 1,
520 }),
521 ),
522 ]
523 .into();
524
525 let token_configuration = TokenConfiguration::V0(TokenConfigurationV0 {
526 conventions: TokenConfigurationConventionV0 {
527 localizations: Default::default(),
528 decimals: 8,
529 }
530 .into(),
531 conventions_change_rules: ChangeControlRulesV0::default().into(),
532 base_supply: 100000,
533 max_supply: None,
534 keeps_history: TokenKeepsHistoryRulesV0::default().into(),
535 start_as_paused: false,
536 allow_transfer_to_frozen_balance: true,
537 max_supply_change_rules: ChangeControlRulesV0 {
538 authorized_to_make_change: AuthorizedActionTakers::ContractOwner,
539 admin_action_takers: Default::default(),
540 changing_authorized_action_takers_to_no_one_allowed: false,
541 changing_admin_action_takers_to_no_one_allowed: false,
542 self_changing_admin_action_takers_allowed: false,
543 }
544 .into(),
545 distribution_rules: TokenDistributionRulesV0 {
546 perpetual_distribution: Some(TokenPerpetualDistribution::V0(
547 TokenPerpetualDistributionV0 {
548 distribution_type: RewardDistributionType::BlockBasedDistribution {
549 interval: 10,
550 function: DistributionFunction::FixedAmount { amount: 100 },
551 },
552 distribution_recipient: TokenDistributionRecipient::ContractOwner,
553 },
554 )),
555 perpetual_distribution_rules: ChangeControlRulesV0::default().into(),
556 pre_programmed_distribution: None,
557 new_tokens_destination_identity: None,
558 new_tokens_destination_identity_rules: ChangeControlRulesV0::default().into(),
559 minting_allow_choosing_destination: true,
560 minting_allow_choosing_destination_rules: ChangeControlRulesV0::default().into(),
561 change_direct_purchase_pricing_rules: ChangeControlRulesV0 {
562 authorized_to_make_change: AuthorizedActionTakers::ContractOwner,
563 admin_action_takers: Default::default(),
564 changing_authorized_action_takers_to_no_one_allowed: false,
565 changing_admin_action_takers_to_no_one_allowed: false,
566 self_changing_admin_action_takers_allowed: false,
567 }
568 .into(),
569 }
570 .into(),
571 marketplace_rules: TokenMarketplaceRulesV0 {
572 trade_mode: Default::default(),
573 trade_mode_change_rules: ChangeControlRulesV0::default().into(),
574 }
575 .into(),
576 manual_minting_rules: ChangeControlRulesV0 {
577 authorized_to_make_change: AuthorizedActionTakers::Group(0),
578 admin_action_takers: Default::default(),
579 changing_authorized_action_takers_to_no_one_allowed: false,
580 changing_admin_action_takers_to_no_one_allowed: false,
581 self_changing_admin_action_takers_allowed: false,
582 }
583 .into(),
584 manual_burning_rules: ChangeControlRulesV0 {
585 authorized_to_make_change: AuthorizedActionTakers::Group(2),
586 admin_action_takers: Default::default(),
587 changing_authorized_action_takers_to_no_one_allowed: false,
588 changing_admin_action_takers_to_no_one_allowed: false,
589 self_changing_admin_action_takers_allowed: false,
590 }
591 .into(),
592 freeze_rules: ChangeControlRulesV0 {
593 authorized_to_make_change: AuthorizedActionTakers::ContractOwner,
594 admin_action_takers: Default::default(),
595 changing_authorized_action_takers_to_no_one_allowed: false,
596 changing_admin_action_takers_to_no_one_allowed: false,
597 self_changing_admin_action_takers_allowed: false,
598 }
599 .into(),
600 unfreeze_rules: ChangeControlRulesV0 {
601 authorized_to_make_change: AuthorizedActionTakers::ContractOwner,
602 admin_action_takers: Default::default(),
603 changing_authorized_action_takers_to_no_one_allowed: false,
604 changing_admin_action_takers_to_no_one_allowed: false,
605 self_changing_admin_action_takers_allowed: false,
606 }
607 .into(),
608 destroy_frozen_funds_rules: ChangeControlRulesV0 {
609 authorized_to_make_change: AuthorizedActionTakers::ContractOwner,
610 admin_action_takers: Default::default(),
611 changing_authorized_action_takers_to_no_one_allowed: false,
612 changing_admin_action_takers_to_no_one_allowed: false,
613 self_changing_admin_action_takers_allowed: false,
614 }
615 .into(),
616 emergency_action_rules: ChangeControlRulesV0 {
617 authorized_to_make_change: AuthorizedActionTakers::ContractOwner,
618 admin_action_takers: Default::default(),
619 changing_authorized_action_takers_to_no_one_allowed: false,
620 changing_admin_action_takers_to_no_one_allowed: false,
621 self_changing_admin_action_takers_allowed: false,
622 }
623 .into(),
624 main_control_group: None,
625 main_control_group_can_be_modified: Default::default(),
626 description: Some("Some token description".to_string()),
627 });
628
629 let mut token_configuration_2 = token_configuration.clone();
631 if let TokenConfiguration::V0(ref mut cfg) = token_configuration_2 {
632 if let TokenDistributionRules::V0(ref mut rules) = cfg.distribution_rules {
633 rules.pre_programmed_distribution = Some(TokenPreProgrammedDistribution::V0(
634 TokenPreProgrammedDistributionV0 {
635 distributions: BTreeMap::from([
636 (
637 1000,
638 BTreeMap::from([
639 (Identifier::new(identity_id_1), 500),
640 (Identifier::new(identity_id_2), 300),
641 ]),
642 ),
643 (
644 5000,
645 BTreeMap::from([(Identifier::new(identity_id_1), 1000)]),
646 ),
647 (
648 10000,
649 BTreeMap::from([
650 (Identifier::new(identity_id_2), 750),
651 (Identifier::new(identity_id_3), 250),
652 ]),
653 ),
654 ]),
655 },
656 ));
657 }
658 }
659
660 let tokens = [
661 (0, token_configuration.clone()),
662 (1, token_configuration),
663 (2, token_configuration_2),
664 ]
665 .into();
666
667 let data_contract = DataContract::V1(DataContractV1 {
668 id: Identifier::new(contract_id),
669 config: DataContractConfig::default_for_version(version)
670 .expect("expected contract config"),
671 version: INITIAL_DATA_CONTRACT_VERSION,
672 owner_id: Identifier::new(identity_id_1),
673 document_types: Default::default(),
674 schema_defs: Default::default(),
675 created_at: None,
676 updated_at: None,
677 created_at_block_height: None,
678 updated_at_block_height: None,
679 created_at_epoch: None,
680 updated_at_epoch: None,
681 groups,
682 tokens,
683 keywords: vec!["cat".into(), "white".into()],
684 description: Some("Some contract description".to_string()),
685 });
686
687 let block_info = BlockInfo::genesis();
688
689 platform
690 .platform
691 .drive
692 .apply_contract(&data_contract, block_info, true, None, None, version)
693 .expect("expected to apply contract");
694
695 for (token_id, id, amount) in [
700 (token_id_0, identity_id_1, 100u64),
701 (token_id_0, identity_id_2, 100),
702 (token_id_1, identity_id_1, 200),
703 (token_id_1, identity_id_3, 100),
704 (token_id_2, identity_id_1, 300),
705 (token_id_2, identity_id_2, 200),
706 ] {
707 platform
708 .platform
709 .drive
710 .token_mint(
711 token_id,
712 id,
713 amount,
714 false,
715 false,
716 &block_info,
717 true,
718 None,
719 version,
720 )
721 .expect("expected to mint tokens");
722 }
723
724 platform
726 .platform
727 .drive
728 .token_freeze(
729 Identifier::new(token_id_0),
730 Identifier::new(identity_id_2),
731 &block_info,
732 true,
733 None,
734 version,
735 )
736 .expect("expected to freeze");
737
738 let status = TokenStatus::V0(TokenStatusV0 { paused: true });
740 platform
741 .platform
742 .drive
743 .token_apply_status(token_id_1, status, &block_info, true, None, version)
744 .expect("expected to apply status");
745
746 platform
748 .platform
749 .drive
750 .token_set_direct_purchase_price(
751 token_id_1,
752 Some(TokenPricingSchedule::SinglePrice(25)),
753 &block_info,
754 true,
755 None,
756 version,
757 )
758 .expect("expected to set direct purchase price");
759
760 let pricing = TokenPricingSchedule::SetPrices(
761 (0..=900)
762 .step_by(100)
763 .map(|amount| (amount, 1000 - amount))
764 .collect(),
765 );
766 platform
767 .platform
768 .drive
769 .token_set_direct_purchase_price(
770 token_id_2,
771 Some(pricing),
772 &block_info,
773 true,
774 None,
775 version,
776 )
777 .expect("expected to set direct purchase price");
778
779 (
780 platform,
781 state,
782 version,
783 contract_id,
784 [token_id_0, token_id_1, token_id_2],
785 [identity_id_1, identity_id_2, identity_id_3],
786 )
787 }
788}