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, fail, 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 262 263 264 265 266 267 268 269 270 Created(u64, u8, AccountId),271272 273 274 275 276 277 278 279 ItemCreated(u64, u64),280281 282 283 284 285 286 287 288 ItemDestroyed(u64, u64),289 }290);291292decl_module! {293 pub struct Module<T: Trait> for enum Call where origin: T::Origin {294295 fn deposit_event() = default;296297 fn on_initialize(now: T::BlockNumber) -> Weight {298299 if ChainVersion::get() < 2300 {301 let value = NextCollectionID::get();302 CreatedCollectionCount::put(value);303 ChainVersion::put(2);304 }305306 0307 }308309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 #[weight = 0]326 pub fn create_collection(origin,327 collection_name: Vec<u16>,328 collection_description: Vec<u16>,329 token_prefix: Vec<u8>,330 mode: CollectionMode) -> DispatchResult {331332 333 let who = ensure_signed(origin)?;334 let custom_data_size = match mode {335 CollectionMode::NFT(size) => {336337 338 ensure!(size < ChainLimit::get().custom_data_limit, "Custom data size bound exceeded");339 size340 },341 CollectionMode::ReFungible(size, _) => {342343 344 ensure!(size < ChainLimit::get().custom_data_limit, "Custom data size bound exceeded");345 size346 },347 _ => 0348 };349350 let decimal_points = match mode {351 CollectionMode::Fungible(points) => points,352 CollectionMode::ReFungible(_, points) => points,353 _ => 0354 };355356 357 ensure!(CollectionCount::get() < ChainLimit::get().collection_numbers_limit, "Total collections bound exceeded");358359 360 ensure!(decimal_points <= 4, "decimal_points parameter must be lower than 4");361362 let mut name = collection_name.to_vec();363 name.push(0);364 ensure!(name.len() <= 64, "Collection name can not be longer than 63 char");365366 let mut description = collection_description.to_vec();367 description.push(0);368 ensure!(name.len() <= 256, "Collection description can not be longer than 255 char");369370 let mut prefix = token_prefix.to_vec();371 prefix.push(0);372 ensure!(prefix.len() <= 16, "Token prefix can not be longer than 15 char");373374 375 let next_id = CreatedCollectionCount::get()376 .checked_add(1)377 .expect("collection id error");378379 380 let total = CollectionCount::get()381 .checked_add(1)382 .expect("collection counter error");383384 CreatedCollectionCount::put(next_id);385 CollectionCount::put(total);386387 388 let new_collection = CollectionType {389 owner: who.clone(),390 name: name,391 mode: mode.clone(),392 mint_mode: false,393 access: AccessMode::Normal,394 description: description,395 decimal_points: decimal_points,396 token_prefix: prefix,397 offchain_schema: Vec::new(),398 custom_data_size: custom_data_size,399 sponsor: T::AccountId::default(),400 unconfirmed_sponsor: T::AccountId::default(),401 };402403 404 <Collection<T>>::insert(next_id, new_collection);405406 407 Self::deposit_event(RawEvent::Created(next_id, mode.into(), who.clone()));408409 Ok(())410 }411412 413 414 415 416 417 418 419 420 421 #[weight = 0]422 pub fn destroy_collection(origin, collection_id: u64) -> DispatchResult {423424 let sender = ensure_signed(origin)?;425 Self::check_owner_permissions(collection_id, sender)?;426427 <AddressTokens<T>>::remove_prefix(collection_id);428 <ApprovedList<T>>::remove_prefix(collection_id);429 <Balance<T>>::remove_prefix(collection_id);430 <ItemListIndex>::remove(collection_id);431 <AdminList<T>>::remove(collection_id);432 <Collection<T>>::remove(collection_id);433 <WhiteList<T>>::remove(collection_id);434435 <NftItemList<T>>::remove_prefix(collection_id);436 <FungibleItemList<T>>::remove_prefix(collection_id);437 <ReFungibleItemList<T>>::remove_prefix(collection_id);438439 <NftTransferBasket<T>>::remove_prefix(collection_id);440 <FungibleTransferBasket<T>>::remove_prefix(collection_id);441 <ReFungibleTransferBasket<T>>::remove_prefix(collection_id);442443 if CollectionCount::get() > 0444 {445 446 let total = CollectionCount::get()447 .checked_sub(1)448 .expect("collection counter error");449450 CollectionCount::put(total);451 }452453 Ok(())454 }455456 457 458 459 460 461 462 463 464 465 466 467 468 #[weight = 0]469 pub fn add_to_white_list(origin, collection_id: u64, address: T::AccountId) -> DispatchResult{470471 let sender = ensure_signed(origin)?;472 Self::check_owner_or_admin_permissions(collection_id, sender)?;473474 let mut white_list_collection: Vec<T::AccountId>;475 if <WhiteList<T>>::contains_key(collection_id) {476 white_list_collection = <WhiteList<T>>::get(collection_id);477 if !white_list_collection.contains(&address.clone())478 {479 white_list_collection.push(address.clone());480 }481 }482 else {483 white_list_collection = Vec::new();484 white_list_collection.push(address.clone());485 }486487 <WhiteList<T>>::insert(collection_id, white_list_collection);488 Ok(())489 }490491 492 493 494 495 496 497 498 499 500 501 502 503 #[weight = 0]504 pub fn remove_from_white_list(origin, collection_id: u64, address: T::AccountId) -> DispatchResult{505506 let sender = ensure_signed(origin)?;507 Self::check_owner_or_admin_permissions(collection_id, sender)?;508509 if <WhiteList<T>>::contains_key(collection_id) {510 let mut white_list_collection = <WhiteList<T>>::get(collection_id);511 if white_list_collection.contains(&address.clone())512 {513 white_list_collection.retain(|i| *i != address.clone());514 <WhiteList<T>>::insert(collection_id, white_list_collection);515 }516 }517518 Ok(())519 }520521 522 523 524 525 526 527 528 529 530 531 532 #[weight = 0]533 pub fn set_public_access_mode(origin, collection_id: u64, mode: AccessMode) -> DispatchResult534 {535 let sender = ensure_signed(origin)?;536537 Self::check_owner_permissions(collection_id, sender)?;538 let mut target_collection = <Collection<T>>::get(collection_id);539 target_collection.access = mode;540 <Collection<T>>::insert(collection_id, target_collection);541542 Ok(())543 }544545 546 547 548 549 550 551 552 553 554 555 556 557 558 #[weight = 0]559 pub fn set_mint_permission(origin, collection_id: u64, mint_permission: bool) -> DispatchResult560 {561 let sender = ensure_signed(origin)?;562563 Self::check_owner_permissions(collection_id, sender)?;564 let mut target_collection = <Collection<T>>::get(collection_id);565 target_collection.mint_mode = mint_permission;566 <Collection<T>>::insert(collection_id, target_collection);567568 Ok(())569 }570571 572 573 574 575 576 577 578 579 580 581 582 #[weight = 0]583 pub fn change_collection_owner(origin, collection_id: u64, new_owner: T::AccountId) -> DispatchResult {584585 let sender = ensure_signed(origin)?;586 Self::check_owner_permissions(collection_id, sender)?;587 let mut target_collection = <Collection<T>>::get(collection_id);588 target_collection.owner = new_owner;589 <Collection<T>>::insert(collection_id, target_collection);590591 Ok(())592 }593594 595 596 597 598 599 600 601 602 603 604 605 606 607 #[weight = 0]608 pub fn add_collection_admin(origin, collection_id: u64, new_admin_id: T::AccountId) -> DispatchResult {609610 let sender = ensure_signed(origin)?;611 Self::check_owner_or_admin_permissions(collection_id, sender)?;612 let mut admin_arr: Vec<T::AccountId> = Vec::new();613614 if <AdminList<T>>::contains_key(collection_id)615 {616 admin_arr = <AdminList<T>>::get(collection_id);617 ensure!(!admin_arr.contains(&new_admin_id), "Account already has admin role");618 }619620 621 ensure!((admin_arr.len() as u64) < ChainLimit::get().collections_admins_limit, "Number of collection admins bound exceeded");622623 admin_arr.push(new_admin_id);624 <AdminList<T>>::insert(collection_id, admin_arr);625626 Ok(())627 }628629 630 631 632 633 634 635 636 637 638 639 640 641 #[weight = 0]642 pub fn remove_collection_admin(origin, collection_id: u64, account_id: T::AccountId) -> DispatchResult {643644 let sender = ensure_signed(origin)?;645 Self::check_owner_or_admin_permissions(collection_id, sender)?;646647 if <AdminList<T>>::contains_key(collection_id)648 {649 let mut admin_arr = <AdminList<T>>::get(collection_id);650 admin_arr.retain(|i| *i != account_id);651 <AdminList<T>>::insert(collection_id, admin_arr);652 }653654 Ok(())655 }656657 658 659 660 661 662 663 664 665 666 #[weight = 0]667 pub fn set_collection_sponsor(origin, collection_id: u64, new_sponsor: T::AccountId) -> DispatchResult {668669 let sender = ensure_signed(origin)?;670 ensure!(<Collection<T>>::contains_key(collection_id), "This collection does not exist");671672 let mut target_collection = <Collection<T>>::get(collection_id);673 ensure!(sender == target_collection.owner, "You do not own this collection");674675 target_collection.unconfirmed_sponsor = new_sponsor;676 <Collection<T>>::insert(collection_id, target_collection);677678 Ok(())679 }680681 682 683 684 685 686 687 688 #[weight = 0]689 pub fn confirm_sponsorship(origin, collection_id: u64) -> DispatchResult {690691 let sender = ensure_signed(origin)?;692 ensure!(<Collection<T>>::contains_key(collection_id), "This collection does not exist");693694 let mut target_collection = <Collection<T>>::get(collection_id);695 ensure!(sender == target_collection.unconfirmed_sponsor, "This address is not set as sponsor, use setCollectionSponsor first");696697 target_collection.sponsor = target_collection.unconfirmed_sponsor;698 target_collection.unconfirmed_sponsor = T::AccountId::default();699 <Collection<T>>::insert(collection_id, target_collection);700701 Ok(())702 }703704 705 706 707 708 709 710 711 712 713 #[weight = 0]714 pub fn remove_collection_sponsor(origin, collection_id: u64) -> DispatchResult {715716 let sender = ensure_signed(origin)?;717 ensure!(<Collection<T>>::contains_key(collection_id), "This collection does not exist");718719 let mut target_collection = <Collection<T>>::get(collection_id);720 ensure!(sender == target_collection.owner, "You do not own this collection");721722 target_collection.sponsor = T::AccountId::default();723 <Collection<T>>::insert(collection_id, target_collection);724725 Ok(())726 }727728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 #[weight = 0]747 pub fn create_item(origin, collection_id: u64, properties: Vec<u8>, owner: T::AccountId) -> DispatchResult {748749 let sender = ensure_signed(origin)?;750751 Self::collection_exists(collection_id)?;752753 let target_collection = <Collection<T>>::get(collection_id);754755 Self::can_create_items_in_collection(collection_id, &target_collection, &sender, &owner)?;756 Self::validate_create_item_args(&target_collection, &properties)?;757 Self::create_item_no_validation(collection_id, &target_collection, &properties, &owner)?;758759 Ok(())760 }761762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 #[weight = 0]781 pub fn create_multiple_items(origin, collection_id: u64, properties: Vec<Vec<u8>>, owner: T::AccountId) -> DispatchResult {782783 ensure!(properties.len() > 0, "Length of items properties must be greater than 0.");784 let sender = ensure_signed(origin)?;785786 Self::collection_exists(collection_id)?;787 let target_collection = <Collection<T>>::get(collection_id);788789 Self::can_create_items_in_collection(collection_id, &target_collection, &sender, &owner)?;790791 for prop in &properties {792 Self::validate_create_item_args(&target_collection, prop)?;793 }794 for prop in &properties {795 Self::create_item_no_validation(collection_id, &target_collection, prop, &owner)?;796 }797798 Ok(())799 }800801 802 803 804 805 806 807 808 809 810 811 812 813 814 #[weight = 0]815 pub fn burn_item(origin, collection_id: u64, item_id: u64) -> DispatchResult {816817 let sender = ensure_signed(origin)?;818 Self::collection_exists(collection_id)?;819820 821 let target_collection = <Collection<T>>::get(collection_id);822 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||823 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),824 "Only item owner, collection owner and admins can modify item");825826 if target_collection.access == AccessMode::WhiteList {827 Self::check_white_list(collection_id, &sender)?;828 }829830 match target_collection.mode831 {832 CollectionMode::NFT(_) => Self::burn_nft_item(collection_id, item_id)?,833 CollectionMode::Fungible(_) => Self::burn_fungible_item(collection_id, item_id)?,834 CollectionMode::ReFungible(_, _) => Self::burn_refungible_item(collection_id, item_id, sender.clone())?,835 _ => ()836 };837838 839 Self::deposit_event(RawEvent::ItemDestroyed(collection_id, item_id));840841 Ok(())842 }843844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 #[weight = 0]868 pub fn transfer(origin, recipient: T::AccountId, collection_id: u64, item_id: u64, value: u64) -> DispatchResult {869870 let sender = ensure_signed(origin)?;871872 873 let target_collection = <Collection<T>>::get(collection_id);874 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||875 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),876 "Only item owner, collection owner and admins can modify item");877878 if target_collection.access == AccessMode::WhiteList {879 Self::check_white_list(collection_id, &sender)?;880 Self::check_white_list(collection_id, &recipient)?;881 }882883 match target_collection.mode884 {885 CollectionMode::NFT(_) => Self::transfer_nft(collection_id, item_id, sender.clone(), recipient)?,886 CollectionMode::Fungible(_) => Self::transfer_fungible(collection_id, item_id, value, sender.clone(), recipient)?,887 CollectionMode::ReFungible(_, _) => Self::transfer_refungible(collection_id, item_id, value, sender.clone(), recipient)?,888 _ => ()889 };890891 Ok(())892 }893894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 #[weight = 0]910 pub fn approve(origin, approved: T::AccountId, collection_id: u64, item_id: u64) -> DispatchResult {911912 let sender = ensure_signed(origin)?;913914 915 let target_collection = <Collection<T>>::get(collection_id);916 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||917 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),918 "Only item owner, collection owner and admins can approve");919920 if target_collection.access == AccessMode::WhiteList {921 Self::check_white_list(collection_id, &sender)?;922 Self::check_white_list(collection_id, &approved)?;923 }924925 926 let amount = 100000000;927928 let list_exists = <ApprovedList<T>>::contains_key(collection_id, (item_id, sender.clone()));929 if list_exists {930931 let mut list = <ApprovedList<T>>::get(collection_id, (item_id, sender.clone()));932 let item_contains = list.iter().any(|i| i.approved == approved);933934 if !item_contains {935 list.push(ApprovePermissions { approved: approved.clone(), amount: amount });936 <ApprovedList<T>>::insert(collection_id, (item_id, sender.clone()), list);937 }938 } else {939940 let mut list = Vec::new();941 list.push(ApprovePermissions { approved: approved.clone(), amount: amount });942 <ApprovedList<T>>::insert(collection_id, (item_id, sender.clone()), list);943 }944945 Ok(())946 }947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 #[weight = 0]968 pub fn transfer_from(origin, from: T::AccountId, recipient: T::AccountId, collection_id: u64, item_id: u64, value: u64 ) -> DispatchResult {969970 let sender = ensure_signed(origin)?;971 let mut appoved_transfer = false;972973 974 if <ApprovedList<T>>::contains_key(collection_id, (item_id, from.clone())) {975 let list_itm = <ApprovedList<T>>::get(collection_id, (item_id, from.clone()));976 let opt_item = list_itm.iter().find(|i| i.approved == sender.clone());977 appoved_transfer = opt_item.is_some();978 ensure!(opt_item.unwrap().amount >= value, "Requested value more than approved");979 }980981 982 let target_collection = <Collection<T>>::get(collection_id);983 ensure!(appoved_transfer || Self::is_owner_or_admin_permissions(collection_id, sender.clone()),984 "Only item owner, collection owner and admins can modify items");985986 if target_collection.access == AccessMode::WhiteList {987 Self::check_white_list(collection_id, &sender)?;988 Self::check_white_list(collection_id, &recipient)?;989 }990991 992 let approve_list: Vec<ApprovePermissions<T::AccountId>> = <ApprovedList<T>>::get(collection_id, (item_id, from.clone()))993 .into_iter().filter(|i| i.approved != sender.clone()).collect();994 <ApprovedList<T>>::insert(collection_id, (item_id, from.clone()), approve_list);995996997 match target_collection.mode998 {999 CollectionMode::NFT(_) => Self::transfer_nft(collection_id, item_id, from, recipient)?,1000 CollectionMode::Fungible(_) => Self::transfer_fungible(collection_id, item_id, value, from.clone(), recipient)?,1001 CollectionMode::ReFungible(_, _) => Self::transfer_refungible(collection_id, item_id, value, from.clone(), recipient)?,1002 _ => ()1003 };10041005 Ok(())1006 }10071008 1009 #[weight = 0]1010 pub fn safe_transfer_from(origin, collection_id: u64, item_id: u64, new_owner: T::AccountId) -> DispatchResult {10111012 1013 1014 1015 10161017 10181019 10201021 Ok(())1022 }10231024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 #[weight = 0]1037 pub fn set_offchain_schema(1038 origin,1039 collection_id: u64,1040 schema: Vec<u8>1041 ) -> DispatchResult {1042 let sender = ensure_signed(origin)?;1043 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;10441045 let mut target_collection = <Collection<T>>::get(collection_id);1046 target_collection.offchain_schema = schema;1047 <Collection<T>>::insert(collection_id, target_collection);10481049 Ok(())1050 }10511052 1053 #[weight = 0]1054 pub fn set_chain_limits(1055 origin,1056 limits: ChainLimits1057 ) -> DispatchResult {1058 ensure_root(origin)?;1059 <ChainLimit>::put(limits);1060 Ok(())1061 } 1062 }1063}10641065impl<T: Trait> Module<T> {10661067 fn can_create_items_in_collection(collection_id: u64, collection: &CollectionType<T::AccountId>, sender: &T::AccountId, owner: &T::AccountId) -> DispatchResult {10681069 if !Self::is_owner_or_admin_permissions(collection_id, sender.clone()) {1070 ensure!(collection.mint_mode == true, "Public minting is not allowed for this collection");1071 Self::check_white_list(collection_id, owner)?;1072 Self::check_white_list(collection_id, sender)?;1073 }10741075 Ok(())1076 }10771078 fn validate_create_item_args(collection: &CollectionType<T::AccountId>, properties: &Vec<u8>) -> DispatchResult {10791080 match collection.mode1081 {1082 CollectionMode::NFT(_) => {10831084 1085 ensure!(collection.custom_data_size >= properties.len() as u32, "Size of item is too large")1086 },1087 CollectionMode::Fungible(_) => {10881089 1090 ensure!(properties.len() as u32 == 0, "Size of item must be 0 with fungible type")1091 },1092 CollectionMode::ReFungible(_, _) => {10931094 1095 ensure!(collection.custom_data_size >= properties.len() as u32, "Size of item is too large")1096 },1097 _ => {1098 fail!("Unexpected collection mode")1099 }1100 }11011102 Ok(())1103 }11041105 fn create_item_no_validation(collection_id: u64, collection: &CollectionType<T::AccountId>, properties: &Vec<u8>, owner: &T::AccountId) -> DispatchResult {1106 match collection.mode1107 {1108 CollectionMode::NFT(_) => {11091110 1111 let item = NftItemType {1112 collection: collection_id,1113 owner: owner.clone(),1114 data: properties.clone(),1115 };11161117 Self::add_nft_item(item)?;11181119 },1120 CollectionMode::Fungible(_) => {11211122 let item = FungibleItemType {1123 collection: collection_id,1124 owner: owner.clone(),1125 value: (10 as u128).pow(collection.decimal_points)1126 };11271128 Self::add_fungible_item(item)?;1129 },1130 CollectionMode::ReFungible(_, _) => {11311132 let mut owner_list = Vec::new();1133 let value = (10 as u128).pow(collection.decimal_points);1134 owner_list.push(Ownership {owner: owner.clone(), fraction: value});11351136 let item = ReFungibleItemType {1137 collection: collection_id,1138 owner: owner_list,1139 data: properties.clone()1140 };11411142 Self::add_refungible_item(item)?;1143 },1144 _ => { ensure!(1 == 0,"just error"); }11451146 };11471148 1149 Self::deposit_event(RawEvent::ItemCreated(collection_id, <ItemListIndex>::get(collection_id)));11501151 Ok(())1152 }11531154 fn add_fungible_item(item: FungibleItemType<T::AccountId>) -> DispatchResult {1155 let current_index = <ItemListIndex>::get(item.collection)1156 .checked_add(1)1157 .expect("Item list index id error");1158 let itemcopy = item.clone();1159 let owner = item.owner.clone();1160 let value = item.value as u64;11611162 Self::add_token_index(item.collection, current_index, owner.clone())?;11631164 <ItemListIndex>::insert(item.collection, current_index);1165 <FungibleItemList<T>>::insert(item.collection, current_index, itemcopy);11661167 1168 let v: Vec<BasketItem<T::AccountId, T::BlockNumber>> = Vec::new();1169 <FungibleTransferBasket<T>>::insert(item.collection, current_index, v);1170 1171 1172 let new_balance = <Balance<T>>::get(item.collection, owner.clone())1173 .checked_add(value)1174 .unwrap();1175 <Balance<T>>::insert(item.collection, owner.clone(), new_balance);11761177 Ok(())1178 }11791180 fn add_refungible_item(item: ReFungibleItemType<T::AccountId>) -> DispatchResult {1181 let current_index = <ItemListIndex>::get(item.collection)1182 .checked_add(1)1183 .expect("Item list index id error");1184 let itemcopy = item.clone();11851186 let value = item.owner.first().unwrap().fraction as u64;1187 let owner = item.owner.first().unwrap().owner.clone();11881189 Self::add_token_index(item.collection, current_index, owner.clone())?;11901191 <ItemListIndex>::insert(item.collection, current_index);1192 <ReFungibleItemList<T>>::insert(item.collection, current_index, itemcopy);11931194 1195 let block_number: T::BlockNumber = 0.into();1196 <ReFungibleTransferBasket<T>>::insert(item.collection, current_index, block_number);11971198 1199 let new_balance = <Balance<T>>::get(item.collection, owner.clone())1200 .checked_add(value)1201 .unwrap();1202 <Balance<T>>::insert(item.collection, owner.clone(), new_balance);12031204 Ok(())1205 }12061207 fn add_nft_item(item: NftItemType<T::AccountId>) -> DispatchResult {1208 let current_index = <ItemListIndex>::get(item.collection)1209 .checked_add(1)1210 .expect("Item list index id error");12111212 let item_owner = item.owner.clone();1213 let collection_id = item.collection.clone();1214 Self::add_token_index(collection_id, current_index, item.owner.clone())?;12151216 <ItemListIndex>::insert(collection_id, current_index);1217 <NftItemList<T>>::insert(collection_id, current_index, item);12181219 1220 let block_number: T::BlockNumber = 0.into();1221 <NftTransferBasket<T>>::insert(collection_id, current_index, block_number);12221223 1224 let new_balance = <Balance<T>>::get(collection_id, item_owner.clone())1225 .checked_add(1)1226 .unwrap();1227 <Balance<T>>::insert(collection_id, item_owner.clone(), new_balance);12281229 Ok(())1230 }12311232 fn burn_refungible_item(1233 collection_id: u64,1234 item_id: u64,1235 owner: T::AccountId,1236 ) -> DispatchResult {1237 ensure!(1238 <ReFungibleItemList<T>>::contains_key(collection_id, item_id),1239 "Item does not exists"1240 );1241 let collection = <ReFungibleItemList<T>>::get(collection_id, item_id);1242 let item = collection1243 .owner1244 .iter()1245 .filter(|&i| i.owner == owner)1246 .next()1247 .unwrap();1248 Self::remove_token_index(collection_id, item_id, owner.clone())?;12491250 1251 <ApprovedList<T>>::remove(collection_id, (item_id, owner.clone()));12521253 1254 let new_balance = <Balance<T>>::get(collection_id, item.owner.clone())1255 .checked_sub(item.fraction as u64)1256 .unwrap();1257 <Balance<T>>::insert(collection_id, item.owner.clone(), new_balance);12581259 <ReFungibleItemList<T>>::remove(collection_id, item_id);12601261 Ok(())1262 }12631264 fn burn_nft_item(collection_id: u64, item_id: u64) -> DispatchResult {1265 ensure!(1266 <NftItemList<T>>::contains_key(collection_id, item_id),1267 "Item does not exists"1268 );1269 let item = <NftItemList<T>>::get(collection_id, item_id);1270 Self::remove_token_index(collection_id, item_id, item.owner.clone())?;12711272 1273 <ApprovedList<T>>::remove(collection_id, (item_id, item.owner.clone()));12741275 1276 let new_balance = <Balance<T>>::get(collection_id, item.owner.clone())1277 .checked_sub(1)1278 .unwrap();1279 <Balance<T>>::insert(collection_id, item.owner.clone(), new_balance);1280 <NftItemList<T>>::remove(collection_id, item_id);12811282 Ok(())1283 }12841285 fn burn_fungible_item(collection_id: u64, item_id: u64) -> DispatchResult {1286 ensure!(1287 <FungibleItemList<T>>::contains_key(collection_id, item_id),1288 "Item does not exists"1289 );1290 let item = <FungibleItemList<T>>::get(collection_id, item_id);1291 Self::remove_token_index(collection_id, item_id, item.owner.clone())?;12921293 1294 <ApprovedList<T>>::remove(collection_id, (item_id, item.owner.clone()));12951296 1297 let new_balance = <Balance<T>>::get(collection_id, item.owner.clone())1298 .checked_sub(item.value as u64)1299 .unwrap();1300 <Balance<T>>::insert(collection_id, item.owner.clone(), new_balance);13011302 <FungibleItemList<T>>::remove(collection_id, item_id);13031304 Ok(())1305 }13061307 fn collection_exists(collection_id: u64) -> DispatchResult {1308 ensure!(1309 <Collection<T>>::contains_key(collection_id),1310 "This collection does not exist"1311 );1312 Ok(())1313 }13141315 fn check_owner_permissions(collection_id: u64, subject: T::AccountId) -> DispatchResult {1316 Self::collection_exists(collection_id)?;13171318 let target_collection = <Collection<T>>::get(collection_id);1319 ensure!(1320 subject == target_collection.owner,1321 "You do not own this collection"1322 );13231324 Ok(())1325 }13261327 fn is_owner_or_admin_permissions(collection_id: u64, subject: T::AccountId) -> bool {1328 let target_collection = <Collection<T>>::get(collection_id);1329 let mut result: bool = subject == target_collection.owner;1330 let exists = <AdminList<T>>::contains_key(collection_id);13311332 if !result & exists {1333 if <AdminList<T>>::get(collection_id).contains(&subject) {1334 result = true1335 }1336 }13371338 result1339 }13401341 fn check_owner_or_admin_permissions(1342 collection_id: u64,1343 subject: T::AccountId,1344 ) -> DispatchResult {1345 Self::collection_exists(collection_id)?;1346 let result = Self::is_owner_or_admin_permissions(collection_id, subject.clone());13471348 ensure!(1349 result,1350 "You do not have permissions to modify this collection"1351 );1352 Ok(())1353 }13541355 fn is_item_owner(subject: T::AccountId, collection_id: u64, item_id: u64) -> bool {1356 let target_collection = <Collection<T>>::get(collection_id);13571358 match target_collection.mode {1359 CollectionMode::NFT(_) => {1360 <NftItemList<T>>::get(collection_id, item_id).owner == subject1361 }1362 CollectionMode::Fungible(_) => {1363 <FungibleItemList<T>>::get(collection_id, item_id).owner == subject1364 }1365 CollectionMode::ReFungible(_, _) => {1366 <ReFungibleItemList<T>>::get(collection_id, item_id)1367 .owner1368 .iter()1369 .any(|i| i.owner == subject)1370 }1371 CollectionMode::Invalid => false,1372 }1373 }13741375 fn check_white_list(collection_id: u64, address: &T::AccountId) -> DispatchResult {1376 let mes = "Address is not in white list";1377 ensure!(<WhiteList<T>>::contains_key(collection_id), mes);1378 let wl = <WhiteList<T>>::get(collection_id);1379 ensure!(wl.contains(address), mes);13801381 Ok(())1382 }13831384 fn transfer_fungible(1385 collection_id: u64,1386 item_id: u64,1387 value: u64,1388 owner: T::AccountId,1389 new_owner: T::AccountId,1390 ) -> DispatchResult {1391 ensure!(1392 <FungibleItemList<T>>::contains_key(collection_id, item_id),1393 "Item not exists"1394 );13951396 let full_item = <FungibleItemList<T>>::get(collection_id, item_id);1397 let amount = full_item.value;13981399 ensure!(amount >= value.into(), "Item balance not enouth");14001401 1402 let balance_old_owner = <Balance<T>>::get(collection_id, owner.clone())1403 .checked_sub(value)1404 .unwrap();1405 <Balance<T>>::insert(collection_id, owner.clone(), balance_old_owner);14061407 let mut new_owner_account_id = 0;1408 let new_owner_items = <AddressTokens<T>>::get(collection_id, new_owner.clone());1409 if new_owner_items.len() > 0 {1410 new_owner_account_id = new_owner_items[0];1411 }14121413 let val64 = value.into();14141415 1416 if amount == val64 && new_owner_account_id == 0 {1417 1418 1419 let mut new_full_item = full_item.clone();1420 new_full_item.owner = new_owner.clone();1421 <FungibleItemList<T>>::insert(collection_id, item_id, new_full_item);14221423 1424 let balance_new_owner = <Balance<T>>::get(collection_id, new_owner.clone())1425 .checked_add(value)1426 .unwrap();1427 <Balance<T>>::insert(collection_id, new_owner.clone(), balance_new_owner);14281429 1430 Self::move_token_index(collection_id, item_id, owner.clone(), new_owner.clone())?;1431 } else {1432 let mut new_full_item = full_item.clone();1433 new_full_item.value -= val64;14341435 1436 if new_owner_account_id > 0 {1437 1438 let mut item = <FungibleItemList<T>>::get(collection_id, new_owner_account_id);1439 item.value += val64;14401441 1442 let balance_new_owner = <Balance<T>>::get(collection_id, new_owner.clone())1443 .checked_add(value)1444 .unwrap();1445 <Balance<T>>::insert(collection_id, new_owner.clone(), balance_new_owner);14461447 <FungibleItemList<T>>::insert(collection_id, new_owner_account_id, item);1448 } else {1449 1450 let item = FungibleItemType {1451 collection: collection_id,1452 owner: new_owner.clone(),1453 value: val64,1454 };14551456 Self::add_fungible_item(item)?;1457 }14581459 if amount == val64 {1460 Self::remove_token_index(collection_id, item_id, full_item.owner.clone())?;14611462 1463 <ApprovedList<T>>::remove(collection_id, (item_id, full_item.owner.clone()));1464 <FungibleItemList<T>>::remove(collection_id, item_id);1465 }14661467 <FungibleItemList<T>>::insert(collection_id, item_id, new_full_item);1468 }14691470 Ok(())1471 }14721473 fn transfer_refungible(1474 collection_id: u64,1475 item_id: u64,1476 value: u64,1477 owner: T::AccountId,1478 new_owner: T::AccountId,1479 ) -> DispatchResult {1480 ensure!(1481 <ReFungibleItemList<T>>::contains_key(collection_id, item_id),1482 "Item not exists"1483 );14841485 let full_item = <ReFungibleItemList<T>>::get(collection_id, item_id);1486 let item = full_item1487 .owner1488 .iter()1489 .filter(|i| i.owner == owner)1490 .next()1491 .unwrap();1492 let amount = item.fraction;14931494 ensure!(amount >= value.into(), "Item balance not enouth");14951496 1497 let balance_old_owner = <Balance<T>>::get(collection_id, item.owner.clone())1498 .checked_sub(value)1499 .unwrap();1500 <Balance<T>>::insert(collection_id, item.owner.clone(), balance_old_owner);15011502 let balance_new_owner = <Balance<T>>::get(collection_id, new_owner.clone())1503 .checked_add(value)1504 .unwrap();1505 <Balance<T>>::insert(collection_id, new_owner.clone(), balance_new_owner);15061507 let old_owner = item.owner.clone();1508 let new_owner_has_account = full_item.owner.iter().any(|i| i.owner == new_owner);1509 let val64 = value.into();15101511 1512 if amount == val64 && !new_owner_has_account {1513 1514 1515 let mut new_full_item = full_item.clone();1516 new_full_item1517 .owner1518 .iter_mut()1519 .find(|i| i.owner == owner)1520 .unwrap()1521 .owner = new_owner.clone();1522 <ReFungibleItemList<T>>::insert(collection_id, item_id, new_full_item);15231524 1525 Self::move_token_index(collection_id, item_id, old_owner.clone(), new_owner.clone())?;1526 } else {1527 let mut new_full_item = full_item.clone();1528 new_full_item1529 .owner1530 .iter_mut()1531 .find(|i| i.owner == owner)1532 .unwrap()1533 .fraction -= val64;15341535 1536 if new_owner_has_account {1537 1538 new_full_item1539 .owner1540 .iter_mut()1541 .find(|i| i.owner == new_owner)1542 .unwrap()1543 .fraction += val64;1544 } else {1545 1546 new_full_item.owner.push(Ownership {1547 owner: new_owner.clone(),1548 fraction: val64,1549 });1550 Self::add_token_index(collection_id, item_id, new_owner.clone())?;1551 }15521553 <ReFungibleItemList<T>>::insert(collection_id, item_id, new_full_item);1554 }15551556 Ok(())1557 }15581559 fn transfer_nft(1560 collection_id: u64,1561 item_id: u64,1562 sender: T::AccountId,1563 new_owner: T::AccountId,1564 ) -> DispatchResult {1565 ensure!(1566 <NftItemList<T>>::contains_key(collection_id, item_id),1567 "Item not exists"1568 );15691570 let mut item = <NftItemList<T>>::get(collection_id, item_id);15711572 ensure!(1573 sender == item.owner,1574 "sender parameter and item owner must be equal"1575 );15761577 1578 let balance_old_owner = <Balance<T>>::get(collection_id, item.owner.clone())1579 .checked_sub(1)1580 .unwrap();1581 <Balance<T>>::insert(collection_id, item.owner.clone(), balance_old_owner);15821583 let balance_new_owner = <Balance<T>>::get(collection_id, new_owner.clone())1584 .checked_add(1)1585 .unwrap();1586 <Balance<T>>::insert(collection_id, new_owner.clone(), balance_new_owner);15871588 1589 let old_owner = item.owner.clone();1590 item.owner = new_owner.clone();1591 <NftItemList<T>>::insert(collection_id, item_id, item);15921593 1594 Self::move_token_index(collection_id, item_id, old_owner.clone(), new_owner.clone())?;15951596 1597 <ApprovedList<T>>::remove(collection_id, (item_id, old_owner));1598 Ok(())1599 }16001601 fn init_collection(item: &CollectionType<T::AccountId>) {1602 1603 assert!(1604 item.decimal_points <= 4,1605 "decimal_points parameter must be lower than 4"1606 );1607 assert!(1608 item.name.len() <= 64,1609 "Collection name can not be longer than 63 char"1610 );1611 assert!(1612 item.name.len() <= 256,1613 "Collection description can not be longer than 255 char"1614 );1615 assert!(1616 item.token_prefix.len() <= 16,1617 "Token prefix can not be longer than 15 char"1618 );16191620 1621 let next_id = CreatedCollectionCount::get()1622 .checked_add(1)1623 .expect("collection id error");16241625 CreatedCollectionCount::put(next_id);1626 }16271628 fn init_nft_token(item: &NftItemType<T::AccountId>) {1629 let current_index = <ItemListIndex>::get(item.collection)1630 .checked_add(1)1631 .expect("Item list index id error");16321633 let item_owner = item.owner.clone();1634 let collection_id = item.collection.clone();1635 Self::add_token_index(collection_id, current_index, item.owner.clone()).unwrap();16361637 <ItemListIndex>::insert(collection_id, current_index);16381639 1640 let new_balance = <Balance<T>>::get(collection_id, item_owner.clone())1641 .checked_add(1)1642 .unwrap();1643 <Balance<T>>::insert(collection_id, item_owner.clone(), new_balance);1644 }16451646 fn init_fungible_token(item: &FungibleItemType<T::AccountId>) {1647 let current_index = <ItemListIndex>::get(item.collection)1648 .checked_add(1)1649 .expect("Item list index id error");1650 let owner = item.owner.clone();1651 let value = item.value as u64;16521653 Self::add_token_index(item.collection, current_index, owner.clone()).unwrap();16541655 <ItemListIndex>::insert(item.collection, current_index);16561657 1658 let new_balance = <Balance<T>>::get(item.collection, owner.clone())1659 .checked_add(value)1660 .unwrap();1661 <Balance<T>>::insert(item.collection, owner.clone(), new_balance);1662 }16631664 fn init_refungible_token(item: &ReFungibleItemType<T::AccountId>) {1665 let current_index = <ItemListIndex>::get(item.collection)1666 .checked_add(1)1667 .expect("Item list index id error");16681669 let value = item.owner.first().unwrap().fraction as u64;1670 let owner = item.owner.first().unwrap().owner.clone();16711672 Self::add_token_index(item.collection, current_index, owner.clone()).unwrap();16731674 <ItemListIndex>::insert(item.collection, current_index);16751676 1677 let new_balance = <Balance<T>>::get(item.collection, owner.clone())1678 .checked_add(value)1679 .unwrap();1680 <Balance<T>>::insert(item.collection, owner.clone(), new_balance);1681 }16821683 fn add_token_index(collection_id: u64, item_index: u64, owner: T::AccountId) -> DispatchResult {16841685 1686 if <AccountItemCount<T>>::contains_key(owner.clone()) {16871688 1689 let count = <AccountItemCount<T>>::get(owner.clone());1690 ensure!(count < ChainLimit::get().account_token_ownership_limit, "Owned tokens by a single address bound exceeded");16911692 <AccountItemCount<T>>::insert(owner.clone(), 1693 count.checked_add(1).unwrap());1694 }1695 else {1696 <AccountItemCount<T>>::insert(owner.clone(), 1);1697 }16981699 let list_exists = <AddressTokens<T>>::contains_key(collection_id, owner.clone());1700 if list_exists {1701 let mut list = <AddressTokens<T>>::get(collection_id, owner.clone());1702 let item_contains = list.contains(&item_index.clone());17031704 if !item_contains {1705 list.push(item_index.clone());1706 }17071708 <AddressTokens<T>>::insert(collection_id, owner.clone(), list);1709 } else {1710 let mut itm = Vec::new();1711 itm.push(item_index.clone());1712 <AddressTokens<T>>::insert(collection_id, owner, itm);1713 1714 }17151716 Ok(())1717 }17181719 fn remove_token_index(1720 collection_id: u64,1721 item_index: u64,1722 owner: T::AccountId,1723 ) -> DispatchResult {17241725 1726 <AccountItemCount<T>>::insert(owner.clone(), 1727 <AccountItemCount<T>>::get(owner.clone()).checked_sub(1).unwrap());172817291730 let list_exists = <AddressTokens<T>>::contains_key(collection_id, owner.clone());1731 if list_exists {1732 let mut list = <AddressTokens<T>>::get(collection_id, owner.clone());1733 let item_contains = list.contains(&item_index.clone());17341735 if item_contains {1736 list.retain(|&item| item != item_index);1737 <AddressTokens<T>>::insert(collection_id, owner, list);1738 }1739 }17401741 Ok(())1742 }17431744 fn move_token_index(1745 collection_id: u64,1746 item_index: u64,1747 old_owner: T::AccountId,1748 new_owner: T::AccountId,1749 ) -> DispatchResult {1750 Self::remove_token_index(collection_id, item_index, old_owner)?;1751 Self::add_token_index(collection_id, item_index, new_owner)?;17521753 Ok(())1754 }1755}1756175717581759176017611762pub type Multiplier = FixedU128;17631764type BalanceOf<T> = <<T as transaction_payment::Trait>::Currency as Currency<1765 <T as system::Trait>::AccountId,1766>>::Balance;1767type NegativeImbalanceOf<T> = <<T as transaction_payment::Trait>::Currency as Currency<1768 <T as system::Trait>::AccountId,1769>>::NegativeImbalance;1770177117721773#[derive(Encode, Decode, Clone, Eq, PartialEq)]1774pub struct ChargeTransactionPayment<T: transaction_payment::Trait + Send + Sync>(1775 #[codec(compact)] BalanceOf<T>,1776);17771778impl<T: Trait + transaction_payment::Trait + Send + Sync> sp_std::fmt::Debug1779 for ChargeTransactionPayment<T>1780{1781 #[cfg(feature = "std")]1782 fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {1783 write!(f, "ChargeTransactionPayment<{:?}>", self.0)1784 }1785 #[cfg(not(feature = "std"))]1786 fn fmt(&self, _: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {1787 Ok(())1788 }1789}17901791impl<T: Trait + transaction_payment::Trait + Send + Sync> ChargeTransactionPayment<T>1792where1793 T::Call:1794 Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo> + IsSubType<Module<T>, T>,1795 BalanceOf<T>: Send + Sync + FixedPointOperand,1796{1797 1798 pub fn from(fee: BalanceOf<T>) -> Self {1799 Self(fee)1800 }18011802 pub fn traditional_fee(1803 len: usize,1804 info: &DispatchInfoOf<T::Call>,1805 tip: BalanceOf<T>,1806 ) -> BalanceOf<T>1807 where1808 T::Call: Dispatchable<Info = DispatchInfo>,1809 {1810 <transaction_payment::Module<T>>::compute_fee(len as u32, info, tip)1811 }18121813 fn withdraw_fee(1814 &self,1815 who: &T::AccountId,1816 call: &T::Call,1817 info: &DispatchInfoOf<T::Call>,1818 len: usize,1819 ) -> Result<(BalanceOf<T>, Option<NegativeImbalanceOf<T>>), TransactionValidityError> {1820 let tip = self.0;18211822 1823 1824 let fee = match call.is_sub_type() {1825 Some(Call::create_collection(..)) => <BalanceOf<T>>::from(1_000_000_000),1826 _ => Self::traditional_fee(len, info, tip), 1827 1828 };18291830 1831 1832 let sponsor: T::AccountId = match call.is_sub_type() {1833 Some(Call::create_item(collection_id, _properties, _owner)) => {1834 <Collection<T>>::get(collection_id).sponsor1835 }1836 Some(Call::transfer(_new_owner, collection_id, _item_id, _value)) => {1837 let _collection_mode = <Collection<T>>::get(collection_id).mode;18381839 1840 let sponsor_transfer = match _collection_mode {1841 CollectionMode::NFT(_) => {1842 let basket = <NftTransferBasket<T>>::get(collection_id, _item_id);1843 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;1844 let limit_time = basket + ChainLimit::get().nft_sponsor_transfer_timeout.into();1845 if block_number >= limit_time {1846 <NftTransferBasket<T>>::insert(collection_id, _item_id, block_number);1847 true1848 }1849 else {1850 false1851 }1852 }1853 CollectionMode::Fungible(_) => {1854 let mut basket = <FungibleTransferBasket<T>>::get(collection_id, _item_id);1855 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;1856 if basket.iter().any(|i| i.address == _new_owner.clone())1857 {1858 let item = basket.iter_mut().find(|i| i.address == _new_owner.clone()).unwrap().clone();1859 let limit_time = item.start_block + ChainLimit::get().fungible_sponsor_transfer_timeout.into();1860 if block_number >= limit_time {1861 basket.retain(|x| x.address == item.address);1862 basket.push(BasketItem { start_block: block_number, address: _new_owner.clone() });1863 <FungibleTransferBasket<T>>::insert(collection_id, _item_id, basket);1864 true1865 }1866 else {1867 false1868 }1869 }1870 else {1871 basket.push(BasketItem { start_block: block_number, address: _new_owner.clone()});1872 true1873 }1874 }1875 CollectionMode::ReFungible(_, _) => {1876 let basket = <ReFungibleTransferBasket<T>>::get(collection_id, _item_id);1877 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;1878 let limit_time = basket + ChainLimit::get().nft_sponsor_transfer_timeout.into();1879 if block_number >= limit_time {1880 <ReFungibleTransferBasket<T>>::insert(collection_id, _item_id, block_number);1881 true1882 } else {1883 false1884 }1885 }1886 _ => {1887 false1888 },1889 };18901891 if !sponsor_transfer {1892 T::AccountId::default()1893 } else {1894 <Collection<T>>::get(collection_id).sponsor1895 }1896 }18971898 _ => T::AccountId::default(),1899 };19001901 let mut who_pays_fee: T::AccountId = sponsor.clone();1902 if sponsor == T::AccountId::default() {1903 who_pays_fee = who.clone();1904 }19051906 1907 if fee.is_zero() {1908 return Ok((fee, None));1909 }19101911 match <T as transaction_payment::Trait>::Currency::withdraw(1912 &who_pays_fee,1913 fee,1914 if tip.is_zero() {1915 WithdrawReason::TransactionPayment.into()1916 } else {1917 WithdrawReason::TransactionPayment | WithdrawReason::Tip1918 },1919 ExistenceRequirement::KeepAlive,1920 ) {1921 Ok(imbalance) => Ok((fee, Some(imbalance))),1922 Err(_) => Err(InvalidTransaction::Payment.into()),1923 }1924 }1925}19261927impl<T: Trait + transaction_payment::Trait + Send + Sync> SignedExtension1928 for ChargeTransactionPayment<T>1929where1930 BalanceOf<T>: Send + Sync + From<u64> + FixedPointOperand,1931 T::Call:1932 Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo> + IsSubType<Module<T>, T>,1933{1934 const IDENTIFIER: &'static str = "ChargeTransactionPayment";1935 type AccountId = T::AccountId;1936 type Call = T::Call;1937 type AdditionalSigned = ();1938 type Pre = (1939 BalanceOf<T>,1940 Self::AccountId,1941 Option<NegativeImbalanceOf<T>>,1942 BalanceOf<T>,1943 );1944 fn additional_signed(&self) -> sp_std::result::Result<(), TransactionValidityError> {1945 Ok(())1946 }19471948 fn validate(1949 &self,1950 who: &Self::AccountId,1951 call: &Self::Call,1952 info: &DispatchInfoOf<Self::Call>,1953 len: usize,1954 ) -> TransactionValidity {1955 let (fee, _) = self.withdraw_fee(who, call, info, len)?;19561957 let mut r = ValidTransaction::default();1958 1959 1960 r.priority = fee.saturated_into::<TransactionPriority>();1961 Ok(r)1962 }19631964 fn pre_dispatch(1965 self,1966 who: &Self::AccountId,1967 call: &Self::Call,1968 info: &DispatchInfoOf<Self::Call>,1969 len: usize,1970 ) -> Result<Self::Pre, TransactionValidityError> {1971 let (fee, imbalance) = self.withdraw_fee(who, call, info, len)?;1972 Ok((self.0, who.clone(), imbalance, fee))1973 }19741975 fn post_dispatch(1976 pre: Self::Pre,1977 info: &DispatchInfoOf<Self::Call>,1978 post_info: &PostDispatchInfoOf<Self::Call>,1979 len: usize,1980 _result: &DispatchResult,1981 ) -> Result<(), TransactionValidityError> {1982 let (tip, who, imbalance, fee) = pre;1983 if let Some(payed) = imbalance {1984 let actual_fee = <transaction_payment::Module<T>>::compute_actual_fee(1985 len as u32, info, post_info, tip,1986 );1987 let refund = fee.saturating_sub(actual_fee);1988 let actual_payment =1989 match <T as transaction_payment::Trait>::Currency::deposit_into_existing(1990 &who, refund,1991 ) {1992 Ok(refund_imbalance) => {1993 1994 1995 match payed.offset(refund_imbalance) {1996 Ok(actual_payment) => actual_payment,1997 Err(_) => return Err(InvalidTransaction::Payment.into()),1998 }1999 }2000 2001 2002 Err(_) => payed,2003 };2004 let imbalances = actual_payment.split(tip);2005 <T as transaction_payment::Trait>::OnTransactionPayment::on_unbalanceds(2006 Some(imbalances.0).into_iter().chain(Some(imbalances.1)),2007 );2008 }2009 Ok(())2010 }2011}2012