difftreelog
Warnings fixed
in: master
5 files changed
pallets/nft-charge-transaction/src/lib.rsdiffbeforeafterboth--- a/pallets/nft-charge-transaction/src/lib.rs
+++ b/pallets/nft-charge-transaction/src/lib.rs
@@ -135,10 +135,10 @@
}
// check errors
- let error = <pallet_nft_transaction_payment::Module<T>>::check_error(who, call);
- match error {
- Err(error) => return Err(error),
- Ok(error) => {}
+ let _error = <pallet_nft_transaction_payment::Module<T>>::check_error(who, call);
+ match _error {
+ Err(_error) => return Err(_error),
+ Ok(_error) => {}
};
// Determine who is paying transaction fee based on ecnomic model
pallets/nft-transaction-payment/src/lib.rsdiffbeforeafterboth--- a/pallets/nft-transaction-payment/src/lib.rs
+++ b/pallets/nft-transaction-payment/src/lib.rs
@@ -140,7 +140,7 @@
},
Some(pallet_nft::Call::set_variable_meta_data(collection_id, item_id, data)) => {
- Self::withdraw_set_variable_meta_data(who, collection_id, item_id, &data)
+ Self::withdraw_set_variable_meta_data(collection_id, item_id, &data)
},
_ => None,
};
@@ -175,7 +175,7 @@
let collection = pallet_nft::CollectionById::<T>::get(collection_id)?;
// sponsor timeout
- let block_number = <frame_system::Module<T>>::block_number() as T::BlockNumber;
+ let block_number = <frame_system::Pallet<T>>::block_number() as T::BlockNumber;
let limit = collection.limits.sponsor_transfer_timeout;
if pallet_nft::CreateItemBasket::<T>::contains_key((collection_id, &who)) {
@@ -212,7 +212,7 @@
let collection_mode = collection.mode.clone();
// sponsor timeout
- let block_number = <frame_system::Module<T>>::block_number() as T::BlockNumber;
+ let block_number = <frame_system::Pallet<T>>::block_number() as T::BlockNumber;
sponsor_transfer = match collection_mode {
CollectionMode::NFT => {
@@ -246,7 +246,7 @@
limits.fungible_sponsor_transfer_timeout
};
- let block_number = <frame_system::Module<T>>::block_number() as T::BlockNumber;
+ let block_number = <frame_system::Pallet<T>>::block_number() as T::BlockNumber;
let mut sponsored = true;
if pallet_nft::FungibleTransferBasket::<T>::contains_key(collection_id, who) {
let last_tx_block = pallet_nft::FungibleTransferBasket::<T>::get(collection_id, who);
@@ -299,7 +299,6 @@
}
pub fn withdraw_set_variable_meta_data(
- who: &T::AccountId,
collection_id: &CollectionId,
item_id: &TokenId,
data: &Vec<u8>,
@@ -317,7 +316,7 @@
data.len() <= collection.limits.sponsored_data_size as usize
{
if let Some(rate_limit) = collection.limits.sponsored_data_rate_limit {
- let block_number = <frame_system::Module<T>>::block_number() as T::BlockNumber;
+ let block_number = <frame_system::Pallet<T>>::block_number() as T::BlockNumber;
if pallet_nft::VariableMetaDataBasket::<T>::get(collection_id, item_id)
.map(|last_block| block_number - last_block > rate_limit)
@@ -358,7 +357,7 @@
let mut sponsor_transfer = false;
if pallet_nft::ContractSponsoringRateLimit::<T>::contains_key(called_contract.clone()) {
let last_tx_block = pallet_nft::ContractSponsorBasket::<T>::get((&called_contract, &who));
- let block_number = <frame_system::Module<T>>::block_number() as T::BlockNumber;
+ let block_number = <frame_system::Pallet<T>>::block_number() as T::BlockNumber;
let rate_limit = pallet_nft::ContractSponsoringRateLimit::<T>::get(&called_contract);
let limit_time = last_tx_block + rate_limit;
@@ -390,7 +389,7 @@
T::AccountId: UncheckedFrom<T::Hash>
{
- let new_contract_address = <pallet_contracts::Module<T>>::contract_address(
+ let new_contract_address = <pallet_contracts::Pallet<T>>::contract_address(
&who,
code_hash,
salt,
pallets/nft/src/lib.rsdiffbeforeafterboth1//2// This file is subject to the terms and conditions defined in3// file 'LICENSE', which is part of this source code package.4//56#![recursion_limit = "1024"]78#![cfg_attr(not(feature = "std"), no_std)]910#[cfg(feature = "std")]11pub use std::*;1213#[cfg(feature = "std")]14pub use serde::*;1516use codec::{Decode, Encode};17pub use frame_support::{18 construct_runtime, decl_event, decl_module, decl_storage, decl_error,19 dispatch::DispatchResult,20 ensure, fail, parameter_types,21 traits::{22 Currency, ExistenceRequirement, Get, Imbalance, KeyOwnerProofSystem, OnUnbalanced,23 Randomness, IsSubType, WithdrawReasons,24 },25 weights::{26 constants::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_PER_SECOND},27 DispatchInfo, GetDispatchInfo, IdentityFee, Pays, PostDispatchInfo, Weight,28 WeightToFeePolynomial, DispatchClass,29 },30 StorageValue,31 transactional,32};3334use frame_system::{self as system, ensure_signed, ensure_root};35use sp_runtime::sp_std::prelude::Vec;36use core::ops::{Deref, DerefMut};37use nft_data_structs::{38 MAX_DECIMAL_POINTS, MAX_SPONSOR_TIMEOUT, MAX_TOKEN_OWNERSHIP, MAX_REFUNGIBLE_PIECES,39 AccessMode, ChainLimits, Collection, CreateItemData, CollectionLimits,40 CollectionId, CollectionMode, TokenId, 41 SchemaVersion, SponsorshipState, Ownership,42 NftItemType, FungibleItemType, ReFungibleItemType43};4445#[cfg(test)]46mod mock;4748#[cfg(test)]49mod tests;5051mod default_weights;5253#[cfg(feature = "runtime-benchmarks")]54mod benchmarking;5556pub trait WeightInfo {57 fn create_collection() -> Weight;58 fn destroy_collection() -> Weight;59 fn add_to_white_list() -> Weight;60 fn remove_from_white_list() -> Weight;61 fn set_public_access_mode() -> Weight;62 fn set_mint_permission() -> Weight;63 fn change_collection_owner() -> Weight;64 fn add_collection_admin() -> Weight;65 fn remove_collection_admin() -> Weight;66 fn set_collection_sponsor() -> Weight;67 fn confirm_sponsorship() -> Weight;68 fn remove_collection_sponsor() -> Weight;69 fn create_item(s: usize) -> Weight;70 fn burn_item() -> Weight;71 fn transfer() -> Weight;72 fn approve() -> Weight;73 fn transfer_from() -> Weight;74 fn set_offchain_schema() -> Weight;75 fn set_const_on_chain_schema() -> Weight;76 fn set_variable_on_chain_schema() -> Weight;77 fn set_variable_meta_data() -> Weight;78 fn enable_contract_sponsoring() -> Weight;79 fn set_schema_version() -> Weight;80 fn set_chain_limits() -> Weight;81 fn set_contract_sponsoring_rate_limit() -> Weight;82 fn set_variable_meta_data_sponsoring_rate_limit() -> Weight;83 fn toggle_contract_white_list() -> Weight;84 fn add_to_contract_white_list() -> Weight;85 fn remove_from_contract_white_list() -> Weight;86 fn set_collection_limits() -> Weight;87}8889decl_error! {90 /// Error for non-fungible-token module.91 pub enum Error for Module<T: Config> {92 /// Total collections bound exceeded.93 TotalCollectionsLimitExceeded,94 /// Decimal_points parameter must be lower than MAX_DECIMAL_POINTS constant, currently it is 30.95 CollectionDecimalPointLimitExceeded, 96 /// Collection name can not be longer than 63 char.97 CollectionNameLimitExceeded, 98 /// Collection description can not be longer than 255 char.99 CollectionDescriptionLimitExceeded, 100 /// Token prefix can not be longer than 15 char.101 CollectionTokenPrefixLimitExceeded,102 /// This collection does not exist.103 CollectionNotFound,104 /// Item not exists.105 TokenNotFound,106 /// Admin not found107 AdminNotFound,108 /// Arithmetic calculation overflow.109 NumOverflow, 110 /// Account already has admin role.111 AlreadyAdmin, 112 /// You do not own this collection.113 NoPermission,114 /// This address is not set as sponsor, use setCollectionSponsor first.115 ConfirmUnsetSponsorFail,116 /// Collection is not in mint mode.117 PublicMintingNotAllowed,118 /// Sender parameter and item owner must be equal.119 MustBeTokenOwner,120 /// Item balance not enough.121 TokenValueTooLow,122 /// Size of item is too large.123 NftSizeLimitExceeded,124 /// No approve found125 ApproveNotFound,126 /// Requested value more than approved.127 TokenValueNotEnough,128 /// Only approved addresses can call this method.129 ApproveRequired,130 /// Address is not in white list.131 AddresNotInWhiteList,132 /// Number of collection admins bound exceeded.133 CollectionAdminsLimitExceeded,134 /// Owned tokens by a single address bound exceeded.135 AddressOwnershipLimitExceeded,136 /// Length of items properties must be greater than 0.137 EmptyArgument,138 /// const_data exceeded data limit.139 TokenConstDataLimitExceeded,140 /// variable_data exceeded data limit.141 TokenVariableDataLimitExceeded,142 /// Not NFT item data used to mint in NFT collection.143 NotNftDataUsedToMintNftCollectionToken,144 /// Not Fungible item data used to mint in Fungible collection.145 NotFungibleDataUsedToMintFungibleCollectionToken,146 /// Not Re Fungible item data used to mint in Re Fungible collection.147 NotReFungibleDataUsedToMintReFungibleCollectionToken,148 /// Unexpected collection type.149 UnexpectedCollectionType,150 /// Can't store metadata in fungible tokens.151 CantStoreMetadataInFungibleTokens,152 /// Collection token limit exceeded153 CollectionTokenLimitExceeded,154 /// Account token limit exceeded per collection155 AccountTokenLimitExceeded,156 /// Collection limit bounds per collection exceeded157 CollectionLimitBoundsExceeded,158 /// Tried to enable permissions which are only permitted to be disabled159 OwnerPermissionsCantBeReverted,160 /// Schema data size limit bound exceeded161 SchemaDataLimitExceeded,162 /// Maximum refungibility exceeded163 WrongRefungiblePieces,164 /// createRefungible should be called with one owner165 BadCreateRefungibleCall,166 }167}168169pub struct CollectionHandle<T: system::Config> {170 pub id: CollectionId,171 pub collection: Collection<T>,172}173174impl<T: frame_system::Config> Deref for CollectionHandle<T> {175 type Target = Collection<T>;176177 fn deref(&self) -> &Self::Target {178 &self.collection179 }180}181182impl<T: frame_system::Config> DerefMut for CollectionHandle<T> {183 fn deref_mut(&mut self) -> &mut Self::Target {184 &mut self.collection185 }186}187188pub trait Config: system::Config + Sized {189 type Event: From<Event<Self>> + Into<<Self as system::Config>::Event>;190191 /// Weight information for extrinsics in this pallet.192 type WeightInfo: WeightInfo;193194 type Currency: Currency<Self::AccountId>;195 type CollectionCreationPrice: Get<<<Self as Config>::Currency as Currency<Self::AccountId>>::Balance>;196 type TreasuryAccountId: Get<Self::AccountId>;197}198199// # Used definitions200//201// ## User control levels202//203// chain-controlled - key is uncontrolled by user204// i.e autoincrementing index205// can use non-cryptographic hash206// real - key is controlled by user207// but it is hard to generate enough colliding values, i.e owner of signed txs208// can use non-cryptographic hash209// controlled - key is completly controlled by users210// i.e maps with mutable keys211// should use cryptographic hash212//213// ## User control level downgrade reasons214//215// ?1 - chain-controlled -> controlled216// collections/tokens can be destroyed, resulting in massive holes217// ?2 - chain-controlled -> controlled218// same as ?1, but can be only added, resulting in easier exploitation219// ?3 - real -> controlled220// no confirmation required, so addresses can be easily generated221decl_storage! {222 trait Store for Module<T: Config> as Nft {223224 //#region Private members225 /// Id of next collection226 CreatedCollectionCount: u32;227 /// Used for migrations228 ChainVersion: u64;229 /// Id of last collection token230 /// Collection id (controlled?1)231 ItemListIndex: map hasher(blake2_128_concat) CollectionId => TokenId;232 //#endregion233234 //#region Chain limits struct235 pub ChainLimit get(fn chain_limit) config(): ChainLimits;236 //#endregion237238 //#region Bound counters239 /// Amount of collections destroyed, used for total amount tracking with240 /// CreatedCollectionCount241 DestroyedCollectionCount: u32;242 /// Total amount of account owned tokens (NFTs + RFTs + unique fungibles)243 /// Account id (real)244 pub AccountItemCount get(fn account_item_count): map hasher(twox_64_concat) T::AccountId => u32;245 //#endregion246247 //#region Basic collections248 /// Collection info249 /// Collection id (controlled?1)250 pub CollectionById get(fn collection_id) config(): map hasher(blake2_128_concat) CollectionId => Option<Collection<T>> = None;251 /// List of collection admins252 /// Collection id (controlled?2)253 pub AdminList get(fn admin_list_collection): map hasher(blake2_128_concat) CollectionId => Vec<T::AccountId>;254 /// Whitelisted collection users255 /// Collection id (controlled?2), user id (controlled?3)256 pub WhiteList get(fn white_list): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) T::AccountId => bool;257 //#endregion258259 /// How many of collection items user have260 /// Collection id (controlled?2), account id (real)261 pub Balance get(fn balance_count): double_map hasher(blake2_128_concat) CollectionId, hasher(twox_64_concat) T::AccountId => u128;262263 /// Amount of items which spender can transfer out of owners account (via transferFrom)264 /// Collection id (controlled?2), (token id (controlled ?2) + owner account id (real) + spender account id (controlled?3))265 /// TODO: Off chain worker should remove from this map when token gets removed266 pub Allowances get(fn approved): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) (TokenId, T::AccountId, T::AccountId) => u128;267268 //#region Item collections269 /// Collection id (controlled?2), token id (controlled?1)270 pub NftItemList get(fn nft_item_id) config(): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId => Option<NftItemType<T::AccountId>>;271 /// Collection id (controlled?2), owner (controlled?2)272 pub FungibleItemList get(fn fungible_item_id) config(): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) T::AccountId => FungibleItemType;273 /// Collection id (controlled?2), token id (controlled?1)274 pub ReFungibleItemList get(fn refungible_item_id) config(): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId => Option<ReFungibleItemType<T::AccountId>>;275 //#endregion276277 //#region Index list278 /// Collection id (controlled?2), tokens owner (controlled?2)279 pub AddressTokens get(fn address_tokens): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) T::AccountId => Vec<TokenId>;280 //#endregion281282 //#region Tokens transfer rate limit baskets283 /// (Collection id (controlled?2), who created (real))284 /// TODO: Off chain worker should remove from this map when collection gets removed285 pub CreateItemBasket get(fn create_item_basket): map hasher(blake2_128_concat) (CollectionId, T::AccountId) => T::BlockNumber;286 /// Collection id (controlled?2), token id (controlled?2)287 pub NftTransferBasket get(fn nft_transfer_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId => T::BlockNumber;288 /// Collection id (controlled?2), owning user (real)289 pub FungibleTransferBasket get(fn fungible_transfer_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(twox_64_concat) T::AccountId => T::BlockNumber;290 /// Collection id (controlled?2), token id (controlled?2)291 pub ReFungibleTransferBasket get(fn refungible_transfer_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId => T::BlockNumber;292 //#endregion293294 /// Variable metadata sponsoring295 /// Collection id (controlled?2), token id (controlled?2)296 pub VariableMetaDataBasket get(fn variable_meta_data_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId => Option<T::BlockNumber> = None;297 298 //#region Contract Sponsorship and Ownership299 /// Contract address (real)300 pub ContractOwner get(fn contract_owner): map hasher(twox_64_concat) T::AccountId => Option<T::AccountId>;301 /// Contract address (real)302 pub ContractSelfSponsoring get(fn contract_self_sponsoring): map hasher(twox_64_concat) T::AccountId => bool;303 /// (Contract address(real), caller (real))304 pub ContractSponsorBasket get(fn contract_sponsor_basket): map hasher(twox_64_concat) (T::AccountId, T::AccountId) => T::BlockNumber;305 /// Contract address (real)306 pub ContractSponsoringRateLimit get(fn contract_sponsoring_rate_limit): map hasher(twox_64_concat) T::AccountId => T::BlockNumber;307 /// Contract address (real)308 pub ContractWhiteListEnabled get(fn contract_white_list_enabled): map hasher(twox_64_concat) T::AccountId => bool; 309 /// Contract address (real) => Whitelisted user (controlled?3)310 pub ContractWhiteList get(fn contract_white_list): double_map hasher(twox_64_concat) T::AccountId, hasher(blake2_128_concat) T::AccountId => bool; 311 //#endregion312 }313 add_extra_genesis {314 build(|config: &GenesisConfig<T>| {315 // Modification of storage316 for (_num, _c) in &config.collection_id {317 <Module<T>>::init_collection(_c);318 }319320 for (_num, _c, _i) in &config.nft_item_id {321 <Module<T>>::init_nft_token(*_c, _i);322 }323324 for (collection_id, account_id, fungible_item) in &config.fungible_item_id {325 <Module<T>>::init_fungible_token(*collection_id, account_id, fungible_item);326 }327328 for (_num, _c, _i) in &config.refungible_item_id {329 <Module<T>>::init_refungible_token(*_c, _i);330 }331 })332 }333}334335decl_event!(336 pub enum Event<T>337 where338 AccountId = <T as system::Config>::AccountId,339 {340 /// New collection was created341 /// 342 /// # Arguments343 /// 344 /// * collection_id: Globally unique identifier of newly created collection.345 /// 346 /// * mode: [CollectionMode] converted into u8.347 /// 348 /// * account_id: Collection owner.349 CollectionCreated(CollectionId, u8, AccountId),350351 /// New item was created.352 /// 353 /// # Arguments354 /// 355 /// * collection_id: Id of the collection where item was created.356 /// 357 /// * item_id: Id of an item. Unique within the collection.358 ///359 /// * recipient: Owner of newly created item 360 ItemCreated(CollectionId, TokenId, AccountId),361362 /// Collection item was burned.363 /// 364 /// # Arguments365 /// 366 /// collection_id.367 /// 368 /// item_id: Identifier of burned NFT.369 ItemDestroyed(CollectionId, TokenId),370371 /// Item was transferred372 ///373 /// * collection_id: Id of collection to which item is belong374 ///375 /// * item_id: Id of an item376 ///377 /// * sender: Original owner of item378 ///379 /// * recipient: New owner of item380 ///381 /// * amount: Always 1 for NFT382 Transfer(CollectionId, TokenId, AccountId, AccountId, u128),383384 /// * collection_id385 ///386 /// * item_id387 ///388 /// * sender389 ///390 /// * spender391 ///392 /// * amount393 Approved(CollectionId, TokenId, AccountId, AccountId, u128),394 }395);396397decl_module! {398 pub struct Module<T: Config> for enum Call 399 where 400 origin: T::Origin401 {402 fn deposit_event() = default;403 type Error = Error<T>;404405 fn on_initialize(_now: T::BlockNumber) -> Weight {406 0407 }408409 /// This method creates a Collection of NFTs. Each Token may have multiple properties encoded as an array of bytes of certain length. The initial owner and admin of the collection are set to the address that signed the transaction. Both addresses can be changed later.410 /// 411 /// # Permissions412 /// 413 /// * Anyone.414 /// 415 /// # Arguments416 /// 417 /// * collection_name: UTF-16 string with collection name (limit 64 characters), will be stored as zero-terminated.418 /// 419 /// * collection_description: UTF-16 string with collection description (limit 256 characters), will be stored as zero-terminated.420 /// 421 /// * token_prefix: UTF-8 string with token prefix.422 /// 423 /// * mode: [CollectionMode] collection type and type dependent data.424 // returns collection ID425 #[weight = <T as Config>::WeightInfo::create_collection()]426 #[transactional]427 pub fn create_collection(origin,428 collection_name: Vec<u16>,429 collection_description: Vec<u16>,430 token_prefix: Vec<u8>,431 mode: CollectionMode) -> DispatchResult {432433 // Anyone can create a collection434 let who = ensure_signed(origin)?;435436 // Take a (non-refundable) deposit of collection creation437 let mut imbalance = <<<T as Config>::Currency as Currency<T::AccountId>>::PositiveImbalance>::zero();438 imbalance.subsume(<<T as Config>::Currency as Currency<T::AccountId>>::deposit_creating(439 &T::TreasuryAccountId::get(),440 T::CollectionCreationPrice::get(),441 ));442 <T as Config>::Currency::settle(443 &who,444 imbalance,445 WithdrawReasons::TRANSFER,446 ExistenceRequirement::KeepAlive,447 ).map_err(|_| Error::<T>::NoPermission)?;448449 let decimal_points = match mode {450 CollectionMode::Fungible(points) => points,451 _ => 0452 };453454 let chain_limit = ChainLimit::get();455456 let created_count = CreatedCollectionCount::get();457 let destroyed_count = DestroyedCollectionCount::get();458459 // bound Total number of collections460 ensure!(created_count - destroyed_count < chain_limit.collection_numbers_limit, Error::<T>::TotalCollectionsLimitExceeded);461462 // check params463 ensure!(decimal_points <= MAX_DECIMAL_POINTS, Error::<T>::CollectionDecimalPointLimitExceeded);464 ensure!(collection_name.len() <= 64, Error::<T>::CollectionNameLimitExceeded);465 ensure!(collection_description.len() <= 256, Error::<T>::CollectionDescriptionLimitExceeded);466 ensure!(token_prefix.len() <= 16, Error::<T>::CollectionTokenPrefixLimitExceeded);467468 // Generate next collection ID469 let next_id = created_count470 .checked_add(1)471 .ok_or(Error::<T>::NumOverflow)?;472473 CreatedCollectionCount::put(next_id);474475 let limits = CollectionLimits {476 sponsored_data_size: chain_limit.custom_data_limit,477 ..Default::default()478 };479480 // Create new collection481 let new_collection = Collection {482 owner: who.clone(),483 name: collection_name,484 mode: mode.clone(),485 mint_mode: false,486 access: AccessMode::Normal,487 description: collection_description,488 decimal_points: decimal_points,489 token_prefix: token_prefix,490 offchain_schema: Vec::new(),491 schema_version: SchemaVersion::ImageURL,492 sponsorship: SponsorshipState::Disabled,493 variable_on_chain_schema: Vec::new(),494 const_on_chain_schema: Vec::new(),495 limits,496 };497498 // Add new collection to map499 <CollectionById<T>>::insert(next_id, new_collection);500501 // call event502 Self::deposit_event(RawEvent::CollectionCreated(next_id, mode.into(), who.clone()));503504 Ok(())505 }506507 /// **DANGEROUS**: Destroys collection and all NFTs within this collection. Users irrecoverably lose their assets and may lose real money.508 /// 509 /// # Permissions510 /// 511 /// * Collection Owner.512 /// 513 /// # Arguments514 /// 515 /// * collection_id: collection to destroy.516 #[weight = <T as Config>::WeightInfo::destroy_collection()]517 #[transactional]518 pub fn destroy_collection(origin, collection_id: CollectionId) -> DispatchResult {519520 let sender = ensure_signed(origin)?;521 let collection = Self::get_collection(collection_id)?;522 Self::check_owner_permissions(&collection, sender)?;523 if !collection.limits.owner_can_destroy {524 fail!(Error::<T>::NoPermission);525 }526527 <AddressTokens<T>>::remove_prefix(collection_id);528 <Allowances<T>>::remove_prefix(collection_id);529 <Balance<T>>::remove_prefix(collection_id);530 <ItemListIndex>::remove(collection_id);531 <AdminList<T>>::remove(collection_id);532 <CollectionById<T>>::remove(collection_id);533 <WhiteList<T>>::remove_prefix(collection_id);534535 <NftItemList<T>>::remove_prefix(collection_id);536 <FungibleItemList<T>>::remove_prefix(collection_id);537 <ReFungibleItemList<T>>::remove_prefix(collection_id);538539 <NftTransferBasket<T>>::remove_prefix(collection_id);540 <FungibleTransferBasket<T>>::remove_prefix(collection_id);541 <ReFungibleTransferBasket<T>>::remove_prefix(collection_id);542543 <VariableMetaDataBasket<T>>::remove_prefix(collection_id);544545 DestroyedCollectionCount::put(DestroyedCollectionCount::get()546 .checked_add(1)547 .ok_or(Error::<T>::NumOverflow)?);548549 Ok(())550 }551552 /// Add an address to white list.553 /// 554 /// # Permissions555 /// 556 /// * Collection Owner557 /// * Collection Admin558 /// 559 /// # Arguments560 /// 561 /// * collection_id.562 /// 563 /// * address.564 #[weight = <T as Config>::WeightInfo::add_to_white_list()]565 #[transactional]566 pub fn add_to_white_list(origin, collection_id: CollectionId, address: T::AccountId) -> DispatchResult{567568 let sender = ensure_signed(origin)?;569 let collection = Self::get_collection(collection_id)?;570 Self::check_owner_or_admin_permissions(&collection, sender)?;571572 <WhiteList<T>>::insert(collection_id, address, true);573 574 Ok(())575 }576577 /// Remove an address from white list.578 /// 579 /// # Permissions580 /// 581 /// * Collection Owner582 /// * Collection Admin583 /// 584 /// # Arguments585 /// 586 /// * collection_id.587 /// 588 /// * address.589 #[weight = <T as Config>::WeightInfo::remove_from_white_list()]590 #[transactional]591 pub fn remove_from_white_list(origin, collection_id: CollectionId, address: T::AccountId) -> DispatchResult{592593 let sender = ensure_signed(origin)?;594 let collection = Self::get_collection(collection_id)?;595 Self::check_owner_or_admin_permissions(&collection, sender)?;596597 <WhiteList<T>>::remove(collection_id, address);598599 Ok(())600 }601602 /// Toggle between normal and white list access for the methods with access for `Anyone`.603 /// 604 /// # Permissions605 /// 606 /// * Collection Owner.607 /// 608 /// # Arguments609 /// 610 /// * collection_id.611 /// 612 /// * mode: [AccessMode]613 #[weight = <T as Config>::WeightInfo::set_public_access_mode()]614 #[transactional]615 pub fn set_public_access_mode(origin, collection_id: CollectionId, mode: AccessMode) -> DispatchResult616 {617 let sender = ensure_signed(origin)?;618619 let mut target_collection = Self::get_collection(collection_id)?;620 Self::check_owner_permissions(&target_collection, sender)?;621 target_collection.access = mode;622 Self::save_collection(target_collection);623624 Ok(())625 }626627 /// Allows Anyone to create tokens if:628 /// * White List is enabled, and629 /// * Address is added to white list, and630 /// * This method was called with True parameter631 /// 632 /// # Permissions633 /// * Collection Owner634 ///635 /// # Arguments636 /// 637 /// * collection_id.638 /// 639 /// * mint_permission: Boolean parameter. If True, allows minting to Anyone with conditions above.640 #[weight = <T as Config>::WeightInfo::set_mint_permission()]641 #[transactional]642 pub fn set_mint_permission(origin, collection_id: CollectionId, mint_permission: bool) -> DispatchResult643 {644 let sender = ensure_signed(origin)?;645646 let mut target_collection = Self::get_collection(collection_id)?;647 Self::check_owner_permissions(&target_collection, sender)?;648 target_collection.mint_mode = mint_permission;649 Self::save_collection(target_collection);650651 Ok(())652 }653654 /// Change the owner of the collection.655 /// 656 /// # Permissions657 /// 658 /// * Collection Owner.659 /// 660 /// # Arguments661 /// 662 /// * collection_id.663 /// 664 /// * new_owner.665 #[weight = <T as Config>::WeightInfo::change_collection_owner()]666 #[transactional]667 pub fn change_collection_owner(origin, collection_id: CollectionId, new_owner: T::AccountId) -> DispatchResult {668669 let sender = ensure_signed(origin)?;670 let mut target_collection = Self::get_collection(collection_id)?;671 Self::check_owner_permissions(&target_collection, sender)?;672 target_collection.owner = new_owner;673 Self::save_collection(target_collection);674675 Ok(())676 }677678 /// Adds an admin of the Collection.679 /// NFT Collection can be controlled by multiple admin addresses (some which can also be servers, for example). Admins can issue and burn NFTs, as well as add and remove other admins, but cannot change NFT or Collection ownership. 680 /// 681 /// # Permissions682 /// 683 /// * Collection Owner.684 /// * Collection Admin.685 /// 686 /// # Arguments687 /// 688 /// * collection_id: ID of the Collection to add admin for.689 /// 690 /// * new_admin_id: Address of new admin to add.691 #[weight = <T as Config>::WeightInfo::add_collection_admin()]692 #[transactional]693 pub fn add_collection_admin(origin, collection_id: CollectionId, new_admin_id: T::AccountId) -> DispatchResult {694695 let sender = ensure_signed(origin)?;696 let collection = Self::get_collection(collection_id)?;697 Self::check_owner_or_admin_permissions(&collection, sender)?;698 let mut admin_arr = <AdminList<T>>::get(collection_id);699700 match admin_arr.binary_search(&new_admin_id) {701 Ok(_) => {},702 Err(idx) => {703 let limits = ChainLimit::get();704 ensure!(admin_arr.len() < limits.collections_admins_limit as usize, Error::<T>::CollectionAdminsLimitExceeded);705 admin_arr.insert(idx, new_admin_id);706 <AdminList<T>>::insert(collection_id, admin_arr);707 }708 }709 Ok(())710 }711712 /// Remove admin address of the Collection. An admin address can remove itself. List of admins may become empty, in which case only Collection Owner will be able to add an Admin.713 ///714 /// # Permissions715 /// 716 /// * Collection Owner.717 /// * Collection Admin.718 /// 719 /// # Arguments720 /// 721 /// * collection_id: ID of the Collection to remove admin for.722 /// 723 /// * account_id: Address of admin to remove.724 #[weight = <T as Config>::WeightInfo::remove_collection_admin()]725 #[transactional]726 pub fn remove_collection_admin(origin, collection_id: CollectionId, account_id: T::AccountId) -> DispatchResult {727728 let sender = ensure_signed(origin)?;729 let collection = Self::get_collection(collection_id)?;730 Self::check_owner_or_admin_permissions(&collection, sender)?;731 let mut admin_arr = <AdminList<T>>::get(collection_id);732733 match admin_arr.binary_search(&account_id) {734 Ok(idx) => {735 admin_arr.remove(idx);736 <AdminList<T>>::insert(collection_id, admin_arr);737 },738 Err(_) => {}739 }740 Ok(())741 }742743 /// # Permissions744 /// 745 /// * Collection Owner746 /// 747 /// # Arguments748 /// 749 /// * collection_id.750 /// 751 /// * new_sponsor.752 #[weight = <T as Config>::WeightInfo::set_collection_sponsor()]753 #[transactional]754 pub fn set_collection_sponsor(origin, collection_id: CollectionId, new_sponsor: T::AccountId) -> DispatchResult {755756 let sender = ensure_signed(origin)?;757 let mut target_collection = Self::get_collection(collection_id)?;758 Self::check_owner_permissions(&target_collection, sender)?;759760 target_collection.sponsorship = SponsorshipState::Unconfirmed(new_sponsor);761 Self::save_collection(target_collection);762763 Ok(())764 }765766 /// # Permissions767 /// 768 /// * Sponsor.769 /// 770 /// # Arguments771 /// 772 /// * collection_id.773 #[weight = <T as Config>::WeightInfo::confirm_sponsorship()]774 #[transactional]775 pub fn confirm_sponsorship(origin, collection_id: CollectionId) -> DispatchResult {776777 let sender = ensure_signed(origin)?;778779 let mut target_collection = Self::get_collection(collection_id)?;780 ensure!(781 target_collection.sponsorship.pending_sponsor() == Some(&sender),782 Error::<T>::ConfirmUnsetSponsorFail783 );784785 target_collection.sponsorship = SponsorshipState::Confirmed(sender);786 Self::save_collection(target_collection);787788 Ok(())789 }790791 /// Switch back to pay-per-own-transaction model.792 ///793 /// # Permissions794 ///795 /// * Collection owner.796 /// 797 /// # Arguments798 /// 799 /// * collection_id.800 #[weight = <T as Config>::WeightInfo::remove_collection_sponsor()]801 #[transactional]802 pub fn remove_collection_sponsor(origin, collection_id: CollectionId) -> DispatchResult {803804 let sender = ensure_signed(origin)?;805806 let mut target_collection = Self::get_collection(collection_id)?;807 Self::check_owner_permissions(&target_collection, sender)?;808809 target_collection.sponsorship = SponsorshipState::Disabled;810 Self::save_collection(target_collection);811812 Ok(())813 }814815 /// This method creates a concrete instance of NFT Collection created with CreateCollection method.816 /// 817 /// # Permissions818 /// 819 /// * Collection Owner.820 /// * Collection Admin.821 /// * Anyone if822 /// * White List is enabled, and823 /// * Address is added to white list, and824 /// * MintPermission is enabled (see SetMintPermission method)825 /// 826 /// # Arguments827 /// 828 /// * collection_id: ID of the collection.829 /// 830 /// * owner: Address, initial owner of the NFT.831 ///832 /// * data: Token data to store on chain.833 // #[weight =834 // (130_000_000 as Weight)835 // .saturating_add((2135 as Weight).saturating_mul((properties.len() as u64) as Weight))836 // .saturating_add(RocksDbWeight::get().reads(10 as Weight))837 // .saturating_add(RocksDbWeight::get().writes(8 as Weight))]838839 #[weight = <T as Config>::WeightInfo::create_item(data.len())]840 #[transactional]841 pub fn create_item(origin, collection_id: CollectionId, owner: T::AccountId, data: CreateItemData) -> DispatchResult {842 let sender = ensure_signed(origin)?;843 Self::create_item_internal(sender, collection_id, owner, data)844 }845846 /// This method creates multiple items in a collection created with CreateCollection method.847 /// 848 /// # Permissions849 /// 850 /// * Collection Owner.851 /// * Collection Admin.852 /// * Anyone if853 /// * White List is enabled, and854 /// * Address is added to white list, and855 /// * MintPermission is enabled (see SetMintPermission method)856 /// 857 /// # Arguments858 /// 859 /// * collection_id: ID of the collection.860 /// 861 /// * itemsData: Array items properties. Each property is an array of bytes itself, see [create_item].862 /// 863 /// * owner: Address, initial owner of the NFT.864 #[weight = <T as Config>::WeightInfo::create_item(items_data.into_iter()865 .map(|data| { data.len() })866 .sum())]867 #[transactional]868 pub fn create_multiple_items(origin, collection_id: CollectionId, owner: T::AccountId, items_data: Vec<CreateItemData>) -> DispatchResult {869870 ensure!(items_data.len() > 0, Error::<T>::EmptyArgument);871 let sender = ensure_signed(origin)?;872873 let target_collection = Self::get_collection(collection_id)?;874875 Self::can_create_items_in_collection(&target_collection, &sender, &owner, items_data.len() as u32)?;876877 for data in &items_data {878 Self::validate_create_item_args(&target_collection, data)?;879 }880 for data in &items_data {881 Self::create_item_no_validation(&target_collection, owner.clone(), data.clone())?;882 }883884 Ok(())885 }886887 /// Destroys a concrete instance of NFT.888 /// 889 /// # Permissions890 /// 891 /// * Collection Owner.892 /// * Collection Admin.893 /// * Current NFT Owner.894 /// 895 /// # Arguments896 /// 897 /// * collection_id: ID of the collection.898 /// 899 /// * item_id: ID of NFT to burn.900 #[weight = <T as Config>::WeightInfo::burn_item()]901 #[transactional]902 pub fn burn_item(origin, collection_id: CollectionId, item_id: TokenId, value: u128) -> DispatchResult {903904 let sender = ensure_signed(origin)?;905906 // Transfer permissions check907 let target_collection = Self::get_collection(collection_id)?;908 ensure!(909 Self::is_item_owner(sender.clone(), &target_collection, item_id) ||910 (911 target_collection.limits.owner_can_transfer &&912 Self::is_owner_or_admin_permissions(&target_collection, sender.clone())913 ),914 Error::<T>::NoPermission915 );916917 if target_collection.access == AccessMode::WhiteList {918 Self::check_white_list(&target_collection, &sender)?;919 }920921 match target_collection.mode922 {923 CollectionMode::NFT => Self::burn_nft_item(&target_collection, item_id)?,924 CollectionMode::Fungible(_) => Self::burn_fungible_item(&sender, &target_collection, value)?,925 CollectionMode::ReFungible => Self::burn_refungible_item(&target_collection, item_id, &sender)?,926 _ => ()927 };928929 // call event930 Self::deposit_event(RawEvent::ItemDestroyed(target_collection.id, item_id));931932 Ok(())933 }934935 /// Change ownership of the token.936 /// 937 /// # Permissions938 /// 939 /// * Collection Owner940 /// * Collection Admin941 /// * Current NFT owner942 ///943 /// # Arguments944 /// 945 /// * recipient: Address of token recipient.946 /// 947 /// * collection_id.948 /// 949 /// * item_id: ID of the item950 /// * Non-Fungible Mode: Required.951 /// * Fungible Mode: Ignored.952 /// * Re-Fungible Mode: Required.953 /// 954 /// * value: Amount to transfer.955 /// * Non-Fungible Mode: Ignored956 /// * Fungible Mode: Must specify transferred amount957 /// * Re-Fungible Mode: Must specify transferred portion (between 0 and 1)958 #[weight = <T as Config>::WeightInfo::transfer()]959 #[transactional]960 pub fn transfer(origin, recipient: T::AccountId, collection_id: CollectionId, item_id: TokenId, value: u128) -> DispatchResult {961 let sender = ensure_signed(origin)?;962 let collection = Self::get_collection(collection_id)?;963964 Self::transfer_internal(sender, recipient, &collection, item_id, value)965 }966967 /// Set, change, or remove approved address to transfer the ownership of the NFT.968 /// 969 /// # Permissions970 /// 971 /// * Collection Owner972 /// * Collection Admin973 /// * Current NFT owner974 /// 975 /// # Arguments976 /// 977 /// * approved: Address that is approved to transfer this NFT or zero (if needed to remove approval).978 /// 979 /// * collection_id.980 /// 981 /// * item_id: ID of the item.982 #[weight = <T as Config>::WeightInfo::approve()]983 #[transactional]984 pub fn approve(origin, spender: T::AccountId, collection_id: CollectionId, item_id: TokenId, amount: u128) -> DispatchResult {985986 let sender = ensure_signed(origin)?;987 let target_collection = Self::get_collection(collection_id)?;988989 Self::token_exists(&target_collection, item_id)?;990991 // Transfer permissions check992 let bypasses_limits = target_collection.limits.owner_can_transfer &&993 Self::is_owner_or_admin_permissions(994 &target_collection,995 sender.clone(),996 );997998 let allowance_limit = if bypasses_limits {999 None1000 } else if let Some(amount) = Self::owned_amount(1001 sender.clone(),1002 &target_collection,1003 item_id,1004 ) {1005 Some(amount)1006 } else {1007 fail!(Error::<T>::NoPermission);1008 };10091010 if target_collection.access == AccessMode::WhiteList {1011 Self::check_white_list(&target_collection, &sender)?;1012 Self::check_white_list(&target_collection, &spender)?;1013 }10141015 let allowance: u128 = amount1016 .checked_add(<Allowances<T>>::get(collection_id, (item_id, &sender, &spender)))1017 .ok_or(Error::<T>::NumOverflow)?;1018 if let Some(limit) = allowance_limit {1019 ensure!(limit >= allowance, Error::<T>::TokenValueTooLow);1020 }1021 <Allowances<T>>::insert(collection_id, (item_id, sender.clone(), spender.clone()), allowance);10221023 Self::deposit_event(RawEvent::Approved(target_collection.id, item_id, sender, spender, allowance));1024 Ok(())1025 }1026 1027 /// Change ownership of a NFT on behalf of the owner. See Approve method for additional information. After this method executes, the approval is removed so that the approved address will not be able to transfer this NFT again from this owner.1028 /// 1029 /// # Permissions1030 /// * Collection Owner1031 /// * Collection Admin1032 /// * Current NFT owner1033 /// * Address approved by current NFT owner1034 /// 1035 /// # Arguments1036 /// 1037 /// * from: Address that owns token.1038 /// 1039 /// * recipient: Address of token recipient.1040 /// 1041 /// * collection_id.1042 /// 1043 /// * item_id: ID of the item.1044 /// 1045 /// * value: Amount to transfer.1046 #[weight = <T as Config>::WeightInfo::transfer_from()]1047 #[transactional]1048 pub fn transfer_from(origin, from: T::AccountId, recipient: T::AccountId, collection_id: CollectionId, item_id: TokenId, value: u128 ) -> DispatchResult {10491050 let sender = ensure_signed(origin)?;1051 let target_collection = Self::get_collection(collection_id)?;10521053 // Check approval1054 let approval: u128 = <Allowances<T>>::get(collection_id, (item_id, &from, &sender));10551056 // Limits check1057 Self::is_correct_transfer(&target_collection, &recipient)?;10581059 // Transfer permissions check 1060 ensure!(1061 approval >= value || 1062 (1063 target_collection.limits.owner_can_transfer &&1064 Self::is_owner_or_admin_permissions(&target_collection, sender.clone())1065 ),1066 Error::<T>::NoPermission1067 );10681069 if target_collection.access == AccessMode::WhiteList {1070 Self::check_white_list(&target_collection, &sender)?;1071 Self::check_white_list(&target_collection, &recipient)?;1072 }10731074 // Reduce approval by transferred amount or remove if remaining approval drops to 01075 if approval.saturating_sub(value) > 0 {1076 <Allowances<T>>::insert(collection_id, (item_id, &from, &sender), approval - value);1077 }1078 else {1079 <Allowances<T>>::remove(collection_id, (item_id, &from, &sender));1080 }10811082 match target_collection.mode1083 {1084 CollectionMode::NFT => Self::transfer_nft(&target_collection, item_id, from.clone(), recipient.clone())?,1085 CollectionMode::Fungible(_) => Self::transfer_fungible(&target_collection, value, &from, &recipient)?,1086 CollectionMode::ReFungible => Self::transfer_refungible(&target_collection, item_id, value, from.clone(), recipient.clone())?,1087 _ => ()1088 };10891090 Self::deposit_event(RawEvent::Transfer(target_collection.id, item_id, from, recipient, value));1091 Ok(())1092 }10931094 // #[weight = 0]1095 // pub fn safe_transfer_from(origin, collection_id: CollectionId, item_id: TokenId, new_owner: T::AccountId) -> DispatchResult {10961097 // // let no_perm_mes = "You do not have permissions to modify this collection";1098 // // ensure!(<ApprovedList<T>>::contains_key((collection_id, item_id)), no_perm_mes);1099 // // let list_itm = <ApprovedList<T>>::get((collection_id, item_id));1100 // // ensure!(list_itm.contains(&new_owner.clone()), no_perm_mes);11011102 // // // on_nft_received call11031104 // // Self::transfer(origin, collection_id, item_id, new_owner)?;11051106 // Ok(())1107 // }11081109 /// Set off-chain data schema.1110 /// 1111 /// # Permissions1112 /// 1113 /// * Collection Owner1114 /// * Collection Admin1115 /// 1116 /// # Arguments1117 /// 1118 /// * collection_id.1119 /// 1120 /// * schema: String representing the offchain data schema.1121 #[weight = <T as Config>::WeightInfo::set_variable_meta_data()]1122 #[transactional]1123 pub fn set_variable_meta_data (1124 origin,1125 collection_id: CollectionId,1126 item_id: TokenId,1127 data: Vec<u8>1128 ) -> DispatchResult {1129 let sender = ensure_signed(origin)?;1130 1131 let target_collection = Self::get_collection(collection_id)?;1132 Self::token_exists(&target_collection, item_id)?;11331134 ensure!(ChainLimit::get().custom_data_limit >= data.len() as u32, Error::<T>::TokenVariableDataLimitExceeded);11351136 // Modify permissions check1137 ensure!(Self::is_item_owner(sender.clone(), &target_collection, item_id) ||1138 Self::is_owner_or_admin_permissions(&target_collection, sender.clone()),1139 Error::<T>::NoPermission);11401141 match target_collection.mode1142 {1143 CollectionMode::NFT => Self::set_nft_variable_data(&target_collection, item_id, data)?,1144 CollectionMode::ReFungible => Self::set_re_fungible_variable_data(&target_collection, item_id, data)?,1145 CollectionMode::Fungible(_) => fail!(Error::<T>::CantStoreMetadataInFungibleTokens),1146 _ => fail!(Error::<T>::UnexpectedCollectionType)1147 };11481149 Ok(())1150 }1151 1152 /// Set schema standard1153 /// ImageURL1154 /// Unique1155 /// 1156 /// # Permissions1157 /// 1158 /// * Collection Owner1159 /// * Collection Admin1160 /// 1161 /// # Arguments1162 /// 1163 /// * collection_id.1164 /// 1165 /// * schema: SchemaVersion: enum1166 #[weight = <T as Config>::WeightInfo::set_schema_version()]1167 #[transactional]1168 pub fn set_schema_version(1169 origin,1170 collection_id: CollectionId,1171 version: SchemaVersion1172 ) -> DispatchResult {1173 let sender = ensure_signed(origin)?;1174 let mut target_collection = Self::get_collection(collection_id)?;1175 Self::check_owner_or_admin_permissions(&target_collection, sender.clone())?;1176 target_collection.schema_version = version;1177 Self::save_collection(target_collection);11781179 Ok(())1180 }11811182 /// Set off-chain data schema.1183 /// 1184 /// # Permissions1185 /// 1186 /// * Collection Owner1187 /// * Collection Admin1188 /// 1189 /// # Arguments1190 /// 1191 /// * collection_id.1192 /// 1193 /// * schema: String representing the offchain data schema.1194 #[weight = <T as Config>::WeightInfo::set_offchain_schema()]1195 #[transactional]1196 pub fn set_offchain_schema(1197 origin,1198 collection_id: CollectionId,1199 schema: Vec<u8>1200 ) -> DispatchResult {1201 let sender = ensure_signed(origin)?;1202 let mut target_collection = Self::get_collection(collection_id)?;1203 Self::check_owner_or_admin_permissions(&target_collection, sender.clone())?;12041205 // check schema limit1206 ensure!(schema.len() as u32 <= ChainLimit::get().offchain_schema_limit, "");12071208 target_collection.offchain_schema = schema;1209 Self::save_collection(target_collection);12101211 Ok(())1212 }12131214 /// Set const on-chain data schema.1215 /// 1216 /// # Permissions1217 /// 1218 /// * Collection Owner1219 /// * Collection Admin1220 /// 1221 /// # Arguments1222 /// 1223 /// * collection_id.1224 /// 1225 /// * schema: String representing the const on-chain data schema.1226 #[weight = <T as Config>::WeightInfo::set_const_on_chain_schema()]1227 #[transactional]1228 pub fn set_const_on_chain_schema (1229 origin,1230 collection_id: CollectionId,1231 schema: Vec<u8>1232 ) -> DispatchResult {1233 let sender = ensure_signed(origin)?;1234 let mut target_collection = Self::get_collection(collection_id)?;1235 Self::check_owner_or_admin_permissions(&target_collection, sender.clone())?;12361237 // check schema limit1238 ensure!(schema.len() as u32 <= ChainLimit::get().const_on_chain_schema_limit, "");12391240 target_collection.const_on_chain_schema = schema;1241 Self::save_collection(target_collection);12421243 Ok(())1244 }12451246 /// Set variable on-chain data schema.1247 /// 1248 /// # Permissions1249 /// 1250 /// * Collection Owner1251 /// * Collection Admin1252 /// 1253 /// # Arguments1254 /// 1255 /// * collection_id.1256 /// 1257 /// * schema: String representing the variable on-chain data schema.1258 #[weight = <T as Config>::WeightInfo::set_const_on_chain_schema()]1259 #[transactional]1260 pub fn set_variable_on_chain_schema (1261 origin,1262 collection_id: CollectionId,1263 schema: Vec<u8>1264 ) -> DispatchResult {1265 let sender = ensure_signed(origin)?;1266 let mut target_collection = Self::get_collection(collection_id)?;1267 Self::check_owner_or_admin_permissions(&target_collection, sender.clone())?;12681269 // check schema limit1270 ensure!(schema.len() as u32 <= ChainLimit::get().variable_on_chain_schema_limit, "");12711272 target_collection.variable_on_chain_schema = schema;1273 Self::save_collection(target_collection);12741275 Ok(())1276 }12771278 // Sudo permissions function1279 #[weight = <T as Config>::WeightInfo::set_chain_limits()]1280 #[transactional]1281 pub fn set_chain_limits(1282 origin,1283 limits: ChainLimits1284 ) -> DispatchResult {12851286 #[cfg(not(feature = "runtime-benchmarks"))]1287 ensure_root(origin)?;12881289 <ChainLimit>::put(limits);1290 Ok(())1291 }12921293 /// Enable smart contract self-sponsoring.1294 /// 1295 /// # Permissions1296 /// 1297 /// * Contract Owner1298 /// 1299 /// # Arguments1300 /// 1301 /// * contract address1302 /// * enable flag1303 /// 1304 #[weight = <T as Config>::WeightInfo::enable_contract_sponsoring()]1305 #[transactional]1306 pub fn enable_contract_sponsoring(1307 origin,1308 contract_address: T::AccountId,1309 enable: bool1310 ) -> DispatchResult {13111312 let sender = ensure_signed(origin)?;13131314 #[cfg(feature = "runtime-benchmarks")]1315 <ContractOwner<T>>::insert(contract_address.clone(), sender.clone());13161317 Self::ensure_contract_owned(sender, &contract_address)?;13181319 <ContractSelfSponsoring<T>>::insert(contract_address, enable);1320 Ok(())1321 }13221323 /// Set the rate limit for contract sponsoring to specified number of blocks.1324 /// 1325 /// If not set (has the default value of 0 blocks), the sponsoring will be disabled. 1326 /// If set to the number B (for blocks), the transactions will be sponsored with a rate 1327 /// limit of B, i.e. fees for every transaction sent to this smart contract will be paid 1328 /// from contract endowment if there are at least B blocks between such transactions. 1329 /// Nonetheless, if transactions are sent more frequently, the fees are paid by the sender.1330 /// 1331 /// # Permissions1332 /// 1333 /// * Contract Owner1334 /// 1335 /// # Arguments1336 /// 1337 /// -`contract_address`: Address of the contract to sponsor1338 /// -`rate_limit`: Number of blocks to wait until the next sponsored transaction is allowed1339 /// 1340 #[weight = <T as Config>::WeightInfo::set_contract_sponsoring_rate_limit()]1341 #[transactional]1342 pub fn set_contract_sponsoring_rate_limit(1343 origin,1344 contract_address: T::AccountId,1345 rate_limit: T::BlockNumber1346 ) -> DispatchResult {1347 let sender = ensure_signed(origin)?;13481349 #[cfg(feature = "runtime-benchmarks")]1350 <ContractOwner<T>>::insert(contract_address.clone(), sender.clone());13511352 Self::ensure_contract_owned(sender, &contract_address)?;1353 <ContractSponsoringRateLimit<T>>::insert(contract_address, rate_limit);1354 Ok(())1355 }13561357 /// Enable the white list for a contract. Only addresses added to the white list with addToContractWhiteList will be able to call this smart contract.1358 /// 1359 /// # Permissions1360 /// 1361 /// * Address that deployed smart contract.1362 /// 1363 /// # Arguments1364 /// 1365 /// -`contract_address`: Address of the contract.1366 /// 1367 /// - `enable`: . 1368 #[weight = <T as Config>::WeightInfo::toggle_contract_white_list()]1369 #[transactional]1370 pub fn toggle_contract_white_list(1371 origin,1372 contract_address: T::AccountId,1373 enable: bool1374 ) -> DispatchResult {1375 let sender = ensure_signed(origin)?;13761377 #[cfg(feature = "runtime-benchmarks")]1378 <ContractOwner<T>>::insert(contract_address.clone(), sender.clone());13791380 Self::ensure_contract_owned(sender, &contract_address)?;1381 if enable {1382 <ContractWhiteListEnabled<T>>::insert(contract_address, true);1383 } else {1384 <ContractWhiteListEnabled<T>>::remove(contract_address);1385 }1386 Ok(())1387 }1388 1389 /// Add an address to smart contract white list.1390 /// 1391 /// # Permissions1392 /// 1393 /// * Address that deployed smart contract.1394 /// 1395 /// # Arguments1396 /// 1397 /// -`contract_address`: Address of the contract.1398 ///1399 /// -`account_address`: Address to add.1400 #[weight = <T as Config>::WeightInfo::add_to_contract_white_list()]1401 #[transactional]1402 pub fn add_to_contract_white_list(1403 origin,1404 contract_address: T::AccountId,1405 account_address: T::AccountId1406 ) -> DispatchResult {1407 let sender = ensure_signed(origin)?;14081409 #[cfg(feature = "runtime-benchmarks")]1410 <ContractOwner<T>>::insert(contract_address.clone(), sender.clone());1411 1412 Self::ensure_contract_owned(sender, &contract_address)?; 1413 <ContractWhiteList<T>>::insert(contract_address, account_address, true);1414 Ok(())1415 }14161417 /// Remove an address from smart contract white list.1418 /// 1419 /// # Permissions1420 /// 1421 /// * Address that deployed smart contract.1422 /// 1423 /// # Arguments1424 /// 1425 /// -`contract_address`: Address of the contract.1426 ///1427 /// -`account_address`: Address to remove.1428 #[weight = <T as Config>::WeightInfo::remove_from_contract_white_list()]1429 #[transactional]1430 pub fn remove_from_contract_white_list(1431 origin,1432 contract_address: T::AccountId,1433 account_address: T::AccountId1434 ) -> DispatchResult {1435 let sender = ensure_signed(origin)?;14361437 #[cfg(feature = "runtime-benchmarks")]1438 <ContractOwner<T>>::insert(contract_address.clone(), sender.clone());14391440 Self::ensure_contract_owned(sender, &contract_address)?;1441 <ContractWhiteList<T>>::remove(contract_address, account_address);1442 Ok(())1443 }14441445 #[weight = <T as Config>::WeightInfo::set_collection_limits()]1446 #[transactional]1447 pub fn set_collection_limits(1448 origin,1449 collection_id: u32,1450 new_limits: CollectionLimits<T::BlockNumber>,1451 ) -> DispatchResult {1452 let sender = ensure_signed(origin)?;1453 let mut target_collection = Self::get_collection(collection_id)?;1454 Self::check_owner_permissions(&target_collection, sender.clone())?;1455 let old_limits = &target_collection.limits;1456 let chain_limits = ChainLimit::get();14571458 // collection bounds1459 ensure!(new_limits.sponsor_transfer_timeout <= MAX_SPONSOR_TIMEOUT &&1460 new_limits.account_token_ownership_limit <= MAX_TOKEN_OWNERSHIP && 1461 new_limits.sponsored_data_size <= chain_limits.custom_data_limit,1462 Error::<T>::CollectionLimitBoundsExceeded);14631464 // token_limit check prev1465 ensure!(old_limits.token_limit >= new_limits.token_limit, Error::<T>::CollectionTokenLimitExceeded);1466 ensure!(new_limits.token_limit > 0, Error::<T>::CollectionTokenLimitExceeded);14671468 ensure!(1469 (old_limits.owner_can_transfer || !new_limits.owner_can_transfer) &&1470 (old_limits.owner_can_destroy || !new_limits.owner_can_destroy),1471 Error::<T>::OwnerPermissionsCantBeReverted,1472 );14731474 target_collection.limits = new_limits;1475 Self::save_collection(target_collection);14761477 Ok(())1478 } 1479 }1480}14811482impl<T: Config> Module<T> {1483 pub fn create_item_internal(sender: T::AccountId, collection_id: CollectionId, owner: T::AccountId, data: CreateItemData) -> DispatchResult {1484 let target_collection = Self::get_collection(collection_id)?;14851486 Self::can_create_items_in_collection(&target_collection, &sender, &owner, 1)?;1487 Self::validate_create_item_args(&target_collection, &data)?;1488 Self::create_item_no_validation(&target_collection, owner, data)?;14891490 Ok(())1491 }14921493 pub fn transfer_internal(sender: T::AccountId, recipient: T::AccountId, target_collection: &CollectionHandle<T>, item_id: TokenId, value: u128) -> DispatchResult {1494 // Limits check1495 Self::is_correct_transfer(target_collection, &recipient)?;14961497 // Transfer permissions check1498 ensure!(Self::is_item_owner(sender.clone(), target_collection, item_id) ||1499 Self::is_owner_or_admin_permissions(target_collection, sender.clone()),1500 Error::<T>::NoPermission);15011502 if target_collection.access == AccessMode::WhiteList {1503 Self::check_white_list(target_collection, &sender)?;1504 Self::check_white_list(target_collection, &recipient)?;1505 }15061507 match target_collection.mode1508 {1509 CollectionMode::NFT => Self::transfer_nft(target_collection, item_id, sender.clone(), recipient.clone())?,1510 CollectionMode::Fungible(_) => Self::transfer_fungible(target_collection, value, &sender, &recipient)?,1511 CollectionMode::ReFungible => Self::transfer_refungible(target_collection, item_id, value, sender.clone(), recipient.clone())?,1512 _ => ()1513 };15141515 Self::deposit_event(RawEvent::Transfer(target_collection.id, item_id, sender, recipient, value));15161517 Ok(())1518 }151915201521 fn is_correct_transfer(collection: &CollectionHandle<T>, recipient: &T::AccountId) -> DispatchResult {1522 let collection_id = collection.id;15231524 // check token limit and account token limit1525 let account_items: u32 = <AddressTokens<T>>::get(collection_id, recipient).len() as u32;1526 ensure!(collection.limits.account_token_ownership_limit > account_items, Error::<T>::AccountTokenLimitExceeded);1527 1528 Ok(())1529 }15301531 fn can_create_items_in_collection(collection: &CollectionHandle<T>, sender: &T::AccountId, owner: &T::AccountId, amount: u32) -> DispatchResult {1532 let collection_id = collection.id;15331534 // check token limit and account token limit1535 let total_items: u32 = ItemListIndex::get(collection_id)1536 .checked_add(amount)1537 .ok_or(Error::<T>::CollectionTokenLimitExceeded)?;1538 let account_items: u32 = (<AddressTokens<T>>::get(collection_id, owner).len() as u32)1539 .checked_add(amount)1540 .ok_or(Error::<T>::AccountTokenLimitExceeded)?;1541 ensure!(collection.limits.token_limit >= total_items, Error::<T>::CollectionTokenLimitExceeded);1542 ensure!(collection.limits.account_token_ownership_limit >= account_items, Error::<T>::AccountTokenLimitExceeded);15431544 if !Self::is_owner_or_admin_permissions(collection, sender.clone()) {1545 ensure!(collection.mint_mode == true, Error::<T>::PublicMintingNotAllowed);1546 Self::check_white_list(collection, owner)?;1547 Self::check_white_list(collection, sender)?;1548 }15491550 Ok(())1551 }15521553 fn validate_create_item_args(target_collection: &CollectionHandle<T>, data: &CreateItemData) -> DispatchResult {1554 match target_collection.mode1555 {1556 CollectionMode::NFT => {1557 if let CreateItemData::NFT(data) = data {1558 // check sizes1559 ensure!(ChainLimit::get().custom_data_limit >= data.const_data.len() as u32, Error::<T>::TokenConstDataLimitExceeded);1560 ensure!(ChainLimit::get().custom_data_limit >= data.variable_data.len() as u32, Error::<T>::TokenVariableDataLimitExceeded);1561 } else {1562 fail!(Error::<T>::NotNftDataUsedToMintNftCollectionToken);1563 }1564 },1565 CollectionMode::Fungible(_) => {1566 if let CreateItemData::Fungible(_) = data {1567 } else {1568 fail!(Error::<T>::NotFungibleDataUsedToMintFungibleCollectionToken);1569 }1570 },1571 CollectionMode::ReFungible => {1572 if let CreateItemData::ReFungible(data) = data {15731574 // check sizes1575 ensure!(ChainLimit::get().custom_data_limit >= data.const_data.len() as u32, Error::<T>::TokenConstDataLimitExceeded);1576 ensure!(ChainLimit::get().custom_data_limit >= data.variable_data.len() as u32, Error::<T>::TokenVariableDataLimitExceeded);15771578 // Check refungibility limits1579 ensure!(data.pieces <= MAX_REFUNGIBLE_PIECES, Error::<T>::WrongRefungiblePieces);1580 ensure!(data.pieces > 0, Error::<T>::WrongRefungiblePieces);1581 } else {1582 fail!(Error::<T>::NotReFungibleDataUsedToMintReFungibleCollectionToken);1583 }1584 },1585 _ => { fail!(Error::<T>::UnexpectedCollectionType); }1586 };15871588 Ok(())1589 }15901591 fn create_item_no_validation(collection: &CollectionHandle<T>, owner: T::AccountId, data: CreateItemData) -> DispatchResult {1592 match data1593 {1594 CreateItemData::NFT(data) => {1595 let item = NftItemType {1596 owner: owner.clone(),1597 const_data: data.const_data,1598 variable_data: data.variable_data1599 };16001601 Self::add_nft_item(collection, item)?;1602 },1603 CreateItemData::Fungible(data) => {1604 Self::add_fungible_item(collection, &owner, data.value)?;1605 },1606 CreateItemData::ReFungible(data) => {1607 let mut owner_list = Vec::new();1608 owner_list.push(Ownership {owner: owner.clone(), fraction: data.pieces});16091610 let item = ReFungibleItemType {1611 owner: owner_list,1612 const_data: data.const_data,1613 variable_data: data.variable_data1614 };16151616 Self::add_refungible_item(collection, item)?;1617 }1618 };16191620 Ok(())1621 }16221623 fn add_fungible_item(collection: &CollectionHandle<T>, owner: &T::AccountId, value: u128) -> DispatchResult {1624 let collection_id = collection.id;16251626 // Does new owner already have an account?1627 let balance: u128 = <FungibleItemList<T>>::get(collection_id, owner).value;16281629 // Mint 1630 let item = FungibleItemType {1631 value: balance.checked_add(value).ok_or(Error::<T>::NumOverflow)?,1632 };1633 <FungibleItemList<T>>::insert(collection_id, (*owner).clone(), item);16341635 // Update balance1636 let new_balance = <Balance<T>>::get(collection_id, owner)1637 .checked_add(value)1638 .ok_or(Error::<T>::NumOverflow)?;1639 <Balance<T>>::insert(collection_id, (*owner).clone(), new_balance);16401641 Self::deposit_event(RawEvent::ItemCreated(collection_id, 0, owner.clone()));1642 Ok(())1643 }16441645 fn add_refungible_item(collection: &CollectionHandle<T>, item: ReFungibleItemType<T::AccountId>) -> DispatchResult {1646 let collection_id = collection.id;16471648 let current_index = <ItemListIndex>::get(collection_id)1649 .checked_add(1)1650 .ok_or(Error::<T>::NumOverflow)?;1651 let itemcopy = item.clone();16521653 ensure!(1654 item.owner.len() == 1,1655 Error::<T>::BadCreateRefungibleCall,1656 );1657 let item_owner = item.owner.first().expect("only one owner is defined");16581659 let value = item_owner.fraction;1660 let owner = item_owner.owner.clone();16611662 Self::add_token_index(collection_id, current_index, &owner)?;16631664 <ItemListIndex>::insert(collection_id, current_index);1665 <ReFungibleItemList<T>>::insert(collection_id, current_index, itemcopy);16661667 // Update balance1668 let new_balance = <Balance<T>>::get(collection_id, &owner)1669 .checked_add(value)1670 .ok_or(Error::<T>::NumOverflow)?;1671 <Balance<T>>::insert(collection_id, owner.clone(), new_balance);16721673 Self::deposit_event(RawEvent::ItemCreated(collection_id, current_index, owner));1674 Ok(())1675 }16761677 fn add_nft_item(collection: &CollectionHandle<T>, item: NftItemType<T::AccountId>) -> DispatchResult {1678 let collection_id = collection.id;16791680 let current_index = <ItemListIndex>::get(collection_id)1681 .checked_add(1)1682 .ok_or(Error::<T>::NumOverflow)?;16831684 let item_owner = item.owner.clone();1685 Self::add_token_index(collection_id, current_index, &item.owner)?;16861687 <ItemListIndex>::insert(collection_id, current_index);1688 <NftItemList<T>>::insert(collection_id, current_index, item);16891690 // Update balance1691 let new_balance = <Balance<T>>::get(collection_id, item_owner.clone())1692 .checked_add(1)1693 .ok_or(Error::<T>::NumOverflow)?;1694 <Balance<T>>::insert(collection_id, item_owner.clone(), new_balance);16951696 Self::deposit_event(RawEvent::ItemCreated(collection_id, current_index, item_owner));1697 Ok(())1698 }16991700 fn burn_refungible_item(1701 collection: &CollectionHandle<T>,1702 item_id: TokenId,1703 owner: &T::AccountId,1704 ) -> DispatchResult {1705 let collection_id = collection.id;17061707 let mut token = <ReFungibleItemList<T>>::get(collection_id, item_id)1708 .ok_or(Error::<T>::TokenNotFound)?;1709 let rft_balance = token1710 .owner1711 .iter()1712 .find(|&i| i.owner == *owner)1713 .ok_or(Error::<T>::TokenNotFound)?;1714 Self::remove_token_index(collection_id, item_id, owner)?;17151716 // update balance1717 let new_balance = <Balance<T>>::get(collection_id, rft_balance.owner.clone())1718 .checked_sub(rft_balance.fraction)1719 .ok_or(Error::<T>::NumOverflow)?;1720 <Balance<T>>::insert(collection_id, rft_balance.owner.clone(), new_balance);17211722 // Re-create owners list with sender removed1723 let index = token1724 .owner1725 .iter()1726 .position(|i| i.owner == *owner)1727 .expect("owned item is exists");1728 token.owner.remove(index);1729 let owner_count = token.owner.len();17301731 // Burn the token completely if this was the last (only) owner1732 if owner_count == 0 {1733 <ReFungibleItemList<T>>::remove(collection_id, item_id);1734 <VariableMetaDataBasket<T>>::remove(collection_id, item_id);1735 }1736 else {1737 <ReFungibleItemList<T>>::insert(collection_id, item_id, token);1738 }17391740 Ok(())1741 }17421743 fn burn_nft_item(collection: &CollectionHandle<T>, item_id: TokenId) -> DispatchResult {1744 let collection_id = collection.id;17451746 let item = <NftItemList<T>>::get(collection_id, item_id)1747 .ok_or(Error::<T>::TokenNotFound)?;1748 Self::remove_token_index(collection_id, item_id, &item.owner)?;17491750 // update balance1751 let new_balance = <Balance<T>>::get(collection_id, &item.owner)1752 .checked_sub(1)1753 .ok_or(Error::<T>::NumOverflow)?;1754 <Balance<T>>::insert(collection_id, item.owner.clone(), new_balance);1755 <NftItemList<T>>::remove(collection_id, item_id);1756 <VariableMetaDataBasket<T>>::remove(collection_id, item_id);17571758 Ok(())1759 }17601761 fn burn_fungible_item(owner: &T::AccountId, collection: &CollectionHandle<T>, value: u128) -> DispatchResult {1762 let collection_id = collection.id;17631764 let mut balance = <FungibleItemList<T>>::get(collection_id, owner);1765 ensure!(balance.value >= value, Error::<T>::TokenValueNotEnough);17661767 // update balance1768 let new_balance = <Balance<T>>::get(collection_id, owner)1769 .checked_sub(value)1770 .ok_or(Error::<T>::NumOverflow)?;1771 <Balance<T>>::insert(collection_id, (*owner).clone(), new_balance);17721773 if balance.value - value > 0 {1774 balance.value -= value;1775 <FungibleItemList<T>>::insert(collection_id, (*owner).clone(), balance);1776 }1777 else {1778 <FungibleItemList<T>>::remove(collection_id, owner);1779 }17801781 Ok(())1782 }17831784 pub fn get_collection(collection_id: CollectionId) -> Result<CollectionHandle<T>, sp_runtime::DispatchError> {1785 Ok(<CollectionById<T>>::get(collection_id)1786 .map(|collection| CollectionHandle {1787 id: collection_id,1788 collection1789 })1790 .ok_or(Error::<T>::CollectionNotFound)?)1791 }17921793 fn save_collection(collection: CollectionHandle<T>) {1794 <CollectionById<T>>::insert(collection.id, collection.collection);1795 }17961797 fn check_owner_permissions(target_collection: &CollectionHandle<T>, subject: T::AccountId) -> DispatchResult {1798 ensure!(1799 subject == target_collection.owner,1800 Error::<T>::NoPermission1801 );18021803 Ok(())1804 }18051806 fn is_owner_or_admin_permissions(collection: &CollectionHandle<T>, subject: T::AccountId) -> bool {1807 subject == collection.owner || <AdminList<T>>::get(collection.id).contains(&subject)1808 }18091810 fn check_owner_or_admin_permissions(1811 collection: &CollectionHandle<T>,1812 subject: T::AccountId,1813 ) -> DispatchResult {1814 ensure!(Self::is_owner_or_admin_permissions(collection, subject), Error::<T>::NoPermission);18151816 Ok(())1817 }18181819 fn owned_amount(1820 subject: T::AccountId,1821 target_collection: &CollectionHandle<T>,1822 item_id: TokenId,1823 ) -> Option<u128> {1824 let collection_id = target_collection.id;18251826 match target_collection.mode {1827 CollectionMode::NFT => (<NftItemList<T>>::get(collection_id, item_id)?.owner == subject)1828 .then(|| 1),1829 CollectionMode::Fungible(_) => Some(<FungibleItemList<T>>::get(collection_id, &subject)1830 .value),1831 CollectionMode::ReFungible => <ReFungibleItemList<T>>::get(collection_id, item_id)?1832 .owner1833 .iter()1834 .find(|i| i.owner == subject)1835 .map(|i| i.fraction),1836 CollectionMode::Invalid => None,1837 }1838 }18391840 fn is_item_owner(subject: T::AccountId, target_collection: &CollectionHandle<T>, item_id: TokenId) -> bool {1841 match target_collection.mode {1842 CollectionMode::Fungible(_) => true,1843 _ => Self::owned_amount(subject, target_collection, item_id).is_some(),1844 }1845 }18461847 fn check_white_list(collection: &CollectionHandle<T>, address: &T::AccountId) -> DispatchResult {1848 let collection_id = collection.id;18491850 let mes = Error::<T>::AddresNotInWhiteList;1851 ensure!(<WhiteList<T>>::contains_key(collection_id, address), mes);18521853 Ok(())1854 }18551856 /// Check if token exists. In case of Fungible, check if there is an entry for 1857 /// the owner in fungible balances double map1858 fn token_exists(1859 target_collection: &CollectionHandle<T>,1860 item_id: TokenId,1861 ) -> DispatchResult {1862 let collection_id = target_collection.id;1863 let exists = match target_collection.mode1864 {1865 CollectionMode::NFT => <NftItemList<T>>::contains_key(collection_id, item_id),1866 CollectionMode::Fungible(_) => true,1867 CollectionMode::ReFungible => <ReFungibleItemList<T>>::contains_key(collection_id, item_id),1868 _ => false1869 };18701871 ensure!(exists == true, Error::<T>::TokenNotFound);1872 Ok(())1873 }18741875 fn transfer_fungible(1876 collection: &CollectionHandle<T>,1877 value: u128,1878 owner: &T::AccountId,1879 recipient: &T::AccountId,1880 ) -> DispatchResult {1881 let collection_id = collection.id;18821883 let mut balance = <FungibleItemList<T>>::get(collection_id, owner);1884 ensure!(balance.value >= value, Error::<T>::TokenValueTooLow);18851886 // Send balance to recipient (updates balanceOf of recipient)1887 Self::add_fungible_item(collection, recipient, value)?;18881889 // update balanceOf of sender1890 <Balance<T>>::insert(collection_id, (*owner).clone(), balance.value - value);18911892 // Reduce or remove sender1893 if balance.value == value {1894 <FungibleItemList<T>>::remove(collection_id, owner);1895 }1896 else {1897 balance.value -= value;1898 <FungibleItemList<T>>::insert(collection_id, (*owner).clone(), balance);1899 }19001901 Ok(())1902 }19031904 fn transfer_refungible(1905 collection: &CollectionHandle<T>,1906 item_id: TokenId,1907 value: u128,1908 owner: T::AccountId,1909 new_owner: T::AccountId,1910 ) -> DispatchResult {1911 let collection_id = collection.id;1912 let full_item = <ReFungibleItemList<T>>::get(collection_id, item_id)1913 .ok_or(Error::<T>::TokenNotFound)?;19141915 let item = full_item1916 .owner1917 .iter()1918 .filter(|i| i.owner == owner)1919 .next()1920 .ok_or(Error::<T>::TokenNotFound)?;1921 let amount = item.fraction;19221923 ensure!(amount >= value, Error::<T>::TokenValueTooLow);19241925 // update balance1926 let balance_old_owner = <Balance<T>>::get(collection_id, item.owner.clone())1927 .checked_sub(value)1928 .ok_or(Error::<T>::NumOverflow)?;1929 <Balance<T>>::insert(collection_id, item.owner.clone(), balance_old_owner);19301931 let balance_new_owner = <Balance<T>>::get(collection_id, new_owner.clone())1932 .checked_add(value)1933 .ok_or(Error::<T>::NumOverflow)?;1934 <Balance<T>>::insert(collection_id, new_owner.clone(), balance_new_owner);19351936 let old_owner = item.owner.clone();1937 let new_owner_has_account = full_item.owner.iter().any(|i| i.owner == new_owner);19381939 // transfer1940 if amount == value && !new_owner_has_account {1941 // change owner1942 // new owner do not have account1943 let mut new_full_item = full_item.clone();1944 new_full_item1945 .owner1946 .iter_mut()1947 .find(|i| i.owner == owner)1948 .expect("old owner does present in refungible")1949 .owner = new_owner.clone();1950 <ReFungibleItemList<T>>::insert(collection_id, item_id, new_full_item);19511952 // update index collection1953 Self::move_token_index(collection_id, item_id, &old_owner, &new_owner)?;1954 } else {1955 let mut new_full_item = full_item.clone();1956 new_full_item1957 .owner1958 .iter_mut()1959 .find(|i| i.owner == owner)1960 .expect("old owner does present in refungible")1961 .fraction -= value;19621963 // separate amount1964 if new_owner_has_account {1965 // new owner has account1966 new_full_item1967 .owner1968 .iter_mut()1969 .find(|i| i.owner == new_owner)1970 .expect("new owner has account")1971 .fraction += value;1972 } else {1973 // new owner do not have account1974 new_full_item.owner.push(Ownership {1975 owner: new_owner.clone(),1976 fraction: value,1977 });1978 Self::add_token_index(collection_id, item_id, &new_owner)?;1979 }19801981 <ReFungibleItemList<T>>::insert(collection_id, item_id, new_full_item);1982 }19831984 Ok(())1985 }19861987 fn transfer_nft(1988 collection: &CollectionHandle<T>,1989 item_id: TokenId,1990 sender: T::AccountId,1991 new_owner: T::AccountId,1992 ) -> DispatchResult {1993 let collection_id = collection.id;1994 let mut item = <NftItemList<T>>::get(collection_id, item_id)1995 .ok_or(Error::<T>::TokenNotFound)?;19961997 ensure!(1998 sender == item.owner,1999 Error::<T>::MustBeTokenOwner2000 );20012002 // update balance2003 let balance_old_owner = <Balance<T>>::get(collection_id, item.owner.clone())2004 .checked_sub(1)2005 .ok_or(Error::<T>::NumOverflow)?;2006 <Balance<T>>::insert(collection_id, item.owner.clone(), balance_old_owner);20072008 let balancenew_owner = <Balance<T>>::get(collection_id, new_owner.clone())2009 .checked_add(1)2010 .ok_or(Error::<T>::NumOverflow)?;2011 <Balance<T>>::insert(collection_id, new_owner.clone(), balancenew_owner);20122013 // change owner2014 let old_owner = item.owner.clone();2015 item.owner = new_owner.clone();2016 <NftItemList<T>>::insert(collection_id, item_id, item);20172018 // update index collection2019 Self::move_token_index(collection_id, item_id, &old_owner, &new_owner)?;20202021 Ok(())2022 }2023 2024 fn set_re_fungible_variable_data(2025 collection: &CollectionHandle<T>,2026 item_id: TokenId,2027 data: Vec<u8>2028 ) -> DispatchResult {2029 let collection_id = collection.id;2030 let mut item = <ReFungibleItemList<T>>::get(collection_id, item_id)2031 .ok_or(Error::<T>::TokenNotFound)?;20322033 item.variable_data = data;20342035 <ReFungibleItemList<T>>::insert(collection_id, item_id, item);20362037 Ok(())2038 }20392040 fn set_nft_variable_data(2041 collection: &CollectionHandle<T>,2042 item_id: TokenId,2043 data: Vec<u8>2044 ) -> DispatchResult {2045 let collection_id = collection.id;2046 let mut item = <NftItemList<T>>::get(collection_id, item_id)2047 .ok_or(Error::<T>::TokenNotFound)?;2048 2049 item.variable_data = data;20502051 <NftItemList<T>>::insert(collection_id, item_id, item);2052 2053 Ok(())2054 }20552056 #[allow(dead_code)]2057 fn init_collection(item: &Collection<T>) {2058 // check params2059 assert!(2060 item.decimal_points <= MAX_DECIMAL_POINTS,2061 "decimal_points parameter must be lower than MAX_DECIMAL_POINTS"2062 );2063 assert!(2064 item.name.len() <= 64,2065 "Collection name can not be longer than 63 char"2066 );2067 assert!(2068 item.name.len() <= 256,2069 "Collection description can not be longer than 255 char"2070 );2071 assert!(2072 item.token_prefix.len() <= 16,2073 "Token prefix can not be longer than 15 char"2074 );20752076 // Generate next collection ID2077 let next_id = CreatedCollectionCount::get()2078 .checked_add(1)2079 .unwrap();20802081 CreatedCollectionCount::put(next_id);2082 }20832084 #[allow(dead_code)]2085 fn init_nft_token(collection_id: CollectionId, item: &NftItemType<T::AccountId>) {2086 let current_index = <ItemListIndex>::get(collection_id)2087 .checked_add(1)2088 .unwrap();20892090 let item_owner = item.owner.clone();2091 Self::add_token_index(collection_id, current_index, &item.owner).unwrap();20922093 <ItemListIndex>::insert(collection_id, current_index);20942095 // Update balance2096 let new_balance = <Balance<T>>::get(collection_id, &item_owner)2097 .checked_add(1)2098 .unwrap();2099 <Balance<T>>::insert(collection_id, item_owner.clone(), new_balance);2100 }21012102 #[allow(dead_code)]2103 fn init_fungible_token(collection_id: CollectionId, owner: &T::AccountId, item: &FungibleItemType) {2104 let current_index = <ItemListIndex>::get(collection_id)2105 .checked_add(1)2106 .unwrap();21072108 Self::add_token_index(collection_id, current_index, owner).unwrap();21092110 <ItemListIndex>::insert(collection_id, current_index);21112112 // Update balance2113 let new_balance = <Balance<T>>::get(collection_id, owner)2114 .checked_add(item.value)2115 .unwrap();2116 <Balance<T>>::insert(collection_id, (*owner).clone(), new_balance);2117 }21182119 #[allow(dead_code)]2120 fn init_refungible_token(collection_id: CollectionId, item: &ReFungibleItemType<T::AccountId>) {2121 let current_index = <ItemListIndex>::get(collection_id)2122 .checked_add(1)2123 .unwrap();21242125 let value = item.owner.first().unwrap().fraction;2126 let owner = item.owner.first().unwrap().owner.clone();21272128 Self::add_token_index(collection_id, current_index, &owner).unwrap();21292130 <ItemListIndex>::insert(collection_id, current_index);21312132 // Update balance2133 let new_balance = <Balance<T>>::get(collection_id, &owner)2134 .checked_add(value)2135 .unwrap();2136 <Balance<T>>::insert(collection_id, owner.clone(), new_balance);2137 }21382139 fn add_token_index(collection_id: CollectionId, item_index: TokenId, owner: &T::AccountId) -> DispatchResult {2140 // add to account limit2141 if <AccountItemCount<T>>::contains_key(owner) {21422143 // bound Owned tokens by a single address2144 let count = <AccountItemCount<T>>::get(owner);2145 ensure!(count < ChainLimit::get().account_token_ownership_limit, Error::<T>::AddressOwnershipLimitExceeded);21462147 <AccountItemCount<T>>::insert(owner.clone(), count2148 .checked_add(1)2149 .ok_or(Error::<T>::NumOverflow)?);2150 }2151 else {2152 <AccountItemCount<T>>::insert(owner.clone(), 1);2153 }21542155 let list_exists = <AddressTokens<T>>::contains_key(collection_id, owner);2156 if list_exists {2157 let mut list = <AddressTokens<T>>::get(collection_id, owner);2158 let item_contains = list.contains(&item_index.clone());21592160 if !item_contains {2161 list.push(item_index.clone());2162 }21632164 <AddressTokens<T>>::insert(collection_id, owner.clone(), list);2165 } else {2166 let mut itm = Vec::new();2167 itm.push(item_index.clone());2168 <AddressTokens<T>>::insert(collection_id, owner.clone(), itm);2169 }21702171 Ok(())2172 }21732174 fn remove_token_index(2175 collection_id: CollectionId,2176 item_index: TokenId,2177 owner: &T::AccountId,2178 ) -> DispatchResult {21792180 // update counter2181 <AccountItemCount<T>>::insert(owner.clone(), 2182 <AccountItemCount<T>>::get(owner)2183 .checked_sub(1)2184 .ok_or(Error::<T>::NumOverflow)?);218521862187 let list_exists = <AddressTokens<T>>::contains_key(collection_id, owner);2188 if list_exists {2189 let mut list = <AddressTokens<T>>::get(collection_id, owner);2190 let item_contains = list.contains(&item_index.clone());21912192 if item_contains {2193 list.retain(|&item| item != item_index);2194 <AddressTokens<T>>::insert(collection_id, owner.clone(), list);2195 }2196 }21972198 Ok(())2199 }22002201 fn move_token_index(2202 collection_id: CollectionId,2203 item_index: TokenId,2204 old_owner: &T::AccountId,2205 new_owner: &T::AccountId,2206 ) -> DispatchResult {2207 Self::remove_token_index(collection_id, item_index, old_owner)?;2208 Self::add_token_index(collection_id, item_index, new_owner)?;22092210 Ok(())2211 }2212 2213 fn ensure_contract_owned(account: T::AccountId, contract: &T::AccountId) -> DispatchResult {2214 ensure!(<ContractOwner<T>>::get(contract) == Some(account), Error::<T>::NoPermission);22152216 Ok(())2217 }2218}runtime/src/chain_extension.rsdiffbeforeafterboth--- a/runtime/src/chain_extension.rs
+++ b/runtime/src/chain_extension.rs
@@ -18,10 +18,6 @@
extern crate pallet_nft;
pub use pallet_nft::*;
use nft_data_structs::*;
-// use crate::Runtime;
-
-use sp_runtime::AccountId32;
-use crate::Vec;
/// Create item parameters
#[derive(Debug, PartialEq, Encode, Decode)]
runtime/src/lib.rsdiffbeforeafterboth--- a/runtime/src/lib.rs
+++ b/runtime/src/lib.rs
@@ -22,8 +22,8 @@
Permill, Perbill, Percent,
create_runtime_str, generic, impl_opaque_keys,
traits::{
- AccountIdLookup, Convert, ConvertInto, BlakeTwo256, Block as BlockT, IdentifyAccount,
- IdentityLookup, NumberFor, Verify, AccountIdConversion,
+ AccountIdLookup, ConvertInto, BlakeTwo256, Block as BlockT, IdentifyAccount,
+ Verify, AccountIdConversion,
},
transaction_validity::{TransactionSource, TransactionValidity},
ApplyExtrinsicResult, MultiSignature,
@@ -53,8 +53,6 @@
WeightToFeePolynomial, WeightToFeeCoefficient, WeightToFeeCoefficients
},
};
-use pallet_nft_transaction_payment::*;
-use pallet_nft_charge_transaction::*;
use nft_data_structs::*;
use pallet_contracts::weights::WeightInfo;
// #[cfg(any(feature = "std", test))]