git.delta.rocks / unique-network / refs/commits / 8eb82cd98ff6

difftreelog

Merge branch 'develop' into feature/NFTPAR-93

sotmorskiy2020-10-05parents: #4fc8a38 #ab1a681.patch.diff
in: master
# Conflicts:
#	tests/package-lock.json
#	tests/package.json

11 files changed

modifiedREADME.mddiffbeforeafterboth
142 "enable_println": "bool",142 "enable_println": "bool",
143 "max_subject_len": "u32"143 "max_subject_len": "u32"
144 },144 },
145 "AccessMode": {
146 "_enum": [
147 "Normal",
148 "WhiteList"
149 ]
150 },
145 "CollectionMode": {151 "CollectionMode": {
146 "_enum": {152 "_enum": {
147 "Invalid": null,153 "Invalid": null,
181 "CollectionType": {187 "CollectionType": {
182 "Owner": "AccountId",188 "Owner": "AccountId",
183 "Mode": "CollectionMode",189 "Mode": "CollectionMode",
184 "Access": "u8",190 "Access": "AccessMode",
185 "DecimalPoints": "u32",191 "DecimalPoints": "u32",
186 "Name": "Vec<u16>",192 "Name": "Vec<u16>",
187 "Description": "Vec<u16>",193 "Description": "Vec<u16>",
188 "TokenPrefix": "Vec<u8>",194 "TokenPrefix": "Vec<u8>",
189 "CustomDataSize": "u32",195 "CustomDataSize": "u32",
196 "MintMode": "bool",
190 "OffchainSchema": "Vec<u8>",197 "OffchainSchema": "Vec<u8>",
191 "Sponsor": "AccountId",198 "Sponsor": "AccountId",
192 "UnconfirmedSponsor": "AccountId"199 "UnconfirmedSponsor": "AccountId"
193 },200 },
201 "ApprovePermissions": {
202 "Approved": "AccountId",
203 "Amount": "u64"
204 },
194 "RawData": "Vec<u8>",205 "RawData": "Vec<u8>",
195 "Address": "AccountId",206 "Address": "AccountId",
196 "LookupSource": "AccountId",207 "LookupSource": "AccountId",
197 "Weight": "u64"208 "Weight": "u64"
198}209}
210
199```211```
modifiednode/src/chain_spec.rsdiffbeforeafterboth
1// use nft_runtime::{
2// AccountId, AuraConfig, BalancesConfig, GenesisConfig, GrandpaConfig, Signature, SudoConfig,
3// SystemConfig, WASM_BINARY,
4// };
5// use nft_runtime::{ContractsConfig, ContractsSchedule, NftConfig, CollectionType};
1use nft_runtime::{6use nft_runtime::*;
2 AccountId, AuraConfig, BalancesConfig, GenesisConfig, GrandpaConfig, Signature, SudoConfig,
3 SystemConfig, WASM_BINARY,
4};
5use nft_runtime::{ContractsConfig, ContractsSchedule};
6use sc_service::ChainType;7use sc_service::ChainType;
7use sp_consensus_aura::sr25519::AuthorityId as AuraId;8use sp_consensus_aura::sr25519::AuthorityId as AuraId;
8use sp_core::{sr25519, Pair, Public};9use sp_core::{sr25519, Pair, Public};
128 .collect(),129 .collect(),
129 }),130 }),
130 sudo: Some(SudoConfig { key: root_key }),131 sudo: Some(SudoConfig { key: root_key }),
132 nft: Some(NftConfig {
133 collection: vec![(1, CollectionType {
134 owner: get_account_id_from_seed::<sr25519::Public>("Alice"),
135 mode: CollectionMode::NFT(50),
136 access: AccessMode::Normal,
137 decimal_points: 0,
138 name: vec!(),
139 description: vec!(),
140 token_prefix: vec!(),
141 custom_data_size: 50,
142 mint_mode: false,
143 offchain_schema: vec!(),
144 sponsor: get_account_id_from_seed::<sr25519::Public>("Alice"),
145 unconfirmed_sponsor: get_account_id_from_seed::<sr25519::Public>("Alice"),
146 })],
147 nft_item_id: vec!(),
148 fungible_item_id: vec!(),
149 refungible_item_id: vec!(),
150 }),
131 contracts: Some(ContractsConfig {151 contracts: Some(ContractsConfig {
132 current_schedule: ContractsSchedule {152 current_schedule: ContractsSchedule {
133 enable_println,153 enable_println,
modifiedpallets/nft/src/lib.rsdiffbeforeafterboth
1#![cfg_attr(not(feature = "std"), no_std)]1#![cfg_attr(not(feature = "std"), no_std)]
22
3/// For more guidance on Substrate FRAME, see the example pallet3#[cfg(feature = "std")]
4/// https://github.com/paritytech/substrate/blob/master/frame/example/src/lib.rs4pub use serde::*;
5
5use codec::{Decode, Encode};6use codec::{Decode, Encode};
6pub use frame_support::{7pub use frame_support::{
32 },33 },
33 FixedPointOperand, FixedU128,34 FixedPointOperand, FixedU128,
34};35};
35use sp_std::prelude::*;
3636
37#[cfg(test)]37#[cfg(test)]
38mod mock;38mod mock;
3939
40#[cfg(test)]40#[cfg(test)]
41mod tests;41mod tests;
4242
43// Structs
43#[derive(Encode, Decode, Debug, Eq, Clone, PartialEq)]44// #region
45
46#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq)]
47#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
44pub enum CollectionMode {48pub enum CollectionMode {
45 Invalid,49 Invalid,
46 // custom data size50 // custom data size
62 }66 }
63}67}
6468
65#[derive(Encode, Decode, Debug, Clone, PartialEq)]69#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq)]
70#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
66pub enum AccessMode {71pub enum AccessMode {
67 Normal,72 Normal,
68 WhiteList,73 WhiteList,
79 }84 }
80}85}
8186
82#[derive(Encode, Decode, Default, Clone, PartialEq)]87#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]
83#[cfg_attr(feature = "std", derive(Debug))]88#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
84pub struct Ownership<AccountId> {89pub struct Ownership<AccountId> {
85 pub owner: AccountId,90 pub owner: AccountId,
86 pub fraction: u128,91 pub fraction: u128,
87}92}
8893
89#[derive(Encode, Decode, Default, Clone, PartialEq)]94#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]
90#[cfg_attr(feature = "std", derive(Debug))]95#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
91pub struct CollectionType<AccountId> {96pub struct CollectionType<AccountId> {
92 pub owner: AccountId,97 pub owner: AccountId,
93 pub mode: CollectionMode,98 pub mode: CollectionMode,
97 pub description: Vec<u16>, // 256 include null escape char102 pub description: Vec<u16>, // 256 include null escape char
98 pub token_prefix: Vec<u8>, // 16 include null escape char103 pub token_prefix: Vec<u8>, // 16 include null escape char
99 pub custom_data_size: u32,104 pub custom_data_size: u32,
105 pub mint_mode: bool,
100 pub offchain_schema: Vec<u8>,106 pub offchain_schema: Vec<u8>,
101 pub sponsor: AccountId, // Who pays fees. If set to default address, the fees are applied to the transaction sender107 pub sponsor: AccountId, // Who pays fees. If set to default address, the fees are applied to the transaction sender
102 pub unconfirmed_sponsor: AccountId, // Sponsor address that has not yet confirmed sponsorship108 pub unconfirmed_sponsor: AccountId, // Sponsor address that has not yet confirmed sponsorship
103}109}
104110
105#[derive(Encode, Decode, Default, Clone, PartialEq)]111#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]
106#[cfg_attr(feature = "std", derive(Debug))]112#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
107pub struct CollectionAdminsType<AccountId> {113pub struct CollectionAdminsType<AccountId> {
108 pub admin: AccountId,114 pub admin: AccountId,
109 pub collection_id: u64,115 pub collection_id: u64,
110}116}
111117
112#[derive(Encode, Decode, Default, Clone, PartialEq)]118#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]
113#[cfg_attr(feature = "std", derive(Debug))]119#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
114pub struct NftItemType<AccountId> {120pub struct NftItemType<AccountId> {
115 pub collection: u64,121 pub collection: u64,
116 pub owner: AccountId,122 pub owner: AccountId,
117 pub data: Vec<u8>,123 pub data: Vec<u8>,
118}124}
119125
120#[derive(Encode, Decode, Default, Clone, PartialEq)]126#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]
121#[cfg_attr(feature = "std", derive(Debug))]127#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
122pub struct FungibleItemType<AccountId> {128pub struct FungibleItemType<AccountId> {
123 pub collection: u64,129 pub collection: u64,
124 pub owner: AccountId,130 pub owner: AccountId,
125 pub value: u128,131 pub value: u128,
126}132}
127133
128#[derive(Encode, Decode, Default, Clone, PartialEq)]134#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]
129#[cfg_attr(feature = "std", derive(Debug))]135#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
130pub struct ReFungibleItemType<AccountId> {136pub struct ReFungibleItemType<AccountId> {
131 pub collection: u64,137 pub collection: u64,
132 pub owner: Vec<Ownership<AccountId>>,138 pub owner: Vec<Ownership<AccountId>>,
133 pub data: Vec<u8>,139 pub data: Vec<u8>,
134}140}
135141
136#[derive(Encode, Decode, Default, Clone, PartialEq)]142#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]
137#[cfg_attr(feature = "std", derive(Debug))]143#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
138pub struct ApprovePermissions<AccountId> {144pub struct ApprovePermissions<AccountId> {
139 pub approved: AccountId,145 pub approved: AccountId,
140 pub amount: u64,146 pub amount: u64,
141}147}
142148
143#[derive(Encode, Decode, Default, Clone, PartialEq)]149#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]
144#[cfg_attr(feature = "std", derive(Debug))]150#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
145pub struct VestingItem<AccountId, Moment> {151pub struct VestingItem<AccountId, Moment> {
146 pub sender: AccountId,152 pub sender: AccountId,
147 pub recipient: AccountId,153 pub recipient: AccountId,
155 type Event: From<Event<Self>> + Into<<Self as system::Trait>::Event>;161 type Event: From<Event<Self>> + Into<<Self as system::Trait>::Event>;
156}162}
157163
164// #endregion
165
158decl_storage! {166decl_storage! {
159 trait Store for Module<T: Trait> as Nft {167 trait Store for Module<T: Trait> as Nft {
160168
164 ChainVersion: u64;172 ChainVersion: u64;
165 ItemListIndex: map hasher(blake2_128_concat) u64 => u64;173 ItemListIndex: map hasher(blake2_128_concat) u64 => u64;
166174
167 pub Collection get(fn collection): map hasher(identity) u64 => CollectionType<T::AccountId>;175 pub Collection get(fn collection) config(): map hasher(identity) u64 => CollectionType<T::AccountId>;
168 pub AdminList get(fn admin_list_collection): map hasher(identity) u64 => Vec<T::AccountId>;176 pub AdminList get(fn admin_list_collection): map hasher(identity) u64 => Vec<T::AccountId>;
169 pub WhiteList get(fn white_list): map hasher(identity) u64 => Vec<T::AccountId>;177 pub WhiteList get(fn white_list): map hasher(identity) u64 => Vec<T::AccountId>;
170178
175 pub ApprovedList get(fn approved): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) (u64, T::AccountId) => Vec<ApprovePermissions<T::AccountId>>;183 pub ApprovedList get(fn approved): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) (u64, T::AccountId) => Vec<ApprovePermissions<T::AccountId>>;
176184
177 /// Item collections185 /// Item collections
178 pub NftItemList get(fn nft_item_id): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => NftItemType<T::AccountId>;186 pub NftItemList get(fn nft_item_id) config(): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => NftItemType<T::AccountId>;
179 pub FungibleItemList get(fn fungible_item_id): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => FungibleItemType<T::AccountId>;187 pub FungibleItemList get(fn fungible_item_id) config(): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => FungibleItemType<T::AccountId>;
180 pub ReFungibleItemList get(fn refungible_item_id): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => ReFungibleItemType<T::AccountId>;188 pub ReFungibleItemList get(fn refungible_item_id) config(): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => ReFungibleItemType<T::AccountId>;
181189
182 // Active vesting list
183 // pub VestingList get(fn vesting): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => VestingItem<T::AccountId, T::Moment>;
184
185 /// Index list190 /// Index list
186 pub AddressTokens get(fn address_tokens): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) T::AccountId => Vec<u64>;191 pub AddressTokens get(fn address_tokens): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) T::AccountId => Vec<u64>;
187192
188 // Sponsorship193 // Sponsorship
189 pub ContractSponsor get(fn contract_sponsor): map hasher(identity) T::AccountId => T::AccountId;194 pub ContractSponsor get(fn contract_sponsor): map hasher(identity) T::AccountId => T::AccountId;
190 pub UnconfirmedContractSponsor get(fn unconfirmed_contract_sponsor): map hasher(identity) T::AccountId => T::AccountId;195 pub UnconfirmedContractSponsor get(fn unconfirmed_contract_sponsor): map hasher(identity) T::AccountId => T::AccountId;
191 }196 }
197 add_extra_genesis {
198 build(|config: &GenesisConfig<T>| {
199 // Modification of storage
200 for (_num, _c) in &config.collection {
201 <Module<T>>::init_collection(_c);
202 }
203
204 for (_num, _q, _i) in &config.nft_item_id {
205 <Module<T>>::init_nft_token(_i);
206 }
207
208 for (_num, _q, _i) in &config.fungible_item_id {
209 <Module<T>>::init_fungible_token(_i);
210 }
211
212 for (_num, _q, _i) in &config.refungible_item_id {
213 <Module<T>>::init_refungible_token(_i);
214 }
215 })
216 }
192}217}
193218
194decl_event!(219decl_event!(
209234
210 fn on_initialize(now: T::BlockNumber) -> Weight {235 fn on_initialize(now: T::BlockNumber) -> Weight {
211236
212 if ChainVersion::get() == 0237 if ChainVersion::get() < 2
213 {238 {
214 let value = NextCollectionID::get();239 let value = NextCollectionID::get();
215 CreatedCollectionCount::put(value);240 CreatedCollectionCount::put(value);
224 // @param customDataSz size of custom data in each collection item249 // @param customDataSz size of custom data in each collection item
225 // returns collection ID250 // returns collection ID
226 #[weight = 0]251 #[weight = 0]
227 pub fn create_collection( origin,252 pub fn create_collection(origin,
228 collection_name: Vec<u16>,253 collection_name: Vec<u16>,
229 collection_description: Vec<u16>,254 collection_description: Vec<u16>,
230 token_prefix: Vec<u8>,255 token_prefix: Vec<u8>,
231 mode: CollectionMode) -> DispatchResult {256 mode: CollectionMode) -> DispatchResult {
232257
233 // Anyone can create a collection258 // Anyone can create a collection
234 let who = ensure_signed(origin)?;259 let who = ensure_signed(origin)?;
271 owner: who.clone(),296 owner: who.clone(),
272 name: name,297 name: name,
273 mode: mode.clone(),298 mode: mode.clone(),
299 mint_mode: false,
274 access: AccessMode::Normal,300 access: AccessMode::Normal,
275 description: description,301 description: description,
276 decimal_points: decimal_points,302 decimal_points: decimal_points,
309 }335 }
310336
311 #[weight = 0]337 #[weight = 0]
338 pub fn add_to_white_list(origin, collection_id: u64, address: T::AccountId) -> DispatchResult{
339
340 let sender = ensure_signed(origin)?;
341 Self::check_owner_or_admin_permissions(collection_id, sender)?;
342
343 let mut white_list_collection: Vec<T::AccountId>;
344 if <WhiteList<T>>::contains_key(collection_id) {
345 white_list_collection = <WhiteList<T>>::get(collection_id);
346 if !white_list_collection.contains(&address.clone())
347 {
348 white_list_collection.push(address.clone());
349 }
350 }
351 else {
352 white_list_collection = Vec::new();
353 white_list_collection.push(address.clone());
354 }
355
356 <WhiteList<T>>::insert(collection_id, white_list_collection);
357 Ok(())
358 }
359
360 #[weight = 0]
361 pub fn remove_from_white_list(origin, collection_id: u64, address: T::AccountId) -> DispatchResult{
362
363 let sender = ensure_signed(origin)?;
364 Self::check_owner_or_admin_permissions(collection_id, sender)?;
365
366 if <WhiteList<T>>::contains_key(collection_id) {
367 let mut white_list_collection = <WhiteList<T>>::get(collection_id);
368 if white_list_collection.contains(&address.clone())
369 {
370 white_list_collection.retain(|i| *i != address.clone());
371 <WhiteList<T>>::insert(collection_id, white_list_collection);
372 }
373 }
374
375 Ok(())
376 }
377
378 #[weight = 0]
379 pub fn set_public_access_mode(origin, collection_id: u64, mode: AccessMode) -> DispatchResult
380 {
381 let sender = ensure_signed(origin)?;
382
383 Self::check_owner_permissions(collection_id, sender)?;
384 let mut target_collection = <Collection<T>>::get(collection_id);
385 target_collection.access = mode;
386 <Collection<T>>::insert(collection_id, target_collection);
387
388 Ok(())
389 }
390
391 #[weight = 0]
392 pub fn set_mint_permission(origin, collection_id: u64, mint_permission: bool) -> DispatchResult
393 {
394 let sender = ensure_signed(origin)?;
395
396 Self::check_owner_permissions(collection_id, sender)?;
397 let mut target_collection = <Collection<T>>::get(collection_id);
398 target_collection.mint_mode = mint_permission;
399 <Collection<T>>::insert(collection_id, target_collection);
400
401 Ok(())
402 }
403
404 #[weight = 0]
312 pub fn change_collection_owner(origin, collection_id: u64, new_owner: T::AccountId) -> DispatchResult {405 pub fn change_collection_owner(origin, collection_id: u64, new_owner: T::AccountId) -> DispatchResult {
313406
314 let sender = ensure_signed(origin)?;407 let sender = ensure_signed(origin)?;
405 pub fn create_item(origin, collection_id: u64, properties: Vec<u8>, owner: T::AccountId) -> DispatchResult {498 pub fn create_item(origin, collection_id: u64, properties: Vec<u8>, owner: T::AccountId) -> DispatchResult {
406499
407 let sender = ensure_signed(origin)?;500 let sender = ensure_signed(origin)?;
501 Self::collection_exists(collection_id)?;
408 let target_collection = <Collection<T>>::get(collection_id);502 let target_collection = <Collection<T>>::get(collection_id);
409 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;
410503
504 if !Self::is_owner_or_admin_permissions(collection_id, sender.clone()) {
505 ensure!(target_collection.mint_mode == true, "Public minting is not allowed for this collection");
506 Self::check_white_list(collection_id, &owner)?;
507 Self::check_white_list(collection_id, &sender)?;
508 }
509
411 match target_collection.mode510 match target_collection.mode
412 {511 {
413 CollectionMode::NFT(_) => {512 CollectionMode::NFT(_) => {
469 pub fn burn_item(origin, collection_id: u64, item_id: u64) -> DispatchResult {568 pub fn burn_item(origin, collection_id: u64, item_id: u64) -> DispatchResult {
470569
471 let sender = ensure_signed(origin)?;570 let sender = ensure_signed(origin)?;
472 let item_owner = Self::is_item_owner(sender.clone(), collection_id, item_id);571 Self::collection_exists(collection_id)?;
473 if !item_owner572
474 {573 // Transfer permissions check
475 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;
476 }
477 let target_collection = <Collection<T>>::get(collection_id);574 let target_collection = <Collection<T>>::get(collection_id);
575 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||
576 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),
577 "Only item owner, collection owner and admins can modify item");
478578
579 if target_collection.access == AccessMode::WhiteList {
580 Self::check_white_list(collection_id, &sender)?;
581 }
582
479 match target_collection.mode583 match target_collection.mode
480 {584 {
481 CollectionMode::NFT(_) => Self::burn_nft_item(collection_id, item_id)?,585 CollectionMode::NFT(_) => Self::burn_nft_item(collection_id, item_id)?,
494 pub fn transfer(origin, recipient: T::AccountId, collection_id: u64, item_id: u64, value: u64) -> DispatchResult {598 pub fn transfer(origin, recipient: T::AccountId, collection_id: u64, item_id: u64, value: u64) -> DispatchResult {
495599
496 let sender = ensure_signed(origin)?;600 let sender = ensure_signed(origin)?;
497 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id), "Only item owner can call transfer method");
498601
602 // Transfer permissions check
499 let target_collection = <Collection<T>>::get(collection_id);603 let target_collection = <Collection<T>>::get(collection_id);
604 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||
605 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),
606 "Only item owner, collection owner and admins can modify item");
500607
501 // TODO: implement other modes608 if target_collection.access == AccessMode::WhiteList {
609 Self::check_white_list(collection_id, &sender)?;
610 Self::check_white_list(collection_id, &recipient)?;
611 }
612
502 match target_collection.mode613 match target_collection.mode
503 {614 {
515626
516 let sender = ensure_signed(origin)?;627 let sender = ensure_signed(origin)?;
517628
629 // Transfer permissions check
630 let target_collection = <Collection<T>>::get(collection_id);
631 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||
632 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),
633 "Only item owner, collection owner and admins can approve");
634
635 if target_collection.access == AccessMode::WhiteList {
636 Self::check_white_list(collection_id, &sender)?;
637 Self::check_white_list(collection_id, &approved)?;
638 }
639
518 // amount param stub640 // amount param stub
519 let amount = 100000000;641 let amount = 100000000;
520642
521 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id), "Only item owner can call transfer method");
522
523 let list_exists = <ApprovedList<T>>::contains_key(collection_id, (item_id, sender.clone()));643 let list_exists = <ApprovedList<T>>::contains_key(collection_id, (item_id, sender.clone()));
524 if list_exists {644 if list_exists {
525645
544 pub fn transfer_from(origin, from: T::AccountId, recipient: T::AccountId, collection_id: u64, item_id: u64, value: u64 ) -> DispatchResult {664 pub fn transfer_from(origin, from: T::AccountId, recipient: T::AccountId, collection_id: u64, item_id: u64, value: u64 ) -> DispatchResult {
545665
546 let sender = ensure_signed(origin)?;666 let sender = ensure_signed(origin)?;
547 let approved_list_exists = <ApprovedList<T>>::contains_key(collection_id, (item_id, from.clone()));667 let mut appoved_transfer = false;
668
548 if approved_list_exists669 // Check approve
549 {670 if <ApprovedList<T>>::contains_key(collection_id, (item_id, from.clone())) {
550 let list_itm = <ApprovedList<T>>::get(collection_id, (item_id, from.clone()));671 let list_itm = <ApprovedList<T>>::get(collection_id, (item_id, from.clone()));
551 let opt_item = list_itm.iter().find(|i| i.approved == sender.clone());672 let opt_item = list_itm.iter().find(|i| i.approved == sender.clone());
552 ensure!(opt_item.is_some(), "No approve found");673 appoved_transfer = opt_item.is_some();
553 ensure!(opt_item.unwrap().amount >= value, "Requested value more than approved");674 ensure!(opt_item.unwrap().amount >= value, "Requested value more than approved");
554
555 // remove approve
556 let approve_list: Vec<ApprovePermissions<T::AccountId>> = <ApprovedList<T>>::get(collection_id, (item_id, from.clone()))
557 .into_iter().filter(|i| i.approved != sender.clone()).collect();
558 <ApprovedList<T>>::insert(collection_id, (item_id, from.clone()), approve_list);
559 }675 }
560 else
561 {
562 Self::check_owner_or_admin_permissions(collection_id, sender)?;
563 }
564676
677 // Transfer permissions check
565 let target_collection = <Collection<T>>::get(collection_id);678 let target_collection = <Collection<T>>::get(collection_id);
679 ensure!(appoved_transfer || Self::is_owner_or_admin_permissions(collection_id, sender.clone()),
680 "Only item owner, collection owner and admins can modify items");
566681
682 if target_collection.access == AccessMode::WhiteList {
683 Self::check_white_list(collection_id, &sender)?;
684 Self::check_white_list(collection_id, &recipient)?;
685 }
686
687 // remove approve
688 let approve_list: Vec<ApprovePermissions<T::AccountId>> = <ApprovedList<T>>::get(collection_id, (item_id, from.clone()))
689 .into_iter().filter(|i| i.approved != sender.clone()).collect();
690 <ApprovedList<T>>::insert(collection_id, (item_id, from.clone()), approve_list);
691
692
567 match target_collection.mode693 match target_collection.mode
568 {694 {
569 CollectionMode::NFT(_) => Self::transfer_nft(collection_id, item_id, from, recipient)?,695 CollectionMode::NFT(_) => Self::transfer_nft(collection_id, item_id, from, recipient)?,
675 Ok(())801 Ok(())
676 }802 }
677803
678 fn burn_refungible_item(804 fn burn_refungible_item(collection_id: u64, item_id: u64, owner: T::AccountId) -> DispatchResult {
679 collection_id: u64,
680 item_id: u64,
681 owner: T::AccountId,
682 ) -> DispatchResult {
683 ensure!(805 ensure!(
684 <ReFungibleItemList<T>>::contains_key(collection_id, item_id),806 <ReFungibleItemList<T>>::contains_key(collection_id, item_id),
685 "Item does not exists"807 "Item does not exists"
770 Ok(())892 Ok(())
771 }893 }
772894
773 fn check_owner_or_admin_permissions(895 fn is_owner_or_admin_permissions(collection_id: u64, subject: T::AccountId) -> bool {
774 collection_id: u64,
775 subject: T::AccountId,
776 ) -> DispatchResult {
777 Self::collection_exists(collection_id)?;
778896
779 let target_collection = <Collection<T>>::get(collection_id);897 let target_collection = <Collection<T>>::get(collection_id);
780 let is_owner = subject == target_collection.owner;898 let mut result: bool = subject == target_collection.owner;
781
782 let no_perm_mes = "You do not have permissions to modify this collection";
783 let exists = <AdminList<T>>::contains_key(collection_id);899 let exists = <AdminList<T>>::contains_key(collection_id);
784900
785 if !is_owner {901 if !result & exists {
786 ensure!(exists, no_perm_mes);
787 ensure!(902 if <AdminList<T>>::get(collection_id).contains(&subject) {
788 <AdminList<T>>::get(collection_id).contains(&subject),
789 no_perm_mes903 result = true
790 );904 }
791 }905 }
906
907 result
908 }
909
910 fn check_owner_or_admin_permissions(collection_id: u64, subject: T::AccountId) -> DispatchResult {
911
912 Self::collection_exists(collection_id)?;
913 let result = Self::is_owner_or_admin_permissions(collection_id, subject.clone());
914
915 ensure!(result, "You do not have permissions to modify this collection");
792 Ok(())916 Ok(())
793 }917 }
794918
812 }936 }
813 }937 }
814938
939 fn check_white_list(collection_id: u64, address: &T::AccountId) -> DispatchResult {
940
941 let mes = "Address is not in white list";
942 ensure!(<WhiteList<T>>::contains_key(collection_id), mes);
943 let wl = <WhiteList<T>>::get(collection_id);
944 ensure!(wl.contains(address), mes);
945
946 Ok(())
947 }
948
815 fn transfer_fungible(949 fn transfer_fungible(
816 collection_id: u64,950 collection_id: u64,
817 item_id: u64,951 item_id: u64,
818 value: u64,952 value: u64,
819 owner: T::AccountId,953 owner: T::AccountId,
820 new_owner: T::AccountId,954 new_owner: T::AccountId,
821 ) -> DispatchResult {955 ) -> DispatchResult {
956
957 ensure!(
958 <FungibleItemList<T>>::contains_key(collection_id, item_id),
959 "Item not exists"
960 );
961
822 let full_item = <FungibleItemList<T>>::get(collection_id, item_id);962 let full_item = <FungibleItemList<T>>::get(collection_id, item_id);
823 let amount = full_item.value;963 let amount = full_item.value;
824964
903 owner: T::AccountId,1043 owner: T::AccountId,
904 new_owner: T::AccountId,1044 new_owner: T::AccountId,
905 ) -> DispatchResult {1045 ) -> DispatchResult {
1046
1047 ensure!(
1048 <ReFungibleItemList<T>>::contains_key(collection_id, item_id),
1049 "Item not exists"
1050 );
1051
906 let full_item = <ReFungibleItemList<T>>::get(collection_id, item_id);1052 let full_item = <ReFungibleItemList<T>>::get(collection_id, item_id);
907 let item = full_item1053 let item = full_item
908 .owner1054 .owner
983 sender: T::AccountId,1129 sender: T::AccountId,
984 new_owner: T::AccountId,1130 new_owner: T::AccountId,
985 ) -> DispatchResult {1131 ) -> DispatchResult {
1132
1133 ensure!(
1134 <NftItemList<T>>::contains_key(collection_id, item_id),
1135 "Item not exists"
1136 );
1137
986 let mut item = <NftItemList<T>>::get(collection_id, item_id);1138 let mut item = <NftItemList<T>>::get(collection_id, item_id);
9871139
988 ensure!(1140 ensure!(
1012 // reset approved list1164 // reset approved list
1013 <ApprovedList<T>>::remove(collection_id, (item_id, old_owner));1165 <ApprovedList<T>>::remove(collection_id, (item_id, old_owner));
1014 Ok(())1166 Ok(())
1167 }
1168
1169 fn init_collection(item: &CollectionType<T::AccountId>){
1170
1171 // check params
1172 assert!(item.decimal_points <= 4, "decimal_points parameter must be lower than 4");
1173 assert!(item.name.len() <= 64, "Collection name can not be longer than 63 char");
1174 assert!(item.name.len() <= 256, "Collection description can not be longer than 255 char");
1175 assert!(item.token_prefix.len() <= 16, "Token prefix can not be longer than 15 char");
1176
1177 // Generate next collection ID
1178 let next_id = CreatedCollectionCount::get()
1179 .checked_add(1)
1180 .expect("collection id error");
1181
1182 CreatedCollectionCount::put(next_id);
1183 }
1184
1185 fn init_nft_token(item: &NftItemType<T::AccountId>){
1186
1187 let current_index = <ItemListIndex>::get(item.collection)
1188 .checked_add(1)
1189 .expect("Item list index id error");
1190
1191 let item_owner = item.owner.clone();
1192 let collection_id = item.collection.clone();
1193 Self::add_token_index(collection_id, current_index, item.owner.clone()).unwrap();
1194
1195 <ItemListIndex>::insert(collection_id, current_index);
1196
1197 // Update balance
1198 let new_balance = <Balance<T>>::get(collection_id, item_owner.clone())
1199 .checked_add(1)
1200 .unwrap();
1201 <Balance<T>>::insert(collection_id, item_owner.clone(), new_balance);
1202 }
1203
1204 fn init_fungible_token(item: &FungibleItemType<T::AccountId>){
1205
1206 let current_index = <ItemListIndex>::get(item.collection)
1207 .checked_add(1)
1208 .expect("Item list index id error");
1209 let owner = item.owner.clone();
1210 let value = item.value as u64;
1211
1212 Self::add_token_index(item.collection, current_index, owner.clone()).unwrap();
1213
1214 <ItemListIndex>::insert(item.collection, current_index);
1215
1216 // Update balance
1217 let new_balance = <Balance<T>>::get(item.collection, owner.clone())
1218 .checked_add(value)
1219 .unwrap();
1220 <Balance<T>>::insert(item.collection, owner.clone(), new_balance);
1221 }
1222
1223 fn init_refungible_token(item: &ReFungibleItemType<T::AccountId>){
1224
1225 let current_index = <ItemListIndex>::get(item.collection)
1226 .checked_add(1)
1227 .expect("Item list index id error");
1228
1229 let value = item.owner.first().unwrap().fraction as u64;
1230 let owner = item.owner.first().unwrap().owner.clone();
1231
1232 Self::add_token_index(item.collection, current_index, owner.clone()).unwrap();
1233
1234 <ItemListIndex>::insert(item.collection, current_index);
1235
1236 // Update balance
1237 let new_balance = <Balance<T>>::get(item.collection, owner.clone())
1238 .checked_add(value)
1239 .unwrap();
1240 <Balance<T>>::insert(item.collection, owner.clone(), new_balance);
1015 }1241 }
10161242
1017 fn add_token_index(collection_id: u64, item_index: u64, owner: T::AccountId) -> DispatchResult {1243 fn add_token_index(collection_id: u64, item_index: u64, owner: T::AccountId) -> DispatchResult {
10681294
1069////////////////////////////////////////////////////////////////////////////////////////////////////1295////////////////////////////////////////////////////////////////////////////////////////////////////
1070// Economic models1296// Economic models
1297// #region
10711298
1072/// Fee multiplier.1299/// Fee multiplier.
1073pub type Multiplier = FixedU128;1300pub type Multiplier = FixedU128;
1262 Ok(())1489 Ok(())
1263 }1490 }
1264}1491}
12651492// #endregion
modifiedpallets/nft/src/tests.rsdiffbeforeafterboth
1// Tests to be written here1// Tests to be written here
2use crate::mock::*;2use crate::mock::*;
3use crate::{ApprovePermissions, CollectionMode, Ownership};3use crate::{ApprovePermissions, CollectionMode, AccessMode, Ownership};
4use frame_support::{assert_noop, assert_ok};4use frame_support::{assert_noop, assert_ok};
55
6// Use cases tests region
7// #region
6#[test]8#[test]
7fn create_nft_item() {9fn create_nft_item() {
8 new_test_ext().execute_with(|| {10 new_test_ext().execute_with(|| {
321 assert_eq!(TemplateModule::balance_count(1, 1), 1);323 assert_eq!(TemplateModule::balance_count(1, 1), 1);
322 assert_eq!(TemplateModule::address_tokens(1, 1), [1]);324 assert_eq!(TemplateModule::address_tokens(1, 1), [1]);
323325
324 assert_noop!(326 assert_ok!(TemplateModule::set_mint_permission(origin1.clone(), 1, true));
325 TemplateModule::transfer_from(origin2.clone(), 1, 3, 1, 1, 1),327 assert_ok!(TemplateModule::set_public_access_mode(origin1.clone(), 1, AccessMode::WhiteList));
326 "You do not have permissions to modify this collection"328 assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 1));
329 assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 2));
327 );330 assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 3));
328331
329 // do approve332 // do approve
330 assert_ok!(TemplateModule::approve(origin1.clone(), 2, 1, 1));333 assert_ok!(TemplateModule::approve(origin1.clone(), 2, 1, 1));
331 assert_eq!(TemplateModule::approved(1, (1, 1)).len(), 1);334 assert_eq!(TemplateModule::approved(1, (1, 1)).len(), 1);
332 assert_ok!(TemplateModule::approve(origin1.clone(), 10, 1, 1));335 assert_ok!(TemplateModule::approve(origin1.clone(), 3, 1, 1));
333 assert_eq!(TemplateModule::approved(1, (1, 1)).len(), 2);336 assert_eq!(TemplateModule::approved(1, (1, 1)).len(), 2);
334 assert_eq!(337 assert_eq!(
335 TemplateModule::approved(1, (1, 1))[0],338 TemplateModule::approved(1, (1, 1))[0],
390 assert_eq!(TemplateModule::balance_count(1, 1), 1000);393 assert_eq!(TemplateModule::balance_count(1, 1), 1000);
391 assert_eq!(TemplateModule::address_tokens(1, 1), [1]);394 assert_eq!(TemplateModule::address_tokens(1, 1), [1]);
392395
393 assert_noop!(396 assert_ok!(TemplateModule::set_mint_permission(origin1.clone(), 1, true));
394 TemplateModule::transfer_from(origin2.clone(), 1, 3, 1, 1, 1),397 assert_ok!(TemplateModule::set_public_access_mode(origin1.clone(), 1, AccessMode::WhiteList));
395 "You do not have permissions to modify this collection"398 assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 1));
399 assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 2));
396 );400 assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 3));
397401
398 // do approve402 // do approve
399 assert_ok!(TemplateModule::approve(origin1.clone(), 2, 1, 1));403 assert_ok!(TemplateModule::approve(origin1.clone(), 2, 1, 1));
400 assert_eq!(TemplateModule::approved(1, (1, 1)).len(), 1);404 assert_eq!(TemplateModule::approved(1, (1, 1)).len(), 1);
401 assert_ok!(TemplateModule::approve(origin1.clone(), 10, 1, 1));405 assert_ok!(TemplateModule::approve(origin1.clone(), 3, 1, 1));
402 assert_eq!(TemplateModule::approved(1, (1, 1)).len(), 2);406 assert_eq!(TemplateModule::approved(1, (1, 1)).len(), 2);
403 assert_eq!(407 assert_eq!(
404 TemplateModule::approved(1, (1, 1))[0],408 TemplateModule::approved(1, (1, 1))[0],
425 assert_eq!(429 assert_eq!(
426 TemplateModule::approved(1, (1, 1))[0],430 TemplateModule::approved(1, (1, 1))[0],
427 ApprovePermissions {431 ApprovePermissions {
428 approved: 10,432 approved: 3,
429 amount: 100000000433 amount: 100000000
430 }434 }
431 );435 );
461 assert_eq!(TemplateModule::balance_count(1, 1), 1000);465 assert_eq!(TemplateModule::balance_count(1, 1), 1000);
462 assert_eq!(TemplateModule::address_tokens(1, 1), [1]);466 assert_eq!(TemplateModule::address_tokens(1, 1), [1]);
463467
464 assert_noop!(468 assert_ok!(TemplateModule::set_mint_permission(origin1.clone(), 1, true));
465 TemplateModule::transfer_from(origin2.clone(), 1, 3, 1, 1, 1),469 assert_ok!(TemplateModule::set_public_access_mode(origin1.clone(), 1, AccessMode::WhiteList));
466 "You do not have permissions to modify this collection"470 assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 1));
471 assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 2));
467 );472 assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 3));
468473
469 // do approve474 // do approve
470 assert_ok!(TemplateModule::approve(origin1.clone(), 2, 1, 1));475 assert_ok!(TemplateModule::approve(origin1.clone(), 2, 1, 1));
471 assert_eq!(TemplateModule::approved(1, (1, 1)).len(), 1);476 assert_eq!(TemplateModule::approved(1, (1, 1)).len(), 1);
472 assert_ok!(TemplateModule::approve(origin1.clone(), 10, 1, 1));477 assert_ok!(TemplateModule::approve(origin1.clone(), 3, 1, 1));
473 assert_eq!(TemplateModule::approved(1, (1, 1)).len(), 2);478 assert_eq!(TemplateModule::approved(1, (1, 1)).len(), 2);
474 assert_eq!(479 assert_eq!(
475 TemplateModule::approved(1, (1, 1))[0],480 TemplateModule::approved(1, (1, 1))[0],
496 assert_eq!(501 assert_eq!(
497 TemplateModule::approved(1, (1, 1))[0],502 TemplateModule::approved(1, (1, 1))[0],
498 ApprovePermissions {503 ApprovePermissions {
499 approved: 10,504 approved: 3,
500 amount: 100000000505 amount: 100000000
501 }506 }
502 );507 );
573 let mode: CollectionMode = CollectionMode::NFT(2000);578 let mode: CollectionMode = CollectionMode::NFT(2000);
574579
575 let origin1 = Origin::signed(1);580 let origin1 = Origin::signed(1);
576 let origin2 = Origin::signed(2);
577 assert_ok!(TemplateModule::create_collection(581 assert_ok!(TemplateModule::create_collection(
578 origin1.clone(),582 origin1.clone(),
579 col_name1.clone(),583 col_name1.clone(),
583 ));587 ));
584 assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), 1, 2));588 assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), 1, 2));
585 assert_ok!(TemplateModule::create_item(589 assert_ok!(TemplateModule::create_item(
586 origin2.clone(),590 origin1.clone(),
587 1,591 1,
588 [1, 2, 3].to_vec(),592 [1, 2, 3].to_vec(),
589 1593 1
614 let mode: CollectionMode = CollectionMode::Fungible(3);618 let mode: CollectionMode = CollectionMode::Fungible(3);
615619
616 let origin1 = Origin::signed(1);620 let origin1 = Origin::signed(1);
617 let origin2 = Origin::signed(2);
618 assert_ok!(TemplateModule::create_collection(621 assert_ok!(TemplateModule::create_collection(
619 origin1.clone(),622 origin1.clone(),
620 col_name1.clone(),623 col_name1.clone(),
624 ));627 ));
625 assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), 1, 2));628 assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), 1, 2));
626 assert_ok!(TemplateModule::create_item(629 assert_ok!(TemplateModule::create_item(
627 origin2.clone(),630 origin1.clone(),
628 1,631 1,
629 [].to_vec(),632 [].to_vec(),
630 1633 1
661 token_prefix1.clone(),664 token_prefix1.clone(),
662 mode665 mode
663 ));666 ));
667
668 assert_ok!(TemplateModule::set_mint_permission(origin1.clone(), 1, true));
669 assert_ok!(TemplateModule::set_public_access_mode(origin1.clone(), 1, AccessMode::WhiteList));
670 assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 1));
671
664 assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), 1, 2));672 assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), 1, 2));
665 assert_ok!(TemplateModule::create_item(673 assert_ok!(TemplateModule::create_item(
666 origin2.clone(),674 origin2.clone(),
928 // approve936 // approve
929 assert_ok!(TemplateModule::approve(origin1.clone(), 2, 1, 1));937 assert_ok!(TemplateModule::approve(origin1.clone(), 2, 1, 1));
930 assert_eq!(TemplateModule::approved(1, (1, 1))[0].approved, 2);938 assert_eq!(TemplateModule::approved(1, (1, 1))[0].approved, 2);
939
940 assert_ok!(TemplateModule::set_mint_permission(origin1.clone(), 1, true));
941 assert_ok!(TemplateModule::set_public_access_mode(origin1.clone(), 1, AccessMode::WhiteList));
942 assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 1));
943 assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 2));
944 assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 3));
945
931 assert_ok!(TemplateModule::transfer_from(946 assert_ok!(TemplateModule::transfer_from(
932 origin2.clone(),947 origin2.clone(),
933 1,948 1,
943 });958 });
944}959}
945960
961// #endregion
962
963// Coverage tests region
964// #region
965
966#[test]
967fn owner_can_add_address_to_white_list() {
968 new_test_ext().execute_with(|| {
969 let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
970 let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
971 let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
972 let mode: CollectionMode = CollectionMode::NFT(2000);
973 let origin1 = Origin::signed(1);
974
975 assert_ok!(TemplateModule::create_collection(
976 origin1.clone(),
977 col_name1.clone(),
978 col_desc1.clone(),
979 token_prefix1.clone(),
980 mode
981 ));
982
983 assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 2));
984 assert_eq!(TemplateModule::white_list(1)[0], 2);
985 });
986}
987
988#[test]
989fn admin_can_add_address_to_white_list() {
990 new_test_ext().execute_with(|| {
991 let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
992 let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
993 let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
994 let mode: CollectionMode = CollectionMode::NFT(2000);
995 let origin1 = Origin::signed(1);
996 let origin2 = Origin::signed(2);
997
998 assert_ok!(TemplateModule::create_collection(
999 origin1.clone(),
1000 col_name1.clone(),
1001 col_desc1.clone(),
1002 token_prefix1.clone(),
1003 mode
1004 ));
1005
1006 assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), 1, 2));
1007 assert_ok!(TemplateModule::add_to_white_list(origin2.clone(), 1, 3));
1008 assert_eq!(TemplateModule::white_list(1)[0], 3);
1009 });
1010}
1011
1012#[test]
1013fn nonprivileged_user_cannot_add_address_to_white_list() {
1014 new_test_ext().execute_with(|| {
1015 let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
1016 let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
1017 let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
1018 let mode: CollectionMode = CollectionMode::NFT(2000);
1019 let origin1 = Origin::signed(1);
1020 let origin2 = Origin::signed(2);
1021
1022 assert_ok!(TemplateModule::create_collection(
1023 origin1.clone(),
1024 col_name1.clone(),
1025 col_desc1.clone(),
1026 token_prefix1.clone(),
1027 mode
1028 ));
1029
1030 assert_noop!(TemplateModule::add_to_white_list(origin2.clone(), 1, 3), "You do not have permissions to modify this collection");
1031 });
1032}
1033
1034#[test]
1035fn nobody_can_add_address_to_white_list_of_nonexisting_collection() {
1036 new_test_ext().execute_with(|| {
1037
1038 let origin1 = Origin::signed(1);
1039 assert_noop!(TemplateModule::add_to_white_list(origin1.clone(), 1, 2), "This collection does not exist");
1040 });
1041}
1042
1043#[test]
1044fn nobody_can_add_address_to_white_list_of_deleted_collection() {
1045 new_test_ext().execute_with(|| {
1046 let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
1047 let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
1048 let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
1049 let mode: CollectionMode = CollectionMode::NFT(2000);
1050 let origin1 = Origin::signed(1);
1051
1052 assert_ok!(TemplateModule::create_collection(
1053 origin1.clone(),
1054 col_name1.clone(),
1055 col_desc1.clone(),
1056 token_prefix1.clone(),
1057 mode
1058 ));
1059
1060 assert_ok!(TemplateModule::destroy_collection(origin1.clone(), 1));
1061 assert_noop!(TemplateModule::add_to_white_list(origin1.clone(), 1, 2), "This collection does not exist");
1062 });
1063}
1064
1065// If address is already added to white list, nothing happens
1066#[test]
1067fn address_is_already_added_to_white_list() {
1068 new_test_ext().execute_with(|| {
1069
1070 let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
1071 let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
1072 let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
1073 let mode: CollectionMode = CollectionMode::NFT(2000);
1074 let origin1 = Origin::signed(1);
1075
1076 assert_ok!(TemplateModule::create_collection(
1077 origin1.clone(),
1078 col_name1.clone(),
1079 col_desc1.clone(),
1080 token_prefix1.clone(),
1081 mode
1082 ));
1083
1084 assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 2));
1085 assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 2));
1086 assert_eq!(TemplateModule::white_list(1)[0], 2);
1087 assert_eq!(TemplateModule::white_list(1).len(), 1);
1088 });
1089}
1090
1091#[test]
1092fn owner_can_remove_address_from_white_list() {
1093 new_test_ext().execute_with(|| {
1094
1095 let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
1096 let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
1097 let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
1098 let mode: CollectionMode = CollectionMode::NFT(2000);
1099 let origin1 = Origin::signed(1);
1100
1101 assert_ok!(TemplateModule::create_collection(
1102 origin1.clone(),
1103 col_name1.clone(),
1104 col_desc1.clone(),
1105 token_prefix1.clone(),
1106 mode
1107 ));
1108
1109 assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 2));
1110 assert_ok!(TemplateModule::remove_from_white_list(origin1.clone(), 1, 2));
1111 assert_eq!(TemplateModule::white_list(1).len(), 0);
1112 });
1113}
1114
1115#[test]
1116fn admin_can_remove_address_from_white_list() {
1117 new_test_ext().execute_with(|| {
1118
1119 let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
1120 let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
1121 let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
1122 let mode: CollectionMode = CollectionMode::NFT(2000);
1123 let origin1 = Origin::signed(1);
1124 let origin2 = Origin::signed(2);
1125
1126 assert_ok!(TemplateModule::create_collection(
1127 origin1.clone(),
1128 col_name1.clone(),
1129 col_desc1.clone(),
1130 token_prefix1.clone(),
1131 mode
1132 ));
1133
1134 assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), 1, 2));
1135
1136 assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 3));
1137 assert_ok!(TemplateModule::remove_from_white_list(origin2.clone(), 1, 3));
1138 assert_eq!(TemplateModule::white_list(1).len(), 0);
1139 });
1140}
1141
1142#[test]
1143fn nonprivileged_user_cannot_remove_address_from_white_list() {
1144 new_test_ext().execute_with(|| {
1145
1146 let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
1147 let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
1148 let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
1149 let mode: CollectionMode = CollectionMode::NFT(2000);
1150 let origin1 = Origin::signed(1);
1151 let origin2 = Origin::signed(2);
1152
1153 assert_ok!(TemplateModule::create_collection(
1154 origin1.clone(),
1155 col_name1.clone(),
1156 col_desc1.clone(),
1157 token_prefix1.clone(),
1158 mode
1159 ));
1160
1161 assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 2));
1162 assert_noop!(TemplateModule::remove_from_white_list(origin2.clone(), 1, 2), "You do not have permissions to modify this collection");
1163 assert_eq!(TemplateModule::white_list(1)[0], 2);
1164 });
1165}
1166
1167#[test]
1168fn nobody_can_remove_address_from_white_list_of_nonexisting_collection() {
1169 new_test_ext().execute_with(|| {
1170
1171 let origin1 = Origin::signed(1);
1172 assert_noop!(TemplateModule::remove_from_white_list(origin1.clone(), 1, 2), "This collection does not exist");
1173 });
1174}
1175
1176#[test]
1177fn nobody_can_remove_address_from_white_list_of_deleted_collection() {
1178 new_test_ext().execute_with(|| {
1179
1180 let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
1181 let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
1182 let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
1183 let mode: CollectionMode = CollectionMode::NFT(2000);
1184 let origin1 = Origin::signed(1);
1185 let origin2 = Origin::signed(2);
1186
1187 assert_ok!(TemplateModule::create_collection(
1188 origin1.clone(),
1189 col_name1.clone(),
1190 col_desc1.clone(),
1191 token_prefix1.clone(),
1192 mode
1193 ));
1194
1195 assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 2));
1196 assert_ok!(TemplateModule::destroy_collection(origin1.clone(), 1));
1197 assert_noop!(TemplateModule::remove_from_white_list(origin2.clone(), 1, 2), "This collection does not exist");
1198 assert_eq!(TemplateModule::white_list(1).len(), 0);
1199 });
1200}
1201
1202// If address is already removed from white list, nothing happens
1203#[test]
1204fn address_is_already_removed_from_white_list() {
1205 new_test_ext().execute_with(|| {
1206 let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
1207 let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
1208 let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
1209 let mode: CollectionMode = CollectionMode::NFT(2000);
1210 let origin1 = Origin::signed(1);
1211
1212 assert_ok!(TemplateModule::create_collection(
1213 origin1.clone(),
1214 col_name1.clone(),
1215 col_desc1.clone(),
1216 token_prefix1.clone(),
1217 mode
1218 ));
1219
1220 assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 2));
1221 assert_ok!(TemplateModule::remove_from_white_list(origin1.clone(), 1, 2));
1222 assert_ok!(TemplateModule::remove_from_white_list(origin1.clone(), 1, 2));
1223 assert_eq!(TemplateModule::white_list(1).len(), 0);
1224 });
1225}
1226
1227// If Public Access mode is set to WhiteList, tokens can’t be transferred from a non-whitelisted address with transfer or transferFrom (2 tests)
1228#[test]
1229fn white_list_test_1() {
1230 new_test_ext().execute_with(|| {
1231 let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
1232 let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
1233 let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
1234 let mode: CollectionMode = CollectionMode::NFT(2000);
1235
1236 let origin1 = Origin::signed(1);
1237 assert_ok!(TemplateModule::create_collection(
1238 origin1.clone(),
1239 col_name1.clone(),
1240 col_desc1.clone(),
1241 token_prefix1.clone(),
1242 mode
1243 ));
1244 assert_eq!(TemplateModule::collection(1).owner, 1);
1245
1246 assert_ok!(TemplateModule::create_item(
1247 origin1.clone(),
1248 1,
1249 [1, 2, 3].to_vec(),
1250 1
1251 ));
1252
1253 assert_ok!(TemplateModule::set_public_access_mode(origin1.clone(), 1, AccessMode::WhiteList));
1254 assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 2));
1255
1256 assert_noop!(TemplateModule::transfer(
1257 origin1.clone(),
1258 3,
1259 1,
1260 1,
1261 1
1262 ), "Address is not in white list");
1263 });
1264}
1265
1266#[test]
1267fn white_list_test_2() {
1268 new_test_ext().execute_with(|| {
1269 let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
1270 let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
1271 let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
1272 let mode: CollectionMode = CollectionMode::NFT(2000);
1273
1274 let origin1 = Origin::signed(1);
1275 assert_ok!(TemplateModule::create_collection(
1276 origin1.clone(),
1277 col_name1.clone(),
1278 col_desc1.clone(),
1279 token_prefix1.clone(),
1280 mode
1281 ));
1282 assert_eq!(TemplateModule::collection(1).owner, 1);
1283
1284 assert_ok!(TemplateModule::create_item(
1285 origin1.clone(),
1286 1,
1287 [1, 2, 3].to_vec(),
1288 1
1289 ));
1290
1291 assert_ok!(TemplateModule::set_public_access_mode(origin1.clone(), 1, AccessMode::WhiteList));
1292 assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 1));
1293 assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 2));
1294
1295 // do approve
1296 assert_ok!(TemplateModule::approve(origin1.clone(), 1, 1, 1));
1297 assert_eq!(TemplateModule::approved(1, (1, 1)).len(), 1);
1298
1299 assert_ok!(TemplateModule::remove_from_white_list(origin1.clone(), 1, 1));
1300
1301 assert_noop!(TemplateModule::transfer_from(
1302 origin1.clone(),
1303 1,
1304 3,
1305 1,
1306 1,
1307 1
1308 ), "Address is not in white list");
1309 });
1310}
1311
1312// If Public Access mode is set to WhiteList, tokens can’t be transferred to a non-whitelisted address with transfer or transferFrom (2 tests)
1313#[test]
1314fn white_list_test_3() {
1315 new_test_ext().execute_with(|| {
1316 let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
1317 let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
1318 let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
1319 let mode: CollectionMode = CollectionMode::NFT(2000);
1320
1321 let origin1 = Origin::signed(1);
1322 assert_ok!(TemplateModule::create_collection(
1323 origin1.clone(),
1324 col_name1.clone(),
1325 col_desc1.clone(),
1326 token_prefix1.clone(),
1327 mode
1328 ));
1329 assert_eq!(TemplateModule::collection(1).owner, 1);
1330
1331 assert_ok!(TemplateModule::create_item(
1332 origin1.clone(),
1333 1,
1334 [1, 2, 3].to_vec(),
1335 1
1336 ));
1337
1338 assert_ok!(TemplateModule::set_public_access_mode(origin1.clone(), 1, AccessMode::WhiteList));
1339 assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 1));
1340
1341 assert_noop!(TemplateModule::transfer(
1342 origin1.clone(),
1343 3,
1344 1,
1345 1,
1346 1
1347 ), "Address is not in white list");
1348 });
1349}
1350
1351#[test]
1352fn white_list_test_4() {
1353 new_test_ext().execute_with(|| {
1354 let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
1355 let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
1356 let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
1357 let mode: CollectionMode = CollectionMode::NFT(2000);
1358
1359 let origin1 = Origin::signed(1);
1360 assert_ok!(TemplateModule::create_collection(
1361 origin1.clone(),
1362 col_name1.clone(),
1363 col_desc1.clone(),
1364 token_prefix1.clone(),
1365 mode
1366 ));
1367 assert_eq!(TemplateModule::collection(1).owner, 1);
1368
1369 assert_ok!(TemplateModule::create_item(
1370 origin1.clone(),
1371 1,
1372 [1, 2, 3].to_vec(),
1373 1
1374 ));
1375
1376 assert_ok!(TemplateModule::set_public_access_mode(origin1.clone(), 1, AccessMode::WhiteList));
1377 assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 1));
1378 assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 2));
1379
1380 // do approve
1381 assert_ok!(TemplateModule::approve(origin1.clone(), 1, 1, 1));
1382 assert_eq!(TemplateModule::approved(1, (1, 1)).len(), 1);
1383
1384 assert_ok!(TemplateModule::remove_from_white_list(origin1.clone(), 1, 2));
1385
1386 assert_noop!(TemplateModule::transfer_from(
1387 origin1.clone(),
1388 1,
1389 3,
1390 1,
1391 1,
1392 1
1393 ), "Address is not in white list");
1394 });
1395}
1396
1397// If Public Access mode is set to WhiteList, tokens can’t be destroyed by a non-whitelisted address (even if it owned them before enabling WhiteList mode)
1398#[test]
1399fn white_list_test_5() {
1400 new_test_ext().execute_with(|| {
1401 let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
1402 let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
1403 let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
1404 let mode: CollectionMode = CollectionMode::NFT(2000);
1405
1406 let origin1 = Origin::signed(1);
1407 assert_ok!(TemplateModule::create_collection(
1408 origin1.clone(),
1409 col_name1.clone(),
1410 col_desc1.clone(),
1411 token_prefix1.clone(),
1412 mode
1413 ));
1414 assert_eq!(TemplateModule::collection(1).owner, 1);
1415
1416 assert_ok!(TemplateModule::create_item(
1417 origin1.clone(),
1418 1,
1419 [1, 2, 3].to_vec(),
1420 1
1421 ));
1422
1423 assert_ok!(TemplateModule::set_public_access_mode(origin1.clone(), 1, AccessMode::WhiteList));
1424 assert_noop!(TemplateModule::burn_item(origin1.clone(), 1, 1), "Address is not in white list");
1425 });
1426}
1427
1428// If Public Access mode is set to WhiteList, oken transfers can’t be Approved by a non-whitelisted address (see Approve method).
1429#[test]
1430fn white_list_test_6() {
1431 new_test_ext().execute_with(|| {
1432 let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
1433 let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
1434 let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
1435 let mode: CollectionMode = CollectionMode::NFT(2000);
1436
1437 let origin1 = Origin::signed(1);
1438 assert_ok!(TemplateModule::create_collection(
1439 origin1.clone(),
1440 col_name1.clone(),
1441 col_desc1.clone(),
1442 token_prefix1.clone(),
1443 mode
1444 ));
1445 assert_ok!(TemplateModule::set_public_access_mode(origin1.clone(), 1, AccessMode::WhiteList));
1446
1447 // do approve
1448 assert_noop!(TemplateModule::approve(origin1.clone(), 1, 1, 1), "Address is not in white list");
1449 });
1450}
1451
1452// If Public Access mode is set to WhiteList, tokens can be transferred from a whitelisted address with transfer or transferFrom (2 tests) and
1453// tokens can be transferred from a whitelisted address with transfer or transferFrom (2 tests)
1454#[test]
1455fn white_list_test_7() {
1456 new_test_ext().execute_with(|| {
1457 let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
1458 let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
1459 let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
1460 let mode: CollectionMode = CollectionMode::NFT(2000);
1461
1462 let origin1 = Origin::signed(1);
1463 assert_ok!(TemplateModule::create_collection(
1464 origin1.clone(),
1465 col_name1.clone(),
1466 col_desc1.clone(),
1467 token_prefix1.clone(),
1468 mode
1469 ));
1470 assert_eq!(TemplateModule::collection(1).owner, 1);
1471
1472 assert_ok!(TemplateModule::create_item(
1473 origin1.clone(),
1474 1,
1475 [1, 2, 3].to_vec(),
1476 1
1477 ));
1478
1479 assert_ok!(TemplateModule::set_public_access_mode(origin1.clone(), 1, AccessMode::WhiteList));
1480 assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 1));
1481 assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 2));
1482
1483 assert_ok!(TemplateModule::transfer(
1484 origin1.clone(),
1485 2,
1486 1,
1487 1,
1488 1
1489 ));
1490 });
1491}
1492
1493#[test]
1494fn white_list_test_8() {
1495 new_test_ext().execute_with(|| {
1496 let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
1497 let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
1498 let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
1499 let mode: CollectionMode = CollectionMode::NFT(2000);
1500
1501 let origin1 = Origin::signed(1);
1502 assert_ok!(TemplateModule::create_collection(
1503 origin1.clone(),
1504 col_name1.clone(),
1505 col_desc1.clone(),
1506 token_prefix1.clone(),
1507 mode
1508 ));
1509 assert_eq!(TemplateModule::collection(1).owner, 1);
1510
1511 assert_ok!(TemplateModule::create_item(
1512 origin1.clone(),
1513 1,
1514 [1, 2, 3].to_vec(),
1515 1
1516 ));
1517
1518 assert_ok!(TemplateModule::set_public_access_mode(origin1.clone(), 1, AccessMode::WhiteList));
1519 assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 1));
1520 assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 2));
1521
1522 // do approve
1523 assert_ok!(TemplateModule::approve(origin1.clone(), 1, 1, 1));
1524 assert_eq!(TemplateModule::approved(1, (1, 1)).len(), 1);
1525
1526 assert_ok!(TemplateModule::transfer_from(
1527 origin1.clone(),
1528 1,
1529 2,
1530 1,
1531 1,
1532 1
1533 ));
1534 });
1535}
1536
1537// If Public Access mode is set to WhiteList, and Mint Permission is set to false, tokens can be created by owner.
1538#[test]
1539fn white_list_test_9() {
1540 new_test_ext().execute_with(|| {
1541 let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
1542 let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
1543 let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
1544 let mode: CollectionMode = CollectionMode::NFT(2000);
1545
1546 let origin1 = Origin::signed(1);
1547 assert_ok!(TemplateModule::create_collection(
1548 origin1.clone(),
1549 col_name1.clone(),
1550 col_desc1.clone(),
1551 token_prefix1.clone(),
1552 mode
1553 ));
1554
1555 assert_ok!(TemplateModule::set_public_access_mode(origin1.clone(), 1, AccessMode::WhiteList));
1556 assert_ok!(TemplateModule::set_mint_permission(origin1.clone(), 1, false));
1557
1558 assert_ok!(TemplateModule::create_item(
1559 origin1.clone(),
1560 1,
1561 [1, 2, 3].to_vec(),
1562 1
1563 ));
1564 });
1565}
1566
1567// If Public Access mode is set to WhiteList, and Mint Permission is set to false, tokens can be created by admin.
1568#[test]
1569fn white_list_test_10() {
1570 new_test_ext().execute_with(|| {
1571 let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
1572 let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
1573 let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
1574 let mode: CollectionMode = CollectionMode::NFT(2000);
1575
1576 let origin1 = Origin::signed(1);
1577 let origin2 = Origin::signed(2);
1578 assert_ok!(TemplateModule::create_collection(
1579 origin1.clone(),
1580 col_name1.clone(),
1581 col_desc1.clone(),
1582 token_prefix1.clone(),
1583 mode
1584 ));
1585
1586 assert_ok!(TemplateModule::set_public_access_mode(origin1.clone(), 1, AccessMode::WhiteList));
1587 assert_ok!(TemplateModule::set_mint_permission(origin1.clone(), 1, false));
1588
1589 assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), 1, 2));
1590
1591 assert_ok!(TemplateModule::create_item(
1592 origin2.clone(),
1593 1,
1594 [1, 2, 3].to_vec(),
1595 2
1596 ));
1597 });
1598}
1599
1600// If Public Access mode is set to WhiteList, and Mint Permission is set to false, tokens cannot be created by non-privileged and white listed address.
1601#[test]
1602fn white_list_test_11() {
1603 new_test_ext().execute_with(|| {
1604 let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
1605 let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
1606 let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
1607 let mode: CollectionMode = CollectionMode::NFT(2000);
1608
1609 let origin1 = Origin::signed(1);
1610 let origin2 = Origin::signed(2);
1611 assert_ok!(TemplateModule::create_collection(
1612 origin1.clone(),
1613 col_name1.clone(),
1614 col_desc1.clone(),
1615 token_prefix1.clone(),
1616 mode
1617 ));
1618
1619 assert_ok!(TemplateModule::set_public_access_mode(origin1.clone(), 1, AccessMode::WhiteList));
1620 assert_ok!(TemplateModule::set_mint_permission(origin1.clone(), 1, false));
1621 assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 2));
1622
1623 assert_noop!(TemplateModule::create_item(
1624 origin2.clone(),
1625 1,
1626 [1, 2, 3].to_vec(),
1627 2
1628 ), "Collection is not in mint mode");
1629 });
1630}
1631
1632// If Public Access mode is set to WhiteList, and Mint Permission is set to false, tokens cannot be created by non-privileged and non-white listed address.
1633#[test]
1634fn white_list_test_12() {
1635 new_test_ext().execute_with(|| {
1636 let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
1637 let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
1638 let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
1639 let mode: CollectionMode = CollectionMode::NFT(2000);
1640
1641 let origin1 = Origin::signed(1);
1642 let origin2 = Origin::signed(2);
1643 assert_ok!(TemplateModule::create_collection(
1644 origin1.clone(),
1645 col_name1.clone(),
1646 col_desc1.clone(),
1647 token_prefix1.clone(),
1648 mode
1649 ));
1650
1651 assert_ok!(TemplateModule::set_public_access_mode(origin1.clone(), 1, AccessMode::WhiteList));
1652 assert_ok!(TemplateModule::set_mint_permission(origin1.clone(), 1, false));
1653
1654 assert_noop!(TemplateModule::create_item(
1655 origin2.clone(),
1656 1,
1657 [1, 2, 3].to_vec(),
1658 2
1659 ), "Collection is not in mint mode");
1660 });
1661}
1662
1663// If Public Access mode is set to WhiteList, and Mint Permission is set to true, tokens can be created by owner.
1664#[test]
1665fn white_list_test_13() {
1666 new_test_ext().execute_with(|| {
1667 let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
1668 let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
1669 let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
1670 let mode: CollectionMode = CollectionMode::NFT(2000);
1671
1672 let origin1 = Origin::signed(1);
1673 assert_ok!(TemplateModule::create_collection(
1674 origin1.clone(),
1675 col_name1.clone(),
1676 col_desc1.clone(),
1677 token_prefix1.clone(),
1678 mode
1679 ));
1680
1681 assert_ok!(TemplateModule::set_public_access_mode(origin1.clone(), 1, AccessMode::WhiteList));
1682 assert_ok!(TemplateModule::set_mint_permission(origin1.clone(), 1, true));
1683
1684 assert_ok!(TemplateModule::create_item(
1685 origin1.clone(),
1686 1,
1687 [1, 2, 3].to_vec(),
1688 1
1689 ));
1690 });
1691}
1692
1693// If Public Access mode is set to WhiteList, and Mint Permission is set to true, tokens can be created by admin.
1694#[test]
1695fn white_list_test_14() {
1696 new_test_ext().execute_with(|| {
1697 let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
1698 let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
1699 let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
1700 let mode: CollectionMode = CollectionMode::NFT(2000);
1701
1702 let origin1 = Origin::signed(1);
1703 let origin2 = Origin::signed(2);
1704 assert_ok!(TemplateModule::create_collection(
1705 origin1.clone(),
1706 col_name1.clone(),
1707 col_desc1.clone(),
1708 token_prefix1.clone(),
1709 mode
1710 ));
1711
1712 assert_ok!(TemplateModule::set_public_access_mode(origin1.clone(), 1, AccessMode::WhiteList));
1713 assert_ok!(TemplateModule::set_mint_permission(origin1.clone(), 1, true));
1714
1715 assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), 1, 2));
1716
1717 assert_ok!(TemplateModule::create_item(
1718 origin2.clone(),
1719 1,
1720 [1, 2, 3].to_vec(),
1721 2
1722 ));
1723 });
1724}
1725
1726// If Public Access mode is set to WhiteList, and Mint Permission is set to true, tokens cannot be created by non-privileged and non-white listed address.
1727#[test]
1728fn white_list_test_15() {
1729 new_test_ext().execute_with(|| {
1730 let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
1731 let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
1732 let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
1733 let mode: CollectionMode = CollectionMode::NFT(2000);
1734
1735 let origin1 = Origin::signed(1);
1736 let origin2 = Origin::signed(2);
1737 assert_ok!(TemplateModule::create_collection(
1738 origin1.clone(),
1739 col_name1.clone(),
1740 col_desc1.clone(),
1741 token_prefix1.clone(),
1742 mode
1743 ));
1744
1745 assert_ok!(TemplateModule::set_public_access_mode(origin1.clone(), 1, AccessMode::WhiteList));
1746 assert_ok!(TemplateModule::set_mint_permission(origin1.clone(), 1, true));
1747
1748 assert_noop!(TemplateModule::create_item(
1749 origin2.clone(),
1750 1,
1751 [1, 2, 3].to_vec(),
1752 2
1753 ), "Address is not in white list");
1754 });
1755}
1756
1757// If Public Access mode is set to WhiteList, and Mint Permission is set to true, tokens can be created by non-privileged and white listed address.
1758#[test]
1759fn white_list_test_16() {
1760 new_test_ext().execute_with(|| {
1761 let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
1762 let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
1763 let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
1764 let mode: CollectionMode = CollectionMode::NFT(2000);
1765
1766 let origin1 = Origin::signed(1);
1767 let origin2 = Origin::signed(2);
1768 assert_ok!(TemplateModule::create_collection(
1769 origin1.clone(),
1770 col_name1.clone(),
1771 col_desc1.clone(),
1772 token_prefix1.clone(),
1773 mode
1774 ));
1775
1776 assert_ok!(TemplateModule::set_public_access_mode(origin1.clone(), 1, AccessMode::WhiteList));
1777 assert_ok!(TemplateModule::set_mint_permission(origin1.clone(), 1, true));
1778 assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 2));
1779
1780 assert_ok!(TemplateModule::create_item(
1781 origin2.clone(),
1782 1,
1783 [1, 2, 3].to_vec(),
1784 2
1785 ));
1786 });
1787}
1788
1789// #endregion
modifiedrun-testnet.shdiffbeforeafterboth
49 --rpc-port $RPCPORT \49 --rpc-port $RPCPORT \
50 --name $NODE \50 --name $NODE \
51 --ws-external \51 --ws-external \
52 --ws-max-connections 10000 \
52 --rpc-cors all \53 --rpc-cors all \
53 -lruntime \54 -lruntime \
54 $BOOTNODES;55 $BOOTNODES;
modifiedruntime/src/lib.rsdiffbeforeafterboth
5353
54pub use timestamp::Call as TimestampCall;54pub use timestamp::Call as TimestampCall;
5555
56/// Importing a nft pallet56/// Re-export a nft pallet
57/// TODO: Check this re-export. Is this safe and good style?
58extern crate nft;
57pub use nft;59pub use nft::*;
5860
59/// An index to a block.61/// An index to a block.
60pub type BlockNumber = u32;62pub type BlockNumber = u32;
111 spec_name: create_runtime_str!("nft"),113 spec_name: create_runtime_str!("nft"),
112 impl_name: create_runtime_str!("nft"),114 impl_name: create_runtime_str!("nft"),
113 authoring_version: 1,115 authoring_version: 1,
114 spec_version: 1,116 spec_version: 2,
115 impl_version: 1,117 impl_version: 1,
116 apis: RUNTIME_API_VERSIONS,118 apis: RUNTIME_API_VERSIONS,
117 transaction_version: 1,119 transaction_version: 1,
318 Balances: balances::{Module, Call, Storage, Config<T>, Event<T>},320 Balances: balances::{Module, Call, Storage, Config<T>, Event<T>},
319 TransactionPayment: transaction_payment::{Module, Storage},321 TransactionPayment: transaction_payment::{Module, Storage},
320 Sudo: sudo::{Module, Call, Config<T>, Storage, Event<T>},322 Sudo: sudo::{Module, Call, Config<T>, Storage, Event<T>},
321 Nft: nft::{Module, Call, Storage, Event<T>},323 Nft: nft::{Module, Call, Config<T>, Storage, Event<T>},
322 }324 }
323);325);
324326
addedtests/src/blocks-production.test.tsdiffbeforeafterboth

no changes

modifiedtests/src/config.tsdiffbeforeafterboth
22
3const config = {3const config = {
4 substrateUrl: process.env.substrateUrl || 'ws://127.0.0.1:9944',4 substrateUrl: process.env.substrateUrl || 'ws://127.0.0.1:9944',
5 customTypes: process.env.customTypes || `{5 customTypes: process.env.customTypes || `{
6 "Schedule": {6 "Schedule": {
7 "version": "u32",7 "version": "u32",
8 "put_code_per_byte_cost": "Gas",8 "put_code_per_byte_cost": "Gas",
9 "grow_mem_cost": "Gas",9 "grow_mem_cost": "Gas",
10 "regular_op_cost": "Gas",10 "regular_op_cost": "Gas",
11 "return_data_per_byte_cost": "Gas",11 "return_data_per_byte_cost": "Gas",
12 "event_data_per_byte_cost": "Gas",12 "event_data_per_byte_cost": "Gas",
13 "event_per_topic_cost": "Gas",13 "event_per_topic_cost": "Gas",
14 "event_base_cost": "Gas",14 "event_base_cost": "Gas",
15 "call_base_cost": "Gas",15 "call_base_cost": "Gas",
16 "instantiate_base_cost": "Gas",16 "instantiate_base_cost": "Gas",
17 "dispatch_base_cost": "Gas",17 "dispatch_base_cost": "Gas",
18 "sandbox_data_read_cost": "Gas",18 "sandbox_data_read_cost": "Gas",
19 "sandbox_data_write_cost": "Gas",19 "sandbox_data_write_cost": "Gas",
20 "transfer_cost": "Gas",20 "transfer_cost": "Gas",
21 "instantiate_cost": "Gas",21 "instantiate_cost": "Gas",
22 "max_event_topics": "u32",22 "max_event_topics": "u32",
23 "max_stack_height": "u32",23 "max_stack_height": "u32",
24 "max_memory_pages": "u32",24 "max_memory_pages": "u32",
25 "max_table_size": "u32",25 "max_table_size": "u32",
26 "enable_println": "bool",26 "enable_println": "bool",
27 "max_subject_len": "u32"27 "max_subject_len": "u32"
28 },28 },
29 "CollectionMode": {29 "CollectionMode": {
30 "_enum": {30 "_enum": {
31 "Invalid": null,31 "Invalid": null,
32 "NFT": "u32",32 "NFT": "u32",
33 "Fungible": "u32",33 "Fungible": "u32",
34 "ReFungible": "(u32, u32)"34 "ReFungible": "(u32, u32)"
35 }35 }
36 },36 },
37 "NftItemType": {37 "Ownership": {
38 "Owner": "AccountId",
39 "Fraction": "u128"
40 },
41 "FungibleItemType": {
42 "Collection": "u64",
43 "Owner": "AccountId",
44 "Value": "u128"
45 },
46 "ReFungibleItemType": {
47 "Collection": "u64",
48 "Owner": "Vec<Ownership>",
49 "Data": "Vec<u8>"
50 },
51 "NftItemType": {
38 "Collection": "u64",52 "Collection": "u64",
39 "Owner": "AccountId",53 "Owner": "AccountId",
40 "Data": "Vec<u8>"54 "Data": "Vec<u8>"
41 },55 },
42 "Ownership": {56 "Ownership": {
43 "owner": "AccountId",57 "owner": "AccountId",
44 "fraction": "u128"58 "fraction": "u128"
45 },59 },
46 "ReFungibleItemType": {60 "ReFungibleItemType": {
47 "Collection": "u64",61 "Collection": "u64",
48 "Owner": "Vec<Ownership<AccountId>>",62 "Owner": "Vec<Ownership<AccountId>>",
49 "Data": "Vec<u8>"63 "Data": "Vec<u8>"
50 },64 },
51 "CollectionType": {65 "CollectionType": {
52 "Owner": "AccountId",66 "Owner": "AccountId",
53 "Mode": "CollectionMode",67 "Mode": "CollectionMode",
54 "Access": "u8",68 "Access": "u8",
55 "DecimalPoints": "u32",69 "DecimalPoints": "u32",
56 "Name": "Vec<u16>",70 "Name": "Vec<u16>",
57 "Description": "Vec<u16>",71 "Description": "Vec<u16>",
58 "TokenPrefix": "Vec<u8>",72 "TokenPrefix": "Vec<u8>",
59 "CustomDataSize": "u32",73 "CustomDataSize": "u32",
60 "OffchainSchema": "Vec<u8>",74 "MintMode": "bool",
75 "OffchainSchema": "Vec<u8>",
61 "Sponsor": "AccountId",76 "Sponsor": "AccountId",
62 "UnconfirmedSponsor": "AccountId"77 "UnconfirmedSponsor": "AccountId"
78 },
79 "ApprovePermissions": {
80 "Approved": "AccountId",
81 "Amount": "u64"
63 },82 },
64 "RawData": "Vec<u8>",83 "RawData": "Vec<u8>",
65 "Address": "AccountId",84 "Address": "AccountId",
66 "LookupSource": "AccountId",85 "LookupSource": "AccountId",
67 "Weight": "u64"86 "Weight": "u64"
68 }`87 }`
69}88}
7089
71export default config;90export default config;
modifiedtests/src/connection.test.tsdiffbeforeafterboth
15 });15 });
16 });16 });
1717
18 it('Cannot connect to 0.0.0.0', () => {18 it('Cannot connect to 255.255.255.255', async () => {
19 const neverConnectProvider = new WsProvider('ws://0.0.0.0:9944');19 const neverConnectProvider = new WsProvider('ws://255.255.255.255:9944');
20 expect((async () => {20 await expect((async () => {
21 await usingApi(async api => {21 await usingApi(async api => {
22 const health = await api.rpc.system.health();22 const health = await api.rpc.system.health();
23 }, { provider: neverConnectProvider });23 }, { provider: neverConnectProvider });
modifiedtests/src/substrate/promisify-substrate.tsdiffbeforeafterboth
44
5export default function promisifySubstrate<T extends (...args: any[]) => any>(api: ApiPromise, action: T): (...args: Parameters<T>) => Promise<PromiseType<ReturnType<T>>> {5export default function promisifySubstrate<T extends (...args: any[]) => any>(api: ApiPromise, action: T): (...args: Parameters<T>) => Promise<PromiseType<ReturnType<T>>> {
6 return (...args: Parameters<T>) => {6 return (...args: Parameters<T>) => {
7 const promise = new Promise<PromiseType<ReturnType<T>>>((resolve, reject) => {7 const promise = new Promise<PromiseType<ReturnType<T>>>((resolve: ((result: PromiseType<ReturnType<T>>) => void) | undefined, reject: ((error: any) => void) | undefined) => {
8 const cleanup = () => {8 const cleanup = () => {
9 api.off('disconnected', fail);9 api.off('disconnected', fail);
10 api.off('error', fail);10 api.off('error', fail);
11 resolve = undefined;
12 reject = undefined;
11 };13 };
1214
13 const success = (r: any) => {15 const success = (r: any) => {
14 cleanup();16 resolve && resolve(r);
15 resolve(r);17 cleanup();
16 };18 };
17 const fail = (error: any) => {19 const fail = (error: any) => {
18 cleanup();20 reject && reject(error);
19 reject(error);21 cleanup();
20 };22 };
21 23
22 api.on('disconnected', fail);24 api.on('disconnected', fail);
modifiedtests/src/substrate/substrate-api.tsdiffbeforeafterboth
1010
11export default async function usingApi(action: (api: ApiPromise) => Promise<void>, settings: ApiOptions | undefined = undefined): Promise<void> {11export default async function usingApi(action: (api: ApiPromise) => Promise<void>, settings: ApiOptions | undefined = undefined): Promise<void> {
12 settings = settings || defaultApiOptions();12 settings = settings || defaultApiOptions();
13 let api: ApiPromise | undefined = undefined;13 let api: ApiPromise = new ApiPromise(settings);
1414
15 try {15 try {
16 api = new ApiPromise(settings);
17 await promisifySubstrate(api, () => api && api.isReady)();16 await promisifySubstrate(api, async () => {
18 await action(api);17 if(api) {
18 await api.isReadyOrError;
19 await action(api);
20 }
21 })();
19 } finally {22 } finally {
20 api && api.disconnect();23 await api.disconnect();
21 }24 }
22}25}