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;4950515253pub type CollectionId = u32;54pub type TokenId = u32;5556pub type DecimalPoints = u8;5758#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq)]59#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]60pub enum CollectionMode {61 Invalid,62 NFT,63 64 Fungible(DecimalPoints),65 66 ReFungible(DecimalPoints),67}6869impl Into<u8> for CollectionMode {70 fn into(self) -> u8 {71 match self {72 CollectionMode::Invalid => 0,73 CollectionMode::NFT => 1,74 CollectionMode::Fungible(_) => 2,75 CollectionMode::ReFungible(_) => 3,76 }77 }78}7980#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq)]81#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]82pub enum AccessMode {83 Normal,84 WhiteList,85}86impl Default for AccessMode {87 fn default() -> Self {88 Self::Normal89 }90}9192impl Default for CollectionMode {93 fn default() -> Self {94 Self::Invalid95 }96}9798#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]99#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]100pub struct Ownership<AccountId> {101 pub owner: AccountId,102 pub fraction: u128,103}104105#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]106#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]107pub struct CollectionType<AccountId> {108 pub owner: AccountId,109 pub mode: CollectionMode,110 pub access: AccessMode,111 pub decimal_points: DecimalPoints,112 pub name: Vec<u16>, 113 pub description: Vec<u16>, 114 pub token_prefix: Vec<u8>, 115 pub mint_mode: bool,116 pub offchain_schema: Vec<u8>,117 pub sponsor: AccountId, 118 pub unconfirmed_sponsor: AccountId, 119 pub limits: CollectionLimits, 120 pub variable_on_chain_schema: Vec<u8>, 121 pub const_on_chain_schema: Vec<u8>, 122}123124#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]125#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]126pub struct NftItemType<AccountId> {127 pub collection: CollectionId,128 pub owner: AccountId,129 pub const_data: Vec<u8>,130 pub variable_data: Vec<u8>,131}132133#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]134#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]135pub struct FungibleItemType<AccountId> {136 pub collection: CollectionId,137 pub owner: AccountId,138 pub value: u128,139}140141#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]142#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]143pub struct ReFungibleItemType<AccountId> {144 pub collection: CollectionId,145 pub owner: Vec<Ownership<AccountId>>,146 pub const_data: Vec<u8>,147 pub variable_data: Vec<u8>,148}149150#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]151#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]152pub struct ApprovePermissions<AccountId> {153 pub approved: AccountId,154 pub amount: u128,155}156157#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]158#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]159pub struct VestingItem<AccountId, Moment> {160 pub sender: AccountId,161 pub recipient: AccountId,162 pub collection_id: CollectionId,163 pub item_id: TokenId,164 pub amount: u64,165 pub vesting_date: Moment,166}167168#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]169#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]170pub struct BasketItem<AccountId, BlockNumber> {171 pub address: AccountId,172 pub start_block: BlockNumber,173}174175#[derive(Encode, Decode, Debug, Clone, PartialEq)]176#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]177pub struct CollectionLimits {178 pub account_token_ownership_limit: u32,179 pub sponsored_data_size: u32,180 pub token_limit: u32,181182 183 pub sponsor_transfer_timeout: u32,184}185186impl Default for CollectionLimits {187 fn default() -> CollectionLimits {188 CollectionLimits { 189 account_token_ownership_limit: u32::max_value(), 190 token_limit: u32::max_value(),191 sponsored_data_size: u32::max_value(), 192 sponsor_transfer_timeout: u32::max_value() }193 }194}195196#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]197#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]198pub struct ChainLimits {199 pub collection_numbers_limit: u32,200 pub account_token_ownership_limit: u32,201 pub collections_admins_limit: u64,202 pub custom_data_limit: u32,203204 205 pub nft_sponsor_transfer_timeout: u32,206 pub fungible_sponsor_transfer_timeout: u32,207 pub refungible_sponsor_transfer_timeout: u32,208}209210pub trait WeightInfo {211 fn create_collection() -> Weight;212 fn destroy_collection() -> Weight;213 fn add_to_white_list() -> Weight;214 fn remove_from_white_list() -> Weight;215 fn set_public_access_mode() -> Weight;216 fn set_mint_permission() -> Weight;217 fn change_collection_owner() -> Weight;218 fn add_collection_admin() -> Weight;219 fn remove_collection_admin() -> Weight;220 fn set_collection_sponsor() -> Weight;221 fn confirm_sponsorship() -> Weight;222 fn remove_collection_sponsor() -> Weight;223 fn create_item(s: usize) -> Weight;224 fn burn_item() -> Weight;225 fn transfer() -> Weight;226 fn approve() -> Weight;227 fn transfer_from() -> Weight;228 fn set_offchain_schema() -> Weight;229 fn set_const_on_chain_schema() -> Weight;230 fn set_variable_on_chain_schema() -> Weight;231 fn set_variable_meta_data() -> Weight;232 fn enable_contract_sponsoring() -> Weight;233}234235#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]236#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]237pub struct CreateNftData {238 pub const_data: Vec<u8>,239 pub variable_data: Vec<u8>,240}241242#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]243#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]244pub struct CreateFungibleData {245}246247#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]248#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]249pub struct CreateReFungibleData {250 pub const_data: Vec<u8>,251 pub variable_data: Vec<u8>,252}253254#[derive(Encode, Decode, Debug, Clone, PartialEq)]255#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]256pub enum CreateItemData {257 NFT(CreateNftData),258 Fungible(CreateFungibleData),259 ReFungible(CreateReFungibleData)260}261262impl CreateItemData {263 pub fn len(&self) -> usize {264 let len = match self {265 CreateItemData::NFT(data) => data.variable_data.len() + data.const_data.len(),266 CreateItemData::ReFungible(data) => data.variable_data.len() + data.const_data.len(),267 _ => 0268 };269 270 return len;271 }272}273274impl From<CreateNftData> for CreateItemData {275 fn from(item: CreateNftData) -> Self {276 CreateItemData::NFT(item)277 }278}279280impl From<CreateReFungibleData> for CreateItemData {281 fn from(item: CreateReFungibleData) -> Self {282 CreateItemData::ReFungible(item)283 }284}285286impl From<CreateFungibleData> for CreateItemData {287 fn from(item: CreateFungibleData) -> Self {288 CreateItemData::Fungible(item)289 }290}291292293decl_error! {294 295 pub enum Error for Module<T: Trait> {296 297 TotalCollectionsLimitExceeded,298 299 CollectionDecimalPointLimitExceeded, 300 301 CollectionNameLimitExceeded, 302 303 CollectionDescriptionLimitExceeded, 304 305 CollectionTokenPrefixLimitExceeded,306 307 CollectionNotFound,308 309 TokenNotFound,310 311 NumOverflow, 312 313 AlreadyAdmin, 314 315 NoPermission,316 317 ConfirmUnsetSponsorFail,318 319 PublicMintingNotAllowed,320 321 MustBeTokenOwner,322 323 TokenValueTooLow,324 325 NftSizeLimitExceeded,326 327 ApproveNotFound,328 329 TokenValueNotEnough,330 331 ApproveRequired,332 333 AddresNotInWhiteList,334 335 CollectionAdminsLimitExceeded,336 337 AddressOwnershipLimitExceeded,338 339 EmptyArgument,340 341 TokenConstDataLimitExceeded,342 343 TokenVariableDataLimitExceeded,344 345 NotNftDataUsedToMintNftCollectionToken,346 347 NotFungibleDataUsedToMintFungibleCollectionToken,348 349 NotReFungibleDataUsedToMintReFungibleCollectionToken,350 351 UnexpectedCollectionType,352 353 CantStoreMetadataInFungibleTokens,354 355 CollectionTokenLimitExceeded,356 357 AccountTokenLimitExceeded358 }359}360361pub trait Trait: system::Trait + Sized + transaction_payment::Trait + pallet_contracts::Trait {362 type Event: From<Event<Self>> + Into<<Self as system::Trait>::Event>;363364 365 type WeightInfo: WeightInfo;366}367368#[cfg(feature = "runtime-benchmarks")]369mod benchmarking;370371372373decl_storage! {374 trait Store for Module<T: Trait> as Nft {375376 377 NextCollectionID: CollectionId;378 CreatedCollectionCount: u32;379 ChainVersion: u64;380 ItemListIndex: map hasher(identity) CollectionId => TokenId;381382 383 pub ChainLimit get(fn chain_limit) config(): ChainLimits;384385 386 CollectionCount: u32;387 pub AccountItemCount get(fn account_item_count): map hasher(twox_64_concat) T::AccountId => u32;388389 390 pub Collection get(fn collection) config(): map hasher(identity) CollectionId => CollectionType<T::AccountId>;391 pub AdminList get(fn admin_list_collection): map hasher(identity) CollectionId => Vec<T::AccountId>;392 pub WhiteList get(fn white_list): map hasher(identity) CollectionId => Vec<T::AccountId>;393394 395 pub Balance get(fn balance_count): double_map hasher(identity) CollectionId, hasher(twox_64_concat) T::AccountId => u128;396397 398 pub ApprovedList get(fn approved): double_map hasher(identity) CollectionId, hasher(twox_64_concat) (TokenId, T::AccountId) => Vec<ApprovePermissions<T::AccountId>>;399400 401 pub NftItemList get(fn nft_item_id) config(): double_map hasher(identity) CollectionId, hasher(identity) TokenId => NftItemType<T::AccountId>;402 pub FungibleItemList get(fn fungible_item_id) config(): double_map hasher(identity) CollectionId, hasher(identity) TokenId => FungibleItemType<T::AccountId>;403 pub ReFungibleItemList get(fn refungible_item_id) config(): double_map hasher(identity) CollectionId, hasher(identity) TokenId => ReFungibleItemType<T::AccountId>;404405 406 pub AddressTokens get(fn address_tokens): double_map hasher(identity) CollectionId, hasher(twox_64_concat) T::AccountId => Vec<TokenId>;407408 409 pub NftTransferBasket get(fn nft_transfer_basket): double_map hasher(identity) CollectionId, hasher(identity) TokenId => T::BlockNumber;410 pub FungibleTransferBasket get(fn fungible_transfer_basket): double_map hasher(identity) CollectionId, hasher(identity) TokenId => Vec<BasketItem<T::AccountId, T::BlockNumber>>;411 pub ReFungibleTransferBasket get(fn refungible_transfer_basket): double_map hasher(identity) CollectionId, hasher(identity) TokenId => T::BlockNumber;412413 414 pub ContractOwner get(fn contract_owner): map hasher(twox_64_concat) T::AccountId => T::AccountId;415 pub ContractSelfSponsoring get(fn contract_self_sponsoring): map hasher(twox_64_concat) T::AccountId => bool;416 pub ContractSponsorBasket get(fn contract_sponsor_basket): map hasher(twox_64_concat) (T::AccountId, T::AccountId) => T::BlockNumber;417 pub ContractSponsoringRateLimit get(fn contract_sponsoring_rate_limit): map hasher(twox_64_concat) T::AccountId => T::BlockNumber;418 }419 add_extra_genesis {420 build(|config: &GenesisConfig<T>| {421 422 for (_num, _c) in &config.collection {423 <Module<T>>::init_collection(_c);424 }425426 for (_num, _q, _i) in &config.nft_item_id {427 <Module<T>>::init_nft_token(_i);428 }429430 for (_num, _q, _i) in &config.fungible_item_id {431 <Module<T>>::init_fungible_token(_i);432 }433434 for (_num, _q, _i) in &config.refungible_item_id {435 <Module<T>>::init_refungible_token(_i);436 }437 })438 }439}440441decl_event!(442 pub enum Event<T>443 where444 AccountId = <T as system::Trait>::AccountId,445 {446 447 448 449 450 451 452 453 454 455 Created(CollectionId, u8, AccountId),456457 458 459 460 461 462 463 464 ItemCreated(CollectionId, TokenId),465466 467 468 469 470 471 472 473 ItemDestroyed(CollectionId, TokenId),474 }475);476477decl_module! {478 pub struct Module<T: Trait> for enum Call where origin: T::Origin {479480 fn deposit_event() = default;481 type Error = Error<T>;482483 fn on_initialize(now: T::BlockNumber) -> Weight {484485 if ChainVersion::get() < 2486 {487 let value = NextCollectionID::get();488 CreatedCollectionCount::put(value);489 ChainVersion::put(2);490 }491492 0493 }494495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 #[weight = T::WeightInfo::create_collection()]512 pub fn create_collection(origin,513 collection_name: Vec<u16>,514 collection_description: Vec<u16>,515 token_prefix: Vec<u8>,516 mode: CollectionMode) -> DispatchResult {517518 519 let who = ensure_signed(origin)?;520521 let decimal_points = match mode {522 CollectionMode::Fungible(points) => points,523 CollectionMode::ReFungible(points) => points,524 _ => 0525 };526527 528 ensure!(CollectionCount::get() < ChainLimit::get().collection_numbers_limit, Error::<T>::TotalCollectionsLimitExceeded);529530 531 ensure!(decimal_points <= MAX_DECIMAL_POINTS, Error::<T>::CollectionDecimalPointLimitExceeded);532533 let mut name = collection_name.to_vec();534 name.push(0);535 ensure!(name.len() <= 64, Error::<T>::CollectionNameLimitExceeded);536537 let mut description = collection_description.to_vec();538 description.push(0);539 ensure!(name.len() <= 256, Error::<T>::CollectionDescriptionLimitExceeded);540541 let mut prefix = token_prefix.to_vec();542 prefix.push(0);543 ensure!(prefix.len() <= 16, Error::<T>::CollectionTokenPrefixLimitExceeded);544545 546 let next_id = CreatedCollectionCount::get()547 .checked_add(1)548 .ok_or(Error::<T>::NumOverflow)?;549550 551 let total = CollectionCount::get()552 .checked_add(1)553 .ok_or(Error::<T>::NumOverflow)?;554555 CreatedCollectionCount::put(next_id);556 CollectionCount::put(total);557558 559 let new_collection = CollectionType {560 owner: who.clone(),561 name: name,562 mode: mode.clone(),563 mint_mode: false,564 access: AccessMode::Normal,565 description: description,566 decimal_points: decimal_points,567 token_prefix: prefix,568 offchain_schema: Vec::new(),569 sponsor: T::AccountId::default(),570 unconfirmed_sponsor: T::AccountId::default(),571 variable_on_chain_schema: Vec::new(),572 const_on_chain_schema: Vec::new(),573 limits: CollectionLimits::default(),574 };575576 577 <Collection<T>>::insert(next_id, new_collection);578579 580 Self::deposit_event(RawEvent::Created(next_id, mode.into(), who.clone()));581582 Ok(())583 }584585 586 587 588 589 590 591 592 593 594 #[weight = T::WeightInfo::destroy_collection()]595 pub fn destroy_collection(origin, collection_id: CollectionId) -> DispatchResult {596597 let sender = ensure_signed(origin)?;598 Self::check_owner_permissions(collection_id, sender)?;599600 <AddressTokens<T>>::remove_prefix(collection_id);601 <ApprovedList<T>>::remove_prefix(collection_id);602 <Balance<T>>::remove_prefix(collection_id);603 <ItemListIndex>::remove(collection_id);604 <AdminList<T>>::remove(collection_id);605 <Collection<T>>::remove(collection_id);606 <WhiteList<T>>::remove(collection_id);607608 <NftItemList<T>>::remove_prefix(collection_id);609 <FungibleItemList<T>>::remove_prefix(collection_id);610 <ReFungibleItemList<T>>::remove_prefix(collection_id);611612 <NftTransferBasket<T>>::remove_prefix(collection_id);613 <FungibleTransferBasket<T>>::remove_prefix(collection_id);614 <ReFungibleTransferBasket<T>>::remove_prefix(collection_id);615616 if CollectionCount::get() > 0617 {618 619 let total = CollectionCount::get()620 .checked_sub(1)621 .ok_or(Error::<T>::NumOverflow)?;622623 CollectionCount::put(total);624 }625626 Ok(())627 }628629 630 631 632 633 634 635 636 637 638 639 640 641 #[weight = T::WeightInfo::add_to_white_list()]642 pub fn add_to_white_list(origin, collection_id: CollectionId, address: T::AccountId) -> DispatchResult{643644 let sender = ensure_signed(origin)?;645 Self::check_owner_or_admin_permissions(collection_id, sender)?;646647 let mut white_list_collection: Vec<T::AccountId>;648 if <WhiteList<T>>::contains_key(collection_id) {649 white_list_collection = <WhiteList<T>>::get(collection_id);650 if !white_list_collection.contains(&address.clone())651 {652 white_list_collection.push(address.clone());653 }654 }655 else {656 white_list_collection = Vec::new();657 white_list_collection.push(address.clone());658 }659660 <WhiteList<T>>::insert(collection_id, white_list_collection);661 Ok(())662 }663664 665 666 667 668 669 670 671 672 673 674 675 676 #[weight = T::WeightInfo::remove_from_white_list()]677 pub fn remove_from_white_list(origin, collection_id: CollectionId, address: T::AccountId) -> DispatchResult{678679 let sender = ensure_signed(origin)?;680 Self::check_owner_or_admin_permissions(collection_id, sender)?;681682 if <WhiteList<T>>::contains_key(collection_id) {683 let mut white_list_collection = <WhiteList<T>>::get(collection_id);684 if white_list_collection.contains(&address.clone())685 {686 white_list_collection.retain(|i| *i != address.clone());687 <WhiteList<T>>::insert(collection_id, white_list_collection);688 }689 }690691 Ok(())692 }693694 695 696 697 698 699 700 701 702 703 704 705 #[weight = T::WeightInfo::set_public_access_mode()]706 pub fn set_public_access_mode(origin, collection_id: CollectionId, mode: AccessMode) -> DispatchResult707 {708 let sender = ensure_signed(origin)?;709710 Self::check_owner_permissions(collection_id, sender)?;711 let mut target_collection = <Collection<T>>::get(collection_id);712 target_collection.access = mode;713 <Collection<T>>::insert(collection_id, target_collection);714715 Ok(())716 }717718 719 720 721 722 723 724 725 726 727 728 729 730 731 #[weight = T::WeightInfo::set_mint_permission()]732 pub fn set_mint_permission(origin, collection_id: CollectionId, mint_permission: bool) -> DispatchResult733 {734 let sender = ensure_signed(origin)?;735736 Self::check_owner_permissions(collection_id, sender)?;737 let mut target_collection = <Collection<T>>::get(collection_id);738 target_collection.mint_mode = mint_permission;739 <Collection<T>>::insert(collection_id, target_collection);740741 Ok(())742 }743744 745 746 747 748 749 750 751 752 753 754 755 #[weight = T::WeightInfo::change_collection_owner()]756 pub fn change_collection_owner(origin, collection_id: CollectionId, new_owner: T::AccountId) -> DispatchResult {757758 let sender = ensure_signed(origin)?;759 Self::check_owner_permissions(collection_id, sender)?;760 let mut target_collection = <Collection<T>>::get(collection_id);761 target_collection.owner = new_owner;762 <Collection<T>>::insert(collection_id, target_collection);763764 Ok(())765 }766767 768 769 770 771 772 773 774 775 776 777 778 779 780 #[weight = T::WeightInfo::add_collection_admin()]781 pub fn add_collection_admin(origin, collection_id: CollectionId, new_admin_id: T::AccountId) -> DispatchResult {782783 let sender = ensure_signed(origin)?;784 Self::check_owner_or_admin_permissions(collection_id, sender)?;785 let mut admin_arr: Vec<T::AccountId> = Vec::new();786787 if <AdminList<T>>::contains_key(collection_id)788 {789 admin_arr = <AdminList<T>>::get(collection_id);790 ensure!(!admin_arr.contains(&new_admin_id), Error::<T>::AlreadyAdmin);791 }792793 794 ensure!((admin_arr.len() as u64) < ChainLimit::get().collections_admins_limit, Error::<T>::CollectionAdminsLimitExceeded);795796 admin_arr.push(new_admin_id);797 <AdminList<T>>::insert(collection_id, admin_arr);798799 Ok(())800 }801802 803 804 805 806 807 808 809 810 811 812 813 814 #[weight = T::WeightInfo::remove_collection_admin()]815 pub fn remove_collection_admin(origin, collection_id: CollectionId, account_id: T::AccountId) -> DispatchResult {816817 let sender = ensure_signed(origin)?;818 Self::check_owner_or_admin_permissions(collection_id, sender)?;819820 if <AdminList<T>>::contains_key(collection_id)821 {822 let mut admin_arr = <AdminList<T>>::get(collection_id);823 admin_arr.retain(|i| *i != account_id);824 <AdminList<T>>::insert(collection_id, admin_arr);825 }826827 Ok(())828 }829830 831 832 833 834 835 836 837 838 839 #[weight = T::WeightInfo::set_collection_sponsor()]840 pub fn set_collection_sponsor(origin, collection_id: CollectionId, new_sponsor: T::AccountId) -> DispatchResult {841842 let sender = ensure_signed(origin)?;843 ensure!(<Collection<T>>::contains_key(collection_id), Error::<T>::CollectionNotFound);844845 let mut target_collection = <Collection<T>>::get(collection_id);846 ensure!(sender == target_collection.owner, Error::<T>::NoPermission);847848 target_collection.unconfirmed_sponsor = new_sponsor;849 <Collection<T>>::insert(collection_id, target_collection);850851 Ok(())852 }853854 855 856 857 858 859 860 861 #[weight = T::WeightInfo::confirm_sponsorship()]862 pub fn confirm_sponsorship(origin, collection_id: CollectionId) -> DispatchResult {863864 let sender = ensure_signed(origin)?;865 ensure!(<Collection<T>>::contains_key(collection_id), Error::<T>::CollectionNotFound);866867 let mut target_collection = <Collection<T>>::get(collection_id);868 ensure!(sender == target_collection.unconfirmed_sponsor, Error::<T>::ConfirmUnsetSponsorFail);869870 target_collection.sponsor = target_collection.unconfirmed_sponsor;871 target_collection.unconfirmed_sponsor = T::AccountId::default();872 <Collection<T>>::insert(collection_id, target_collection);873874 Ok(())875 }876877 878 879 880 881 882 883 884 885 886 #[weight = T::WeightInfo::remove_collection_sponsor()]887 pub fn remove_collection_sponsor(origin, collection_id: CollectionId) -> DispatchResult {888889 let sender = ensure_signed(origin)?;890 ensure!(<Collection<T>>::contains_key(collection_id), Error::<T>::CollectionNotFound);891892 let mut target_collection = <Collection<T>>::get(collection_id);893 ensure!(sender == target_collection.owner, Error::<T>::NoPermission);894895 target_collection.sponsor = T::AccountId::default();896 <Collection<T>>::insert(collection_id, target_collection);897898 Ok(())899 }900901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924925 #[weight = T::WeightInfo::create_item(data.len())]926 pub fn create_item(origin, collection_id: CollectionId, owner: T::AccountId, data: CreateItemData) -> DispatchResult {927928 let sender = ensure_signed(origin)?;929930 Self::collection_exists(collection_id)?;931932 let target_collection = <Collection<T>>::get(collection_id);933934 Self::can_create_items_in_collection(collection_id, &target_collection, &sender, &owner)?;935 Self::validate_create_item_args(&target_collection, &data)?;936 Self::create_item_no_validation(collection_id, &target_collection, owner, data)?;937938 Ok(())939 }940941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 #[weight = T::WeightInfo::create_item(items_data.into_iter()960 .map(|data| { data.len() })961 .sum())]962 pub fn create_multiple_items(origin, collection_id: CollectionId, owner: T::AccountId, items_data: Vec<CreateItemData>) -> DispatchResult {963964 ensure!(items_data.len() > 0, Error::<T>::EmptyArgument);965 let sender = ensure_signed(origin)?;966967 Self::collection_exists(collection_id)?;968 let target_collection = <Collection<T>>::get(collection_id);969970 Self::can_create_items_in_collection(collection_id, &target_collection, &sender, &owner)?;971972 for data in &items_data {973 Self::validate_create_item_args(&target_collection, data)?;974 }975 for data in &items_data {976 Self::create_item_no_validation(collection_id, &target_collection, owner.clone(), data.clone())?;977 }978979 Ok(())980 }981982 983 984 985 986 987 988 989 990 991 992 993 994 995 #[weight = T::WeightInfo::burn_item()]996 pub fn burn_item(origin, collection_id: CollectionId, item_id: TokenId) -> DispatchResult {997998 let sender = ensure_signed(origin)?;999 Self::collection_exists(collection_id)?;10001001 1002 let target_collection = <Collection<T>>::get(collection_id);1003 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||1004 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1005 Error::<T>::NoPermission);10061007 if target_collection.access == AccessMode::WhiteList {1008 Self::check_white_list(collection_id, &sender)?;1009 }10101011 match target_collection.mode1012 {1013 CollectionMode::NFT => Self::burn_nft_item(collection_id, item_id)?,1014 CollectionMode::Fungible(_) => Self::burn_fungible_item(collection_id, item_id)?,1015 CollectionMode::ReFungible(_) => Self::burn_refungible_item(collection_id, item_id, sender.clone())?,1016 _ => ()1017 };10181019 1020 Self::deposit_event(RawEvent::ItemDestroyed(collection_id, item_id));10211022 Ok(())1023 }10241025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 #[weight = T::WeightInfo::transfer()]1049 pub fn transfer(origin, recipient: T::AccountId, collection_id: CollectionId, item_id: TokenId, value: u128) -> DispatchResult {10501051 let sender = ensure_signed(origin)?;1052 let target_collection = <Collection<T>>::get(collection_id);10531054 1055 Self::is_correct_transfer(collection_id, &target_collection, &recipient)?;10561057 1058 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||1059 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1060 Error::<T>::NoPermission);10611062 if target_collection.access == AccessMode::WhiteList {1063 Self::check_white_list(collection_id, &sender)?;1064 Self::check_white_list(collection_id, &recipient)?;1065 }10661067 match target_collection.mode1068 {1069 CollectionMode::NFT => Self::transfer_nft(collection_id, item_id, sender.clone(), recipient)?,1070 CollectionMode::Fungible(_) => Self::transfer_fungible(collection_id, item_id, value, sender.clone(), recipient)?,1071 CollectionMode::ReFungible(_) => Self::transfer_refungible(collection_id, item_id, value, sender.clone(), recipient)?,1072 _ => ()1073 };10741075 Ok(())1076 }10771078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 #[weight = T::WeightInfo::approve()]1094 pub fn approve(origin, approved: T::AccountId, collection_id: CollectionId, item_id: TokenId) -> DispatchResult {10951096 let sender = ensure_signed(origin)?;10971098 1099 let target_collection = <Collection<T>>::get(collection_id);1100 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||1101 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1102 Error::<T>::NoPermission);11031104 if target_collection.access == AccessMode::WhiteList {1105 Self::check_white_list(collection_id, &sender)?;1106 Self::check_white_list(collection_id, &approved)?;1107 }11081109 1110 let amount = 100000000;11111112 let list_exists = <ApprovedList<T>>::contains_key(collection_id, (item_id, sender.clone()));1113 if list_exists {11141115 let mut list = <ApprovedList<T>>::get(collection_id, (item_id, sender.clone()));1116 let item_contains = list.iter().any(|i| i.approved == approved);11171118 if !item_contains {1119 list.push(ApprovePermissions { approved: approved.clone(), amount: amount });1120 <ApprovedList<T>>::insert(collection_id, (item_id, sender.clone()), list);1121 }1122 } else {11231124 let mut list = Vec::new();1125 list.push(ApprovePermissions { approved: approved.clone(), amount: amount });1126 <ApprovedList<T>>::insert(collection_id, (item_id, sender.clone()), list);1127 }11281129 Ok(())1130 }1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 #[weight = T::WeightInfo::transfer_from()]1152 pub fn transfer_from(origin, from: T::AccountId, recipient: T::AccountId, collection_id: CollectionId, item_id: TokenId, value: u128 ) -> DispatchResult {11531154 let sender = ensure_signed(origin)?;1155 let mut appoved_transfer = false;11561157 1158 if <ApprovedList<T>>::contains_key(collection_id, (item_id, from.clone())) {1159 let list_itm = <ApprovedList<T>>::get(collection_id, (item_id, from.clone()));1160 let opt_item = list_itm.iter().find(|i| i.approved == sender.clone());1161 if opt_item.is_some()1162 {1163 appoved_transfer = true;1164 ensure!(opt_item.unwrap().amount >= value, Error::<T>::TokenValueNotEnough);1165 }1166 }11671168 let target_collection = <Collection<T>>::get(collection_id);11691170 1171 Self::is_correct_transfer(collection_id, &target_collection, &recipient)?;11721173 1174 ensure!(appoved_transfer || Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1175 Error::<T>::NoPermission);11761177 if target_collection.access == AccessMode::WhiteList {1178 Self::check_white_list(collection_id, &sender)?;1179 Self::check_white_list(collection_id, &recipient)?;1180 }11811182 1183 let approve_list: Vec<ApprovePermissions<T::AccountId>> = <ApprovedList<T>>::get(collection_id, (item_id, from.clone()))1184 .into_iter().filter(|i| i.approved != sender.clone()).collect();1185 <ApprovedList<T>>::insert(collection_id, (item_id, from.clone()), approve_list);118611871188 match target_collection.mode1189 {1190 CollectionMode::NFT => Self::transfer_nft(collection_id, item_id, from, recipient)?,1191 CollectionMode::Fungible(_) => Self::transfer_fungible(collection_id, item_id, value, from.clone(), recipient)?,1192 CollectionMode::ReFungible(_) => Self::transfer_refungible(collection_id, item_id, value, from.clone(), recipient)?,1193 _ => ()1194 };11951196 Ok(())1197 }11981199 1200 #[weight = 0]1201 pub fn safe_transfer_from(origin, collection_id: CollectionId, item_id: TokenId, new_owner: T::AccountId) -> DispatchResult {12021203 1204 1205 1206 12071208 12091210 12111212 Ok(())1213 }12141215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 #[weight = T::WeightInfo::set_variable_meta_data()]1228 pub fn set_variable_meta_data (1229 origin,1230 collection_id: CollectionId,1231 item_id: TokenId,1232 data: Vec<u8>1233 ) -> DispatchResult {1234 let sender = ensure_signed(origin)?;1235 1236 Self::collection_exists(collection_id)?;1237 1238 ensure!(ChainLimit::get().custom_data_limit >= data.len() as u32, Error::<T>::TokenVariableDataLimitExceeded);12391240 1241 let target_collection = <Collection<T>>::get(collection_id);1242 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||1243 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1244 Error::<T>::NoPermission);12451246 Self::item_exists(collection_id, item_id, &target_collection.mode)?;12471248 match target_collection.mode1249 {1250 CollectionMode::NFT => Self::set_nft_variable_data(collection_id, item_id, data)?,1251 CollectionMode::ReFungible(_) => Self::set_re_fungible_variable_data(collection_id, item_id, data)?,1252 CollectionMode::Fungible(_) => fail!(Error::<T>::CantStoreMetadataInFungibleTokens),1253 _ => fail!(Error::<T>::UnexpectedCollectionType)1254 };12551256 Ok(())1257 }1258 12591260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 #[weight = T::WeightInfo::set_offchain_schema()]1273 pub fn set_offchain_schema(1274 origin,1275 collection_id: CollectionId,1276 schema: Vec<u8>1277 ) -> DispatchResult {1278 let sender = ensure_signed(origin)?;1279 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;12801281 let mut target_collection = <Collection<T>>::get(collection_id);1282 target_collection.offchain_schema = schema;1283 <Collection<T>>::insert(collection_id, target_collection);12841285 Ok(())1286 }12871288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 #[weight = T::WeightInfo::set_const_on_chain_schema()]1301 pub fn set_const_on_chain_schema (1302 origin,1303 collection_id: CollectionId,1304 schema: Vec<u8>1305 ) -> DispatchResult {1306 let sender = ensure_signed(origin)?;1307 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;13081309 let mut target_collection = <Collection<T>>::get(collection_id);1310 target_collection.const_on_chain_schema = schema;1311 <Collection<T>>::insert(collection_id, target_collection);13121313 Ok(())1314 }13151316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 #[weight = T::WeightInfo::set_const_on_chain_schema()]1329 pub fn set_variable_on_chain_schema (1330 origin,1331 collection_id: CollectionId,1332 schema: Vec<u8>1333 ) -> DispatchResult {1334 let sender = ensure_signed(origin)?;1335 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;13361337 let mut target_collection = <Collection<T>>::get(collection_id);1338 target_collection.variable_on_chain_schema = schema;1339 <Collection<T>>::insert(collection_id, target_collection);13401341 Ok(())1342 }13431344 1345 #[weight = 0]1346 pub fn set_chain_limits(1347 origin,1348 limits: ChainLimits1349 ) -> DispatchResult {1350 ensure_root(origin)?;1351 <ChainLimit>::put(limits);1352 Ok(())1353 }13541355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 #[weight = T::WeightInfo::enable_contract_sponsoring()]1367 pub fn enable_contract_sponsoring(1368 origin,1369 contract_address: T::AccountId,1370 enable: bool1371 ) -> DispatchResult {13721373 let sender = ensure_signed(origin)?;13741375 #[cfg(feature = "runtime-benchmarks")]1376 <ContractOwner<T>>::insert(contract_address.clone(), sender.clone());13771378 let mut is_owner = false;1379 if <ContractOwner<T>>::contains_key(contract_address.clone()) {1380 let owner = <ContractOwner<T>>::get(&contract_address);1381 is_owner = sender == owner;1382 }1383 ensure!(is_owner, Error::<T>::NoPermission);13841385 <ContractSelfSponsoring<T>>::insert(contract_address, enable);1386 Ok(())1387 }13881389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 #[weight = 0]1407 pub fn set_contract_sponsoring_rate_limit(1408 origin,1409 contract_address: T::AccountId,1410 rate_limit: T::BlockNumber1411 ) -> DispatchResult {1412 let sender = ensure_signed(origin)?;1413 let mut is_owner = false;1414 if <ContractOwner<T>>::contains_key(contract_address.clone()) {1415 let owner = <ContractOwner<T>>::get(&contract_address);1416 is_owner = sender == owner;1417 }1418 ensure!(is_owner, Error::<T>::NoPermission);14191420 <ContractSponsoringRateLimit<T>>::insert(contract_address, rate_limit);1421 Ok(())1422 }14231424 #[weight = 0]1425 pub fn set_collection_limits(1426 origin,1427 collection_id: u32,1428 limits: CollectionLimits,1429 ) -> DispatchResult {1430 let sender = ensure_signed(origin)?;1431 Self::check_owner_permissions(collection_id, sender.clone())?;1432 let mut target_collection = <Collection<T>>::get(collection_id);1433 let chain_limits = ChainLimit::get();1434 let climits = target_collection.limits;14351436 1437 ensure!(climits.token_limit > limits.token_limit && 1438 climits.token_limit <= chain_limits.account_token_ownership_limit, 1439 Error::<T>::AccountTokenLimitExceeded);14401441 target_collection.limits = limits;1442 <Collection<T>>::insert(collection_id, target_collection);14431444 Ok(())1445 } 1446 }1447}14481449impl<T: Trait> Module<T> {14501451 fn is_correct_transfer(collection_id: CollectionId, collection: &CollectionType<T::AccountId>, recipient: &T::AccountId) -> DispatchResult {14521453 if !Self::is_owner_or_admin_permissions(collection_id, recipient.clone()) {14541455 1456 let account_items: u32 = <AddressTokens<T>>::get(collection_id, recipient).len() as u32;1457 ensure!(collection.limits.account_token_ownership_limit > account_items, Error::<T>::AccountTokenLimitExceeded);1458 }14591460 Ok(())1461 }14621463 fn can_create_items_in_collection(collection_id: CollectionId, collection: &CollectionType<T::AccountId>, sender: &T::AccountId, owner: &T::AccountId) -> DispatchResult {14641465 if !Self::is_owner_or_admin_permissions(collection_id, sender.clone()) {14661467 1468 let total_items: u32 = ItemListIndex::get(collection_id);1469 let account_items: u32 = <AddressTokens<T>>::get(collection_id, owner).len() as u32;1470 ensure!(collection.limits.token_limit > total_items, Error::<T>::CollectionTokenLimitExceeded);1471 ensure!(collection.limits.account_token_ownership_limit > account_items, Error::<T>::AccountTokenLimitExceeded);1472 ensure!(collection.mint_mode == true, Error::<T>::PublicMintingNotAllowed);1473 Self::check_white_list(collection_id, owner)?;1474 Self::check_white_list(collection_id, sender)?;1475 }14761477 Ok(())1478 }14791480 fn validate_create_item_args(target_collection: &CollectionType<T::AccountId>, data: &CreateItemData) -> DispatchResult {1481 match target_collection.mode1482 {1483 CollectionMode::NFT => {1484 if let CreateItemData::NFT(data) = data {1485 1486 ensure!(ChainLimit::get().custom_data_limit >= data.const_data.len() as u32, Error::<T>::TokenConstDataLimitExceeded);1487 ensure!(ChainLimit::get().custom_data_limit >= data.variable_data.len() as u32, Error::<T>::TokenVariableDataLimitExceeded);1488 } else {1489 fail!(Error::<T>::NotNftDataUsedToMintNftCollectionToken);1490 }1491 },1492 CollectionMode::Fungible(_) => {1493 if let CreateItemData::Fungible(_) = data {1494 } else {1495 fail!(Error::<T>::NotFungibleDataUsedToMintFungibleCollectionToken);1496 }1497 },1498 CollectionMode::ReFungible(_) => {1499 if let CreateItemData::ReFungible(data) = data {15001501 1502 ensure!(ChainLimit::get().custom_data_limit >= data.const_data.len() as u32, Error::<T>::TokenConstDataLimitExceeded);1503 ensure!(ChainLimit::get().custom_data_limit >= data.variable_data.len() as u32, Error::<T>::TokenVariableDataLimitExceeded);1504 } else {1505 fail!(Error::<T>::NotReFungibleDataUsedToMintReFungibleCollectionToken);1506 }1507 },1508 _ => { fail!(Error::<T>::UnexpectedCollectionType); }1509 };15101511 Ok(())1512 }15131514 fn create_item_no_validation(collection_id: CollectionId, collection: &CollectionType<T::AccountId>, owner: T::AccountId, data: CreateItemData) -> DispatchResult {1515 match data1516 {1517 CreateItemData::NFT(data) => {1518 let item = NftItemType {1519 collection: collection_id,1520 owner,1521 const_data: data.const_data,1522 variable_data: data.variable_data1523 };15241525 Self::add_nft_item(item)?;1526 },1527 CreateItemData::Fungible(_) => {1528 let item = FungibleItemType {1529 collection: collection_id,1530 owner,1531 value: (10 as u128).pow(collection.decimal_points as u32)1532 };15331534 Self::add_fungible_item(item)?;1535 },1536 CreateItemData::ReFungible(data) => {1537 let mut owner_list = Vec::new();1538 let value = (10 as u128).pow(collection.decimal_points as u32);1539 owner_list.push(Ownership {owner: owner.clone(), fraction: value});15401541 let item = ReFungibleItemType {1542 collection: collection_id,1543 owner: owner_list,1544 const_data: data.const_data,1545 variable_data: data.variable_data1546 };15471548 Self::add_refungible_item(item)?;1549 }1550 };15511552 1553 Self::deposit_event(RawEvent::ItemCreated(collection_id, <ItemListIndex>::get(collection_id)));15541555 Ok(())1556 }15571558 fn add_fungible_item(item: FungibleItemType<T::AccountId>) -> DispatchResult {1559 let current_index = <ItemListIndex>::get(item.collection)1560 .checked_add(1)1561 .ok_or(Error::<T>::NumOverflow)?;1562 let itemcopy = item.clone();1563 let owner = item.owner.clone();15641565 Self::add_token_index(item.collection, current_index, owner.clone())?;15661567 <ItemListIndex>::insert(item.collection, current_index);1568 <FungibleItemList<T>>::insert(item.collection, current_index, itemcopy);15691570 1571 let v: Vec<BasketItem<T::AccountId, T::BlockNumber>> = Vec::new();1572 <FungibleTransferBasket<T>>::insert(item.collection, current_index, v);1573 1574 1575 let new_balance = <Balance<T>>::get(item.collection, owner.clone())1576 .checked_add(item.value)1577 .ok_or(Error::<T>::NumOverflow)?;1578 <Balance<T>>::insert(item.collection, owner.clone(), new_balance);15791580 Ok(())1581 }15821583 fn add_refungible_item(item: ReFungibleItemType<T::AccountId>) -> DispatchResult {1584 let current_index = <ItemListIndex>::get(item.collection)1585 .checked_add(1)1586 .ok_or(Error::<T>::NumOverflow)?;1587 let itemcopy = item.clone();15881589 let value = item.owner.first().unwrap().fraction;1590 let owner = item.owner.first().unwrap().owner.clone();15911592 Self::add_token_index(item.collection, current_index, owner.clone())?;15931594 <ItemListIndex>::insert(item.collection, current_index);1595 <ReFungibleItemList<T>>::insert(item.collection, current_index, itemcopy);15961597 1598 let block_number: T::BlockNumber = 0.into();1599 <ReFungibleTransferBasket<T>>::insert(item.collection, current_index, block_number);16001601 1602 let new_balance = <Balance<T>>::get(item.collection, owner.clone())1603 .checked_add(value)1604 .ok_or(Error::<T>::NumOverflow)?;1605 <Balance<T>>::insert(item.collection, owner.clone(), new_balance);16061607 Ok(())1608 }16091610 fn add_nft_item(item: NftItemType<T::AccountId>) -> DispatchResult {1611 let current_index = <ItemListIndex>::get(item.collection)1612 .checked_add(1)1613 .ok_or(Error::<T>::NumOverflow)?;16141615 let item_owner = item.owner.clone();1616 let collection_id = item.collection.clone();1617 Self::add_token_index(collection_id, current_index, item.owner.clone())?;16181619 <ItemListIndex>::insert(collection_id, current_index);1620 <NftItemList<T>>::insert(collection_id, current_index, item);16211622 1623 let block_number: T::BlockNumber = 0.into();1624 <NftTransferBasket<T>>::insert(collection_id, current_index, block_number);16251626 1627 let new_balance = <Balance<T>>::get(collection_id, item_owner.clone())1628 .checked_add(1)1629 .ok_or(Error::<T>::NumOverflow)?;1630 <Balance<T>>::insert(collection_id, item_owner.clone(), new_balance);16311632 Ok(())1633 }16341635 fn burn_refungible_item(1636 collection_id: CollectionId,1637 item_id: TokenId,1638 owner: T::AccountId,1639 ) -> DispatchResult {1640 ensure!(1641 <ReFungibleItemList<T>>::contains_key(collection_id, item_id),1642 Error::<T>::TokenNotFound1643 );1644 let collection = <ReFungibleItemList<T>>::get(collection_id, item_id);1645 let item = collection1646 .owner1647 .iter()1648 .filter(|&i| i.owner == owner)1649 .next()1650 .unwrap();1651 Self::remove_token_index(collection_id, item_id, owner.clone())?;16521653 1654 <ApprovedList<T>>::remove(collection_id, (item_id, owner.clone()));16551656 1657 let new_balance = <Balance<T>>::get(collection_id, item.owner.clone())1658 .checked_sub(item.fraction)1659 .ok_or(Error::<T>::NumOverflow)?;1660 <Balance<T>>::insert(collection_id, item.owner.clone(), new_balance);16611662 <ReFungibleItemList<T>>::remove(collection_id, item_id);16631664 Ok(())1665 }16661667 fn burn_nft_item(collection_id: CollectionId, item_id: TokenId) -> DispatchResult {1668 ensure!(1669 <NftItemList<T>>::contains_key(collection_id, item_id),1670 Error::<T>::TokenNotFound1671 );1672 let item = <NftItemList<T>>::get(collection_id, item_id);1673 Self::remove_token_index(collection_id, item_id, item.owner.clone())?;16741675 1676 <ApprovedList<T>>::remove(collection_id, (item_id, item.owner.clone()));16771678 1679 let new_balance = <Balance<T>>::get(collection_id, item.owner.clone())1680 .checked_sub(1)1681 .ok_or(Error::<T>::NumOverflow)?;1682 <Balance<T>>::insert(collection_id, item.owner.clone(), new_balance);1683 <NftItemList<T>>::remove(collection_id, item_id);16841685 Ok(())1686 }16871688 fn burn_fungible_item(collection_id: CollectionId, item_id: TokenId) -> DispatchResult {1689 ensure!(1690 <FungibleItemList<T>>::contains_key(collection_id, item_id),1691 Error::<T>::TokenNotFound1692 );1693 let item = <FungibleItemList<T>>::get(collection_id, item_id);1694 Self::remove_token_index(collection_id, item_id, item.owner.clone())?;16951696 1697 <ApprovedList<T>>::remove(collection_id, (item_id, item.owner.clone()));16981699 1700 let new_balance = <Balance<T>>::get(collection_id, item.owner.clone())1701 .checked_sub(item.value)1702 .ok_or(Error::<T>::NumOverflow)?;1703 <Balance<T>>::insert(collection_id, item.owner.clone(), new_balance);17041705 <FungibleItemList<T>>::remove(collection_id, item_id);17061707 Ok(())1708 }17091710 fn collection_exists(collection_id: CollectionId) -> DispatchResult {1711 ensure!(1712 <Collection<T>>::contains_key(collection_id),1713 Error::<T>::CollectionNotFound1714 );1715 Ok(())1716 }17171718 fn check_owner_permissions(collection_id: CollectionId, subject: T::AccountId) -> DispatchResult {1719 Self::collection_exists(collection_id)?;17201721 let target_collection = <Collection<T>>::get(collection_id);1722 ensure!(1723 subject == target_collection.owner,1724 Error::<T>::NoPermission1725 );17261727 Ok(())1728 }17291730 fn is_owner_or_admin_permissions(collection_id: CollectionId, subject: T::AccountId) -> bool {1731 let target_collection = <Collection<T>>::get(collection_id);1732 let mut result: bool = subject == target_collection.owner;1733 let exists = <AdminList<T>>::contains_key(collection_id);17341735 if !result & exists {1736 if <AdminList<T>>::get(collection_id).contains(&subject) {1737 result = true1738 }1739 }17401741 result1742 }17431744 fn check_owner_or_admin_permissions(1745 collection_id: CollectionId,1746 subject: T::AccountId,1747 ) -> DispatchResult {1748 Self::collection_exists(collection_id)?;1749 let result = Self::is_owner_or_admin_permissions(collection_id, subject.clone());17501751 ensure!(1752 result,1753 Error::<T>::NoPermission1754 );1755 Ok(())1756 }17571758 fn is_item_owner(subject: T::AccountId, collection_id: CollectionId, item_id: TokenId) -> bool {1759 let target_collection = <Collection<T>>::get(collection_id);17601761 match target_collection.mode {1762 CollectionMode::NFT => {1763 <NftItemList<T>>::get(collection_id, item_id).owner == subject1764 }1765 CollectionMode::Fungible(_) => {1766 <FungibleItemList<T>>::get(collection_id, item_id).owner == subject1767 }1768 CollectionMode::ReFungible(_) => {1769 <ReFungibleItemList<T>>::get(collection_id, item_id)1770 .owner1771 .iter()1772 .any(|i| i.owner == subject)1773 }1774 CollectionMode::Invalid => false,1775 }1776 }17771778 fn check_white_list(collection_id: CollectionId, address: &T::AccountId) -> DispatchResult {1779 let mes = Error::<T>::AddresNotInWhiteList;1780 ensure!(<WhiteList<T>>::contains_key(collection_id), mes);1781 let wl = <WhiteList<T>>::get(collection_id);1782 ensure!(wl.contains(address), mes);17831784 Ok(())1785 }17861787 fn transfer_fungible(1788 collection_id: CollectionId,1789 item_id: TokenId,1790 value: u128,1791 owner: T::AccountId,1792 new_owner: T::AccountId,1793 ) -> DispatchResult {1794 ensure!(1795 <FungibleItemList<T>>::contains_key(collection_id, item_id),1796 Error::<T>::TokenNotFound1797 );17981799 let full_item = <FungibleItemList<T>>::get(collection_id, item_id);1800 let amount = full_item.value;18011802 ensure!(amount >= value, Error::<T>::TokenValueTooLow);18031804 1805 let balance_old_owner = <Balance<T>>::get(collection_id, owner.clone())1806 .checked_sub(value)1807 .ok_or(Error::<T>::NumOverflow)?;1808 <Balance<T>>::insert(collection_id, owner.clone(), balance_old_owner);18091810 let mut new_owner_account_id = 0;1811 let new_owner_items = <AddressTokens<T>>::get(collection_id, new_owner.clone());1812 if new_owner_items.len() > 0 {1813 new_owner_account_id = new_owner_items[0];1814 }18151816 1817 if amount == value && new_owner_account_id == 0 {1818 1819 1820 let mut new_full_item = full_item.clone();1821 new_full_item.owner = new_owner.clone();1822 <FungibleItemList<T>>::insert(collection_id, item_id, new_full_item);18231824 1825 let balance_new_owner = <Balance<T>>::get(collection_id, new_owner.clone())1826 .checked_add(value)1827 .ok_or(Error::<T>::NumOverflow)?;1828 <Balance<T>>::insert(collection_id, new_owner.clone(), balance_new_owner);18291830 1831 Self::move_token_index(collection_id, item_id, owner.clone(), new_owner.clone())?;1832 } else {1833 let mut new_full_item = full_item.clone();1834 new_full_item.value -= value;18351836 1837 if new_owner_account_id > 0 {1838 1839 let mut item = <FungibleItemList<T>>::get(collection_id, new_owner_account_id);1840 item.value += value;18411842 1843 let balance_new_owner = <Balance<T>>::get(collection_id, new_owner.clone())1844 .checked_add(value)1845 .ok_or(Error::<T>::NumOverflow)?;1846 <Balance<T>>::insert(collection_id, new_owner.clone(), balance_new_owner);18471848 <FungibleItemList<T>>::insert(collection_id, new_owner_account_id, item);1849 } else {1850 1851 let item = FungibleItemType {1852 collection: collection_id,1853 owner: new_owner.clone(),1854 value1855 };18561857 Self::add_fungible_item(item)?;1858 }18591860 if amount == value {1861 Self::remove_token_index(collection_id, item_id, full_item.owner.clone())?;18621863 1864 <ApprovedList<T>>::remove(collection_id, (item_id, full_item.owner.clone()));1865 <FungibleItemList<T>>::remove(collection_id, item_id);1866 }18671868 <FungibleItemList<T>>::insert(collection_id, item_id, new_full_item);1869 }18701871 Ok(())1872 }18731874 fn transfer_refungible(1875 collection_id: CollectionId,1876 item_id: TokenId,1877 value: u128,1878 owner: T::AccountId,1879 new_owner: T::AccountId,1880 ) -> DispatchResult {1881 ensure!(1882 <ReFungibleItemList<T>>::contains_key(collection_id, item_id),1883 Error::<T>::TokenNotFound1884 );18851886 let full_item = <ReFungibleItemList<T>>::get(collection_id, item_id);1887 let item = full_item1888 .owner1889 .iter()1890 .filter(|i| i.owner == owner)1891 .next()1892 .ok_or(Error::<T>::NumOverflow)?;1893 let amount = item.fraction;18941895 ensure!(amount >= value, Error::<T>::TokenValueTooLow);18961897 1898 let balance_old_owner = <Balance<T>>::get(collection_id, item.owner.clone())1899 .checked_sub(value)1900 .ok_or(Error::<T>::NumOverflow)?;1901 <Balance<T>>::insert(collection_id, item.owner.clone(), balance_old_owner);19021903 let balance_new_owner = <Balance<T>>::get(collection_id, new_owner.clone())1904 .checked_add(value)1905 .ok_or(Error::<T>::NumOverflow)?;1906 <Balance<T>>::insert(collection_id, new_owner.clone(), balance_new_owner);19071908 let old_owner = item.owner.clone();1909 let new_owner_has_account = full_item.owner.iter().any(|i| i.owner == new_owner);19101911 1912 if amount == value && !new_owner_has_account {1913 1914 1915 let mut new_full_item = full_item.clone();1916 new_full_item1917 .owner1918 .iter_mut()1919 .find(|i| i.owner == owner)1920 .unwrap()1921 .owner = new_owner.clone();1922 <ReFungibleItemList<T>>::insert(collection_id, item_id, new_full_item);19231924 1925 Self::move_token_index(collection_id, item_id, old_owner.clone(), new_owner.clone())?;1926 } else {1927 let mut new_full_item = full_item.clone();1928 new_full_item1929 .owner1930 .iter_mut()1931 .find(|i| i.owner == owner)1932 .unwrap()1933 .fraction -= value;19341935 1936 if new_owner_has_account {1937 1938 new_full_item1939 .owner1940 .iter_mut()1941 .find(|i| i.owner == new_owner)1942 .unwrap()1943 .fraction += value;1944 } else {1945 1946 new_full_item.owner.push(Ownership {1947 owner: new_owner.clone(),1948 fraction: value,1949 });1950 Self::add_token_index(collection_id, item_id, new_owner.clone())?;1951 }19521953 <ReFungibleItemList<T>>::insert(collection_id, item_id, new_full_item);1954 }19551956 Ok(())1957 }19581959 fn transfer_nft(1960 collection_id: CollectionId,1961 item_id: TokenId,1962 sender: T::AccountId,1963 new_owner: T::AccountId,1964 ) -> DispatchResult {1965 ensure!(1966 <NftItemList<T>>::contains_key(collection_id, item_id),1967 Error::<T>::TokenNotFound1968 );19691970 let mut item = <NftItemList<T>>::get(collection_id, item_id);19711972 ensure!(1973 sender == item.owner,1974 Error::<T>::MustBeTokenOwner1975 );19761977 1978 let balance_old_owner = <Balance<T>>::get(collection_id, item.owner.clone())1979 .checked_sub(1)1980 .ok_or(Error::<T>::NumOverflow)?;1981 <Balance<T>>::insert(collection_id, item.owner.clone(), balance_old_owner);19821983 let balance_new_owner = <Balance<T>>::get(collection_id, new_owner.clone())1984 .checked_add(1)1985 .ok_or(Error::<T>::NumOverflow)?;1986 <Balance<T>>::insert(collection_id, new_owner.clone(), balance_new_owner);19871988 1989 let old_owner = item.owner.clone();1990 item.owner = new_owner.clone();1991 <NftItemList<T>>::insert(collection_id, item_id, item);19921993 1994 Self::move_token_index(collection_id, item_id, old_owner.clone(), new_owner.clone())?;19951996 1997 <ApprovedList<T>>::remove(collection_id, (item_id, old_owner));1998 Ok(())1999 }2000 2001 fn item_exists(2002 collection_id: CollectionId,2003 item_id: TokenId,2004 mode: &CollectionMode2005 ) -> DispatchResult {2006 match mode {2007 CollectionMode::NFT => ensure!(<NftItemList<T>>::contains_key(collection_id, item_id), Error::<T>::TokenNotFound),2008 CollectionMode::ReFungible(_) => ensure!(<ReFungibleItemList<T>>::contains_key(collection_id, item_id), Error::<T>::TokenNotFound),2009 CollectionMode::Fungible(_) => ensure!(<FungibleItemList<T>>::contains_key(collection_id, item_id), Error::<T>::TokenNotFound),2010 _ => ()2011 };2012 2013 Ok(())2014 }20152016 fn set_re_fungible_variable_data(2017 collection_id: CollectionId,2018 item_id: TokenId,2019 data: Vec<u8>2020 ) -> DispatchResult {2021 let mut item = <ReFungibleItemList<T>>::get(collection_id, item_id);20222023 item.variable_data = data;20242025 <ReFungibleItemList<T>>::insert(collection_id, item_id, item);20262027 Ok(())2028 }20292030 fn set_nft_variable_data(2031 collection_id: CollectionId,2032 item_id: TokenId,2033 data: Vec<u8>2034 ) -> DispatchResult {2035 let mut item = <NftItemList<T>>::get(collection_id, item_id);2036 2037 item.variable_data = data;20382039 <NftItemList<T>>::insert(collection_id, item_id, item);2040 2041 Ok(())2042 }20432044 fn init_collection(item: &CollectionType<T::AccountId>) {2045 2046 assert!(2047 item.decimal_points <= MAX_DECIMAL_POINTS,2048 "decimal_points parameter must be lower than MAX_DECIMAL_POINTS"2049 );2050 assert!(2051 item.name.len() <= 64,2052 "Collection name can not be longer than 63 char"2053 );2054 assert!(2055 item.name.len() <= 256,2056 "Collection description can not be longer than 255 char"2057 );2058 assert!(2059 item.token_prefix.len() <= 16,2060 "Token prefix can not be longer than 15 char"2061 );20622063 2064 let next_id = CreatedCollectionCount::get()2065 .checked_add(1)2066 .unwrap();20672068 CreatedCollectionCount::put(next_id);2069 }20702071 fn init_nft_token(item: &NftItemType<T::AccountId>) {2072 let current_index = <ItemListIndex>::get(item.collection)2073 .checked_add(1)2074 .unwrap();20752076 let item_owner = item.owner.clone();2077 let collection_id = item.collection.clone();2078 Self::add_token_index(collection_id, current_index, item.owner.clone()).unwrap();20792080 <ItemListIndex>::insert(collection_id, current_index);20812082 2083 let new_balance = <Balance<T>>::get(collection_id, item_owner.clone())2084 .checked_add(1)2085 .unwrap();2086 <Balance<T>>::insert(collection_id, item_owner.clone(), new_balance);2087 }20882089 fn init_fungible_token(item: &FungibleItemType<T::AccountId>) {2090 let current_index = <ItemListIndex>::get(item.collection)2091 .checked_add(1)2092 .unwrap();2093 let owner = item.owner.clone();20942095 Self::add_token_index(item.collection, current_index, owner.clone()).unwrap();20962097 <ItemListIndex>::insert(item.collection, current_index);20982099 2100 let new_balance = <Balance<T>>::get(item.collection, owner.clone())2101 .checked_add(item.value)2102 .unwrap();2103 <Balance<T>>::insert(item.collection, owner.clone(), new_balance);2104 }21052106 fn init_refungible_token(item: &ReFungibleItemType<T::AccountId>) {2107 let current_index = <ItemListIndex>::get(item.collection)2108 .checked_add(1)2109 .unwrap();21102111 let value = item.owner.first().unwrap().fraction;2112 let owner = item.owner.first().unwrap().owner.clone();21132114 Self::add_token_index(item.collection, current_index, owner.clone()).unwrap();21152116 <ItemListIndex>::insert(item.collection, current_index);21172118 2119 let new_balance = <Balance<T>>::get(item.collection, owner.clone())2120 .checked_add(value)2121 .unwrap();2122 <Balance<T>>::insert(item.collection, owner.clone(), new_balance);2123 }21242125 fn add_token_index(collection_id: CollectionId, item_index: TokenId, owner: T::AccountId) -> DispatchResult {21262127 2128 if <AccountItemCount<T>>::contains_key(owner.clone()) {21292130 2131 let count = <AccountItemCount<T>>::get(owner.clone());2132 ensure!(count < ChainLimit::get().account_token_ownership_limit, Error::<T>::AddressOwnershipLimitExceeded);21332134 <AccountItemCount<T>>::insert(owner.clone(), count2135 .checked_add(1)2136 .ok_or(Error::<T>::NumOverflow)?);2137 }2138 else {2139 <AccountItemCount<T>>::insert(owner.clone(), 1);2140 }21412142 let list_exists = <AddressTokens<T>>::contains_key(collection_id, owner.clone());2143 if list_exists {2144 let mut list = <AddressTokens<T>>::get(collection_id, owner.clone());2145 let item_contains = list.contains(&item_index.clone());21462147 if !item_contains {2148 list.push(item_index.clone());2149 }21502151 <AddressTokens<T>>::insert(collection_id, owner.clone(), list);2152 } else {2153 let mut itm = Vec::new();2154 itm.push(item_index.clone());2155 <AddressTokens<T>>::insert(collection_id, owner, itm);2156 2157 }21582159 Ok(())2160 }21612162 fn remove_token_index(2163 collection_id: CollectionId,2164 item_index: TokenId,2165 owner: T::AccountId,2166 ) -> DispatchResult {21672168 2169 <AccountItemCount<T>>::insert(owner.clone(), 2170 <AccountItemCount<T>>::get(owner.clone())2171 .checked_sub(1)2172 .ok_or(Error::<T>::NumOverflow)?);217321742175 let list_exists = <AddressTokens<T>>::contains_key(collection_id, owner.clone());2176 if list_exists {2177 let mut list = <AddressTokens<T>>::get(collection_id, owner.clone());2178 let item_contains = list.contains(&item_index.clone());21792180 if item_contains {2181 list.retain(|&item| item != item_index);2182 <AddressTokens<T>>::insert(collection_id, owner, list);2183 }2184 }21852186 Ok(())2187 }21882189 fn move_token_index(2190 collection_id: CollectionId,2191 item_index: TokenId,2192 old_owner: T::AccountId,2193 new_owner: T::AccountId,2194 ) -> DispatchResult {2195 Self::remove_token_index(collection_id, item_index, old_owner)?;2196 Self::add_token_index(collection_id, item_index, new_owner)?;21972198 Ok(())2199 }2200}2201220222032204220522062207pub type Multiplier = FixedU128;22082209type BalanceOf<T> = <<T as transaction_payment::Trait>::Currency as Currency<2210 <T as system::Trait>::AccountId,2211>>::Balance;2212type NegativeImbalanceOf<T> = <<T as transaction_payment::Trait>::Currency as Currency<2213 <T as system::Trait>::AccountId,2214>>::NegativeImbalance;2215221622172218#[derive(Encode, Decode, Clone, Eq, PartialEq)]2219pub struct ChargeTransactionPayment<T: Trait + Send + Sync>(2220 #[codec(compact)] BalanceOf<T>2221);22222223impl<T: Trait + Send + Sync> sp_std::fmt::Debug2224 for ChargeTransactionPayment<T>2225{2226 #[cfg(feature = "std")]2227 fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {2228 write!(f, "ChargeTransactionPayment<{:?}>", self.0)2229 }2230 #[cfg(not(feature = "std"))]2231 fn fmt(&self, _: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {2232 Ok(())2233 }2234}22352236impl<T: Trait + Send + Sync> ChargeTransactionPayment<T>2237where2238 T::Call: Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo> + IsSubType<Call<T>> + IsSubType<pallet_contracts::Call<T>>,2239 BalanceOf<T>: Send + Sync + FixedPointOperand,2240{2241 2242 pub fn from(fee: BalanceOf<T>) -> Self {2243 Self(fee)2244 }22452246 pub fn traditional_fee(2247 len: usize,2248 info: &DispatchInfoOf<T::Call>,2249 tip: BalanceOf<T>,2250 ) -> BalanceOf<T>2251 where2252 T::Call: Dispatchable<Info = DispatchInfo>,2253 {2254 <transaction_payment::Module<T>>::compute_fee(len as u32, info, tip)2255 }22562257 fn withdraw_fee(2258 &self,2259 who: &T::AccountId,2260 call: &T::Call,2261 info: &DispatchInfoOf<T::Call>,2262 len: usize,2263 ) -> Result<(BalanceOf<T>, Option<NegativeImbalanceOf<T>>), TransactionValidityError> {2264 let tip = self.0;22652266 2267 2268 2269 2270 2271 2272 2273 let fee = Self::traditional_fee(len, info, tip);22742275 2276 2277 let mut sponsor: T::AccountId = match IsSubType::<Call<T>>::is_sub_type(call) {2278 Some(Call::create_item(collection_id, _owner, _properties)) => {22792280 2281 if <Collection<T>>::get(collection_id).limits.sponsored_data_size >= (_properties.len() as u32)2282 {2283 <Collection<T>>::get(collection_id).sponsor2284 } else {2285 T::AccountId::default()2286 }2287 }2288 Some(Call::transfer(_new_owner, collection_id, _item_id, _value)) => {2289 2290 let _collection_limits = <Collection<T>>::get(collection_id).limits;2291 let _collection_mode = <Collection<T>>::get(collection_id).mode;22922293 2294 let sponsor_transfer = match _collection_mode {2295 CollectionMode::NFT => {22962297 2298 let limit: u32 = if _collection_limits.sponsor_transfer_timeout > 0 {2299 _collection_limits.sponsor_transfer_timeout2300 } else {2301 ChainLimit::get().nft_sponsor_transfer_timeout2302 };23032304 let basket = <NftTransferBasket<T>>::get(collection_id, _item_id);2305 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;2306 let limit_time = basket + limit.into();2307 if block_number >= limit_time {2308 <NftTransferBasket<T>>::insert(collection_id, _item_id, block_number);2309 true2310 }2311 else {2312 false2313 }2314 }2315 CollectionMode::Fungible(_) => {23162317 2318 let limit: u32 = if _collection_limits.sponsor_transfer_timeout > 0 {2319 _collection_limits.sponsor_transfer_timeout2320 } else {2321 ChainLimit::get().fungible_sponsor_transfer_timeout2322 };23232324 let mut basket = <FungibleTransferBasket<T>>::get(collection_id, _item_id);2325 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;2326 if basket.iter().any(|i| i.address == _new_owner.clone())2327 {2328 let item = basket.iter_mut().find(|i| i.address == _new_owner.clone()).unwrap().clone();2329 let limit_time = item.start_block + limit.into();2330 if block_number >= limit_time {2331 basket.retain(|x| x.address == item.address);2332 basket.push(BasketItem { start_block: block_number, address: _new_owner.clone() });2333 <FungibleTransferBasket<T>>::insert(collection_id, _item_id, basket);2334 true2335 }2336 else {2337 false2338 }2339 }2340 else {2341 basket.push(BasketItem { start_block: block_number, address: _new_owner.clone()});2342 true2343 }2344 }2345 CollectionMode::ReFungible(_) => {23462347 2348 let limit: u32 = if _collection_limits.sponsor_transfer_timeout > 0 {2349 _collection_limits.sponsor_transfer_timeout2350 } else {2351 ChainLimit::get().refungible_sponsor_transfer_timeout2352 };23532354 let basket = <ReFungibleTransferBasket<T>>::get(collection_id, _item_id);2355 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;2356 let limit_time = basket + limit.into();2357 if block_number >= limit_time {2358 <ReFungibleTransferBasket<T>>::insert(collection_id, _item_id, block_number);2359 true2360 } else {2361 false2362 }2363 }2364 _ => {2365 false2366 },2367 };23682369 if !sponsor_transfer {2370 T::AccountId::default()2371 } else {2372 <Collection<T>>::get(collection_id).sponsor2373 }2374 }23752376 _ => T::AccountId::default(),2377 };23782379 2380 sponsor = match IsSubType::<pallet_contracts::Call<T>>::is_sub_type(call) {23812382 2383 Some(pallet_contracts::Call::instantiate(_endowment, _gas_limit, code_hash, data)) => {23842385 let new_contract_address = <T as pallet_contracts::Trait>::DetermineContractAddress::contract_address_for(2386 code_hash,2387 &data,2388 &who,2389 );2390 <ContractOwner<T>>::insert(new_contract_address.clone(), who.clone());23912392 T::AccountId::default()2393 },23942395 2396 Some(pallet_contracts::Call::call(dest, _value, _gas_limit, _data)) => {23972398 let called_contract: T::AccountId = T::Lookup::lookup((*dest).clone()).unwrap_or(T::AccountId::default());23992400 let mut sponsor_transfer = false;2401 if <ContractSponsoringRateLimit<T>>::contains_key(called_contract.clone()) {2402 let last_tx_block = <ContractSponsorBasket<T>>::get((&called_contract, &who));2403 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;2404 let rate_limit = <ContractSponsoringRateLimit<T>>::get(&called_contract);2405 let limit_time = last_tx_block + rate_limit;24062407 if block_number >= limit_time {2408 <ContractSponsorBasket<T>>::insert((called_contract.clone(), who.clone()), block_number);2409 sponsor_transfer = true;2410 }2411 } else {2412 sponsor_transfer = false;2413 }2414 2415 2416 let mut sp = T::AccountId::default();2417 if sponsor_transfer {2418 if <ContractSelfSponsoring<T>>::contains_key(called_contract.clone()) {2419 if <ContractSelfSponsoring<T>>::get(called_contract.clone()) {2420 sp = called_contract;2421 }2422 }2423 }24242425 sp2426 },24272428 _ => sponsor,2429 };24302431 let mut who_pays_fee: T::AccountId = sponsor.clone();2432 if sponsor == T::AccountId::default() {2433 who_pays_fee = who.clone();2434 }24352436 2437 if fee.is_zero() {2438 return Ok((fee, None));2439 }24402441 match <T as transaction_payment::Trait>::Currency::withdraw(2442 &who_pays_fee,2443 fee,2444 if tip.is_zero() {2445 WithdrawReason::TransactionPayment.into()2446 } else {2447 WithdrawReason::TransactionPayment | WithdrawReason::Tip2448 },2449 ExistenceRequirement::KeepAlive,2450 ) {2451 Ok(imbalance) => Ok((fee, Some(imbalance))),2452 Err(_) => Err(InvalidTransaction::Payment.into()),2453 }2454 }2455}245624572458impl<T: Trait + Send + Sync> SignedExtension2459 for ChargeTransactionPayment<T>2460where2461 BalanceOf<T>: Send + Sync + From<u64> + FixedPointOperand,2462 T::Call: Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo> + IsSubType<Call<T>> + IsSubType<pallet_contracts::Call<T>>,2463{2464 const IDENTIFIER: &'static str = "ChargeTransactionPayment";2465 type AccountId = T::AccountId;2466 type Call = T::Call;2467 type AdditionalSigned = ();2468 type Pre = (2469 BalanceOf<T>,2470 Self::AccountId,2471 Option<NegativeImbalanceOf<T>>,2472 BalanceOf<T>,2473 );2474 fn additional_signed(&self) -> sp_std::result::Result<(), TransactionValidityError> {2475 Ok(())2476 }24772478 fn validate(2479 &self,2480 _who: &Self::AccountId,2481 _call: &Self::Call,2482 _info: &DispatchInfoOf<Self::Call>,2483 _len: usize,2484 ) -> TransactionValidity {2485 Ok(ValidTransaction::default())2486 }24872488 fn pre_dispatch(2489 self,2490 who: &Self::AccountId,2491 call: &Self::Call,2492 info: &DispatchInfoOf<Self::Call>,2493 len: usize,2494 ) -> Result<Self::Pre, TransactionValidityError> {2495 let (fee, imbalance) = self.withdraw_fee(who, call, info, len)?;2496 Ok((self.0, who.clone(), imbalance, fee))2497 }24982499 fn post_dispatch(2500 pre: Self::Pre,2501 info: &DispatchInfoOf<Self::Call>,2502 post_info: &PostDispatchInfoOf<Self::Call>,2503 len: usize,2504 _result: &DispatchResult,2505 ) -> Result<(), TransactionValidityError> {2506 let (tip, who, imbalance, fee) = pre;2507 if let Some(payed) = imbalance {2508 let actual_fee = <transaction_payment::Module<T>>::compute_actual_fee(2509 len as u32, info, post_info, tip,2510 );2511 let refund = fee.saturating_sub(actual_fee);2512 let actual_payment =2513 match <T as transaction_payment::Trait>::Currency::deposit_into_existing(2514 &who, refund,2515 ) {2516 Ok(refund_imbalance) => {2517 2518 2519 match payed.offset(refund_imbalance) {2520 Ok(actual_payment) => actual_payment,2521 Err(_) => return Err(InvalidTransaction::Payment.into()),2522 }2523 }2524 2525 2526 Err(_) => payed,2527 };2528 let imbalances = actual_payment.split(tip);2529 <T as transaction_payment::Trait>::OnTransactionPayment::on_unbalanceds(2530 Some(imbalances.0).into_iter().chain(Some(imbalances.1)),2531 );2532 }2533 Ok(())2534 }2535}25362537