123456#![recursion_limit = "1024"]78#![cfg_attr(not(feature = "std"), no_std)]910#[cfg(feature = "std")]11pub use std::*;1213#[cfg(feature = "std")]14pub use serde::*;1516use codec::{Decode, Encode};17pub use frame_support::{18 construct_runtime, decl_event, decl_module, decl_storage, decl_error,19 dispatch::DispatchResult,20 ensure, fail, parameter_types,21 traits::{22 Currency, ExistenceRequirement, Get, Imbalance, KeyOwnerProofSystem, OnUnbalanced,23 Randomness, WithdrawReason,24 },25 weights::{26 constants::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_PER_SECOND},27 DispatchInfo, GetDispatchInfo, IdentityFee, Pays, PostDispatchInfo, Weight,28 WeightToFeePolynomial,29 },30 IsSubType, StorageValue,31};3233use frame_system::{self as system, ensure_signed, ensure_root};34use sp_runtime::sp_std::prelude::Vec;35use sp_runtime::{36 traits::{37 DispatchInfoOf, Dispatchable, PostDispatchInfoOf, Saturating, SaturatedConversion, SignedExtension, Zero,38 },39 transaction_validity::{40 TransactionPriority, InvalidTransaction, TransactionValidity, TransactionValidityError, ValidTransaction,41 },42 FixedPointOperand, FixedU128,43};44use pallet_contracts::ContractAddressFor;45use sp_runtime::traits::StaticLookup;4647#[cfg(test)]48mod mock;4950#[cfg(test)]51mod tests;5253mod default_weights;5455pub const MAX_DECIMAL_POINTS: DecimalPoints = 30;56pub const MAX_SPONSOR_TIMEOUT: u32 = 10_368_000;57pub const MAX_TOKEN_OWNERSHIP: u32 = 10_000_000;5859606162pub type CollectionId = u32;63pub type TokenId = u32;64pub type DecimalPoints = u8;6566#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq)]67#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]68pub enum CollectionMode {69 Invalid,70 NFT,71 72 Fungible(DecimalPoints),73 74 ReFungible(DecimalPoints),75}7677impl Into<u8> for CollectionMode {78 fn into(self) -> u8 {79 match self {80 CollectionMode::Invalid => 0,81 CollectionMode::NFT => 1,82 CollectionMode::Fungible(_) => 2,83 CollectionMode::ReFungible(_) => 3,84 }85 }86}8788#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq)]89#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]90pub enum AccessMode {91 Normal,92 WhiteList,93}94impl Default for AccessMode {95 fn default() -> Self {96 Self::Normal97 }98}99100impl Default for CollectionMode {101 fn default() -> Self {102 Self::Invalid103 }104}105106#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq)]107#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]108pub enum SchemaVersion {109 ImageURL,110 Unique,111}112impl Default for SchemaVersion {113 fn default() -> Self {114 Self::ImageURL115 }116}117118#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]119#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]120pub struct Ownership<AccountId> {121 pub owner: AccountId,122 pub fraction: u128,123}124125#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]126#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]127pub struct CollectionType<AccountId> {128 pub owner: AccountId,129 pub mode: CollectionMode,130 pub access: AccessMode,131 pub decimal_points: DecimalPoints,132 pub name: Vec<u16>, 133 pub description: Vec<u16>, 134 pub token_prefix: Vec<u8>, 135 pub mint_mode: bool,136 pub offchain_schema: Vec<u8>,137 pub schema_version: SchemaVersion,138 pub sponsor: AccountId, 139 pub sponsor_confirmed: bool, 140 pub limits: CollectionLimits, 141 pub variable_on_chain_schema: Vec<u8>, 142 pub const_on_chain_schema: Vec<u8>, 143}144145#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]146#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]147pub struct NftItemType<AccountId> {148 pub owner: AccountId,149 pub const_data: Vec<u8>,150 pub variable_data: Vec<u8>,151}152153#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]154#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]155pub struct FungibleItemType<AccountId> {156 pub owner: AccountId,157 pub value: u128,158}159160#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]161#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]162pub struct ReFungibleItemType<AccountId> {163 pub owner: Vec<Ownership<AccountId>>,164 pub const_data: Vec<u8>,165 pub variable_data: Vec<u8>,166}167168#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]169#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]170pub struct ApprovePermissions<AccountId> {171 pub approved: AccountId,172 pub amount: u128,173}174175176177178179180181182183184185186#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]187#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]188pub struct BasketItem<AccountId, BlockNumber> {189 pub address: AccountId,190 pub start_block: BlockNumber,191}192193#[derive(Encode, Decode, Debug, Clone, PartialEq)]194#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]195pub struct CollectionLimits {196 pub account_token_ownership_limit: u32,197 pub sponsored_data_size: u32,198 pub token_limit: u32,199200 201 pub sponsor_transfer_timeout: u32,202}203204impl Default for CollectionLimits {205 fn default() -> CollectionLimits {206 CollectionLimits { 207 account_token_ownership_limit: 10_000_000, 208 token_limit: u32::max_value(),209 sponsored_data_size: u32::max_value(), 210 sponsor_transfer_timeout: 14400 }211 }212}213214#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]215#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]216pub struct ChainLimits {217 pub collection_numbers_limit: u32,218 pub account_token_ownership_limit: u32,219 pub collections_admins_limit: u64,220 pub custom_data_limit: u32,221222 223 pub nft_sponsor_transfer_timeout: u32,224 pub fungible_sponsor_transfer_timeout: u32,225 pub refungible_sponsor_transfer_timeout: u32,226}227228pub trait WeightInfo {229 fn create_collection() -> Weight;230 fn destroy_collection() -> Weight;231 fn add_to_white_list() -> Weight;232 fn remove_from_white_list() -> Weight;233 fn set_public_access_mode() -> Weight;234 fn set_mint_permission() -> Weight;235 fn change_collection_owner() -> Weight;236 fn add_collection_admin() -> Weight;237 fn remove_collection_admin() -> Weight;238 fn set_collection_sponsor() -> Weight;239 fn confirm_sponsorship() -> Weight;240 fn remove_collection_sponsor() -> Weight;241 fn create_item(s: usize) -> Weight;242 fn burn_item() -> Weight;243 fn transfer() -> Weight;244 fn approve() -> Weight;245 fn transfer_from() -> Weight;246 fn set_offchain_schema() -> Weight;247 fn set_const_on_chain_schema() -> Weight;248 fn set_variable_on_chain_schema() -> Weight;249 fn set_variable_meta_data() -> Weight;250 fn enable_contract_sponsoring() -> Weight;251}252253#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]254#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]255pub struct CreateNftData {256 pub const_data: Vec<u8>,257 pub variable_data: Vec<u8>,258}259260#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]261#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]262pub struct CreateFungibleData {263}264265#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]266#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]267pub struct CreateReFungibleData {268 pub const_data: Vec<u8>,269 pub variable_data: Vec<u8>,270}271272#[derive(Encode, Decode, Debug, Clone, PartialEq)]273#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]274pub enum CreateItemData {275 NFT(CreateNftData),276 Fungible(CreateFungibleData),277 ReFungible(CreateReFungibleData),278}279280impl CreateItemData {281 pub fn len(&self) -> usize {282 let len = match self {283 CreateItemData::NFT(data) => data.variable_data.len() + data.const_data.len(),284 CreateItemData::ReFungible(data) => data.variable_data.len() + data.const_data.len(),285 _ => 0286 };287 288 return len;289 }290}291292impl From<CreateNftData> for CreateItemData {293 fn from(item: CreateNftData) -> Self {294 CreateItemData::NFT(item)295 }296}297298impl From<CreateReFungibleData> for CreateItemData {299 fn from(item: CreateReFungibleData) -> Self {300 CreateItemData::ReFungible(item)301 }302}303304impl From<CreateFungibleData> for CreateItemData {305 fn from(item: CreateFungibleData) -> Self {306 CreateItemData::Fungible(item)307 }308}309310311decl_error! {312 313 pub enum Error for Module<T: Trait> {314 315 TotalCollectionsLimitExceeded,316 317 CollectionDecimalPointLimitExceeded, 318 319 CollectionNameLimitExceeded, 320 321 CollectionDescriptionLimitExceeded, 322 323 CollectionTokenPrefixLimitExceeded,324 325 CollectionNotFound,326 327 TokenNotFound,328 329 NumOverflow, 330 331 AlreadyAdmin, 332 333 NoPermission,334 335 ConfirmUnsetSponsorFail,336 337 PublicMintingNotAllowed,338 339 MustBeTokenOwner,340 341 TokenValueTooLow,342 343 NftSizeLimitExceeded,344 345 ApproveNotFound,346 347 TokenValueNotEnough,348 349 ApproveRequired,350 351 AddresNotInWhiteList,352 353 CollectionAdminsLimitExceeded,354 355 AddressOwnershipLimitExceeded,356 357 EmptyArgument,358 359 TokenConstDataLimitExceeded,360 361 TokenVariableDataLimitExceeded,362 363 NotNftDataUsedToMintNftCollectionToken,364 365 NotFungibleDataUsedToMintFungibleCollectionToken,366 367 NotReFungibleDataUsedToMintReFungibleCollectionToken,368 369 UnexpectedCollectionType,370 371 CantStoreMetadataInFungibleTokens,372 373 CollectionTokenLimitExceeded,374 375 AccountTokenLimitExceeded,376 377 CollectionLimitBoundsExceeded378 }379}380381pub trait Trait: system::Trait + Sized + transaction_payment::Trait + pallet_contracts::Trait {382 type Event: From<Event<Self>> + Into<<Self as system::Trait>::Event>;383384 385 type WeightInfo: WeightInfo;386}387388#[cfg(feature = "runtime-benchmarks")]389mod benchmarking;390391392393decl_storage! {394 trait Store for Module<T: Trait> as Nft {395396 397 NextCollectionID: CollectionId;398 CreatedCollectionCount: u32;399 ChainVersion: u64;400 ItemListIndex: map hasher(identity) CollectionId => TokenId;401402 403 pub ChainLimit get(fn chain_limit) config(): ChainLimits;404405 406 CollectionCount: u32;407 pub AccountItemCount get(fn account_item_count): map hasher(twox_64_concat) T::AccountId => u32;408409 410 pub Collection get(fn collection) config(): map hasher(identity) CollectionId => CollectionType<T::AccountId>;411 pub AdminList get(fn admin_list_collection): map hasher(identity) CollectionId => Vec<T::AccountId>;412 pub WhiteList get(fn white_list): map hasher(identity) CollectionId => Vec<T::AccountId>;413414 415 pub Balance get(fn balance_count): double_map hasher(identity) CollectionId, hasher(twox_64_concat) T::AccountId => u128;416417 418 pub ApprovedList get(fn approved): double_map hasher(identity) CollectionId, hasher(twox_64_concat) (TokenId, T::AccountId) => Vec<ApprovePermissions<T::AccountId>>;419420 421 pub NftItemList get(fn nft_item_id) config(): double_map hasher(identity) CollectionId, hasher(identity) TokenId => NftItemType<T::AccountId>;422 pub FungibleItemList get(fn fungible_item_id) config(): double_map hasher(identity) CollectionId, hasher(identity) TokenId => FungibleItemType<T::AccountId>;423 pub ReFungibleItemList get(fn refungible_item_id) config(): double_map hasher(identity) CollectionId, hasher(identity) TokenId => ReFungibleItemType<T::AccountId>;424425 426 pub AddressTokens get(fn address_tokens): double_map hasher(identity) CollectionId, hasher(twox_64_concat) T::AccountId => Vec<TokenId>;427428 429 pub NftTransferBasket get(fn nft_transfer_basket): double_map hasher(identity) CollectionId, hasher(identity) TokenId => T::BlockNumber;430 pub FungibleTransferBasket get(fn fungible_transfer_basket): double_map hasher(identity) CollectionId, hasher(identity) TokenId => Vec<BasketItem<T::AccountId, T::BlockNumber>>;431 pub ReFungibleTransferBasket get(fn refungible_transfer_basket): double_map hasher(identity) CollectionId, hasher(identity) TokenId => T::BlockNumber;432433 434 pub ContractOwner get(fn contract_owner): map hasher(twox_64_concat) T::AccountId => T::AccountId;435 pub ContractSelfSponsoring get(fn contract_self_sponsoring): map hasher(twox_64_concat) T::AccountId => bool;436 pub ContractSponsorBasket get(fn contract_sponsor_basket): map hasher(twox_64_concat) (T::AccountId, T::AccountId) => T::BlockNumber;437 pub ContractSponsoringRateLimit get(fn contract_sponsoring_rate_limit): map hasher(twox_64_concat) T::AccountId => T::BlockNumber;438 }439 add_extra_genesis {440 build(|config: &GenesisConfig<T>| {441 442 for (_num, _c) in &config.collection {443 <Module<T>>::init_collection(_c);444 }445446 for (_num, _c, _i) in &config.nft_item_id {447 <Module<T>>::init_nft_token(*_c, _i);448 }449450 for (_num, _c, _i) in &config.fungible_item_id {451 <Module<T>>::init_fungible_token(*_c, _i);452 }453454 for (_num, _c, _i) in &config.refungible_item_id {455 <Module<T>>::init_refungible_token(*_c, _i);456 }457 })458 }459}460461decl_event!(462 pub enum Event<T>463 where464 AccountId = <T as system::Trait>::AccountId,465 {466 467 468 469 470 471 472 473 474 475 Created(CollectionId, u8, AccountId),476477 478 479 480 481 482 483 484 ItemCreated(CollectionId, TokenId),485486 487 488 489 490 491 492 493 ItemDestroyed(CollectionId, TokenId),494 }495);496497decl_module! {498 pub struct Module<T: Trait> for enum Call where origin: T::Origin {499500 fn deposit_event() = default;501 type Error = Error<T>;502503 fn on_initialize(now: T::BlockNumber) -> Weight {504505 if ChainVersion::get() < 2506 {507 let value = NextCollectionID::get();508 CreatedCollectionCount::put(value);509 ChainVersion::put(2);510 }511512 0513 }514515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 #[weight = T::WeightInfo::create_collection()]532 pub fn create_collection(origin,533 collection_name: Vec<u16>,534 collection_description: Vec<u16>,535 token_prefix: Vec<u8>,536 mode: CollectionMode) -> DispatchResult {537538 539 let who = ensure_signed(origin)?;540541 let decimal_points = match mode {542 CollectionMode::Fungible(points) => points,543 CollectionMode::ReFungible(points) => points,544 _ => 0545 };546547 548 ensure!(CollectionCount::get() < ChainLimit::get().collection_numbers_limit, Error::<T>::TotalCollectionsLimitExceeded);549550 551 ensure!(decimal_points <= MAX_DECIMAL_POINTS, Error::<T>::CollectionDecimalPointLimitExceeded);552553 let mut name = collection_name.to_vec();554 name.push(0);555 ensure!(name.len() <= 64, Error::<T>::CollectionNameLimitExceeded);556557 let mut description = collection_description.to_vec();558 description.push(0);559 ensure!(name.len() <= 256, Error::<T>::CollectionDescriptionLimitExceeded);560561 let mut prefix = token_prefix.to_vec();562 prefix.push(0);563 ensure!(prefix.len() <= 16, Error::<T>::CollectionTokenPrefixLimitExceeded);564565 566 let next_id = CreatedCollectionCount::get()567 .checked_add(1)568 .ok_or(Error::<T>::NumOverflow)?;569570 571 let total = CollectionCount::get()572 .checked_add(1)573 .ok_or(Error::<T>::NumOverflow)?;574575 CreatedCollectionCount::put(next_id);576 CollectionCount::put(total);577578 579 let new_collection = CollectionType {580 owner: who.clone(),581 name: name,582 mode: mode.clone(),583 mint_mode: false,584 access: AccessMode::Normal,585 description: description,586 decimal_points: decimal_points,587 token_prefix: prefix,588 offchain_schema: Vec::new(),589 schema_version: SchemaVersion::ImageURL,590 sponsor: T::AccountId::default(),591 sponsor_confirmed: false,592 variable_on_chain_schema: Vec::new(),593 const_on_chain_schema: Vec::new(),594 limits: CollectionLimits::default(),595 };596597 598 <Collection<T>>::insert(next_id, new_collection);599600 601 Self::deposit_event(RawEvent::Created(next_id, mode.into(), who.clone()));602603 Ok(())604 }605606 607 608 609 610 611 612 613 614 615 #[weight = T::WeightInfo::destroy_collection()]616 pub fn destroy_collection(origin, collection_id: CollectionId) -> DispatchResult {617618 let sender = ensure_signed(origin)?;619 Self::check_owner_permissions(collection_id, sender)?;620621 <AddressTokens<T>>::remove_prefix(collection_id);622 <ApprovedList<T>>::remove_prefix(collection_id);623 <Balance<T>>::remove_prefix(collection_id);624 <ItemListIndex>::remove(collection_id);625 <AdminList<T>>::remove(collection_id);626 <Collection<T>>::remove(collection_id);627 <WhiteList<T>>::remove(collection_id);628629 <NftItemList<T>>::remove_prefix(collection_id);630 <FungibleItemList<T>>::remove_prefix(collection_id);631 <ReFungibleItemList<T>>::remove_prefix(collection_id);632633 <NftTransferBasket<T>>::remove_prefix(collection_id);634 <FungibleTransferBasket<T>>::remove_prefix(collection_id);635 <ReFungibleTransferBasket<T>>::remove_prefix(collection_id);636637 if CollectionCount::get() > 0638 {639 640 let total = CollectionCount::get()641 .checked_sub(1)642 .ok_or(Error::<T>::NumOverflow)?;643644 CollectionCount::put(total);645 }646647 Ok(())648 }649650 651 652 653 654 655 656 657 658 659 660 661 662 #[weight = T::WeightInfo::add_to_white_list()]663 pub fn add_to_white_list(origin, collection_id: CollectionId, address: T::AccountId) -> DispatchResult{664665 let sender = ensure_signed(origin)?;666 Self::check_owner_or_admin_permissions(collection_id, sender)?;667668 let mut white_list_collection: Vec<T::AccountId>;669 if <WhiteList<T>>::contains_key(collection_id) {670 white_list_collection = <WhiteList<T>>::get(collection_id);671 if !white_list_collection.contains(&address.clone())672 {673 white_list_collection.push(address.clone());674 }675 }676 else {677 white_list_collection = Vec::new();678 white_list_collection.push(address.clone());679 }680681 <WhiteList<T>>::insert(collection_id, white_list_collection);682 Ok(())683 }684685 686 687 688 689 690 691 692 693 694 695 696 697 #[weight = T::WeightInfo::remove_from_white_list()]698 pub fn remove_from_white_list(origin, collection_id: CollectionId, address: T::AccountId) -> DispatchResult{699700 let sender = ensure_signed(origin)?;701 Self::check_owner_or_admin_permissions(collection_id, sender)?;702703 if <WhiteList<T>>::contains_key(collection_id) {704 let mut white_list_collection = <WhiteList<T>>::get(collection_id);705 if white_list_collection.contains(&address.clone())706 {707 white_list_collection.retain(|i| *i != address.clone());708 <WhiteList<T>>::insert(collection_id, white_list_collection);709 }710 }711712 Ok(())713 }714715 716 717 718 719 720 721 722 723 724 725 726 #[weight = T::WeightInfo::set_public_access_mode()]727 pub fn set_public_access_mode(origin, collection_id: CollectionId, mode: AccessMode) -> DispatchResult728 {729 let sender = ensure_signed(origin)?;730731 Self::check_owner_permissions(collection_id, sender)?;732 let mut target_collection = <Collection<T>>::get(collection_id);733 target_collection.access = mode;734 <Collection<T>>::insert(collection_id, target_collection);735736 Ok(())737 }738739 740 741 742 743 744 745 746 747 748 749 750 751 752 #[weight = T::WeightInfo::set_mint_permission()]753 pub fn set_mint_permission(origin, collection_id: CollectionId, mint_permission: bool) -> DispatchResult754 {755 let sender = ensure_signed(origin)?;756757 Self::check_owner_permissions(collection_id, sender)?;758 let mut target_collection = <Collection<T>>::get(collection_id);759 target_collection.mint_mode = mint_permission;760 <Collection<T>>::insert(collection_id, target_collection);761762 Ok(())763 }764765 766 767 768 769 770 771 772 773 774 775 776 #[weight = T::WeightInfo::change_collection_owner()]777 pub fn change_collection_owner(origin, collection_id: CollectionId, new_owner: T::AccountId) -> DispatchResult {778779 let sender = ensure_signed(origin)?;780 Self::check_owner_permissions(collection_id, sender)?;781 let mut target_collection = <Collection<T>>::get(collection_id);782 target_collection.owner = new_owner;783 <Collection<T>>::insert(collection_id, target_collection);784785 Ok(())786 }787788 789 790 791 792 793 794 795 796 797 798 799 800 801 #[weight = T::WeightInfo::add_collection_admin()]802 pub fn add_collection_admin(origin, collection_id: CollectionId, new_admin_id: T::AccountId) -> DispatchResult {803804 let sender = ensure_signed(origin)?;805 Self::check_owner_or_admin_permissions(collection_id, sender)?;806 let mut admin_arr: Vec<T::AccountId> = Vec::new();807808 if <AdminList<T>>::contains_key(collection_id)809 {810 admin_arr = <AdminList<T>>::get(collection_id);811 ensure!(!admin_arr.contains(&new_admin_id), Error::<T>::AlreadyAdmin);812 }813814 815 ensure!((admin_arr.len() as u64) < ChainLimit::get().collections_admins_limit, Error::<T>::CollectionAdminsLimitExceeded);816817 admin_arr.push(new_admin_id);818 <AdminList<T>>::insert(collection_id, admin_arr);819820 Ok(())821 }822823 824 825 826 827 828 829 830 831 832 833 834 835 #[weight = T::WeightInfo::remove_collection_admin()]836 pub fn remove_collection_admin(origin, collection_id: CollectionId, account_id: T::AccountId) -> DispatchResult {837838 let sender = ensure_signed(origin)?;839 Self::check_owner_or_admin_permissions(collection_id, sender)?;840841 if <AdminList<T>>::contains_key(collection_id)842 {843 let mut admin_arr = <AdminList<T>>::get(collection_id);844 admin_arr.retain(|i| *i != account_id);845 <AdminList<T>>::insert(collection_id, admin_arr);846 }847848 Ok(())849 }850851 852 853 854 855 856 857 858 859 860 #[weight = T::WeightInfo::set_collection_sponsor()]861 pub fn set_collection_sponsor(origin, collection_id: CollectionId, new_sponsor: T::AccountId) -> DispatchResult {862863 let sender = ensure_signed(origin)?;864 ensure!(<Collection<T>>::contains_key(collection_id), Error::<T>::CollectionNotFound);865866 let mut target_collection = <Collection<T>>::get(collection_id);867 ensure!(sender == target_collection.owner, Error::<T>::NoPermission);868869 target_collection.sponsor = new_sponsor;870 target_collection.sponsor_confirmed = false;871 <Collection<T>>::insert(collection_id, target_collection);872873 Ok(())874 }875876 877 878 879 880 881 882 883 #[weight = T::WeightInfo::confirm_sponsorship()]884 pub fn confirm_sponsorship(origin, collection_id: CollectionId) -> DispatchResult {885886 let sender = ensure_signed(origin)?;887 ensure!(<Collection<T>>::contains_key(collection_id), Error::<T>::CollectionNotFound);888889 let mut target_collection = <Collection<T>>::get(collection_id);890 ensure!(sender == target_collection.sponsor, Error::<T>::ConfirmUnsetSponsorFail);891892 target_collection.sponsor_confirmed = true;893 <Collection<T>>::insert(collection_id, target_collection);894895 Ok(())896 }897898 899 900 901 902 903 904 905 906 907 #[weight = T::WeightInfo::remove_collection_sponsor()]908 pub fn remove_collection_sponsor(origin, collection_id: CollectionId) -> DispatchResult {909910 let sender = ensure_signed(origin)?;911 ensure!(<Collection<T>>::contains_key(collection_id), Error::<T>::CollectionNotFound);912913 let mut target_collection = <Collection<T>>::get(collection_id);914 ensure!(sender == target_collection.owner, Error::<T>::NoPermission);915916 target_collection.sponsor = T::AccountId::default();917 target_collection.sponsor_confirmed = false;918 <Collection<T>>::insert(collection_id, target_collection);919920 Ok(())921 }922923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946947 #[weight = T::WeightInfo::create_item(data.len())]948 pub fn create_item(origin, collection_id: CollectionId, owner: T::AccountId, data: CreateItemData) -> DispatchResult {949950 let sender = ensure_signed(origin)?;951952 Self::collection_exists(collection_id)?;953954 let target_collection = <Collection<T>>::get(collection_id);955956 Self::can_create_items_in_collection(collection_id, &target_collection, &sender, &owner)?;957 Self::validate_create_item_args(&target_collection, &data)?;958 Self::create_item_no_validation(collection_id, &target_collection, owner, data)?;959960 Ok(())961 }962963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 #[weight = T::WeightInfo::create_item(items_data.into_iter()982 .map(|data| { data.len() })983 .sum())]984 pub fn create_multiple_items(origin, collection_id: CollectionId, owner: T::AccountId, items_data: Vec<CreateItemData>) -> DispatchResult {985986 ensure!(items_data.len() > 0, Error::<T>::EmptyArgument);987 let sender = ensure_signed(origin)?;988989 Self::collection_exists(collection_id)?;990 let target_collection = <Collection<T>>::get(collection_id);991992 Self::can_create_items_in_collection(collection_id, &target_collection, &sender, &owner)?;993994 for data in &items_data {995 Self::validate_create_item_args(&target_collection, data)?;996 }997 for data in &items_data {998 Self::create_item_no_validation(collection_id, &target_collection, owner.clone(), data.clone())?;999 }10001001 Ok(())1002 }10031004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 #[weight = T::WeightInfo::burn_item()]1018 pub fn burn_item(origin, collection_id: CollectionId, item_id: TokenId) -> DispatchResult {10191020 let sender = ensure_signed(origin)?;1021 Self::collection_exists(collection_id)?;10221023 1024 let target_collection = <Collection<T>>::get(collection_id);1025 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||1026 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1027 Error::<T>::NoPermission);10281029 if target_collection.access == AccessMode::WhiteList {1030 Self::check_white_list(collection_id, &sender)?;1031 }10321033 match target_collection.mode1034 {1035 CollectionMode::NFT => Self::burn_nft_item(collection_id, item_id)?,1036 CollectionMode::Fungible(_) => Self::burn_fungible_item(collection_id, item_id)?,1037 CollectionMode::ReFungible(_) => Self::burn_refungible_item(collection_id, item_id, sender.clone())?,1038 _ => ()1039 };10401041 1042 Self::deposit_event(RawEvent::ItemDestroyed(collection_id, item_id));10431044 Ok(())1045 }10461047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 #[weight = T::WeightInfo::transfer()]1071 pub fn transfer(origin, recipient: T::AccountId, collection_id: CollectionId, item_id: TokenId, value: u128) -> DispatchResult {10721073 let sender = ensure_signed(origin)?;1074 let target_collection = <Collection<T>>::get(collection_id);10751076 1077 Self::is_correct_transfer(collection_id, &target_collection, &recipient)?;10781079 1080 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||1081 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1082 Error::<T>::NoPermission);10831084 if target_collection.access == AccessMode::WhiteList {1085 Self::check_white_list(collection_id, &sender)?;1086 Self::check_white_list(collection_id, &recipient)?;1087 }10881089 match target_collection.mode1090 {1091 CollectionMode::NFT => Self::transfer_nft(collection_id, item_id, sender.clone(), recipient)?,1092 CollectionMode::Fungible(_) => Self::transfer_fungible(collection_id, item_id, value, sender.clone(), recipient)?,1093 CollectionMode::ReFungible(_) => Self::transfer_refungible(collection_id, item_id, value, sender.clone(), recipient)?,1094 _ => ()1095 };10961097 Ok(())1098 }10991100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 #[weight = T::WeightInfo::approve()]1116 pub fn approve(origin, approved: T::AccountId, collection_id: CollectionId, item_id: TokenId) -> DispatchResult {11171118 let sender = ensure_signed(origin)?;11191120 1121 let target_collection = <Collection<T>>::get(collection_id);1122 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||1123 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1124 Error::<T>::NoPermission);11251126 if target_collection.access == AccessMode::WhiteList {1127 Self::check_white_list(collection_id, &sender)?;1128 Self::check_white_list(collection_id, &approved)?;1129 }11301131 1132 let amount = 100000000;11331134 let list_exists = <ApprovedList<T>>::contains_key(collection_id, (item_id, sender.clone()));1135 if list_exists {11361137 let mut list = <ApprovedList<T>>::get(collection_id, (item_id, sender.clone()));1138 let item_contains = list.iter().any(|i| i.approved == approved);11391140 if !item_contains {1141 list.push(ApprovePermissions { approved: approved.clone(), amount: amount });1142 <ApprovedList<T>>::insert(collection_id, (item_id, sender.clone()), list);1143 }1144 } else {11451146 let mut list = Vec::new();1147 list.push(ApprovePermissions { approved: approved.clone(), amount: amount });1148 <ApprovedList<T>>::insert(collection_id, (item_id, sender.clone()), list);1149 }11501151 Ok(())1152 }1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 #[weight = T::WeightInfo::transfer_from()]1174 pub fn transfer_from(origin, from: T::AccountId, recipient: T::AccountId, collection_id: CollectionId, item_id: TokenId, value: u128 ) -> DispatchResult {11751176 let sender = ensure_signed(origin)?;1177 let mut appoved_transfer = false;11781179 1180 if <ApprovedList<T>>::contains_key(collection_id, (item_id, from.clone())) {1181 let list_itm = <ApprovedList<T>>::get(collection_id, (item_id, from.clone()));1182 let opt_item = list_itm.iter().find(|i| i.approved == sender.clone());1183 if opt_item.is_some()1184 {1185 appoved_transfer = true;1186 ensure!(opt_item.unwrap().amount >= value, Error::<T>::TokenValueNotEnough);1187 }1188 }11891190 let target_collection = <Collection<T>>::get(collection_id);11911192 1193 Self::is_correct_transfer(collection_id, &target_collection, &recipient)?;11941195 1196 ensure!(appoved_transfer || Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1197 Error::<T>::NoPermission);11981199 if target_collection.access == AccessMode::WhiteList {1200 Self::check_white_list(collection_id, &sender)?;1201 Self::check_white_list(collection_id, &recipient)?;1202 }12031204 1205 let approve_list: Vec<ApprovePermissions<T::AccountId>> = <ApprovedList<T>>::get(collection_id, (item_id, from.clone()))1206 .into_iter().filter(|i| i.approved != sender.clone()).collect();1207 <ApprovedList<T>>::insert(collection_id, (item_id, from.clone()), approve_list);120812091210 match target_collection.mode1211 {1212 CollectionMode::NFT => Self::transfer_nft(collection_id, item_id, from, recipient)?,1213 CollectionMode::Fungible(_) => Self::transfer_fungible(collection_id, item_id, value, from.clone(), recipient)?,1214 CollectionMode::ReFungible(_) => Self::transfer_refungible(collection_id, item_id, value, from.clone(), recipient)?,1215 _ => ()1216 };12171218 Ok(())1219 }12201221 #[weight = 0]1222 pub fn safe_transfer_from(origin, collection_id: CollectionId, item_id: TokenId, new_owner: T::AccountId) -> DispatchResult {12231224 1225 1226 1227 12281229 12301231 12321233 Ok(())1234 }12351236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 #[weight = T::WeightInfo::set_variable_meta_data()]1249 pub fn set_variable_meta_data (1250 origin,1251 collection_id: CollectionId,1252 item_id: TokenId,1253 data: Vec<u8>1254 ) -> DispatchResult {1255 let sender = ensure_signed(origin)?;1256 1257 Self::collection_exists(collection_id)?;1258 1259 ensure!(ChainLimit::get().custom_data_limit >= data.len() as u32, Error::<T>::TokenVariableDataLimitExceeded);12601261 1262 let target_collection = <Collection<T>>::get(collection_id);1263 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||1264 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1265 Error::<T>::NoPermission);12661267 Self::item_exists(collection_id, item_id, &target_collection.mode)?;12681269 match target_collection.mode1270 {1271 CollectionMode::NFT => Self::set_nft_variable_data(collection_id, item_id, data)?,1272 CollectionMode::ReFungible(_) => Self::set_re_fungible_variable_data(collection_id, item_id, data)?,1273 CollectionMode::Fungible(_) => fail!(Error::<T>::CantStoreMetadataInFungibleTokens),1274 _ => fail!(Error::<T>::UnexpectedCollectionType)1275 };12761277 Ok(())1278 }1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 #[weight = 0]1295 pub fn set_schema_version(1296 origin,1297 collection_id: CollectionId,1298 version: SchemaVersion1299 ) -> DispatchResult {1300 let sender = ensure_signed(origin)?;1301 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;1302 let mut target_collection = <Collection<T>>::get(collection_id);1303 target_collection.schema_version = version;1304 <Collection<T>>::insert(collection_id, target_collection);13051306 Ok(())1307 }13081309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 #[weight = T::WeightInfo::set_offchain_schema()]1322 pub fn set_offchain_schema(1323 origin,1324 collection_id: CollectionId,1325 schema: Vec<u8>1326 ) -> DispatchResult {1327 let sender = ensure_signed(origin)?;1328 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;13291330 let mut target_collection = <Collection<T>>::get(collection_id);1331 target_collection.offchain_schema = schema;1332 <Collection<T>>::insert(collection_id, target_collection);13331334 Ok(())1335 }13361337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 #[weight = T::WeightInfo::set_const_on_chain_schema()]1350 pub fn set_const_on_chain_schema (1351 origin,1352 collection_id: CollectionId,1353 schema: Vec<u8>1354 ) -> DispatchResult {1355 let sender = ensure_signed(origin)?;1356 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;13571358 let mut target_collection = <Collection<T>>::get(collection_id);1359 target_collection.const_on_chain_schema = schema;1360 <Collection<T>>::insert(collection_id, target_collection);13611362 Ok(())1363 }13641365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 #[weight = T::WeightInfo::set_const_on_chain_schema()]1378 pub fn set_variable_on_chain_schema (1379 origin,1380 collection_id: CollectionId,1381 schema: Vec<u8>1382 ) -> DispatchResult {1383 let sender = ensure_signed(origin)?;1384 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;13851386 let mut target_collection = <Collection<T>>::get(collection_id);1387 target_collection.variable_on_chain_schema = schema;1388 <Collection<T>>::insert(collection_id, target_collection);13891390 Ok(())1391 }13921393 1394 #[weight = 0]1395 pub fn set_chain_limits(1396 origin,1397 limits: ChainLimits1398 ) -> DispatchResult {1399 ensure_root(origin)?;1400 <ChainLimit>::put(limits);1401 Ok(())1402 }14031404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 #[weight = T::WeightInfo::enable_contract_sponsoring()]1416 pub fn enable_contract_sponsoring(1417 origin,1418 contract_address: T::AccountId,1419 enable: bool1420 ) -> DispatchResult {14211422 let sender = ensure_signed(origin)?;14231424 #[cfg(feature = "runtime-benchmarks")]1425 <ContractOwner<T>>::insert(contract_address.clone(), sender.clone());14261427 let mut is_owner = false;1428 if <ContractOwner<T>>::contains_key(contract_address.clone()) {1429 let owner = <ContractOwner<T>>::get(&contract_address);1430 is_owner = sender == owner;1431 }1432 ensure!(is_owner, Error::<T>::NoPermission);14331434 <ContractSelfSponsoring<T>>::insert(contract_address, enable);1435 Ok(())1436 }14371438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 #[weight = 0]1456 pub fn set_contract_sponsoring_rate_limit(1457 origin,1458 contract_address: T::AccountId,1459 rate_limit: T::BlockNumber1460 ) -> DispatchResult {1461 let sender = ensure_signed(origin)?;1462 let mut is_owner = false;1463 if <ContractOwner<T>>::contains_key(contract_address.clone()) {1464 let owner = <ContractOwner<T>>::get(&contract_address);1465 is_owner = sender == owner;1466 }1467 ensure!(is_owner, Error::<T>::NoPermission);14681469 <ContractSponsoringRateLimit<T>>::insert(contract_address, rate_limit);1470 Ok(())1471 }14721473 #[weight = 0]1474 pub fn set_collection_limits(1475 origin,1476 collection_id: u32,1477 limits: CollectionLimits,1478 ) -> DispatchResult {1479 let sender = ensure_signed(origin)?;1480 Self::check_owner_permissions(collection_id, sender.clone())?;1481 let mut target_collection = <Collection<T>>::get(collection_id);1482 let chain_limits = ChainLimit::get();1483 let climits = target_collection.limits;14841485 1486 ensure!(limits.sponsor_transfer_timeout <= MAX_SPONSOR_TIMEOUT &&1487 limits.account_token_ownership_limit <= MAX_TOKEN_OWNERSHIP, 1488 Error::<T>::CollectionLimitBoundsExceeded);14891490 1491 ensure!(climits.token_limit > limits.token_limit && 1492 limits.token_limit <= chain_limits.account_token_ownership_limit, 1493 Error::<T>::AccountTokenLimitExceeded);14941495 target_collection.limits = limits;1496 <Collection<T>>::insert(collection_id, target_collection);14971498 Ok(())1499 } 1500 }1501}15021503impl<T: Trait> Module<T> {15041505 fn is_correct_transfer(collection_id: CollectionId, collection: &CollectionType<T::AccountId>, recipient: &T::AccountId) -> DispatchResult {15061507 1508 let account_items: u32 = <AddressTokens<T>>::get(collection_id, recipient).len() as u32;1509 ensure!(collection.limits.account_token_ownership_limit > account_items, Error::<T>::AccountTokenLimitExceeded);1510 1511 Ok(())1512 }15131514 fn can_create_items_in_collection(collection_id: CollectionId, collection: &CollectionType<T::AccountId>, sender: &T::AccountId, owner: &T::AccountId) -> DispatchResult {15151516 1517 let total_items: u32 = ItemListIndex::get(collection_id);1518 let account_items: u32 = <AddressTokens<T>>::get(collection_id, owner).len() as u32;1519 ensure!(collection.limits.token_limit > total_items, Error::<T>::CollectionTokenLimitExceeded);1520 ensure!(collection.limits.account_token_ownership_limit > account_items, Error::<T>::AccountTokenLimitExceeded);15211522 if !Self::is_owner_or_admin_permissions(collection_id, sender.clone()) {1523 ensure!(collection.mint_mode == true, Error::<T>::PublicMintingNotAllowed);1524 Self::check_white_list(collection_id, owner)?;1525 Self::check_white_list(collection_id, sender)?;1526 }15271528 Ok(())1529 }15301531 fn validate_create_item_args(target_collection: &CollectionType<T::AccountId>, data: &CreateItemData) -> DispatchResult {1532 match target_collection.mode1533 {1534 CollectionMode::NFT => {1535 if let CreateItemData::NFT(data) = data {1536 1537 ensure!(ChainLimit::get().custom_data_limit >= data.const_data.len() as u32, Error::<T>::TokenConstDataLimitExceeded);1538 ensure!(ChainLimit::get().custom_data_limit >= data.variable_data.len() as u32, Error::<T>::TokenVariableDataLimitExceeded);1539 } else {1540 fail!(Error::<T>::NotNftDataUsedToMintNftCollectionToken);1541 }1542 },1543 CollectionMode::Fungible(_) => {1544 if let CreateItemData::Fungible(_) = data {1545 } else {1546 fail!(Error::<T>::NotFungibleDataUsedToMintFungibleCollectionToken);1547 }1548 },1549 CollectionMode::ReFungible(_) => {1550 if let CreateItemData::ReFungible(data) = data {15511552 1553 ensure!(ChainLimit::get().custom_data_limit >= data.const_data.len() as u32, Error::<T>::TokenConstDataLimitExceeded);1554 ensure!(ChainLimit::get().custom_data_limit >= data.variable_data.len() as u32, Error::<T>::TokenVariableDataLimitExceeded);1555 } else {1556 fail!(Error::<T>::NotReFungibleDataUsedToMintReFungibleCollectionToken);1557 }1558 },1559 _ => { fail!(Error::<T>::UnexpectedCollectionType); }1560 };15611562 Ok(())1563 }15641565 fn create_item_no_validation(collection_id: CollectionId, collection: &CollectionType<T::AccountId>, owner: T::AccountId, data: CreateItemData) -> DispatchResult {1566 match data1567 {1568 CreateItemData::NFT(data) => {1569 let item = NftItemType {1570 owner,1571 const_data: data.const_data,1572 variable_data: data.variable_data1573 };15741575 Self::add_nft_item(collection_id, item)?;1576 },1577 CreateItemData::Fungible(_) => {1578 let item = FungibleItemType {1579 owner,1580 value: (10 as u128).pow(collection.decimal_points as u32)1581 };15821583 Self::add_fungible_item(collection_id, item)?;1584 },1585 CreateItemData::ReFungible(data) => {1586 let mut owner_list = Vec::new();1587 let value = (10 as u128).pow(collection.decimal_points as u32);1588 owner_list.push(Ownership {owner: owner.clone(), fraction: value});15891590 let item = ReFungibleItemType {1591 owner: owner_list,1592 const_data: data.const_data,1593 variable_data: data.variable_data1594 };15951596 Self::add_refungible_item(collection_id, item)?;1597 }1598 };15991600 1601 Self::deposit_event(RawEvent::ItemCreated(collection_id, <ItemListIndex>::get(collection_id)));16021603 Ok(())1604 }16051606 fn add_fungible_item(collection_id: CollectionId, item: FungibleItemType<T::AccountId>) -> DispatchResult {1607 let current_index = <ItemListIndex>::get(collection_id)1608 .checked_add(1)1609 .ok_or(Error::<T>::NumOverflow)?;1610 let itemcopy = item.clone();1611 let owner = item.owner.clone();16121613 Self::add_token_index(collection_id, current_index, owner.clone())?;16141615 <ItemListIndex>::insert(collection_id, current_index);1616 <FungibleItemList<T>>::insert(collection_id, current_index, itemcopy);16171618 1619 let v: Vec<BasketItem<T::AccountId, T::BlockNumber>> = Vec::new();1620 <FungibleTransferBasket<T>>::insert(collection_id, current_index, v);1621 1622 1623 let new_balance = <Balance<T>>::get(collection_id, owner.clone())1624 .checked_add(item.value)1625 .ok_or(Error::<T>::NumOverflow)?;1626 <Balance<T>>::insert(collection_id, owner.clone(), new_balance);16271628 Ok(())1629 }16301631 fn add_refungible_item(collection_id: CollectionId, item: ReFungibleItemType<T::AccountId>) -> DispatchResult {1632 let current_index = <ItemListIndex>::get(collection_id)1633 .checked_add(1)1634 .ok_or(Error::<T>::NumOverflow)?;1635 let itemcopy = item.clone();16361637 let value = item.owner.first().unwrap().fraction;1638 let owner = item.owner.first().unwrap().owner.clone();16391640 Self::add_token_index(collection_id, current_index, owner.clone())?;16411642 <ItemListIndex>::insert(collection_id, current_index);1643 <ReFungibleItemList<T>>::insert(collection_id, current_index, itemcopy);16441645 1646 let block_number: T::BlockNumber = 0.into();1647 <ReFungibleTransferBasket<T>>::insert(collection_id, current_index, block_number);16481649 1650 let new_balance = <Balance<T>>::get(collection_id, owner.clone())1651 .checked_add(value)1652 .ok_or(Error::<T>::NumOverflow)?;1653 <Balance<T>>::insert(collection_id, owner.clone(), new_balance);16541655 Ok(())1656 }16571658 fn add_nft_item(collection_id: CollectionId, item: NftItemType<T::AccountId>) -> DispatchResult {1659 let current_index = <ItemListIndex>::get(collection_id)1660 .checked_add(1)1661 .ok_or(Error::<T>::NumOverflow)?;16621663 let item_owner = item.owner.clone();1664 Self::add_token_index(collection_id, current_index, item.owner.clone())?;16651666 <ItemListIndex>::insert(collection_id, current_index);1667 <NftItemList<T>>::insert(collection_id, current_index, item);16681669 1670 let block_number: T::BlockNumber = 0.into();1671 <NftTransferBasket<T>>::insert(collection_id, current_index, block_number);16721673 1674 let new_balance = <Balance<T>>::get(collection_id, item_owner.clone())1675 .checked_add(1)1676 .ok_or(Error::<T>::NumOverflow)?;1677 <Balance<T>>::insert(collection_id, item_owner.clone(), new_balance);16781679 Ok(())1680 }16811682 fn burn_refungible_item(1683 collection_id: CollectionId,1684 item_id: TokenId,1685 owner: T::AccountId,1686 ) -> DispatchResult {1687 ensure!(1688 <ReFungibleItemList<T>>::contains_key(collection_id, item_id),1689 Error::<T>::TokenNotFound1690 );1691 let collection = <ReFungibleItemList<T>>::get(collection_id, item_id);1692 let item = collection1693 .owner1694 .iter()1695 .filter(|&i| i.owner == owner)1696 .next()1697 .unwrap();1698 Self::remove_token_index(collection_id, item_id, owner.clone())?;16991700 1701 <ApprovedList<T>>::remove(collection_id, (item_id, owner.clone()));17021703 1704 let new_balance = <Balance<T>>::get(collection_id, item.owner.clone())1705 .checked_sub(item.fraction)1706 .ok_or(Error::<T>::NumOverflow)?;1707 <Balance<T>>::insert(collection_id, item.owner.clone(), new_balance);17081709 <ReFungibleItemList<T>>::remove(collection_id, item_id);17101711 Ok(())1712 }17131714 fn burn_nft_item(collection_id: CollectionId, item_id: TokenId) -> DispatchResult {1715 ensure!(1716 <NftItemList<T>>::contains_key(collection_id, item_id),1717 Error::<T>::TokenNotFound1718 );1719 let item = <NftItemList<T>>::get(collection_id, item_id);1720 Self::remove_token_index(collection_id, item_id, item.owner.clone())?;17211722 1723 <ApprovedList<T>>::remove(collection_id, (item_id, item.owner.clone()));17241725 1726 let new_balance = <Balance<T>>::get(collection_id, item.owner.clone())1727 .checked_sub(1)1728 .ok_or(Error::<T>::NumOverflow)?;1729 <Balance<T>>::insert(collection_id, item.owner.clone(), new_balance);1730 <NftItemList<T>>::remove(collection_id, item_id);17311732 Ok(())1733 }17341735 fn burn_fungible_item(collection_id: CollectionId, item_id: TokenId) -> DispatchResult {1736 ensure!(1737 <FungibleItemList<T>>::contains_key(collection_id, item_id),1738 Error::<T>::TokenNotFound1739 );1740 let item = <FungibleItemList<T>>::get(collection_id, item_id);1741 Self::remove_token_index(collection_id, item_id, item.owner.clone())?;17421743 1744 <ApprovedList<T>>::remove(collection_id, (item_id, item.owner.clone()));17451746 1747 let new_balance = <Balance<T>>::get(collection_id, item.owner.clone())1748 .checked_sub(item.value)1749 .ok_or(Error::<T>::NumOverflow)?;1750 <Balance<T>>::insert(collection_id, item.owner.clone(), new_balance);17511752 <FungibleItemList<T>>::remove(collection_id, item_id);17531754 Ok(())1755 }17561757 fn collection_exists(collection_id: CollectionId) -> DispatchResult {1758 ensure!(1759 <Collection<T>>::contains_key(collection_id),1760 Error::<T>::CollectionNotFound1761 );1762 Ok(())1763 }17641765 fn check_owner_permissions(collection_id: CollectionId, subject: T::AccountId) -> DispatchResult {1766 Self::collection_exists(collection_id)?;17671768 let target_collection = <Collection<T>>::get(collection_id);1769 ensure!(1770 subject == target_collection.owner,1771 Error::<T>::NoPermission1772 );17731774 Ok(())1775 }17761777 fn is_owner_or_admin_permissions(collection_id: CollectionId, subject: T::AccountId) -> bool {1778 let target_collection = <Collection<T>>::get(collection_id);1779 let mut result: bool = subject == target_collection.owner;1780 let exists = <AdminList<T>>::contains_key(collection_id);17811782 if !result & exists {1783 if <AdminList<T>>::get(collection_id).contains(&subject) {1784 result = true1785 }1786 }17871788 result1789 }17901791 fn check_owner_or_admin_permissions(1792 collection_id: CollectionId,1793 subject: T::AccountId,1794 ) -> DispatchResult {1795 Self::collection_exists(collection_id)?;1796 let result = Self::is_owner_or_admin_permissions(collection_id, subject.clone());17971798 ensure!(1799 result,1800 Error::<T>::NoPermission1801 );1802 Ok(())1803 }18041805 fn is_item_owner(subject: T::AccountId, collection_id: CollectionId, item_id: TokenId) -> bool {1806 let target_collection = <Collection<T>>::get(collection_id);18071808 match target_collection.mode {1809 CollectionMode::NFT => {1810 <NftItemList<T>>::get(collection_id, item_id).owner == subject1811 }1812 CollectionMode::Fungible(_) => {1813 <FungibleItemList<T>>::get(collection_id, item_id).owner == subject1814 }1815 CollectionMode::ReFungible(_) => {1816 <ReFungibleItemList<T>>::get(collection_id, item_id)1817 .owner1818 .iter()1819 .any(|i| i.owner == subject)1820 }1821 CollectionMode::Invalid => false,1822 }1823 }18241825 fn check_white_list(collection_id: CollectionId, address: &T::AccountId) -> DispatchResult {1826 let mes = Error::<T>::AddresNotInWhiteList;1827 ensure!(<WhiteList<T>>::contains_key(collection_id), mes);1828 let wl = <WhiteList<T>>::get(collection_id);1829 ensure!(wl.contains(address), mes);18301831 Ok(())1832 }18331834 fn transfer_fungible(1835 collection_id: CollectionId,1836 item_id: TokenId,1837 value: u128,1838 owner: T::AccountId,1839 new_owner: T::AccountId,1840 ) -> DispatchResult {1841 ensure!(1842 <FungibleItemList<T>>::contains_key(collection_id, item_id),1843 Error::<T>::TokenNotFound1844 );18451846 let full_item = <FungibleItemList<T>>::get(collection_id, item_id);1847 let amount = full_item.value;18481849 ensure!(amount >= value, Error::<T>::TokenValueTooLow);18501851 1852 let balance_old_owner = <Balance<T>>::get(collection_id, owner.clone())1853 .checked_sub(value)1854 .ok_or(Error::<T>::NumOverflow)?;1855 <Balance<T>>::insert(collection_id, owner.clone(), balance_old_owner);18561857 let mut new_owner_account_id = 0;1858 let new_owner_items = <AddressTokens<T>>::get(collection_id, new_owner.clone());1859 if new_owner_items.len() > 0 {1860 new_owner_account_id = new_owner_items[0];1861 }18621863 1864 if amount == value && new_owner_account_id == 0 {1865 1866 1867 let mut new_full_item = full_item.clone();1868 new_full_item.owner = new_owner.clone();1869 <FungibleItemList<T>>::insert(collection_id, item_id, new_full_item);18701871 1872 let balancenew_owner = <Balance<T>>::get(collection_id, new_owner.clone())1873 .checked_add(value)1874 .ok_or(Error::<T>::NumOverflow)?;1875 <Balance<T>>::insert(collection_id, new_owner.clone(), balancenew_owner);18761877 1878 Self::move_token_index(collection_id, item_id, owner.clone(), new_owner.clone())?;1879 } else {1880 let mut new_full_item = full_item.clone();1881 new_full_item.value -= value;18821883 1884 if new_owner_account_id > 0 {1885 1886 let mut item = <FungibleItemList<T>>::get(collection_id, new_owner_account_id);1887 item.value += value;18881889 1890 let balancenew_owner = <Balance<T>>::get(collection_id, new_owner.clone())1891 .checked_add(value)1892 .ok_or(Error::<T>::NumOverflow)?;1893 <Balance<T>>::insert(collection_id, new_owner.clone(), balancenew_owner);18941895 <FungibleItemList<T>>::insert(collection_id, new_owner_account_id, item);1896 } else {1897 1898 let item = FungibleItemType {1899 owner: new_owner.clone(),1900 value1901 };19021903 Self::add_fungible_item(collection_id, item)?;1904 }19051906 if amount == value {1907 Self::remove_token_index(collection_id, item_id, full_item.owner.clone())?;19081909 1910 <ApprovedList<T>>::remove(collection_id, (item_id, full_item.owner.clone()));1911 <FungibleItemList<T>>::remove(collection_id, item_id);1912 }19131914 <FungibleItemList<T>>::insert(collection_id, item_id, new_full_item);1915 }19161917 Ok(())1918 }19191920 fn transfer_refungible(1921 collection_id: CollectionId,1922 item_id: TokenId,1923 value: u128,1924 owner: T::AccountId,1925 new_owner: T::AccountId,1926 ) -> DispatchResult {1927 ensure!(1928 <ReFungibleItemList<T>>::contains_key(collection_id, item_id),1929 Error::<T>::TokenNotFound1930 );19311932 let full_item = <ReFungibleItemList<T>>::get(collection_id, item_id);1933 let item = full_item1934 .owner1935 .iter()1936 .filter(|i| i.owner == owner)1937 .next()1938 .ok_or(Error::<T>::NumOverflow)?;1939 let amount = item.fraction;19401941 ensure!(amount >= value, Error::<T>::TokenValueTooLow);19421943 1944 let balance_old_owner = <Balance<T>>::get(collection_id, item.owner.clone())1945 .checked_sub(value)1946 .ok_or(Error::<T>::NumOverflow)?;1947 <Balance<T>>::insert(collection_id, item.owner.clone(), balance_old_owner);19481949 let balancenew_owner = <Balance<T>>::get(collection_id, new_owner.clone())1950 .checked_add(value)1951 .ok_or(Error::<T>::NumOverflow)?;1952 <Balance<T>>::insert(collection_id, new_owner.clone(), balancenew_owner);19531954 let old_owner = item.owner.clone();1955 let new_owner_has_account = full_item.owner.iter().any(|i| i.owner == new_owner);19561957 1958 if amount == value && !new_owner_has_account {1959 1960 1961 let mut new_full_item = full_item.clone();1962 new_full_item1963 .owner1964 .iter_mut()1965 .find(|i| i.owner == owner)1966 .unwrap()1967 .owner = new_owner.clone();1968 <ReFungibleItemList<T>>::insert(collection_id, item_id, new_full_item);19691970 1971 Self::move_token_index(collection_id, item_id, old_owner.clone(), new_owner.clone())?;1972 } else {1973 let mut new_full_item = full_item.clone();1974 new_full_item1975 .owner1976 .iter_mut()1977 .find(|i| i.owner == owner)1978 .unwrap()1979 .fraction -= value;19801981 1982 if new_owner_has_account {1983 1984 new_full_item1985 .owner1986 .iter_mut()1987 .find(|i| i.owner == new_owner)1988 .unwrap()1989 .fraction += value;1990 } else {1991 1992 new_full_item.owner.push(Ownership {1993 owner: new_owner.clone(),1994 fraction: value,1995 });1996 Self::add_token_index(collection_id, item_id, new_owner.clone())?;1997 }19981999 <ReFungibleItemList<T>>::insert(collection_id, item_id, new_full_item);2000 }20012002 Ok(())2003 }20042005 fn transfer_nft(2006 collection_id: CollectionId,2007 item_id: TokenId,2008 sender: T::AccountId,2009 new_owner: T::AccountId,2010 ) -> DispatchResult {2011 ensure!(2012 <NftItemList<T>>::contains_key(collection_id, item_id),2013 Error::<T>::TokenNotFound2014 );20152016 let mut item = <NftItemList<T>>::get(collection_id, item_id);20172018 ensure!(2019 sender == item.owner,2020 Error::<T>::MustBeTokenOwner2021 );20222023 2024 let balance_old_owner = <Balance<T>>::get(collection_id, item.owner.clone())2025 .checked_sub(1)2026 .ok_or(Error::<T>::NumOverflow)?;2027 <Balance<T>>::insert(collection_id, item.owner.clone(), balance_old_owner);20282029 let balancenew_owner = <Balance<T>>::get(collection_id, new_owner.clone())2030 .checked_add(1)2031 .ok_or(Error::<T>::NumOverflow)?;2032 <Balance<T>>::insert(collection_id, new_owner.clone(), balancenew_owner);20332034 2035 let old_owner = item.owner.clone();2036 item.owner = new_owner.clone();2037 <NftItemList<T>>::insert(collection_id, item_id, item);20382039 2040 Self::move_token_index(collection_id, item_id, old_owner.clone(), new_owner.clone())?;20412042 2043 <ApprovedList<T>>::remove(collection_id, (item_id, old_owner));2044 Ok(())2045 }2046 2047 fn item_exists(2048 collection_id: CollectionId,2049 item_id: TokenId,2050 mode: &CollectionMode2051 ) -> DispatchResult {2052 match mode {2053 CollectionMode::NFT => ensure!(<NftItemList<T>>::contains_key(collection_id, item_id), Error::<T>::TokenNotFound),2054 CollectionMode::ReFungible(_) => ensure!(<ReFungibleItemList<T>>::contains_key(collection_id, item_id), Error::<T>::TokenNotFound),2055 CollectionMode::Fungible(_) => ensure!(<FungibleItemList<T>>::contains_key(collection_id, item_id), Error::<T>::TokenNotFound),2056 _ => ()2057 };2058 2059 Ok(())2060 }20612062 fn set_re_fungible_variable_data(2063 collection_id: CollectionId,2064 item_id: TokenId,2065 data: Vec<u8>2066 ) -> DispatchResult {2067 let mut item = <ReFungibleItemList<T>>::get(collection_id, item_id);20682069 item.variable_data = data;20702071 <ReFungibleItemList<T>>::insert(collection_id, item_id, item);20722073 Ok(())2074 }20752076 fn set_nft_variable_data(2077 collection_id: CollectionId,2078 item_id: TokenId,2079 data: Vec<u8>2080 ) -> DispatchResult {2081 let mut item = <NftItemList<T>>::get(collection_id, item_id);2082 2083 item.variable_data = data;20842085 <NftItemList<T>>::insert(collection_id, item_id, item);2086 2087 Ok(())2088 }20892090 fn init_collection(item: &CollectionType<T::AccountId>) {2091 2092 assert!(2093 item.decimal_points <= MAX_DECIMAL_POINTS,2094 "decimal_points parameter must be lower than MAX_DECIMAL_POINTS"2095 );2096 assert!(2097 item.name.len() <= 64,2098 "Collection name can not be longer than 63 char"2099 );2100 assert!(2101 item.name.len() <= 256,2102 "Collection description can not be longer than 255 char"2103 );2104 assert!(2105 item.token_prefix.len() <= 16,2106 "Token prefix can not be longer than 15 char"2107 );21082109 2110 let next_id = CreatedCollectionCount::get()2111 .checked_add(1)2112 .unwrap();21132114 CreatedCollectionCount::put(next_id);2115 }21162117 fn init_nft_token(collection_id: CollectionId, item: &NftItemType<T::AccountId>) {2118 let current_index = <ItemListIndex>::get(collection_id)2119 .checked_add(1)2120 .unwrap();21212122 let item_owner = item.owner.clone();2123 Self::add_token_index(collection_id, current_index, item.owner.clone()).unwrap();21242125 <ItemListIndex>::insert(collection_id, current_index);21262127 2128 let new_balance = <Balance<T>>::get(collection_id, item_owner.clone())2129 .checked_add(1)2130 .unwrap();2131 <Balance<T>>::insert(collection_id, item_owner.clone(), new_balance);2132 }21332134 fn init_fungible_token(collection_id: CollectionId, item: &FungibleItemType<T::AccountId>) {2135 let current_index = <ItemListIndex>::get(collection_id)2136 .checked_add(1)2137 .unwrap();2138 let owner = item.owner.clone();21392140 Self::add_token_index(collection_id, current_index, owner.clone()).unwrap();21412142 <ItemListIndex>::insert(collection_id, current_index);21432144 2145 let new_balance = <Balance<T>>::get(collection_id, owner.clone())2146 .checked_add(item.value)2147 .unwrap();2148 <Balance<T>>::insert(collection_id, owner.clone(), new_balance);2149 }21502151 fn init_refungible_token(collection_id: CollectionId, item: &ReFungibleItemType<T::AccountId>) {2152 let current_index = <ItemListIndex>::get(collection_id)2153 .checked_add(1)2154 .unwrap();21552156 let value = item.owner.first().unwrap().fraction;2157 let owner = item.owner.first().unwrap().owner.clone();21582159 Self::add_token_index(collection_id, current_index, owner.clone()).unwrap();21602161 <ItemListIndex>::insert(collection_id, current_index);21622163 2164 let new_balance = <Balance<T>>::get(collection_id, owner.clone())2165 .checked_add(value)2166 .unwrap();2167 <Balance<T>>::insert(collection_id, owner.clone(), new_balance);2168 }21692170 fn add_token_index(collection_id: CollectionId, item_index: TokenId, owner: T::AccountId) -> DispatchResult {21712172 2173 if <AccountItemCount<T>>::contains_key(owner.clone()) {21742175 2176 let count = <AccountItemCount<T>>::get(owner.clone());2177 ensure!(count < ChainLimit::get().account_token_ownership_limit, Error::<T>::AddressOwnershipLimitExceeded);21782179 <AccountItemCount<T>>::insert(owner.clone(), count2180 .checked_add(1)2181 .ok_or(Error::<T>::NumOverflow)?);2182 }2183 else {2184 <AccountItemCount<T>>::insert(owner.clone(), 1);2185 }21862187 let list_exists = <AddressTokens<T>>::contains_key(collection_id, owner.clone());2188 if list_exists {2189 let mut list = <AddressTokens<T>>::get(collection_id, owner.clone());2190 let item_contains = list.contains(&item_index.clone());21912192 if !item_contains {2193 list.push(item_index.clone());2194 }21952196 <AddressTokens<T>>::insert(collection_id, owner.clone(), list);2197 } else {2198 let mut itm = Vec::new();2199 itm.push(item_index.clone());2200 <AddressTokens<T>>::insert(collection_id, owner, itm);2201 2202 }22032204 Ok(())2205 }22062207 fn remove_token_index(2208 collection_id: CollectionId,2209 item_index: TokenId,2210 owner: T::AccountId,2211 ) -> DispatchResult {22122213 2214 <AccountItemCount<T>>::insert(owner.clone(), 2215 <AccountItemCount<T>>::get(owner.clone())2216 .checked_sub(1)2217 .ok_or(Error::<T>::NumOverflow)?);221822192220 let list_exists = <AddressTokens<T>>::contains_key(collection_id, owner.clone());2221 if list_exists {2222 let mut list = <AddressTokens<T>>::get(collection_id, owner.clone());2223 let item_contains = list.contains(&item_index.clone());22242225 if item_contains {2226 list.retain(|&item| item != item_index);2227 <AddressTokens<T>>::insert(collection_id, owner, list);2228 }2229 }22302231 Ok(())2232 }22332234 fn move_token_index(2235 collection_id: CollectionId,2236 item_index: TokenId,2237 old_owner: T::AccountId,2238 new_owner: T::AccountId,2239 ) -> DispatchResult {2240 Self::remove_token_index(collection_id, item_index, old_owner)?;2241 Self::add_token_index(collection_id, item_index, new_owner)?;22422243 Ok(())2244 }2245}2246224722482249225022512252pub type Multiplier = FixedU128;22532254type BalanceOf<T> = <<T as transaction_payment::Trait>::Currency as Currency<2255 <T as system::Trait>::AccountId,2256>>::Balance;2257type NegativeImbalanceOf<T> = <<T as transaction_payment::Trait>::Currency as Currency<2258 <T as system::Trait>::AccountId,2259>>::NegativeImbalance;2260226122622263#[derive(Encode, Decode, Clone, Eq, PartialEq)]2264pub struct ChargeTransactionPayment<T: Trait + Send + Sync>(2265 #[codec(compact)] BalanceOf<T>2266);22672268impl<T: Trait + Send + Sync> sp_std::fmt::Debug2269 for ChargeTransactionPayment<T>2270{2271 #[cfg(feature = "std")]2272 fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {2273 write!(f, "ChargeTransactionPayment<{:?}>", self.0)2274 }2275 #[cfg(not(feature = "std"))]2276 fn fmt(&self, _: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {2277 Ok(())2278 }2279}22802281impl<T: Trait + Send + Sync> ChargeTransactionPayment<T>2282where2283 T::Call: Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo> + IsSubType<Call<T>> + IsSubType<pallet_contracts::Call<T>>,2284 BalanceOf<T>: Send + Sync + FixedPointOperand,2285{2286 2287 pub fn from(fee: BalanceOf<T>) -> Self {2288 Self(fee)2289 }22902291 pub fn traditional_fee(2292 len: usize,2293 info: &DispatchInfoOf<T::Call>,2294 tip: BalanceOf<T>,2295 ) -> BalanceOf<T>2296 where2297 T::Call: Dispatchable<Info = DispatchInfo>,2298 {2299 <transaction_payment::Module<T>>::compute_fee(len as u32, info, tip)2300 }23012302 fn get_priority(len: usize, info: &DispatchInfoOf<T::Call>, final_fee: BalanceOf<T>) -> TransactionPriority {2303 let weight_saturation = T::MaximumBlockWeight::get() / info.weight.max(1);2304 let len_saturation = T::MaximumBlockLength::get() as u64 / (len as u64).max(1);2305 let coefficient: BalanceOf<T> = weight_saturation.min(len_saturation).saturated_into::<BalanceOf<T>>();2306 final_fee.saturating_mul(coefficient).saturated_into::<TransactionPriority>()2307 }23082309 fn withdraw_fee(2310 &self,2311 who: &T::AccountId,2312 call: &T::Call,2313 info: &DispatchInfoOf<T::Call>,2314 len: usize,2315 ) -> Result<(BalanceOf<T>, Option<NegativeImbalanceOf<T>>), TransactionValidityError> {2316 let tip = self.0;23172318 2319 2320 2321 2322 2323 2324 2325 let fee = Self::traditional_fee(len, info, tip);23262327 2328 if fee.is_zero() {2329 return Ok((fee, None));2330 }23312332 2333 2334 let mut sponsor: T::AccountId = match IsSubType::<Call<T>>::is_sub_type(call) {2335 Some(Call::create_item(collection_id, _owner, _properties)) => {23362337 2338 if (<Collection<T>>::get(collection_id).limits.sponsored_data_size >= (_properties.len() as u32)) &&2339 (<Collection<T>>::get(collection_id).sponsor_confirmed)2340 {2341 <Collection<T>>::get(collection_id).sponsor2342 } else {2343 T::AccountId::default()2344 }2345 }2346 Some(Call::transfer(new_owner, collection_id, item_id, _value)) => {2347 2348 let mut sponsor_transfer = false;2349 if <Collection<T>>::get(collection_id).sponsor_confirmed {23502351 let collection_limits = <Collection<T>>::get(collection_id).limits;2352 let collection_mode = <Collection<T>>::get(collection_id).mode;2353 2354 2355 sponsor_transfer = match collection_mode {2356 CollectionMode::NFT => {2357 2358 2359 let limit: u32 = if collection_limits.sponsor_transfer_timeout > 0 {2360 collection_limits.sponsor_transfer_timeout2361 } else {2362 ChainLimit::get().nft_sponsor_transfer_timeout2363 };2364 2365 let basket = <NftTransferBasket<T>>::get(collection_id, item_id);2366 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;2367 let limit_time = basket + limit.into();2368 if block_number >= limit_time {2369 <NftTransferBasket<T>>::insert(collection_id, item_id, block_number);2370 true2371 }2372 else {2373 false2374 }2375 }2376 CollectionMode::Fungible(_) => {2377 2378 2379 let limit: u32 = if collection_limits.sponsor_transfer_timeout > 0 {2380 collection_limits.sponsor_transfer_timeout2381 } else {2382 ChainLimit::get().fungible_sponsor_transfer_timeout2383 };2384 2385 let mut basket = <FungibleTransferBasket<T>>::get(collection_id, item_id);2386 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;2387 if basket.iter().any(|i| i.address == new_owner.clone())2388 {2389 let item = basket.iter_mut().find(|i| i.address == new_owner.clone()).unwrap().clone();2390 let limit_time = item.start_block + limit.into();2391 if block_number >= limit_time {2392 basket.retain(|x| x.address == item.address);2393 basket.push(BasketItem { start_block: block_number, address: new_owner.clone() });2394 <FungibleTransferBasket<T>>::insert(collection_id, item_id, basket);2395 true2396 }2397 else {2398 false2399 }2400 }2401 else {2402 basket.push(BasketItem { start_block: block_number, address: new_owner.clone()});2403 true2404 }2405 }2406 CollectionMode::ReFungible(_) => {2407 2408 2409 let limit: u32 = if collection_limits.sponsor_transfer_timeout > 0 {2410 collection_limits.sponsor_transfer_timeout2411 } else {2412 ChainLimit::get().refungible_sponsor_transfer_timeout2413 };2414 2415 let basket = <ReFungibleTransferBasket<T>>::get(collection_id, item_id);2416 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;2417 let limit_time = basket + limit.into();2418 if block_number >= limit_time {2419 <ReFungibleTransferBasket<T>>::insert(collection_id, item_id, block_number);2420 true2421 } else {2422 false2423 }2424 }2425 _ => {2426 false2427 },2428 };2429 }24302431 if !sponsor_transfer {2432 T::AccountId::default()2433 } else {2434 <Collection<T>>::get(collection_id).sponsor2435 }2436 }24372438 _ => T::AccountId::default(),2439 };24402441 2442 sponsor = match IsSubType::<pallet_contracts::Call<T>>::is_sub_type(call) {24432444 2445 Some(pallet_contracts::Call::instantiate(_endowment, _gas_limit, code_hash, data)) => {24462447 let new_contract_address = <T as pallet_contracts::Trait>::DetermineContractAddress::contract_address_for(2448 code_hash,2449 &data,2450 &who,2451 );2452 <ContractOwner<T>>::insert(new_contract_address.clone(), who.clone());24532454 T::AccountId::default()2455 },24562457 2458 Some(pallet_contracts::Call::call(dest, _value, _gas_limit, _data)) => {24592460 let called_contract: T::AccountId = T::Lookup::lookup((*dest).clone()).unwrap_or(T::AccountId::default());24612462 let mut sponsor_transfer = false;2463 if <ContractSponsoringRateLimit<T>>::contains_key(called_contract.clone()) {2464 let last_tx_block = <ContractSponsorBasket<T>>::get((&called_contract, &who));2465 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;2466 let rate_limit = <ContractSponsoringRateLimit<T>>::get(&called_contract);2467 let limit_time = last_tx_block + rate_limit;24682469 if block_number >= limit_time {2470 <ContractSponsorBasket<T>>::insert((called_contract.clone(), who.clone()), block_number);2471 sponsor_transfer = true;2472 }2473 } else {2474 sponsor_transfer = false;2475 }2476 2477 2478 let mut sp = T::AccountId::default();2479 if sponsor_transfer {2480 if <ContractSelfSponsoring<T>>::contains_key(called_contract.clone()) {2481 if <ContractSelfSponsoring<T>>::get(called_contract.clone()) {2482 sp = called_contract;2483 }2484 }2485 }24862487 sp2488 },24892490 _ => sponsor,2491 };24922493 let mut who_pays_fee: T::AccountId = sponsor.clone();2494 if sponsor == T::AccountId::default() {2495 who_pays_fee = who.clone();2496 }24972498 match <T as transaction_payment::Trait>::Currency::withdraw(2499 &who_pays_fee,2500 fee,2501 if tip.is_zero() {2502 WithdrawReason::TransactionPayment.into()2503 } else {2504 WithdrawReason::TransactionPayment | WithdrawReason::Tip2505 },2506 ExistenceRequirement::KeepAlive,2507 ) {2508 Ok(imbalance) => Ok((fee, Some(imbalance))),2509 Err(_) => Err(InvalidTransaction::Payment.into()),2510 }2511 }2512}251325142515impl<T: Trait + Send + Sync> SignedExtension2516 for ChargeTransactionPayment<T>2517where2518 BalanceOf<T>: Send + Sync + From<u64> + FixedPointOperand,2519 T::Call: Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo> + IsSubType<Call<T>> + IsSubType<pallet_contracts::Call<T>>,2520{2521 const IDENTIFIER: &'static str = "ChargeTransactionPayment";2522 type AccountId = T::AccountId;2523 type Call = T::Call;2524 type AdditionalSigned = ();2525 type Pre = (2526 BalanceOf<T>,2527 Self::AccountId,2528 Option<NegativeImbalanceOf<T>>,2529 BalanceOf<T>,2530 );2531 fn additional_signed(&self) -> sp_std::result::Result<(), TransactionValidityError> {2532 Ok(())2533 }25342535 fn validate(2536 &self,2537 who: &Self::AccountId,2538 call: &Self::Call,2539 info: &DispatchInfoOf<Self::Call>,2540 len: usize,2541 ) -> TransactionValidity {2542 let (fee, _) = self.withdraw_fee(who, call, info, len)?;2543 Ok(ValidTransaction {2544 priority: Self::get_priority(len, info, fee),2545 ..Default::default()2546 })2547 }25482549 fn pre_dispatch(2550 self,2551 who: &Self::AccountId,2552 call: &Self::Call,2553 info: &DispatchInfoOf<Self::Call>,2554 len: usize,2555 ) -> Result<Self::Pre, TransactionValidityError> {2556 let (fee, imbalance) = self.withdraw_fee(who, call, info, len)?;2557 Ok((self.0, who.clone(), imbalance, fee))2558 }25592560 fn post_dispatch(2561 pre: Self::Pre,2562 info: &DispatchInfoOf<Self::Call>,2563 post_info: &PostDispatchInfoOf<Self::Call>,2564 len: usize,2565 _result: &DispatchResult,2566 ) -> Result<(), TransactionValidityError> {2567 let (tip, who, imbalance, fee) = pre;2568 if let Some(payed) = imbalance {2569 let actual_fee = <transaction_payment::Module<T>>::compute_actual_fee(2570 len as u32, info, post_info, tip,2571 );2572 let refund = fee.saturating_sub(actual_fee);2573 let actual_payment =2574 match <T as transaction_payment::Trait>::Currency::deposit_into_existing(2575 &who, refund,2576 ) {2577 Ok(refund_imbalance) => {2578 2579 2580 match payed.offset(refund_imbalance) {2581 Ok(actual_payment) => actual_payment,2582 Err(_) => return Err(InvalidTransaction::Payment.into()),2583 }2584 }2585 2586 2587 Err(_) => payed,2588 };2589 let imbalances = actual_payment.split(tip);2590 <T as transaction_payment::Trait>::OnTransactionPayment::on_unbalanceds(2591 Some(imbalances.0).into_iter().chain(Some(imbalances.1)),2592 );2593 }2594 Ok(())2595 }2596}25972598