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)?;10521053 1054 let target_collection = <Collection<T>>::get(collection_id);1055 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||1056 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1057 Error::<T>::NoPermission);10581059 if target_collection.access == AccessMode::WhiteList {1060 Self::check_white_list(collection_id, &sender)?;1061 Self::check_white_list(collection_id, &recipient)?;1062 }10631064 match target_collection.mode1065 {1066 CollectionMode::NFT => Self::transfer_nft(collection_id, item_id, sender.clone(), recipient)?,1067 CollectionMode::Fungible(_) => Self::transfer_fungible(collection_id, item_id, value, sender.clone(), recipient)?,1068 CollectionMode::ReFungible(_) => Self::transfer_refungible(collection_id, item_id, value, sender.clone(), recipient)?,1069 _ => ()1070 };10711072 Ok(())1073 }10741075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 #[weight = T::WeightInfo::approve()]1091 pub fn approve(origin, approved: T::AccountId, collection_id: CollectionId, item_id: TokenId) -> DispatchResult {10921093 let sender = ensure_signed(origin)?;10941095 1096 let target_collection = <Collection<T>>::get(collection_id);1097 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||1098 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1099 Error::<T>::NoPermission);11001101 if target_collection.access == AccessMode::WhiteList {1102 Self::check_white_list(collection_id, &sender)?;1103 Self::check_white_list(collection_id, &approved)?;1104 }11051106 1107 let amount = 100000000;11081109 let list_exists = <ApprovedList<T>>::contains_key(collection_id, (item_id, sender.clone()));1110 if list_exists {11111112 let mut list = <ApprovedList<T>>::get(collection_id, (item_id, sender.clone()));1113 let item_contains = list.iter().any(|i| i.approved == approved);11141115 if !item_contains {1116 list.push(ApprovePermissions { approved: approved.clone(), amount: amount });1117 <ApprovedList<T>>::insert(collection_id, (item_id, sender.clone()), list);1118 }1119 } else {11201121 let mut list = Vec::new();1122 list.push(ApprovePermissions { approved: approved.clone(), amount: amount });1123 <ApprovedList<T>>::insert(collection_id, (item_id, sender.clone()), list);1124 }11251126 Ok(())1127 }1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 #[weight = T::WeightInfo::transfer_from()]1149 pub fn transfer_from(origin, from: T::AccountId, recipient: T::AccountId, collection_id: CollectionId, item_id: TokenId, value: u128 ) -> DispatchResult {11501151 let sender = ensure_signed(origin)?;1152 let mut appoved_transfer = false;11531154 1155 if <ApprovedList<T>>::contains_key(collection_id, (item_id, from.clone())) {1156 let list_itm = <ApprovedList<T>>::get(collection_id, (item_id, from.clone()));1157 let opt_item = list_itm.iter().find(|i| i.approved == sender.clone());1158 if opt_item.is_some()1159 {1160 appoved_transfer = true;1161 ensure!(opt_item.unwrap().amount >= value, Error::<T>::TokenValueNotEnough);1162 }1163 }11641165 1166 let target_collection = <Collection<T>>::get(collection_id);1167 ensure!(appoved_transfer || Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1168 Error::<T>::NoPermission);11691170 if target_collection.access == AccessMode::WhiteList {1171 Self::check_white_list(collection_id, &sender)?;1172 Self::check_white_list(collection_id, &recipient)?;1173 }11741175 1176 let approve_list: Vec<ApprovePermissions<T::AccountId>> = <ApprovedList<T>>::get(collection_id, (item_id, from.clone()))1177 .into_iter().filter(|i| i.approved != sender.clone()).collect();1178 <ApprovedList<T>>::insert(collection_id, (item_id, from.clone()), approve_list);117911801181 match target_collection.mode1182 {1183 CollectionMode::NFT => Self::transfer_nft(collection_id, item_id, from, recipient)?,1184 CollectionMode::Fungible(_) => Self::transfer_fungible(collection_id, item_id, value, from.clone(), recipient)?,1185 CollectionMode::ReFungible(_) => Self::transfer_refungible(collection_id, item_id, value, from.clone(), recipient)?,1186 _ => ()1187 };11881189 Ok(())1190 }11911192 1193 #[weight = 0]1194 pub fn safe_transfer_from(origin, collection_id: CollectionId, item_id: TokenId, new_owner: T::AccountId) -> DispatchResult {11951196 1197 1198 1199 12001201 12021203 12041205 Ok(())1206 }12071208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 #[weight = T::WeightInfo::set_variable_meta_data()]1221 pub fn set_variable_meta_data (1222 origin,1223 collection_id: CollectionId,1224 item_id: TokenId,1225 data: Vec<u8>1226 ) -> DispatchResult {1227 let sender = ensure_signed(origin)?;1228 1229 Self::collection_exists(collection_id)?;1230 1231 ensure!(ChainLimit::get().custom_data_limit >= data.len() as u32, Error::<T>::TokenVariableDataLimitExceeded);12321233 1234 let target_collection = <Collection<T>>::get(collection_id);1235 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||1236 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1237 Error::<T>::NoPermission);12381239 Self::item_exists(collection_id, item_id, &target_collection.mode)?;12401241 match target_collection.mode1242 {1243 CollectionMode::NFT => Self::set_nft_variable_data(collection_id, item_id, data)?,1244 CollectionMode::ReFungible(_) => Self::set_re_fungible_variable_data(collection_id, item_id, data)?,1245 CollectionMode::Fungible(_) => fail!(Error::<T>::CantStoreMetadataInFungibleTokens),1246 _ => fail!(Error::<T>::UnexpectedCollectionType)1247 };12481249 Ok(())1250 }1251 12521253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 #[weight = T::WeightInfo::set_offchain_schema()]1266 pub fn set_offchain_schema(1267 origin,1268 collection_id: CollectionId,1269 schema: Vec<u8>1270 ) -> DispatchResult {1271 let sender = ensure_signed(origin)?;1272 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;12731274 let mut target_collection = <Collection<T>>::get(collection_id);1275 target_collection.offchain_schema = schema;1276 <Collection<T>>::insert(collection_id, target_collection);12771278 Ok(())1279 }12801281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 #[weight = T::WeightInfo::set_const_on_chain_schema()]1294 pub fn set_const_on_chain_schema (1295 origin,1296 collection_id: CollectionId,1297 schema: Vec<u8>1298 ) -> DispatchResult {1299 let sender = ensure_signed(origin)?;1300 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;13011302 let mut target_collection = <Collection<T>>::get(collection_id);1303 target_collection.const_on_chain_schema = schema;1304 <Collection<T>>::insert(collection_id, target_collection);13051306 Ok(())1307 }13081309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 #[weight = T::WeightInfo::set_const_on_chain_schema()]1322 pub fn set_variable_on_chain_schema (1323 origin,1324 collection_id: CollectionId,1325 schema: Vec<u8>1326 ) -> DispatchResult {1327 let sender = ensure_signed(origin)?;1328 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;13291330 let mut target_collection = <Collection<T>>::get(collection_id);1331 target_collection.variable_on_chain_schema = schema;1332 <Collection<T>>::insert(collection_id, target_collection);13331334 Ok(())1335 }13361337 1338 #[weight = 0]1339 pub fn set_chain_limits(1340 origin,1341 limits: ChainLimits1342 ) -> DispatchResult {1343 ensure_root(origin)?;1344 <ChainLimit>::put(limits);1345 Ok(())1346 }13471348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 #[weight = T::WeightInfo::enable_contract_sponsoring()]1360 pub fn enable_contract_sponsoring(1361 origin,1362 contract_address: T::AccountId,1363 enable: bool1364 ) -> DispatchResult {13651366 let sender = ensure_signed(origin)?;13671368 #[cfg(feature = "runtime-benchmarks")]1369 <ContractOwner<T>>::insert(contract_address.clone(), sender.clone());13701371 let mut is_owner = false;1372 if <ContractOwner<T>>::contains_key(contract_address.clone()) {1373 let owner = <ContractOwner<T>>::get(&contract_address);1374 is_owner = sender == owner;1375 }1376 ensure!(is_owner, Error::<T>::NoPermission);13771378 <ContractSelfSponsoring<T>>::insert(contract_address, enable);1379 Ok(())1380 }13811382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 #[weight = 0]1400 pub fn set_contract_sponsoring_rate_limit(1401 origin,1402 contract_address: T::AccountId,1403 rate_limit: T::BlockNumber1404 ) -> DispatchResult {1405 let sender = ensure_signed(origin)?;1406 let mut is_owner = false;1407 if <ContractOwner<T>>::contains_key(contract_address.clone()) {1408 let owner = <ContractOwner<T>>::get(&contract_address);1409 is_owner = sender == owner;1410 }1411 ensure!(is_owner, Error::<T>::NoPermission);14121413 <ContractSponsoringRateLimit<T>>::insert(contract_address, rate_limit);1414 Ok(())1415 }14161417 #[weight = 0]1418 pub fn set_collection_limits(1419 origin,1420 collection_id: u32,1421 limits: CollectionLimits,1422 ) -> DispatchResult {1423 let sender = ensure_signed(origin)?;1424 Self::check_owner_permissions(collection_id, sender.clone())?;14251426 let mut target_collection = <Collection<T>>::get(collection_id);1427 target_collection.limits = limits;1428 <Collection<T>>::insert(collection_id, target_collection);14291430 Ok(())1431 } 1432 }1433}14341435impl<T: Trait> Module<T> {14361437 fn can_create_items_in_collection(collection_id: CollectionId, collection: &CollectionType<T::AccountId>, sender: &T::AccountId, owner: &T::AccountId) -> DispatchResult {14381439 if !Self::is_owner_or_admin_permissions(collection_id, sender.clone()) {14401441 1442 let total_items: u32 = ItemListIndex::get(collection_id);1443 let account_items: u32 = <AddressTokens<T>>::get(collection_id, sender.clone()).len() as u32;1444 ensure!(collection.limits.token_limit > total_items, Error::<T>::CollectionTokenLimitExceeded);1445 ensure!(collection.limits.account_token_ownership_limit > account_items, Error::<T>::AccountTokenLimitExceeded);1446 ensure!(collection.mint_mode == true, Error::<T>::PublicMintingNotAllowed);1447 Self::check_white_list(collection_id, owner)?;1448 Self::check_white_list(collection_id, sender)?;1449 }14501451 Ok(())1452 }14531454 fn validate_create_item_args(target_collection: &CollectionType<T::AccountId>, data: &CreateItemData) -> DispatchResult {1455 match target_collection.mode1456 {1457 CollectionMode::NFT => {1458 if let CreateItemData::NFT(data) = data {1459 1460 ensure!(ChainLimit::get().custom_data_limit >= data.const_data.len() as u32, Error::<T>::TokenConstDataLimitExceeded);1461 ensure!(ChainLimit::get().custom_data_limit >= data.variable_data.len() as u32, Error::<T>::TokenVariableDataLimitExceeded);1462 } else {1463 fail!(Error::<T>::NotNftDataUsedToMintNftCollectionToken);1464 }1465 },1466 CollectionMode::Fungible(_) => {1467 if let CreateItemData::Fungible(_) = data {1468 } else {1469 fail!(Error::<T>::NotFungibleDataUsedToMintFungibleCollectionToken);1470 }1471 },1472 CollectionMode::ReFungible(_) => {1473 if let CreateItemData::ReFungible(data) = data {14741475 1476 ensure!(ChainLimit::get().custom_data_limit >= data.const_data.len() as u32, Error::<T>::TokenConstDataLimitExceeded);1477 ensure!(ChainLimit::get().custom_data_limit >= data.variable_data.len() as u32, Error::<T>::TokenVariableDataLimitExceeded);1478 } else {1479 fail!(Error::<T>::NotReFungibleDataUsedToMintReFungibleCollectionToken);1480 }1481 },1482 _ => { fail!(Error::<T>::UnexpectedCollectionType); }1483 };14841485 Ok(())1486 }14871488 fn create_item_no_validation(collection_id: CollectionId, collection: &CollectionType<T::AccountId>, owner: T::AccountId, data: CreateItemData) -> DispatchResult {1489 match data1490 {1491 CreateItemData::NFT(data) => {1492 let item = NftItemType {1493 collection: collection_id,1494 owner,1495 const_data: data.const_data,1496 variable_data: data.variable_data1497 };14981499 Self::add_nft_item(item)?;1500 },1501 CreateItemData::Fungible(_) => {1502 let item = FungibleItemType {1503 collection: collection_id,1504 owner,1505 value: (10 as u128).pow(collection.decimal_points as u32)1506 };15071508 Self::add_fungible_item(item)?;1509 },1510 CreateItemData::ReFungible(data) => {1511 let mut owner_list = Vec::new();1512 let value = (10 as u128).pow(collection.decimal_points as u32);1513 owner_list.push(Ownership {owner: owner.clone(), fraction: value});15141515 let item = ReFungibleItemType {1516 collection: collection_id,1517 owner: owner_list,1518 const_data: data.const_data,1519 variable_data: data.variable_data1520 };15211522 Self::add_refungible_item(item)?;1523 }1524 };15251526 1527 Self::deposit_event(RawEvent::ItemCreated(collection_id, <ItemListIndex>::get(collection_id)));15281529 Ok(())1530 }15311532 fn add_fungible_item(item: FungibleItemType<T::AccountId>) -> DispatchResult {1533 let current_index = <ItemListIndex>::get(item.collection)1534 .checked_add(1)1535 .ok_or(Error::<T>::NumOverflow)?;1536 let itemcopy = item.clone();1537 let owner = item.owner.clone();15381539 Self::add_token_index(item.collection, current_index, owner.clone())?;15401541 <ItemListIndex>::insert(item.collection, current_index);1542 <FungibleItemList<T>>::insert(item.collection, current_index, itemcopy);15431544 1545 let v: Vec<BasketItem<T::AccountId, T::BlockNumber>> = Vec::new();1546 <FungibleTransferBasket<T>>::insert(item.collection, current_index, v);1547 1548 1549 let new_balance = <Balance<T>>::get(item.collection, owner.clone())1550 .checked_add(item.value)1551 .ok_or(Error::<T>::NumOverflow)?;1552 <Balance<T>>::insert(item.collection, owner.clone(), new_balance);15531554 Ok(())1555 }15561557 fn add_refungible_item(item: ReFungibleItemType<T::AccountId>) -> DispatchResult {1558 let current_index = <ItemListIndex>::get(item.collection)1559 .checked_add(1)1560 .ok_or(Error::<T>::NumOverflow)?;1561 let itemcopy = item.clone();15621563 let value = item.owner.first().unwrap().fraction;1564 let owner = item.owner.first().unwrap().owner.clone();15651566 Self::add_token_index(item.collection, current_index, owner.clone())?;15671568 <ItemListIndex>::insert(item.collection, current_index);1569 <ReFungibleItemList<T>>::insert(item.collection, current_index, itemcopy);15701571 1572 let block_number: T::BlockNumber = 0.into();1573 <ReFungibleTransferBasket<T>>::insert(item.collection, current_index, block_number);15741575 1576 let new_balance = <Balance<T>>::get(item.collection, owner.clone())1577 .checked_add(value)1578 .ok_or(Error::<T>::NumOverflow)?;1579 <Balance<T>>::insert(item.collection, owner.clone(), new_balance);15801581 Ok(())1582 }15831584 fn add_nft_item(item: NftItemType<T::AccountId>) -> DispatchResult {1585 let current_index = <ItemListIndex>::get(item.collection)1586 .checked_add(1)1587 .ok_or(Error::<T>::NumOverflow)?;15881589 let item_owner = item.owner.clone();1590 let collection_id = item.collection.clone();1591 Self::add_token_index(collection_id, current_index, item.owner.clone())?;15921593 <ItemListIndex>::insert(collection_id, current_index);1594 <NftItemList<T>>::insert(collection_id, current_index, item);15951596 1597 let block_number: T::BlockNumber = 0.into();1598 <NftTransferBasket<T>>::insert(collection_id, current_index, block_number);15991600 1601 let new_balance = <Balance<T>>::get(collection_id, item_owner.clone())1602 .checked_add(1)1603 .ok_or(Error::<T>::NumOverflow)?;1604 <Balance<T>>::insert(collection_id, item_owner.clone(), new_balance);16051606 Ok(())1607 }16081609 fn burn_refungible_item(1610 collection_id: CollectionId,1611 item_id: TokenId,1612 owner: T::AccountId,1613 ) -> DispatchResult {1614 ensure!(1615 <ReFungibleItemList<T>>::contains_key(collection_id, item_id),1616 Error::<T>::TokenNotFound1617 );1618 let collection = <ReFungibleItemList<T>>::get(collection_id, item_id);1619 let item = collection1620 .owner1621 .iter()1622 .filter(|&i| i.owner == owner)1623 .next()1624 .unwrap();1625 Self::remove_token_index(collection_id, item_id, owner.clone())?;16261627 1628 <ApprovedList<T>>::remove(collection_id, (item_id, owner.clone()));16291630 1631 let new_balance = <Balance<T>>::get(collection_id, item.owner.clone())1632 .checked_sub(item.fraction)1633 .ok_or(Error::<T>::NumOverflow)?;1634 <Balance<T>>::insert(collection_id, item.owner.clone(), new_balance);16351636 <ReFungibleItemList<T>>::remove(collection_id, item_id);16371638 Ok(())1639 }16401641 fn burn_nft_item(collection_id: CollectionId, item_id: TokenId) -> DispatchResult {1642 ensure!(1643 <NftItemList<T>>::contains_key(collection_id, item_id),1644 Error::<T>::TokenNotFound1645 );1646 let item = <NftItemList<T>>::get(collection_id, item_id);1647 Self::remove_token_index(collection_id, item_id, item.owner.clone())?;16481649 1650 <ApprovedList<T>>::remove(collection_id, (item_id, item.owner.clone()));16511652 1653 let new_balance = <Balance<T>>::get(collection_id, item.owner.clone())1654 .checked_sub(1)1655 .ok_or(Error::<T>::NumOverflow)?;1656 <Balance<T>>::insert(collection_id, item.owner.clone(), new_balance);1657 <NftItemList<T>>::remove(collection_id, item_id);16581659 Ok(())1660 }16611662 fn burn_fungible_item(collection_id: CollectionId, item_id: TokenId) -> DispatchResult {1663 ensure!(1664 <FungibleItemList<T>>::contains_key(collection_id, item_id),1665 Error::<T>::TokenNotFound1666 );1667 let item = <FungibleItemList<T>>::get(collection_id, item_id);1668 Self::remove_token_index(collection_id, item_id, item.owner.clone())?;16691670 1671 <ApprovedList<T>>::remove(collection_id, (item_id, item.owner.clone()));16721673 1674 let new_balance = <Balance<T>>::get(collection_id, item.owner.clone())1675 .checked_sub(item.value)1676 .ok_or(Error::<T>::NumOverflow)?;1677 <Balance<T>>::insert(collection_id, item.owner.clone(), new_balance);16781679 <FungibleItemList<T>>::remove(collection_id, item_id);16801681 Ok(())1682 }16831684 fn collection_exists(collection_id: CollectionId) -> DispatchResult {1685 ensure!(1686 <Collection<T>>::contains_key(collection_id),1687 Error::<T>::CollectionNotFound1688 );1689 Ok(())1690 }16911692 fn check_owner_permissions(collection_id: CollectionId, subject: T::AccountId) -> DispatchResult {1693 Self::collection_exists(collection_id)?;16941695 let target_collection = <Collection<T>>::get(collection_id);1696 ensure!(1697 subject == target_collection.owner,1698 Error::<T>::NoPermission1699 );17001701 Ok(())1702 }17031704 fn is_owner_or_admin_permissions(collection_id: CollectionId, subject: T::AccountId) -> bool {1705 let target_collection = <Collection<T>>::get(collection_id);1706 let mut result: bool = subject == target_collection.owner;1707 let exists = <AdminList<T>>::contains_key(collection_id);17081709 if !result & exists {1710 if <AdminList<T>>::get(collection_id).contains(&subject) {1711 result = true1712 }1713 }17141715 result1716 }17171718 fn check_owner_or_admin_permissions(1719 collection_id: CollectionId,1720 subject: T::AccountId,1721 ) -> DispatchResult {1722 Self::collection_exists(collection_id)?;1723 let result = Self::is_owner_or_admin_permissions(collection_id, subject.clone());17241725 ensure!(1726 result,1727 Error::<T>::NoPermission1728 );1729 Ok(())1730 }17311732 fn is_item_owner(subject: T::AccountId, collection_id: CollectionId, item_id: TokenId) -> bool {1733 let target_collection = <Collection<T>>::get(collection_id);17341735 match target_collection.mode {1736 CollectionMode::NFT => {1737 <NftItemList<T>>::get(collection_id, item_id).owner == subject1738 }1739 CollectionMode::Fungible(_) => {1740 <FungibleItemList<T>>::get(collection_id, item_id).owner == subject1741 }1742 CollectionMode::ReFungible(_) => {1743 <ReFungibleItemList<T>>::get(collection_id, item_id)1744 .owner1745 .iter()1746 .any(|i| i.owner == subject)1747 }1748 CollectionMode::Invalid => false,1749 }1750 }17511752 fn check_white_list(collection_id: CollectionId, address: &T::AccountId) -> DispatchResult {1753 let mes = Error::<T>::AddresNotInWhiteList;1754 ensure!(<WhiteList<T>>::contains_key(collection_id), mes);1755 let wl = <WhiteList<T>>::get(collection_id);1756 ensure!(wl.contains(address), mes);17571758 Ok(())1759 }17601761 fn transfer_fungible(1762 collection_id: CollectionId,1763 item_id: TokenId,1764 value: u128,1765 owner: T::AccountId,1766 new_owner: T::AccountId,1767 ) -> DispatchResult {1768 ensure!(1769 <FungibleItemList<T>>::contains_key(collection_id, item_id),1770 Error::<T>::TokenNotFound1771 );17721773 let full_item = <FungibleItemList<T>>::get(collection_id, item_id);1774 let amount = full_item.value;17751776 ensure!(amount >= value, Error::<T>::TokenValueTooLow);17771778 1779 let balance_old_owner = <Balance<T>>::get(collection_id, owner.clone())1780 .checked_sub(value)1781 .ok_or(Error::<T>::NumOverflow)?;1782 <Balance<T>>::insert(collection_id, owner.clone(), balance_old_owner);17831784 let mut new_owner_account_id = 0;1785 let new_owner_items = <AddressTokens<T>>::get(collection_id, new_owner.clone());1786 if new_owner_items.len() > 0 {1787 new_owner_account_id = new_owner_items[0];1788 }17891790 1791 if amount == value && new_owner_account_id == 0 {1792 1793 1794 let mut new_full_item = full_item.clone();1795 new_full_item.owner = new_owner.clone();1796 <FungibleItemList<T>>::insert(collection_id, item_id, new_full_item);17971798 1799 let balance_new_owner = <Balance<T>>::get(collection_id, new_owner.clone())1800 .checked_add(value)1801 .ok_or(Error::<T>::NumOverflow)?;1802 <Balance<T>>::insert(collection_id, new_owner.clone(), balance_new_owner);18031804 1805 Self::move_token_index(collection_id, item_id, owner.clone(), new_owner.clone())?;1806 } else {1807 let mut new_full_item = full_item.clone();1808 new_full_item.value -= value;18091810 1811 if new_owner_account_id > 0 {1812 1813 let mut item = <FungibleItemList<T>>::get(collection_id, new_owner_account_id);1814 item.value += value;18151816 1817 let balance_new_owner = <Balance<T>>::get(collection_id, new_owner.clone())1818 .checked_add(value)1819 .ok_or(Error::<T>::NumOverflow)?;1820 <Balance<T>>::insert(collection_id, new_owner.clone(), balance_new_owner);18211822 <FungibleItemList<T>>::insert(collection_id, new_owner_account_id, item);1823 } else {1824 1825 let item = FungibleItemType {1826 collection: collection_id,1827 owner: new_owner.clone(),1828 value1829 };18301831 Self::add_fungible_item(item)?;1832 }18331834 if amount == value {1835 Self::remove_token_index(collection_id, item_id, full_item.owner.clone())?;18361837 1838 <ApprovedList<T>>::remove(collection_id, (item_id, full_item.owner.clone()));1839 <FungibleItemList<T>>::remove(collection_id, item_id);1840 }18411842 <FungibleItemList<T>>::insert(collection_id, item_id, new_full_item);1843 }18441845 Ok(())1846 }18471848 fn transfer_refungible(1849 collection_id: CollectionId,1850 item_id: TokenId,1851 value: u128,1852 owner: T::AccountId,1853 new_owner: T::AccountId,1854 ) -> DispatchResult {1855 ensure!(1856 <ReFungibleItemList<T>>::contains_key(collection_id, item_id),1857 Error::<T>::TokenNotFound1858 );18591860 let full_item = <ReFungibleItemList<T>>::get(collection_id, item_id);1861 let item = full_item1862 .owner1863 .iter()1864 .filter(|i| i.owner == owner)1865 .next()1866 .ok_or(Error::<T>::NumOverflow)?;1867 let amount = item.fraction;18681869 ensure!(amount >= value, Error::<T>::TokenValueTooLow);18701871 1872 let balance_old_owner = <Balance<T>>::get(collection_id, item.owner.clone())1873 .checked_sub(value)1874 .ok_or(Error::<T>::NumOverflow)?;1875 <Balance<T>>::insert(collection_id, item.owner.clone(), balance_old_owner);18761877 let balance_new_owner = <Balance<T>>::get(collection_id, new_owner.clone())1878 .checked_add(value)1879 .ok_or(Error::<T>::NumOverflow)?;1880 <Balance<T>>::insert(collection_id, new_owner.clone(), balance_new_owner);18811882 let old_owner = item.owner.clone();1883 let new_owner_has_account = full_item.owner.iter().any(|i| i.owner == new_owner);18841885 1886 if amount == value && !new_owner_has_account {1887 1888 1889 let mut new_full_item = full_item.clone();1890 new_full_item1891 .owner1892 .iter_mut()1893 .find(|i| i.owner == owner)1894 .unwrap()1895 .owner = new_owner.clone();1896 <ReFungibleItemList<T>>::insert(collection_id, item_id, new_full_item);18971898 1899 Self::move_token_index(collection_id, item_id, old_owner.clone(), new_owner.clone())?;1900 } else {1901 let mut new_full_item = full_item.clone();1902 new_full_item1903 .owner1904 .iter_mut()1905 .find(|i| i.owner == owner)1906 .unwrap()1907 .fraction -= value;19081909 1910 if new_owner_has_account {1911 1912 new_full_item1913 .owner1914 .iter_mut()1915 .find(|i| i.owner == new_owner)1916 .unwrap()1917 .fraction += value;1918 } else {1919 1920 new_full_item.owner.push(Ownership {1921 owner: new_owner.clone(),1922 fraction: value,1923 });1924 Self::add_token_index(collection_id, item_id, new_owner.clone())?;1925 }19261927 <ReFungibleItemList<T>>::insert(collection_id, item_id, new_full_item);1928 }19291930 Ok(())1931 }19321933 fn transfer_nft(1934 collection_id: CollectionId,1935 item_id: TokenId,1936 sender: T::AccountId,1937 new_owner: T::AccountId,1938 ) -> DispatchResult {1939 ensure!(1940 <NftItemList<T>>::contains_key(collection_id, item_id),1941 Error::<T>::TokenNotFound1942 );19431944 let mut item = <NftItemList<T>>::get(collection_id, item_id);19451946 ensure!(1947 sender == item.owner,1948 Error::<T>::MustBeTokenOwner1949 );19501951 1952 let balance_old_owner = <Balance<T>>::get(collection_id, item.owner.clone())1953 .checked_sub(1)1954 .ok_or(Error::<T>::NumOverflow)?;1955 <Balance<T>>::insert(collection_id, item.owner.clone(), balance_old_owner);19561957 let balance_new_owner = <Balance<T>>::get(collection_id, new_owner.clone())1958 .checked_add(1)1959 .ok_or(Error::<T>::NumOverflow)?;1960 <Balance<T>>::insert(collection_id, new_owner.clone(), balance_new_owner);19611962 1963 let old_owner = item.owner.clone();1964 item.owner = new_owner.clone();1965 <NftItemList<T>>::insert(collection_id, item_id, item);19661967 1968 Self::move_token_index(collection_id, item_id, old_owner.clone(), new_owner.clone())?;19691970 1971 <ApprovedList<T>>::remove(collection_id, (item_id, old_owner));1972 Ok(())1973 }1974 1975 fn item_exists(1976 collection_id: CollectionId,1977 item_id: TokenId,1978 mode: &CollectionMode1979 ) -> DispatchResult {1980 match mode {1981 CollectionMode::NFT => ensure!(<NftItemList<T>>::contains_key(collection_id, item_id), Error::<T>::TokenNotFound),1982 CollectionMode::ReFungible(_) => ensure!(<ReFungibleItemList<T>>::contains_key(collection_id, item_id), Error::<T>::TokenNotFound),1983 CollectionMode::Fungible(_) => ensure!(<FungibleItemList<T>>::contains_key(collection_id, item_id), Error::<T>::TokenNotFound),1984 _ => ()1985 };1986 1987 Ok(())1988 }19891990 fn set_re_fungible_variable_data(1991 collection_id: CollectionId,1992 item_id: TokenId,1993 data: Vec<u8>1994 ) -> DispatchResult {1995 let mut item = <ReFungibleItemList<T>>::get(collection_id, item_id);19961997 item.variable_data = data;19981999 <ReFungibleItemList<T>>::insert(collection_id, item_id, item);20002001 Ok(())2002 }20032004 fn set_nft_variable_data(2005 collection_id: CollectionId,2006 item_id: TokenId,2007 data: Vec<u8>2008 ) -> DispatchResult {2009 let mut item = <NftItemList<T>>::get(collection_id, item_id);2010 2011 item.variable_data = data;20122013 <NftItemList<T>>::insert(collection_id, item_id, item);2014 2015 Ok(())2016 }20172018 fn init_collection(item: &CollectionType<T::AccountId>) {2019 2020 assert!(2021 item.decimal_points <= MAX_DECIMAL_POINTS,2022 "decimal_points parameter must be lower than MAX_DECIMAL_POINTS"2023 );2024 assert!(2025 item.name.len() <= 64,2026 "Collection name can not be longer than 63 char"2027 );2028 assert!(2029 item.name.len() <= 256,2030 "Collection description can not be longer than 255 char"2031 );2032 assert!(2033 item.token_prefix.len() <= 16,2034 "Token prefix can not be longer than 15 char"2035 );20362037 2038 let next_id = CreatedCollectionCount::get()2039 .checked_add(1)2040 .unwrap();20412042 CreatedCollectionCount::put(next_id);2043 }20442045 fn init_nft_token(item: &NftItemType<T::AccountId>) {2046 let current_index = <ItemListIndex>::get(item.collection)2047 .checked_add(1)2048 .unwrap();20492050 let item_owner = item.owner.clone();2051 let collection_id = item.collection.clone();2052 Self::add_token_index(collection_id, current_index, item.owner.clone()).unwrap();20532054 <ItemListIndex>::insert(collection_id, current_index);20552056 2057 let new_balance = <Balance<T>>::get(collection_id, item_owner.clone())2058 .checked_add(1)2059 .unwrap();2060 <Balance<T>>::insert(collection_id, item_owner.clone(), new_balance);2061 }20622063 fn init_fungible_token(item: &FungibleItemType<T::AccountId>) {2064 let current_index = <ItemListIndex>::get(item.collection)2065 .checked_add(1)2066 .unwrap();2067 let owner = item.owner.clone();20682069 Self::add_token_index(item.collection, current_index, owner.clone()).unwrap();20702071 <ItemListIndex>::insert(item.collection, current_index);20722073 2074 let new_balance = <Balance<T>>::get(item.collection, owner.clone())2075 .checked_add(item.value)2076 .unwrap();2077 <Balance<T>>::insert(item.collection, owner.clone(), new_balance);2078 }20792080 fn init_refungible_token(item: &ReFungibleItemType<T::AccountId>) {2081 let current_index = <ItemListIndex>::get(item.collection)2082 .checked_add(1)2083 .unwrap();20842085 let value = item.owner.first().unwrap().fraction;2086 let owner = item.owner.first().unwrap().owner.clone();20872088 Self::add_token_index(item.collection, current_index, owner.clone()).unwrap();20892090 <ItemListIndex>::insert(item.collection, current_index);20912092 2093 let new_balance = <Balance<T>>::get(item.collection, owner.clone())2094 .checked_add(value)2095 .unwrap();2096 <Balance<T>>::insert(item.collection, owner.clone(), new_balance);2097 }20982099 fn add_token_index(collection_id: CollectionId, item_index: TokenId, owner: T::AccountId) -> DispatchResult {21002101 2102 if <AccountItemCount<T>>::contains_key(owner.clone()) {21032104 2105 let count = <AccountItemCount<T>>::get(owner.clone());2106 ensure!(count < ChainLimit::get().account_token_ownership_limit, Error::<T>::AddressOwnershipLimitExceeded);21072108 <AccountItemCount<T>>::insert(owner.clone(), count2109 .checked_add(1)2110 .ok_or(Error::<T>::NumOverflow)?);2111 }2112 else {2113 <AccountItemCount<T>>::insert(owner.clone(), 1);2114 }21152116 let list_exists = <AddressTokens<T>>::contains_key(collection_id, owner.clone());2117 if list_exists {2118 let mut list = <AddressTokens<T>>::get(collection_id, owner.clone());2119 let item_contains = list.contains(&item_index.clone());21202121 if !item_contains {2122 list.push(item_index.clone());2123 }21242125 <AddressTokens<T>>::insert(collection_id, owner.clone(), list);2126 } else {2127 let mut itm = Vec::new();2128 itm.push(item_index.clone());2129 <AddressTokens<T>>::insert(collection_id, owner, itm);2130 2131 }21322133 Ok(())2134 }21352136 fn remove_token_index(2137 collection_id: CollectionId,2138 item_index: TokenId,2139 owner: T::AccountId,2140 ) -> DispatchResult {21412142 2143 <AccountItemCount<T>>::insert(owner.clone(), 2144 <AccountItemCount<T>>::get(owner.clone())2145 .checked_sub(1)2146 .ok_or(Error::<T>::NumOverflow)?);214721482149 let list_exists = <AddressTokens<T>>::contains_key(collection_id, owner.clone());2150 if list_exists {2151 let mut list = <AddressTokens<T>>::get(collection_id, owner.clone());2152 let item_contains = list.contains(&item_index.clone());21532154 if item_contains {2155 list.retain(|&item| item != item_index);2156 <AddressTokens<T>>::insert(collection_id, owner, list);2157 }2158 }21592160 Ok(())2161 }21622163 fn move_token_index(2164 collection_id: CollectionId,2165 item_index: TokenId,2166 old_owner: T::AccountId,2167 new_owner: T::AccountId,2168 ) -> DispatchResult {2169 Self::remove_token_index(collection_id, item_index, old_owner)?;2170 Self::add_token_index(collection_id, item_index, new_owner)?;21712172 Ok(())2173 }2174}2175217621772178217921802181pub type Multiplier = FixedU128;21822183type BalanceOf<T> = <<T as transaction_payment::Trait>::Currency as Currency<2184 <T as system::Trait>::AccountId,2185>>::Balance;2186type NegativeImbalanceOf<T> = <<T as transaction_payment::Trait>::Currency as Currency<2187 <T as system::Trait>::AccountId,2188>>::NegativeImbalance;2189219021912192#[derive(Encode, Decode, Clone, Eq, PartialEq)]2193pub struct ChargeTransactionPayment<T: Trait + Send + Sync>(2194 #[codec(compact)] BalanceOf<T>2195);21962197impl<T: Trait + Send + Sync> sp_std::fmt::Debug2198 for ChargeTransactionPayment<T>2199{2200 #[cfg(feature = "std")]2201 fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {2202 write!(f, "ChargeTransactionPayment<{:?}>", self.0)2203 }2204 #[cfg(not(feature = "std"))]2205 fn fmt(&self, _: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {2206 Ok(())2207 }2208}22092210impl<T: Trait + Send + Sync> ChargeTransactionPayment<T>2211where2212 T::Call: Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo> + IsSubType<Call<T>> + IsSubType<pallet_contracts::Call<T>>,2213 BalanceOf<T>: Send + Sync + FixedPointOperand,2214{2215 2216 pub fn from(fee: BalanceOf<T>) -> Self {2217 Self(fee)2218 }22192220 pub fn traditional_fee(2221 len: usize,2222 info: &DispatchInfoOf<T::Call>,2223 tip: BalanceOf<T>,2224 ) -> BalanceOf<T>2225 where2226 T::Call: Dispatchable<Info = DispatchInfo>,2227 {2228 <transaction_payment::Module<T>>::compute_fee(len as u32, info, tip)2229 }22302231 fn withdraw_fee(2232 &self,2233 who: &T::AccountId,2234 call: &T::Call,2235 info: &DispatchInfoOf<T::Call>,2236 len: usize,2237 ) -> Result<(BalanceOf<T>, Option<NegativeImbalanceOf<T>>), TransactionValidityError> {2238 let tip = self.0;22392240 2241 2242 2243 2244 2245 2246 2247 let fee = Self::traditional_fee(len, info, tip);22482249 2250 2251 let mut sponsor: T::AccountId = match IsSubType::<Call<T>>::is_sub_type(call) {2252 Some(Call::create_item(collection_id, _owner, _properties)) => {22532254 2255 if <Collection<T>>::get(collection_id).limits.sponsored_data_size >= (_properties.len() as u32)2256 {2257 <Collection<T>>::get(collection_id).sponsor2258 } else {2259 T::AccountId::default()2260 }2261 }2262 Some(Call::transfer(_new_owner, collection_id, _item_id, _value)) => {2263 2264 let _collection_limits = <Collection<T>>::get(collection_id).limits;2265 let _collection_mode = <Collection<T>>::get(collection_id).mode;22662267 2268 let sponsor_transfer = match _collection_mode {2269 CollectionMode::NFT => {22702271 2272 let limit: u32 = if _collection_limits.sponsor_transfer_timeout > 0 {2273 _collection_limits.sponsor_transfer_timeout2274 } else {2275 ChainLimit::get().nft_sponsor_transfer_timeout2276 };22772278 let basket = <NftTransferBasket<T>>::get(collection_id, _item_id);2279 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;2280 let limit_time = basket + limit.into();2281 if block_number >= limit_time {2282 <NftTransferBasket<T>>::insert(collection_id, _item_id, block_number);2283 true2284 }2285 else {2286 false2287 }2288 }2289 CollectionMode::Fungible(_) => {22902291 2292 let limit: u32 = if _collection_limits.sponsor_transfer_timeout > 0 {2293 _collection_limits.sponsor_transfer_timeout2294 } else {2295 ChainLimit::get().fungible_sponsor_transfer_timeout2296 };22972298 let mut basket = <FungibleTransferBasket<T>>::get(collection_id, _item_id);2299 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;2300 if basket.iter().any(|i| i.address == _new_owner.clone())2301 {2302 let item = basket.iter_mut().find(|i| i.address == _new_owner.clone()).unwrap().clone();2303 let limit_time = item.start_block + limit.into();2304 if block_number >= limit_time {2305 basket.retain(|x| x.address == item.address);2306 basket.push(BasketItem { start_block: block_number, address: _new_owner.clone() });2307 <FungibleTransferBasket<T>>::insert(collection_id, _item_id, basket);2308 true2309 }2310 else {2311 false2312 }2313 }2314 else {2315 basket.push(BasketItem { start_block: block_number, address: _new_owner.clone()});2316 true2317 }2318 }2319 CollectionMode::ReFungible(_) => {23202321 2322 let limit: u32 = if _collection_limits.sponsor_transfer_timeout > 0 {2323 _collection_limits.sponsor_transfer_timeout2324 } else {2325 ChainLimit::get().refungible_sponsor_transfer_timeout2326 };23272328 let basket = <ReFungibleTransferBasket<T>>::get(collection_id, _item_id);2329 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;2330 let limit_time = basket + limit.into();2331 if block_number >= limit_time {2332 <ReFungibleTransferBasket<T>>::insert(collection_id, _item_id, block_number);2333 true2334 } else {2335 false2336 }2337 }2338 _ => {2339 false2340 },2341 };23422343 if !sponsor_transfer {2344 T::AccountId::default()2345 } else {2346 <Collection<T>>::get(collection_id).sponsor2347 }2348 }23492350 _ => T::AccountId::default(),2351 };23522353 2354 sponsor = match IsSubType::<pallet_contracts::Call<T>>::is_sub_type(call) {23552356 2357 Some(pallet_contracts::Call::instantiate(_endowment, _gas_limit, code_hash, data)) => {23582359 let new_contract_address = <T as pallet_contracts::Trait>::DetermineContractAddress::contract_address_for(2360 code_hash,2361 &data,2362 &who,2363 );2364 <ContractOwner<T>>::insert(new_contract_address.clone(), who.clone());23652366 T::AccountId::default()2367 },23682369 2370 Some(pallet_contracts::Call::call(dest, _value, _gas_limit, _data)) => {23712372 let called_contract: T::AccountId = T::Lookup::lookup((*dest).clone()).unwrap_or(T::AccountId::default());23732374 let mut sponsor_transfer = false;2375 if <ContractSponsoringRateLimit<T>>::contains_key(called_contract.clone()) {2376 let last_tx_block = <ContractSponsorBasket<T>>::get((&called_contract, &who));2377 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;2378 let rate_limit = <ContractSponsoringRateLimit<T>>::get(&called_contract);2379 let limit_time = last_tx_block + rate_limit;23802381 if block_number >= limit_time {2382 <ContractSponsorBasket<T>>::insert((called_contract.clone(), who.clone()), block_number);2383 sponsor_transfer = true;2384 }2385 } else {2386 sponsor_transfer = false;2387 }2388 2389 2390 let mut sp = T::AccountId::default();2391 if sponsor_transfer {2392 if <ContractSelfSponsoring<T>>::contains_key(called_contract.clone()) {2393 if <ContractSelfSponsoring<T>>::get(called_contract.clone()) {2394 sp = called_contract;2395 }2396 }2397 }23982399 sp2400 },24012402 _ => sponsor,2403 };24042405 let mut who_pays_fee: T::AccountId = sponsor.clone();2406 if sponsor == T::AccountId::default() {2407 who_pays_fee = who.clone();2408 }24092410 2411 if fee.is_zero() {2412 return Ok((fee, None));2413 }24142415 match <T as transaction_payment::Trait>::Currency::withdraw(2416 &who_pays_fee,2417 fee,2418 if tip.is_zero() {2419 WithdrawReason::TransactionPayment.into()2420 } else {2421 WithdrawReason::TransactionPayment | WithdrawReason::Tip2422 },2423 ExistenceRequirement::KeepAlive,2424 ) {2425 Ok(imbalance) => Ok((fee, Some(imbalance))),2426 Err(_) => Err(InvalidTransaction::Payment.into()),2427 }2428 }2429}243024312432impl<T: Trait + Send + Sync> SignedExtension2433 for ChargeTransactionPayment<T>2434where2435 BalanceOf<T>: Send + Sync + From<u64> + FixedPointOperand,2436 T::Call: Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo> + IsSubType<Call<T>> + IsSubType<pallet_contracts::Call<T>>,2437{2438 const IDENTIFIER: &'static str = "ChargeTransactionPayment";2439 type AccountId = T::AccountId;2440 type Call = T::Call;2441 type AdditionalSigned = ();2442 type Pre = (2443 BalanceOf<T>,2444 Self::AccountId,2445 Option<NegativeImbalanceOf<T>>,2446 BalanceOf<T>,2447 );2448 fn additional_signed(&self) -> sp_std::result::Result<(), TransactionValidityError> {2449 Ok(())2450 }24512452 fn validate(2453 &self,2454 _who: &Self::AccountId,2455 _call: &Self::Call,2456 _info: &DispatchInfoOf<Self::Call>,2457 _len: usize,2458 ) -> TransactionValidity {2459 Ok(ValidTransaction::default())2460 }24612462 fn pre_dispatch(2463 self,2464 who: &Self::AccountId,2465 call: &Self::Call,2466 info: &DispatchInfoOf<Self::Call>,2467 len: usize,2468 ) -> Result<Self::Pre, TransactionValidityError> {2469 let (fee, imbalance) = self.withdraw_fee(who, call, info, len)?;2470 Ok((self.0, who.clone(), imbalance, fee))2471 }24722473 fn post_dispatch(2474 pre: Self::Pre,2475 info: &DispatchInfoOf<Self::Call>,2476 post_info: &PostDispatchInfoOf<Self::Call>,2477 len: usize,2478 _result: &DispatchResult,2479 ) -> Result<(), TransactionValidityError> {2480 let (tip, who, imbalance, fee) = pre;2481 if let Some(payed) = imbalance {2482 let actual_fee = <transaction_payment::Module<T>>::compute_actual_fee(2483 len as u32, info, post_info, tip,2484 );2485 let refund = fee.saturating_sub(actual_fee);2486 let actual_payment =2487 match <T as transaction_payment::Trait>::Currency::deposit_into_existing(2488 &who, refund,2489 ) {2490 Ok(refund_imbalance) => {2491 2492 2493 match payed.offset(refund_imbalance) {2494 Ok(actual_payment) => actual_payment,2495 Err(_) => return Err(InvalidTransaction::Payment.into()),2496 }2497 }2498 2499 2500 Err(_) => payed,2501 };2502 let imbalances = actual_payment.split(tip);2503 <T as transaction_payment::Trait>::OnTransactionPayment::on_unbalanceds(2504 Some(imbalances.0).into_iter().chain(Some(imbalances.1)),2505 );2506 }2507 Ok(())2508 }2509}25102511