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, decl_error,12 dispatch::DispatchResult,13 ensure, fail, parameter_types,14 traits::{15 Currency, ExistenceRequirement, Get, Imbalance, KeyOwnerProofSystem, OnUnbalanced,16 Randomness, WithdrawReason,17 },18 weights::{19 constants::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_PER_SECOND},20 DispatchInfo, GetDispatchInfo, IdentityFee, Pays, PostDispatchInfo, Weight,21 WeightToFeePolynomial,22 },23 IsSubType, StorageValue,24};2526use frame_system::{self as system, ensure_signed, ensure_root};27use sp_runtime::sp_std::prelude::Vec;28use sp_runtime::{29 traits::{30 DispatchInfoOf, Dispatchable, PostDispatchInfoOf, Saturating, SignedExtension, Zero,31 },32 transaction_validity::{33 InvalidTransaction, TransactionValidity, TransactionValidityError, ValidTransaction,34 },35 FixedPointOperand, FixedU128,36};37use pallet_contracts::ContractAddressFor;38use sp_runtime::traits::StaticLookup;3940#[cfg(test)]41mod mock;4243#[cfg(test)]44mod tests;4546mod default_weights;4748pub const MAX_DECIMAL_POINTS: DecimalPoints = 30;49pub const MAX_SPONSOR_TIMEOUT: u32 = 10_368_000;50pub const MAX_TOKEN_OWNERSHIP: u32 = 10_000_000;5152535455pub type CollectionId = u32;56pub type TokenId = u32;5758pub type DecimalPoints = u8;5960#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq)]61#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]62pub enum CollectionMode {63 Invalid,64 NFT,65 66 Fungible(DecimalPoints),67 68 ReFungible(DecimalPoints),69}7071impl Into<u8> for CollectionMode {72 fn into(self) -> u8 {73 match self {74 CollectionMode::Invalid => 0,75 CollectionMode::NFT => 1,76 CollectionMode::Fungible(_) => 2,77 CollectionMode::ReFungible(_) => 3,78 }79 }80}8182#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq)]83#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]84pub enum AccessMode {85 Normal,86 WhiteList,87}88impl Default for AccessMode {89 fn default() -> Self {90 Self::Normal91 }92}9394impl Default for CollectionMode {95 fn default() -> Self {96 Self::Invalid97 }98}99100#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]101#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]102pub struct Ownership<AccountId> {103 pub owner: AccountId,104 pub fraction: u128,105}106107#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]108#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]109pub struct CollectionType<AccountId> {110 pub owner: AccountId,111 pub mode: CollectionMode,112 pub access: AccessMode,113 pub decimal_points: DecimalPoints,114 pub name: Vec<u16>, 115 pub description: Vec<u16>, 116 pub token_prefix: Vec<u8>, 117 pub mint_mode: bool,118 pub offchain_schema: Vec<u8>,119 pub sponsor: AccountId, 120 pub unconfirmed_sponsor: AccountId, 121 pub limits: CollectionLimits, 122 pub variable_on_chain_schema: Vec<u8>, 123 pub const_on_chain_schema: Vec<u8>, 124}125126#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]127#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]128pub struct NftItemType<AccountId> {129 pub collection: CollectionId,130 pub owner: AccountId,131 pub const_data: Vec<u8>,132 pub variable_data: Vec<u8>,133}134135#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]136#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]137pub struct FungibleItemType<AccountId> {138 pub collection: CollectionId,139 pub owner: AccountId,140 pub value: u128,141}142143#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]144#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]145pub struct ReFungibleItemType<AccountId> {146 pub collection: CollectionId,147 pub owner: Vec<Ownership<AccountId>>,148 pub const_data: Vec<u8>,149 pub variable_data: Vec<u8>,150}151152#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]153#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]154pub struct ApprovePermissions<AccountId> {155 pub approved: AccountId,156 pub amount: u128,157}158159#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]160#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]161pub struct VestingItem<AccountId, Moment> {162 pub sender: AccountId,163 pub recipient: AccountId,164 pub collection_id: CollectionId,165 pub item_id: TokenId,166 pub amount: u64,167 pub vesting_date: Moment,168}169170#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]171#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]172pub struct BasketItem<AccountId, BlockNumber> {173 pub address: AccountId,174 pub start_block: BlockNumber,175}176177#[derive(Encode, Decode, Debug, Clone, PartialEq)]178#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]179pub struct CollectionLimits {180 pub account_token_ownership_limit: u32,181 pub sponsored_data_size: u32,182 pub token_limit: u32,183184 185 pub sponsor_transfer_timeout: u32,186}187188impl Default for CollectionLimits {189 fn default() -> CollectionLimits {190 CollectionLimits { 191 account_token_ownership_limit: 10_000_000, 192 token_limit: u32::max_value(),193 sponsored_data_size: u32::max_value(), 194 sponsor_transfer_timeout: 14400 }195 }196}197198#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]199#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]200pub struct ChainLimits {201 pub collection_numbers_limit: u32,202 pub account_token_ownership_limit: u32,203 pub collections_admins_limit: u64,204 pub custom_data_limit: u32,205206 207 pub nft_sponsor_transfer_timeout: u32,208 pub fungible_sponsor_transfer_timeout: u32,209 pub refungible_sponsor_transfer_timeout: u32,210}211212pub trait WeightInfo {213 fn create_collection() -> Weight;214 fn destroy_collection() -> Weight;215 fn add_to_white_list() -> Weight;216 fn remove_from_white_list() -> Weight;217 fn set_public_access_mode() -> Weight;218 fn set_mint_permission() -> Weight;219 fn change_collection_owner() -> Weight;220 fn add_collection_admin() -> Weight;221 fn remove_collection_admin() -> Weight;222 fn set_collection_sponsor() -> Weight;223 fn confirm_sponsorship() -> Weight;224 fn remove_collection_sponsor() -> Weight;225 fn create_item(s: usize) -> Weight;226 fn burn_item() -> Weight;227 fn transfer() -> Weight;228 fn approve() -> Weight;229 fn transfer_from() -> Weight;230 fn set_offchain_schema() -> Weight;231 fn set_const_on_chain_schema() -> Weight;232 fn set_variable_on_chain_schema() -> Weight;233 fn set_variable_meta_data() -> Weight;234 fn enable_contract_sponsoring() -> Weight;235}236237#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]238#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]239pub struct CreateNftData {240 pub const_data: Vec<u8>,241 pub variable_data: Vec<u8>,242}243244#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]245#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]246pub struct CreateFungibleData {247}248249#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]250#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]251pub struct CreateReFungibleData {252 pub const_data: Vec<u8>,253 pub variable_data: Vec<u8>,254}255256#[derive(Encode, Decode, Debug, Clone, PartialEq)]257#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]258pub enum CreateItemData {259 NFT(CreateNftData),260 Fungible(CreateFungibleData),261 ReFungible(CreateReFungibleData)262}263264impl CreateItemData {265 pub fn len(&self) -> usize {266 let len = match self {267 CreateItemData::NFT(data) => data.variable_data.len() + data.const_data.len(),268 CreateItemData::ReFungible(data) => data.variable_data.len() + data.const_data.len(),269 _ => 0270 };271 272 return len;273 }274}275276impl From<CreateNftData> for CreateItemData {277 fn from(item: CreateNftData) -> Self {278 CreateItemData::NFT(item)279 }280}281282impl From<CreateReFungibleData> for CreateItemData {283 fn from(item: CreateReFungibleData) -> Self {284 CreateItemData::ReFungible(item)285 }286}287288impl From<CreateFungibleData> for CreateItemData {289 fn from(item: CreateFungibleData) -> Self {290 CreateItemData::Fungible(item)291 }292}293294295decl_error! {296 297 pub enum Error for Module<T: Trait> {298 299 TotalCollectionsLimitExceeded,300 301 CollectionDecimalPointLimitExceeded, 302 303 CollectionNameLimitExceeded, 304 305 CollectionDescriptionLimitExceeded, 306 307 CollectionTokenPrefixLimitExceeded,308 309 CollectionNotFound,310 311 TokenNotFound,312 313 NumOverflow, 314 315 AlreadyAdmin, 316 317 NoPermission,318 319 ConfirmUnsetSponsorFail,320 321 PublicMintingNotAllowed,322 323 MustBeTokenOwner,324 325 TokenValueTooLow,326 327 NftSizeLimitExceeded,328 329 ApproveNotFound,330 331 TokenValueNotEnough,332 333 ApproveRequired,334 335 AddresNotInWhiteList,336 337 CollectionAdminsLimitExceeded,338 339 AddressOwnershipLimitExceeded,340 341 EmptyArgument,342 343 TokenConstDataLimitExceeded,344 345 TokenVariableDataLimitExceeded,346 347 NotNftDataUsedToMintNftCollectionToken,348 349 NotFungibleDataUsedToMintFungibleCollectionToken,350 351 NotReFungibleDataUsedToMintReFungibleCollectionToken,352 353 UnexpectedCollectionType,354 355 CantStoreMetadataInFungibleTokens,356 357 CollectionTokenLimitExceeded,358 359 AccountTokenLimitExceeded,360 361 CollectionLimitBoundsExceeded362 }363}364365pub trait Trait: system::Trait + Sized + transaction_payment::Trait + pallet_contracts::Trait {366 type Event: From<Event<Self>> + Into<<Self as system::Trait>::Event>;367368 369 type WeightInfo: WeightInfo;370}371372#[cfg(feature = "runtime-benchmarks")]373mod benchmarking;374375376377decl_storage! {378 trait Store for Module<T: Trait> as Nft {379380 381 NextCollectionID: CollectionId;382 CreatedCollectionCount: u32;383 ChainVersion: u64;384 ItemListIndex: map hasher(identity) CollectionId => TokenId;385386 387 pub ChainLimit get(fn chain_limit) config(): ChainLimits;388389 390 CollectionCount: u32;391 pub AccountItemCount get(fn account_item_count): map hasher(twox_64_concat) T::AccountId => u32;392393 394 pub Collection get(fn collection) config(): map hasher(identity) CollectionId => CollectionType<T::AccountId>;395 pub AdminList get(fn admin_list_collection): map hasher(identity) CollectionId => Vec<T::AccountId>;396 pub WhiteList get(fn white_list): map hasher(identity) CollectionId => Vec<T::AccountId>;397398 399 pub Balance get(fn balance_count): double_map hasher(identity) CollectionId, hasher(twox_64_concat) T::AccountId => u128;400401 402 pub ApprovedList get(fn approved): double_map hasher(identity) CollectionId, hasher(twox_64_concat) (TokenId, T::AccountId) => Vec<ApprovePermissions<T::AccountId>>;403404 405 pub NftItemList get(fn nft_item_id) config(): double_map hasher(identity) CollectionId, hasher(identity) TokenId => NftItemType<T::AccountId>;406 pub FungibleItemList get(fn fungible_item_id) config(): double_map hasher(identity) CollectionId, hasher(identity) TokenId => FungibleItemType<T::AccountId>;407 pub ReFungibleItemList get(fn refungible_item_id) config(): double_map hasher(identity) CollectionId, hasher(identity) TokenId => ReFungibleItemType<T::AccountId>;408409 410 pub AddressTokens get(fn address_tokens): double_map hasher(identity) CollectionId, hasher(twox_64_concat) T::AccountId => Vec<TokenId>;411412 413 pub NftTransferBasket get(fn nft_transfer_basket): double_map hasher(identity) CollectionId, hasher(identity) TokenId => T::BlockNumber;414 pub FungibleTransferBasket get(fn fungible_transfer_basket): double_map hasher(identity) CollectionId, hasher(identity) TokenId => Vec<BasketItem<T::AccountId, T::BlockNumber>>;415 pub ReFungibleTransferBasket get(fn refungible_transfer_basket): double_map hasher(identity) CollectionId, hasher(identity) TokenId => T::BlockNumber;416417 418 pub ContractOwner get(fn contract_owner): map hasher(twox_64_concat) T::AccountId => T::AccountId;419 pub ContractSelfSponsoring get(fn contract_self_sponsoring): map hasher(twox_64_concat) T::AccountId => bool;420 pub ContractSponsorBasket get(fn contract_sponsor_basket): map hasher(twox_64_concat) (T::AccountId, T::AccountId) => T::BlockNumber;421 pub ContractSponsoringRateLimit get(fn contract_sponsoring_rate_limit): map hasher(twox_64_concat) T::AccountId => T::BlockNumber;422 }423 add_extra_genesis {424 build(|config: &GenesisConfig<T>| {425 426 for (_num, _c) in &config.collection {427 <Module<T>>::init_collection(_c);428 }429430 for (_num, _q, _i) in &config.nft_item_id {431 <Module<T>>::init_nft_token(_i);432 }433434 for (_num, _q, _i) in &config.fungible_item_id {435 <Module<T>>::init_fungible_token(_i);436 }437438 for (_num, _q, _i) in &config.refungible_item_id {439 <Module<T>>::init_refungible_token(_i);440 }441 })442 }443}444445decl_event!(446 pub enum Event<T>447 where448 AccountId = <T as system::Trait>::AccountId,449 {450 451 452 453 454 455 456 457 458 459 Created(CollectionId, u8, AccountId),460461 462 463 464 465 466 467 468 ItemCreated(CollectionId, TokenId),469470 471 472 473 474 475 476 477 ItemDestroyed(CollectionId, TokenId),478 }479);480481decl_module! {482 pub struct Module<T: Trait> for enum Call where origin: T::Origin {483484 fn deposit_event() = default;485 type Error = Error<T>;486487 fn on_initialize(now: T::BlockNumber) -> Weight {488489 if ChainVersion::get() < 2490 {491 let value = NextCollectionID::get();492 CreatedCollectionCount::put(value);493 ChainVersion::put(2);494 }495496 0497 }498499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 #[weight = T::WeightInfo::create_collection()]516 pub fn create_collection(origin,517 collection_name: Vec<u16>,518 collection_description: Vec<u16>,519 token_prefix: Vec<u8>,520 mode: CollectionMode) -> DispatchResult {521522 523 let who = ensure_signed(origin)?;524525 let decimal_points = match mode {526 CollectionMode::Fungible(points) => points,527 CollectionMode::ReFungible(points) => points,528 _ => 0529 };530531 532 ensure!(CollectionCount::get() < ChainLimit::get().collection_numbers_limit, Error::<T>::TotalCollectionsLimitExceeded);533534 535 ensure!(decimal_points <= MAX_DECIMAL_POINTS, Error::<T>::CollectionDecimalPointLimitExceeded);536537 let mut name = collection_name.to_vec();538 name.push(0);539 ensure!(name.len() <= 64, Error::<T>::CollectionNameLimitExceeded);540541 let mut description = collection_description.to_vec();542 description.push(0);543 ensure!(name.len() <= 256, Error::<T>::CollectionDescriptionLimitExceeded);544545 let mut prefix = token_prefix.to_vec();546 prefix.push(0);547 ensure!(prefix.len() <= 16, Error::<T>::CollectionTokenPrefixLimitExceeded);548549 550 let next_id = CreatedCollectionCount::get()551 .checked_add(1)552 .ok_or(Error::<T>::NumOverflow)?;553554 555 let total = CollectionCount::get()556 .checked_add(1)557 .ok_or(Error::<T>::NumOverflow)?;558559 CreatedCollectionCount::put(next_id);560 CollectionCount::put(total);561562 563 let new_collection = CollectionType {564 owner: who.clone(),565 name: name,566 mode: mode.clone(),567 mint_mode: false,568 access: AccessMode::Normal,569 description: description,570 decimal_points: decimal_points,571 token_prefix: prefix,572 offchain_schema: Vec::new(),573 sponsor: T::AccountId::default(),574 unconfirmed_sponsor: T::AccountId::default(),575 variable_on_chain_schema: Vec::new(),576 const_on_chain_schema: Vec::new(),577 limits: CollectionLimits::default(),578 };579580 581 <Collection<T>>::insert(next_id, new_collection);582583 584 Self::deposit_event(RawEvent::Created(next_id, mode.into(), who.clone()));585586 Ok(())587 }588589 590 591 592 593 594 595 596 597 598 #[weight = T::WeightInfo::destroy_collection()]599 pub fn destroy_collection(origin, collection_id: CollectionId) -> DispatchResult {600601 let sender = ensure_signed(origin)?;602 Self::check_owner_permissions(collection_id, sender)?;603604 <AddressTokens<T>>::remove_prefix(collection_id);605 <ApprovedList<T>>::remove_prefix(collection_id);606 <Balance<T>>::remove_prefix(collection_id);607 <ItemListIndex>::remove(collection_id);608 <AdminList<T>>::remove(collection_id);609 <Collection<T>>::remove(collection_id);610 <WhiteList<T>>::remove(collection_id);611612 <NftItemList<T>>::remove_prefix(collection_id);613 <FungibleItemList<T>>::remove_prefix(collection_id);614 <ReFungibleItemList<T>>::remove_prefix(collection_id);615616 <NftTransferBasket<T>>::remove_prefix(collection_id);617 <FungibleTransferBasket<T>>::remove_prefix(collection_id);618 <ReFungibleTransferBasket<T>>::remove_prefix(collection_id);619620 if CollectionCount::get() > 0621 {622 623 let total = CollectionCount::get()624 .checked_sub(1)625 .ok_or(Error::<T>::NumOverflow)?;626627 CollectionCount::put(total);628 }629630 Ok(())631 }632633 634 635 636 637 638 639 640 641 642 643 644 645 #[weight = T::WeightInfo::add_to_white_list()]646 pub fn add_to_white_list(origin, collection_id: CollectionId, address: T::AccountId) -> DispatchResult{647648 let sender = ensure_signed(origin)?;649 Self::check_owner_or_admin_permissions(collection_id, sender)?;650651 let mut white_list_collection: Vec<T::AccountId>;652 if <WhiteList<T>>::contains_key(collection_id) {653 white_list_collection = <WhiteList<T>>::get(collection_id);654 if !white_list_collection.contains(&address.clone())655 {656 white_list_collection.push(address.clone());657 }658 }659 else {660 white_list_collection = Vec::new();661 white_list_collection.push(address.clone());662 }663664 <WhiteList<T>>::insert(collection_id, white_list_collection);665 Ok(())666 }667668 669 670 671 672 673 674 675 676 677 678 679 680 #[weight = T::WeightInfo::remove_from_white_list()]681 pub fn remove_from_white_list(origin, collection_id: CollectionId, address: T::AccountId) -> DispatchResult{682683 let sender = ensure_signed(origin)?;684 Self::check_owner_or_admin_permissions(collection_id, sender)?;685686 if <WhiteList<T>>::contains_key(collection_id) {687 let mut white_list_collection = <WhiteList<T>>::get(collection_id);688 if white_list_collection.contains(&address.clone())689 {690 white_list_collection.retain(|i| *i != address.clone());691 <WhiteList<T>>::insert(collection_id, white_list_collection);692 }693 }694695 Ok(())696 }697698 699 700 701 702 703 704 705 706 707 708 709 #[weight = T::WeightInfo::set_public_access_mode()]710 pub fn set_public_access_mode(origin, collection_id: CollectionId, mode: AccessMode) -> DispatchResult711 {712 let sender = ensure_signed(origin)?;713714 Self::check_owner_permissions(collection_id, sender)?;715 let mut target_collection = <Collection<T>>::get(collection_id);716 target_collection.access = mode;717 <Collection<T>>::insert(collection_id, target_collection);718719 Ok(())720 }721722 723 724 725 726 727 728 729 730 731 732 733 734 735 #[weight = T::WeightInfo::set_mint_permission()]736 pub fn set_mint_permission(origin, collection_id: CollectionId, mint_permission: bool) -> DispatchResult737 {738 let sender = ensure_signed(origin)?;739740 Self::check_owner_permissions(collection_id, sender)?;741 let mut target_collection = <Collection<T>>::get(collection_id);742 target_collection.mint_mode = mint_permission;743 <Collection<T>>::insert(collection_id, target_collection);744745 Ok(())746 }747748 749 750 751 752 753 754 755 756 757 758 759 #[weight = T::WeightInfo::change_collection_owner()]760 pub fn change_collection_owner(origin, collection_id: CollectionId, new_owner: T::AccountId) -> DispatchResult {761762 let sender = ensure_signed(origin)?;763 Self::check_owner_permissions(collection_id, sender)?;764 let mut target_collection = <Collection<T>>::get(collection_id);765 target_collection.owner = new_owner;766 <Collection<T>>::insert(collection_id, target_collection);767768 Ok(())769 }770771 772 773 774 775 776 777 778 779 780 781 782 783 784 #[weight = T::WeightInfo::add_collection_admin()]785 pub fn add_collection_admin(origin, collection_id: CollectionId, new_admin_id: T::AccountId) -> DispatchResult {786787 let sender = ensure_signed(origin)?;788 Self::check_owner_or_admin_permissions(collection_id, sender)?;789 let mut admin_arr: Vec<T::AccountId> = Vec::new();790791 if <AdminList<T>>::contains_key(collection_id)792 {793 admin_arr = <AdminList<T>>::get(collection_id);794 ensure!(!admin_arr.contains(&new_admin_id), Error::<T>::AlreadyAdmin);795 }796797 798 ensure!((admin_arr.len() as u64) < ChainLimit::get().collections_admins_limit, Error::<T>::CollectionAdminsLimitExceeded);799800 admin_arr.push(new_admin_id);801 <AdminList<T>>::insert(collection_id, admin_arr);802803 Ok(())804 }805806 807 808 809 810 811 812 813 814 815 816 817 818 #[weight = T::WeightInfo::remove_collection_admin()]819 pub fn remove_collection_admin(origin, collection_id: CollectionId, account_id: T::AccountId) -> DispatchResult {820821 let sender = ensure_signed(origin)?;822 Self::check_owner_or_admin_permissions(collection_id, sender)?;823824 if <AdminList<T>>::contains_key(collection_id)825 {826 let mut admin_arr = <AdminList<T>>::get(collection_id);827 admin_arr.retain(|i| *i != account_id);828 <AdminList<T>>::insert(collection_id, admin_arr);829 }830831 Ok(())832 }833834 835 836 837 838 839 840 841 842 843 #[weight = T::WeightInfo::set_collection_sponsor()]844 pub fn set_collection_sponsor(origin, collection_id: CollectionId, new_sponsor: T::AccountId) -> DispatchResult {845846 let sender = ensure_signed(origin)?;847 ensure!(<Collection<T>>::contains_key(collection_id), Error::<T>::CollectionNotFound);848849 let mut target_collection = <Collection<T>>::get(collection_id);850 ensure!(sender == target_collection.owner, Error::<T>::NoPermission);851852 target_collection.unconfirmed_sponsor = new_sponsor;853 <Collection<T>>::insert(collection_id, target_collection);854855 Ok(())856 }857858 859 860 861 862 863 864 865 #[weight = T::WeightInfo::confirm_sponsorship()]866 pub fn confirm_sponsorship(origin, collection_id: CollectionId) -> DispatchResult {867868 let sender = ensure_signed(origin)?;869 ensure!(<Collection<T>>::contains_key(collection_id), Error::<T>::CollectionNotFound);870871 let mut target_collection = <Collection<T>>::get(collection_id);872 ensure!(sender == target_collection.unconfirmed_sponsor, Error::<T>::ConfirmUnsetSponsorFail);873874 target_collection.sponsor = target_collection.unconfirmed_sponsor;875 target_collection.unconfirmed_sponsor = T::AccountId::default();876 <Collection<T>>::insert(collection_id, target_collection);877878 Ok(())879 }880881 882 883 884 885 886 887 888 889 890 #[weight = T::WeightInfo::remove_collection_sponsor()]891 pub fn remove_collection_sponsor(origin, collection_id: CollectionId) -> DispatchResult {892893 let sender = ensure_signed(origin)?;894 ensure!(<Collection<T>>::contains_key(collection_id), Error::<T>::CollectionNotFound);895896 let mut target_collection = <Collection<T>>::get(collection_id);897 ensure!(sender == target_collection.owner, Error::<T>::NoPermission);898899 target_collection.sponsor = T::AccountId::default();900 <Collection<T>>::insert(collection_id, target_collection);901902 Ok(())903 }904905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928929 #[weight = T::WeightInfo::create_item(data.len())]930 pub fn create_item(origin, collection_id: CollectionId, owner: T::AccountId, data: CreateItemData) -> DispatchResult {931932 let sender = ensure_signed(origin)?;933934 Self::collection_exists(collection_id)?;935936 let target_collection = <Collection<T>>::get(collection_id);937938 Self::can_create_items_in_collection(collection_id, &target_collection, &sender, &owner)?;939 Self::validate_create_item_args(&target_collection, &data)?;940 Self::create_item_no_validation(collection_id, &target_collection, owner, data)?;941942 Ok(())943 }944945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 #[weight = T::WeightInfo::create_item(items_data.into_iter()964 .map(|data| { data.len() })965 .sum())]966 pub fn create_multiple_items(origin, collection_id: CollectionId, owner: T::AccountId, items_data: Vec<CreateItemData>) -> DispatchResult {967968 ensure!(items_data.len() > 0, Error::<T>::EmptyArgument);969 let sender = ensure_signed(origin)?;970971 Self::collection_exists(collection_id)?;972 let target_collection = <Collection<T>>::get(collection_id);973974 Self::can_create_items_in_collection(collection_id, &target_collection, &sender, &owner)?;975976 for data in &items_data {977 Self::validate_create_item_args(&target_collection, data)?;978 }979 for data in &items_data {980 Self::create_item_no_validation(collection_id, &target_collection, owner.clone(), data.clone())?;981 }982983 Ok(())984 }985986 987 988 989 990 991 992 993 994 995 996 997 998 999 #[weight = T::WeightInfo::burn_item()]1000 pub fn burn_item(origin, collection_id: CollectionId, item_id: TokenId) -> DispatchResult {10011002 let sender = ensure_signed(origin)?;1003 Self::collection_exists(collection_id)?;10041005 1006 let target_collection = <Collection<T>>::get(collection_id);1007 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||1008 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1009 Error::<T>::NoPermission);10101011 if target_collection.access == AccessMode::WhiteList {1012 Self::check_white_list(collection_id, &sender)?;1013 }10141015 match target_collection.mode1016 {1017 CollectionMode::NFT => Self::burn_nft_item(collection_id, item_id)?,1018 CollectionMode::Fungible(_) => Self::burn_fungible_item(collection_id, item_id)?,1019 CollectionMode::ReFungible(_) => Self::burn_refungible_item(collection_id, item_id, sender.clone())?,1020 _ => ()1021 };10221023 1024 Self::deposit_event(RawEvent::ItemDestroyed(collection_id, item_id));10251026 Ok(())1027 }10281029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 #[weight = T::WeightInfo::transfer()]1053 pub fn transfer(origin, recipient: T::AccountId, collection_id: CollectionId, item_id: TokenId, value: u128) -> DispatchResult {10541055 let sender = ensure_signed(origin)?;1056 let target_collection = <Collection<T>>::get(collection_id);10571058 1059 Self::is_correct_transfer(collection_id, &target_collection, &recipient)?;10601061 1062 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||1063 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1064 Error::<T>::NoPermission);10651066 if target_collection.access == AccessMode::WhiteList {1067 Self::check_white_list(collection_id, &sender)?;1068 Self::check_white_list(collection_id, &recipient)?;1069 }10701071 match target_collection.mode1072 {1073 CollectionMode::NFT => Self::transfer_nft(collection_id, item_id, sender.clone(), recipient)?,1074 CollectionMode::Fungible(_) => Self::transfer_fungible(collection_id, item_id, value, sender.clone(), recipient)?,1075 CollectionMode::ReFungible(_) => Self::transfer_refungible(collection_id, item_id, value, sender.clone(), recipient)?,1076 _ => ()1077 };10781079 Ok(())1080 }10811082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 #[weight = T::WeightInfo::approve()]1098 pub fn approve(origin, approved: T::AccountId, collection_id: CollectionId, item_id: TokenId) -> DispatchResult {10991100 let sender = ensure_signed(origin)?;11011102 1103 let target_collection = <Collection<T>>::get(collection_id);1104 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||1105 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1106 Error::<T>::NoPermission);11071108 if target_collection.access == AccessMode::WhiteList {1109 Self::check_white_list(collection_id, &sender)?;1110 Self::check_white_list(collection_id, &approved)?;1111 }11121113 1114 let amount = 100000000;11151116 let list_exists = <ApprovedList<T>>::contains_key(collection_id, (item_id, sender.clone()));1117 if list_exists {11181119 let mut list = <ApprovedList<T>>::get(collection_id, (item_id, sender.clone()));1120 let item_contains = list.iter().any(|i| i.approved == approved);11211122 if !item_contains {1123 list.push(ApprovePermissions { approved: approved.clone(), amount: amount });1124 <ApprovedList<T>>::insert(collection_id, (item_id, sender.clone()), list);1125 }1126 } else {11271128 let mut list = Vec::new();1129 list.push(ApprovePermissions { approved: approved.clone(), amount: amount });1130 <ApprovedList<T>>::insert(collection_id, (item_id, sender.clone()), list);1131 }11321133 Ok(())1134 }1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 #[weight = T::WeightInfo::transfer_from()]1156 pub fn transfer_from(origin, from: T::AccountId, recipient: T::AccountId, collection_id: CollectionId, item_id: TokenId, value: u128 ) -> DispatchResult {11571158 let sender = ensure_signed(origin)?;1159 let mut appoved_transfer = false;11601161 1162 if <ApprovedList<T>>::contains_key(collection_id, (item_id, from.clone())) {1163 let list_itm = <ApprovedList<T>>::get(collection_id, (item_id, from.clone()));1164 let opt_item = list_itm.iter().find(|i| i.approved == sender.clone());1165 if opt_item.is_some()1166 {1167 appoved_transfer = true;1168 ensure!(opt_item.unwrap().amount >= value, Error::<T>::TokenValueNotEnough);1169 }1170 }11711172 let target_collection = <Collection<T>>::get(collection_id);11731174 1175 Self::is_correct_transfer(collection_id, &target_collection, &recipient)?;11761177 1178 ensure!(appoved_transfer || Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1179 Error::<T>::NoPermission);11801181 if target_collection.access == AccessMode::WhiteList {1182 Self::check_white_list(collection_id, &sender)?;1183 Self::check_white_list(collection_id, &recipient)?;1184 }11851186 1187 let approve_list: Vec<ApprovePermissions<T::AccountId>> = <ApprovedList<T>>::get(collection_id, (item_id, from.clone()))1188 .into_iter().filter(|i| i.approved != sender.clone()).collect();1189 <ApprovedList<T>>::insert(collection_id, (item_id, from.clone()), approve_list);119011911192 match target_collection.mode1193 {1194 CollectionMode::NFT => Self::transfer_nft(collection_id, item_id, from, recipient)?,1195 CollectionMode::Fungible(_) => Self::transfer_fungible(collection_id, item_id, value, from.clone(), recipient)?,1196 CollectionMode::ReFungible(_) => Self::transfer_refungible(collection_id, item_id, value, from.clone(), recipient)?,1197 _ => ()1198 };11991200 Ok(())1201 }12021203 1204 #[weight = 0]1205 pub fn safe_transfer_from(origin, collection_id: CollectionId, item_id: TokenId, new_owner: T::AccountId) -> DispatchResult {12061207 1208 1209 1210 12111212 12131214 12151216 Ok(())1217 }12181219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 #[weight = T::WeightInfo::set_variable_meta_data()]1232 pub fn set_variable_meta_data (1233 origin,1234 collection_id: CollectionId,1235 item_id: TokenId,1236 data: Vec<u8>1237 ) -> DispatchResult {1238 let sender = ensure_signed(origin)?;1239 1240 Self::collection_exists(collection_id)?;1241 1242 ensure!(ChainLimit::get().custom_data_limit >= data.len() as u32, Error::<T>::TokenVariableDataLimitExceeded);12431244 1245 let target_collection = <Collection<T>>::get(collection_id);1246 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||1247 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1248 Error::<T>::NoPermission);12491250 Self::item_exists(collection_id, item_id, &target_collection.mode)?;12511252 match target_collection.mode1253 {1254 CollectionMode::NFT => Self::set_nft_variable_data(collection_id, item_id, data)?,1255 CollectionMode::ReFungible(_) => Self::set_re_fungible_variable_data(collection_id, item_id, data)?,1256 CollectionMode::Fungible(_) => fail!(Error::<T>::CantStoreMetadataInFungibleTokens),1257 _ => fail!(Error::<T>::UnexpectedCollectionType)1258 };12591260 Ok(())1261 }1262 12631264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 #[weight = T::WeightInfo::set_offchain_schema()]1277 pub fn set_offchain_schema(1278 origin,1279 collection_id: CollectionId,1280 schema: Vec<u8>1281 ) -> DispatchResult {1282 let sender = ensure_signed(origin)?;1283 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;12841285 let mut target_collection = <Collection<T>>::get(collection_id);1286 target_collection.offchain_schema = schema;1287 <Collection<T>>::insert(collection_id, target_collection);12881289 Ok(())1290 }12911292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 #[weight = T::WeightInfo::set_const_on_chain_schema()]1305 pub fn set_const_on_chain_schema (1306 origin,1307 collection_id: CollectionId,1308 schema: Vec<u8>1309 ) -> DispatchResult {1310 let sender = ensure_signed(origin)?;1311 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;13121313 let mut target_collection = <Collection<T>>::get(collection_id);1314 target_collection.const_on_chain_schema = schema;1315 <Collection<T>>::insert(collection_id, target_collection);13161317 Ok(())1318 }13191320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 #[weight = T::WeightInfo::set_const_on_chain_schema()]1333 pub fn set_variable_on_chain_schema (1334 origin,1335 collection_id: CollectionId,1336 schema: Vec<u8>1337 ) -> DispatchResult {1338 let sender = ensure_signed(origin)?;1339 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;13401341 let mut target_collection = <Collection<T>>::get(collection_id);1342 target_collection.variable_on_chain_schema = schema;1343 <Collection<T>>::insert(collection_id, target_collection);13441345 Ok(())1346 }13471348 1349 #[weight = 0]1350 pub fn set_chain_limits(1351 origin,1352 limits: ChainLimits1353 ) -> DispatchResult {1354 ensure_root(origin)?;1355 <ChainLimit>::put(limits);1356 Ok(())1357 }13581359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 #[weight = T::WeightInfo::enable_contract_sponsoring()]1371 pub fn enable_contract_sponsoring(1372 origin,1373 contract_address: T::AccountId,1374 enable: bool1375 ) -> DispatchResult {13761377 let sender = ensure_signed(origin)?;13781379 #[cfg(feature = "runtime-benchmarks")]1380 <ContractOwner<T>>::insert(contract_address.clone(), sender.clone());13811382 let mut is_owner = false;1383 if <ContractOwner<T>>::contains_key(contract_address.clone()) {1384 let owner = <ContractOwner<T>>::get(&contract_address);1385 is_owner = sender == owner;1386 }1387 ensure!(is_owner, Error::<T>::NoPermission);13881389 <ContractSelfSponsoring<T>>::insert(contract_address, enable);1390 Ok(())1391 }13921393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 #[weight = 0]1411 pub fn set_contract_sponsoring_rate_limit(1412 origin,1413 contract_address: T::AccountId,1414 rate_limit: T::BlockNumber1415 ) -> DispatchResult {1416 let sender = ensure_signed(origin)?;1417 let mut is_owner = false;1418 if <ContractOwner<T>>::contains_key(contract_address.clone()) {1419 let owner = <ContractOwner<T>>::get(&contract_address);1420 is_owner = sender == owner;1421 }1422 ensure!(is_owner, Error::<T>::NoPermission);14231424 <ContractSponsoringRateLimit<T>>::insert(contract_address, rate_limit);1425 Ok(())1426 }14271428 #[weight = 0]1429 pub fn set_collection_limits(1430 origin,1431 collection_id: u32,1432 limits: CollectionLimits,1433 ) -> DispatchResult {1434 let sender = ensure_signed(origin)?;1435 Self::check_owner_permissions(collection_id, sender.clone())?;1436 let mut target_collection = <Collection<T>>::get(collection_id);1437 let chain_limits = ChainLimit::get();1438 let climits = target_collection.limits;14391440 1441 ensure!(limits.sponsor_transfer_timeout <= MAX_SPONSOR_TIMEOUT &&1442 limits.account_token_ownership_limit <= MAX_TOKEN_OWNERSHIP, 1443 Error::<T>::CollectionLimitBoundsExceeded);14441445 1446 ensure!(climits.token_limit > limits.token_limit && 1447 limits.token_limit <= chain_limits.account_token_ownership_limit, 1448 Error::<T>::AccountTokenLimitExceeded);14491450 target_collection.limits = limits;1451 <Collection<T>>::insert(collection_id, target_collection);14521453 Ok(())1454 } 1455 }1456}14571458impl<T: Trait> Module<T> {14591460 fn is_correct_transfer(collection_id: CollectionId, collection: &CollectionType<T::AccountId>, recipient: &T::AccountId) -> DispatchResult {14611462 if !Self::is_owner_or_admin_permissions(collection_id, recipient.clone()) {14631464 1465 let account_items: u32 = <AddressTokens<T>>::get(collection_id, recipient).len() as u32;1466 ensure!(collection.limits.account_token_ownership_limit > account_items, Error::<T>::AccountTokenLimitExceeded);1467 }14681469 Ok(())1470 }14711472 fn can_create_items_in_collection(collection_id: CollectionId, collection: &CollectionType<T::AccountId>, sender: &T::AccountId, owner: &T::AccountId) -> DispatchResult {14731474 if !Self::is_owner_or_admin_permissions(collection_id, sender.clone()) {14751476 1477 let total_items: u32 = ItemListIndex::get(collection_id);1478 let account_items: u32 = <AddressTokens<T>>::get(collection_id, owner).len() as u32;1479 ensure!(collection.limits.token_limit > total_items, Error::<T>::CollectionTokenLimitExceeded);1480 ensure!(collection.limits.account_token_ownership_limit > account_items, Error::<T>::AccountTokenLimitExceeded);1481 ensure!(collection.mint_mode == true, Error::<T>::PublicMintingNotAllowed);1482 Self::check_white_list(collection_id, owner)?;1483 Self::check_white_list(collection_id, sender)?;1484 }14851486 Ok(())1487 }14881489 fn validate_create_item_args(target_collection: &CollectionType<T::AccountId>, data: &CreateItemData) -> DispatchResult {1490 match target_collection.mode1491 {1492 CollectionMode::NFT => {1493 if let CreateItemData::NFT(data) = data {1494 1495 ensure!(ChainLimit::get().custom_data_limit >= data.const_data.len() as u32, Error::<T>::TokenConstDataLimitExceeded);1496 ensure!(ChainLimit::get().custom_data_limit >= data.variable_data.len() as u32, Error::<T>::TokenVariableDataLimitExceeded);1497 } else {1498 fail!(Error::<T>::NotNftDataUsedToMintNftCollectionToken);1499 }1500 },1501 CollectionMode::Fungible(_) => {1502 if let CreateItemData::Fungible(_) = data {1503 } else {1504 fail!(Error::<T>::NotFungibleDataUsedToMintFungibleCollectionToken);1505 }1506 },1507 CollectionMode::ReFungible(_) => {1508 if let CreateItemData::ReFungible(data) = data {15091510 1511 ensure!(ChainLimit::get().custom_data_limit >= data.const_data.len() as u32, Error::<T>::TokenConstDataLimitExceeded);1512 ensure!(ChainLimit::get().custom_data_limit >= data.variable_data.len() as u32, Error::<T>::TokenVariableDataLimitExceeded);1513 } else {1514 fail!(Error::<T>::NotReFungibleDataUsedToMintReFungibleCollectionToken);1515 }1516 },1517 _ => { fail!(Error::<T>::UnexpectedCollectionType); }1518 };15191520 Ok(())1521 }15221523 fn create_item_no_validation(collection_id: CollectionId, collection: &CollectionType<T::AccountId>, owner: T::AccountId, data: CreateItemData) -> DispatchResult {1524 match data1525 {1526 CreateItemData::NFT(data) => {1527 let item = NftItemType {1528 collection: collection_id,1529 owner,1530 const_data: data.const_data,1531 variable_data: data.variable_data1532 };15331534 Self::add_nft_item(item)?;1535 },1536 CreateItemData::Fungible(_) => {1537 let item = FungibleItemType {1538 collection: collection_id,1539 owner,1540 value: (10 as u128).pow(collection.decimal_points as u32)1541 };15421543 Self::add_fungible_item(item)?;1544 },1545 CreateItemData::ReFungible(data) => {1546 let mut owner_list = Vec::new();1547 let value = (10 as u128).pow(collection.decimal_points as u32);1548 owner_list.push(Ownership {owner: owner.clone(), fraction: value});15491550 let item = ReFungibleItemType {1551 collection: collection_id,1552 owner: owner_list,1553 const_data: data.const_data,1554 variable_data: data.variable_data1555 };15561557 Self::add_refungible_item(item)?;1558 }1559 };15601561 1562 Self::deposit_event(RawEvent::ItemCreated(collection_id, <ItemListIndex>::get(collection_id)));15631564 Ok(())1565 }15661567 fn add_fungible_item(item: FungibleItemType<T::AccountId>) -> DispatchResult {1568 let current_index = <ItemListIndex>::get(item.collection)1569 .checked_add(1)1570 .ok_or(Error::<T>::NumOverflow)?;1571 let itemcopy = item.clone();1572 let owner = item.owner.clone();15731574 Self::add_token_index(item.collection, current_index, owner.clone())?;15751576 <ItemListIndex>::insert(item.collection, current_index);1577 <FungibleItemList<T>>::insert(item.collection, current_index, itemcopy);15781579 1580 let v: Vec<BasketItem<T::AccountId, T::BlockNumber>> = Vec::new();1581 <FungibleTransferBasket<T>>::insert(item.collection, current_index, v);1582 1583 1584 let new_balance = <Balance<T>>::get(item.collection, owner.clone())1585 .checked_add(item.value)1586 .ok_or(Error::<T>::NumOverflow)?;1587 <Balance<T>>::insert(item.collection, owner.clone(), new_balance);15881589 Ok(())1590 }15911592 fn add_refungible_item(item: ReFungibleItemType<T::AccountId>) -> DispatchResult {1593 let current_index = <ItemListIndex>::get(item.collection)1594 .checked_add(1)1595 .ok_or(Error::<T>::NumOverflow)?;1596 let itemcopy = item.clone();15971598 let value = item.owner.first().unwrap().fraction;1599 let owner = item.owner.first().unwrap().owner.clone();16001601 Self::add_token_index(item.collection, current_index, owner.clone())?;16021603 <ItemListIndex>::insert(item.collection, current_index);1604 <ReFungibleItemList<T>>::insert(item.collection, current_index, itemcopy);16051606 1607 let block_number: T::BlockNumber = 0.into();1608 <ReFungibleTransferBasket<T>>::insert(item.collection, current_index, block_number);16091610 1611 let new_balance = <Balance<T>>::get(item.collection, owner.clone())1612 .checked_add(value)1613 .ok_or(Error::<T>::NumOverflow)?;1614 <Balance<T>>::insert(item.collection, owner.clone(), new_balance);16151616 Ok(())1617 }16181619 fn add_nft_item(item: NftItemType<T::AccountId>) -> DispatchResult {1620 let current_index = <ItemListIndex>::get(item.collection)1621 .checked_add(1)1622 .ok_or(Error::<T>::NumOverflow)?;16231624 let item_owner = item.owner.clone();1625 let collection_id = item.collection.clone();1626 Self::add_token_index(collection_id, current_index, item.owner.clone())?;16271628 <ItemListIndex>::insert(collection_id, current_index);1629 <NftItemList<T>>::insert(collection_id, current_index, item);16301631 1632 let block_number: T::BlockNumber = 0.into();1633 <NftTransferBasket<T>>::insert(collection_id, current_index, block_number);16341635 1636 let new_balance = <Balance<T>>::get(collection_id, item_owner.clone())1637 .checked_add(1)1638 .ok_or(Error::<T>::NumOverflow)?;1639 <Balance<T>>::insert(collection_id, item_owner.clone(), new_balance);16401641 Ok(())1642 }16431644 fn burn_refungible_item(1645 collection_id: CollectionId,1646 item_id: TokenId,1647 owner: T::AccountId,1648 ) -> DispatchResult {1649 ensure!(1650 <ReFungibleItemList<T>>::contains_key(collection_id, item_id),1651 Error::<T>::TokenNotFound1652 );1653 let collection = <ReFungibleItemList<T>>::get(collection_id, item_id);1654 let item = collection1655 .owner1656 .iter()1657 .filter(|&i| i.owner == owner)1658 .next()1659 .unwrap();1660 Self::remove_token_index(collection_id, item_id, owner.clone())?;16611662 1663 <ApprovedList<T>>::remove(collection_id, (item_id, owner.clone()));16641665 1666 let new_balance = <Balance<T>>::get(collection_id, item.owner.clone())1667 .checked_sub(item.fraction)1668 .ok_or(Error::<T>::NumOverflow)?;1669 <Balance<T>>::insert(collection_id, item.owner.clone(), new_balance);16701671 <ReFungibleItemList<T>>::remove(collection_id, item_id);16721673 Ok(())1674 }16751676 fn burn_nft_item(collection_id: CollectionId, item_id: TokenId) -> DispatchResult {1677 ensure!(1678 <NftItemList<T>>::contains_key(collection_id, item_id),1679 Error::<T>::TokenNotFound1680 );1681 let item = <NftItemList<T>>::get(collection_id, item_id);1682 Self::remove_token_index(collection_id, item_id, item.owner.clone())?;16831684 1685 <ApprovedList<T>>::remove(collection_id, (item_id, item.owner.clone()));16861687 1688 let new_balance = <Balance<T>>::get(collection_id, item.owner.clone())1689 .checked_sub(1)1690 .ok_or(Error::<T>::NumOverflow)?;1691 <Balance<T>>::insert(collection_id, item.owner.clone(), new_balance);1692 <NftItemList<T>>::remove(collection_id, item_id);16931694 Ok(())1695 }16961697 fn burn_fungible_item(collection_id: CollectionId, item_id: TokenId) -> DispatchResult {1698 ensure!(1699 <FungibleItemList<T>>::contains_key(collection_id, item_id),1700 Error::<T>::TokenNotFound1701 );1702 let item = <FungibleItemList<T>>::get(collection_id, item_id);1703 Self::remove_token_index(collection_id, item_id, item.owner.clone())?;17041705 1706 <ApprovedList<T>>::remove(collection_id, (item_id, item.owner.clone()));17071708 1709 let new_balance = <Balance<T>>::get(collection_id, item.owner.clone())1710 .checked_sub(item.value)1711 .ok_or(Error::<T>::NumOverflow)?;1712 <Balance<T>>::insert(collection_id, item.owner.clone(), new_balance);17131714 <FungibleItemList<T>>::remove(collection_id, item_id);17151716 Ok(())1717 }17181719 fn collection_exists(collection_id: CollectionId) -> DispatchResult {1720 ensure!(1721 <Collection<T>>::contains_key(collection_id),1722 Error::<T>::CollectionNotFound1723 );1724 Ok(())1725 }17261727 fn check_owner_permissions(collection_id: CollectionId, subject: T::AccountId) -> DispatchResult {1728 Self::collection_exists(collection_id)?;17291730 let target_collection = <Collection<T>>::get(collection_id);1731 ensure!(1732 subject == target_collection.owner,1733 Error::<T>::NoPermission1734 );17351736 Ok(())1737 }17381739 fn is_owner_or_admin_permissions(collection_id: CollectionId, subject: T::AccountId) -> bool {1740 let target_collection = <Collection<T>>::get(collection_id);1741 let mut result: bool = subject == target_collection.owner;1742 let exists = <AdminList<T>>::contains_key(collection_id);17431744 if !result & exists {1745 if <AdminList<T>>::get(collection_id).contains(&subject) {1746 result = true1747 }1748 }17491750 result1751 }17521753 fn check_owner_or_admin_permissions(1754 collection_id: CollectionId,1755 subject: T::AccountId,1756 ) -> DispatchResult {1757 Self::collection_exists(collection_id)?;1758 let result = Self::is_owner_or_admin_permissions(collection_id, subject.clone());17591760 ensure!(1761 result,1762 Error::<T>::NoPermission1763 );1764 Ok(())1765 }17661767 fn is_item_owner(subject: T::AccountId, collection_id: CollectionId, item_id: TokenId) -> bool {1768 let target_collection = <Collection<T>>::get(collection_id);17691770 match target_collection.mode {1771 CollectionMode::NFT => {1772 <NftItemList<T>>::get(collection_id, item_id).owner == subject1773 }1774 CollectionMode::Fungible(_) => {1775 <FungibleItemList<T>>::get(collection_id, item_id).owner == subject1776 }1777 CollectionMode::ReFungible(_) => {1778 <ReFungibleItemList<T>>::get(collection_id, item_id)1779 .owner1780 .iter()1781 .any(|i| i.owner == subject)1782 }1783 CollectionMode::Invalid => false,1784 }1785 }17861787 fn check_white_list(collection_id: CollectionId, address: &T::AccountId) -> DispatchResult {1788 let mes = Error::<T>::AddresNotInWhiteList;1789 ensure!(<WhiteList<T>>::contains_key(collection_id), mes);1790 let wl = <WhiteList<T>>::get(collection_id);1791 ensure!(wl.contains(address), mes);17921793 Ok(())1794 }17951796 fn transfer_fungible(1797 collection_id: CollectionId,1798 item_id: TokenId,1799 value: u128,1800 owner: T::AccountId,1801 new_owner: T::AccountId,1802 ) -> DispatchResult {1803 ensure!(1804 <FungibleItemList<T>>::contains_key(collection_id, item_id),1805 Error::<T>::TokenNotFound1806 );18071808 let full_item = <FungibleItemList<T>>::get(collection_id, item_id);1809 let amount = full_item.value;18101811 ensure!(amount >= value, Error::<T>::TokenValueTooLow);18121813 1814 let balance_old_owner = <Balance<T>>::get(collection_id, owner.clone())1815 .checked_sub(value)1816 .ok_or(Error::<T>::NumOverflow)?;1817 <Balance<T>>::insert(collection_id, owner.clone(), balance_old_owner);18181819 let mut new_owner_account_id = 0;1820 let new_owner_items = <AddressTokens<T>>::get(collection_id, new_owner.clone());1821 if new_owner_items.len() > 0 {1822 new_owner_account_id = new_owner_items[0];1823 }18241825 1826 if amount == value && new_owner_account_id == 0 {1827 1828 1829 let mut new_full_item = full_item.clone();1830 new_full_item.owner = new_owner.clone();1831 <FungibleItemList<T>>::insert(collection_id, item_id, new_full_item);18321833 1834 let balance_new_owner = <Balance<T>>::get(collection_id, new_owner.clone())1835 .checked_add(value)1836 .ok_or(Error::<T>::NumOverflow)?;1837 <Balance<T>>::insert(collection_id, new_owner.clone(), balance_new_owner);18381839 1840 Self::move_token_index(collection_id, item_id, owner.clone(), new_owner.clone())?;1841 } else {1842 let mut new_full_item = full_item.clone();1843 new_full_item.value -= value;18441845 1846 if new_owner_account_id > 0 {1847 1848 let mut item = <FungibleItemList<T>>::get(collection_id, new_owner_account_id);1849 item.value += value;18501851 1852 let balance_new_owner = <Balance<T>>::get(collection_id, new_owner.clone())1853 .checked_add(value)1854 .ok_or(Error::<T>::NumOverflow)?;1855 <Balance<T>>::insert(collection_id, new_owner.clone(), balance_new_owner);18561857 <FungibleItemList<T>>::insert(collection_id, new_owner_account_id, item);1858 } else {1859 1860 let item = FungibleItemType {1861 collection: collection_id,1862 owner: new_owner.clone(),1863 value1864 };18651866 Self::add_fungible_item(item)?;1867 }18681869 if amount == value {1870 Self::remove_token_index(collection_id, item_id, full_item.owner.clone())?;18711872 1873 <ApprovedList<T>>::remove(collection_id, (item_id, full_item.owner.clone()));1874 <FungibleItemList<T>>::remove(collection_id, item_id);1875 }18761877 <FungibleItemList<T>>::insert(collection_id, item_id, new_full_item);1878 }18791880 Ok(())1881 }18821883 fn transfer_refungible(1884 collection_id: CollectionId,1885 item_id: TokenId,1886 value: u128,1887 owner: T::AccountId,1888 new_owner: T::AccountId,1889 ) -> DispatchResult {1890 ensure!(1891 <ReFungibleItemList<T>>::contains_key(collection_id, item_id),1892 Error::<T>::TokenNotFound1893 );18941895 let full_item = <ReFungibleItemList<T>>::get(collection_id, item_id);1896 let item = full_item1897 .owner1898 .iter()1899 .filter(|i| i.owner == owner)1900 .next()1901 .ok_or(Error::<T>::NumOverflow)?;1902 let amount = item.fraction;19031904 ensure!(amount >= value, Error::<T>::TokenValueTooLow);19051906 1907 let balance_old_owner = <Balance<T>>::get(collection_id, item.owner.clone())1908 .checked_sub(value)1909 .ok_or(Error::<T>::NumOverflow)?;1910 <Balance<T>>::insert(collection_id, item.owner.clone(), balance_old_owner);19111912 let balance_new_owner = <Balance<T>>::get(collection_id, new_owner.clone())1913 .checked_add(value)1914 .ok_or(Error::<T>::NumOverflow)?;1915 <Balance<T>>::insert(collection_id, new_owner.clone(), balance_new_owner);19161917 let old_owner = item.owner.clone();1918 let new_owner_has_account = full_item.owner.iter().any(|i| i.owner == new_owner);19191920 1921 if amount == value && !new_owner_has_account {1922 1923 1924 let mut new_full_item = full_item.clone();1925 new_full_item1926 .owner1927 .iter_mut()1928 .find(|i| i.owner == owner)1929 .unwrap()1930 .owner = new_owner.clone();1931 <ReFungibleItemList<T>>::insert(collection_id, item_id, new_full_item);19321933 1934 Self::move_token_index(collection_id, item_id, old_owner.clone(), new_owner.clone())?;1935 } else {1936 let mut new_full_item = full_item.clone();1937 new_full_item1938 .owner1939 .iter_mut()1940 .find(|i| i.owner == owner)1941 .unwrap()1942 .fraction -= value;19431944 1945 if new_owner_has_account {1946 1947 new_full_item1948 .owner1949 .iter_mut()1950 .find(|i| i.owner == new_owner)1951 .unwrap()1952 .fraction += value;1953 } else {1954 1955 new_full_item.owner.push(Ownership {1956 owner: new_owner.clone(),1957 fraction: value,1958 });1959 Self::add_token_index(collection_id, item_id, new_owner.clone())?;1960 }19611962 <ReFungibleItemList<T>>::insert(collection_id, item_id, new_full_item);1963 }19641965 Ok(())1966 }19671968 fn transfer_nft(1969 collection_id: CollectionId,1970 item_id: TokenId,1971 sender: T::AccountId,1972 new_owner: T::AccountId,1973 ) -> DispatchResult {1974 ensure!(1975 <NftItemList<T>>::contains_key(collection_id, item_id),1976 Error::<T>::TokenNotFound1977 );19781979 let mut item = <NftItemList<T>>::get(collection_id, item_id);19801981 ensure!(1982 sender == item.owner,1983 Error::<T>::MustBeTokenOwner1984 );19851986 1987 let balance_old_owner = <Balance<T>>::get(collection_id, item.owner.clone())1988 .checked_sub(1)1989 .ok_or(Error::<T>::NumOverflow)?;1990 <Balance<T>>::insert(collection_id, item.owner.clone(), balance_old_owner);19911992 let balance_new_owner = <Balance<T>>::get(collection_id, new_owner.clone())1993 .checked_add(1)1994 .ok_or(Error::<T>::NumOverflow)?;1995 <Balance<T>>::insert(collection_id, new_owner.clone(), balance_new_owner);19961997 1998 let old_owner = item.owner.clone();1999 item.owner = new_owner.clone();2000 <NftItemList<T>>::insert(collection_id, item_id, item);20012002 2003 Self::move_token_index(collection_id, item_id, old_owner.clone(), new_owner.clone())?;20042005 2006 <ApprovedList<T>>::remove(collection_id, (item_id, old_owner));2007 Ok(())2008 }2009 2010 fn item_exists(2011 collection_id: CollectionId,2012 item_id: TokenId,2013 mode: &CollectionMode2014 ) -> DispatchResult {2015 match mode {2016 CollectionMode::NFT => ensure!(<NftItemList<T>>::contains_key(collection_id, item_id), Error::<T>::TokenNotFound),2017 CollectionMode::ReFungible(_) => ensure!(<ReFungibleItemList<T>>::contains_key(collection_id, item_id), Error::<T>::TokenNotFound),2018 CollectionMode::Fungible(_) => ensure!(<FungibleItemList<T>>::contains_key(collection_id, item_id), Error::<T>::TokenNotFound),2019 _ => ()2020 };2021 2022 Ok(())2023 }20242025 fn set_re_fungible_variable_data(2026 collection_id: CollectionId,2027 item_id: TokenId,2028 data: Vec<u8>2029 ) -> DispatchResult {2030 let mut item = <ReFungibleItemList<T>>::get(collection_id, item_id);20312032 item.variable_data = data;20332034 <ReFungibleItemList<T>>::insert(collection_id, item_id, item);20352036 Ok(())2037 }20382039 fn set_nft_variable_data(2040 collection_id: CollectionId,2041 item_id: TokenId,2042 data: Vec<u8>2043 ) -> DispatchResult {2044 let mut item = <NftItemList<T>>::get(collection_id, item_id);2045 2046 item.variable_data = data;20472048 <NftItemList<T>>::insert(collection_id, item_id, item);2049 2050 Ok(())2051 }20522053 fn init_collection(item: &CollectionType<T::AccountId>) {2054 2055 assert!(2056 item.decimal_points <= MAX_DECIMAL_POINTS,2057 "decimal_points parameter must be lower than MAX_DECIMAL_POINTS"2058 );2059 assert!(2060 item.name.len() <= 64,2061 "Collection name can not be longer than 63 char"2062 );2063 assert!(2064 item.name.len() <= 256,2065 "Collection description can not be longer than 255 char"2066 );2067 assert!(2068 item.token_prefix.len() <= 16,2069 "Token prefix can not be longer than 15 char"2070 );20712072 2073 let next_id = CreatedCollectionCount::get()2074 .checked_add(1)2075 .unwrap();20762077 CreatedCollectionCount::put(next_id);2078 }20792080 fn init_nft_token(item: &NftItemType<T::AccountId>) {2081 let current_index = <ItemListIndex>::get(item.collection)2082 .checked_add(1)2083 .unwrap();20842085 let item_owner = item.owner.clone();2086 let collection_id = item.collection.clone();2087 Self::add_token_index(collection_id, current_index, item.owner.clone()).unwrap();20882089 <ItemListIndex>::insert(collection_id, current_index);20902091 2092 let new_balance = <Balance<T>>::get(collection_id, item_owner.clone())2093 .checked_add(1)2094 .unwrap();2095 <Balance<T>>::insert(collection_id, item_owner.clone(), new_balance);2096 }20972098 fn init_fungible_token(item: &FungibleItemType<T::AccountId>) {2099 let current_index = <ItemListIndex>::get(item.collection)2100 .checked_add(1)2101 .unwrap();2102 let owner = item.owner.clone();21032104 Self::add_token_index(item.collection, current_index, owner.clone()).unwrap();21052106 <ItemListIndex>::insert(item.collection, current_index);21072108 2109 let new_balance = <Balance<T>>::get(item.collection, owner.clone())2110 .checked_add(item.value)2111 .unwrap();2112 <Balance<T>>::insert(item.collection, owner.clone(), new_balance);2113 }21142115 fn init_refungible_token(item: &ReFungibleItemType<T::AccountId>) {2116 let current_index = <ItemListIndex>::get(item.collection)2117 .checked_add(1)2118 .unwrap();21192120 let value = item.owner.first().unwrap().fraction;2121 let owner = item.owner.first().unwrap().owner.clone();21222123 Self::add_token_index(item.collection, current_index, owner.clone()).unwrap();21242125 <ItemListIndex>::insert(item.collection, current_index);21262127 2128 let new_balance = <Balance<T>>::get(item.collection, owner.clone())2129 .checked_add(value)2130 .unwrap();2131 <Balance<T>>::insert(item.collection, owner.clone(), new_balance);2132 }21332134 fn add_token_index(collection_id: CollectionId, item_index: TokenId, owner: T::AccountId) -> DispatchResult {21352136 2137 if <AccountItemCount<T>>::contains_key(owner.clone()) {21382139 2140 let count = <AccountItemCount<T>>::get(owner.clone());2141 ensure!(count < ChainLimit::get().account_token_ownership_limit, Error::<T>::AddressOwnershipLimitExceeded);21422143 <AccountItemCount<T>>::insert(owner.clone(), count2144 .checked_add(1)2145 .ok_or(Error::<T>::NumOverflow)?);2146 }2147 else {2148 <AccountItemCount<T>>::insert(owner.clone(), 1);2149 }21502151 let list_exists = <AddressTokens<T>>::contains_key(collection_id, owner.clone());2152 if list_exists {2153 let mut list = <AddressTokens<T>>::get(collection_id, owner.clone());2154 let item_contains = list.contains(&item_index.clone());21552156 if !item_contains {2157 list.push(item_index.clone());2158 }21592160 <AddressTokens<T>>::insert(collection_id, owner.clone(), list);2161 } else {2162 let mut itm = Vec::new();2163 itm.push(item_index.clone());2164 <AddressTokens<T>>::insert(collection_id, owner, itm);2165 2166 }21672168 Ok(())2169 }21702171 fn remove_token_index(2172 collection_id: CollectionId,2173 item_index: TokenId,2174 owner: T::AccountId,2175 ) -> DispatchResult {21762177 2178 <AccountItemCount<T>>::insert(owner.clone(), 2179 <AccountItemCount<T>>::get(owner.clone())2180 .checked_sub(1)2181 .ok_or(Error::<T>::NumOverflow)?);218221832184 let list_exists = <AddressTokens<T>>::contains_key(collection_id, owner.clone());2185 if list_exists {2186 let mut list = <AddressTokens<T>>::get(collection_id, owner.clone());2187 let item_contains = list.contains(&item_index.clone());21882189 if item_contains {2190 list.retain(|&item| item != item_index);2191 <AddressTokens<T>>::insert(collection_id, owner, list);2192 }2193 }21942195 Ok(())2196 }21972198 fn move_token_index(2199 collection_id: CollectionId,2200 item_index: TokenId,2201 old_owner: T::AccountId,2202 new_owner: T::AccountId,2203 ) -> DispatchResult {2204 Self::remove_token_index(collection_id, item_index, old_owner)?;2205 Self::add_token_index(collection_id, item_index, new_owner)?;22062207 Ok(())2208 }2209}2210221122122213221422152216pub type Multiplier = FixedU128;22172218type BalanceOf<T> = <<T as transaction_payment::Trait>::Currency as Currency<2219 <T as system::Trait>::AccountId,2220>>::Balance;2221type NegativeImbalanceOf<T> = <<T as transaction_payment::Trait>::Currency as Currency<2222 <T as system::Trait>::AccountId,2223>>::NegativeImbalance;2224222522262227#[derive(Encode, Decode, Clone, Eq, PartialEq)]2228pub struct ChargeTransactionPayment<T: Trait + Send + Sync>(2229 #[codec(compact)] BalanceOf<T>2230);22312232impl<T: Trait + Send + Sync> sp_std::fmt::Debug2233 for ChargeTransactionPayment<T>2234{2235 #[cfg(feature = "std")]2236 fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {2237 write!(f, "ChargeTransactionPayment<{:?}>", self.0)2238 }2239 #[cfg(not(feature = "std"))]2240 fn fmt(&self, _: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {2241 Ok(())2242 }2243}22442245impl<T: Trait + Send + Sync> ChargeTransactionPayment<T>2246where2247 T::Call: Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo> + IsSubType<Call<T>> + IsSubType<pallet_contracts::Call<T>>,2248 BalanceOf<T>: Send + Sync + FixedPointOperand,2249{2250 2251 pub fn from(fee: BalanceOf<T>) -> Self {2252 Self(fee)2253 }22542255 pub fn traditional_fee(2256 len: usize,2257 info: &DispatchInfoOf<T::Call>,2258 tip: BalanceOf<T>,2259 ) -> BalanceOf<T>2260 where2261 T::Call: Dispatchable<Info = DispatchInfo>,2262 {2263 <transaction_payment::Module<T>>::compute_fee(len as u32, info, tip)2264 }22652266 fn withdraw_fee(2267 &self,2268 who: &T::AccountId,2269 call: &T::Call,2270 info: &DispatchInfoOf<T::Call>,2271 len: usize,2272 ) -> Result<(BalanceOf<T>, Option<NegativeImbalanceOf<T>>), TransactionValidityError> {2273 let tip = self.0;22742275 2276 2277 2278 2279 2280 2281 2282 let fee = Self::traditional_fee(len, info, tip);22832284 2285 2286 let mut sponsor: T::AccountId = match IsSubType::<Call<T>>::is_sub_type(call) {2287 Some(Call::create_item(collection_id, _owner, _properties)) => {22882289 2290 if <Collection<T>>::get(collection_id).limits.sponsored_data_size >= (_properties.len() as u32)2291 {2292 <Collection<T>>::get(collection_id).sponsor2293 } else {2294 T::AccountId::default()2295 }2296 }2297 Some(Call::transfer(_new_owner, collection_id, _item_id, _value)) => {2298 2299 let _collection_limits = <Collection<T>>::get(collection_id).limits;2300 let _collection_mode = <Collection<T>>::get(collection_id).mode;23012302 2303 let sponsor_transfer = match _collection_mode {2304 CollectionMode::NFT => {23052306 2307 let limit: u32 = if _collection_limits.sponsor_transfer_timeout > 0 {2308 _collection_limits.sponsor_transfer_timeout2309 } else {2310 ChainLimit::get().nft_sponsor_transfer_timeout2311 };23122313 let basket = <NftTransferBasket<T>>::get(collection_id, _item_id);2314 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;2315 let limit_time = basket + limit.into();2316 if block_number >= limit_time {2317 <NftTransferBasket<T>>::insert(collection_id, _item_id, block_number);2318 true2319 }2320 else {2321 false2322 }2323 }2324 CollectionMode::Fungible(_) => {23252326 2327 let limit: u32 = if _collection_limits.sponsor_transfer_timeout > 0 {2328 _collection_limits.sponsor_transfer_timeout2329 } else {2330 ChainLimit::get().fungible_sponsor_transfer_timeout2331 };23322333 let mut basket = <FungibleTransferBasket<T>>::get(collection_id, _item_id);2334 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;2335 if basket.iter().any(|i| i.address == _new_owner.clone())2336 {2337 let item = basket.iter_mut().find(|i| i.address == _new_owner.clone()).unwrap().clone();2338 let limit_time = item.start_block + limit.into();2339 if block_number >= limit_time {2340 basket.retain(|x| x.address == item.address);2341 basket.push(BasketItem { start_block: block_number, address: _new_owner.clone() });2342 <FungibleTransferBasket<T>>::insert(collection_id, _item_id, basket);2343 true2344 }2345 else {2346 false2347 }2348 }2349 else {2350 basket.push(BasketItem { start_block: block_number, address: _new_owner.clone()});2351 true2352 }2353 }2354 CollectionMode::ReFungible(_) => {23552356 2357 let limit: u32 = if _collection_limits.sponsor_transfer_timeout > 0 {2358 _collection_limits.sponsor_transfer_timeout2359 } else {2360 ChainLimit::get().refungible_sponsor_transfer_timeout2361 };23622363 let basket = <ReFungibleTransferBasket<T>>::get(collection_id, _item_id);2364 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;2365 let limit_time = basket + limit.into();2366 if block_number >= limit_time {2367 <ReFungibleTransferBasket<T>>::insert(collection_id, _item_id, block_number);2368 true2369 } else {2370 false2371 }2372 }2373 _ => {2374 false2375 },2376 };23772378 if !sponsor_transfer {2379 T::AccountId::default()2380 } else {2381 <Collection<T>>::get(collection_id).sponsor2382 }2383 }23842385 _ => T::AccountId::default(),2386 };23872388 2389 sponsor = match IsSubType::<pallet_contracts::Call<T>>::is_sub_type(call) {23902391 2392 Some(pallet_contracts::Call::instantiate(_endowment, _gas_limit, code_hash, data)) => {23932394 let new_contract_address = <T as pallet_contracts::Trait>::DetermineContractAddress::contract_address_for(2395 code_hash,2396 &data,2397 &who,2398 );2399 <ContractOwner<T>>::insert(new_contract_address.clone(), who.clone());24002401 T::AccountId::default()2402 },24032404 2405 Some(pallet_contracts::Call::call(dest, _value, _gas_limit, _data)) => {24062407 let called_contract: T::AccountId = T::Lookup::lookup((*dest).clone()).unwrap_or(T::AccountId::default());24082409 let mut sponsor_transfer = false;2410 if <ContractSponsoringRateLimit<T>>::contains_key(called_contract.clone()) {2411 let last_tx_block = <ContractSponsorBasket<T>>::get((&called_contract, &who));2412 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;2413 let rate_limit = <ContractSponsoringRateLimit<T>>::get(&called_contract);2414 let limit_time = last_tx_block + rate_limit;24152416 if block_number >= limit_time {2417 <ContractSponsorBasket<T>>::insert((called_contract.clone(), who.clone()), block_number);2418 sponsor_transfer = true;2419 }2420 } else {2421 sponsor_transfer = false;2422 }2423 2424 2425 let mut sp = T::AccountId::default();2426 if sponsor_transfer {2427 if <ContractSelfSponsoring<T>>::contains_key(called_contract.clone()) {2428 if <ContractSelfSponsoring<T>>::get(called_contract.clone()) {2429 sp = called_contract;2430 }2431 }2432 }24332434 sp2435 },24362437 _ => sponsor,2438 };24392440 let mut who_pays_fee: T::AccountId = sponsor.clone();2441 if sponsor == T::AccountId::default() {2442 who_pays_fee = who.clone();2443 }24442445 2446 if fee.is_zero() {2447 return Ok((fee, None));2448 }24492450 match <T as transaction_payment::Trait>::Currency::withdraw(2451 &who_pays_fee,2452 fee,2453 if tip.is_zero() {2454 WithdrawReason::TransactionPayment.into()2455 } else {2456 WithdrawReason::TransactionPayment | WithdrawReason::Tip2457 },2458 ExistenceRequirement::KeepAlive,2459 ) {2460 Ok(imbalance) => Ok((fee, Some(imbalance))),2461 Err(_) => Err(InvalidTransaction::Payment.into()),2462 }2463 }2464}246524662467impl<T: Trait + Send + Sync> SignedExtension2468 for ChargeTransactionPayment<T>2469where2470 BalanceOf<T>: Send + Sync + From<u64> + FixedPointOperand,2471 T::Call: Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo> + IsSubType<Call<T>> + IsSubType<pallet_contracts::Call<T>>,2472{2473 const IDENTIFIER: &'static str = "ChargeTransactionPayment";2474 type AccountId = T::AccountId;2475 type Call = T::Call;2476 type AdditionalSigned = ();2477 type Pre = (2478 BalanceOf<T>,2479 Self::AccountId,2480 Option<NegativeImbalanceOf<T>>,2481 BalanceOf<T>,2482 );2483 fn additional_signed(&self) -> sp_std::result::Result<(), TransactionValidityError> {2484 Ok(())2485 }24862487 fn validate(2488 &self,2489 _who: &Self::AccountId,2490 _call: &Self::Call,2491 _info: &DispatchInfoOf<Self::Call>,2492 _len: usize,2493 ) -> TransactionValidity {2494 Ok(ValidTransaction::default())2495 }24962497 fn pre_dispatch(2498 self,2499 who: &Self::AccountId,2500 call: &Self::Call,2501 info: &DispatchInfoOf<Self::Call>,2502 len: usize,2503 ) -> Result<Self::Pre, TransactionValidityError> {2504 let (fee, imbalance) = self.withdraw_fee(who, call, info, len)?;2505 Ok((self.0, who.clone(), imbalance, fee))2506 }25072508 fn post_dispatch(2509 pre: Self::Pre,2510 info: &DispatchInfoOf<Self::Call>,2511 post_info: &PostDispatchInfoOf<Self::Call>,2512 len: usize,2513 _result: &DispatchResult,2514 ) -> Result<(), TransactionValidityError> {2515 let (tip, who, imbalance, fee) = pre;2516 if let Some(payed) = imbalance {2517 let actual_fee = <transaction_payment::Module<T>>::compute_actual_fee(2518 len as u32, info, post_info, tip,2519 );2520 let refund = fee.saturating_sub(actual_fee);2521 let actual_payment =2522 match <T as transaction_payment::Trait>::Currency::deposit_into_existing(2523 &who, refund,2524 ) {2525 Ok(refund_imbalance) => {2526 2527 2528 match payed.offset(refund_imbalance) {2529 Ok(actual_payment) => actual_payment,2530 Err(_) => return Err(InvalidTransaction::Payment.into()),2531 }2532 }2533 2534 2535 Err(_) => payed,2536 };2537 let imbalances = actual_payment.split(tip);2538 <T as transaction_payment::Trait>::OnTransactionPayment::on_unbalanceds(2539 Some(imbalances.0).into_iter().chain(Some(imbalances.1)),2540 );2541 }2542 Ok(())2543 }2544}25452546