difftreelog
Transaction payment and weights fix
in: master
4 files changed
pallets/nft/src/default_weights.rsdiffbeforeafterboth--- /dev/null
+++ b/pallets/nft/src/default_weights.rs
@@ -0,0 +1,95 @@
+use frame_support::weights::{Weight, constants::RocksDbWeight as DbWeight};
+
+impl crate::WeightInfo for () {
+ fn create_collection() -> Weight {
+ (70_000_000 as Weight)
+ .saturating_add(DbWeight::get().reads(7 as Weight))
+ .saturating_add(DbWeight::get().writes(5 as Weight))
+ }
+ fn destroy_collection() -> Weight {
+ (90_000_000 as Weight)
+ .saturating_add(DbWeight::get().reads(2 as Weight))
+ .saturating_add(DbWeight::get().writes(5 as Weight))
+ }
+ fn add_to_white_list() -> Weight {
+ (30_000_000 as Weight)
+ .saturating_add(DbWeight::get().reads(3 as Weight))
+ .saturating_add(DbWeight::get().writes(1 as Weight))
+ }
+ fn remove_from_white_list() -> Weight {
+ (35_000_000 as Weight)
+ .saturating_add(DbWeight::get().reads(3 as Weight))
+ .saturating_add(DbWeight::get().writes(1 as Weight))
+ }
+ fn set_public_access_mode() -> Weight {
+ (27_000_000 as Weight)
+ .saturating_add(DbWeight::get().reads(1 as Weight))
+ .saturating_add(DbWeight::get().writes(1 as Weight))
+ }
+ fn set_mint_permission() -> Weight {
+ (27_000_000 as Weight)
+ .saturating_add(DbWeight::get().reads(1 as Weight))
+ .saturating_add(DbWeight::get().writes(1 as Weight))
+ }
+ fn change_collection_owner() -> Weight {
+ (27_000_000 as Weight)
+ .saturating_add(DbWeight::get().reads(1 as Weight))
+ .saturating_add(DbWeight::get().writes(1 as Weight))
+ }
+ fn add_collection_admin() -> Weight {
+ (32_000_000 as Weight)
+ .saturating_add(DbWeight::get().reads(3 as Weight))
+ .saturating_add(DbWeight::get().writes(1 as Weight))
+ }
+ fn remove_collection_admin() -> Weight {
+ (50_000_000 as Weight)
+ .saturating_add(DbWeight::get().reads(2 as Weight))
+ .saturating_add(DbWeight::get().writes(1 as Weight))
+ }
+ fn set_collection_sponsor() -> Weight {
+ (32_000_000 as Weight)
+ .saturating_add(DbWeight::get().reads(2 as Weight))
+ .saturating_add(DbWeight::get().writes(1 as Weight))
+ }
+ fn confirm_sponsorship() -> Weight {
+ (22_000_000 as Weight)
+ .saturating_add(DbWeight::get().reads(1 as Weight))
+ .saturating_add(DbWeight::get().writes(1 as Weight))
+ }
+ fn remove_collection_sponsor() -> Weight {
+ (24_000_000 as Weight)
+ .saturating_add(DbWeight::get().reads(1 as Weight))
+ .saturating_add(DbWeight::get().writes(1 as Weight))
+ }
+ fn create_item(s: usize, ) -> Weight {
+ (130_000_000 as Weight)
+ .saturating_add((2135 as Weight).saturating_mul(s as Weight))
+ .saturating_add(DbWeight::get().reads(10 as Weight))
+ .saturating_add(DbWeight::get().writes(8 as Weight))
+ }
+ fn burn_item() -> Weight {
+ (170_000_000 as Weight)
+ .saturating_add(DbWeight::get().reads(9 as Weight))
+ .saturating_add(DbWeight::get().writes(7 as Weight))
+ }
+ fn transfer() -> Weight {
+ (125_000_000 as Weight)
+ .saturating_add(DbWeight::get().reads(7 as Weight))
+ .saturating_add(DbWeight::get().writes(7 as Weight))
+ }
+ fn approve() -> Weight {
+ (45_000_000 as Weight)
+ .saturating_add(DbWeight::get().reads(3 as Weight))
+ .saturating_add(DbWeight::get().writes(1 as Weight))
+ }
+ fn transfer_from() -> Weight {
+ (150_000_000 as Weight)
+ .saturating_add(DbWeight::get().reads(9 as Weight))
+ .saturating_add(DbWeight::get().writes(8 as Weight))
+ }
+ fn set_offchain_schema() -> Weight {
+ (33_000_000 as Weight)
+ .saturating_add(DbWeight::get().reads(2 as Weight))
+ .saturating_add(DbWeight::get().writes(1 as Weight))
+ }
+}
pallets/nft/src/lib.rsdiffbeforeafterboth1#![cfg_attr(not(feature = "std"), no_std)]23#[cfg(feature = "std")]4pub use std::*;56#[cfg(feature = "std")]7pub use serde::*;89use codec::{Decode, Encode};10pub use frame_support::{11 construct_runtime, decl_event, decl_module, decl_storage,12 dispatch::DispatchResult,13 ensure, parameter_types,14 traits::{15 Currency, ExistenceRequirement, Get, Imbalance, KeyOwnerProofSystem, OnUnbalanced,16 Randomness, WithdrawReason,17 },18 weights::{19 constants::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_PER_SECOND},20 DispatchInfo, GetDispatchInfo, IdentityFee, Pays, PostDispatchInfo, Weight,21 WeightToFeePolynomial,22 },23 IsSubType, StorageValue,24};25// use frame_support::weights::{Weight, constants::RocksDbWeight as DbWeight};2627use frame_system::{self as system, ensure_signed, ensure_root};28use sp_runtime::sp_std::prelude::Vec;29use sp_runtime::{30 traits::{31 DispatchInfoOf, Dispatchable, PostDispatchInfoOf, SaturatedConversion, Saturating,32 SignedExtension, Zero,33 },34 transaction_validity::{35 InvalidTransaction, TransactionPriority, TransactionValidity, TransactionValidityError,36 ValidTransaction,37 },38 FixedPointOperand, FixedU128,39};4041#[cfg(test)]42mod mock;4344#[cfg(test)]45mod tests;4647// Structs48// #region4950#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq)]51#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]52pub enum CollectionMode {53 Invalid,54 // custom data size55 NFT(u32),56 // decimal points57 Fungible(u32),58 // custom data size and decimal points59 ReFungible(u32, u32),60}6162impl Into<u8> for CollectionMode {63 fn into(self) -> u8 {64 match self {65 CollectionMode::Invalid => 0,66 CollectionMode::NFT(_) => 1,67 CollectionMode::Fungible(_) => 2,68 CollectionMode::ReFungible(_, _) => 3,69 }70 }71}7273#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq)]74#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]75pub enum AccessMode {76 Normal,77 WhiteList,78}79impl Default for AccessMode {80 fn default() -> Self {81 Self::Normal82 }83}8485impl Default for CollectionMode {86 fn default() -> Self {87 Self::Invalid88 }89}9091#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]92#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]93pub struct Ownership<AccountId> {94 pub owner: AccountId,95 pub fraction: u128,96}9798#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]99#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]100pub struct CollectionType<AccountId> {101 pub owner: AccountId,102 pub mode: CollectionMode,103 pub access: AccessMode,104 pub decimal_points: u32,105 pub name: Vec<u16>, // 64 include null escape char106 pub description: Vec<u16>, // 256 include null escape char107 pub token_prefix: Vec<u8>, // 16 include null escape char108 pub custom_data_size: u32,109 pub mint_mode: bool,110 pub offchain_schema: Vec<u8>,111 pub sponsor: AccountId, // Who pays fees. If set to default address, the fees are applied to the transaction sender112 pub unconfirmed_sponsor: AccountId, // Sponsor address that has not yet confirmed sponsorship113}114115#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]116#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]117pub struct CollectionAdminsType<AccountId> {118 pub admin: AccountId,119 pub collection_id: u64,120}121122#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]123#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]124pub struct NftItemType<AccountId> {125 pub collection: u64,126 pub owner: AccountId,127 pub data: Vec<u8>,128}129130#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]131#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]132pub struct FungibleItemType<AccountId> {133 pub collection: u64,134 pub owner: AccountId,135 pub value: u128,136}137138#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]139#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]140pub struct ReFungibleItemType<AccountId> {141 pub collection: u64,142 pub owner: Vec<Ownership<AccountId>>,143 pub data: Vec<u8>,144}145146#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]147#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]148pub struct ApprovePermissions<AccountId> {149 pub approved: AccountId,150 pub amount: u64,151}152153#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]154#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]155pub struct VestingItem<AccountId, Moment> {156 pub sender: AccountId,157 pub recipient: AccountId,158 pub collection_id: u64,159 pub item_id: u64,160 pub amount: u64,161 pub vesting_date: Moment,162}163164#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]165#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]166pub struct BasketItem<AccountId, BlockNumber> {167 pub address: AccountId,168 pub start_block: BlockNumber,169}170171#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]172#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]173pub struct ChainLimits {174 pub collection_numbers_limit: u64,175 pub account_token_ownership_limit: u64,176 pub collections_admins_limit: u64,177 pub custom_data_limit: u32,178179 // Timeouts for item types in passed blocks180 pub nft_sponsor_transfer_timeout: u32,181 pub fungible_sponsor_transfer_timeout: u32,182 pub refungible_sponsor_transfer_timeout: u32,183}184185pub trait Trait: system::Trait {186 type Event: From<Event<Self>> + Into<<Self as system::Trait>::Event>;187}188189#[cfg(feature = "runtime-benchmarks")]190mod benchmarking;191192// #endregion193194decl_storage! {195 trait Store for Module<T: Trait> as Nft {196197 // Private members198 NextCollectionID: u64;199 CreatedCollectionCount: u64;200 ChainVersion: u64;201 ItemListIndex: map hasher(blake2_128_concat) u64 => u64;202203 // Chain limits struct204 pub ChainLimit get(fn chain_limit) config(): ChainLimits;205206 // Bound counters207 CollectionCount: u64;208 pub AccountItemCount get(fn account_item_count): map hasher(identity) T::AccountId => u64;209210 // Basic collections211 pub Collection get(fn collection) config(): map hasher(identity) u64 => CollectionType<T::AccountId>;212 pub AdminList get(fn admin_list_collection): map hasher(identity) u64 => Vec<T::AccountId>;213 pub WhiteList get(fn white_list): map hasher(identity) u64 => Vec<T::AccountId>;214215 /// Balance owner per collection map216 pub Balance get(fn balance_count): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) T::AccountId => u64;217218 /// second parameter: item id + owner account id219 pub ApprovedList get(fn approved): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) (u64, T::AccountId) => Vec<ApprovePermissions<T::AccountId>>;220221 /// Item collections222 pub NftItemList get(fn nft_item_id) config(): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => NftItemType<T::AccountId>;223 pub FungibleItemList get(fn fungible_item_id) config(): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => FungibleItemType<T::AccountId>;224 pub ReFungibleItemList get(fn refungible_item_id) config(): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => ReFungibleItemType<T::AccountId>;225226 /// Index list227 pub AddressTokens get(fn address_tokens): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) T::AccountId => Vec<u64>;228229 /// Tokens transfer baskets230 pub NftTransferBasket get(fn nft_transfer_basket): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => T::BlockNumber;231 pub FungibleTransferBasket get(fn fungible_transfer_basket): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => Vec<BasketItem<T::AccountId, T::BlockNumber>>;232 pub ReFungibleTransferBasket get(fn refungible_transfer_basket): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => T::BlockNumber;233234 // Sponsorship235 pub ContractSponsor get(fn contract_sponsor): map hasher(identity) T::AccountId => T::AccountId;236 pub UnconfirmedContractSponsor get(fn unconfirmed_contract_sponsor): map hasher(identity) T::AccountId => T::AccountId;237 }238 add_extra_genesis {239 build(|config: &GenesisConfig<T>| {240 // Modification of storage241 for (_num, _c) in &config.collection {242 <Module<T>>::init_collection(_c);243 }244245 for (_num, _q, _i) in &config.nft_item_id {246 <Module<T>>::init_nft_token(_i);247 }248249 for (_num, _q, _i) in &config.fungible_item_id {250 <Module<T>>::init_fungible_token(_i);251 }252253 for (_num, _q, _i) in &config.refungible_item_id {254 <Module<T>>::init_refungible_token(_i);255 }256 })257 }258}259260decl_event!(261 pub enum Event<T>262 where263 AccountId = <T as system::Trait>::AccountId,264 {265 /// New collection was created266 /// 267 /// # Arguments268 /// 269 /// * collection_id: Globally unique identifier of newly created collection.270 /// 271 /// * mode: [CollectionMode] converted into u8.272 /// 273 /// * account_id: Collection owner.274 Created(u64, u8, AccountId),275276 /// New item was created.277 /// 278 /// # Arguments279 /// 280 /// * collection_id: Id of the collection where item was created.281 /// 282 /// * item_id: Id of an item. Unique within the collection.283 ItemCreated(u64, u64),284285 /// Collection item was burned.286 /// 287 /// # Arguments288 /// 289 /// collection_id.290 /// 291 /// item_id: Identifier of burned NFT.292 ItemDestroyed(u64, u64),293 }294);295296decl_module! {297 pub struct Module<T: Trait> for enum Call where origin: T::Origin {298299 fn deposit_event() = default;300301 fn on_initialize(now: T::BlockNumber) -> Weight {302303 if ChainVersion::get() < 2304 {305 let value = NextCollectionID::get();306 CreatedCollectionCount::put(value);307 ChainVersion::put(2);308 }309310 0311 }312313 /// 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.314 /// 315 /// # Permissions316 /// 317 /// * Anyone.318 /// 319 /// # Arguments320 /// 321 /// * collection_name: UTF-16 string with collection name (limit 64 characters), will be stored as zero-terminated.322 /// 323 /// * collection_description: UTF-16 string with collection description (limit 256 characters), will be stored as zero-terminated.324 /// 325 /// * token_prefix: UTF-8 string with token prefix.326 /// 327 /// * mode: [CollectionMode] collection type and type dependent data.328 // returns collection ID329 #[weight =330 (70_000_000 as Weight)331 .saturating_add(RocksDbWeight::get().reads(7 as Weight))332 .saturating_add(RocksDbWeight::get().writes(5 as Weight))]333 pub fn create_collection(origin,334 collection_name: Vec<u16>,335 collection_description: Vec<u16>,336 token_prefix: Vec<u8>,337 mode: CollectionMode) -> DispatchResult {338339 // Anyone can create a collection340 let who = ensure_signed(origin)?;341 let custom_data_size = match mode {342 CollectionMode::NFT(size) => {343344 // bound Custom data size345 ensure!(size < ChainLimit::get().custom_data_limit, "Custom data size bound exceeded");346 size347 },348 CollectionMode::ReFungible(size, _) => {349350 // bound Custom data size351 ensure!(size < ChainLimit::get().custom_data_limit, "Custom data size bound exceeded");352 size353 },354 _ => 0355 };356357 let decimal_points = match mode {358 CollectionMode::Fungible(points) => points,359 CollectionMode::ReFungible(_, points) => points,360 _ => 0361 };362363 // bound Total number of collections364 ensure!(CollectionCount::get() < ChainLimit::get().collection_numbers_limit, "Total collections bound exceeded");365366 // check params367 ensure!(decimal_points <= 4, "decimal_points parameter must be lower than 4");368369 let mut name = collection_name.to_vec();370 name.push(0);371 ensure!(name.len() <= 64, "Collection name can not be longer than 63 char");372373 let mut description = collection_description.to_vec();374 description.push(0);375 ensure!(name.len() <= 256, "Collection description can not be longer than 255 char");376377 let mut prefix = token_prefix.to_vec();378 prefix.push(0);379 ensure!(prefix.len() <= 16, "Token prefix can not be longer than 15 char");380381 // Generate next collection ID382 let next_id = CreatedCollectionCount::get()383 .checked_add(1)384 .expect("collection id error");385386 // bound counter387 let total = CollectionCount::get()388 .checked_add(1)389 .expect("collection counter error");390391 CreatedCollectionCount::put(next_id);392 CollectionCount::put(total);393394 // Create new collection395 let new_collection = CollectionType {396 owner: who.clone(),397 name: name,398 mode: mode.clone(),399 mint_mode: false,400 access: AccessMode::Normal,401 description: description,402 decimal_points: decimal_points,403 token_prefix: prefix,404 offchain_schema: Vec::new(),405 custom_data_size: custom_data_size,406 sponsor: T::AccountId::default(),407 unconfirmed_sponsor: T::AccountId::default(),408 };409410 // Add new collection to map411 <Collection<T>>::insert(next_id, new_collection);412413 // call event414 Self::deposit_event(RawEvent::Created(next_id, mode.into(), who.clone()));415416 Ok(())417 }418419 /// **DANGEROUS**: Destroys collection and all NFTs within this collection. Users irrecoverably lose their assets and may lose real money.420 /// 421 /// # Permissions422 /// 423 /// * Collection Owner.424 /// 425 /// # Arguments426 /// 427 /// * collection_id: collection to destroy.428 #[weight =429 (90_000_000 as Weight)430 .saturating_add(RocksDbWeight::get().reads(2 as Weight))431 .saturating_add(RocksDbWeight::get().writes(5 as Weight))]432 pub fn destroy_collection(origin, collection_id: u64) -> DispatchResult {433434 let sender = ensure_signed(origin)?;435 Self::check_owner_permissions(collection_id, sender)?;436437 <AddressTokens<T>>::remove_prefix(collection_id);438 <ApprovedList<T>>::remove_prefix(collection_id);439 <Balance<T>>::remove_prefix(collection_id);440 <ItemListIndex>::remove(collection_id);441 <AdminList<T>>::remove(collection_id);442 <Collection<T>>::remove(collection_id);443 <WhiteList<T>>::remove(collection_id);444445 <NftItemList<T>>::remove_prefix(collection_id);446 <FungibleItemList<T>>::remove_prefix(collection_id);447 <ReFungibleItemList<T>>::remove_prefix(collection_id);448449 <NftTransferBasket<T>>::remove_prefix(collection_id);450 <FungibleTransferBasket<T>>::remove_prefix(collection_id);451 <ReFungibleTransferBasket<T>>::remove_prefix(collection_id);452453 if CollectionCount::get() > 0454 {455 // bound couter456 let total = CollectionCount::get()457 .checked_sub(1)458 .expect("collection counter error");459460 CollectionCount::put(total);461 }462463 Ok(())464 }465466 /// Add an address to white list.467 /// 468 /// # Permissions469 /// 470 /// * Collection Owner471 /// * Collection Admin472 /// 473 /// # Arguments474 /// 475 /// * collection_id.476 /// 477 /// * address.478 #[weight =479 (30_000_000 as Weight)480 .saturating_add(RocksDbWeight::get().reads(3 as Weight))481 .saturating_add(RocksDbWeight::get().writes(1 as Weight))]482 pub fn add_to_white_list(origin, collection_id: u64, address: T::AccountId) -> DispatchResult{483484 let sender = ensure_signed(origin)?;485 Self::check_owner_or_admin_permissions(collection_id, sender)?;486487 let mut white_list_collection: Vec<T::AccountId>;488 if <WhiteList<T>>::contains_key(collection_id) {489 white_list_collection = <WhiteList<T>>::get(collection_id);490 if !white_list_collection.contains(&address.clone())491 {492 white_list_collection.push(address.clone());493 }494 }495 else {496 white_list_collection = Vec::new();497 white_list_collection.push(address.clone());498 }499500 <WhiteList<T>>::insert(collection_id, white_list_collection);501 Ok(())502 }503504 /// Remove an address from white list.505 /// 506 /// # Permissions507 /// 508 /// * Collection Owner509 /// * Collection Admin510 /// 511 /// # Arguments512 /// 513 /// * collection_id.514 /// 515 /// * address.516 #[weight =517 (35_000_000 as Weight)518 .saturating_add(RocksDbWeight::get().reads(3 as Weight))519 .saturating_add(RocksDbWeight::get().writes(1 as Weight))]520 pub fn remove_from_white_list(origin, collection_id: u64, address: T::AccountId) -> DispatchResult{521522 let sender = ensure_signed(origin)?;523 Self::check_owner_or_admin_permissions(collection_id, sender)?;524525 if <WhiteList<T>>::contains_key(collection_id) {526 let mut white_list_collection = <WhiteList<T>>::get(collection_id);527 if white_list_collection.contains(&address.clone())528 {529 white_list_collection.retain(|i| *i != address.clone());530 <WhiteList<T>>::insert(collection_id, white_list_collection);531 }532 }533534 Ok(())535 }536537 /// Toggle between normal and white list access for the methods with access for `Anyone`.538 /// 539 /// # Permissions540 /// 541 /// * Collection Owner.542 /// 543 /// # Arguments544 /// 545 /// * collection_id.546 /// 547 /// * mode: [AccessMode]548 #[weight =549 (27_000_000 as Weight)550 .saturating_add(RocksDbWeight::get().reads(1 as Weight))551 .saturating_add(RocksDbWeight::get().writes(1 as Weight))]552 pub fn set_public_access_mode(origin, collection_id: u64, mode: AccessMode) -> DispatchResult553 {554 let sender = ensure_signed(origin)?;555556 Self::check_owner_permissions(collection_id, sender)?;557 let mut target_collection = <Collection<T>>::get(collection_id);558 target_collection.access = mode;559 <Collection<T>>::insert(collection_id, target_collection);560561 Ok(())562 }563564 /// Allows Anyone to create tokens if:565 /// * White List is enabled, and566 /// * Address is added to white list, and567 /// * This method was called with True parameter568 /// 569 /// # Permissions570 /// * Collection Owner571 ///572 /// # Arguments573 /// 574 /// * collection_id.575 /// 576 /// * mint_permission: Boolean parameter. If True, allows minting to Anyone with conditions above.577 #[weight =578 (27_000_000 as Weight)579 .saturating_add(RocksDbWeight::get().reads(1 as Weight))580 .saturating_add(RocksDbWeight::get().writes(1 as Weight))]581 pub fn set_mint_permission(origin, collection_id: u64, mint_permission: bool) -> DispatchResult582 {583 let sender = ensure_signed(origin)?;584585 Self::check_owner_permissions(collection_id, sender)?;586 let mut target_collection = <Collection<T>>::get(collection_id);587 target_collection.mint_mode = mint_permission;588 <Collection<T>>::insert(collection_id, target_collection);589590 Ok(())591 }592593 /// Change the owner of the collection.594 /// 595 /// # Permissions596 /// 597 /// * Collection Owner.598 /// 599 /// # Arguments600 /// 601 /// * collection_id.602 /// 603 /// * new_owner.604 #[weight =605 (27_000_000 as Weight)606 .saturating_add(RocksDbWeight::get().reads(1 as Weight))607 .saturating_add(RocksDbWeight::get().writes(1 as Weight))]608 pub fn change_collection_owner(origin, collection_id: u64, new_owner: T::AccountId) -> DispatchResult {609610 let sender = ensure_signed(origin)?;611 Self::check_owner_permissions(collection_id, sender)?;612 let mut target_collection = <Collection<T>>::get(collection_id);613 target_collection.owner = new_owner;614 <Collection<T>>::insert(collection_id, target_collection);615616 Ok(())617 }618619 /// Adds an admin of the Collection.620 /// 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. 621 /// 622 /// # Permissions623 /// 624 /// * Collection Owner.625 /// * Collection Admin.626 /// 627 /// # Arguments628 /// 629 /// * collection_id: ID of the Collection to add admin for.630 /// 631 /// * new_admin_id: Address of new admin to add.632 #[weight =633 (32_000_000 as Weight)634 .saturating_add(RocksDbWeight::get().reads(3 as Weight))635 .saturating_add(RocksDbWeight::get().writes(1 as Weight))]636 pub fn add_collection_admin(origin, collection_id: u64, new_admin_id: T::AccountId) -> DispatchResult {637638 let sender = ensure_signed(origin)?;639 Self::check_owner_or_admin_permissions(collection_id, sender)?;640 let mut admin_arr: Vec<T::AccountId> = Vec::new();641642 if <AdminList<T>>::contains_key(collection_id)643 {644 admin_arr = <AdminList<T>>::get(collection_id);645 ensure!(!admin_arr.contains(&new_admin_id), "Account already has admin role");646 }647648 // Number of collection admins649 ensure!((admin_arr.len() as u64) < ChainLimit::get().collections_admins_limit, "Number of collection admins bound exceeded");650651 admin_arr.push(new_admin_id);652 <AdminList<T>>::insert(collection_id, admin_arr);653654 Ok(())655 }656657 /// 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.658 ///659 /// # Permissions660 /// 661 /// * Collection Owner.662 /// * Collection Admin.663 /// 664 /// # Arguments665 /// 666 /// * collection_id: ID of the Collection to remove admin for.667 /// 668 /// * account_id: Address of admin to remove.669 #[weight =670 (50_000_000 as Weight)671 .saturating_add(RocksDbWeight::get().reads(2 as Weight))672 .saturating_add(RocksDbWeight::get().writes(1 as Weight))]673 pub fn remove_collection_admin(origin, collection_id: u64, account_id: T::AccountId) -> DispatchResult {674675 let sender = ensure_signed(origin)?;676 Self::check_owner_or_admin_permissions(collection_id, sender)?;677678 if <AdminList<T>>::contains_key(collection_id)679 {680 let mut admin_arr = <AdminList<T>>::get(collection_id);681 admin_arr.retain(|i| *i != account_id);682 <AdminList<T>>::insert(collection_id, admin_arr);683 }684685 Ok(())686 }687688 /// # Permissions689 /// 690 /// * Collection Owner691 /// 692 /// # Arguments693 /// 694 /// * collection_id.695 /// 696 /// * new_sponsor.697 #[weight =698 (32_000_000 as Weight)699 .saturating_add(RocksDbWeight::get().reads(2 as Weight))700 .saturating_add(RocksDbWeight::get().writes(1 as Weight))]701 pub fn set_collection_sponsor(origin, collection_id: u64, new_sponsor: T::AccountId) -> DispatchResult {702703 let sender = ensure_signed(origin)?;704 ensure!(<Collection<T>>::contains_key(collection_id), "This collection does not exist");705706 let mut target_collection = <Collection<T>>::get(collection_id);707 ensure!(sender == target_collection.owner, "You do not own this collection");708709 target_collection.unconfirmed_sponsor = new_sponsor;710 <Collection<T>>::insert(collection_id, target_collection);711712 Ok(())713 }714715 /// # Permissions716 /// 717 /// * Sponsor.718 /// 719 /// # Arguments720 /// 721 /// * collection_id.722 #[weight =723 (22_000_000 as Weight)724 .saturating_add(RocksDbWeight::get().reads(1 as Weight))725 .saturating_add(RocksDbWeight::get().writes(1 as Weight))]726 pub fn confirm_sponsorship(origin, collection_id: u64) -> DispatchResult {727728 let sender = ensure_signed(origin)?;729 ensure!(<Collection<T>>::contains_key(collection_id), "This collection does not exist");730731 let mut target_collection = <Collection<T>>::get(collection_id);732 ensure!(sender == target_collection.unconfirmed_sponsor, "This address is not set as sponsor, use setCollectionSponsor first");733734 target_collection.sponsor = target_collection.unconfirmed_sponsor;735 target_collection.unconfirmed_sponsor = T::AccountId::default();736 <Collection<T>>::insert(collection_id, target_collection);737738 Ok(())739 }740741 /// Switch back to pay-per-own-transaction model.742 ///743 /// # Permissions744 ///745 /// * Collection owner.746 /// 747 /// # Arguments748 /// 749 /// * collection_id.750 #[weight =751 (24_000_000 as Weight)752 .saturating_add(RocksDbWeight::get().reads(1 as Weight))753 .saturating_add(RocksDbWeight::get().writes(1 as Weight))]754 pub fn remove_collection_sponsor(origin, collection_id: u64) -> DispatchResult {755756 let sender = ensure_signed(origin)?;757 ensure!(<Collection<T>>::contains_key(collection_id), "This collection does not exist");758759 let mut target_collection = <Collection<T>>::get(collection_id);760 ensure!(sender == target_collection.owner, "You do not own this collection");761762 target_collection.sponsor = T::AccountId::default();763 <Collection<T>>::insert(collection_id, target_collection);764765 Ok(())766 }767768 /// This method creates a concrete instance of NFT Collection created with CreateCollection method.769 /// 770 /// # Permissions771 /// 772 /// * Collection Owner.773 /// * Collection Admin.774 /// * Anyone if775 /// * White List is enabled, and776 /// * Address is added to white list, and777 /// * MintPermission is enabled (see SetMintPermission method)778 /// 779 /// # Arguments780 /// 781 /// * collection_id: ID of the collection.782 /// 783 /// * properties: Array of bytes that contains NFT properties. Since NFT Module is agnostic of properties meaning, it is treated purely as an array of bytes.784 /// 785 /// * owner: Address, initial owner of the NFT.786 #[weight =787 (130_000_000 as Weight)788 .saturating_add((2135 as Weight).saturating_mul((properties.len() as u64) as Weight))789 .saturating_add(RocksDbWeight::get().reads(10 as Weight))790 .saturating_add(RocksDbWeight::get().writes(8 as Weight))]791 pub fn create_item(origin, collection_id: u64, properties: Vec<u8>, owner: T::AccountId) -> DispatchResult {792793 let sender = ensure_signed(origin)?;794 Self::collection_exists(collection_id)?;795 let target_collection = <Collection<T>>::get(collection_id);796797 if !Self::is_owner_or_admin_permissions(collection_id, sender.clone()) {798 ensure!(target_collection.mint_mode == true, "Public minting is not allowed for this collection");799 Self::check_white_list(collection_id, &owner)?;800 Self::check_white_list(collection_id, &sender)?;801 }802803 match target_collection.mode804 {805 CollectionMode::NFT(_) => {806807 // check size808 ensure!(target_collection.custom_data_size >= properties.len() as u32, "Size of item is too large");809810 // Create nft item811 let item = NftItemType {812 collection: collection_id,813 owner: owner,814 data: properties.clone(),815 };816817 Self::add_nft_item(item)?;818819 },820 CollectionMode::Fungible(_) => {821822 // check size823 ensure!(properties.len() as u32 == 0, "Size of item must be 0 with fungible type");824825 let item = FungibleItemType {826 collection: collection_id,827 owner: owner,828 value: (10 as u128).pow(target_collection.decimal_points)829 };830831 Self::add_fungible_item(item)?;832 },833 CollectionMode::ReFungible(_, _) => {834835 // check size836 ensure!(target_collection.custom_data_size >= properties.len() as u32, "Size of item is too large");837838 let mut owner_list = Vec::new();839 let value = (10 as u128).pow(target_collection.decimal_points);840 owner_list.push(Ownership {owner: owner.clone(), fraction: value});841842 let item = ReFungibleItemType {843 collection: collection_id,844 owner: owner_list,845 data: properties.clone()846 };847848 Self::add_refungible_item(item)?;849 },850 _ => { ensure!(1 == 0,"just error"); }851852 };853854 // call event855 Self::deposit_event(RawEvent::ItemCreated(collection_id, <ItemListIndex>::get(collection_id)));856857 Ok(())858 }859860 /// Destroys a concrete instance of NFT.861 /// 862 /// # Permissions863 /// 864 /// * Collection Owner.865 /// * Collection Admin.866 /// * Current NFT Owner.867 /// 868 /// # Arguments869 /// 870 /// * collection_id: ID of the collection.871 /// 872 /// * item_id: ID of NFT to burn.873 #[weight =874 (170_000_000 as Weight)875 .saturating_add(RocksDbWeight::get().reads(9 as Weight))876 .saturating_add(RocksDbWeight::get().writes(7 as Weight))]877 pub fn burn_item(origin, collection_id: u64, item_id: u64) -> DispatchResult {878879 let sender = ensure_signed(origin)?;880 Self::collection_exists(collection_id)?;881882 // Transfer permissions check883 let target_collection = <Collection<T>>::get(collection_id);884 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||885 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),886 "Only item owner, collection owner and admins can modify item");887888 if target_collection.access == AccessMode::WhiteList {889 Self::check_white_list(collection_id, &sender)?;890 }891892 match target_collection.mode893 {894 CollectionMode::NFT(_) => Self::burn_nft_item(collection_id, item_id)?,895 CollectionMode::Fungible(_) => Self::burn_fungible_item(collection_id, item_id)?,896 CollectionMode::ReFungible(_, _) => Self::burn_refungible_item(collection_id, item_id, sender.clone())?,897 _ => ()898 };899900 // call event901 Self::deposit_event(RawEvent::ItemDestroyed(collection_id, item_id));902903 Ok(())904 }905906 /// Change ownership of the token.907 /// 908 /// # Permissions909 /// 910 /// * Collection Owner911 /// * Collection Admin912 /// * Current NFT owner913 ///914 /// # Arguments915 /// 916 /// * recipient: Address of token recipient.917 /// 918 /// * collection_id.919 /// 920 /// * item_id: ID of the item921 /// * Non-Fungible Mode: Required.922 /// * Fungible Mode: Ignored.923 /// * Re-Fungible Mode: Required.924 /// 925 /// * value: Amount to transfer.926 /// * Non-Fungible Mode: Ignored927 /// * Fungible Mode: Must specify transferred amount928 /// * Re-Fungible Mode: Must specify transferred portion (between 0 and 1)929 #[weight =930 (125_000_000 as Weight)931 .saturating_add(RocksDbWeight::get().reads(7 as Weight))932 .saturating_add(RocksDbWeight::get().writes(7 as Weight))]933 pub fn transfer(origin, recipient: T::AccountId, collection_id: u64, item_id: u64, value: u64) -> DispatchResult {934935 let sender = ensure_signed(origin)?;936937 // Transfer permissions check938 let target_collection = <Collection<T>>::get(collection_id);939 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||940 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),941 "Only item owner, collection owner and admins can modify item");942943 if target_collection.access == AccessMode::WhiteList {944 Self::check_white_list(collection_id, &sender)?;945 Self::check_white_list(collection_id, &recipient)?;946 }947948 match target_collection.mode949 {950 CollectionMode::NFT(_) => Self::transfer_nft(collection_id, item_id, sender.clone(), recipient)?,951 CollectionMode::Fungible(_) => Self::transfer_fungible(collection_id, item_id, value, sender.clone(), recipient)?,952 CollectionMode::ReFungible(_, _) => Self::transfer_refungible(collection_id, item_id, value, sender.clone(), recipient)?,953 _ => ()954 };955956 Ok(())957 }958959 /// Set, change, or remove approved address to transfer the ownership of the NFT.960 /// 961 /// # Permissions962 /// 963 /// * Collection Owner964 /// * Collection Admin965 /// * Current NFT owner966 /// 967 /// # Arguments968 /// 969 /// * approved: Address that is approved to transfer this NFT or zero (if needed to remove approval).970 /// 971 /// * collection_id.972 /// 973 /// * item_id: ID of the item.974 #[weight =975 (45_000_000 as Weight)976 .saturating_add(RocksDbWeight::get().reads(3 as Weight))977 .saturating_add(RocksDbWeight::get().writes(1 as Weight))]978 pub fn approve(origin, approved: T::AccountId, collection_id: u64, item_id: u64) -> DispatchResult {979980 let sender = ensure_signed(origin)?;981982 // Transfer permissions check983 let target_collection = <Collection<T>>::get(collection_id);984 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||985 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),986 "Only item owner, collection owner and admins can approve");987988 if target_collection.access == AccessMode::WhiteList {989 Self::check_white_list(collection_id, &sender)?;990 Self::check_white_list(collection_id, &approved)?;991 }992993 // amount param stub994 let amount = 100000000;995996 let list_exists = <ApprovedList<T>>::contains_key(collection_id, (item_id, sender.clone()));997 if list_exists {998999 let mut list = <ApprovedList<T>>::get(collection_id, (item_id, sender.clone()));1000 let item_contains = list.iter().any(|i| i.approved == approved);10011002 if !item_contains {1003 list.push(ApprovePermissions { approved: approved.clone(), amount: amount });1004 <ApprovedList<T>>::insert(collection_id, (item_id, sender.clone()), list);1005 }1006 } else {10071008 let mut list = Vec::new();1009 list.push(ApprovePermissions { approved: approved.clone(), amount: amount });1010 <ApprovedList<T>>::insert(collection_id, (item_id, sender.clone()), list);1011 }10121013 Ok(())1014 }1015 1016 /// 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.1017 /// 1018 /// # Permissions1019 /// * Collection Owner1020 /// * Collection Admin1021 /// * Current NFT owner1022 /// * Address approved by current NFT owner1023 /// 1024 /// # Arguments1025 /// 1026 /// * from: Address that owns token.1027 /// 1028 /// * recipient: Address of token recipient.1029 /// 1030 /// * collection_id.1031 /// 1032 /// * item_id: ID of the item.1033 /// 1034 /// * value: Amount to transfer.1035 #[weight =1036 (150_000_000 as Weight)1037 .saturating_add(RocksDbWeight::get().reads(9 as Weight))1038 .saturating_add(RocksDbWeight::get().writes(8 as Weight))]1039 pub fn transfer_from(origin, from: T::AccountId, recipient: T::AccountId, collection_id: u64, item_id: u64, value: u64 ) -> DispatchResult {10401041 let sender = ensure_signed(origin)?;1042 let mut appoved_transfer = false;10431044 // Check approve1045 if <ApprovedList<T>>::contains_key(collection_id, (item_id, from.clone())) {1046 let list_itm = <ApprovedList<T>>::get(collection_id, (item_id, from.clone()));1047 let opt_item = list_itm.iter().find(|i| i.approved == sender.clone());1048 if opt_item.is_some()1049 {1050 appoved_transfer = true;1051 ensure!(opt_item.unwrap().amount >= value, "Requested value more than approved");1052 }1053 }10541055 // Transfer permissions check1056 let target_collection = <Collection<T>>::get(collection_id);1057 ensure!(appoved_transfer || Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1058 "Only item owner, collection owner and admins can modify items");10591060 if target_collection.access == AccessMode::WhiteList {1061 Self::check_white_list(collection_id, &sender)?;1062 Self::check_white_list(collection_id, &recipient)?;1063 }10641065 // remove approve1066 let approve_list: Vec<ApprovePermissions<T::AccountId>> = <ApprovedList<T>>::get(collection_id, (item_id, from.clone()))1067 .into_iter().filter(|i| i.approved != sender.clone()).collect();1068 <ApprovedList<T>>::insert(collection_id, (item_id, from.clone()), approve_list);106910701071 match target_collection.mode1072 {1073 CollectionMode::NFT(_) => Self::transfer_nft(collection_id, item_id, from, recipient)?,1074 CollectionMode::Fungible(_) => Self::transfer_fungible(collection_id, item_id, value, from.clone(), recipient)?,1075 CollectionMode::ReFungible(_, _) => Self::transfer_refungible(collection_id, item_id, value, from.clone(), recipient)?,1076 _ => ()1077 };10781079 Ok(())1080 }10811082 ///1083 #[weight = 0]1084 pub fn safe_transfer_from(origin, collection_id: u64, item_id: u64, new_owner: T::AccountId) -> DispatchResult {10851086 // let no_perm_mes = "You do not have permissions to modify this collection";1087 // ensure!(<ApprovedList<T>>::contains_key((collection_id, item_id)), no_perm_mes);1088 // let list_itm = <ApprovedList<T>>::get((collection_id, item_id));1089 // ensure!(list_itm.contains(&new_owner.clone()), no_perm_mes);10901091 // // on_nft_received call10921093 // Self::transfer(origin, collection_id, item_id, new_owner)?;10941095 Ok(())1096 }10971098 /// Set off-chain data schema.1099 /// 1100 /// # Permissions1101 /// 1102 /// * Collection Owner1103 /// * Collection Admin1104 /// 1105 /// # Arguments1106 /// 1107 /// * collection_id.1108 /// 1109 /// * schema: String representing the offchain data schema.1110 #[weight =1111 (33_000_000 as Weight)1112 .saturating_add(RocksDbWeight::get().reads(2 as Weight))1113 .saturating_add(RocksDbWeight::get().writes(1 as Weight))]1114 pub fn set_offchain_schema(1115 origin,1116 collection_id: u64,1117 schema: Vec<u8>1118 ) -> DispatchResult {1119 let sender = ensure_signed(origin)?;1120 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;11211122 let mut target_collection = <Collection<T>>::get(collection_id);1123 target_collection.offchain_schema = schema;1124 <Collection<T>>::insert(collection_id, target_collection);11251126 Ok(())1127 }11281129 // Sudo permissions function1130 #[weight = 0]1131 pub fn set_chain_limits(1132 origin,1133 limits: ChainLimits1134 ) -> DispatchResult {1135 ensure_root(origin)?;1136 <ChainLimit>::put(limits);1137 Ok(())1138 } 1139 }1140}11411142impl<T: Trait> Module<T> {1143 fn add_fungible_item(item: FungibleItemType<T::AccountId>) -> DispatchResult {1144 let current_index = <ItemListIndex>::get(item.collection)1145 .checked_add(1)1146 .expect("Item list index id error");1147 let itemcopy = item.clone();1148 let owner = item.owner.clone();1149 let value = item.value as u64;11501151 Self::add_token_index(item.collection, current_index, owner.clone())?;11521153 <ItemListIndex>::insert(item.collection, current_index);1154 <FungibleItemList<T>>::insert(item.collection, current_index, itemcopy);11551156 // Add current block1157 let v: Vec<BasketItem<T::AccountId, T::BlockNumber>> = Vec::new();1158 <FungibleTransferBasket<T>>::insert(item.collection, current_index, v);1159 1160 // Update balance1161 let new_balance = <Balance<T>>::get(item.collection, owner.clone())1162 .checked_add(value)1163 .unwrap();1164 <Balance<T>>::insert(item.collection, owner.clone(), new_balance);11651166 Ok(())1167 }11681169 fn add_refungible_item(item: ReFungibleItemType<T::AccountId>) -> DispatchResult {1170 let current_index = <ItemListIndex>::get(item.collection)1171 .checked_add(1)1172 .expect("Item list index id error");1173 let itemcopy = item.clone();11741175 let value = item.owner.first().unwrap().fraction as u64;1176 let owner = item.owner.first().unwrap().owner.clone();11771178 Self::add_token_index(item.collection, current_index, owner.clone())?;11791180 <ItemListIndex>::insert(item.collection, current_index);1181 <ReFungibleItemList<T>>::insert(item.collection, current_index, itemcopy);11821183 // Add current block1184 let block_number: T::BlockNumber = 0.into();1185 <ReFungibleTransferBasket<T>>::insert(item.collection, current_index, block_number);11861187 // Update balance1188 let new_balance = <Balance<T>>::get(item.collection, owner.clone())1189 .checked_add(value)1190 .unwrap();1191 <Balance<T>>::insert(item.collection, owner.clone(), new_balance);11921193 Ok(())1194 }11951196 fn add_nft_item(item: NftItemType<T::AccountId>) -> DispatchResult {1197 let current_index = <ItemListIndex>::get(item.collection)1198 .checked_add(1)1199 .expect("Item list index id error");12001201 let item_owner = item.owner.clone();1202 let collection_id = item.collection.clone();1203 Self::add_token_index(collection_id, current_index, item.owner.clone())?;12041205 <ItemListIndex>::insert(collection_id, current_index);1206 <NftItemList<T>>::insert(collection_id, current_index, item);12071208 // Add current block1209 let block_number: T::BlockNumber = 0.into();1210 <NftTransferBasket<T>>::insert(collection_id, current_index, block_number);12111212 // Update balance1213 let new_balance = <Balance<T>>::get(collection_id, item_owner.clone())1214 .checked_add(1)1215 .unwrap();1216 <Balance<T>>::insert(collection_id, item_owner.clone(), new_balance);12171218 Ok(())1219 }12201221 fn burn_refungible_item(1222 collection_id: u64,1223 item_id: u64,1224 owner: T::AccountId,1225 ) -> DispatchResult {1226 ensure!(1227 <ReFungibleItemList<T>>::contains_key(collection_id, item_id),1228 "Item does not exists"1229 );1230 let collection = <ReFungibleItemList<T>>::get(collection_id, item_id);1231 let item = collection1232 .owner1233 .iter()1234 .filter(|&i| i.owner == owner)1235 .next()1236 .unwrap();1237 Self::remove_token_index(collection_id, item_id, owner.clone())?;12381239 // remove approve list1240 <ApprovedList<T>>::remove(collection_id, (item_id, owner.clone()));12411242 // update balance1243 let new_balance = <Balance<T>>::get(collection_id, item.owner.clone())1244 .checked_sub(item.fraction as u64)1245 .unwrap();1246 <Balance<T>>::insert(collection_id, item.owner.clone(), new_balance);12471248 <ReFungibleItemList<T>>::remove(collection_id, item_id);12491250 Ok(())1251 }12521253 fn burn_nft_item(collection_id: u64, item_id: u64) -> DispatchResult {1254 ensure!(1255 <NftItemList<T>>::contains_key(collection_id, item_id),1256 "Item does not exists"1257 );1258 let item = <NftItemList<T>>::get(collection_id, item_id);1259 Self::remove_token_index(collection_id, item_id, item.owner.clone())?;12601261 // remove approve list1262 <ApprovedList<T>>::remove(collection_id, (item_id, item.owner.clone()));12631264 // update balance1265 let new_balance = <Balance<T>>::get(collection_id, item.owner.clone())1266 .checked_sub(1)1267 .unwrap();1268 <Balance<T>>::insert(collection_id, item.owner.clone(), new_balance);1269 <NftItemList<T>>::remove(collection_id, item_id);12701271 Ok(())1272 }12731274 fn burn_fungible_item(collection_id: u64, item_id: u64) -> DispatchResult {1275 ensure!(1276 <FungibleItemList<T>>::contains_key(collection_id, item_id),1277 "Item does not exists"1278 );1279 let item = <FungibleItemList<T>>::get(collection_id, item_id);1280 Self::remove_token_index(collection_id, item_id, item.owner.clone())?;12811282 // remove approve list1283 <ApprovedList<T>>::remove(collection_id, (item_id, item.owner.clone()));12841285 // update balance1286 let new_balance = <Balance<T>>::get(collection_id, item.owner.clone())1287 .checked_sub(item.value as u64)1288 .unwrap();1289 <Balance<T>>::insert(collection_id, item.owner.clone(), new_balance);12901291 <FungibleItemList<T>>::remove(collection_id, item_id);12921293 Ok(())1294 }12951296 fn collection_exists(collection_id: u64) -> DispatchResult {1297 ensure!(1298 <Collection<T>>::contains_key(collection_id),1299 "This collection does not exist"1300 );1301 Ok(())1302 }13031304 fn check_owner_permissions(collection_id: u64, subject: T::AccountId) -> DispatchResult {1305 Self::collection_exists(collection_id)?;13061307 let target_collection = <Collection<T>>::get(collection_id);1308 ensure!(1309 subject == target_collection.owner,1310 "You do not own this collection"1311 );13121313 Ok(())1314 }13151316 fn is_owner_or_admin_permissions(collection_id: u64, subject: T::AccountId) -> bool {1317 let target_collection = <Collection<T>>::get(collection_id);1318 let mut result: bool = subject == target_collection.owner;1319 let exists = <AdminList<T>>::contains_key(collection_id);13201321 if !result & exists {1322 if <AdminList<T>>::get(collection_id).contains(&subject) {1323 result = true1324 }1325 }13261327 result1328 }13291330 fn check_owner_or_admin_permissions(1331 collection_id: u64,1332 subject: T::AccountId,1333 ) -> DispatchResult {1334 Self::collection_exists(collection_id)?;1335 let result = Self::is_owner_or_admin_permissions(collection_id, subject.clone());13361337 ensure!(1338 result,1339 "You do not have permissions to modify this collection"1340 );1341 Ok(())1342 }13431344 fn is_item_owner(subject: T::AccountId, collection_id: u64, item_id: u64) -> bool {1345 let target_collection = <Collection<T>>::get(collection_id);13461347 match target_collection.mode {1348 CollectionMode::NFT(_) => {1349 <NftItemList<T>>::get(collection_id, item_id).owner == subject1350 }1351 CollectionMode::Fungible(_) => {1352 <FungibleItemList<T>>::get(collection_id, item_id).owner == subject1353 }1354 CollectionMode::ReFungible(_, _) => {1355 <ReFungibleItemList<T>>::get(collection_id, item_id)1356 .owner1357 .iter()1358 .any(|i| i.owner == subject)1359 }1360 CollectionMode::Invalid => false,1361 }1362 }13631364 fn check_white_list(collection_id: u64, address: &T::AccountId) -> DispatchResult {1365 let mes = "Address is not in white list";1366 ensure!(<WhiteList<T>>::contains_key(collection_id), mes);1367 let wl = <WhiteList<T>>::get(collection_id);1368 ensure!(wl.contains(address), mes);13691370 Ok(())1371 }13721373 fn transfer_fungible(1374 collection_id: u64,1375 item_id: u64,1376 value: u64,1377 owner: T::AccountId,1378 new_owner: T::AccountId,1379 ) -> DispatchResult {1380 ensure!(1381 <FungibleItemList<T>>::contains_key(collection_id, item_id),1382 "Item not exists"1383 );13841385 let full_item = <FungibleItemList<T>>::get(collection_id, item_id);1386 let amount = full_item.value;13871388 ensure!(amount >= value.into(), "Item balance not enouth");13891390 // update balance1391 let balance_old_owner = <Balance<T>>::get(collection_id, owner.clone())1392 .checked_sub(value)1393 .unwrap();1394 <Balance<T>>::insert(collection_id, owner.clone(), balance_old_owner);13951396 let mut new_owner_account_id = 0;1397 let new_owner_items = <AddressTokens<T>>::get(collection_id, new_owner.clone());1398 if new_owner_items.len() > 0 {1399 new_owner_account_id = new_owner_items[0];1400 }14011402 let val64 = value.into();14031404 // transfer1405 if amount == val64 && new_owner_account_id == 0 {1406 // change owner1407 // new owner do not have account1408 let mut new_full_item = full_item.clone();1409 new_full_item.owner = new_owner.clone();1410 <FungibleItemList<T>>::insert(collection_id, item_id, new_full_item);14111412 // update balance1413 let balance_new_owner = <Balance<T>>::get(collection_id, new_owner.clone())1414 .checked_add(value)1415 .unwrap();1416 <Balance<T>>::insert(collection_id, new_owner.clone(), balance_new_owner);14171418 // update index collection1419 Self::move_token_index(collection_id, item_id, owner.clone(), new_owner.clone())?;1420 } else {1421 let mut new_full_item = full_item.clone();1422 new_full_item.value -= val64;14231424 // separate amount1425 if new_owner_account_id > 0 {1426 // new owner has account1427 let mut item = <FungibleItemList<T>>::get(collection_id, new_owner_account_id);1428 item.value += val64;14291430 // update balance1431 let balance_new_owner = <Balance<T>>::get(collection_id, new_owner.clone())1432 .checked_add(value)1433 .unwrap();1434 <Balance<T>>::insert(collection_id, new_owner.clone(), balance_new_owner);14351436 <FungibleItemList<T>>::insert(collection_id, new_owner_account_id, item);1437 } else {1438 // new owner do not have account1439 let item = FungibleItemType {1440 collection: collection_id,1441 owner: new_owner.clone(),1442 value: val64,1443 };14441445 Self::add_fungible_item(item)?;1446 }14471448 if amount == val64 {1449 Self::remove_token_index(collection_id, item_id, full_item.owner.clone())?;14501451 // remove approve list1452 <ApprovedList<T>>::remove(collection_id, (item_id, full_item.owner.clone()));1453 <FungibleItemList<T>>::remove(collection_id, item_id);1454 }14551456 <FungibleItemList<T>>::insert(collection_id, item_id, new_full_item);1457 }14581459 Ok(())1460 }14611462 fn transfer_refungible(1463 collection_id: u64,1464 item_id: u64,1465 value: u64,1466 owner: T::AccountId,1467 new_owner: T::AccountId,1468 ) -> DispatchResult {1469 ensure!(1470 <ReFungibleItemList<T>>::contains_key(collection_id, item_id),1471 "Item not exists"1472 );14731474 let full_item = <ReFungibleItemList<T>>::get(collection_id, item_id);1475 let item = full_item1476 .owner1477 .iter()1478 .filter(|i| i.owner == owner)1479 .next()1480 .unwrap();1481 let amount = item.fraction;14821483 ensure!(amount >= value.into(), "Item balance not enouth");14841485 // update balance1486 let balance_old_owner = <Balance<T>>::get(collection_id, item.owner.clone())1487 .checked_sub(value)1488 .unwrap();1489 <Balance<T>>::insert(collection_id, item.owner.clone(), balance_old_owner);14901491 let balance_new_owner = <Balance<T>>::get(collection_id, new_owner.clone())1492 .checked_add(value)1493 .unwrap();1494 <Balance<T>>::insert(collection_id, new_owner.clone(), balance_new_owner);14951496 let old_owner = item.owner.clone();1497 let new_owner_has_account = full_item.owner.iter().any(|i| i.owner == new_owner);1498 let val64 = value.into();14991500 // transfer1501 if amount == val64 && !new_owner_has_account {1502 // change owner1503 // new owner do not have account1504 let mut new_full_item = full_item.clone();1505 new_full_item1506 .owner1507 .iter_mut()1508 .find(|i| i.owner == owner)1509 .unwrap()1510 .owner = new_owner.clone();1511 <ReFungibleItemList<T>>::insert(collection_id, item_id, new_full_item);15121513 // update index collection1514 Self::move_token_index(collection_id, item_id, old_owner.clone(), new_owner.clone())?;1515 } else {1516 let mut new_full_item = full_item.clone();1517 new_full_item1518 .owner1519 .iter_mut()1520 .find(|i| i.owner == owner)1521 .unwrap()1522 .fraction -= val64;15231524 // separate amount1525 if new_owner_has_account {1526 // new owner has account1527 new_full_item1528 .owner1529 .iter_mut()1530 .find(|i| i.owner == new_owner)1531 .unwrap()1532 .fraction += val64;1533 } else {1534 // new owner do not have account1535 new_full_item.owner.push(Ownership {1536 owner: new_owner.clone(),1537 fraction: val64,1538 });1539 Self::add_token_index(collection_id, item_id, new_owner.clone())?;1540 }15411542 <ReFungibleItemList<T>>::insert(collection_id, item_id, new_full_item);1543 }15441545 Ok(())1546 }15471548 fn transfer_nft(1549 collection_id: u64,1550 item_id: u64,1551 sender: T::AccountId,1552 new_owner: T::AccountId,1553 ) -> DispatchResult {1554 ensure!(1555 <NftItemList<T>>::contains_key(collection_id, item_id),1556 "Item not exists"1557 );15581559 let mut item = <NftItemList<T>>::get(collection_id, item_id);15601561 ensure!(1562 sender == item.owner,1563 "sender parameter and item owner must be equal"1564 );15651566 // update balance1567 let balance_old_owner = <Balance<T>>::get(collection_id, item.owner.clone())1568 .checked_sub(1)1569 .unwrap();1570 <Balance<T>>::insert(collection_id, item.owner.clone(), balance_old_owner);15711572 let balance_new_owner = <Balance<T>>::get(collection_id, new_owner.clone())1573 .checked_add(1)1574 .unwrap();1575 <Balance<T>>::insert(collection_id, new_owner.clone(), balance_new_owner);15761577 // change owner1578 let old_owner = item.owner.clone();1579 item.owner = new_owner.clone();1580 <NftItemList<T>>::insert(collection_id, item_id, item);15811582 // update index collection1583 Self::move_token_index(collection_id, item_id, old_owner.clone(), new_owner.clone())?;15841585 // reset approved list1586 <ApprovedList<T>>::remove(collection_id, (item_id, old_owner));1587 Ok(())1588 }15891590 fn init_collection(item: &CollectionType<T::AccountId>) {1591 // check params1592 assert!(1593 item.decimal_points <= 4,1594 "decimal_points parameter must be lower than 4"1595 );1596 assert!(1597 item.name.len() <= 64,1598 "Collection name can not be longer than 63 char"1599 );1600 assert!(1601 item.name.len() <= 256,1602 "Collection description can not be longer than 255 char"1603 );1604 assert!(1605 item.token_prefix.len() <= 16,1606 "Token prefix can not be longer than 15 char"1607 );16081609 // Generate next collection ID1610 let next_id = CreatedCollectionCount::get()1611 .checked_add(1)1612 .expect("collection id error");16131614 CreatedCollectionCount::put(next_id);1615 }16161617 fn init_nft_token(item: &NftItemType<T::AccountId>) {1618 let current_index = <ItemListIndex>::get(item.collection)1619 .checked_add(1)1620 .expect("Item list index id error");16211622 let item_owner = item.owner.clone();1623 let collection_id = item.collection.clone();1624 Self::add_token_index(collection_id, current_index, item.owner.clone()).unwrap();16251626 <ItemListIndex>::insert(collection_id, current_index);16271628 // Update balance1629 let new_balance = <Balance<T>>::get(collection_id, item_owner.clone())1630 .checked_add(1)1631 .unwrap();1632 <Balance<T>>::insert(collection_id, item_owner.clone(), new_balance);1633 }16341635 fn init_fungible_token(item: &FungibleItemType<T::AccountId>) {1636 let current_index = <ItemListIndex>::get(item.collection)1637 .checked_add(1)1638 .expect("Item list index id error");1639 let owner = item.owner.clone();1640 let value = item.value as u64;16411642 Self::add_token_index(item.collection, current_index, owner.clone()).unwrap();16431644 <ItemListIndex>::insert(item.collection, current_index);16451646 // Update balance1647 let new_balance = <Balance<T>>::get(item.collection, owner.clone())1648 .checked_add(value)1649 .unwrap();1650 <Balance<T>>::insert(item.collection, owner.clone(), new_balance);1651 }16521653 fn init_refungible_token(item: &ReFungibleItemType<T::AccountId>) {1654 let current_index = <ItemListIndex>::get(item.collection)1655 .checked_add(1)1656 .expect("Item list index id error");16571658 let value = item.owner.first().unwrap().fraction as u64;1659 let owner = item.owner.first().unwrap().owner.clone();16601661 Self::add_token_index(item.collection, current_index, owner.clone()).unwrap();16621663 <ItemListIndex>::insert(item.collection, current_index);16641665 // Update balance1666 let new_balance = <Balance<T>>::get(item.collection, owner.clone())1667 .checked_add(value)1668 .unwrap();1669 <Balance<T>>::insert(item.collection, owner.clone(), new_balance);1670 }16711672 fn add_token_index(collection_id: u64, item_index: u64, owner: T::AccountId) -> DispatchResult {16731674 // add to account limit1675 if <AccountItemCount<T>>::contains_key(owner.clone()) {16761677 // bound Owned tokens by a single address1678 let count = <AccountItemCount<T>>::get(owner.clone());1679 ensure!(count < ChainLimit::get().account_token_ownership_limit, "Owned tokens by a single address bound exceeded");16801681 <AccountItemCount<T>>::insert(owner.clone(), 1682 count.checked_add(1).unwrap());1683 }1684 else {1685 <AccountItemCount<T>>::insert(owner.clone(), 1);1686 }16871688 let list_exists = <AddressTokens<T>>::contains_key(collection_id, owner.clone());1689 if list_exists {1690 let mut list = <AddressTokens<T>>::get(collection_id, owner.clone());1691 let item_contains = list.contains(&item_index.clone());16921693 if !item_contains {1694 list.push(item_index.clone());1695 }16961697 <AddressTokens<T>>::insert(collection_id, owner.clone(), list);1698 } else {1699 let mut itm = Vec::new();1700 itm.push(item_index.clone());1701 <AddressTokens<T>>::insert(collection_id, owner, itm);1702 1703 }17041705 Ok(())1706 }17071708 fn remove_token_index(1709 collection_id: u64,1710 item_index: u64,1711 owner: T::AccountId,1712 ) -> DispatchResult {17131714 // update counter1715 <AccountItemCount<T>>::insert(owner.clone(), 1716 <AccountItemCount<T>>::get(owner.clone()).checked_sub(1).unwrap());171717181719 let list_exists = <AddressTokens<T>>::contains_key(collection_id, owner.clone());1720 if list_exists {1721 let mut list = <AddressTokens<T>>::get(collection_id, owner.clone());1722 let item_contains = list.contains(&item_index.clone());17231724 if item_contains {1725 list.retain(|&item| item != item_index);1726 <AddressTokens<T>>::insert(collection_id, owner, list);1727 }1728 }17291730 Ok(())1731 }17321733 fn move_token_index(1734 collection_id: u64,1735 item_index: u64,1736 old_owner: T::AccountId,1737 new_owner: T::AccountId,1738 ) -> DispatchResult {1739 Self::remove_token_index(collection_id, item_index, old_owner)?;1740 Self::add_token_index(collection_id, item_index, new_owner)?;17411742 Ok(())1743 }1744}17451746////////////////////////////////////////////////////////////////////////////////////////////////////1747// Economic models1748// #region17491750/// Fee multiplier.1751pub type Multiplier = FixedU128;17521753type BalanceOf<T> = <<T as transaction_payment::Trait>::Currency as Currency<1754 <T as system::Trait>::AccountId,1755>>::Balance;1756type NegativeImbalanceOf<T> = <<T as transaction_payment::Trait>::Currency as Currency<1757 <T as system::Trait>::AccountId,1758>>::NegativeImbalance;17591760/// Require the transactor pay for themselves and maybe include a tip to gain additional priority1761/// in the queue.1762#[derive(Encode, Decode, Clone, Eq, PartialEq)]1763pub struct ChargeTransactionPayment<T: transaction_payment::Trait + Send + Sync>(1764 #[codec(compact)] BalanceOf<T>,1765);17661767impl<T: Trait + transaction_payment::Trait + Send + Sync> sp_std::fmt::Debug1768 for ChargeTransactionPayment<T>1769{1770 #[cfg(feature = "std")]1771 fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {1772 write!(f, "ChargeTransactionPayment<{:?}>", self.0)1773 }1774 #[cfg(not(feature = "std"))]1775 fn fmt(&self, _: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {1776 Ok(())1777 }1778}17791780impl<T: Trait + transaction_payment::Trait + Send + Sync> ChargeTransactionPayment<T>1781where1782 T::Call:1783 Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo> + IsSubType<Call<T>>,1784 BalanceOf<T>: Send + Sync + FixedPointOperand,1785{1786 /// utility constructor. Used only in client/factory code.1787 pub fn from(fee: BalanceOf<T>) -> Self {1788 Self(fee)1789 }17901791 pub fn traditional_fee(1792 len: usize,1793 info: &DispatchInfoOf<T::Call>,1794 tip: BalanceOf<T>,1795 ) -> BalanceOf<T>1796 where1797 T::Call: Dispatchable<Info = DispatchInfo>,1798 {1799 <transaction_payment::Module<T>>::compute_fee(len as u32, info, tip)1800 }18011802 fn withdraw_fee(1803 &self,1804 who: &T::AccountId,1805 call: &T::Call,1806 info: &DispatchInfoOf<T::Call>,1807 len: usize,1808 ) -> Result<(BalanceOf<T>, Option<NegativeImbalanceOf<T>>), TransactionValidityError> {1809 let tip = self.0;18101811 // Set fee based on call type. Creating collection costs 1 Unique.1812 // All other transactions have traditional fees so far1813 let fee = match call.is_sub_type() {1814 Some(Call::create_collection(..)) => <BalanceOf<T>>::from(1_000_000_000),1815 _ => Self::traditional_fee(len, info, tip), // Flat fee model, use only for testing purposes1816 // _ => <BalanceOf<T>>::from(100)1817 };18181819 // Determine who is paying transaction fee based on ecnomic model1820 // Parse call to extract collection ID and access collection sponsor1821 let sponsor: T::AccountId = match call.is_sub_type() {1822 Some(Call::create_item(collection_id, _properties, _owner)) => {1823 <Collection<T>>::get(collection_id).sponsor1824 }1825 Some(Call::transfer(_new_owner, collection_id, _item_id, _value)) => {1826 let _collection_mode = <Collection<T>>::get(collection_id).mode;18271828 // sponsor timeout1829 let sponsor_transfer = match _collection_mode {1830 CollectionMode::NFT(_) => {1831 let basket = <NftTransferBasket<T>>::get(collection_id, _item_id);1832 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;1833 let limit_time = basket + ChainLimit::get().nft_sponsor_transfer_timeout.into();1834 if block_number >= limit_time {1835 <NftTransferBasket<T>>::insert(collection_id, _item_id, block_number);1836 true1837 }1838 else {1839 false1840 }1841 }1842 CollectionMode::Fungible(_) => {1843 let mut basket = <FungibleTransferBasket<T>>::get(collection_id, _item_id);1844 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;1845 if basket.iter().any(|i| i.address == _new_owner.clone())1846 {1847 let item = basket.iter_mut().find(|i| i.address == _new_owner.clone()).unwrap().clone();1848 let limit_time = item.start_block + ChainLimit::get().fungible_sponsor_transfer_timeout.into();1849 if block_number >= limit_time {1850 basket.retain(|x| x.address == item.address);1851 basket.push(BasketItem { start_block: block_number, address: _new_owner.clone() });1852 <FungibleTransferBasket<T>>::insert(collection_id, _item_id, basket);1853 true1854 }1855 else {1856 false1857 }1858 }1859 else {1860 basket.push(BasketItem { start_block: block_number, address: _new_owner.clone()});1861 true1862 }1863 }1864 CollectionMode::ReFungible(_, _) => {1865 let basket = <ReFungibleTransferBasket<T>>::get(collection_id, _item_id);1866 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;1867 let limit_time = basket + ChainLimit::get().nft_sponsor_transfer_timeout.into();1868 if block_number >= limit_time {1869 <ReFungibleTransferBasket<T>>::insert(collection_id, _item_id, block_number);1870 true1871 } else {1872 false1873 }1874 }1875 _ => {1876 false1877 },1878 };18791880 if !sponsor_transfer {1881 T::AccountId::default()1882 } else {1883 <Collection<T>>::get(collection_id).sponsor1884 }1885 }18861887 _ => T::AccountId::default(),1888 };18891890 let mut who_pays_fee: T::AccountId = sponsor.clone();1891 if sponsor == T::AccountId::default() {1892 who_pays_fee = who.clone();1893 }18941895 // Only mess with balances if fee is not zero.1896 if fee.is_zero() {1897 return Ok((fee, None));1898 }18991900 match <T as transaction_payment::Trait>::Currency::withdraw(1901 &who_pays_fee,1902 fee,1903 if tip.is_zero() {1904 WithdrawReason::TransactionPayment.into()1905 } else {1906 WithdrawReason::TransactionPayment | WithdrawReason::Tip1907 },1908 ExistenceRequirement::KeepAlive,1909 ) {1910 Ok(imbalance) => Ok((fee, Some(imbalance))),1911 Err(_) => Err(InvalidTransaction::Payment.into()),1912 }1913 }1914}19151916impl<T: Trait + transaction_payment::Trait + Send + Sync> SignedExtension1917 for ChargeTransactionPayment<T>1918where1919 BalanceOf<T>: Send + Sync + From<u64> + FixedPointOperand,1920 T::Call: Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo> + IsSubType<Call<T>>,1921{1922 const IDENTIFIER: &'static str = "ChargeTransactionPayment";1923 type AccountId = T::AccountId;1924 type Call = T::Call;1925 type AdditionalSigned = ();1926 type Pre = (1927 BalanceOf<T>,1928 Self::AccountId,1929 Option<NegativeImbalanceOf<T>>,1930 BalanceOf<T>,1931 );1932 fn additional_signed(&self) -> sp_std::result::Result<(), TransactionValidityError> {1933 Ok(())1934 }19351936 fn validate(1937 &self,1938 who: &Self::AccountId,1939 call: &Self::Call,1940 info: &DispatchInfoOf<Self::Call>,1941 len: usize,1942 ) -> TransactionValidity {1943 let (fee, _) = self.withdraw_fee(who, call, info, len)?;19441945 let mut r = ValidTransaction::default();1946 // NOTE: we probably want to maximize the _fee (of any type) per weight unit_ here, which1947 // will be a bit more than setting the priority to tip. For now, this is enough.1948 r.priority = fee.saturated_into::<TransactionPriority>();1949 Ok(r)1950 }19511952 fn pre_dispatch(1953 self,1954 who: &Self::AccountId,1955 call: &Self::Call,1956 info: &DispatchInfoOf<Self::Call>,1957 len: usize,1958 ) -> Result<Self::Pre, TransactionValidityError> {1959 let (fee, imbalance) = self.withdraw_fee(who, call, info, len)?;1960 Ok((self.0, who.clone(), imbalance, fee))1961 }19621963 fn post_dispatch(1964 pre: Self::Pre,1965 info: &DispatchInfoOf<Self::Call>,1966 post_info: &PostDispatchInfoOf<Self::Call>,1967 len: usize,1968 _result: &DispatchResult,1969 ) -> Result<(), TransactionValidityError> {1970 let (tip, who, imbalance, fee) = pre;1971 if let Some(payed) = imbalance {1972 let actual_fee = <transaction_payment::Module<T>>::compute_actual_fee(1973 len as u32, info, post_info, tip,1974 );1975 let refund = fee.saturating_sub(actual_fee);1976 let actual_payment =1977 match <T as transaction_payment::Trait>::Currency::deposit_into_existing(1978 &who, refund,1979 ) {1980 Ok(refund_imbalance) => {1981 // The refund cannot be larger than the up front payed max weight.1982 // `PostDispatchInfo::calc_unspent` guards against such a case.1983 match payed.offset(refund_imbalance) {1984 Ok(actual_payment) => actual_payment,1985 Err(_) => return Err(InvalidTransaction::Payment.into()),1986 }1987 }1988 // We do not recreate the account using the refund. The up front payment1989 // is gone in that case.1990 Err(_) => payed,1991 };1992 let imbalances = actual_payment.split(tip);1993 <T as transaction_payment::Trait>::OnTransactionPayment::on_unbalanceds(1994 Some(imbalances.0).into_iter().chain(Some(imbalances.1)),1995 );1996 }1997 Ok(())1998 }1999}2000// #endregion20012002runtime/src/lib.rsdiffbeforeafterboth--- a/runtime/src/lib.rs
+++ b/runtime/src/lib.rs
@@ -84,6 +84,7 @@
/// Digest item type.
pub type DigestItem = generic::DigestItem<Hash>;
+mod nft_weights;
/// Opaque types. These are used by the CLI to instantiate machinery that don't need to know
/// the specifics of the runtime. They can then be made to be agnostic over specific formats
@@ -144,9 +145,12 @@
pub const MaximumBlockWeight: Weight = 2 * WEIGHT_PER_SECOND;
pub const AvailableBlockRatio: Perbill = Perbill::from_percent(75);
/// Assume 10% of weight for average on_initialize calls.
- pub MaximumExtrinsicWeight: Weight = AvailableBlockRatio::get()
- .saturating_sub(Perbill::from_percent(10)) * MaximumBlockWeight::get();
- pub const MaximumBlockLength: u32 = 5 * 1024 * 1024;
+ // pub MaximumExtrinsicWeight: Weight = AvailableBlockRatio::get()
+ // .saturating_sub(Perbill::from_percent(10)) * MaximumBlockWeight::get();
+
+ pub MaximumExtrinsicWeight: Weight = 4_294_967_295;
+ //pub const MaximumBlockLength: u32 = 5 * 1024 * 1024;
+ pub const MaximumBlockLength: u32 = 4_294_967_295;
pub const Version: RuntimeVersion = VERSION;
}
@@ -291,7 +295,7 @@
}
parameter_types! {
- pub const TransactionByteFee: Balance = 1;
+ pub const TransactionByteFee: Balance = 10 * MILLICENTS;
}
impl pallet_transaction_payment::Trait for Runtime {
@@ -299,7 +303,7 @@
type OnTransactionPayment = ();
type TransactionByteFee = TransactionByteFee;
type WeightToFee = IdentityFee<Balance>;
- type FeeMultiplierUpdate = ();
+ type FeeMultiplierUpdate = ();
}
impl pallet_sudo::Trait for Runtime {
@@ -310,6 +314,7 @@
/// Used for the module nft in `./nft.rs`
impl pallet_nft::Trait for Runtime {
type Event = Event;
+ type WeightInfo = nft_weights::WeightInfo;
}
construct_runtime!(
runtime/src/nft_weights.rsdiffbeforeafterboth--- /dev/null
+++ b/runtime/src/nft_weights.rs
@@ -0,0 +1,96 @@
+use frame_support::weights::{Weight, constants::RocksDbWeight as DbWeight};
+
+pub struct WeightInfo;
+impl pallet_nft::WeightInfo for WeightInfo {
+ fn create_collection() -> Weight {
+ (70_000_000 as Weight)
+ .saturating_add(DbWeight::get().reads(7 as Weight))
+ .saturating_add(DbWeight::get().writes(5 as Weight))
+ }
+ fn destroy_collection() -> Weight {
+ (90_000_000 as Weight)
+ .saturating_add(DbWeight::get().reads(2 as Weight))
+ .saturating_add(DbWeight::get().writes(5 as Weight))
+ }
+ fn add_to_white_list() -> Weight {
+ (30_000_000 as Weight)
+ .saturating_add(DbWeight::get().reads(3 as Weight))
+ .saturating_add(DbWeight::get().writes(1 as Weight))
+ }
+ fn remove_from_white_list() -> Weight {
+ (35_000_000 as Weight)
+ .saturating_add(DbWeight::get().reads(3 as Weight))
+ .saturating_add(DbWeight::get().writes(1 as Weight))
+ }
+ fn set_public_access_mode() -> Weight {
+ (27_000_000 as Weight)
+ .saturating_add(DbWeight::get().reads(1 as Weight))
+ .saturating_add(DbWeight::get().writes(1 as Weight))
+ }
+ fn set_mint_permission() -> Weight {
+ (27_000_000 as Weight)
+ .saturating_add(DbWeight::get().reads(1 as Weight))
+ .saturating_add(DbWeight::get().writes(1 as Weight))
+ }
+ fn change_collection_owner() -> Weight {
+ (27_000_000 as Weight)
+ .saturating_add(DbWeight::get().reads(1 as Weight))
+ .saturating_add(DbWeight::get().writes(1 as Weight))
+ }
+ fn add_collection_admin() -> Weight {
+ (32_000_000 as Weight)
+ .saturating_add(DbWeight::get().reads(3 as Weight))
+ .saturating_add(DbWeight::get().writes(1 as Weight))
+ }
+ fn remove_collection_admin() -> Weight {
+ (50_000_000 as Weight)
+ .saturating_add(DbWeight::get().reads(2 as Weight))
+ .saturating_add(DbWeight::get().writes(1 as Weight))
+ }
+ fn set_collection_sponsor() -> Weight {
+ (32_000_000 as Weight)
+ .saturating_add(DbWeight::get().reads(2 as Weight))
+ .saturating_add(DbWeight::get().writes(1 as Weight))
+ }
+ fn confirm_sponsorship() -> Weight {
+ (22_000_000 as Weight)
+ .saturating_add(DbWeight::get().reads(1 as Weight))
+ .saturating_add(DbWeight::get().writes(1 as Weight))
+ }
+ fn remove_collection_sponsor() -> Weight {
+ (24_000_000 as Weight)
+ .saturating_add(DbWeight::get().reads(1 as Weight))
+ .saturating_add(DbWeight::get().writes(1 as Weight))
+ }
+ fn create_item(s: usize, ) -> Weight {
+ (130_000_000 as Weight)
+ .saturating_add((2135 as Weight).saturating_mul(s as Weight))
+ .saturating_add(DbWeight::get().reads(10 as Weight))
+ .saturating_add(DbWeight::get().writes(8 as Weight))
+ }
+ fn burn_item() -> Weight {
+ (170_000_000 as Weight)
+ .saturating_add(DbWeight::get().reads(9 as Weight))
+ .saturating_add(DbWeight::get().writes(7 as Weight))
+ }
+ fn transfer() -> Weight {
+ (125_000_000 as Weight)
+ .saturating_add(DbWeight::get().reads(7 as Weight))
+ .saturating_add(DbWeight::get().writes(7 as Weight))
+ }
+ fn approve() -> Weight {
+ (45_000_000 as Weight)
+ .saturating_add(DbWeight::get().reads(3 as Weight))
+ .saturating_add(DbWeight::get().writes(1 as Weight))
+ }
+ fn transfer_from() -> Weight {
+ (150_000_000 as Weight)
+ .saturating_add(DbWeight::get().reads(9 as Weight))
+ .saturating_add(DbWeight::get().writes(8 as Weight))
+ }
+ fn set_offchain_schema() -> Weight {
+ (33_000_000 as Weight)
+ .saturating_add(DbWeight::get().reads(2 as Weight))
+ .saturating_add(DbWeight::get().writes(1 as Weight))
+ }
+}