1#![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};2526use frame_system::{self as system, ensure_signed, ensure_root};27use sp_runtime::sp_std::prelude::Vec;28use sp_runtime::{29 traits::{30 DispatchInfoOf, Dispatchable, PostDispatchInfoOf, SaturatedConversion, Saturating,31 SignedExtension, Zero,32 },33 transaction_validity::{34 InvalidTransaction, TransactionPriority, TransactionValidity, TransactionValidityError,35 ValidTransaction,36 },37 FixedPointOperand, FixedU128,38};3940#[cfg(test)]41mod mock;4243#[cfg(test)]44mod tests;4546474849#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq)]50#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]51pub enum CollectionMode {52 Invalid,53 54 NFT(u32),55 56 Fungible(u32),57 58 ReFungible(u32, u32),59}6061impl Into<u8> for CollectionMode {62 fn into(self) -> u8 {63 match self {64 CollectionMode::Invalid => 0,65 CollectionMode::NFT(_) => 1,66 CollectionMode::Fungible(_) => 2,67 CollectionMode::ReFungible(_, _) => 3,68 }69 }70}7172#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq)]73#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]74pub enum AccessMode {75 Normal,76 WhiteList,77}78impl Default for AccessMode {79 fn default() -> Self {80 Self::Normal81 }82}8384impl Default for CollectionMode {85 fn default() -> Self {86 Self::Invalid87 }88}8990#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]91#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]92pub struct Ownership<AccountId> {93 pub owner: AccountId,94 pub fraction: u128,95}9697#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]98#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]99pub struct CollectionType<AccountId> {100 pub owner: AccountId,101 pub mode: CollectionMode,102 pub access: AccessMode,103 pub decimal_points: u32,104 pub name: Vec<u16>, 105 pub description: Vec<u16>, 106 pub token_prefix: Vec<u8>, 107 pub custom_data_size: u32,108 pub mint_mode: bool,109 pub offchain_schema: Vec<u8>,110 pub sponsor: AccountId, 111 pub unconfirmed_sponsor: AccountId, 112}113114#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]115#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]116pub struct CollectionAdminsType<AccountId> {117 pub admin: AccountId,118 pub collection_id: u64,119}120121#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]122#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]123pub struct NftItemType<AccountId> {124 pub collection: u64,125 pub owner: AccountId,126 pub data: Vec<u8>,127}128129#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]130#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]131pub struct FungibleItemType<AccountId> {132 pub collection: u64,133 pub owner: AccountId,134 pub value: u128,135}136137#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]138#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]139pub struct ReFungibleItemType<AccountId> {140 pub collection: u64,141 pub owner: Vec<Ownership<AccountId>>,142 pub data: Vec<u8>,143}144145#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]146#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]147pub struct ApprovePermissions<AccountId> {148 pub approved: AccountId,149 pub amount: u64,150}151152#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]153#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]154pub struct VestingItem<AccountId, Moment> {155 pub sender: AccountId,156 pub recipient: AccountId,157 pub collection_id: u64,158 pub item_id: u64,159 pub amount: u64,160 pub vesting_date: Moment,161}162163#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]164#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]165pub struct BasketItem<AccountId, BlockNumber> {166 pub address: AccountId,167 pub start_block: BlockNumber,168}169170#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]171#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]172pub struct ChainLimits {173 pub collection_numbers_limit: u64,174 pub account_token_ownership_limit: u64,175 pub collections_admins_limit: u64,176 pub custom_data_limit: u32,177178 179 pub nft_sponsor_transfer_timeout: u32,180 pub fungible_sponsor_transfer_timeout: u32,181 pub refungible_sponsor_transfer_timeout: u32,182}183184pub trait Trait: system::Trait {185 type Event: From<Event<Self>> + Into<<Self as system::Trait>::Event>;186}187188189190decl_storage! {191 trait Store for Module<T: Trait> as Nft {192193 194 NextCollectionID: u64;195 CreatedCollectionCount: u64;196 ChainVersion: u64;197 ItemListIndex: map hasher(blake2_128_concat) u64 => u64;198199 200 pub ChainLimit get(fn chain_limit) config(): ChainLimits;201202 203 CollectionCount: u64;204 pub AccountItemCount get(fn account_item_count): map hasher(identity) T::AccountId => u64;205206 207 pub Collection get(fn collection) config(): map hasher(identity) u64 => CollectionType<T::AccountId>;208 pub AdminList get(fn admin_list_collection): map hasher(identity) u64 => Vec<T::AccountId>;209 pub WhiteList get(fn white_list): map hasher(identity) u64 => Vec<T::AccountId>;210211 212 pub Balance get(fn balance_count): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) T::AccountId => u64;213214 215 pub ApprovedList get(fn approved): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) (u64, T::AccountId) => Vec<ApprovePermissions<T::AccountId>>;216217 218 pub NftItemList get(fn nft_item_id) config(): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => NftItemType<T::AccountId>;219 pub FungibleItemList get(fn fungible_item_id) config(): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => FungibleItemType<T::AccountId>;220 pub ReFungibleItemList get(fn refungible_item_id) config(): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => ReFungibleItemType<T::AccountId>;221222 223 pub AddressTokens get(fn address_tokens): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) T::AccountId => Vec<u64>;224225 226 pub NftTransferBasket get(fn nft_transfer_basket): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => T::BlockNumber;227 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>>;228 pub ReFungibleTransferBasket get(fn refungible_transfer_basket): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => T::BlockNumber;229230 231 pub ContractSponsor get(fn contract_sponsor): map hasher(identity) T::AccountId => T::AccountId;232 pub UnconfirmedContractSponsor get(fn unconfirmed_contract_sponsor): map hasher(identity) T::AccountId => T::AccountId;233 }234 add_extra_genesis {235 build(|config: &GenesisConfig<T>| {236 237 for (_num, _c) in &config.collection {238 <Module<T>>::init_collection(_c);239 }240241 for (_num, _q, _i) in &config.nft_item_id {242 <Module<T>>::init_nft_token(_i);243 }244245 for (_num, _q, _i) in &config.fungible_item_id {246 <Module<T>>::init_fungible_token(_i);247 }248249 for (_num, _q, _i) in &config.refungible_item_id {250 <Module<T>>::init_refungible_token(_i);251 }252 })253 }254}255256decl_event!(257 pub enum Event<T>258 where259 AccountId = <T as system::Trait>::AccountId,260 {261 Created(u64, u8, AccountId),262 ItemCreated(u64, u64),263 ItemDestroyed(u64, u64),264 }265);266267decl_module! {268 pub struct Module<T: Trait> for enum Call where origin: T::Origin {269270 fn deposit_event() = default;271272 fn on_initialize(now: T::BlockNumber) -> Weight {273274 if ChainVersion::get() < 2275 {276 let value = NextCollectionID::get();277 CreatedCollectionCount::put(value);278 ChainVersion::put(2);279 }280281 0282 }283284 285 286 287 288 #[weight = 0]289 pub fn create_collection(origin,290 collection_name: Vec<u16>,291 collection_description: Vec<u16>,292 token_prefix: Vec<u8>,293 mode: CollectionMode) -> DispatchResult {294295 296 let who = ensure_signed(origin)?;297 let custom_data_size = match mode {298 CollectionMode::NFT(size) => {299300 301 ensure!(size < ChainLimit::get().custom_data_limit, "Custom data size bound exceeded");302 size303 },304 CollectionMode::ReFungible(size, _) => {305306 307 ensure!(size < ChainLimit::get().custom_data_limit, "Custom data size bound exceeded");308 size309 },310 _ => 0311 };312313 let decimal_points = match mode {314 CollectionMode::Fungible(points) => points,315 CollectionMode::ReFungible(_, points) => points,316 _ => 0317 };318319 320 ensure!(CollectionCount::get() < ChainLimit::get().collection_numbers_limit, "Total collections bound exceeded");321322 323 ensure!(decimal_points <= 4, "decimal_points parameter must be lower than 4");324325 let mut name = collection_name.to_vec();326 name.push(0);327 ensure!(name.len() <= 64, "Collection name can not be longer than 63 char");328329 let mut description = collection_description.to_vec();330 description.push(0);331 ensure!(name.len() <= 256, "Collection description can not be longer than 255 char");332333 let mut prefix = token_prefix.to_vec();334 prefix.push(0);335 ensure!(prefix.len() <= 16, "Token prefix can not be longer than 15 char");336337 338 let next_id = CreatedCollectionCount::get()339 .checked_add(1)340 .expect("collection id error");341342 343 let total = CollectionCount::get()344 .checked_add(1)345 .expect("collection counter error");346347 CreatedCollectionCount::put(next_id);348 CollectionCount::put(total);349350 351 let new_collection = CollectionType {352 owner: who.clone(),353 name: name,354 mode: mode.clone(),355 mint_mode: false,356 access: AccessMode::Normal,357 description: description,358 decimal_points: decimal_points,359 token_prefix: prefix,360 offchain_schema: Vec::new(),361 custom_data_size: custom_data_size,362 sponsor: T::AccountId::default(),363 unconfirmed_sponsor: T::AccountId::default(),364 };365366 367 <Collection<T>>::insert(next_id, new_collection);368369 370 Self::deposit_event(RawEvent::Created(next_id, mode.into(), who.clone()));371372 Ok(())373 }374375 #[weight = 0]376 pub fn destroy_collection(origin, collection_id: u64) -> DispatchResult {377378 let sender = ensure_signed(origin)?;379 Self::check_owner_permissions(collection_id, sender)?;380381 <AddressTokens<T>>::remove_prefix(collection_id);382 <ApprovedList<T>>::remove_prefix(collection_id);383 <Balance<T>>::remove_prefix(collection_id);384 <ItemListIndex>::remove(collection_id);385 <AdminList<T>>::remove(collection_id);386 <Collection<T>>::remove(collection_id);387 <WhiteList<T>>::remove(collection_id);388389 <NftItemList<T>>::remove_prefix(collection_id);390 <FungibleItemList<T>>::remove_prefix(collection_id);391 <ReFungibleItemList<T>>::remove_prefix(collection_id);392393 <NftTransferBasket<T>>::remove_prefix(collection_id);394 <FungibleTransferBasket<T>>::remove_prefix(collection_id);395 <ReFungibleTransferBasket<T>>::remove_prefix(collection_id);396397 if CollectionCount::get() > 0398 {399 400 let total = CollectionCount::get()401 .checked_sub(1)402 .expect("collection counter error");403404 CollectionCount::put(total);405 }406407 Ok(())408 }409410 #[weight = 0]411 pub fn add_to_white_list(origin, collection_id: u64, address: T::AccountId) -> DispatchResult{412413 let sender = ensure_signed(origin)?;414 Self::check_owner_or_admin_permissions(collection_id, sender)?;415416 let mut white_list_collection: Vec<T::AccountId>;417 if <WhiteList<T>>::contains_key(collection_id) {418 white_list_collection = <WhiteList<T>>::get(collection_id);419 if !white_list_collection.contains(&address.clone())420 {421 white_list_collection.push(address.clone());422 }423 }424 else {425 white_list_collection = Vec::new();426 white_list_collection.push(address.clone());427 }428429 <WhiteList<T>>::insert(collection_id, white_list_collection);430 Ok(())431 }432433 #[weight = 0]434 pub fn remove_from_white_list(origin, collection_id: u64, address: T::AccountId) -> DispatchResult{435436 let sender = ensure_signed(origin)?;437 Self::check_owner_or_admin_permissions(collection_id, sender)?;438439 if <WhiteList<T>>::contains_key(collection_id) {440 let mut white_list_collection = <WhiteList<T>>::get(collection_id);441 if white_list_collection.contains(&address.clone())442 {443 white_list_collection.retain(|i| *i != address.clone());444 <WhiteList<T>>::insert(collection_id, white_list_collection);445 }446 }447448 Ok(())449 }450451 #[weight = 0]452 pub fn set_public_access_mode(origin, collection_id: u64, mode: AccessMode) -> DispatchResult453 {454 let sender = ensure_signed(origin)?;455456 Self::check_owner_permissions(collection_id, sender)?;457 let mut target_collection = <Collection<T>>::get(collection_id);458 target_collection.access = mode;459 <Collection<T>>::insert(collection_id, target_collection);460461 Ok(())462 }463464 #[weight = 0]465 pub fn set_mint_permission(origin, collection_id: u64, mint_permission: bool) -> DispatchResult466 {467 let sender = ensure_signed(origin)?;468469 Self::check_owner_permissions(collection_id, sender)?;470 let mut target_collection = <Collection<T>>::get(collection_id);471 target_collection.mint_mode = mint_permission;472 <Collection<T>>::insert(collection_id, target_collection);473474 Ok(())475 }476477 #[weight = 0]478 pub fn change_collection_owner(origin, collection_id: u64, new_owner: T::AccountId) -> DispatchResult {479480 let sender = ensure_signed(origin)?;481 Self::check_owner_permissions(collection_id, sender)?;482 let mut target_collection = <Collection<T>>::get(collection_id);483 target_collection.owner = new_owner;484 <Collection<T>>::insert(collection_id, target_collection);485486 Ok(())487 }488489 #[weight = 0]490 pub fn add_collection_admin(origin, collection_id: u64, new_admin_id: T::AccountId) -> DispatchResult {491492 let sender = ensure_signed(origin)?;493 Self::check_owner_or_admin_permissions(collection_id, sender)?;494 let mut admin_arr: Vec<T::AccountId> = Vec::new();495496 if <AdminList<T>>::contains_key(collection_id)497 {498 admin_arr = <AdminList<T>>::get(collection_id);499 ensure!(!admin_arr.contains(&new_admin_id), "Account already has admin role");500 }501502 503 ensure!((admin_arr.len() as u64) < ChainLimit::get().collections_admins_limit, "Number of collection admins bound exceeded");504505 admin_arr.push(new_admin_id);506 <AdminList<T>>::insert(collection_id, admin_arr);507508 Ok(())509 }510511 #[weight = 0]512 pub fn remove_collection_admin(origin, collection_id: u64, account_id: T::AccountId) -> DispatchResult {513514 let sender = ensure_signed(origin)?;515 Self::check_owner_or_admin_permissions(collection_id, sender)?;516517 if <AdminList<T>>::contains_key(collection_id)518 {519 let mut admin_arr = <AdminList<T>>::get(collection_id);520 admin_arr.retain(|i| *i != account_id);521 <AdminList<T>>::insert(collection_id, admin_arr);522 }523524 Ok(())525 }526527 #[weight = 0]528 pub fn set_collection_sponsor(origin, collection_id: u64, new_sponsor: T::AccountId) -> DispatchResult {529530 let sender = ensure_signed(origin)?;531 ensure!(<Collection<T>>::contains_key(collection_id), "This collection does not exist");532533 let mut target_collection = <Collection<T>>::get(collection_id);534 ensure!(sender == target_collection.owner, "You do not own this collection");535536 target_collection.unconfirmed_sponsor = new_sponsor;537 <Collection<T>>::insert(collection_id, target_collection);538539 Ok(())540 }541542 #[weight = 0]543 pub fn confirm_sponsorship(origin, collection_id: u64) -> DispatchResult {544545 let sender = ensure_signed(origin)?;546 ensure!(<Collection<T>>::contains_key(collection_id), "This collection does not exist");547548 let mut target_collection = <Collection<T>>::get(collection_id);549 ensure!(sender == target_collection.unconfirmed_sponsor, "This address is not set as sponsor, use setCollectionSponsor first");550551 target_collection.sponsor = target_collection.unconfirmed_sponsor;552 target_collection.unconfirmed_sponsor = T::AccountId::default();553 <Collection<T>>::insert(collection_id, target_collection);554555 Ok(())556 }557558 #[weight = 0]559 pub fn remove_collection_sponsor(origin, collection_id: u64) -> DispatchResult {560561 let sender = ensure_signed(origin)?;562 ensure!(<Collection<T>>::contains_key(collection_id), "This collection does not exist");563564 let mut target_collection = <Collection<T>>::get(collection_id);565 ensure!(sender == target_collection.owner, "You do not own this collection");566567 target_collection.sponsor = T::AccountId::default();568 <Collection<T>>::insert(collection_id, target_collection);569570 Ok(())571 }572573 #[weight = 0]574 pub fn create_item(origin, collection_id: u64, properties: Vec<u8>, owner: T::AccountId) -> DispatchResult {575576 let sender = ensure_signed(origin)?;577 Self::collection_exists(collection_id)?;578 let target_collection = <Collection<T>>::get(collection_id);579580 if !Self::is_owner_or_admin_permissions(collection_id, sender.clone()) {581 ensure!(target_collection.mint_mode == true, "Collection is not in mint mode");582 Self::check_white_list(collection_id, owner.clone())?;583 }584585 match target_collection.mode586 {587 CollectionMode::NFT(_) => {588589 590 ensure!(target_collection.custom_data_size >= properties.len() as u32, "Size of item is too large");591592 593 let item = NftItemType {594 collection: collection_id,595 owner: owner,596 data: properties,597 };598599 Self::add_nft_item(item)?;600601 },602 CollectionMode::Fungible(_) => {603604 605 ensure!(properties.len() as u32 == 0, "Size of item must be 0 with fungible type");606607 let item = FungibleItemType {608 collection: collection_id,609 owner: owner,610 value: (10 as u128).pow(target_collection.decimal_points)611 };612613 Self::add_fungible_item(item)?;614 },615 CollectionMode::ReFungible(_, _) => {616617 618 ensure!(target_collection.custom_data_size >= properties.len() as u32, "Size of item is too large");619620 let mut owner_list = Vec::new();621 let value = (10 as u128).pow(target_collection.decimal_points);622 owner_list.push(Ownership {owner: owner, fraction: value});623624 let item = ReFungibleItemType {625 collection: collection_id,626 owner: owner_list,627 data: properties628 };629630 Self::add_refungible_item(item)?;631 },632 _ => ()633 };634635 636 Self::deposit_event(RawEvent::ItemCreated(collection_id, <ItemListIndex>::get(collection_id)));637638 Ok(())639 }640641 #[weight = 0]642 pub fn burn_item(origin, collection_id: u64, item_id: u64) -> DispatchResult {643644 let sender = ensure_signed(origin)?;645 Self::collection_exists(collection_id)?;646647 648 let target_collection = <Collection<T>>::get(collection_id);649 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||650 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),651 "Only item owner, collection owner and admins can modify item");652653 if target_collection.access == AccessMode::WhiteList {654 Self::check_white_list(collection_id, sender.clone())?;655 }656657 match target_collection.mode658 {659 CollectionMode::NFT(_) => Self::burn_nft_item(collection_id, item_id)?,660 CollectionMode::Fungible(_) => Self::burn_fungible_item(collection_id, item_id)?,661 CollectionMode::ReFungible(_, _) => Self::burn_refungible_item(collection_id, item_id, sender.clone())?,662 _ => ()663 };664665 666 Self::deposit_event(RawEvent::ItemDestroyed(collection_id, item_id));667668 Ok(())669 }670671 #[weight = 0]672 pub fn transfer(origin, recipient: T::AccountId, collection_id: u64, item_id: u64, value: u64) -> DispatchResult {673674 let sender = ensure_signed(origin)?;675676 677 let target_collection = <Collection<T>>::get(collection_id);678 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||679 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),680 "Only item owner, collection owner and admins can modify item");681682 if target_collection.access == AccessMode::WhiteList {683 Self::check_white_list(collection_id, sender.clone())?;684 Self::check_white_list(collection_id, recipient.clone())?;685 }686687 match target_collection.mode688 {689 CollectionMode::NFT(_) => Self::transfer_nft(collection_id, item_id, sender.clone(), recipient)?,690 CollectionMode::Fungible(_) => Self::transfer_fungible(collection_id, item_id, value, sender.clone(), recipient)?,691 CollectionMode::ReFungible(_, _) => Self::transfer_refungible(collection_id, item_id, value, sender.clone(), recipient)?,692 _ => ()693 };694695 Ok(())696 }697698 #[weight = 0]699 pub fn approve(origin, approved: T::AccountId, collection_id: u64, item_id: u64) -> DispatchResult {700701 let sender = ensure_signed(origin)?;702703 704 let target_collection = <Collection<T>>::get(collection_id);705 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||706 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),707 "Only item owner, collection owner and admins can approve");708709 if target_collection.access == AccessMode::WhiteList {710 Self::check_white_list(collection_id, sender.clone())?;711 Self::check_white_list(collection_id, approved.clone())?;712 }713714 715 let amount = 100000000;716717 let list_exists = <ApprovedList<T>>::contains_key(collection_id, (item_id, sender.clone()));718 if list_exists {719720 let mut list = <ApprovedList<T>>::get(collection_id, (item_id, sender.clone()));721 let item_contains = list.iter().any(|i| i.approved == approved);722723 if !item_contains {724 list.push(ApprovePermissions { approved: approved.clone(), amount: amount });725 <ApprovedList<T>>::insert(collection_id, (item_id, sender.clone()), list);726 }727 } else {728729 let mut list = Vec::new();730 list.push(ApprovePermissions { approved: approved.clone(), amount: amount });731 <ApprovedList<T>>::insert(collection_id, (item_id, sender.clone()), list);732 }733734 Ok(())735 }736737 #[weight = 0]738 pub fn transfer_from(origin, from: T::AccountId, recipient: T::AccountId, collection_id: u64, item_id: u64, value: u64 ) -> DispatchResult {739740 let sender = ensure_signed(origin)?;741 let mut appoved_transfer = false;742743 744 if <ApprovedList<T>>::contains_key(collection_id, (item_id, from.clone())) {745 let list_itm = <ApprovedList<T>>::get(collection_id, (item_id, from.clone()));746 let opt_item = list_itm.iter().find(|i| i.approved == sender.clone());747 appoved_transfer = opt_item.is_some();748 ensure!(opt_item.unwrap().amount >= value, "Requested value more than approved");749 }750751 752 let target_collection = <Collection<T>>::get(collection_id);753 ensure!(appoved_transfer || Self::is_owner_or_admin_permissions(collection_id, sender.clone()),754 "Only item owner, collection owner and admins can modify items");755756 if target_collection.access == AccessMode::WhiteList {757 Self::check_white_list(collection_id, sender.clone())?;758 Self::check_white_list(collection_id, recipient.clone())?;759 }760761 762 let approve_list: Vec<ApprovePermissions<T::AccountId>> = <ApprovedList<T>>::get(collection_id, (item_id, from.clone()))763 .into_iter().filter(|i| i.approved != sender.clone()).collect();764 <ApprovedList<T>>::insert(collection_id, (item_id, from.clone()), approve_list);765766767 match target_collection.mode768 {769 CollectionMode::NFT(_) => Self::transfer_nft(collection_id, item_id, from, recipient)?,770 CollectionMode::Fungible(_) => Self::transfer_fungible(collection_id, item_id, value, from.clone(), recipient)?,771 CollectionMode::ReFungible(_, _) => Self::transfer_refungible(collection_id, item_id, value, from.clone(), recipient)?,772 _ => ()773 };774775 Ok(())776 }777778 #[weight = 0]779 pub fn safe_transfer_from(origin, collection_id: u64, item_id: u64, new_owner: T::AccountId) -> DispatchResult {780781 782 783 784 785786 787788 789790 Ok(())791 }792793 #[weight = 0]794 pub fn set_offchain_schema(795 origin,796 collection_id: u64,797 schema: Vec<u8>798 ) -> DispatchResult {799 let sender = ensure_signed(origin)?;800 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;801802 let mut target_collection = <Collection<T>>::get(collection_id);803 target_collection.offchain_schema = schema;804 <Collection<T>>::insert(collection_id, target_collection);805806 Ok(())807 }808809 810 #[weight = 0]811 pub fn set_chain_limits(812 origin,813 limits: ChainLimits814 ) -> DispatchResult {815 ensure_root(origin)?;816 <ChainLimit>::put(limits);817 Ok(())818 } 819 }820}821822impl<T: Trait> Module<T> {823 fn add_fungible_item(item: FungibleItemType<T::AccountId>) -> DispatchResult {824 let current_index = <ItemListIndex>::get(item.collection)825 .checked_add(1)826 .expect("Item list index id error");827 let itemcopy = item.clone();828 let owner = item.owner.clone();829 let value = item.value as u64;830831 Self::add_token_index(item.collection, current_index, owner.clone())?;832833 <ItemListIndex>::insert(item.collection, current_index);834 <FungibleItemList<T>>::insert(item.collection, current_index, itemcopy);835836 837 let v: Vec<BasketItem<T::AccountId, T::BlockNumber>> = Vec::new();838 <FungibleTransferBasket<T>>::insert(item.collection, current_index, v);839 840 841 let new_balance = <Balance<T>>::get(item.collection, owner.clone())842 .checked_add(value)843 .unwrap();844 <Balance<T>>::insert(item.collection, owner.clone(), new_balance);845846 Ok(())847 }848849 fn add_refungible_item(item: ReFungibleItemType<T::AccountId>) -> DispatchResult {850 let current_index = <ItemListIndex>::get(item.collection)851 .checked_add(1)852 .expect("Item list index id error");853 let itemcopy = item.clone();854855 let value = item.owner.first().unwrap().fraction as u64;856 let owner = item.owner.first().unwrap().owner.clone();857858 Self::add_token_index(item.collection, current_index, owner.clone())?;859860 <ItemListIndex>::insert(item.collection, current_index);861 <ReFungibleItemList<T>>::insert(item.collection, current_index, itemcopy);862863 864 let block_number: T::BlockNumber = 0.into();865 <ReFungibleTransferBasket<T>>::insert(item.collection, current_index, block_number);866867 868 let new_balance = <Balance<T>>::get(item.collection, owner.clone())869 .checked_add(value)870 .unwrap();871 <Balance<T>>::insert(item.collection, owner.clone(), new_balance);872873 Ok(())874 }875876 fn add_nft_item(item: NftItemType<T::AccountId>) -> DispatchResult {877 let current_index = <ItemListIndex>::get(item.collection)878 .checked_add(1)879 .expect("Item list index id error");880881 let item_owner = item.owner.clone();882 let collection_id = item.collection.clone();883 Self::add_token_index(collection_id, current_index, item.owner.clone())?;884885 <ItemListIndex>::insert(collection_id, current_index);886 <NftItemList<T>>::insert(collection_id, current_index, item);887888 889 let block_number: T::BlockNumber = 0.into();890 <NftTransferBasket<T>>::insert(collection_id, current_index, block_number);891892 893 let new_balance = <Balance<T>>::get(collection_id, item_owner.clone())894 .checked_add(1)895 .unwrap();896 <Balance<T>>::insert(collection_id, item_owner.clone(), new_balance);897898 Ok(())899 }900901 fn burn_refungible_item(902 collection_id: u64,903 item_id: u64,904 owner: T::AccountId,905 ) -> DispatchResult {906 ensure!(907 <ReFungibleItemList<T>>::contains_key(collection_id, item_id),908 "Item does not exists"909 );910 let collection = <ReFungibleItemList<T>>::get(collection_id, item_id);911 let item = collection912 .owner913 .iter()914 .filter(|&i| i.owner == owner)915 .next()916 .unwrap();917 Self::remove_token_index(collection_id, item_id, owner.clone())?;918919 920 <ApprovedList<T>>::remove(collection_id, (item_id, owner.clone()));921922 923 let new_balance = <Balance<T>>::get(collection_id, item.owner.clone())924 .checked_sub(item.fraction as u64)925 .unwrap();926 <Balance<T>>::insert(collection_id, item.owner.clone(), new_balance);927928 <ReFungibleItemList<T>>::remove(collection_id, item_id);929930 Ok(())931 }932933 fn burn_nft_item(collection_id: u64, item_id: u64) -> DispatchResult {934 ensure!(935 <NftItemList<T>>::contains_key(collection_id, item_id),936 "Item does not exists"937 );938 let item = <NftItemList<T>>::get(collection_id, item_id);939 Self::remove_token_index(collection_id, item_id, item.owner.clone())?;940941 942 <ApprovedList<T>>::remove(collection_id, (item_id, item.owner.clone()));943944 945 let new_balance = <Balance<T>>::get(collection_id, item.owner.clone())946 .checked_sub(1)947 .unwrap();948 <Balance<T>>::insert(collection_id, item.owner.clone(), new_balance);949 <NftItemList<T>>::remove(collection_id, item_id);950951 Ok(())952 }953954 fn burn_fungible_item(collection_id: u64, item_id: u64) -> DispatchResult {955 ensure!(956 <FungibleItemList<T>>::contains_key(collection_id, item_id),957 "Item does not exists"958 );959 let item = <FungibleItemList<T>>::get(collection_id, item_id);960 Self::remove_token_index(collection_id, item_id, item.owner.clone())?;961962 963 <ApprovedList<T>>::remove(collection_id, (item_id, item.owner.clone()));964965 966 let new_balance = <Balance<T>>::get(collection_id, item.owner.clone())967 .checked_sub(item.value as u64)968 .unwrap();969 <Balance<T>>::insert(collection_id, item.owner.clone(), new_balance);970971 <FungibleItemList<T>>::remove(collection_id, item_id);972973 Ok(())974 }975976 fn collection_exists(collection_id: u64) -> DispatchResult {977 ensure!(978 <Collection<T>>::contains_key(collection_id),979 "This collection does not exist"980 );981 Ok(())982 }983984 fn check_owner_permissions(collection_id: u64, subject: T::AccountId) -> DispatchResult {985 Self::collection_exists(collection_id)?;986987 let target_collection = <Collection<T>>::get(collection_id);988 ensure!(989 subject == target_collection.owner,990 "You do not own this collection"991 );992993 Ok(())994 }995996 fn is_owner_or_admin_permissions(collection_id: u64, subject: T::AccountId) -> bool {997 let target_collection = <Collection<T>>::get(collection_id);998 let mut result: bool = subject == target_collection.owner;999 let exists = <AdminList<T>>::contains_key(collection_id);10001001 if !result & exists {1002 if <AdminList<T>>::get(collection_id).contains(&subject) {1003 result = true1004 }1005 }10061007 result1008 }10091010 fn check_owner_or_admin_permissions(1011 collection_id: u64,1012 subject: T::AccountId,1013 ) -> DispatchResult {1014 Self::collection_exists(collection_id)?;1015 let result = Self::is_owner_or_admin_permissions(collection_id, subject.clone());10161017 ensure!(1018 result,1019 "You do not have permissions to modify this collection"1020 );1021 Ok(())1022 }10231024 fn is_item_owner(subject: T::AccountId, collection_id: u64, item_id: u64) -> bool {1025 let target_collection = <Collection<T>>::get(collection_id);10261027 match target_collection.mode {1028 CollectionMode::NFT(_) => {1029 <NftItemList<T>>::get(collection_id, item_id).owner == subject1030 }1031 CollectionMode::Fungible(_) => {1032 <FungibleItemList<T>>::get(collection_id, item_id).owner == subject1033 }1034 CollectionMode::ReFungible(_, _) => {1035 <ReFungibleItemList<T>>::get(collection_id, item_id)1036 .owner1037 .iter()1038 .any(|i| i.owner == subject)1039 }1040 CollectionMode::Invalid => false,1041 }1042 }10431044 fn check_white_list(collection_id: u64, address: T::AccountId) -> DispatchResult {1045 let mes = "Address is not in white list";1046 ensure!(<WhiteList<T>>::contains_key(collection_id), mes);1047 let wl = <WhiteList<T>>::get(collection_id);1048 ensure!(wl.contains(&address.clone()), mes);10491050 Ok(())1051 }10521053 fn transfer_fungible(1054 collection_id: u64,1055 item_id: u64,1056 value: u64,1057 owner: T::AccountId,1058 new_owner: T::AccountId,1059 ) -> DispatchResult {1060 ensure!(1061 <FungibleItemList<T>>::contains_key(collection_id, item_id),1062 "Item not exists"1063 );10641065 let full_item = <FungibleItemList<T>>::get(collection_id, item_id);1066 let amount = full_item.value;10671068 ensure!(amount >= value.into(), "Item balance not enouth");10691070 1071 let balance_old_owner = <Balance<T>>::get(collection_id, owner.clone())1072 .checked_sub(value)1073 .unwrap();1074 <Balance<T>>::insert(collection_id, owner.clone(), balance_old_owner);10751076 let mut new_owner_account_id = 0;1077 let new_owner_items = <AddressTokens<T>>::get(collection_id, new_owner.clone());1078 if new_owner_items.len() > 0 {1079 new_owner_account_id = new_owner_items[0];1080 }10811082 let val64 = value.into();10831084 1085 if amount == val64 && new_owner_account_id == 0 {1086 1087 1088 let mut new_full_item = full_item.clone();1089 new_full_item.owner = new_owner.clone();1090 <FungibleItemList<T>>::insert(collection_id, item_id, new_full_item);10911092 1093 let balance_new_owner = <Balance<T>>::get(collection_id, new_owner.clone())1094 .checked_add(value)1095 .unwrap();1096 <Balance<T>>::insert(collection_id, new_owner.clone(), balance_new_owner);10971098 1099 Self::move_token_index(collection_id, item_id, owner.clone(), new_owner.clone())?;1100 } else {1101 let mut new_full_item = full_item.clone();1102 new_full_item.value -= val64;11031104 1105 if new_owner_account_id > 0 {1106 1107 let mut item = <FungibleItemList<T>>::get(collection_id, new_owner_account_id);1108 item.value += val64;11091110 1111 let balance_new_owner = <Balance<T>>::get(collection_id, new_owner.clone())1112 .checked_add(value)1113 .unwrap();1114 <Balance<T>>::insert(collection_id, new_owner.clone(), balance_new_owner);11151116 <FungibleItemList<T>>::insert(collection_id, new_owner_account_id, item);1117 } else {1118 1119 let item = FungibleItemType {1120 collection: collection_id,1121 owner: new_owner.clone(),1122 value: val64,1123 };11241125 Self::add_fungible_item(item)?;1126 }11271128 if amount == val64 {1129 Self::remove_token_index(collection_id, item_id, full_item.owner.clone())?;11301131 1132 <ApprovedList<T>>::remove(collection_id, (item_id, full_item.owner.clone()));1133 <FungibleItemList<T>>::remove(collection_id, item_id);1134 }11351136 <FungibleItemList<T>>::insert(collection_id, item_id, new_full_item);1137 }11381139 Ok(())1140 }11411142 fn transfer_refungible(1143 collection_id: u64,1144 item_id: u64,1145 value: u64,1146 owner: T::AccountId,1147 new_owner: T::AccountId,1148 ) -> DispatchResult {1149 ensure!(1150 <ReFungibleItemList<T>>::contains_key(collection_id, item_id),1151 "Item not exists"1152 );11531154 let full_item = <ReFungibleItemList<T>>::get(collection_id, item_id);1155 let item = full_item1156 .owner1157 .iter()1158 .filter(|i| i.owner == owner)1159 .next()1160 .unwrap();1161 let amount = item.fraction;11621163 ensure!(amount >= value.into(), "Item balance not enouth");11641165 1166 let balance_old_owner = <Balance<T>>::get(collection_id, item.owner.clone())1167 .checked_sub(value)1168 .unwrap();1169 <Balance<T>>::insert(collection_id, item.owner.clone(), balance_old_owner);11701171 let balance_new_owner = <Balance<T>>::get(collection_id, new_owner.clone())1172 .checked_add(value)1173 .unwrap();1174 <Balance<T>>::insert(collection_id, new_owner.clone(), balance_new_owner);11751176 let old_owner = item.owner.clone();1177 let new_owner_has_account = full_item.owner.iter().any(|i| i.owner == new_owner);1178 let val64 = value.into();11791180 1181 if amount == val64 && !new_owner_has_account {1182 1183 1184 let mut new_full_item = full_item.clone();1185 new_full_item1186 .owner1187 .iter_mut()1188 .find(|i| i.owner == owner)1189 .unwrap()1190 .owner = new_owner.clone();1191 <ReFungibleItemList<T>>::insert(collection_id, item_id, new_full_item);11921193 1194 Self::move_token_index(collection_id, item_id, old_owner.clone(), new_owner.clone())?;1195 } else {1196 let mut new_full_item = full_item.clone();1197 new_full_item1198 .owner1199 .iter_mut()1200 .find(|i| i.owner == owner)1201 .unwrap()1202 .fraction -= val64;12031204 1205 if new_owner_has_account {1206 1207 new_full_item1208 .owner1209 .iter_mut()1210 .find(|i| i.owner == new_owner)1211 .unwrap()1212 .fraction += val64;1213 } else {1214 1215 new_full_item.owner.push(Ownership {1216 owner: new_owner.clone(),1217 fraction: val64,1218 });1219 Self::add_token_index(collection_id, item_id, new_owner.clone())?;1220 }12211222 <ReFungibleItemList<T>>::insert(collection_id, item_id, new_full_item);1223 }12241225 Ok(())1226 }12271228 fn transfer_nft(1229 collection_id: u64,1230 item_id: u64,1231 sender: T::AccountId,1232 new_owner: T::AccountId,1233 ) -> DispatchResult {1234 ensure!(1235 <NftItemList<T>>::contains_key(collection_id, item_id),1236 "Item not exists"1237 );12381239 let mut item = <NftItemList<T>>::get(collection_id, item_id);12401241 ensure!(1242 sender == item.owner,1243 "sender parameter and item owner must be equal"1244 );12451246 1247 let balance_old_owner = <Balance<T>>::get(collection_id, item.owner.clone())1248 .checked_sub(1)1249 .unwrap();1250 <Balance<T>>::insert(collection_id, item.owner.clone(), balance_old_owner);12511252 let balance_new_owner = <Balance<T>>::get(collection_id, new_owner.clone())1253 .checked_add(1)1254 .unwrap();1255 <Balance<T>>::insert(collection_id, new_owner.clone(), balance_new_owner);12561257 1258 let old_owner = item.owner.clone();1259 item.owner = new_owner.clone();1260 <NftItemList<T>>::insert(collection_id, item_id, item);12611262 1263 Self::move_token_index(collection_id, item_id, old_owner.clone(), new_owner.clone())?;12641265 1266 <ApprovedList<T>>::remove(collection_id, (item_id, old_owner));1267 Ok(())1268 }12691270 fn init_collection(item: &CollectionType<T::AccountId>) {1271 1272 assert!(1273 item.decimal_points <= 4,1274 "decimal_points parameter must be lower than 4"1275 );1276 assert!(1277 item.name.len() <= 64,1278 "Collection name can not be longer than 63 char"1279 );1280 assert!(1281 item.name.len() <= 256,1282 "Collection description can not be longer than 255 char"1283 );1284 assert!(1285 item.token_prefix.len() <= 16,1286 "Token prefix can not be longer than 15 char"1287 );12881289 1290 let next_id = CreatedCollectionCount::get()1291 .checked_add(1)1292 .expect("collection id error");12931294 CreatedCollectionCount::put(next_id);1295 }12961297 fn init_nft_token(item: &NftItemType<T::AccountId>) {1298 let current_index = <ItemListIndex>::get(item.collection)1299 .checked_add(1)1300 .expect("Item list index id error");13011302 let item_owner = item.owner.clone();1303 let collection_id = item.collection.clone();1304 Self::add_token_index(collection_id, current_index, item.owner.clone()).unwrap();13051306 <ItemListIndex>::insert(collection_id, current_index);13071308 1309 let new_balance = <Balance<T>>::get(collection_id, item_owner.clone())1310 .checked_add(1)1311 .unwrap();1312 <Balance<T>>::insert(collection_id, item_owner.clone(), new_balance);1313 }13141315 fn init_fungible_token(item: &FungibleItemType<T::AccountId>) {1316 let current_index = <ItemListIndex>::get(item.collection)1317 .checked_add(1)1318 .expect("Item list index id error");1319 let owner = item.owner.clone();1320 let value = item.value as u64;13211322 Self::add_token_index(item.collection, current_index, owner.clone()).unwrap();13231324 <ItemListIndex>::insert(item.collection, current_index);13251326 1327 let new_balance = <Balance<T>>::get(item.collection, owner.clone())1328 .checked_add(value)1329 .unwrap();1330 <Balance<T>>::insert(item.collection, owner.clone(), new_balance);1331 }13321333 fn init_refungible_token(item: &ReFungibleItemType<T::AccountId>) {1334 let current_index = <ItemListIndex>::get(item.collection)1335 .checked_add(1)1336 .expect("Item list index id error");13371338 let value = item.owner.first().unwrap().fraction as u64;1339 let owner = item.owner.first().unwrap().owner.clone();13401341 Self::add_token_index(item.collection, current_index, owner.clone()).unwrap();13421343 <ItemListIndex>::insert(item.collection, current_index);13441345 1346 let new_balance = <Balance<T>>::get(item.collection, owner.clone())1347 .checked_add(value)1348 .unwrap();1349 <Balance<T>>::insert(item.collection, owner.clone(), new_balance);1350 }13511352 fn add_token_index(collection_id: u64, item_index: u64, owner: T::AccountId) -> DispatchResult {13531354 1355 if <AccountItemCount<T>>::contains_key(owner.clone()) {13561357 1358 let count = <AccountItemCount<T>>::get(owner.clone());1359 ensure!(count < ChainLimit::get().account_token_ownership_limit, "Owned tokens by a single address bound exceeded");13601361 <AccountItemCount<T>>::insert(owner.clone(), 1362 count.checked_add(1).unwrap());1363 }1364 else {1365 <AccountItemCount<T>>::insert(owner.clone(), 1);1366 }13671368 let list_exists = <AddressTokens<T>>::contains_key(collection_id, owner.clone());1369 if list_exists {1370 let mut list = <AddressTokens<T>>::get(collection_id, owner.clone());1371 let item_contains = list.contains(&item_index.clone());13721373 if !item_contains {1374 list.push(item_index.clone());1375 }13761377 <AddressTokens<T>>::insert(collection_id, owner.clone(), list);1378 } else {1379 let mut itm = Vec::new();1380 itm.push(item_index.clone());1381 <AddressTokens<T>>::insert(collection_id, owner, itm);1382 1383 }13841385 Ok(())1386 }13871388 fn remove_token_index(1389 collection_id: u64,1390 item_index: u64,1391 owner: T::AccountId,1392 ) -> DispatchResult {13931394 1395 <AccountItemCount<T>>::insert(owner.clone(), 1396 <AccountItemCount<T>>::get(owner.clone()).checked_sub(1).unwrap());139713981399 let list_exists = <AddressTokens<T>>::contains_key(collection_id, owner.clone());1400 if list_exists {1401 let mut list = <AddressTokens<T>>::get(collection_id, owner.clone());1402 let item_contains = list.contains(&item_index.clone());14031404 if item_contains {1405 list.retain(|&item| item != item_index);1406 <AddressTokens<T>>::insert(collection_id, owner, list);1407 }1408 }14091410 Ok(())1411 }14121413 fn move_token_index(1414 collection_id: u64,1415 item_index: u64,1416 old_owner: T::AccountId,1417 new_owner: T::AccountId,1418 ) -> DispatchResult {1419 Self::remove_token_index(collection_id, item_index, old_owner)?;1420 Self::add_token_index(collection_id, item_index, new_owner)?;14211422 Ok(())1423 }1424}1425142614271428142914301431pub type Multiplier = FixedU128;14321433type BalanceOf<T> = <<T as transaction_payment::Trait>::Currency as Currency<1434 <T as system::Trait>::AccountId,1435>>::Balance;1436type NegativeImbalanceOf<T> = <<T as transaction_payment::Trait>::Currency as Currency<1437 <T as system::Trait>::AccountId,1438>>::NegativeImbalance;1439144014411442#[derive(Encode, Decode, Clone, Eq, PartialEq)]1443pub struct ChargeTransactionPayment<T: transaction_payment::Trait + Send + Sync>(1444 #[codec(compact)] BalanceOf<T>,1445);14461447impl<T: Trait + transaction_payment::Trait + Send + Sync> sp_std::fmt::Debug1448 for ChargeTransactionPayment<T>1449{1450 #[cfg(feature = "std")]1451 fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {1452 write!(f, "ChargeTransactionPayment<{:?}>", self.0)1453 }1454 #[cfg(not(feature = "std"))]1455 fn fmt(&self, _: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {1456 Ok(())1457 }1458}14591460impl<T: Trait + transaction_payment::Trait + Send + Sync> ChargeTransactionPayment<T>1461where1462 T::Call:1463 Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo> + IsSubType<Module<T>, T>,1464 BalanceOf<T>: Send + Sync + FixedPointOperand,1465{1466 1467 pub fn from(fee: BalanceOf<T>) -> Self {1468 Self(fee)1469 }14701471 pub fn traditional_fee(1472 len: usize,1473 info: &DispatchInfoOf<T::Call>,1474 tip: BalanceOf<T>,1475 ) -> BalanceOf<T>1476 where1477 T::Call: Dispatchable<Info = DispatchInfo>,1478 {1479 <transaction_payment::Module<T>>::compute_fee(len as u32, info, tip)1480 }14811482 fn withdraw_fee(1483 &self,1484 who: &T::AccountId,1485 call: &T::Call,1486 info: &DispatchInfoOf<T::Call>,1487 len: usize,1488 ) -> Result<(BalanceOf<T>, Option<NegativeImbalanceOf<T>>), TransactionValidityError> {1489 let tip = self.0;14901491 1492 1493 let fee = match call.is_sub_type() {1494 Some(Call::create_collection(..)) => <BalanceOf<T>>::from(1_000_000_000),1495 _ => Self::traditional_fee(len, info, tip), 1496 1497 };14981499 1500 1501 let sponsor: T::AccountId = match call.is_sub_type() {1502 Some(Call::create_item(collection_id, _properties, _owner)) => {1503 <Collection<T>>::get(collection_id).sponsor1504 }1505 Some(Call::transfer(_new_owner, collection_id, _item_id, _value)) => {1506 let _collection_mode = <Collection<T>>::get(collection_id).mode;15071508 1509 let sponsor_transfer = match _collection_mode {1510 CollectionMode::NFT(_) => {1511 let basket = <NftTransferBasket<T>>::get(collection_id, _item_id);1512 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;1513 let limit_time = basket + ChainLimit::get().nft_sponsor_transfer_timeout.into();1514 if block_number >= limit_time {1515 <NftTransferBasket<T>>::insert(collection_id, _item_id, block_number);1516 true1517 }1518 else {1519 false1520 }1521 }1522 CollectionMode::Fungible(_) => {1523 let mut basket = <FungibleTransferBasket<T>>::get(collection_id, _item_id);1524 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;1525 if basket.iter().any(|i| i.address == _new_owner.clone())1526 {1527 let item = basket.iter_mut().find(|i| i.address == _new_owner.clone()).unwrap().clone();1528 let limit_time = item.start_block + ChainLimit::get().fungible_sponsor_transfer_timeout.into();1529 if block_number >= limit_time {1530 basket.retain(|x| x.address == item.address);1531 basket.push(BasketItem { start_block: block_number, address: _new_owner.clone() });1532 <FungibleTransferBasket<T>>::insert(collection_id, _item_id, basket);1533 true1534 }1535 else {1536 false1537 }1538 }1539 else {1540 basket.push(BasketItem { start_block: block_number, address: _new_owner.clone()});1541 true1542 }1543 }1544 CollectionMode::ReFungible(_, _) => {1545 let basket = <ReFungibleTransferBasket<T>>::get(collection_id, _item_id);1546 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;1547 let limit_time = basket + ChainLimit::get().nft_sponsor_transfer_timeout.into();1548 if block_number >= limit_time {1549 <ReFungibleTransferBasket<T>>::insert(collection_id, _item_id, block_number);1550 true1551 } else {1552 false1553 }1554 }1555 _ => {1556 false1557 },1558 };15591560 if !sponsor_transfer {1561 T::AccountId::default()1562 } else {1563 <Collection<T>>::get(collection_id).sponsor1564 }1565 }15661567 _ => T::AccountId::default(),1568 };15691570 let mut who_pays_fee: T::AccountId = sponsor.clone();1571 if sponsor == T::AccountId::default() {1572 who_pays_fee = who.clone();1573 }15741575 1576 if fee.is_zero() {1577 return Ok((fee, None));1578 }15791580 match <T as transaction_payment::Trait>::Currency::withdraw(1581 &who_pays_fee,1582 fee,1583 if tip.is_zero() {1584 WithdrawReason::TransactionPayment.into()1585 } else {1586 WithdrawReason::TransactionPayment | WithdrawReason::Tip1587 },1588 ExistenceRequirement::KeepAlive,1589 ) {1590 Ok(imbalance) => Ok((fee, Some(imbalance))),1591 Err(_) => Err(InvalidTransaction::Payment.into()),1592 }1593 }1594}15951596impl<T: Trait + transaction_payment::Trait + Send + Sync> SignedExtension1597 for ChargeTransactionPayment<T>1598where1599 BalanceOf<T>: Send + Sync + From<u64> + FixedPointOperand,1600 T::Call:1601 Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo> + IsSubType<Module<T>, T>,1602{1603 const IDENTIFIER: &'static str = "ChargeTransactionPayment";1604 type AccountId = T::AccountId;1605 type Call = T::Call;1606 type AdditionalSigned = ();1607 type Pre = (1608 BalanceOf<T>,1609 Self::AccountId,1610 Option<NegativeImbalanceOf<T>>,1611 BalanceOf<T>,1612 );1613 fn additional_signed(&self) -> sp_std::result::Result<(), TransactionValidityError> {1614 Ok(())1615 }16161617 fn validate(1618 &self,1619 who: &Self::AccountId,1620 call: &Self::Call,1621 info: &DispatchInfoOf<Self::Call>,1622 len: usize,1623 ) -> TransactionValidity {1624 let (fee, _) = self.withdraw_fee(who, call, info, len)?;16251626 let mut r = ValidTransaction::default();1627 1628 1629 r.priority = fee.saturated_into::<TransactionPriority>();1630 Ok(r)1631 }16321633 fn pre_dispatch(1634 self,1635 who: &Self::AccountId,1636 call: &Self::Call,1637 info: &DispatchInfoOf<Self::Call>,1638 len: usize,1639 ) -> Result<Self::Pre, TransactionValidityError> {1640 let (fee, imbalance) = self.withdraw_fee(who, call, info, len)?;1641 Ok((self.0, who.clone(), imbalance, fee))1642 }16431644 fn post_dispatch(1645 pre: Self::Pre,1646 info: &DispatchInfoOf<Self::Call>,1647 post_info: &PostDispatchInfoOf<Self::Call>,1648 len: usize,1649 _result: &DispatchResult,1650 ) -> Result<(), TransactionValidityError> {1651 let (tip, who, imbalance, fee) = pre;1652 if let Some(payed) = imbalance {1653 let actual_fee = <transaction_payment::Module<T>>::compute_actual_fee(1654 len as u32, info, post_info, tip,1655 );1656 let refund = fee.saturating_sub(actual_fee);1657 let actual_payment =1658 match <T as transaction_payment::Trait>::Currency::deposit_into_existing(1659 &who, refund,1660 ) {1661 Ok(refund_imbalance) => {1662 1663 1664 match payed.offset(refund_imbalance) {1665 Ok(actual_payment) => actual_payment,1666 Err(_) => return Err(InvalidTransaction::Payment.into()),1667 }1668 }1669 1670 1671 Err(_) => payed,1672 };1673 let imbalances = actual_payment.split(tip);1674 <T as transaction_payment::Trait>::OnTransactionPayment::on_unbalanceds(1675 Some(imbalances.0).into_iter().chain(Some(imbalances.1)),1676 );1677 }1678 Ok(())1679 }1680}1681