difftreelog
cargo fmt
in: master
10 files changed
pallets/common/src/lib.rsdiffbeforeafterboth1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// This file is part of Unique Network.34// Unique Network is free software: you can redistribute it and/or modify5// it under the terms of the GNU General Public License as published by6// the Free Software Foundation, either version 3 of the License, or7// (at your option) any later version.89// Unique Network is distributed in the hope that it will be useful,10// but WITHOUT ANY WARRANTY; without even the implied warranty of11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the12// GNU General Public License for more details.1314// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.1617#![cfg_attr(not(feature = "std"), no_std)]1819use core::ops::{Deref, DerefMut};20use pallet_evm_coder_substrate::{SubstrateRecorder, WithRecorder};21use sp_std::vec::Vec;22use pallet_evm::account::CrossAccountId;23use frame_support::{24 dispatch::{DispatchErrorWithPostInfo, DispatchResultWithPostInfo},25 ensure, fail,26 traits::{Imbalance, Get, Currency},27 BoundedVec,28};29use pallet_evm::GasWeightMapping;30use up_data_structs::{31 COLLECTION_NUMBER_LIMIT, Collection, CollectionId, CreateItemData, ExistenceRequirement,32 MAX_TOKEN_PREFIX_LENGTH, COLLECTION_ADMINS_LIMIT, MetaUpdatePermission, Pays, PostDispatchInfo,33 TokenId, Weight, WithdrawReasons, CollectionStats, MAX_TOKEN_OWNERSHIP, CollectionMode,34 NFT_SPONSOR_TRANSFER_TIMEOUT, FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,35 REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT, MAX_SPONSOR_TIMEOUT, CUSTOM_DATA_LIMIT, CollectionLimits,36 CustomDataLimit, CreateCollectionData, SponsorshipState, CreateItemExData,37};38pub use pallet::*;39use sp_core::H160;40use sp_runtime::{ArithmeticError, DispatchError, DispatchResult};41#[cfg(feature = "runtime-benchmarks")]42pub mod benchmarking;43pub mod erc;44pub mod eth;4546#[must_use = "Should call submit_logs or save, otherwise some data will be lost for evm side"]47pub struct CollectionHandle<T: Config> {48 pub id: CollectionId,49 collection: Collection<T::AccountId>,50 pub recorder: SubstrateRecorder<T>,51}52impl<T: Config> WithRecorder<T> for CollectionHandle<T> {53 fn recorder(&self) -> &SubstrateRecorder<T> {54 &self.recorder55 }56 fn into_recorder(self) -> SubstrateRecorder<T> {57 self.recorder58 }59}60impl<T: Config> CollectionHandle<T> {61 pub fn new_with_gas_limit(id: CollectionId, gas_limit: u64) -> Option<Self> {62 <CollectionById<T>>::get(id).map(|collection| Self {63 id,64 collection,65 recorder: SubstrateRecorder::new(eth::collection_id_to_address(id), gas_limit),66 })67 }68 pub fn new(id: CollectionId) -> Option<Self> {69 Self::new_with_gas_limit(id, u64::MAX)70 }71 pub fn try_get(id: CollectionId) -> Result<Self, DispatchError> {72 Ok(Self::new(id).ok_or(<Error<T>>::CollectionNotFound)?)73 }74 pub fn log_mirrored(&self, log: impl evm_coder::ToLog) {75 self.recorder.log_mirrored(log)76 }77 pub fn log_direct(&self, log: impl evm_coder::ToLog) {78 self.recorder.log_direct(log)79 }80 pub fn consume_store_reads(&self, reads: u64) -> evm_coder::execution::Result<()> {81 self.recorder82 .consume_gas(T::GasWeightMapping::weight_to_gas(83 <T as frame_system::Config>::DbWeight::get()84 .read85 .saturating_mul(reads),86 ))87 }88 pub fn consume_store_writes(&self, writes: u64) -> evm_coder::execution::Result<()> {89 self.recorder90 .consume_gas(T::GasWeightMapping::weight_to_gas(91 <T as frame_system::Config>::DbWeight::get()92 .write93 .saturating_mul(writes),94 ))95 }96 pub fn submit_logs(self) {97 self.recorder.submit_logs()98 }99 pub fn save(self) -> DispatchResult {100 self.recorder.submit_logs();101 <CollectionById<T>>::insert(self.id, self.collection);102 Ok(())103 }104}105impl<T: Config> Deref for CollectionHandle<T> {106 type Target = Collection<T::AccountId>;107108 fn deref(&self) -> &Self::Target {109 &self.collection110 }111}112113impl<T: Config> DerefMut for CollectionHandle<T> {114 fn deref_mut(&mut self) -> &mut Self::Target {115 &mut self.collection116 }117}118119impl<T: Config> CollectionHandle<T> {120 pub fn check_is_owner(&self, subject: &T::CrossAccountId) -> DispatchResult {121 ensure!(*subject.as_sub() == self.owner, <Error<T>>::NoPermission);122 Ok(())123 }124 pub fn is_owner_or_admin(&self, subject: &T::CrossAccountId) -> bool {125 *subject.as_sub() == self.owner || <IsAdmin<T>>::get((self.id, subject))126 }127 pub fn check_is_owner_or_admin(&self, subject: &T::CrossAccountId) -> DispatchResult {128 ensure!(self.is_owner_or_admin(subject), <Error<T>>::NoPermission);129 Ok(())130 }131 pub fn ignores_allowance(&self, user: &T::CrossAccountId) -> bool {132 self.limits.owner_can_transfer() && self.is_owner_or_admin(user)133 }134 pub fn ignores_owned_amount(&self, user: &T::CrossAccountId) -> bool {135 self.limits.owner_can_transfer() && self.is_owner_or_admin(user)136 }137 pub fn check_allowlist(&self, user: &T::CrossAccountId) -> DispatchResult {138 ensure!(139 <Allowlist<T>>::get((self.id, user)),140 <Error<T>>::AddressNotInAllowlist141 );142 Ok(())143 }144145 pub fn check_can_update_meta(146 &self,147 subject: &T::CrossAccountId,148 item_owner: &T::CrossAccountId,149 ) -> DispatchResult {150 match self.meta_update_permission {151 MetaUpdatePermission::ItemOwner => {152 ensure!(subject == item_owner, <Error<T>>::NoPermission);153 Ok(())154 }155 MetaUpdatePermission::Admin => self.check_is_owner_or_admin(subject),156 MetaUpdatePermission::None => fail!(<Error<T>>::NoPermission),157 }158 }159}160161#[frame_support::pallet]162pub mod pallet {163 use super::*;164 use frame_support::{Blake2_128Concat, pallet_prelude::*, storage::Key};165 use pallet_evm::account;166 use frame_support::traits::Currency;167 use up_data_structs::TokenId;168 use scale_info::TypeInfo;169170 #[pallet::config]171 pub trait Config: frame_system::Config + pallet_evm_coder_substrate::Config + TypeInfo + account::Config {172 type Event: IsType<<Self as frame_system::Config>::Event> + From<Event<Self>>;173174 type Currency: Currency<Self::AccountId>;175176 #[pallet::constant]177 type CollectionCreationPrice: Get<178 <<Self as Config>::Currency as Currency<Self::AccountId>>::Balance,179 >;180181 type TreasuryAccountId: Get<Self::AccountId>;182 }183184 #[pallet::pallet]185 #[pallet::generate_store(pub(super) trait Store)]186 pub struct Pallet<T>(_);187188 #[pallet::extra_constants]189 impl<T: Config> Pallet<T> {190 pub fn collection_admins_limit() -> u32 {191 COLLECTION_ADMINS_LIMIT192 }193 }194195 #[pallet::event]196 #[pallet::generate_deposit(pub fn deposit_event)]197 pub enum Event<T: Config> {198 /// New collection was created199 ///200 /// # Arguments201 ///202 /// * collection_id: Globally unique identifier of newly created collection.203 ///204 /// * mode: [CollectionMode] converted into u8.205 ///206 /// * account_id: Collection owner.207 CollectionCreated(CollectionId, u8, T::AccountId),208209 /// New collection was destroyed210 ///211 /// # Arguments212 ///213 /// * collection_id: Globally unique identifier of collection.214 CollectionDestroyed(CollectionId),215216 /// New item was created.217 ///218 /// # Arguments219 ///220 /// * collection_id: Id of the collection where item was created.221 ///222 /// * item_id: Id of an item. Unique within the collection.223 ///224 /// * recipient: Owner of newly created item225 ///226 /// * amount: Always 1 for NFT227 ItemCreated(CollectionId, TokenId, T::CrossAccountId, u128),228229 /// Collection item was burned.230 ///231 /// # Arguments232 ///233 /// * collection_id.234 ///235 /// * item_id: Identifier of burned NFT.236 ///237 /// * owner: which user has destroyed its tokens238 ///239 /// * amount: Always 1 for NFT240 ItemDestroyed(CollectionId, TokenId, T::CrossAccountId, u128),241242 /// Item was transferred243 ///244 /// * collection_id: Id of collection to which item is belong245 ///246 /// * item_id: Id of an item247 ///248 /// * sender: Original owner of item249 ///250 /// * recipient: New owner of item251 ///252 /// * amount: Always 1 for NFT253 Transfer(254 CollectionId,255 TokenId,256 T::CrossAccountId,257 T::CrossAccountId,258 u128,259 ),260261 /// * collection_id262 ///263 /// * item_id264 ///265 /// * sender266 ///267 /// * spender268 ///269 /// * amount270 Approved(271 CollectionId,272 TokenId,273 T::CrossAccountId,274 T::CrossAccountId,275 u128,276 ),277 }278279 #[pallet::error]280 pub enum Error<T> {281 /// This collection does not exist.282 CollectionNotFound,283 /// Sender parameter and item owner must be equal.284 MustBeTokenOwner,285 /// No permission to perform action286 NoPermission,287 /// Collection is not in mint mode.288 PublicMintingNotAllowed,289 /// Address is not in allow list.290 AddressNotInAllowlist,291292 /// Collection name can not be longer than 63 char.293 CollectionNameLimitExceeded,294 /// Collection description can not be longer than 255 char.295 CollectionDescriptionLimitExceeded,296 /// Token prefix can not be longer than 15 char.297 CollectionTokenPrefixLimitExceeded,298 /// Total collections bound exceeded.299 TotalCollectionsLimitExceeded,300 /// variable_data exceeded data limit.301 TokenVariableDataLimitExceeded,302 /// Exceeded max admin count303 CollectionAdminCountExceeded,304 /// Collection limit bounds per collection exceeded305 CollectionLimitBoundsExceeded,306 /// Tried to enable permissions which are only permitted to be disabled307 OwnerPermissionsCantBeReverted,308309 /// Collection settings not allowing items transferring310 TransferNotAllowed,311 /// Account token limit exceeded per collection312 AccountTokenLimitExceeded,313 /// Collection token limit exceeded314 CollectionTokenLimitExceeded,315 /// Metadata flag frozen316 MetadataFlagFrozen,317318 /// Item not exists.319 TokenNotFound,320 /// Item balance not enough.321 TokenValueTooLow,322 /// Requested value more than approved.323 ApprovedValueTooLow,324 /// Tried to approve more than owned325 CantApproveMoreThanOwned,326327 /// Can't transfer tokens to ethereum zero address328 AddressIsZero,329 /// Target collection doesn't supports this operation330 UnsupportedOperation,331332 /// Not sufficient founds to perform action333 NotSufficientFounds,334 }335336 #[pallet::storage]337 pub type CreatedCollectionCount<T> = StorageValue<Value = CollectionId, QueryKind = ValueQuery>;338 #[pallet::storage]339 pub type DestroyedCollectionCount<T> =340 StorageValue<Value = CollectionId, QueryKind = ValueQuery>;341342 /// Collection info343 #[pallet::storage]344 pub type CollectionById<T> = StorageMap<345 Hasher = Blake2_128Concat,346 Key = CollectionId,347 Value = Collection<<T as frame_system::Config>::AccountId>,348 QueryKind = OptionQuery,349 >;350351 #[pallet::storage]352 pub type AdminAmount<T> = StorageMap<353 Hasher = Blake2_128Concat,354 Key = CollectionId,355 Value = u32,356 QueryKind = ValueQuery,357 >;358359 /// List of collection admins360 #[pallet::storage]361 pub type IsAdmin<T: Config> = StorageNMap<362 Key = (363 Key<Blake2_128Concat, CollectionId>,364 Key<Blake2_128Concat, T::CrossAccountId>,365 ),366 Value = bool,367 QueryKind = ValueQuery,368 >;369370 /// Allowlisted collection users371 #[pallet::storage]372 pub type Allowlist<T: Config> = StorageNMap<373 Key = (374 Key<Blake2_128Concat, CollectionId>,375 Key<Blake2_128Concat, T::CrossAccountId>,376 ),377 Value = bool,378 QueryKind = ValueQuery,379 >;380381 /// Not used by code, exists only to provide some types to metadata382 #[pallet::storage]383 pub type DummyStorageValue<T> =384 StorageValue<Value = (CollectionStats, CollectionId, TokenId), QueryKind = OptionQuery>;385}386387impl<T: Config> Pallet<T> {388 /// Ethereum receiver 0x0000000000000000000000000000000000000000 is reserved, and shouldn't own tokens389 pub fn ensure_correct_receiver(receiver: &T::CrossAccountId) -> DispatchResult {390 ensure!(391 &T::CrossAccountId::from_eth(H160([0; 20])) != receiver,392 <Error<T>>::AddressIsZero393 );394 Ok(())395 }396 pub fn adminlist(collection: CollectionId) -> Vec<T::CrossAccountId> {397 <IsAdmin<T>>::iter_prefix((collection,))398 .map(|(a, _)| a)399 .collect()400 }401 pub fn allowlist(collection: CollectionId) -> Vec<T::CrossAccountId> {402 <Allowlist<T>>::iter_prefix((collection,))403 .map(|(a, _)| a)404 .collect()405 }406 pub fn allowed(collection: CollectionId, user: T::CrossAccountId) -> bool {407 <Allowlist<T>>::get((collection, user))408 }409 pub fn collection_stats() -> CollectionStats {410 let created = <CreatedCollectionCount<T>>::get();411 let destroyed = <DestroyedCollectionCount<T>>::get();412 CollectionStats {413 created: created.0,414 destroyed: destroyed.0,415 alive: created.0 - destroyed.0,416 }417 }418}419420impl<T: Config> Pallet<T> {421 pub fn init_collection(422 owner: T::AccountId,423 data: CreateCollectionData<T::AccountId>,424 ) -> Result<CollectionId, DispatchError> {425 {426 ensure!(427 data.token_prefix.len() <= MAX_TOKEN_PREFIX_LENGTH as usize,428 Error::<T>::CollectionTokenPrefixLimitExceeded429 );430 }431432 let created_count = <CreatedCollectionCount<T>>::get()433 .0434 .checked_add(1)435 .ok_or(ArithmeticError::Overflow)?;436 let destroyed_count = <DestroyedCollectionCount<T>>::get().0;437 let id = CollectionId(created_count);438439 // bound Total number of collections440 ensure!(441 created_count - destroyed_count <= COLLECTION_NUMBER_LIMIT,442 <Error<T>>::TotalCollectionsLimitExceeded443 );444445 // =========446447 let collection = Collection {448 owner: owner.clone(),449 name: data.name,450 mode: data.mode.clone(),451 mint_mode: false,452 access: data.access.unwrap_or_default(),453 description: data.description,454 token_prefix: data.token_prefix,455 offchain_schema: data.offchain_schema,456 schema_version: data.schema_version.unwrap_or_default(),457 sponsorship: data458 .pending_sponsor459 .map(SponsorshipState::Unconfirmed)460 .unwrap_or_default(),461 variable_on_chain_schema: data.variable_on_chain_schema,462 const_on_chain_schema: data.const_on_chain_schema,463 limits: data464 .limits465 .map(|limits| Self::clamp_limits(data.mode.clone(), &Default::default(), limits))466 .unwrap_or_else(|| Ok(CollectionLimits::default()))?,467 meta_update_permission: data.meta_update_permission.unwrap_or_default(),468 };469470 // Take a (non-refundable) deposit of collection creation471 {472 let mut imbalance =473 <<<T as Config>::Currency as Currency<T::AccountId>>::PositiveImbalance>::zero();474 imbalance.subsume(475 <<T as Config>::Currency as Currency<T::AccountId>>::deposit_creating(476 &T::TreasuryAccountId::get(),477 T::CollectionCreationPrice::get(),478 ),479 );480 <T as Config>::Currency::settle(481 &owner,482 imbalance,483 WithdrawReasons::TRANSFER,484 ExistenceRequirement::KeepAlive,485 )486 .map_err(|_| Error::<T>::NotSufficientFounds)?;487 }488489 <CreatedCollectionCount<T>>::put(created_count);490 <Pallet<T>>::deposit_event(Event::CollectionCreated(id, data.mode.id(), owner.clone()));491 <CollectionById<T>>::insert(id, collection);492 Ok(id)493 }494495 pub fn destroy_collection(496 collection: CollectionHandle<T>,497 sender: &T::CrossAccountId,498 ) -> DispatchResult {499 ensure!(500 collection.limits.owner_can_destroy(),501 <Error<T>>::NoPermission,502 );503 collection.check_is_owner(sender)?;504505 let destroyed_collections = <DestroyedCollectionCount<T>>::get()506 .0507 .checked_add(1)508 .ok_or(ArithmeticError::Overflow)?;509510 // =========511512 <DestroyedCollectionCount<T>>::put(destroyed_collections);513 <CollectionById<T>>::remove(collection.id);514 <AdminAmount<T>>::remove(collection.id);515 <IsAdmin<T>>::remove_prefix((collection.id,), None);516 <Allowlist<T>>::remove_prefix((collection.id,), None);517518 <Pallet<T>>::deposit_event(Event::CollectionDestroyed(collection.id));519 Ok(())520 }521522 pub fn toggle_allowlist(523 collection: &CollectionHandle<T>,524 sender: &T::CrossAccountId,525 user: &T::CrossAccountId,526 allowed: bool,527 ) -> DispatchResult {528 collection.check_is_owner_or_admin(sender)?;529530 // =========531532 if allowed {533 <Allowlist<T>>::insert((collection.id, user), true);534 } else {535 <Allowlist<T>>::remove((collection.id, user));536 }537538 Ok(())539 }540541 pub fn toggle_admin(542 collection: &CollectionHandle<T>,543 sender: &T::CrossAccountId,544 user: &T::CrossAccountId,545 admin: bool,546 ) -> DispatchResult {547 collection.check_is_owner_or_admin(sender)?;548549 let was_admin = <IsAdmin<T>>::get((collection.id, user));550 if was_admin == admin {551 return Ok(());552 }553 let amount = <AdminAmount<T>>::get(collection.id);554555 if admin {556 let amount = amount557 .checked_add(1)558 .ok_or(<Error<T>>::CollectionAdminCountExceeded)?;559 ensure!(560 amount <= Self::collection_admins_limit(),561 <Error<T>>::CollectionAdminCountExceeded,562 );563564 // =========565566 <AdminAmount<T>>::insert(collection.id, amount);567 <IsAdmin<T>>::insert((collection.id, user), true);568 } else {569 <AdminAmount<T>>::insert(collection.id, amount.saturating_sub(1));570 <IsAdmin<T>>::remove((collection.id, user));571 }572573 Ok(())574 }575576 pub fn clamp_limits(577 mode: CollectionMode,578 old_limit: &CollectionLimits,579 mut new_limit: CollectionLimits,580 ) -> Result<CollectionLimits, DispatchError> {581 macro_rules! limit_default {582 ($old:ident, $new:ident, $($field:ident $(($arg:expr))? => $check:expr),* $(,)?) => {{583 $(584 if let Some($new) = $new.$field {585 let $old = $old.$field($($arg)?);586 let _ = $new;587 let _ = $old;588 $check589 } else {590 $new.$field = $old.$field591 }592 )*593 }};594 }595596 limit_default!(old_limit, new_limit,597 account_token_ownership_limit => ensure!(598 new_limit <= MAX_TOKEN_OWNERSHIP,599 <Error<T>>::CollectionLimitBoundsExceeded,600 ),601 sponsor_transfer_timeout(match mode {602 CollectionMode::NFT => NFT_SPONSOR_TRANSFER_TIMEOUT,603 CollectionMode::Fungible(_) => FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,604 CollectionMode::ReFungible => REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,605 }) => ensure!(606 new_limit <= MAX_SPONSOR_TIMEOUT,607 <Error<T>>::CollectionLimitBoundsExceeded,608 ),609 sponsored_data_size => ensure!(610 new_limit <= CUSTOM_DATA_LIMIT,611 <Error<T>>::CollectionLimitBoundsExceeded,612 ),613 token_limit => ensure!(614 old_limit >= new_limit && new_limit > 0,615 <Error<T>>::CollectionTokenLimitExceeded616 ),617 owner_can_transfer => ensure!(618 old_limit || !new_limit,619 <Error<T>>::OwnerPermissionsCantBeReverted,620 ),621 owner_can_destroy => ensure!(622 old_limit || !new_limit,623 <Error<T>>::OwnerPermissionsCantBeReverted,624 ),625 sponsored_data_rate_limit => {},626 transfers_enabled => {},627 );628 Ok(new_limit)629 }630}631632#[macro_export]633macro_rules! unsupported {634 () => {635 Err(<Error<T>>::UnsupportedOperation.into())636 };637}638639/// Worst cases640pub trait CommonWeightInfo<CrossAccountId> {641 fn create_item() -> Weight;642 fn create_multiple_items(amount: u32) -> Weight;643 fn create_multiple_items_ex(cost: &CreateItemExData<CrossAccountId>) -> Weight;644 fn burn_item() -> Weight;645 fn transfer() -> Weight;646 fn approve() -> Weight;647 fn transfer_from() -> Weight;648 fn burn_from() -> Weight;649 fn set_variable_metadata(bytes: u32) -> Weight;650}651652pub trait CommonCollectionOperations<T: Config> {653 fn create_item(654 &self,655 sender: T::CrossAccountId,656 to: T::CrossAccountId,657 data: CreateItemData,658 ) -> DispatchResultWithPostInfo;659 fn create_multiple_items(660 &self,661 sender: T::CrossAccountId,662 to: T::CrossAccountId,663 data: Vec<CreateItemData>,664 ) -> DispatchResultWithPostInfo;665 fn create_multiple_items_ex(666 &self,667 sender: T::CrossAccountId,668 data: CreateItemExData<T::CrossAccountId>,669 ) -> DispatchResultWithPostInfo;670 fn burn_item(671 &self,672 sender: T::CrossAccountId,673 token: TokenId,674 amount: u128,675 ) -> DispatchResultWithPostInfo;676677 fn transfer(678 &self,679 sender: T::CrossAccountId,680 to: T::CrossAccountId,681 token: TokenId,682 amount: u128,683 ) -> DispatchResultWithPostInfo;684 fn approve(685 &self,686 sender: T::CrossAccountId,687 spender: T::CrossAccountId,688 token: TokenId,689 amount: u128,690 ) -> DispatchResultWithPostInfo;691 fn transfer_from(692 &self,693 sender: T::CrossAccountId,694 from: T::CrossAccountId,695 to: T::CrossAccountId,696 token: TokenId,697 amount: u128,698 ) -> DispatchResultWithPostInfo;699 fn burn_from(700 &self,701 sender: T::CrossAccountId,702 from: T::CrossAccountId,703 token: TokenId,704 amount: u128,705 ) -> DispatchResultWithPostInfo;706707 fn set_variable_metadata(708 &self,709 sender: T::CrossAccountId,710 token: TokenId,711 data: BoundedVec<u8, CustomDataLimit>,712 ) -> DispatchResultWithPostInfo;713714 fn account_tokens(&self, account: T::CrossAccountId) -> Vec<TokenId>;715 fn token_exists(&self, token: TokenId) -> bool;716 fn last_token_id(&self) -> TokenId;717718 fn token_owner(&self, token: TokenId) -> Option<T::CrossAccountId>;719 fn const_metadata(&self, token: TokenId) -> Vec<u8>;720 fn variable_metadata(&self, token: TokenId) -> Vec<u8>;721722 /// How many tokens collection contains (Applicable to nonfungible/refungible)723 fn collection_tokens(&self) -> u32;724 /// Amount of different tokens account has (Applicable to nonfungible/refungible)725 fn account_balance(&self, account: T::CrossAccountId) -> u32;726 /// Amount of specific token account have (Applicable to fungible/refungible)727 fn balance(&self, account: T::CrossAccountId, token: TokenId) -> u128;728 fn allowance(729 &self,730 sender: T::CrossAccountId,731 spender: T::CrossAccountId,732 token: TokenId,733 ) -> u128;734}735736// Flexible enough for implementing CommonCollectionOperations737pub fn with_weight(res: DispatchResult, weight: Weight) -> DispatchResultWithPostInfo {738 let post_info = PostDispatchInfo {739 actual_weight: Some(weight),740 pays_fee: Pays::Yes,741 };742 match res {743 Ok(()) => Ok(post_info),744 Err(error) => Err(DispatchErrorWithPostInfo { post_info, error }),745 }746}pallets/evm-contract-helpers/src/eth.rsdiffbeforeafterboth--- a/pallets/evm-contract-helpers/src/eth.rs
+++ b/pallets/evm-contract-helpers/src/eth.rs
@@ -18,7 +18,8 @@
use evm_coder::{abi::AbiWriter, execution::Result, generate_stubgen, solidity_interface, types::*};
use pallet_evm_coder_substrate::{SubstrateRecorder, WithRecorder};
use pallet_evm::{
- ExitRevert, OnCreate, OnMethodCall, PrecompileResult, PrecompileFailure, account::CrossAccountId
+ ExitRevert, OnCreate, OnMethodCall, PrecompileResult, PrecompileFailure,
+ account::CrossAccountId,
};
use sp_core::H160;
use crate::{
@@ -179,7 +180,9 @@
}
pub struct HelpersContractSponsoring<T: Config>(PhantomData<*const T>);
-impl<T: Config> SponsorshipHandler<T::CrossAccountId, (H160, Vec<u8>)> for HelpersContractSponsoring<T> {
+impl<T: Config> SponsorshipHandler<T::CrossAccountId, (H160, Vec<u8>)>
+ for HelpersContractSponsoring<T>
+{
fn get_sponsor(who: &T::CrossAccountId, call: &(H160, Vec<u8>)) -> Option<T::CrossAccountId> {
let mode = <Pallet<T>>::sponsoring_mode(call.0);
if mode == SponsoringModeT::Disabled {
pallets/evm-contract-helpers/src/lib.rsdiffbeforeafterboth--- a/pallets/evm-contract-helpers/src/lib.rs
+++ b/pallets/evm-contract-helpers/src/lib.rs
@@ -30,7 +30,9 @@
use sp_core::H160;
#[pallet::config]
- pub trait Config: frame_system::Config + pallet_evm_coder_substrate::Config + pallet_evm::account::Config {
+ pub trait Config:
+ frame_system::Config + pallet_evm_coder_substrate::Config + pallet_evm::account::Config
+ {
type ContractAddress: Get<H160>;
type DefaultSponsoringRateLimit: Get<Self::BlockNumber>;
}
pallets/evm-transaction-payment/src/lib.rsdiffbeforeafterboth--- a/pallets/evm-transaction-payment/src/lib.rs
+++ b/pallets/evm-transaction-payment/src/lib.rs
@@ -87,7 +87,8 @@
fee: U256,
) -> core::result::Result<Self::LiquidityInfo, pallet_evm::Error<T>> {
let who_pays_fee = if let WithdrawReason::Call { target, input } = &reason {
- T::EvmSponsorshipHandler::get_sponsor(who, &(*target, input.clone())).unwrap_or(who.clone())
+ T::EvmSponsorshipHandler::get_sponsor(who, &(*target, input.clone()))
+ .unwrap_or(who.clone())
} else {
who.clone()
};
pallets/fungible/src/lib.rsdiffbeforeafterboth--- a/pallets/fungible/src/lib.rs
+++ b/pallets/fungible/src/lib.rs
@@ -19,9 +19,7 @@
use core::ops::Deref;
use frame_support::{ensure};
use up_data_structs::{AccessMode, CollectionId, TokenId, CreateCollectionData};
-use pallet_common::{
- Error as CommonError, Event as CommonEvent, Pallet as PalletCommon,
-};
+use pallet_common::{Error as CommonError, Event as CommonEvent, Pallet as PalletCommon};
use pallet_evm::account::CrossAccountId;
use pallet_evm_coder_substrate::WithRecorder;
use sp_core::H160;
pallets/nonfungible/src/lib.rsdiffbeforeafterboth--- a/pallets/nonfungible/src/lib.rs
+++ b/pallets/nonfungible/src/lib.rs
@@ -21,9 +21,7 @@
use up_data_structs::{
AccessMode, CollectionId, CustomDataLimit, TokenId, CreateCollectionData, CreateNftExData,
};
-use pallet_common::{
- Error as CommonError, Pallet as PalletCommon, Event as CommonEvent,
-};
+use pallet_common::{Error as CommonError, Pallet as PalletCommon, Event as CommonEvent};
use pallet_evm::account::CrossAccountId;
use pallet_evm_coder_substrate::{SubstrateRecorder, WithRecorder};
use sp_core::H160;
pallets/refungible/src/lib.rsdiffbeforeafterboth--- a/pallets/refungible/src/lib.rs
+++ b/pallets/refungible/src/lib.rs
@@ -21,9 +21,7 @@
AccessMode, CollectionId, CustomDataLimit, MAX_REFUNGIBLE_PIECES, TokenId,
CreateCollectionData, CreateRefungibleExData,
};
-use pallet_common::{
- Error as CommonError, Event as CommonEvent, Pallet as PalletCommon,
-};
+use pallet_common::{Error as CommonError, Event as CommonEvent, Pallet as PalletCommon};
use pallet_evm::account::CrossAccountId;
use sp_runtime::{ArithmeticError, DispatchError, DispatchResult};
use sp_std::{vec::Vec, vec, collections::btree_map::BTreeMap};
pallets/unique/src/eth/sponsoring.rsdiffbeforeafterboth--- a/pallets/unique/src/eth/sponsoring.rs
+++ b/pallets/unique/src/eth/sponsoring.rs
@@ -32,7 +32,9 @@
use up_data_structs::{CreateItemData, CreateNftData};
pub struct UniqueEthSponsorshipHandler<T: Config>(PhantomData<*const T>);
-impl<T: Config> SponsorshipHandler<T::CrossAccountId, (H160, Vec<u8>)> for UniqueEthSponsorshipHandler<T> {
+impl<T: Config> SponsorshipHandler<T::CrossAccountId, (H160, Vec<u8>)>
+ for UniqueEthSponsorshipHandler<T>
+{
fn get_sponsor(who: &T::CrossAccountId, call: &(H160, Vec<u8>)) -> Option<T::CrossAccountId> {
let collection_id = map_eth_to_id(&call.0)?;
let collection = <CollectionHandle<T>>::new(collection_id)?;
@@ -59,16 +61,17 @@
.map(|()| sponsor)
}
UniqueNFTCall::ERC721Mintable(call) => match call {
- pallet_nonfungible::erc::ERC721MintableCall::Mint { .. } |
- pallet_nonfungible::erc::ERC721MintableCall::MintWithTokenUri { .. } => {
- withdraw_create_item(
- &collection,
- who.as_sub(),
- &CreateItemData::NFT(CreateNftData::default()))
- .map(|()| sponsor)
- }
+ pallet_nonfungible::erc::ERC721MintableCall::Mint { .. }
+ | pallet_nonfungible::erc::ERC721MintableCall::MintWithTokenUri {
+ ..
+ } => withdraw_create_item(
+ &collection,
+ who.as_sub(),
+ &CreateItemData::NFT(CreateNftData::default()),
+ )
+ .map(|()| sponsor),
_ => None,
- }
+ },
_ => None,
}
}
pallets/unique/src/lib.rsdiffbeforeafterboth--- a/pallets/unique/src/lib.rs
+++ b/pallets/unique/src/lib.rs
@@ -53,10 +53,7 @@
CollectionMode, TokenId, SchemaVersion, SponsorshipState, MetaUpdatePermission,
CreateCollectionData, CustomDataLimit, CreateItemExData,
};
-use pallet_common::{
- CollectionHandle, Pallet as PalletCommon, Error as CommonError,
- CommonWeightInfo,
-};
+use pallet_common::{CollectionHandle, Pallet as PalletCommon, Error as CommonError, CommonWeightInfo};
use pallet_evm::account::CrossAccountId;
use pallet_refungible::{Pallet as PalletRefungible, RefungibleHandle};
use pallet_fungible::{Pallet as PalletFungible, FungibleHandle};
pallets/unique/src/tests.rsdiffbeforeafterboth--- a/pallets/unique/src/tests.rs
+++ b/pallets/unique/src/tests.rs
@@ -2865,18 +2865,49 @@
let origin1 = Origin::signed(user1);
let origin2 = Origin::signed(user2);
let account2 = account(user2);
-
- let collection_id = create_test_collection_for_owner(&CollectionMode::NFT, user1, CollectionId(1));
- assert_ok!(TemplateModule::set_collection_sponsor(origin1.clone(), collection_id, user1));
- assert_ok!(TemplateModule::confirm_sponsorship(origin1.clone(), collection_id));
+ let collection_id =
+ create_test_collection_for_owner(&CollectionMode::NFT, user1, CollectionId(1));
+ assert_ok!(TemplateModule::set_collection_sponsor(
+ origin1.clone(),
+ collection_id,
+ user1
+ ));
+ assert_ok!(TemplateModule::confirm_sponsorship(
+ origin1.clone(),
+ collection_id
+ ));
+
// Expect error while have no permissions
- assert!(TemplateModule::create_item(origin2.clone(), collection_id, account2.clone(), default_nft_data().into()).is_err());
+ assert!(TemplateModule::create_item(
+ origin2.clone(),
+ collection_id,
+ account2.clone(),
+ default_nft_data().into()
+ )
+ .is_err());
- assert_ok!(TemplateModule::set_public_access_mode(origin1.clone(), collection_id, AccessMode::AllowList));
- assert_ok!(TemplateModule::add_to_allow_list(origin1.clone(), collection_id, account2.clone()));
- assert_ok!(TemplateModule::set_mint_permission(origin1.clone(), collection_id, true));
-
- assert_ok!(TemplateModule::create_item(origin2, collection_id, account2, default_nft_data().into()));
+ assert_ok!(TemplateModule::set_public_access_mode(
+ origin1.clone(),
+ collection_id,
+ AccessMode::AllowList
+ ));
+ assert_ok!(TemplateModule::add_to_allow_list(
+ origin1.clone(),
+ collection_id,
+ account2.clone()
+ ));
+ assert_ok!(TemplateModule::set_mint_permission(
+ origin1.clone(),
+ collection_id,
+ true
+ ));
+
+ assert_ok!(TemplateModule::create_item(
+ origin2,
+ collection_id,
+ account2,
+ default_nft_data().into()
+ ));
});
-}
\ No newline at end of file
+}