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 Default for CollectionMode {78 fn default() -> Self {79 Self::Invalid80 }81}8283impl Into<u8> for CollectionMode {84 fn into(self) -> u8 {85 match self {86 CollectionMode::Invalid => 0,87 CollectionMode::NFT => 1,88 CollectionMode::Fungible(_) => 2,89 CollectionMode::ReFungible(_) => 3,90 }91 }92}9394#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq)]95#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]96pub enum AccessMode {97 Normal,98 WhiteList,99}100impl Default for AccessMode {101 fn default() -> Self {102 Self::Normal103 }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,211212 213 pub offchain_schema_limit: u32,214 pub variable_on_chain_schema_limit: u32,215 pub const_on_chain_schema_limit: u32,216}217218pub trait WeightInfo {219 fn create_collection() -> Weight;220 fn destroy_collection() -> Weight;221 fn add_to_white_list() -> Weight;222 fn remove_from_white_list() -> Weight;223 fn set_public_access_mode() -> Weight;224 fn set_mint_permission() -> Weight;225 fn change_collection_owner() -> Weight;226 fn add_collection_admin() -> Weight;227 fn remove_collection_admin() -> Weight;228 fn set_collection_sponsor() -> Weight;229 fn confirm_sponsorship() -> Weight;230 fn remove_collection_sponsor() -> Weight;231 fn create_item(s: usize) -> Weight;232 fn burn_item() -> Weight;233 fn transfer() -> Weight;234 fn approve() -> Weight;235 fn transfer_from() -> Weight;236 fn set_offchain_schema() -> Weight;237 fn set_const_on_chain_schema() -> Weight;238 fn set_variable_on_chain_schema() -> Weight;239 fn set_variable_meta_data() -> Weight;240 fn enable_contract_sponsoring() -> Weight;241 fn set_schema_version() -> Weight;242 fn set_chain_limits() -> Weight;243 fn set_contract_sponsoring_rate_limit() -> Weight;244 fn toggle_contract_white_list() -> Weight;245 fn add_to_contract_white_list() -> Weight;246 fn remove_from_contract_white_list() -> Weight;247 fn set_collection_limits() -> Weight;248}249250#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]251#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]252pub struct CreateNftData {253 pub const_data: Vec<u8>,254 pub variable_data: Vec<u8>,255}256257#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]258#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]259pub struct CreateFungibleData {260 pub value: u128,261}262263#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]264#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]265pub struct CreateReFungibleData {266 pub const_data: Vec<u8>,267 pub variable_data: Vec<u8>,268}269270#[derive(Encode, Decode, Debug, Clone, PartialEq)]271#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]272pub enum CreateItemData {273 NFT(CreateNftData),274 Fungible(CreateFungibleData),275 ReFungible(CreateReFungibleData),276}277278impl CreateItemData {279 pub fn len(&self) -> usize {280 let len = match self {281 CreateItemData::NFT(data) => data.variable_data.len() + data.const_data.len(),282 CreateItemData::ReFungible(data) => data.variable_data.len() + data.const_data.len(),283 _ => 0284 };285 286 return len;287 }288}289290impl From<CreateNftData> for CreateItemData {291 fn from(item: CreateNftData) -> Self {292 CreateItemData::NFT(item)293 }294}295296impl From<CreateReFungibleData> for CreateItemData {297 fn from(item: CreateReFungibleData) -> Self {298 CreateItemData::ReFungible(item)299 }300}301302impl From<CreateFungibleData> for CreateItemData {303 fn from(item: CreateFungibleData) -> Self {304 CreateItemData::Fungible(item)305 }306}307308309decl_error! {310 311 pub enum Error for Module<T: Trait> {312 313 TotalCollectionsLimitExceeded,314 315 CollectionDecimalPointLimitExceeded, 316 317 CollectionNameLimitExceeded, 318 319 CollectionDescriptionLimitExceeded, 320 321 CollectionTokenPrefixLimitExceeded,322 323 CollectionNotFound,324 325 TokenNotFound,326 327 NumOverflow, 328 329 AlreadyAdmin, 330 331 NoPermission,332 333 ConfirmUnsetSponsorFail,334 335 PublicMintingNotAllowed,336 337 MustBeTokenOwner,338 339 TokenValueTooLow,340 341 NftSizeLimitExceeded,342 343 ApproveNotFound,344 345 TokenValueNotEnough,346 347 ApproveRequired,348 349 AddresNotInWhiteList,350 351 CollectionAdminsLimitExceeded,352 353 AddressOwnershipLimitExceeded,354 355 EmptyArgument,356 357 TokenConstDataLimitExceeded,358 359 TokenVariableDataLimitExceeded,360 361 NotNftDataUsedToMintNftCollectionToken,362 363 NotFungibleDataUsedToMintFungibleCollectionToken,364 365 NotReFungibleDataUsedToMintReFungibleCollectionToken,366 367 UnexpectedCollectionType,368 369 CantStoreMetadataInFungibleTokens,370 371 CollectionTokenLimitExceeded,372 373 AccountTokenLimitExceeded,374 375 CollectionLimitBoundsExceeded,376 377 SchemaDataLimitExceeded378 }379}380381pub trait Trait: system::Trait + Sized + transaction_payment::Trait + pallet_contracts::Trait {382 type Event: From<Event<Self>> + Into<<Self as system::Trait>::Event>;383384 385 type WeightInfo: WeightInfo;386}387388#[cfg(feature = "runtime-benchmarks")]389mod benchmarking;390391392393decl_storage! {394 trait Store for Module<T: Trait> as Nft {395396 397 NextCollectionID: CollectionId;398 CreatedCollectionCount: u32;399 ChainVersion: u64;400 ItemListIndex: map hasher(identity) CollectionId => TokenId;401402 403 pub ChainLimit get(fn chain_limit) config(): ChainLimits;404405 406 CollectionCount: u32;407 pub AccountItemCount get(fn account_item_count): map hasher(twox_64_concat) T::AccountId => u32;408409 410 pub Collection get(fn collection) config(): map hasher(identity) CollectionId => CollectionType<T::AccountId>;411 pub AdminList get(fn admin_list_collection): map hasher(identity) CollectionId => Vec<T::AccountId>;412 pub WhiteList get(fn white_list): double_map hasher(identity) CollectionId, hasher(twox_64_concat) T::AccountId => bool;413414 415 pub Balance get(fn balance_count): double_map hasher(identity) CollectionId, hasher(twox_64_concat) T::AccountId => u128;416417 418 pub Allowances get(fn approved): double_map hasher(identity) CollectionId, hasher(twox_64_concat) (TokenId, T::AccountId, T::AccountId) => u128;419420 421 pub NftItemList get(fn nft_item_id) config(): double_map hasher(identity) CollectionId, hasher(identity) TokenId => NftItemType<T::AccountId>;422 pub FungibleItemList get(fn fungible_item_id) config(): double_map hasher(identity) CollectionId, hasher(twox_64_concat) T::AccountId => FungibleItemType;423 pub ReFungibleItemList get(fn refungible_item_id) config(): double_map hasher(identity) CollectionId, hasher(identity) TokenId => ReFungibleItemType<T::AccountId>;424425 426 pub AddressTokens get(fn address_tokens): double_map hasher(identity) CollectionId, hasher(twox_64_concat) T::AccountId => Vec<TokenId>;427428 429 pub CreateItemBasket get(fn create_item_basket): map hasher(twox_64_concat) (CollectionId, T::AccountId) => T::BlockNumber;430 pub NftTransferBasket get(fn nft_transfer_basket): double_map hasher(identity) CollectionId, hasher(identity) TokenId => T::BlockNumber;431 pub FungibleTransferBasket get(fn fungible_transfer_basket): double_map hasher(identity) CollectionId, hasher(twox_64_concat) T::AccountId => T::BlockNumber;432 pub ReFungibleTransferBasket get(fn refungible_transfer_basket): double_map hasher(identity) CollectionId, hasher(identity) TokenId => T::BlockNumber;433434 435 pub ContractOwner get(fn contract_owner): map hasher(twox_64_concat) T::AccountId => T::AccountId;436 pub ContractSelfSponsoring get(fn contract_self_sponsoring): map hasher(twox_64_concat) T::AccountId => bool;437 pub ContractSponsorBasket get(fn contract_sponsor_basket): map hasher(twox_64_concat) (T::AccountId, T::AccountId) => T::BlockNumber;438 pub ContractSponsoringRateLimit get(fn contract_sponsoring_rate_limit): map hasher(twox_64_concat) T::AccountId => T::BlockNumber;439 pub ContractWhiteListEnabled get(fn contract_white_list_enabled): map hasher(twox_64_concat) T::AccountId => bool; 440 pub ContractWhiteList get(fn contract_white_list): double_map hasher(twox_64_concat) T::AccountId, hasher(twox_64_concat) T::AccountId => bool; 441 }442 add_extra_genesis {443 build(|config: &GenesisConfig<T>| {444 445 for (_num, _c) in &config.collection {446 <Module<T>>::init_collection(_c);447 }448449 for (_num, _c, _i) in &config.nft_item_id {450 <Module<T>>::init_nft_token(*_c, _i);451 }452453 for (collection_id, account_id, fungible_item) in &config.fungible_item_id {454 <Module<T>>::init_fungible_token(*collection_id, account_id, fungible_item);455 }456457 for (_num, _c, _i) in &config.refungible_item_id {458 <Module<T>>::init_refungible_token(*_c, _i);459 }460 })461 }462}463464decl_event!(465 pub enum Event<T>466 where467 AccountId = <T as system::Trait>::AccountId,468 {469 470 471 472 473 474 475 476 477 478 Created(CollectionId, u8, AccountId),479480 481 482 483 484 485 486 487 ItemCreated(CollectionId, TokenId),488489 490 491 492 493 494 495 496 ItemDestroyed(CollectionId, TokenId),497 }498);499500decl_module! {501 pub struct Module<T: Trait> for enum Call where origin: T::Origin {502503 fn deposit_event() = default;504 type Error = Error<T>;505506 fn on_initialize(now: T::BlockNumber) -> Weight {507508 if ChainVersion::get() < 2509 {510 let value = NextCollectionID::get();511 CreatedCollectionCount::put(value);512 ChainVersion::put(2);513 }514515 0516 }517518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 #[weight = T::WeightInfo::create_collection()]535 pub fn create_collection(origin,536 collection_name: Vec<u16>,537 collection_description: Vec<u16>,538 token_prefix: Vec<u8>,539 mode: CollectionMode) -> DispatchResult {540541 542 let who = ensure_signed(origin)?;543544 let decimal_points = match mode {545 CollectionMode::Fungible(points) => points,546 CollectionMode::ReFungible(points) => points,547 _ => 0548 };549550 551 ensure!(CollectionCount::get() < ChainLimit::get().collection_numbers_limit, Error::<T>::TotalCollectionsLimitExceeded);552553 554 ensure!(decimal_points <= MAX_DECIMAL_POINTS, Error::<T>::CollectionDecimalPointLimitExceeded);555 ensure!(collection_name.len() <= 64, Error::<T>::CollectionNameLimitExceeded);556 ensure!(collection_description.len() <= 256, Error::<T>::CollectionDescriptionLimitExceeded);557 ensure!(token_prefix.len() <= 16, Error::<T>::CollectionTokenPrefixLimitExceeded);558559 560 let next_id = CreatedCollectionCount::get()561 .checked_add(1)562 .ok_or(Error::<T>::NumOverflow)?;563564 565 let total = CollectionCount::get()566 .checked_add(1)567 .ok_or(Error::<T>::NumOverflow)?;568569 CreatedCollectionCount::put(next_id);570 CollectionCount::put(total);571572 573 let new_collection = CollectionType {574 owner: who.clone(),575 name: collection_name,576 mode: mode.clone(),577 mint_mode: false,578 access: AccessMode::Normal,579 description: collection_description,580 decimal_points: decimal_points,581 token_prefix: token_prefix,582 offchain_schema: Vec::new(),583 schema_version: SchemaVersion::ImageURL,584 sponsor: T::AccountId::default(),585 sponsor_confirmed: false,586 variable_on_chain_schema: Vec::new(),587 const_on_chain_schema: Vec::new(),588 limits: CollectionLimits::default(),589 };590591 592 <Collection<T>>::insert(next_id, new_collection);593594 595 Self::deposit_event(RawEvent::Created(next_id, mode.into(), who.clone()));596597 Ok(())598 }599600 601 602 603 604 605 606 607 608 609 #[weight = T::WeightInfo::destroy_collection()]610 pub fn destroy_collection(origin, collection_id: CollectionId) -> DispatchResult {611612 let sender = ensure_signed(origin)?;613 Self::check_owner_permissions(collection_id, sender)?;614615 <AddressTokens<T>>::remove_prefix(collection_id);616 <Allowances<T>>::remove_prefix(collection_id);617 <Balance<T>>::remove_prefix(collection_id);618 <ItemListIndex>::remove(collection_id);619 <AdminList<T>>::remove(collection_id);620 <Collection<T>>::remove(collection_id);621 <WhiteList<T>>::remove_prefix(collection_id);622623 <NftItemList<T>>::remove_prefix(collection_id);624 <FungibleItemList<T>>::remove_prefix(collection_id);625 <ReFungibleItemList<T>>::remove_prefix(collection_id);626627 <NftTransferBasket<T>>::remove_prefix(collection_id);628 <FungibleTransferBasket<T>>::remove_prefix(collection_id);629 <ReFungibleTransferBasket<T>>::remove_prefix(collection_id);630631 if CollectionCount::get() > 0632 {633 634 let total = CollectionCount::get()635 .checked_sub(1)636 .ok_or(Error::<T>::NumOverflow)?;637638 CollectionCount::put(total);639 }640641 Ok(())642 }643644 645 646 647 648 649 650 651 652 653 654 655 656 #[weight = T::WeightInfo::add_to_white_list()]657 pub fn add_to_white_list(origin, collection_id: CollectionId, address: T::AccountId) -> DispatchResult{658659 let sender = ensure_signed(origin)?;660 Self::check_owner_or_admin_permissions(collection_id, sender)?;661662 <WhiteList<T>>::insert(collection_id, address, true);663 664 Ok(())665 }666667 668 669 670 671 672 673 674 675 676 677 678 679 #[weight = T::WeightInfo::remove_from_white_list()]680 pub fn remove_from_white_list(origin, collection_id: CollectionId, address: T::AccountId) -> DispatchResult{681682 let sender = ensure_signed(origin)?;683 Self::check_owner_or_admin_permissions(collection_id, sender)?;684685 <WhiteList<T>>::remove(collection_id, address);686687 Ok(())688 }689690 691 692 693 694 695 696 697 698 699 700 701 #[weight = T::WeightInfo::set_public_access_mode()]702 pub fn set_public_access_mode(origin, collection_id: CollectionId, mode: AccessMode) -> DispatchResult703 {704 let sender = ensure_signed(origin)?;705706 Self::check_owner_permissions(collection_id, sender)?;707 let mut target_collection = <Collection<T>>::get(collection_id);708 target_collection.access = mode;709 <Collection<T>>::insert(collection_id, target_collection);710711 Ok(())712 }713714 715 716 717 718 719 720 721 722 723 724 725 726 727 #[weight = T::WeightInfo::set_mint_permission()]728 pub fn set_mint_permission(origin, collection_id: CollectionId, mint_permission: bool) -> DispatchResult729 {730 let sender = ensure_signed(origin)?;731732 Self::check_owner_permissions(collection_id, sender)?;733 let mut target_collection = <Collection<T>>::get(collection_id);734 target_collection.mint_mode = mint_permission;735 <Collection<T>>::insert(collection_id, target_collection);736737 Ok(())738 }739740 741 742 743 744 745 746 747 748 749 750 751 #[weight = T::WeightInfo::change_collection_owner()]752 pub fn change_collection_owner(origin, collection_id: CollectionId, new_owner: T::AccountId) -> DispatchResult {753754 let sender = ensure_signed(origin)?;755 Self::check_owner_permissions(collection_id, sender)?;756 let mut target_collection = <Collection<T>>::get(collection_id);757 target_collection.owner = new_owner;758 <Collection<T>>::insert(collection_id, target_collection);759760 Ok(())761 }762763 764 765 766 767 768 769 770 771 772 773 774 775 776 #[weight = T::WeightInfo::add_collection_admin()]777 pub fn add_collection_admin(origin, collection_id: CollectionId, new_admin_id: T::AccountId) -> DispatchResult {778779 let sender = ensure_signed(origin)?;780 Self::check_owner_or_admin_permissions(collection_id, sender)?;781 let mut admin_arr: Vec<T::AccountId> = Vec::new();782783 if <AdminList<T>>::contains_key(collection_id)784 {785 admin_arr = <AdminList<T>>::get(collection_id);786 ensure!(!admin_arr.contains(&new_admin_id), Error::<T>::AlreadyAdmin);787 }788789 790 ensure!((admin_arr.len() as u64) < ChainLimit::get().collections_admins_limit, Error::<T>::CollectionAdminsLimitExceeded);791792 admin_arr.push(new_admin_id);793 <AdminList<T>>::insert(collection_id, admin_arr);794795 Ok(())796 }797798 799 800 801 802 803 804 805 806 807 808 809 810 #[weight = T::WeightInfo::remove_collection_admin()]811 pub fn remove_collection_admin(origin, collection_id: CollectionId, account_id: T::AccountId) -> DispatchResult {812813 let sender = ensure_signed(origin)?;814 Self::check_owner_or_admin_permissions(collection_id, sender)?;815816 if <AdminList<T>>::contains_key(collection_id)817 {818 let mut admin_arr = <AdminList<T>>::get(collection_id);819 admin_arr.retain(|i| *i != account_id);820 <AdminList<T>>::insert(collection_id, admin_arr);821 }822823 Ok(())824 }825826 827 828 829 830 831 832 833 834 835 #[weight = T::WeightInfo::set_collection_sponsor()]836 pub fn set_collection_sponsor(origin, collection_id: CollectionId, new_sponsor: T::AccountId) -> DispatchResult {837838 let sender = ensure_signed(origin)?;839 ensure!(<Collection<T>>::contains_key(collection_id), Error::<T>::CollectionNotFound);840841 let mut target_collection = <Collection<T>>::get(collection_id);842 ensure!(sender == target_collection.owner, Error::<T>::NoPermission);843844 target_collection.sponsor = new_sponsor;845 target_collection.sponsor_confirmed = false;846 <Collection<T>>::insert(collection_id, target_collection);847848 Ok(())849 }850851 852 853 854 855 856 857 858 #[weight = T::WeightInfo::confirm_sponsorship()]859 pub fn confirm_sponsorship(origin, collection_id: CollectionId) -> DispatchResult {860861 let sender = ensure_signed(origin)?;862 ensure!(<Collection<T>>::contains_key(collection_id), Error::<T>::CollectionNotFound);863864 let mut target_collection = <Collection<T>>::get(collection_id);865 ensure!(sender == target_collection.sponsor, Error::<T>::ConfirmUnsetSponsorFail);866867 target_collection.sponsor_confirmed = true;868 <Collection<T>>::insert(collection_id, target_collection);869870 Ok(())871 }872873 874 875 876 877 878 879 880 881 882 #[weight = T::WeightInfo::remove_collection_sponsor()]883 pub fn remove_collection_sponsor(origin, collection_id: CollectionId) -> DispatchResult {884885 let sender = ensure_signed(origin)?;886 ensure!(<Collection<T>>::contains_key(collection_id), Error::<T>::CollectionNotFound);887888 let mut target_collection = <Collection<T>>::get(collection_id);889 ensure!(sender == target_collection.owner, Error::<T>::NoPermission);890891 target_collection.sponsor = T::AccountId::default();892 target_collection.sponsor_confirmed = false;893 <Collection<T>>::insert(collection_id, target_collection);894895 Ok(())896 }897898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921922 #[weight = T::WeightInfo::create_item(data.len())]923 pub fn create_item(origin, collection_id: CollectionId, owner: T::AccountId, data: CreateItemData) -> DispatchResult {924925 let sender = ensure_signed(origin)?;926927 Self::collection_exists(collection_id)?;928929 let target_collection = <Collection<T>>::get(collection_id);930931 Self::can_create_items_in_collection(collection_id, &target_collection, &sender, &owner)?;932 Self::validate_create_item_args(&target_collection, &data)?;933 Self::create_item_no_validation(collection_id, &target_collection, owner, data)?;934935 Ok(())936 }937938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 #[weight = T::WeightInfo::create_item(items_data.into_iter()957 .map(|data| { data.len() })958 .sum())]959 pub fn create_multiple_items(origin, collection_id: CollectionId, owner: T::AccountId, items_data: Vec<CreateItemData>) -> DispatchResult {960961 ensure!(items_data.len() > 0, Error::<T>::EmptyArgument);962 let sender = ensure_signed(origin)?;963964 Self::collection_exists(collection_id)?;965 let target_collection = <Collection<T>>::get(collection_id);966967 Self::can_create_items_in_collection(collection_id, &target_collection, &sender, &owner)?;968969 for data in &items_data {970 Self::validate_create_item_args(&target_collection, data)?;971 }972 for data in &items_data {973 Self::create_item_no_validation(collection_id, &target_collection, owner.clone(), data.clone())?;974 }975976 Ok(())977 }978979 980 981 982 983 984 985 986 987 988 989 990 991 992 #[weight = T::WeightInfo::burn_item()]993 pub fn burn_item(origin, collection_id: CollectionId, item_id: TokenId, value: u128) -> DispatchResult {994995 let sender = ensure_signed(origin)?;996 Self::collection_exists(collection_id)?;997998 999 let target_collection = <Collection<T>>::get(collection_id);1000 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||1001 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1002 Error::<T>::NoPermission);10031004 if target_collection.access == AccessMode::WhiteList {1005 Self::check_white_list(collection_id, &sender)?;1006 }10071008 match target_collection.mode1009 {1010 CollectionMode::NFT => Self::burn_nft_item(collection_id, item_id)?,1011 CollectionMode::Fungible(_) => Self::burn_fungible_item(&sender, collection_id, value)?,1012 CollectionMode::ReFungible(_) => Self::burn_refungible_item(collection_id, item_id, &sender)?,1013 _ => ()1014 };10151016 1017 Self::deposit_event(RawEvent::ItemDestroyed(collection_id, item_id));10181019 Ok(())1020 }10211022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 #[weight = T::WeightInfo::transfer()]1046 pub fn transfer(origin, recipient: T::AccountId, collection_id: CollectionId, item_id: TokenId, value: u128) -> DispatchResult {10471048 let sender = ensure_signed(origin)?;1049 let target_collection = <Collection<T>>::get(collection_id);10501051 1052 Self::is_correct_transfer(collection_id, &target_collection, &recipient)?;10531054 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, value, &sender, &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, spender: T::AccountId, collection_id: CollectionId, item_id: TokenId, amount: u128) -> DispatchResult {10921093 let sender = ensure_signed(origin)?;10941095 Self::collection_exists(collection_id)?;1096 Self::token_exists(collection_id, item_id, &sender)?;10971098 1099 let target_collection = <Collection<T>>::get(collection_id);1100 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||1101 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1102 Error::<T>::NoPermission);11031104 if target_collection.access == AccessMode::WhiteList {1105 Self::check_white_list(collection_id, &sender)?;1106 Self::check_white_list(collection_id, &spender)?;1107 }11081109 let allowance_exists = <Allowances<T>>::contains_key(collection_id, (item_id, &sender, &spender));1110 let mut allowance: u128 = amount;1111 if allowance_exists {1112 allowance += <Allowances<T>>::get(collection_id, (item_id, &sender, &spender));1113 }1114 <Allowances<T>>::insert(collection_id, (item_id, sender.clone(), spender.clone()), allowance);11151116 Ok(())1117 }1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 #[weight = T::WeightInfo::transfer_from()]1139 pub fn transfer_from(origin, from: T::AccountId, recipient: T::AccountId, collection_id: CollectionId, item_id: TokenId, value: u128 ) -> DispatchResult {11401141 let sender = ensure_signed(origin)?;1142 let mut appoved_transfer = false;11431144 1145 let mut approval: u128 = 0;1146 if <Allowances<T>>::contains_key(collection_id, (item_id, &from, &recipient)) {1147 approval = <Allowances<T>>::get(collection_id, (item_id, &from, &recipient));1148 ensure!(approval >= value, Error::<T>::TokenValueNotEnough);1149 appoved_transfer = true;1150 }11511152 let target_collection = <Collection<T>>::get(collection_id);11531154 1155 Self::is_correct_transfer(collection_id, &target_collection, &recipient)?;11561157 1158 ensure!(appoved_transfer || Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1159 Error::<T>::NoPermission);11601161 if target_collection.access == AccessMode::WhiteList {1162 Self::check_white_list(collection_id, &sender)?;1163 Self::check_white_list(collection_id, &recipient)?;1164 }11651166 1167 if approval.checked_sub(value).unwrap_or(0) > 0 {1168 <Allowances<T>>::insert(collection_id, (item_id, &from, &recipient), approval - value);1169 }1170 else {1171 <Allowances<T>>::remove(collection_id, (item_id, &from, &recipient));1172 }11731174 match target_collection.mode1175 {1176 CollectionMode::NFT => Self::transfer_nft(collection_id, item_id, from, recipient)?,1177 CollectionMode::Fungible(_) => Self::transfer_fungible(collection_id, value, &from, &recipient)?,1178 CollectionMode::ReFungible(_) => Self::transfer_refungible(collection_id, item_id, value, from.clone(), recipient)?,1179 _ => ()1180 };11811182 Ok(())1183 }11841185 #[weight = 0]1186 pub fn safe_transfer_from(origin, collection_id: CollectionId, item_id: TokenId, new_owner: T::AccountId) -> DispatchResult {11871188 1189 1190 1191 11921193 11941195 11961197 Ok(())1198 }11991200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 #[weight = T::WeightInfo::set_variable_meta_data()]1213 pub fn set_variable_meta_data (1214 origin,1215 collection_id: CollectionId,1216 item_id: TokenId,1217 data: Vec<u8>1218 ) -> DispatchResult {1219 let sender = ensure_signed(origin)?;1220 1221 Self::collection_exists(collection_id)?;1222 Self::token_exists(collection_id, item_id, &sender)?;12231224 ensure!(ChainLimit::get().custom_data_limit >= data.len() as u32, Error::<T>::TokenVariableDataLimitExceeded);12251226 1227 let target_collection = <Collection<T>>::get(collection_id);1228 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||1229 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1230 Error::<T>::NoPermission);12311232 match target_collection.mode1233 {1234 CollectionMode::NFT => Self::set_nft_variable_data(collection_id, item_id, data)?,1235 CollectionMode::ReFungible(_) => Self::set_re_fungible_variable_data(collection_id, item_id, data)?,1236 CollectionMode::Fungible(_) => fail!(Error::<T>::CantStoreMetadataInFungibleTokens),1237 _ => fail!(Error::<T>::UnexpectedCollectionType)1238 };12391240 Ok(())1241 }1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 #[weight = T::WeightInfo::set_schema_version()]1258 pub fn set_schema_version(1259 origin,1260 collection_id: CollectionId,1261 version: SchemaVersion1262 ) -> DispatchResult {1263 let sender = ensure_signed(origin)?;1264 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;1265 let mut target_collection = <Collection<T>>::get(collection_id);1266 target_collection.schema_version = version;1267 <Collection<T>>::insert(collection_id, target_collection);12681269 Ok(())1270 }12711272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 #[weight = T::WeightInfo::set_offchain_schema()]1285 pub fn set_offchain_schema(1286 origin,1287 collection_id: CollectionId,1288 schema: Vec<u8>1289 ) -> DispatchResult {1290 let sender = ensure_signed(origin)?;1291 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;12921293 1294 ensure!(schema.len() as u32 > ChainLimit::get().offchain_schema_limit, "");12951296 let mut target_collection = <Collection<T>>::get(collection_id);1297 target_collection.offchain_schema = schema;1298 <Collection<T>>::insert(collection_id, target_collection);12991300 Ok(())1301 }13021303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 #[weight = T::WeightInfo::set_const_on_chain_schema()]1316 pub fn set_const_on_chain_schema (1317 origin,1318 collection_id: CollectionId,1319 schema: Vec<u8>1320 ) -> DispatchResult {1321 let sender = ensure_signed(origin)?;1322 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;13231324 1325 ensure!(schema.len() as u32 > ChainLimit::get().const_on_chain_schema_limit, "");13261327 let mut target_collection = <Collection<T>>::get(collection_id);1328 target_collection.const_on_chain_schema = schema;1329 <Collection<T>>::insert(collection_id, target_collection);13301331 Ok(())1332 }13331334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 #[weight = T::WeightInfo::set_const_on_chain_schema()]1347 pub fn set_variable_on_chain_schema (1348 origin,1349 collection_id: CollectionId,1350 schema: Vec<u8>1351 ) -> DispatchResult {1352 let sender = ensure_signed(origin)?;1353 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;13541355 1356 ensure!(schema.len() as u32 > ChainLimit::get().variable_on_chain_schema_limit, "");13571358 let mut target_collection = <Collection<T>>::get(collection_id);1359 target_collection.variable_on_chain_schema = schema;1360 <Collection<T>>::insert(collection_id, target_collection);13611362 Ok(())1363 }13641365 1366 #[weight = T::WeightInfo::set_chain_limits()]1367 pub fn set_chain_limits(1368 origin,1369 limits: ChainLimits1370 ) -> DispatchResult {13711372 #[cfg(not(feature = "runtime-benchmarks"))]1373 ensure_root(origin)?;13741375 <ChainLimit>::put(limits);1376 Ok(())1377 }13781379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 #[weight = T::WeightInfo::enable_contract_sponsoring()]1391 pub fn enable_contract_sponsoring(1392 origin,1393 contract_address: T::AccountId,1394 enable: bool1395 ) -> DispatchResult {13961397 let sender = ensure_signed(origin)?;13981399 #[cfg(feature = "runtime-benchmarks")]1400 <ContractOwner<T>>::insert(contract_address.clone(), sender.clone());14011402 Self::ensure_contract_owned(sender, &contract_address)?;14031404 <ContractSelfSponsoring<T>>::insert(contract_address, enable);1405 Ok(())1406 }14071408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 #[weight = T::WeightInfo::set_contract_sponsoring_rate_limit()]1426 pub fn set_contract_sponsoring_rate_limit(1427 origin,1428 contract_address: T::AccountId,1429 rate_limit: T::BlockNumber1430 ) -> DispatchResult {1431 let sender = ensure_signed(origin)?;14321433 #[cfg(feature = "runtime-benchmarks")]1434 <ContractOwner<T>>::insert(contract_address.clone(), sender.clone());14351436 Self::ensure_contract_owned(sender, &contract_address)?;1437 <ContractSponsoringRateLimit<T>>::insert(contract_address, rate_limit);1438 Ok(())1439 }14401441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 #[weight = T::WeightInfo::toggle_contract_white_list()]1453 pub fn toggle_contract_white_list(1454 origin,1455 contract_address: T::AccountId,1456 enable: bool1457 ) -> DispatchResult {1458 let sender = ensure_signed(origin)?;14591460 #[cfg(feature = "runtime-benchmarks")]1461 <ContractOwner<T>>::insert(contract_address.clone(), sender.clone());14621463 Self::ensure_contract_owned(sender, &contract_address)?;1464 <ContractWhiteListEnabled<T>>::insert(contract_address, enable);1465 Ok(())1466 }1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 #[weight = T::WeightInfo::add_to_contract_white_list()]1480 pub fn add_to_contract_white_list(1481 origin,1482 contract_address: T::AccountId,1483 account_address: T::AccountId1484 ) -> DispatchResult {1485 let sender = ensure_signed(origin)?;14861487 #[cfg(feature = "runtime-benchmarks")]1488 <ContractOwner<T>>::insert(contract_address.clone(), sender.clone());1489 1490 Self::ensure_contract_owned(sender, &contract_address)?; 1491 <ContractWhiteList<T>>::insert(contract_address, account_address, true);1492 Ok(())1493 }14941495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 #[weight = T::WeightInfo::remove_from_contract_white_list()]1507 pub fn remove_from_contract_white_list(1508 origin,1509 contract_address: T::AccountId,1510 account_address: T::AccountId1511 ) -> DispatchResult {1512 let sender = ensure_signed(origin)?;15131514 #[cfg(feature = "runtime-benchmarks")]1515 <ContractOwner<T>>::insert(contract_address.clone(), sender.clone());15161517 Self::ensure_contract_owned(sender, &contract_address)?;1518 <ContractWhiteList<T>>::remove(contract_address, account_address);1519 Ok(())1520 }15211522 #[weight = T::WeightInfo::set_collection_limits()]1523 pub fn set_collection_limits(1524 origin,1525 collection_id: u32,1526 limits: CollectionLimits,1527 ) -> DispatchResult {1528 let sender = ensure_signed(origin)?;1529 Self::check_owner_permissions(collection_id, sender.clone())?;1530 let mut target_collection = <Collection<T>>::get(collection_id);1531 let chain_limits = ChainLimit::get();1532 let climits = target_collection.limits;15331534 1535 ensure!(limits.sponsor_transfer_timeout <= MAX_SPONSOR_TIMEOUT &&1536 limits.account_token_ownership_limit <= MAX_TOKEN_OWNERSHIP, 1537 Error::<T>::CollectionLimitBoundsExceeded);15381539 1540 ensure!(climits.token_limit > limits.token_limit && 1541 limits.token_limit <= chain_limits.account_token_ownership_limit, 1542 Error::<T>::AccountTokenLimitExceeded);15431544 target_collection.limits = limits;1545 <Collection<T>>::insert(collection_id, target_collection);15461547 Ok(())1548 } 1549 }1550}15511552impl<T: Trait> Module<T> {15531554 fn is_correct_transfer(collection_id: CollectionId, collection: &CollectionType<T::AccountId>, recipient: &T::AccountId) -> DispatchResult {15551556 1557 let account_items: u32 = <AddressTokens<T>>::get(collection_id, recipient).len() as u32;1558 ensure!(collection.limits.account_token_ownership_limit > account_items, Error::<T>::AccountTokenLimitExceeded);1559 1560 Ok(())1561 }15621563 fn can_create_items_in_collection(collection_id: CollectionId, collection: &CollectionType<T::AccountId>, sender: &T::AccountId, owner: &T::AccountId) -> DispatchResult {15641565 1566 let total_items: u32 = ItemListIndex::get(collection_id);1567 let account_items: u32 = <AddressTokens<T>>::get(collection_id, owner).len() as u32;1568 ensure!(collection.limits.token_limit > total_items, Error::<T>::CollectionTokenLimitExceeded);1569 ensure!(collection.limits.account_token_ownership_limit > account_items, Error::<T>::AccountTokenLimitExceeded);15701571 if !Self::is_owner_or_admin_permissions(collection_id, sender.clone()) {1572 ensure!(collection.mint_mode == true, Error::<T>::PublicMintingNotAllowed);1573 Self::check_white_list(collection_id, owner)?;1574 Self::check_white_list(collection_id, sender)?;1575 }15761577 Ok(())1578 }15791580 fn validate_create_item_args(target_collection: &CollectionType<T::AccountId>, data: &CreateItemData) -> DispatchResult {1581 match target_collection.mode1582 {1583 CollectionMode::NFT => {1584 if let CreateItemData::NFT(data) = data {1585 1586 ensure!(ChainLimit::get().custom_data_limit >= data.const_data.len() as u32, Error::<T>::TokenConstDataLimitExceeded);1587 ensure!(ChainLimit::get().custom_data_limit >= data.variable_data.len() as u32, Error::<T>::TokenVariableDataLimitExceeded);1588 } else {1589 fail!(Error::<T>::NotNftDataUsedToMintNftCollectionToken);1590 }1591 },1592 CollectionMode::Fungible(_) => {1593 if let CreateItemData::Fungible(_) = data {1594 } else {1595 fail!(Error::<T>::NotFungibleDataUsedToMintFungibleCollectionToken);1596 }1597 },1598 CollectionMode::ReFungible(_) => {1599 if let CreateItemData::ReFungible(data) = data {16001601 1602 ensure!(ChainLimit::get().custom_data_limit >= data.const_data.len() as u32, Error::<T>::TokenConstDataLimitExceeded);1603 ensure!(ChainLimit::get().custom_data_limit >= data.variable_data.len() as u32, Error::<T>::TokenVariableDataLimitExceeded);1604 } else {1605 fail!(Error::<T>::NotReFungibleDataUsedToMintReFungibleCollectionToken);1606 }1607 },1608 _ => { fail!(Error::<T>::UnexpectedCollectionType); }1609 };16101611 Ok(())1612 }16131614 fn create_item_no_validation(collection_id: CollectionId, collection: &CollectionType<T::AccountId>, owner: T::AccountId, data: CreateItemData) -> DispatchResult {1615 match data1616 {1617 CreateItemData::NFT(data) => {1618 let item = NftItemType {1619 owner,1620 const_data: data.const_data,1621 variable_data: data.variable_data1622 };16231624 Self::add_nft_item(collection_id, item)?;1625 },1626 CreateItemData::Fungible(data) => {1627 Self::add_fungible_item(collection_id, &owner, data.value)?;1628 },1629 CreateItemData::ReFungible(data) => {1630 let mut owner_list = Vec::new();1631 let value = (10 as u128).pow(collection.decimal_points as u32);1632 owner_list.push(Ownership {owner: owner.clone(), fraction: value});16331634 let item = ReFungibleItemType {1635 owner: owner_list,1636 const_data: data.const_data,1637 variable_data: data.variable_data1638 };16391640 Self::add_refungible_item(collection_id, item)?;1641 }1642 };16431644 1645 Self::deposit_event(RawEvent::ItemCreated(collection_id, <ItemListIndex>::get(collection_id)));16461647 Ok(())1648 }16491650 fn add_fungible_item(collection_id: CollectionId, owner: &T::AccountId, value: u128) -> DispatchResult {16511652 1653 let mut balance: u128 = 0;1654 if <FungibleItemList<T>>::contains_key(collection_id, owner) {1655 balance = <FungibleItemList<T>>::get(collection_id, owner).value;1656 } 16571658 1659 let item = FungibleItemType {1660 value: balance + value1661 };1662 <FungibleItemList<T>>::insert(collection_id, (*owner).clone(), item);16631664 1665 let new_balance = <Balance<T>>::get(collection_id, owner)1666 .checked_add(value)1667 .ok_or(Error::<T>::NumOverflow)?;1668 <Balance<T>>::insert(collection_id, (*owner).clone(), new_balance);16691670 Ok(())1671 }16721673 fn add_refungible_item(collection_id: CollectionId, item: ReFungibleItemType<T::AccountId>) -> DispatchResult {1674 let current_index = <ItemListIndex>::get(collection_id)1675 .checked_add(1)1676 .ok_or(Error::<T>::NumOverflow)?;1677 let itemcopy = item.clone();16781679 let value = item.owner.first().unwrap().fraction;1680 let owner = item.owner.first().unwrap().owner.clone();16811682 Self::add_token_index(collection_id, current_index, &owner)?;16831684 <ItemListIndex>::insert(collection_id, current_index);1685 <ReFungibleItemList<T>>::insert(collection_id, current_index, itemcopy);16861687 1688 let new_balance = <Balance<T>>::get(collection_id, &owner)1689 .checked_add(value)1690 .ok_or(Error::<T>::NumOverflow)?;1691 <Balance<T>>::insert(collection_id, owner.clone(), new_balance);16921693 Ok(())1694 }16951696 fn add_nft_item(collection_id: CollectionId, item: NftItemType<T::AccountId>) -> DispatchResult {1697 let current_index = <ItemListIndex>::get(collection_id)1698 .checked_add(1)1699 .ok_or(Error::<T>::NumOverflow)?;17001701 let item_owner = item.owner.clone();1702 Self::add_token_index(collection_id, current_index, &item.owner)?;17031704 <ItemListIndex>::insert(collection_id, current_index);1705 <NftItemList<T>>::insert(collection_id, current_index, item);17061707 1708 let new_balance = <Balance<T>>::get(collection_id, item_owner.clone())1709 .checked_add(1)1710 .ok_or(Error::<T>::NumOverflow)?;1711 <Balance<T>>::insert(collection_id, item_owner.clone(), new_balance);17121713 Ok(())1714 }17151716 fn burn_refungible_item(1717 collection_id: CollectionId,1718 item_id: TokenId,1719 owner: &T::AccountId,1720 ) -> DispatchResult {1721 ensure!(1722 <ReFungibleItemList<T>>::contains_key(collection_id, item_id),1723 Error::<T>::TokenNotFound1724 );1725 let mut token = <ReFungibleItemList<T>>::get(collection_id, item_id);1726 let rft_balance = token1727 .owner1728 .iter()1729 .filter(|&i| i.owner == *owner)1730 .next()1731 .unwrap();1732 Self::remove_token_index(collection_id, item_id, owner)?;17331734 1735 let new_balance = <Balance<T>>::get(collection_id, rft_balance.owner.clone())1736 .checked_sub(rft_balance.fraction)1737 .ok_or(Error::<T>::NumOverflow)?;1738 <Balance<T>>::insert(collection_id, rft_balance.owner.clone(), new_balance);17391740 1741 let index = token1742 .owner1743 .iter()1744 .position(|i| i.owner == *owner)1745 .unwrap();1746 token.owner.remove(index);1747 let owner_count = token.owner.len();17481749 1750 if owner_count == 0 {1751 <ReFungibleItemList<T>>::remove(collection_id, item_id);1752 }1753 else {1754 <ReFungibleItemList<T>>::insert(collection_id, item_id, token);1755 }17561757 Ok(())1758 }17591760 fn burn_nft_item(collection_id: CollectionId, item_id: TokenId) -> DispatchResult {1761 ensure!(1762 <NftItemList<T>>::contains_key(collection_id, item_id),1763 Error::<T>::TokenNotFound1764 );1765 let item = <NftItemList<T>>::get(collection_id, item_id);1766 Self::remove_token_index(collection_id, item_id, &item.owner)?;17671768 1769 let new_balance = <Balance<T>>::get(collection_id, &item.owner)1770 .checked_sub(1)1771 .ok_or(Error::<T>::NumOverflow)?;1772 <Balance<T>>::insert(collection_id, item.owner.clone(), new_balance);1773 <NftItemList<T>>::remove(collection_id, item_id);17741775 Ok(())1776 }17771778 fn burn_fungible_item(owner: &T::AccountId, collection_id: CollectionId, value: u128) -> DispatchResult {1779 ensure!(1780 <FungibleItemList<T>>::contains_key(collection_id, owner),1781 Error::<T>::TokenNotFound1782 );1783 let mut balance = <FungibleItemList<T>>::get(collection_id, owner);1784 ensure!(balance.value >= value, Error::<T>::TokenValueNotEnough);17851786 1787 let new_balance = <Balance<T>>::get(collection_id, owner)1788 .checked_sub(value)1789 .ok_or(Error::<T>::NumOverflow)?;1790 <Balance<T>>::insert(collection_id, (*owner).clone(), new_balance);17911792 if balance.value - value > 0 {1793 balance.value -= value;1794 <FungibleItemList<T>>::insert(collection_id, (*owner).clone(), balance);1795 }1796 else {1797 <FungibleItemList<T>>::remove(collection_id, owner);1798 }17991800 Ok(())1801 }18021803 fn collection_exists(collection_id: CollectionId) -> DispatchResult {1804 ensure!(1805 <Collection<T>>::contains_key(collection_id),1806 Error::<T>::CollectionNotFound1807 );1808 Ok(())1809 }18101811 fn check_owner_permissions(collection_id: CollectionId, subject: T::AccountId) -> DispatchResult {1812 Self::collection_exists(collection_id)?;18131814 let target_collection = <Collection<T>>::get(collection_id);1815 ensure!(1816 subject == target_collection.owner,1817 Error::<T>::NoPermission1818 );18191820 Ok(())1821 }18221823 fn is_owner_or_admin_permissions(collection_id: CollectionId, subject: T::AccountId) -> bool {1824 let target_collection = <Collection<T>>::get(collection_id);1825 let mut result: bool = subject == target_collection.owner;1826 let exists = <AdminList<T>>::contains_key(collection_id);18271828 if !result & exists {1829 if <AdminList<T>>::get(collection_id).contains(&subject) {1830 result = true1831 }1832 }18331834 result1835 }18361837 fn check_owner_or_admin_permissions(1838 collection_id: CollectionId,1839 subject: T::AccountId,1840 ) -> DispatchResult {1841 Self::collection_exists(collection_id)?;1842 let result = Self::is_owner_or_admin_permissions(collection_id, subject.clone());18431844 ensure!(1845 result,1846 Error::<T>::NoPermission1847 );1848 Ok(())1849 }18501851 fn is_item_owner(subject: T::AccountId, collection_id: CollectionId, item_id: TokenId) -> bool {1852 let target_collection = <Collection<T>>::get(collection_id);18531854 match target_collection.mode {1855 CollectionMode::NFT => {1856 <NftItemList<T>>::get(collection_id, item_id).owner == subject1857 }1858 CollectionMode::Fungible(_) => {1859 <FungibleItemList<T>>::contains_key(collection_id, &subject)1860 }1861 CollectionMode::ReFungible(_) => {1862 <ReFungibleItemList<T>>::get(collection_id, item_id)1863 .owner1864 .iter()1865 .any(|i| i.owner == subject)1866 }1867 CollectionMode::Invalid => false,1868 }1869 }18701871 fn check_white_list(collection_id: CollectionId, address: &T::AccountId) -> DispatchResult {1872 let mes = Error::<T>::AddresNotInWhiteList;1873 ensure!(<WhiteList<T>>::contains_key(collection_id, address), mes);18741875 Ok(())1876 }18771878 1879 1880 fn token_exists(1881 collection_id: CollectionId,1882 item_id: TokenId,1883 owner: &T::AccountId1884 ) -> DispatchResult {1885 let target_collection = <Collection<T>>::get(collection_id);1886 let exists = match target_collection.mode1887 {1888 CollectionMode::NFT => <NftItemList<T>>::contains_key(collection_id, item_id),1889 CollectionMode::Fungible(_) => <FungibleItemList<T>>::contains_key(collection_id, owner),1890 CollectionMode::ReFungible(_) => <ReFungibleItemList<T>>::contains_key(collection_id, item_id),1891 _ => false1892 };18931894 ensure!(exists == true, Error::<T>::TokenNotFound);1895 Ok(())1896 }18971898 fn transfer_fungible(1899 collection_id: CollectionId,1900 value: u128,1901 owner: &T::AccountId,1902 recipient: &T::AccountId,1903 ) -> DispatchResult {1904 Self::token_exists(collection_id, 0, owner)?;19051906 let mut balance = <FungibleItemList<T>>::get(collection_id, owner);1907 ensure!(balance.value >= value, Error::<T>::TokenValueTooLow);19081909 1910 Self::add_fungible_item(collection_id, recipient, value)?;19111912 1913 <Balance<T>>::insert(collection_id, (*owner).clone(), balance.value - value);19141915 1916 if balance.value == value {1917 <FungibleItemList<T>>::remove(collection_id, owner);1918 }1919 else {1920 balance.value -= value;1921 <FungibleItemList<T>>::insert(collection_id, (*owner).clone(), balance);1922 }19231924 Ok(())1925 }19261927 fn transfer_refungible(1928 collection_id: CollectionId,1929 item_id: TokenId,1930 value: u128,1931 owner: T::AccountId,1932 new_owner: T::AccountId,1933 ) -> DispatchResult {1934 Self::token_exists(collection_id, item_id, &owner)?;19351936 let full_item = <ReFungibleItemList<T>>::get(collection_id, item_id);1937 let item = full_item1938 .owner1939 .iter()1940 .filter(|i| i.owner == owner)1941 .next()1942 .ok_or(Error::<T>::NumOverflow)?;1943 let amount = item.fraction;19441945 ensure!(amount >= value, Error::<T>::TokenValueTooLow);19461947 1948 let balance_old_owner = <Balance<T>>::get(collection_id, item.owner.clone())1949 .checked_sub(value)1950 .ok_or(Error::<T>::NumOverflow)?;1951 <Balance<T>>::insert(collection_id, item.owner.clone(), balance_old_owner);19521953 let balancenew_owner = <Balance<T>>::get(collection_id, new_owner.clone())1954 .checked_add(value)1955 .ok_or(Error::<T>::NumOverflow)?;1956 <Balance<T>>::insert(collection_id, new_owner.clone(), balancenew_owner);19571958 let old_owner = item.owner.clone();1959 let new_owner_has_account = full_item.owner.iter().any(|i| i.owner == new_owner);19601961 1962 if amount == value && !new_owner_has_account {1963 1964 1965 let mut new_full_item = full_item.clone();1966 new_full_item1967 .owner1968 .iter_mut()1969 .find(|i| i.owner == owner)1970 .unwrap()1971 .owner = new_owner.clone();1972 <ReFungibleItemList<T>>::insert(collection_id, item_id, new_full_item);19731974 1975 Self::move_token_index(collection_id, item_id, &old_owner, &new_owner)?;1976 } else {1977 let mut new_full_item = full_item.clone();1978 new_full_item1979 .owner1980 .iter_mut()1981 .find(|i| i.owner == owner)1982 .unwrap()1983 .fraction -= value;19841985 1986 if new_owner_has_account {1987 1988 new_full_item1989 .owner1990 .iter_mut()1991 .find(|i| i.owner == new_owner)1992 .unwrap()1993 .fraction += value;1994 } else {1995 1996 new_full_item.owner.push(Ownership {1997 owner: new_owner.clone(),1998 fraction: value,1999 });2000 Self::add_token_index(collection_id, item_id, &new_owner)?;2001 }20022003 <ReFungibleItemList<T>>::insert(collection_id, item_id, new_full_item);2004 }20052006 Ok(())2007 }20082009 fn transfer_nft(2010 collection_id: CollectionId,2011 item_id: TokenId,2012 sender: T::AccountId,2013 new_owner: T::AccountId,2014 ) -> DispatchResult {2015 Self::token_exists(collection_id, item_id, &sender)?;20162017 let mut item = <NftItemList<T>>::get(collection_id, item_id);20182019 ensure!(2020 sender == item.owner,2021 Error::<T>::MustBeTokenOwner2022 );20232024 2025 let balance_old_owner = <Balance<T>>::get(collection_id, item.owner.clone())2026 .checked_sub(1)2027 .ok_or(Error::<T>::NumOverflow)?;2028 <Balance<T>>::insert(collection_id, item.owner.clone(), balance_old_owner);20292030 let balancenew_owner = <Balance<T>>::get(collection_id, new_owner.clone())2031 .checked_add(1)2032 .ok_or(Error::<T>::NumOverflow)?;2033 <Balance<T>>::insert(collection_id, new_owner.clone(), balancenew_owner);20342035 2036 let old_owner = item.owner.clone();2037 item.owner = new_owner.clone();2038 <NftItemList<T>>::insert(collection_id, item_id, item);20392040 2041 Self::move_token_index(collection_id, item_id, &old_owner, &new_owner)?;20422043 Ok(())2044 }2045 2046 fn set_re_fungible_variable_data(2047 collection_id: CollectionId,2048 item_id: TokenId,2049 data: Vec<u8>2050 ) -> DispatchResult {2051 let mut item = <ReFungibleItemList<T>>::get(collection_id, item_id);20522053 item.variable_data = data;20542055 <ReFungibleItemList<T>>::insert(collection_id, item_id, item);20562057 Ok(())2058 }20592060 fn set_nft_variable_data(2061 collection_id: CollectionId,2062 item_id: TokenId,2063 data: Vec<u8>2064 ) -> DispatchResult {2065 let mut item = <NftItemList<T>>::get(collection_id, item_id);2066 2067 item.variable_data = data;20682069 <NftItemList<T>>::insert(collection_id, item_id, item);2070 2071 Ok(())2072 }20732074 fn init_collection(item: &CollectionType<T::AccountId>) {2075 2076 assert!(2077 item.decimal_points <= MAX_DECIMAL_POINTS,2078 "decimal_points parameter must be lower than MAX_DECIMAL_POINTS"2079 );2080 assert!(2081 item.name.len() <= 64,2082 "Collection name can not be longer than 63 char"2083 );2084 assert!(2085 item.name.len() <= 256,2086 "Collection description can not be longer than 255 char"2087 );2088 assert!(2089 item.token_prefix.len() <= 16,2090 "Token prefix can not be longer than 15 char"2091 );20922093 2094 let next_id = CreatedCollectionCount::get()2095 .checked_add(1)2096 .unwrap();20972098 CreatedCollectionCount::put(next_id);2099 }21002101 fn init_nft_token(collection_id: CollectionId, item: &NftItemType<T::AccountId>) {2102 let current_index = <ItemListIndex>::get(collection_id)2103 .checked_add(1)2104 .unwrap();21052106 let item_owner = item.owner.clone();2107 Self::add_token_index(collection_id, current_index, &item.owner).unwrap();21082109 <ItemListIndex>::insert(collection_id, current_index);21102111 2112 let new_balance = <Balance<T>>::get(collection_id, &item_owner)2113 .checked_add(1)2114 .unwrap();2115 <Balance<T>>::insert(collection_id, item_owner.clone(), new_balance);2116 }21172118 fn init_fungible_token(collection_id: CollectionId, owner: &T::AccountId, item: &FungibleItemType) {2119 let current_index = <ItemListIndex>::get(collection_id)2120 .checked_add(1)2121 .unwrap();21222123 Self::add_token_index(collection_id, current_index, owner).unwrap();21242125 <ItemListIndex>::insert(collection_id, current_index);21262127 2128 let new_balance = <Balance<T>>::get(collection_id, owner)2129 .checked_add(item.value)2130 .unwrap();2131 <Balance<T>>::insert(collection_id, (*owner).clone(), new_balance);2132 }21332134 fn init_refungible_token(collection_id: CollectionId, item: &ReFungibleItemType<T::AccountId>) {2135 let current_index = <ItemListIndex>::get(collection_id)2136 .checked_add(1)2137 .unwrap();21382139 let value = item.owner.first().unwrap().fraction;2140 let owner = item.owner.first().unwrap().owner.clone();21412142 Self::add_token_index(collection_id, current_index, &owner).unwrap();21432144 <ItemListIndex>::insert(collection_id, current_index);21452146 2147 let new_balance = <Balance<T>>::get(collection_id, &owner)2148 .checked_add(value)2149 .unwrap();2150 <Balance<T>>::insert(collection_id, owner.clone(), new_balance);2151 }21522153 fn add_token_index(collection_id: CollectionId, item_index: TokenId, owner: &T::AccountId) -> DispatchResult {21542155 2156 if <AccountItemCount<T>>::contains_key(owner) {21572158 2159 let count = <AccountItemCount<T>>::get(owner);2160 ensure!(count < ChainLimit::get().account_token_ownership_limit, Error::<T>::AddressOwnershipLimitExceeded);21612162 <AccountItemCount<T>>::insert(owner.clone(), count2163 .checked_add(1)2164 .ok_or(Error::<T>::NumOverflow)?);2165 }2166 else {2167 <AccountItemCount<T>>::insert(owner.clone(), 1);2168 }21692170 let list_exists = <AddressTokens<T>>::contains_key(collection_id, owner);2171 if list_exists {2172 let mut list = <AddressTokens<T>>::get(collection_id, owner);2173 let item_contains = list.contains(&item_index.clone());21742175 if !item_contains {2176 list.push(item_index.clone());2177 }21782179 <AddressTokens<T>>::insert(collection_id, owner.clone(), list);2180 } else {2181 let mut itm = Vec::new();2182 itm.push(item_index.clone());2183 <AddressTokens<T>>::insert(collection_id, owner.clone(), itm);2184 }21852186 Ok(())2187 }21882189 fn remove_token_index(2190 collection_id: CollectionId,2191 item_index: TokenId,2192 owner: &T::AccountId,2193 ) -> DispatchResult {21942195 2196 <AccountItemCount<T>>::insert(owner.clone(), 2197 <AccountItemCount<T>>::get(owner)2198 .checked_sub(1)2199 .ok_or(Error::<T>::NumOverflow)?);220022012202 let list_exists = <AddressTokens<T>>::contains_key(collection_id, owner);2203 if list_exists {2204 let mut list = <AddressTokens<T>>::get(collection_id, owner);2205 let item_contains = list.contains(&item_index.clone());22062207 if item_contains {2208 list.retain(|&item| item != item_index);2209 <AddressTokens<T>>::insert(collection_id, owner.clone(), list);2210 }2211 }22122213 Ok(())2214 }22152216 fn move_token_index(2217 collection_id: CollectionId,2218 item_index: TokenId,2219 old_owner: &T::AccountId,2220 new_owner: &T::AccountId,2221 ) -> DispatchResult {2222 Self::remove_token_index(collection_id, item_index, old_owner)?;2223 Self::add_token_index(collection_id, item_index, new_owner)?;22242225 Ok(())2226 }2227 2228 fn ensure_contract_owned(account: T::AccountId, contract: &T::AccountId) -> DispatchResult {2229 if <ContractOwner<T>>::contains_key(contract.clone()) {2230 let owner = <ContractOwner<T>>::get(contract);2231 ensure!(account == owner, Error::<T>::NoPermission);2232 } else {2233 fail!(Error::<T>::NoPermission);2234 }22352236 Ok(())2237 }2238}2239224022412242224322442245pub type Multiplier = FixedU128;22462247type BalanceOf<T> = <<T as transaction_payment::Trait>::Currency as Currency<2248 <T as system::Trait>::AccountId,2249>>::Balance;2250type NegativeImbalanceOf<T> = <<T as transaction_payment::Trait>::Currency as Currency<2251 <T as system::Trait>::AccountId,2252>>::NegativeImbalance;2253225422552256#[derive(Encode, Decode, Clone, Eq, PartialEq)]2257pub struct ChargeTransactionPayment<T: Trait + Send + Sync>(2258 #[codec(compact)] BalanceOf<T>2259);22602261impl<T: Trait + Send + Sync> sp_std::fmt::Debug2262 for ChargeTransactionPayment<T>2263{2264 #[cfg(feature = "std")]2265 fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {2266 write!(f, "ChargeTransactionPayment<{:?}>", self.0)2267 }2268 #[cfg(not(feature = "std"))]2269 fn fmt(&self, _: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {2270 Ok(())2271 }2272}22732274impl<T: Trait + Send + Sync> ChargeTransactionPayment<T>2275where2276 T::Call: Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo> + IsSubType<Call<T>> + IsSubType<pallet_contracts::Call<T>>,2277 BalanceOf<T>: Send + Sync + FixedPointOperand,2278{2279 2280 pub fn from(fee: BalanceOf<T>) -> Self {2281 Self(fee)2282 }22832284 pub fn traditional_fee(2285 len: usize,2286 info: &DispatchInfoOf<T::Call>,2287 tip: BalanceOf<T>,2288 ) -> BalanceOf<T>2289 where2290 T::Call: Dispatchable<Info = DispatchInfo>,2291 {2292 <transaction_payment::Module<T>>::compute_fee(len as u32, info, tip)2293 }22942295 fn get_priority(len: usize, info: &DispatchInfoOf<T::Call>, final_fee: BalanceOf<T>) -> TransactionPriority {2296 let weight_saturation = T::MaximumBlockWeight::get() / info.weight.max(1);2297 let len_saturation = T::MaximumBlockLength::get() as u64 / (len as u64).max(1);2298 let coefficient: BalanceOf<T> = weight_saturation.min(len_saturation).saturated_into::<BalanceOf<T>>();2299 final_fee.saturating_mul(coefficient).saturated_into::<TransactionPriority>()2300 }23012302 fn withdraw_fee(2303 &self,2304 who: &T::AccountId,2305 call: &T::Call,2306 info: &DispatchInfoOf<T::Call>,2307 len: usize,2308 ) -> Result<(BalanceOf<T>, Option<NegativeImbalanceOf<T>>), TransactionValidityError> {2309 let tip = self.0;23102311 2312 2313 2314 2315 2316 2317 2318 let fee = Self::traditional_fee(len, info, tip);23192320 2321 if fee.is_zero() {2322 return Ok((fee, None));2323 }23242325 2326 2327 let mut sponsor: T::AccountId = match IsSubType::<Call<T>>::is_sub_type(call) {2328 Some(Call::create_item(collection_id, _owner, _properties)) => {23292330 2331 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;23322333 let limit = <Collection<T>>::get(collection_id).limits.sponsor_transfer_timeout;2334 let mut sponsored = true;2335 if <CreateItemBasket<T>>::contains_key((collection_id, &who)) {2336 let last_tx_block = <CreateItemBasket<T>>::get((collection_id, &who));2337 let limit_time = last_tx_block + limit.into();2338 if block_number <= limit_time {2339 sponsored = false;2340 }2341 }2342 if sponsored {2343 <CreateItemBasket<T>>::insert((collection_id, who.clone()), block_number);2344 }23452346 2347 if (<Collection<T>>::get(collection_id).limits.sponsored_data_size >= (_properties.len() as u32)) &&2348 (<Collection<T>>::get(collection_id).sponsor_confirmed) &&2349 (sponsored)2350 {2351 <Collection<T>>::get(collection_id).sponsor2352 } else {2353 T::AccountId::default()2354 }2355 }2356 Some(Call::transfer(_new_owner, collection_id, item_id, _value)) => {2357 2358 let mut sponsor_transfer = false;2359 if <Collection<T>>::get(collection_id).sponsor_confirmed {23602361 let collection_limits = <Collection<T>>::get(collection_id).limits;2362 let collection_mode = <Collection<T>>::get(collection_id).mode;2363 2364 2365 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;2366 sponsor_transfer = match collection_mode {2367 CollectionMode::NFT => {2368 2369 2370 let limit: u32 = if collection_limits.sponsor_transfer_timeout > 0 {2371 collection_limits.sponsor_transfer_timeout2372 } else {2373 ChainLimit::get().nft_sponsor_transfer_timeout2374 };2375 2376 let mut sponsored = true;2377 if <NftTransferBasket<T>>::contains_key(collection_id, item_id) {2378 let last_tx_block = <NftTransferBasket<T>>::get(collection_id, item_id);2379 let limit_time = last_tx_block + limit.into();2380 if block_number <= limit_time {2381 sponsored = false;2382 }2383 }2384 if sponsored {2385 <NftTransferBasket<T>>::insert(collection_id, item_id, block_number);2386 }23872388 sponsored2389 }2390 CollectionMode::Fungible(_) => {2391 2392 2393 let limit: u32 = if collection_limits.sponsor_transfer_timeout > 0 {2394 collection_limits.sponsor_transfer_timeout2395 } else {2396 ChainLimit::get().fungible_sponsor_transfer_timeout2397 };2398 2399 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;2400 let mut sponsored = true;2401 if <FungibleTransferBasket<T>>::contains_key(collection_id, who) {2402 let last_tx_block = <FungibleTransferBasket<T>>::get(collection_id, who);2403 let limit_time = last_tx_block + limit.into();2404 if block_number <= limit_time {2405 sponsored = false;2406 }2407 }2408 if sponsored {2409 <FungibleTransferBasket<T>>::insert(collection_id, who, block_number);2410 }24112412 sponsored2413 }2414 CollectionMode::ReFungible(_) => {2415 2416 2417 let limit: u32 = if collection_limits.sponsor_transfer_timeout > 0 {2418 collection_limits.sponsor_transfer_timeout2419 } else {2420 ChainLimit::get().refungible_sponsor_transfer_timeout2421 };2422 2423 let mut sponsored = true;2424 if <ReFungibleTransferBasket<T>>::contains_key(collection_id, item_id) {2425 let last_tx_block = <ReFungibleTransferBasket<T>>::get(collection_id, item_id);2426 let limit_time = last_tx_block + limit.into();2427 if block_number <= limit_time {2428 sponsored = false;2429 }2430 }2431 if sponsored {2432 <ReFungibleTransferBasket<T>>::insert(collection_id, item_id, block_number);2433 }24342435 sponsored2436 }2437 _ => {2438 false2439 },2440 };2441 }24422443 if !sponsor_transfer {2444 T::AccountId::default()2445 } else {2446 <Collection<T>>::get(collection_id).sponsor2447 }2448 }24492450 _ => T::AccountId::default(),2451 };24522453 2454 sponsor = match IsSubType::<pallet_contracts::Call<T>>::is_sub_type(call) {24552456 2457 Some(pallet_contracts::Call::instantiate(_endowment, _gas_limit, code_hash, data)) => {24582459 let new_contract_address = <T as pallet_contracts::Trait>::DetermineContractAddress::contract_address_for(2460 code_hash,2461 &data,2462 &who,2463 );2464 <ContractOwner<T>>::insert(new_contract_address.clone(), who.clone());24652466 T::AccountId::default()2467 },24682469 2470 Some(pallet_contracts::Call::call(dest, _value, _gas_limit, _data)) => {24712472 let called_contract: T::AccountId = T::Lookup::lookup((*dest).clone()).unwrap_or(T::AccountId::default());24732474 let owned_contract = <ContractOwner<T>>::contains_key(called_contract.clone())2475 && <ContractOwner<T>>::get(called_contract.clone()) == *who;2476 let white_list_enabled = <ContractWhiteListEnabled<T>>::contains_key(called_contract.clone()) && <ContractWhiteListEnabled<T>>::get(called_contract.clone());2477 2478 if !owned_contract && white_list_enabled {2479 if !<ContractWhiteList<T>>::contains_key(called_contract.clone(), who) {2480 return Err(InvalidTransaction::Call.into());2481 }2482 }24832484 let mut sponsor_transfer = false;2485 if <ContractSponsoringRateLimit<T>>::contains_key(called_contract.clone()) {2486 let last_tx_block = <ContractSponsorBasket<T>>::get((&called_contract, &who));2487 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;2488 let rate_limit = <ContractSponsoringRateLimit<T>>::get(&called_contract);2489 let limit_time = last_tx_block + rate_limit;24902491 if block_number >= limit_time {2492 <ContractSponsorBasket<T>>::insert((called_contract.clone(), who.clone()), block_number);2493 sponsor_transfer = true;2494 }2495 } else {2496 sponsor_transfer = false;2497 }2498 2499 2500 let mut sp = T::AccountId::default();2501 if sponsor_transfer {2502 if <ContractSelfSponsoring<T>>::contains_key(called_contract.clone()) {2503 if <ContractSelfSponsoring<T>>::get(called_contract.clone()) {2504 sp = called_contract;2505 }2506 }2507 }25082509 sp2510 },25112512 _ => sponsor,2513 };25142515 let mut who_pays_fee: T::AccountId = sponsor.clone();2516 if sponsor == T::AccountId::default() {2517 who_pays_fee = who.clone();2518 }25192520 match <T as transaction_payment::Trait>::Currency::withdraw(2521 &who_pays_fee,2522 fee,2523 if tip.is_zero() {2524 WithdrawReason::TransactionPayment.into()2525 } else {2526 WithdrawReason::TransactionPayment | WithdrawReason::Tip2527 },2528 ExistenceRequirement::KeepAlive,2529 ) {2530 Ok(imbalance) => Ok((fee, Some(imbalance))),2531 Err(_) => Err(InvalidTransaction::Payment.into()),2532 }2533 }2534}253525362537impl<T: Trait + Send + Sync> SignedExtension2538 for ChargeTransactionPayment<T>2539where2540 BalanceOf<T>: Send + Sync + From<u64> + FixedPointOperand,2541 T::Call: Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo> + IsSubType<Call<T>> + IsSubType<pallet_contracts::Call<T>>,2542{2543 const IDENTIFIER: &'static str = "ChargeTransactionPayment";2544 type AccountId = T::AccountId;2545 type Call = T::Call;2546 type AdditionalSigned = ();2547 type Pre = (2548 BalanceOf<T>,2549 Self::AccountId,2550 Option<NegativeImbalanceOf<T>>,2551 BalanceOf<T>,2552 );2553 fn additional_signed(&self) -> sp_std::result::Result<(), TransactionValidityError> {2554 Ok(())2555 }25562557 fn validate(2558 &self,2559 who: &Self::AccountId,2560 call: &Self::Call,2561 info: &DispatchInfoOf<Self::Call>,2562 len: usize,2563 ) -> TransactionValidity {2564 let (fee, _) = self.withdraw_fee(who, call, info, len)?;2565 Ok(ValidTransaction {2566 priority: Self::get_priority(len, info, fee),2567 ..Default::default()2568 })2569 }25702571 fn pre_dispatch(2572 self,2573 who: &Self::AccountId,2574 call: &Self::Call,2575 info: &DispatchInfoOf<Self::Call>,2576 len: usize,2577 ) -> Result<Self::Pre, TransactionValidityError> {2578 let (fee, imbalance) = self.withdraw_fee(who, call, info, len)?;2579 Ok((self.0, who.clone(), imbalance, fee))2580 }25812582 fn post_dispatch(2583 pre: Self::Pre,2584 info: &DispatchInfoOf<Self::Call>,2585 post_info: &PostDispatchInfoOf<Self::Call>,2586 len: usize,2587 _result: &DispatchResult,2588 ) -> Result<(), TransactionValidityError> {2589 let (tip, who, imbalance, fee) = pre;2590 if let Some(payed) = imbalance {2591 let actual_fee = <transaction_payment::Module<T>>::compute_actual_fee(2592 len as u32, info, post_info, tip,2593 );2594 let refund = fee.saturating_sub(actual_fee);2595 let actual_payment =2596 match <T as transaction_payment::Trait>::Currency::deposit_into_existing(2597 &who, refund,2598 ) {2599 Ok(refund_imbalance) => {2600 2601 2602 match payed.offset(refund_imbalance) {2603 Ok(actual_payment) => actual_payment,2604 Err(_) => return Err(InvalidTransaction::Payment.into()),2605 }2606 }2607 2608 2609 Err(_) => payed,2610 };2611 let imbalances = actual_payment.split(tip);2612 <T as transaction_payment::Trait>::OnTransactionPayment::on_unbalanceds(2613 Some(imbalances.0).into_iter().chain(Some(imbalances.1)),2614 );2615 }2616 Ok(())2617 }2618}26192620