123456#![recursion_limit = "1024"]78#![cfg_attr(not(feature = "std"), no_std)]910#[cfg(feature = "std")]11pub use std::*;1213#[cfg(feature = "std")]14pub use serde::*;1516use codec::{Decode, Encode};17pub use frame_support::{18 construct_runtime, decl_event, decl_module, decl_storage, decl_error,19 dispatch::DispatchResult,20 ensure, fail, parameter_types,21 traits::{22 Currency, ExistenceRequirement, Get, Imbalance, KeyOwnerProofSystem, OnUnbalanced,23 Randomness, WithdrawReason,24 },25 weights::{26 constants::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_PER_SECOND},27 DispatchInfo, GetDispatchInfo, IdentityFee, Pays, PostDispatchInfo, Weight,28 WeightToFeePolynomial,29 },30 IsSubType, StorageValue,31};3233use frame_system::{self as system, ensure_signed, ensure_root};34use sp_runtime::sp_std::prelude::Vec;35use sp_runtime::{36 traits::{37 DispatchInfoOf, Dispatchable, PostDispatchInfoOf, Saturating, SaturatedConversion, SignedExtension, Zero,38 },39 transaction_validity::{40 TransactionPriority, InvalidTransaction, TransactionValidity, TransactionValidityError, ValidTransaction,41 },42 FixedPointOperand, FixedU128,43};44use pallet_contracts::ContractAddressFor;45use sp_runtime::traits::StaticLookup;4647#[cfg(test)]48mod mock;4950#[cfg(test)]51mod tests;5253mod default_weights;5455pub const MAX_DECIMAL_POINTS: DecimalPoints = 30;56pub const MAX_SPONSOR_TIMEOUT: u32 = 10_368_000;57pub const MAX_TOKEN_OWNERSHIP: u32 = 10_000_000;5859606162pub type CollectionId = u32;63pub type TokenId = u32;64pub type DecimalPoints = u8;6566#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq)]67#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]68pub enum CollectionMode {69 Invalid,70 NFT,71 72 Fungible(DecimalPoints),73 74 ReFungible(DecimalPoints),75}7677impl Into<u8> for CollectionMode {78 fn into(self) -> u8 {79 match self {80 CollectionMode::Invalid => 0,81 CollectionMode::NFT => 1,82 CollectionMode::Fungible(_) => 2,83 CollectionMode::ReFungible(_) => 3,84 }85 }86}8788#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq)]89#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]90pub enum AccessMode {91 Normal,92 WhiteList,93}94impl Default for AccessMode {95 fn default() -> Self {96 Self::Normal97 }98}99100impl Default for CollectionMode {101 fn default() -> Self {102 Self::Invalid103 }104}105106#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq)]107#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]108pub enum SchemaVersion {109 ImageURL,110 Unique,111}112impl Default for SchemaVersion {113 fn default() -> Self {114 Self::ImageURL115 }116}117118#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]119#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]120pub struct Ownership<AccountId> {121 pub owner: AccountId,122 pub fraction: u128,123}124125#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]126#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]127pub struct CollectionType<AccountId> {128 pub owner: AccountId,129 pub mode: CollectionMode,130 pub access: AccessMode,131 pub decimal_points: DecimalPoints,132 pub name: Vec<u16>, 133 pub description: Vec<u16>, 134 pub token_prefix: Vec<u8>, 135 pub mint_mode: bool,136 pub offchain_schema: Vec<u8>,137 pub schema_version: SchemaVersion,138 pub sponsor: AccountId, 139 pub sponsor_confirmed: bool, 140 pub limits: CollectionLimits, 141 pub variable_on_chain_schema: Vec<u8>, 142 pub const_on_chain_schema: Vec<u8>, 143}144145#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]146#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]147pub struct NftItemType<AccountId> {148 pub owner: AccountId,149 pub const_data: Vec<u8>,150 pub variable_data: Vec<u8>,151}152153#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]154#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]155pub struct FungibleItemType {156 pub value: u128,157}158159#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]160#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]161pub struct ReFungibleItemType<AccountId> {162 pub owner: Vec<Ownership<AccountId>>,163 pub const_data: Vec<u8>,164 pub variable_data: Vec<u8>,165}166167168169170171172173174175176177178#[derive(Encode, Decode, Debug, Clone, PartialEq)]179#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]180pub struct CollectionLimits {181 pub account_token_ownership_limit: u32,182 pub sponsored_data_size: u32,183 pub token_limit: u32,184185 186 pub sponsor_transfer_timeout: u32,187}188189impl Default for CollectionLimits {190 fn default() -> CollectionLimits {191 CollectionLimits { 192 account_token_ownership_limit: 10_000_000, 193 token_limit: u32::max_value(),194 sponsored_data_size: u32::max_value(), 195 sponsor_transfer_timeout: 14400 }196 }197}198199#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]200#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]201pub struct ChainLimits {202 pub collection_numbers_limit: u32,203 pub account_token_ownership_limit: u32,204 pub collections_admins_limit: u64,205 pub custom_data_limit: u32,206207 208 pub nft_sponsor_transfer_timeout: u32,209 pub fungible_sponsor_transfer_timeout: u32,210 pub refungible_sponsor_transfer_timeout: u32,211}212213pub trait WeightInfo {214 fn create_collection() -> Weight;215 fn destroy_collection() -> Weight;216 fn add_to_white_list() -> Weight;217 fn remove_from_white_list() -> Weight;218 fn set_public_access_mode() -> Weight;219 fn set_mint_permission() -> Weight;220 fn change_collection_owner() -> Weight;221 fn add_collection_admin() -> Weight;222 fn remove_collection_admin() -> Weight;223 fn set_collection_sponsor() -> Weight;224 fn confirm_sponsorship() -> Weight;225 fn remove_collection_sponsor() -> Weight;226 fn create_item(s: usize) -> Weight;227 fn burn_item() -> Weight;228 fn transfer() -> Weight;229 fn approve() -> Weight;230 fn transfer_from() -> Weight;231 fn set_offchain_schema() -> Weight;232 fn set_const_on_chain_schema() -> Weight;233 fn set_variable_on_chain_schema() -> Weight;234 fn set_variable_meta_data() -> Weight;235 fn enable_contract_sponsoring() -> Weight;236}237238#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]239#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]240pub struct CreateNftData {241 pub const_data: Vec<u8>,242 pub variable_data: Vec<u8>,243}244245#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]246#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]247pub struct CreateFungibleData {248 pub value: u128,249}250251#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]252#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]253pub struct CreateReFungibleData {254 pub const_data: Vec<u8>,255 pub variable_data: Vec<u8>,256}257258#[derive(Encode, Decode, Debug, Clone, PartialEq)]259#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]260pub enum CreateItemData {261 NFT(CreateNftData),262 Fungible(CreateFungibleData),263 ReFungible(CreateReFungibleData),264}265266impl CreateItemData {267 pub fn len(&self) -> usize {268 let len = match self {269 CreateItemData::NFT(data) => data.variable_data.len() + data.const_data.len(),270 CreateItemData::ReFungible(data) => data.variable_data.len() + data.const_data.len(),271 _ => 0272 };273 274 return len;275 }276}277278impl From<CreateNftData> for CreateItemData {279 fn from(item: CreateNftData) -> Self {280 CreateItemData::NFT(item)281 }282}283284impl From<CreateReFungibleData> for CreateItemData {285 fn from(item: CreateReFungibleData) -> Self {286 CreateItemData::ReFungible(item)287 }288}289290impl From<CreateFungibleData> for CreateItemData {291 fn from(item: CreateFungibleData) -> Self {292 CreateItemData::Fungible(item)293 }294}295296297decl_error! {298 299 pub enum Error for Module<T: Trait> {300 301 TotalCollectionsLimitExceeded,302 303 CollectionDecimalPointLimitExceeded, 304 305 CollectionNameLimitExceeded, 306 307 CollectionDescriptionLimitExceeded, 308 309 CollectionTokenPrefixLimitExceeded,310 311 CollectionNotFound,312 313 TokenNotFound,314 315 NumOverflow, 316 317 AlreadyAdmin, 318 319 NoPermission,320 321 ConfirmUnsetSponsorFail,322 323 PublicMintingNotAllowed,324 325 MustBeTokenOwner,326 327 TokenValueTooLow,328 329 NftSizeLimitExceeded,330 331 ApproveNotFound,332 333 TokenValueNotEnough,334 335 ApproveRequired,336 337 AddresNotInWhiteList,338 339 CollectionAdminsLimitExceeded,340 341 AddressOwnershipLimitExceeded,342 343 EmptyArgument,344 345 TokenConstDataLimitExceeded,346 347 TokenVariableDataLimitExceeded,348 349 NotNftDataUsedToMintNftCollectionToken,350 351 NotFungibleDataUsedToMintFungibleCollectionToken,352 353 NotReFungibleDataUsedToMintReFungibleCollectionToken,354 355 UnexpectedCollectionType,356 357 CantStoreMetadataInFungibleTokens,358 359 CollectionTokenLimitExceeded,360 361 AccountTokenLimitExceeded,362 363 CollectionLimitBoundsExceeded364 }365}366367pub trait Trait: system::Trait + Sized + transaction_payment::Trait + pallet_contracts::Trait {368 type Event: From<Event<Self>> + Into<<Self as system::Trait>::Event>;369370 371 type WeightInfo: WeightInfo;372}373374#[cfg(feature = "runtime-benchmarks")]375mod benchmarking;376377378379decl_storage! {380 trait Store for Module<T: Trait> as Nft {381382 383 NextCollectionID: CollectionId;384 CreatedCollectionCount: u32;385 ChainVersion: u64;386 ItemListIndex: map hasher(identity) CollectionId => TokenId;387388 389 pub ChainLimit get(fn chain_limit) config(): ChainLimits;390391 392 CollectionCount: u32;393 pub AccountItemCount get(fn account_item_count): map hasher(twox_64_concat) T::AccountId => u32;394395 396 pub Collection get(fn collection) config(): map hasher(identity) CollectionId => CollectionType<T::AccountId>;397 pub AdminList get(fn admin_list_collection): map hasher(identity) CollectionId => Vec<T::AccountId>;398 pub WhiteList get(fn white_list): double_map hasher(identity) CollectionId, hasher(twox_64_concat) T::AccountId => bool;399400 401 pub Balance get(fn balance_count): double_map hasher(identity) CollectionId, hasher(twox_64_concat) T::AccountId => u128;402403 404 pub Allowances get(fn approved): double_map hasher(identity) CollectionId, hasher(twox_64_concat) (TokenId, T::AccountId, T::AccountId) => u128;405406 407 pub NftItemList get(fn nft_item_id) config(): double_map hasher(identity) CollectionId, hasher(identity) TokenId => NftItemType<T::AccountId>;408 pub FungibleItemList get(fn fungible_item_id) config(): double_map hasher(identity) CollectionId, hasher(twox_64_concat) T::AccountId => FungibleItemType;409 pub ReFungibleItemList get(fn refungible_item_id) config(): double_map hasher(identity) CollectionId, hasher(identity) TokenId => ReFungibleItemType<T::AccountId>;410411 412 pub AddressTokens get(fn address_tokens): double_map hasher(identity) CollectionId, hasher(twox_64_concat) T::AccountId => Vec<TokenId>;413414 415 pub NftTransferBasket get(fn nft_transfer_basket): double_map hasher(identity) CollectionId, hasher(identity) TokenId => T::BlockNumber;416 pub FungibleTransferBasket get(fn fungible_transfer_basket): double_map hasher(identity) CollectionId, hasher(twox_64_concat) T::AccountId => T::BlockNumber;417 pub ReFungibleTransferBasket get(fn refungible_transfer_basket): double_map hasher(identity) CollectionId, hasher(identity) TokenId => T::BlockNumber;418419 420 pub ContractOwner get(fn contract_owner): map hasher(twox_64_concat) T::AccountId => T::AccountId;421 pub ContractSelfSponsoring get(fn contract_self_sponsoring): map hasher(twox_64_concat) T::AccountId => bool;422 pub ContractSponsorBasket get(fn contract_sponsor_basket): map hasher(twox_64_concat) (T::AccountId, T::AccountId) => T::BlockNumber;423 pub ContractSponsoringRateLimit get(fn contract_sponsoring_rate_limit): map hasher(twox_64_concat) T::AccountId => T::BlockNumber;424 pub ContractWhiteListEnabled get(fn contract_white_list_enabled): map hasher(twox_64_concat) T::AccountId => bool; 425 pub ContractWhiteList get(fn contract_white_list): double_map hasher(twox_64_concat) T::AccountId, hasher(twox_64_concat) T::AccountId => bool; 426 }427 add_extra_genesis {428 build(|config: &GenesisConfig<T>| {429 430 for (_num, _c) in &config.collection {431 <Module<T>>::init_collection(_c);432 }433434 for (_num, _c, _i) in &config.nft_item_id {435 <Module<T>>::init_nft_token(*_c, _i);436 }437438 for (collection_id, account_id, fungible_item) in &config.fungible_item_id {439 <Module<T>>::init_fungible_token(*collection_id, account_id, fungible_item);440 }441442 for (_num, _c, _i) in &config.refungible_item_id {443 <Module<T>>::init_refungible_token(*_c, _i);444 }445 })446 }447}448449decl_event!(450 pub enum Event<T>451 where452 AccountId = <T as system::Trait>::AccountId,453 {454 455 456 457 458 459 460 461 462 463 Created(CollectionId, u8, AccountId),464465 466 467 468 469 470 471 472 ItemCreated(CollectionId, TokenId),473474 475 476 477 478 479 480 481 ItemDestroyed(CollectionId, TokenId),482 }483);484485decl_module! {486 pub struct Module<T: Trait> for enum Call where origin: T::Origin {487488 fn deposit_event() = default;489 type Error = Error<T>;490491 fn on_initialize(now: T::BlockNumber) -> Weight {492493 if ChainVersion::get() < 2494 {495 let value = NextCollectionID::get();496 CreatedCollectionCount::put(value);497 ChainVersion::put(2);498 }499500 0501 }502503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 #[weight = T::WeightInfo::create_collection()]520 pub fn create_collection(origin,521 collection_name: Vec<u16>,522 collection_description: Vec<u16>,523 token_prefix: Vec<u8>,524 mode: CollectionMode) -> DispatchResult {525526 527 let who = ensure_signed(origin)?;528529 let decimal_points = match mode {530 CollectionMode::Fungible(points) => points,531 CollectionMode::ReFungible(points) => points,532 _ => 0533 };534535 536 ensure!(CollectionCount::get() < ChainLimit::get().collection_numbers_limit, Error::<T>::TotalCollectionsLimitExceeded);537538 539 ensure!(decimal_points <= MAX_DECIMAL_POINTS, Error::<T>::CollectionDecimalPointLimitExceeded);540541 let mut name = collection_name.to_vec();542 name.push(0);543 ensure!(name.len() <= 64, Error::<T>::CollectionNameLimitExceeded);544545 let mut description = collection_description.to_vec();546 description.push(0);547 ensure!(name.len() <= 256, Error::<T>::CollectionDescriptionLimitExceeded);548549 let mut prefix = token_prefix.to_vec();550 prefix.push(0);551 ensure!(prefix.len() <= 16, Error::<T>::CollectionTokenPrefixLimitExceeded);552553 554 let next_id = CreatedCollectionCount::get()555 .checked_add(1)556 .ok_or(Error::<T>::NumOverflow)?;557558 559 let total = CollectionCount::get()560 .checked_add(1)561 .ok_or(Error::<T>::NumOverflow)?;562563 CreatedCollectionCount::put(next_id);564 CollectionCount::put(total);565566 567 let new_collection = CollectionType {568 owner: who.clone(),569 name: name,570 mode: mode.clone(),571 mint_mode: false,572 access: AccessMode::Normal,573 description: description,574 decimal_points: decimal_points,575 token_prefix: prefix,576 offchain_schema: Vec::new(),577 schema_version: SchemaVersion::ImageURL,578 sponsor: T::AccountId::default(),579 sponsor_confirmed: false,580 variable_on_chain_schema: Vec::new(),581 const_on_chain_schema: Vec::new(),582 limits: CollectionLimits::default(),583 };584585 586 <Collection<T>>::insert(next_id, new_collection);587588 589 Self::deposit_event(RawEvent::Created(next_id, mode.into(), who.clone()));590591 Ok(())592 }593594 595 596 597 598 599 600 601 602 603 #[weight = T::WeightInfo::destroy_collection()]604 pub fn destroy_collection(origin, collection_id: CollectionId) -> DispatchResult {605606 let sender = ensure_signed(origin)?;607 Self::check_owner_permissions(collection_id, sender)?;608609 <AddressTokens<T>>::remove_prefix(collection_id);610 <Allowances<T>>::remove_prefix(collection_id);611 <Balance<T>>::remove_prefix(collection_id);612 <ItemListIndex>::remove(collection_id);613 <AdminList<T>>::remove(collection_id);614 <Collection<T>>::remove(collection_id);615 <WhiteList<T>>::remove_prefix(collection_id);616617 <NftItemList<T>>::remove_prefix(collection_id);618 <FungibleItemList<T>>::remove_prefix(collection_id);619 <ReFungibleItemList<T>>::remove_prefix(collection_id);620621 <NftTransferBasket<T>>::remove_prefix(collection_id);622 <FungibleTransferBasket<T>>::remove_prefix(collection_id);623 <ReFungibleTransferBasket<T>>::remove_prefix(collection_id);624625 if CollectionCount::get() > 0626 {627 628 let total = CollectionCount::get()629 .checked_sub(1)630 .ok_or(Error::<T>::NumOverflow)?;631632 CollectionCount::put(total);633 }634635 Ok(())636 }637638 639 640 641 642 643 644 645 646 647 648 649 650 #[weight = T::WeightInfo::add_to_white_list()]651 pub fn add_to_white_list(origin, collection_id: CollectionId, address: T::AccountId) -> DispatchResult{652653 let sender = ensure_signed(origin)?;654 Self::check_owner_or_admin_permissions(collection_id, sender)?;655656 <WhiteList<T>>::insert(collection_id, address, true);657 658 Ok(())659 }660661 662 663 664 665 666 667 668 669 670 671 672 673 #[weight = T::WeightInfo::remove_from_white_list()]674 pub fn remove_from_white_list(origin, collection_id: CollectionId, address: T::AccountId) -> DispatchResult{675676 let sender = ensure_signed(origin)?;677 Self::check_owner_or_admin_permissions(collection_id, sender)?;678679 <WhiteList<T>>::remove(collection_id, address);680681 Ok(())682 }683684 685 686 687 688 689 690 691 692 693 694 695 #[weight = T::WeightInfo::set_public_access_mode()]696 pub fn set_public_access_mode(origin, collection_id: CollectionId, mode: AccessMode) -> DispatchResult697 {698 let sender = ensure_signed(origin)?;699700 Self::check_owner_permissions(collection_id, sender)?;701 let mut target_collection = <Collection<T>>::get(collection_id);702 target_collection.access = mode;703 <Collection<T>>::insert(collection_id, target_collection);704705 Ok(())706 }707708 709 710 711 712 713 714 715 716 717 718 719 720 721 #[weight = T::WeightInfo::set_mint_permission()]722 pub fn set_mint_permission(origin, collection_id: CollectionId, mint_permission: bool) -> DispatchResult723 {724 let sender = ensure_signed(origin)?;725726 Self::check_owner_permissions(collection_id, sender)?;727 let mut target_collection = <Collection<T>>::get(collection_id);728 target_collection.mint_mode = mint_permission;729 <Collection<T>>::insert(collection_id, target_collection);730731 Ok(())732 }733734 735 736 737 738 739 740 741 742 743 744 745 #[weight = T::WeightInfo::change_collection_owner()]746 pub fn change_collection_owner(origin, collection_id: CollectionId, new_owner: T::AccountId) -> DispatchResult {747748 let sender = ensure_signed(origin)?;749 Self::check_owner_permissions(collection_id, sender)?;750 let mut target_collection = <Collection<T>>::get(collection_id);751 target_collection.owner = new_owner;752 <Collection<T>>::insert(collection_id, target_collection);753754 Ok(())755 }756757 758 759 760 761 762 763 764 765 766 767 768 769 770 #[weight = T::WeightInfo::add_collection_admin()]771 pub fn add_collection_admin(origin, collection_id: CollectionId, new_admin_id: T::AccountId) -> DispatchResult {772773 let sender = ensure_signed(origin)?;774 Self::check_owner_or_admin_permissions(collection_id, sender)?;775 let mut admin_arr: Vec<T::AccountId> = Vec::new();776777 if <AdminList<T>>::contains_key(collection_id)778 {779 admin_arr = <AdminList<T>>::get(collection_id);780 ensure!(!admin_arr.contains(&new_admin_id), Error::<T>::AlreadyAdmin);781 }782783 784 ensure!((admin_arr.len() as u64) < ChainLimit::get().collections_admins_limit, Error::<T>::CollectionAdminsLimitExceeded);785786 admin_arr.push(new_admin_id);787 <AdminList<T>>::insert(collection_id, admin_arr);788789 Ok(())790 }791792 793 794 795 796 797 798 799 800 801 802 803 804 #[weight = T::WeightInfo::remove_collection_admin()]805 pub fn remove_collection_admin(origin, collection_id: CollectionId, account_id: T::AccountId) -> DispatchResult {806807 let sender = ensure_signed(origin)?;808 Self::check_owner_or_admin_permissions(collection_id, sender)?;809810 if <AdminList<T>>::contains_key(collection_id)811 {812 let mut admin_arr = <AdminList<T>>::get(collection_id);813 admin_arr.retain(|i| *i != account_id);814 <AdminList<T>>::insert(collection_id, admin_arr);815 }816817 Ok(())818 }819820 821 822 823 824 825 826 827 828 829 #[weight = T::WeightInfo::set_collection_sponsor()]830 pub fn set_collection_sponsor(origin, collection_id: CollectionId, new_sponsor: T::AccountId) -> DispatchResult {831832 let sender = ensure_signed(origin)?;833 ensure!(<Collection<T>>::contains_key(collection_id), Error::<T>::CollectionNotFound);834835 let mut target_collection = <Collection<T>>::get(collection_id);836 ensure!(sender == target_collection.owner, Error::<T>::NoPermission);837838 target_collection.sponsor = new_sponsor;839 target_collection.sponsor_confirmed = false;840 <Collection<T>>::insert(collection_id, target_collection);841842 Ok(())843 }844845 846 847 848 849 850 851 852 #[weight = T::WeightInfo::confirm_sponsorship()]853 pub fn confirm_sponsorship(origin, collection_id: CollectionId) -> DispatchResult {854855 let sender = ensure_signed(origin)?;856 ensure!(<Collection<T>>::contains_key(collection_id), Error::<T>::CollectionNotFound);857858 let mut target_collection = <Collection<T>>::get(collection_id);859 ensure!(sender == target_collection.sponsor, Error::<T>::ConfirmUnsetSponsorFail);860861 target_collection.sponsor_confirmed = true;862 <Collection<T>>::insert(collection_id, target_collection);863864 Ok(())865 }866867 868 869 870 871 872 873 874 875 876 #[weight = T::WeightInfo::remove_collection_sponsor()]877 pub fn remove_collection_sponsor(origin, collection_id: CollectionId) -> DispatchResult {878879 let sender = ensure_signed(origin)?;880 ensure!(<Collection<T>>::contains_key(collection_id), Error::<T>::CollectionNotFound);881882 let mut target_collection = <Collection<T>>::get(collection_id);883 ensure!(sender == target_collection.owner, Error::<T>::NoPermission);884885 target_collection.sponsor = T::AccountId::default();886 target_collection.sponsor_confirmed = false;887 <Collection<T>>::insert(collection_id, target_collection);888889 Ok(())890 }891892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915916 #[weight = T::WeightInfo::create_item(data.len())]917 pub fn create_item(origin, collection_id: CollectionId, owner: T::AccountId, data: CreateItemData) -> DispatchResult {918919 let sender = ensure_signed(origin)?;920921 Self::collection_exists(collection_id)?;922923 let target_collection = <Collection<T>>::get(collection_id);924925 Self::can_create_items_in_collection(collection_id, &target_collection, &sender, &owner)?;926 Self::validate_create_item_args(&target_collection, &data)?;927 Self::create_item_no_validation(collection_id, &target_collection, owner, data)?;928929 Ok(())930 }931932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 #[weight = T::WeightInfo::create_item(items_data.into_iter()951 .map(|data| { data.len() })952 .sum())]953 pub fn create_multiple_items(origin, collection_id: CollectionId, owner: T::AccountId, items_data: Vec<CreateItemData>) -> DispatchResult {954955 ensure!(items_data.len() > 0, Error::<T>::EmptyArgument);956 let sender = ensure_signed(origin)?;957958 Self::collection_exists(collection_id)?;959 let target_collection = <Collection<T>>::get(collection_id);960961 Self::can_create_items_in_collection(collection_id, &target_collection, &sender, &owner)?;962963 for data in &items_data {964 Self::validate_create_item_args(&target_collection, data)?;965 }966 for data in &items_data {967 Self::create_item_no_validation(collection_id, &target_collection, owner.clone(), data.clone())?;968 }969970 Ok(())971 }972973 974 975 976 977 978 979 980 981 982 983 984 985 986 #[weight = T::WeightInfo::burn_item()]987 pub fn burn_item(origin, collection_id: CollectionId, item_id: TokenId, value: u128) -> DispatchResult {988989 let sender = ensure_signed(origin)?;990 Self::collection_exists(collection_id)?;991992 993 let target_collection = <Collection<T>>::get(collection_id);994 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||995 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),996 Error::<T>::NoPermission);997998 if target_collection.access == AccessMode::WhiteList {999 Self::check_white_list(collection_id, &sender)?;1000 }10011002 match target_collection.mode1003 {1004 CollectionMode::NFT => Self::burn_nft_item(collection_id, item_id)?,1005 CollectionMode::Fungible(_) => Self::burn_fungible_item(&sender, collection_id, value)?,1006 CollectionMode::ReFungible(_) => Self::burn_refungible_item(collection_id, item_id, sender.clone())?,1007 _ => ()1008 };10091010 1011 Self::deposit_event(RawEvent::ItemDestroyed(collection_id, item_id));10121013 Ok(())1014 }10151016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 #[weight = T::WeightInfo::transfer()]1040 pub fn transfer(origin, recipient: T::AccountId, collection_id: CollectionId, item_id: TokenId, value: u128) -> DispatchResult {10411042 let sender = ensure_signed(origin)?;1043 let target_collection = <Collection<T>>::get(collection_id);10441045 1046 Self::is_correct_transfer(collection_id, &target_collection, &recipient)?;10471048 1049 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||1050 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1051 Error::<T>::NoPermission);10521053 if target_collection.access == AccessMode::WhiteList {1054 Self::check_white_list(collection_id, &sender)?;1055 Self::check_white_list(collection_id, &recipient)?;1056 }10571058 match target_collection.mode1059 {1060 CollectionMode::NFT => Self::transfer_nft(collection_id, item_id, sender.clone(), recipient)?,1061 CollectionMode::Fungible(_) => Self::transfer_fungible(collection_id, value, &sender, &recipient)?,1062 CollectionMode::ReFungible(_) => Self::transfer_refungible(collection_id, item_id, value, sender.clone(), recipient)?,1063 _ => ()1064 };10651066 Ok(())1067 }10681069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 #[weight = T::WeightInfo::approve()]1085 pub fn approve(origin, spender: T::AccountId, collection_id: CollectionId, item_id: TokenId, amount: u128) -> DispatchResult {10861087 let sender = ensure_signed(origin)?;10881089 1090 let target_collection = <Collection<T>>::get(collection_id);1091 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||1092 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1093 Error::<T>::NoPermission);10941095 if target_collection.access == AccessMode::WhiteList {1096 Self::check_white_list(collection_id, &sender)?;1097 Self::check_white_list(collection_id, &spender)?;1098 }10991100 let allowance_exists = <Allowances<T>>::contains_key(collection_id, (item_id, &sender, &spender));1101 let mut allowance: u128 = amount;1102 if allowance_exists {1103 allowance += <Allowances<T>>::get(collection_id, (item_id, &sender, &spender));1104 }1105 <Allowances<T>>::insert(collection_id, (item_id, sender.clone(), spender.clone()), allowance);11061107 Ok(())1108 }1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 #[weight = T::WeightInfo::transfer_from()]1130 pub fn transfer_from(origin, from: T::AccountId, recipient: T::AccountId, collection_id: CollectionId, item_id: TokenId, value: u128 ) -> DispatchResult {11311132 let sender = ensure_signed(origin)?;1133 let mut appoved_transfer = false;11341135 1136 let mut approval: u128 = 0;1137 if <Allowances<T>>::contains_key(collection_id, (item_id, &from, &recipient)) {1138 approval = <Allowances<T>>::get(collection_id, (item_id, &from, &recipient));1139 ensure!(approval >= value, Error::<T>::TokenValueNotEnough);1140 appoved_transfer = true;1141 }11421143 let target_collection = <Collection<T>>::get(collection_id);11441145 1146 Self::is_correct_transfer(collection_id, &target_collection, &recipient)?;11471148 1149 ensure!(appoved_transfer || Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1150 Error::<T>::NoPermission);11511152 if target_collection.access == AccessMode::WhiteList {1153 Self::check_white_list(collection_id, &sender)?;1154 Self::check_white_list(collection_id, &recipient)?;1155 }11561157 1158 if approval - value > 0 {1159 <Allowances<T>>::insert(collection_id, (item_id, &from, &recipient), approval - value);1160 }1161 else {1162 <Allowances<T>>::remove(collection_id, (item_id, &from, &recipient));1163 }11641165 match target_collection.mode1166 {1167 CollectionMode::NFT => Self::transfer_nft(collection_id, item_id, from, recipient)?,1168 CollectionMode::Fungible(_) => Self::transfer_fungible(collection_id, value, &from, &recipient)?,1169 CollectionMode::ReFungible(_) => Self::transfer_refungible(collection_id, item_id, value, from.clone(), recipient)?,1170 _ => ()1171 };11721173 Ok(())1174 }11751176 #[weight = 0]1177 pub fn safe_transfer_from(origin, collection_id: CollectionId, item_id: TokenId, new_owner: T::AccountId) -> DispatchResult {11781179 1180 1181 1182 11831184 11851186 11871188 Ok(())1189 }11901191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 #[weight = T::WeightInfo::set_variable_meta_data()]1204 pub fn set_variable_meta_data (1205 origin,1206 collection_id: CollectionId,1207 item_id: TokenId,1208 data: Vec<u8>1209 ) -> DispatchResult {1210 let sender = ensure_signed(origin)?;1211 1212 Self::collection_exists(collection_id)?;1213 1214 ensure!(ChainLimit::get().custom_data_limit >= data.len() as u32, Error::<T>::TokenVariableDataLimitExceeded);12151216 1217 let target_collection = <Collection<T>>::get(collection_id);1218 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||1219 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1220 Error::<T>::NoPermission);12211222 Self::item_exists(collection_id, item_id, &target_collection.mode)?;12231224 match target_collection.mode1225 {1226 CollectionMode::NFT => Self::set_nft_variable_data(collection_id, item_id, data)?,1227 CollectionMode::ReFungible(_) => Self::set_re_fungible_variable_data(collection_id, item_id, data)?,1228 CollectionMode::Fungible(_) => fail!(Error::<T>::CantStoreMetadataInFungibleTokens),1229 _ => fail!(Error::<T>::UnexpectedCollectionType)1230 };12311232 Ok(())1233 }1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 #[weight = 0]1250 pub fn set_schema_version(1251 origin,1252 collection_id: CollectionId,1253 version: SchemaVersion1254 ) -> DispatchResult {1255 let sender = ensure_signed(origin)?;1256 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;1257 let mut target_collection = <Collection<T>>::get(collection_id);1258 target_collection.schema_version = version;1259 <Collection<T>>::insert(collection_id, target_collection);12601261 Ok(())1262 }12631264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 #[weight = T::WeightInfo::set_offchain_schema()]1277 pub fn set_offchain_schema(1278 origin,1279 collection_id: CollectionId,1280 schema: Vec<u8>1281 ) -> DispatchResult {1282 let sender = ensure_signed(origin)?;1283 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;12841285 let mut target_collection = <Collection<T>>::get(collection_id);1286 target_collection.offchain_schema = schema;1287 <Collection<T>>::insert(collection_id, target_collection);12881289 Ok(())1290 }12911292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 #[weight = T::WeightInfo::set_const_on_chain_schema()]1305 pub fn set_const_on_chain_schema (1306 origin,1307 collection_id: CollectionId,1308 schema: Vec<u8>1309 ) -> DispatchResult {1310 let sender = ensure_signed(origin)?;1311 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;13121313 let mut target_collection = <Collection<T>>::get(collection_id);1314 target_collection.const_on_chain_schema = schema;1315 <Collection<T>>::insert(collection_id, target_collection);13161317 Ok(())1318 }13191320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 #[weight = T::WeightInfo::set_const_on_chain_schema()]1333 pub fn set_variable_on_chain_schema (1334 origin,1335 collection_id: CollectionId,1336 schema: Vec<u8>1337 ) -> DispatchResult {1338 let sender = ensure_signed(origin)?;1339 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;13401341 let mut target_collection = <Collection<T>>::get(collection_id);1342 target_collection.variable_on_chain_schema = schema;1343 <Collection<T>>::insert(collection_id, target_collection);13441345 Ok(())1346 }13471348 1349 #[weight = 0]1350 pub fn set_chain_limits(1351 origin,1352 limits: ChainLimits1353 ) -> DispatchResult {1354 ensure_root(origin)?;1355 <ChainLimit>::put(limits);1356 Ok(())1357 }13581359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 #[weight = T::WeightInfo::enable_contract_sponsoring()]1371 pub fn enable_contract_sponsoring(1372 origin,1373 contract_address: T::AccountId,1374 enable: bool1375 ) -> DispatchResult {13761377 let sender = ensure_signed(origin)?;13781379 #[cfg(feature = "runtime-benchmarks")]1380 <ContractOwner<T>>::insert(contract_address.clone(), sender.clone());13811382 Self::ensure_contract_owned(sender, &contract_address)?;13831384 <ContractSelfSponsoring<T>>::insert(contract_address, enable);1385 Ok(())1386 }13871388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 #[weight = 0]1406 pub fn set_contract_sponsoring_rate_limit(1407 origin,1408 contract_address: T::AccountId,1409 rate_limit: T::BlockNumber1410 ) -> DispatchResult {1411 let sender = ensure_signed(origin)?;1412 Self::ensure_contract_owned(sender, &contract_address)?;14131414 <ContractSponsoringRateLimit<T>>::insert(contract_address, rate_limit);1415 Ok(())1416 }14171418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 #[weight = 0]1430 pub fn toggle_contract_white_list(1431 origin,1432 contract_address: T::AccountId,1433 enable: bool1434 ) -> DispatchResult {1435 let sender = ensure_signed(origin)?;1436 Self::ensure_contract_owned(sender, &contract_address)?;14371438 <ContractWhiteListEnabled<T>>::insert(contract_address, enable);1439 Ok(())1440 }1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 #[weight = 0]1454 pub fn add_to_contract_white_list(1455 origin,1456 contract_address: T::AccountId,1457 account_address: T::AccountId1458 ) -> DispatchResult {1459 let sender = ensure_signed(origin)?;1460 Self::ensure_contract_owned(sender, &contract_address)?;1461 1462 <ContractWhiteList<T>>::insert(contract_address, account_address, true);1463 Ok(())1464 }14651466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 #[weight = 0]1478 pub fn remove_from_contract_white_list(1479 origin,1480 contract_address: T::AccountId,1481 account_address: T::AccountId1482 ) -> DispatchResult {1483 let sender = ensure_signed(origin)?;1484 Self::ensure_contract_owned(sender, &contract_address)?;1485 1486 <ContractWhiteList<T>>::remove(contract_address, account_address);1487 Ok(())1488 }14891490 #[weight = 0]1491 pub fn set_collection_limits(1492 origin,1493 collection_id: u32,1494 limits: CollectionLimits,1495 ) -> DispatchResult {1496 let sender = ensure_signed(origin)?;1497 Self::check_owner_permissions(collection_id, sender.clone())?;1498 let mut target_collection = <Collection<T>>::get(collection_id);1499 let chain_limits = ChainLimit::get();1500 let climits = target_collection.limits;15011502 1503 ensure!(limits.sponsor_transfer_timeout <= MAX_SPONSOR_TIMEOUT &&1504 limits.account_token_ownership_limit <= MAX_TOKEN_OWNERSHIP, 1505 Error::<T>::CollectionLimitBoundsExceeded);15061507 1508 ensure!(climits.token_limit > limits.token_limit && 1509 limits.token_limit <= chain_limits.account_token_ownership_limit, 1510 Error::<T>::AccountTokenLimitExceeded);15111512 target_collection.limits = limits;1513 <Collection<T>>::insert(collection_id, target_collection);15141515 Ok(())1516 } 1517 }1518}15191520impl<T: Trait> Module<T> {15211522 fn is_correct_transfer(collection_id: CollectionId, collection: &CollectionType<T::AccountId>, recipient: &T::AccountId) -> DispatchResult {15231524 1525 let account_items: u32 = <AddressTokens<T>>::get(collection_id, recipient).len() as u32;1526 ensure!(collection.limits.account_token_ownership_limit > account_items, Error::<T>::AccountTokenLimitExceeded);1527 1528 Ok(())1529 }15301531 fn can_create_items_in_collection(collection_id: CollectionId, collection: &CollectionType<T::AccountId>, sender: &T::AccountId, owner: &T::AccountId) -> DispatchResult {15321533 1534 let total_items: u32 = ItemListIndex::get(collection_id);1535 let account_items: u32 = <AddressTokens<T>>::get(collection_id, owner).len() as u32;1536 ensure!(collection.limits.token_limit > total_items, Error::<T>::CollectionTokenLimitExceeded);1537 ensure!(collection.limits.account_token_ownership_limit > account_items, Error::<T>::AccountTokenLimitExceeded);15381539 if !Self::is_owner_or_admin_permissions(collection_id, sender.clone()) {1540 ensure!(collection.mint_mode == true, Error::<T>::PublicMintingNotAllowed);1541 Self::check_white_list(collection_id, owner)?;1542 Self::check_white_list(collection_id, sender)?;1543 }15441545 Ok(())1546 }15471548 fn validate_create_item_args(target_collection: &CollectionType<T::AccountId>, data: &CreateItemData) -> DispatchResult {1549 match target_collection.mode1550 {1551 CollectionMode::NFT => {1552 if let CreateItemData::NFT(data) = data {1553 1554 ensure!(ChainLimit::get().custom_data_limit >= data.const_data.len() as u32, Error::<T>::TokenConstDataLimitExceeded);1555 ensure!(ChainLimit::get().custom_data_limit >= data.variable_data.len() as u32, Error::<T>::TokenVariableDataLimitExceeded);1556 } else {1557 fail!(Error::<T>::NotNftDataUsedToMintNftCollectionToken);1558 }1559 },1560 CollectionMode::Fungible(_) => {1561 if let CreateItemData::Fungible(_) = data {1562 } else {1563 fail!(Error::<T>::NotFungibleDataUsedToMintFungibleCollectionToken);1564 }1565 },1566 CollectionMode::ReFungible(_) => {1567 if let CreateItemData::ReFungible(data) = data {15681569 1570 ensure!(ChainLimit::get().custom_data_limit >= data.const_data.len() as u32, Error::<T>::TokenConstDataLimitExceeded);1571 ensure!(ChainLimit::get().custom_data_limit >= data.variable_data.len() as u32, Error::<T>::TokenVariableDataLimitExceeded);1572 } else {1573 fail!(Error::<T>::NotReFungibleDataUsedToMintReFungibleCollectionToken);1574 }1575 },1576 _ => { fail!(Error::<T>::UnexpectedCollectionType); }1577 };15781579 Ok(())1580 }15811582 fn create_item_no_validation(collection_id: CollectionId, collection: &CollectionType<T::AccountId>, owner: T::AccountId, data: CreateItemData) -> DispatchResult {1583 match data1584 {1585 CreateItemData::NFT(data) => {1586 let item = NftItemType {1587 owner,1588 const_data: data.const_data,1589 variable_data: data.variable_data1590 };15911592 Self::add_nft_item(collection_id, item)?;1593 },1594 CreateItemData::Fungible(data) => {1595 Self::add_fungible_item(collection_id, &owner, data.value)?;1596 },1597 CreateItemData::ReFungible(data) => {1598 let mut owner_list = Vec::new();1599 let value = (10 as u128).pow(collection.decimal_points as u32);1600 owner_list.push(Ownership {owner: owner.clone(), fraction: value});16011602 let item = ReFungibleItemType {1603 owner: owner_list,1604 const_data: data.const_data,1605 variable_data: data.variable_data1606 };16071608 Self::add_refungible_item(collection_id, item)?;1609 }1610 };16111612 1613 Self::deposit_event(RawEvent::ItemCreated(collection_id, <ItemListIndex>::get(collection_id)));16141615 Ok(())1616 }16171618 fn add_fungible_item(collection_id: CollectionId, owner: &T::AccountId, value: u128) -> DispatchResult {16191620 1621 let mut balance: u128 = 0;1622 if <FungibleItemList<T>>::contains_key(collection_id, owner) {1623 balance = <FungibleItemList<T>>::get(collection_id, owner).value;1624 } 16251626 1627 let item = FungibleItemType {1628 value: balance + value1629 };1630 <FungibleItemList<T>>::insert(collection_id, (*owner).clone(), item);16311632 1633 let new_balance = <Balance<T>>::get(collection_id, owner)1634 .checked_add(value)1635 .ok_or(Error::<T>::NumOverflow)?;1636 <Balance<T>>::insert(collection_id, (*owner).clone(), new_balance);16371638 Ok(())1639 }16401641 fn add_refungible_item(collection_id: CollectionId, item: ReFungibleItemType<T::AccountId>) -> DispatchResult {1642 let current_index = <ItemListIndex>::get(collection_id)1643 .checked_add(1)1644 .ok_or(Error::<T>::NumOverflow)?;1645 let itemcopy = item.clone();16461647 let value = item.owner.first().unwrap().fraction;1648 let owner = item.owner.first().unwrap().owner.clone();16491650 Self::add_token_index(collection_id, current_index, owner.clone())?;16511652 <ItemListIndex>::insert(collection_id, current_index);1653 <ReFungibleItemList<T>>::insert(collection_id, current_index, itemcopy);16541655 1656 let new_balance = <Balance<T>>::get(collection_id, owner.clone())1657 .checked_add(value)1658 .ok_or(Error::<T>::NumOverflow)?;1659 <Balance<T>>::insert(collection_id, owner.clone(), new_balance);16601661 Ok(())1662 }16631664 fn add_nft_item(collection_id: CollectionId, item: NftItemType<T::AccountId>) -> DispatchResult {1665 let current_index = <ItemListIndex>::get(collection_id)1666 .checked_add(1)1667 .ok_or(Error::<T>::NumOverflow)?;16681669 let item_owner = item.owner.clone();1670 Self::add_token_index(collection_id, current_index, item.owner.clone())?;16711672 <ItemListIndex>::insert(collection_id, current_index);1673 <NftItemList<T>>::insert(collection_id, current_index, item);16741675 1676 let new_balance = <Balance<T>>::get(collection_id, item_owner.clone())1677 .checked_add(1)1678 .ok_or(Error::<T>::NumOverflow)?;1679 <Balance<T>>::insert(collection_id, item_owner.clone(), new_balance);16801681 Ok(())1682 }16831684 fn burn_refungible_item(1685 collection_id: CollectionId,1686 item_id: TokenId,1687 owner: T::AccountId,1688 ) -> DispatchResult {1689 ensure!(1690 <ReFungibleItemList<T>>::contains_key(collection_id, item_id),1691 Error::<T>::TokenNotFound1692 );1693 let collection = <ReFungibleItemList<T>>::get(collection_id, item_id);1694 let item = collection1695 .owner1696 .iter()1697 .filter(|&i| i.owner == owner)1698 .next()1699 .unwrap();1700 Self::remove_token_index(collection_id, item_id, owner.clone())?;17011702 1703 let new_balance = <Balance<T>>::get(collection_id, item.owner.clone())1704 .checked_sub(item.fraction)1705 .ok_or(Error::<T>::NumOverflow)?;1706 <Balance<T>>::insert(collection_id, item.owner.clone(), new_balance);17071708 <ReFungibleItemList<T>>::remove(collection_id, item_id);17091710 Ok(())1711 }17121713 fn burn_nft_item(collection_id: CollectionId, item_id: TokenId) -> DispatchResult {1714 ensure!(1715 <NftItemList<T>>::contains_key(collection_id, item_id),1716 Error::<T>::TokenNotFound1717 );1718 let item = <NftItemList<T>>::get(collection_id, item_id);1719 Self::remove_token_index(collection_id, item_id, item.owner.clone())?;17201721 1722 let new_balance = <Balance<T>>::get(collection_id, item.owner.clone())1723 .checked_sub(1)1724 .ok_or(Error::<T>::NumOverflow)?;1725 <Balance<T>>::insert(collection_id, item.owner.clone(), new_balance);1726 <NftItemList<T>>::remove(collection_id, item_id);17271728 Ok(())1729 }17301731 fn burn_fungible_item(owner: &T::AccountId, collection_id: CollectionId, value: u128) -> DispatchResult {1732 ensure!(1733 <FungibleItemList<T>>::contains_key(collection_id, owner),1734 Error::<T>::TokenNotFound1735 );1736 let mut balance = <FungibleItemList<T>>::get(collection_id, owner);1737 ensure!(balance.value >= value, Error::<T>::TokenValueNotEnough);17381739 1740 let new_balance = <Balance<T>>::get(collection_id, owner)1741 .checked_sub(value)1742 .ok_or(Error::<T>::NumOverflow)?;1743 <Balance<T>>::insert(collection_id, (*owner).clone(), new_balance);17441745 if balance.value - value > 0 {1746 balance.value -= value;1747 <FungibleItemList<T>>::insert(collection_id, (*owner).clone(), balance);1748 }1749 else {1750 <FungibleItemList<T>>::remove(collection_id, owner);1751 }17521753 Ok(())1754 }17551756 fn collection_exists(collection_id: CollectionId) -> DispatchResult {1757 ensure!(1758 <Collection<T>>::contains_key(collection_id),1759 Error::<T>::CollectionNotFound1760 );1761 Ok(())1762 }17631764 fn check_owner_permissions(collection_id: CollectionId, subject: T::AccountId) -> DispatchResult {1765 Self::collection_exists(collection_id)?;17661767 let target_collection = <Collection<T>>::get(collection_id);1768 ensure!(1769 subject == target_collection.owner,1770 Error::<T>::NoPermission1771 );17721773 Ok(())1774 }17751776 fn is_owner_or_admin_permissions(collection_id: CollectionId, subject: T::AccountId) -> bool {1777 let target_collection = <Collection<T>>::get(collection_id);1778 let mut result: bool = subject == target_collection.owner;1779 let exists = <AdminList<T>>::contains_key(collection_id);17801781 if !result & exists {1782 if <AdminList<T>>::get(collection_id).contains(&subject) {1783 result = true1784 }1785 }17861787 result1788 }17891790 fn check_owner_or_admin_permissions(1791 collection_id: CollectionId,1792 subject: T::AccountId,1793 ) -> DispatchResult {1794 Self::collection_exists(collection_id)?;1795 let result = Self::is_owner_or_admin_permissions(collection_id, subject.clone());17961797 ensure!(1798 result,1799 Error::<T>::NoPermission1800 );1801 Ok(())1802 }18031804 fn is_item_owner(subject: T::AccountId, collection_id: CollectionId, item_id: TokenId) -> bool {1805 let target_collection = <Collection<T>>::get(collection_id);18061807 match target_collection.mode {1808 CollectionMode::NFT => {1809 <NftItemList<T>>::get(collection_id, item_id).owner == subject1810 }1811 CollectionMode::Fungible(_) => {1812 <FungibleItemList<T>>::contains_key(collection_id, &subject)1813 }1814 CollectionMode::ReFungible(_) => {1815 <ReFungibleItemList<T>>::get(collection_id, item_id)1816 .owner1817 .iter()1818 .any(|i| i.owner == subject)1819 }1820 CollectionMode::Invalid => false,1821 }1822 }18231824 fn check_white_list(collection_id: CollectionId, address: &T::AccountId) -> DispatchResult {1825 let mes = Error::<T>::AddresNotInWhiteList;1826 ensure!(<WhiteList<T>>::contains_key(collection_id, address), mes);18271828 Ok(())1829 }18301831 fn transfer_fungible(1832 collection_id: CollectionId,1833 value: u128,1834 owner: &T::AccountId,1835 recipient: &T::AccountId,1836 ) -> DispatchResult {1837 ensure!(1838 <FungibleItemList<T>>::contains_key(collection_id, owner),1839 Error::<T>::TokenNotFound1840 );18411842 let mut balance = <FungibleItemList<T>>::get(collection_id, owner);1843 ensure!(balance.value >= value, Error::<T>::TokenValueTooLow);18441845 1846 Self::add_fungible_item(collection_id, recipient, value)?;18471848 1849 <Balance<T>>::insert(collection_id, (*owner).clone(), balance.value - value);18501851 1852 if balance.value == value {1853 <FungibleItemList<T>>::remove(collection_id, owner);1854 }1855 else {1856 balance.value -= value;1857 <FungibleItemList<T>>::insert(collection_id, (*owner).clone(), balance);1858 }18591860 Ok(())1861 }18621863 fn transfer_refungible(1864 collection_id: CollectionId,1865 item_id: TokenId,1866 value: u128,1867 owner: T::AccountId,1868 new_owner: T::AccountId,1869 ) -> DispatchResult {1870 ensure!(1871 <ReFungibleItemList<T>>::contains_key(collection_id, item_id),1872 Error::<T>::TokenNotFound1873 );18741875 let full_item = <ReFungibleItemList<T>>::get(collection_id, item_id);1876 let item = full_item1877 .owner1878 .iter()1879 .filter(|i| i.owner == owner)1880 .next()1881 .ok_or(Error::<T>::NumOverflow)?;1882 let amount = item.fraction;18831884 ensure!(amount >= value, Error::<T>::TokenValueTooLow);18851886 1887 let balance_old_owner = <Balance<T>>::get(collection_id, item.owner.clone())1888 .checked_sub(value)1889 .ok_or(Error::<T>::NumOverflow)?;1890 <Balance<T>>::insert(collection_id, item.owner.clone(), balance_old_owner);18911892 let balancenew_owner = <Balance<T>>::get(collection_id, new_owner.clone())1893 .checked_add(value)1894 .ok_or(Error::<T>::NumOverflow)?;1895 <Balance<T>>::insert(collection_id, new_owner.clone(), balancenew_owner);18961897 let old_owner = item.owner.clone();1898 let new_owner_has_account = full_item.owner.iter().any(|i| i.owner == new_owner);18991900 1901 if amount == value && !new_owner_has_account {1902 1903 1904 let mut new_full_item = full_item.clone();1905 new_full_item1906 .owner1907 .iter_mut()1908 .find(|i| i.owner == owner)1909 .unwrap()1910 .owner = new_owner.clone();1911 <ReFungibleItemList<T>>::insert(collection_id, item_id, new_full_item);19121913 1914 Self::move_token_index(collection_id, item_id, old_owner.clone(), new_owner.clone())?;1915 } else {1916 let mut new_full_item = full_item.clone();1917 new_full_item1918 .owner1919 .iter_mut()1920 .find(|i| i.owner == owner)1921 .unwrap()1922 .fraction -= value;19231924 1925 if new_owner_has_account {1926 1927 new_full_item1928 .owner1929 .iter_mut()1930 .find(|i| i.owner == new_owner)1931 .unwrap()1932 .fraction += value;1933 } else {1934 1935 new_full_item.owner.push(Ownership {1936 owner: new_owner.clone(),1937 fraction: value,1938 });1939 Self::add_token_index(collection_id, item_id, new_owner.clone())?;1940 }19411942 <ReFungibleItemList<T>>::insert(collection_id, item_id, new_full_item);1943 }19441945 Ok(())1946 }19471948 fn transfer_nft(1949 collection_id: CollectionId,1950 item_id: TokenId,1951 sender: T::AccountId,1952 new_owner: T::AccountId,1953 ) -> DispatchResult {1954 ensure!(1955 <NftItemList<T>>::contains_key(collection_id, item_id),1956 Error::<T>::TokenNotFound1957 );19581959 let mut item = <NftItemList<T>>::get(collection_id, item_id);19601961 ensure!(1962 sender == item.owner,1963 Error::<T>::MustBeTokenOwner1964 );19651966 1967 let balance_old_owner = <Balance<T>>::get(collection_id, item.owner.clone())1968 .checked_sub(1)1969 .ok_or(Error::<T>::NumOverflow)?;1970 <Balance<T>>::insert(collection_id, item.owner.clone(), balance_old_owner);19711972 let balancenew_owner = <Balance<T>>::get(collection_id, new_owner.clone())1973 .checked_add(1)1974 .ok_or(Error::<T>::NumOverflow)?;1975 <Balance<T>>::insert(collection_id, new_owner.clone(), balancenew_owner);19761977 1978 let old_owner = item.owner.clone();1979 item.owner = new_owner.clone();1980 <NftItemList<T>>::insert(collection_id, item_id, item);19811982 1983 Self::move_token_index(collection_id, item_id, old_owner.clone(), new_owner.clone())?;19841985 Ok(())1986 }1987 1988 fn item_exists(1989 collection_id: CollectionId,1990 item_id: TokenId,1991 mode: &CollectionMode1992 ) -> DispatchResult {1993 match mode {1994 CollectionMode::NFT => ensure!(<NftItemList<T>>::contains_key(collection_id, item_id), Error::<T>::TokenNotFound),1995 CollectionMode::ReFungible(_) => ensure!(<ReFungibleItemList<T>>::contains_key(collection_id, item_id), Error::<T>::TokenNotFound),1996 _ => ()1997 };1998 1999 Ok(())2000 }20012002 fn set_re_fungible_variable_data(2003 collection_id: CollectionId,2004 item_id: TokenId,2005 data: Vec<u8>2006 ) -> DispatchResult {2007 let mut item = <ReFungibleItemList<T>>::get(collection_id, item_id);20082009 item.variable_data = data;20102011 <ReFungibleItemList<T>>::insert(collection_id, item_id, item);20122013 Ok(())2014 }20152016 fn set_nft_variable_data(2017 collection_id: CollectionId,2018 item_id: TokenId,2019 data: Vec<u8>2020 ) -> DispatchResult {2021 let mut item = <NftItemList<T>>::get(collection_id, item_id);2022 2023 item.variable_data = data;20242025 <NftItemList<T>>::insert(collection_id, item_id, item);2026 2027 Ok(())2028 }20292030 fn init_collection(item: &CollectionType<T::AccountId>) {2031 2032 assert!(2033 item.decimal_points <= MAX_DECIMAL_POINTS,2034 "decimal_points parameter must be lower than MAX_DECIMAL_POINTS"2035 );2036 assert!(2037 item.name.len() <= 64,2038 "Collection name can not be longer than 63 char"2039 );2040 assert!(2041 item.name.len() <= 256,2042 "Collection description can not be longer than 255 char"2043 );2044 assert!(2045 item.token_prefix.len() <= 16,2046 "Token prefix can not be longer than 15 char"2047 );20482049 2050 let next_id = CreatedCollectionCount::get()2051 .checked_add(1)2052 .unwrap();20532054 CreatedCollectionCount::put(next_id);2055 }20562057 fn init_nft_token(collection_id: CollectionId, item: &NftItemType<T::AccountId>) {2058 let current_index = <ItemListIndex>::get(collection_id)2059 .checked_add(1)2060 .unwrap();20612062 let item_owner = item.owner.clone();2063 Self::add_token_index(collection_id, current_index, item.owner.clone()).unwrap();20642065 <ItemListIndex>::insert(collection_id, current_index);20662067 2068 let new_balance = <Balance<T>>::get(collection_id, item_owner.clone())2069 .checked_add(1)2070 .unwrap();2071 <Balance<T>>::insert(collection_id, item_owner.clone(), new_balance);2072 }20732074 fn init_fungible_token(collection_id: CollectionId, owner: &T::AccountId, item: &FungibleItemType) {2075 let current_index = <ItemListIndex>::get(collection_id)2076 .checked_add(1)2077 .unwrap();20782079 Self::add_token_index(collection_id, current_index, (*owner).clone()).unwrap();20802081 <ItemListIndex>::insert(collection_id, current_index);20822083 2084 let new_balance = <Balance<T>>::get(collection_id, owner)2085 .checked_add(item.value)2086 .unwrap();2087 <Balance<T>>::insert(collection_id, (*owner).clone(), new_balance);2088 }20892090 fn init_refungible_token(collection_id: CollectionId, item: &ReFungibleItemType<T::AccountId>) {2091 let current_index = <ItemListIndex>::get(collection_id)2092 .checked_add(1)2093 .unwrap();20942095 let value = item.owner.first().unwrap().fraction;2096 let owner = item.owner.first().unwrap().owner.clone();20972098 Self::add_token_index(collection_id, current_index, owner.clone()).unwrap();20992100 <ItemListIndex>::insert(collection_id, current_index);21012102 2103 let new_balance = <Balance<T>>::get(collection_id, owner.clone())2104 .checked_add(value)2105 .unwrap();2106 <Balance<T>>::insert(collection_id, owner.clone(), new_balance);2107 }21082109 fn add_token_index(collection_id: CollectionId, item_index: TokenId, owner: T::AccountId) -> DispatchResult {21102111 2112 if <AccountItemCount<T>>::contains_key(owner.clone()) {21132114 2115 let count = <AccountItemCount<T>>::get(owner.clone());2116 ensure!(count < ChainLimit::get().account_token_ownership_limit, Error::<T>::AddressOwnershipLimitExceeded);21172118 <AccountItemCount<T>>::insert(owner.clone(), count2119 .checked_add(1)2120 .ok_or(Error::<T>::NumOverflow)?);2121 }2122 else {2123 <AccountItemCount<T>>::insert(owner.clone(), 1);2124 }21252126 let list_exists = <AddressTokens<T>>::contains_key(collection_id, owner.clone());2127 if list_exists {2128 let mut list = <AddressTokens<T>>::get(collection_id, owner.clone());2129 let item_contains = list.contains(&item_index.clone());21302131 if !item_contains {2132 list.push(item_index.clone());2133 }21342135 <AddressTokens<T>>::insert(collection_id, owner.clone(), list);2136 } else {2137 let mut itm = Vec::new();2138 itm.push(item_index.clone());2139 <AddressTokens<T>>::insert(collection_id, owner, itm);2140 2141 }21422143 Ok(())2144 }21452146 fn remove_token_index(2147 collection_id: CollectionId,2148 item_index: TokenId,2149 owner: T::AccountId,2150 ) -> DispatchResult {21512152 2153 <AccountItemCount<T>>::insert(owner.clone(), 2154 <AccountItemCount<T>>::get(owner.clone())2155 .checked_sub(1)2156 .ok_or(Error::<T>::NumOverflow)?);215721582159 let list_exists = <AddressTokens<T>>::contains_key(collection_id, owner.clone());2160 if list_exists {2161 let mut list = <AddressTokens<T>>::get(collection_id, owner.clone());2162 let item_contains = list.contains(&item_index.clone());21632164 if item_contains {2165 list.retain(|&item| item != item_index);2166 <AddressTokens<T>>::insert(collection_id, owner, list);2167 }2168 }21692170 Ok(())2171 }21722173 fn move_token_index(2174 collection_id: CollectionId,2175 item_index: TokenId,2176 old_owner: T::AccountId,2177 new_owner: T::AccountId,2178 ) -> DispatchResult {2179 Self::remove_token_index(collection_id, item_index, old_owner)?;2180 Self::add_token_index(collection_id, item_index, new_owner)?;21812182 Ok(())2183 }2184 2185 fn ensure_contract_owned(account: T::AccountId, contract: &T::AccountId) -> DispatchResult {2186 if <ContractOwner<T>>::contains_key(contract.clone()) {2187 let owner = <ContractOwner<T>>::get(contract);2188 ensure!(account == owner, Error::<T>::NoPermission);2189 } else {2190 fail!(Error::<T>::NoPermission);2191 }21922193 Ok(())2194 }2195}2196219721982199220022012202pub type Multiplier = FixedU128;22032204type BalanceOf<T> = <<T as transaction_payment::Trait>::Currency as Currency<2205 <T as system::Trait>::AccountId,2206>>::Balance;2207type NegativeImbalanceOf<T> = <<T as transaction_payment::Trait>::Currency as Currency<2208 <T as system::Trait>::AccountId,2209>>::NegativeImbalance;2210221122122213#[derive(Encode, Decode, Clone, Eq, PartialEq)]2214pub struct ChargeTransactionPayment<T: Trait + Send + Sync>(2215 #[codec(compact)] BalanceOf<T>2216);22172218impl<T: Trait + Send + Sync> sp_std::fmt::Debug2219 for ChargeTransactionPayment<T>2220{2221 #[cfg(feature = "std")]2222 fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {2223 write!(f, "ChargeTransactionPayment<{:?}>", self.0)2224 }2225 #[cfg(not(feature = "std"))]2226 fn fmt(&self, _: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {2227 Ok(())2228 }2229}22302231impl<T: Trait + Send + Sync> ChargeTransactionPayment<T>2232where2233 T::Call: Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo> + IsSubType<Call<T>> + IsSubType<pallet_contracts::Call<T>>,2234 BalanceOf<T>: Send + Sync + FixedPointOperand,2235{2236 2237 pub fn from(fee: BalanceOf<T>) -> Self {2238 Self(fee)2239 }22402241 pub fn traditional_fee(2242 len: usize,2243 info: &DispatchInfoOf<T::Call>,2244 tip: BalanceOf<T>,2245 ) -> BalanceOf<T>2246 where2247 T::Call: Dispatchable<Info = DispatchInfo>,2248 {2249 <transaction_payment::Module<T>>::compute_fee(len as u32, info, tip)2250 }22512252 fn get_priority(len: usize, info: &DispatchInfoOf<T::Call>, final_fee: BalanceOf<T>) -> TransactionPriority {2253 let weight_saturation = T::MaximumBlockWeight::get() / info.weight.max(1);2254 let len_saturation = T::MaximumBlockLength::get() as u64 / (len as u64).max(1);2255 let coefficient: BalanceOf<T> = weight_saturation.min(len_saturation).saturated_into::<BalanceOf<T>>();2256 final_fee.saturating_mul(coefficient).saturated_into::<TransactionPriority>()2257 }22582259 fn withdraw_fee(2260 &self,2261 who: &T::AccountId,2262 call: &T::Call,2263 info: &DispatchInfoOf<T::Call>,2264 len: usize,2265 ) -> Result<(BalanceOf<T>, Option<NegativeImbalanceOf<T>>), TransactionValidityError> {2266 let tip = self.0;22672268 2269 2270 2271 2272 2273 2274 2275 let fee = Self::traditional_fee(len, info, tip);22762277 2278 if fee.is_zero() {2279 return Ok((fee, None));2280 }22812282 2283 2284 let mut sponsor: T::AccountId = match IsSubType::<Call<T>>::is_sub_type(call) {2285 Some(Call::create_item(collection_id, _owner, _properties)) => {22862287 2288 if (<Collection<T>>::get(collection_id).limits.sponsored_data_size >= (_properties.len() as u32)) &&2289 (<Collection<T>>::get(collection_id).sponsor_confirmed)2290 {2291 <Collection<T>>::get(collection_id).sponsor2292 } else {2293 T::AccountId::default()2294 }2295 }2296 Some(Call::transfer(_new_owner, collection_id, item_id, _value)) => {2297 2298 let mut sponsor_transfer = false;2299 if <Collection<T>>::get(collection_id).sponsor_confirmed {23002301 let collection_limits = <Collection<T>>::get(collection_id).limits;2302 let collection_mode = <Collection<T>>::get(collection_id).mode;2303 2304 2305 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;2306 sponsor_transfer = match collection_mode {2307 CollectionMode::NFT => {2308 2309 2310 let limit: u32 = if collection_limits.sponsor_transfer_timeout > 0 {2311 collection_limits.sponsor_transfer_timeout2312 } else {2313 ChainLimit::get().nft_sponsor_transfer_timeout2314 };2315 2316 let mut sponsored = true;2317 if <NftTransferBasket<T>>::contains_key(collection_id, item_id) {2318 let last_tx_block = <NftTransferBasket<T>>::get(collection_id, item_id);2319 let limit_time = last_tx_block + limit.into();2320 if block_number <= limit_time {2321 sponsored = false;2322 }2323 }2324 if sponsored {2325 <NftTransferBasket<T>>::insert(collection_id, item_id, block_number);2326 }23272328 sponsored2329 }2330 CollectionMode::Fungible(_) => {2331 2332 2333 let limit: u32 = if collection_limits.sponsor_transfer_timeout > 0 {2334 collection_limits.sponsor_transfer_timeout2335 } else {2336 ChainLimit::get().fungible_sponsor_transfer_timeout2337 };2338 2339 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;2340 let mut sponsored = true;2341 if <FungibleTransferBasket<T>>::contains_key(collection_id, who) {2342 let last_tx_block = <FungibleTransferBasket<T>>::get(collection_id, who);2343 let limit_time = last_tx_block + limit.into();2344 if block_number <= limit_time {2345 sponsored = false;2346 }2347 }2348 if sponsored {2349 <FungibleTransferBasket<T>>::insert(collection_id, who, block_number);2350 }23512352 sponsored2353 }2354 CollectionMode::ReFungible(_) => {2355 2356 2357 let limit: u32 = if collection_limits.sponsor_transfer_timeout > 0 {2358 collection_limits.sponsor_transfer_timeout2359 } else {2360 ChainLimit::get().refungible_sponsor_transfer_timeout2361 };2362 2363 let mut sponsored = true;2364 if <ReFungibleTransferBasket<T>>::contains_key(collection_id, item_id) {2365 let last_tx_block = <ReFungibleTransferBasket<T>>::get(collection_id, item_id);2366 let limit_time = last_tx_block + limit.into();2367 if block_number <= limit_time {2368 sponsored = false;2369 }2370 }2371 if sponsored {2372 <ReFungibleTransferBasket<T>>::insert(collection_id, item_id, block_number);2373 }23742375 sponsored2376 }2377 _ => {2378 false2379 },2380 };2381 }23822383 if !sponsor_transfer {2384 T::AccountId::default()2385 } else {2386 <Collection<T>>::get(collection_id).sponsor2387 }2388 }23892390 _ => T::AccountId::default(),2391 };23922393 2394 sponsor = match IsSubType::<pallet_contracts::Call<T>>::is_sub_type(call) {23952396 2397 Some(pallet_contracts::Call::instantiate(_endowment, _gas_limit, code_hash, data)) => {23982399 let new_contract_address = <T as pallet_contracts::Trait>::DetermineContractAddress::contract_address_for(2400 code_hash,2401 &data,2402 &who,2403 );2404 <ContractOwner<T>>::insert(new_contract_address.clone(), who.clone());24052406 T::AccountId::default()2407 },24082409 2410 Some(pallet_contracts::Call::call(dest, _value, _gas_limit, _data)) => {24112412 let called_contract: T::AccountId = T::Lookup::lookup((*dest).clone()).unwrap_or(T::AccountId::default());24132414 let owned_contract = <ContractOwner<T>>::contains_key(called_contract.clone())2415 && <ContractOwner<T>>::get(called_contract.clone()) == *who;2416 let white_list_enabled = <ContractWhiteListEnabled<T>>::contains_key(called_contract.clone()) && <ContractWhiteListEnabled<T>>::get(called_contract.clone());2417 2418 if !owned_contract && white_list_enabled {2419 if !<ContractWhiteList<T>>::contains_key(called_contract.clone(), who) {2420 return Err(InvalidTransaction::Call.into());2421 }2422 }24232424 let mut sponsor_transfer = false;2425 if <ContractSponsoringRateLimit<T>>::contains_key(called_contract.clone()) {2426 let last_tx_block = <ContractSponsorBasket<T>>::get((&called_contract, &who));2427 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;2428 let rate_limit = <ContractSponsoringRateLimit<T>>::get(&called_contract);2429 let limit_time = last_tx_block + rate_limit;24302431 if block_number >= limit_time {2432 <ContractSponsorBasket<T>>::insert((called_contract.clone(), who.clone()), block_number);2433 sponsor_transfer = true;2434 }2435 } else {2436 sponsor_transfer = false;2437 }2438 2439 2440 let mut sp = T::AccountId::default();2441 if sponsor_transfer {2442 if <ContractSelfSponsoring<T>>::contains_key(called_contract.clone()) {2443 if <ContractSelfSponsoring<T>>::get(called_contract.clone()) {2444 sp = called_contract;2445 }2446 }2447 }24482449 sp2450 },24512452 _ => sponsor,2453 };24542455 let mut who_pays_fee: T::AccountId = sponsor.clone();2456 if sponsor == T::AccountId::default() {2457 who_pays_fee = who.clone();2458 }24592460 match <T as transaction_payment::Trait>::Currency::withdraw(2461 &who_pays_fee,2462 fee,2463 if tip.is_zero() {2464 WithdrawReason::TransactionPayment.into()2465 } else {2466 WithdrawReason::TransactionPayment | WithdrawReason::Tip2467 },2468 ExistenceRequirement::KeepAlive,2469 ) {2470 Ok(imbalance) => Ok((fee, Some(imbalance))),2471 Err(_) => Err(InvalidTransaction::Payment.into()),2472 }2473 }2474}247524762477impl<T: Trait + Send + Sync> SignedExtension2478 for ChargeTransactionPayment<T>2479where2480 BalanceOf<T>: Send + Sync + From<u64> + FixedPointOperand,2481 T::Call: Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo> + IsSubType<Call<T>> + IsSubType<pallet_contracts::Call<T>>,2482{2483 const IDENTIFIER: &'static str = "ChargeTransactionPayment";2484 type AccountId = T::AccountId;2485 type Call = T::Call;2486 type AdditionalSigned = ();2487 type Pre = (2488 BalanceOf<T>,2489 Self::AccountId,2490 Option<NegativeImbalanceOf<T>>,2491 BalanceOf<T>,2492 );2493 fn additional_signed(&self) -> sp_std::result::Result<(), TransactionValidityError> {2494 Ok(())2495 }24962497 fn validate(2498 &self,2499 who: &Self::AccountId,2500 call: &Self::Call,2501 info: &DispatchInfoOf<Self::Call>,2502 len: usize,2503 ) -> TransactionValidity {2504 let (fee, _) = self.withdraw_fee(who, call, info, len)?;2505 Ok(ValidTransaction {2506 priority: Self::get_priority(len, info, fee),2507 ..Default::default()2508 })2509 }25102511 fn pre_dispatch(2512 self,2513 who: &Self::AccountId,2514 call: &Self::Call,2515 info: &DispatchInfoOf<Self::Call>,2516 len: usize,2517 ) -> Result<Self::Pre, TransactionValidityError> {2518 let (fee, imbalance) = self.withdraw_fee(who, call, info, len)?;2519 Ok((self.0, who.clone(), imbalance, fee))2520 }25212522 fn post_dispatch(2523 pre: Self::Pre,2524 info: &DispatchInfoOf<Self::Call>,2525 post_info: &PostDispatchInfoOf<Self::Call>,2526 len: usize,2527 _result: &DispatchResult,2528 ) -> Result<(), TransactionValidityError> {2529 let (tip, who, imbalance, fee) = pre;2530 if let Some(payed) = imbalance {2531 let actual_fee = <transaction_payment::Module<T>>::compute_actual_fee(2532 len as u32, info, post_info, tip,2533 );2534 let refund = fee.saturating_sub(actual_fee);2535 let actual_payment =2536 match <T as transaction_payment::Trait>::Currency::deposit_into_existing(2537 &who, refund,2538 ) {2539 Ok(refund_imbalance) => {2540 2541 2542 match payed.offset(refund_imbalance) {2543 Ok(actual_payment) => actual_payment,2544 Err(_) => return Err(InvalidTransaction::Payment.into()),2545 }2546 }2547 2548 2549 Err(_) => payed,2550 };2551 let imbalances = actual_payment.split(tip);2552 <T as transaction_payment::Trait>::OnTransactionPayment::on_unbalanceds(2553 Some(imbalances.0).into_iter().chain(Some(imbalances.1)),2554 );2555 }2556 Ok(())2557 }2558}25592560