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 debug,15 traits::{16 Currency, ExistenceRequirement, Get, Imbalance, KeyOwnerProofSystem, OnUnbalanced,17 Randomness, WithdrawReason,18 },19 weights::{20 constants::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_PER_SECOND},21 DispatchInfo, GetDispatchInfo, IdentityFee, Pays, PostDispatchInfo, Weight,22 WeightToFeePolynomial,23 },24 IsSubType, StorageValue,25};26use sp_runtime::print;272829use frame_system::{self as system, ensure_signed, ensure_root};30use sp_runtime::sp_std::prelude::Vec;31use sp_runtime::{32 traits::{33 DispatchInfoOf, Dispatchable, PostDispatchInfoOf, SaturatedConversion, Saturating,34 SignedExtension, Zero,35 },36 transaction_validity::{37 InvalidTransaction, TransactionPriority, TransactionValidity, TransactionValidityError,38 ValidTransaction,39 },40 FixedPointOperand, FixedU128,41};4243#[cfg(test)]44mod mock;4546#[cfg(test)]47mod tests;4849mod default_weights;5051525354#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq)]55#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]56pub enum CollectionMode {57 Invalid,58 59 NFT(u32),60 61 Fungible(u32),62 63 ReFungible(u32, u32),64}6566impl Into<u8> for CollectionMode {67 fn into(self) -> u8 {68 match self {69 CollectionMode::Invalid => 0,70 CollectionMode::NFT(_) => 1,71 CollectionMode::Fungible(_) => 2,72 CollectionMode::ReFungible(_, _) => 3,73 }74 }75}7677#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq)]78#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]79pub enum AccessMode {80 Normal,81 WhiteList,82}83impl Default for AccessMode {84 fn default() -> Self {85 Self::Normal86 }87}8889impl Default for CollectionMode {90 fn default() -> Self {91 Self::Invalid92 }93}9495#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]96#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]97pub struct Ownership<AccountId> {98 pub owner: AccountId,99 pub fraction: u128,100}101102#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]103#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]104pub struct CollectionType<AccountId> {105 pub owner: AccountId,106 pub mode: CollectionMode,107 pub access: AccessMode,108 pub decimal_points: u32,109 pub name: Vec<u16>, 110 pub description: Vec<u16>, 111 pub token_prefix: Vec<u8>, 112 pub custom_data_size: u32,113 pub mint_mode: bool,114 pub offchain_schema: Vec<u8>,115 pub sponsor: AccountId, 116 pub unconfirmed_sponsor: AccountId, 117}118119#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]120#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]121pub struct CollectionAdminsType<AccountId> {122 pub admin: AccountId,123 pub collection_id: u64,124}125126#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]127#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]128pub struct NftItemType<AccountId> {129 pub collection: u64,130 pub owner: AccountId,131 pub data: Vec<u8>,132}133134#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]135#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]136pub struct FungibleItemType<AccountId> {137 pub collection: u64,138 pub owner: AccountId,139 pub value: u128,140}141142#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]143#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]144pub struct ReFungibleItemType<AccountId> {145 pub collection: u64,146 pub owner: Vec<Ownership<AccountId>>,147 pub data: Vec<u8>,148}149150#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]151#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]152pub struct ApprovePermissions<AccountId> {153 pub approved: AccountId,154 pub amount: u64,155}156157#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]158#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]159pub struct VestingItem<AccountId, Moment> {160 pub sender: AccountId,161 pub recipient: AccountId,162 pub collection_id: u64,163 pub item_id: u64,164 pub amount: u64,165 pub vesting_date: Moment,166}167168#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]169#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]170pub struct BasketItem<AccountId, BlockNumber> {171 pub address: AccountId,172 pub start_block: BlockNumber,173}174175#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]176#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]177pub struct ChainLimits {178 pub collection_numbers_limit: u64,179 pub account_token_ownership_limit: u64,180 pub collections_admins_limit: u64,181 pub custom_data_limit: u32,182183 184 pub nft_sponsor_transfer_timeout: u32,185 pub fungible_sponsor_transfer_timeout: u32,186 pub refungible_sponsor_transfer_timeout: u32,187}188189pub trait WeightInfo {190 fn create_collection() -> Weight;191 fn destroy_collection() -> Weight;192 fn add_to_white_list() -> Weight;193 fn remove_from_white_list() -> Weight;194 fn set_public_access_mode() -> Weight;195 fn set_mint_permission() -> Weight;196 fn change_collection_owner() -> Weight;197 fn add_collection_admin() -> Weight;198 fn remove_collection_admin() -> Weight;199 fn set_collection_sponsor() -> Weight;200 fn confirm_sponsorship() -> Weight;201 fn remove_collection_sponsor() -> Weight;202 fn create_item(s: usize, ) -> Weight;203 fn burn_item() -> Weight;204 fn transfer() -> Weight;205 fn approve() -> Weight;206 fn transfer_from() -> Weight;207 fn set_offchain_schema() -> Weight;208}209210pub trait Trait: system::Trait + Sized + transaction_payment::Trait + pallet_contracts::Trait {211 type Event: From<Event<Self>> + Into<<Self as system::Trait>::Event>;212213 214 type WeightInfo: WeightInfo;215}216217#[cfg(feature = "runtime-benchmarks")]218mod benchmarking;219220221222decl_storage! {223 trait Store for Module<T: Trait> as Nft {224225 226 NextCollectionID: u64;227 CreatedCollectionCount: u64;228 ChainVersion: u64;229 ItemListIndex: map hasher(blake2_128_concat) u64 => u64;230231 232 pub ChainLimit get(fn chain_limit) config(): ChainLimits;233234 235 CollectionCount: u64;236 pub AccountItemCount get(fn account_item_count): map hasher(identity) T::AccountId => u64;237238 239 pub Collection get(fn collection) config(): map hasher(identity) u64 => CollectionType<T::AccountId>;240 pub AdminList get(fn admin_list_collection): map hasher(identity) u64 => Vec<T::AccountId>;241 pub WhiteList get(fn white_list): map hasher(identity) u64 => Vec<T::AccountId>;242243 244 pub Balance get(fn balance_count): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) T::AccountId => u64;245246 247 pub ApprovedList get(fn approved): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) (u64, T::AccountId) => Vec<ApprovePermissions<T::AccountId>>;248249 250 pub NftItemList get(fn nft_item_id) config(): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => NftItemType<T::AccountId>;251 pub FungibleItemList get(fn fungible_item_id) config(): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => FungibleItemType<T::AccountId>;252 pub ReFungibleItemList get(fn refungible_item_id) config(): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => ReFungibleItemType<T::AccountId>;253254 255 pub AddressTokens get(fn address_tokens): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) T::AccountId => Vec<u64>;256257 258 pub NftTransferBasket get(fn nft_transfer_basket): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => T::BlockNumber;259 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>>;260 pub ReFungibleTransferBasket get(fn refungible_transfer_basket): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => T::BlockNumber;261262 263 pub ContractSponsor get(fn contract_sponsor): map hasher(identity) T::AccountId => T::AccountId;264 pub UnconfirmedContractSponsor get(fn unconfirmed_contract_sponsor): map hasher(identity) T::AccountId => T::AccountId;265 }266 add_extra_genesis {267 build(|config: &GenesisConfig<T>| {268 269 for (_num, _c) in &config.collection {270 <Module<T>>::init_collection(_c);271 }272273 for (_num, _q, _i) in &config.nft_item_id {274 <Module<T>>::init_nft_token(_i);275 }276277 for (_num, _q, _i) in &config.fungible_item_id {278 <Module<T>>::init_fungible_token(_i);279 }280281 for (_num, _q, _i) in &config.refungible_item_id {282 <Module<T>>::init_refungible_token(_i);283 }284 })285 }286}287288decl_event!(289 pub enum Event<T>290 where291 AccountId = <T as system::Trait>::AccountId,292 {293 294 295 296 297 298 299 300 301 302 Created(u64, u8, AccountId),303304 305 306 307 308 309 310 311 ItemCreated(u64, u64),312313 314 315 316 317 318 319 320 ItemDestroyed(u64, u64),321 }322);323324decl_module! {325 pub struct Module<T: Trait> for enum Call where origin: T::Origin {326327 fn deposit_event() = default;328329 fn on_initialize(now: T::BlockNumber) -> Weight {330331 if ChainVersion::get() < 2332 {333 let value = NextCollectionID::get();334 CreatedCollectionCount::put(value);335 ChainVersion::put(2);336 }337338 0339 }340341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 #[weight = T::WeightInfo::create_collection()]358 pub fn create_collection(origin,359 collection_name: Vec<u16>,360 collection_description: Vec<u16>,361 token_prefix: Vec<u8>,362 mode: CollectionMode) -> DispatchResult {363364 365 let who = ensure_signed(origin)?;366 let custom_data_size = match mode {367 CollectionMode::NFT(size) => {368369 370 ensure!(size < ChainLimit::get().custom_data_limit, "Custom data size bound exceeded");371 size372 },373 CollectionMode::ReFungible(size, _) => {374375 376 ensure!(size < ChainLimit::get().custom_data_limit, "Custom data size bound exceeded");377 size378 },379 _ => 0380 };381382 let decimal_points = match mode {383 CollectionMode::Fungible(points) => points,384 CollectionMode::ReFungible(_, points) => points,385 _ => 0386 };387388 389 ensure!(CollectionCount::get() < ChainLimit::get().collection_numbers_limit, "Total collections bound exceeded");390391 392 ensure!(decimal_points <= 4, "decimal_points parameter must be lower than 4");393394 let mut name = collection_name.to_vec();395 name.push(0);396 ensure!(name.len() <= 64, "Collection name can not be longer than 63 char");397398 let mut description = collection_description.to_vec();399 description.push(0);400 ensure!(name.len() <= 256, "Collection description can not be longer than 255 char");401402 let mut prefix = token_prefix.to_vec();403 prefix.push(0);404 ensure!(prefix.len() <= 16, "Token prefix can not be longer than 15 char");405406 407 let next_id = CreatedCollectionCount::get()408 .checked_add(1)409 .expect("collection id error");410411 412 let total = CollectionCount::get()413 .checked_add(1)414 .expect("collection counter error");415416 CreatedCollectionCount::put(next_id);417 CollectionCount::put(total);418419 420 let new_collection = CollectionType {421 owner: who.clone(),422 name: name,423 mode: mode.clone(),424 mint_mode: false,425 access: AccessMode::Normal,426 description: description,427 decimal_points: decimal_points,428 token_prefix: prefix,429 offchain_schema: Vec::new(),430 custom_data_size: custom_data_size,431 sponsor: T::AccountId::default(),432 unconfirmed_sponsor: T::AccountId::default(),433 };434435 436 <Collection<T>>::insert(next_id, new_collection);437438 439 Self::deposit_event(RawEvent::Created(next_id, mode.into(), who.clone()));440441 Ok(())442 }443444 445 446 447 448 449 450 451 452 453 #[weight = T::WeightInfo::destroy_collection()]454 pub fn destroy_collection(origin, collection_id: u64) -> DispatchResult {455456 let sender = ensure_signed(origin)?;457 Self::check_owner_permissions(collection_id, sender)?;458459 <AddressTokens<T>>::remove_prefix(collection_id);460 <ApprovedList<T>>::remove_prefix(collection_id);461 <Balance<T>>::remove_prefix(collection_id);462 <ItemListIndex>::remove(collection_id);463 <AdminList<T>>::remove(collection_id);464 <Collection<T>>::remove(collection_id);465 <WhiteList<T>>::remove(collection_id);466467 <NftItemList<T>>::remove_prefix(collection_id);468 <FungibleItemList<T>>::remove_prefix(collection_id);469 <ReFungibleItemList<T>>::remove_prefix(collection_id);470471 <NftTransferBasket<T>>::remove_prefix(collection_id);472 <FungibleTransferBasket<T>>::remove_prefix(collection_id);473 <ReFungibleTransferBasket<T>>::remove_prefix(collection_id);474475 if CollectionCount::get() > 0476 {477 478 let total = CollectionCount::get()479 .checked_sub(1)480 .expect("collection counter error");481482 CollectionCount::put(total);483 }484485 Ok(())486 }487488 489 490 491 492 493 494 495 496 497 498 499 500 #[weight = T::WeightInfo::add_to_white_list()]501 pub fn add_to_white_list(origin, collection_id: u64, address: T::AccountId) -> DispatchResult{502503 let sender = ensure_signed(origin)?;504 Self::check_owner_or_admin_permissions(collection_id, sender)?;505506 let mut white_list_collection: Vec<T::AccountId>;507 if <WhiteList<T>>::contains_key(collection_id) {508 white_list_collection = <WhiteList<T>>::get(collection_id);509 if !white_list_collection.contains(&address.clone())510 {511 white_list_collection.push(address.clone());512 }513 }514 else {515 white_list_collection = Vec::new();516 white_list_collection.push(address.clone());517 }518519 <WhiteList<T>>::insert(collection_id, white_list_collection);520 Ok(())521 }522523 524 525 526 527 528 529 530 531 532 533 534 535 #[weight = T::WeightInfo::remove_from_white_list()]536 pub fn remove_from_white_list(origin, collection_id: u64, address: T::AccountId) -> DispatchResult{537538 let sender = ensure_signed(origin)?;539 Self::check_owner_or_admin_permissions(collection_id, sender)?;540541 if <WhiteList<T>>::contains_key(collection_id) {542 let mut white_list_collection = <WhiteList<T>>::get(collection_id);543 if white_list_collection.contains(&address.clone())544 {545 white_list_collection.retain(|i| *i != address.clone());546 <WhiteList<T>>::insert(collection_id, white_list_collection);547 }548 }549550 Ok(())551 }552553 554 555 556 557 558 559 560 561 562 563 564 #[weight = T::WeightInfo::set_public_access_mode()]565 pub fn set_public_access_mode(origin, collection_id: u64, mode: AccessMode) -> DispatchResult566 {567 let sender = ensure_signed(origin)?;568569 Self::check_owner_permissions(collection_id, sender)?;570 let mut target_collection = <Collection<T>>::get(collection_id);571 target_collection.access = mode;572 <Collection<T>>::insert(collection_id, target_collection);573574 Ok(())575 }576577 578 579 580 581 582 583 584 585 586 587 588 589 590 #[weight = T::WeightInfo::set_mint_permission()]591 pub fn set_mint_permission(origin, collection_id: u64, mint_permission: bool) -> DispatchResult592 {593 let sender = ensure_signed(origin)?;594595 Self::check_owner_permissions(collection_id, sender)?;596 let mut target_collection = <Collection<T>>::get(collection_id);597 target_collection.mint_mode = mint_permission;598 <Collection<T>>::insert(collection_id, target_collection);599600 Ok(())601 }602603 604 605 606 607 608 609 610 611 612 613 614 #[weight = T::WeightInfo::change_collection_owner()]615 pub fn change_collection_owner(origin, collection_id: u64, new_owner: T::AccountId) -> DispatchResult {616617 let sender = ensure_signed(origin)?;618 Self::check_owner_permissions(collection_id, sender)?;619 let mut target_collection = <Collection<T>>::get(collection_id);620 target_collection.owner = new_owner;621 <Collection<T>>::insert(collection_id, target_collection);622623 Ok(())624 }625626 627 628 629 630 631 632 633 634 635 636 637 638 639 #[weight = T::WeightInfo::add_collection_admin()]640 pub fn add_collection_admin(origin, collection_id: u64, new_admin_id: T::AccountId) -> DispatchResult {641642 let sender = ensure_signed(origin)?;643 Self::check_owner_or_admin_permissions(collection_id, sender)?;644 let mut admin_arr: Vec<T::AccountId> = Vec::new();645646 if <AdminList<T>>::contains_key(collection_id)647 {648 admin_arr = <AdminList<T>>::get(collection_id);649 ensure!(!admin_arr.contains(&new_admin_id), "Account already has admin role");650 }651652 653 ensure!((admin_arr.len() as u64) < ChainLimit::get().collections_admins_limit, "Number of collection admins bound exceeded");654655 admin_arr.push(new_admin_id);656 <AdminList<T>>::insert(collection_id, admin_arr);657658 Ok(())659 }660661 662 663 664 665 666 667 668 669 670 671 672 673 #[weight = T::WeightInfo::remove_collection_admin()]674 pub fn remove_collection_admin(origin, collection_id: u64, account_id: T::AccountId) -> DispatchResult {675676 let sender = ensure_signed(origin)?;677 Self::check_owner_or_admin_permissions(collection_id, sender)?;678679 if <AdminList<T>>::contains_key(collection_id)680 {681 let mut admin_arr = <AdminList<T>>::get(collection_id);682 admin_arr.retain(|i| *i != account_id);683 <AdminList<T>>::insert(collection_id, admin_arr);684 }685686 Ok(())687 }688689 690 691 692 693 694 695 696 697 698 #[weight = T::WeightInfo::set_collection_sponsor()]699 pub fn set_collection_sponsor(origin, collection_id: u64, new_sponsor: T::AccountId) -> DispatchResult {700701 let sender = ensure_signed(origin)?;702 ensure!(<Collection<T>>::contains_key(collection_id), "This collection does not exist");703704 let mut target_collection = <Collection<T>>::get(collection_id);705 ensure!(sender == target_collection.owner, "You do not own this collection");706707 target_collection.unconfirmed_sponsor = new_sponsor;708 <Collection<T>>::insert(collection_id, target_collection);709710 Ok(())711 }712713 714 715 716 717 718 719 720 #[weight = T::WeightInfo::confirm_sponsorship()]721 pub fn confirm_sponsorship(origin, collection_id: u64) -> DispatchResult {722723 let sender = ensure_signed(origin)?;724 ensure!(<Collection<T>>::contains_key(collection_id), "This collection does not exist");725726 let mut target_collection = <Collection<T>>::get(collection_id);727 ensure!(sender == target_collection.unconfirmed_sponsor, "This address is not set as sponsor, use setCollectionSponsor first");728729 target_collection.sponsor = target_collection.unconfirmed_sponsor;730 target_collection.unconfirmed_sponsor = T::AccountId::default();731 <Collection<T>>::insert(collection_id, target_collection);732733 Ok(())734 }735736 737 738 739 740 741 742 743 744 745 #[weight = T::WeightInfo::remove_collection_sponsor()]746 pub fn remove_collection_sponsor(origin, collection_id: u64) -> DispatchResult {747748 let sender = ensure_signed(origin)?;749 ensure!(<Collection<T>>::contains_key(collection_id), "This collection does not exist");750751 let mut target_collection = <Collection<T>>::get(collection_id);752 ensure!(sender == target_collection.owner, "You do not own this collection");753754 target_collection.sponsor = T::AccountId::default();755 <Collection<T>>::insert(collection_id, target_collection);756757 Ok(())758 }759760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783784 #[weight = T::WeightInfo::create_item(properties.len())]785 pub fn create_item(origin, collection_id: u64, properties: Vec<u8>, owner: T::AccountId) -> DispatchResult {786787 let sender = ensure_signed(origin)?;788 Self::collection_exists(collection_id)?;789 let target_collection = <Collection<T>>::get(collection_id);790791 if !Self::is_owner_or_admin_permissions(collection_id, sender.clone()) {792 ensure!(target_collection.mint_mode == true, "Public minting is not allowed for this collection");793 Self::check_white_list(collection_id, &owner)?;794 Self::check_white_list(collection_id, &sender)?;795 }796797 match target_collection.mode798 {799 CollectionMode::NFT(_) => {800801 802 ensure!(target_collection.custom_data_size >= properties.len() as u32, "Size of item is too large");803804 805 let item = NftItemType {806 collection: collection_id,807 owner: owner,808 data: properties.clone(),809 };810811 Self::add_nft_item(item)?;812813 },814 CollectionMode::Fungible(_) => {815816 817 ensure!(properties.len() as u32 == 0, "Size of item must be 0 with fungible type");818819 let item = FungibleItemType {820 collection: collection_id,821 owner: owner,822 value: (10 as u128).pow(target_collection.decimal_points)823 };824825 Self::add_fungible_item(item)?;826 },827 CollectionMode::ReFungible(_, _) => {828829 830 ensure!(target_collection.custom_data_size >= properties.len() as u32, "Size of item is too large");831832 let mut owner_list = Vec::new();833 let value = (10 as u128).pow(target_collection.decimal_points);834 owner_list.push(Ownership {owner: owner.clone(), fraction: value});835836 let item = ReFungibleItemType {837 collection: collection_id,838 owner: owner_list,839 data: properties.clone()840 };841842 Self::add_refungible_item(item)?;843 },844 _ => { ensure!(1 == 0,"just error"); }845846 };847848 849 Self::deposit_event(RawEvent::ItemCreated(collection_id, <ItemListIndex>::get(collection_id)));850851 Ok(())852 }853854 855 856 857 858 859 860 861 862 863 864 865 866 867 #[weight = T::WeightInfo::burn_item()]868 pub fn burn_item(origin, collection_id: u64, item_id: u64) -> DispatchResult {869870 let sender = ensure_signed(origin)?;871 Self::collection_exists(collection_id)?;872873 874 let target_collection = <Collection<T>>::get(collection_id);875 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||876 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),877 "Only item owner, collection owner and admins can modify item");878879 if target_collection.access == AccessMode::WhiteList {880 Self::check_white_list(collection_id, &sender)?;881 }882883 match target_collection.mode884 {885 CollectionMode::NFT(_) => Self::burn_nft_item(collection_id, item_id)?,886 CollectionMode::Fungible(_) => Self::burn_fungible_item(collection_id, item_id)?,887 CollectionMode::ReFungible(_, _) => Self::burn_refungible_item(collection_id, item_id, sender.clone())?,888 _ => ()889 };890891 892 Self::deposit_event(RawEvent::ItemDestroyed(collection_id, item_id));893894 Ok(())895 }896897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 #[weight = T::WeightInfo::transfer()]921 pub fn transfer(origin, recipient: T::AccountId, collection_id: u64, item_id: u64, value: u64) -> DispatchResult {922923 let sender = ensure_signed(origin)?;924925 926 let target_collection = <Collection<T>>::get(collection_id);927 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||928 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),929 "Only item owner, collection owner and admins can modify item");930931 if target_collection.access == AccessMode::WhiteList {932 Self::check_white_list(collection_id, &sender)?;933 Self::check_white_list(collection_id, &recipient)?;934 }935936 match target_collection.mode937 {938 CollectionMode::NFT(_) => Self::transfer_nft(collection_id, item_id, sender.clone(), recipient)?,939 CollectionMode::Fungible(_) => Self::transfer_fungible(collection_id, item_id, value, sender.clone(), recipient)?,940 CollectionMode::ReFungible(_, _) => Self::transfer_refungible(collection_id, item_id, value, sender.clone(), recipient)?,941 _ => ()942 };943944 Ok(())945 }946947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 #[weight = T::WeightInfo::approve()]963 pub fn approve(origin, approved: T::AccountId, collection_id: u64, item_id: u64) -> DispatchResult {964965 let sender = ensure_signed(origin)?;966967 968 let target_collection = <Collection<T>>::get(collection_id);969 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||970 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),971 "Only item owner, collection owner and admins can approve");972973 if target_collection.access == AccessMode::WhiteList {974 Self::check_white_list(collection_id, &sender)?;975 Self::check_white_list(collection_id, &approved)?;976 }977978 979 let amount = 100000000;980981 let list_exists = <ApprovedList<T>>::contains_key(collection_id, (item_id, sender.clone()));982 if list_exists {983984 let mut list = <ApprovedList<T>>::get(collection_id, (item_id, sender.clone()));985 let item_contains = list.iter().any(|i| i.approved == approved);986987 if !item_contains {988 list.push(ApprovePermissions { approved: approved.clone(), amount: amount });989 <ApprovedList<T>>::insert(collection_id, (item_id, sender.clone()), list);990 }991 } else {992993 let mut list = Vec::new();994 list.push(ApprovePermissions { approved: approved.clone(), amount: amount });995 <ApprovedList<T>>::insert(collection_id, (item_id, sender.clone()), list);996 }997998 Ok(())999 }1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 #[weight = T::WeightInfo::transfer_from()]1021 pub fn transfer_from(origin, from: T::AccountId, recipient: T::AccountId, collection_id: u64, item_id: u64, value: u64 ) -> DispatchResult {10221023 let sender = ensure_signed(origin)?;1024 let mut appoved_transfer = false;10251026 1027 if <ApprovedList<T>>::contains_key(collection_id, (item_id, from.clone())) {1028 let list_itm = <ApprovedList<T>>::get(collection_id, (item_id, from.clone()));1029 let opt_item = list_itm.iter().find(|i| i.approved == sender.clone());1030 if opt_item.is_some()1031 {1032 appoved_transfer = true;1033 ensure!(opt_item.unwrap().amount >= value, "Requested value more than approved");1034 }1035 }10361037 1038 let target_collection = <Collection<T>>::get(collection_id);1039 ensure!(appoved_transfer || Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1040 "Only item owner, collection owner and admins can modify items");10411042 if target_collection.access == AccessMode::WhiteList {1043 Self::check_white_list(collection_id, &sender)?;1044 Self::check_white_list(collection_id, &recipient)?;1045 }10461047 1048 let approve_list: Vec<ApprovePermissions<T::AccountId>> = <ApprovedList<T>>::get(collection_id, (item_id, from.clone()))1049 .into_iter().filter(|i| i.approved != sender.clone()).collect();1050 <ApprovedList<T>>::insert(collection_id, (item_id, from.clone()), approve_list);105110521053 match target_collection.mode1054 {1055 CollectionMode::NFT(_) => Self::transfer_nft(collection_id, item_id, from, recipient)?,1056 CollectionMode::Fungible(_) => Self::transfer_fungible(collection_id, item_id, value, from.clone(), recipient)?,1057 CollectionMode::ReFungible(_, _) => Self::transfer_refungible(collection_id, item_id, value, from.clone(), recipient)?,1058 _ => ()1059 };10601061 Ok(())1062 }10631064 1065 #[weight = 0]1066 pub fn safe_transfer_from(origin, collection_id: u64, item_id: u64, new_owner: T::AccountId) -> DispatchResult {10671068 1069 1070 1071 10721073 10741075 10761077 Ok(())1078 }10791080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 #[weight = T::WeightInfo::set_offchain_schema()]1093 pub fn set_offchain_schema(1094 origin,1095 collection_id: u64,1096 schema: Vec<u8>1097 ) -> DispatchResult {1098 let sender = ensure_signed(origin)?;1099 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;11001101 let mut target_collection = <Collection<T>>::get(collection_id);1102 target_collection.offchain_schema = schema;1103 <Collection<T>>::insert(collection_id, target_collection);11041105 Ok(())1106 }11071108 1109 #[weight = 0]1110 pub fn set_chain_limits(1111 origin,1112 limits: ChainLimits1113 ) -> DispatchResult {1114 ensure_root(origin)?;1115 <ChainLimit>::put(limits);1116 Ok(())1117 } 1118 }1119}11201121impl<T: Trait> Module<T> {1122 fn add_fungible_item(item: FungibleItemType<T::AccountId>) -> DispatchResult {1123 let current_index = <ItemListIndex>::get(item.collection)1124 .checked_add(1)1125 .expect("Item list index id error");1126 let itemcopy = item.clone();1127 let owner = item.owner.clone();1128 let value = item.value as u64;11291130 Self::add_token_index(item.collection, current_index, owner.clone())?;11311132 <ItemListIndex>::insert(item.collection, current_index);1133 <FungibleItemList<T>>::insert(item.collection, current_index, itemcopy);11341135 1136 let v: Vec<BasketItem<T::AccountId, T::BlockNumber>> = Vec::new();1137 <FungibleTransferBasket<T>>::insert(item.collection, current_index, v);1138 1139 1140 let new_balance = <Balance<T>>::get(item.collection, owner.clone())1141 .checked_add(value)1142 .unwrap();1143 <Balance<T>>::insert(item.collection, owner.clone(), new_balance);11441145 Ok(())1146 }11471148 fn add_refungible_item(item: ReFungibleItemType<T::AccountId>) -> DispatchResult {1149 let current_index = <ItemListIndex>::get(item.collection)1150 .checked_add(1)1151 .expect("Item list index id error");1152 let itemcopy = item.clone();11531154 let value = item.owner.first().unwrap().fraction as u64;1155 let owner = item.owner.first().unwrap().owner.clone();11561157 Self::add_token_index(item.collection, current_index, owner.clone())?;11581159 <ItemListIndex>::insert(item.collection, current_index);1160 <ReFungibleItemList<T>>::insert(item.collection, current_index, itemcopy);11611162 1163 let block_number: T::BlockNumber = 0.into();1164 <ReFungibleTransferBasket<T>>::insert(item.collection, current_index, block_number);11651166 1167 let new_balance = <Balance<T>>::get(item.collection, owner.clone())1168 .checked_add(value)1169 .unwrap();1170 <Balance<T>>::insert(item.collection, owner.clone(), new_balance);11711172 Ok(())1173 }11741175 fn add_nft_item(item: NftItemType<T::AccountId>) -> DispatchResult {1176 let current_index = <ItemListIndex>::get(item.collection)1177 .checked_add(1)1178 .expect("Item list index id error");11791180 let item_owner = item.owner.clone();1181 let collection_id = item.collection.clone();1182 Self::add_token_index(collection_id, current_index, item.owner.clone())?;11831184 <ItemListIndex>::insert(collection_id, current_index);1185 <NftItemList<T>>::insert(collection_id, current_index, item);11861187 1188 let block_number: T::BlockNumber = 0.into();1189 <NftTransferBasket<T>>::insert(collection_id, current_index, block_number);11901191 1192 let new_balance = <Balance<T>>::get(collection_id, item_owner.clone())1193 .checked_add(1)1194 .unwrap();1195 <Balance<T>>::insert(collection_id, item_owner.clone(), new_balance);11961197 Ok(())1198 }11991200 fn burn_refungible_item(1201 collection_id: u64,1202 item_id: u64,1203 owner: T::AccountId,1204 ) -> DispatchResult {1205 ensure!(1206 <ReFungibleItemList<T>>::contains_key(collection_id, item_id),1207 "Item does not exists"1208 );1209 let collection = <ReFungibleItemList<T>>::get(collection_id, item_id);1210 let item = collection1211 .owner1212 .iter()1213 .filter(|&i| i.owner == owner)1214 .next()1215 .unwrap();1216 Self::remove_token_index(collection_id, item_id, owner.clone())?;12171218 1219 <ApprovedList<T>>::remove(collection_id, (item_id, owner.clone()));12201221 1222 let new_balance = <Balance<T>>::get(collection_id, item.owner.clone())1223 .checked_sub(item.fraction as u64)1224 .unwrap();1225 <Balance<T>>::insert(collection_id, item.owner.clone(), new_balance);12261227 <ReFungibleItemList<T>>::remove(collection_id, item_id);12281229 Ok(())1230 }12311232 fn burn_nft_item(collection_id: u64, item_id: u64) -> DispatchResult {1233 ensure!(1234 <NftItemList<T>>::contains_key(collection_id, item_id),1235 "Item does not exists"1236 );1237 let item = <NftItemList<T>>::get(collection_id, item_id);1238 Self::remove_token_index(collection_id, item_id, item.owner.clone())?;12391240 1241 <ApprovedList<T>>::remove(collection_id, (item_id, item.owner.clone()));12421243 1244 let new_balance = <Balance<T>>::get(collection_id, item.owner.clone())1245 .checked_sub(1)1246 .unwrap();1247 <Balance<T>>::insert(collection_id, item.owner.clone(), new_balance);1248 <NftItemList<T>>::remove(collection_id, item_id);12491250 Ok(())1251 }12521253 fn burn_fungible_item(collection_id: u64, item_id: u64) -> DispatchResult {1254 ensure!(1255 <FungibleItemList<T>>::contains_key(collection_id, item_id),1256 "Item does not exists"1257 );1258 let item = <FungibleItemList<T>>::get(collection_id, item_id);1259 Self::remove_token_index(collection_id, item_id, item.owner.clone())?;12601261 1262 <ApprovedList<T>>::remove(collection_id, (item_id, item.owner.clone()));12631264 1265 let new_balance = <Balance<T>>::get(collection_id, item.owner.clone())1266 .checked_sub(item.value as u64)1267 .unwrap();1268 <Balance<T>>::insert(collection_id, item.owner.clone(), new_balance);12691270 <FungibleItemList<T>>::remove(collection_id, item_id);12711272 Ok(())1273 }12741275 fn collection_exists(collection_id: u64) -> DispatchResult {1276 ensure!(1277 <Collection<T>>::contains_key(collection_id),1278 "This collection does not exist"1279 );1280 Ok(())1281 }12821283 fn check_owner_permissions(collection_id: u64, subject: T::AccountId) -> DispatchResult {1284 Self::collection_exists(collection_id)?;12851286 let target_collection = <Collection<T>>::get(collection_id);1287 ensure!(1288 subject == target_collection.owner,1289 "You do not own this collection"1290 );12911292 Ok(())1293 }12941295 fn is_owner_or_admin_permissions(collection_id: u64, subject: T::AccountId) -> bool {1296 let target_collection = <Collection<T>>::get(collection_id);1297 let mut result: bool = subject == target_collection.owner;1298 let exists = <AdminList<T>>::contains_key(collection_id);12991300 if !result & exists {1301 if <AdminList<T>>::get(collection_id).contains(&subject) {1302 result = true1303 }1304 }13051306 result1307 }13081309 fn check_owner_or_admin_permissions(1310 collection_id: u64,1311 subject: T::AccountId,1312 ) -> DispatchResult {1313 Self::collection_exists(collection_id)?;1314 let result = Self::is_owner_or_admin_permissions(collection_id, subject.clone());13151316 ensure!(1317 result,1318 "You do not have permissions to modify this collection"1319 );1320 Ok(())1321 }13221323 fn is_item_owner(subject: T::AccountId, collection_id: u64, item_id: u64) -> bool {1324 let target_collection = <Collection<T>>::get(collection_id);13251326 match target_collection.mode {1327 CollectionMode::NFT(_) => {1328 <NftItemList<T>>::get(collection_id, item_id).owner == subject1329 }1330 CollectionMode::Fungible(_) => {1331 <FungibleItemList<T>>::get(collection_id, item_id).owner == subject1332 }1333 CollectionMode::ReFungible(_, _) => {1334 <ReFungibleItemList<T>>::get(collection_id, item_id)1335 .owner1336 .iter()1337 .any(|i| i.owner == subject)1338 }1339 CollectionMode::Invalid => false,1340 }1341 }13421343 fn check_white_list(collection_id: u64, address: &T::AccountId) -> DispatchResult {1344 let mes = "Address is not in white list";1345 ensure!(<WhiteList<T>>::contains_key(collection_id), mes);1346 let wl = <WhiteList<T>>::get(collection_id);1347 ensure!(wl.contains(address), mes);13481349 Ok(())1350 }13511352 fn transfer_fungible(1353 collection_id: u64,1354 item_id: u64,1355 value: u64,1356 owner: T::AccountId,1357 new_owner: T::AccountId,1358 ) -> DispatchResult {1359 ensure!(1360 <FungibleItemList<T>>::contains_key(collection_id, item_id),1361 "Item not exists"1362 );13631364 let full_item = <FungibleItemList<T>>::get(collection_id, item_id);1365 let amount = full_item.value;13661367 ensure!(amount >= value.into(), "Item balance not enouth");13681369 1370 let balance_old_owner = <Balance<T>>::get(collection_id, owner.clone())1371 .checked_sub(value)1372 .unwrap();1373 <Balance<T>>::insert(collection_id, owner.clone(), balance_old_owner);13741375 let mut new_owner_account_id = 0;1376 let new_owner_items = <AddressTokens<T>>::get(collection_id, new_owner.clone());1377 if new_owner_items.len() > 0 {1378 new_owner_account_id = new_owner_items[0];1379 }13801381 let val64 = value.into();13821383 1384 if amount == val64 && new_owner_account_id == 0 {1385 1386 1387 let mut new_full_item = full_item.clone();1388 new_full_item.owner = new_owner.clone();1389 <FungibleItemList<T>>::insert(collection_id, item_id, new_full_item);13901391 1392 let balance_new_owner = <Balance<T>>::get(collection_id, new_owner.clone())1393 .checked_add(value)1394 .unwrap();1395 <Balance<T>>::insert(collection_id, new_owner.clone(), balance_new_owner);13961397 1398 Self::move_token_index(collection_id, item_id, owner.clone(), new_owner.clone())?;1399 } else {1400 let mut new_full_item = full_item.clone();1401 new_full_item.value -= val64;14021403 1404 if new_owner_account_id > 0 {1405 1406 let mut item = <FungibleItemList<T>>::get(collection_id, new_owner_account_id);1407 item.value += val64;14081409 1410 let balance_new_owner = <Balance<T>>::get(collection_id, new_owner.clone())1411 .checked_add(value)1412 .unwrap();1413 <Balance<T>>::insert(collection_id, new_owner.clone(), balance_new_owner);14141415 <FungibleItemList<T>>::insert(collection_id, new_owner_account_id, item);1416 } else {1417 1418 let item = FungibleItemType {1419 collection: collection_id,1420 owner: new_owner.clone(),1421 value: val64,1422 };14231424 Self::add_fungible_item(item)?;1425 }14261427 if amount == val64 {1428 Self::remove_token_index(collection_id, item_id, full_item.owner.clone())?;14291430 1431 <ApprovedList<T>>::remove(collection_id, (item_id, full_item.owner.clone()));1432 <FungibleItemList<T>>::remove(collection_id, item_id);1433 }14341435 <FungibleItemList<T>>::insert(collection_id, item_id, new_full_item);1436 }14371438 Ok(())1439 }14401441 fn transfer_refungible(1442 collection_id: u64,1443 item_id: u64,1444 value: u64,1445 owner: T::AccountId,1446 new_owner: T::AccountId,1447 ) -> DispatchResult {1448 ensure!(1449 <ReFungibleItemList<T>>::contains_key(collection_id, item_id),1450 "Item not exists"1451 );14521453 let full_item = <ReFungibleItemList<T>>::get(collection_id, item_id);1454 let item = full_item1455 .owner1456 .iter()1457 .filter(|i| i.owner == owner)1458 .next()1459 .unwrap();1460 let amount = item.fraction;14611462 ensure!(amount >= value.into(), "Item balance not enouth");14631464 1465 let balance_old_owner = <Balance<T>>::get(collection_id, item.owner.clone())1466 .checked_sub(value)1467 .unwrap();1468 <Balance<T>>::insert(collection_id, item.owner.clone(), balance_old_owner);14691470 let balance_new_owner = <Balance<T>>::get(collection_id, new_owner.clone())1471 .checked_add(value)1472 .unwrap();1473 <Balance<T>>::insert(collection_id, new_owner.clone(), balance_new_owner);14741475 let old_owner = item.owner.clone();1476 let new_owner_has_account = full_item.owner.iter().any(|i| i.owner == new_owner);1477 let val64 = value.into();14781479 1480 if amount == val64 && !new_owner_has_account {1481 1482 1483 let mut new_full_item = full_item.clone();1484 new_full_item1485 .owner1486 .iter_mut()1487 .find(|i| i.owner == owner)1488 .unwrap()1489 .owner = new_owner.clone();1490 <ReFungibleItemList<T>>::insert(collection_id, item_id, new_full_item);14911492 1493 Self::move_token_index(collection_id, item_id, old_owner.clone(), new_owner.clone())?;1494 } else {1495 let mut new_full_item = full_item.clone();1496 new_full_item1497 .owner1498 .iter_mut()1499 .find(|i| i.owner == owner)1500 .unwrap()1501 .fraction -= val64;15021503 1504 if new_owner_has_account {1505 1506 new_full_item1507 .owner1508 .iter_mut()1509 .find(|i| i.owner == new_owner)1510 .unwrap()1511 .fraction += val64;1512 } else {1513 1514 new_full_item.owner.push(Ownership {1515 owner: new_owner.clone(),1516 fraction: val64,1517 });1518 Self::add_token_index(collection_id, item_id, new_owner.clone())?;1519 }15201521 <ReFungibleItemList<T>>::insert(collection_id, item_id, new_full_item);1522 }15231524 Ok(())1525 }15261527 fn transfer_nft(1528 collection_id: u64,1529 item_id: u64,1530 sender: T::AccountId,1531 new_owner: T::AccountId,1532 ) -> DispatchResult {1533 ensure!(1534 <NftItemList<T>>::contains_key(collection_id, item_id),1535 "Item not exists"1536 );15371538 let mut item = <NftItemList<T>>::get(collection_id, item_id);15391540 ensure!(1541 sender == item.owner,1542 "sender parameter and item owner must be equal"1543 );15441545 1546 let balance_old_owner = <Balance<T>>::get(collection_id, item.owner.clone())1547 .checked_sub(1)1548 .unwrap();1549 <Balance<T>>::insert(collection_id, item.owner.clone(), balance_old_owner);15501551 let balance_new_owner = <Balance<T>>::get(collection_id, new_owner.clone())1552 .checked_add(1)1553 .unwrap();1554 <Balance<T>>::insert(collection_id, new_owner.clone(), balance_new_owner);15551556 1557 let old_owner = item.owner.clone();1558 item.owner = new_owner.clone();1559 <NftItemList<T>>::insert(collection_id, item_id, item);15601561 1562 Self::move_token_index(collection_id, item_id, old_owner.clone(), new_owner.clone())?;15631564 1565 <ApprovedList<T>>::remove(collection_id, (item_id, old_owner));1566 Ok(())1567 }15681569 fn init_collection(item: &CollectionType<T::AccountId>) {1570 1571 assert!(1572 item.decimal_points <= 4,1573 "decimal_points parameter must be lower than 4"1574 );1575 assert!(1576 item.name.len() <= 64,1577 "Collection name can not be longer than 63 char"1578 );1579 assert!(1580 item.name.len() <= 256,1581 "Collection description can not be longer than 255 char"1582 );1583 assert!(1584 item.token_prefix.len() <= 16,1585 "Token prefix can not be longer than 15 char"1586 );15871588 1589 let next_id = CreatedCollectionCount::get()1590 .checked_add(1)1591 .expect("collection id error");15921593 CreatedCollectionCount::put(next_id);1594 }15951596 fn init_nft_token(item: &NftItemType<T::AccountId>) {1597 let current_index = <ItemListIndex>::get(item.collection)1598 .checked_add(1)1599 .expect("Item list index id error");16001601 let item_owner = item.owner.clone();1602 let collection_id = item.collection.clone();1603 Self::add_token_index(collection_id, current_index, item.owner.clone()).unwrap();16041605 <ItemListIndex>::insert(collection_id, current_index);16061607 1608 let new_balance = <Balance<T>>::get(collection_id, item_owner.clone())1609 .checked_add(1)1610 .unwrap();1611 <Balance<T>>::insert(collection_id, item_owner.clone(), new_balance);1612 }16131614 fn init_fungible_token(item: &FungibleItemType<T::AccountId>) {1615 let current_index = <ItemListIndex>::get(item.collection)1616 .checked_add(1)1617 .expect("Item list index id error");1618 let owner = item.owner.clone();1619 let value = item.value as u64;16201621 Self::add_token_index(item.collection, current_index, owner.clone()).unwrap();16221623 <ItemListIndex>::insert(item.collection, current_index);16241625 1626 let new_balance = <Balance<T>>::get(item.collection, owner.clone())1627 .checked_add(value)1628 .unwrap();1629 <Balance<T>>::insert(item.collection, owner.clone(), new_balance);1630 }16311632 fn init_refungible_token(item: &ReFungibleItemType<T::AccountId>) {1633 let current_index = <ItemListIndex>::get(item.collection)1634 .checked_add(1)1635 .expect("Item list index id error");16361637 let value = item.owner.first().unwrap().fraction as u64;1638 let owner = item.owner.first().unwrap().owner.clone();16391640 Self::add_token_index(item.collection, current_index, owner.clone()).unwrap();16411642 <ItemListIndex>::insert(item.collection, current_index);16431644 1645 let new_balance = <Balance<T>>::get(item.collection, owner.clone())1646 .checked_add(value)1647 .unwrap();1648 <Balance<T>>::insert(item.collection, owner.clone(), new_balance);1649 }16501651 fn add_token_index(collection_id: u64, item_index: u64, owner: T::AccountId) -> DispatchResult {16521653 1654 if <AccountItemCount<T>>::contains_key(owner.clone()) {16551656 1657 let count = <AccountItemCount<T>>::get(owner.clone());1658 ensure!(count < ChainLimit::get().account_token_ownership_limit, "Owned tokens by a single address bound exceeded");16591660 <AccountItemCount<T>>::insert(owner.clone(), 1661 count.checked_add(1).unwrap());1662 }1663 else {1664 <AccountItemCount<T>>::insert(owner.clone(), 1);1665 }16661667 let list_exists = <AddressTokens<T>>::contains_key(collection_id, owner.clone());1668 if list_exists {1669 let mut list = <AddressTokens<T>>::get(collection_id, owner.clone());1670 let item_contains = list.contains(&item_index.clone());16711672 if !item_contains {1673 list.push(item_index.clone());1674 }16751676 <AddressTokens<T>>::insert(collection_id, owner.clone(), list);1677 } else {1678 let mut itm = Vec::new();1679 itm.push(item_index.clone());1680 <AddressTokens<T>>::insert(collection_id, owner, itm);1681 1682 }16831684 Ok(())1685 }16861687 fn remove_token_index(1688 collection_id: u64,1689 item_index: u64,1690 owner: T::AccountId,1691 ) -> DispatchResult {16921693 1694 <AccountItemCount<T>>::insert(owner.clone(), 1695 <AccountItemCount<T>>::get(owner.clone()).checked_sub(1).unwrap());169616971698 let list_exists = <AddressTokens<T>>::contains_key(collection_id, owner.clone());1699 if list_exists {1700 let mut list = <AddressTokens<T>>::get(collection_id, owner.clone());1701 let item_contains = list.contains(&item_index.clone());17021703 if item_contains {1704 list.retain(|&item| item != item_index);1705 <AddressTokens<T>>::insert(collection_id, owner, list);1706 }1707 }17081709 Ok(())1710 }17111712 fn move_token_index(1713 collection_id: u64,1714 item_index: u64,1715 old_owner: T::AccountId,1716 new_owner: T::AccountId,1717 ) -> DispatchResult {1718 Self::remove_token_index(collection_id, item_index, old_owner)?;1719 Self::add_token_index(collection_id, item_index, new_owner)?;17201721 Ok(())1722 }1723}1724172517261727172817291730pub type Multiplier = FixedU128;17311732type BalanceOf<T> = <<T as transaction_payment::Trait>::Currency as Currency<1733 <T as system::Trait>::AccountId,1734>>::Balance;1735type NegativeImbalanceOf<T> = <<T as transaction_payment::Trait>::Currency as Currency<1736 <T as system::Trait>::AccountId,1737>>::NegativeImbalance;1738173917401741#[derive(Encode, Decode, Clone, Eq, PartialEq)]1742pub struct ChargeTransactionPayment<T: Trait + Send + Sync>(1743 #[codec(compact)] BalanceOf<T>1744);17451746impl<T: Trait + Send + Sync> sp_std::fmt::Debug1747 for ChargeTransactionPayment<T>1748{1749 #[cfg(feature = "std")]1750 fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {1751 write!(f, "ChargeTransactionPayment<{:?}>", self.0)1752 }1753 #[cfg(not(feature = "std"))]1754 fn fmt(&self, _: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {1755 Ok(())1756 }1757}17581759impl<T: Trait + Send + Sync> ChargeTransactionPayment<T>1760where1761 T::Call: Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo> + IsSubType<Call<T>>,1762 BalanceOf<T>: Send + Sync + FixedPointOperand,1763{1764 1765 pub fn from(fee: BalanceOf<T>) -> Self {1766 Self(fee)1767 }17681769 pub fn traditional_fee(1770 len: usize,1771 info: &DispatchInfoOf<T::Call>,1772 tip: BalanceOf<T>,1773 ) -> BalanceOf<T>1774 where1775 T::Call: Dispatchable<Info = DispatchInfo>,1776 {1777 <transaction_payment::Module<T>>::compute_fee(len as u32, info, tip)1778 }17791780 fn withdraw_fee(1781 &self,1782 who: &T::AccountId,1783 call: &T::Call,1784 info: &DispatchInfoOf<T::Call>,1785 len: usize,1786 ) -> Result<(BalanceOf<T>, Option<NegativeImbalanceOf<T>>), TransactionValidityError> {1787 let tip = self.0;17881789 1790 1791 1792 1793 1794 1795 1796 let fee = Self::traditional_fee(len, info, tip);17971798 1799 1800 let sponsor: T::AccountId = match call.is_sub_type() {1801 Some(Call::create_item(collection_id, _properties, _owner)) => {1802 <Collection<T>>::get(collection_id).sponsor1803 }1804 Some(Call::transfer(_new_owner, collection_id, _item_id, _value)) => {1805 let _collection_mode = <Collection<T>>::get(collection_id).mode;18061807 1808 let sponsor_transfer = match _collection_mode {1809 CollectionMode::NFT(_) => {1810 let basket = <NftTransferBasket<T>>::get(collection_id, _item_id);1811 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;1812 let limit_time = basket + ChainLimit::get().nft_sponsor_transfer_timeout.into();1813 if block_number >= limit_time {1814 <NftTransferBasket<T>>::insert(collection_id, _item_id, block_number);1815 true1816 }1817 else {1818 false1819 }1820 }1821 CollectionMode::Fungible(_) => {1822 let mut basket = <FungibleTransferBasket<T>>::get(collection_id, _item_id);1823 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;1824 if basket.iter().any(|i| i.address == _new_owner.clone())1825 {1826 let item = basket.iter_mut().find(|i| i.address == _new_owner.clone()).unwrap().clone();1827 let limit_time = item.start_block + ChainLimit::get().fungible_sponsor_transfer_timeout.into();1828 if block_number >= limit_time {1829 basket.retain(|x| x.address == item.address);1830 basket.push(BasketItem { start_block: block_number, address: _new_owner.clone() });1831 <FungibleTransferBasket<T>>::insert(collection_id, _item_id, basket);1832 true1833 }1834 else {1835 false1836 }1837 }1838 else {1839 basket.push(BasketItem { start_block: block_number, address: _new_owner.clone()});1840 true1841 }1842 }1843 CollectionMode::ReFungible(_, _) => {1844 let basket = <ReFungibleTransferBasket<T>>::get(collection_id, _item_id);1845 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;1846 let limit_time = basket + ChainLimit::get().nft_sponsor_transfer_timeout.into();1847 if block_number >= limit_time {1848 <ReFungibleTransferBasket<T>>::insert(collection_id, _item_id, block_number);1849 true1850 } else {1851 false1852 }1853 }1854 _ => {1855 false1856 },1857 };18581859 if !sponsor_transfer {1860 T::AccountId::default()1861 } else {1862 <Collection<T>>::get(collection_id).sponsor1863 }1864 }18651866 1867 1868 1869 18701871 _ => T::AccountId::default(),1872 };18731874 let mut who_pays_fee: T::AccountId = sponsor.clone();1875 if sponsor == T::AccountId::default() {1876 who_pays_fee = who.clone();1877 }18781879 1880 if fee.is_zero() {1881 return Ok((fee, None));1882 }18831884 match <T as transaction_payment::Trait>::Currency::withdraw(1885 &who_pays_fee,1886 fee,1887 if tip.is_zero() {1888 WithdrawReason::TransactionPayment.into()1889 } else {1890 WithdrawReason::TransactionPayment | WithdrawReason::Tip1891 },1892 ExistenceRequirement::KeepAlive,1893 ) {1894 Ok(imbalance) => Ok((fee, Some(imbalance))),1895 Err(_) => Err(InvalidTransaction::Payment.into()),1896 }1897 }1898}189919001901impl<T: Trait + Send + Sync> SignedExtension1902 for ChargeTransactionPayment<T>1903where1904 BalanceOf<T>: Send + Sync + From<u64> + FixedPointOperand,1905 T::Call: Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo> + IsSubType<Call<T>>,1906{1907 const IDENTIFIER: &'static str = "ChargeTransactionPayment";1908 type AccountId = T::AccountId;1909 type Call = T::Call;1910 type AdditionalSigned = ();1911 type Pre = ();1912 1913 1914 1915 1916 1917 1918 fn additional_signed(&self) -> sp_std::result::Result<(), TransactionValidityError> {1919 Ok(())1920 }19211922 fn validate(1923 &self,1924 who: &Self::AccountId,1925 call: &Self::Call,1926 info: &DispatchInfoOf<Self::Call>,1927 len: usize,1928 ) -> TransactionValidity {1929 let (fee, _) = self.withdraw_fee(who, call, info, len)?;19301931 print("====== validate");19321933 Ok(ValidTransaction::default())1934 }19351936 fn pre_dispatch(1937 self,1938 who: &Self::AccountId,1939 call: &Self::Call,1940 info: &DispatchInfoOf<Self::Call>,1941 len: usize,1942 ) -> Result<Self::Pre, TransactionValidityError> {19431944 print("========= PreDispatch");19451946 19471948 19491950 1951 Ok(())1952 }19531954 fn post_dispatch(1955 pre: Self::Pre,1956 info: &DispatchInfoOf<Self::Call>,1957 post_info: &PostDispatchInfoOf<Self::Call>,1958 len: usize,1959 _result: &DispatchResult,1960 ) -> Result<(), TransactionValidityError> {1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 Ok(())1989 }1990}19911992199319941995#[derive(Encode, Decode, Clone, Eq, PartialEq)]1996pub struct ChargeContractTransactionPayment<T: Trait + Send + Sync>(1997 #[codec(compact)] BalanceOf<T>1998);19992000impl<T: Trait + Send + Sync> sp_std::fmt::Debug2001 for ChargeContractTransactionPayment<T>2002{2003 #[cfg(feature = "std")]2004 fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {2005 write!(f, "ChargeContractTransactionPayment<{:?}>", self.0)2006 }2007 #[cfg(not(feature = "std"))]2008 fn fmt(&self, _: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {2009 Ok(())2010 }2011}201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086impl<T: Trait + Send + Sync> SignedExtension2087 for ChargeContractTransactionPayment<T>2088where2089 BalanceOf<T>: Send + Sync + From<u64> + FixedPointOperand,2090 2091 T::Call: Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo> + IsSubType<pallet_contracts::Call<T>>,2092{2093 const IDENTIFIER: &'static str = "ChargeContractTransactionPayment";2094 type AccountId = T::AccountId;2095 type Call = T::Call;2096 type AdditionalSigned = ();2097 type Pre = ();20982099 2100 2101 2102 2103 2104 2105 fn additional_signed(&self) -> sp_std::result::Result<(), TransactionValidityError> {2106 Ok(())2107 }21082109 fn validate(2110 &self,2111 who: &Self::AccountId,2112 call: &Self::Call,2113 info: &DispatchInfoOf<Self::Call>,2114 len: usize,2115 ) -> TransactionValidity {2116 21172118 print("====== Contracts validate");21192120 Ok(ValidTransaction::default())2121 }21222123 fn pre_dispatch(2124 self,2125 who: &Self::AccountId,2126 call: &Self::Call,2127 info: &DispatchInfoOf<Self::Call>,2128 len: usize,2129 ) -> Result<Self::Pre, TransactionValidityError> {2130 2131 21322133 print("====== Contracts pre-dispatch");2134 21352136 Ok(())2137 }21382139 fn post_dispatch(2140 pre: Self::Pre,2141 info: &DispatchInfoOf<Self::Call>,2142 post_info: &PostDispatchInfoOf<Self::Call>,2143 len: usize,2144 _result: &DispatchResult,2145 ) -> Result<(), TransactionValidityError> {2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 Ok(())2174 }2175}21762177217821792180