difftreelog
Merge pull request #462 from UniqueNetwork/fix/pallets_disabled
in: master
98 files changed
Cargo.lockdiffbeforeafterboth--- a/Cargo.lock
+++ b/Cargo.lock
@@ -5291,6 +5291,7 @@
"cumulus-primitives-timestamp",
"cumulus-primitives-utility",
"derivative",
+ "evm-coder",
"fp-evm-mapping",
"fp-rpc",
"fp-self-contained",
@@ -5352,9 +5353,10 @@
"sp-transaction-pool",
"sp-version",
"substrate-wasm-builder",
- "unique-runtime-common",
+ "up-common",
"up-data-structs",
"up-rpc",
+ "up-sponsorship",
"xcm",
"xcm-builder",
"xcm-executor",
@@ -8605,6 +8607,7 @@
"cumulus-primitives-timestamp",
"cumulus-primitives-utility",
"derivative",
+ "evm-coder",
"fp-evm-mapping",
"fp-rpc",
"fp-self-contained",
@@ -8666,9 +8669,10 @@
"sp-transaction-pool",
"sp-version",
"substrate-wasm-builder",
- "unique-runtime-common",
+ "up-common",
"up-data-structs",
"up-rpc",
+ "up-sponsorship",
"xcm",
"xcm-builder",
"xcm-executor",
@@ -11881,6 +11885,7 @@
name = "tests"
version = "0.1.0"
dependencies = [
+ "evm-coder",
"fp-evm-mapping",
"frame-support",
"frame-system",
@@ -11902,8 +11907,8 @@
"sp-io",
"sp-runtime",
"sp-std",
- "unique-runtime-common",
"up-data-structs",
+ "up-sponsorship",
]
[[package]]
@@ -12387,7 +12392,6 @@
"sp-core",
"sp-rpc",
"sp-runtime",
- "unique-runtime-common",
"up-data-structs",
"up-rpc",
]
@@ -12541,7 +12545,7 @@
"try-runtime-cli",
"unique-rpc",
"unique-runtime",
- "unique-runtime-common",
+ "up-common",
"up-data-structs",
"up-rpc",
]
@@ -12590,7 +12594,7 @@
"substrate-frame-rpc-system",
"tokio 0.2.25",
"uc-rpc",
- "unique-runtime-common",
+ "up-common",
"up-data-structs",
"up-rpc",
]
@@ -12608,6 +12612,7 @@
"cumulus-primitives-timestamp",
"cumulus-primitives-utility",
"derivative",
+ "evm-coder",
"fp-evm-mapping",
"fp-rpc",
"fp-self-contained",
@@ -12669,41 +12674,16 @@
"sp-transaction-pool",
"sp-version",
"substrate-wasm-builder",
- "unique-runtime-common",
+ "up-common",
"up-data-structs",
"up-rpc",
+ "up-sponsorship",
"xcm",
"xcm-builder",
"xcm-executor",
]
[[package]]
-name = "unique-runtime-common"
-version = "0.9.24"
-dependencies = [
- "evm-coder",
- "fp-rpc",
- "frame-support",
- "frame-system",
- "pallet-common",
- "pallet-evm",
- "pallet-fungible",
- "pallet-nonfungible",
- "pallet-refungible",
- "pallet-unique",
- "pallet-unique-scheduler",
- "parity-scale-codec 3.1.5",
- "rmrk-rpc",
- "scale-info",
- "sp-consensus-aura",
- "sp-core",
- "sp-runtime",
- "sp-std",
- "up-data-structs",
- "up-sponsorship",
-]
-
-[[package]]
name = "universal-hash"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -12732,6 +12712,19 @@
checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a"
[[package]]
+name = "up-common"
+version = "0.9.24"
+dependencies = [
+ "fp-rpc",
+ "frame-support",
+ "pallet-evm",
+ "sp-consensus-aura",
+ "sp-core",
+ "sp-runtime",
+ "sp-std",
+]
+
+[[package]]
name = "up-data-structs"
version = "0.2.1"
dependencies = [
client/rpc/Cargo.tomldiffbeforeafterboth--- a/client/rpc/Cargo.toml
+++ b/client/rpc/Cargo.toml
@@ -5,7 +5,6 @@
edition = "2021"
[dependencies]
-unique-runtime-common = { default-features = false, path = "../../runtime/common" }
pallet-common = { default-features = false, path = '../../pallets/common' }
up-data-structs = { default-features = false, path = '../../primitives/data-structs' }
up-rpc = { path = "../../primitives/rpc" }
node/cli/Cargo.tomldiffbeforeafterboth--- a/node/cli/Cargo.toml
+++ b/node/cli/Cargo.toml
@@ -253,9 +253,8 @@
################################################################################
# Local dependencies
-[dependencies.unique-runtime-common]
-default-features = false
-path = "../../runtime/common"
+[dependencies.up-common]
+path = "../../primitives/common"
[dependencies.unique-runtime]
path = '../../runtime/unique'
node/cli/src/chain_spec.rsdiffbeforeafterboth--- a/node/cli/src/chain_spec.rs
+++ b/node/cli/src/chain_spec.rs
@@ -23,7 +23,7 @@
use serde::{Deserialize, Serialize};
use serde_json::map::Map;
-use unique_runtime_common::types::*;
+use up_common::types::opaque::*;
#[cfg(feature = "unique-runtime")]
pub use unique_runtime as default_runtime;
node/cli/src/command.rsdiffbeforeafterboth--- a/node/cli/src/command.rs
+++ b/node/cli/src/command.rs
@@ -64,7 +64,7 @@
use sp_runtime::traits::{AccountIdConversion, Block as BlockT};
use std::{io::Write, net::SocketAddr, time::Duration};
-use unique_runtime_common::types::Block;
+use up_common::types::opaque::Block;
macro_rules! no_runtime_err {
($chain_name:expr) => {
node/cli/src/service.rsdiffbeforeafterboth--- a/node/cli/src/service.rs
+++ b/node/cli/src/service.rs
@@ -63,7 +63,7 @@
use fc_rpc_core::types::FilterPool;
use fc_mapping_sync::{MappingSyncWorker, SyncStrategy};
-use unique_runtime_common::types::{AuraId, RuntimeInstance, AccountId, Balance, Index, Hash, Block};
+use up_common::types::opaque::{AuraId, RuntimeInstance, AccountId, Balance, Index, Hash, Block};
// RMRK
use up_data_structs::{
node/rpc/Cargo.tomldiffbeforeafterboth--- a/node/rpc/Cargo.toml
+++ b/node/rpc/Cargo.toml
@@ -49,7 +49,7 @@
fc-mapping-sync = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.24" }
pallet-common = { default-features = false, path = "../../pallets/common" }
-unique-runtime-common = { default-features = false, path = "../../runtime/common" }
+up-common = { path = "../../primitives/common" }
pallet-unique = { path = "../../pallets/unique" }
uc-rpc = { path = "../../client/rpc" }
up-rpc = { path = "../../primitives/rpc" }
node/rpc/src/lib.rsdiffbeforeafterboth--- a/node/rpc/src/lib.rs
+++ b/node/rpc/src/lib.rs
@@ -40,9 +40,8 @@
use sc_service::TransactionPool;
use std::{collections::BTreeMap, sync::Arc};
-use unique_runtime_common::types::{
- Hash, AccountId, RuntimeInstance, Index, Block, BlockNumber, Balance,
-};
+use up_common::types::opaque::{Hash, AccountId, RuntimeInstance, Index, Block, BlockNumber, Balance};
+
// RMRK
use up_data_structs::{
RmrkCollectionInfo, RmrkInstanceInfo, RmrkResourceInfo, RmrkPropertyInfo, RmrkBaseInfo,
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//! # Common pallet18//!19//! The Common pallet provides functionality for handling collections.20//!21//! ## Overview22//!23//! The Common pallet provides an interface for common collection operations for different collection types24//! (see [CommonCollectionOperations]), as well as a generic dispatcher for these, see [dispatch] module.25//! It also provides this functionality to EVM, see [erc] and [eth] modules.26//!27//! The Common pallet provides functions for:28//!29//! - Setting and approving collection sponsor.30//! - Get\set\delete allow list.31//! - Get\set\delete collection properties.32//! - Get\set\delete collection property permissions.33//! - Get\set\delete token property permissions.34//! - Get\set\delete collection administrators.35//! - Checking access permissions.36//!37//! ### Terminology38//! **Collection sponsor** - For the collection, you can set a sponsor, at whose expense it will39//! be possible to mint tokens.40//!41//! **Allow list** - List of users who have the right to minting tokens.42//!43//! **Collection properties** - Collection properties are simply key-value stores where various44//! metadata can be placed.45//!46//! **Permissions on token properties** - For each property in the token can be set permission47//! to change, see [`PropertyPermission`].48//!49//! **Collection administrator** - For a collection, you can set administrators who have the right50//! to most actions on the collection.5152#![warn(missing_docs)]53#![cfg_attr(not(feature = "std"), no_std)]54extern crate alloc;5556use core::ops::{Deref, DerefMut};57use pallet_evm_coder_substrate::{SubstrateRecorder, WithRecorder};58use sp_std::vec::Vec;59use pallet_evm::{account::CrossAccountId, Pallet as PalletEvm};60use evm_coder::ToLog;61use frame_support::{62 dispatch::{DispatchErrorWithPostInfo, DispatchResultWithPostInfo, Weight, PostDispatchInfo},63 ensure,64 traits::{Imbalance, Get, Currency, WithdrawReasons, ExistenceRequirement},65 weights::Pays,66 transactional,67};68use pallet_evm::GasWeightMapping;69use up_data_structs::{70 COLLECTION_NUMBER_LIMIT,71 Collection,72 RpcCollection,73 CollectionId,74 CreateItemData,75 MAX_TOKEN_PREFIX_LENGTH,76 COLLECTION_ADMINS_LIMIT,77 TokenId,78 TokenChild,79 CollectionStats,80 MAX_TOKEN_OWNERSHIP,81 CollectionMode,82 NFT_SPONSOR_TRANSFER_TIMEOUT,83 FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,84 REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,85 MAX_SPONSOR_TIMEOUT,86 CUSTOM_DATA_LIMIT,87 CollectionLimits,88 CreateCollectionData,89 SponsorshipState,90 CreateItemExData,91 SponsoringRateLimit,92 budget::Budget,93 PhantomType,94 Property,95 Properties,96 PropertiesPermissionMap,97 PropertyKey,98 PropertyValue,99 PropertyPermission,100 PropertiesError,101 PropertyKeyPermission,102 TokenData,103 TrySetProperty,104 PropertyScope,105 // RMRK106 RmrkCollectionInfo,107 RmrkInstanceInfo,108 RmrkResourceInfo,109 RmrkPropertyInfo,110 RmrkBaseInfo,111 RmrkPartType,112 RmrkBoundedTheme,113 RmrkNftChild,114 CollectionPermissions,115 SchemaVersion,116};117118pub use pallet::*;119use sp_core::H160;120use sp_runtime::{ArithmeticError, DispatchError, DispatchResult};121#[cfg(feature = "runtime-benchmarks")]122pub mod benchmarking;123pub mod dispatch;124pub mod erc;125pub mod eth;126pub mod weights;127128/// Weight info.129pub type SelfWeightOf<T> = <T as Config>::WeightInfo;130131/// Collection handle contains information about collection data and id.132/// Also provides functionality to count consumed gas.133///134/// CollectionHandle is used as a generic wrapper for collections of all types.135/// It allows to perform common operations and queries on any collection type,136/// both completely general for all, as well as their respective implementations of [`CommonCollectionOperations`].137#[must_use = "Should call submit_logs or save, otherwise some data will be lost for evm side"]138pub struct CollectionHandle<T: Config> {139 /// Collection id140 pub id: CollectionId,141 collection: Collection<T::AccountId>,142 /// Substrate recorder for counting consumed gas143 pub recorder: SubstrateRecorder<T>,144}145146impl<T: Config> WithRecorder<T> for CollectionHandle<T> {147 fn recorder(&self) -> &SubstrateRecorder<T> {148 &self.recorder149 }150 fn into_recorder(self) -> SubstrateRecorder<T> {151 self.recorder152 }153}154155impl<T: Config> CollectionHandle<T> {156 /// Same as [CollectionHandle::new] but with an explicit gas limit.157 pub fn new_with_gas_limit(id: CollectionId, gas_limit: u64) -> Option<Self> {158 <CollectionById<T>>::get(id).map(|collection| Self {159 id,160 collection,161 recorder: SubstrateRecorder::new(gas_limit),162 })163 }164165 /// Same as [CollectionHandle::new] but with an existed [`SubstrateRecorder`].166 pub fn new_with_recorder(id: CollectionId, recorder: SubstrateRecorder<T>) -> Option<Self> {167 <CollectionById<T>>::get(id).map(|collection| Self {168 id,169 collection,170 recorder,171 })172 }173174 /// Retrives collection data from storage and creates collection handle with default parameters.175 /// If collection not found return `None`176 pub fn new(id: CollectionId) -> Option<Self> {177 Self::new_with_gas_limit(id, u64::MAX)178 }179180 /// Same as [`CollectionHandle::new`] but if collection not found [CollectionNotFound](Error::CollectionNotFound) returned.181 pub fn try_get(id: CollectionId) -> Result<Self, DispatchError> {182 Ok(Self::new(id).ok_or(<Error<T>>::CollectionNotFound)?)183 }184185 /// Consume gas for reading.186 pub fn consume_store_reads(&self, reads: u64) -> evm_coder::execution::Result<()> {187 self.recorder188 .consume_gas(T::GasWeightMapping::weight_to_gas(189 <T as frame_system::Config>::DbWeight::get()190 .read191 .saturating_mul(reads),192 ))193 }194195 /// Consume gas for writing.196 pub fn consume_store_writes(&self, writes: u64) -> evm_coder::execution::Result<()> {197 self.recorder198 .consume_gas(T::GasWeightMapping::weight_to_gas(199 <T as frame_system::Config>::DbWeight::get()200 .write201 .saturating_mul(writes),202 ))203 }204205 /// Save collection to storage.206 pub fn save(self) -> DispatchResult {207 <CollectionById<T>>::insert(self.id, self.collection);208 Ok(())209 }210211 /// Set collection sponsor.212 ///213 /// Unique collections allows sponsoring for certain actions.214 /// This method allows you to set the sponsor of the collection.215 /// In order for sponsorship to become active, it must be confirmed through [`Self::confirm_sponsorship`].216 pub fn set_sponsor(&mut self, sponsor: T::AccountId) -> DispatchResult {217 self.collection.sponsorship = SponsorshipState::Unconfirmed(sponsor);218 Ok(())219 }220221 /// Confirm sponsorship222 ///223 /// In order for the sponsorship to become active, the user set as the sponsor must confirm their participation.224 /// Before confirming sponsorship, the user must be specified as the sponsor of the collection via [`Self::set_sponsor`].225 pub fn confirm_sponsorship(&mut self, sender: &T::AccountId) -> Result<bool, DispatchError> {226 if self.collection.sponsorship.pending_sponsor() != Some(sender) {227 return Ok(false);228 }229230 self.collection.sponsorship = SponsorshipState::Confirmed(sender.clone());231 Ok(true)232 }233234 /// Checks that the collection was created with, and must be operated upon through **Unique API**.235 /// Now check only the `external_collection` flag and if it's **true**, then return [`Error::CollectionIsExternal`] error.236 pub fn check_is_internal(&self) -> DispatchResult {237 if self.external_collection {238 return Err(<Error<T>>::CollectionIsExternal)?;239 }240241 Ok(())242 }243244 /// Checks that the collection was created with, and must be operated upon through an **assimilated API**.245 /// Now check only the `external_collection` flag and if it's **false**, then return [`Error::CollectionIsInternal`] error.246 pub fn check_is_external(&self) -> DispatchResult {247 if !self.external_collection {248 return Err(<Error<T>>::CollectionIsInternal)?;249 }250251 Ok(())252 }253}254255impl<T: Config> Deref for CollectionHandle<T> {256 type Target = Collection<T::AccountId>;257258 fn deref(&self) -> &Self::Target {259 &self.collection260 }261}262263impl<T: Config> DerefMut for CollectionHandle<T> {264 fn deref_mut(&mut self) -> &mut Self::Target {265 &mut self.collection266 }267}268269impl<T: Config> CollectionHandle<T> {270 /// Checks if the `user` is the owner of the collection.271 pub fn check_is_owner(&self, user: &T::CrossAccountId) -> DispatchResult {272 ensure!(*user.as_sub() == self.owner, <Error<T>>::NoPermission);273 Ok(())274 }275276 /// Returns **true** if the `user` is the owner or administrator of the collection.277 pub fn is_owner_or_admin(&self, user: &T::CrossAccountId) -> bool {278 *user.as_sub() == self.owner || <IsAdmin<T>>::get((self.id, user))279 }280281 /// Checks if the `user` is the owner or administrator of the collection.282 pub fn check_is_owner_or_admin(&self, user: &T::CrossAccountId) -> DispatchResult {283 ensure!(self.is_owner_or_admin(user), <Error<T>>::NoPermission);284 Ok(())285 }286287 /// Return **true** if `user` was not allowed to have tokens, and he can ignore such restrictions.288 pub fn ignores_allowance(&self, user: &T::CrossAccountId) -> bool {289 self.limits.owner_can_transfer() && self.is_owner_or_admin(user)290 }291292 /// Return **true** if `user` does not have enough token parts, and he can ignore such restrictions.293 pub fn ignores_owned_amount(&self, user: &T::CrossAccountId) -> bool {294 self.limits.owner_can_transfer() && self.is_owner_or_admin(user)295 }296297 /// Checks if the user is in the allow list. If not [Error::AddressNotInAllowlist] returns.298 pub fn check_allowlist(&self, user: &T::CrossAccountId) -> DispatchResult {299 ensure!(300 <Allowlist<T>>::get((self.id, user)),301 <Error<T>>::AddressNotInAllowlist302 );303 Ok(())304 }305}306307#[frame_support::pallet]308pub mod pallet {309 use super::*;310 use pallet_evm::account;311 use dispatch::CollectionDispatch;312 use frame_support::{Blake2_128Concat, pallet_prelude::*, storage::Key, traits::StorageVersion};313 use frame_system::pallet_prelude::*;314 use frame_support::traits::Currency;315 use up_data_structs::{TokenId, mapping::TokenAddressMapping};316 use scale_info::TypeInfo;317 use weights::WeightInfo;318319 #[pallet::config]320 pub trait Config:321 frame_system::Config322 + pallet_evm_coder_substrate::Config323 + pallet_evm::Config324 + TypeInfo325 + account::Config326 {327 /// Weight information for functions of this pallet.328 type WeightInfo: WeightInfo;329330 /// Events compatible with [`frame_system::Config::Event`].331 type Event: IsType<<Self as frame_system::Config>::Event> + From<Event<Self>>;332333 /// Handler of accounts and payment.334 type Currency: Currency<Self::AccountId>;335336 /// Set price to create a collection.337 #[pallet::constant]338 type CollectionCreationPrice: Get<339 <<Self as Config>::Currency as Currency<Self::AccountId>>::Balance,340 >;341342 /// Dispatcher of operations on collections.343 type CollectionDispatch: CollectionDispatch<Self>;344345 /// Account which holds the chain's treasury.346 type TreasuryAccountId: Get<Self::AccountId>;347348 /// Address under which the CollectionHelper contract would be available.349 type ContractAddress: Get<H160>;350351 /// Mapper for token addresses to Ethereum addresses.352 type EvmTokenAddressMapping: TokenAddressMapping<H160>;353354 /// Mapper for token addresses to [`CrossAccountId`].355 type CrossTokenAddressMapping: TokenAddressMapping<Self::CrossAccountId>;356 }357358 const STORAGE_VERSION: StorageVersion = StorageVersion::new(1);359360 #[pallet::pallet]361 #[pallet::storage_version(STORAGE_VERSION)]362 #[pallet::generate_store(pub(super) trait Store)]363 pub struct Pallet<T>(_);364365 #[pallet::extra_constants]366 impl<T: Config> Pallet<T> {367 /// Maximum admins per collection.368 pub fn collection_admins_limit() -> u32 {369 COLLECTION_ADMINS_LIMIT370 }371 }372373 #[pallet::event]374 #[pallet::generate_deposit(pub fn deposit_event)]375 pub enum Event<T: Config> {376 /// New collection was created377 CollectionCreated(378 /// Globally unique identifier of newly created collection.379 CollectionId,380 /// [`CollectionMode`] converted into _u8_.381 u8,382 /// Collection owner.383 T::AccountId,384 ),385386 /// New collection was destroyed387 CollectionDestroyed(388 /// Globally unique identifier of collection.389 CollectionId,390 ),391392 /// New item was created.393 ItemCreated(394 /// Id of the collection where item was created.395 CollectionId,396 /// Id of an item. Unique within the collection.397 TokenId,398 /// Owner of newly created item399 T::CrossAccountId,400 /// Always 1 for NFT401 u128,402 ),403404 /// Collection item was burned.405 ItemDestroyed(406 /// Id of the collection where item was destroyed.407 CollectionId,408 /// Identifier of burned NFT.409 TokenId,410 /// Which user has destroyed its tokens.411 T::CrossAccountId,412 /// Amount of token pieces destroed. Always 1 for NFT.413 u128,414 ),415416 /// Item was transferred417 Transfer(418 /// Id of collection to which item is belong.419 CollectionId,420 /// Id of an item.421 TokenId,422 /// Original owner of item.423 T::CrossAccountId,424 /// New owner of item.425 T::CrossAccountId,426 /// Amount of token pieces transfered. Always 1 for NFT.427 u128,428 ),429430 /// Amount pieces of token owned by `sender` was approved for `spender`.431 Approved(432 /// Id of collection to which item is belong.433 CollectionId,434 /// Id of an item.435 TokenId,436 /// Original owner of item.437 T::CrossAccountId,438 /// Id for which the approval was granted.439 T::CrossAccountId,440 /// Amount of token pieces transfered. Always 1 for NFT.441 u128,442 ),443444 /// The colletion property has been added or edited.445 CollectionPropertySet(446 /// Id of collection to which property has been set.447 CollectionId,448 /// The property that was set.449 PropertyKey,450 ),451452 /// The property has been deleted.453 CollectionPropertyDeleted(454 /// Id of collection to which property has been deleted.455 CollectionId,456 /// The property that was deleted.457 PropertyKey,458 ),459460 /// The token property has been added or edited.461 TokenPropertySet(462 /// Identifier of the collection whose token has the property set.463 CollectionId,464 /// The token for which the property was set.465 TokenId,466 /// The property that was set.467 PropertyKey,468 ),469470 /// The token property has been deleted.471 TokenPropertyDeleted(472 /// Identifier of the collection whose token has the property deleted.473 CollectionId,474 /// The token for which the property was deleted.475 TokenId,476 /// The property that was deleted.477 PropertyKey,478 ),479480 /// The token property permission of a collection has been set.481 PropertyPermissionSet(482 /// ID of collection to which property permission has been set.483 CollectionId,484 /// The property permission that was set.485 PropertyKey,486 ),487 }488489 #[pallet::error]490 pub enum Error<T> {491 /// This collection does not exist.492 CollectionNotFound,493 /// Sender parameter and item owner must be equal.494 MustBeTokenOwner,495 /// No permission to perform action496 NoPermission,497 /// Destroying only empty collections is allowed498 CantDestroyNotEmptyCollection,499 /// Collection is not in mint mode.500 PublicMintingNotAllowed,501 /// Address is not in allow list.502 AddressNotInAllowlist,503504 /// Collection name can not be longer than 63 char.505 CollectionNameLimitExceeded,506 /// Collection description can not be longer than 255 char.507 CollectionDescriptionLimitExceeded,508 /// Token prefix can not be longer than 15 char.509 CollectionTokenPrefixLimitExceeded,510 /// Total collections bound exceeded.511 TotalCollectionsLimitExceeded,512 /// Exceeded max admin count513 CollectionAdminCountExceeded,514 /// Collection limit bounds per collection exceeded515 CollectionLimitBoundsExceeded,516 /// Tried to enable permissions which are only permitted to be disabled517 OwnerPermissionsCantBeReverted,518 /// Collection settings not allowing items transferring519 TransferNotAllowed,520 /// Account token limit exceeded per collection521 AccountTokenLimitExceeded,522 /// Collection token limit exceeded523 CollectionTokenLimitExceeded,524 /// Metadata flag frozen525 MetadataFlagFrozen,526527 /// Item does not exist528 TokenNotFound,529 /// Item is balance not enough530 TokenValueTooLow,531 /// Requested value is more than the approved532 ApprovedValueTooLow,533 /// Tried to approve more than owned534 CantApproveMoreThanOwned,535536 /// Can't transfer tokens to ethereum zero address537 AddressIsZero,538 /// Target collection doesn't support this operation539 UnsupportedOperation,540541 /// Insufficient funds to perform an action542 NotSufficientFounds,543544 /// User does not satisfy the nesting rule545 UserIsNotAllowedToNest,546 /// Only tokens from specific collections may nest tokens under this one547 SourceCollectionIsNotAllowedToNest,548549 /// Tried to store more data than allowed in collection field550 CollectionFieldSizeExceeded,551552 /// Tried to store more property data than allowed553 NoSpaceForProperty,554555 /// Tried to store more property keys than allowed556 PropertyLimitReached,557558 /// Property key is too long559 PropertyKeyIsTooLong,560561 /// Only ASCII letters, digits, and symbols `_`, `-`, and `.` are allowed562 InvalidCharacterInPropertyKey,563564 /// Empty property keys are forbidden565 EmptyPropertyKey,566567 /// Tried to access an external collection with an internal API568 CollectionIsExternal,569570 /// Tried to access an internal collection with an external API571 CollectionIsInternal,572 }573574 /// Storage of the count of created collections. Essentially contains the last collection ID.575 #[pallet::storage]576 pub type CreatedCollectionCount<T> = StorageValue<Value = CollectionId, QueryKind = ValueQuery>;577578 /// Storage of the count of deleted collections.579 #[pallet::storage]580 pub type DestroyedCollectionCount<T> =581 StorageValue<Value = CollectionId, QueryKind = ValueQuery>;582583 /// Storage of collection info.584 #[pallet::storage]585 pub type CollectionById<T> = StorageMap<586 Hasher = Blake2_128Concat,587 Key = CollectionId,588 Value = Collection<<T as frame_system::Config>::AccountId>,589 QueryKind = OptionQuery,590 >;591592 /// Storage of collection properties.593 #[pallet::storage]594 #[pallet::getter(fn collection_properties)]595 pub type CollectionProperties<T> = StorageMap<596 Hasher = Blake2_128Concat,597 Key = CollectionId,598 Value = Properties,599 QueryKind = ValueQuery,600 OnEmpty = up_data_structs::CollectionProperties,601 >;602603 /// Storage of token property permissions of a collection.604 #[pallet::storage]605 #[pallet::getter(fn property_permissions)]606 pub type CollectionPropertyPermissions<T> = StorageMap<607 Hasher = Blake2_128Concat,608 Key = CollectionId,609 Value = PropertiesPermissionMap,610 QueryKind = ValueQuery,611 >;612613 /// Storage of the amount of collection admins.614 #[pallet::storage]615 pub type AdminAmount<T> = StorageMap<616 Hasher = Blake2_128Concat,617 Key = CollectionId,618 Value = u32,619 QueryKind = ValueQuery,620 >;621622 /// List of collection admins.623 #[pallet::storage]624 pub type IsAdmin<T: Config> = StorageNMap<625 Key = (626 Key<Blake2_128Concat, CollectionId>,627 Key<Blake2_128Concat, T::CrossAccountId>,628 ),629 Value = bool,630 QueryKind = ValueQuery,631 >;632633 /// Allowlisted collection users.634 #[pallet::storage]635 pub type Allowlist<T: Config> = StorageNMap<636 Key = (637 Key<Blake2_128Concat, CollectionId>,638 Key<Blake2_128Concat, T::CrossAccountId>,639 ),640 Value = bool,641 QueryKind = ValueQuery,642 >;643644 /// Not used by code, exists only to provide some types to metadata.645 #[pallet::storage]646 pub type DummyStorageValue<T: Config> = StorageValue<647 Value = (648 CollectionStats,649 CollectionId,650 TokenId,651 TokenChild,652 PhantomType<(653 TokenData<T::CrossAccountId>,654 RpcCollection<T::AccountId>,655 // RMRK656 RmrkCollectionInfo<T::AccountId>,657 RmrkInstanceInfo<T::AccountId>,658 RmrkResourceInfo,659 RmrkPropertyInfo,660 RmrkBaseInfo<T::AccountId>,661 RmrkPartType,662 RmrkBoundedTheme,663 RmrkNftChild,664 )>,665 ),666 QueryKind = OptionQuery,667 >;668669 #[pallet::hooks]670 impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {671 fn on_runtime_upgrade() -> Weight {672 StorageVersion::new(1).put::<Pallet<T>>();673674 0675 }676 }677}678679impl<T: Config> Pallet<T> {680 /// Enshure that receiver address is correct.681 ///682 /// Ethereum receiver 0x0000000000000000000000000000000000000000 is reserved, and shouldn't own tokens.683 pub fn ensure_correct_receiver(receiver: &T::CrossAccountId) -> DispatchResult {684 ensure!(685 &T::CrossAccountId::from_eth(H160([0; 20])) != receiver,686 <Error<T>>::AddressIsZero687 );688 Ok(())689 }690691 /// Get a vector of collection admins.692 pub fn adminlist(collection: CollectionId) -> Vec<T::CrossAccountId> {693 <IsAdmin<T>>::iter_prefix((collection,))694 .map(|(a, _)| a)695 .collect()696 }697698 /// Get a vector of users allowed to mint tokens.699 pub fn allowlist(collection: CollectionId) -> Vec<T::CrossAccountId> {700 <Allowlist<T>>::iter_prefix((collection,))701 .map(|(a, _)| a)702 .collect()703 }704705 /// Is `user` allowed to mint token in `collection`.706 pub fn allowed(collection: CollectionId, user: T::CrossAccountId) -> bool {707 <Allowlist<T>>::get((collection, user))708 }709710 /// Get statistics of collections.711 pub fn collection_stats() -> CollectionStats {712 let created = <CreatedCollectionCount<T>>::get();713 let destroyed = <DestroyedCollectionCount<T>>::get();714 CollectionStats {715 created: created.0,716 destroyed: destroyed.0,717 alive: created.0 - destroyed.0,718 }719 }720721 /// Get the effective limits for the collection.722 pub fn effective_collection_limits(collection: CollectionId) -> Option<CollectionLimits> {723 let collection = <CollectionById<T>>::get(collection);724 if collection.is_none() {725 return None;726 }727728 let collection = collection.unwrap();729 let limits = collection.limits;730 let effective_limits = CollectionLimits {731 account_token_ownership_limit: Some(limits.account_token_ownership_limit()),732 sponsored_data_size: Some(limits.sponsored_data_size()),733 sponsored_data_rate_limit: Some(734 limits735 .sponsored_data_rate_limit736 .unwrap_or(SponsoringRateLimit::SponsoringDisabled),737 ),738 token_limit: Some(limits.token_limit()),739 sponsor_transfer_timeout: Some(limits.sponsor_transfer_timeout(740 match collection.mode {741 CollectionMode::NFT => NFT_SPONSOR_TRANSFER_TIMEOUT,742 CollectionMode::Fungible(_) => FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,743 CollectionMode::ReFungible => REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,744 },745 )),746 sponsor_approve_timeout: Some(limits.sponsor_approve_timeout()),747 owner_can_transfer: Some(limits.owner_can_transfer()),748 owner_can_destroy: Some(limits.owner_can_destroy()),749 transfers_enabled: Some(limits.transfers_enabled()),750 };751752 Some(effective_limits)753 }754755 /// Returns information about the `collection` adapted for rpc.756 pub fn rpc_collection(collection: CollectionId) -> Option<RpcCollection<T::AccountId>> {757 let Collection {758 name,759 description,760 owner,761 mode,762 token_prefix,763 sponsorship,764 limits,765 permissions,766 external_collection,767 } = <CollectionById<T>>::get(collection)?;768769 let token_property_permissions = <CollectionPropertyPermissions<T>>::get(collection)770 .into_iter()771 .map(|(key, permission)| PropertyKeyPermission { key, permission })772 .collect();773774 let properties = <CollectionProperties<T>>::get(collection)775 .into_iter()776 .map(|(key, value)| Property { key, value })777 .collect();778779 let permissions = CollectionPermissions {780 access: Some(permissions.access()),781 mint_mode: Some(permissions.mint_mode()),782 nesting: Some(permissions.nesting().clone()),783 };784785 Some(RpcCollection {786 name: name.into_inner(),787 description: description.into_inner(),788 owner,789 mode,790 token_prefix: token_prefix.into_inner(),791 sponsorship,792 limits,793 permissions,794 token_property_permissions,795 properties,796 read_only: external_collection,797 })798 }799}800801macro_rules! limit_default {802 ($old:ident, $new:ident, $($field:ident $(($arg:expr))? => $check:expr),* $(,)?) => {{803 $(804 if let Some($new) = $new.$field {805 let $old = $old.$field($($arg)?);806 let _ = $new;807 let _ = $old;808 $check809 } else {810 $new.$field = $old.$field811 }812 )*813 }};814}815macro_rules! limit_default_clone {816 ($old:ident, $new:ident, $($field:ident $(($arg:expr))? => $check:expr),* $(,)?) => {{817 $(818 if let Some($new) = $new.$field.clone() {819 let $old = $old.$field($($arg)?);820 let _ = $new;821 let _ = $old;822 $check823 } else {824 $new.$field = $old.$field.clone()825 }826 )*827 }};828}829830impl<T: Config> Pallet<T> {831 /// Create new collection.832 ///833 /// * `owner` - The owner of the collection.834 /// * `data` - Description of the created collection.835 /// * `is_external` - Marks that collection managet by not "Unique network".836 pub fn init_collection(837 owner: T::CrossAccountId,838 data: CreateCollectionData<T::AccountId>,839 is_external: bool,840 ) -> Result<CollectionId, DispatchError> {841 {842 ensure!(843 data.token_prefix.len() <= MAX_TOKEN_PREFIX_LENGTH as usize,844 Error::<T>::CollectionTokenPrefixLimitExceeded845 );846 }847848 let created_count = <CreatedCollectionCount<T>>::get()849 .0850 .checked_add(1)851 .ok_or(ArithmeticError::Overflow)?;852 let destroyed_count = <DestroyedCollectionCount<T>>::get().0;853 let id = CollectionId(created_count);854855 // bound Total number of collections856 ensure!(857 created_count - destroyed_count <= COLLECTION_NUMBER_LIMIT,858 <Error<T>>::TotalCollectionsLimitExceeded859 );860861 // =========862863 let collection = Collection {864 owner: owner.as_sub().clone(),865 name: data.name,866 mode: data.mode.clone(),867 description: data.description,868 token_prefix: data.token_prefix,869 sponsorship: data870 .pending_sponsor871 .map(SponsorshipState::Unconfirmed)872 .unwrap_or_default(),873 limits: data874 .limits875 .map(|limits| Self::clamp_limits(data.mode.clone(), &Default::default(), limits))876 .unwrap_or_else(|| Ok(CollectionLimits::default()))?,877 permissions: data878 .permissions879 .map(|permissions| {880 Self::clamp_permissions(data.mode.clone(), &Default::default(), permissions)881 })882 .unwrap_or_else(|| Ok(CollectionPermissions::default()))?,883 external_collection: is_external,884 };885886 let mut collection_properties = up_data_structs::CollectionProperties::get();887 collection_properties888 .try_set_from_iter(data.properties.into_iter())889 .map_err(<Error<T>>::from)?;890891 CollectionProperties::<T>::insert(id, collection_properties);892893 let mut token_props_permissions = PropertiesPermissionMap::new();894 token_props_permissions895 .try_set_from_iter(data.token_property_permissions.into_iter())896 .map_err(<Error<T>>::from)?;897898 CollectionPropertyPermissions::<T>::insert(id, token_props_permissions);899900 // Take a (non-refundable) deposit of collection creation901 {902 let mut imbalance =903 <<<T as Config>::Currency as Currency<T::AccountId>>::PositiveImbalance>::zero();904 imbalance.subsume(905 <<T as Config>::Currency as Currency<T::AccountId>>::deposit_creating(906 &T::TreasuryAccountId::get(),907 T::CollectionCreationPrice::get(),908 ),909 );910 <T as Config>::Currency::settle(911 owner.as_sub(),912 imbalance,913 WithdrawReasons::TRANSFER,914 ExistenceRequirement::KeepAlive,915 )916 .map_err(|_| Error::<T>::NotSufficientFounds)?;917 }918919 <CreatedCollectionCount<T>>::put(created_count);920 <Pallet<T>>::deposit_event(Event::CollectionCreated(921 id,922 data.mode.id(),923 owner.as_sub().clone(),924 ));925 <PalletEvm<T>>::deposit_log(926 erc::CollectionHelpersEvents::CollectionCreated {927 owner: *owner.as_eth(),928 collection_id: eth::collection_id_to_address(id),929 }930 .to_log(T::ContractAddress::get()),931 );932 <CollectionById<T>>::insert(id, collection);933 Ok(id)934 }935936 /// Destroy collection.937 ///938 /// * `collection` - Collection handler.939 /// * `sender` - The owner or administrator of the collection.940 pub fn destroy_collection(941 collection: CollectionHandle<T>,942 sender: &T::CrossAccountId,943 ) -> DispatchResult {944 ensure!(945 collection.limits.owner_can_destroy(),946 <Error<T>>::NoPermission,947 );948 collection.check_is_owner(sender)?;949950 let destroyed_collections = <DestroyedCollectionCount<T>>::get()951 .0952 .checked_add(1)953 .ok_or(ArithmeticError::Overflow)?;954955 // =========956957 <DestroyedCollectionCount<T>>::put(destroyed_collections);958 <CollectionById<T>>::remove(collection.id);959 <AdminAmount<T>>::remove(collection.id);960 <IsAdmin<T>>::remove_prefix((collection.id,), None);961 <Allowlist<T>>::remove_prefix((collection.id,), None);962 <CollectionProperties<T>>::remove(collection.id);963964 <Pallet<T>>::deposit_event(Event::CollectionDestroyed(collection.id));965 Ok(())966 }967968 /// Set collection property.969 ///970 /// * `collection` - Collection handler.971 /// * `sender` - The owner or administrator of the collection.972 /// * `property` - The property to set.973 pub fn set_collection_property(974 collection: &CollectionHandle<T>,975 sender: &T::CrossAccountId,976 property: Property,977 ) -> DispatchResult {978 collection.check_is_owner_or_admin(sender)?;979980 CollectionProperties::<T>::try_mutate(collection.id, |properties| {981 let property = property.clone();982 properties.try_set(property.key, property.value)983 })984 .map_err(<Error<T>>::from)?;985986 Self::deposit_event(Event::CollectionPropertySet(collection.id, property.key));987988 Ok(())989 }990991 /// Set scouped collection property.992 ///993 /// * `collection_id` - ID of the collection for which the property is being set.994 /// * `scope` - Property scope.995 /// * `property` - The property to set.996 pub fn set_scoped_collection_property(997 collection_id: CollectionId,998 scope: PropertyScope,999 property: Property,1000 ) -> DispatchResult {1001 CollectionProperties::<T>::try_mutate(collection_id, |properties| {1002 properties.try_scoped_set(scope, property.key, property.value)1003 })1004 .map_err(<Error<T>>::from)?;10051006 Ok(())1007 }10081009 /// Set scouped collection properties.1010 ///1011 /// * `collection_id` - ID of the collection for which the properties is being set.1012 /// * `scope` - Property scope.1013 /// * `properties` - The properties to set.1014 pub fn set_scoped_collection_properties(1015 collection_id: CollectionId,1016 scope: PropertyScope,1017 properties: impl Iterator<Item = Property>,1018 ) -> DispatchResult {1019 CollectionProperties::<T>::try_mutate(collection_id, |stored_properties| {1020 stored_properties.try_scoped_set_from_iter(scope, properties)1021 })1022 .map_err(<Error<T>>::from)?;10231024 Ok(())1025 }10261027 /// Set collection properties.1028 ///1029 /// * `collection` - Collection handler.1030 /// * `sender` - The owner or administrator of the collection.1031 /// * `properties` - The properties to set.1032 #[transactional]1033 pub fn set_collection_properties(1034 collection: &CollectionHandle<T>,1035 sender: &T::CrossAccountId,1036 properties: Vec<Property>,1037 ) -> DispatchResult {1038 for property in properties {1039 Self::set_collection_property(collection, sender, property)?;1040 }10411042 Ok(())1043 }10441045 /// Delete collection property.1046 ///1047 /// * `collection` - Collection handler.1048 /// * `sender` - The owner or administrator of the collection.1049 /// * `property` - The property to delete.1050 pub fn delete_collection_property(1051 collection: &CollectionHandle<T>,1052 sender: &T::CrossAccountId,1053 property_key: PropertyKey,1054 ) -> DispatchResult {1055 collection.check_is_owner_or_admin(sender)?;10561057 CollectionProperties::<T>::try_mutate(collection.id, |properties| {1058 properties.remove(&property_key)1059 })1060 .map_err(<Error<T>>::from)?;10611062 Self::deposit_event(Event::CollectionPropertyDeleted(1063 collection.id,1064 property_key,1065 ));10661067 Ok(())1068 }10691070 /// Delete collection properties.1071 ///1072 /// * `collection` - Collection handler.1073 /// * `sender` - The owner or administrator of the collection.1074 /// * `properties` - The properties to delete.1075 #[transactional]1076 pub fn delete_collection_properties(1077 collection: &CollectionHandle<T>,1078 sender: &T::CrossAccountId,1079 property_keys: Vec<PropertyKey>,1080 ) -> DispatchResult {1081 for key in property_keys {1082 Self::delete_collection_property(collection, sender, key)?;1083 }10841085 Ok(())1086 }10871088 /// Set collection propetry permission without any checks.1089 ///1090 /// Used for migrations.1091 ///1092 /// * `collection` - Collection handler.1093 /// * `property_permissions` - Property permissions.1094 pub fn set_property_permission_unchecked(1095 collection: CollectionId,1096 property_permission: PropertyKeyPermission,1097 ) -> DispatchResult {1098 <CollectionPropertyPermissions<T>>::try_mutate(collection, |permissions| {1099 permissions.try_set(property_permission.key, property_permission.permission)1100 })1101 .map_err(<Error<T>>::from)?;1102 Ok(())1103 }11041105 /// Set collection property permission.1106 ///1107 /// * `collection` - Collection handler.1108 /// * `sender` - The owner or administrator of the collection.1109 /// * `property_permission` - Property permission.1110 pub fn set_property_permission(1111 collection: &CollectionHandle<T>,1112 sender: &T::CrossAccountId,1113 property_permission: PropertyKeyPermission,1114 ) -> DispatchResult {1115 collection.check_is_owner_or_admin(sender)?;11161117 let all_permissions = CollectionPropertyPermissions::<T>::get(collection.id);1118 let current_permission = all_permissions.get(&property_permission.key);1119 if matches![1120 current_permission,1121 Some(PropertyPermission { mutable: false, .. })1122 ] {1123 return Err(<Error<T>>::NoPermission.into());1124 }11251126 CollectionPropertyPermissions::<T>::try_mutate(collection.id, |permissions| {1127 let property_permission = property_permission.clone();1128 permissions.try_set(property_permission.key, property_permission.permission)1129 })1130 .map_err(<Error<T>>::from)?;11311132 Self::deposit_event(Event::PropertyPermissionSet(1133 collection.id,1134 property_permission.key,1135 ));11361137 Ok(())1138 }11391140 /// Set token property permission.1141 ///1142 /// * `collection` - Collection handler.1143 /// * `sender` - The owner or administrator of the collection.1144 /// * `property_permissions` - Property permissions.1145 #[transactional]1146 pub fn set_token_property_permissions(1147 collection: &CollectionHandle<T>,1148 sender: &T::CrossAccountId,1149 property_permissions: Vec<PropertyKeyPermission>,1150 ) -> DispatchResult {1151 for prop_pemission in property_permissions {1152 Self::set_property_permission(collection, sender, prop_pemission)?;1153 }11541155 Ok(())1156 }11571158 /// Get collection property.1159 pub fn get_collection_property(1160 collection_id: CollectionId,1161 key: &PropertyKey,1162 ) -> Option<PropertyValue> {1163 Self::collection_properties(collection_id).get(key).cloned()1164 }11651166 /// Convert byte vector to property key vector.1167 pub fn bytes_keys_to_property_keys(1168 keys: Vec<Vec<u8>>,1169 ) -> Result<Vec<PropertyKey>, DispatchError> {1170 keys.into_iter()1171 .map(|key| -> Result<PropertyKey, DispatchError> {1172 key.try_into()1173 .map_err(|_| <Error<T>>::PropertyKeyIsTooLong.into())1174 })1175 .collect::<Result<Vec<PropertyKey>, DispatchError>>()1176 }11771178 /// Get properties according to given keys.1179 pub fn filter_collection_properties(1180 collection_id: CollectionId,1181 keys: Option<Vec<PropertyKey>>,1182 ) -> Result<Vec<Property>, DispatchError> {1183 let properties = Self::collection_properties(collection_id);11841185 let properties = keys1186 .map(|keys| {1187 keys.into_iter()1188 .filter_map(|key| {1189 properties.get(&key).map(|value| Property {1190 key,1191 value: value.clone(),1192 })1193 })1194 .collect()1195 })1196 .unwrap_or_else(|| {1197 properties1198 .into_iter()1199 .map(|(key, value)| Property { key, value })1200 .collect()1201 });12021203 Ok(properties)1204 }12051206 /// Get property permissions according to given keys.1207 pub fn filter_property_permissions(1208 collection_id: CollectionId,1209 keys: Option<Vec<PropertyKey>>,1210 ) -> Result<Vec<PropertyKeyPermission>, DispatchError> {1211 let permissions = Self::property_permissions(collection_id);12121213 let key_permissions = keys1214 .map(|keys| {1215 keys.into_iter()1216 .filter_map(|key| {1217 permissions1218 .get(&key)1219 .map(|permission| PropertyKeyPermission {1220 key,1221 permission: permission.clone(),1222 })1223 })1224 .collect()1225 })1226 .unwrap_or_else(|| {1227 permissions1228 .into_iter()1229 .map(|(key, permission)| PropertyKeyPermission { key, permission })1230 .collect()1231 });12321233 Ok(key_permissions)1234 }12351236 /// Toggle `user` participation in the `collection`'s allow list.1237 pub fn toggle_allowlist(1238 collection: &CollectionHandle<T>,1239 sender: &T::CrossAccountId,1240 user: &T::CrossAccountId,1241 allowed: bool,1242 ) -> DispatchResult {1243 collection.check_is_owner_or_admin(sender)?;12441245 // =========12461247 if allowed {1248 <Allowlist<T>>::insert((collection.id, user), true);1249 } else {1250 <Allowlist<T>>::remove((collection.id, user));1251 }12521253 Ok(())1254 }12551256 /// Toggle `user` participation in the `collection`'s admin list.1257 pub fn toggle_admin(1258 collection: &CollectionHandle<T>,1259 sender: &T::CrossAccountId,1260 user: &T::CrossAccountId,1261 admin: bool,1262 ) -> DispatchResult {1263 collection.check_is_owner(sender)?;12641265 let was_admin = <IsAdmin<T>>::get((collection.id, user));1266 if was_admin == admin {1267 return Ok(());1268 }1269 let amount = <AdminAmount<T>>::get(collection.id);12701271 if admin {1272 let amount = amount1273 .checked_add(1)1274 .ok_or(<Error<T>>::CollectionAdminCountExceeded)?;1275 ensure!(1276 amount <= Self::collection_admins_limit(),1277 <Error<T>>::CollectionAdminCountExceeded,1278 );12791280 // =========12811282 <AdminAmount<T>>::insert(collection.id, amount);1283 <IsAdmin<T>>::insert((collection.id, user), true);1284 } else {1285 <AdminAmount<T>>::insert(collection.id, amount.saturating_sub(1));1286 <IsAdmin<T>>::remove((collection.id, user));1287 }12881289 Ok(())1290 }12911292 /// Merge set fields from `new_limit` to `old_limit`.1293 pub fn clamp_limits(1294 mode: CollectionMode,1295 old_limit: &CollectionLimits,1296 mut new_limit: CollectionLimits,1297 ) -> Result<CollectionLimits, DispatchError> {1298 let limits = old_limit;1299 limit_default!(old_limit, new_limit,1300 account_token_ownership_limit => ensure!(1301 new_limit <= MAX_TOKEN_OWNERSHIP,1302 <Error<T>>::CollectionLimitBoundsExceeded,1303 ),1304 sponsored_data_size => ensure!(1305 new_limit <= CUSTOM_DATA_LIMIT,1306 <Error<T>>::CollectionLimitBoundsExceeded,1307 ),13081309 sponsored_data_rate_limit => {},1310 token_limit => ensure!(1311 old_limit >= new_limit && new_limit > 0,1312 <Error<T>>::CollectionTokenLimitExceeded1313 ),13141315 sponsor_transfer_timeout(match mode {1316 CollectionMode::NFT => NFT_SPONSOR_TRANSFER_TIMEOUT,1317 CollectionMode::Fungible(_) => FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,1318 CollectionMode::ReFungible => REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,1319 }) => ensure!(1320 new_limit <= MAX_SPONSOR_TIMEOUT,1321 <Error<T>>::CollectionLimitBoundsExceeded,1322 ),1323 sponsor_approve_timeout => {},1324 owner_can_transfer => ensure!(1325 !limits.owner_can_transfer_instaled() ||1326 old_limit || !new_limit,1327 <Error<T>>::OwnerPermissionsCantBeReverted,1328 ),1329 owner_can_destroy => ensure!(1330 old_limit || !new_limit,1331 <Error<T>>::OwnerPermissionsCantBeReverted,1332 ),1333 transfers_enabled => {},1334 );1335 Ok(new_limit)1336 }13371338 /// Merge set fields from `new_permission` to `old_permission`.1339 pub fn clamp_permissions(1340 _mode: CollectionMode,1341 old_permission: &CollectionPermissions,1342 mut new_permission: CollectionPermissions,1343 ) -> Result<CollectionPermissions, DispatchError> {1344 limit_default_clone!(old_permission, new_permission,1345 access => {},1346 mint_mode => {},1347 nesting => { /* todo check for permissive, if only it gets out of benchmarks */ },1348 );1349 Ok(new_permission)1350 }1351}13521353/// Indicates unsupported methods by returning [Error::UnsupportedOperation].1354#[macro_export]1355macro_rules! unsupported {1356 () => {1357 Err(<Error<T>>::UnsupportedOperation.into())1358 };1359}13601361/// Return weights for various worst-case operations.1362pub trait CommonWeightInfo<CrossAccountId> {1363 /// Weight of item creation.1364 fn create_item() -> Weight;13651366 /// Weight of items creation.1367 fn create_multiple_items(amount: &[CreateItemData]) -> Weight;13681369 /// Weight of items creation.1370 fn create_multiple_items_ex(cost: &CreateItemExData<CrossAccountId>) -> Weight;13711372 /// The weight of the burning item.1373 fn burn_item() -> Weight;13741375 /// Property setting weight.1376 ///1377 /// * `amount`- The number of properties to set.1378 fn set_collection_properties(amount: u32) -> Weight;13791380 /// Collection property deletion weight.1381 ///1382 /// * `amount`- The number of properties to set.1383 fn delete_collection_properties(amount: u32) -> Weight;13841385 /// Token property setting weight.1386 ///1387 /// * `amount`- The number of properties to set.1388 fn set_token_properties(amount: u32) -> Weight;13891390 /// Token property deletion weight.1391 ///1392 /// * `amount`- The number of properties to delete.1393 fn delete_token_properties(amount: u32) -> Weight;13941395 /// Token property permissions set weight.1396 ///1397 /// * `amount`- The number of property permissions to set.1398 fn set_token_property_permissions(amount: u32) -> Weight;13991400 /// Transfer price of the token or its parts.1401 fn transfer() -> Weight;14021403 /// The price of setting the permission of the operation from another user.1404 fn approve() -> Weight;14051406 /// Transfer price from another user.1407 fn transfer_from() -> Weight;14081409 /// The price of burning a token from another user.1410 fn burn_from() -> Weight;14111412 /// Differs from burn_item in case of Fungible and Refungible, as it should burn1413 /// whole users's balance.1414 ///1415 /// This method shouldn't be used directly, as it doesn't count breadth price, use [burn_recursively](CommonWeightInfo::burn_recursively) instead1416 fn burn_recursively_self_raw() -> Weight;14171418 /// Cost of iterating over `amount` children while burning, without counting child burning itself.1419 ///1420 /// This method shouldn't be used directly, as it doesn't count depth price, use [burn_recursively](CommonWeightInfo::burn_recursively) instead1421 fn burn_recursively_breadth_raw(amount: u32) -> Weight;14221423 /// The price of recursive burning a token.1424 ///1425 /// `max_selfs` - The maximum burning weight of the token itself.1426 /// `max_breadth` - The maximum number of nested tokens to burn.1427 fn burn_recursively(max_selfs: u32, max_breadth: u32) -> Weight {1428 Self::burn_recursively_self_raw()1429 .saturating_mul(max_selfs.max(1) as u64)1430 .saturating_add(Self::burn_recursively_breadth_raw(max_breadth))1431 }1432}14331434/// Weight info extension trait for refungible pallet.1435pub trait RefungibleExtensionsWeightInfo {1436 /// Weight of token repartition.1437 fn repartition() -> Weight;1438}14391440/// Common collection operations.1441///1442/// It wraps methods in Fungible, Nonfungible and Refungible pallets1443/// and adds weight info.1444pub trait CommonCollectionOperations<T: Config> {1445 /// Create token.1446 ///1447 /// * `sender` - The user who mint the token and pays for the transaction.1448 /// * `to` - The user who will own the token.1449 /// * `data` - Token data.1450 /// * `nesting_budget` - A budget that can be spent on nesting tokens.1451 fn create_item(1452 &self,1453 sender: T::CrossAccountId,1454 to: T::CrossAccountId,1455 data: CreateItemData,1456 nesting_budget: &dyn Budget,1457 ) -> DispatchResultWithPostInfo;14581459 /// Create multiple tokens.1460 ///1461 /// * `sender` - The user who mint the token and pays for the transaction.1462 /// * `to` - The user who will own the token.1463 /// * `data` - Token data.1464 /// * `nesting_budget` - A budget that can be spent on nesting tokens.1465 fn create_multiple_items(1466 &self,1467 sender: T::CrossAccountId,1468 to: T::CrossAccountId,1469 data: Vec<CreateItemData>,1470 nesting_budget: &dyn Budget,1471 ) -> DispatchResultWithPostInfo;14721473 /// Create multiple tokens.1474 ///1475 /// * `sender` - The user who mint the token and pays for the transaction.1476 /// * `to` - The user who will own the token.1477 /// * `data` - Token data.1478 /// * `nesting_budget` - A budget that can be spent on nesting tokens.1479 fn create_multiple_items_ex(1480 &self,1481 sender: T::CrossAccountId,1482 data: CreateItemExData<T::CrossAccountId>,1483 nesting_budget: &dyn Budget,1484 ) -> DispatchResultWithPostInfo;14851486 /// Burn token.1487 ///1488 /// * `sender` - The user who owns the token.1489 /// * `token` - Token id that will burned.1490 /// * `amount` - The number of parts of the token that will be burned.1491 fn burn_item(1492 &self,1493 sender: T::CrossAccountId,1494 token: TokenId,1495 amount: u128,1496 ) -> DispatchResultWithPostInfo;14971498 /// Burn token and all nested tokens recursievly.1499 ///1500 /// * `sender` - The user who owns the token.1501 /// * `token` - Token id that will burned.1502 /// * `self_budget` - The budget that can be spent on burning tokens.1503 /// * `breadth_budget` - The budget that can be spent on burning nested tokens.1504 fn burn_item_recursively(1505 &self,1506 sender: T::CrossAccountId,1507 token: TokenId,1508 self_budget: &dyn Budget,1509 breadth_budget: &dyn Budget,1510 ) -> DispatchResultWithPostInfo;15111512 /// Set collection properties.1513 ///1514 /// * `sender` - Must be either the owner of the collection or its admin.1515 /// * `properties` - Properties to be set.1516 fn set_collection_properties(1517 &self,1518 sender: T::CrossAccountId,1519 properties: Vec<Property>,1520 ) -> DispatchResultWithPostInfo;15211522 /// Delete collection properties.1523 ///1524 /// * `sender` - Must be either the owner of the collection or its admin.1525 /// * `properties` - The properties to be removed.1526 fn delete_collection_properties(1527 &self,1528 sender: &T::CrossAccountId,1529 property_keys: Vec<PropertyKey>,1530 ) -> DispatchResultWithPostInfo;15311532 /// Set token properties.1533 ///1534 /// The appropriate [`PropertyPermission`] for the token property1535 /// must be set with [`Self::set_token_property_permissions`].1536 ///1537 /// * `sender` - Must be either the owner of the token or its admin.1538 /// * `token_id` - The token for which the properties are being set.1539 /// * `properties` - Properties to be set.1540 /// * `budget` - Budget for setting properties.1541 fn set_token_properties(1542 &self,1543 sender: T::CrossAccountId,1544 token_id: TokenId,1545 properties: Vec<Property>,1546 budget: &dyn Budget,1547 ) -> DispatchResultWithPostInfo;15481549 /// Remove token properties.1550 ///1551 /// The appropriate [`PropertyPermission`] for the token property1552 /// must be set with [`Self::set_token_property_permissions`].1553 ///1554 /// * `sender` - Must be either the owner of the token or its admin.1555 /// * `token_id` - The token for which the properties are being remove.1556 /// * `property_keys` - Keys to remove corresponding properties.1557 /// * `budget` - Budget for removing properties.1558 fn delete_token_properties(1559 &self,1560 sender: T::CrossAccountId,1561 token_id: TokenId,1562 property_keys: Vec<PropertyKey>,1563 budget: &dyn Budget,1564 ) -> DispatchResultWithPostInfo;15651566 /// Set token property permissions.1567 ///1568 /// * `sender` - Must be either the owner of the token or its admin.1569 /// * `token_id` - The token for which the properties are being set.1570 /// * `properties` - Properties to be set.1571 /// * `budget` - Budget for setting properties.1572 fn set_token_property_permissions(1573 &self,1574 sender: &T::CrossAccountId,1575 property_permissions: Vec<PropertyKeyPermission>,1576 ) -> DispatchResultWithPostInfo;15771578 /// Transfer amount of token pieces.1579 ///1580 /// * `sender` - Donor user.1581 /// * `to` - Recepient user.1582 /// * `token` - The token of which parts are being sent.1583 /// * `amount` - The number of parts of the token that will be transferred.1584 /// * `budget` - The maximum budget that can be spent on the transfer.1585 fn transfer(1586 &self,1587 sender: T::CrossAccountId,1588 to: T::CrossAccountId,1589 token: TokenId,1590 amount: u128,1591 budget: &dyn Budget,1592 ) -> DispatchResultWithPostInfo;15931594 /// Grant access to another account to transfer parts of the token owned by the calling user via [Self::transfer_from].1595 ///1596 /// * `sender` - The user who grants access to the token.1597 /// * `spender` - The user to whom the rights are granted.1598 /// * `token` - The token to which access is granted.1599 /// * `amount` - The amount of pieces that another user can dispose of.1600 fn approve(1601 &self,1602 sender: T::CrossAccountId,1603 spender: T::CrossAccountId,1604 token: TokenId,1605 amount: u128,1606 ) -> DispatchResultWithPostInfo;16071608 /// Send parts of a token owned by another user.1609 ///1610 /// Before calling this method, you must grant rights to the calling user via [`Self::approve`].1611 ///1612 /// * `sender` - The user who must have access to the token (see [`Self::approve`]).1613 /// * `from` - The user who owns the token.1614 /// * `to` - Recepient user.1615 /// * `token` - The token of which parts are being sent.1616 /// * `amount` - The number of parts of the token that will be transferred.1617 /// * `budget` - The maximum budget that can be spent on the transfer.1618 fn transfer_from(1619 &self,1620 sender: T::CrossAccountId,1621 from: T::CrossAccountId,1622 to: T::CrossAccountId,1623 token: TokenId,1624 amount: u128,1625 budget: &dyn Budget,1626 ) -> DispatchResultWithPostInfo;16271628 /// Burn parts of a token owned by another user.1629 ///1630 /// Before calling this method, you must grant rights to the calling user via [`Self::approve`].1631 ///1632 /// * `sender` - The user who must have access to the token (see [`Self::approve`]).1633 /// * `from` - The user who owns the token.1634 /// * `token` - The token of which parts are being sent.1635 /// * `amount` - The number of parts of the token that will be transferred.1636 /// * `budget` - The maximum budget that can be spent on the burn.1637 fn burn_from(1638 &self,1639 sender: T::CrossAccountId,1640 from: T::CrossAccountId,1641 token: TokenId,1642 amount: u128,1643 budget: &dyn Budget,1644 ) -> DispatchResultWithPostInfo;16451646 /// Check permission to nest token.1647 ///1648 /// * `sender` - The user who initiated the check.1649 /// * `from` - The token that is checked for embedding.1650 /// * `under` - Token under which to check.1651 /// * `budget` - The maximum budget that can be spent on the check.1652 fn check_nesting(1653 &self,1654 sender: T::CrossAccountId,1655 from: (CollectionId, TokenId),1656 under: TokenId,1657 budget: &dyn Budget,1658 ) -> DispatchResult;16591660 /// Nest one token into another.1661 ///1662 /// * `under` - Token holder.1663 /// * `to_nest` - Nested token.1664 fn nest(&self, under: TokenId, to_nest: (CollectionId, TokenId));16651666 /// Unnest token.1667 ///1668 /// * `under` - Token holder.1669 /// * `to_nest` - Token to unnest.1670 fn unnest(&self, under: TokenId, to_nest: (CollectionId, TokenId));16711672 /// Get all user tokens.1673 ///1674 /// * `account` - Account for which you need to get tokens.1675 fn account_tokens(&self, account: T::CrossAccountId) -> Vec<TokenId>;16761677 /// Get all the tokens in the collection.1678 fn collection_tokens(&self) -> Vec<TokenId>;16791680 /// Check if the token exists.1681 ///1682 /// * `token` - Id token to check.1683 fn token_exists(&self, token: TokenId) -> bool;16841685 /// Get the id of the last minted token.1686 fn last_token_id(&self) -> TokenId;16871688 /// Get the owner of the token.1689 ///1690 /// * `token` - The token for which you need to find out the owner.1691 fn token_owner(&self, token: TokenId) -> Option<T::CrossAccountId>;16921693 /// Returns 10 tokens owners in no particular order.1694 ///1695 /// * `token` - The token for which you need to find out the owners.1696 fn token_owners(&self, token: TokenId) -> Vec<T::CrossAccountId>;16971698 /// Get the value of the token property by key.1699 ///1700 /// * `token` - Token with the property to get.1701 /// * `key` - Property name.1702 fn token_property(&self, token_id: TokenId, key: &PropertyKey) -> Option<PropertyValue>;17031704 /// Get a set of token properties by key vector.1705 ///1706 /// * `token` - Token with the property to get.1707 /// * `keys` - Vector of property keys. If this parameter is [None](sp_std::result::Result),1708 /// then all properties are returned.1709 fn token_properties(&self, token: TokenId, keys: Option<Vec<PropertyKey>>) -> Vec<Property>;17101711 /// Amount of unique collection tokens1712 fn total_supply(&self) -> u32;17131714 /// Amount of different tokens account has.1715 ///1716 /// * `account` - The account for which need to get the balance.1717 fn account_balance(&self, account: T::CrossAccountId) -> u32;17181719 /// Amount of specific token account have.1720 fn balance(&self, account: T::CrossAccountId, token: TokenId) -> u128;17211722 /// Amount of token pieces1723 fn total_pieces(&self, token: TokenId) -> Option<u128>;17241725 /// Get the number of parts of the token that a trusted user can manage.1726 ///1727 /// * `sender` - Trusted user.1728 /// * `spender` - Owner of the token.1729 /// * `token` - The token for which to get the value.1730 fn allowance(1731 &self,1732 sender: T::CrossAccountId,1733 spender: T::CrossAccountId,1734 token: TokenId,1735 ) -> u128;17361737 /// Get extension for RFT collection.1738 fn refungible_extensions(&self) -> Option<&dyn RefungibleExtensions<T>>;1739}17401741/// Extension for RFT collection.1742pub trait RefungibleExtensions<T>1743where1744 T: Config,1745{1746 /// Change the number of parts of the token.1747 ///1748 /// When the value changes down, this function is equivalent to burning parts of the token.1749 ///1750 /// * `sender` - The user calling the repartition operation. Must be the owner of the token.1751 /// * `token` - The token for which you want to change the number of parts.1752 /// * `amount` - The new value of the parts of the token.1753 fn repartition(1754 &self,1755 sender: &T::CrossAccountId,1756 token: TokenId,1757 amount: u128,1758 ) -> DispatchResultWithPostInfo;1759}17601761/// Merge [`DispatchResult`] with [`Weight`] into [`DispatchResultWithPostInfo`].1762///1763/// Used for [`CommonCollectionOperations`] implementations and flexible enough to do so.1764pub fn with_weight(res: DispatchResult, weight: Weight) -> DispatchResultWithPostInfo {1765 let post_info = PostDispatchInfo {1766 actual_weight: Some(weight),1767 pays_fee: Pays::Yes,1768 };1769 match res {1770 Ok(()) => Ok(post_info),1771 Err(error) => Err(DispatchErrorWithPostInfo { post_info, error }),1772 }1773}17741775impl<T: Config> From<PropertiesError> for Error<T> {1776 fn from(error: PropertiesError) -> Self {1777 match error {1778 PropertiesError::NoSpaceForProperty => Self::NoSpaceForProperty,1779 PropertiesError::PropertyLimitReached => Self::PropertyLimitReached,1780 PropertiesError::InvalidCharacterInPropertyKey => Self::InvalidCharacterInPropertyKey,1781 PropertiesError::PropertyKeyIsTooLong => Self::PropertyKeyIsTooLong,1782 PropertiesError::EmptyPropertyKey => Self::EmptyPropertyKey,1783 }1784 }1785}1// 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//! # Common pallet18//!19//! The Common pallet provides functionality for handling collections.20//!21//! ## Overview22//!23//! The Common pallet provides an interface for common collection operations for different collection types24//! (see [CommonCollectionOperations]), as well as a generic dispatcher for these, see [dispatch] module.25//! It also provides this functionality to EVM, see [erc] and [eth] modules.26//!27//! The Common pallet provides functions for:28//!29//! - Setting and approving collection sponsor.30//! - Get\set\delete allow list.31//! - Get\set\delete collection properties.32//! - Get\set\delete collection property permissions.33//! - Get\set\delete token property permissions.34//! - Get\set\delete collection administrators.35//! - Checking access permissions.36//!37//! ### Terminology38//! **Collection sponsor** - For the collection, you can set a sponsor, at whose expense it will39//! be possible to mint tokens.40//!41//! **Allow list** - List of users who have the right to minting tokens.42//!43//! **Collection properties** - Collection properties are simply key-value stores where various44//! metadata can be placed.45//!46//! **Permissions on token properties** - For each property in the token can be set permission47//! to change, see [`PropertyPermission`].48//!49//! **Collection administrator** - For a collection, you can set administrators who have the right50//! to most actions on the collection.5152#![warn(missing_docs)]53#![cfg_attr(not(feature = "std"), no_std)]54extern crate alloc;5556use core::ops::{Deref, DerefMut};57use pallet_evm_coder_substrate::{SubstrateRecorder, WithRecorder};58use sp_std::vec::Vec;59use pallet_evm::{account::CrossAccountId, Pallet as PalletEvm};60use evm_coder::ToLog;61use frame_support::{62 dispatch::{DispatchErrorWithPostInfo, DispatchResultWithPostInfo, Weight, PostDispatchInfo},63 ensure,64 traits::{Imbalance, Get, Currency, WithdrawReasons, ExistenceRequirement},65 weights::Pays,66 transactional,67};68use pallet_evm::GasWeightMapping;69use up_data_structs::{70 COLLECTION_NUMBER_LIMIT,71 Collection,72 RpcCollection,73 CollectionId,74 CreateItemData,75 MAX_TOKEN_PREFIX_LENGTH,76 COLLECTION_ADMINS_LIMIT,77 TokenId,78 TokenChild,79 CollectionStats,80 MAX_TOKEN_OWNERSHIP,81 CollectionMode,82 NFT_SPONSOR_TRANSFER_TIMEOUT,83 FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,84 REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,85 MAX_SPONSOR_TIMEOUT,86 CUSTOM_DATA_LIMIT,87 CollectionLimits,88 CreateCollectionData,89 SponsorshipState,90 CreateItemExData,91 SponsoringRateLimit,92 budget::Budget,93 PhantomType,94 Property,95 Properties,96 PropertiesPermissionMap,97 PropertyKey,98 PropertyValue,99 PropertyPermission,100 PropertiesError,101 PropertyKeyPermission,102 TokenData,103 TrySetProperty,104 PropertyScope,105 // RMRK106 RmrkCollectionInfo,107 RmrkInstanceInfo,108 RmrkResourceInfo,109 RmrkPropertyInfo,110 RmrkBaseInfo,111 RmrkPartType,112 RmrkBoundedTheme,113 RmrkNftChild,114 CollectionPermissions,115 SchemaVersion,116};117118pub use pallet::*;119use sp_core::H160;120use sp_runtime::{ArithmeticError, DispatchError, DispatchResult};121#[cfg(feature = "runtime-benchmarks")]122pub mod benchmarking;123pub mod dispatch;124pub mod erc;125pub mod eth;126pub mod weights;127128/// Weight info.129pub type SelfWeightOf<T> = <T as Config>::WeightInfo;130131/// Collection handle contains information about collection data and id.132/// Also provides functionality to count consumed gas.133///134/// CollectionHandle is used as a generic wrapper for collections of all types.135/// It allows to perform common operations and queries on any collection type,136/// both completely general for all, as well as their respective implementations of [`CommonCollectionOperations`].137#[must_use = "Should call submit_logs or save, otherwise some data will be lost for evm side"]138pub struct CollectionHandle<T: Config> {139 /// Collection id140 pub id: CollectionId,141 collection: Collection<T::AccountId>,142 /// Substrate recorder for counting consumed gas143 pub recorder: SubstrateRecorder<T>,144}145146impl<T: Config> WithRecorder<T> for CollectionHandle<T> {147 fn recorder(&self) -> &SubstrateRecorder<T> {148 &self.recorder149 }150 fn into_recorder(self) -> SubstrateRecorder<T> {151 self.recorder152 }153}154155impl<T: Config> CollectionHandle<T> {156 /// Same as [CollectionHandle::new] but with an explicit gas limit.157 pub fn new_with_gas_limit(id: CollectionId, gas_limit: u64) -> Option<Self> {158 <CollectionById<T>>::get(id).map(|collection| Self {159 id,160 collection,161 recorder: SubstrateRecorder::new(gas_limit),162 })163 }164165 /// Same as [CollectionHandle::new] but with an existed [`SubstrateRecorder`].166 pub fn new_with_recorder(id: CollectionId, recorder: SubstrateRecorder<T>) -> Option<Self> {167 <CollectionById<T>>::get(id).map(|collection| Self {168 id,169 collection,170 recorder,171 })172 }173174 /// Retrives collection data from storage and creates collection handle with default parameters.175 /// If collection not found return `None`176 pub fn new(id: CollectionId) -> Option<Self> {177 Self::new_with_gas_limit(id, u64::MAX)178 }179180 /// Same as [`CollectionHandle::new`] but if collection not found [CollectionNotFound](Error::CollectionNotFound) returned.181 pub fn try_get(id: CollectionId) -> Result<Self, DispatchError> {182 Ok(Self::new(id).ok_or(<Error<T>>::CollectionNotFound)?)183 }184185 /// Consume gas for reading.186 pub fn consume_store_reads(&self, reads: u64) -> evm_coder::execution::Result<()> {187 self.recorder188 .consume_gas(T::GasWeightMapping::weight_to_gas(189 <T as frame_system::Config>::DbWeight::get()190 .read191 .saturating_mul(reads),192 ))193 }194195 /// Consume gas for writing.196 pub fn consume_store_writes(&self, writes: u64) -> evm_coder::execution::Result<()> {197 self.recorder198 .consume_gas(T::GasWeightMapping::weight_to_gas(199 <T as frame_system::Config>::DbWeight::get()200 .write201 .saturating_mul(writes),202 ))203 }204205 /// Save collection to storage.206 pub fn save(self) -> DispatchResult {207 <CollectionById<T>>::insert(self.id, self.collection);208 Ok(())209 }210211 /// Set collection sponsor.212 ///213 /// Unique collections allows sponsoring for certain actions.214 /// This method allows you to set the sponsor of the collection.215 /// In order for sponsorship to become active, it must be confirmed through [`Self::confirm_sponsorship`].216 pub fn set_sponsor(&mut self, sponsor: T::AccountId) -> DispatchResult {217 self.collection.sponsorship = SponsorshipState::Unconfirmed(sponsor);218 Ok(())219 }220221 /// Confirm sponsorship222 ///223 /// In order for the sponsorship to become active, the user set as the sponsor must confirm their participation.224 /// Before confirming sponsorship, the user must be specified as the sponsor of the collection via [`Self::set_sponsor`].225 pub fn confirm_sponsorship(&mut self, sender: &T::AccountId) -> Result<bool, DispatchError> {226 if self.collection.sponsorship.pending_sponsor() != Some(sender) {227 return Ok(false);228 }229230 self.collection.sponsorship = SponsorshipState::Confirmed(sender.clone());231 Ok(true)232 }233234 /// Checks that the collection was created with, and must be operated upon through **Unique API**.235 /// Now check only the `external_collection` flag and if it's **true**, then return [`Error::CollectionIsExternal`] error.236 pub fn check_is_internal(&self) -> DispatchResult {237 if self.external_collection {238 return Err(<Error<T>>::CollectionIsExternal)?;239 }240241 Ok(())242 }243244 /// Checks that the collection was created with, and must be operated upon through an **assimilated API**.245 /// Now check only the `external_collection` flag and if it's **false**, then return [`Error::CollectionIsInternal`] error.246 pub fn check_is_external(&self) -> DispatchResult {247 if !self.external_collection {248 return Err(<Error<T>>::CollectionIsInternal)?;249 }250251 Ok(())252 }253}254255impl<T: Config> Deref for CollectionHandle<T> {256 type Target = Collection<T::AccountId>;257258 fn deref(&self) -> &Self::Target {259 &self.collection260 }261}262263impl<T: Config> DerefMut for CollectionHandle<T> {264 fn deref_mut(&mut self) -> &mut Self::Target {265 &mut self.collection266 }267}268269impl<T: Config> CollectionHandle<T> {270 /// Checks if the `user` is the owner of the collection.271 pub fn check_is_owner(&self, user: &T::CrossAccountId) -> DispatchResult {272 ensure!(*user.as_sub() == self.owner, <Error<T>>::NoPermission);273 Ok(())274 }275276 /// Returns **true** if the `user` is the owner or administrator of the collection.277 pub fn is_owner_or_admin(&self, user: &T::CrossAccountId) -> bool {278 *user.as_sub() == self.owner || <IsAdmin<T>>::get((self.id, user))279 }280281 /// Checks if the `user` is the owner or administrator of the collection.282 pub fn check_is_owner_or_admin(&self, user: &T::CrossAccountId) -> DispatchResult {283 ensure!(self.is_owner_or_admin(user), <Error<T>>::NoPermission);284 Ok(())285 }286287 /// Return **true** if `user` was not allowed to have tokens, and he can ignore such restrictions.288 pub fn ignores_allowance(&self, user: &T::CrossAccountId) -> bool {289 self.limits.owner_can_transfer() && self.is_owner_or_admin(user)290 }291292 /// Return **true** if `user` does not have enough token parts, and he can ignore such restrictions.293 pub fn ignores_owned_amount(&self, user: &T::CrossAccountId) -> bool {294 self.limits.owner_can_transfer() && self.is_owner_or_admin(user)295 }296297 /// Checks if the user is in the allow list. If not [Error::AddressNotInAllowlist] returns.298 pub fn check_allowlist(&self, user: &T::CrossAccountId) -> DispatchResult {299 ensure!(300 <Allowlist<T>>::get((self.id, user)),301 <Error<T>>::AddressNotInAllowlist302 );303 Ok(())304 }305}306307#[frame_support::pallet]308pub mod pallet {309 use super::*;310 use pallet_evm::account;311 use dispatch::CollectionDispatch;312 use frame_support::{Blake2_128Concat, pallet_prelude::*, storage::Key, traits::StorageVersion};313 use frame_system::pallet_prelude::*;314 use frame_support::traits::Currency;315 use up_data_structs::{TokenId, mapping::TokenAddressMapping};316 use scale_info::TypeInfo;317 use weights::WeightInfo;318319 #[pallet::config]320 pub trait Config:321 frame_system::Config322 + pallet_evm_coder_substrate::Config323 + pallet_evm::Config324 + TypeInfo325 + account::Config326 {327 /// Weight information for functions of this pallet.328 type WeightInfo: WeightInfo;329330 /// Events compatible with [`frame_system::Config::Event`].331 type Event: IsType<<Self as frame_system::Config>::Event> + From<Event<Self>>;332333 /// Handler of accounts and payment.334 type Currency: Currency<Self::AccountId>;335336 /// Set price to create a collection.337 #[pallet::constant]338 type CollectionCreationPrice: Get<339 <<Self as Config>::Currency as Currency<Self::AccountId>>::Balance,340 >;341342 /// Dispatcher of operations on collections.343 type CollectionDispatch: CollectionDispatch<Self>;344345 /// Account which holds the chain's treasury.346 type TreasuryAccountId: Get<Self::AccountId>;347348 /// Address under which the CollectionHelper contract would be available.349 type ContractAddress: Get<H160>;350351 /// Mapper for token addresses to Ethereum addresses.352 type EvmTokenAddressMapping: TokenAddressMapping<H160>;353354 /// Mapper for token addresses to [`CrossAccountId`].355 type CrossTokenAddressMapping: TokenAddressMapping<Self::CrossAccountId>;356 }357358 const STORAGE_VERSION: StorageVersion = StorageVersion::new(1);359360 #[pallet::pallet]361 #[pallet::storage_version(STORAGE_VERSION)]362 #[pallet::generate_store(pub(super) trait Store)]363 pub struct Pallet<T>(_);364365 #[pallet::extra_constants]366 impl<T: Config> Pallet<T> {367 /// Maximum admins per collection.368 pub fn collection_admins_limit() -> u32 {369 COLLECTION_ADMINS_LIMIT370 }371 }372373 #[pallet::event]374 #[pallet::generate_deposit(pub fn deposit_event)]375 pub enum Event<T: Config> {376 /// New collection was created377 CollectionCreated(378 /// Globally unique identifier of newly created collection.379 CollectionId,380 /// [`CollectionMode`] converted into _u8_.381 u8,382 /// Collection owner.383 T::AccountId,384 ),385386 /// New collection was destroyed387 CollectionDestroyed(388 /// Globally unique identifier of collection.389 CollectionId,390 ),391392 /// New item was created.393 ItemCreated(394 /// Id of the collection where item was created.395 CollectionId,396 /// Id of an item. Unique within the collection.397 TokenId,398 /// Owner of newly created item399 T::CrossAccountId,400 /// Always 1 for NFT401 u128,402 ),403404 /// Collection item was burned.405 ItemDestroyed(406 /// Id of the collection where item was destroyed.407 CollectionId,408 /// Identifier of burned NFT.409 TokenId,410 /// Which user has destroyed its tokens.411 T::CrossAccountId,412 /// Amount of token pieces destroed. Always 1 for NFT.413 u128,414 ),415416 /// Item was transferred417 Transfer(418 /// Id of collection to which item is belong.419 CollectionId,420 /// Id of an item.421 TokenId,422 /// Original owner of item.423 T::CrossAccountId,424 /// New owner of item.425 T::CrossAccountId,426 /// Amount of token pieces transfered. Always 1 for NFT.427 u128,428 ),429430 /// Amount pieces of token owned by `sender` was approved for `spender`.431 Approved(432 /// Id of collection to which item is belong.433 CollectionId,434 /// Id of an item.435 TokenId,436 /// Original owner of item.437 T::CrossAccountId,438 /// Id for which the approval was granted.439 T::CrossAccountId,440 /// Amount of token pieces transfered. Always 1 for NFT.441 u128,442 ),443444 /// The colletion property has been added or edited.445 CollectionPropertySet(446 /// Id of collection to which property has been set.447 CollectionId,448 /// The property that was set.449 PropertyKey,450 ),451452 /// The property has been deleted.453 CollectionPropertyDeleted(454 /// Id of collection to which property has been deleted.455 CollectionId,456 /// The property that was deleted.457 PropertyKey,458 ),459460 /// The token property has been added or edited.461 TokenPropertySet(462 /// Identifier of the collection whose token has the property set.463 CollectionId,464 /// The token for which the property was set.465 TokenId,466 /// The property that was set.467 PropertyKey,468 ),469470 /// The token property has been deleted.471 TokenPropertyDeleted(472 /// Identifier of the collection whose token has the property deleted.473 CollectionId,474 /// The token for which the property was deleted.475 TokenId,476 /// The property that was deleted.477 PropertyKey,478 ),479480 /// The token property permission of a collection has been set.481 PropertyPermissionSet(482 /// ID of collection to which property permission has been set.483 CollectionId,484 /// The property permission that was set.485 PropertyKey,486 ),487 }488489 #[pallet::error]490 pub enum Error<T> {491 /// This collection does not exist.492 CollectionNotFound,493 /// Sender parameter and item owner must be equal.494 MustBeTokenOwner,495 /// No permission to perform action496 NoPermission,497 /// Destroying only empty collections is allowed498 CantDestroyNotEmptyCollection,499 /// Collection is not in mint mode.500 PublicMintingNotAllowed,501 /// Address is not in allow list.502 AddressNotInAllowlist,503504 /// Collection name can not be longer than 63 char.505 CollectionNameLimitExceeded,506 /// Collection description can not be longer than 255 char.507 CollectionDescriptionLimitExceeded,508 /// Token prefix can not be longer than 15 char.509 CollectionTokenPrefixLimitExceeded,510 /// Total collections bound exceeded.511 TotalCollectionsLimitExceeded,512 /// Exceeded max admin count513 CollectionAdminCountExceeded,514 /// Collection limit bounds per collection exceeded515 CollectionLimitBoundsExceeded,516 /// Tried to enable permissions which are only permitted to be disabled517 OwnerPermissionsCantBeReverted,518 /// Collection settings not allowing items transferring519 TransferNotAllowed,520 /// Account token limit exceeded per collection521 AccountTokenLimitExceeded,522 /// Collection token limit exceeded523 CollectionTokenLimitExceeded,524 /// Metadata flag frozen525 MetadataFlagFrozen,526527 /// Item does not exist528 TokenNotFound,529 /// Item is balance not enough530 TokenValueTooLow,531 /// Requested value is more than the approved532 ApprovedValueTooLow,533 /// Tried to approve more than owned534 CantApproveMoreThanOwned,535536 /// Can't transfer tokens to ethereum zero address537 AddressIsZero,538539 /// The oprtation is not supported540 UnsupportedOperation,541542 /// Insufficient funds to perform an action543 NotSufficientFounds,544545 /// User does not satisfy the nesting rule546 UserIsNotAllowedToNest,547 /// Only tokens from specific collections may nest tokens under this one548 SourceCollectionIsNotAllowedToNest,549550 /// Tried to store more data than allowed in collection field551 CollectionFieldSizeExceeded,552553 /// Tried to store more property data than allowed554 NoSpaceForProperty,555556 /// Tried to store more property keys than allowed557 PropertyLimitReached,558559 /// Property key is too long560 PropertyKeyIsTooLong,561562 /// Only ASCII letters, digits, and symbols `_`, `-`, and `.` are allowed563 InvalidCharacterInPropertyKey,564565 /// Empty property keys are forbidden566 EmptyPropertyKey,567568 /// Tried to access an external collection with an internal API569 CollectionIsExternal,570571 /// Tried to access an internal collection with an external API572 CollectionIsInternal,573 }574575 /// Storage of the count of created collections. Essentially contains the last collection ID.576 #[pallet::storage]577 pub type CreatedCollectionCount<T> = StorageValue<Value = CollectionId, QueryKind = ValueQuery>;578579 /// Storage of the count of deleted collections.580 #[pallet::storage]581 pub type DestroyedCollectionCount<T> =582 StorageValue<Value = CollectionId, QueryKind = ValueQuery>;583584 /// Storage of collection info.585 #[pallet::storage]586 pub type CollectionById<T> = StorageMap<587 Hasher = Blake2_128Concat,588 Key = CollectionId,589 Value = Collection<<T as frame_system::Config>::AccountId>,590 QueryKind = OptionQuery,591 >;592593 /// Storage of collection properties.594 #[pallet::storage]595 #[pallet::getter(fn collection_properties)]596 pub type CollectionProperties<T> = StorageMap<597 Hasher = Blake2_128Concat,598 Key = CollectionId,599 Value = Properties,600 QueryKind = ValueQuery,601 OnEmpty = up_data_structs::CollectionProperties,602 >;603604 /// Storage of token property permissions of a collection.605 #[pallet::storage]606 #[pallet::getter(fn property_permissions)]607 pub type CollectionPropertyPermissions<T> = StorageMap<608 Hasher = Blake2_128Concat,609 Key = CollectionId,610 Value = PropertiesPermissionMap,611 QueryKind = ValueQuery,612 >;613614 /// Storage of the amount of collection admins.615 #[pallet::storage]616 pub type AdminAmount<T> = StorageMap<617 Hasher = Blake2_128Concat,618 Key = CollectionId,619 Value = u32,620 QueryKind = ValueQuery,621 >;622623 /// List of collection admins.624 #[pallet::storage]625 pub type IsAdmin<T: Config> = StorageNMap<626 Key = (627 Key<Blake2_128Concat, CollectionId>,628 Key<Blake2_128Concat, T::CrossAccountId>,629 ),630 Value = bool,631 QueryKind = ValueQuery,632 >;633634 /// Allowlisted collection users.635 #[pallet::storage]636 pub type Allowlist<T: Config> = StorageNMap<637 Key = (638 Key<Blake2_128Concat, CollectionId>,639 Key<Blake2_128Concat, T::CrossAccountId>,640 ),641 Value = bool,642 QueryKind = ValueQuery,643 >;644645 /// Not used by code, exists only to provide some types to metadata.646 #[pallet::storage]647 pub type DummyStorageValue<T: Config> = StorageValue<648 Value = (649 CollectionStats,650 CollectionId,651 TokenId,652 TokenChild,653 PhantomType<(654 TokenData<T::CrossAccountId>,655 RpcCollection<T::AccountId>,656 // RMRK657 RmrkCollectionInfo<T::AccountId>,658 RmrkInstanceInfo<T::AccountId>,659 RmrkResourceInfo,660 RmrkPropertyInfo,661 RmrkBaseInfo<T::AccountId>,662 RmrkPartType,663 RmrkBoundedTheme,664 RmrkNftChild,665 )>,666 ),667 QueryKind = OptionQuery,668 >;669670 #[pallet::hooks]671 impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {672 fn on_runtime_upgrade() -> Weight {673 StorageVersion::new(1).put::<Pallet<T>>();674675 0676 }677 }678}679680impl<T: Config> Pallet<T> {681 /// Enshure that receiver address is correct.682 ///683 /// Ethereum receiver 0x0000000000000000000000000000000000000000 is reserved, and shouldn't own tokens.684 pub fn ensure_correct_receiver(receiver: &T::CrossAccountId) -> DispatchResult {685 ensure!(686 &T::CrossAccountId::from_eth(H160([0; 20])) != receiver,687 <Error<T>>::AddressIsZero688 );689 Ok(())690 }691692 /// Get a vector of collection admins.693 pub fn adminlist(collection: CollectionId) -> Vec<T::CrossAccountId> {694 <IsAdmin<T>>::iter_prefix((collection,))695 .map(|(a, _)| a)696 .collect()697 }698699 /// Get a vector of users allowed to mint tokens.700 pub fn allowlist(collection: CollectionId) -> Vec<T::CrossAccountId> {701 <Allowlist<T>>::iter_prefix((collection,))702 .map(|(a, _)| a)703 .collect()704 }705706 /// Is `user` allowed to mint token in `collection`.707 pub fn allowed(collection: CollectionId, user: T::CrossAccountId) -> bool {708 <Allowlist<T>>::get((collection, user))709 }710711 /// Get statistics of collections.712 pub fn collection_stats() -> CollectionStats {713 let created = <CreatedCollectionCount<T>>::get();714 let destroyed = <DestroyedCollectionCount<T>>::get();715 CollectionStats {716 created: created.0,717 destroyed: destroyed.0,718 alive: created.0 - destroyed.0,719 }720 }721722 /// Get the effective limits for the collection.723 pub fn effective_collection_limits(collection: CollectionId) -> Option<CollectionLimits> {724 let collection = <CollectionById<T>>::get(collection);725 if collection.is_none() {726 return None;727 }728729 let collection = collection.unwrap();730 let limits = collection.limits;731 let effective_limits = CollectionLimits {732 account_token_ownership_limit: Some(limits.account_token_ownership_limit()),733 sponsored_data_size: Some(limits.sponsored_data_size()),734 sponsored_data_rate_limit: Some(735 limits736 .sponsored_data_rate_limit737 .unwrap_or(SponsoringRateLimit::SponsoringDisabled),738 ),739 token_limit: Some(limits.token_limit()),740 sponsor_transfer_timeout: Some(limits.sponsor_transfer_timeout(741 match collection.mode {742 CollectionMode::NFT => NFT_SPONSOR_TRANSFER_TIMEOUT,743 CollectionMode::Fungible(_) => FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,744 CollectionMode::ReFungible => REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,745 },746 )),747 sponsor_approve_timeout: Some(limits.sponsor_approve_timeout()),748 owner_can_transfer: Some(limits.owner_can_transfer()),749 owner_can_destroy: Some(limits.owner_can_destroy()),750 transfers_enabled: Some(limits.transfers_enabled()),751 };752753 Some(effective_limits)754 }755756 /// Returns information about the `collection` adapted for rpc.757 pub fn rpc_collection(collection: CollectionId) -> Option<RpcCollection<T::AccountId>> {758 let Collection {759 name,760 description,761 owner,762 mode,763 token_prefix,764 sponsorship,765 limits,766 permissions,767 external_collection,768 } = <CollectionById<T>>::get(collection)?;769770 let token_property_permissions = <CollectionPropertyPermissions<T>>::get(collection)771 .into_iter()772 .map(|(key, permission)| PropertyKeyPermission { key, permission })773 .collect();774775 let properties = <CollectionProperties<T>>::get(collection)776 .into_iter()777 .map(|(key, value)| Property { key, value })778 .collect();779780 let permissions = CollectionPermissions {781 access: Some(permissions.access()),782 mint_mode: Some(permissions.mint_mode()),783 nesting: Some(permissions.nesting().clone()),784 };785786 Some(RpcCollection {787 name: name.into_inner(),788 description: description.into_inner(),789 owner,790 mode,791 token_prefix: token_prefix.into_inner(),792 sponsorship,793 limits,794 permissions,795 token_property_permissions,796 properties,797 read_only: external_collection,798 })799 }800}801802macro_rules! limit_default {803 ($old:ident, $new:ident, $($field:ident $(($arg:expr))? => $check:expr),* $(,)?) => {{804 $(805 if let Some($new) = $new.$field {806 let $old = $old.$field($($arg)?);807 let _ = $new;808 let _ = $old;809 $check810 } else {811 $new.$field = $old.$field812 }813 )*814 }};815}816macro_rules! limit_default_clone {817 ($old:ident, $new:ident, $($field:ident $(($arg:expr))? => $check:expr),* $(,)?) => {{818 $(819 if let Some($new) = $new.$field.clone() {820 let $old = $old.$field($($arg)?);821 let _ = $new;822 let _ = $old;823 $check824 } else {825 $new.$field = $old.$field.clone()826 }827 )*828 }};829}830831impl<T: Config> Pallet<T> {832 /// Create new collection.833 ///834 /// * `owner` - The owner of the collection.835 /// * `data` - Description of the created collection.836 /// * `is_external` - Marks that collection managet by not "Unique network".837 pub fn init_collection(838 owner: T::CrossAccountId,839 data: CreateCollectionData<T::AccountId>,840 is_external: bool,841 ) -> Result<CollectionId, DispatchError> {842 {843 ensure!(844 data.token_prefix.len() <= MAX_TOKEN_PREFIX_LENGTH as usize,845 Error::<T>::CollectionTokenPrefixLimitExceeded846 );847 }848849 let created_count = <CreatedCollectionCount<T>>::get()850 .0851 .checked_add(1)852 .ok_or(ArithmeticError::Overflow)?;853 let destroyed_count = <DestroyedCollectionCount<T>>::get().0;854 let id = CollectionId(created_count);855856 // bound Total number of collections857 ensure!(858 created_count - destroyed_count <= COLLECTION_NUMBER_LIMIT,859 <Error<T>>::TotalCollectionsLimitExceeded860 );861862 // =========863864 let collection = Collection {865 owner: owner.as_sub().clone(),866 name: data.name,867 mode: data.mode.clone(),868 description: data.description,869 token_prefix: data.token_prefix,870 sponsorship: data871 .pending_sponsor872 .map(SponsorshipState::Unconfirmed)873 .unwrap_or_default(),874 limits: data875 .limits876 .map(|limits| Self::clamp_limits(data.mode.clone(), &Default::default(), limits))877 .unwrap_or_else(|| Ok(CollectionLimits::default()))?,878 permissions: data879 .permissions880 .map(|permissions| {881 Self::clamp_permissions(data.mode.clone(), &Default::default(), permissions)882 })883 .unwrap_or_else(|| Ok(CollectionPermissions::default()))?,884 external_collection: is_external,885 };886887 let mut collection_properties = up_data_structs::CollectionProperties::get();888 collection_properties889 .try_set_from_iter(data.properties.into_iter())890 .map_err(<Error<T>>::from)?;891892 CollectionProperties::<T>::insert(id, collection_properties);893894 let mut token_props_permissions = PropertiesPermissionMap::new();895 token_props_permissions896 .try_set_from_iter(data.token_property_permissions.into_iter())897 .map_err(<Error<T>>::from)?;898899 CollectionPropertyPermissions::<T>::insert(id, token_props_permissions);900901 // Take a (non-refundable) deposit of collection creation902 {903 let mut imbalance =904 <<<T as Config>::Currency as Currency<T::AccountId>>::PositiveImbalance>::zero();905 imbalance.subsume(906 <<T as Config>::Currency as Currency<T::AccountId>>::deposit_creating(907 &T::TreasuryAccountId::get(),908 T::CollectionCreationPrice::get(),909 ),910 );911 <T as Config>::Currency::settle(912 owner.as_sub(),913 imbalance,914 WithdrawReasons::TRANSFER,915 ExistenceRequirement::KeepAlive,916 )917 .map_err(|_| Error::<T>::NotSufficientFounds)?;918 }919920 <CreatedCollectionCount<T>>::put(created_count);921 <Pallet<T>>::deposit_event(Event::CollectionCreated(922 id,923 data.mode.id(),924 owner.as_sub().clone(),925 ));926 <PalletEvm<T>>::deposit_log(927 erc::CollectionHelpersEvents::CollectionCreated {928 owner: *owner.as_eth(),929 collection_id: eth::collection_id_to_address(id),930 }931 .to_log(T::ContractAddress::get()),932 );933 <CollectionById<T>>::insert(id, collection);934 Ok(id)935 }936937 /// Destroy collection.938 ///939 /// * `collection` - Collection handler.940 /// * `sender` - The owner or administrator of the collection.941 pub fn destroy_collection(942 collection: CollectionHandle<T>,943 sender: &T::CrossAccountId,944 ) -> DispatchResult {945 ensure!(946 collection.limits.owner_can_destroy(),947 <Error<T>>::NoPermission,948 );949 collection.check_is_owner(sender)?;950951 let destroyed_collections = <DestroyedCollectionCount<T>>::get()952 .0953 .checked_add(1)954 .ok_or(ArithmeticError::Overflow)?;955956 // =========957958 <DestroyedCollectionCount<T>>::put(destroyed_collections);959 <CollectionById<T>>::remove(collection.id);960 <AdminAmount<T>>::remove(collection.id);961 <IsAdmin<T>>::remove_prefix((collection.id,), None);962 <Allowlist<T>>::remove_prefix((collection.id,), None);963 <CollectionProperties<T>>::remove(collection.id);964965 <Pallet<T>>::deposit_event(Event::CollectionDestroyed(collection.id));966 Ok(())967 }968969 /// Set collection property.970 ///971 /// * `collection` - Collection handler.972 /// * `sender` - The owner or administrator of the collection.973 /// * `property` - The property to set.974 pub fn set_collection_property(975 collection: &CollectionHandle<T>,976 sender: &T::CrossAccountId,977 property: Property,978 ) -> DispatchResult {979 collection.check_is_owner_or_admin(sender)?;980981 CollectionProperties::<T>::try_mutate(collection.id, |properties| {982 let property = property.clone();983 properties.try_set(property.key, property.value)984 })985 .map_err(<Error<T>>::from)?;986987 Self::deposit_event(Event::CollectionPropertySet(collection.id, property.key));988989 Ok(())990 }991992 /// Set scouped collection property.993 ///994 /// * `collection_id` - ID of the collection for which the property is being set.995 /// * `scope` - Property scope.996 /// * `property` - The property to set.997 pub fn set_scoped_collection_property(998 collection_id: CollectionId,999 scope: PropertyScope,1000 property: Property,1001 ) -> DispatchResult {1002 CollectionProperties::<T>::try_mutate(collection_id, |properties| {1003 properties.try_scoped_set(scope, property.key, property.value)1004 })1005 .map_err(<Error<T>>::from)?;10061007 Ok(())1008 }10091010 /// Set scouped collection properties.1011 ///1012 /// * `collection_id` - ID of the collection for which the properties is being set.1013 /// * `scope` - Property scope.1014 /// * `properties` - The properties to set.1015 pub fn set_scoped_collection_properties(1016 collection_id: CollectionId,1017 scope: PropertyScope,1018 properties: impl Iterator<Item = Property>,1019 ) -> DispatchResult {1020 CollectionProperties::<T>::try_mutate(collection_id, |stored_properties| {1021 stored_properties.try_scoped_set_from_iter(scope, properties)1022 })1023 .map_err(<Error<T>>::from)?;10241025 Ok(())1026 }10271028 /// Set collection properties.1029 ///1030 /// * `collection` - Collection handler.1031 /// * `sender` - The owner or administrator of the collection.1032 /// * `properties` - The properties to set.1033 #[transactional]1034 pub fn set_collection_properties(1035 collection: &CollectionHandle<T>,1036 sender: &T::CrossAccountId,1037 properties: Vec<Property>,1038 ) -> DispatchResult {1039 for property in properties {1040 Self::set_collection_property(collection, sender, property)?;1041 }10421043 Ok(())1044 }10451046 /// Delete collection property.1047 ///1048 /// * `collection` - Collection handler.1049 /// * `sender` - The owner or administrator of the collection.1050 /// * `property` - The property to delete.1051 pub fn delete_collection_property(1052 collection: &CollectionHandle<T>,1053 sender: &T::CrossAccountId,1054 property_key: PropertyKey,1055 ) -> DispatchResult {1056 collection.check_is_owner_or_admin(sender)?;10571058 CollectionProperties::<T>::try_mutate(collection.id, |properties| {1059 properties.remove(&property_key)1060 })1061 .map_err(<Error<T>>::from)?;10621063 Self::deposit_event(Event::CollectionPropertyDeleted(1064 collection.id,1065 property_key,1066 ));10671068 Ok(())1069 }10701071 /// Delete collection properties.1072 ///1073 /// * `collection` - Collection handler.1074 /// * `sender` - The owner or administrator of the collection.1075 /// * `properties` - The properties to delete.1076 #[transactional]1077 pub fn delete_collection_properties(1078 collection: &CollectionHandle<T>,1079 sender: &T::CrossAccountId,1080 property_keys: Vec<PropertyKey>,1081 ) -> DispatchResult {1082 for key in property_keys {1083 Self::delete_collection_property(collection, sender, key)?;1084 }10851086 Ok(())1087 }10881089 /// Set collection propetry permission without any checks.1090 ///1091 /// Used for migrations.1092 ///1093 /// * `collection` - Collection handler.1094 /// * `property_permissions` - Property permissions.1095 pub fn set_property_permission_unchecked(1096 collection: CollectionId,1097 property_permission: PropertyKeyPermission,1098 ) -> DispatchResult {1099 <CollectionPropertyPermissions<T>>::try_mutate(collection, |permissions| {1100 permissions.try_set(property_permission.key, property_permission.permission)1101 })1102 .map_err(<Error<T>>::from)?;1103 Ok(())1104 }11051106 /// Set collection property permission.1107 ///1108 /// * `collection` - Collection handler.1109 /// * `sender` - The owner or administrator of the collection.1110 /// * `property_permission` - Property permission.1111 pub fn set_property_permission(1112 collection: &CollectionHandle<T>,1113 sender: &T::CrossAccountId,1114 property_permission: PropertyKeyPermission,1115 ) -> DispatchResult {1116 collection.check_is_owner_or_admin(sender)?;11171118 let all_permissions = CollectionPropertyPermissions::<T>::get(collection.id);1119 let current_permission = all_permissions.get(&property_permission.key);1120 if matches![1121 current_permission,1122 Some(PropertyPermission { mutable: false, .. })1123 ] {1124 return Err(<Error<T>>::NoPermission.into());1125 }11261127 CollectionPropertyPermissions::<T>::try_mutate(collection.id, |permissions| {1128 let property_permission = property_permission.clone();1129 permissions.try_set(property_permission.key, property_permission.permission)1130 })1131 .map_err(<Error<T>>::from)?;11321133 Self::deposit_event(Event::PropertyPermissionSet(1134 collection.id,1135 property_permission.key,1136 ));11371138 Ok(())1139 }11401141 /// Set token property permission.1142 ///1143 /// * `collection` - Collection handler.1144 /// * `sender` - The owner or administrator of the collection.1145 /// * `property_permissions` - Property permissions.1146 #[transactional]1147 pub fn set_token_property_permissions(1148 collection: &CollectionHandle<T>,1149 sender: &T::CrossAccountId,1150 property_permissions: Vec<PropertyKeyPermission>,1151 ) -> DispatchResult {1152 for prop_pemission in property_permissions {1153 Self::set_property_permission(collection, sender, prop_pemission)?;1154 }11551156 Ok(())1157 }11581159 /// Get collection property.1160 pub fn get_collection_property(1161 collection_id: CollectionId,1162 key: &PropertyKey,1163 ) -> Option<PropertyValue> {1164 Self::collection_properties(collection_id).get(key).cloned()1165 }11661167 /// Convert byte vector to property key vector.1168 pub fn bytes_keys_to_property_keys(1169 keys: Vec<Vec<u8>>,1170 ) -> Result<Vec<PropertyKey>, DispatchError> {1171 keys.into_iter()1172 .map(|key| -> Result<PropertyKey, DispatchError> {1173 key.try_into()1174 .map_err(|_| <Error<T>>::PropertyKeyIsTooLong.into())1175 })1176 .collect::<Result<Vec<PropertyKey>, DispatchError>>()1177 }11781179 /// Get properties according to given keys.1180 pub fn filter_collection_properties(1181 collection_id: CollectionId,1182 keys: Option<Vec<PropertyKey>>,1183 ) -> Result<Vec<Property>, DispatchError> {1184 let properties = Self::collection_properties(collection_id);11851186 let properties = keys1187 .map(|keys| {1188 keys.into_iter()1189 .filter_map(|key| {1190 properties.get(&key).map(|value| Property {1191 key,1192 value: value.clone(),1193 })1194 })1195 .collect()1196 })1197 .unwrap_or_else(|| {1198 properties1199 .into_iter()1200 .map(|(key, value)| Property { key, value })1201 .collect()1202 });12031204 Ok(properties)1205 }12061207 /// Get property permissions according to given keys.1208 pub fn filter_property_permissions(1209 collection_id: CollectionId,1210 keys: Option<Vec<PropertyKey>>,1211 ) -> Result<Vec<PropertyKeyPermission>, DispatchError> {1212 let permissions = Self::property_permissions(collection_id);12131214 let key_permissions = keys1215 .map(|keys| {1216 keys.into_iter()1217 .filter_map(|key| {1218 permissions1219 .get(&key)1220 .map(|permission| PropertyKeyPermission {1221 key,1222 permission: permission.clone(),1223 })1224 })1225 .collect()1226 })1227 .unwrap_or_else(|| {1228 permissions1229 .into_iter()1230 .map(|(key, permission)| PropertyKeyPermission { key, permission })1231 .collect()1232 });12331234 Ok(key_permissions)1235 }12361237 /// Toggle `user` participation in the `collection`'s allow list.1238 pub fn toggle_allowlist(1239 collection: &CollectionHandle<T>,1240 sender: &T::CrossAccountId,1241 user: &T::CrossAccountId,1242 allowed: bool,1243 ) -> DispatchResult {1244 collection.check_is_owner_or_admin(sender)?;12451246 // =========12471248 if allowed {1249 <Allowlist<T>>::insert((collection.id, user), true);1250 } else {1251 <Allowlist<T>>::remove((collection.id, user));1252 }12531254 Ok(())1255 }12561257 /// Toggle `user` participation in the `collection`'s admin list.1258 pub fn toggle_admin(1259 collection: &CollectionHandle<T>,1260 sender: &T::CrossAccountId,1261 user: &T::CrossAccountId,1262 admin: bool,1263 ) -> DispatchResult {1264 collection.check_is_owner(sender)?;12651266 let was_admin = <IsAdmin<T>>::get((collection.id, user));1267 if was_admin == admin {1268 return Ok(());1269 }1270 let amount = <AdminAmount<T>>::get(collection.id);12711272 if admin {1273 let amount = amount1274 .checked_add(1)1275 .ok_or(<Error<T>>::CollectionAdminCountExceeded)?;1276 ensure!(1277 amount <= Self::collection_admins_limit(),1278 <Error<T>>::CollectionAdminCountExceeded,1279 );12801281 // =========12821283 <AdminAmount<T>>::insert(collection.id, amount);1284 <IsAdmin<T>>::insert((collection.id, user), true);1285 } else {1286 <AdminAmount<T>>::insert(collection.id, amount.saturating_sub(1));1287 <IsAdmin<T>>::remove((collection.id, user));1288 }12891290 Ok(())1291 }12921293 /// Merge set fields from `new_limit` to `old_limit`.1294 pub fn clamp_limits(1295 mode: CollectionMode,1296 old_limit: &CollectionLimits,1297 mut new_limit: CollectionLimits,1298 ) -> Result<CollectionLimits, DispatchError> {1299 let limits = old_limit;1300 limit_default!(old_limit, new_limit,1301 account_token_ownership_limit => ensure!(1302 new_limit <= MAX_TOKEN_OWNERSHIP,1303 <Error<T>>::CollectionLimitBoundsExceeded,1304 ),1305 sponsored_data_size => ensure!(1306 new_limit <= CUSTOM_DATA_LIMIT,1307 <Error<T>>::CollectionLimitBoundsExceeded,1308 ),13091310 sponsored_data_rate_limit => {},1311 token_limit => ensure!(1312 old_limit >= new_limit && new_limit > 0,1313 <Error<T>>::CollectionTokenLimitExceeded1314 ),13151316 sponsor_transfer_timeout(match mode {1317 CollectionMode::NFT => NFT_SPONSOR_TRANSFER_TIMEOUT,1318 CollectionMode::Fungible(_) => FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,1319 CollectionMode::ReFungible => REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,1320 }) => ensure!(1321 new_limit <= MAX_SPONSOR_TIMEOUT,1322 <Error<T>>::CollectionLimitBoundsExceeded,1323 ),1324 sponsor_approve_timeout => {},1325 owner_can_transfer => ensure!(1326 !limits.owner_can_transfer_instaled() ||1327 old_limit || !new_limit,1328 <Error<T>>::OwnerPermissionsCantBeReverted,1329 ),1330 owner_can_destroy => ensure!(1331 old_limit || !new_limit,1332 <Error<T>>::OwnerPermissionsCantBeReverted,1333 ),1334 transfers_enabled => {},1335 );1336 Ok(new_limit)1337 }13381339 /// Merge set fields from `new_permission` to `old_permission`.1340 pub fn clamp_permissions(1341 _mode: CollectionMode,1342 old_permission: &CollectionPermissions,1343 mut new_permission: CollectionPermissions,1344 ) -> Result<CollectionPermissions, DispatchError> {1345 limit_default_clone!(old_permission, new_permission,1346 access => {},1347 mint_mode => {},1348 nesting => { /* todo check for permissive, if only it gets out of benchmarks */ },1349 );1350 Ok(new_permission)1351 }1352}13531354/// Indicates unsupported methods by returning [Error::UnsupportedOperation].1355#[macro_export]1356macro_rules! unsupported {1357 ($runtime:path) => {1358 Err($crate::Error::<$runtime>::UnsupportedOperation.into())1359 };1360}13611362/// Return weights for various worst-case operations.1363pub trait CommonWeightInfo<CrossAccountId> {1364 /// Weight of item creation.1365 fn create_item() -> Weight;13661367 /// Weight of items creation.1368 fn create_multiple_items(amount: &[CreateItemData]) -> Weight;13691370 /// Weight of items creation.1371 fn create_multiple_items_ex(cost: &CreateItemExData<CrossAccountId>) -> Weight;13721373 /// The weight of the burning item.1374 fn burn_item() -> Weight;13751376 /// Property setting weight.1377 ///1378 /// * `amount`- The number of properties to set.1379 fn set_collection_properties(amount: u32) -> Weight;13801381 /// Collection property deletion weight.1382 ///1383 /// * `amount`- The number of properties to set.1384 fn delete_collection_properties(amount: u32) -> Weight;13851386 /// Token property setting weight.1387 ///1388 /// * `amount`- The number of properties to set.1389 fn set_token_properties(amount: u32) -> Weight;13901391 /// Token property deletion weight.1392 ///1393 /// * `amount`- The number of properties to delete.1394 fn delete_token_properties(amount: u32) -> Weight;13951396 /// Token property permissions set weight.1397 ///1398 /// * `amount`- The number of property permissions to set.1399 fn set_token_property_permissions(amount: u32) -> Weight;14001401 /// Transfer price of the token or its parts.1402 fn transfer() -> Weight;14031404 /// The price of setting the permission of the operation from another user.1405 fn approve() -> Weight;14061407 /// Transfer price from another user.1408 fn transfer_from() -> Weight;14091410 /// The price of burning a token from another user.1411 fn burn_from() -> Weight;14121413 /// Differs from burn_item in case of Fungible and Refungible, as it should burn1414 /// whole users's balance.1415 ///1416 /// This method shouldn't be used directly, as it doesn't count breadth price, use [burn_recursively](CommonWeightInfo::burn_recursively) instead1417 fn burn_recursively_self_raw() -> Weight;14181419 /// Cost of iterating over `amount` children while burning, without counting child burning itself.1420 ///1421 /// This method shouldn't be used directly, as it doesn't count depth price, use [burn_recursively](CommonWeightInfo::burn_recursively) instead1422 fn burn_recursively_breadth_raw(amount: u32) -> Weight;14231424 /// The price of recursive burning a token.1425 ///1426 /// `max_selfs` - The maximum burning weight of the token itself.1427 /// `max_breadth` - The maximum number of nested tokens to burn.1428 fn burn_recursively(max_selfs: u32, max_breadth: u32) -> Weight {1429 Self::burn_recursively_self_raw()1430 .saturating_mul(max_selfs.max(1) as u64)1431 .saturating_add(Self::burn_recursively_breadth_raw(max_breadth))1432 }1433}14341435/// Weight info extension trait for refungible pallet.1436pub trait RefungibleExtensionsWeightInfo {1437 /// Weight of token repartition.1438 fn repartition() -> Weight;1439}14401441/// Common collection operations.1442///1443/// It wraps methods in Fungible, Nonfungible and Refungible pallets1444/// and adds weight info.1445pub trait CommonCollectionOperations<T: Config> {1446 /// Create token.1447 ///1448 /// * `sender` - The user who mint the token and pays for the transaction.1449 /// * `to` - The user who will own the token.1450 /// * `data` - Token data.1451 /// * `nesting_budget` - A budget that can be spent on nesting tokens.1452 fn create_item(1453 &self,1454 sender: T::CrossAccountId,1455 to: T::CrossAccountId,1456 data: CreateItemData,1457 nesting_budget: &dyn Budget,1458 ) -> DispatchResultWithPostInfo;14591460 /// Create multiple tokens.1461 ///1462 /// * `sender` - The user who mint the token and pays for the transaction.1463 /// * `to` - The user who will own the token.1464 /// * `data` - Token data.1465 /// * `nesting_budget` - A budget that can be spent on nesting tokens.1466 fn create_multiple_items(1467 &self,1468 sender: T::CrossAccountId,1469 to: T::CrossAccountId,1470 data: Vec<CreateItemData>,1471 nesting_budget: &dyn Budget,1472 ) -> DispatchResultWithPostInfo;14731474 /// Create multiple tokens.1475 ///1476 /// * `sender` - The user who mint the token and pays for the transaction.1477 /// * `to` - The user who will own the token.1478 /// * `data` - Token data.1479 /// * `nesting_budget` - A budget that can be spent on nesting tokens.1480 fn create_multiple_items_ex(1481 &self,1482 sender: T::CrossAccountId,1483 data: CreateItemExData<T::CrossAccountId>,1484 nesting_budget: &dyn Budget,1485 ) -> DispatchResultWithPostInfo;14861487 /// Burn token.1488 ///1489 /// * `sender` - The user who owns the token.1490 /// * `token` - Token id that will burned.1491 /// * `amount` - The number of parts of the token that will be burned.1492 fn burn_item(1493 &self,1494 sender: T::CrossAccountId,1495 token: TokenId,1496 amount: u128,1497 ) -> DispatchResultWithPostInfo;14981499 /// Burn token and all nested tokens recursievly.1500 ///1501 /// * `sender` - The user who owns the token.1502 /// * `token` - Token id that will burned.1503 /// * `self_budget` - The budget that can be spent on burning tokens.1504 /// * `breadth_budget` - The budget that can be spent on burning nested tokens.1505 fn burn_item_recursively(1506 &self,1507 sender: T::CrossAccountId,1508 token: TokenId,1509 self_budget: &dyn Budget,1510 breadth_budget: &dyn Budget,1511 ) -> DispatchResultWithPostInfo;15121513 /// Set collection properties.1514 ///1515 /// * `sender` - Must be either the owner of the collection or its admin.1516 /// * `properties` - Properties to be set.1517 fn set_collection_properties(1518 &self,1519 sender: T::CrossAccountId,1520 properties: Vec<Property>,1521 ) -> DispatchResultWithPostInfo;15221523 /// Delete collection properties.1524 ///1525 /// * `sender` - Must be either the owner of the collection or its admin.1526 /// * `properties` - The properties to be removed.1527 fn delete_collection_properties(1528 &self,1529 sender: &T::CrossAccountId,1530 property_keys: Vec<PropertyKey>,1531 ) -> DispatchResultWithPostInfo;15321533 /// Set token properties.1534 ///1535 /// The appropriate [`PropertyPermission`] for the token property1536 /// must be set with [`Self::set_token_property_permissions`].1537 ///1538 /// * `sender` - Must be either the owner of the token or its admin.1539 /// * `token_id` - The token for which the properties are being set.1540 /// * `properties` - Properties to be set.1541 /// * `budget` - Budget for setting properties.1542 fn set_token_properties(1543 &self,1544 sender: T::CrossAccountId,1545 token_id: TokenId,1546 properties: Vec<Property>,1547 budget: &dyn Budget,1548 ) -> DispatchResultWithPostInfo;15491550 /// Remove token properties.1551 ///1552 /// The appropriate [`PropertyPermission`] for the token property1553 /// must be set with [`Self::set_token_property_permissions`].1554 ///1555 /// * `sender` - Must be either the owner of the token or its admin.1556 /// * `token_id` - The token for which the properties are being remove.1557 /// * `property_keys` - Keys to remove corresponding properties.1558 /// * `budget` - Budget for removing properties.1559 fn delete_token_properties(1560 &self,1561 sender: T::CrossAccountId,1562 token_id: TokenId,1563 property_keys: Vec<PropertyKey>,1564 budget: &dyn Budget,1565 ) -> DispatchResultWithPostInfo;15661567 /// Set token property permissions.1568 ///1569 /// * `sender` - Must be either the owner of the token or its admin.1570 /// * `token_id` - The token for which the properties are being set.1571 /// * `properties` - Properties to be set.1572 /// * `budget` - Budget for setting properties.1573 fn set_token_property_permissions(1574 &self,1575 sender: &T::CrossAccountId,1576 property_permissions: Vec<PropertyKeyPermission>,1577 ) -> DispatchResultWithPostInfo;15781579 /// Transfer amount of token pieces.1580 ///1581 /// * `sender` - Donor user.1582 /// * `to` - Recepient user.1583 /// * `token` - The token of which parts are being sent.1584 /// * `amount` - The number of parts of the token that will be transferred.1585 /// * `budget` - The maximum budget that can be spent on the transfer.1586 fn transfer(1587 &self,1588 sender: T::CrossAccountId,1589 to: T::CrossAccountId,1590 token: TokenId,1591 amount: u128,1592 budget: &dyn Budget,1593 ) -> DispatchResultWithPostInfo;15941595 /// Grant access to another account to transfer parts of the token owned by the calling user via [Self::transfer_from].1596 ///1597 /// * `sender` - The user who grants access to the token.1598 /// * `spender` - The user to whom the rights are granted.1599 /// * `token` - The token to which access is granted.1600 /// * `amount` - The amount of pieces that another user can dispose of.1601 fn approve(1602 &self,1603 sender: T::CrossAccountId,1604 spender: T::CrossAccountId,1605 token: TokenId,1606 amount: u128,1607 ) -> DispatchResultWithPostInfo;16081609 /// Send parts of a token owned by another user.1610 ///1611 /// Before calling this method, you must grant rights to the calling user via [`Self::approve`].1612 ///1613 /// * `sender` - The user who must have access to the token (see [`Self::approve`]).1614 /// * `from` - The user who owns the token.1615 /// * `to` - Recepient user.1616 /// * `token` - The token of which parts are being sent.1617 /// * `amount` - The number of parts of the token that will be transferred.1618 /// * `budget` - The maximum budget that can be spent on the transfer.1619 fn transfer_from(1620 &self,1621 sender: T::CrossAccountId,1622 from: T::CrossAccountId,1623 to: T::CrossAccountId,1624 token: TokenId,1625 amount: u128,1626 budget: &dyn Budget,1627 ) -> DispatchResultWithPostInfo;16281629 /// Burn parts of a token owned by another user.1630 ///1631 /// Before calling this method, you must grant rights to the calling user via [`Self::approve`].1632 ///1633 /// * `sender` - The user who must have access to the token (see [`Self::approve`]).1634 /// * `from` - The user who owns the token.1635 /// * `token` - The token of which parts are being sent.1636 /// * `amount` - The number of parts of the token that will be transferred.1637 /// * `budget` - The maximum budget that can be spent on the burn.1638 fn burn_from(1639 &self,1640 sender: T::CrossAccountId,1641 from: T::CrossAccountId,1642 token: TokenId,1643 amount: u128,1644 budget: &dyn Budget,1645 ) -> DispatchResultWithPostInfo;16461647 /// Check permission to nest token.1648 ///1649 /// * `sender` - The user who initiated the check.1650 /// * `from` - The token that is checked for embedding.1651 /// * `under` - Token under which to check.1652 /// * `budget` - The maximum budget that can be spent on the check.1653 fn check_nesting(1654 &self,1655 sender: T::CrossAccountId,1656 from: (CollectionId, TokenId),1657 under: TokenId,1658 budget: &dyn Budget,1659 ) -> DispatchResult;16601661 /// Nest one token into another.1662 ///1663 /// * `under` - Token holder.1664 /// * `to_nest` - Nested token.1665 fn nest(&self, under: TokenId, to_nest: (CollectionId, TokenId));16661667 /// Unnest token.1668 ///1669 /// * `under` - Token holder.1670 /// * `to_nest` - Token to unnest.1671 fn unnest(&self, under: TokenId, to_nest: (CollectionId, TokenId));16721673 /// Get all user tokens.1674 ///1675 /// * `account` - Account for which you need to get tokens.1676 fn account_tokens(&self, account: T::CrossAccountId) -> Vec<TokenId>;16771678 /// Get all the tokens in the collection.1679 fn collection_tokens(&self) -> Vec<TokenId>;16801681 /// Check if the token exists.1682 ///1683 /// * `token` - Id token to check.1684 fn token_exists(&self, token: TokenId) -> bool;16851686 /// Get the id of the last minted token.1687 fn last_token_id(&self) -> TokenId;16881689 /// Get the owner of the token.1690 ///1691 /// * `token` - The token for which you need to find out the owner.1692 fn token_owner(&self, token: TokenId) -> Option<T::CrossAccountId>;16931694 /// Returns 10 tokens owners in no particular order.1695 ///1696 /// * `token` - The token for which you need to find out the owners.1697 fn token_owners(&self, token: TokenId) -> Vec<T::CrossAccountId>;16981699 /// Get the value of the token property by key.1700 ///1701 /// * `token` - Token with the property to get.1702 /// * `key` - Property name.1703 fn token_property(&self, token_id: TokenId, key: &PropertyKey) -> Option<PropertyValue>;17041705 /// Get a set of token properties by key vector.1706 ///1707 /// * `token` - Token with the property to get.1708 /// * `keys` - Vector of property keys. If this parameter is [None](sp_std::result::Result),1709 /// then all properties are returned.1710 fn token_properties(&self, token: TokenId, keys: Option<Vec<PropertyKey>>) -> Vec<Property>;17111712 /// Amount of unique collection tokens1713 fn total_supply(&self) -> u32;17141715 /// Amount of different tokens account has.1716 ///1717 /// * `account` - The account for which need to get the balance.1718 fn account_balance(&self, account: T::CrossAccountId) -> u32;17191720 /// Amount of specific token account have.1721 fn balance(&self, account: T::CrossAccountId, token: TokenId) -> u128;17221723 /// Amount of token pieces1724 fn total_pieces(&self, token: TokenId) -> Option<u128>;17251726 /// Get the number of parts of the token that a trusted user can manage.1727 ///1728 /// * `sender` - Trusted user.1729 /// * `spender` - Owner of the token.1730 /// * `token` - The token for which to get the value.1731 fn allowance(1732 &self,1733 sender: T::CrossAccountId,1734 spender: T::CrossAccountId,1735 token: TokenId,1736 ) -> u128;17371738 /// Get extension for RFT collection.1739 fn refungible_extensions(&self) -> Option<&dyn RefungibleExtensions<T>>;1740}17411742/// Extension for RFT collection.1743pub trait RefungibleExtensions<T>1744where1745 T: Config,1746{1747 /// Change the number of parts of the token.1748 ///1749 /// When the value changes down, this function is equivalent to burning parts of the token.1750 ///1751 /// * `sender` - The user calling the repartition operation. Must be the owner of the token.1752 /// * `token` - The token for which you want to change the number of parts.1753 /// * `amount` - The new value of the parts of the token.1754 fn repartition(1755 &self,1756 sender: &T::CrossAccountId,1757 token: TokenId,1758 amount: u128,1759 ) -> DispatchResultWithPostInfo;1760}17611762/// Merge [`DispatchResult`] with [`Weight`] into [`DispatchResultWithPostInfo`].1763///1764/// Used for [`CommonCollectionOperations`] implementations and flexible enough to do so.1765pub fn with_weight(res: DispatchResult, weight: Weight) -> DispatchResultWithPostInfo {1766 let post_info = PostDispatchInfo {1767 actual_weight: Some(weight),1768 pays_fee: Pays::Yes,1769 };1770 match res {1771 Ok(()) => Ok(post_info),1772 Err(error) => Err(DispatchErrorWithPostInfo { post_info, error }),1773 }1774}17751776impl<T: Config> From<PropertiesError> for Error<T> {1777 fn from(error: PropertiesError) -> Self {1778 match error {1779 PropertiesError::NoSpaceForProperty => Self::NoSpaceForProperty,1780 PropertiesError::PropertyLimitReached => Self::PropertyLimitReached,1781 PropertiesError::InvalidCharacterInPropertyKey => Self::InvalidCharacterInPropertyKey,1782 PropertiesError::PropertyKeyIsTooLong => Self::PropertyKeyIsTooLong,1783 PropertiesError::EmptyPropertyKey => Self::EmptyPropertyKey,1784 }1785 }1786}primitives/common/Cargo.tomldiffbeforeafterboth--- /dev/null
+++ b/primitives/common/Cargo.toml
@@ -0,0 +1,56 @@
+[package]
+authors = ['Unique Network <support@uniquenetwork.io>']
+description = 'Unique Runtime Common Primitives'
+edition = '2021'
+homepage = 'https://unique.network'
+license = 'All Rights Reserved'
+name = 'up-common'
+repository = 'https://github.com/UniqueNetwork/unique-chain'
+version = '0.9.24'
+
+[features]
+default = ['std']
+std = [
+ 'sp-std/std',
+ 'frame-support/std',
+ 'sp-runtime/std',
+ 'sp-core/std',
+ 'sp-consensus-aura/std',
+ 'fp-rpc/std',
+ 'pallet-evm/std',
+]
+
+[dependencies.sp-std]
+default-features = false
+git = "https://github.com/paritytech/substrate"
+branch = "polkadot-v0.9.24"
+
+[dependencies.frame-support]
+default-features = false
+git = "https://github.com/paritytech/substrate"
+branch = "polkadot-v0.9.24"
+
+[dependencies.sp-runtime]
+default-features = false
+git = "https://github.com/paritytech/substrate"
+branch = "polkadot-v0.9.24"
+
+[dependencies.sp-core]
+default-features = false
+git = "https://github.com/paritytech/substrate"
+branch = "polkadot-v0.9.24"
+
+[dependencies.sp-consensus-aura]
+default-features = false
+git = "https://github.com/paritytech/substrate"
+branch = "polkadot-v0.9.24"
+
+[dependencies.fp-rpc]
+default-features = false
+git = "https://github.com/uniquenetwork/frontier"
+branch = "unique-polkadot-v0.9.24"
+
+[dependencies.pallet-evm]
+default-features = false
+git = "https://github.com/uniquenetwork/frontier"
+branch = "unique-polkadot-v0.9.24"
primitives/common/src/constants.rsdiffbeforeafterboth--- /dev/null
+++ b/primitives/common/src/constants.rs
@@ -0,0 +1,55 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+use sp_runtime::Perbill;
+use frame_support::{
+ parameter_types,
+ weights::{Weight, constants::WEIGHT_PER_SECOND},
+};
+use crate::types::{BlockNumber, Balance};
+
+pub const MILLISECS_PER_BLOCK: u64 = 12000;
+
+pub const SLOT_DURATION: u64 = MILLISECS_PER_BLOCK;
+
+// These time units are defined in number of blocks.
+pub const MINUTES: BlockNumber = 60_000 / (MILLISECS_PER_BLOCK as BlockNumber);
+pub const HOURS: BlockNumber = MINUTES * 60;
+pub const DAYS: BlockNumber = HOURS * 24;
+
+pub const MICROUNIQUE: Balance = 1_000_000_000_000;
+pub const MILLIUNIQUE: Balance = 1_000 * MICROUNIQUE;
+pub const CENTIUNIQUE: Balance = 10 * MILLIUNIQUE;
+pub const UNIQUE: Balance = 100 * CENTIUNIQUE;
+
+// Targeting 0.1 UNQ per transfer
+pub const WEIGHT_TO_FEE_COEFF: u32 = 207_890_902;
+
+// Targeting 0.15 UNQ per transfer via ETH
+pub const MIN_GAS_PRICE: u64 = 1_019_493_469_850;
+
+/// We assume that ~10% of the block weight is consumed by `on_initalize` handlers.
+/// This is used to limit the maximal weight of a single extrinsic.
+pub const AVERAGE_ON_INITIALIZE_RATIO: Perbill = Perbill::from_percent(10);
+/// We allow `Normal` extrinsics to fill up the block up to 75%, the rest can be used
+/// by Operational extrinsics.
+pub const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75);
+/// We allow for 2 seconds of compute with a 6 second average block time.
+pub const MAXIMUM_BLOCK_WEIGHT: Weight = WEIGHT_PER_SECOND / 2;
+
+parameter_types! {
+ pub const TransactionByteFee: Balance = 501 * MICROUNIQUE;
+}
primitives/common/src/lib.rsdiffbeforeafterboth--- /dev/null
+++ b/primitives/common/src/lib.rs
@@ -0,0 +1,20 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+#![cfg_attr(not(feature = "std"), no_std)]
+
+pub mod constants;
+pub mod types;
primitives/common/src/types.rsdiffbeforeafterboth--- /dev/null
+++ b/primitives/common/src/types.rs
@@ -0,0 +1,81 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+use sp_runtime::{
+ generic,
+ traits::{Verify, IdentifyAccount},
+ MultiSignature,
+};
+
+/// Opaque types. These are used by the CLI to instantiate machinery that don't need to know
+/// the specifics of the runtime. They can then be made to be agnostic over specific formats
+/// of data like extrinsics, allowing for them to continue syncing the network through upgrades
+/// to even the core data structures.
+pub mod opaque {
+ pub use sp_runtime::{generic, traits::BlakeTwo256, OpaqueExtrinsic as UncheckedExtrinsic};
+
+ pub use super::{BlockNumber, Signature, AccountId, Balance, Index, Hash, AuraId};
+
+ /// Opaque block header type.
+ pub type Header = generic::Header<BlockNumber, BlakeTwo256>;
+
+ /// Opaque block type.
+ pub type Block = generic::Block<Header, UncheckedExtrinsic>;
+
+ pub trait RuntimeInstance {
+ type CrossAccountId: pallet_evm::account::CrossAccountId<sp_runtime::AccountId32>
+ + Send
+ + Sync
+ + 'static;
+
+ type TransactionConverter: fp_rpc::ConvertTransaction<UncheckedExtrinsic>
+ + Send
+ + Sync
+ + 'static;
+
+ fn get_transaction_converter() -> Self::TransactionConverter;
+ }
+}
+
+pub type SessionHandlers = ();
+
+/// An index to a block.
+pub type BlockNumber = u32;
+
+/// Alias to 512-bit hash when used in the context of a transaction signature on the chain.
+pub type Signature = MultiSignature;
+
+/// Some way of identifying an account on the chain. We intentionally make it equivalent
+/// to the public key of our transaction signing scheme.
+pub type AccountId = <<Signature as Verify>::Signer as IdentifyAccount>::AccountId;
+
+/// The type for looking up accounts. We don't expect more than 4 billion of them, but you
+/// never know...
+pub type AccountIndex = u32;
+
+/// Balance of an account.
+pub type Balance = u128;
+
+/// Index of a transaction in the chain.
+pub type Index = u32;
+
+/// A hash of some data used by the chain.
+pub type Hash = sp_core::H256;
+
+/// Digest item type.
+pub type DigestItem = generic::DigestItem;
+
+pub use sp_consensus_aura::sr25519::AuthorityId as AuraId;
runtime/common/Cargo.tomldiffbeforeafterboth--- a/runtime/common/Cargo.toml
+++ /dev/null
@@ -1,115 +0,0 @@
-[package]
-authors = ['Unique Network <support@uniquenetwork.io>']
-description = 'Unique Runtime Common'
-edition = '2021'
-homepage = 'https://unique.network'
-license = 'All Rights Reserved'
-name = 'unique-runtime-common'
-repository = 'https://github.com/UniqueNetwork/unique-chain'
-version = '0.9.24'
-
-[features]
-default = ['std']
-std = [
- 'sp-core/std',
- 'sp-std/std',
- 'sp-runtime/std',
- 'codec/std',
- 'frame-support/std',
- 'frame-system/std',
- 'sp-consensus-aura/std',
- 'pallet-common/std',
- 'pallet-unique/std',
- 'pallet-fungible/std',
- 'pallet-nonfungible/std',
- 'pallet-refungible/std',
- 'up-data-structs/std',
- 'pallet-evm/std',
- 'fp-rpc/std',
-]
-runtime-benchmarks = [
- 'sp-runtime/runtime-benchmarks',
- 'frame-support/runtime-benchmarks',
- 'frame-system/runtime-benchmarks',
-]
-
-[dependencies.sp-core]
-default-features = false
-git = "https://github.com/paritytech/substrate"
-branch = "polkadot-v0.9.24"
-
-[dependencies.sp-std]
-default-features = false
-git = 'https://github.com/paritytech/substrate'
-branch = 'polkadot-v0.9.24'
-
-[dependencies.sp-runtime]
-default-features = false
-git = "https://github.com/paritytech/substrate"
-branch = "polkadot-v0.9.24"
-
-[dependencies.codec]
-default-features = false
-features = ['derive']
-package = 'parity-scale-codec'
-version = '3.1.2'
-
-[dependencies.scale-info]
-default-features = false
-features = ["derive"]
-version = "2.0.1"
-
-[dependencies.frame-support]
-default-features = false
-git = "https://github.com/paritytech/substrate"
-branch = "polkadot-v0.9.24"
-
-[dependencies.frame-system]
-default-features = false
-git = "https://github.com/paritytech/substrate"
-branch = "polkadot-v0.9.24"
-
-[dependencies.pallet-common]
-default-features = false
-path = "../../pallets/common"
-
-[dependencies.pallet-unique]
-default-features = false
-path = "../../pallets/unique"
-
-[dependencies.pallet-fungible]
-default-features = false
-path = "../../pallets/fungible"
-
-[dependencies.pallet-nonfungible]
-default-features = false
-path = "../../pallets/nonfungible"
-
-[dependencies.pallet-refungible]
-default-features = false
-path = "../../pallets/refungible"
-
-[dependencies.pallet-unique-scheduler]
-default-features = false
-path = "../../pallets/scheduler"
-
-[dependencies.up-data-structs]
-default-features = false
-path = "../../primitives/data-structs"
-
-[dependencies.sp-consensus-aura]
-default-features = false
-git = "https://github.com/paritytech/substrate"
-branch = "polkadot-v0.9.24"
-
-[dependencies.fp-rpc]
-default-features = false
-git = "https://github.com/uniquenetwork/frontier"
-branch = "unique-polkadot-v0.9.24"
-
-[dependencies]
-pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.24" }
-evm-coder = { default-features = false, path = '../../crates/evm-coder' }
-up-sponsorship = { default-features = false, git = "https://github.com/UniqueNetwork/pallet-sponsoring", branch = 'polkadot-v0.9.24' }
-
-rmrk-rpc = { default-features = false, path = "../../primitives/rmrk-rpc" }
runtime/common/config/ethereum.rsdiffbeforeafterboth--- /dev/null
+++ b/runtime/common/config/ethereum.rs
@@ -0,0 +1,131 @@
+use sp_core::{U256, H160};
+use frame_support::{
+ weights::{Weight, constants::WEIGHT_PER_SECOND},
+ traits::{FindAuthor},
+ parameter_types, ConsensusEngineId,
+};
+use sp_runtime::{RuntimeAppPublic, Perbill};
+use crate::{
+ runtime_common::{
+ dispatch::CollectionDispatchT, ethereum::sponsoring::EvmSponsorshipHandler,
+ config::sponsoring::DefaultSponsoringRateLimit, DealWithFees,
+ },
+ Runtime, Aura, Balances, Event, ChainId,
+};
+use pallet_evm::{EnsureAddressTruncated, HashedAddressMapping};
+use up_common::constants::*;
+
+pub type CrossAccountId = pallet_evm::account::BasicCrossAccountId<Runtime>;
+
+impl pallet_evm::account::Config for Runtime {
+ type CrossAccountId = CrossAccountId;
+ type EvmAddressMapping = pallet_evm::HashedAddressMapping<Self::Hashing>;
+ type EvmBackwardsAddressMapping = fp_evm_mapping::MapBackwardsAddressTruncated;
+}
+
+// Assuming slowest ethereum opcode is SSTORE, with gas price of 20000 as our worst case
+// (contract, which only writes a lot of data),
+// approximating on top of our real store write weight
+parameter_types! {
+ pub const WritesPerSecond: u64 = WEIGHT_PER_SECOND / <Runtime as frame_system::Config>::DbWeight::get().write;
+ pub const GasPerSecond: u64 = WritesPerSecond::get() * 20000;
+ pub const WeightPerGas: u64 = WEIGHT_PER_SECOND / GasPerSecond::get();
+}
+
+/// Limiting EVM execution to 50% of block for substrate users and management tasks
+/// EVM transaction consumes more weight than substrate's, so we can't rely on them being
+/// scheduled fairly
+const EVM_DISPATCH_RATIO: Perbill = Perbill::from_percent(50);
+parameter_types! {
+ pub BlockGasLimit: U256 = U256::from(NORMAL_DISPATCH_RATIO * EVM_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT / WeightPerGas::get());
+}
+
+pub enum FixedGasWeightMapping {}
+impl pallet_evm::GasWeightMapping for FixedGasWeightMapping {
+ fn gas_to_weight(gas: u64) -> Weight {
+ gas.saturating_mul(WeightPerGas::get())
+ }
+ fn weight_to_gas(weight: Weight) -> u64 {
+ weight / WeightPerGas::get()
+ }
+}
+
+pub struct FixedFee;
+impl pallet_evm::FeeCalculator for FixedFee {
+ fn min_gas_price() -> (U256, u64) {
+ (MIN_GAS_PRICE.into(), 0)
+ }
+}
+
+pub struct EthereumFindAuthor<F>(core::marker::PhantomData<F>);
+impl<F: FindAuthor<u32>> FindAuthor<H160> for EthereumFindAuthor<F> {
+ fn find_author<'a, I>(digests: I) -> Option<H160>
+ where
+ I: 'a + IntoIterator<Item = (ConsensusEngineId, &'a [u8])>,
+ {
+ if let Some(author_index) = F::find_author(digests) {
+ let authority_id = Aura::authorities()[author_index as usize].clone();
+ return Some(H160::from_slice(&authority_id.to_raw_vec()[4..24]));
+ }
+ None
+ }
+}
+
+impl pallet_evm::Config for Runtime {
+ type BlockGasLimit = BlockGasLimit;
+ type FeeCalculator = FixedFee;
+ type GasWeightMapping = FixedGasWeightMapping;
+ type BlockHashMapping = pallet_ethereum::EthereumBlockHashMapping<Self>;
+ type CallOrigin = EnsureAddressTruncated<Self>;
+ type WithdrawOrigin = EnsureAddressTruncated<Self>;
+ type AddressMapping = HashedAddressMapping<Self::Hashing>;
+ type PrecompilesType = ();
+ type PrecompilesValue = ();
+ type Currency = Balances;
+ type Event = Event;
+ type OnMethodCall = (
+ pallet_evm_migration::OnMethodCall<Self>,
+ pallet_evm_contract_helpers::HelpersOnMethodCall<Self>,
+ CollectionDispatchT<Self>,
+ pallet_unique::eth::CollectionHelpersOnMethodCall<Self>,
+ );
+ type OnCreate = pallet_evm_contract_helpers::HelpersOnCreate<Self>;
+ type ChainId = ChainId;
+ type Runner = pallet_evm::runner::stack::Runner<Self>;
+ type OnChargeTransaction = pallet_evm::EVMCurrencyAdapter<Balances, DealWithFees>;
+ type TransactionValidityHack = pallet_evm_transaction_payment::TransactionValidityHack<Self>;
+ type FindAuthor = EthereumFindAuthor<Aura>;
+}
+
+impl pallet_evm_migration::Config for Runtime {
+ type WeightInfo = pallet_evm_migration::weights::SubstrateWeight<Self>;
+}
+
+impl pallet_ethereum::Config for Runtime {
+ type Event = Event;
+ type StateRoot = pallet_ethereum::IntermediateStateRoot<Self>;
+}
+
+parameter_types! {
+ // 0x842899ECF380553E8a4de75bF534cdf6fBF64049
+ pub const HelpersContractAddress: H160 = H160([
+ 0x84, 0x28, 0x99, 0xec, 0xf3, 0x80, 0x55, 0x3e, 0x8a, 0x4d, 0xe7, 0x5b, 0xf5, 0x34, 0xcd, 0xf6, 0xfb, 0xf6, 0x40, 0x49,
+ ]);
+
+ // 0x6c4e9fe1ae37a41e93cee429e8e1881abdcbb54f
+ pub const EvmCollectionHelpersAddress: H160 = H160([
+ 0x6c, 0x4e, 0x9f, 0xe1, 0xae, 0x37, 0xa4, 0x1e, 0x93, 0xce, 0xe4, 0x29, 0xe8, 0xe1, 0x88, 0x1a, 0xbd, 0xcb, 0xb5, 0x4f,
+ ]);
+}
+
+impl pallet_evm_contract_helpers::Config for Runtime {
+ type ContractAddress = HelpersContractAddress;
+ type DefaultSponsoringRateLimit = DefaultSponsoringRateLimit;
+}
+
+impl pallet_evm_coder_substrate::Config for Runtime {}
+
+impl pallet_evm_transaction_payment::Config for Runtime {
+ type EvmSponsorshipHandler = EvmSponsorshipHandler;
+ type Currency = Balances;
+}
runtime/common/config/mod.rsdiffbeforeafterboth--- /dev/null
+++ b/runtime/common/config/mod.rs
@@ -0,0 +1,23 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+pub mod ethereum;
+pub mod orml;
+pub mod pallets;
+pub mod parachain;
+pub mod sponsoring;
+pub mod substrate;
+pub mod xcm;
runtime/common/config/orml.rsdiffbeforeafterboth--- /dev/null
+++ b/runtime/common/config/orml.rs
@@ -0,0 +1,38 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+use frame_support::parameter_types;
+use frame_system::EnsureSigned;
+use crate::{Runtime, Event, RelayChainBlockNumberProvider};
+use up_common::{
+ types::{AccountId, Balance},
+ constants::*,
+};
+
+parameter_types! {
+ pub const MinVestedTransfer: Balance = 10 * UNIQUE;
+ pub const MaxVestingSchedules: u32 = 28;
+}
+
+impl orml_vesting::Config for Runtime {
+ type Event = Event;
+ type Currency = pallet_balances::Pallet<Runtime>;
+ type MinVestedTransfer = MinVestedTransfer;
+ type VestedTransferOrigin = EnsureSigned<AccountId>;
+ type WeightInfo = ();
+ type MaxVestingSchedules = MaxVestingSchedules;
+ type BlockNumberProvider = RelayChainBlockNumberProvider<Runtime>;
+}
runtime/common/config/pallets/mod.rsdiffbeforeafterboth--- /dev/null
+++ b/runtime/common/config/pallets/mod.rs
@@ -0,0 +1,93 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+use frame_support::parameter_types;
+use sp_runtime::traits::AccountIdConversion;
+use crate::{
+ runtime_common::{
+ dispatch::CollectionDispatchT,
+ config::{substrate::TreasuryModuleId, ethereum::EvmCollectionHelpersAddress},
+ weights::CommonWeights,
+ RelayChainBlockNumberProvider,
+ },
+ Runtime, Event, Call, Balances,
+};
+use up_common::{
+ types::{AccountId, Balance, BlockNumber},
+ constants::*,
+};
+use up_data_structs::{
+ mapping::{EvmTokenAddressMapping, CrossTokenAddressMapping},
+};
+
+#[cfg(feature = "rmrk")]
+pub mod rmrk;
+
+#[cfg(feature = "scheduler")]
+pub mod scheduler;
+
+parameter_types! {
+ pub TreasuryAccountId: AccountId = TreasuryModuleId::get().into_account_truncating();
+ pub const CollectionCreationPrice: Balance = 2 * UNIQUE;
+}
+
+impl pallet_common::Config for Runtime {
+ type WeightInfo = pallet_common::weights::SubstrateWeight<Self>;
+ type Event = Event;
+ type Currency = Balances;
+ type CollectionCreationPrice = CollectionCreationPrice;
+ type TreasuryAccountId = TreasuryAccountId;
+ type CollectionDispatch = CollectionDispatchT<Self>;
+
+ type EvmTokenAddressMapping = EvmTokenAddressMapping;
+ type CrossTokenAddressMapping = CrossTokenAddressMapping<Self::AccountId>;
+ type ContractAddress = EvmCollectionHelpersAddress;
+}
+
+impl pallet_structure::Config for Runtime {
+ type Event = Event;
+ type Call = Call;
+ type WeightInfo = pallet_structure::weights::SubstrateWeight<Self>;
+}
+
+impl pallet_fungible::Config for Runtime {
+ type WeightInfo = pallet_fungible::weights::SubstrateWeight<Self>;
+}
+impl pallet_refungible::Config for Runtime {
+ type WeightInfo = pallet_refungible::weights::SubstrateWeight<Self>;
+}
+impl pallet_nonfungible::Config for Runtime {
+ type WeightInfo = pallet_nonfungible::weights::SubstrateWeight<Self>;
+}
+
+parameter_types! {
+ pub const InflationBlockInterval: BlockNumber = 100; // every time per how many blocks inflation is applied
+}
+
+/// Used for the pallet inflation
+impl pallet_inflation::Config for Runtime {
+ type Currency = Balances;
+ type TreasuryAccountId = TreasuryAccountId;
+ type InflationBlockInterval = InflationBlockInterval;
+ type BlockNumberProvider = RelayChainBlockNumberProvider<Runtime>;
+}
+
+impl pallet_unique::Config for Runtime {
+ type Event = Event;
+ type WeightInfo = pallet_unique::weights::SubstrateWeight<Self>;
+ type CommonWeightInfo = CommonWeights<Self>;
+ type RefungibleExtensionsWeightInfo = CommonWeights<Self>;
+}
runtime/common/config/pallets/rmrk.rsdiffbeforeafterboth--- /dev/null
+++ b/runtime/common/config/pallets/rmrk.rs
@@ -0,0 +1,27 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+use crate::{Runtime, Event};
+
+impl pallet_proxy_rmrk_core::Config for Runtime {
+ type WeightInfo = pallet_proxy_rmrk_core::weights::SubstrateWeight<Self>;
+ type Event = Event;
+}
+
+impl pallet_proxy_rmrk_equip::Config for Runtime {
+ type WeightInfo = pallet_proxy_rmrk_equip::weights::SubstrateWeight<Self>;
+ type Event = Event;
+}
runtime/common/config/pallets/scheduler.rsdiffbeforeafterboth--- /dev/null
+++ b/runtime/common/config/pallets/scheduler.rs
@@ -0,0 +1,59 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+use frame_support::{traits::PrivilegeCmp, weights::Weight, parameter_types};
+use frame_system::EnsureSigned;
+use sp_runtime::Perbill;
+use sp_std::cmp::Ordering;
+use crate::{
+ runtime_common::{scheduler::SchedulerPaymentExecutor, config::substrate::RuntimeBlockWeights},
+ Runtime, Call, Event, Origin, OriginCaller, Balances,
+};
+use up_common::types::AccountId;
+
+parameter_types! {
+ pub MaximumSchedulerWeight: Weight = Perbill::from_percent(50) *
+ RuntimeBlockWeights::get().max_block;
+ pub const MaxScheduledPerBlock: u32 = 50;
+
+ pub const NoPreimagePostponement: Option<u32> = Some(10);
+ pub const Preimage: Option<u32> = Some(10);
+}
+
+/// Used the compare the privilege of an origin inside the scheduler.
+pub struct OriginPrivilegeCmp;
+
+impl PrivilegeCmp<OriginCaller> for OriginPrivilegeCmp {
+ fn cmp_privilege(_left: &OriginCaller, _right: &OriginCaller) -> Option<Ordering> {
+ Some(Ordering::Equal)
+ }
+}
+
+impl pallet_unique_scheduler::Config for Runtime {
+ type Event = Event;
+ type Origin = Origin;
+ type Currency = Balances;
+ type PalletsOrigin = OriginCaller;
+ type Call = Call;
+ type MaximumWeight = MaximumSchedulerWeight;
+ type ScheduleOrigin = EnsureSigned<AccountId>;
+ type MaxScheduledPerBlock = MaxScheduledPerBlock;
+ type WeightInfo = ();
+ type CallExecutor = SchedulerPaymentExecutor;
+ type OriginPrivilegeCmp = OriginPrivilegeCmp;
+ type PreimageProvider = ();
+ type NoPreimagePostponement = NoPreimagePostponement;
+}
runtime/common/config/parachain.rsdiffbeforeafterboth--- /dev/null
+++ b/runtime/common/config/parachain.rs
@@ -0,0 +1,44 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+use frame_support::{weights::Weight, parameter_types};
+use crate::{Runtime, Event, XcmpQueue, DmpQueue};
+use up_common::constants::*;
+
+parameter_types! {
+ pub const ReservedDmpWeight: Weight = MAXIMUM_BLOCK_WEIGHT / 4;
+ pub const ReservedXcmpWeight: Weight = MAXIMUM_BLOCK_WEIGHT / 4;
+}
+
+impl cumulus_pallet_parachain_system::Config for Runtime {
+ type Event = Event;
+ type SelfParaId = parachain_info::Pallet<Self>;
+ type OnSystemEvent = ();
+ // type DownwardMessageHandlers = cumulus_primitives_utility::UnqueuedDmpAsParent<
+ // MaxDownwardMessageWeight,
+ // XcmExecutor<XcmConfig>,
+ // Call,
+ // >;
+ type OutboundXcmpMessageSource = XcmpQueue;
+ type DmpMessageHandler = DmpQueue;
+ type ReservedDmpWeight = ReservedDmpWeight;
+ type ReservedXcmpWeight = ReservedXcmpWeight;
+ type XcmpMessageHandler = XcmpQueue;
+}
+
+impl parachain_info::Config for Runtime {}
+
+impl cumulus_pallet_aura_ext::Config for Runtime {}
runtime/common/config/sponsoring.rsdiffbeforeafterboth--- /dev/null
+++ b/runtime/common/config/sponsoring.rs
@@ -0,0 +1,35 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+use frame_support::parameter_types;
+use crate::{
+ runtime_common::{sponsoring::UniqueSponsorshipHandler},
+ Runtime,
+};
+use up_common::{types::BlockNumber, constants::*};
+
+parameter_types! {
+ pub const DefaultSponsoringRateLimit: BlockNumber = 1 * DAYS;
+}
+
+type SponsorshipHandler = (
+ UniqueSponsorshipHandler<Runtime>,
+ pallet_evm_transaction_payment::BridgeSponsorshipHandler<Runtime>,
+);
+
+impl pallet_charge_transaction::Config for Runtime {
+ type SponsorshipHandler = SponsorshipHandler;
+}
runtime/common/config/substrate.rsdiffbeforeafterboth--- /dev/null
+++ b/runtime/common/config/substrate.rs
@@ -0,0 +1,237 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+use frame_support::{
+ traits::{Everything, ConstU32},
+ weights::{
+ constants::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight},
+ DispatchClass, WeightToFeePolynomial, WeightToFeeCoefficients, ConstantMultiplier,
+ WeightToFeeCoefficient,
+ },
+ parameter_types, PalletId,
+};
+use sp_runtime::{
+ generic,
+ traits::{BlakeTwo256, AccountIdLookup},
+ Perbill, Permill, Percent,
+};
+use frame_system::{
+ limits::{BlockLength, BlockWeights},
+ EnsureRoot,
+};
+use sp_arithmetic::traits::{BaseArithmetic, Unsigned};
+use smallvec::smallvec;
+use crate::{
+ runtime_common::DealWithFees, Runtime, Event, Call, Origin, PalletInfo, System, Balances,
+ Treasury, SS58Prefix, Version,
+};
+use up_common::{types::*, constants::*};
+
+parameter_types! {
+ pub const BlockHashCount: BlockNumber = 2400;
+ pub RuntimeBlockLength: BlockLength =
+ BlockLength::max_with_normal_ratio(5 * 1024 * 1024, NORMAL_DISPATCH_RATIO);
+ pub const AvailableBlockRatio: Perbill = Perbill::from_percent(75);
+ pub const MaximumBlockLength: u32 = 5 * 1024 * 1024;
+ pub RuntimeBlockWeights: BlockWeights = BlockWeights::builder()
+ .base_block(BlockExecutionWeight::get())
+ .for_class(DispatchClass::all(), |weights| {
+ weights.base_extrinsic = ExtrinsicBaseWeight::get();
+ })
+ .for_class(DispatchClass::Normal, |weights| {
+ weights.max_total = Some(NORMAL_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT);
+ })
+ .for_class(DispatchClass::Operational, |weights| {
+ weights.max_total = Some(MAXIMUM_BLOCK_WEIGHT);
+ // Operational transactions have some extra reserved space, so that they
+ // are included even if block reached `MAXIMUM_BLOCK_WEIGHT`.
+ weights.reserved = Some(
+ MAXIMUM_BLOCK_WEIGHT - NORMAL_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT
+ );
+ })
+ .avg_block_initialization(AVERAGE_ON_INITIALIZE_RATIO)
+ .build_or_panic();
+}
+
+impl frame_system::Config for Runtime {
+ /// The data to be stored in an account.
+ type AccountData = pallet_balances::AccountData<Balance>;
+ /// The identifier used to distinguish between accounts.
+ type AccountId = AccountId;
+ /// The basic call filter to use in dispatchable.
+ type BaseCallFilter = Everything;
+ /// Maximum number of block number to block hash mappings to keep (oldest pruned first).
+ type BlockHashCount = BlockHashCount;
+ /// The maximum length of a block (in bytes).
+ type BlockLength = RuntimeBlockLength;
+ /// The index type for blocks.
+ type BlockNumber = BlockNumber;
+ /// The weight of the overhead invoked on the block import process, independent of the extrinsics included in that block.
+ type BlockWeights = RuntimeBlockWeights;
+ /// The aggregated dispatch type that is available for extrinsics.
+ type Call = Call;
+ /// The weight of database operations that the runtime can invoke.
+ type DbWeight = RocksDbWeight;
+ /// The ubiquitous event type.
+ type Event = Event;
+ /// The type for hashing blocks and tries.
+ type Hash = Hash;
+ /// The hashing algorithm used.
+ type Hashing = BlakeTwo256;
+ /// The header type.
+ type Header = generic::Header<BlockNumber, BlakeTwo256>;
+ /// The index type for storing how many extrinsics an account has signed.
+ type Index = Index;
+ /// The lookup mechanism to get account ID from whatever is passed in dispatchers.
+ type Lookup = AccountIdLookup<AccountId, ()>;
+ /// What to do if an account is fully reaped from the system.
+ type OnKilledAccount = ();
+ /// What to do if a new account is created.
+ type OnNewAccount = ();
+ type OnSetCode = cumulus_pallet_parachain_system::ParachainSetCode<Self>;
+ /// The ubiquitous origin type.
+ type Origin = Origin;
+ /// This type is being generated by `construct_runtime!`.
+ type PalletInfo = PalletInfo;
+ /// This is used as an identifier of the chain. 42 is the generic substrate prefix.
+ type SS58Prefix = SS58Prefix;
+ /// Weight information for the extrinsics of this pallet.
+ type SystemWeightInfo = frame_system::weights::SubstrateWeight<Self>;
+ /// Version of the runtime.
+ type Version = Version;
+ type MaxConsumers = ConstU32<16>;
+}
+
+impl pallet_randomness_collective_flip::Config for Runtime {}
+
+parameter_types! {
+ pub const MinimumPeriod: u64 = SLOT_DURATION / 2;
+}
+
+impl pallet_timestamp::Config for Runtime {
+ /// A timestamp: milliseconds since the unix epoch.
+ type Moment = u64;
+ type OnTimestampSet = ();
+ type MinimumPeriod = MinimumPeriod;
+ type WeightInfo = ();
+}
+
+parameter_types! {
+ // pub const ExistentialDeposit: u128 = 500;
+ pub const ExistentialDeposit: u128 = 0;
+ pub const MaxLocks: u32 = 50;
+ pub const MaxReserves: u32 = 50;
+}
+
+impl pallet_balances::Config for Runtime {
+ type MaxLocks = MaxLocks;
+ type MaxReserves = MaxReserves;
+ type ReserveIdentifier = [u8; 16];
+ /// The type for recording an account's balance.
+ type Balance = Balance;
+ /// The ubiquitous event type.
+ type Event = Event;
+ type DustRemoval = Treasury;
+ type ExistentialDeposit = ExistentialDeposit;
+ type AccountStore = System;
+ type WeightInfo = pallet_balances::weights::SubstrateWeight<Self>;
+}
+
+parameter_types! {
+ /// This value increases the priority of `Operational` transactions by adding
+ /// a "virtual tip" that's equal to the `OperationalFeeMultiplier * final_fee`.
+ pub const OperationalFeeMultiplier: u8 = 5;
+}
+
+/// Linear implementor of `WeightToFeePolynomial`
+pub struct LinearFee<T>(sp_std::marker::PhantomData<T>);
+
+impl<T> WeightToFeePolynomial for LinearFee<T>
+where
+ T: BaseArithmetic + From<u32> + Copy + Unsigned,
+{
+ type Balance = T;
+
+ fn polynomial() -> WeightToFeeCoefficients<Self::Balance> {
+ smallvec!(WeightToFeeCoefficient {
+ coeff_integer: WEIGHT_TO_FEE_COEFF.into(),
+ coeff_frac: Perbill::zero(),
+ negative: false,
+ degree: 1,
+ })
+ }
+}
+
+impl pallet_transaction_payment::Config for Runtime {
+ type OnChargeTransaction = pallet_transaction_payment::CurrencyAdapter<Balances, DealWithFees>;
+ type LengthToFee = ConstantMultiplier<Balance, TransactionByteFee>;
+ type OperationalFeeMultiplier = OperationalFeeMultiplier;
+ type WeightToFee = LinearFee<Balance>;
+ type FeeMultiplierUpdate = ();
+}
+
+parameter_types! {
+ pub const ProposalBond: Permill = Permill::from_percent(5);
+ pub const ProposalBondMinimum: Balance = 1 * UNIQUE;
+ pub const ProposalBondMaximum: Balance = 1000 * UNIQUE;
+ pub const SpendPeriod: BlockNumber = 5 * MINUTES;
+ pub const Burn: Permill = Permill::from_percent(0);
+ pub const TipCountdown: BlockNumber = 1 * DAYS;
+ pub const TipFindersFee: Percent = Percent::from_percent(20);
+ pub const TipReportDepositBase: Balance = 1 * UNIQUE;
+ pub const DataDepositPerByte: Balance = 1 * CENTIUNIQUE;
+ pub const BountyDepositBase: Balance = 1 * UNIQUE;
+ pub const BountyDepositPayoutDelay: BlockNumber = 1 * DAYS;
+ pub const TreasuryModuleId: PalletId = PalletId(*b"py/trsry");
+ pub const BountyUpdatePeriod: BlockNumber = 14 * DAYS;
+ pub const MaximumReasonLength: u32 = 16384;
+ pub const BountyCuratorDeposit: Permill = Permill::from_percent(50);
+ pub const BountyValueMinimum: Balance = 5 * UNIQUE;
+ pub const MaxApprovals: u32 = 100;
+}
+
+impl pallet_treasury::Config for Runtime {
+ type PalletId = TreasuryModuleId;
+ type Currency = Balances;
+ type ApproveOrigin = EnsureRoot<AccountId>;
+ type RejectOrigin = EnsureRoot<AccountId>;
+ type Event = Event;
+ type OnSlash = ();
+ type ProposalBond = ProposalBond;
+ type ProposalBondMinimum = ProposalBondMinimum;
+ type ProposalBondMaximum = ProposalBondMaximum;
+ type SpendPeriod = SpendPeriod;
+ type Burn = Burn;
+ type BurnDestination = ();
+ type SpendFunds = ();
+ type WeightInfo = pallet_treasury::weights::SubstrateWeight<Self>;
+ type MaxApprovals = MaxApprovals;
+}
+
+impl pallet_sudo::Config for Runtime {
+ type Event = Event;
+ type Call = Call;
+}
+
+parameter_types! {
+ pub const MaxAuthorities: u32 = 100_000;
+}
+
+impl pallet_aura::Config for Runtime {
+ type AuthorityId = AuraId;
+ type DisabledValidators = ();
+ type MaxAuthorities = MaxAuthorities;
+}
runtime/common/config/xcm.rsdiffbeforeafterboth--- /dev/null
+++ b/runtime/common/config/xcm.rs
@@ -0,0 +1,295 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+use frame_support::{
+ traits::{
+ tokens::currency::Currency as CurrencyT, OnUnbalanced as OnUnbalancedT, Get, Everything,
+ },
+ weights::{Weight, WeightToFeePolynomial, WeightToFee},
+ parameter_types, match_types,
+};
+use frame_system::EnsureRoot;
+use sp_runtime::{
+ traits::{Saturating, CheckedConversion, Zero},
+ SaturatedConversion,
+};
+use pallet_xcm::XcmPassthrough;
+use polkadot_parachain::primitives::Sibling;
+use xcm::v1::{BodyId, Junction::*, MultiLocation, NetworkId, Junctions::*};
+use xcm::latest::{
+ AssetId::{Concrete},
+ Fungibility::Fungible as XcmFungible,
+ MultiAsset, Error as XcmError,
+};
+use xcm_executor::traits::{MatchesFungible, WeightTrader};
+use xcm_builder::{
+ AccountId32Aliases, AllowTopLevelPaidExecutionFrom, CurrencyAdapter, EnsureXcmOrigin,
+ FixedWeightBounds, LocationInverter, NativeAsset, ParentAsSuperuser, RelayChainAsNative,
+ SiblingParachainAsNative, SiblingParachainConvertsVia, SignedAccountId32AsNative,
+ SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, ParentIsPreset,
+};
+use xcm_executor::{Config, XcmExecutor, Assets};
+use sp_std::marker::PhantomData;
+use crate::{
+ runtime_common::config::substrate::LinearFee, Runtime, Call, Event, Origin, Balances,
+ ParachainInfo, ParachainSystem, PolkadotXcm, XcmpQueue,
+};
+use up_common::{
+ types::{AccountId, Balance},
+ constants::*,
+};
+
+parameter_types! {
+ pub const RelayLocation: MultiLocation = MultiLocation::parent();
+ pub const RelayNetwork: NetworkId = NetworkId::Polkadot;
+ pub RelayOrigin: Origin = cumulus_pallet_xcm::Origin::Relay.into();
+ pub Ancestry: MultiLocation = Parachain(ParachainInfo::parachain_id().into()).into();
+}
+
+/// Type for specifying how a `MultiLocation` can be converted into an `AccountId`. This is used
+/// when determining ownership of accounts for asset transacting and when attempting to use XCM
+/// `Transact` in order to determine the dispatch Origin.
+pub type LocationToAccountId = (
+ // The parent (Relay-chain) origin converts to the default `AccountId`.
+ ParentIsPreset<AccountId>,
+ // Sibling parachain origins convert to AccountId via the `ParaId::into`.
+ SiblingParachainConvertsVia<Sibling, AccountId>,
+ // Straight up local `AccountId32` origins just alias directly to `AccountId`.
+ AccountId32Aliases<RelayNetwork, AccountId>,
+);
+
+pub struct OnlySelfCurrency;
+impl<B: TryFrom<u128>> MatchesFungible<B> for OnlySelfCurrency {
+ fn matches_fungible(a: &MultiAsset) -> Option<B> {
+ match (&a.id, &a.fun) {
+ (Concrete(_), XcmFungible(ref amount)) => CheckedConversion::checked_from(*amount),
+ _ => None,
+ }
+ }
+}
+
+/// Means for transacting assets on this chain.
+pub type LocalAssetTransactor = CurrencyAdapter<
+ // Use this currency:
+ Balances,
+ // Use this currency when it is a fungible asset matching the given location or name:
+ OnlySelfCurrency,
+ // Do a simple punn to convert an AccountId32 MultiLocation into a native chain account ID:
+ LocationToAccountId,
+ // Our chain's account ID type (we can't get away without mentioning it explicitly):
+ AccountId,
+ // We don't track any teleports.
+ (),
+>;
+
+/// No local origins on this chain are allowed to dispatch XCM sends/executions.
+pub type LocalOriginToLocation = (SignedToAccountId32<Origin, AccountId, RelayNetwork>,);
+
+/// The means for routing XCM messages which are not for local execution into the right message
+/// queues.
+pub type XcmRouter = (
+ // Two routers - use UMP to communicate with the relay chain:
+ cumulus_primitives_utility::ParentAsUmp<ParachainSystem, ()>,
+ // ..and XCMP to communicate with the sibling chains.
+ XcmpQueue,
+);
+
+/// This is the type we use to convert an (incoming) XCM origin into a local `Origin` instance,
+/// ready for dispatching a transaction with Xcm's `Transact`. There is an `OriginKind` which can
+/// biases the kind of local `Origin` it will become.
+pub type XcmOriginToTransactDispatchOrigin = (
+ // Sovereign account converter; this attempts to derive an `AccountId` from the origin location
+ // using `LocationToAccountId` and then turn that into the usual `Signed` origin. Useful for
+ // foreign chains who want to have a local sovereign account on this chain which they control.
+ SovereignSignedViaLocation<LocationToAccountId, Origin>,
+ // Native converter for Relay-chain (Parent) location; will converts to a `Relay` origin when
+ // recognised.
+ RelayChainAsNative<RelayOrigin, Origin>,
+ // Native converter for sibling Parachains; will convert to a `SiblingPara` origin when
+ // recognised.
+ SiblingParachainAsNative<cumulus_pallet_xcm::Origin, Origin>,
+ // Superuser converter for the Relay-chain (Parent) location. This will allow it to issue a
+ // transaction from the Root origin.
+ ParentAsSuperuser<Origin>,
+ // Native signed account converter; this just converts an `AccountId32` origin into a normal
+ // `Origin::Signed` origin of the same 32-byte value.
+ SignedAccountId32AsNative<RelayNetwork, Origin>,
+ // Xcm origins can be represented natively under the Xcm pallet's Xcm origin.
+ XcmPassthrough<Origin>,
+);
+
+parameter_types! {
+ // One XCM operation is 1_000_000 weight - almost certainly a conservative estimate.
+ pub UnitWeightCost: Weight = 1_000_000;
+ // 1200 UNIQUEs buy 1 second of weight.
+ pub const WeightPrice: (MultiLocation, u128) = (MultiLocation::parent(), 1_200 * UNIQUE);
+ pub const MaxInstructions: u32 = 100;
+}
+
+match_types! {
+ pub type ParentOrParentsUnitPlurality: impl Contains<MultiLocation> = {
+ MultiLocation { parents: 1, interior: Here } |
+ MultiLocation { parents: 1, interior: X1(Plurality { id: BodyId::Unit, .. }) }
+ };
+}
+
+pub type Barrier = (
+ TakeWeightCredit,
+ AllowTopLevelPaidExecutionFrom<Everything>,
+ // ^^^ Parent & its unit plurality gets free execution
+);
+
+pub struct UsingOnlySelfCurrencyComponents<
+ WeightToFee: WeightToFeePolynomial<Balance = Currency::Balance>,
+ AssetId: Get<MultiLocation>,
+ AccountId,
+ Currency: CurrencyT<AccountId>,
+ OnUnbalanced: OnUnbalancedT<Currency::NegativeImbalance>,
+>(
+ Weight,
+ Currency::Balance,
+ PhantomData<(WeightToFee, AssetId, AccountId, Currency, OnUnbalanced)>,
+);
+impl<
+ WeightToFee: WeightToFeePolynomial<Balance = Currency::Balance>,
+ AssetId: Get<MultiLocation>,
+ AccountId,
+ Currency: CurrencyT<AccountId>,
+ OnUnbalanced: OnUnbalancedT<Currency::NegativeImbalance>,
+ > WeightTrader
+ for UsingOnlySelfCurrencyComponents<WeightToFee, AssetId, AccountId, Currency, OnUnbalanced>
+{
+ fn new() -> Self {
+ Self(0, Zero::zero(), PhantomData)
+ }
+
+ fn buy_weight(&mut self, weight: Weight, payment: Assets) -> Result<Assets, XcmError> {
+ let amount = WeightToFee::weight_to_fee(&weight);
+ let u128_amount: u128 = amount.try_into().map_err(|_| XcmError::Overflow)?;
+
+ // location to this parachain through relay chain
+ let option1: xcm::v1::AssetId = Concrete(MultiLocation {
+ parents: 1,
+ interior: X1(Parachain(ParachainInfo::parachain_id().into())),
+ });
+ // direct location
+ let option2: xcm::v1::AssetId = Concrete(MultiLocation {
+ parents: 0,
+ interior: Here,
+ });
+
+ let required = if payment.fungible.contains_key(&option1) {
+ (option1, u128_amount).into()
+ } else if payment.fungible.contains_key(&option2) {
+ (option2, u128_amount).into()
+ } else {
+ (Concrete(MultiLocation::default()), u128_amount).into()
+ };
+
+ let unused = payment
+ .checked_sub(required)
+ .map_err(|_| XcmError::TooExpensive)?;
+ self.0 = self.0.saturating_add(weight);
+ self.1 = self.1.saturating_add(amount);
+ Ok(unused)
+ }
+
+ fn refund_weight(&mut self, weight: Weight) -> Option<MultiAsset> {
+ let weight = weight.min(self.0);
+ let amount = WeightToFee::weight_to_fee(&weight);
+ self.0 -= weight;
+ self.1 = self.1.saturating_sub(amount);
+ let amount: u128 = amount.saturated_into();
+ if amount > 0 {
+ Some((AssetId::get(), amount).into())
+ } else {
+ None
+ }
+ }
+}
+impl<
+ WeightToFee: WeightToFeePolynomial<Balance = Currency::Balance>,
+ AssetId: Get<MultiLocation>,
+ AccountId,
+ Currency: CurrencyT<AccountId>,
+ OnUnbalanced: OnUnbalancedT<Currency::NegativeImbalance>,
+ > Drop
+ for UsingOnlySelfCurrencyComponents<WeightToFee, AssetId, AccountId, Currency, OnUnbalanced>
+{
+ fn drop(&mut self) {
+ OnUnbalanced::on_unbalanced(Currency::issue(self.1));
+ }
+}
+
+pub struct XcmConfig;
+impl Config for XcmConfig {
+ type Call = Call;
+ type XcmSender = XcmRouter;
+ // How to withdraw and deposit an asset.
+ type AssetTransactor = LocalAssetTransactor;
+ type OriginConverter = XcmOriginToTransactDispatchOrigin;
+ type IsReserve = NativeAsset;
+ type IsTeleporter = (); // Teleportation is disabled
+ type LocationInverter = LocationInverter<Ancestry>;
+ type Barrier = Barrier;
+ type Weigher = FixedWeightBounds<UnitWeightCost, Call, MaxInstructions>;
+ type Trader =
+ UsingOnlySelfCurrencyComponents<LinearFee<Balance>, RelayLocation, AccountId, Balances, ()>;
+ type ResponseHandler = (); // Don't handle responses for now.
+ type SubscriptionService = PolkadotXcm;
+
+ type AssetTrap = PolkadotXcm;
+ type AssetClaims = PolkadotXcm;
+}
+
+impl pallet_xcm::Config for Runtime {
+ type Event = Event;
+ type SendXcmOrigin = EnsureXcmOrigin<Origin, LocalOriginToLocation>;
+ type XcmRouter = XcmRouter;
+ type ExecuteXcmOrigin = EnsureXcmOrigin<Origin, LocalOriginToLocation>;
+ type XcmExecuteFilter = Everything;
+ type XcmExecutor = XcmExecutor<XcmConfig>;
+ type XcmTeleportFilter = Everything;
+ type XcmReserveTransferFilter = Everything;
+ type Weigher = FixedWeightBounds<UnitWeightCost, Call, MaxInstructions>;
+ type LocationInverter = LocationInverter<Ancestry>;
+ type Origin = Origin;
+ type Call = Call;
+ const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 100;
+ type AdvertisedXcmVersion = pallet_xcm::CurrentXcmVersion;
+}
+
+impl cumulus_pallet_xcm::Config for Runtime {
+ type Event = Event;
+ type XcmExecutor = XcmExecutor<XcmConfig>;
+}
+
+impl cumulus_pallet_xcmp_queue::Config for Runtime {
+ type WeightInfo = ();
+ type Event = Event;
+ type XcmExecutor = XcmExecutor<XcmConfig>;
+ type ChannelInfo = ParachainSystem;
+ type VersionWrapper = ();
+ type ExecuteOverweightOrigin = frame_system::EnsureRoot<AccountId>;
+ type ControllerOrigin = EnsureRoot<AccountId>;
+ type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin;
+}
+
+impl cumulus_pallet_dmp_queue::Config for Runtime {
+ type Event = Event;
+ type XcmExecutor = XcmExecutor<XcmConfig>;
+ type ExecuteOverweightOrigin = frame_system::EnsureRoot<AccountId>;
+}
runtime/common/constants.rsdiffbeforeafterboth--- /dev/null
+++ b/runtime/common/constants.rs
@@ -0,0 +1,55 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+use sp_runtime::Perbill;
+use frame_support::{
+ parameter_types,
+ weights::{Weight, constants::WEIGHT_PER_SECOND},
+};
+use up_common::types::{BlockNumber, Balance};
+
+pub const MILLISECS_PER_BLOCK: u64 = 12000;
+
+pub const SLOT_DURATION: u64 = MILLISECS_PER_BLOCK;
+
+// These time units are defined in number of blocks.
+pub const MINUTES: BlockNumber = 60_000 / (MILLISECS_PER_BLOCK as BlockNumber);
+pub const HOURS: BlockNumber = MINUTES * 60;
+pub const DAYS: BlockNumber = HOURS * 24;
+
+pub const MICROUNIQUE: Balance = 1_000_000_000_000;
+pub const MILLIUNIQUE: Balance = 1_000 * MICROUNIQUE;
+pub const CENTIUNIQUE: Balance = 10 * MILLIUNIQUE;
+pub const UNIQUE: Balance = 100 * CENTIUNIQUE;
+
+// Targeting 0.1 UNQ per transfer
+pub const WEIGHT_TO_FEE_COEFF: u32 = 207_890_902;
+
+// Targeting 0.15 UNQ per transfer via ETH
+pub const MIN_GAS_PRICE: u64 = 1_019_493_469_850;
+
+/// We assume that ~10% of the block weight is consumed by `on_initalize` handlers.
+/// This is used to limit the maximal weight of a single extrinsic.
+pub const AVERAGE_ON_INITIALIZE_RATIO: Perbill = Perbill::from_percent(10);
+/// We allow `Normal` extrinsics to fill up the block up to 75%, the rest can be used
+/// by Operational extrinsics.
+pub const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75);
+/// We allow for 2 seconds of compute with a 6 second average block time.
+pub const MAXIMUM_BLOCK_WEIGHT: Weight = WEIGHT_PER_SECOND / 2;
+
+parameter_types! {
+ pub const TransactionByteFee: Balance = 501 * MICROUNIQUE;
+}
runtime/common/construct_runtime/mod.rsdiffbeforeafterboth--- /dev/null
+++ b/runtime/common/construct_runtime/mod.rs
@@ -0,0 +1,90 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+mod util;
+
+#[macro_export]
+macro_rules! construct_runtime {
+ ($select_runtime:ident) => {
+ $crate::construct_runtime_impl! {
+ select_runtime($select_runtime);
+
+ pub enum Runtime where
+ Block = Block,
+ NodeBlock = opaque::Block,
+ UncheckedExtrinsic = UncheckedExtrinsic
+ {
+ ParachainSystem: cumulus_pallet_parachain_system::{Pallet, Call, Config, Storage, Inherent, Event<T>, ValidateUnsigned} = 20,
+ ParachainInfo: parachain_info::{Pallet, Storage, Config} = 21,
+
+ Aura: pallet_aura::{Pallet, Config<T>} = 22,
+ AuraExt: cumulus_pallet_aura_ext::{Pallet, Config} = 23,
+
+ Balances: pallet_balances::{Pallet, Call, Storage, Config<T>, Event<T>} = 30,
+ RandomnessCollectiveFlip: pallet_randomness_collective_flip::{Pallet, Storage} = 31,
+ Timestamp: pallet_timestamp::{Pallet, Call, Storage, Inherent} = 32,
+ TransactionPayment: pallet_transaction_payment::{Pallet, Storage} = 33,
+ Treasury: pallet_treasury::{Pallet, Call, Storage, Config, Event<T>} = 34,
+ Sudo: pallet_sudo::{Pallet, Call, Storage, Config<T>, Event<T>} = 35,
+ System: frame_system::{Pallet, Call, Storage, Config, Event<T>} = 36,
+ Vesting: orml_vesting::{Pallet, Storage, Call, Event<T>, Config<T>} = 37,
+ // Vesting: pallet_vesting::{Pallet, Call, Config<T>, Storage, Event<T>} = 37,
+ // Contracts: pallet_contracts::{Pallet, Call, Storage, Event<T>} = 38,
+
+ // XCM helpers.
+ XcmpQueue: cumulus_pallet_xcmp_queue::{Pallet, Call, Storage, Event<T>} = 50,
+ PolkadotXcm: pallet_xcm::{Pallet, Call, Event<T>, Origin} = 51,
+ CumulusXcm: cumulus_pallet_xcm::{Pallet, Call, Event<T>, Origin} = 52,
+ DmpQueue: cumulus_pallet_dmp_queue::{Pallet, Call, Storage, Event<T>} = 53,
+
+ // Unique Pallets
+ Inflation: pallet_inflation::{Pallet, Call, Storage} = 60,
+ Unique: pallet_unique::{Pallet, Call, Storage, Event<T>} = 61,
+
+ #[runtimes(opal)]
+ Scheduler: pallet_unique_scheduler::{Pallet, Call, Storage, Event<T>} = 62,
+
+ // free = 63
+
+ Charging: pallet_charge_transaction::{Pallet, Call, Storage } = 64,
+ // ContractHelpers: pallet_contract_helpers::{Pallet, Call, Storage} = 65,
+ Common: pallet_common::{Pallet, Storage, Event<T>} = 66,
+ Fungible: pallet_fungible::{Pallet, Storage} = 67,
+
+ #[runtimes(opal)]
+ Refungible: pallet_refungible::{Pallet, Storage} = 68,
+
+ Nonfungible: pallet_nonfungible::{Pallet, Storage} = 69,
+ Structure: pallet_structure::{Pallet, Call, Storage, Event<T>} = 70,
+
+ #[runtimes(opal)]
+ RmrkCore: pallet_proxy_rmrk_core::{Pallet, Call, Storage, Event<T>} = 71,
+
+ #[runtimes(opal)]
+ RmrkEquip: pallet_proxy_rmrk_equip::{Pallet, Call, Storage, Event<T>} = 72,
+
+ // Frontier
+ EVM: pallet_evm::{Pallet, Config, Call, Storage, Event<T>} = 100,
+ Ethereum: pallet_ethereum::{Pallet, Config, Call, Storage, Event, Origin} = 101,
+
+ EvmCoderSubstrate: pallet_evm_coder_substrate::{Pallet, Storage} = 150,
+ EvmContractHelpers: pallet_evm_contract_helpers::{Pallet, Storage} = 151,
+ EvmTransactionPayment: pallet_evm_transaction_payment::{Pallet} = 152,
+ EvmMigration: pallet_evm_migration::{Pallet, Call, Storage} = 153,
+ }
+ }
+ }
+}
runtime/common/construct_runtime/util.rsdiffbeforeafterboth--- /dev/null
+++ b/runtime/common/construct_runtime/util.rs
@@ -0,0 +1,222 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+#[macro_export]
+macro_rules! construct_runtime_impl {
+ (
+ select_runtime($select_runtime:ident);
+
+ pub enum Runtime where
+ $($where_ident:ident = $where_ty:ty),* $(,)?
+ {
+ $(
+ $(#[runtimes($($pallet_runtimes:ident),+ $(,)?)])?
+ $pallet_name:ident: $pallet_mod:ident::{$($pallet_parts:ty),*} = $index:literal
+ ),*
+ $(,)?
+ }
+ ) => {
+ $crate::construct_runtime_helper! {
+ select_runtime($select_runtime),
+ selected_pallets(),
+
+ where_clause($($where_ident = $where_ty),*),
+ pallets(
+ $(
+ $(#[runtimes($($pallet_runtimes),+)])?
+ $pallet_name: $pallet_mod::{$($pallet_parts),*} = $index
+ ),*,
+ )
+ }
+ }
+}
+
+#[macro_export]
+macro_rules! construct_runtime_helper {
+ (
+ select_runtime($select_runtime:ident),
+ selected_pallets($($selected_pallets:tt)*),
+
+ where_clause($($where_clause:tt)*),
+ pallets(
+ #[runtimes($($pallet_runtimes:ident),+)]
+ $pallet_name:ident: $pallet_mod:ident::{$($pallet_parts:ty),*} = $index:literal,
+
+ $($pallets_tl:tt)*
+ )
+ ) => {
+ $crate::add_runtime_specific_pallets! {
+ select_runtime($select_runtime),
+ runtimes($($pallet_runtimes),+,),
+ selected_pallets($($selected_pallets)*),
+
+ where_clause($($where_clause)*),
+ pallets(
+ $pallet_name: $pallet_mod::{$($pallet_parts),*} = $index,
+ $($pallets_tl)*
+ )
+ }
+ };
+
+ (
+ select_runtime($select_runtime:ident),
+ selected_pallets($($selected_pallets:tt)*),
+
+ where_clause($($where_clause:tt)*),
+ pallets(
+ $pallet_name:ident: $pallet_mod:ident::{$($pallet_parts:ty),*} = $index:literal,
+
+ $($pallets_tl:tt)*
+ )
+ ) => {
+ $crate::construct_runtime_helper! {
+ select_runtime($select_runtime),
+ selected_pallets(
+ $($selected_pallets)*
+ $pallet_name: $pallet_mod::{$($pallet_parts),*} = $index,
+ ),
+
+ where_clause($($where_clause)*),
+ pallets($($pallets_tl)*)
+ }
+ };
+
+ (
+ select_runtime($select_runtime:ident),
+ selected_pallets($($selected_pallets:tt)*),
+
+ where_clause($($where_clause:tt)*),
+ pallets()
+ ) => {
+ frame_support::construct_runtime! {
+ pub enum Runtime where
+ $($where_clause)*
+ {
+ $($selected_pallets)*
+ }
+ }
+ };
+}
+
+#[macro_export]
+macro_rules! add_runtime_specific_pallets {
+ (
+ select_runtime(opal),
+ runtimes(opal, $($_runtime_tl:tt)*),
+ selected_pallets($($selected_pallets:tt)*),
+
+ where_clause($($where_clause:tt)*),
+ pallets(
+ $pallet_name:ident: $pallet_mod:ident::{$($pallet_parts:ty),*} = $index:literal,
+ $($pallets_tl:tt)*
+ )
+ ) => {
+ $crate::construct_runtime_helper! {
+ select_runtime(opal),
+ selected_pallets(
+ $($selected_pallets)*
+ $pallet_name: $pallet_mod::{$($pallet_parts),*} = $index,
+ ),
+
+ where_clause($($where_clause)*),
+ pallets($($pallets_tl)*)
+ }
+ };
+
+ (
+ select_runtime(quartz),
+ runtimes(quartz, $($_runtime_tl:tt)*),
+ selected_pallets($($selected_pallets:tt)*),
+
+ where_clause($($where_clause:tt)*),
+ pallets(
+ $pallet_name:ident: $pallet_mod:ident::{$($pallet_parts:ty),*} = $index:literal,
+ $($pallets_tl:tt)*
+ )
+ ) => {
+ $crate::construct_runtime_helper! {
+ select_runtime(quartz),
+ selected_pallets(
+ $($selected_pallets)*
+ $pallet_name: $pallet_mod::{$($pallet_parts),*} = $index,
+ ),
+
+ where_clause($($where_clause)*),
+ pallets($($pallets_tl)*)
+ }
+ };
+
+ (
+ select_runtime(unique),
+ runtimes(unique, $($_runtime_tl:tt)*),
+ selected_pallets($($selected_pallets:tt)*),
+
+ where_clause($($where_clause:tt)*),
+ pallets(
+ $pallet_name:ident: $pallet_mod:ident::{$($pallet_parts:ty),*} = $index:literal,
+ $($pallets_tl:tt)*
+ )
+ ) => {
+ $crate::construct_runtime_helper! {
+ select_runtime(unique),
+ selected_pallets(
+ $($selected_pallets)*
+ $pallet_name: $pallet_mod::{$($pallet_parts),*} = $index,
+ ),
+
+ where_clause($($where_clause)*),
+ pallets($($pallets_tl)*)
+ }
+ };
+
+ (
+ select_runtime($select_runtime:ident),
+ runtimes($_current_runtime:ident, $($runtime_tl:tt)*),
+ selected_pallets($($selected_pallets:tt)*),
+
+ where_clause($($where_clause:tt)*),
+ pallets($($pallets:tt)*)
+ ) => {
+ $crate::add_runtime_specific_pallets! {
+ select_runtime($select_runtime),
+ runtimes($($runtime_tl)*),
+ selected_pallets($($selected_pallets)*),
+
+ where_clause($($where_clause)*),
+ pallets($($pallets)*)
+ }
+ };
+
+ (
+ select_runtime($select_runtime:ident),
+ runtimes(),
+ selected_pallets($($selected_pallets:tt)*),
+
+ where_clause($($where_clause:tt)*),
+ pallets(
+ $_pallet_name:ident: $_pallet_mod:ident::{$($_pallet_parts:ty),*} = $_index:literal,
+ $($pallets_tl:tt)*
+ )
+ ) => {
+ $crate::construct_runtime_helper! {
+ select_runtime($select_runtime),
+ selected_pallets($($selected_pallets)*),
+
+ where_clause($($where_clause)*),
+ pallets($($pallets_tl)*)
+ }
+ };
+}
runtime/common/dispatch.rsdiffbeforeafterboth--- /dev/null
+++ b/runtime/common/dispatch.rs
@@ -0,0 +1,189 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+use frame_support::{dispatch::DispatchResult, ensure};
+use pallet_evm::{PrecompileHandle, PrecompileResult};
+use sp_core::H160;
+use sp_runtime::DispatchError;
+use sp_std::{borrow::ToOwned, vec::Vec};
+use pallet_common::{
+ CollectionById, CollectionHandle, CommonCollectionOperations, erc::CommonEvmHandler,
+ eth::map_eth_to_id,
+};
+pub use pallet_common::dispatch::CollectionDispatch;
+use pallet_fungible::{Pallet as PalletFungible, FungibleHandle};
+use pallet_nonfungible::{Pallet as PalletNonfungible, NonfungibleHandle};
+use pallet_refungible::{
+ Pallet as PalletRefungible, RefungibleHandle, erc_token::RefungibleTokenHandle,
+};
+use up_data_structs::{
+ CollectionMode, CreateCollectionData, MAX_DECIMAL_POINTS, mapping::TokenAddressMapping,
+ CollectionId,
+};
+
+#[cfg(not(feature = "refungible"))]
+use pallet_common::unsupported;
+
+pub enum CollectionDispatchT<T>
+where
+ T: pallet_fungible::Config + pallet_nonfungible::Config + pallet_refungible::Config,
+{
+ Fungible(FungibleHandle<T>),
+ Nonfungible(NonfungibleHandle<T>),
+ Refungible(RefungibleHandle<T>),
+}
+impl<T> CollectionDispatch<T> for CollectionDispatchT<T>
+where
+ T: pallet_common::Config
+ + pallet_unique::Config
+ + pallet_fungible::Config
+ + pallet_nonfungible::Config
+ + pallet_refungible::Config,
+{
+ fn create(
+ sender: T::CrossAccountId,
+ data: CreateCollectionData<T::AccountId>,
+ ) -> Result<CollectionId, DispatchError> {
+ let id = match data.mode {
+ CollectionMode::NFT => <PalletNonfungible<T>>::init_collection(sender, data, false)?,
+ CollectionMode::Fungible(decimal_points) => {
+ // check params
+ ensure!(
+ decimal_points <= MAX_DECIMAL_POINTS,
+ pallet_unique::Error::<T>::CollectionDecimalPointLimitExceeded
+ );
+ <PalletFungible<T>>::init_collection(sender, data)?
+ }
+
+ #[cfg(feature = "refungible")]
+ CollectionMode::ReFungible => <PalletRefungible<T>>::init_collection(sender, data)?,
+
+ #[cfg(not(feature = "refungible"))]
+ CollectionMode::ReFungible => return unsupported!(T),
+ };
+ Ok(id)
+ }
+
+ fn destroy(sender: T::CrossAccountId, collection: CollectionHandle<T>) -> DispatchResult {
+ match collection.mode {
+ CollectionMode::ReFungible => {
+ PalletRefungible::destroy_collection(RefungibleHandle::cast(collection), &sender)?
+ }
+ CollectionMode::Fungible(_) => {
+ PalletFungible::destroy_collection(FungibleHandle::cast(collection), &sender)?
+ }
+ CollectionMode::NFT => {
+ PalletNonfungible::destroy_collection(NonfungibleHandle::cast(collection), &sender)?
+ }
+ }
+ Ok(())
+ }
+
+ fn dispatch(handle: CollectionHandle<T>) -> Self {
+ match handle.mode {
+ CollectionMode::Fungible(_) => Self::Fungible(FungibleHandle::cast(handle)),
+ CollectionMode::NFT => Self::Nonfungible(NonfungibleHandle::cast(handle)),
+ CollectionMode::ReFungible => Self::Refungible(RefungibleHandle::cast(handle)),
+ }
+ }
+
+ fn into_inner(self) -> CollectionHandle<T> {
+ match self {
+ Self::Fungible(f) => f.into_inner(),
+ Self::Nonfungible(f) => f.into_inner(),
+ Self::Refungible(f) => f.into_inner(),
+ }
+ }
+
+ fn as_dyn(&self) -> &dyn CommonCollectionOperations<T> {
+ match self {
+ Self::Fungible(h) => h,
+ Self::Nonfungible(h) => h,
+ Self::Refungible(h) => h,
+ }
+ }
+}
+
+impl<T> pallet_evm::OnMethodCall<T> for CollectionDispatchT<T>
+where
+ T: pallet_common::Config
+ + pallet_unique::Config
+ + pallet_fungible::Config
+ + pallet_nonfungible::Config
+ + pallet_refungible::Config,
+ T::AccountId: From<[u8; 32]>,
+{
+ fn is_reserved(target: &H160) -> bool {
+ map_eth_to_id(target).is_some()
+ }
+ fn is_used(target: &H160) -> bool {
+ map_eth_to_id(target)
+ .map(<CollectionById<T>>::contains_key)
+ .unwrap_or(false)
+ }
+ fn get_code(target: &H160) -> Option<Vec<u8>> {
+ if let Some(collection_id) = map_eth_to_id(target) {
+ let collection = <CollectionById<T>>::get(collection_id)?;
+ Some(
+ match collection.mode {
+ CollectionMode::NFT => <NonfungibleHandle<T>>::CODE,
+ CollectionMode::Fungible(_) => <FungibleHandle<T>>::CODE,
+ CollectionMode::ReFungible => <RefungibleHandle<T>>::CODE,
+ }
+ .to_owned(),
+ )
+ } else if let Some((collection_id, _token_id)) =
+ <T as pallet_common::Config>::EvmTokenAddressMapping::address_to_token(target)
+ {
+ let collection = <CollectionById<T>>::get(collection_id)?;
+ if collection.mode != CollectionMode::ReFungible {
+ return None;
+ }
+ // TODO: check token existence
+ Some(<RefungibleTokenHandle<T>>::CODE.to_owned())
+ } else {
+ None
+ }
+ }
+ fn call(handle: &mut impl PrecompileHandle) -> Option<PrecompileResult> {
+ if let Some(collection_id) = map_eth_to_id(&handle.code_address()) {
+ let collection =
+ <CollectionHandle<T>>::new_with_gas_limit(collection_id, handle.remaining_gas())?;
+ let dispatched = Self::dispatch(collection);
+
+ match dispatched {
+ Self::Fungible(h) => h.call(handle),
+ Self::Nonfungible(h) => h.call(handle),
+ Self::Refungible(h) => h.call(handle),
+ }
+ } else if let Some((collection_id, token_id)) =
+ <T as pallet_common::Config>::EvmTokenAddressMapping::address_to_token(
+ &handle.code_address(),
+ ) {
+ let collection =
+ <CollectionHandle<T>>::new_with_gas_limit(collection_id, handle.remaining_gas())?;
+ if collection.mode != CollectionMode::ReFungible {
+ return None;
+ }
+
+ let h = RefungibleHandle::cast(collection);
+ // TODO: check token existence
+ RefungibleTokenHandle(h, token_id).call(handle)
+ } else {
+ None
+ }
+ }
+}
runtime/common/ethereum/mod.rsdiffbeforeafterboth--- /dev/null
+++ b/runtime/common/ethereum/mod.rs
@@ -0,0 +1,19 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+pub mod self_contained_call;
+pub mod sponsoring;
+pub mod transaction_converter;
runtime/common/ethereum/self_contained_call.rsdiffbeforeafterboth--- /dev/null
+++ b/runtime/common/ethereum/self_contained_call.rs
@@ -0,0 +1,74 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+use sp_core::H160;
+use sp_runtime::{
+ traits::{Dispatchable, DispatchInfoOf, PostDispatchInfoOf},
+ transaction_validity::{TransactionValidityError, TransactionValidity},
+};
+use crate::{Origin, Call};
+
+impl fp_self_contained::SelfContainedCall for Call {
+ type SignedInfo = H160;
+
+ fn is_self_contained(&self) -> bool {
+ match self {
+ Call::Ethereum(call) => call.is_self_contained(),
+ _ => false,
+ }
+ }
+
+ fn check_self_contained(&self) -> Option<Result<Self::SignedInfo, TransactionValidityError>> {
+ match self {
+ Call::Ethereum(call) => call.check_self_contained(),
+ _ => None,
+ }
+ }
+
+ fn validate_self_contained(
+ &self,
+ info: &Self::SignedInfo,
+ dispatch_info: &DispatchInfoOf<Call>,
+ len: usize,
+ ) -> Option<TransactionValidity> {
+ match self {
+ Call::Ethereum(call) => call.validate_self_contained(info, dispatch_info, len),
+ _ => None,
+ }
+ }
+
+ fn pre_dispatch_self_contained(
+ &self,
+ info: &Self::SignedInfo,
+ ) -> Option<Result<(), TransactionValidityError>> {
+ match self {
+ Call::Ethereum(call) => call.pre_dispatch_self_contained(info),
+ _ => None,
+ }
+ }
+
+ fn apply_self_contained(
+ self,
+ info: Self::SignedInfo,
+ ) -> Option<sp_runtime::DispatchResultWithInfo<PostDispatchInfoOf<Self>>> {
+ match self {
+ call @ Call::Ethereum(pallet_ethereum::Call::transact { .. }) => Some(call.dispatch(
+ Origin::from(pallet_ethereum::RawOrigin::EthereumTransaction(info)),
+ )),
+ _ => None,
+ }
+ }
+}
runtime/common/ethereum/sponsoring.rsdiffbeforeafterboth--- /dev/null
+++ b/runtime/common/ethereum/sponsoring.rs
@@ -0,0 +1,127 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+//! Implements EVM sponsoring logic via TransactionValidityHack
+
+use evm_coder::{Call, abi::AbiReader};
+use pallet_common::{CollectionHandle, eth::map_eth_to_id};
+use sp_core::H160;
+use sp_std::prelude::*;
+use up_sponsorship::SponsorshipHandler;
+use core::marker::PhantomData;
+use core::convert::TryInto;
+use pallet_evm::account::CrossAccountId;
+use up_data_structs::{TokenId, CreateItemData, CreateNftData, CollectionMode};
+use pallet_unique::Config as UniqueConfig;
+
+use crate::{Runtime, runtime_common::sponsoring::*};
+
+use pallet_nonfungible::erc::{
+ UniqueNFTCall, ERC721UniqueExtensionsCall, ERC721MintableCall, ERC721Call, TokenPropertiesCall,
+};
+use pallet_fungible::erc::{UniqueFungibleCall, ERC20Call};
+use pallet_fungible::Config as FungibleConfig;
+use pallet_nonfungible::Config as NonfungibleConfig;
+use pallet_refungible::Config as RefungibleConfig;
+
+pub type EvmSponsorshipHandler = (
+ UniqueEthSponsorshipHandler<Runtime>,
+ pallet_evm_contract_helpers::HelpersContractSponsoring<Runtime>,
+);
+
+pub struct UniqueEthSponsorshipHandler<T: UniqueConfig>(PhantomData<*const T>);
+impl<T: UniqueConfig + FungibleConfig + NonfungibleConfig + RefungibleConfig>
+ 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)?;
+ let sponsor = collection.sponsorship.sponsor()?.clone();
+ let (method_id, mut reader) = AbiReader::new_call(&call.1).ok()?;
+ Some(T::CrossAccountId::from_sub(match &collection.mode {
+ CollectionMode::NFT => {
+ let call = <UniqueNFTCall<T>>::parse(method_id, &mut reader).ok()??;
+ match call {
+ UniqueNFTCall::TokenProperties(TokenPropertiesCall::SetProperty {
+ token_id,
+ key,
+ value,
+ ..
+ }) => {
+ let token_id: TokenId = token_id.try_into().ok()?;
+ withdraw_set_token_property::<T>(
+ &collection,
+ &who,
+ &token_id,
+ key.len() + value.len(),
+ )
+ .map(|()| sponsor)
+ }
+ UniqueNFTCall::ERC721UniqueExtensions(
+ ERC721UniqueExtensionsCall::Transfer { token_id, .. },
+ ) => {
+ let token_id: TokenId = token_id.try_into().ok()?;
+ withdraw_transfer::<T>(&collection, &who, &token_id).map(|()| sponsor)
+ }
+ UniqueNFTCall::ERC721Mintable(
+ ERC721MintableCall::Mint { token_id, .. }
+ | ERC721MintableCall::MintWithTokenUri { token_id, .. },
+ ) => {
+ let _token_id: TokenId = token_id.try_into().ok()?;
+ withdraw_create_item::<T>(
+ &collection,
+ &who,
+ &CreateItemData::NFT(CreateNftData::default()),
+ )
+ .map(|()| sponsor)
+ }
+ UniqueNFTCall::ERC721(ERC721Call::TransferFrom { token_id, from, .. }) => {
+ let token_id: TokenId = token_id.try_into().ok()?;
+ let from = T::CrossAccountId::from_eth(from);
+ withdraw_transfer::<T>(&collection, &from, &token_id).map(|()| sponsor)
+ }
+ UniqueNFTCall::ERC721(ERC721Call::Approve { token_id, .. }) => {
+ let token_id: TokenId = token_id.try_into().ok()?;
+ withdraw_approve::<T>(&collection, who.as_sub(), &token_id)
+ .map(|()| sponsor)
+ }
+ _ => None,
+ }
+ }
+ CollectionMode::Fungible(_) => {
+ let call = <UniqueFungibleCall<T>>::parse(method_id, &mut reader).ok()??;
+ #[allow(clippy::single_match)]
+ match call {
+ UniqueFungibleCall::ERC20(ERC20Call::Transfer { .. }) => {
+ withdraw_transfer::<T>(&collection, who, &TokenId::default())
+ .map(|()| sponsor)
+ }
+ UniqueFungibleCall::ERC20(ERC20Call::TransferFrom { from, .. }) => {
+ let from = T::CrossAccountId::from_eth(from);
+ withdraw_transfer::<T>(&collection, &from, &TokenId::default())
+ .map(|()| sponsor)
+ }
+ UniqueFungibleCall::ERC20(ERC20Call::Approve { .. }) => {
+ withdraw_approve::<T>(&collection, who.as_sub(), &TokenId::default())
+ .map(|()| sponsor)
+ }
+ _ => None,
+ }
+ }
+ _ => None,
+ }?))
+ }
+}
runtime/common/ethereum/transaction_converter.rsdiffbeforeafterboth--- /dev/null
+++ b/runtime/common/ethereum/transaction_converter.rs
@@ -0,0 +1,42 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+use codec::{Encode, Decode};
+use crate::{opaque, Runtime, UncheckedExtrinsic};
+
+pub struct TransactionConverter;
+
+impl fp_rpc::ConvertTransaction<UncheckedExtrinsic> for TransactionConverter {
+ fn convert_transaction(&self, transaction: pallet_ethereum::Transaction) -> UncheckedExtrinsic {
+ UncheckedExtrinsic::new_unsigned(
+ pallet_ethereum::Call::<Runtime>::transact { transaction }.into(),
+ )
+ }
+}
+
+impl fp_rpc::ConvertTransaction<opaque::UncheckedExtrinsic> for TransactionConverter {
+ fn convert_transaction(
+ &self,
+ transaction: pallet_ethereum::Transaction,
+ ) -> opaque::UncheckedExtrinsic {
+ let extrinsic = UncheckedExtrinsic::new_unsigned(
+ pallet_ethereum::Call::<Runtime>::transact { transaction }.into(),
+ );
+ let encoded = extrinsic.encode();
+ opaque::UncheckedExtrinsic::decode(&mut &encoded[..])
+ .expect("Encoded extrinsic is always valid")
+ }
+}
runtime/common/instance.rsdiffbeforeafterboth--- /dev/null
+++ b/runtime/common/instance.rs
@@ -0,0 +1,16 @@
+use crate::{
+ runtime_common::{
+ config::ethereum::CrossAccountId, ethereum::transaction_converter::TransactionConverter,
+ },
+ Runtime,
+};
+use up_common::types::opaque::RuntimeInstance;
+
+impl RuntimeInstance for Runtime {
+ type CrossAccountId = CrossAccountId;
+ type TransactionConverter = TransactionConverter;
+
+ fn get_transaction_converter() -> TransactionConverter {
+ TransactionConverter
+ }
+}
runtime/common/mod.rsdiffbeforeafterboth--- /dev/null
+++ b/runtime/common/mod.rs
@@ -0,0 +1,168 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+pub mod config;
+pub mod constants;
+pub mod construct_runtime;
+pub mod dispatch;
+pub mod ethereum;
+pub mod instance;
+pub mod runtime_apis;
+pub mod scheduler;
+pub mod sponsoring;
+pub mod weights;
+
+use sp_core::H160;
+use frame_support::traits::{Currency, OnUnbalanced, Imbalance};
+use sp_runtime::{
+ generic,
+ traits::{BlakeTwo256, BlockNumberProvider},
+ impl_opaque_keys,
+};
+use sp_std::vec::Vec;
+
+#[cfg(feature = "std")]
+use sp_version::NativeVersion;
+
+use crate::{
+ Runtime, Call, Balances, Treasury, Aura, Signature, AllPalletsReversedWithSystemFirst,
+ InherentDataExt,
+};
+use up_common::types::{AccountId, BlockNumber};
+
+#[macro_export]
+macro_rules! unsupported {
+ () => {
+ pallet_common::unsupported!($crate::Runtime)
+ };
+}
+
+/// The address format for describing accounts.
+pub type Address = sp_runtime::MultiAddress<AccountId, ()>;
+/// Block header type as expected by this runtime.
+pub type Header = generic::Header<BlockNumber, BlakeTwo256>;
+/// Block type as expected by this runtime.
+pub type Block = generic::Block<Header, UncheckedExtrinsic>;
+/// A Block signed with a Justification
+pub type SignedBlock = generic::SignedBlock<Block>;
+/// BlockId type as expected by this runtime.
+pub type BlockId = generic::BlockId<Block>;
+
+impl_opaque_keys! {
+ pub struct SessionKeys {
+ pub aura: Aura,
+ }
+}
+
+/// The version information used to identify this runtime when compiled natively.
+#[cfg(feature = "std")]
+pub fn native_version() -> NativeVersion {
+ NativeVersion {
+ runtime_version: crate::VERSION,
+ can_author_with: Default::default(),
+ }
+}
+
+pub type ChargeTransactionPayment = pallet_charge_transaction::ChargeTransactionPayment<Runtime>;
+
+pub type SignedExtra = (
+ frame_system::CheckSpecVersion<Runtime>,
+ // system::CheckTxVersion<Runtime>,
+ frame_system::CheckGenesis<Runtime>,
+ frame_system::CheckEra<Runtime>,
+ frame_system::CheckNonce<Runtime>,
+ frame_system::CheckWeight<Runtime>,
+ ChargeTransactionPayment,
+ //pallet_contract_helpers::ContractHelpersExtension<Runtime>,
+ pallet_ethereum::FakeTransactionFinalizer<Runtime>,
+);
+
+/// Unchecked extrinsic type as expected by this runtime.
+pub type UncheckedExtrinsic =
+ fp_self_contained::UncheckedExtrinsic<Address, Call, Signature, SignedExtra>;
+
+/// Extrinsic type that has already been checked.
+pub type CheckedExtrinsic = fp_self_contained::CheckedExtrinsic<AccountId, Call, SignedExtra, H160>;
+
+/// Executive: handles dispatch to the various modules.
+pub type Executive = frame_executive::Executive<
+ Runtime,
+ Block,
+ frame_system::ChainContext<Runtime>,
+ Runtime,
+ AllPalletsReversedWithSystemFirst,
+>;
+
+type NegativeImbalance = <Balances as Currency<AccountId>>::NegativeImbalance;
+
+pub struct DealWithFees;
+impl OnUnbalanced<NegativeImbalance> for DealWithFees {
+ fn on_unbalanceds<B>(mut fees_then_tips: impl Iterator<Item = NegativeImbalance>) {
+ if let Some(fees) = fees_then_tips.next() {
+ // for fees, 100% to treasury
+ let mut split = fees.ration(100, 0);
+ if let Some(tips) = fees_then_tips.next() {
+ // for tips, if any, 100% to treasury
+ tips.ration_merge_into(100, 0, &mut split);
+ }
+ Treasury::on_unbalanced(split.0);
+ // Author::on_unbalanced(split.1);
+ }
+ }
+}
+
+pub struct RelayChainBlockNumberProvider<T>(sp_std::marker::PhantomData<T>);
+
+impl<T: cumulus_pallet_parachain_system::Config> BlockNumberProvider
+ for RelayChainBlockNumberProvider<T>
+{
+ type BlockNumber = BlockNumber;
+
+ fn current_block_number() -> Self::BlockNumber {
+ cumulus_pallet_parachain_system::Pallet::<T>::validation_data()
+ .map(|d| d.relay_parent_number)
+ .unwrap_or_default()
+ }
+}
+
+pub(crate) struct CheckInherents;
+
+impl cumulus_pallet_parachain_system::CheckInherents<Block> for CheckInherents {
+ fn check_inherents(
+ block: &Block,
+ relay_state_proof: &cumulus_pallet_parachain_system::RelayChainStateProof,
+ ) -> sp_inherents::CheckInherentsResult {
+ let relay_chain_slot = relay_state_proof
+ .read_slot()
+ .expect("Could not read the relay chain slot from the proof");
+
+ let inherent_data =
+ cumulus_primitives_timestamp::InherentDataProvider::from_relay_chain_slot_and_duration(
+ relay_chain_slot,
+ sp_std::time::Duration::from_secs(6),
+ )
+ .create_inherent_data()
+ .expect("Could not create the timestamp inherent data");
+
+ inherent_data.check_extrinsics(block)
+ }
+}
+
+#[derive(codec::Encode, codec::Decode)]
+pub enum XCMPMessage<XAccountId, XBalance> {
+ /// Transfer tokens to the given account from the Parachain account.
+ TransferToken(XAccountId, XBalance),
+}
runtime/common/runtime_apis.rsdiffbeforeafterboth--- /dev/null
+++ b/runtime/common/runtime_apis.rs
@@ -0,0 +1,724 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+#[macro_export]
+macro_rules! dispatch_unique_runtime {
+ ($collection:ident.$method:ident($($name:ident),*)) => {{
+ let collection = <Runtime as pallet_common::Config>::CollectionDispatch::dispatch(<pallet_common::CollectionHandle<Runtime>>::try_get($collection)?);
+ let dispatch = collection.as_dyn();
+
+ Ok::<_, DispatchError>(dispatch.$method($($name),*))
+ }};
+}
+
+#[macro_export]
+macro_rules! impl_common_runtime_apis {
+ (
+ $(
+ #![custom_apis]
+
+ $($custom_apis:tt)+
+ )?
+ ) => {
+ use sp_std::prelude::*;
+ use sp_api::impl_runtime_apis;
+ use sp_core::{crypto::KeyTypeId, OpaqueMetadata, H256, U256, H160};
+ use sp_runtime::{
+ Permill,
+ traits::Block as BlockT,
+ transaction_validity::{TransactionSource, TransactionValidity},
+ ApplyExtrinsicResult, DispatchError,
+ };
+ use fp_rpc::TransactionStatus;
+ use pallet_transaction_payment::{
+ FeeDetails, RuntimeDispatchInfo,
+ };
+ use pallet_evm::{
+ Runner, account::CrossAccountId as _,
+ Account as EVMAccount, FeeCalculator,
+ };
+ use runtime_common::{
+ sponsoring::{SponsorshipPredict, UniqueSponsorshipPredict},
+ dispatch::CollectionDispatch,
+ config::ethereum::CrossAccountId,
+ };
+ use up_data_structs::*;
+
+
+ impl_runtime_apis! {
+ $($($custom_apis)+)?
+
+ impl up_rpc::UniqueApi<Block, CrossAccountId, AccountId> for Runtime {
+ fn account_tokens(collection: CollectionId, account: CrossAccountId) -> Result<Vec<TokenId>, DispatchError> {
+ dispatch_unique_runtime!(collection.account_tokens(account))
+ }
+ fn collection_tokens(collection: CollectionId) -> Result<Vec<TokenId>, DispatchError> {
+ dispatch_unique_runtime!(collection.collection_tokens())
+ }
+ fn token_exists(collection: CollectionId, token: TokenId) -> Result<bool, DispatchError> {
+ dispatch_unique_runtime!(collection.token_exists(token))
+ }
+
+ fn token_owner(collection: CollectionId, token: TokenId) -> Result<Option<CrossAccountId>, DispatchError> {
+ dispatch_unique_runtime!(collection.token_owner(token))
+ }
+
+ fn token_owners(collection: CollectionId, token: TokenId) -> Result<Vec::<CrossAccountId>, DispatchError> {
+ dispatch_unique_runtime!(collection.token_owners(token))
+ }
+
+ fn topmost_token_owner(collection: CollectionId, token: TokenId) -> Result<Option<CrossAccountId>, DispatchError> {
+ let budget = up_data_structs::budget::Value::new(10);
+
+ Ok(Some(<pallet_structure::Pallet<Runtime>>::find_topmost_owner(collection, token, &budget)?))
+ }
+ fn token_children(collection: CollectionId, token: TokenId) -> Result<Vec<TokenChild>, DispatchError> {
+ Ok(<pallet_nonfungible::Pallet<Runtime>>::token_children_ids(collection, token))
+ }
+ fn collection_properties(
+ collection: CollectionId,
+ keys: Option<Vec<Vec<u8>>>
+ ) -> Result<Vec<Property>, DispatchError> {
+ let keys = keys.map(
+ |keys| Common::bytes_keys_to_property_keys(keys)
+ ).transpose()?;
+
+ Common::filter_collection_properties(collection, keys)
+ }
+
+ fn token_properties(
+ collection: CollectionId,
+ token_id: TokenId,
+ keys: Option<Vec<Vec<u8>>>
+ ) -> Result<Vec<Property>, DispatchError> {
+ let keys = keys.map(
+ |keys| Common::bytes_keys_to_property_keys(keys)
+ ).transpose()?;
+
+ dispatch_unique_runtime!(collection.token_properties(token_id, keys))
+ }
+
+ fn property_permissions(
+ collection: CollectionId,
+ keys: Option<Vec<Vec<u8>>>
+ ) -> Result<Vec<PropertyKeyPermission>, DispatchError> {
+ let keys = keys.map(
+ |keys| Common::bytes_keys_to_property_keys(keys)
+ ).transpose()?;
+
+ Common::filter_property_permissions(collection, keys)
+ }
+
+ fn token_data(
+ collection: CollectionId,
+ token_id: TokenId,
+ keys: Option<Vec<Vec<u8>>>
+ ) -> Result<TokenData<CrossAccountId>, DispatchError> {
+ let token_data = TokenData {
+ properties: Self::token_properties(collection, token_id, keys)?,
+ owner: Self::token_owner(collection, token_id)?,
+ pieces: Self::total_pieces(collection, token_id)?.unwrap_or(0),
+ };
+
+ Ok(token_data)
+ }
+
+ fn total_supply(collection: CollectionId) -> Result<u32, DispatchError> {
+ dispatch_unique_runtime!(collection.total_supply())
+ }
+ fn account_balance(collection: CollectionId, account: CrossAccountId) -> Result<u32, DispatchError> {
+ dispatch_unique_runtime!(collection.account_balance(account))
+ }
+ fn balance(collection: CollectionId, account: CrossAccountId, token: TokenId) -> Result<u128, DispatchError> {
+ dispatch_unique_runtime!(collection.balance(account, token))
+ }
+ fn allowance(
+ collection: CollectionId,
+ sender: CrossAccountId,
+ spender: CrossAccountId,
+ token: TokenId,
+ ) -> Result<u128, DispatchError> {
+ dispatch_unique_runtime!(collection.allowance(sender, spender, token))
+ }
+
+ fn adminlist(collection: CollectionId) -> Result<Vec<CrossAccountId>, DispatchError> {
+ Ok(<pallet_common::Pallet<Runtime>>::adminlist(collection))
+ }
+ fn allowlist(collection: CollectionId) -> Result<Vec<CrossAccountId>, DispatchError> {
+ Ok(<pallet_common::Pallet<Runtime>>::allowlist(collection))
+ }
+ fn allowed(collection: CollectionId, user: CrossAccountId) -> Result<bool, DispatchError> {
+ Ok(<pallet_common::Pallet<Runtime>>::allowed(collection, user))
+ }
+ fn last_token_id(collection: CollectionId) -> Result<TokenId, DispatchError> {
+ dispatch_unique_runtime!(collection.last_token_id())
+ }
+ fn collection_by_id(collection: CollectionId) -> Result<Option<RpcCollection<AccountId>>, DispatchError> {
+ Ok(<pallet_common::Pallet<Runtime>>::rpc_collection(collection))
+ }
+ fn collection_stats() -> Result<CollectionStats, DispatchError> {
+ Ok(<pallet_common::Pallet<Runtime>>::collection_stats())
+ }
+ fn next_sponsored(collection: CollectionId, account: CrossAccountId, token: TokenId) -> Result<Option<u64>, DispatchError> {
+ Ok(<UniqueSponsorshipPredict<Runtime> as SponsorshipPredict<Runtime>>::predict(
+ collection,
+ account,
+ token
+ ))
+ }
+
+ fn effective_collection_limits(collection: CollectionId) -> Result<Option<CollectionLimits>, DispatchError> {
+ Ok(<pallet_common::Pallet<Runtime>>::effective_collection_limits(collection))
+ }
+
+ fn total_pieces(collection: CollectionId, token_id: TokenId) -> Result<Option<u128>, DispatchError> {
+ dispatch_unique_runtime!(collection.total_pieces(token_id))
+ }
+ }
+
+ impl rmrk_rpc::RmrkApi<
+ Block,
+ AccountId,
+ RmrkCollectionInfo<AccountId>,
+ RmrkInstanceInfo<AccountId>,
+ RmrkResourceInfo,
+ RmrkPropertyInfo,
+ RmrkBaseInfo<AccountId>,
+ RmrkPartType,
+ RmrkTheme
+ > for Runtime {
+ fn last_collection_idx() -> Result<RmrkCollectionId, DispatchError> {
+ #[cfg(feature = "rmrk")]
+ return pallet_proxy_rmrk_core::rpc::last_collection_idx::<Runtime>();
+
+ #[cfg(not(feature = "rmrk"))]
+ return unsupported!();
+ }
+
+ #[allow(unused_variables)]
+ fn collection_by_id(collection_id: RmrkCollectionId) -> Result<Option<RmrkCollectionInfo<AccountId>>, DispatchError> {
+ #[cfg(feature = "rmrk")]
+ return pallet_proxy_rmrk_core::rpc::collection_by_id::<Runtime>(collection_id);
+
+ #[cfg(not(feature = "rmrk"))]
+ return unsupported!();
+ }
+
+ #[allow(unused_variables)]
+ fn nft_by_id(collection_id: RmrkCollectionId, nft_by_id: RmrkNftId) -> Result<Option<RmrkInstanceInfo<AccountId>>, DispatchError> {
+ #[cfg(feature = "rmrk")]
+ return pallet_proxy_rmrk_core::rpc::nft_by_id::<Runtime>(collection_id, nft_by_id);
+
+ #[cfg(not(feature = "rmrk"))]
+ return unsupported!();
+ }
+
+ #[allow(unused_variables)]
+ fn account_tokens(account_id: AccountId, collection_id: RmrkCollectionId) -> Result<Vec<RmrkNftId>, DispatchError> {
+ #[cfg(feature = "rmrk")]
+ return pallet_proxy_rmrk_core::rpc::account_tokens::<Runtime>(account_id, collection_id);
+
+ #[cfg(not(feature = "rmrk"))]
+ return unsupported!();
+ }
+
+ #[allow(unused_variables)]
+ fn nft_children(collection_id: RmrkCollectionId, nft_id: RmrkNftId) -> Result<Vec<RmrkNftChild>, DispatchError> {
+ #[cfg(feature = "rmrk")]
+ return pallet_proxy_rmrk_core::rpc::nft_children::<Runtime>(collection_id, nft_id);
+
+ #[cfg(not(feature = "rmrk"))]
+ return unsupported!();
+ }
+
+ #[allow(unused_variables)]
+ fn collection_properties(
+ collection_id: RmrkCollectionId,
+ filter_keys: Option<Vec<RmrkPropertyKey>>
+ ) -> Result<Vec<RmrkPropertyInfo>, DispatchError> {
+ #[cfg(feature = "rmrk")]
+ return pallet_proxy_rmrk_core::rpc::collection_properties::<Runtime>(collection_id, filter_keys);
+
+ #[cfg(not(feature = "rmrk"))]
+ return unsupported!();
+ }
+
+ #[allow(unused_variables)]
+ fn nft_properties(
+ collection_id: RmrkCollectionId,
+ nft_id: RmrkNftId,
+ filter_keys: Option<Vec<RmrkPropertyKey>>
+ ) -> Result<Vec<RmrkPropertyInfo>, DispatchError> {
+ #[cfg(feature = "rmrk")]
+ return pallet_proxy_rmrk_core::rpc::nft_properties::<Runtime>(collection_id, nft_id, filter_keys);
+
+ #[cfg(not(feature = "rmrk"))]
+ return unsupported!();
+ }
+
+ #[allow(unused_variables)]
+ fn nft_resources(collection_id: RmrkCollectionId,nft_id: RmrkNftId) -> Result<Vec<RmrkResourceInfo>, DispatchError> {
+ #[cfg(feature = "rmrk")]
+ return pallet_proxy_rmrk_core::rpc::nft_resources::<Runtime>(collection_id, nft_id);
+
+ #[cfg(not(feature = "rmrk"))]
+ return unsupported!();
+ }
+
+ #[allow(unused_variables)]
+ fn nft_resource_priority(
+ collection_id: RmrkCollectionId,
+ nft_id: RmrkNftId,
+ resource_id: RmrkResourceId
+ ) -> Result<Option<u32>, DispatchError> {
+ #[cfg(feature = "rmrk")]
+ return pallet_proxy_rmrk_core::rpc::nft_resource_priority::<Runtime>(collection_id, nft_id, resource_id);
+
+ #[cfg(not(feature = "rmrk"))]
+ return unsupported!();
+ }
+
+ #[allow(unused_variables)]
+ fn base(base_id: RmrkBaseId) -> Result<Option<RmrkBaseInfo<AccountId>>, DispatchError> {
+ #[cfg(feature = "rmrk")]
+ return pallet_proxy_rmrk_equip::rpc::base::<Runtime>(base_id);
+
+ #[cfg(not(feature = "rmrk"))]
+ return unsupported!();
+ }
+
+ #[allow(unused_variables)]
+ fn base_parts(base_id: RmrkBaseId) -> Result<Vec<RmrkPartType>, DispatchError> {
+ #[cfg(feature = "rmrk")]
+ return pallet_proxy_rmrk_equip::rpc::base_parts::<Runtime>(base_id);
+
+ #[cfg(not(feature = "rmrk"))]
+ return unsupported!();
+ }
+
+ #[allow(unused_variables)]
+ fn theme_names(base_id: RmrkBaseId) -> Result<Vec<RmrkThemeName>, DispatchError> {
+ #[cfg(feature = "rmrk")]
+ return pallet_proxy_rmrk_equip::rpc::theme_names::<Runtime>(base_id);
+
+ #[cfg(not(feature = "rmrk"))]
+ return unsupported!();
+ }
+
+ #[allow(unused_variables)]
+ fn theme(
+ base_id: RmrkBaseId,
+ theme_name: RmrkThemeName,
+ filter_keys: Option<Vec<RmrkPropertyKey>>
+ ) -> Result<Option<RmrkTheme>, DispatchError> {
+ #[cfg(feature = "rmrk")]
+ return pallet_proxy_rmrk_equip::rpc::theme::<Runtime>(base_id, theme_name, filter_keys);
+
+ #[cfg(not(feature = "rmrk"))]
+ return unsupported!();
+ }
+ }
+
+ impl sp_api::Core<Block> for Runtime {
+ fn version() -> RuntimeVersion {
+ VERSION
+ }
+
+ fn execute_block(block: Block) {
+ Executive::execute_block(block)
+ }
+
+ fn initialize_block(header: &<Block as BlockT>::Header) {
+ Executive::initialize_block(header)
+ }
+ }
+
+ impl sp_api::Metadata<Block> for Runtime {
+ fn metadata() -> OpaqueMetadata {
+ OpaqueMetadata::new(Runtime::metadata().into())
+ }
+ }
+
+ impl sp_block_builder::BlockBuilder<Block> for Runtime {
+ fn apply_extrinsic(extrinsic: <Block as BlockT>::Extrinsic) -> ApplyExtrinsicResult {
+ Executive::apply_extrinsic(extrinsic)
+ }
+
+ fn finalize_block() -> <Block as BlockT>::Header {
+ Executive::finalize_block()
+ }
+
+ fn inherent_extrinsics(data: sp_inherents::InherentData) -> Vec<<Block as BlockT>::Extrinsic> {
+ data.create_extrinsics()
+ }
+
+ fn check_inherents(
+ block: Block,
+ data: sp_inherents::InherentData,
+ ) -> sp_inherents::CheckInherentsResult {
+ data.check_extrinsics(&block)
+ }
+
+ // fn random_seed() -> <Block as BlockT>::Hash {
+ // RandomnessCollectiveFlip::random_seed().0
+ // }
+ }
+
+ impl sp_transaction_pool::runtime_api::TaggedTransactionQueue<Block> for Runtime {
+ fn validate_transaction(
+ source: TransactionSource,
+ tx: <Block as BlockT>::Extrinsic,
+ hash: <Block as BlockT>::Hash,
+ ) -> TransactionValidity {
+ Executive::validate_transaction(source, tx, hash)
+ }
+ }
+
+ impl sp_offchain::OffchainWorkerApi<Block> for Runtime {
+ fn offchain_worker(header: &<Block as BlockT>::Header) {
+ Executive::offchain_worker(header)
+ }
+ }
+
+ impl fp_rpc::EthereumRuntimeRPCApi<Block> for Runtime {
+ fn chain_id() -> u64 {
+ <Runtime as pallet_evm::Config>::ChainId::get()
+ }
+
+ fn account_basic(address: H160) -> EVMAccount {
+ let (account, _) = EVM::account_basic(&address);
+ account
+ }
+
+ fn gas_price() -> U256 {
+ let (price, _) = <Runtime as pallet_evm::Config>::FeeCalculator::min_gas_price();
+ price
+ }
+
+ fn account_code_at(address: H160) -> Vec<u8> {
+ EVM::account_codes(address)
+ }
+
+ fn author() -> H160 {
+ <pallet_evm::Pallet<Runtime>>::find_author()
+ }
+
+ fn storage_at(address: H160, index: U256) -> H256 {
+ let mut tmp = [0u8; 32];
+ index.to_big_endian(&mut tmp);
+ EVM::account_storages(address, H256::from_slice(&tmp[..]))
+ }
+
+ #[allow(clippy::redundant_closure)]
+ fn call(
+ from: H160,
+ to: H160,
+ data: Vec<u8>,
+ value: U256,
+ gas_limit: U256,
+ max_fee_per_gas: Option<U256>,
+ max_priority_fee_per_gas: Option<U256>,
+ nonce: Option<U256>,
+ estimate: bool,
+ access_list: Option<Vec<(H160, Vec<H256>)>>,
+ ) -> Result<pallet_evm::CallInfo, sp_runtime::DispatchError> {
+ let config = if estimate {
+ let mut config = <Runtime as pallet_evm::Config>::config().clone();
+ config.estimate = true;
+ Some(config)
+ } else {
+ None
+ };
+
+ let is_transactional = false;
+ <Runtime as pallet_evm::Config>::Runner::call(
+ CrossAccountId::from_eth(from),
+ to,
+ data,
+ value,
+ gas_limit.low_u64(),
+ max_fee_per_gas,
+ max_priority_fee_per_gas,
+ nonce,
+ access_list.unwrap_or_default(),
+ is_transactional,
+ config.as_ref().unwrap_or_else(|| <Runtime as pallet_evm::Config>::config()),
+ ).map_err(|err| err.error.into())
+ }
+
+ #[allow(clippy::redundant_closure)]
+ fn create(
+ from: H160,
+ data: Vec<u8>,
+ value: U256,
+ gas_limit: U256,
+ max_fee_per_gas: Option<U256>,
+ max_priority_fee_per_gas: Option<U256>,
+ nonce: Option<U256>,
+ estimate: bool,
+ access_list: Option<Vec<(H160, Vec<H256>)>>,
+ ) -> Result<pallet_evm::CreateInfo, sp_runtime::DispatchError> {
+ let config = if estimate {
+ let mut config = <Runtime as pallet_evm::Config>::config().clone();
+ config.estimate = true;
+ Some(config)
+ } else {
+ None
+ };
+
+ let is_transactional = false;
+ <Runtime as pallet_evm::Config>::Runner::create(
+ CrossAccountId::from_eth(from),
+ data,
+ value,
+ gas_limit.low_u64(),
+ max_fee_per_gas,
+ max_priority_fee_per_gas,
+ nonce,
+ access_list.unwrap_or_default(),
+ is_transactional,
+ config.as_ref().unwrap_or_else(|| <Runtime as pallet_evm::Config>::config()),
+ ).map_err(|err| err.error.into())
+ }
+
+ fn current_transaction_statuses() -> Option<Vec<TransactionStatus>> {
+ Ethereum::current_transaction_statuses()
+ }
+
+ fn current_block() -> Option<pallet_ethereum::Block> {
+ Ethereum::current_block()
+ }
+
+ fn current_receipts() -> Option<Vec<pallet_ethereum::Receipt>> {
+ Ethereum::current_receipts()
+ }
+
+ fn current_all() -> (
+ Option<pallet_ethereum::Block>,
+ Option<Vec<pallet_ethereum::Receipt>>,
+ Option<Vec<TransactionStatus>>
+ ) {
+ (
+ Ethereum::current_block(),
+ Ethereum::current_receipts(),
+ Ethereum::current_transaction_statuses()
+ )
+ }
+
+ fn extrinsic_filter(xts: Vec<<Block as sp_api::BlockT>::Extrinsic>) -> Vec<pallet_ethereum::Transaction> {
+ xts.into_iter().filter_map(|xt| match xt.0.function {
+ Call::Ethereum(pallet_ethereum::Call::transact { transaction }) => Some(transaction),
+ _ => None
+ }).collect()
+ }
+
+ fn elasticity() -> Option<Permill> {
+ None
+ }
+ }
+
+ impl fp_rpc::ConvertTransactionRuntimeApi<Block> for Runtime {
+ fn convert_transaction(transaction: pallet_ethereum::Transaction) -> <Block as BlockT>::Extrinsic {
+ UncheckedExtrinsic::new_unsigned(
+ pallet_ethereum::Call::<Runtime>::transact { transaction }.into(),
+ )
+ }
+ }
+
+ impl sp_session::SessionKeys<Block> for Runtime {
+ fn decode_session_keys(
+ encoded: Vec<u8>,
+ ) -> Option<Vec<(Vec<u8>, KeyTypeId)>> {
+ SessionKeys::decode_into_raw_public_keys(&encoded)
+ }
+
+ fn generate_session_keys(seed: Option<Vec<u8>>) -> Vec<u8> {
+ SessionKeys::generate(seed)
+ }
+ }
+
+ impl sp_consensus_aura::AuraApi<Block, AuraId> for Runtime {
+ fn slot_duration() -> sp_consensus_aura::SlotDuration {
+ sp_consensus_aura::SlotDuration::from_millis(Aura::slot_duration())
+ }
+
+ fn authorities() -> Vec<AuraId> {
+ Aura::authorities().to_vec()
+ }
+ }
+
+ impl cumulus_primitives_core::CollectCollationInfo<Block> for Runtime {
+ fn collect_collation_info(header: &<Block as BlockT>::Header) -> cumulus_primitives_core::CollationInfo {
+ ParachainSystem::collect_collation_info(header)
+ }
+ }
+
+ impl frame_system_rpc_runtime_api::AccountNonceApi<Block, AccountId, Index> for Runtime {
+ fn account_nonce(account: AccountId) -> Index {
+ System::account_nonce(account)
+ }
+ }
+
+ impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi<Block, Balance> for Runtime {
+ fn query_info(uxt: <Block as BlockT>::Extrinsic, len: u32) -> RuntimeDispatchInfo<Balance> {
+ TransactionPayment::query_info(uxt, len)
+ }
+ fn query_fee_details(uxt: <Block as BlockT>::Extrinsic, len: u32) -> FeeDetails<Balance> {
+ TransactionPayment::query_fee_details(uxt, len)
+ }
+ }
+
+ /*
+ impl pallet_contracts_rpc_runtime_api::ContractsApi<Block, AccountId, Balance, BlockNumber, Hash>
+ for Runtime
+ {
+ fn call(
+ origin: AccountId,
+ dest: AccountId,
+ value: Balance,
+ gas_limit: u64,
+ input_data: Vec<u8>,
+ ) -> pallet_contracts_primitives::ContractExecResult {
+ Contracts::bare_call(origin, dest, value, gas_limit, input_data, false)
+ }
+
+ fn instantiate(
+ origin: AccountId,
+ endowment: Balance,
+ gas_limit: u64,
+ code: pallet_contracts_primitives::Code<Hash>,
+ data: Vec<u8>,
+ salt: Vec<u8>,
+ ) -> pallet_contracts_primitives::ContractInstantiateResult<AccountId, BlockNumber>
+ {
+ Contracts::bare_instantiate(origin, endowment, gas_limit, code, data, salt, true, false)
+ }
+
+ fn get_storage(
+ address: AccountId,
+ key: [u8; 32],
+ ) -> pallet_contracts_primitives::GetStorageResult {
+ Contracts::get_storage(address, key)
+ }
+
+ fn rent_projection(
+ address: AccountId,
+ ) -> pallet_contracts_primitives::RentProjectionResult<BlockNumber> {
+ Contracts::rent_projection(address)
+ }
+ }
+ */
+
+ #[cfg(feature = "runtime-benchmarks")]
+ impl frame_benchmarking::Benchmark<Block> for Runtime {
+ fn benchmark_metadata(extra: bool) -> (
+ Vec<frame_benchmarking::BenchmarkList>,
+ Vec<frame_support::traits::StorageInfo>,
+ ) {
+ use frame_benchmarking::{list_benchmark, Benchmarking, BenchmarkList};
+ use frame_support::traits::StorageInfoTrait;
+
+ let mut list = Vec::<BenchmarkList>::new();
+
+ list_benchmark!(list, extra, pallet_evm_migration, EvmMigration);
+ list_benchmark!(list, extra, pallet_common, Common);
+ list_benchmark!(list, extra, pallet_unique, Unique);
+ list_benchmark!(list, extra, pallet_structure, Structure);
+ list_benchmark!(list, extra, pallet_inflation, Inflation);
+ list_benchmark!(list, extra, pallet_fungible, Fungible);
+ list_benchmark!(list, extra, pallet_refungible, Refungible);
+ list_benchmark!(list, extra, pallet_nonfungible, Nonfungible);
+ list_benchmark!(list, extra, pallet_unique_scheduler, Scheduler);
+
+ #[cfg(not(feature = "unique-runtime"))]
+ list_benchmark!(list, extra, pallet_proxy_rmrk_core, RmrkCore);
+
+ #[cfg(not(feature = "unique-runtime"))]
+ list_benchmark!(list, extra, pallet_proxy_rmrk_equip, RmrkEquip);
+
+ // list_benchmark!(list, extra, pallet_evm_coder_substrate, EvmCoderSubstrate);
+
+ let storage_info = AllPalletsReversedWithSystemFirst::storage_info();
+
+ return (list, storage_info)
+ }
+
+ fn dispatch_benchmark(
+ config: frame_benchmarking::BenchmarkConfig
+ ) -> Result<Vec<frame_benchmarking::BenchmarkBatch>, sp_runtime::RuntimeString> {
+ use frame_benchmarking::{Benchmarking, BenchmarkBatch, add_benchmark, TrackedStorageKey};
+
+ let allowlist: Vec<TrackedStorageKey> = vec![
+ // Total Issuance
+ hex_literal::hex!("c2261276cc9d1f8598ea4b6a74b15c2f57c875e4cff74148e4628f264b974c80").to_vec().into(),
+
+ // Block Number
+ hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef702a5c1b19ab7a04f536c519aca4983ac").to_vec().into(),
+ // Execution Phase
+ hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef7ff553b5a9862a516939d82b3d3d8661a").to_vec().into(),
+ // Event Count
+ hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef70a98fdbe9ce6c55837576c60c7af3850").to_vec().into(),
+ // System Events
+ hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef780d41e5e16056765bc8461851072c9d7").to_vec().into(),
+
+ // Evm CurrentLogs
+ hex_literal::hex!("1da53b775b270400e7e61ed5cbc5a146547f210cec367e9af919603343b9cb56").to_vec().into(),
+
+ // Transactional depth
+ hex_literal::hex!("3a7472616e73616374696f6e5f6c6576656c3a").to_vec().into(),
+ ];
+
+ let mut batches = Vec::<BenchmarkBatch>::new();
+ let params = (&config, &allowlist);
+
+ add_benchmark!(params, batches, pallet_evm_migration, EvmMigration);
+ add_benchmark!(params, batches, pallet_common, Common);
+ add_benchmark!(params, batches, pallet_unique, Unique);
+ add_benchmark!(params, batches, pallet_structure, Structure);
+ add_benchmark!(params, batches, pallet_inflation, Inflation);
+ add_benchmark!(params, batches, pallet_fungible, Fungible);
+ add_benchmark!(params, batches, pallet_refungible, Refungible);
+ add_benchmark!(params, batches, pallet_nonfungible, Nonfungible);
+ add_benchmark!(params, batches, pallet_unique_scheduler, Scheduler);
+
+ #[cfg(not(feature = "unique-runtime"))]
+ add_benchmark!(params, batches, pallet_proxy_rmrk_core, RmrkCore);
+
+ #[cfg(not(feature = "unique-runtime"))]
+ add_benchmark!(params, batches, pallet_proxy_rmrk_equip, RmrkEquip);
+
+ // add_benchmark!(params, batches, pallet_evm_coder_substrate, EvmCoderSubstrate);
+
+ if batches.is_empty() { return Err("Benchmark not found for this pallet.".into()) }
+ Ok(batches)
+ }
+ }
+
+ #[cfg(feature = "try-runtime")]
+ impl frame_try_runtime::TryRuntime<Block> for Runtime {
+ fn on_runtime_upgrade() -> (Weight, Weight) {
+ log::info!("try-runtime::on_runtime_upgrade unique-chain.");
+ let weight = Executive::try_runtime_upgrade().unwrap();
+ (weight, RuntimeBlockWeights::get().max_block)
+ }
+
+ fn execute_block_no_check(block: Block) -> Weight {
+ Executive::execute_block_no_check(block)
+ }
+ }
+ }
+ }
+}
runtime/common/scheduler.rsdiffbeforeafterboth--- /dev/null
+++ b/runtime/common/scheduler.rs
@@ -0,0 +1,141 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+use frame_support::{
+ traits::NamedReservableCurrency,
+ weights::{GetDispatchInfo, PostDispatchInfo, DispatchInfo},
+};
+use sp_runtime::{
+ traits::{Dispatchable, Applyable, Member},
+ generic::Era,
+ transaction_validity::TransactionValidityError,
+ DispatchErrorWithPostInfo, DispatchError,
+};
+use crate::{Runtime, Call, Origin, Balances, ChargeTransactionPayment};
+use up_common::types::{AccountId, Balance};
+use fp_self_contained::SelfContainedCall;
+use pallet_unique_scheduler::DispatchCall;
+
+/// The SignedExtension to the basic transaction logic.
+pub type SignedExtraScheduler = (
+ frame_system::CheckSpecVersion<Runtime>,
+ frame_system::CheckGenesis<Runtime>,
+ frame_system::CheckEra<Runtime>,
+ frame_system::CheckNonce<Runtime>,
+ frame_system::CheckWeight<Runtime>,
+);
+
+fn get_signed_extras(from: <Runtime as frame_system::Config>::AccountId) -> SignedExtraScheduler {
+ (
+ frame_system::CheckSpecVersion::<Runtime>::new(),
+ frame_system::CheckGenesis::<Runtime>::new(),
+ frame_system::CheckEra::<Runtime>::from(Era::Immortal),
+ frame_system::CheckNonce::<Runtime>::from(frame_system::Pallet::<Runtime>::account_nonce(
+ from,
+ )),
+ frame_system::CheckWeight::<Runtime>::new(),
+ // sponsoring transaction logic
+ // pallet_charge_transaction::ChargeTransactionPayment::<Runtime>::new(0),
+ )
+}
+
+pub struct SchedulerPaymentExecutor;
+
+impl<T: frame_system::Config + pallet_unique_scheduler::Config, SelfContainedSignedInfo>
+ DispatchCall<T, SelfContainedSignedInfo> for SchedulerPaymentExecutor
+where
+ <T as frame_system::Config>::Call: Member
+ + Dispatchable<Origin = Origin, Info = DispatchInfo>
+ + SelfContainedCall<SignedInfo = SelfContainedSignedInfo>
+ + GetDispatchInfo
+ + From<frame_system::Call<Runtime>>,
+ SelfContainedSignedInfo: Send + Sync + 'static,
+ Call: From<<T as frame_system::Config>::Call>
+ + From<<T as pallet_unique_scheduler::Config>::Call>
+ + SelfContainedCall<SignedInfo = SelfContainedSignedInfo>,
+ sp_runtime::AccountId32: From<<T as frame_system::Config>::AccountId>,
+{
+ fn dispatch_call(
+ signer: <T as frame_system::Config>::AccountId,
+ call: <T as pallet_unique_scheduler::Config>::Call,
+ ) -> Result<
+ Result<PostDispatchInfo, DispatchErrorWithPostInfo<PostDispatchInfo>>,
+ TransactionValidityError,
+ > {
+ let dispatch_info = call.get_dispatch_info();
+ let extrinsic = fp_self_contained::CheckedExtrinsic::<
+ AccountId,
+ Call,
+ SignedExtraScheduler,
+ SelfContainedSignedInfo,
+ > {
+ signed: fp_self_contained::CheckedSignature::<
+ AccountId,
+ SignedExtraScheduler,
+ SelfContainedSignedInfo,
+ >::Signed(signer.clone().into(), get_signed_extras(signer.into())),
+ function: call.into(),
+ };
+
+ extrinsic.apply::<Runtime>(&dispatch_info, 0)
+ }
+
+ fn reserve_balance(
+ id: [u8; 16],
+ sponsor: <T as frame_system::Config>::AccountId,
+ call: <T as pallet_unique_scheduler::Config>::Call,
+ count: u32,
+ ) -> Result<(), DispatchError> {
+ let dispatch_info = call.get_dispatch_info();
+ let weight: Balance = ChargeTransactionPayment::traditional_fee(0, &dispatch_info, 0)
+ .saturating_mul(count.into());
+
+ <Balances as NamedReservableCurrency<AccountId>>::reserve_named(
+ &id,
+ &(sponsor.into()),
+ weight,
+ )
+ }
+
+ fn pay_for_call(
+ id: [u8; 16],
+ sponsor: <T as frame_system::Config>::AccountId,
+ call: <T as pallet_unique_scheduler::Config>::Call,
+ ) -> Result<u128, DispatchError> {
+ let dispatch_info = call.get_dispatch_info();
+ let weight: Balance = ChargeTransactionPayment::traditional_fee(0, &dispatch_info, 0);
+ Ok(
+ <Balances as NamedReservableCurrency<AccountId>>::unreserve_named(
+ &id,
+ &(sponsor.into()),
+ weight,
+ ),
+ )
+ }
+
+ fn cancel_reserve(
+ id: [u8; 16],
+ sponsor: <T as frame_system::Config>::AccountId,
+ ) -> Result<u128, DispatchError> {
+ Ok(
+ <Balances as NamedReservableCurrency<AccountId>>::unreserve_named(
+ &id,
+ &(sponsor.into()),
+ u128::MAX,
+ ),
+ )
+ }
+}
runtime/common/sponsoring.rsdiffbeforeafterboth--- /dev/null
+++ b/runtime/common/sponsoring.rs
@@ -0,0 +1,359 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+use core::marker::PhantomData;
+use up_sponsorship::SponsorshipHandler;
+use frame_support::{
+ traits::{IsSubType},
+ storage::{StorageMap, StorageDoubleMap, StorageNMap},
+};
+use up_data_structs::{
+ CollectionId, FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT, NFT_SPONSOR_TRANSFER_TIMEOUT,
+ REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT, TokenId, CollectionMode, CreateItemData,
+};
+use sp_runtime::traits::Saturating;
+use pallet_common::{CollectionHandle};
+use pallet_evm::account::CrossAccountId;
+use pallet_unique::{
+ Call as UniqueCall, Config as UniqueConfig, FungibleApproveBasket, RefungibleApproveBasket,
+ NftApproveBasket, CreateItemBasket, ReFungibleTransferBasket, FungibleTransferBasket,
+ NftTransferBasket, TokenPropertyBasket,
+};
+use pallet_fungible::Config as FungibleConfig;
+use pallet_nonfungible::Config as NonfungibleConfig;
+use pallet_refungible::Config as RefungibleConfig;
+
+pub trait Config: UniqueConfig + FungibleConfig + NonfungibleConfig + RefungibleConfig {}
+impl<T> Config for T where T: UniqueConfig + FungibleConfig + NonfungibleConfig + RefungibleConfig {}
+
+// TODO: permission check?
+pub fn withdraw_set_token_property<T: Config>(
+ collection: &CollectionHandle<T>,
+ who: &T::CrossAccountId,
+ item_id: &TokenId,
+ data_size: usize,
+) -> Option<()> {
+ // preliminary sponsoring correctness check
+ match collection.mode {
+ CollectionMode::NFT => {
+ let owner = pallet_nonfungible::TokenData::<T>::get((collection.id, item_id))?.owner;
+ if !owner.conv_eq(who) {
+ return None;
+ }
+ }
+ CollectionMode::Fungible(_) => {
+ // Fungible tokens have no properties
+ return None;
+ }
+ CollectionMode::ReFungible => {
+ if !<pallet_refungible::Owned<T>>::get((collection.id, who, item_id)) {
+ return None;
+ }
+ }
+ }
+
+ if data_size > collection.limits.sponsored_data_size() as usize {
+ return None;
+ }
+
+ let block_number = <frame_system::Pallet<T>>::block_number() as T::BlockNumber;
+ let limit = collection.limits.sponsored_data_rate_limit()?;
+
+ if let Some(last_tx_block) = TokenPropertyBasket::<T>::get(collection.id, item_id) {
+ let timeout = last_tx_block + limit.into();
+ if block_number < timeout {
+ return None;
+ }
+ }
+
+ <TokenPropertyBasket<T>>::insert(collection.id, item_id, block_number);
+
+ Some(())
+}
+
+pub fn withdraw_transfer<T: Config>(
+ collection: &CollectionHandle<T>,
+ who: &T::CrossAccountId,
+ item_id: &TokenId,
+) -> Option<()> {
+ // preliminary sponsoring correctness check
+ match collection.mode {
+ CollectionMode::NFT => {
+ let owner = pallet_nonfungible::TokenData::<T>::get((collection.id, item_id))?.owner;
+ if !owner.conv_eq(who) {
+ return None;
+ }
+ }
+ CollectionMode::Fungible(_) => {
+ if item_id != &TokenId::default() {
+ return None;
+ }
+ if <pallet_fungible::Balance<T>>::get((collection.id, who)) == 0 {
+ return None;
+ }
+ }
+ CollectionMode::ReFungible => {
+ if !<pallet_refungible::Owned<T>>::get((collection.id, who, item_id)) {
+ return None;
+ }
+ }
+ }
+
+ // sponsor timeout
+ let block_number = <frame_system::Pallet<T>>::block_number() as T::BlockNumber;
+ let limit = collection
+ .limits
+ .sponsor_transfer_timeout(match collection.mode {
+ CollectionMode::NFT => NFT_SPONSOR_TRANSFER_TIMEOUT,
+ CollectionMode::Fungible(_) => FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,
+ CollectionMode::ReFungible => REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,
+ });
+
+ let last_tx_block = match collection.mode {
+ CollectionMode::NFT => <NftTransferBasket<T>>::get(collection.id, item_id),
+ CollectionMode::Fungible(_) => {
+ <FungibleTransferBasket<T>>::get(collection.id, who.as_sub())
+ }
+ CollectionMode::ReFungible => {
+ <ReFungibleTransferBasket<T>>::get((collection.id, item_id, who.as_sub()))
+ }
+ };
+
+ if let Some(last_tx_block) = last_tx_block {
+ let timeout = last_tx_block + limit.into();
+ if block_number < timeout {
+ return None;
+ }
+ }
+
+ match collection.mode {
+ CollectionMode::NFT => <NftTransferBasket<T>>::insert(collection.id, item_id, block_number),
+ CollectionMode::Fungible(_) => {
+ <FungibleTransferBasket<T>>::insert(collection.id, who.as_sub(), block_number)
+ }
+ CollectionMode::ReFungible => <ReFungibleTransferBasket<T>>::insert(
+ (collection.id, item_id, who.as_sub()),
+ block_number,
+ ),
+ };
+
+ Some(())
+}
+
+pub fn withdraw_create_item<T: Config>(
+ collection: &CollectionHandle<T>,
+ who: &T::CrossAccountId,
+ properties: &CreateItemData,
+) -> Option<()> {
+ // sponsor timeout
+ let block_number = <frame_system::Pallet<T>>::block_number() as T::BlockNumber;
+ let limit = collection
+ .limits
+ .sponsor_transfer_timeout(match properties {
+ CreateItemData::NFT(_) => NFT_SPONSOR_TRANSFER_TIMEOUT,
+ CreateItemData::Fungible(_) => FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,
+ CreateItemData::ReFungible(_) => REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,
+ });
+
+ if let Some(last_tx_block) = <CreateItemBasket<T>>::get((collection.id, who.as_sub())) {
+ let timeout = last_tx_block + limit.into();
+ if block_number < timeout {
+ return None;
+ }
+ }
+
+ CreateItemBasket::<T>::insert((collection.id, who.as_sub()), block_number);
+
+ Some(())
+}
+
+pub fn withdraw_approve<T: Config>(
+ collection: &CollectionHandle<T>,
+ who: &T::AccountId,
+ item_id: &TokenId,
+) -> Option<()> {
+ // sponsor timeout
+ let block_number = <frame_system::Pallet<T>>::block_number() as T::BlockNumber;
+ let limit = collection.limits.sponsor_approve_timeout();
+
+ let last_tx_block = match collection.mode {
+ CollectionMode::NFT => <NftApproveBasket<T>>::get(collection.id, item_id),
+ CollectionMode::Fungible(_) => <FungibleApproveBasket<T>>::get(collection.id, who),
+ CollectionMode::ReFungible => {
+ <RefungibleApproveBasket<T>>::get((collection.id, item_id, who))
+ }
+ };
+
+ if let Some(last_tx_block) = last_tx_block {
+ let timeout = last_tx_block + limit.into();
+ if block_number < timeout {
+ return None;
+ }
+ }
+
+ match collection.mode {
+ CollectionMode::NFT => <NftApproveBasket<T>>::insert(collection.id, item_id, block_number),
+ CollectionMode::Fungible(_) => {
+ <FungibleApproveBasket<T>>::insert(collection.id, who, block_number)
+ }
+ CollectionMode::ReFungible => {
+ <RefungibleApproveBasket<T>>::insert((collection.id, item_id, who), block_number)
+ }
+ };
+
+ Some(())
+}
+
+fn load<T: UniqueConfig>(id: CollectionId) -> Option<(T::AccountId, CollectionHandle<T>)> {
+ let collection = CollectionHandle::new(id)?;
+ let sponsor = collection.sponsorship.sponsor().cloned()?;
+ Some((sponsor, collection))
+}
+
+pub struct UniqueSponsorshipHandler<T>(PhantomData<T>);
+impl<T, C> SponsorshipHandler<T::AccountId, C> for UniqueSponsorshipHandler<T>
+where
+ T: Config,
+ C: IsSubType<UniqueCall<T>>,
+{
+ fn get_sponsor(who: &T::AccountId, call: &C) -> Option<T::AccountId> {
+ match IsSubType::<UniqueCall<T>>::is_sub_type(call)? {
+ UniqueCall::set_token_properties {
+ collection_id,
+ token_id,
+ properties,
+ ..
+ } => {
+ let (sponsor, collection) = load::<T>(*collection_id)?;
+ withdraw_set_token_property(
+ &collection,
+ &T::CrossAccountId::from_sub(who.clone()),
+ &token_id,
+ // No overflow may happen, as data larger than usize can't reach here
+ properties.iter().map(|p| p.key.len() + p.value.len()).sum(),
+ )
+ .map(|()| sponsor)
+ }
+ UniqueCall::create_item {
+ collection_id,
+ data,
+ ..
+ } => {
+ let (sponsor, collection) = load(*collection_id)?;
+ withdraw_create_item::<T>(
+ &collection,
+ &T::CrossAccountId::from_sub(who.clone()),
+ data,
+ )
+ .map(|()| sponsor)
+ }
+ UniqueCall::transfer {
+ collection_id,
+ item_id,
+ ..
+ } => {
+ let (sponsor, collection) = load(*collection_id)?;
+ withdraw_transfer::<T>(
+ &collection,
+ &T::CrossAccountId::from_sub(who.clone()),
+ item_id,
+ )
+ .map(|()| sponsor)
+ }
+ UniqueCall::transfer_from {
+ collection_id,
+ item_id,
+ from,
+ ..
+ } => {
+ let (sponsor, collection) = load(*collection_id)?;
+ withdraw_transfer::<T>(&collection, from, item_id).map(|()| sponsor)
+ }
+ UniqueCall::approve {
+ collection_id,
+ item_id,
+ ..
+ } => {
+ let (sponsor, collection) = load(*collection_id)?;
+ withdraw_approve::<T>(&collection, who, item_id).map(|()| sponsor)
+ }
+ _ => None,
+ }
+ }
+}
+
+pub trait SponsorshipPredict<T: Config> {
+ fn predict(collection: CollectionId, account: T::CrossAccountId, token: TokenId) -> Option<u64>
+ where
+ u64: From<<T as frame_system::Config>::BlockNumber>;
+}
+
+pub struct UniqueSponsorshipPredict<T>(PhantomData<T>);
+
+impl<T: Config> SponsorshipPredict<T> for UniqueSponsorshipPredict<T> {
+ fn predict(collection_id: CollectionId, who: T::CrossAccountId, token: TokenId) -> Option<u64>
+ where
+ u64: From<<T as frame_system::Config>::BlockNumber>,
+ {
+ let collection = <CollectionHandle<T>>::try_get(collection_id).ok()?;
+ let _ = collection.sponsorship.sponsor()?;
+
+ // sponsor timeout
+ let block_number = <frame_system::Pallet<T>>::block_number() as T::BlockNumber;
+ let limit = collection
+ .limits
+ .sponsor_transfer_timeout(match collection.mode {
+ CollectionMode::NFT => NFT_SPONSOR_TRANSFER_TIMEOUT,
+ CollectionMode::Fungible(_) => FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,
+ CollectionMode::ReFungible => REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,
+ });
+
+ let last_tx_block = match collection.mode {
+ CollectionMode::NFT => <NftTransferBasket<T>>::get(collection.id, token),
+ CollectionMode::Fungible(_) => {
+ <FungibleTransferBasket<T>>::get(collection.id, who.as_sub())
+ }
+ CollectionMode::ReFungible => {
+ <ReFungibleTransferBasket<T>>::get((collection.id, token, who.as_sub()))
+ }
+ };
+
+ if let Some(last_tx_block) = last_tx_block {
+ return Some(
+ last_tx_block
+ .saturating_add(limit.into())
+ .saturating_sub(block_number)
+ .into(),
+ );
+ }
+
+ let token_exists = match collection.mode {
+ CollectionMode::NFT => {
+ <pallet_nonfungible::TokenData<T>>::contains_key((collection.id, token))
+ }
+ CollectionMode::Fungible(_) => token == TokenId::default(),
+ CollectionMode::ReFungible => {
+ <pallet_refungible::TotalSupply<T>>::contains_key((collection.id, token))
+ }
+ };
+
+ if token_exists {
+ Some(0)
+ } else {
+ None
+ }
+ }
+}
runtime/common/src/constants.rsdiffbeforeafterboth--- a/runtime/common/src/constants.rs
+++ /dev/null
@@ -1,57 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-use sp_runtime::Perbill;
-use frame_support::{
- parameter_types,
- weights::{Weight, constants::WEIGHT_PER_SECOND},
-};
-use crate::types::{BlockNumber, Balance};
-
-pub const MILLISECS_PER_BLOCK: u64 = 12000;
-
-pub const SLOT_DURATION: u64 = MILLISECS_PER_BLOCK;
-
-// These time units are defined in number of blocks.
-pub const MINUTES: BlockNumber = 60_000 / (MILLISECS_PER_BLOCK as BlockNumber);
-pub const HOURS: BlockNumber = MINUTES * 60;
-pub const DAYS: BlockNumber = HOURS * 24;
-
-pub const MICROUNIQUE: Balance = 1_000_000_000_000;
-pub const MILLIUNIQUE: Balance = 1_000 * MICROUNIQUE;
-pub const CENTIUNIQUE: Balance = 10 * MILLIUNIQUE;
-pub const UNIQUE: Balance = 100 * CENTIUNIQUE;
-
-// Targeting 0.1 UNQ per transfer
-pub const WEIGHT_TO_FEE_COEFF: u32 = 207_890_902;
-
-// Targeting 0.15 UNQ per transfer via ETH
-pub const MIN_GAS_PRICE: u64 = 1_019_493_469_850;
-
-/// We assume that ~10% of the block weight is consumed by `on_initalize` handlers.
-/// This is used to limit the maximal weight of a single extrinsic.
-pub const AVERAGE_ON_INITIALIZE_RATIO: Perbill = Perbill::from_percent(10);
-/// We allow `Normal` extrinsics to fill up the block up to 75%, the rest can be used
-/// by Operational extrinsics.
-pub const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75);
-/// We allow for 2 seconds of compute with a 6 second average block time.
-pub const MAXIMUM_BLOCK_WEIGHT: Weight = WEIGHT_PER_SECOND / 2;
-
-parameter_types! {
- pub const DefaultSponsoringRateLimit: BlockNumber = 1 * DAYS;
-
- pub const TransactionByteFee: Balance = 501 * MICROUNIQUE;
-}
runtime/common/src/dispatch.rsdiffbeforeafterboth--- a/runtime/common/src/dispatch.rs
+++ /dev/null
@@ -1,181 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-use frame_support::{dispatch::DispatchResult, ensure};
-use pallet_evm::{PrecompileHandle, PrecompileResult};
-use sp_core::H160;
-use sp_runtime::DispatchError;
-use sp_std::{borrow::ToOwned, vec::Vec};
-use pallet_common::{
- CollectionById, CollectionHandle, CommonCollectionOperations, erc::CommonEvmHandler,
- eth::map_eth_to_id,
-};
-pub use pallet_common::dispatch::CollectionDispatch;
-use pallet_fungible::{Pallet as PalletFungible, FungibleHandle};
-use pallet_nonfungible::{Pallet as PalletNonfungible, NonfungibleHandle};
-use pallet_refungible::{
- Pallet as PalletRefungible, RefungibleHandle, erc_token::RefungibleTokenHandle,
-};
-use up_data_structs::{
- CollectionMode, CreateCollectionData, MAX_DECIMAL_POINTS, mapping::TokenAddressMapping,
- CollectionId,
-};
-
-pub enum CollectionDispatchT<T>
-where
- T: pallet_fungible::Config + pallet_nonfungible::Config + pallet_refungible::Config,
-{
- Fungible(FungibleHandle<T>),
- Nonfungible(NonfungibleHandle<T>),
- Refungible(RefungibleHandle<T>),
-}
-impl<T> CollectionDispatch<T> for CollectionDispatchT<T>
-where
- T: pallet_common::Config
- + pallet_unique::Config
- + pallet_fungible::Config
- + pallet_nonfungible::Config
- + pallet_refungible::Config,
-{
- fn create(
- sender: T::CrossAccountId,
- data: CreateCollectionData<T::AccountId>,
- ) -> Result<CollectionId, DispatchError> {
- let id = match data.mode {
- CollectionMode::NFT => <PalletNonfungible<T>>::init_collection(sender, data, false)?,
- CollectionMode::Fungible(decimal_points) => {
- // check params
- ensure!(
- decimal_points <= MAX_DECIMAL_POINTS,
- pallet_unique::Error::<T>::CollectionDecimalPointLimitExceeded
- );
- <PalletFungible<T>>::init_collection(sender, data)?
- }
- CollectionMode::ReFungible => <PalletRefungible<T>>::init_collection(sender, data)?,
- };
- Ok(id)
- }
-
- fn destroy(sender: T::CrossAccountId, collection: CollectionHandle<T>) -> DispatchResult {
- match collection.mode {
- CollectionMode::ReFungible => {
- PalletRefungible::destroy_collection(RefungibleHandle::cast(collection), &sender)?
- }
- CollectionMode::Fungible(_) => {
- PalletFungible::destroy_collection(FungibleHandle::cast(collection), &sender)?
- }
- CollectionMode::NFT => {
- PalletNonfungible::destroy_collection(NonfungibleHandle::cast(collection), &sender)?
- }
- }
- Ok(())
- }
-
- fn dispatch(handle: CollectionHandle<T>) -> Self {
- match handle.mode {
- CollectionMode::Fungible(_) => Self::Fungible(FungibleHandle::cast(handle)),
- CollectionMode::NFT => Self::Nonfungible(NonfungibleHandle::cast(handle)),
- CollectionMode::ReFungible => Self::Refungible(RefungibleHandle::cast(handle)),
- }
- }
-
- fn into_inner(self) -> CollectionHandle<T> {
- match self {
- Self::Fungible(f) => f.into_inner(),
- Self::Nonfungible(f) => f.into_inner(),
- Self::Refungible(f) => f.into_inner(),
- }
- }
-
- fn as_dyn(&self) -> &dyn CommonCollectionOperations<T> {
- match self {
- Self::Fungible(h) => h,
- Self::Nonfungible(h) => h,
- Self::Refungible(h) => h,
- }
- }
-}
-
-impl<T> pallet_evm::OnMethodCall<T> for CollectionDispatchT<T>
-where
- T: pallet_common::Config
- + pallet_unique::Config
- + pallet_fungible::Config
- + pallet_nonfungible::Config
- + pallet_refungible::Config,
- T::AccountId: From<[u8; 32]>,
-{
- fn is_reserved(target: &H160) -> bool {
- map_eth_to_id(target).is_some()
- }
- fn is_used(target: &H160) -> bool {
- map_eth_to_id(target)
- .map(<CollectionById<T>>::contains_key)
- .unwrap_or(false)
- }
- fn get_code(target: &H160) -> Option<Vec<u8>> {
- if let Some(collection_id) = map_eth_to_id(target) {
- let collection = <CollectionById<T>>::get(collection_id)?;
- Some(
- match collection.mode {
- CollectionMode::NFT => <NonfungibleHandle<T>>::CODE,
- CollectionMode::Fungible(_) => <FungibleHandle<T>>::CODE,
- CollectionMode::ReFungible => <RefungibleHandle<T>>::CODE,
- }
- .to_owned(),
- )
- } else if let Some((collection_id, _token_id)) =
- <T as pallet_common::Config>::EvmTokenAddressMapping::address_to_token(target)
- {
- let collection = <CollectionById<T>>::get(collection_id)?;
- if collection.mode != CollectionMode::ReFungible {
- return None;
- }
- // TODO: check token existence
- Some(<RefungibleTokenHandle<T>>::CODE.to_owned())
- } else {
- None
- }
- }
- fn call(handle: &mut impl PrecompileHandle) -> Option<PrecompileResult> {
- if let Some(collection_id) = map_eth_to_id(&handle.code_address()) {
- let collection =
- <CollectionHandle<T>>::new_with_gas_limit(collection_id, handle.remaining_gas())?;
- let dispatched = Self::dispatch(collection);
-
- match dispatched {
- Self::Fungible(h) => h.call(handle),
- Self::Nonfungible(h) => h.call(handle),
- Self::Refungible(h) => h.call(handle),
- }
- } else if let Some((collection_id, token_id)) =
- <T as pallet_common::Config>::EvmTokenAddressMapping::address_to_token(
- &handle.code_address(),
- ) {
- let collection =
- <CollectionHandle<T>>::new_with_gas_limit(collection_id, handle.remaining_gas())?;
- if collection.mode != CollectionMode::ReFungible {
- return None;
- }
-
- let h = RefungibleHandle::cast(collection);
- // TODO: check token existence
- RefungibleTokenHandle(h, token_id).call(handle)
- } else {
- None
- }
- }
-}
runtime/common/src/eth_sponsoring.rsdiffbeforeafterboth--- a/runtime/common/src/eth_sponsoring.rs
+++ /dev/null
@@ -1,122 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-//! Implements EVM sponsoring logic via TransactionValidityHack
-
-use evm_coder::{Call, abi::AbiReader};
-use pallet_common::{CollectionHandle, eth::map_eth_to_id};
-use sp_core::H160;
-use sp_std::prelude::*;
-use up_sponsorship::SponsorshipHandler;
-use core::marker::PhantomData;
-use core::convert::TryInto;
-use pallet_evm::account::CrossAccountId;
-use up_data_structs::{TokenId, CreateItemData, CreateNftData, CollectionMode};
-use pallet_unique::Config as UniqueConfig;
-
-use crate::sponsoring::*;
-
-use pallet_nonfungible::erc::{
- UniqueNFTCall, ERC721UniqueExtensionsCall, ERC721MintableCall, ERC721Call, TokenPropertiesCall,
-};
-use pallet_fungible::erc::{UniqueFungibleCall, ERC20Call};
-use pallet_fungible::Config as FungibleConfig;
-use pallet_nonfungible::Config as NonfungibleConfig;
-use pallet_refungible::Config as RefungibleConfig;
-
-pub struct UniqueEthSponsorshipHandler<T: UniqueConfig>(PhantomData<*const T>);
-impl<T: UniqueConfig + FungibleConfig + NonfungibleConfig + RefungibleConfig>
- 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)?;
- let sponsor = collection.sponsorship.sponsor()?.clone();
- let (method_id, mut reader) = AbiReader::new_call(&call.1).ok()?;
- Some(T::CrossAccountId::from_sub(match &collection.mode {
- CollectionMode::NFT => {
- let call = <UniqueNFTCall<T>>::parse(method_id, &mut reader).ok()??;
- match call {
- UniqueNFTCall::TokenProperties(TokenPropertiesCall::SetProperty {
- token_id,
- key,
- value,
- ..
- }) => {
- let token_id: TokenId = token_id.try_into().ok()?;
- withdraw_set_token_property::<T>(
- &collection,
- &who,
- &token_id,
- key.len() + value.len(),
- )
- .map(|()| sponsor)
- }
- UniqueNFTCall::ERC721UniqueExtensions(
- ERC721UniqueExtensionsCall::Transfer { token_id, .. },
- ) => {
- let token_id: TokenId = token_id.try_into().ok()?;
- withdraw_transfer::<T>(&collection, &who, &token_id).map(|()| sponsor)
- }
- UniqueNFTCall::ERC721Mintable(
- ERC721MintableCall::Mint { token_id, .. }
- | ERC721MintableCall::MintWithTokenUri { token_id, .. },
- ) => {
- let _token_id: TokenId = token_id.try_into().ok()?;
- withdraw_create_item::<T>(
- &collection,
- &who,
- &CreateItemData::NFT(CreateNftData::default()),
- )
- .map(|()| sponsor)
- }
- UniqueNFTCall::ERC721(ERC721Call::TransferFrom { token_id, from, .. }) => {
- let token_id: TokenId = token_id.try_into().ok()?;
- let from = T::CrossAccountId::from_eth(from);
- withdraw_transfer::<T>(&collection, &from, &token_id).map(|()| sponsor)
- }
- UniqueNFTCall::ERC721(ERC721Call::Approve { token_id, .. }) => {
- let token_id: TokenId = token_id.try_into().ok()?;
- withdraw_approve::<T>(&collection, who.as_sub(), &token_id)
- .map(|()| sponsor)
- }
- _ => None,
- }
- }
- CollectionMode::Fungible(_) => {
- let call = <UniqueFungibleCall<T>>::parse(method_id, &mut reader).ok()??;
- #[allow(clippy::single_match)]
- match call {
- UniqueFungibleCall::ERC20(ERC20Call::Transfer { .. }) => {
- withdraw_transfer::<T>(&collection, who, &TokenId::default())
- .map(|()| sponsor)
- }
- UniqueFungibleCall::ERC20(ERC20Call::TransferFrom { from, .. }) => {
- let from = T::CrossAccountId::from_eth(from);
- withdraw_transfer::<T>(&collection, &from, &TokenId::default())
- .map(|()| sponsor)
- }
- UniqueFungibleCall::ERC20(ERC20Call::Approve { .. }) => {
- withdraw_approve::<T>(&collection, who.as_sub(), &TokenId::default())
- .map(|()| sponsor)
- }
- _ => None,
- }
- }
- _ => None,
- }?))
- }
-}
runtime/common/src/lib.rsdiffbeforeafterboth--- a/runtime/common/src/lib.rs
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-#![cfg_attr(not(feature = "std"), no_std)]
-
-pub mod constants;
-pub mod dispatch;
-pub mod eth_sponsoring;
-pub mod runtime_apis;
-pub mod sponsoring;
-pub mod types;
-pub mod weights;
runtime/common/src/runtime_apis.rsdiffbeforeafterboth--- a/runtime/common/src/runtime_apis.rs
+++ /dev/null
@@ -1,546 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-#[macro_export]
-macro_rules! impl_common_runtime_apis {
- (
- $(
- #![custom_apis]
-
- $($custom_apis:tt)+
- )?
- ) => {
- impl_runtime_apis! {
- $($($custom_apis)+)?
-
- impl up_rpc::UniqueApi<Block, CrossAccountId, AccountId> for Runtime {
- fn account_tokens(collection: CollectionId, account: CrossAccountId) -> Result<Vec<TokenId>, DispatchError> {
- dispatch_unique_runtime!(collection.account_tokens(account))
- }
- fn collection_tokens(collection: CollectionId) -> Result<Vec<TokenId>, DispatchError> {
- dispatch_unique_runtime!(collection.collection_tokens())
- }
- fn token_exists(collection: CollectionId, token: TokenId) -> Result<bool, DispatchError> {
- dispatch_unique_runtime!(collection.token_exists(token))
- }
-
- fn token_owner(collection: CollectionId, token: TokenId) -> Result<Option<CrossAccountId>, DispatchError> {
- dispatch_unique_runtime!(collection.token_owner(token))
- }
-
- fn token_owners(collection: CollectionId, token: TokenId) -> Result<Vec::<CrossAccountId>, DispatchError> {
- dispatch_unique_runtime!(collection.token_owners(token))
- }
-
- fn topmost_token_owner(collection: CollectionId, token: TokenId) -> Result<Option<CrossAccountId>, DispatchError> {
- let budget = up_data_structs::budget::Value::new(10);
-
- Ok(Some(<pallet_structure::Pallet<Runtime>>::find_topmost_owner(collection, token, &budget)?))
- }
- fn token_children(collection: CollectionId, token: TokenId) -> Result<Vec<TokenChild>, DispatchError> {
- Ok(<pallet_nonfungible::Pallet<Runtime>>::token_children_ids(collection, token))
- }
- fn collection_properties(
- collection: CollectionId,
- keys: Option<Vec<Vec<u8>>>
- ) -> Result<Vec<Property>, DispatchError> {
- let keys = keys.map(
- |keys| Common::bytes_keys_to_property_keys(keys)
- ).transpose()?;
-
- Common::filter_collection_properties(collection, keys)
- }
-
- fn token_properties(
- collection: CollectionId,
- token_id: TokenId,
- keys: Option<Vec<Vec<u8>>>
- ) -> Result<Vec<Property>, DispatchError> {
- let keys = keys.map(
- |keys| Common::bytes_keys_to_property_keys(keys)
- ).transpose()?;
-
- dispatch_unique_runtime!(collection.token_properties(token_id, keys))
- }
-
- fn property_permissions(
- collection: CollectionId,
- keys: Option<Vec<Vec<u8>>>
- ) -> Result<Vec<PropertyKeyPermission>, DispatchError> {
- let keys = keys.map(
- |keys| Common::bytes_keys_to_property_keys(keys)
- ).transpose()?;
-
- Common::filter_property_permissions(collection, keys)
- }
-
- fn token_data(
- collection: CollectionId,
- token_id: TokenId,
- keys: Option<Vec<Vec<u8>>>
- ) -> Result<TokenData<CrossAccountId>, DispatchError> {
- let token_data = TokenData {
- properties: Self::token_properties(collection, token_id, keys)?,
- owner: Self::token_owner(collection, token_id)?,
- pieces: Self::total_pieces(collection, token_id)?.unwrap_or(0),
- };
-
- Ok(token_data)
- }
-
- fn total_supply(collection: CollectionId) -> Result<u32, DispatchError> {
- dispatch_unique_runtime!(collection.total_supply())
- }
- fn account_balance(collection: CollectionId, account: CrossAccountId) -> Result<u32, DispatchError> {
- dispatch_unique_runtime!(collection.account_balance(account))
- }
- fn balance(collection: CollectionId, account: CrossAccountId, token: TokenId) -> Result<u128, DispatchError> {
- dispatch_unique_runtime!(collection.balance(account, token))
- }
- fn allowance(
- collection: CollectionId,
- sender: CrossAccountId,
- spender: CrossAccountId,
- token: TokenId,
- ) -> Result<u128, DispatchError> {
- dispatch_unique_runtime!(collection.allowance(sender, spender, token))
- }
-
- fn adminlist(collection: CollectionId) -> Result<Vec<CrossAccountId>, DispatchError> {
- Ok(<pallet_common::Pallet<Runtime>>::adminlist(collection))
- }
- fn allowlist(collection: CollectionId) -> Result<Vec<CrossAccountId>, DispatchError> {
- Ok(<pallet_common::Pallet<Runtime>>::allowlist(collection))
- }
- fn allowed(collection: CollectionId, user: CrossAccountId) -> Result<bool, DispatchError> {
- Ok(<pallet_common::Pallet<Runtime>>::allowed(collection, user))
- }
- fn last_token_id(collection: CollectionId) -> Result<TokenId, DispatchError> {
- dispatch_unique_runtime!(collection.last_token_id())
- }
- fn collection_by_id(collection: CollectionId) -> Result<Option<RpcCollection<AccountId>>, DispatchError> {
- Ok(<pallet_common::Pallet<Runtime>>::rpc_collection(collection))
- }
- fn collection_stats() -> Result<CollectionStats, DispatchError> {
- Ok(<pallet_common::Pallet<Runtime>>::collection_stats())
- }
- fn next_sponsored(collection: CollectionId, account: CrossAccountId, token: TokenId) -> Result<Option<u64>, DispatchError> {
- Ok(<$crate::sponsoring::UniqueSponsorshipPredict<Runtime> as
- $crate::sponsoring::SponsorshipPredict<Runtime>>::predict(
- collection,
- account,
- token))
- }
-
- fn effective_collection_limits(collection: CollectionId) -> Result<Option<CollectionLimits>, DispatchError> {
- Ok(<pallet_common::Pallet<Runtime>>::effective_collection_limits(collection))
- }
-
- fn total_pieces(collection: CollectionId, token_id: TokenId) -> Result<Option<u128>, DispatchError> {
- dispatch_unique_runtime!(collection.total_pieces(token_id))
- }
- }
-
- impl sp_api::Core<Block> for Runtime {
- fn version() -> RuntimeVersion {
- VERSION
- }
-
- fn execute_block(block: Block) {
- Executive::execute_block(block)
- }
-
- fn initialize_block(header: &<Block as BlockT>::Header) {
- Executive::initialize_block(header)
- }
- }
-
- impl sp_api::Metadata<Block> for Runtime {
- fn metadata() -> OpaqueMetadata {
- OpaqueMetadata::new(Runtime::metadata().into())
- }
- }
-
- impl sp_block_builder::BlockBuilder<Block> for Runtime {
- fn apply_extrinsic(extrinsic: <Block as BlockT>::Extrinsic) -> ApplyExtrinsicResult {
- Executive::apply_extrinsic(extrinsic)
- }
-
- fn finalize_block() -> <Block as BlockT>::Header {
- Executive::finalize_block()
- }
-
- fn inherent_extrinsics(data: sp_inherents::InherentData) -> Vec<<Block as BlockT>::Extrinsic> {
- data.create_extrinsics()
- }
-
- fn check_inherents(
- block: Block,
- data: sp_inherents::InherentData,
- ) -> sp_inherents::CheckInherentsResult {
- data.check_extrinsics(&block)
- }
-
- // fn random_seed() -> <Block as BlockT>::Hash {
- // RandomnessCollectiveFlip::random_seed().0
- // }
- }
-
- impl sp_transaction_pool::runtime_api::TaggedTransactionQueue<Block> for Runtime {
- fn validate_transaction(
- source: TransactionSource,
- tx: <Block as BlockT>::Extrinsic,
- hash: <Block as BlockT>::Hash,
- ) -> TransactionValidity {
- Executive::validate_transaction(source, tx, hash)
- }
- }
-
- impl sp_offchain::OffchainWorkerApi<Block> for Runtime {
- fn offchain_worker(header: &<Block as BlockT>::Header) {
- Executive::offchain_worker(header)
- }
- }
-
- impl fp_rpc::EthereumRuntimeRPCApi<Block> for Runtime {
- fn chain_id() -> u64 {
- <Runtime as pallet_evm::Config>::ChainId::get()
- }
-
- fn account_basic(address: H160) -> EVMAccount {
- let (account, _) = EVM::account_basic(&address);
- account
- }
-
- fn gas_price() -> U256 {
- let (price, _) = <Runtime as pallet_evm::Config>::FeeCalculator::min_gas_price();
- price
- }
-
- fn account_code_at(address: H160) -> Vec<u8> {
- EVM::account_codes(address)
- }
-
- fn author() -> H160 {
- <pallet_evm::Pallet<Runtime>>::find_author()
- }
-
- fn storage_at(address: H160, index: U256) -> H256 {
- let mut tmp = [0u8; 32];
- index.to_big_endian(&mut tmp);
- EVM::account_storages(address, H256::from_slice(&tmp[..]))
- }
-
- #[allow(clippy::redundant_closure)]
- fn call(
- from: H160,
- to: H160,
- data: Vec<u8>,
- value: U256,
- gas_limit: U256,
- max_fee_per_gas: Option<U256>,
- max_priority_fee_per_gas: Option<U256>,
- nonce: Option<U256>,
- estimate: bool,
- access_list: Option<Vec<(H160, Vec<H256>)>>,
- ) -> Result<pallet_evm::CallInfo, sp_runtime::DispatchError> {
- let config = if estimate {
- let mut config = <Runtime as pallet_evm::Config>::config().clone();
- config.estimate = true;
- Some(config)
- } else {
- None
- };
-
- let is_transactional = false;
- <Runtime as pallet_evm::Config>::Runner::call(
- CrossAccountId::from_eth(from),
- to,
- data,
- value,
- gas_limit.low_u64(),
- max_fee_per_gas,
- max_priority_fee_per_gas,
- nonce,
- access_list.unwrap_or_default(),
- is_transactional,
- config.as_ref().unwrap_or_else(|| <Runtime as pallet_evm::Config>::config()),
- ).map_err(|err| err.error.into())
- }
-
- #[allow(clippy::redundant_closure)]
- fn create(
- from: H160,
- data: Vec<u8>,
- value: U256,
- gas_limit: U256,
- max_fee_per_gas: Option<U256>,
- max_priority_fee_per_gas: Option<U256>,
- nonce: Option<U256>,
- estimate: bool,
- access_list: Option<Vec<(H160, Vec<H256>)>>,
- ) -> Result<pallet_evm::CreateInfo, sp_runtime::DispatchError> {
- let config = if estimate {
- let mut config = <Runtime as pallet_evm::Config>::config().clone();
- config.estimate = true;
- Some(config)
- } else {
- None
- };
-
- let is_transactional = false;
- <Runtime as pallet_evm::Config>::Runner::create(
- CrossAccountId::from_eth(from),
- data,
- value,
- gas_limit.low_u64(),
- max_fee_per_gas,
- max_priority_fee_per_gas,
- nonce,
- access_list.unwrap_or_default(),
- is_transactional,
- config.as_ref().unwrap_or_else(|| <Runtime as pallet_evm::Config>::config()),
- ).map_err(|err| err.error.into())
- }
-
- fn current_transaction_statuses() -> Option<Vec<TransactionStatus>> {
- Ethereum::current_transaction_statuses()
- }
-
- fn current_block() -> Option<pallet_ethereum::Block> {
- Ethereum::current_block()
- }
-
- fn current_receipts() -> Option<Vec<pallet_ethereum::Receipt>> {
- Ethereum::current_receipts()
- }
-
- fn current_all() -> (
- Option<pallet_ethereum::Block>,
- Option<Vec<pallet_ethereum::Receipt>>,
- Option<Vec<TransactionStatus>>
- ) {
- (
- Ethereum::current_block(),
- Ethereum::current_receipts(),
- Ethereum::current_transaction_statuses()
- )
- }
-
- fn extrinsic_filter(xts: Vec<<Block as sp_api::BlockT>::Extrinsic>) -> Vec<pallet_ethereum::Transaction> {
- xts.into_iter().filter_map(|xt| match xt.0.function {
- Call::Ethereum(pallet_ethereum::Call::transact { transaction }) => Some(transaction),
- _ => None
- }).collect()
- }
-
- fn elasticity() -> Option<Permill> {
- None
- }
- }
-
- impl fp_rpc::ConvertTransactionRuntimeApi<Block> for Runtime {
- fn convert_transaction(transaction: pallet_ethereum::Transaction) -> <Block as BlockT>::Extrinsic {
- UncheckedExtrinsic::new_unsigned(
- pallet_ethereum::Call::<Runtime>::transact { transaction }.into(),
- )
- }
- }
-
- impl sp_session::SessionKeys<Block> for Runtime {
- fn decode_session_keys(
- encoded: Vec<u8>,
- ) -> Option<Vec<(Vec<u8>, KeyTypeId)>> {
- SessionKeys::decode_into_raw_public_keys(&encoded)
- }
-
- fn generate_session_keys(seed: Option<Vec<u8>>) -> Vec<u8> {
- SessionKeys::generate(seed)
- }
- }
-
- impl sp_consensus_aura::AuraApi<Block, AuraId> for Runtime {
- fn slot_duration() -> sp_consensus_aura::SlotDuration {
- sp_consensus_aura::SlotDuration::from_millis(Aura::slot_duration())
- }
-
- fn authorities() -> Vec<AuraId> {
- Aura::authorities().to_vec()
- }
- }
-
- impl cumulus_primitives_core::CollectCollationInfo<Block> for Runtime {
- fn collect_collation_info(header: &<Block as BlockT>::Header) -> cumulus_primitives_core::CollationInfo {
- ParachainSystem::collect_collation_info(header)
- }
- }
-
- impl frame_system_rpc_runtime_api::AccountNonceApi<Block, AccountId, Index> for Runtime {
- fn account_nonce(account: AccountId) -> Index {
- System::account_nonce(account)
- }
- }
-
- impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi<Block, Balance> for Runtime {
- fn query_info(uxt: <Block as BlockT>::Extrinsic, len: u32) -> RuntimeDispatchInfo<Balance> {
- TransactionPayment::query_info(uxt, len)
- }
- fn query_fee_details(uxt: <Block as BlockT>::Extrinsic, len: u32) -> FeeDetails<Balance> {
- TransactionPayment::query_fee_details(uxt, len)
- }
- }
-
- /*
- impl pallet_contracts_rpc_runtime_api::ContractsApi<Block, AccountId, Balance, BlockNumber, Hash>
- for Runtime
- {
- fn call(
- origin: AccountId,
- dest: AccountId,
- value: Balance,
- gas_limit: u64,
- input_data: Vec<u8>,
- ) -> pallet_contracts_primitives::ContractExecResult {
- Contracts::bare_call(origin, dest, value, gas_limit, input_data, false)
- }
-
- fn instantiate(
- origin: AccountId,
- endowment: Balance,
- gas_limit: u64,
- code: pallet_contracts_primitives::Code<Hash>,
- data: Vec<u8>,
- salt: Vec<u8>,
- ) -> pallet_contracts_primitives::ContractInstantiateResult<AccountId, BlockNumber>
- {
- Contracts::bare_instantiate(origin, endowment, gas_limit, code, data, salt, true, false)
- }
-
- fn get_storage(
- address: AccountId,
- key: [u8; 32],
- ) -> pallet_contracts_primitives::GetStorageResult {
- Contracts::get_storage(address, key)
- }
-
- fn rent_projection(
- address: AccountId,
- ) -> pallet_contracts_primitives::RentProjectionResult<BlockNumber> {
- Contracts::rent_projection(address)
- }
- }
- */
-
- #[cfg(feature = "runtime-benchmarks")]
- impl frame_benchmarking::Benchmark<Block> for Runtime {
- fn benchmark_metadata(extra: bool) -> (
- Vec<frame_benchmarking::BenchmarkList>,
- Vec<frame_support::traits::StorageInfo>,
- ) {
- use frame_benchmarking::{list_benchmark, Benchmarking, BenchmarkList};
- use frame_support::traits::StorageInfoTrait;
-
- let mut list = Vec::<BenchmarkList>::new();
-
- list_benchmark!(list, extra, pallet_evm_migration, EvmMigration);
- list_benchmark!(list, extra, pallet_common, Common);
- list_benchmark!(list, extra, pallet_unique, Unique);
- list_benchmark!(list, extra, pallet_structure, Structure);
- list_benchmark!(list, extra, pallet_inflation, Inflation);
- list_benchmark!(list, extra, pallet_fungible, Fungible);
- list_benchmark!(list, extra, pallet_refungible, Refungible);
- list_benchmark!(list, extra, pallet_nonfungible, Nonfungible);
- list_benchmark!(list, extra, pallet_unique_scheduler, Scheduler);
-
- #[cfg(not(feature = "unique-runtime"))]
- list_benchmark!(list, extra, pallet_proxy_rmrk_core, RmrkCore);
-
- #[cfg(not(feature = "unique-runtime"))]
- list_benchmark!(list, extra, pallet_proxy_rmrk_equip, RmrkEquip);
-
- // list_benchmark!(list, extra, pallet_evm_coder_substrate, EvmCoderSubstrate);
-
- let storage_info = AllPalletsReversedWithSystemFirst::storage_info();
-
- return (list, storage_info)
- }
-
- fn dispatch_benchmark(
- config: frame_benchmarking::BenchmarkConfig
- ) -> Result<Vec<frame_benchmarking::BenchmarkBatch>, sp_runtime::RuntimeString> {
- use frame_benchmarking::{Benchmarking, BenchmarkBatch, add_benchmark, TrackedStorageKey};
-
- let allowlist: Vec<TrackedStorageKey> = vec![
- // Total Issuance
- hex_literal::hex!("c2261276cc9d1f8598ea4b6a74b15c2f57c875e4cff74148e4628f264b974c80").to_vec().into(),
-
- // Block Number
- hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef702a5c1b19ab7a04f536c519aca4983ac").to_vec().into(),
- // Execution Phase
- hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef7ff553b5a9862a516939d82b3d3d8661a").to_vec().into(),
- // Event Count
- hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef70a98fdbe9ce6c55837576c60c7af3850").to_vec().into(),
- // System Events
- hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef780d41e5e16056765bc8461851072c9d7").to_vec().into(),
-
- // Evm CurrentLogs
- hex_literal::hex!("1da53b775b270400e7e61ed5cbc5a146547f210cec367e9af919603343b9cb56").to_vec().into(),
-
- // Transactional depth
- hex_literal::hex!("3a7472616e73616374696f6e5f6c6576656c3a").to_vec().into(),
- ];
-
- let mut batches = Vec::<BenchmarkBatch>::new();
- let params = (&config, &allowlist);
-
- add_benchmark!(params, batches, pallet_evm_migration, EvmMigration);
- add_benchmark!(params, batches, pallet_common, Common);
- add_benchmark!(params, batches, pallet_unique, Unique);
- add_benchmark!(params, batches, pallet_structure, Structure);
- add_benchmark!(params, batches, pallet_inflation, Inflation);
- add_benchmark!(params, batches, pallet_fungible, Fungible);
- add_benchmark!(params, batches, pallet_refungible, Refungible);
- add_benchmark!(params, batches, pallet_nonfungible, Nonfungible);
- add_benchmark!(params, batches, pallet_unique_scheduler, Scheduler);
-
- #[cfg(not(feature = "unique-runtime"))]
- add_benchmark!(params, batches, pallet_proxy_rmrk_core, RmrkCore);
-
- #[cfg(not(feature = "unique-runtime"))]
- add_benchmark!(params, batches, pallet_proxy_rmrk_equip, RmrkEquip);
-
- // add_benchmark!(params, batches, pallet_evm_coder_substrate, EvmCoderSubstrate);
-
- if batches.is_empty() { return Err("Benchmark not found for this pallet.".into()) }
- Ok(batches)
- }
- }
-
- #[cfg(feature = "try-runtime")]
- impl frame_try_runtime::TryRuntime<Block> for Runtime {
- fn on_runtime_upgrade() -> (Weight, Weight) {
- log::info!("try-runtime::on_runtime_upgrade unique-chain.");
- let weight = Executive::try_runtime_upgrade().unwrap();
- (weight, RuntimeBlockWeights::get().max_block)
- }
-
- fn execute_block_no_check(block: Block) -> Weight {
- Executive::execute_block_no_check(block)
- }
- }
- }
- }
-}
runtime/common/src/sponsoring.rsdiffbeforeafterboth--- a/runtime/common/src/sponsoring.rs
+++ /dev/null
@@ -1,359 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-use core::marker::PhantomData;
-use up_sponsorship::SponsorshipHandler;
-use frame_support::{
- traits::{IsSubType},
- storage::{StorageMap, StorageDoubleMap, StorageNMap},
-};
-use up_data_structs::{
- CollectionId, FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT, NFT_SPONSOR_TRANSFER_TIMEOUT,
- REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT, TokenId, CollectionMode, CreateItemData,
-};
-use sp_runtime::traits::Saturating;
-use pallet_common::{CollectionHandle};
-use pallet_evm::account::CrossAccountId;
-use pallet_unique::{
- Call as UniqueCall, Config as UniqueConfig, FungibleApproveBasket, RefungibleApproveBasket,
- NftApproveBasket, CreateItemBasket, ReFungibleTransferBasket, FungibleTransferBasket,
- NftTransferBasket, TokenPropertyBasket,
-};
-use pallet_fungible::Config as FungibleConfig;
-use pallet_nonfungible::Config as NonfungibleConfig;
-use pallet_refungible::Config as RefungibleConfig;
-
-pub trait Config: UniqueConfig + FungibleConfig + NonfungibleConfig + RefungibleConfig {}
-impl<T> Config for T where T: UniqueConfig + FungibleConfig + NonfungibleConfig + RefungibleConfig {}
-
-// TODO: permission check?
-pub fn withdraw_set_token_property<T: Config>(
- collection: &CollectionHandle<T>,
- who: &T::CrossAccountId,
- item_id: &TokenId,
- data_size: usize,
-) -> Option<()> {
- // preliminary sponsoring correctness check
- match collection.mode {
- CollectionMode::NFT => {
- let owner = pallet_nonfungible::TokenData::<T>::get((collection.id, item_id))?.owner;
- if !owner.conv_eq(who) {
- return None;
- }
- }
- CollectionMode::Fungible(_) => {
- // Fungible tokens have no properties
- return None;
- }
- CollectionMode::ReFungible => {
- if !<pallet_refungible::Owned<T>>::get((collection.id, who, item_id)) {
- return None;
- }
- }
- }
-
- if data_size > collection.limits.sponsored_data_size() as usize {
- return None;
- }
-
- let block_number = <frame_system::Pallet<T>>::block_number() as T::BlockNumber;
- let limit = collection.limits.sponsored_data_rate_limit()?;
-
- if let Some(last_tx_block) = TokenPropertyBasket::<T>::get(collection.id, item_id) {
- let timeout = last_tx_block + limit.into();
- if block_number < timeout {
- return None;
- }
- }
-
- <TokenPropertyBasket<T>>::insert(collection.id, item_id, block_number);
-
- Some(())
-}
-
-pub fn withdraw_transfer<T: Config>(
- collection: &CollectionHandle<T>,
- who: &T::CrossAccountId,
- item_id: &TokenId,
-) -> Option<()> {
- // preliminary sponsoring correctness check
- match collection.mode {
- CollectionMode::NFT => {
- let owner = pallet_nonfungible::TokenData::<T>::get((collection.id, item_id))?.owner;
- if !owner.conv_eq(who) {
- return None;
- }
- }
- CollectionMode::Fungible(_) => {
- if item_id != &TokenId::default() {
- return None;
- }
- if <pallet_fungible::Balance<T>>::get((collection.id, who)) == 0 {
- return None;
- }
- }
- CollectionMode::ReFungible => {
- if !<pallet_refungible::Owned<T>>::get((collection.id, who, item_id)) {
- return None;
- }
- }
- }
-
- // sponsor timeout
- let block_number = <frame_system::Pallet<T>>::block_number() as T::BlockNumber;
- let limit = collection
- .limits
- .sponsor_transfer_timeout(match collection.mode {
- CollectionMode::NFT => NFT_SPONSOR_TRANSFER_TIMEOUT,
- CollectionMode::Fungible(_) => FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,
- CollectionMode::ReFungible => REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,
- });
-
- let last_tx_block = match collection.mode {
- CollectionMode::NFT => <NftTransferBasket<T>>::get(collection.id, item_id),
- CollectionMode::Fungible(_) => {
- <FungibleTransferBasket<T>>::get(collection.id, who.as_sub())
- }
- CollectionMode::ReFungible => {
- <ReFungibleTransferBasket<T>>::get((collection.id, item_id, who.as_sub()))
- }
- };
-
- if let Some(last_tx_block) = last_tx_block {
- let timeout = last_tx_block + limit.into();
- if block_number < timeout {
- return None;
- }
- }
-
- match collection.mode {
- CollectionMode::NFT => <NftTransferBasket<T>>::insert(collection.id, item_id, block_number),
- CollectionMode::Fungible(_) => {
- <FungibleTransferBasket<T>>::insert(collection.id, who.as_sub(), block_number)
- }
- CollectionMode::ReFungible => <ReFungibleTransferBasket<T>>::insert(
- (collection.id, item_id, who.as_sub()),
- block_number,
- ),
- };
-
- Some(())
-}
-
-pub fn withdraw_create_item<T: Config>(
- collection: &CollectionHandle<T>,
- who: &T::CrossAccountId,
- properties: &CreateItemData,
-) -> Option<()> {
- // sponsor timeout
- let block_number = <frame_system::Pallet<T>>::block_number() as T::BlockNumber;
- let limit = collection
- .limits
- .sponsor_transfer_timeout(match properties {
- CreateItemData::NFT(_) => NFT_SPONSOR_TRANSFER_TIMEOUT,
- CreateItemData::Fungible(_) => FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,
- CreateItemData::ReFungible(_) => REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,
- });
-
- if let Some(last_tx_block) = <CreateItemBasket<T>>::get((collection.id, who.as_sub())) {
- let timeout = last_tx_block + limit.into();
- if block_number < timeout {
- return None;
- }
- }
-
- CreateItemBasket::<T>::insert((collection.id, who.as_sub()), block_number);
-
- Some(())
-}
-
-pub fn withdraw_approve<T: Config>(
- collection: &CollectionHandle<T>,
- who: &T::AccountId,
- item_id: &TokenId,
-) -> Option<()> {
- // sponsor timeout
- let block_number = <frame_system::Pallet<T>>::block_number() as T::BlockNumber;
- let limit = collection.limits.sponsor_approve_timeout();
-
- let last_tx_block = match collection.mode {
- CollectionMode::NFT => <NftApproveBasket<T>>::get(collection.id, item_id),
- CollectionMode::Fungible(_) => <FungibleApproveBasket<T>>::get(collection.id, who),
- CollectionMode::ReFungible => {
- <RefungibleApproveBasket<T>>::get((collection.id, item_id, who))
- }
- };
-
- if let Some(last_tx_block) = last_tx_block {
- let timeout = last_tx_block + limit.into();
- if block_number < timeout {
- return None;
- }
- }
-
- match collection.mode {
- CollectionMode::NFT => <NftApproveBasket<T>>::insert(collection.id, item_id, block_number),
- CollectionMode::Fungible(_) => {
- <FungibleApproveBasket<T>>::insert(collection.id, who, block_number)
- }
- CollectionMode::ReFungible => {
- <RefungibleApproveBasket<T>>::insert((collection.id, item_id, who), block_number)
- }
- };
-
- Some(())
-}
-
-fn load<T: UniqueConfig>(id: CollectionId) -> Option<(T::AccountId, CollectionHandle<T>)> {
- let collection = CollectionHandle::new(id)?;
- let sponsor = collection.sponsorship.sponsor().cloned()?;
- Some((sponsor, collection))
-}
-
-pub struct UniqueSponsorshipHandler<T>(PhantomData<T>);
-impl<T, C> SponsorshipHandler<T::AccountId, C> for UniqueSponsorshipHandler<T>
-where
- T: Config,
- C: IsSubType<UniqueCall<T>>,
-{
- fn get_sponsor(who: &T::AccountId, call: &C) -> Option<T::AccountId> {
- match IsSubType::<UniqueCall<T>>::is_sub_type(call)? {
- UniqueCall::set_token_properties {
- collection_id,
- token_id,
- properties,
- ..
- } => {
- let (sponsor, collection) = load::<T>(*collection_id)?;
- withdraw_set_token_property(
- &collection,
- &T::CrossAccountId::from_sub(who.clone()),
- &token_id,
- // No overflow may happen, as data larger than usize can't reach here
- properties.iter().map(|p| p.key.len() + p.value.len()).sum(),
- )
- .map(|()| sponsor)
- }
- UniqueCall::create_item {
- collection_id,
- data,
- ..
- } => {
- let (sponsor, collection) = load(*collection_id)?;
- withdraw_create_item::<T>(
- &collection,
- &T::CrossAccountId::from_sub(who.clone()),
- data,
- )
- .map(|()| sponsor)
- }
- UniqueCall::transfer {
- collection_id,
- item_id,
- ..
- } => {
- let (sponsor, collection) = load(*collection_id)?;
- withdraw_transfer::<T>(
- &collection,
- &T::CrossAccountId::from_sub(who.clone()),
- item_id,
- )
- .map(|()| sponsor)
- }
- UniqueCall::transfer_from {
- collection_id,
- item_id,
- from,
- ..
- } => {
- let (sponsor, collection) = load(*collection_id)?;
- withdraw_transfer::<T>(&collection, from, item_id).map(|()| sponsor)
- }
- UniqueCall::approve {
- collection_id,
- item_id,
- ..
- } => {
- let (sponsor, collection) = load(*collection_id)?;
- withdraw_approve::<T>(&collection, who, item_id).map(|()| sponsor)
- }
- _ => None,
- }
- }
-}
-
-pub trait SponsorshipPredict<T: Config> {
- fn predict(collection: CollectionId, account: T::CrossAccountId, token: TokenId) -> Option<u64>
- where
- u64: From<<T as frame_system::Config>::BlockNumber>;
-}
-
-pub struct UniqueSponsorshipPredict<T>(PhantomData<T>);
-
-impl<T: Config> SponsorshipPredict<T> for UniqueSponsorshipPredict<T> {
- fn predict(collection_id: CollectionId, who: T::CrossAccountId, token: TokenId) -> Option<u64>
- where
- u64: From<<T as frame_system::Config>::BlockNumber>,
- {
- let collection = <CollectionHandle<T>>::try_get(collection_id).ok()?;
- let _ = collection.sponsorship.sponsor()?;
-
- // sponsor timeout
- let block_number = <frame_system::Pallet<T>>::block_number() as T::BlockNumber;
- let limit = collection
- .limits
- .sponsor_transfer_timeout(match collection.mode {
- CollectionMode::NFT => NFT_SPONSOR_TRANSFER_TIMEOUT,
- CollectionMode::Fungible(_) => FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,
- CollectionMode::ReFungible => REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,
- });
-
- let last_tx_block = match collection.mode {
- CollectionMode::NFT => <NftTransferBasket<T>>::get(collection.id, token),
- CollectionMode::Fungible(_) => {
- <FungibleTransferBasket<T>>::get(collection.id, who.as_sub())
- }
- CollectionMode::ReFungible => {
- <ReFungibleTransferBasket<T>>::get((collection.id, token, who.as_sub()))
- }
- };
-
- if let Some(last_tx_block) = last_tx_block {
- return Some(
- last_tx_block
- .saturating_add(limit.into())
- .saturating_sub(block_number)
- .into(),
- );
- }
-
- let token_exists = match collection.mode {
- CollectionMode::NFT => {
- <pallet_nonfungible::TokenData<T>>::contains_key((collection.id, token))
- }
- CollectionMode::Fungible(_) => token == TokenId::default(),
- CollectionMode::ReFungible => {
- <pallet_refungible::TotalSupply<T>>::contains_key((collection.id, token))
- }
- };
-
- if token_exists {
- Some(0)
- } else {
- None
- }
- }
-}
runtime/common/src/types.rsdiffbeforeafterboth--- a/runtime/common/src/types.rs
+++ /dev/null
@@ -1,72 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-use sp_runtime::{
- traits::{Verify, IdentifyAccount, BlakeTwo256},
- generic, MultiSignature,
-};
-
-pub use sp_runtime::OpaqueExtrinsic as UncheckedExtrinsic;
-
-/// Opaque block header type.
-pub type Header = generic::Header<BlockNumber, BlakeTwo256>;
-
-/// Opaque block type.
-pub type Block = generic::Block<Header, UncheckedExtrinsic>;
-
-pub type SessionHandlers = ();
-
-/// An index to a block.
-pub type BlockNumber = u32;
-
-/// Alias to 512-bit hash when used in the context of a transaction signature on the chain.
-pub type Signature = MultiSignature;
-
-/// Some way of identifying an account on the chain. We intentionally make it equivalent
-/// to the public key of our transaction signing scheme.
-pub type AccountId = <<Signature as Verify>::Signer as IdentifyAccount>::AccountId;
-
-/// The type for looking up accounts. We don't expect more than 4 billion of them, but you
-/// never know...
-pub type AccountIndex = u32;
-
-/// Balance of an account.
-pub type Balance = u128;
-
-/// Index of a transaction in the chain.
-pub type Index = u32;
-
-/// A hash of some data used by the chain.
-pub type Hash = sp_core::H256;
-
-/// Digest item type.
-pub type DigestItem = generic::DigestItem;
-
-pub use sp_consensus_aura::sr25519::AuthorityId as AuraId;
-
-pub trait RuntimeInstance {
- type CrossAccountId: pallet_evm::account::CrossAccountId<sp_runtime::AccountId32>
- + Send
- + Sync
- + 'static;
-
- type TransactionConverter: fp_rpc::ConvertTransaction<UncheckedExtrinsic>
- + Send
- + Sync
- + 'static;
-
- fn get_transaction_converter() -> Self::TransactionConverter;
-}
runtime/common/src/weights.rsdiffbeforeafterboth--- a/runtime/common/src/weights.rs
+++ /dev/null
@@ -1,111 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-use core::marker::PhantomData;
-use frame_support::{weights::Weight};
-use pallet_common::{CommonWeightInfo, dispatch::dispatch_weight, RefungibleExtensionsWeightInfo};
-
-use pallet_fungible::{Config as FungibleConfig, common::CommonWeights as FungibleWeights};
-use pallet_nonfungible::{Config as NonfungibleConfig, common::CommonWeights as NonfungibleWeights};
-use pallet_refungible::{
- Config as RefungibleConfig, weights::WeightInfo, common::CommonWeights as RefungibleWeights,
-};
-use up_data_structs::{CreateItemExData, CreateItemData};
-
-macro_rules! max_weight_of {
- ($method:ident ( $($args:tt)* )) => {
- <FungibleWeights<T>>::$method($($args)*)
- .max(<NonfungibleWeights<T>>::$method($($args)*))
- .max(<RefungibleWeights<T>>::$method($($args)*))
- };
-}
-
-pub struct CommonWeights<T>(PhantomData<T>)
-where
- T: FungibleConfig + NonfungibleConfig + RefungibleConfig;
-impl<T> CommonWeightInfo<T::CrossAccountId> for CommonWeights<T>
-where
- T: FungibleConfig + NonfungibleConfig + RefungibleConfig,
-{
- fn create_item() -> Weight {
- dispatch_weight::<T>() + max_weight_of!(create_item())
- }
-
- fn create_multiple_items(data: &[CreateItemData]) -> Weight {
- dispatch_weight::<T>() + max_weight_of!(create_multiple_items(data))
- }
-
- fn create_multiple_items_ex(data: &CreateItemExData<T::CrossAccountId>) -> Weight {
- dispatch_weight::<T>() + max_weight_of!(create_multiple_items_ex(data))
- }
-
- fn burn_item() -> Weight {
- dispatch_weight::<T>() + max_weight_of!(burn_item())
- }
-
- fn set_collection_properties(amount: u32) -> Weight {
- dispatch_weight::<T>() + max_weight_of!(set_collection_properties(amount))
- }
-
- fn delete_collection_properties(amount: u32) -> Weight {
- dispatch_weight::<T>() + max_weight_of!(delete_collection_properties(amount))
- }
-
- fn set_token_properties(amount: u32) -> Weight {
- dispatch_weight::<T>() + max_weight_of!(set_token_properties(amount))
- }
-
- fn delete_token_properties(amount: u32) -> Weight {
- dispatch_weight::<T>() + max_weight_of!(delete_token_properties(amount))
- }
-
- fn set_token_property_permissions(amount: u32) -> Weight {
- dispatch_weight::<T>() + max_weight_of!(set_token_property_permissions(amount))
- }
-
- fn transfer() -> Weight {
- dispatch_weight::<T>() + max_weight_of!(transfer())
- }
-
- fn approve() -> Weight {
- dispatch_weight::<T>() + max_weight_of!(approve())
- }
-
- fn transfer_from() -> Weight {
- dispatch_weight::<T>() + max_weight_of!(transfer_from())
- }
-
- fn burn_from() -> Weight {
- dispatch_weight::<T>() + max_weight_of!(burn_from())
- }
-
- fn burn_recursively_self_raw() -> Weight {
- max_weight_of!(burn_recursively_self_raw())
- }
-
- fn burn_recursively_breadth_raw(amount: u32) -> Weight {
- max_weight_of!(burn_recursively_breadth_raw(amount))
- }
-}
-
-impl<T> RefungibleExtensionsWeightInfo for CommonWeights<T>
-where
- T: FungibleConfig + NonfungibleConfig + RefungibleConfig,
-{
- fn repartition() -> Weight {
- dispatch_weight::<T>() + <<T as RefungibleConfig>::WeightInfo>::repartition_item()
- }
-}
runtime/common/weights.rsdiffbeforeafterboth--- /dev/null
+++ b/runtime/common/weights.rs
@@ -0,0 +1,139 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+use core::marker::PhantomData;
+use frame_support::{weights::Weight};
+use pallet_common::{CommonWeightInfo, dispatch::dispatch_weight, RefungibleExtensionsWeightInfo};
+
+use pallet_fungible::{Config as FungibleConfig, common::CommonWeights as FungibleWeights};
+use pallet_nonfungible::{Config as NonfungibleConfig, common::CommonWeights as NonfungibleWeights};
+
+#[cfg(feature = "refungible")]
+use pallet_refungible::{
+ Config as RefungibleConfig, weights::WeightInfo, common::CommonWeights as RefungibleWeights,
+};
+use up_data_structs::{CreateItemExData, CreateItemData};
+
+macro_rules! max_weight_of {
+ ($method:ident ( $($args:tt)* )) => {{
+ let max_weight = <FungibleWeights<T>>::$method($($args)*)
+ .max(<NonfungibleWeights<T>>::$method($($args)*));
+
+ #[cfg(feature = "refungible")]
+ let max_weight = max_weight.max(<RefungibleWeights<T>>::$method($($args)*));
+
+ max_weight
+ }};
+}
+
+#[cfg(not(feature = "refungible"))]
+pub trait CommonWeightConfigs: FungibleConfig + NonfungibleConfig {}
+
+#[cfg(not(feature = "refungible"))]
+impl<T: FungibleConfig + NonfungibleConfig> CommonWeightConfigs for T {}
+
+#[cfg(feature = "refungible")]
+pub trait CommonWeightConfigs: FungibleConfig + NonfungibleConfig + RefungibleConfig {}
+
+#[cfg(feature = "refungible")]
+impl<T: FungibleConfig + NonfungibleConfig + RefungibleConfig> CommonWeightConfigs for T {}
+
+pub struct CommonWeights<T>(PhantomData<T>);
+
+impl<T> CommonWeightInfo<T::CrossAccountId> for CommonWeights<T>
+where
+ T: CommonWeightConfigs,
+{
+ fn create_item() -> Weight {
+ dispatch_weight::<T>() + max_weight_of!(create_item())
+ }
+
+ fn create_multiple_items(data: &[CreateItemData]) -> Weight {
+ dispatch_weight::<T>() + max_weight_of!(create_multiple_items(data))
+ }
+
+ fn create_multiple_items_ex(data: &CreateItemExData<T::CrossAccountId>) -> Weight {
+ dispatch_weight::<T>() + max_weight_of!(create_multiple_items_ex(data))
+ }
+
+ fn burn_item() -> Weight {
+ dispatch_weight::<T>() + max_weight_of!(burn_item())
+ }
+
+ fn set_collection_properties(amount: u32) -> Weight {
+ dispatch_weight::<T>() + max_weight_of!(set_collection_properties(amount))
+ }
+
+ fn delete_collection_properties(amount: u32) -> Weight {
+ dispatch_weight::<T>() + max_weight_of!(delete_collection_properties(amount))
+ }
+
+ fn set_token_properties(amount: u32) -> Weight {
+ dispatch_weight::<T>() + max_weight_of!(set_token_properties(amount))
+ }
+
+ fn delete_token_properties(amount: u32) -> Weight {
+ dispatch_weight::<T>() + max_weight_of!(delete_token_properties(amount))
+ }
+
+ fn set_token_property_permissions(amount: u32) -> Weight {
+ dispatch_weight::<T>() + max_weight_of!(set_token_property_permissions(amount))
+ }
+
+ fn transfer() -> Weight {
+ dispatch_weight::<T>() + max_weight_of!(transfer())
+ }
+
+ fn approve() -> Weight {
+ dispatch_weight::<T>() + max_weight_of!(approve())
+ }
+
+ fn transfer_from() -> Weight {
+ dispatch_weight::<T>() + max_weight_of!(transfer_from())
+ }
+
+ fn burn_from() -> Weight {
+ dispatch_weight::<T>() + max_weight_of!(burn_from())
+ }
+
+ fn burn_recursively_self_raw() -> Weight {
+ max_weight_of!(burn_recursively_self_raw())
+ }
+
+ fn burn_recursively_breadth_raw(amount: u32) -> Weight {
+ max_weight_of!(burn_recursively_breadth_raw(amount))
+ }
+}
+
+#[cfg(feature = "refungible")]
+impl<T> RefungibleExtensionsWeightInfo for CommonWeights<T>
+where
+ T: FungibleConfig + NonfungibleConfig + RefungibleConfig,
+{
+ fn repartition() -> Weight {
+ dispatch_weight::<T>() + <<T as RefungibleConfig>::WeightInfo>::repartition_item()
+ }
+}
+
+#[cfg(not(feature = "refungible"))]
+impl<T> RefungibleExtensionsWeightInfo for CommonWeights<T>
+where
+ T: FungibleConfig + NonfungibleConfig,
+{
+ fn repartition() -> Weight {
+ dispatch_weight::<T>()
+ }
+}
runtime/opal/Cargo.tomldiffbeforeafterboth--- a/runtime/opal/Cargo.toml
+++ b/runtime/opal/Cargo.toml
@@ -16,7 +16,7 @@
targets = ['x86_64-unknown-linux-gnu']
[features]
-default = ['std']
+default = ['std', 'opal-runtime']
runtime-benchmarks = [
'hex-literal',
'frame-benchmarking',
@@ -113,13 +113,20 @@
'xcm/std',
'xcm-builder/std',
'xcm-executor/std',
- 'unique-runtime-common/std',
+ 'up-common/std',
'rmrk-rpc/std',
+ 'evm-coder/std',
+ 'up-sponsorship/std',
"orml-vesting/std",
]
limit-testing = ['pallet-unique/limit-testing', 'up-data-structs/limit-testing']
+opal-runtime = ['refungible', 'scheduler', 'rmrk']
+refungible = []
+scheduler = []
+rmrk = []
+
################################################################################
# Substrate Dependencies
@@ -396,7 +403,7 @@
[dependencies]
log = { version = "0.4.16", default-features = false }
-unique-runtime-common = { path = "../common", default-features = false }
+up-common = { path = "../../primitives/common", default-features = false }
scale-info = { version = "2.0.1", default-features = false, features = [
"derive",
] }
@@ -426,6 +433,8 @@
pallet-base-fee = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.24" }
fp-rpc = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.24" }
fp-self-contained = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.24" }
+evm-coder = { default-features = false, path = '../../crates/evm-coder' }
+up-sponsorship = { default-features = false, git = "https://github.com/uniquenetwork/pallet-sponsoring", branch = 'polkadot-v0.9.24' }
################################################################################
# Build Dependencies
runtime/opal/src/lib.rsdiffbeforeafterboth--- a/runtime/opal/src/lib.rs
+++ b/runtime/opal/src/lib.rs
@@ -25,168 +25,21 @@
#[cfg(feature = "std")]
include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs"));
-use sp_api::impl_runtime_apis;
-use sp_core::{crypto::KeyTypeId, OpaqueMetadata, H256, U256, H160};
-use sp_runtime::DispatchError;
-use fp_self_contained::*;
-// #[cfg(any(feature = "std", test))]
-// pub use sp_runtime::BuildStorage;
-
-use sp_runtime::{
- Permill, Perbill, Percent, create_runtime_str, generic, impl_opaque_keys,
- traits::{AccountIdLookup, BlakeTwo256, Block as BlockT, AccountIdConversion, Zero, Member},
- transaction_validity::{TransactionSource, TransactionValidity},
- ApplyExtrinsicResult, RuntimeAppPublic,
-};
+use frame_support::parameter_types;
-use sp_std::prelude::*;
-
-#[cfg(feature = "std")]
-use sp_version::NativeVersion;
use sp_version::RuntimeVersion;
-pub use pallet_transaction_payment::{
- Multiplier, TargetedFeeAdjustment, FeeDetails, RuntimeDispatchInfo,
-};
-// A few exports that help ease life for downstream crates.
-pub use pallet_balances::Call as BalancesCall;
-pub use pallet_evm::{
- EnsureAddressTruncated, HashedAddressMapping, Runner, account::CrossAccountId as _,
- OnMethodCall, Account as EVMAccount, FeeCalculator, GasWeightMapping,
-};
-pub use frame_support::{
- construct_runtime, match_types,
- dispatch::DispatchResult,
- PalletId, parameter_types, StorageValue, ConsensusEngineId,
- traits::{
- tokens::currency::Currency as CurrencyT, OnUnbalanced as OnUnbalancedT, Everything,
- Currency, ExistenceRequirement, Get, IsInVec, KeyOwnerProofSystem, LockIdentifier,
- OnUnbalanced, Randomness, FindAuthor, ConstU32, Imbalance, PrivilegeCmp,
- },
- weights::{
- constants::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_PER_SECOND},
- DispatchClass, DispatchInfo, GetDispatchInfo, IdentityFee, Pays, PostDispatchInfo, Weight,
- WeightToFeePolynomial, WeightToFeeCoefficient, WeightToFeeCoefficients, ConstantMultiplier,
- WeightToFee,
- },
-};
-use pallet_unique_scheduler::DispatchCall;
-use up_data_structs::{
- CollectionId, TokenId, TokenData, Property, PropertyKeyPermission, CollectionLimits,
- CollectionStats, RpcCollection,
- mapping::{EvmTokenAddressMapping, CrossTokenAddressMapping},
- TokenChild, RmrkCollectionInfo, RmrkInstanceInfo, RmrkResourceInfo, RmrkPropertyInfo,
- RmrkBaseInfo, RmrkPartType, RmrkTheme, RmrkThemeName, RmrkCollectionId, RmrkNftId,
- RmrkNftChild, RmrkPropertyKey, RmrkResourceId, RmrkBaseId,
-};
+use sp_runtime::create_runtime_str;
-// use pallet_contracts::weights::WeightInfo;
-// #[cfg(any(feature = "std", test))]
-use frame_system::{
- self as frame_system, EnsureRoot, EnsureSigned,
- limits::{BlockWeights, BlockLength},
-};
-use sp_arithmetic::{
- traits::{BaseArithmetic, Unsigned},
-};
-use smallvec::smallvec;
-// use scale_info::TypeInfo;
-use codec::{Encode, Decode};
-use fp_rpc::TransactionStatus;
-use sp_runtime::{
- traits::{
- Applyable, BlockNumberProvider, Dispatchable, PostDispatchInfoOf, DispatchInfoOf,
- Saturating, CheckedConversion,
- },
- generic::Era,
- transaction_validity::TransactionValidityError,
- DispatchErrorWithPostInfo, SaturatedConversion,
-};
+use up_common::types::*;
-// pub use pallet_timestamp::Call as TimestampCall;
-pub use sp_consensus_aura::sr25519::AuthorityId as AuraId;
+#[path = "../../common/mod.rs"]
+mod runtime_common;
-// Polkadot imports
-use pallet_xcm::XcmPassthrough;
-use polkadot_parachain::primitives::Sibling;
-use xcm::v1::{BodyId, Junction::*, MultiLocation, NetworkId, Junctions::*};
-use xcm_builder::{
- AccountId32Aliases, AllowTopLevelPaidExecutionFrom, AllowUnpaidExecutionFrom, CurrencyAdapter,
- EnsureXcmOrigin, FixedWeightBounds, LocationInverter, NativeAsset, ParentAsSuperuser,
- RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia,
- SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit,
- ParentIsPreset,
-};
-use xcm_executor::{Config, XcmExecutor, Assets};
-use sp_std::{cmp::Ordering, marker::PhantomData};
-
-use xcm::latest::{
- // Xcm,
- AssetId::{Concrete},
- Fungibility::Fungible as XcmFungible,
- MultiAsset,
- Error as XcmError,
-};
-use xcm_executor::traits::{MatchesFungible, WeightTrader};
-//use xcm_executor::traits::MatchesFungible;
+pub use runtime_common::*;
-use unique_runtime_common::{
- impl_common_runtime_apis,
- types::*,
- constants::*,
- dispatch::{CollectionDispatchT, CollectionDispatch},
- sponsoring::UniqueSponsorshipHandler,
- eth_sponsoring::UniqueEthSponsorshipHandler,
- weights::CommonWeights,
-};
-
pub const RUNTIME_NAME: &str = "opal";
pub const TOKEN_SYMBOL: &str = "OPL";
-
-type CrossAccountId = pallet_evm::account::BasicCrossAccountId<Runtime>;
-impl RuntimeInstance for Runtime {
- type CrossAccountId = self::CrossAccountId;
- type TransactionConverter = self::TransactionConverter;
-
- fn get_transaction_converter() -> TransactionConverter {
- TransactionConverter
- }
-}
-
-/// The type for looking up accounts. We don't expect more than 4 billion of them, but you
-/// never know...
-pub type AccountIndex = u32;
-
-/// Balance of an account.
-pub type Balance = u128;
-
-/// Index of a transaction in the chain.
-pub type Index = u32;
-
-/// A hash of some data used by the chain.
-pub type Hash = sp_core::H256;
-
-/// Digest item type.
-pub type DigestItem = generic::DigestItem;
-
-/// Opaque types. These are used by the CLI to instantiate machinery that don't need to know
-/// the specifics of the runtime. They can then be made to be agnostic over specific formats
-/// of data like extrinsics, allowing for them to continue syncing the network through upgrades
-/// to even the core data structures.
-pub mod opaque {
- use sp_std::prelude::*;
- use sp_runtime::impl_opaque_keys;
- use super::Aura;
-
- pub use unique_runtime_common::types::*;
-
- impl_opaque_keys! {
- pub struct SessionKeys {
- pub aura: Aura,
- }
- }
-}
-
/// This runtime version.
pub const VERSION: RuntimeVersion = RuntimeVersion {
spec_name: create_runtime_str!(RUNTIME_NAME),
@@ -199,1206 +52,15 @@
state_version: 0,
};
-#[derive(codec::Encode, codec::Decode)]
-pub enum XCMPMessage<XAccountId, XBalance> {
- /// Transfer tokens to the given account from the Parachain account.
- TransferToken(XAccountId, XBalance),
-}
-
-/// The version information used to identify this runtime when compiled natively.
-#[cfg(feature = "std")]
-pub fn native_version() -> NativeVersion {
- NativeVersion {
- runtime_version: VERSION,
- can_author_with: Default::default(),
- }
-}
-
-type NegativeImbalance = <Balances as Currency<AccountId>>::NegativeImbalance;
-
-pub struct DealWithFees;
-impl OnUnbalanced<NegativeImbalance> for DealWithFees {
- fn on_unbalanceds<B>(mut fees_then_tips: impl Iterator<Item = NegativeImbalance>) {
- if let Some(fees) = fees_then_tips.next() {
- // for fees, 100% to treasury
- let mut split = fees.ration(100, 0);
- if let Some(tips) = fees_then_tips.next() {
- // for tips, if any, 100% to treasury
- tips.ration_merge_into(100, 0, &mut split);
- }
- Treasury::on_unbalanced(split.0);
- // Author::on_unbalanced(split.1);
- }
- }
-}
-
parameter_types! {
- pub const BlockHashCount: BlockNumber = 2400;
- pub RuntimeBlockLength: BlockLength =
- BlockLength::max_with_normal_ratio(5 * 1024 * 1024, NORMAL_DISPATCH_RATIO);
- pub const AvailableBlockRatio: Perbill = Perbill::from_percent(75);
- pub const MaximumBlockLength: u32 = 5 * 1024 * 1024;
- pub RuntimeBlockWeights: BlockWeights = BlockWeights::builder()
- .base_block(BlockExecutionWeight::get())
- .for_class(DispatchClass::all(), |weights| {
- weights.base_extrinsic = ExtrinsicBaseWeight::get();
- })
- .for_class(DispatchClass::Normal, |weights| {
- weights.max_total = Some(NORMAL_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT);
- })
- .for_class(DispatchClass::Operational, |weights| {
- weights.max_total = Some(MAXIMUM_BLOCK_WEIGHT);
- // Operational transactions have some extra reserved space, so that they
- // are included even if block reached `MAXIMUM_BLOCK_WEIGHT`.
- weights.reserved = Some(
- MAXIMUM_BLOCK_WEIGHT - NORMAL_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT
- );
- })
- .avg_block_initialization(AVERAGE_ON_INITIALIZE_RATIO)
- .build_or_panic();
pub const Version: RuntimeVersion = VERSION;
pub const SS58Prefix: u8 = 42;
-}
-
-parameter_types! {
pub const ChainId: u64 = 8882;
-}
-
-pub struct FixedFee;
-impl FeeCalculator for FixedFee {
- fn min_gas_price() -> (U256, u64) {
- (MIN_GAS_PRICE.into(), 0)
- }
-}
-
-// Assuming slowest ethereum opcode is SSTORE, with gas price of 20000 as our worst case
-// (contract, which only writes a lot of data),
-// approximating on top of our real store write weight
-parameter_types! {
- pub const WritesPerSecond: u64 = WEIGHT_PER_SECOND / <Runtime as frame_system::Config>::DbWeight::get().write;
- pub const GasPerSecond: u64 = WritesPerSecond::get() * 20000;
- pub const WeightPerGas: u64 = WEIGHT_PER_SECOND / GasPerSecond::get();
}
-/// Limiting EVM execution to 50% of block for substrate users and management tasks
-/// EVM transaction consumes more weight than substrate's, so we can't rely on them being
-/// scheduled fairly
-const EVM_DISPATCH_RATIO: Perbill = Perbill::from_percent(50);
-parameter_types! {
- pub BlockGasLimit: U256 = U256::from(NORMAL_DISPATCH_RATIO * EVM_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT / WeightPerGas::get());
-}
-
-pub enum FixedGasWeightMapping {}
-impl GasWeightMapping for FixedGasWeightMapping {
- fn gas_to_weight(gas: u64) -> Weight {
- gas.saturating_mul(WeightPerGas::get())
- }
- fn weight_to_gas(weight: Weight) -> u64 {
- weight / WeightPerGas::get()
- }
-}
-
-impl pallet_evm::account::Config for Runtime {
- type CrossAccountId = pallet_evm::account::BasicCrossAccountId<Self>;
- type EvmAddressMapping = pallet_evm::HashedAddressMapping<Self::Hashing>;
- type EvmBackwardsAddressMapping = fp_evm_mapping::MapBackwardsAddressTruncated;
-}
-
-impl pallet_evm::Config for Runtime {
- type BlockGasLimit = BlockGasLimit;
- type FeeCalculator = FixedFee;
- type GasWeightMapping = FixedGasWeightMapping;
- type BlockHashMapping = pallet_ethereum::EthereumBlockHashMapping<Self>;
- type CallOrigin = EnsureAddressTruncated<Self>;
- type WithdrawOrigin = EnsureAddressTruncated<Self>;
- type AddressMapping = HashedAddressMapping<Self::Hashing>;
- type PrecompilesType = ();
- type PrecompilesValue = ();
- type Currency = Balances;
- type Event = Event;
- type OnMethodCall = (
- pallet_evm_migration::OnMethodCall<Self>,
- pallet_evm_contract_helpers::HelpersOnMethodCall<Self>,
- CollectionDispatchT<Self>,
- pallet_unique::eth::CollectionHelpersOnMethodCall<Self>,
- );
- type OnCreate = pallet_evm_contract_helpers::HelpersOnCreate<Self>;
- type ChainId = ChainId;
- type Runner = pallet_evm::runner::stack::Runner<Self>;
- type OnChargeTransaction = pallet_evm::EVMCurrencyAdapter<Balances, DealWithFees>;
- type TransactionValidityHack = pallet_evm_transaction_payment::TransactionValidityHack<Self>;
- type FindAuthor = EthereumFindAuthor<Aura>;
-}
-
-impl pallet_evm_migration::Config for Runtime {
- type WeightInfo = pallet_evm_migration::weights::SubstrateWeight<Self>;
-}
-
-pub struct EthereumFindAuthor<F>(core::marker::PhantomData<F>);
-impl<F: FindAuthor<u32>> FindAuthor<H160> for EthereumFindAuthor<F> {
- fn find_author<'a, I>(digests: I) -> Option<H160>
- where
- I: 'a + IntoIterator<Item = (ConsensusEngineId, &'a [u8])>,
- {
- if let Some(author_index) = F::find_author(digests) {
- let authority_id = Aura::authorities()[author_index as usize].clone();
- return Some(H160::from_slice(&authority_id.to_raw_vec()[4..24]));
- }
- None
- }
-}
-
-impl pallet_ethereum::Config for Runtime {
- type Event = Event;
- type StateRoot = pallet_ethereum::IntermediateStateRoot<Self>;
-}
-
-impl pallet_randomness_collective_flip::Config for Runtime {}
-
-impl frame_system::Config for Runtime {
- /// The data to be stored in an account.
- type AccountData = pallet_balances::AccountData<Balance>;
- /// The identifier used to distinguish between accounts.
- type AccountId = AccountId;
- /// The basic call filter to use in dispatchable.
- type BaseCallFilter = Everything;
- /// Maximum number of block number to block hash mappings to keep (oldest pruned first).
- type BlockHashCount = BlockHashCount;
- /// The maximum length of a block (in bytes).
- type BlockLength = RuntimeBlockLength;
- /// The index type for blocks.
- type BlockNumber = BlockNumber;
- /// The weight of the overhead invoked on the block import process, independent of the extrinsics included in that block.
- type BlockWeights = RuntimeBlockWeights;
- /// The aggregated dispatch type that is available for extrinsics.
- type Call = Call;
- /// The weight of database operations that the runtime can invoke.
- type DbWeight = RocksDbWeight;
- /// The ubiquitous event type.
- type Event = Event;
- /// The type for hashing blocks and tries.
- type Hash = Hash;
- /// The hashing algorithm used.
- type Hashing = BlakeTwo256;
- /// The header type.
- type Header = generic::Header<BlockNumber, BlakeTwo256>;
- /// The index type for storing how many extrinsics an account has signed.
- type Index = Index;
- /// The lookup mechanism to get account ID from whatever is passed in dispatchers.
- type Lookup = AccountIdLookup<AccountId, ()>;
- /// What to do if an account is fully reaped from the system.
- type OnKilledAccount = ();
- /// What to do if a new account is created.
- type OnNewAccount = ();
- type OnSetCode = cumulus_pallet_parachain_system::ParachainSetCode<Self>;
- /// The ubiquitous origin type.
- type Origin = Origin;
- /// This type is being generated by `construct_runtime!`.
- type PalletInfo = PalletInfo;
- /// This is used as an identifier of the chain. 42 is the generic substrate prefix.
- type SS58Prefix = SS58Prefix;
- /// Weight information for the extrinsics of this pallet.
- type SystemWeightInfo = frame_system::weights::SubstrateWeight<Self>;
- /// Version of the runtime.
- type Version = Version;
- type MaxConsumers = ConstU32<16>;
-}
-
-parameter_types! {
- pub const MinimumPeriod: u64 = SLOT_DURATION / 2;
-}
-
-impl pallet_timestamp::Config for Runtime {
- /// A timestamp: milliseconds since the unix epoch.
- type Moment = u64;
- type OnTimestampSet = ();
- type MinimumPeriod = MinimumPeriod;
- type WeightInfo = ();
-}
-
-parameter_types! {
- // pub const ExistentialDeposit: u128 = 500;
- pub const ExistentialDeposit: u128 = 0;
- pub const MaxLocks: u32 = 50;
- pub const MaxReserves: u32 = 50;
-}
-
-impl pallet_balances::Config for Runtime {
- type MaxLocks = MaxLocks;
- type MaxReserves = MaxReserves;
- type ReserveIdentifier = [u8; 16];
- /// The type for recording an account's balance.
- type Balance = Balance;
- /// The ubiquitous event type.
- type Event = Event;
- type DustRemoval = Treasury;
- type ExistentialDeposit = ExistentialDeposit;
- type AccountStore = System;
- type WeightInfo = pallet_balances::weights::SubstrateWeight<Self>;
-}
-
-pub const fn deposit(items: u32, bytes: u32) -> Balance {
- items as Balance * 15 * CENTIUNIQUE + (bytes as Balance) * 6 * CENTIUNIQUE
-}
-
-/*
-parameter_types! {
- pub TombstoneDeposit: Balance = deposit(
- 1,
- sp_std::mem::size_of::<pallet_contracts::Pallet<Runtime>> as u32,
- );
- pub DepositPerContract: Balance = TombstoneDeposit::get();
- pub const DepositPerStorageByte: Balance = deposit(0, 1);
- pub const DepositPerStorageItem: Balance = deposit(1, 0);
- pub RentFraction: Perbill = Perbill::from_rational(1u32, 30 * DAYS);
- pub const SurchargeReward: Balance = 150 * MILLIUNIQUE;
- pub const SignedClaimHandicap: u32 = 2;
- pub const MaxDepth: u32 = 32;
- pub const MaxValueSize: u32 = 16 * 1024;
- pub const MaxCodeSize: u32 = 1024 * 1024 * 25; // 25 Mb
- // The lazy deletion runs inside on_initialize.
- pub DeletionWeightLimit: Weight = AVERAGE_ON_INITIALIZE_RATIO *
- RuntimeBlockWeights::get().max_block;
- // The weight needed for decoding the queue should be less or equal than a fifth
- // of the overall weight dedicated to the lazy deletion.
- pub DeletionQueueDepth: u32 = ((DeletionWeightLimit::get() / (
- <Runtime as pallet_contracts::Config>::WeightInfo::on_initialize_per_queue_item(1) -
- <Runtime as pallet_contracts::Config>::WeightInfo::on_initialize_per_queue_item(0)
- )) / 5) as u32;
- pub Schedule: pallet_contracts::Schedule<Runtime> = Default::default();
-}
-
-impl pallet_contracts::Config for Runtime {
- type Time = Timestamp;
- type Randomness = RandomnessCollectiveFlip;
- type Currency = Balances;
- type Event = Event;
- type RentPayment = ();
- type SignedClaimHandicap = SignedClaimHandicap;
- type TombstoneDeposit = TombstoneDeposit;
- type DepositPerContract = DepositPerContract;
- type DepositPerStorageByte = DepositPerStorageByte;
- type DepositPerStorageItem = DepositPerStorageItem;
- type RentFraction = RentFraction;
- type SurchargeReward = SurchargeReward;
- type WeightPrice = pallet_transaction_payment::Pallet<Self>;
- type WeightInfo = pallet_contracts::weights::SubstrateWeight<Self>;
- type ChainExtension = NFTExtension;
- type DeletionQueueDepth = DeletionQueueDepth;
- type DeletionWeightLimit = DeletionWeightLimit;
- type Schedule = Schedule;
- type CallStack = [pallet_contracts::Frame<Self>; 31];
-}
-*/
+construct_runtime!(opal);
-parameter_types! {
- /// This value increases the priority of `Operational` transactions by adding
- /// a "virtual tip" that's equal to the `OperationalFeeMultiplier * final_fee`.
- pub const OperationalFeeMultiplier: u8 = 5;
-}
-
-/// Linear implementor of `WeightToFeePolynomial`
-pub struct LinearFee<T>(sp_std::marker::PhantomData<T>);
-
-impl<T> WeightToFeePolynomial for LinearFee<T>
-where
- T: BaseArithmetic + From<u32> + Copy + Unsigned,
-{
- type Balance = T;
-
- fn polynomial() -> WeightToFeeCoefficients<Self::Balance> {
- smallvec!(WeightToFeeCoefficient {
- coeff_integer: WEIGHT_TO_FEE_COEFF.into(),
- coeff_frac: Perbill::zero(),
- negative: false,
- degree: 1,
- })
- }
-}
-
-impl pallet_transaction_payment::Config for Runtime {
- type OnChargeTransaction = pallet_transaction_payment::CurrencyAdapter<Balances, DealWithFees>;
- type LengthToFee = ConstantMultiplier<Balance, TransactionByteFee>;
- type OperationalFeeMultiplier = OperationalFeeMultiplier;
- type WeightToFee = LinearFee<Balance>;
- type FeeMultiplierUpdate = ();
-}
-
-parameter_types! {
- pub const ProposalBond: Permill = Permill::from_percent(5);
- pub const ProposalBondMinimum: Balance = 1 * UNIQUE;
- pub const ProposalBondMaximum: Balance = 1000 * UNIQUE;
- pub const SpendPeriod: BlockNumber = 5 * MINUTES;
- pub const Burn: Permill = Permill::from_percent(0);
- pub const TipCountdown: BlockNumber = 1 * DAYS;
- pub const TipFindersFee: Percent = Percent::from_percent(20);
- pub const TipReportDepositBase: Balance = 1 * UNIQUE;
- pub const DataDepositPerByte: Balance = 1 * CENTIUNIQUE;
- pub const BountyDepositBase: Balance = 1 * UNIQUE;
- pub const BountyDepositPayoutDelay: BlockNumber = 1 * DAYS;
- pub const TreasuryModuleId: PalletId = PalletId(*b"py/trsry");
- pub const BountyUpdatePeriod: BlockNumber = 14 * DAYS;
- pub const MaximumReasonLength: u32 = 16384;
- pub const BountyCuratorDeposit: Permill = Permill::from_percent(50);
- pub const BountyValueMinimum: Balance = 5 * UNIQUE;
- pub const MaxApprovals: u32 = 100;
-}
-
-impl pallet_treasury::Config for Runtime {
- type PalletId = TreasuryModuleId;
- type Currency = Balances;
- type ApproveOrigin = EnsureRoot<AccountId>;
- type RejectOrigin = EnsureRoot<AccountId>;
- type Event = Event;
- type OnSlash = ();
- type ProposalBond = ProposalBond;
- type ProposalBondMinimum = ProposalBondMinimum;
- type ProposalBondMaximum = ProposalBondMaximum;
- type SpendPeriod = SpendPeriod;
- type Burn = Burn;
- type BurnDestination = ();
- type SpendFunds = ();
- type WeightInfo = pallet_treasury::weights::SubstrateWeight<Self>;
- type MaxApprovals = MaxApprovals;
-}
-
-impl pallet_sudo::Config for Runtime {
- type Event = Event;
- type Call = Call;
-}
-
-pub struct RelayChainBlockNumberProvider<T>(sp_std::marker::PhantomData<T>);
-
-impl<T: cumulus_pallet_parachain_system::Config> BlockNumberProvider
- for RelayChainBlockNumberProvider<T>
-{
- type BlockNumber = BlockNumber;
-
- fn current_block_number() -> Self::BlockNumber {
- cumulus_pallet_parachain_system::Pallet::<T>::validation_data()
- .map(|d| d.relay_parent_number)
- .unwrap_or_default()
- }
-}
-
-parameter_types! {
- pub const MinVestedTransfer: Balance = 10 * UNIQUE;
- pub const MaxVestingSchedules: u32 = 28;
-}
-
-impl orml_vesting::Config for Runtime {
- type Event = Event;
- type Currency = pallet_balances::Pallet<Runtime>;
- type MinVestedTransfer = MinVestedTransfer;
- type VestedTransferOrigin = EnsureSigned<AccountId>;
- type WeightInfo = ();
- type MaxVestingSchedules = MaxVestingSchedules;
- type BlockNumberProvider = RelayChainBlockNumberProvider<Runtime>;
-}
-
-parameter_types! {
- pub const ReservedDmpWeight: Weight = MAXIMUM_BLOCK_WEIGHT / 4;
- pub const ReservedXcmpWeight: Weight = MAXIMUM_BLOCK_WEIGHT / 4;
-}
-
-impl cumulus_pallet_parachain_system::Config for Runtime {
- type Event = Event;
- type SelfParaId = parachain_info::Pallet<Self>;
- type OnSystemEvent = ();
- // type DownwardMessageHandlers = cumulus_primitives_utility::UnqueuedDmpAsParent<
- // MaxDownwardMessageWeight,
- // XcmExecutor<XcmConfig>,
- // Call,
- // >;
- type OutboundXcmpMessageSource = XcmpQueue;
- type DmpMessageHandler = DmpQueue;
- type ReservedDmpWeight = ReservedDmpWeight;
- type ReservedXcmpWeight = ReservedXcmpWeight;
- type XcmpMessageHandler = XcmpQueue;
-}
-
-impl parachain_info::Config for Runtime {}
-
-impl cumulus_pallet_aura_ext::Config for Runtime {}
-
-parameter_types! {
- pub const RelayLocation: MultiLocation = MultiLocation::parent();
- pub const RelayNetwork: NetworkId = NetworkId::Polkadot;
- pub RelayOrigin: Origin = cumulus_pallet_xcm::Origin::Relay.into();
- pub Ancestry: MultiLocation = Parachain(ParachainInfo::parachain_id().into()).into();
-}
-
-/// Type for specifying how a `MultiLocation` can be converted into an `AccountId`. This is used
-/// when determining ownership of accounts for asset transacting and when attempting to use XCM
-/// `Transact` in order to determine the dispatch Origin.
-pub type LocationToAccountId = (
- // The parent (Relay-chain) origin converts to the default `AccountId`.
- ParentIsPreset<AccountId>,
- // Sibling parachain origins convert to AccountId via the `ParaId::into`.
- SiblingParachainConvertsVia<Sibling, AccountId>,
- // Straight up local `AccountId32` origins just alias directly to `AccountId`.
- AccountId32Aliases<RelayNetwork, AccountId>,
-);
-
-pub struct OnlySelfCurrency;
-impl<B: TryFrom<u128>> MatchesFungible<B> for OnlySelfCurrency {
- fn matches_fungible(a: &MultiAsset) -> Option<B> {
- match (&a.id, &a.fun) {
- (Concrete(_), XcmFungible(ref amount)) => CheckedConversion::checked_from(*amount),
- _ => None,
- }
- }
-}
-
-/// Means for transacting assets on this chain.
-pub type LocalAssetTransactor = CurrencyAdapter<
- // Use this currency:
- Balances,
- // Use this currency when it is a fungible asset matching the given location or name:
- OnlySelfCurrency,
- // Do a simple punn to convert an AccountId32 MultiLocation into a native chain account ID:
- LocationToAccountId,
- // Our chain's account ID type (we can't get away without mentioning it explicitly):
- AccountId,
- // We don't track any teleports.
- (),
->;
-
-/// This is the type we use to convert an (incoming) XCM origin into a local `Origin` instance,
-/// ready for dispatching a transaction with Xcm's `Transact`. There is an `OriginKind` which can
-/// biases the kind of local `Origin` it will become.
-pub type XcmOriginToTransactDispatchOrigin = (
- // Sovereign account converter; this attempts to derive an `AccountId` from the origin location
- // using `LocationToAccountId` and then turn that into the usual `Signed` origin. Useful for
- // foreign chains who want to have a local sovereign account on this chain which they control.
- SovereignSignedViaLocation<LocationToAccountId, Origin>,
- // Native converter for Relay-chain (Parent) location; will converts to a `Relay` origin when
- // recognised.
- RelayChainAsNative<RelayOrigin, Origin>,
- // Native converter for sibling Parachains; will convert to a `SiblingPara` origin when
- // recognised.
- SiblingParachainAsNative<cumulus_pallet_xcm::Origin, Origin>,
- // Superuser converter for the Relay-chain (Parent) location. This will allow it to issue a
- // transaction from the Root origin.
- ParentAsSuperuser<Origin>,
- // Native signed account converter; this just converts an `AccountId32` origin into a normal
- // `Origin::Signed` origin of the same 32-byte value.
- SignedAccountId32AsNative<RelayNetwork, Origin>,
- // Xcm origins can be represented natively under the Xcm pallet's Xcm origin.
- XcmPassthrough<Origin>,
-);
-
-parameter_types! {
- // One XCM operation is 1_000_000 weight - almost certainly a conservative estimate.
- pub UnitWeightCost: Weight = 1_000_000;
- // 1200 UNIQUEs buy 1 second of weight.
- pub const WeightPrice: (MultiLocation, u128) = (MultiLocation::parent(), 1_200 * UNIQUE);
- pub const MaxInstructions: u32 = 100;
- pub const MaxAuthorities: u32 = 100_000;
-}
-
-match_types! {
- pub type ParentOrParentsUnitPlurality: impl Contains<MultiLocation> = {
- MultiLocation { parents: 1, interior: Here } |
- MultiLocation { parents: 1, interior: X1(Plurality { id: BodyId::Unit, .. }) }
- };
-}
-
-pub type Barrier = (
- TakeWeightCredit,
- AllowTopLevelPaidExecutionFrom<Everything>,
- // ^^^ Parent & its unit plurality gets free execution
-);
-
-pub struct UsingOnlySelfCurrencyComponents<
- WeightToFee: WeightToFeePolynomial<Balance = Currency::Balance>,
- AssetId: Get<MultiLocation>,
- AccountId,
- Currency: CurrencyT<AccountId>,
- OnUnbalanced: OnUnbalancedT<Currency::NegativeImbalance>,
->(
- Weight,
- Currency::Balance,
- PhantomData<(WeightToFee, AssetId, AccountId, Currency, OnUnbalanced)>,
-);
-impl<
- WeightToFee: WeightToFeePolynomial<Balance = Currency::Balance>,
- AssetId: Get<MultiLocation>,
- AccountId,
- Currency: CurrencyT<AccountId>,
- OnUnbalanced: OnUnbalancedT<Currency::NegativeImbalance>,
- > WeightTrader
- for UsingOnlySelfCurrencyComponents<WeightToFee, AssetId, AccountId, Currency, OnUnbalanced>
-{
- fn new() -> Self {
- Self(0, Zero::zero(), PhantomData)
- }
-
- fn buy_weight(&mut self, weight: Weight, payment: Assets) -> Result<Assets, XcmError> {
- let amount = WeightToFee::weight_to_fee(&weight);
- let u128_amount: u128 = amount.try_into().map_err(|_| XcmError::Overflow)?;
-
- // location to this parachain through relay chain
- let option1: xcm::v1::AssetId = Concrete(MultiLocation {
- parents: 1,
- interior: X1(Parachain(ParachainInfo::parachain_id().into())),
- });
- // direct location
- let option2: xcm::v1::AssetId = Concrete(MultiLocation {
- parents: 0,
- interior: Here,
- });
-
- let required = if payment.fungible.contains_key(&option1) {
- (option1, u128_amount).into()
- } else if payment.fungible.contains_key(&option2) {
- (option2, u128_amount).into()
- } else {
- (Concrete(MultiLocation::default()), u128_amount).into()
- };
-
- let unused = payment
- .checked_sub(required)
- .map_err(|_| XcmError::TooExpensive)?;
- self.0 = self.0.saturating_add(weight);
- self.1 = self.1.saturating_add(amount);
- Ok(unused)
- }
-
- fn refund_weight(&mut self, weight: Weight) -> Option<MultiAsset> {
- let weight = weight.min(self.0);
- let amount = WeightToFee::weight_to_fee(&weight);
- self.0 -= weight;
- self.1 = self.1.saturating_sub(amount);
- let amount: u128 = amount.saturated_into();
- if amount > 0 {
- Some((AssetId::get(), amount).into())
- } else {
- None
- }
- }
-}
-impl<
- WeightToFee: WeightToFeePolynomial<Balance = Currency::Balance>,
- AssetId: Get<MultiLocation>,
- AccountId,
- Currency: CurrencyT<AccountId>,
- OnUnbalanced: OnUnbalancedT<Currency::NegativeImbalance>,
- > Drop
- for UsingOnlySelfCurrencyComponents<WeightToFee, AssetId, AccountId, Currency, OnUnbalanced>
-{
- fn drop(&mut self) {
- OnUnbalanced::on_unbalanced(Currency::issue(self.1));
- }
-}
-
-pub struct XcmConfig;
-impl Config for XcmConfig {
- type Call = Call;
- type XcmSender = XcmRouter;
- // How to withdraw and deposit an asset.
- type AssetTransactor = LocalAssetTransactor;
- type OriginConverter = XcmOriginToTransactDispatchOrigin;
- type IsReserve = NativeAsset;
- type IsTeleporter = (); // Teleportation is disabled
- type LocationInverter = LocationInverter<Ancestry>;
- type Barrier = Barrier;
- type Weigher = FixedWeightBounds<UnitWeightCost, Call, MaxInstructions>;
- type Trader =
- UsingOnlySelfCurrencyComponents<LinearFee<Balance>, RelayLocation, AccountId, Balances, ()>;
- type ResponseHandler = (); // Don't handle responses for now.
- type SubscriptionService = PolkadotXcm;
-
- type AssetTrap = PolkadotXcm;
- type AssetClaims = PolkadotXcm;
-}
-
-// parameter_types! {
-// pub const MaxDownwardMessageWeight: Weight = MAXIMUM_BLOCK_WEIGHT / 10;
-// }
-
-/// No local origins on this chain are allowed to dispatch XCM sends/executions.
-pub type LocalOriginToLocation = (SignedToAccountId32<Origin, AccountId, RelayNetwork>,);
-
-/// The means for routing XCM messages which are not for local execution into the right message
-/// queues.
-pub type XcmRouter = (
- // Two routers - use UMP to communicate with the relay chain:
- cumulus_primitives_utility::ParentAsUmp<ParachainSystem, ()>,
- // ..and XCMP to communicate with the sibling chains.
- XcmpQueue,
-);
-
-impl pallet_evm_coder_substrate::Config for Runtime {}
-
-impl pallet_xcm::Config for Runtime {
- type Event = Event;
- type SendXcmOrigin = EnsureXcmOrigin<Origin, LocalOriginToLocation>;
- type XcmRouter = XcmRouter;
- type ExecuteXcmOrigin = EnsureXcmOrigin<Origin, LocalOriginToLocation>;
- type XcmExecuteFilter = Everything;
- type XcmExecutor = XcmExecutor<XcmConfig>;
- type XcmTeleportFilter = Everything;
- type XcmReserveTransferFilter = Everything;
- type Weigher = FixedWeightBounds<UnitWeightCost, Call, MaxInstructions>;
- type LocationInverter = LocationInverter<Ancestry>;
- type Origin = Origin;
- type Call = Call;
- const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 100;
- type AdvertisedXcmVersion = pallet_xcm::CurrentXcmVersion;
-}
-
-impl cumulus_pallet_xcm::Config for Runtime {
- type Event = Event;
- type XcmExecutor = XcmExecutor<XcmConfig>;
-}
-
-impl cumulus_pallet_xcmp_queue::Config for Runtime {
- type WeightInfo = ();
- type Event = Event;
- type XcmExecutor = XcmExecutor<XcmConfig>;
- type ChannelInfo = ParachainSystem;
- type VersionWrapper = ();
- type ExecuteOverweightOrigin = frame_system::EnsureRoot<AccountId>;
- type ControllerOrigin = EnsureRoot<AccountId>;
- type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin;
-}
-
-impl cumulus_pallet_dmp_queue::Config for Runtime {
- type Event = Event;
- type XcmExecutor = XcmExecutor<XcmConfig>;
- type ExecuteOverweightOrigin = frame_system::EnsureRoot<AccountId>;
-}
-
-impl pallet_aura::Config for Runtime {
- type AuthorityId = AuraId;
- type DisabledValidators = ();
- type MaxAuthorities = MaxAuthorities;
-}
-
-parameter_types! {
- pub TreasuryAccountId: AccountId = TreasuryModuleId::get().into_account_truncating();
- pub const CollectionCreationPrice: Balance = 2 * UNIQUE;
-}
-
-impl pallet_common::Config for Runtime {
- type WeightInfo = pallet_common::weights::SubstrateWeight<Self>;
- type Event = Event;
- type Currency = Balances;
- type CollectionCreationPrice = CollectionCreationPrice;
- type TreasuryAccountId = TreasuryAccountId;
- type CollectionDispatch = CollectionDispatchT<Self>;
-
- type EvmTokenAddressMapping = EvmTokenAddressMapping;
- type CrossTokenAddressMapping = CrossTokenAddressMapping<Self::AccountId>;
- type ContractAddress = EvmCollectionHelpersAddress;
-}
-
-impl pallet_structure::Config for Runtime {
- type Event = Event;
- type Call = Call;
- type WeightInfo = pallet_structure::weights::SubstrateWeight<Self>;
-}
-
-impl pallet_fungible::Config for Runtime {
- type WeightInfo = pallet_fungible::weights::SubstrateWeight<Self>;
-}
-impl pallet_refungible::Config for Runtime {
- type WeightInfo = pallet_refungible::weights::SubstrateWeight<Self>;
-}
-impl pallet_nonfungible::Config for Runtime {
- type WeightInfo = pallet_nonfungible::weights::SubstrateWeight<Self>;
-}
-
-impl pallet_proxy_rmrk_core::Config for Runtime {
- type WeightInfo = pallet_proxy_rmrk_core::weights::SubstrateWeight<Self>;
- type Event = Event;
-}
-
-impl pallet_proxy_rmrk_equip::Config for Runtime {
- type WeightInfo = pallet_proxy_rmrk_equip::weights::SubstrateWeight<Self>;
- type Event = Event;
-}
-
-impl pallet_unique::Config for Runtime {
- type Event = Event;
- type WeightInfo = pallet_unique::weights::SubstrateWeight<Self>;
- type CommonWeightInfo = CommonWeights<Self>;
- type RefungibleExtensionsWeightInfo = CommonWeights<Self>;
-}
-
-parameter_types! {
- pub const InflationBlockInterval: BlockNumber = 100; // every time per how many blocks inflation is applied
-}
-
-/// Used for the pallet inflation
-impl pallet_inflation::Config for Runtime {
- type Currency = Balances;
- type TreasuryAccountId = TreasuryAccountId;
- type InflationBlockInterval = InflationBlockInterval;
- type BlockNumberProvider = RelayChainBlockNumberProvider<Runtime>;
-}
-
-parameter_types! {
- pub MaximumSchedulerWeight: Weight = Perbill::from_percent(50) *
- RuntimeBlockWeights::get().max_block;
- pub const MaxScheduledPerBlock: u32 = 50;
-}
-
-type ChargeTransactionPayment = pallet_charge_transaction::ChargeTransactionPayment<Runtime>;
-use frame_support::traits::NamedReservableCurrency;
-
-fn get_signed_extras(from: <Runtime as frame_system::Config>::AccountId) -> SignedExtraScheduler {
- (
- frame_system::CheckSpecVersion::<Runtime>::new(),
- frame_system::CheckGenesis::<Runtime>::new(),
- frame_system::CheckEra::<Runtime>::from(Era::Immortal),
- frame_system::CheckNonce::<Runtime>::from(frame_system::Pallet::<Runtime>::account_nonce(
- from,
- )),
- frame_system::CheckWeight::<Runtime>::new(),
- // sponsoring transaction logic
- // pallet_charge_transaction::ChargeTransactionPayment::<Runtime>::new(0),
- )
-}
-
-pub struct SchedulerPaymentExecutor;
-impl<T: frame_system::Config + pallet_unique_scheduler::Config, SelfContainedSignedInfo>
- DispatchCall<T, SelfContainedSignedInfo> for SchedulerPaymentExecutor
-where
- <T as frame_system::Config>::Call: Member
- + Dispatchable<Origin = Origin, Info = DispatchInfo>
- + SelfContainedCall<SignedInfo = SelfContainedSignedInfo>
- + GetDispatchInfo
- + From<frame_system::Call<Runtime>>,
- SelfContainedSignedInfo: Send + Sync + 'static,
- Call: From<<T as frame_system::Config>::Call>
- + From<<T as pallet_unique_scheduler::Config>::Call>
- + SelfContainedCall<SignedInfo = SelfContainedSignedInfo>,
- sp_runtime::AccountId32: From<<T as frame_system::Config>::AccountId>,
-{
- fn dispatch_call(
- signer: <T as frame_system::Config>::AccountId,
- call: <T as pallet_unique_scheduler::Config>::Call,
- ) -> Result<
- Result<PostDispatchInfo, DispatchErrorWithPostInfo<PostDispatchInfo>>,
- TransactionValidityError,
- > {
- let dispatch_info = call.get_dispatch_info();
- let extrinsic = fp_self_contained::CheckedExtrinsic::<
- AccountId,
- Call,
- SignedExtraScheduler,
- SelfContainedSignedInfo,
- > {
- signed:
- CheckedSignature::<AccountId, SignedExtraScheduler, SelfContainedSignedInfo>::Signed(
- signer.clone().into(),
- get_signed_extras(signer.into()),
- ),
- function: call.into(),
- };
-
- extrinsic.apply::<Runtime>(&dispatch_info, 0)
- }
-
- fn reserve_balance(
- id: [u8; 16],
- sponsor: <T as frame_system::Config>::AccountId,
- call: <T as pallet_unique_scheduler::Config>::Call,
- count: u32,
- ) -> Result<(), DispatchError> {
- let dispatch_info = call.get_dispatch_info();
- let weight: Balance = ChargeTransactionPayment::traditional_fee(0, &dispatch_info, 0)
- .saturating_mul(count.into());
-
- <Balances as NamedReservableCurrency<AccountId>>::reserve_named(
- &id,
- &(sponsor.into()),
- weight,
- )
- }
-
- fn pay_for_call(
- id: [u8; 16],
- sponsor: <T as frame_system::Config>::AccountId,
- call: <T as pallet_unique_scheduler::Config>::Call,
- ) -> Result<u128, DispatchError> {
- let dispatch_info = call.get_dispatch_info();
- let weight: Balance = ChargeTransactionPayment::traditional_fee(0, &dispatch_info, 0);
- Ok(
- <Balances as NamedReservableCurrency<AccountId>>::unreserve_named(
- &id,
- &(sponsor.into()),
- weight,
- ),
- )
- }
-
- fn cancel_reserve(
- id: [u8; 16],
- sponsor: <T as frame_system::Config>::AccountId,
- ) -> Result<u128, DispatchError> {
- Ok(
- <Balances as NamedReservableCurrency<AccountId>>::unreserve_named(
- &id,
- &(sponsor.into()),
- u128::MAX,
- ),
- )
- }
-}
-
-parameter_types! {
- pub const NoPreimagePostponement: Option<u32> = Some(10);
- pub const Preimage: Option<u32> = Some(10);
-}
-
-/// Used the compare the privilege of an origin inside the scheduler.
-pub struct OriginPrivilegeCmp;
-
-impl PrivilegeCmp<OriginCaller> for OriginPrivilegeCmp {
- fn cmp_privilege(_left: &OriginCaller, _right: &OriginCaller) -> Option<Ordering> {
- Some(Ordering::Equal)
- }
-}
-
-impl pallet_unique_scheduler::Config for Runtime {
- type Event = Event;
- type Origin = Origin;
- type Currency = Balances;
- type PalletsOrigin = OriginCaller;
- type Call = Call;
- type MaximumWeight = MaximumSchedulerWeight;
- type ScheduleOrigin = EnsureSigned<AccountId>;
- type MaxScheduledPerBlock = MaxScheduledPerBlock;
- type WeightInfo = ();
- type CallExecutor = SchedulerPaymentExecutor;
- type OriginPrivilegeCmp = OriginPrivilegeCmp;
- type PreimageProvider = ();
- type NoPreimagePostponement = NoPreimagePostponement;
-}
-
-type EvmSponsorshipHandler = (
- UniqueEthSponsorshipHandler<Runtime>,
- pallet_evm_contract_helpers::HelpersContractSponsoring<Runtime>,
-);
-
-type SponsorshipHandler = (
- UniqueSponsorshipHandler<Runtime>,
- //pallet_contract_helpers::ContractSponsorshipHandler<Runtime>,
- pallet_evm_transaction_payment::BridgeSponsorshipHandler<Runtime>,
-);
-
-impl pallet_evm_transaction_payment::Config for Runtime {
- type EvmSponsorshipHandler = EvmSponsorshipHandler;
- type Currency = Balances;
-}
-
-impl pallet_charge_transaction::Config for Runtime {
- type SponsorshipHandler = SponsorshipHandler;
-}
-
-// impl pallet_contract_helpers::Config for Runtime {
-// type DefaultSponsoringRateLimit = DefaultSponsoringRateLimit;
-// }
-
-parameter_types! {
- // 0x842899ECF380553E8a4de75bF534cdf6fBF64049
- pub const HelpersContractAddress: H160 = H160([
- 0x84, 0x28, 0x99, 0xec, 0xf3, 0x80, 0x55, 0x3e, 0x8a, 0x4d, 0xe7, 0x5b, 0xf5, 0x34, 0xcd, 0xf6, 0xfb, 0xf6, 0x40, 0x49,
- ]);
-
- // 0x6c4e9fe1ae37a41e93cee429e8e1881abdcbb54f
- pub const EvmCollectionHelpersAddress: H160 = H160([
- 0x6c, 0x4e, 0x9f, 0xe1, 0xae, 0x37, 0xa4, 0x1e, 0x93, 0xce, 0xe4, 0x29, 0xe8, 0xe1, 0x88, 0x1a, 0xbd, 0xcb, 0xb5, 0x4f,
- ]);
-}
-
-impl pallet_evm_contract_helpers::Config for Runtime {
- type ContractAddress = HelpersContractAddress;
- type DefaultSponsoringRateLimit = DefaultSponsoringRateLimit;
-}
-
-construct_runtime!(
- pub enum Runtime where
- Block = Block,
- NodeBlock = opaque::Block,
- UncheckedExtrinsic = UncheckedExtrinsic
- {
- ParachainSystem: cumulus_pallet_parachain_system::{Pallet, Call, Config, Storage, Inherent, Event<T>, ValidateUnsigned} = 20,
- ParachainInfo: parachain_info::{Pallet, Storage, Config} = 21,
-
- Aura: pallet_aura::{Pallet, Config<T>} = 22,
- AuraExt: cumulus_pallet_aura_ext::{Pallet, Config} = 23,
-
- Balances: pallet_balances::{Pallet, Call, Storage, Config<T>, Event<T>} = 30,
- RandomnessCollectiveFlip: pallet_randomness_collective_flip::{Pallet, Storage} = 31,
- Timestamp: pallet_timestamp::{Pallet, Call, Storage, Inherent} = 32,
- TransactionPayment: pallet_transaction_payment::{Pallet, Storage} = 33,
- Treasury: pallet_treasury::{Pallet, Call, Storage, Config, Event<T>} = 34,
- Sudo: pallet_sudo::{Pallet, Call, Storage, Config<T>, Event<T>} = 35,
- System: frame_system::{Pallet, Call, Storage, Config, Event<T>} = 36,
- Vesting: orml_vesting::{Pallet, Storage, Call, Event<T>, Config<T>} = 37,
- // Vesting: pallet_vesting::{Pallet, Call, Config<T>, Storage, Event<T>} = 37,
- // Contracts: pallet_contracts::{Pallet, Call, Storage, Event<T>} = 38,
-
- // XCM helpers.
- XcmpQueue: cumulus_pallet_xcmp_queue::{Pallet, Call, Storage, Event<T>} = 50,
- PolkadotXcm: pallet_xcm::{Pallet, Call, Event<T>, Origin} = 51,
- CumulusXcm: cumulus_pallet_xcm::{Pallet, Call, Event<T>, Origin} = 52,
- DmpQueue: cumulus_pallet_dmp_queue::{Pallet, Call, Storage, Event<T>} = 53,
-
- // Unique Pallets
- Inflation: pallet_inflation::{Pallet, Call, Storage} = 60,
- Unique: pallet_unique::{Pallet, Call, Storage, Event<T>} = 61,
- Scheduler: pallet_unique_scheduler::{Pallet, Call, Storage, Event<T>} = 62,
- // free = 63
- Charging: pallet_charge_transaction::{Pallet, Call, Storage } = 64,
- // ContractHelpers: pallet_contract_helpers::{Pallet, Call, Storage} = 65,
- Common: pallet_common::{Pallet, Storage, Event<T>} = 66,
- Fungible: pallet_fungible::{Pallet, Storage} = 67,
- Refungible: pallet_refungible::{Pallet, Storage} = 68,
- Nonfungible: pallet_nonfungible::{Pallet, Storage} = 69,
- Structure: pallet_structure::{Pallet, Call, Storage, Event<T>} = 70,
- RmrkCore: pallet_proxy_rmrk_core::{Pallet, Call, Storage, Event<T>} = 71,
- RmrkEquip: pallet_proxy_rmrk_equip::{Pallet, Call, Storage, Event<T>} = 72,
-
- // Frontier
- EVM: pallet_evm::{Pallet, Config, Call, Storage, Event<T>} = 100,
- Ethereum: pallet_ethereum::{Pallet, Config, Call, Storage, Event, Origin} = 101,
-
- EvmCoderSubstrate: pallet_evm_coder_substrate::{Pallet, Storage} = 150,
- EvmContractHelpers: pallet_evm_contract_helpers::{Pallet, Storage} = 151,
- EvmTransactionPayment: pallet_evm_transaction_payment::{Pallet} = 152,
- EvmMigration: pallet_evm_migration::{Pallet, Call, Storage} = 153,
- }
-);
-
-pub struct TransactionConverter;
-
-impl fp_rpc::ConvertTransaction<UncheckedExtrinsic> for TransactionConverter {
- fn convert_transaction(&self, transaction: pallet_ethereum::Transaction) -> UncheckedExtrinsic {
- UncheckedExtrinsic::new_unsigned(
- pallet_ethereum::Call::<Runtime>::transact { transaction }.into(),
- )
- }
-}
-
-impl fp_rpc::ConvertTransaction<opaque::UncheckedExtrinsic> for TransactionConverter {
- fn convert_transaction(
- &self,
- transaction: pallet_ethereum::Transaction,
- ) -> opaque::UncheckedExtrinsic {
- let extrinsic = UncheckedExtrinsic::new_unsigned(
- pallet_ethereum::Call::<Runtime>::transact { transaction }.into(),
- );
- let encoded = extrinsic.encode();
- opaque::UncheckedExtrinsic::decode(&mut &encoded[..])
- .expect("Encoded extrinsic is always valid")
- }
-}
-
-/// The address format for describing accounts.
-pub type Address = sp_runtime::MultiAddress<AccountId, ()>;
-/// Block header type as expected by this runtime.
-pub type Header = generic::Header<BlockNumber, BlakeTwo256>;
-/// Block type as expected by this runtime.
-pub type Block = generic::Block<Header, UncheckedExtrinsic>;
-/// A Block signed with a Justification
-pub type SignedBlock = generic::SignedBlock<Block>;
-/// BlockId type as expected by this runtime.
-pub type BlockId = generic::BlockId<Block>;
-/// The SignedExtension to the basic transaction logic.
-pub type SignedExtra = (
- frame_system::CheckSpecVersion<Runtime>,
- // system::CheckTxVersion<Runtime>,
- frame_system::CheckGenesis<Runtime>,
- frame_system::CheckEra<Runtime>,
- frame_system::CheckNonce<Runtime>,
- frame_system::CheckWeight<Runtime>,
- ChargeTransactionPayment,
- //pallet_contract_helpers::ContractHelpersExtension<Runtime>,
- pallet_ethereum::FakeTransactionFinalizer<Runtime>,
-);
-pub type SignedExtraScheduler = (
- frame_system::CheckSpecVersion<Runtime>,
- frame_system::CheckGenesis<Runtime>,
- frame_system::CheckEra<Runtime>,
- frame_system::CheckNonce<Runtime>,
- frame_system::CheckWeight<Runtime>,
-);
-/// Unchecked extrinsic type as expected by this runtime.
-pub type UncheckedExtrinsic =
- fp_self_contained::UncheckedExtrinsic<Address, Call, Signature, SignedExtra>;
-/// Extrinsic type that has already been checked.
-pub type CheckedExtrinsic = fp_self_contained::CheckedExtrinsic<AccountId, Call, SignedExtra, H160>;
-/// Executive: handles dispatch to the various modules.
-pub type Executive = frame_executive::Executive<
- Runtime,
- Block,
- frame_system::ChainContext<Runtime>,
- Runtime,
- AllPalletsReversedWithSystemFirst,
->;
-
-impl_opaque_keys! {
- pub struct SessionKeys {
- pub aura: Aura,
- }
-}
-
-impl fp_self_contained::SelfContainedCall for Call {
- type SignedInfo = H160;
-
- fn is_self_contained(&self) -> bool {
- match self {
- Call::Ethereum(call) => call.is_self_contained(),
- _ => false,
- }
- }
-
- fn check_self_contained(&self) -> Option<Result<Self::SignedInfo, TransactionValidityError>> {
- match self {
- Call::Ethereum(call) => call.check_self_contained(),
- _ => None,
- }
- }
-
- fn validate_self_contained(
- &self,
- info: &Self::SignedInfo,
- dispatch_info: &DispatchInfoOf<Call>,
- len: usize,
- ) -> Option<TransactionValidity> {
- match self {
- Call::Ethereum(call) => call.validate_self_contained(info, dispatch_info, len),
- _ => None,
- }
- }
-
- fn pre_dispatch_self_contained(
- &self,
- info: &Self::SignedInfo,
- ) -> Option<Result<(), TransactionValidityError>> {
- match self {
- Call::Ethereum(call) => call.pre_dispatch_self_contained(info),
- _ => None,
- }
- }
-
- fn apply_self_contained(
- self,
- info: Self::SignedInfo,
- ) -> Option<sp_runtime::DispatchResultWithInfo<PostDispatchInfoOf<Self>>> {
- match self {
- call @ Call::Ethereum(pallet_ethereum::Call::transact { .. }) => Some(call.dispatch(
- Origin::from(pallet_ethereum::RawOrigin::EthereumTransaction(info)),
- )),
- _ => None,
- }
- }
-}
-
-macro_rules! dispatch_unique_runtime {
- ($collection:ident.$method:ident($($name:ident),*)) => {{
- let collection = <Runtime as pallet_common::Config>::CollectionDispatch::dispatch(<pallet_common::CollectionHandle<Runtime>>::try_get($collection)?);
- let dispatch = collection.as_dyn();
-
- Ok::<_, DispatchError>(dispatch.$method($($name),*))
- }};
-}
-
-impl_common_runtime_apis! {
- #![custom_apis]
-
- impl rmrk_rpc::RmrkApi<
- Block,
- AccountId,
- RmrkCollectionInfo<AccountId>,
- RmrkInstanceInfo<AccountId>,
- RmrkResourceInfo,
- RmrkPropertyInfo,
- RmrkBaseInfo<AccountId>,
- RmrkPartType,
- RmrkTheme
- > for Runtime {
- fn last_collection_idx() -> Result<RmrkCollectionId, DispatchError> {
- pallet_proxy_rmrk_core::rpc::last_collection_idx::<Runtime>()
- }
-
- fn collection_by_id(collection_id: RmrkCollectionId) -> Result<Option<RmrkCollectionInfo<AccountId>>, DispatchError> {
- pallet_proxy_rmrk_core::rpc::collection_by_id::<Runtime>(collection_id)
- }
-
- fn nft_by_id(collection_id: RmrkCollectionId, nft_by_id: RmrkNftId) -> Result<Option<RmrkInstanceInfo<AccountId>>, DispatchError> {
- pallet_proxy_rmrk_core::rpc::nft_by_id::<Runtime>(collection_id, nft_by_id)
- }
-
- fn account_tokens(account_id: AccountId, collection_id: RmrkCollectionId) -> Result<Vec<RmrkNftId>, DispatchError> {
- pallet_proxy_rmrk_core::rpc::account_tokens::<Runtime>(account_id, collection_id)
- }
-
- fn nft_children(collection_id: RmrkCollectionId, nft_id: RmrkNftId) -> Result<Vec<RmrkNftChild>, DispatchError> {
- pallet_proxy_rmrk_core::rpc::nft_children::<Runtime>(collection_id, nft_id)
- }
-
- fn collection_properties(collection_id: RmrkCollectionId, filter_keys: Option<Vec<RmrkPropertyKey>>) -> Result<Vec<RmrkPropertyInfo>, DispatchError> {
- pallet_proxy_rmrk_core::rpc::collection_properties::<Runtime>(collection_id, filter_keys)
- }
-
- fn nft_properties(collection_id: RmrkCollectionId, nft_id: RmrkNftId, filter_keys: Option<Vec<RmrkPropertyKey>>) -> Result<Vec<RmrkPropertyInfo>, DispatchError> {
- pallet_proxy_rmrk_core::rpc::nft_properties::<Runtime>(collection_id, nft_id, filter_keys)
- }
-
- fn nft_resources(collection_id: RmrkCollectionId, nft_id: RmrkNftId) -> Result<Vec<RmrkResourceInfo>, DispatchError> {
- pallet_proxy_rmrk_core::rpc::nft_resources::<Runtime>(collection_id, nft_id)
- }
-
- fn nft_resource_priority(collection_id: RmrkCollectionId, nft_id: RmrkNftId, resource_id: RmrkResourceId) -> Result<Option<u32>, DispatchError> {
- pallet_proxy_rmrk_core::rpc::nft_resource_priority::<Runtime>(collection_id, nft_id, resource_id)
- }
-
- fn base(base_id: RmrkBaseId) -> Result<Option<RmrkBaseInfo<AccountId>>, DispatchError> {
- pallet_proxy_rmrk_equip::rpc::base::<Runtime>(base_id)
- }
-
- fn base_parts(base_id: RmrkBaseId) -> Result<Vec<RmrkPartType>, DispatchError> {
- pallet_proxy_rmrk_equip::rpc::base_parts::<Runtime>(base_id)
- }
-
- fn theme_names(base_id: RmrkBaseId) -> Result<Vec<RmrkThemeName>, DispatchError> {
- pallet_proxy_rmrk_equip::rpc::theme_names::<Runtime>(base_id)
- }
-
- fn theme(base_id: RmrkBaseId, theme_name: RmrkThemeName, filter_keys: Option<Vec<RmrkPropertyKey>>) -> Result<Option<RmrkTheme>, DispatchError> {
- pallet_proxy_rmrk_equip::rpc::theme::<Runtime>(base_id, theme_name, filter_keys)
- }
- }
-}
-
-struct CheckInherents;
-
-impl cumulus_pallet_parachain_system::CheckInherents<Block> for CheckInherents {
- fn check_inherents(
- block: &Block,
- relay_state_proof: &cumulus_pallet_parachain_system::RelayChainStateProof,
- ) -> sp_inherents::CheckInherentsResult {
- let relay_chain_slot = relay_state_proof
- .read_slot()
- .expect("Could not read the relay chain slot from the proof");
-
- let inherent_data =
- cumulus_primitives_timestamp::InherentDataProvider::from_relay_chain_slot_and_duration(
- relay_chain_slot,
- sp_std::time::Duration::from_secs(6),
- )
- .create_inherent_data()
- .expect("Could not create the timestamp inherent data");
-
- inherent_data.check_extrinsics(block)
- }
-}
+impl_common_runtime_apis!();
cumulus_pallet_parachain_system::register_validate_block!(
Runtime = Runtime,
runtime/quartz/Cargo.tomldiffbeforeafterboth--- a/runtime/quartz/Cargo.toml
+++ b/runtime/quartz/Cargo.toml
@@ -16,7 +16,7 @@
targets = ['x86_64-unknown-linux-gnu']
[features]
-default = ['std']
+default = ['std', 'quartz-runtime']
runtime-benchmarks = [
'hex-literal',
'frame-benchmarking',
@@ -113,12 +113,17 @@
'xcm/std',
'xcm-builder/std',
'xcm-executor/std',
- 'unique-runtime-common/std',
+ 'up-common/std',
"orml-vesting/std",
]
limit-testing = ['pallet-unique/limit-testing', 'up-data-structs/limit-testing']
+quartz-runtime = []
+refungible = []
+scheduler = []
+rmrk = []
+
################################################################################
# Substrate Dependencies
@@ -403,7 +408,7 @@
[dependencies]
log = { version = "0.4.16", default-features = false }
-unique-runtime-common = { path = "../common", default-features = false }
+up-common = { path = "../../primitives/common", default-features = false }
scale-info = { version = "2.0.1", default-features = false, features = [
"derive",
] }
@@ -432,6 +437,8 @@
pallet-base-fee = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.24" }
fp-rpc = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.24" }
fp-self-contained = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.24" }
+evm-coder = { default-features = false, path = '../../crates/evm-coder' }
+up-sponsorship = { default-features = false, git = "https://github.com/uniquenetwork/pallet-sponsoring", branch = 'polkadot-v0.9.24' }
################################################################################
# Build Dependencies
runtime/quartz/src/lib.rsdiffbeforeafterboth--- a/runtime/quartz/src/lib.rs
+++ b/runtime/quartz/src/lib.rs
@@ -25,167 +25,21 @@
#[cfg(feature = "std")]
include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs"));
-use sp_api::impl_runtime_apis;
-use sp_core::{crypto::KeyTypeId, OpaqueMetadata, H256, U256, H160};
-use sp_runtime::DispatchError;
-use fp_self_contained::*;
-// #[cfg(any(feature = "std", test))]
-// pub use sp_runtime::BuildStorage;
-
-use sp_runtime::{
- Permill, Perbill, Percent, create_runtime_str, generic, impl_opaque_keys,
- traits::{AccountIdLookup, BlakeTwo256, Block as BlockT, AccountIdConversion, Zero, Member},
- transaction_validity::{TransactionSource, TransactionValidity},
- ApplyExtrinsicResult, RuntimeAppPublic,
-};
+use frame_support::parameter_types;
-use sp_std::prelude::*;
-
-#[cfg(feature = "std")]
-use sp_version::NativeVersion;
use sp_version::RuntimeVersion;
-pub use pallet_transaction_payment::{
- Multiplier, TargetedFeeAdjustment, FeeDetails, RuntimeDispatchInfo,
-};
-// A few exports that help ease life for downstream crates.
-pub use pallet_balances::Call as BalancesCall;
-pub use pallet_evm::{
- EnsureAddressTruncated, HashedAddressMapping, Runner, account::CrossAccountId as _,
- OnMethodCall, Account as EVMAccount, FeeCalculator, GasWeightMapping,
-};
-pub use frame_support::{
- construct_runtime, match_types,
- dispatch::DispatchResult,
- PalletId, parameter_types, StorageValue, ConsensusEngineId,
- traits::{
- tokens::currency::Currency as CurrencyT, OnUnbalanced as OnUnbalancedT, Everything,
- Currency, ExistenceRequirement, Get, IsInVec, KeyOwnerProofSystem, LockIdentifier,
- OnUnbalanced, Randomness, FindAuthor, ConstU32, Imbalance, PrivilegeCmp,
- },
- weights::{
- constants::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_PER_SECOND},
- DispatchClass, DispatchInfo, GetDispatchInfo, IdentityFee, Pays, PostDispatchInfo, Weight,
- WeightToFeePolynomial, WeightToFeeCoefficient, WeightToFeeCoefficients, ConstantMultiplier,
- WeightToFee,
- },
-};
-use pallet_unique_scheduler::DispatchCall;
-use up_data_structs::{
- CollectionId, TokenId, TokenData, Property, PropertyKeyPermission, CollectionLimits,
- CollectionStats, RpcCollection,
- mapping::{EvmTokenAddressMapping, CrossTokenAddressMapping},
- TokenChild, RmrkCollectionInfo, RmrkInstanceInfo, RmrkResourceInfo, RmrkPropertyInfo,
- RmrkBaseInfo, RmrkPartType, RmrkTheme, RmrkThemeName, RmrkCollectionId, RmrkNftId,
- RmrkNftChild, RmrkPropertyKey, RmrkResourceId, RmrkBaseId,
-};
+use sp_runtime::create_runtime_str;
-// use pallet_contracts::weights::WeightInfo;
-// #[cfg(any(feature = "std", test))]
-use frame_system::{
- self as frame_system, EnsureRoot, EnsureSigned,
- limits::{BlockWeights, BlockLength},
-};
-use sp_arithmetic::{
- traits::{BaseArithmetic, Unsigned},
-};
-use smallvec::smallvec;
-use codec::{Encode, Decode};
-use fp_rpc::TransactionStatus;
-use sp_runtime::{
- traits::{
- Applyable, BlockNumberProvider, Dispatchable, PostDispatchInfoOf, DispatchInfoOf,
- Saturating, CheckedConversion,
- },
- generic::Era,
- transaction_validity::TransactionValidityError,
- DispatchErrorWithPostInfo, SaturatedConversion,
-};
+use up_common::types::*;
-// pub use pallet_timestamp::Call as TimestampCall;
-pub use sp_consensus_aura::sr25519::AuthorityId as AuraId;
+#[path = "../../common/mod.rs"]
+mod runtime_common;
-// Polkadot imports
-use pallet_xcm::XcmPassthrough;
-use polkadot_parachain::primitives::Sibling;
-use xcm::v1::{BodyId, Junction::*, MultiLocation, NetworkId, Junctions::*};
-use xcm_builder::{
- AccountId32Aliases, AllowTopLevelPaidExecutionFrom, AllowUnpaidExecutionFrom, CurrencyAdapter,
- EnsureXcmOrigin, FixedWeightBounds, LocationInverter, NativeAsset, ParentAsSuperuser,
- RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia,
- SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit,
- ParentIsPreset,
-};
-use xcm_executor::{Config, XcmExecutor, Assets};
-use sp_std::{cmp::Ordering, marker::PhantomData};
-
-use xcm::latest::{
- // Xcm,
- AssetId::{Concrete},
- Fungibility::Fungible as XcmFungible,
- MultiAsset,
- Error as XcmError,
-};
-use xcm_executor::traits::{MatchesFungible, WeightTrader};
+pub use runtime_common::*;
-use unique_runtime_common::{
- impl_common_runtime_apis,
- types::*,
- constants::*,
- dispatch::{CollectionDispatchT, CollectionDispatch},
- sponsoring::UniqueSponsorshipHandler,
- eth_sponsoring::UniqueEthSponsorshipHandler,
- weights::CommonWeights,
-};
-
pub const RUNTIME_NAME: &str = "quartz";
pub const TOKEN_SYMBOL: &str = "QTZ";
-
-type CrossAccountId = pallet_evm::account::BasicCrossAccountId<Runtime>;
-
-impl RuntimeInstance for Runtime {
- type CrossAccountId = self::CrossAccountId;
-
- type TransactionConverter = self::TransactionConverter;
-
- fn get_transaction_converter() -> TransactionConverter {
- TransactionConverter
- }
-}
-
-/// The type for looking up accounts. We don't expect more than 4 billion of them, but you
-/// never know...
-pub type AccountIndex = u32;
-/// Balance of an account.
-pub type Balance = u128;
-
-/// Index of a transaction in the chain.
-pub type Index = u32;
-
-/// A hash of some data used by the chain.
-pub type Hash = sp_core::H256;
-
-/// Digest item type.
-pub type DigestItem = generic::DigestItem;
-
-/// Opaque types. These are used by the CLI to instantiate machinery that don't need to know
-/// the specifics of the runtime. They can then be made to be agnostic over specific formats
-/// of data like extrinsics, allowing for them to continue syncing the network through upgrades
-/// to even the core data structures.
-pub mod opaque {
- use sp_std::prelude::*;
- use sp_runtime::impl_opaque_keys;
- use super::Aura;
-
- pub use unique_runtime_common::types::*;
-
- impl_opaque_keys! {
- pub struct SessionKeys {
- pub aura: Aura,
- }
- }
-}
-
/// This runtime version.
pub const VERSION: RuntimeVersion = RuntimeVersion {
spec_name: create_runtime_str!(RUNTIME_NAME),
@@ -198,1207 +52,15 @@
state_version: 0,
};
-#[derive(codec::Encode, codec::Decode)]
-pub enum XCMPMessage<XAccountId, XBalance> {
- /// Transfer tokens to the given account from the Parachain account.
- TransferToken(XAccountId, XBalance),
-}
-
-/// The version information used to identify this runtime when compiled natively.
-#[cfg(feature = "std")]
-pub fn native_version() -> NativeVersion {
- NativeVersion {
- runtime_version: VERSION,
- can_author_with: Default::default(),
- }
-}
-
-type NegativeImbalance = <Balances as Currency<AccountId>>::NegativeImbalance;
-
-pub struct DealWithFees;
-impl OnUnbalanced<NegativeImbalance> for DealWithFees {
- fn on_unbalanceds<B>(mut fees_then_tips: impl Iterator<Item = NegativeImbalance>) {
- if let Some(fees) = fees_then_tips.next() {
- // for fees, 100% to treasury
- let mut split = fees.ration(100, 0);
- if let Some(tips) = fees_then_tips.next() {
- // for tips, if any, 100% to treasury
- tips.ration_merge_into(100, 0, &mut split);
- }
- Treasury::on_unbalanced(split.0);
- // Author::on_unbalanced(split.1);
- }
- }
-}
-
parameter_types! {
- pub const BlockHashCount: BlockNumber = 2400;
- pub RuntimeBlockLength: BlockLength =
- BlockLength::max_with_normal_ratio(5 * 1024 * 1024, NORMAL_DISPATCH_RATIO);
- pub const AvailableBlockRatio: Perbill = Perbill::from_percent(75);
- pub const MaximumBlockLength: u32 = 5 * 1024 * 1024;
- pub RuntimeBlockWeights: BlockWeights = BlockWeights::builder()
- .base_block(BlockExecutionWeight::get())
- .for_class(DispatchClass::all(), |weights| {
- weights.base_extrinsic = ExtrinsicBaseWeight::get();
- })
- .for_class(DispatchClass::Normal, |weights| {
- weights.max_total = Some(NORMAL_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT);
- })
- .for_class(DispatchClass::Operational, |weights| {
- weights.max_total = Some(MAXIMUM_BLOCK_WEIGHT);
- // Operational transactions have some extra reserved space, so that they
- // are included even if block reached `MAXIMUM_BLOCK_WEIGHT`.
- weights.reserved = Some(
- MAXIMUM_BLOCK_WEIGHT - NORMAL_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT
- );
- })
- .avg_block_initialization(AVERAGE_ON_INITIALIZE_RATIO)
- .build_or_panic();
pub const Version: RuntimeVersion = VERSION;
pub const SS58Prefix: u8 = 255;
-}
-
-parameter_types! {
pub const ChainId: u64 = 8881;
-}
-
-pub struct FixedFee;
-impl FeeCalculator for FixedFee {
- fn min_gas_price() -> (U256, u64) {
- (MIN_GAS_PRICE.into(), 0)
- }
-}
-
-// Assuming slowest ethereum opcode is SSTORE, with gas price of 20000 as our worst case
-// (contract, which only writes a lot of data),
-// approximating on top of our real store write weight
-parameter_types! {
- pub const WritesPerSecond: u64 = WEIGHT_PER_SECOND / <Runtime as frame_system::Config>::DbWeight::get().write;
- pub const GasPerSecond: u64 = WritesPerSecond::get() * 20000;
- pub const WeightPerGas: u64 = WEIGHT_PER_SECOND / GasPerSecond::get();
-}
-
-/// Limiting EVM execution to 50% of block for substrate users and management tasks
-/// EVM transaction consumes more weight than substrate's, so we can't rely on them being
-/// scheduled fairly
-const EVM_DISPATCH_RATIO: Perbill = Perbill::from_percent(50);
-parameter_types! {
- pub BlockGasLimit: U256 = U256::from(NORMAL_DISPATCH_RATIO * EVM_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT / WeightPerGas::get());
}
-pub enum FixedGasWeightMapping {}
-impl GasWeightMapping for FixedGasWeightMapping {
- fn gas_to_weight(gas: u64) -> Weight {
- gas.saturating_mul(WeightPerGas::get())
- }
- fn weight_to_gas(weight: Weight) -> u64 {
- weight / WeightPerGas::get()
- }
-}
-
-impl pallet_evm::account::Config for Runtime {
- type CrossAccountId = pallet_evm::account::BasicCrossAccountId<Self>;
- type EvmAddressMapping = HashedAddressMapping<Self::Hashing>;
- type EvmBackwardsAddressMapping = fp_evm_mapping::MapBackwardsAddressTruncated;
-}
-
-impl pallet_evm::Config for Runtime {
- type BlockGasLimit = BlockGasLimit;
- type FeeCalculator = FixedFee;
- type GasWeightMapping = FixedGasWeightMapping;
- type BlockHashMapping = pallet_ethereum::EthereumBlockHashMapping<Self>;
- type CallOrigin = EnsureAddressTruncated<Self>;
- type WithdrawOrigin = EnsureAddressTruncated<Self>;
- type AddressMapping = HashedAddressMapping<Self::Hashing>;
- type PrecompilesType = ();
- type PrecompilesValue = ();
- type Currency = Balances;
- type Event = Event;
- type OnMethodCall = (
- pallet_evm_migration::OnMethodCall<Self>,
- pallet_evm_contract_helpers::HelpersOnMethodCall<Self>,
- CollectionDispatchT<Self>,
- pallet_unique::eth::CollectionHelpersOnMethodCall<Self>,
- );
- type OnCreate = pallet_evm_contract_helpers::HelpersOnCreate<Self>;
- type ChainId = ChainId;
- type Runner = pallet_evm::runner::stack::Runner<Self>;
- type OnChargeTransaction = pallet_evm::EVMCurrencyAdapter<Balances, DealWithFees>;
- type TransactionValidityHack = pallet_evm_transaction_payment::TransactionValidityHack<Self>;
- type FindAuthor = EthereumFindAuthor<Aura>;
-}
-
-impl pallet_evm_migration::Config for Runtime {
- type WeightInfo = pallet_evm_migration::weights::SubstrateWeight<Self>;
-}
-
-pub struct EthereumFindAuthor<F>(core::marker::PhantomData<F>);
-impl<F: FindAuthor<u32>> FindAuthor<H160> for EthereumFindAuthor<F> {
- fn find_author<'a, I>(digests: I) -> Option<H160>
- where
- I: 'a + IntoIterator<Item = (ConsensusEngineId, &'a [u8])>,
- {
- if let Some(author_index) = F::find_author(digests) {
- let authority_id = Aura::authorities()[author_index as usize].clone();
- return Some(H160::from_slice(&authority_id.to_raw_vec()[4..24]));
- }
- None
- }
-}
-
-impl pallet_ethereum::Config for Runtime {
- type Event = Event;
- type StateRoot = pallet_ethereum::IntermediateStateRoot<Self>;
-}
-
-impl pallet_randomness_collective_flip::Config for Runtime {}
-
-impl frame_system::Config for Runtime {
- /// The data to be stored in an account.
- type AccountData = pallet_balances::AccountData<Balance>;
- /// The identifier used to distinguish between accounts.
- type AccountId = AccountId;
- /// The basic call filter to use in dispatchable.
- type BaseCallFilter = Everything;
- /// Maximum number of block number to block hash mappings to keep (oldest pruned first).
- type BlockHashCount = BlockHashCount;
- /// The maximum length of a block (in bytes).
- type BlockLength = RuntimeBlockLength;
- /// The index type for blocks.
- type BlockNumber = BlockNumber;
- /// The weight of the overhead invoked on the block import process, independent of the extrinsics included in that block.
- type BlockWeights = RuntimeBlockWeights;
- /// The aggregated dispatch type that is available for extrinsics.
- type Call = Call;
- /// The weight of database operations that the runtime can invoke.
- type DbWeight = RocksDbWeight;
- /// The ubiquitous event type.
- type Event = Event;
- /// The type for hashing blocks and tries.
- type Hash = Hash;
- /// The hashing algorithm used.
- type Hashing = BlakeTwo256;
- /// The header type.
- type Header = generic::Header<BlockNumber, BlakeTwo256>;
- /// The index type for storing how many extrinsics an account has signed.
- type Index = Index;
- /// The lookup mechanism to get account ID from whatever is passed in dispatchers.
- type Lookup = AccountIdLookup<AccountId, ()>;
- /// What to do if an account is fully reaped from the system.
- type OnKilledAccount = ();
- /// What to do if a new account is created.
- type OnNewAccount = ();
- type OnSetCode = cumulus_pallet_parachain_system::ParachainSetCode<Self>;
- /// The ubiquitous origin type.
- type Origin = Origin;
- /// This type is being generated by `construct_runtime!`.
- type PalletInfo = PalletInfo;
- /// This is used as an identifier of the chain. 42 is the generic substrate prefix.
- type SS58Prefix = SS58Prefix;
- /// Weight information for the extrinsics of this pallet.
- type SystemWeightInfo = frame_system::weights::SubstrateWeight<Self>;
- /// Version of the runtime.
- type Version = Version;
- type MaxConsumers = ConstU32<16>;
-}
-
-parameter_types! {
- pub const MinimumPeriod: u64 = SLOT_DURATION / 2;
-}
-
-impl pallet_timestamp::Config for Runtime {
- /// A timestamp: milliseconds since the unix epoch.
- type Moment = u64;
- type OnTimestampSet = ();
- type MinimumPeriod = MinimumPeriod;
- type WeightInfo = ();
-}
-
-parameter_types! {
- // pub const ExistentialDeposit: u128 = 500;
- pub const ExistentialDeposit: u128 = 0;
- pub const MaxLocks: u32 = 50;
- pub const MaxReserves: u32 = 50;
-}
-
-impl pallet_balances::Config for Runtime {
- type MaxLocks = MaxLocks;
- type MaxReserves = MaxReserves;
- type ReserveIdentifier = [u8; 16];
- /// The type for recording an account's balance.
- type Balance = Balance;
- /// The ubiquitous event type.
- type Event = Event;
- type DustRemoval = Treasury;
- type ExistentialDeposit = ExistentialDeposit;
- type AccountStore = System;
- type WeightInfo = pallet_balances::weights::SubstrateWeight<Self>;
-}
-
-pub const fn deposit(items: u32, bytes: u32) -> Balance {
- items as Balance * 15 * CENTIUNIQUE + (bytes as Balance) * 6 * CENTIUNIQUE
-}
-
-/*
-parameter_types! {
- pub TombstoneDeposit: Balance = deposit(
- 1,
- sp_std::mem::size_of::<pallet_contracts::Pallet<Runtime>> as u32,
- );
- pub DepositPerContract: Balance = TombstoneDeposit::get();
- pub const DepositPerStorageByte: Balance = deposit(0, 1);
- pub const DepositPerStorageItem: Balance = deposit(1, 0);
- pub RentFraction: Perbill = Perbill::from_rational(1u32, 30 * DAYS);
- pub const SurchargeReward: Balance = 150 * MILLIUNIQUE;
- pub const SignedClaimHandicap: u32 = 2;
- pub const MaxDepth: u32 = 32;
- pub const MaxValueSize: u32 = 16 * 1024;
- pub const MaxCodeSize: u32 = 1024 * 1024 * 25; // 25 Mb
- // The lazy deletion runs inside on_initialize.
- pub DeletionWeightLimit: Weight = AVERAGE_ON_INITIALIZE_RATIO *
- RuntimeBlockWeights::get().max_block;
- // The weight needed for decoding the queue should be less or equal than a fifth
- // of the overall weight dedicated to the lazy deletion.
- pub DeletionQueueDepth: u32 = ((DeletionWeightLimit::get() / (
- <Runtime as pallet_contracts::Config>::WeightInfo::on_initialize_per_queue_item(1) -
- <Runtime as pallet_contracts::Config>::WeightInfo::on_initialize_per_queue_item(0)
- )) / 5) as u32;
- pub Schedule: pallet_contracts::Schedule<Runtime> = Default::default();
-}
-
-impl pallet_contracts::Config for Runtime {
- type Time = Timestamp;
- type Randomness = RandomnessCollectiveFlip;
- type Currency = Balances;
- type Event = Event;
- type RentPayment = ();
- type SignedClaimHandicap = SignedClaimHandicap;
- type TombstoneDeposit = TombstoneDeposit;
- type DepositPerContract = DepositPerContract;
- type DepositPerStorageByte = DepositPerStorageByte;
- type DepositPerStorageItem = DepositPerStorageItem;
- type RentFraction = RentFraction;
- type SurchargeReward = SurchargeReward;
- type WeightPrice = pallet_transaction_payment::Pallet<Self>;
- type WeightInfo = pallet_contracts::weights::SubstrateWeight<Self>;
- type ChainExtension = NFTExtension;
- type DeletionQueueDepth = DeletionQueueDepth;
- type DeletionWeightLimit = DeletionWeightLimit;
- type Schedule = Schedule;
- type CallStack = [pallet_contracts::Frame<Self>; 31];
-}
-*/
+construct_runtime!(quartz);
-parameter_types! {
- /// This value increases the priority of `Operational` transactions by adding
- /// a "virtual tip" that's equal to the `OperationalFeeMultiplier * final_fee`.
- pub const OperationalFeeMultiplier: u8 = 5;
-}
-
-/// Linear implementor of `WeightToFeePolynomial`
-pub struct LinearFee<T>(sp_std::marker::PhantomData<T>);
-
-impl<T> WeightToFeePolynomial for LinearFee<T>
-where
- T: BaseArithmetic + From<u32> + Copy + Unsigned,
-{
- type Balance = T;
-
- fn polynomial() -> WeightToFeeCoefficients<Self::Balance> {
- smallvec!(WeightToFeeCoefficient {
- coeff_integer: WEIGHT_TO_FEE_COEFF.into(),
- coeff_frac: Perbill::zero(),
- negative: false,
- degree: 1,
- })
- }
-}
-
-impl pallet_transaction_payment::Config for Runtime {
- type OnChargeTransaction = pallet_transaction_payment::CurrencyAdapter<Balances, DealWithFees>;
- type LengthToFee = ConstantMultiplier<Balance, TransactionByteFee>;
- type OperationalFeeMultiplier = OperationalFeeMultiplier;
- type WeightToFee = LinearFee<Balance>;
- type FeeMultiplierUpdate = ();
-}
-
-parameter_types! {
- pub const ProposalBond: Permill = Permill::from_percent(5);
- pub const ProposalBondMinimum: Balance = 1 * UNIQUE;
- pub const ProposalBondMaximum: Balance = 1000 * UNIQUE;
- pub const SpendPeriod: BlockNumber = 5 * MINUTES;
- pub const Burn: Permill = Permill::from_percent(0);
- pub const TipCountdown: BlockNumber = 1 * DAYS;
- pub const TipFindersFee: Percent = Percent::from_percent(20);
- pub const TipReportDepositBase: Balance = 1 * UNIQUE;
- pub const DataDepositPerByte: Balance = 1 * CENTIUNIQUE;
- pub const BountyDepositBase: Balance = 1 * UNIQUE;
- pub const BountyDepositPayoutDelay: BlockNumber = 1 * DAYS;
- pub const TreasuryModuleId: PalletId = PalletId(*b"py/trsry");
- pub const BountyUpdatePeriod: BlockNumber = 14 * DAYS;
- pub const MaximumReasonLength: u32 = 16384;
- pub const BountyCuratorDeposit: Permill = Permill::from_percent(50);
- pub const BountyValueMinimum: Balance = 5 * UNIQUE;
- pub const MaxApprovals: u32 = 100;
-}
-
-impl pallet_treasury::Config for Runtime {
- type PalletId = TreasuryModuleId;
- type Currency = Balances;
- type ApproveOrigin = EnsureRoot<AccountId>;
- type RejectOrigin = EnsureRoot<AccountId>;
- type Event = Event;
- type OnSlash = ();
- type ProposalBond = ProposalBond;
- type ProposalBondMinimum = ProposalBondMinimum;
- type ProposalBondMaximum = ProposalBondMaximum;
- type SpendPeriod = SpendPeriod;
- type Burn = Burn;
- type BurnDestination = ();
- type SpendFunds = ();
- type WeightInfo = pallet_treasury::weights::SubstrateWeight<Self>;
- type MaxApprovals = MaxApprovals;
-}
-
-impl pallet_sudo::Config for Runtime {
- type Event = Event;
- type Call = Call;
-}
-
-pub struct RelayChainBlockNumberProvider<T>(sp_std::marker::PhantomData<T>);
-
-impl<T: cumulus_pallet_parachain_system::Config> BlockNumberProvider
- for RelayChainBlockNumberProvider<T>
-{
- type BlockNumber = BlockNumber;
-
- fn current_block_number() -> Self::BlockNumber {
- cumulus_pallet_parachain_system::Pallet::<T>::validation_data()
- .map(|d| d.relay_parent_number)
- .unwrap_or_default()
- }
-}
-
-parameter_types! {
- pub const MinVestedTransfer: Balance = 10 * UNIQUE;
- pub const MaxVestingSchedules: u32 = 28;
-}
-
-impl orml_vesting::Config for Runtime {
- type Event = Event;
- type Currency = pallet_balances::Pallet<Runtime>;
- type MinVestedTransfer = MinVestedTransfer;
- type VestedTransferOrigin = EnsureSigned<AccountId>;
- type WeightInfo = ();
- type MaxVestingSchedules = MaxVestingSchedules;
- type BlockNumberProvider = RelayChainBlockNumberProvider<Runtime>;
-}
-
-parameter_types! {
- pub const ReservedDmpWeight: Weight = MAXIMUM_BLOCK_WEIGHT / 4;
- pub const ReservedXcmpWeight: Weight = MAXIMUM_BLOCK_WEIGHT / 4;
-}
-
-impl cumulus_pallet_parachain_system::Config for Runtime {
- type Event = Event;
- type SelfParaId = parachain_info::Pallet<Self>;
- type OnSystemEvent = ();
- // type DownwardMessageHandlers = cumulus_primitives_utility::UnqueuedDmpAsParent<
- // MaxDownwardMessageWeight,
- // XcmExecutor<XcmConfig>,
- // Call,
- // >;
- type OutboundXcmpMessageSource = XcmpQueue;
- type DmpMessageHandler = DmpQueue;
- type ReservedDmpWeight = ReservedDmpWeight;
- type ReservedXcmpWeight = ReservedXcmpWeight;
- type XcmpMessageHandler = XcmpQueue;
-}
-
-impl parachain_info::Config for Runtime {}
-
-impl cumulus_pallet_aura_ext::Config for Runtime {}
-
-parameter_types! {
- pub const RelayLocation: MultiLocation = MultiLocation::parent();
- pub const RelayNetwork: NetworkId = NetworkId::Polkadot;
- pub RelayOrigin: Origin = cumulus_pallet_xcm::Origin::Relay.into();
- pub Ancestry: MultiLocation = Parachain(ParachainInfo::parachain_id().into()).into();
-}
-
-/// Type for specifying how a `MultiLocation` can be converted into an `AccountId`. This is used
-/// when determining ownership of accounts for asset transacting and when attempting to use XCM
-/// `Transact` in order to determine the dispatch Origin.
-pub type LocationToAccountId = (
- // The parent (Relay-chain) origin converts to the default `AccountId`.
- ParentIsPreset<AccountId>,
- // Sibling parachain origins convert to AccountId via the `ParaId::into`.
- SiblingParachainConvertsVia<Sibling, AccountId>,
- // Straight up local `AccountId32` origins just alias directly to `AccountId`.
- AccountId32Aliases<RelayNetwork, AccountId>,
-);
-
-pub struct OnlySelfCurrency;
-impl<B: TryFrom<u128>> MatchesFungible<B> for OnlySelfCurrency {
- fn matches_fungible(a: &MultiAsset) -> Option<B> {
- match (&a.id, &a.fun) {
- (Concrete(_), XcmFungible(ref amount)) => CheckedConversion::checked_from(*amount),
- _ => None,
- }
- }
-}
-
-/// Means for transacting assets on this chain.
-pub type LocalAssetTransactor = CurrencyAdapter<
- // Use this currency:
- Balances,
- // Use this currency when it is a fungible asset matching the given location or name:
- OnlySelfCurrency,
- // Do a simple punn to convert an AccountId32 MultiLocation into a native chain account ID:
- LocationToAccountId,
- // Our chain's account ID type (we can't get away without mentioning it explicitly):
- AccountId,
- // We don't track any teleports.
- (),
->;
-
-/// This is the type we use to convert an (incoming) XCM origin into a local `Origin` instance,
-/// ready for dispatching a transaction with Xcm's `Transact`. There is an `OriginKind` which can
-/// biases the kind of local `Origin` it will become.
-pub type XcmOriginToTransactDispatchOrigin = (
- // Sovereign account converter; this attempts to derive an `AccountId` from the origin location
- // using `LocationToAccountId` and then turn that into the usual `Signed` origin. Useful for
- // foreign chains who want to have a local sovereign account on this chain which they control.
- SovereignSignedViaLocation<LocationToAccountId, Origin>,
- // Native converter for Relay-chain (Parent) location; will converts to a `Relay` origin when
- // recognised.
- RelayChainAsNative<RelayOrigin, Origin>,
- // Native converter for sibling Parachains; will convert to a `SiblingPara` origin when
- // recognised.
- SiblingParachainAsNative<cumulus_pallet_xcm::Origin, Origin>,
- // Superuser converter for the Relay-chain (Parent) location. This will allow it to issue a
- // transaction from the Root origin.
- ParentAsSuperuser<Origin>,
- // Native signed account converter; this just converts an `AccountId32` origin into a normal
- // `Origin::Signed` origin of the same 32-byte value.
- SignedAccountId32AsNative<RelayNetwork, Origin>,
- // Xcm origins can be represented natively under the Xcm pallet's Xcm origin.
- XcmPassthrough<Origin>,
-);
-
-parameter_types! {
- // One XCM operation is 1_000_000 weight - almost certainly a conservative estimate.
- pub UnitWeightCost: Weight = 1_000_000;
- // 1200 UNIQUEs buy 1 second of weight.
- pub const WeightPrice: (MultiLocation, u128) = (MultiLocation::parent(), 1_200 * UNIQUE);
- pub const MaxInstructions: u32 = 100;
- pub const MaxAuthorities: u32 = 100_000;
-}
-
-match_types! {
- pub type ParentOrParentsUnitPlurality: impl Contains<MultiLocation> = {
- MultiLocation { parents: 1, interior: Here } |
- MultiLocation { parents: 1, interior: X1(Plurality { id: BodyId::Unit, .. }) }
- };
-}
-
-pub type Barrier = (
- TakeWeightCredit,
- AllowTopLevelPaidExecutionFrom<Everything>,
- // ^^^ Parent & its unit plurality gets free execution
-);
-
-pub struct UsingOnlySelfCurrencyComponents<
- WeightToFee: WeightToFeePolynomial<Balance = Currency::Balance>,
- AssetId: Get<MultiLocation>,
- AccountId,
- Currency: CurrencyT<AccountId>,
- OnUnbalanced: OnUnbalancedT<Currency::NegativeImbalance>,
->(
- Weight,
- Currency::Balance,
- PhantomData<(WeightToFee, AssetId, AccountId, Currency, OnUnbalanced)>,
-);
-impl<
- WeightToFee: WeightToFeePolynomial<Balance = Currency::Balance>,
- AssetId: Get<MultiLocation>,
- AccountId,
- Currency: CurrencyT<AccountId>,
- OnUnbalanced: OnUnbalancedT<Currency::NegativeImbalance>,
- > WeightTrader
- for UsingOnlySelfCurrencyComponents<WeightToFee, AssetId, AccountId, Currency, OnUnbalanced>
-{
- fn new() -> Self {
- Self(0, Zero::zero(), PhantomData)
- }
-
- fn buy_weight(&mut self, weight: Weight, payment: Assets) -> Result<Assets, XcmError> {
- let amount = WeightToFee::weight_to_fee(&weight);
- let u128_amount: u128 = amount.try_into().map_err(|_| XcmError::Overflow)?;
-
- // location to this parachain through relay chain
- let option1: xcm::v1::AssetId = Concrete(MultiLocation {
- parents: 1,
- interior: X1(Parachain(ParachainInfo::parachain_id().into())),
- });
- // direct location
- let option2: xcm::v1::AssetId = Concrete(MultiLocation {
- parents: 0,
- interior: Here,
- });
-
- let required = if payment.fungible.contains_key(&option1) {
- (option1, u128_amount).into()
- } else if payment.fungible.contains_key(&option2) {
- (option2, u128_amount).into()
- } else {
- (Concrete(MultiLocation::default()), u128_amount).into()
- };
-
- let unused = payment
- .checked_sub(required)
- .map_err(|_| XcmError::TooExpensive)?;
- self.0 = self.0.saturating_add(weight);
- self.1 = self.1.saturating_add(amount);
- Ok(unused)
- }
-
- fn refund_weight(&mut self, weight: Weight) -> Option<MultiAsset> {
- let weight = weight.min(self.0);
- let amount = WeightToFee::weight_to_fee(&weight);
- self.0 -= weight;
- self.1 = self.1.saturating_sub(amount);
- let amount: u128 = amount.saturated_into();
- if amount > 0 {
- Some((AssetId::get(), amount).into())
- } else {
- None
- }
- }
-}
-impl<
- WeightToFee: WeightToFeePolynomial<Balance = Currency::Balance>,
- AssetId: Get<MultiLocation>,
- AccountId,
- Currency: CurrencyT<AccountId>,
- OnUnbalanced: OnUnbalancedT<Currency::NegativeImbalance>,
- > Drop
- for UsingOnlySelfCurrencyComponents<WeightToFee, AssetId, AccountId, Currency, OnUnbalanced>
-{
- fn drop(&mut self) {
- OnUnbalanced::on_unbalanced(Currency::issue(self.1));
- }
-}
-
-pub struct XcmConfig;
-impl Config for XcmConfig {
- type Call = Call;
- type XcmSender = XcmRouter;
- // How to withdraw and deposit an asset.
- type AssetTransactor = LocalAssetTransactor;
- type OriginConverter = XcmOriginToTransactDispatchOrigin;
- type IsReserve = NativeAsset;
- type IsTeleporter = (); // Teleportation is disabled
- type LocationInverter = LocationInverter<Ancestry>;
- type Barrier = Barrier;
- type Weigher = FixedWeightBounds<UnitWeightCost, Call, MaxInstructions>;
- type Trader =
- UsingOnlySelfCurrencyComponents<LinearFee<Balance>, RelayLocation, AccountId, Balances, ()>;
- type ResponseHandler = (); // Don't handle responses for now.
- type SubscriptionService = PolkadotXcm;
-
- type AssetTrap = PolkadotXcm;
- type AssetClaims = PolkadotXcm;
-}
-
-// parameter_types! {
-// pub const MaxDownwardMessageWeight: Weight = MAXIMUM_BLOCK_WEIGHT / 10;
-// }
-
-/// No local origins on this chain are allowed to dispatch XCM sends/executions.
-pub type LocalOriginToLocation = (SignedToAccountId32<Origin, AccountId, RelayNetwork>,);
-
-/// The means for routing XCM messages which are not for local execution into the right message
-/// queues.
-pub type XcmRouter = (
- // Two routers - use UMP to communicate with the relay chain:
- cumulus_primitives_utility::ParentAsUmp<ParachainSystem, ()>,
- // ..and XCMP to communicate with the sibling chains.
- XcmpQueue,
-);
-
-impl pallet_evm_coder_substrate::Config for Runtime {}
-
-impl pallet_xcm::Config for Runtime {
- type Event = Event;
- type SendXcmOrigin = EnsureXcmOrigin<Origin, LocalOriginToLocation>;
- type XcmRouter = XcmRouter;
- type ExecuteXcmOrigin = EnsureXcmOrigin<Origin, LocalOriginToLocation>;
- type XcmExecuteFilter = Everything;
- type XcmExecutor = XcmExecutor<XcmConfig>;
- type XcmTeleportFilter = Everything;
- type XcmReserveTransferFilter = Everything;
- type Weigher = FixedWeightBounds<UnitWeightCost, Call, MaxInstructions>;
- type LocationInverter = LocationInverter<Ancestry>;
- type Origin = Origin;
- type Call = Call;
- const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 100;
- type AdvertisedXcmVersion = pallet_xcm::CurrentXcmVersion;
-}
-
-impl cumulus_pallet_xcm::Config for Runtime {
- type Event = Event;
- type XcmExecutor = XcmExecutor<XcmConfig>;
-}
-
-impl cumulus_pallet_xcmp_queue::Config for Runtime {
- type WeightInfo = ();
- type Event = Event;
- type XcmExecutor = XcmExecutor<XcmConfig>;
- type ChannelInfo = ParachainSystem;
- type VersionWrapper = ();
- type ExecuteOverweightOrigin = frame_system::EnsureRoot<AccountId>;
- type ControllerOrigin = EnsureRoot<AccountId>;
- type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin;
-}
-
-impl cumulus_pallet_dmp_queue::Config for Runtime {
- type Event = Event;
- type XcmExecutor = XcmExecutor<XcmConfig>;
- type ExecuteOverweightOrigin = frame_system::EnsureRoot<AccountId>;
-}
-
-impl pallet_aura::Config for Runtime {
- type AuthorityId = AuraId;
- type DisabledValidators = ();
- type MaxAuthorities = MaxAuthorities;
-}
-
-parameter_types! {
- pub TreasuryAccountId: AccountId = TreasuryModuleId::get().into_account_truncating();
- pub const CollectionCreationPrice: Balance = 2 * UNIQUE;
-}
-
-impl pallet_common::Config for Runtime {
- type WeightInfo = pallet_common::weights::SubstrateWeight<Self>;
- type Event = Event;
- type Currency = Balances;
- type CollectionCreationPrice = CollectionCreationPrice;
- type TreasuryAccountId = TreasuryAccountId;
- type CollectionDispatch = CollectionDispatchT<Self>;
-
- type EvmTokenAddressMapping = EvmTokenAddressMapping;
- type CrossTokenAddressMapping = CrossTokenAddressMapping<Self::AccountId>;
- type ContractAddress = EvmCollectionHelpersAddress;
-}
-
-impl pallet_structure::Config for Runtime {
- type Event = Event;
- type Call = Call;
- type WeightInfo = pallet_structure::weights::SubstrateWeight<Self>;
-}
-
-impl pallet_fungible::Config for Runtime {
- type WeightInfo = pallet_fungible::weights::SubstrateWeight<Self>;
-}
-impl pallet_refungible::Config for Runtime {
- type WeightInfo = pallet_refungible::weights::SubstrateWeight<Self>;
-}
-impl pallet_nonfungible::Config for Runtime {
- type WeightInfo = pallet_nonfungible::weights::SubstrateWeight<Self>;
-}
-
-impl pallet_proxy_rmrk_core::Config for Runtime {
- type WeightInfo = pallet_proxy_rmrk_core::weights::SubstrateWeight<Self>;
- type Event = Event;
-}
-
-impl pallet_proxy_rmrk_equip::Config for Runtime {
- type WeightInfo = pallet_proxy_rmrk_equip::weights::SubstrateWeight<Self>;
- type Event = Event;
-}
-
-impl pallet_unique::Config for Runtime {
- type Event = Event;
- type WeightInfo = pallet_unique::weights::SubstrateWeight<Self>;
- type CommonWeightInfo = CommonWeights<Self>;
- type RefungibleExtensionsWeightInfo = CommonWeights<Self>;
-}
-
-parameter_types! {
- pub const InflationBlockInterval: BlockNumber = 100; // every time per how many blocks inflation is applied
-}
-
-/// Used for the pallet inflation
-impl pallet_inflation::Config for Runtime {
- type Currency = Balances;
- type TreasuryAccountId = TreasuryAccountId;
- type InflationBlockInterval = InflationBlockInterval;
- type BlockNumberProvider = RelayChainBlockNumberProvider<Runtime>;
-}
-
-parameter_types! {
- pub MaximumSchedulerWeight: Weight = Perbill::from_percent(50) *
- RuntimeBlockWeights::get().max_block;
- pub const MaxScheduledPerBlock: u32 = 50;
-}
-
-type ChargeTransactionPayment = pallet_charge_transaction::ChargeTransactionPayment<Runtime>;
-use frame_support::traits::NamedReservableCurrency;
-
-fn get_signed_extras(from: <Runtime as frame_system::Config>::AccountId) -> SignedExtraScheduler {
- (
- frame_system::CheckSpecVersion::<Runtime>::new(),
- frame_system::CheckGenesis::<Runtime>::new(),
- frame_system::CheckEra::<Runtime>::from(Era::Immortal),
- frame_system::CheckNonce::<Runtime>::from(frame_system::Pallet::<Runtime>::account_nonce(
- from,
- )),
- frame_system::CheckWeight::<Runtime>::new(),
- // sponsoring transaction logic
- // pallet_charge_transaction::ChargeTransactionPayment::<Runtime>::new(0),
- )
-}
-
-pub struct SchedulerPaymentExecutor;
-impl<T: frame_system::Config + pallet_unique_scheduler::Config, SelfContainedSignedInfo>
- DispatchCall<T, SelfContainedSignedInfo> for SchedulerPaymentExecutor
-where
- <T as frame_system::Config>::Call: Member
- + Dispatchable<Origin = Origin, Info = DispatchInfo>
- + SelfContainedCall<SignedInfo = SelfContainedSignedInfo>
- + GetDispatchInfo
- + From<frame_system::Call<Runtime>>,
- SelfContainedSignedInfo: Send + Sync + 'static,
- Call: From<<T as frame_system::Config>::Call>
- + From<<T as pallet_unique_scheduler::Config>::Call>
- + SelfContainedCall<SignedInfo = SelfContainedSignedInfo>,
- sp_runtime::AccountId32: From<<T as frame_system::Config>::AccountId>,
-{
- fn dispatch_call(
- signer: <T as frame_system::Config>::AccountId,
- call: <T as pallet_unique_scheduler::Config>::Call,
- ) -> Result<
- Result<PostDispatchInfo, DispatchErrorWithPostInfo<PostDispatchInfo>>,
- TransactionValidityError,
- > {
- let dispatch_info = call.get_dispatch_info();
- let extrinsic = fp_self_contained::CheckedExtrinsic::<
- AccountId,
- Call,
- SignedExtraScheduler,
- SelfContainedSignedInfo,
- > {
- signed:
- CheckedSignature::<AccountId, SignedExtraScheduler, SelfContainedSignedInfo>::Signed(
- signer.clone().into(),
- get_signed_extras(signer.into()),
- ),
- function: call.into(),
- };
-
- extrinsic.apply::<Runtime>(&dispatch_info, 0)
- }
-
- fn reserve_balance(
- id: [u8; 16],
- sponsor: <T as frame_system::Config>::AccountId,
- call: <T as pallet_unique_scheduler::Config>::Call,
- count: u32,
- ) -> Result<(), DispatchError> {
- let dispatch_info = call.get_dispatch_info();
- let weight: Balance = ChargeTransactionPayment::traditional_fee(0, &dispatch_info, 0)
- .saturating_mul(count.into());
-
- <Balances as NamedReservableCurrency<AccountId>>::reserve_named(
- &id,
- &(sponsor.into()),
- weight.into(),
- )
- }
-
- fn pay_for_call(
- id: [u8; 16],
- sponsor: <T as frame_system::Config>::AccountId,
- call: <T as pallet_unique_scheduler::Config>::Call,
- ) -> Result<u128, DispatchError> {
- let dispatch_info = call.get_dispatch_info();
- let weight: Balance = ChargeTransactionPayment::traditional_fee(0, &dispatch_info, 0);
- Ok(
- <Balances as NamedReservableCurrency<AccountId>>::unreserve_named(
- &id,
- &(sponsor.into()),
- weight.into(),
- ),
- )
- }
-
- fn cancel_reserve(
- id: [u8; 16],
- sponsor: <T as frame_system::Config>::AccountId,
- ) -> Result<u128, DispatchError> {
- Ok(
- <Balances as NamedReservableCurrency<AccountId>>::unreserve_named(
- &id,
- &(sponsor.into()),
- u128::MAX,
- ),
- )
- }
-}
-
-parameter_types! {
- pub const NoPreimagePostponement: Option<u32> = Some(10);
- pub const Preimage: Option<u32> = Some(10);
-}
-
-/// Used the compare the privilege of an origin inside the scheduler.
-pub struct OriginPrivilegeCmp;
-
-impl PrivilegeCmp<OriginCaller> for OriginPrivilegeCmp {
- fn cmp_privilege(_left: &OriginCaller, _right: &OriginCaller) -> Option<Ordering> {
- Some(Ordering::Equal)
- }
-}
-
-impl pallet_unique_scheduler::Config for Runtime {
- type Event = Event;
- type Origin = Origin;
- type Currency = Balances;
- type PalletsOrigin = OriginCaller;
- type Call = Call;
- type MaximumWeight = MaximumSchedulerWeight;
- type ScheduleOrigin = EnsureSigned<AccountId>;
- type MaxScheduledPerBlock = MaxScheduledPerBlock;
- type WeightInfo = ();
- type CallExecutor = SchedulerPaymentExecutor;
- type OriginPrivilegeCmp = OriginPrivilegeCmp;
- type PreimageProvider = ();
- type NoPreimagePostponement = NoPreimagePostponement;
-}
-
-type EvmSponsorshipHandler = (
- UniqueEthSponsorshipHandler<Runtime>,
- pallet_evm_contract_helpers::HelpersContractSponsoring<Runtime>,
-);
-type SponsorshipHandler = (
- UniqueSponsorshipHandler<Runtime>,
- //pallet_contract_helpers::ContractSponsorshipHandler<Runtime>,
- pallet_evm_transaction_payment::BridgeSponsorshipHandler<Runtime>,
-);
-
-impl pallet_evm_transaction_payment::Config for Runtime {
- type EvmSponsorshipHandler = EvmSponsorshipHandler;
- type Currency = Balances;
-}
-
-impl pallet_charge_transaction::Config for Runtime {
- type SponsorshipHandler = SponsorshipHandler;
-}
-
-// impl pallet_contract_helpers::Config for Runtime {
-// type DefaultSponsoringRateLimit = DefaultSponsoringRateLimit;
-// }
-
-parameter_types! {
- // 0x842899ECF380553E8a4de75bF534cdf6fBF64049
- pub const HelpersContractAddress: H160 = H160([
- 0x84, 0x28, 0x99, 0xec, 0xf3, 0x80, 0x55, 0x3e, 0x8a, 0x4d, 0xe7, 0x5b, 0xf5, 0x34, 0xcd, 0xf6, 0xfb, 0xf6, 0x40, 0x49,
- ]);
-
- // 0x6c4e9fe1ae37a41e93cee429e8e1881abdcbb54f
- pub const EvmCollectionHelpersAddress: H160 = H160([
- 0x6c, 0x4e, 0x9f, 0xe1, 0xae, 0x37, 0xa4, 0x1e, 0x93, 0xce, 0xe4, 0x29, 0xe8, 0xe1, 0x88, 0x1a, 0xbd, 0xcb, 0xb5, 0x4f,
- ]);
-}
-
-impl pallet_evm_contract_helpers::Config for Runtime {
- type ContractAddress = HelpersContractAddress;
- type DefaultSponsoringRateLimit = DefaultSponsoringRateLimit;
-}
-
-construct_runtime!(
- pub enum Runtime where
- Block = Block,
- NodeBlock = opaque::Block,
- UncheckedExtrinsic = UncheckedExtrinsic
- {
- ParachainSystem: cumulus_pallet_parachain_system::{Pallet, Call, Config, Storage, Inherent, Event<T>, ValidateUnsigned} = 20,
- ParachainInfo: parachain_info::{Pallet, Storage, Config} = 21,
-
- Aura: pallet_aura::{Pallet, Config<T>} = 22,
- AuraExt: cumulus_pallet_aura_ext::{Pallet, Config} = 23,
-
- Balances: pallet_balances::{Pallet, Call, Storage, Config<T>, Event<T>} = 30,
- RandomnessCollectiveFlip: pallet_randomness_collective_flip::{Pallet, Storage} = 31,
- Timestamp: pallet_timestamp::{Pallet, Call, Storage, Inherent} = 32,
- TransactionPayment: pallet_transaction_payment::{Pallet, Storage} = 33,
- Treasury: pallet_treasury::{Pallet, Call, Storage, Config, Event<T>} = 34,
- Sudo: pallet_sudo::{Pallet, Call, Storage, Config<T>, Event<T>} = 35,
- System: frame_system::{Pallet, Call, Storage, Config, Event<T>} = 36,
- Vesting: orml_vesting::{Pallet, Storage, Call, Event<T>, Config<T>} = 37,
- // Vesting: pallet_vesting::{Pallet, Call, Config<T>, Storage, Event<T>} = 37,
- // Contracts: pallet_contracts::{Pallet, Call, Storage, Event<T>} = 38,
-
- // XCM helpers.
- XcmpQueue: cumulus_pallet_xcmp_queue::{Pallet, Call, Storage, Event<T>} = 50,
- PolkadotXcm: pallet_xcm::{Pallet, Call, Event<T>, Origin} = 51,
- CumulusXcm: cumulus_pallet_xcm::{Pallet, Call, Event<T>, Origin} = 52,
- DmpQueue: cumulus_pallet_dmp_queue::{Pallet, Call, Storage, Event<T>} = 53,
-
- // Unique Pallets
- Inflation: pallet_inflation::{Pallet, Call, Storage} = 60,
- Unique: pallet_unique::{Pallet, Call, Storage, Event<T>} = 61,
- Scheduler: pallet_unique_scheduler::{Pallet, Call, Storage, Event<T>} = 62,
- // free = 63
- Charging: pallet_charge_transaction::{Pallet, Call, Storage } = 64,
- // ContractHelpers: pallet_contract_helpers::{Pallet, Call, Storage} = 65,
- Common: pallet_common::{Pallet, Storage, Event<T>} = 66,
- Fungible: pallet_fungible::{Pallet, Storage} = 67,
- Refungible: pallet_refungible::{Pallet, Storage} = 68,
- Nonfungible: pallet_nonfungible::{Pallet, Storage} = 69,
- Structure: pallet_structure::{Pallet, Call, Storage, Event<T>} = 70,
- RmrkCore: pallet_proxy_rmrk_core::{Pallet, Call, Storage, Event<T>} = 71,
- RmrkEquip: pallet_proxy_rmrk_equip::{Pallet, Call, Storage, Event<T>} = 72,
-
- // Frontier
- EVM: pallet_evm::{Pallet, Config, Call, Storage, Event<T>} = 100,
- Ethereum: pallet_ethereum::{Pallet, Config, Call, Storage, Event, Origin} = 101,
-
- EvmCoderSubstrate: pallet_evm_coder_substrate::{Pallet, Storage} = 150,
- EvmContractHelpers: pallet_evm_contract_helpers::{Pallet, Storage} = 151,
- EvmTransactionPayment: pallet_evm_transaction_payment::{Pallet} = 152,
- EvmMigration: pallet_evm_migration::{Pallet, Call, Storage} = 153,
- }
-);
-
-pub struct TransactionConverter;
-
-impl fp_rpc::ConvertTransaction<UncheckedExtrinsic> for TransactionConverter {
- fn convert_transaction(&self, transaction: pallet_ethereum::Transaction) -> UncheckedExtrinsic {
- UncheckedExtrinsic::new_unsigned(
- pallet_ethereum::Call::<Runtime>::transact { transaction }.into(),
- )
- }
-}
-
-impl fp_rpc::ConvertTransaction<opaque::UncheckedExtrinsic> for TransactionConverter {
- fn convert_transaction(
- &self,
- transaction: pallet_ethereum::Transaction,
- ) -> opaque::UncheckedExtrinsic {
- let extrinsic = UncheckedExtrinsic::new_unsigned(
- pallet_ethereum::Call::<Runtime>::transact { transaction }.into(),
- );
- let encoded = extrinsic.encode();
- opaque::UncheckedExtrinsic::decode(&mut &encoded[..])
- .expect("Encoded extrinsic is always valid")
- }
-}
-
-/// The address format for describing accounts.
-pub type Address = sp_runtime::MultiAddress<AccountId, ()>;
-/// Block header type as expected by this runtime.
-pub type Header = generic::Header<BlockNumber, BlakeTwo256>;
-/// Block type as expected by this runtime.
-pub type Block = generic::Block<Header, UncheckedExtrinsic>;
-/// A Block signed with a Justification
-pub type SignedBlock = generic::SignedBlock<Block>;
-/// BlockId type as expected by this runtime.
-pub type BlockId = generic::BlockId<Block>;
-/// The SignedExtension to the basic transaction logic.
-pub type SignedExtra = (
- frame_system::CheckSpecVersion<Runtime>,
- // system::CheckTxVersion<Runtime>,
- frame_system::CheckGenesis<Runtime>,
- frame_system::CheckEra<Runtime>,
- frame_system::CheckNonce<Runtime>,
- frame_system::CheckWeight<Runtime>,
- ChargeTransactionPayment,
- //pallet_contract_helpers::ContractHelpersExtension<Runtime>,
- pallet_ethereum::FakeTransactionFinalizer<Runtime>,
-);
-
-pub type SignedExtraScheduler = (
- frame_system::CheckSpecVersion<Runtime>,
- frame_system::CheckGenesis<Runtime>,
- frame_system::CheckEra<Runtime>,
- frame_system::CheckNonce<Runtime>,
- frame_system::CheckWeight<Runtime>,
- // pallet_charge_transaction::ChargeTransactionPayment<Runtime>,
-);
-/// Unchecked extrinsic type as expected by this runtime.
-pub type UncheckedExtrinsic =
- fp_self_contained::UncheckedExtrinsic<Address, Call, Signature, SignedExtra>;
-/// Extrinsic type that has already been checked.
-pub type CheckedExtrinsic = fp_self_contained::CheckedExtrinsic<AccountId, Call, SignedExtra, H160>;
-/// Executive: handles dispatch to the various modules.
-pub type Executive = frame_executive::Executive<
- Runtime,
- Block,
- frame_system::ChainContext<Runtime>,
- Runtime,
- AllPalletsReversedWithSystemFirst,
->;
-
-impl_opaque_keys! {
- pub struct SessionKeys {
- pub aura: Aura,
- }
-}
-
-impl fp_self_contained::SelfContainedCall for Call {
- type SignedInfo = H160;
-
- fn is_self_contained(&self) -> bool {
- match self {
- Call::Ethereum(call) => call.is_self_contained(),
- _ => false,
- }
- }
-
- fn check_self_contained(&self) -> Option<Result<Self::SignedInfo, TransactionValidityError>> {
- match self {
- Call::Ethereum(call) => call.check_self_contained(),
- _ => None,
- }
- }
-
- fn validate_self_contained(
- &self,
- info: &Self::SignedInfo,
- dispatch_info: &DispatchInfoOf<Call>,
- len: usize,
- ) -> Option<TransactionValidity> {
- match self {
- Call::Ethereum(call) => call.validate_self_contained(info, dispatch_info, len),
- _ => None,
- }
- }
-
- fn pre_dispatch_self_contained(
- &self,
- info: &Self::SignedInfo,
- ) -> Option<Result<(), TransactionValidityError>> {
- match self {
- Call::Ethereum(call) => call.pre_dispatch_self_contained(info),
- _ => None,
- }
- }
-
- fn apply_self_contained(
- self,
- info: Self::SignedInfo,
- ) -> Option<sp_runtime::DispatchResultWithInfo<PostDispatchInfoOf<Self>>> {
- match self {
- call @ Call::Ethereum(pallet_ethereum::Call::transact { .. }) => Some(call.dispatch(
- Origin::from(pallet_ethereum::RawOrigin::EthereumTransaction(info)),
- )),
- _ => None,
- }
- }
-}
-
-macro_rules! dispatch_unique_runtime {
- ($collection:ident.$method:ident($($name:ident),*)) => {{
- let collection = <Runtime as pallet_common::Config>::CollectionDispatch::dispatch(<pallet_common::CollectionHandle<Runtime>>::try_get($collection)?);
- let dispatch = collection.as_dyn();
-
- Ok::<_, DispatchError>(dispatch.$method($($name),*))
- }};
-}
-
-impl_common_runtime_apis! {
- #![custom_apis]
-
- impl rmrk_rpc::RmrkApi<
- Block,
- AccountId,
- RmrkCollectionInfo<AccountId>,
- RmrkInstanceInfo<AccountId>,
- RmrkResourceInfo,
- RmrkPropertyInfo,
- RmrkBaseInfo<AccountId>,
- RmrkPartType,
- RmrkTheme
- > for Runtime {
- fn last_collection_idx() -> Result<RmrkCollectionId, DispatchError> {
- pallet_proxy_rmrk_core::rpc::last_collection_idx::<Runtime>()
- }
-
- fn collection_by_id(collection_id: RmrkCollectionId) -> Result<Option<RmrkCollectionInfo<AccountId>>, DispatchError> {
- pallet_proxy_rmrk_core::rpc::collection_by_id::<Runtime>(collection_id)
- }
-
- fn nft_by_id(collection_id: RmrkCollectionId, nft_by_id: RmrkNftId) -> Result<Option<RmrkInstanceInfo<AccountId>>, DispatchError> {
- pallet_proxy_rmrk_core::rpc::nft_by_id::<Runtime>(collection_id, nft_by_id)
- }
-
- fn account_tokens(account_id: AccountId, collection_id: RmrkCollectionId) -> Result<Vec<RmrkNftId>, DispatchError> {
- pallet_proxy_rmrk_core::rpc::account_tokens::<Runtime>(account_id, collection_id)
- }
-
- fn nft_children(collection_id: RmrkCollectionId, nft_id: RmrkNftId) -> Result<Vec<RmrkNftChild>, DispatchError> {
- pallet_proxy_rmrk_core::rpc::nft_children::<Runtime>(collection_id, nft_id)
- }
-
- fn collection_properties(collection_id: RmrkCollectionId, filter_keys: Option<Vec<RmrkPropertyKey>>) -> Result<Vec<RmrkPropertyInfo>, DispatchError> {
- pallet_proxy_rmrk_core::rpc::collection_properties::<Runtime>(collection_id, filter_keys)
- }
-
- fn nft_properties(collection_id: RmrkCollectionId, nft_id: RmrkNftId, filter_keys: Option<Vec<RmrkPropertyKey>>) -> Result<Vec<RmrkPropertyInfo>, DispatchError> {
- pallet_proxy_rmrk_core::rpc::nft_properties::<Runtime>(collection_id, nft_id, filter_keys)
- }
-
- fn nft_resources(collection_id: RmrkCollectionId, nft_id: RmrkNftId) -> Result<Vec<RmrkResourceInfo>, DispatchError> {
- pallet_proxy_rmrk_core::rpc::nft_resources::<Runtime>(collection_id, nft_id)
- }
-
- fn nft_resource_priority(collection_id: RmrkCollectionId, nft_id: RmrkNftId, resource_id: RmrkResourceId) -> Result<Option<u32>, DispatchError> {
- pallet_proxy_rmrk_core::rpc::nft_resource_priority::<Runtime>(collection_id, nft_id, resource_id)
- }
-
- fn base(base_id: RmrkBaseId) -> Result<Option<RmrkBaseInfo<AccountId>>, DispatchError> {
- pallet_proxy_rmrk_equip::rpc::base::<Runtime>(base_id)
- }
-
- fn base_parts(base_id: RmrkBaseId) -> Result<Vec<RmrkPartType>, DispatchError> {
- pallet_proxy_rmrk_equip::rpc::base_parts::<Runtime>(base_id)
- }
-
- fn theme_names(base_id: RmrkBaseId) -> Result<Vec<RmrkThemeName>, DispatchError> {
- pallet_proxy_rmrk_equip::rpc::theme_names::<Runtime>(base_id)
- }
-
- fn theme(base_id: RmrkBaseId, theme_name: RmrkThemeName, filter_keys: Option<Vec<RmrkPropertyKey>>) -> Result<Option<RmrkTheme>, DispatchError> {
- pallet_proxy_rmrk_equip::rpc::theme::<Runtime>(base_id, theme_name, filter_keys)
- }
- }
-}
-
-struct CheckInherents;
-
-impl cumulus_pallet_parachain_system::CheckInherents<Block> for CheckInherents {
- fn check_inherents(
- block: &Block,
- relay_state_proof: &cumulus_pallet_parachain_system::RelayChainStateProof,
- ) -> sp_inherents::CheckInherentsResult {
- let relay_chain_slot = relay_state_proof
- .read_slot()
- .expect("Could not read the relay chain slot from the proof");
-
- let inherent_data =
- cumulus_primitives_timestamp::InherentDataProvider::from_relay_chain_slot_and_duration(
- relay_chain_slot,
- sp_std::time::Duration::from_secs(6),
- )
- .create_inherent_data()
- .expect("Could not create the timestamp inherent data");
-
- inherent_data.check_extrinsics(block)
- }
-}
+impl_common_runtime_apis!();
cumulus_pallet_parachain_system::register_validate_block!(
Runtime = Runtime,
runtime/tests/Cargo.tomldiffbeforeafterboth--- a/runtime/tests/Cargo.toml
+++ b/runtime/tests/Cargo.toml
@@ -3,8 +3,12 @@
version = "0.1.0"
edition = "2021"
+[features]
+default = ['refungible']
+
+refungible = []
+
[dependencies]
-unique-runtime-common = { path = '../common' }
up-data-structs = { default-features = false, path = '../../primitives/data-structs' }
sp-core = { git = 'https://github.com/paritytech/substrate', branch = 'polkadot-v0.9.24' }
@@ -37,3 +41,6 @@
"derive",
] }
scale-info = "*"
+
+evm-coder = { default-features = false, path = '../../crates/evm-coder' }
+up-sponsorship = { default-features = false, git = "https://github.com/uniquenetwork/pallet-sponsoring", branch = 'polkadot-v0.9.24' }
runtime/tests/src/lib.rsdiffbeforeafterboth--- a/runtime/tests/src/lib.rs
+++ b/runtime/tests/src/lib.rs
@@ -35,9 +35,18 @@
use parity_scale_codec::{Encode, Decode, MaxEncodedLen};
use scale_info::TypeInfo;
-use unique_runtime_common::{dispatch::CollectionDispatchT, weights::CommonWeights};
use up_data_structs::mapping::{CrossTokenAddressMapping, EvmTokenAddressMapping};
+#[path = "../../common/dispatch.rs"]
+mod dispatch;
+
+use dispatch::CollectionDispatchT;
+
+#[path = "../../common/weights.rs"]
+mod weights;
+
+use weights::CommonWeights;
+
type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic<Test>;
type Block = frame_system::mocking::MockBlock<Test>;
runtime/unique/Cargo.tomldiffbeforeafterboth--- a/runtime/unique/Cargo.toml
+++ b/runtime/unique/Cargo.toml
@@ -114,13 +114,17 @@
'xcm/std',
'xcm-builder/std',
'xcm-executor/std',
- 'unique-runtime-common/std',
+ 'up-common/std',
"orml-vesting/std",
]
limit-testing = ['pallet-unique/limit-testing', 'up-data-structs/limit-testing']
unique-runtime = []
+refungible = []
+scheduler = []
+rmrk = []
+
################################################################################
# Substrate Dependencies
@@ -397,7 +401,7 @@
[dependencies]
log = { version = "0.4.16", default-features = false }
-unique-runtime-common = { path = "../common", default-features = false }
+up-common = { path = "../../primitives/common", default-features = false }
scale-info = { version = "2.0.1", default-features = false, features = [
"derive",
] }
@@ -427,6 +431,8 @@
fp-rpc = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.24" }
fp-self-contained = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.24" }
fp-evm-mapping = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.24" }
+evm-coder = { default-features = false, path = '../../crates/evm-coder' }
+up-sponsorship = { default-features = false, git = "https://github.com/uniquenetwork/pallet-sponsoring", branch = 'polkadot-v0.9.24' }
################################################################################
# Build Dependencies
runtime/unique/src/lib.rsdiffbeforeafterboth--- a/runtime/unique/src/lib.rs
+++ b/runtime/unique/src/lib.rs
@@ -25,166 +25,21 @@
#[cfg(feature = "std")]
include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs"));
-use sp_api::impl_runtime_apis;
-use sp_core::{crypto::KeyTypeId, OpaqueMetadata, H256, U256, H160};
-use sp_runtime::DispatchError;
-use fp_self_contained::*;
-// #[cfg(any(feature = "std", test))]
-// pub use sp_runtime::BuildStorage;
-
-use sp_runtime::{
- Permill, Perbill, Percent, create_runtime_str, generic, impl_opaque_keys,
- traits::{AccountIdLookup, BlakeTwo256, Block as BlockT, AccountIdConversion, Zero, Member},
- transaction_validity::{TransactionSource, TransactionValidity},
- ApplyExtrinsicResult, RuntimeAppPublic,
-};
-
-use sp_std::prelude::*;
+use frame_support::parameter_types;
-#[cfg(feature = "std")]
-use sp_version::NativeVersion;
use sp_version::RuntimeVersion;
-pub use pallet_transaction_payment::{
- Multiplier, TargetedFeeAdjustment, FeeDetails, RuntimeDispatchInfo,
-};
-// A few exports that help ease life for downstream crates.
-pub use pallet_balances::Call as BalancesCall;
-pub use pallet_evm::{
- EnsureAddressTruncated, HashedAddressMapping, Runner, account::CrossAccountId as _,
- OnMethodCall, Account as EVMAccount, FeeCalculator, GasWeightMapping,
-};
-pub use frame_support::{
- construct_runtime, match_types,
- dispatch::DispatchResult,
- PalletId, parameter_types, StorageValue, ConsensusEngineId,
- traits::{
- tokens::currency::Currency as CurrencyT, OnUnbalanced as OnUnbalancedT, Everything,
- Currency, ExistenceRequirement, Get, IsInVec, KeyOwnerProofSystem, LockIdentifier,
- OnUnbalanced, Randomness, FindAuthor, ConstU32, Imbalance, PrivilegeCmp,
- },
- weights::{
- constants::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_PER_SECOND},
- DispatchClass, DispatchInfo, GetDispatchInfo, IdentityFee, Pays, PostDispatchInfo, Weight,
- WeightToFeePolynomial, WeightToFeeCoefficient, WeightToFeeCoefficients, ConstantMultiplier,
- WeightToFee,
- },
-};
-use pallet_unique_scheduler::DispatchCall;
-use up_data_structs::{
- CollectionId, TokenId, TokenData, Property, PropertyKeyPermission, CollectionLimits,
- CollectionStats, RpcCollection,
- mapping::{EvmTokenAddressMapping, CrossTokenAddressMapping},
- TokenChild, RmrkCollectionInfo, RmrkInstanceInfo, RmrkResourceInfo, RmrkPropertyInfo,
- RmrkBaseInfo, RmrkPartType, RmrkTheme, RmrkThemeName, RmrkCollectionId, RmrkNftId,
- RmrkNftChild, RmrkPropertyKey, RmrkResourceId, RmrkBaseId,
-};
+use sp_runtime::create_runtime_str;
-// use pallet_contracts::weights::WeightInfo;
-// #[cfg(any(feature = "std", test))]
-use frame_system::{
- self as frame_system, EnsureRoot, EnsureSigned,
- limits::{BlockWeights, BlockLength},
-};
-use sp_arithmetic::{
- traits::{BaseArithmetic, Unsigned},
-};
-use smallvec::smallvec;
-use codec::{Encode, Decode};
-use fp_rpc::TransactionStatus;
-use sp_runtime::{
- traits::{
- Applyable, BlockNumberProvider, Dispatchable, PostDispatchInfoOf, DispatchInfoOf,
- Saturating, CheckedConversion,
- },
- generic::Era,
- transaction_validity::TransactionValidityError,
- DispatchErrorWithPostInfo, SaturatedConversion,
-};
+use up_common::types::*;
-// pub use pallet_timestamp::Call as TimestampCall;
-pub use sp_consensus_aura::sr25519::AuthorityId as AuraId;
+#[path = "../../common/mod.rs"]
+mod runtime_common;
-// Polkadot imports
-use pallet_xcm::XcmPassthrough;
-use polkadot_parachain::primitives::Sibling;
-use xcm::v1::{BodyId, Junction::*, MultiLocation, NetworkId, Junctions::*};
-use xcm_builder::{
- AccountId32Aliases, AllowTopLevelPaidExecutionFrom, AllowUnpaidExecutionFrom, CurrencyAdapter,
- EnsureXcmOrigin, FixedWeightBounds, LocationInverter, NativeAsset, ParentAsSuperuser,
- RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia,
- SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit,
- ParentIsPreset,
-};
-use xcm_executor::{Config, XcmExecutor, Assets};
-use sp_std::{cmp::Ordering, marker::PhantomData};
-
-use xcm::latest::{
- // Xcm,
- AssetId::{Concrete},
- Fungibility::Fungible as XcmFungible,
- MultiAsset,
- Error as XcmError,
-};
-use xcm_executor::traits::{MatchesFungible, WeightTrader};
-
-use unique_runtime_common::{
- impl_common_runtime_apis,
- types::*,
- constants::*,
- dispatch::{CollectionDispatchT, CollectionDispatch},
- sponsoring::UniqueSponsorshipHandler,
- eth_sponsoring::UniqueEthSponsorshipHandler,
- weights::CommonWeights,
-};
+pub use runtime_common::*;
pub const RUNTIME_NAME: &str = "unique";
pub const TOKEN_SYMBOL: &str = "UNQ";
-
-type CrossAccountId = pallet_evm::account::BasicCrossAccountId<Runtime>;
-
-impl RuntimeInstance for Runtime {
- type CrossAccountId = self::CrossAccountId;
- type TransactionConverter = self::TransactionConverter;
-
- fn get_transaction_converter() -> TransactionConverter {
- TransactionConverter
- }
-}
-
-/// The type for looking up accounts. We don't expect more than 4 billion of them, but you
-/// never know...
-pub type AccountIndex = u32;
-
-/// Balance of an account.
-pub type Balance = u128;
-
-/// Index of a transaction in the chain.
-pub type Index = u32;
-
-/// A hash of some data used by the chain.
-pub type Hash = sp_core::H256;
-
-/// Digest item type.
-pub type DigestItem = generic::DigestItem;
-
-/// Opaque types. These are used by the CLI to instantiate machinery that don't need to know
-/// the specifics of the runtime. They can then be made to be agnostic over specific formats
-/// of data like extrinsics, allowing for them to continue syncing the network through upgrades
-/// to even the core data structures.
-pub mod opaque {
- use sp_std::prelude::*;
- use sp_runtime::impl_opaque_keys;
- use super::Aura;
-
- pub use unique_runtime_common::types::*;
- impl_opaque_keys! {
- pub struct SessionKeys {
- pub aura: Aura,
- }
- }
-}
-
/// This runtime version.
pub const VERSION: RuntimeVersion = RuntimeVersion {
spec_name: create_runtime_str!(RUNTIME_NAME),
@@ -197,1194 +52,15 @@
state_version: 0,
};
-#[derive(codec::Encode, codec::Decode)]
-pub enum XCMPMessage<XAccountId, XBalance> {
- /// Transfer tokens to the given account from the Parachain account.
- TransferToken(XAccountId, XBalance),
-}
-
-/// The version information used to identify this runtime when compiled natively.
-#[cfg(feature = "std")]
-pub fn native_version() -> NativeVersion {
- NativeVersion {
- runtime_version: VERSION,
- can_author_with: Default::default(),
- }
-}
-
-type NegativeImbalance = <Balances as Currency<AccountId>>::NegativeImbalance;
-
-pub struct DealWithFees;
-impl OnUnbalanced<NegativeImbalance> for DealWithFees {
- fn on_unbalanceds<B>(mut fees_then_tips: impl Iterator<Item = NegativeImbalance>) {
- if let Some(fees) = fees_then_tips.next() {
- // for fees, 100% to treasury
- let mut split = fees.ration(100, 0);
- if let Some(tips) = fees_then_tips.next() {
- // for tips, if any, 100% to treasury
- tips.ration_merge_into(100, 0, &mut split);
- }
- Treasury::on_unbalanced(split.0);
- // Author::on_unbalanced(split.1);
- }
- }
-}
-
parameter_types! {
- pub const BlockHashCount: BlockNumber = 2400;
- pub RuntimeBlockLength: BlockLength =
- BlockLength::max_with_normal_ratio(5 * 1024 * 1024, NORMAL_DISPATCH_RATIO);
- pub const AvailableBlockRatio: Perbill = Perbill::from_percent(75);
- pub const MaximumBlockLength: u32 = 5 * 1024 * 1024;
- pub RuntimeBlockWeights: BlockWeights = BlockWeights::builder()
- .base_block(BlockExecutionWeight::get())
- .for_class(DispatchClass::all(), |weights| {
- weights.base_extrinsic = ExtrinsicBaseWeight::get();
- })
- .for_class(DispatchClass::Normal, |weights| {
- weights.max_total = Some(NORMAL_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT);
- })
- .for_class(DispatchClass::Operational, |weights| {
- weights.max_total = Some(MAXIMUM_BLOCK_WEIGHT);
- // Operational transactions have some extra reserved space, so that they
- // are included even if block reached `MAXIMUM_BLOCK_WEIGHT`.
- weights.reserved = Some(
- MAXIMUM_BLOCK_WEIGHT - NORMAL_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT
- );
- })
- .avg_block_initialization(AVERAGE_ON_INITIALIZE_RATIO)
- .build_or_panic();
pub const Version: RuntimeVersion = VERSION;
pub const SS58Prefix: u16 = 7391;
-}
-
-parameter_types! {
pub const ChainId: u64 = 8880;
-}
-
-pub struct FixedFee;
-impl FeeCalculator for FixedFee {
- fn min_gas_price() -> (U256, u64) {
- (MIN_GAS_PRICE.into(), 0)
- }
-}
-
-// Assuming slowest ethereum opcode is SSTORE, with gas price of 20000 as our worst case
-// (contract, which only writes a lot of data),
-// approximating on top of our real store write weight
-parameter_types! {
- pub const WritesPerSecond: u64 = WEIGHT_PER_SECOND / <Runtime as frame_system::Config>::DbWeight::get().write;
- pub const GasPerSecond: u64 = WritesPerSecond::get() * 20000;
- pub const WeightPerGas: u64 = WEIGHT_PER_SECOND / GasPerSecond::get();
}
-/// Limiting EVM execution to 50% of block for substrate users and management tasks
-/// EVM transaction consumes more weight than substrate's, so we can't rely on them being
-/// scheduled fairly
-const EVM_DISPATCH_RATIO: Perbill = Perbill::from_percent(50);
-parameter_types! {
- pub BlockGasLimit: U256 = U256::from(NORMAL_DISPATCH_RATIO * EVM_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT / WeightPerGas::get());
-}
-
-pub enum FixedGasWeightMapping {}
-impl GasWeightMapping for FixedGasWeightMapping {
- fn gas_to_weight(gas: u64) -> Weight {
- gas.saturating_mul(WeightPerGas::get())
- }
- fn weight_to_gas(weight: Weight) -> u64 {
- weight / WeightPerGas::get()
- }
-}
-
-impl pallet_evm::account::Config for Runtime {
- type CrossAccountId = pallet_evm::account::BasicCrossAccountId<Self>;
- type EvmAddressMapping = pallet_evm::HashedAddressMapping<Self::Hashing>;
- type EvmBackwardsAddressMapping = fp_evm_mapping::MapBackwardsAddressTruncated;
-}
-
-impl pallet_evm::Config for Runtime {
- type BlockGasLimit = BlockGasLimit;
- type FeeCalculator = FixedFee;
- type GasWeightMapping = FixedGasWeightMapping;
- type BlockHashMapping = pallet_ethereum::EthereumBlockHashMapping<Self>;
- type CallOrigin = EnsureAddressTruncated<Self>;
- type WithdrawOrigin = EnsureAddressTruncated<Self>;
- type AddressMapping = HashedAddressMapping<Self::Hashing>;
- type PrecompilesType = ();
- type PrecompilesValue = ();
- type Currency = Balances;
- type Event = Event;
- type OnMethodCall = (
- pallet_evm_migration::OnMethodCall<Self>,
- pallet_evm_contract_helpers::HelpersOnMethodCall<Self>,
- CollectionDispatchT<Self>,
- pallet_unique::eth::CollectionHelpersOnMethodCall<Self>,
- );
- type OnCreate = pallet_evm_contract_helpers::HelpersOnCreate<Self>;
- type ChainId = ChainId;
- type Runner = pallet_evm::runner::stack::Runner<Self>;
- type OnChargeTransaction = pallet_evm::EVMCurrencyAdapter<Balances, DealWithFees>;
- type TransactionValidityHack = pallet_evm_transaction_payment::TransactionValidityHack<Self>;
- type FindAuthor = EthereumFindAuthor<Aura>;
-}
-
-impl pallet_evm_migration::Config for Runtime {
- type WeightInfo = pallet_evm_migration::weights::SubstrateWeight<Self>;
-}
-
-pub struct EthereumFindAuthor<F>(core::marker::PhantomData<F>);
-impl<F: FindAuthor<u32>> FindAuthor<H160> for EthereumFindAuthor<F> {
- fn find_author<'a, I>(digests: I) -> Option<H160>
- where
- I: 'a + IntoIterator<Item = (ConsensusEngineId, &'a [u8])>,
- {
- if let Some(author_index) = F::find_author(digests) {
- let authority_id = Aura::authorities()[author_index as usize].clone();
- return Some(H160::from_slice(&authority_id.to_raw_vec()[4..24]));
- }
- None
- }
-}
-
-impl pallet_ethereum::Config for Runtime {
- type Event = Event;
- type StateRoot = pallet_ethereum::IntermediateStateRoot<Self>;
-}
-
-impl pallet_randomness_collective_flip::Config for Runtime {}
+construct_runtime!(unique);
-impl frame_system::Config for Runtime {
- /// The data to be stored in an account.
- type AccountData = pallet_balances::AccountData<Balance>;
- /// The identifier used to distinguish between accounts.
- type AccountId = AccountId;
- /// The basic call filter to use in dispatchable.
- type BaseCallFilter = Everything;
- /// Maximum number of block number to block hash mappings to keep (oldest pruned first).
- type BlockHashCount = BlockHashCount;
- /// The maximum length of a block (in bytes).
- type BlockLength = RuntimeBlockLength;
- /// The index type for blocks.
- type BlockNumber = BlockNumber;
- /// The weight of the overhead invoked on the block import process, independent of the extrinsics included in that block.
- type BlockWeights = RuntimeBlockWeights;
- /// The aggregated dispatch type that is available for extrinsics.
- type Call = Call;
- /// The weight of database operations that the runtime can invoke.
- type DbWeight = RocksDbWeight;
- /// The ubiquitous event type.
- type Event = Event;
- /// The type for hashing blocks and tries.
- type Hash = Hash;
- /// The hashing algorithm used.
- type Hashing = BlakeTwo256;
- /// The header type.
- type Header = generic::Header<BlockNumber, BlakeTwo256>;
- /// The index type for storing how many extrinsics an account has signed.
- type Index = Index;
- /// The lookup mechanism to get account ID from whatever is passed in dispatchers.
- type Lookup = AccountIdLookup<AccountId, ()>;
- /// What to do if an account is fully reaped from the system.
- type OnKilledAccount = ();
- /// What to do if a new account is created.
- type OnNewAccount = ();
- type OnSetCode = cumulus_pallet_parachain_system::ParachainSetCode<Self>;
- /// The ubiquitous origin type.
- type Origin = Origin;
- /// This type is being generated by `construct_runtime!`.
- type PalletInfo = PalletInfo;
- /// This is used as an identifier of the chain. 42 is the generic substrate prefix.
- type SS58Prefix = SS58Prefix;
- /// Weight information for the extrinsics of this pallet.
- type SystemWeightInfo = frame_system::weights::SubstrateWeight<Self>;
- /// Version of the runtime.
- type Version = Version;
- type MaxConsumers = ConstU32<16>;
-}
-
-parameter_types! {
- pub const MinimumPeriod: u64 = SLOT_DURATION / 2;
-}
-
-impl pallet_timestamp::Config for Runtime {
- /// A timestamp: milliseconds since the unix epoch.
- type Moment = u64;
- type OnTimestampSet = ();
- type MinimumPeriod = MinimumPeriod;
- type WeightInfo = ();
-}
-
-parameter_types! {
- // pub const ExistentialDeposit: u128 = 500;
- pub const ExistentialDeposit: u128 = 0;
- pub const MaxLocks: u32 = 50;
- pub const MaxReserves: u32 = 50;
-}
-
-impl pallet_balances::Config for Runtime {
- type MaxLocks = MaxLocks;
- type MaxReserves = MaxReserves;
- type ReserveIdentifier = [u8; 16];
- /// The type for recording an account's balance.
- type Balance = Balance;
- /// The ubiquitous event type.
- type Event = Event;
- type DustRemoval = Treasury;
- type ExistentialDeposit = ExistentialDeposit;
- type AccountStore = System;
- type WeightInfo = pallet_balances::weights::SubstrateWeight<Self>;
-}
-
-pub const fn deposit(items: u32, bytes: u32) -> Balance {
- items as Balance * 15 * CENTIUNIQUE + (bytes as Balance) * 6 * CENTIUNIQUE
-}
-
-/*
-parameter_types! {
- pub TombstoneDeposit: Balance = deposit(
- 1,
- sp_std::mem::size_of::<pallet_contracts::Pallet<Runtime>> as u32,
- );
- pub DepositPerContract: Balance = TombstoneDeposit::get();
- pub const DepositPerStorageByte: Balance = deposit(0, 1);
- pub const DepositPerStorageItem: Balance = deposit(1, 0);
- pub RentFraction: Perbill = Perbill::from_rational(1u32, 30 * DAYS);
- pub const SurchargeReward: Balance = 150 * MILLIUNIQUE;
- pub const SignedClaimHandicap: u32 = 2;
- pub const MaxDepth: u32 = 32;
- pub const MaxValueSize: u32 = 16 * 1024;
- pub const MaxCodeSize: u32 = 1024 * 1024 * 25; // 25 Mb
- // The lazy deletion runs inside on_initialize.
- pub DeletionWeightLimit: Weight = AVERAGE_ON_INITIALIZE_RATIO *
- RuntimeBlockWeights::get().max_block;
- // The weight needed for decoding the queue should be less or equal than a fifth
- // of the overall weight dedicated to the lazy deletion.
- pub DeletionQueueDepth: u32 = ((DeletionWeightLimit::get() / (
- <Runtime as pallet_contracts::Config>::WeightInfo::on_initialize_per_queue_item(1) -
- <Runtime as pallet_contracts::Config>::WeightInfo::on_initialize_per_queue_item(0)
- )) / 5) as u32;
- pub Schedule: pallet_contracts::Schedule<Runtime> = Default::default();
-}
-
-impl pallet_contracts::Config for Runtime {
- type Time = Timestamp;
- type Randomness = RandomnessCollectiveFlip;
- type Currency = Balances;
- type Event = Event;
- type RentPayment = ();
- type SignedClaimHandicap = SignedClaimHandicap;
- type TombstoneDeposit = TombstoneDeposit;
- type DepositPerContract = DepositPerContract;
- type DepositPerStorageByte = DepositPerStorageByte;
- type DepositPerStorageItem = DepositPerStorageItem;
- type RentFraction = RentFraction;
- type SurchargeReward = SurchargeReward;
- type WeightPrice = pallet_transaction_payment::Pallet<Self>;
- type WeightInfo = pallet_contracts::weights::SubstrateWeight<Self>;
- type ChainExtension = NFTExtension;
- type DeletionQueueDepth = DeletionQueueDepth;
- type DeletionWeightLimit = DeletionWeightLimit;
- type Schedule = Schedule;
- type CallStack = [pallet_contracts::Frame<Self>; 31];
-}
-*/
-
-parameter_types! {
- /// This value increases the priority of `Operational` transactions by adding
- /// a "virtual tip" that's equal to the `OperationalFeeMultiplier * final_fee`.
- pub const OperationalFeeMultiplier: u8 = 5;
-}
-
-/// Linear implementor of `WeightToFeePolynomial`
-pub struct LinearFee<T>(sp_std::marker::PhantomData<T>);
-
-impl<T> WeightToFeePolynomial for LinearFee<T>
-where
- T: BaseArithmetic + From<u32> + Copy + Unsigned,
-{
- type Balance = T;
-
- fn polynomial() -> WeightToFeeCoefficients<Self::Balance> {
- smallvec!(WeightToFeeCoefficient {
- coeff_integer: WEIGHT_TO_FEE_COEFF.into(),
- coeff_frac: Perbill::zero(),
- negative: false,
- degree: 1,
- })
- }
-}
-
-impl pallet_transaction_payment::Config for Runtime {
- type OnChargeTransaction = pallet_transaction_payment::CurrencyAdapter<Balances, DealWithFees>;
- type LengthToFee = ConstantMultiplier<Balance, TransactionByteFee>;
- type OperationalFeeMultiplier = OperationalFeeMultiplier;
- type WeightToFee = LinearFee<Balance>;
- type FeeMultiplierUpdate = ();
-}
-
-parameter_types! {
- pub const ProposalBond: Permill = Permill::from_percent(5);
- pub const ProposalBondMinimum: Balance = 1 * UNIQUE;
- pub const ProposalBondMaximum: Balance = 1000 * UNIQUE;
- pub const SpendPeriod: BlockNumber = 5 * MINUTES;
- pub const Burn: Permill = Permill::from_percent(0);
- pub const TipCountdown: BlockNumber = 1 * DAYS;
- pub const TipFindersFee: Percent = Percent::from_percent(20);
- pub const TipReportDepositBase: Balance = 1 * UNIQUE;
- pub const DataDepositPerByte: Balance = 1 * CENTIUNIQUE;
- pub const BountyDepositBase: Balance = 1 * UNIQUE;
- pub const BountyDepositPayoutDelay: BlockNumber = 1 * DAYS;
- pub const TreasuryModuleId: PalletId = PalletId(*b"py/trsry");
- pub const BountyUpdatePeriod: BlockNumber = 14 * DAYS;
- pub const MaximumReasonLength: u32 = 16384;
- pub const BountyCuratorDeposit: Permill = Permill::from_percent(50);
- pub const BountyValueMinimum: Balance = 5 * UNIQUE;
- pub const MaxApprovals: u32 = 100;
-}
-
-impl pallet_treasury::Config for Runtime {
- type PalletId = TreasuryModuleId;
- type Currency = Balances;
- type ApproveOrigin = EnsureRoot<AccountId>;
- type RejectOrigin = EnsureRoot<AccountId>;
- type Event = Event;
- type OnSlash = ();
- type ProposalBond = ProposalBond;
- type ProposalBondMinimum = ProposalBondMinimum;
- type ProposalBondMaximum = ProposalBondMaximum;
- type SpendPeriod = SpendPeriod;
- type Burn = Burn;
- type BurnDestination = ();
- type SpendFunds = ();
- type WeightInfo = pallet_treasury::weights::SubstrateWeight<Self>;
- type MaxApprovals = MaxApprovals;
-}
-
-impl pallet_sudo::Config for Runtime {
- type Event = Event;
- type Call = Call;
-}
-
-pub struct RelayChainBlockNumberProvider<T>(sp_std::marker::PhantomData<T>);
-
-impl<T: cumulus_pallet_parachain_system::Config> BlockNumberProvider
- for RelayChainBlockNumberProvider<T>
-{
- type BlockNumber = BlockNumber;
-
- fn current_block_number() -> Self::BlockNumber {
- cumulus_pallet_parachain_system::Pallet::<T>::validation_data()
- .map(|d| d.relay_parent_number)
- .unwrap_or_default()
- }
-}
-
-parameter_types! {
- pub const MinVestedTransfer: Balance = 10 * UNIQUE;
- pub const MaxVestingSchedules: u32 = 28;
-}
-
-impl orml_vesting::Config for Runtime {
- type Event = Event;
- type Currency = pallet_balances::Pallet<Runtime>;
- type MinVestedTransfer = MinVestedTransfer;
- type VestedTransferOrigin = EnsureSigned<AccountId>;
- type WeightInfo = ();
- type MaxVestingSchedules = MaxVestingSchedules;
- type BlockNumberProvider = RelayChainBlockNumberProvider<Runtime>;
-}
-
-parameter_types! {
- pub const ReservedDmpWeight: Weight = MAXIMUM_BLOCK_WEIGHT / 4;
- pub const ReservedXcmpWeight: Weight = MAXIMUM_BLOCK_WEIGHT / 4;
-}
-
-impl cumulus_pallet_parachain_system::Config for Runtime {
- type Event = Event;
- type SelfParaId = parachain_info::Pallet<Self>;
- type OnSystemEvent = ();
- // type DownwardMessageHandlers = cumulus_primitives_utility::UnqueuedDmpAsParent<
- // MaxDownwardMessageWeight,
- // XcmExecutor<XcmConfig>,
- // Call,
- // >;
- type OutboundXcmpMessageSource = XcmpQueue;
- type DmpMessageHandler = DmpQueue;
- type ReservedDmpWeight = ReservedDmpWeight;
- type ReservedXcmpWeight = ReservedXcmpWeight;
- type XcmpMessageHandler = XcmpQueue;
-}
-
-impl parachain_info::Config for Runtime {}
-
-impl cumulus_pallet_aura_ext::Config for Runtime {}
-
-parameter_types! {
- pub const RelayLocation: MultiLocation = MultiLocation::parent();
- pub const RelayNetwork: NetworkId = NetworkId::Polkadot;
- pub RelayOrigin: Origin = cumulus_pallet_xcm::Origin::Relay.into();
- pub Ancestry: MultiLocation = Parachain(ParachainInfo::parachain_id().into()).into();
-}
-
-/// Type for specifying how a `MultiLocation` can be converted into an `AccountId`. This is used
-/// when determining ownership of accounts for asset transacting and when attempting to use XCM
-/// `Transact` in order to determine the dispatch Origin.
-pub type LocationToAccountId = (
- // The parent (Relay-chain) origin converts to the default `AccountId`.
- ParentIsPreset<AccountId>,
- // Sibling parachain origins convert to AccountId via the `ParaId::into`.
- SiblingParachainConvertsVia<Sibling, AccountId>,
- // Straight up local `AccountId32` origins just alias directly to `AccountId`.
- AccountId32Aliases<RelayNetwork, AccountId>,
-);
-
-pub struct OnlySelfCurrency;
-impl<B: TryFrom<u128>> MatchesFungible<B> for OnlySelfCurrency {
- fn matches_fungible(a: &MultiAsset) -> Option<B> {
- match (&a.id, &a.fun) {
- (Concrete(_), XcmFungible(ref amount)) => CheckedConversion::checked_from(*amount),
- _ => None,
- }
- }
-}
-
-/// Means for transacting assets on this chain.
-pub type LocalAssetTransactor = CurrencyAdapter<
- // Use this currency:
- Balances,
- // Use this currency when it is a fungible asset matching the given location or name:
- OnlySelfCurrency,
- // Do a simple punn to convert an AccountId32 MultiLocation into a native chain account ID:
- LocationToAccountId,
- // Our chain's account ID type (we can't get away without mentioning it explicitly):
- AccountId,
- // We don't track any teleports.
- (),
->;
-
-/// This is the type we use to convert an (incoming) XCM origin into a local `Origin` instance,
-/// ready for dispatching a transaction with Xcm's `Transact`. There is an `OriginKind` which can
-/// biases the kind of local `Origin` it will become.
-pub type XcmOriginToTransactDispatchOrigin = (
- // Sovereign account converter; this attempts to derive an `AccountId` from the origin location
- // using `LocationToAccountId` and then turn that into the usual `Signed` origin. Useful for
- // foreign chains who want to have a local sovereign account on this chain which they control.
- SovereignSignedViaLocation<LocationToAccountId, Origin>,
- // Native converter for Relay-chain (Parent) location; will converts to a `Relay` origin when
- // recognised.
- RelayChainAsNative<RelayOrigin, Origin>,
- // Native converter for sibling Parachains; will convert to a `SiblingPara` origin when
- // recognised.
- SiblingParachainAsNative<cumulus_pallet_xcm::Origin, Origin>,
- // Superuser converter for the Relay-chain (Parent) location. This will allow it to issue a
- // transaction from the Root origin.
- ParentAsSuperuser<Origin>,
- // Native signed account converter; this just converts an `AccountId32` origin into a normal
- // `Origin::Signed` origin of the same 32-byte value.
- SignedAccountId32AsNative<RelayNetwork, Origin>,
- // Xcm origins can be represented natively under the Xcm pallet's Xcm origin.
- XcmPassthrough<Origin>,
-);
-
-parameter_types! {
- // One XCM operation is 1_000_000 weight - almost certainly a conservative estimate.
- pub UnitWeightCost: Weight = 1_000_000;
- // 1200 UNIQUEs buy 1 second of weight.
- pub const WeightPrice: (MultiLocation, u128) = (MultiLocation::parent(), 1_200 * UNIQUE);
- pub const MaxInstructions: u32 = 100;
- pub const MaxAuthorities: u32 = 100_000;
-}
-
-match_types! {
- pub type ParentOrParentsUnitPlurality: impl Contains<MultiLocation> = {
- MultiLocation { parents: 1, interior: Here } |
- MultiLocation { parents: 1, interior: X1(Plurality { id: BodyId::Unit, .. }) }
- };
-}
-
-pub type Barrier = (
- TakeWeightCredit,
- AllowTopLevelPaidExecutionFrom<Everything>,
- // ^^^ Parent & its unit plurality gets free execution
-);
-
-pub struct UsingOnlySelfCurrencyComponents<
- WeightToFee: WeightToFeePolynomial<Balance = Currency::Balance>,
- AssetId: Get<MultiLocation>,
- AccountId,
- Currency: CurrencyT<AccountId>,
- OnUnbalanced: OnUnbalancedT<Currency::NegativeImbalance>,
->(
- Weight,
- Currency::Balance,
- PhantomData<(WeightToFee, AssetId, AccountId, Currency, OnUnbalanced)>,
-);
-impl<
- WeightToFee: WeightToFeePolynomial<Balance = Currency::Balance>,
- AssetId: Get<MultiLocation>,
- AccountId,
- Currency: CurrencyT<AccountId>,
- OnUnbalanced: OnUnbalancedT<Currency::NegativeImbalance>,
- > WeightTrader
- for UsingOnlySelfCurrencyComponents<WeightToFee, AssetId, AccountId, Currency, OnUnbalanced>
-{
- fn new() -> Self {
- Self(0, Zero::zero(), PhantomData)
- }
-
- fn buy_weight(&mut self, weight: Weight, payment: Assets) -> Result<Assets, XcmError> {
- let amount = WeightToFee::weight_to_fee(&weight);
- let u128_amount: u128 = amount.try_into().map_err(|_| XcmError::Overflow)?;
-
- // location to this parachain through relay chain
- let option1: xcm::v1::AssetId = Concrete(MultiLocation {
- parents: 1,
- interior: X1(Parachain(ParachainInfo::parachain_id().into())),
- });
- // direct location
- let option2: xcm::v1::AssetId = Concrete(MultiLocation {
- parents: 0,
- interior: Here,
- });
-
- let required = if payment.fungible.contains_key(&option1) {
- (option1, u128_amount).into()
- } else if payment.fungible.contains_key(&option2) {
- (option2, u128_amount).into()
- } else {
- (Concrete(MultiLocation::default()), u128_amount).into()
- };
-
- let unused = payment
- .checked_sub(required)
- .map_err(|_| XcmError::TooExpensive)?;
- self.0 = self.0.saturating_add(weight);
- self.1 = self.1.saturating_add(amount);
- Ok(unused)
- }
-
- fn refund_weight(&mut self, weight: Weight) -> Option<MultiAsset> {
- let weight = weight.min(self.0);
- let amount = WeightToFee::weight_to_fee(&weight);
- self.0 -= weight;
- self.1 = self.1.saturating_sub(amount);
- let amount: u128 = amount.saturated_into();
- if amount > 0 {
- Some((AssetId::get(), amount).into())
- } else {
- None
- }
- }
-}
-impl<
- WeightToFee: WeightToFeePolynomial<Balance = Currency::Balance>,
- AssetId: Get<MultiLocation>,
- AccountId,
- Currency: CurrencyT<AccountId>,
- OnUnbalanced: OnUnbalancedT<Currency::NegativeImbalance>,
- > Drop
- for UsingOnlySelfCurrencyComponents<WeightToFee, AssetId, AccountId, Currency, OnUnbalanced>
-{
- fn drop(&mut self) {
- OnUnbalanced::on_unbalanced(Currency::issue(self.1));
- }
-}
-
-pub struct XcmConfig;
-impl Config for XcmConfig {
- type Call = Call;
- type XcmSender = XcmRouter;
- // How to withdraw and deposit an asset.
- type AssetTransactor = LocalAssetTransactor;
- type OriginConverter = XcmOriginToTransactDispatchOrigin;
- type IsReserve = NativeAsset;
- type IsTeleporter = (); // Teleportation is disabled
- type LocationInverter = LocationInverter<Ancestry>;
- type Barrier = Barrier;
- type Weigher = FixedWeightBounds<UnitWeightCost, Call, MaxInstructions>;
- type Trader =
- UsingOnlySelfCurrencyComponents<LinearFee<Balance>, RelayLocation, AccountId, Balances, ()>;
- type ResponseHandler = (); // Don't handle responses for now.
- type SubscriptionService = PolkadotXcm;
-
- type AssetTrap = PolkadotXcm;
- type AssetClaims = PolkadotXcm;
-}
-
-// parameter_types! {
-// pub const MaxDownwardMessageWeight: Weight = MAXIMUM_BLOCK_WEIGHT / 10;
-// }
-
-/// No local origins on this chain are allowed to dispatch XCM sends/executions.
-pub type LocalOriginToLocation = (SignedToAccountId32<Origin, AccountId, RelayNetwork>,);
-
-/// The means for routing XCM messages which are not for local execution into the right message
-/// queues.
-pub type XcmRouter = (
- // Two routers - use UMP to communicate with the relay chain:
- cumulus_primitives_utility::ParentAsUmp<ParachainSystem, ()>,
- // ..and XCMP to communicate with the sibling chains.
- XcmpQueue,
-);
-
-impl pallet_evm_coder_substrate::Config for Runtime {}
-
-impl pallet_xcm::Config for Runtime {
- type Event = Event;
- type SendXcmOrigin = EnsureXcmOrigin<Origin, LocalOriginToLocation>;
- type XcmRouter = XcmRouter;
- type ExecuteXcmOrigin = EnsureXcmOrigin<Origin, LocalOriginToLocation>;
- type XcmExecuteFilter = Everything;
- type XcmExecutor = XcmExecutor<XcmConfig>;
- type XcmTeleportFilter = Everything;
- type XcmReserveTransferFilter = Everything;
- type Weigher = FixedWeightBounds<UnitWeightCost, Call, MaxInstructions>;
- type LocationInverter = LocationInverter<Ancestry>;
- type Origin = Origin;
- type Call = Call;
- const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 100;
- type AdvertisedXcmVersion = pallet_xcm::CurrentXcmVersion;
-}
-
-impl cumulus_pallet_xcm::Config for Runtime {
- type Event = Event;
- type XcmExecutor = XcmExecutor<XcmConfig>;
-}
-
-impl cumulus_pallet_xcmp_queue::Config for Runtime {
- type WeightInfo = ();
- type Event = Event;
- type XcmExecutor = XcmExecutor<XcmConfig>;
- type ChannelInfo = ParachainSystem;
- type VersionWrapper = ();
- type ExecuteOverweightOrigin = frame_system::EnsureRoot<AccountId>;
- type ControllerOrigin = EnsureRoot<AccountId>;
- type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin;
-}
-
-impl cumulus_pallet_dmp_queue::Config for Runtime {
- type Event = Event;
- type XcmExecutor = XcmExecutor<XcmConfig>;
- type ExecuteOverweightOrigin = frame_system::EnsureRoot<AccountId>;
-}
-
-impl pallet_aura::Config for Runtime {
- type AuthorityId = AuraId;
- type DisabledValidators = ();
- type MaxAuthorities = MaxAuthorities;
-}
-
-parameter_types! {
- pub TreasuryAccountId: AccountId = TreasuryModuleId::get().into_account_truncating();
- pub const CollectionCreationPrice: Balance = 2 * UNIQUE;
-}
-
-impl pallet_common::Config for Runtime {
- type WeightInfo = pallet_common::weights::SubstrateWeight<Self>;
- type Event = Event;
- type Currency = Balances;
- type CollectionCreationPrice = CollectionCreationPrice;
- type TreasuryAccountId = TreasuryAccountId;
- type CollectionDispatch = CollectionDispatchT<Self>;
-
- type EvmTokenAddressMapping = EvmTokenAddressMapping;
- type CrossTokenAddressMapping = CrossTokenAddressMapping<Self::AccountId>;
- type ContractAddress = EvmCollectionHelpersAddress;
-}
-
-impl pallet_structure::Config for Runtime {
- type Event = Event;
- type Call = Call;
- type WeightInfo = pallet_structure::weights::SubstrateWeight<Self>;
-}
-
-impl pallet_fungible::Config for Runtime {
- type WeightInfo = pallet_fungible::weights::SubstrateWeight<Self>;
-}
-impl pallet_refungible::Config for Runtime {
- type WeightInfo = pallet_refungible::weights::SubstrateWeight<Self>;
-}
-impl pallet_nonfungible::Config for Runtime {
- type WeightInfo = pallet_nonfungible::weights::SubstrateWeight<Self>;
-}
-
-impl pallet_unique::Config for Runtime {
- type Event = Event;
- type WeightInfo = pallet_unique::weights::SubstrateWeight<Self>;
- type CommonWeightInfo = CommonWeights<Self>;
- type RefungibleExtensionsWeightInfo = CommonWeights<Self>;
-}
-
-parameter_types! {
- pub const InflationBlockInterval: BlockNumber = 100; // every time per how many blocks inflation is applied
-}
-
-/// Used for the pallet inflation
-impl pallet_inflation::Config for Runtime {
- type Currency = Balances;
- type TreasuryAccountId = TreasuryAccountId;
- type InflationBlockInterval = InflationBlockInterval;
- type BlockNumberProvider = RelayChainBlockNumberProvider<Runtime>;
-}
-
-parameter_types! {
- pub MaximumSchedulerWeight: Weight = Perbill::from_percent(50) *
- RuntimeBlockWeights::get().max_block;
- pub const MaxScheduledPerBlock: u32 = 50;
-}
-
-type ChargeTransactionPayment = pallet_charge_transaction::ChargeTransactionPayment<Runtime>;
-use frame_support::traits::NamedReservableCurrency;
-
-fn get_signed_extras(from: <Runtime as frame_system::Config>::AccountId) -> SignedExtraScheduler {
- (
- frame_system::CheckSpecVersion::<Runtime>::new(),
- frame_system::CheckGenesis::<Runtime>::new(),
- frame_system::CheckEra::<Runtime>::from(Era::Immortal),
- frame_system::CheckNonce::<Runtime>::from(frame_system::Pallet::<Runtime>::account_nonce(
- from,
- )),
- frame_system::CheckWeight::<Runtime>::new(),
- // sponsoring transaction logic
- // pallet_charge_transaction::ChargeTransactionPayment::<Runtime>::new(0),
- )
-}
-
-pub struct SchedulerPaymentExecutor;
-impl<T: frame_system::Config + pallet_unique_scheduler::Config, SelfContainedSignedInfo>
- DispatchCall<T, SelfContainedSignedInfo> for SchedulerPaymentExecutor
-where
- <T as frame_system::Config>::Call: Member
- + Dispatchable<Origin = Origin, Info = DispatchInfo>
- + SelfContainedCall<SignedInfo = SelfContainedSignedInfo>
- + GetDispatchInfo
- + From<frame_system::Call<Runtime>>,
- SelfContainedSignedInfo: Send + Sync + 'static,
- Call: From<<T as frame_system::Config>::Call>
- + From<<T as pallet_unique_scheduler::Config>::Call>
- + SelfContainedCall<SignedInfo = SelfContainedSignedInfo>,
- sp_runtime::AccountId32: From<<T as frame_system::Config>::AccountId>,
-{
- fn dispatch_call(
- signer: <T as frame_system::Config>::AccountId,
- call: <T as pallet_unique_scheduler::Config>::Call,
- ) -> Result<
- Result<PostDispatchInfo, DispatchErrorWithPostInfo<PostDispatchInfo>>,
- TransactionValidityError,
- > {
- let dispatch_info = call.get_dispatch_info();
- let extrinsic = fp_self_contained::CheckedExtrinsic::<
- AccountId,
- Call,
- SignedExtraScheduler,
- SelfContainedSignedInfo,
- > {
- signed:
- CheckedSignature::<AccountId, SignedExtraScheduler, SelfContainedSignedInfo>::Signed(
- signer.clone().into(),
- get_signed_extras(signer.into()),
- ),
- function: call.into(),
- };
-
- extrinsic.apply::<Runtime>(&dispatch_info, 0)
- }
-
- fn reserve_balance(
- id: [u8; 16],
- sponsor: <T as frame_system::Config>::AccountId,
- call: <T as pallet_unique_scheduler::Config>::Call,
- count: u32,
- ) -> Result<(), DispatchError> {
- let dispatch_info = call.get_dispatch_info();
- let weight: Balance = ChargeTransactionPayment::traditional_fee(0, &dispatch_info, 0)
- .saturating_mul(count.into());
-
- <Balances as NamedReservableCurrency<AccountId>>::reserve_named(
- &id,
- &(sponsor.into()),
- weight,
- )
- }
-
- fn pay_for_call(
- id: [u8; 16],
- sponsor: <T as frame_system::Config>::AccountId,
- call: <T as pallet_unique_scheduler::Config>::Call,
- ) -> Result<u128, DispatchError> {
- let dispatch_info = call.get_dispatch_info();
- let weight: Balance = ChargeTransactionPayment::traditional_fee(0, &dispatch_info, 0);
- Ok(
- <Balances as NamedReservableCurrency<AccountId>>::unreserve_named(
- &id,
- &(sponsor.into()),
- weight,
- ),
- )
- }
-
- fn cancel_reserve(
- id: [u8; 16],
- sponsor: <T as frame_system::Config>::AccountId,
- ) -> Result<u128, DispatchError> {
- Ok(
- <Balances as NamedReservableCurrency<AccountId>>::unreserve_named(
- &id,
- &(sponsor.into()),
- u128::MAX,
- ),
- )
- }
-}
-
-parameter_types! {
- pub const NoPreimagePostponement: Option<u32> = Some(10);
- pub const Preimage: Option<u32> = Some(10);
-}
-
-/// Used the compare the privilege of an origin inside the scheduler.
-pub struct OriginPrivilegeCmp;
-
-impl PrivilegeCmp<OriginCaller> for OriginPrivilegeCmp {
- fn cmp_privilege(_left: &OriginCaller, _right: &OriginCaller) -> Option<Ordering> {
- Some(Ordering::Equal)
- }
-}
-
-impl pallet_unique_scheduler::Config for Runtime {
- type Event = Event;
- type Origin = Origin;
- type Currency = Balances;
- type PalletsOrigin = OriginCaller;
- type Call = Call;
- type MaximumWeight = MaximumSchedulerWeight;
- type ScheduleOrigin = EnsureSigned<AccountId>;
- type MaxScheduledPerBlock = MaxScheduledPerBlock;
- type WeightInfo = ();
- type CallExecutor = SchedulerPaymentExecutor;
- type OriginPrivilegeCmp = OriginPrivilegeCmp;
- type PreimageProvider = ();
- type NoPreimagePostponement = NoPreimagePostponement;
-}
-
-type EvmSponsorshipHandler = (
- UniqueEthSponsorshipHandler<Runtime>,
- pallet_evm_contract_helpers::HelpersContractSponsoring<Runtime>,
-);
-type SponsorshipHandler = (
- UniqueSponsorshipHandler<Runtime>,
- //pallet_contract_helpers::ContractSponsorshipHandler<Runtime>,
- pallet_evm_transaction_payment::BridgeSponsorshipHandler<Runtime>,
-);
-
-impl pallet_evm_transaction_payment::Config for Runtime {
- type EvmSponsorshipHandler = EvmSponsorshipHandler;
- type Currency = Balances;
-}
-
-impl pallet_charge_transaction::Config for Runtime {
- type SponsorshipHandler = SponsorshipHandler;
-}
-
-// impl pallet_contract_helpers::Config for Runtime {
-// type DefaultSponsoringRateLimit = DefaultSponsoringRateLimit;
-// }
-
-parameter_types! {
- // 0x842899ECF380553E8a4de75bF534cdf6fBF64049
- pub const HelpersContractAddress: H160 = H160([
- 0x84, 0x28, 0x99, 0xec, 0xf3, 0x80, 0x55, 0x3e, 0x8a, 0x4d, 0xe7, 0x5b, 0xf5, 0x34, 0xcd, 0xf6, 0xfb, 0xf6, 0x40, 0x49,
- ]);
-
- // 0x6c4e9fe1ae37a41e93cee429e8e1881abdcbb54f
- pub const EvmCollectionHelpersAddress: H160 = H160([
- 0x6c, 0x4e, 0x9f, 0xe1, 0xae, 0x37, 0xa4, 0x1e, 0x93, 0xce, 0xe4, 0x29, 0xe8, 0xe1, 0x88, 0x1a, 0xbd, 0xcb, 0xb5, 0x4f,
- ]);
-}
-
-impl pallet_evm_contract_helpers::Config for Runtime {
- type ContractAddress = HelpersContractAddress;
- type DefaultSponsoringRateLimit = DefaultSponsoringRateLimit;
-}
-
-construct_runtime!(
- pub enum Runtime where
- Block = Block,
- NodeBlock = opaque::Block,
- UncheckedExtrinsic = UncheckedExtrinsic
- {
- ParachainSystem: cumulus_pallet_parachain_system::{Pallet, Call, Config, Storage, Inherent, Event<T>, ValidateUnsigned} = 20,
- ParachainInfo: parachain_info::{Pallet, Storage, Config} = 21,
-
- Aura: pallet_aura::{Pallet, Config<T>} = 22,
- AuraExt: cumulus_pallet_aura_ext::{Pallet, Config} = 23,
-
- Balances: pallet_balances::{Pallet, Call, Storage, Config<T>, Event<T>} = 30,
- RandomnessCollectiveFlip: pallet_randomness_collective_flip::{Pallet, Storage} = 31,
- Timestamp: pallet_timestamp::{Pallet, Call, Storage, Inherent} = 32,
- TransactionPayment: pallet_transaction_payment::{Pallet, Storage} = 33,
- Treasury: pallet_treasury::{Pallet, Call, Storage, Config, Event<T>} = 34,
- Sudo: pallet_sudo::{Pallet, Call, Storage, Config<T>, Event<T>} = 35,
- System: frame_system::{Pallet, Call, Storage, Config, Event<T>} = 36,
- Vesting: orml_vesting::{Pallet, Storage, Call, Event<T>, Config<T>} = 37,
- // Vesting: pallet_vesting::{Pallet, Call, Config<T>, Storage, Event<T>} = 37,
- // Contracts: pallet_contracts::{Pallet, Call, Storage, Event<T>} = 38,
-
- // XCM helpers.
- XcmpQueue: cumulus_pallet_xcmp_queue::{Pallet, Call, Storage, Event<T>} = 50,
- PolkadotXcm: pallet_xcm::{Pallet, Call, Event<T>, Origin} = 51,
- CumulusXcm: cumulus_pallet_xcm::{Pallet, Call, Event<T>, Origin} = 52,
- DmpQueue: cumulus_pallet_dmp_queue::{Pallet, Call, Storage, Event<T>} = 53,
-
- // Unique Pallets
- Inflation: pallet_inflation::{Pallet, Call, Storage} = 60,
- Unique: pallet_unique::{Pallet, Call, Storage, Event<T>} = 61,
- Scheduler: pallet_unique_scheduler::{Pallet, Call, Storage, Event<T>} = 62,
- // free = 63
- Charging: pallet_charge_transaction::{Pallet, Call, Storage } = 64,
- // ContractHelpers: pallet_contract_helpers::{Pallet, Call, Storage} = 65,
- Common: pallet_common::{Pallet, Storage, Event<T>} = 66,
- Fungible: pallet_fungible::{Pallet, Storage} = 67,
- Refungible: pallet_refungible::{Pallet, Storage} = 68,
- Nonfungible: pallet_nonfungible::{Pallet, Storage} = 69,
- Structure: pallet_structure::{Pallet, Call, Storage, Event<T>} = 70,
-
- // Frontier
- EVM: pallet_evm::{Pallet, Config, Call, Storage, Event<T>} = 100,
- Ethereum: pallet_ethereum::{Pallet, Config, Call, Storage, Event, Origin} = 101,
-
- EvmCoderSubstrate: pallet_evm_coder_substrate::{Pallet, Storage} = 150,
- EvmContractHelpers: pallet_evm_contract_helpers::{Pallet, Storage} = 151,
- EvmTransactionPayment: pallet_evm_transaction_payment::{Pallet} = 152,
- EvmMigration: pallet_evm_migration::{Pallet, Call, Storage} = 153,
- }
-);
-
-pub struct TransactionConverter;
-
-impl fp_rpc::ConvertTransaction<UncheckedExtrinsic> for TransactionConverter {
- fn convert_transaction(&self, transaction: pallet_ethereum::Transaction) -> UncheckedExtrinsic {
- UncheckedExtrinsic::new_unsigned(
- pallet_ethereum::Call::<Runtime>::transact { transaction }.into(),
- )
- }
-}
-
-impl fp_rpc::ConvertTransaction<opaque::UncheckedExtrinsic> for TransactionConverter {
- fn convert_transaction(
- &self,
- transaction: pallet_ethereum::Transaction,
- ) -> opaque::UncheckedExtrinsic {
- let extrinsic = UncheckedExtrinsic::new_unsigned(
- pallet_ethereum::Call::<Runtime>::transact { transaction }.into(),
- );
- let encoded = extrinsic.encode();
- opaque::UncheckedExtrinsic::decode(&mut &encoded[..])
- .expect("Encoded extrinsic is always valid")
- }
-}
-
-/// The address format for describing accounts.
-pub type Address = sp_runtime::MultiAddress<AccountId, ()>;
-/// Block header type as expected by this runtime.
-pub type Header = generic::Header<BlockNumber, BlakeTwo256>;
-/// Block type as expected by this runtime.
-pub type Block = generic::Block<Header, UncheckedExtrinsic>;
-/// A Block signed with a Justification
-pub type SignedBlock = generic::SignedBlock<Block>;
-/// BlockId type as expected by this runtime.
-pub type BlockId = generic::BlockId<Block>;
-/// The SignedExtension to the basic transaction logic.
-pub type SignedExtra = (
- frame_system::CheckSpecVersion<Runtime>,
- // system::CheckTxVersion<Runtime>,
- frame_system::CheckGenesis<Runtime>,
- frame_system::CheckEra<Runtime>,
- frame_system::CheckNonce<Runtime>,
- frame_system::CheckWeight<Runtime>,
- pallet_charge_transaction::ChargeTransactionPayment<Runtime>,
- //pallet_contract_helpers::ContractHelpersExtension<Runtime>,
- pallet_ethereum::FakeTransactionFinalizer<Runtime>,
-);
-pub type SignedExtraScheduler = (
- frame_system::CheckSpecVersion<Runtime>,
- frame_system::CheckGenesis<Runtime>,
- frame_system::CheckEra<Runtime>,
- frame_system::CheckNonce<Runtime>,
- frame_system::CheckWeight<Runtime>,
- // pallet_charge_transaction::ChargeTransactionPayment<Runtime>,
-);
-/// Unchecked extrinsic type as expected by this runtime.
-pub type UncheckedExtrinsic =
- fp_self_contained::UncheckedExtrinsic<Address, Call, Signature, SignedExtra>;
-/// Extrinsic type that has already been checked.
-pub type CheckedExtrinsic = fp_self_contained::CheckedExtrinsic<AccountId, Call, SignedExtra, H160>;
-/// Executive: handles dispatch to the various modules.
-pub type Executive = frame_executive::Executive<
- Runtime,
- Block,
- frame_system::ChainContext<Runtime>,
- Runtime,
- AllPalletsReversedWithSystemFirst,
->;
-
-impl_opaque_keys! {
- pub struct SessionKeys {
- pub aura: Aura,
- }
-}
-
-impl fp_self_contained::SelfContainedCall for Call {
- type SignedInfo = H160;
-
- fn is_self_contained(&self) -> bool {
- match self {
- Call::Ethereum(call) => call.is_self_contained(),
- _ => false,
- }
- }
-
- fn check_self_contained(&self) -> Option<Result<Self::SignedInfo, TransactionValidityError>> {
- match self {
- Call::Ethereum(call) => call.check_self_contained(),
- _ => None,
- }
- }
-
- fn validate_self_contained(
- &self,
- info: &Self::SignedInfo,
- dispatch_info: &DispatchInfoOf<Call>,
- len: usize,
- ) -> Option<TransactionValidity> {
- match self {
- Call::Ethereum(call) => call.validate_self_contained(info, dispatch_info, len),
- _ => None,
- }
- }
-
- fn pre_dispatch_self_contained(
- &self,
- info: &Self::SignedInfo,
- ) -> Option<Result<(), TransactionValidityError>> {
- match self {
- Call::Ethereum(call) => call.pre_dispatch_self_contained(info),
- _ => None,
- }
- }
-
- fn apply_self_contained(
- self,
- info: Self::SignedInfo,
- ) -> Option<sp_runtime::DispatchResultWithInfo<PostDispatchInfoOf<Self>>> {
- match self {
- call @ Call::Ethereum(pallet_ethereum::Call::transact { .. }) => Some(call.dispatch(
- Origin::from(pallet_ethereum::RawOrigin::EthereumTransaction(info)),
- )),
- _ => None,
- }
- }
-}
-
-macro_rules! dispatch_unique_runtime {
- ($collection:ident.$method:ident($($name:ident),*)) => {{
- let collection = <Runtime as pallet_common::Config>::CollectionDispatch::dispatch(<pallet_common::CollectionHandle<Runtime>>::try_get($collection)?);
- let dispatch = collection.as_dyn();
-
- Ok::<_, DispatchError>(dispatch.$method($($name),*))
- }};
-}
-
-impl_common_runtime_apis! {
- #![custom_apis]
-
- impl rmrk_rpc::RmrkApi<
- Block,
- AccountId,
- RmrkCollectionInfo<AccountId>,
- RmrkInstanceInfo<AccountId>,
- RmrkResourceInfo,
- RmrkPropertyInfo,
- RmrkBaseInfo<AccountId>,
- RmrkPartType,
- RmrkTheme
- > for Runtime {
- fn last_collection_idx() -> Result<RmrkCollectionId, DispatchError> {
- Ok(Default::default())
- }
-
- fn collection_by_id(_collection_id: RmrkCollectionId) -> Result<Option<RmrkCollectionInfo<AccountId>>, DispatchError> {
- Ok(Default::default())
- }
-
- fn nft_by_id(_collection_id: RmrkCollectionId, _nft_by_id: RmrkNftId) -> Result<Option<RmrkInstanceInfo<AccountId>>, DispatchError> {
- Ok(Default::default())
- }
-
- fn account_tokens(_account_id: AccountId, _collection_id: RmrkCollectionId) -> Result<Vec<RmrkNftId>, DispatchError> {
- Ok(Default::default())
- }
-
- fn nft_children(_collection_id: RmrkCollectionId, _nft_id: RmrkNftId) -> Result<Vec<RmrkNftChild>, DispatchError> {
- Ok(Default::default())
- }
-
- fn collection_properties(_collection_id: RmrkCollectionId, _filter_keys: Option<Vec<RmrkPropertyKey>>) -> Result<Vec<RmrkPropertyInfo>, DispatchError> {
- Ok(Default::default())
- }
-
- fn nft_properties(_collection_id: RmrkCollectionId, _nft_id: RmrkNftId, _filter_keys: Option<Vec<RmrkPropertyKey>>) -> Result<Vec<RmrkPropertyInfo>, DispatchError> {
- Ok(Default::default())
- }
-
- fn nft_resources(_collection_id: RmrkCollectionId, _nft_id: RmrkNftId) -> Result<Vec<RmrkResourceInfo>, DispatchError> {
- Ok(Default::default())
- }
-
- fn nft_resource_priority(_collection_id: RmrkCollectionId, _nft_id: RmrkNftId, _resource_id: RmrkResourceId) -> Result<Option<u32>, DispatchError> {
- Ok(Default::default())
- }
-
- fn base(_base_id: RmrkBaseId) -> Result<Option<RmrkBaseInfo<AccountId>>, DispatchError> {
- Ok(Default::default())
- }
-
- fn base_parts(_base_id: RmrkBaseId) -> Result<Vec<RmrkPartType>, DispatchError> {
- Ok(Default::default())
- }
-
- fn theme_names(_base_id: RmrkBaseId) -> Result<Vec<RmrkThemeName>, DispatchError> {
- Ok(Default::default())
- }
-
- fn theme(_base_id: RmrkBaseId, _theme_name: RmrkThemeName, _filter_keys: Option<Vec<RmrkPropertyKey>>) -> Result<Option<RmrkTheme>, DispatchError> {
- Ok(Default::default())
- }
- }
-}
-
-struct CheckInherents;
-
-impl cumulus_pallet_parachain_system::CheckInherents<Block> for CheckInherents {
- fn check_inherents(
- block: &Block,
- relay_state_proof: &cumulus_pallet_parachain_system::RelayChainStateProof,
- ) -> sp_inherents::CheckInherentsResult {
- let relay_chain_slot = relay_state_proof
- .read_slot()
- .expect("Could not read the relay chain slot from the proof");
-
- let inherent_data =
- cumulus_primitives_timestamp::InherentDataProvider::from_relay_chain_slot_and_duration(
- relay_chain_slot,
- sp_std::time::Duration::from_secs(6),
- )
- .create_inherent_data()
- .expect("Could not create the timestamp inherent data");
-
- inherent_data.check_extrinsics(block)
- }
-}
+impl_common_runtime_apis!();
cumulus_pallet_parachain_system::register_validate_block!(
Runtime = Runtime,
tests/src/approve.test.tsdiffbeforeafterboth--- a/tests/src/approve.test.ts
+++ b/tests/src/approve.test.ts
@@ -32,6 +32,8 @@
getCreatedCollectionCount,
transferFromExpectSuccess,
transferFromExpectFail,
+ requirePallets,
+ Pallets,
} from './util/helpers';
chai.use(chaiAsPromised);
@@ -49,34 +51,44 @@
});
});
- it('Execute the extrinsic and check approvedList', async () => {
+ it('[nft] Execute the extrinsic and check approvedList', async () => {
const nftCollectionId = await createCollectionExpectSuccess();
- // nft
const newNftTokenId = await createItemExpectSuccess(alice, nftCollectionId, 'NFT');
await approveExpectSuccess(nftCollectionId, newNftTokenId, alice, bob.address);
- // fungible
+ });
+
+ it('[fungible] Execute the extrinsic and check approvedList', async () => {
const fungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});
const newFungibleTokenId = await createItemExpectSuccess(alice, fungibleCollectionId, 'Fungible');
await approveExpectSuccess(fungibleCollectionId, newFungibleTokenId, alice, bob.address);
- // reFungible
+ });
+
+ it('[refungible] Execute the extrinsic and check approvedList', async function() {
+ await requirePallets(this, [Pallets.ReFungible]);
+
const reFungibleCollectionId =
await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
const newReFungibleTokenId = await createItemExpectSuccess(alice, reFungibleCollectionId, 'ReFungible');
await approveExpectSuccess(reFungibleCollectionId, newReFungibleTokenId, alice, bob.address);
});
- it('Remove approval by using 0 amount', async () => {
+ it('[nft] Remove approval by using 0 amount', async () => {
const nftCollectionId = await createCollectionExpectSuccess();
- // nft
const newNftTokenId = await createItemExpectSuccess(alice, nftCollectionId, 'NFT');
await approveExpectSuccess(nftCollectionId, newNftTokenId, alice, bob.address, 1);
await approveExpectSuccess(nftCollectionId, newNftTokenId, alice, bob.address, 0);
- // fungible
+ });
+
+ it('[fungible] Remove approval by using 0 amount', async () => {
const fungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});
const newFungibleTokenId = await createItemExpectSuccess(alice, fungibleCollectionId, 'Fungible');
await approveExpectSuccess(fungibleCollectionId, newFungibleTokenId, alice, bob.address, 1);
await approveExpectSuccess(fungibleCollectionId, newFungibleTokenId, alice, bob.address, 0);
- // reFungible
+ });
+
+ it('[refungible] Remove approval by using 0 amount', async function() {
+ await requirePallets(this, [Pallets.ReFungible]);
+
const reFungibleCollectionId =
await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
const newReFungibleTokenId = await createItemExpectSuccess(alice, reFungibleCollectionId, 'ReFungible');
@@ -117,7 +129,9 @@
await approveExpectSuccess(collectionId, itemId, bob, charlie.address);
});
- it('ReFungible up to an approved amount', async () => {
+ it('ReFungible up to an approved amount', async function() {
+ await requirePallets(this, [Pallets.ReFungible]);
+
const collectionId = await createCollectionExpectSuccess({mode:{type: 'ReFungible'}});
const itemId = await createItemExpectSuccess(alice, collectionId, 'ReFungible', bob.address);
await approveExpectSuccess(collectionId, itemId, bob, charlie.address);
@@ -151,7 +165,9 @@
await transferFromExpectSuccess(collectionId, itemId, charlie, bob, alice, 1, 'Fungible');
});
- it('ReFungible up to an approved amount', async () => {
+ it('ReFungible up to an approved amount', async function() {
+ await requirePallets(this, [Pallets.ReFungible]);
+
const collectionId = await createCollectionExpectSuccess({mode:{type: 'ReFungible'}});
const itemId = await createItemExpectSuccess(alice, collectionId, 'ReFungible', bob.address);
await approveExpectSuccess(collectionId, itemId, bob, charlie.address);
@@ -188,7 +204,9 @@
await transferFromExpectFail(collectionId, itemId, charlie, bob, alice, 1);
});
- it('ReFungible up to an approved amount', async () => {
+ it('ReFungible up to an approved amount', async function() {
+ await requirePallets(this, [Pallets.ReFungible]);
+
const collectionId = await createCollectionExpectSuccess({mode:{type: 'ReFungible'}});
const itemId = await createItemExpectSuccess(alice, collectionId, 'ReFungible', bob.address);
await approveExpectSuccess(collectionId, itemId, bob, charlie.address);
@@ -250,7 +268,9 @@
await transferFromExpectFail(fungibleCollectionId, newFungibleTokenId, bob, bob, charlie, 1);
});
- it('ReFungible', async () => {
+ it('ReFungible', async function() {
+ await requirePallets(this, [Pallets.ReFungible]);
+
const reFungibleCollectionId =
await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
const newReFungibleTokenId = await createItemExpectSuccess(alice, reFungibleCollectionId, 'ReFungible');
@@ -285,7 +305,9 @@
await approveExpectFail(fungibleCollectionId, newFungibleTokenId, bob, charlie, 11);
});
- it('ReFungible', async () => {
+ it('ReFungible', async function() {
+ await requirePallets(this, [Pallets.ReFungible]);
+
const reFungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
const newReFungibleTokenId = await createItemExpectSuccess(alice, reFungibleCollectionId, 'ReFungible');
await approveExpectFail(reFungibleCollectionId, newReFungibleTokenId, bob, charlie, 101);
@@ -325,7 +347,9 @@
await transferFromExpectSuccess(collectionId, itemId, bob, dave, alice, 1, 'Fungible');
});
- it('ReFungible up to an approved amount', async () => {
+ it('ReFungible up to an approved amount', async function() {
+ await requirePallets(this, [Pallets.ReFungible]);
+
const collectionId = await createCollectionExpectSuccess({mode:{type: 'ReFungible'}});
await setCollectionLimitsExpectSuccess(alice, collectionId, {ownerCanTransfer: true});
const itemId = await createItemExpectSuccess(alice, collectionId, 'ReFungible', charlie.address);
@@ -422,63 +446,87 @@
});
});
- it('Approve for a collection that does not exist', async () => {
+ it('[nft] Approve for a collection that does not exist', async () => {
await usingApi(async (api: ApiPromise) => {
- // nft
const nftCollectionCount = await getCreatedCollectionCount(api);
await approveExpectFail(nftCollectionCount + 1, 1, alice, bob);
- // fungible
+ });
+ });
+
+ it('[fungible] Approve for a collection that does not exist', async () => {
+ await usingApi(async (api: ApiPromise) => {
const fungibleCollectionCount = await getCreatedCollectionCount(api);
await approveExpectFail(fungibleCollectionCount + 1, 0, alice, bob);
- // reFungible
+ });
+ });
+
+ it('[refungible] Approve for a collection that does not exist', async function() {
+ await requirePallets(this, [Pallets.ReFungible]);
+
+ await usingApi(async (api: ApiPromise) => {
const reFungibleCollectionCount = await getCreatedCollectionCount(api);
await approveExpectFail(reFungibleCollectionCount + 1, 1, alice, bob);
});
});
- it('Approve for a collection that was destroyed', async () => {
- // nft
+ it('[nft] Approve for a collection that was destroyed', async () => {
const nftCollectionId = await createCollectionExpectSuccess();
await destroyCollectionExpectSuccess(nftCollectionId);
await approveExpectFail(nftCollectionId, 1, alice, bob);
- // fungible
+ });
+
+ it('Approve for a collection that was destroyed', async () => {
const fungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});
await destroyCollectionExpectSuccess(fungibleCollectionId);
await approveExpectFail(fungibleCollectionId, 0, alice, bob);
- // reFungible
+ });
+
+ it('[refungible] Approve for a collection that was destroyed', async function() {
+ await requirePallets(this, [Pallets.ReFungible]);
+
const reFungibleCollectionId =
await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
await destroyCollectionExpectSuccess(reFungibleCollectionId);
await approveExpectFail(reFungibleCollectionId, 1, alice, bob);
});
- it('Approve transfer of a token that does not exist', async () => {
- // nft
+ it('[nft] Approve transfer of a token that does not exist', async () => {
const nftCollectionId = await createCollectionExpectSuccess();
await approveExpectFail(nftCollectionId, 2, alice, bob);
- // reFungible
+ });
+
+ it('[refungible] Approve transfer of a token that does not exist', async function() {
+ await requirePallets(this, [Pallets.ReFungible]);
+
const reFungibleCollectionId =
await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
await approveExpectFail(reFungibleCollectionId, 2, alice, bob);
});
- it('Approve using the address that does not own the approved token', async () => {
+ it('[nft] Approve using the address that does not own the approved token', async () => {
const nftCollectionId = await createCollectionExpectSuccess();
- // nft
const newNftTokenId = await createItemExpectSuccess(alice, nftCollectionId, 'NFT');
await approveExpectFail(nftCollectionId, newNftTokenId, bob, alice);
- // fungible
+ });
+
+ it('[fungible] Approve using the address that does not own the approved token', async () => {
const fungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});
const newFungibleTokenId = await createItemExpectSuccess(alice, fungibleCollectionId, 'Fungible');
await approveExpectFail(fungibleCollectionId, newFungibleTokenId, bob, alice);
- // reFungible
+ });
+
+ it('[refungible] Approve using the address that does not own the approved token', async function() {
+ await requirePallets(this, [Pallets.ReFungible]);
+
const reFungibleCollectionId =
await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
const newReFungibleTokenId = await createItemExpectSuccess(alice, reFungibleCollectionId, 'ReFungible');
await approveExpectFail(reFungibleCollectionId, newReFungibleTokenId, bob, alice);
});
- it('should fail if approved more ReFungibles than owned', async () => {
+ it('should fail if approved more ReFungibles than owned', async function() {
+ await requirePallets(this, [Pallets.ReFungible]);
+
const nftCollectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
const newNftTokenId = await createItemExpectSuccess(alice, nftCollectionId, 'ReFungible');
await transferExpectSuccess(nftCollectionId, newNftTokenId, alice, bob, 100, 'ReFungible');
tests/src/burnItem.test.tsdiffbeforeafterboth--- a/tests/src/burnItem.test.ts
+++ b/tests/src/burnItem.test.ts
@@ -25,6 +25,8 @@
getBalance,
setCollectionLimitsExpectSuccess,
isTokenExists,
+ requirePallets,
+ Pallets,
} from './util/helpers';
import chai from 'chai';
@@ -80,7 +82,9 @@
});
});
- it('Burn item in ReFungible collection', async () => {
+ it('Burn item in ReFungible collection', async function() {
+ await requirePallets(this, [Pallets.ReFungible]);
+
const createMode = 'ReFungible';
const collectionId = await createCollectionExpectSuccess({mode: {type: createMode}});
const tokenId = await createItemExpectSuccess(alice, collectionId, createMode);
@@ -99,7 +103,9 @@
});
});
- it('Burn owned portion of item in ReFungible collection', async () => {
+ it('Burn owned portion of item in ReFungible collection', async function() {
+ await requirePallets(this, [Pallets.ReFungible]);
+
const createMode = 'ReFungible';
const collectionId = await createCollectionExpectSuccess({mode: {type: createMode}});
const tokenId = await createItemExpectSuccess(alice, collectionId, createMode);
@@ -189,7 +195,9 @@
});
// TODO: burnFrom
- it('Burn item in ReFungible collection', async () => {
+ it('Burn item in ReFungible collection', async function() {
+ await requirePallets(this, [Pallets.ReFungible]);
+
const createMode = 'ReFungible';
const collectionId = await createCollectionExpectSuccess({mode: {type: createMode}});
await setCollectionLimitsExpectSuccess(alice, collectionId, {ownerCanTransfer: true});
tests/src/confirmSponsorship.test.tsdiffbeforeafterboth--- a/tests/src/confirmSponsorship.test.ts
+++ b/tests/src/confirmSponsorship.test.ts
@@ -33,6 +33,8 @@
addCollectionAdminExpectSuccess,
getCreatedCollectionCount,
UNIQUE,
+ requirePallets,
+ Pallets,
} from './util/helpers';
import {IKeyringPair} from '@polkadot/types/types';
@@ -124,7 +126,9 @@
});
});
- it('ReFungible: Transfer fees are paid by the sponsor after confirmation', async () => {
+ it('ReFungible: Transfer fees are paid by the sponsor after confirmation', async function() {
+ await requirePallets(this, [Pallets.ReFungible]);
+
const collectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
await setCollectionSponsorExpectSuccess(collectionId, bob.address);
await confirmSponsorshipExpectSuccess(collectionId, '//Bob');
@@ -252,7 +256,9 @@
});
});
- it('ReFungible: Sponsoring is rate limited', async () => {
+ it('ReFungible: Sponsoring is rate limited', async function() {
+ await requirePallets(this, [Pallets.ReFungible]);
+
const collectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
await setCollectionSponsorExpectSuccess(collectionId, bob.address);
await confirmSponsorshipExpectSuccess(collectionId, '//Bob');
tests/src/createCollection.test.tsdiffbeforeafterboth--- a/tests/src/createCollection.test.ts
+++ b/tests/src/createCollection.test.ts
@@ -16,7 +16,7 @@
import {expect} from 'chai';
import usingApi, {executeTransaction, submitTransactionAsync} from './substrate/substrate-api';
-import {createCollectionWithPropsExpectFailure, createCollectionExpectFailure, createCollectionExpectSuccess, getCreateCollectionResult, getDetailedCollectionInfo, createCollectionWithPropsExpectSuccess} from './util/helpers';
+import {createCollectionWithPropsExpectFailure, createCollectionExpectFailure, createCollectionExpectSuccess, getCreateCollectionResult, getDetailedCollectionInfo, createCollectionWithPropsExpectSuccess, requirePallets, Pallets} from './util/helpers';
describe('integration test: ext. createCollection():', () => {
it('Create new NFT collection', async () => {
@@ -34,7 +34,9 @@
it('Create new Fungible collection', async () => {
await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});
});
- it('Create new ReFungible collection', async () => {
+ it('Create new ReFungible collection', async function() {
+ await requirePallets(this, [Pallets.ReFungible]);
+
await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
});
tests/src/createItem.test.tsdiffbeforeafterboth--- a/tests/src/createItem.test.ts
+++ b/tests/src/createItem.test.ts
@@ -29,6 +29,8 @@
itApi,
normalizeAccountId,
getCreateItemResult,
+ requirePallets,
+ Pallets,
} from './util/helpers';
const expect = chai.expect;
@@ -79,7 +81,9 @@
}
});
- it('Create new item in ReFungible collection', async () => {
+ it('Create new item in ReFungible collection', async function() {
+ await requirePallets(this, [Pallets.ReFungible]);
+
const createMode = 'ReFungible';
const newCollectionID = await createCollectionExpectSuccess({mode: {type: createMode}});
await createItemExpectSuccess(alice, newCollectionID, createMode);
@@ -96,7 +100,9 @@
await addCollectionAdminExpectSuccess(alice, newCollectionID, bob.address);
await createItemExpectSuccess(bob, newCollectionID, createMode);
});
- it('Create new item in ReFungible collection with collection admin permissions', async () => {
+ it('Create new item in ReFungible collection with collection admin permissions', async function() {
+ await requirePallets(this, [Pallets.ReFungible]);
+
const createMode = 'ReFungible';
const newCollectionID = await createCollectionExpectSuccess({mode: {type: createMode}});
await addCollectionAdminExpectSuccess(alice, newCollectionID, bob.address);
@@ -175,7 +181,9 @@
});
});
- it('Check total pieces of ReFungible token', async () => {
+ it('Check total pieces of ReFungible token', async function() {
+ await requirePallets(this, [Pallets.ReFungible]);
+
await usingApi(async api => {
const createMode = 'ReFungible';
const createCollectionResult = await createCollection(api, alice, {mode: {type: createMode}});
@@ -219,7 +227,9 @@
const newCollectionID = await createCollectionExpectSuccess({mode: {type: createMode, decimalPoints: 0}});
await expect(createItemExpectSuccess(bob, newCollectionID, createMode)).to.be.rejected;
});
- it('Regular user cannot create new item in ReFungible collection', async () => {
+ it('Regular user cannot create new item in ReFungible collection', async function() {
+ await requirePallets(this, [Pallets.ReFungible]);
+
const createMode = 'ReFungible';
const newCollectionID = await createCollectionExpectSuccess({mode: {type: createMode}});
await expect(createItemExpectSuccess(bob, newCollectionID, createMode)).to.be.rejected;
@@ -296,7 +306,9 @@
});
});
- it('Check total pieces for invalid Refungible token', async () => {
+ it('Check total pieces for invalid Refungible token', async function() {
+ await requirePallets(this, [Pallets.ReFungible]);
+
await usingApi(async api => {
const createCollectionResult = await createCollection(api, alice, {mode: {type: 'ReFungible'}});
const collectionId = createCollectionResult.collectionId;
tests/src/createMultipleItems.test.tsdiffbeforeafterboth--- a/tests/src/createMultipleItems.test.ts
+++ b/tests/src/createMultipleItems.test.ts
@@ -33,6 +33,9 @@
createCollectionWithPropsExpectSuccess,
createMultipleItemsWithPropsExpectSuccess,
getTokenProperties,
+ requirePallets,
+ Pallets,
+ checkPalletsPresence,
} from './util/helpers';
chai.use(chaiAsPromised);
@@ -91,7 +94,9 @@
});
});
- it('Create 0x31, 0x32, 0x33 items in active ReFungible collection and verify tokens data in chain', async () => {
+ it('Create 0x31, 0x32, 0x33 items in active ReFungible collection and verify tokens data in chain', async function() {
+ await requirePallets(this, [Pallets.ReFungible]);
+
await usingApi(async (api, privateKeyWrapper) => {
const collectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
const itemsListIndexBefore = await getLastTokenId(api, collectionId);
@@ -272,7 +277,9 @@
});
});
- it('Create 0x31, 0x32, 0x33 items in active ReFungible collection and verify tokens data in chain', async () => {
+ it('Create 0x31, 0x32, 0x33 items in active ReFungible collection and verify tokens data in chain', async function() {
+ await requirePallets(this, [Pallets.ReFungible]);
+
await usingApi(async (api: ApiPromise) => {
const collectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
const itemsListIndexBefore = await getLastTokenId(api, collectionId);
@@ -335,7 +342,9 @@
});
});
- it('Regular user cannot create items in active ReFungible collection', async () => {
+ it('Regular user cannot create items in active ReFungible collection', async function() {
+ await requirePallets(this, [Pallets.ReFungible]);
+
await usingApi(async (api: ApiPromise) => {
const collectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
const itemsListIndexBefore = await getLastTokenId(api, collectionId);
@@ -358,9 +367,8 @@
});
});
- it('Create NFT and Re-fungible tokens that has reached the maximum data limit', async () => {
+ it('Create NFTs that has reached the maximum data limit', async function() {
await usingApi(async (api, privateKeyWrapper) => {
- // NFT
const collectionId = await createCollectionWithPropsExpectSuccess({
propPerm: [{key: 'key', permission: {mutable: true, collectionAdmin: true, tokenOwner: true}}],
});
@@ -372,8 +380,13 @@
];
const createMultipleItemsTx = api.tx.unique.createMultipleItems(collectionId, normalizeAccountId(alice.address), args);
await expect(submitTransactionExpectFailAsync(alice, createMultipleItemsTx)).to.be.rejected;
+ });
+ });
- // ReFungible
+ it('Create Refungible tokens that has reached the maximum data limit', async function() {
+ await requirePallets(this, [Pallets.ReFungible]);
+
+ await usingApi(async api => {
const collectionIdReFungible =
await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
{
@@ -402,8 +415,15 @@
it('Create tokens with different types', async () => {
await usingApi(async (api: ApiPromise) => {
const collectionId = await createCollectionExpectSuccess();
+
+ const types = ['NFT', 'Fungible'];
+
+ if (await checkPalletsPresence([Pallets.ReFungible])) {
+ types.push('ReFungible');
+ }
+
const createMultipleItemsTx = api.tx.unique
- .createMultipleItems(collectionId, normalizeAccountId(alice.address), ['NFT', 'Fungible', 'ReFungible']);
+ .createMultipleItems(collectionId, normalizeAccountId(alice.address), types);
await expect(executeTransaction(api, alice, createMultipleItemsTx)).to.be.rejectedWith(/nonfungible\.NotNonfungibleDataUsedToMintFungibleCollectionToken/);
// garbage collection :-D // lol
await destroyCollectionExpectSuccess(collectionId);
tests/src/createMultipleItemsEx.test.tsdiffbeforeafterboth--- a/tests/src/createMultipleItemsEx.test.ts
+++ b/tests/src/createMultipleItemsEx.test.ts
@@ -16,7 +16,7 @@
import {expect} from 'chai';
import usingApi, {executeTransaction} from './substrate/substrate-api';
-import {addCollectionAdminExpectSuccess, createCollectionExpectSuccess, createCollectionWithPropsExpectSuccess, getBalance, getLastTokenId, getTokenProperties} from './util/helpers';
+import {addCollectionAdminExpectSuccess, createCollectionExpectSuccess, createCollectionWithPropsExpectSuccess, getBalance, getLastTokenId, getTokenProperties, requirePallets, Pallets} from './util/helpers';
describe('Integration Test: createMultipleItemsEx', () => {
it('can initialize multiple NFT with different owners', async () => {
@@ -146,7 +146,9 @@
});
});
- it('can initialize an RFT with multiple owners', async () => {
+ it('can initialize an RFT with multiple owners', async function() {
+ await requirePallets(this, [Pallets.ReFungible]);
+
await usingApi(async (api, privateKeyWrapper) => {
const alice = privateKeyWrapper('//Alice');
const bob = privateKeyWrapper('//Bob');
@@ -178,7 +180,9 @@
});
});
- it('can initialize multiple RFTs with the same owner', async () => {
+ it('can initialize multiple RFTs with the same owner', async function() {
+ await requirePallets(this, [Pallets.ReFungible]);
+
await usingApi(async (api, privateKeyWrapper) => {
const alice = privateKeyWrapper('//Alice');
const collection = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
@@ -389,7 +393,9 @@
});
});
- it('fails when trying to set multiple owners when creating multiple refungibles', async () => {
+ it('fails when trying to set multiple owners when creating multiple refungibles', async function() {
+ await requirePallets(this, [Pallets.ReFungible]);
+
const collection = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
await usingApi(async (api, privateKeyWrapper) => {
tests/src/destroyCollection.test.tsdiffbeforeafterboth--- a/tests/src/destroyCollection.test.ts
+++ b/tests/src/destroyCollection.test.ts
@@ -25,6 +25,8 @@
addCollectionAdminExpectSuccess,
getCreatedCollectionCount,
createItemExpectSuccess,
+ requirePallets,
+ Pallets,
} from './util/helpers';
chai.use(chaiAsPromised);
@@ -38,7 +40,9 @@
const collectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});
await destroyCollectionExpectSuccess(collectionId);
});
- it('ReFungible collection can be destroyed', async () => {
+ it('ReFungible collection can be destroyed', async function() {
+ await requirePallets(this, [Pallets.ReFungible]);
+
const collectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
await destroyCollectionExpectSuccess(collectionId);
});
tests/src/eth/createRFTCollection.test.tsdiffbeforeafterboth--- a/tests/src/eth/createRFTCollection.test.ts
+++ b/tests/src/eth/createRFTCollection.test.ts
@@ -16,7 +16,7 @@
import {evmToAddress} from '@polkadot/util-crypto';
import {expect} from 'chai';
-import {getCreatedCollectionCount, getDetailedCollectionInfo} from '../util/helpers';
+import {getCreatedCollectionCount, getDetailedCollectionInfo, requirePallets, Pallets} from '../util/helpers';
import {
evmCollectionHelpers,
collectionIdToAddress,
@@ -28,6 +28,10 @@
} from './util/helpers';
describe('Create RFT collection from EVM', () => {
+ before(async function() {
+ await requirePallets(this, [Pallets.ReFungible]);
+ });
+
itWeb3('Create collection', async ({api, web3, privateKeyWrapper}) => {
const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
const collectionHelper = evmCollectionHelpers(web3, owner);
@@ -146,6 +150,10 @@
});
describe('(!negative tests!) Create RFT collection from EVM', () => {
+ before(async function() {
+ await requirePallets(this, [Pallets.ReFungible]);
+ });
+
itWeb3('(!negative test!) Create collection (bad lengths)', async ({api, web3, privateKeyWrapper}) => {
const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
const helper = evmCollectionHelpers(web3, owner);
@@ -228,4 +236,4 @@
.setCollectionLimit('badLimit', 'true')
.call()).to.be.rejectedWith('unknown boolean limit "badLimit"');
});
-});
\ No newline at end of file
+});
tests/src/eth/reFungible.test.tsdiffbeforeafterboth--- a/tests/src/eth/reFungible.test.ts
+++ b/tests/src/eth/reFungible.test.ts
@@ -14,12 +14,16 @@
// You should have received a copy of the GNU General Public License
// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-import {createCollectionExpectSuccess, UNIQUE} from '../util/helpers';
+import {createCollectionExpectSuccess, UNIQUE, requirePallets, Pallets} from '../util/helpers';
import {collectionIdToAddress, createEthAccount, createEthAccountWithBalance, evmCollection, evmCollectionHelpers, GAS_ARGS, getCollectionAddressFromResult, itWeb3, normalizeEvents, recordEthFee, recordEvents, tokenIdToAddress} from './util/helpers';
import reFungibleTokenAbi from './reFungibleTokenAbi.json';
import {expect} from 'chai';
describe('Refungible: Information getting', () => {
+ before(async function() {
+ await requirePallets(this, [Pallets.ReFungible]);
+ });
+
itWeb3('totalSupply', async ({api, web3, privateKeyWrapper}) => {
const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
const helper = evmCollectionHelpers(web3, caller);
@@ -120,6 +124,10 @@
});
describe('Refungible: Plain calls', () => {
+ before(async function() {
+ await requirePallets(this, [Pallets.ReFungible]);
+ });
+
itWeb3('Can perform mint()', async ({web3, api, privateKeyWrapper}) => {
const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
const helper = evmCollectionHelpers(web3, owner);
@@ -399,6 +407,10 @@
});
describe('RFT: Fees', () => {
+ before(async function() {
+ await requirePallets(this, [Pallets.ReFungible]);
+ });
+
itWeb3('transferFrom() call fee is less than 0.2UNQ', async ({web3, api, privateKeyWrapper}) => {
const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
const helper = evmCollectionHelpers(web3, caller);
@@ -435,6 +447,10 @@
});
describe('Common metadata', () => {
+ before(async function() {
+ await requirePallets(this, [Pallets.ReFungible]);
+ });
+
itWeb3('Returns collection name', async ({api, web3, privateKeyWrapper}) => {
const collection = await createCollectionExpectSuccess({
name: 'token name',
@@ -462,4 +478,4 @@
expect(symbol).to.equal('TOK');
});
-});
\ No newline at end of file
+});
tests/src/eth/reFungibleToken.test.tsdiffbeforeafterboth--- a/tests/src/eth/reFungibleToken.test.ts
+++ b/tests/src/eth/reFungibleToken.test.ts
@@ -14,7 +14,7 @@
// You should have received a copy of the GNU General Public License
// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-import {approve, createCollection, createRefungibleToken, transfer, transferFrom, UNIQUE} from '../util/helpers';
+import {approve, createCollection, createRefungibleToken, transfer, transferFrom, UNIQUE, requirePallets, Pallets} from '../util/helpers';
import {collectionIdToAddress, createEthAccount, createEthAccountWithBalance, evmCollection, evmCollectionHelpers, GAS_ARGS, getCollectionAddressFromResult, itWeb3, normalizeEvents, recordEthFee, recordEvents, subToEth, tokenIdToAddress, transferBalanceToEth} from './util/helpers';
import reFungibleTokenAbi from './reFungibleTokenAbi.json';
@@ -24,6 +24,10 @@
const expect = chai.expect;
describe('Refungible token: Information getting', () => {
+ before(async function() {
+ await requirePallets(this, [Pallets.ReFungible]);
+ });
+
itWeb3('totalSupply', async ({api, web3, privateKeyWrapper}) => {
const alice = privateKeyWrapper('//Alice');
@@ -75,6 +79,10 @@
// FIXME: Need erc721 for ReFubgible.
describe('Check ERC721 token URI for ReFungible', () => {
+ before(async function() {
+ await requirePallets(this, [Pallets.ReFungible]);
+ });
+
itWeb3('Empty tokenURI', async ({web3, api, privateKeyWrapper}) => {
const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
const helper = evmCollectionHelpers(web3, owner);
@@ -216,6 +224,10 @@
});
describe('Refungible: Plain calls', () => {
+ before(async function() {
+ await requirePallets(this, [Pallets.ReFungible]);
+ });
+
itWeb3('Can perform approve()', async ({web3, api, privateKeyWrapper}) => {
const alice = privateKeyWrapper('//Alice');
@@ -477,6 +489,10 @@
});
describe('Refungible: Fees', () => {
+ before(async function() {
+ await requirePallets(this, [Pallets.ReFungible]);
+ });
+
itWeb3('approve() call fee is less than 0.2UNQ', async ({web3, api, privateKeyWrapper}) => {
const alice = privateKeyWrapper('//Alice');
@@ -532,6 +548,10 @@
});
describe('Refungible: Substrate calls', () => {
+ before(async function() {
+ await requirePallets(this, [Pallets.ReFungible]);
+ });
+
itWeb3('Events emitted for approve()', async ({web3, api, privateKeyWrapper}) => {
const alice = privateKeyWrapper('//Alice');
tests/src/eth/scheduling.test.tsdiffbeforeafterboth--- a/tests/src/eth/scheduling.test.ts
+++ b/tests/src/eth/scheduling.test.ts
@@ -16,9 +16,13 @@
import {expect} from 'chai';
import {createEthAccountWithBalance, deployFlipper, GAS_ARGS, itWeb3, subToEth, transferBalanceToEth} from './util/helpers';
-import {scheduleExpectSuccess, waitNewBlocks} from '../util/helpers';
+import {scheduleExpectSuccess, waitNewBlocks, requirePallets, Pallets} from '../util/helpers';
describe('Scheduing EVM smart contracts', () => {
+ before(async function() {
+ await requirePallets(this, [Pallets.Scheduler]);
+ });
+
itWeb3('Successfully schedules and periodically executes an EVM contract', async ({api, web3, privateKeyWrapper}) => {
const deployer = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
const flipper = await deployFlipper(web3, deployer);
@@ -51,4 +55,4 @@
expect(await flipper.methods.getValue().call()).to.be.equal(initialValue);
}
});
-});
\ No newline at end of file
+});
tests/src/limits.test.tsdiffbeforeafterboth--- a/tests/src/limits.test.ts
+++ b/tests/src/limits.test.ts
@@ -27,6 +27,8 @@
transferExpectSuccess,
getFreeBalance,
waitNewBlocks, burnItemExpectSuccess,
+ requirePallets,
+ Pallets,
} from './util/helpers';
import {expect} from 'chai';
@@ -67,7 +69,9 @@
describe('Number of tokens per address (ReFungible)', () => {
let alice: IKeyringPair;
- before(async () => {
+ before(async function() {
+ await requirePallets(this, [Pallets.ReFungible]);
+
await usingApi(async (api, privateKeyWrapper) => {
alice = privateKeyWrapper('//Alice');
});
@@ -367,7 +371,9 @@
let bob: IKeyringPair;
let charlie: IKeyringPair;
- before(async () => {
+ before(async function() {
+ await requirePallets(this, [Pallets.ReFungible]);
+
await usingApi(async (api, privateKeyWrapper) => {
alice = privateKeyWrapper('//Alice');
bob = privateKeyWrapper('//Bob');
tests/src/nesting/nest.test.tsdiffbeforeafterboth--- a/tests/src/nesting/nest.test.ts
+++ b/tests/src/nesting/nest.test.ts
@@ -17,6 +17,8 @@
transferExpectSuccess,
transferFromExpectSuccess,
setCollectionLimitsExpectSuccess,
+ requirePallets,
+ Pallets,
} from '../util/helpers';
import {IKeyringPair} from '@polkadot/types/types';
@@ -311,7 +313,9 @@
// ---------- Re-Fungible ----------
- it('ReFungible: allows an Owner to nest/unnest their token', async () => {
+ it('ReFungible: allows an Owner to nest/unnest their token', async function() {
+ await requirePallets(this, [Pallets.ReFungible]);
+
await usingApi(async api => {
const collectionNFT = await createCollectionExpectSuccess({mode: {type: 'NFT'}});
await setCollectionPermissionsExpectSuccess(alice, collectionNFT, {nesting: {tokenOwner: true}});
@@ -333,7 +337,9 @@
});
});
- it('ReFungible: allows an Owner to nest/unnest their token (Restricted nesting)', async () => {
+ it('ReFungible: allows an Owner to nest/unnest their token (Restricted nesting)', async function() {
+ await requirePallets(this, [Pallets.ReFungible]);
+
await usingApi(async api => {
const collectionNFT = await createCollectionExpectSuccess({mode: {type: 'NFT'}});
const targetToken = await createItemExpectSuccess(alice, collectionNFT, 'NFT', {Substrate: alice.address});
@@ -715,7 +721,9 @@
// ---------- Re-Fungible ----------
- it('ReFungible: disallows to nest token if nesting is disabled', async () => {
+ it('ReFungible: disallows to nest token if nesting is disabled', async function() {
+ await requirePallets(this, [Pallets.ReFungible]);
+
await usingApi(async api => {
const collectionNFT = await createCollectionExpectSuccess({mode: {type: 'NFT'}});
await setCollectionPermissionsExpectSuccess(alice, collectionNFT, {nesting: {}});
@@ -745,7 +753,9 @@
});
});
- it('ReFungible: disallows a non-Owner to nest someone else\'s token', async () => {
+ it('ReFungible: disallows a non-Owner to nest someone else\'s token', async function() {
+ await requirePallets(this, [Pallets.ReFungible]);
+
await usingApi(async api => {
const collectionNFT = await createCollectionExpectSuccess({mode: {type: 'NFT'}});
await setCollectionPermissionsExpectSuccess(alice, collectionNFT, {nesting: {tokenOwner: true}});
@@ -773,7 +783,9 @@
});
});
- it('ReFungible: disallows a non-Owner to nest someone else\'s token (Restricted nesting)', async () => {
+ it('ReFungible: disallows a non-Owner to nest someone else\'s token (Restricted nesting)', async function() {
+ await requirePallets(this, [Pallets.ReFungible]);
+
await usingApi(async api => {
const collectionNFT = await createCollectionExpectSuccess({mode: {type: 'NFT'}});
await addToAllowListExpectSuccess(alice, collectionNFT, bob.address);
@@ -800,7 +812,9 @@
});
});
- it('ReFungible: disallows to nest token to an unlisted collection', async () => {
+ it('ReFungible: disallows to nest token to an unlisted collection', async function() {
+ await requirePallets(this, [Pallets.ReFungible]);
+
await usingApi(async api => {
const collectionNFT = await createCollectionExpectSuccess({mode: {type: 'NFT'}});
await setCollectionPermissionsExpectSuccess(alice, collectionNFT, {nesting: {tokenOwner: true, restricted:[]}});
tests/src/nesting/properties.test.tsdiffbeforeafterboth--- a/tests/src/nesting/properties.test.ts
+++ b/tests/src/nesting/properties.test.ts
@@ -8,6 +8,8 @@
createItemExpectSuccess,
getCreateCollectionResult,
transferExpectSuccess,
+ requirePallets,
+ Pallets,
} from '../util/helpers';
import {IKeyringPair} from '@polkadot/types/types';
import {tokenIdToAddress} from '../eth/util/helpers';
@@ -64,7 +66,9 @@
await testMakeSureSuppliesRequired({type: 'NFT'});
});
- it('Makes sure collectionById supplies required fields for ReFungible', async () => {
+ it('Makes sure collectionById supplies required fields for ReFungible', async function() {
+ await requirePallets(this, [Pallets.ReFungible]);
+
await testMakeSureSuppliesRequired({type: 'ReFungible'});
});
});
@@ -120,7 +124,9 @@
it('Sets properties for a NFT collection', async () => {
await testSetsPropertiesForCollection('NFT');
});
- it('Sets properties for a ReFungible collection', async () => {
+ it('Sets properties for a ReFungible collection', async function() {
+ await requirePallets(this, [Pallets.ReFungible]);
+
await testSetsPropertiesForCollection('ReFungible');
});
@@ -178,7 +184,9 @@
it('Check valid names for NFT collection properties keys', async () => {
await testCheckValidNames('NFT');
});
- it('Check valid names for ReFungible collection properties keys', async () => {
+ it('Check valid names for ReFungible collection properties keys', async function() {
+ await requirePallets(this, [Pallets.ReFungible]);
+
await testCheckValidNames('ReFungible');
});
@@ -209,7 +217,9 @@
it('Changes properties of a NFT collection', async () => {
await testChangesProperties({type: 'NFT'});
});
- it('Changes properties of a ReFungible collection', async () => {
+ it('Changes properties of a ReFungible collection', async function() {
+ await requirePallets(this, [Pallets.ReFungible]);
+
await testChangesProperties({type: 'ReFungible'});
});
@@ -238,7 +248,9 @@
it('Deletes properties of a NFT collection', async () => {
await testDeleteProperties({type: 'NFT'});
});
- it('Deletes properties of a ReFungible collection', async () => {
+ it('Deletes properties of a ReFungible collection', async function() {
+ await requirePallets(this, [Pallets.ReFungible]);
+
await testDeleteProperties({type: 'ReFungible'});
});
});
@@ -269,7 +281,9 @@
it('Fails to set properties in a NFT collection if not its onwer/administrator', async () => {
await testFailsSetPropertiesIfNotOwnerOrAdmin({type: 'NFT'});
});
- it('Fails to set properties in a ReFungible collection if not its onwer/administrator', async () => {
+ it('Fails to set properties in a ReFungible collection if not its onwer/administrator', async function() {
+ await requirePallets(this, [Pallets.ReFungible]);
+
await testFailsSetPropertiesIfNotOwnerOrAdmin({type: 'ReFungible'});
});
@@ -307,7 +321,9 @@
it('Fails to set properties that exceed the limits (NFT)', async () => {
await testFailsSetPropertiesThatExeedLimits({type: 'NFT'});
});
- it('Fails to set properties that exceed the limits (ReFungible)', async () => {
+ it('Fails to set properties that exceed the limits (ReFungible)', async function() {
+ await requirePallets(this, [Pallets.ReFungible]);
+
await testFailsSetPropertiesThatExeedLimits({type: 'ReFungible'});
});
@@ -337,7 +353,9 @@
it('Fails to set more properties than it is allowed (NFT)', async () => {
await testFailsSetMorePropertiesThanAllowed({type: 'NFT'});
});
- it('Fails to set more properties than it is allowed (ReFungible)', async () => {
+ it('Fails to set more properties than it is allowed (ReFungible)', async function() {
+ await requirePallets(this, [Pallets.ReFungible]);
+
await testFailsSetMorePropertiesThanAllowed({type: 'ReFungible'});
});
@@ -392,7 +410,9 @@
it('Fails to set properties with invalid names (NFT)', async () => {
await testFailsSetPropertiesWithInvalidNames({type: 'NFT'});
});
- it('Fails to set properties with invalid names (ReFungible)', async () => {
+ it('Fails to set properties with invalid names (ReFungible)', async function() {
+ await requirePallets(this, [Pallets.ReFungible]);
+
await testFailsSetPropertiesWithInvalidNames({type: 'ReFungible'});
});
});
@@ -443,7 +463,9 @@
it('Sets access rights to properties of a collection (NFT)', async () => {
await testSetsAccessRightsToProperties({type: 'NFT'});
});
- it('Sets access rights to properties of a collection (ReFungible)', async () => {
+ it('Sets access rights to properties of a collection (ReFungible)', async function() {
+ await requirePallets(this, [Pallets.ReFungible]);
+
await testSetsAccessRightsToProperties({type: 'ReFungible'});
});
@@ -472,7 +494,9 @@
it('Changes access rights to properties of a NFT collection', async () => {
await testChangesAccessRightsToProperty({type: 'NFT'});
});
- it('Changes access rights to properties of a ReFungible collection', async () => {
+ it('Changes access rights to properties of a ReFungible collection', async function() {
+ await requirePallets(this, [Pallets.ReFungible]);
+
await testChangesAccessRightsToProperty({type: 'ReFungible'});
});
});
@@ -502,7 +526,9 @@
it('Prevents from setting access rights to properties of a NFT collection if not an onwer/admin', async () => {
await testPreventsFromSettingAccessRightsNotAdminOrOwner({type: 'NFT'});
});
- it('Prevents from setting access rights to properties of a ReFungible collection if not an onwer/admin', async () => {
+ it('Prevents from setting access rights to properties of a ReFungible collection if not an onwer/admin', async function() {
+ await requirePallets(this, [Pallets.ReFungible]);
+
await testPreventsFromSettingAccessRightsNotAdminOrOwner({type: 'ReFungible'});
});
@@ -531,7 +557,9 @@
it('Prevents from adding too many possible properties (NFT)', async () => {
await testPreventFromAddingTooManyPossibleProperties({type: 'NFT'});
});
- it('Prevents from adding too many possible properties (ReFungible)', async () => {
+ it('Prevents from adding too many possible properties (ReFungible)', async function() {
+ await requirePallets(this, [Pallets.ReFungible]);
+
await testPreventFromAddingTooManyPossibleProperties({type: 'ReFungible'});
});
@@ -560,7 +588,9 @@
it('Prevents access rights to be modified if constant (NFT)', async () => {
await testPreventAccessRightsModifiedIfConstant({type: 'NFT'});
});
- it('Prevents access rights to be modified if constant (ReFungible)', async () => {
+ it('Prevents access rights to be modified if constant (ReFungible)', async function() {
+ await requirePallets(this, [Pallets.ReFungible]);
+
await testPreventAccessRightsModifiedIfConstant({type: 'ReFungible'});
});
@@ -608,7 +638,9 @@
it('Prevents adding properties with invalid names (NFT)', async () => {
await testPreventsAddingPropertiesWithInvalidNames({type: 'NFT'});
});
- it('Prevents adding properties with invalid names (ReFungible)', async () => {
+ it('Prevents adding properties with invalid names (ReFungible)', async function() {
+ await requirePallets(this, [Pallets.ReFungible]);
+
await testPreventsAddingPropertiesWithInvalidNames({type: 'ReFungible'});
});
});
@@ -651,7 +683,9 @@
it('Reads yet empty properties of a token (NFT)', async () => {
await testReadsYetEmptyProperties({type: 'NFT'});
});
- it('Reads yet empty properties of a token (ReFungible)', async () => {
+ it('Reads yet empty properties of a token (ReFungible)', async function() {
+ await requirePallets(this, [Pallets.ReFungible]);
+
await testReadsYetEmptyProperties({type: 'ReFungible'});
});
@@ -696,7 +730,9 @@
it('Assigns properties to a token according to permissions (NFT)', async () => {
await testAssignPropertiesAccordingToPermissions({type: 'NFT'}, 1);
});
- it('Assigns properties to a token according to permissions (ReFungible)', async () => {
+ it('Assigns properties to a token according to permissions (ReFungible)', async function() {
+ await requirePallets(this, [Pallets.ReFungible]);
+
await testAssignPropertiesAccordingToPermissions({type: 'ReFungible'}, 100);
});
@@ -749,7 +785,9 @@
it('Changes properties of a token according to permissions (NFT)', async () => {
await testChangesPropertiesAccordingPermission({type: 'NFT'}, 1);
});
- it('Changes properties of a token according to permissions (ReFungible)', async () => {
+ it('Changes properties of a token according to permissions (ReFungible)', async function() {
+ await requirePallets(this, [Pallets.ReFungible]);
+
await testChangesPropertiesAccordingPermission({type: 'ReFungible'}, 100);
});
@@ -802,7 +840,9 @@
it('Deletes properties of a token according to permissions (NFT)', async () => {
await testDeletePropertiesAccordingPermission({type: 'NFT'}, 1);
});
- it('Deletes properties of a token according to permissions (ReFungible)', async () => {
+ it('Deletes properties of a token according to permissions (ReFungible)', async function() {
+ await requirePallets(this, [Pallets.ReFungible]);
+
await testDeletePropertiesAccordingPermission({type: 'ReFungible'}, 100);
});
@@ -1029,7 +1069,9 @@
it('Forbids changing/deleting properties of a token if the user is outside of permissions (NFT)', async () => {
await testForbidsChangingDeletingPropertiesUserOutsideOfPermissions({type: 'NFT'}, 1);
});
- it('Forbids changing/deleting properties of a token if the user is outside of permissions (ReFungible)', async () => {
+ it('Forbids changing/deleting properties of a token if the user is outside of permissions (ReFungible)', async function() {
+ await requirePallets(this, [Pallets.ReFungible]);
+
await testForbidsChangingDeletingPropertiesUserOutsideOfPermissions({type: 'ReFungible'}, 100);
});
@@ -1062,7 +1104,9 @@
it('Forbids changing/deleting properties of a token if the property is permanent (immutable) (NFT)', async () => {
await testForbidsChangingDeletingPropertiesIfPropertyImmutable({type: 'NFT'}, 1);
});
- it('Forbids changing/deleting properties of a token if the property is permanent (immutable) (ReFungible)', async () => {
+ it('Forbids changing/deleting properties of a token if the property is permanent (immutable) (ReFungible)', async function() {
+ await requirePallets(this, [Pallets.ReFungible]);
+
await testForbidsChangingDeletingPropertiesIfPropertyImmutable({type: 'ReFungible'}, 100);
});
@@ -1096,7 +1140,9 @@
it('Forbids adding properties to a token if the property is not declared / forbidden with the \'None\' permission (NFT)', async () => {
await testForbidsAddingPropertiesIfPropertyNotDeclared({type: 'NFT'}, 1);
});
- it('Forbids adding properties to a token if the property is not declared / forbidden with the \'None\' permission (ReFungible)', async () => {
+ it('Forbids adding properties to a token if the property is not declared / forbidden with the \'None\' permission (ReFungible)', async function() {
+ await requirePallets(this, [Pallets.ReFungible]);
+
await testForbidsAddingPropertiesIfPropertyNotDeclared({type: 'ReFungible'}, 100);
});
@@ -1140,7 +1186,9 @@
it('Forbids adding too many properties to a token (NFT)', async () => {
await testForbidsAddingTooManyProperties({type: 'NFT'}, 1);
});
- it('Forbids adding too many properties to a token (ReFungible)', async () => {
+ it('Forbids adding too many properties to a token (ReFungible)', async function() {
+ await requirePallets(this, [Pallets.ReFungible]);
+
await testForbidsAddingTooManyProperties({type: 'ReFungible'}, 100);
});
});
@@ -1149,7 +1197,9 @@
let collection: number;
let token: number;
- before(async () => {
+ before(async function() {
+ await requirePallets(this, [Pallets.ReFungible]);
+
await usingApi(async (api, privateKeyWrapper) => {
alice = privateKeyWrapper('//Alice');
bob = privateKeyWrapper('//Bob');
tests/src/nesting/rules-smoke.test.tsdiffbeforeafterboth--- a/tests/src/nesting/rules-smoke.test.ts
+++ b/tests/src/nesting/rules-smoke.test.ts
@@ -1,7 +1,7 @@
import {expect} from 'chai';
import {tokenIdToAddress} from '../eth/util/helpers';
import usingApi, {executeTransaction} from '../substrate/substrate-api';
-import {createCollectionExpectSuccess, createFungibleItemExpectSuccess, createItemExpectSuccess, CrossAccountId, getCreateCollectionResult} from '../util/helpers';
+import {createCollectionExpectSuccess, createFungibleItemExpectSuccess, createItemExpectSuccess, CrossAccountId, getCreateCollectionResult, requirePallets, Pallets} from '../util/helpers';
import {IKeyringPair} from '@polkadot/types/types';
describe('nesting check', () => {
@@ -47,7 +47,9 @@
});
});
- it('called for refungible', async () => {
+ it('called for refungible', async function() {
+ await requirePallets(this, [Pallets.ReFungible]);
+
await usingApi(async api => {
const collection = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
await expect(executeTransaction(api, alice, api.tx.unique.createItem(collection, nestTarget, {ReFungible: {}})))
tests/src/nesting/unnest.test.tsdiffbeforeafterboth--- a/tests/src/nesting/unnest.test.ts
+++ b/tests/src/nesting/unnest.test.ts
@@ -10,6 +10,8 @@
setCollectionPermissionsExpectSuccess,
transferExpectSuccess,
transferFromExpectSuccess,
+ requirePallets,
+ Pallets,
} from '../util/helpers';
import {IKeyringPair} from '@polkadot/types/types';
@@ -80,7 +82,9 @@
});
});
- it('ReFungible: allows the owner to successfully unnest a token', async () => {
+ it('ReFungible: allows the owner to successfully unnest a token', async function() {
+ await requirePallets(this, [Pallets.ReFungible]);
+
await usingApi(async api => {
const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}});
await setCollectionPermissionsExpectSuccess(alice, collection, {nesting: {tokenOwner: true}});
tests/src/nextSponsoring.test.tsdiffbeforeafterboth--- a/tests/src/nextSponsoring.test.ts
+++ b/tests/src/nextSponsoring.test.ts
@@ -27,6 +27,8 @@
transferExpectSuccess,
normalizeAccountId,
getNextSponsored,
+ requirePallets,
+ Pallets,
} from './util/helpers';
chai.use(chaiAsPromised);
@@ -89,7 +91,9 @@
});
});
- it('ReFungible', async () => {
+ it('ReFungible', async function() {
+ await requirePallets(this, [Pallets.ReFungible]);
+
await usingApi(async (api: ApiPromise) => {
const createMode = 'ReFungible';
tests/src/pallet-presence.test.tsdiffbeforeafterboth--- a/tests/src/pallet-presence.test.ts
+++ b/tests/src/pallet-presence.test.ts
@@ -49,8 +49,6 @@
'inflation',
'unique',
'nonfungible',
- 'refungible',
- 'scheduler',
'charging',
];
@@ -66,8 +64,16 @@
await usingApi(async api => {
const chain = await api.rpc.system.chain();
- if (!chain.eq('UNIQUE')) {
- requiredPallets.push(...['rmrkcore', 'rmrkequip']);
+ const refungible = 'refungible';
+ const scheduler = 'scheduler';
+ const rmrkPallets = ['rmrkcore', 'rmrkequip'];
+
+ if (chain.eq('OPAL by UNIQUE')) {
+ requiredPallets.push(refungible, scheduler, ...rmrkPallets);
+ } else if (chain.eq('QUARTZ by UNIQUE')) {
+ // Insert Quartz additional pallets here
+ } else if (chain.eq('UNIQUE')) {
+ // Insert Unique additional pallets here
}
});
});
tests/src/refungible.test.tsdiffbeforeafterboth--- a/tests/src/refungible.test.ts
+++ b/tests/src/refungible.test.ts
@@ -36,6 +36,9 @@
CrossAccountId,
getCreateItemsResult,
getDestroyItemsResult,
+ getModuleNames,
+ Pallets,
+ requirePallets,
} from './util/helpers';
import chai from 'chai';
@@ -46,14 +49,20 @@
let alice: IKeyringPair;
let bob: IKeyringPair;
-describe('integration test: Refungible functionality:', () => {
- before(async () => {
+
+
+describe('integration test: Refungible functionality:', async () => {
+ before(async function() {
+ await requirePallets(this, [Pallets.ReFungible]);
+
await usingApi(async (api, privateKeyWrapper) => {
alice = privateKeyWrapper('//Alice');
bob = privateKeyWrapper('//Bob');
+ if (!getModuleNames(api).includes(Pallets.ReFungible)) this.skip();
});
+
});
-
+
it('Create refungible collection and token', async () => {
await usingApi(async api => {
const createCollectionResult = await createCollection(api, alice, {mode: {type: 'ReFungible'}});
@@ -266,15 +275,6 @@
amount: 50,
},
]);
- });
- });
-});
-
-describe('Test Refungible properties:', () => {
- before(async () => {
- await usingApi(async (api, privateKeyWrapper) => {
- alice = privateKeyWrapper('//Alice');
- bob = privateKeyWrapper('//Bob');
});
});
@@ -292,3 +292,4 @@
});
});
});
+
tests/src/rmrk/acceptNft.test.tsdiffbeforeafterboth--- a/tests/src/rmrk/acceptNft.test.ts
+++ b/tests/src/rmrk/acceptNft.test.ts
@@ -8,14 +8,19 @@
} from './util/tx';
import {NftIdTuple} from './util/fetch';
import {isNftChildOfAnother, expectTxFailure} from './util/helpers';
+import {requirePallets, Pallets} from '../util/helpers';
describe('integration test: accept NFT', () => {
let api: any;
- before(async () => { api = await getApiConnection(); });
-
+ before(async function() {
+ api = await getApiConnection();
+ await requirePallets(this, [Pallets.RmrkCore]);
+ });
+
+
const alice = '//Alice';
const bob = '//Bob';
-
+
const createTestCollection = async (issuerUri: string) => {
return await createCollection(
api,
tests/src/rmrk/addResource.test.tsdiffbeforeafterboth--- a/tests/src/rmrk/addResource.test.ts
+++ b/tests/src/rmrk/addResource.test.ts
@@ -12,6 +12,7 @@
addNftComposableResource,
} from './util/tx';
import {RmrkTraitsResourceResourceInfo as ResourceInfo} from '@polkadot/types/lookup';
+import {requirePallets, Pallets} from '../util/helpers';
describe('integration test: add NFT resource', () => {
const Alice = '//Alice';
@@ -24,8 +25,9 @@
const nonexistentId = 99999;
let api: any;
- before(async () => {
+ before(async function() {
api = await getApiConnection();
+ await requirePallets(this, [Pallets.RmrkCore]);
});
it('add resource', async () => {
tests/src/rmrk/addTheme.test.tsdiffbeforeafterboth--- a/tests/src/rmrk/addTheme.test.ts
+++ b/tests/src/rmrk/addTheme.test.ts
@@ -3,10 +3,14 @@
import {createBase, addTheme} from './util/tx';
import {expectTxFailure} from './util/helpers';
import {getThemeNames} from './util/fetch';
+import {requirePallets, Pallets} from '../util/helpers';
describe('integration test: add Theme to Base', () => {
let api: any;
- before(async () => { api = await getApiConnection(); });
+ before(async function() {
+ api = await getApiConnection();
+ await requirePallets(this, [Pallets.RmrkEquip]);
+ });
const alice = '//Alice';
const bob = '//Bob';
tests/src/rmrk/burnNft.test.tsdiffbeforeafterboth--- a/tests/src/rmrk/burnNft.test.ts
+++ b/tests/src/rmrk/burnNft.test.ts
@@ -5,6 +5,7 @@
import chai from 'chai';
import chaiAsPromised from 'chai-as-promised';
+import {requirePallets, Pallets} from '../util/helpers';
chai.use(chaiAsPromised);
const expect = chai.expect;
@@ -14,10 +15,12 @@
const Bob = '//Bob';
let api: any;
- before(async () => {
+ before(async function() {
api = await getApiConnection();
+ await requirePallets(this, [Pallets.RmrkCore]);
});
+
it('burn nft', async () => {
await createCollection(
api,
tests/src/rmrk/changeCollectionIssuer.test.tsdiffbeforeafterboth--- a/tests/src/rmrk/changeCollectionIssuer.test.ts
+++ b/tests/src/rmrk/changeCollectionIssuer.test.ts
@@ -1,4 +1,5 @@
import {getApiConnection} from '../substrate/substrate-api';
+import {requirePallets, Pallets} from '../util/helpers';
import {expectTxFailure} from './util/helpers';
import {
changeIssuer,
@@ -10,10 +11,13 @@
const Bob = '//Bob';
let api: any;
- before(async () => {
+ before(async function() {
api = await getApiConnection();
+ await requirePallets(this, [Pallets.RmrkCore]);
});
+
+
it('change collection issuer', async () => {
await createCollection(
api,
tests/src/rmrk/createBase.test.tsdiffbeforeafterboth--- a/tests/src/rmrk/createBase.test.ts
+++ b/tests/src/rmrk/createBase.test.ts
@@ -1,9 +1,13 @@
import {getApiConnection} from '../substrate/substrate-api';
+import {requirePallets, Pallets} from '../util/helpers';
import {createCollection, createBase} from './util/tx';
describe('integration test: create new Base', () => {
let api: any;
- before(async () => { api = await getApiConnection(); });
+ before(async function() {
+ api = await getApiConnection();
+ await requirePallets(this, [Pallets.RmrkCore, Pallets.RmrkEquip]);
+ });
const alice = '//Alice';
tests/src/rmrk/createCollection.test.tsdiffbeforeafterboth--- a/tests/src/rmrk/createCollection.test.ts
+++ b/tests/src/rmrk/createCollection.test.ts
@@ -1,9 +1,15 @@
import {getApiConnection} from '../substrate/substrate-api';
+import {requirePallets, Pallets} from '../util/helpers';
import {createCollection} from './util/tx';
describe('Integration test: create new collection', () => {
let api: any;
- before(async () => { api = await getApiConnection(); });
+ before(async function () {
+ api = await getApiConnection();
+ await requirePallets(this, [Pallets.RmrkCore]);
+ });
+
+
const alice = '//Alice';
tests/src/rmrk/deleteCollection.test.tsdiffbeforeafterboth--- a/tests/src/rmrk/deleteCollection.test.ts
+++ b/tests/src/rmrk/deleteCollection.test.ts
@@ -1,11 +1,13 @@
import {getApiConnection} from '../substrate/substrate-api';
+import {requirePallets, Pallets} from '../util/helpers';
import {expectTxFailure} from './util/helpers';
import {createCollection, deleteCollection} from './util/tx';
describe('integration test: delete collection', () => {
let api: any;
- before(async () => {
+ before(async function () {
api = await getApiConnection();
+ await requirePallets(this, [Pallets.RmrkCore]);
});
const Alice = '//Alice';
tests/src/rmrk/equipNft.test.tsdiffbeforeafterboth--- a/tests/src/rmrk/equipNft.test.ts
+++ b/tests/src/rmrk/equipNft.test.ts
@@ -1,6 +1,7 @@
import {ApiPromise} from '@polkadot/api';
import {expect} from 'chai';
import {getApiConnection} from '../substrate/substrate-api';
+import {requirePallets, Pallets} from '../util/helpers';
import {getNft, getParts, NftIdTuple} from './util/fetch';
import {expectTxFailure} from './util/helpers';
import {
@@ -122,8 +123,10 @@
describe.skip('integration test: Equip NFT', () => {
let api: any;
- before(async () => {
+
+ before(async function () {
api = await getApiConnection();
+ await requirePallets(this, [Pallets.RmrkCore, Pallets.RmrkEquip]);
});
it('equip nft', async () => {
tests/src/rmrk/getOwnedNfts.test.tsdiffbeforeafterboth--- a/tests/src/rmrk/getOwnedNfts.test.ts
+++ b/tests/src/rmrk/getOwnedNfts.test.ts
@@ -1,11 +1,17 @@
import {expect} from 'chai';
import {getApiConnection} from '../substrate/substrate-api';
+import {requirePallets, Pallets} from '../util/helpers';
import {getOwnedNfts} from './util/fetch';
import {mintNft, createCollection} from './util/tx';
describe('integration test: get owned NFTs', () => {
let api: any;
- before(async () => { api = await getApiConnection(); });
+
+ before(async function () {
+ api = await getApiConnection();
+ await requirePallets(this, [Pallets.RmrkCore]);
+ });
+
const alice = '//Alice';
tests/src/rmrk/lockCollection.test.tsdiffbeforeafterboth--- a/tests/src/rmrk/lockCollection.test.ts
+++ b/tests/src/rmrk/lockCollection.test.ts
@@ -1,4 +1,5 @@
import {getApiConnection} from '../substrate/substrate-api';
+import {requirePallets, Pallets} from '../util/helpers';
import {expectTxFailure} from './util/helpers';
import {createCollection, lockCollection, mintNft} from './util/tx';
@@ -8,8 +9,9 @@
const Max = 5;
let api: any;
- before(async () => {
+ before(async function () {
api = await getApiConnection();
+ await requirePallets(this, [Pallets.RmrkCore]);
});
it('lock collection', async () => {
tests/src/rmrk/mintNft.test.tsdiffbeforeafterboth--- a/tests/src/rmrk/mintNft.test.ts
+++ b/tests/src/rmrk/mintNft.test.ts
@@ -1,12 +1,18 @@
import {expect} from 'chai';
import {getApiConnection} from '../substrate/substrate-api';
+import {requirePallets, Pallets} from '../util/helpers';
import {getNft} from './util/fetch';
import {expectTxFailure} from './util/helpers';
import {createCollection, mintNft} from './util/tx';
describe('integration test: mint new NFT', () => {
let api: any;
- before(async () => { api = await getApiConnection(); });
+
+ before(async function () {
+ api = await getApiConnection();
+ await requirePallets(this, [Pallets.RmrkCore]);
+ });
+
const alice = '//Alice';
const bob = '//Bob';
tests/src/rmrk/rejectNft.test.tsdiffbeforeafterboth--- a/tests/src/rmrk/rejectNft.test.ts
+++ b/tests/src/rmrk/rejectNft.test.ts
@@ -8,10 +8,16 @@
} from './util/tx';
import {getChildren, NftIdTuple} from './util/fetch';
import {isNftChildOfAnother, expectTxFailure} from './util/helpers';
+import {requirePallets, Pallets} from '../util/helpers';
describe('integration test: reject NFT', () => {
let api: any;
- before(async () => { api = await getApiConnection(); });
+ before(async function () {
+ api = await getApiConnection();
+ await requirePallets(this, [Pallets.RmrkCore]);
+ });
+
+
const alice = '//Alice';
const bob = '//Bob';
tests/src/rmrk/removeResource.test.tsdiffbeforeafterboth--- a/tests/src/rmrk/removeResource.test.ts
+++ b/tests/src/rmrk/removeResource.test.ts
@@ -1,6 +1,7 @@
import {expect} from 'chai';
import privateKey from '../substrate/privateKey';
import {executeTransaction, getApiConnection} from '../substrate/substrate-api';
+import {requirePallets, Pallets} from '../util/helpers';
import {getNft, NftIdTuple} from './util/fetch';
import {expectTxFailure} from './util/helpers';
import {
@@ -16,9 +17,10 @@
describe('Integration test: remove nft resource', () => {
let api: any;
let ss58Format: string;
- before(async () => {
+ before(async function() {
api = await getApiConnection();
ss58Format = api.registry.getChainProperties()!.toJSON().ss58Format;
+ await requirePallets(this, [Pallets.RmrkCore]);
});
const Alice = '//Alice';
tests/src/rmrk/rmrkIsolation.test.tsdiffbeforeafterboth--- a/tests/src/rmrk/rmrkIsolation.test.ts
+++ b/tests/src/rmrk/rmrkIsolation.test.ts
@@ -6,7 +6,9 @@
getCreateCollectionResult,
getDetailedCollectionInfo,
getGenericResult,
+ requirePallets,
normalizeAccountId,
+ Pallets,
} from '../util/helpers';
import {IKeyringPair} from '@polkadot/types/types';
import {ApiPromise} from '@polkadot/api';
@@ -59,11 +61,10 @@
describe('RMRK External Integration Test', async () => {
const it_rmrk = (await isUnique() ? it : it.skip);
- before(async () => {
+ before(async function() {
await usingApi(async (api, privateKeyWrapper) => {
alice = privateKeyWrapper('//Alice');
-
-
+ await requirePallets(this, [Pallets.RmrkCore]);
});
});
tests/src/rmrk/sendNft.test.tsdiffbeforeafterboth--- a/tests/src/rmrk/sendNft.test.ts
+++ b/tests/src/rmrk/sendNft.test.ts
@@ -3,10 +3,14 @@
import {createCollection, mintNft, sendNft} from './util/tx';
import {NftIdTuple} from './util/fetch';
import {isNftChildOfAnother, expectTxFailure} from './util/helpers';
+import {requirePallets, Pallets} from '../util/helpers';
describe('integration test: send NFT', () => {
let api: any;
- before(async () => { api = await getApiConnection(); });
+ before(async function () {
+ api = await getApiConnection();
+ await requirePallets(this, [Pallets.RmrkCore]);
+ });
const maxNftId = 0xFFFFFFFF;
tests/src/rmrk/setCollectionProperty.test.tsdiffbeforeafterboth--- a/tests/src/rmrk/setCollectionProperty.test.ts
+++ b/tests/src/rmrk/setCollectionProperty.test.ts
@@ -1,4 +1,5 @@
import {getApiConnection} from '../substrate/substrate-api';
+import {requirePallets, Pallets} from '../util/helpers';
import {expectTxFailure} from './util/helpers';
import {createCollection, setPropertyCollection} from './util/tx';
@@ -7,8 +8,9 @@
const Bob = '//Bob';
let api: any;
- before(async () => {
+ before(async function () {
api = await getApiConnection();
+ await requirePallets(this, [Pallets.RmrkCore]);
});
it('set collection property', async () => {
tests/src/rmrk/setEquippableList.test.tsdiffbeforeafterboth--- a/tests/src/rmrk/setEquippableList.test.ts
+++ b/tests/src/rmrk/setEquippableList.test.ts
@@ -1,10 +1,14 @@
import {getApiConnection} from '../substrate/substrate-api';
+import {requirePallets, Pallets} from '../util/helpers';
import {expectTxFailure} from './util/helpers';
import {createCollection, createBase, setEquippableList} from './util/tx';
describe("integration test: set slot's Equippable List", () => {
let api: any;
- before(async () => { api = await getApiConnection(); });
+ before(async function () {
+ api = await getApiConnection();
+ await requirePallets(this, [Pallets.RmrkCore]);
+ });
const alice = '//Alice';
const bob = '//Bob';
tests/src/rmrk/setNftProperty.test.tsdiffbeforeafterboth--- a/tests/src/rmrk/setNftProperty.test.ts
+++ b/tests/src/rmrk/setNftProperty.test.ts
@@ -1,11 +1,15 @@
import {getApiConnection} from '../substrate/substrate-api';
+import {requirePallets, Pallets} from '../util/helpers';
import {NftIdTuple} from './util/fetch';
import {expectTxFailure} from './util/helpers';
import {createCollection, mintNft, sendNft, setNftProperty} from './util/tx';
describe('integration test: set NFT property', () => {
let api: any;
- before(async () => { api = await getApiConnection(); });
+ before(async function () {
+ api = await getApiConnection();
+ await requirePallets(this, [Pallets.RmrkCore]);
+ });
const alice = '//Alice';
const bob = '//Bob';
tests/src/rmrk/setResourcePriorities.test.tsdiffbeforeafterboth--- a/tests/src/rmrk/setResourcePriorities.test.ts
+++ b/tests/src/rmrk/setResourcePriorities.test.ts
@@ -1,10 +1,14 @@
import {getApiConnection} from '../substrate/substrate-api';
+import {requirePallets, Pallets} from '../util/helpers';
import {expectTxFailure} from './util/helpers';
import {mintNft, createCollection, setResourcePriorities} from './util/tx';
describe('integration test: set NFT resource priorities', () => {
let api: any;
- before(async () => { api = await getApiConnection(); });
+ before(async function () {
+ api = await getApiConnection();
+ await requirePallets(this, [Pallets.RmrkCore]);
+ });
const alice = '//Alice';
const bob = '//Bob';
tests/src/setCollectionSponsor.test.tsdiffbeforeafterboth--- a/tests/src/setCollectionSponsor.test.ts
+++ b/tests/src/setCollectionSponsor.test.ts
@@ -23,6 +23,8 @@
setCollectionSponsorExpectFailure,
addCollectionAdminExpectSuccess,
getCreatedCollectionCount,
+ requirePallets,
+ Pallets,
} from './util/helpers';
import {IKeyringPair} from '@polkadot/types/types';
@@ -50,7 +52,9 @@
const collectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});
await setCollectionSponsorExpectSuccess(collectionId, bob.address);
});
- it('Set ReFungible collection sponsor', async () => {
+ it('Set ReFungible collection sponsor', async function() {
+ await requirePallets(this, [Pallets.ReFungible]);
+
const collectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
await setCollectionSponsorExpectSuccess(collectionId, bob.address);
});
tests/src/transfer.test.tsdiffbeforeafterboth--- a/tests/src/transfer.test.ts
+++ b/tests/src/transfer.test.ts
@@ -35,11 +35,14 @@
getBalance as getTokenBalance,
transferFromExpectSuccess,
transferFromExpectFail,
+ requirePallets,
+ Pallets,
} from './util/helpers';
import {
subToEth,
itWeb3,
} from './eth/util/helpers';
+import {request} from 'https';
let alice: IKeyringPair;
let bob: IKeyringPair;
@@ -89,56 +92,61 @@
});
});
- it('User can transfer owned token', async () => {
- await usingApi(async (api, privateKeyWrapper) => {
- // nft
- const nftCollectionId = await createCollectionExpectSuccess();
- const newNftTokenId = await createItemExpectSuccess(alice, nftCollectionId, 'NFT');
- await transferExpectSuccess(nftCollectionId, newNftTokenId, alice, bob, 1, 'NFT');
- // fungible
- const fungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});
- const newFungibleTokenId = await createItemExpectSuccess(alice, fungibleCollectionId, 'Fungible');
- await transferExpectSuccess(fungibleCollectionId, newFungibleTokenId, alice, bob, 1, 'Fungible');
- // reFungible
- const reFungibleCollectionId = await
- createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
- const newReFungibleTokenId = await createItemExpectSuccess(alice, reFungibleCollectionId, 'ReFungible');
- await transferExpectSuccess(
- reFungibleCollectionId,
- newReFungibleTokenId,
- alice,
- bob,
- 100,
- 'ReFungible',
- );
- });
+ it('[nft] User can transfer owned token', async () => {
+ const nftCollectionId = await createCollectionExpectSuccess();
+ const newNftTokenId = await createItemExpectSuccess(alice, nftCollectionId, 'NFT');
+ await transferExpectSuccess(nftCollectionId, newNftTokenId, alice, bob, 1, 'NFT');
+ });
+
+ it('[fungible] User can transfer owned token', async () => {
+ const fungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});
+ const newFungibleTokenId = await createItemExpectSuccess(alice, fungibleCollectionId, 'Fungible');
+ await transferExpectSuccess(fungibleCollectionId, newFungibleTokenId, alice, bob, 1, 'Fungible');
+ });
+
+ it('[refungible] User can transfer owned token', async function() {
+ await requirePallets(this, [Pallets.ReFungible]);
+
+ const reFungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
+ const newReFungibleTokenId = await createItemExpectSuccess(alice, reFungibleCollectionId, 'ReFungible');
+ await transferExpectSuccess(
+ reFungibleCollectionId,
+ newReFungibleTokenId,
+ alice,
+ bob,
+ 100,
+ 'ReFungible',
+ );
+ });
+
+ it('[nft] Collection admin can transfer owned token', async () => {
+ const nftCollectionId = await createCollectionExpectSuccess();
+ await addCollectionAdminExpectSuccess(alice, nftCollectionId, bob.address);
+ const newNftTokenId = await createItemExpectSuccess(bob, nftCollectionId, 'NFT', bob.address);
+ await transferExpectSuccess(nftCollectionId, newNftTokenId, bob, alice, 1, 'NFT');
+ });
+
+ it('[fungible] Collection admin can transfer owned token', async () => {
+ const fungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});
+ await addCollectionAdminExpectSuccess(alice, fungibleCollectionId, bob.address);
+ const newFungibleTokenId = await createItemExpectSuccess(alice, fungibleCollectionId, 'Fungible', bob.address);
+ await transferExpectSuccess(fungibleCollectionId, newFungibleTokenId, bob, alice, 1, 'Fungible');
});
- it('Collection admin can transfer owned token', async () => {
- await usingApi(async (api, privateKeyWrapper) => {
- // nft
- const nftCollectionId = await createCollectionExpectSuccess();
- await addCollectionAdminExpectSuccess(alice, nftCollectionId, bob.address);
- const newNftTokenId = await createItemExpectSuccess(bob, nftCollectionId, 'NFT', bob.address);
- await transferExpectSuccess(nftCollectionId, newNftTokenId, bob, alice, 1, 'NFT');
- // fungible
- const fungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});
- await addCollectionAdminExpectSuccess(alice, fungibleCollectionId, bob.address);
- const newFungibleTokenId = await createItemExpectSuccess(alice, fungibleCollectionId, 'Fungible', bob.address);
- await transferExpectSuccess(fungibleCollectionId, newFungibleTokenId, bob, alice, 1, 'Fungible');
- // reFungible
- const reFungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
- await addCollectionAdminExpectSuccess(alice, reFungibleCollectionId, bob.address);
- const newReFungibleTokenId = await createItemExpectSuccess(bob, reFungibleCollectionId, 'ReFungible', bob.address);
- await transferExpectSuccess(
- reFungibleCollectionId,
- newReFungibleTokenId,
- bob,
- alice,
- 100,
- 'ReFungible',
- );
- });
+ it('[refungible] Collection admin can transfer owned token', async function() {
+ await requirePallets(this, [Pallets.ReFungible]);
+
+ const reFungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
+ await addCollectionAdminExpectSuccess(alice, reFungibleCollectionId, bob.address);
+ const newReFungibleTokenId = await createItemExpectSuccess(bob, reFungibleCollectionId, 'ReFungible', bob.address);
+ await transferExpectSuccess(
+ reFungibleCollectionId,
+ newReFungibleTokenId,
+ bob,
+ alice,
+ 100,
+ 'ReFungible',
+ );
});
});
@@ -150,33 +158,49 @@
charlie = privateKeyWrapper('//Charlie');
});
});
- it('Transfer with not existed collection_id', async () => {
+
+ it('[nft] Transfer with not existed collection_id', async () => {
await usingApi(async (api) => {
- // nft
const nftCollectionCount = await getCreatedCollectionCount(api);
await transferExpectFailure(nftCollectionCount + 1, 1, alice, bob, 1);
- // fungible
+ });
+ });
+
+ it('[fungible] Transfer with not existed collection_id', async () => {
+ await usingApi(async (api) => {
const fungibleCollectionCount = await getCreatedCollectionCount(api);
await transferExpectFailure(fungibleCollectionCount + 1, 0, alice, bob, 1);
- // reFungible
+ });
+ });
+
+ it('[refungible] Transfer with not existed collection_id', async function() {
+ await requirePallets(this, [Pallets.ReFungible]);
+
+ await usingApi(async (api) => {
const reFungibleCollectionCount = await getCreatedCollectionCount(api);
await transferExpectFailure(reFungibleCollectionCount + 1, 1, alice, bob, 1);
});
});
- it('Transfer with deleted collection_id', async () => {
- // nft
+
+ it('[nft] Transfer with deleted collection_id', async () => {
const nftCollectionId = await createCollectionExpectSuccess();
const newNftTokenId = await createItemExpectSuccess(alice, nftCollectionId, 'NFT');
await burnItemExpectSuccess(alice, nftCollectionId, newNftTokenId);
await destroyCollectionExpectSuccess(nftCollectionId);
await transferExpectFailure(nftCollectionId, newNftTokenId, alice, bob, 1);
- // fungible
+ });
+
+ it('[fungible] Transfer with deleted collection_id', async () => {
const fungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});
const newFungibleTokenId = await createItemExpectSuccess(alice, fungibleCollectionId, 'Fungible');
await burnItemExpectSuccess(alice, fungibleCollectionId, newFungibleTokenId, 10);
await destroyCollectionExpectSuccess(fungibleCollectionId);
await transferExpectFailure(fungibleCollectionId, newFungibleTokenId, alice, bob, 1);
- // reFungible
+ });
+
+ it('[refungible] Transfer with deleted collection_id', async function() {
+ await requirePallets(this, [Pallets.ReFungible]);
+
const reFungibleCollectionId = await
createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
const newReFungibleTokenId = await createItemExpectSuccess(alice, reFungibleCollectionId, 'ReFungible');
@@ -190,16 +214,21 @@
1,
);
});
- it('Transfer with not existed item_id', async () => {
- // nft
+
+ it('[nft] Transfer with not existed item_id', async () => {
const nftCollectionId = await createCollectionExpectSuccess();
await transferExpectFailure(nftCollectionId, 2, alice, bob, 1);
- // fungible
+ });
+
+ it('[fungible] Transfer with not existed item_id', async () => {
const fungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});
await transferExpectFailure(fungibleCollectionId, 2, alice, bob, 1);
- // reFungible
- const reFungibleCollectionId = await
- createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
+ });
+
+ it('[refungible] Transfer with not existed item_id', async function() {
+ await requirePallets(this, [Pallets.ReFungible]);
+
+ const reFungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
await transferExpectFailure(
reFungibleCollectionId,
2,
@@ -208,18 +237,24 @@
1,
);
});
- it('Transfer with deleted item_id', async () => {
- // nft
+
+ it('[nft] Transfer with deleted item_id', async () => {
const nftCollectionId = await createCollectionExpectSuccess();
const newNftTokenId = await createItemExpectSuccess(alice, nftCollectionId, 'NFT');
await burnItemExpectSuccess(alice, nftCollectionId, newNftTokenId, 1);
await transferExpectFailure(nftCollectionId, newNftTokenId, alice, bob, 1);
- // fungible
+ });
+
+ it('[fungible] Transfer with deleted item_id', async () => {
const fungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});
const newFungibleTokenId = await createItemExpectSuccess(alice, fungibleCollectionId, 'Fungible');
await burnItemExpectSuccess(alice, fungibleCollectionId, newFungibleTokenId, 10);
await transferExpectFailure(fungibleCollectionId, newFungibleTokenId, alice, bob, 1);
- // reFungible
+ });
+
+ it('[refungible] Transfer with deleted item_id', async function() {
+ await requirePallets(this, [Pallets.ReFungible]);
+
const reFungibleCollectionId = await
createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
const newReFungibleTokenId = await createItemExpectSuccess(alice, reFungibleCollectionId, 'ReFungible');
@@ -232,18 +267,23 @@
1,
);
});
- it('Transfer with recipient that is not owner', async () => {
- // nft
+
+ it('[nft] Transfer with recipient that is not owner', async () => {
const nftCollectionId = await createCollectionExpectSuccess();
const newNftTokenId = await createItemExpectSuccess(alice, nftCollectionId, 'NFT');
await transferExpectFailure(nftCollectionId, newNftTokenId, charlie, bob, 1);
- // fungible
+ });
+
+ it('[fungible] Transfer with recipient that is not owner', async () => {
const fungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});
const newFungibleTokenId = await createItemExpectSuccess(alice, fungibleCollectionId, 'Fungible');
await transferExpectFailure(fungibleCollectionId, newFungibleTokenId, charlie, bob, 1);
- // reFungible
- const reFungibleCollectionId = await
- createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
+ });
+
+ it('[refungible] Transfer with recipient that is not owner', async function() {
+ await requirePallets(this, [Pallets.ReFungible]);
+
+ const reFungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
const newReFungibleTokenId = await createItemExpectSuccess(alice, reFungibleCollectionId, 'ReFungible');
await transferExpectFailure(
reFungibleCollectionId,
@@ -276,7 +316,9 @@
});
});
- it('RFT', async () => {
+ it('RFT', async function() {
+ await requirePallets(this, [Pallets.ReFungible]);
+
await usingApi(async (api: ApiPromise) => {
const reFungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
const newReFungibleTokenId = await createItemExpectSuccess(alice, reFungibleCollectionId, 'ReFungible');
tests/src/transferFrom.test.tsdiffbeforeafterboth--- a/tests/src/transferFrom.test.ts
+++ b/tests/src/transferFrom.test.ts
@@ -31,6 +31,8 @@
burnItemExpectSuccess,
setCollectionLimitsExpectSuccess,
getCreatedCollectionCount,
+ requirePallets,
+ Pallets,
} from './util/helpers';
chai.use(chaiAsPromised);
@@ -49,36 +51,36 @@
});
});
- it('Execute the extrinsic and check nftItemList - owner of token', async () => {
- await usingApi(async () => {
- // nft
- const nftCollectionId = await createCollectionExpectSuccess();
- const newNftTokenId = await createItemExpectSuccess(alice, nftCollectionId, 'NFT');
- await approveExpectSuccess(nftCollectionId, newNftTokenId, alice, bob.address);
+ it('[nft] Execute the extrinsic and check nftItemList - owner of token', async () => {
+ const nftCollectionId = await createCollectionExpectSuccess();
+ const newNftTokenId = await createItemExpectSuccess(alice, nftCollectionId, 'NFT');
+ await approveExpectSuccess(nftCollectionId, newNftTokenId, alice, bob.address);
- await transferFromExpectSuccess(nftCollectionId, newNftTokenId, bob, alice, charlie, 1, 'NFT');
+ await transferFromExpectSuccess(nftCollectionId, newNftTokenId, bob, alice, charlie, 1, 'NFT');
+ });
- // fungible
- const fungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});
- const newFungibleTokenId = await createItemExpectSuccess(alice, fungibleCollectionId, 'Fungible');
- await approveExpectSuccess(fungibleCollectionId, newFungibleTokenId, alice, bob.address);
- await transferFromExpectSuccess(fungibleCollectionId, newFungibleTokenId, bob, alice, charlie, 1, 'Fungible');
+ it('[fungible] Execute the extrinsic and check nftItemList - owner of token', async () => {
+ const fungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});
+ const newFungibleTokenId = await createItemExpectSuccess(alice, fungibleCollectionId, 'Fungible');
+ await approveExpectSuccess(fungibleCollectionId, newFungibleTokenId, alice, bob.address);
+ await transferFromExpectSuccess(fungibleCollectionId, newFungibleTokenId, bob, alice, charlie, 1, 'Fungible');
+ });
- // reFungible
- const reFungibleCollectionId = await
- createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
- const newReFungibleTokenId = await createItemExpectSuccess(alice, reFungibleCollectionId, 'ReFungible');
- await approveExpectSuccess(reFungibleCollectionId, newReFungibleTokenId, alice, bob.address, 100);
- await transferFromExpectSuccess(
- reFungibleCollectionId,
- newReFungibleTokenId,
- bob,
- alice,
- charlie,
- 100,
- 'ReFungible',
- );
- });
+ it('[refungible] Execute the extrinsic and check nftItemList - owner of token', async function() {
+ await requirePallets(this, [Pallets.ReFungible]);
+
+ const reFungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
+ const newReFungibleTokenId = await createItemExpectSuccess(alice, reFungibleCollectionId, 'ReFungible');
+ await approveExpectSuccess(reFungibleCollectionId, newReFungibleTokenId, alice, bob.address, 100);
+ await transferFromExpectSuccess(
+ reFungibleCollectionId,
+ newReFungibleTokenId,
+ bob,
+ alice,
+ charlie,
+ 100,
+ 'ReFungible',
+ );
});
it('Should reduce allowance if value is big', async () => {
@@ -119,20 +121,28 @@
});
});
- it('transferFrom for a collection that does not exist', async () => {
+ it('[nft] transferFrom for a collection that does not exist', async () => {
await usingApi(async (api: ApiPromise) => {
- // nft
const nftCollectionCount = await getCreatedCollectionCount(api);
await approveExpectFail(nftCollectionCount + 1, 1, alice, bob);
await transferFromExpectFail(nftCollectionCount + 1, 1, bob, alice, charlie, 1);
+ });
+ });
- // fungible
+ it('[fungible] transferFrom for a collection that does not exist', async () => {
+ await usingApi(async (api: ApiPromise) => {
const fungibleCollectionCount = await getCreatedCollectionCount(api);
await approveExpectFail(fungibleCollectionCount + 1, 0, alice, bob);
await transferFromExpectFail(fungibleCollectionCount + 1, 0, bob, alice, charlie, 1);
- // reFungible
+ });
+ });
+
+ it('[refungible] transferFrom for a collection that does not exist', async function() {
+ await requirePallets(this, [Pallets.ReFungible]);
+
+ await usingApi(async (api: ApiPromise) => {
const reFungibleCollectionCount = await getCreatedCollectionCount(api);
await approveExpectFail(reFungibleCollectionCount + 1, 1, alice, bob);
@@ -158,67 +168,70 @@
});
}); */
- it('transferFrom for not approved address', async () => {
- await usingApi(async () => {
- // nft
- const nftCollectionId = await createCollectionExpectSuccess();
- const newNftTokenId = await createItemExpectSuccess(alice, nftCollectionId, 'NFT');
+ it('[nft] transferFrom for not approved address', async () => {
+ const nftCollectionId = await createCollectionExpectSuccess();
+ const newNftTokenId = await createItemExpectSuccess(alice, nftCollectionId, 'NFT');
- await transferFromExpectFail(nftCollectionId, newNftTokenId, bob, alice, charlie, 1);
+ await transferFromExpectFail(nftCollectionId, newNftTokenId, bob, alice, charlie, 1);
+ });
- // fungible
- const fungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});
- const newFungibleTokenId = await createItemExpectSuccess(alice, fungibleCollectionId, 'Fungible');
- await transferFromExpectFail(fungibleCollectionId, newFungibleTokenId, bob, alice, charlie, 1);
- // reFungible
- const reFungibleCollectionId = await
- createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
- const newReFungibleTokenId = await createItemExpectSuccess(alice, reFungibleCollectionId, 'ReFungible');
- await transferFromExpectFail(
- reFungibleCollectionId,
- newReFungibleTokenId,
- bob,
- alice,
- charlie,
- 1,
- );
- });
+ it('[fungible] transferFrom for not approved address', async () => {
+ const fungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});
+ const newFungibleTokenId = await createItemExpectSuccess(alice, fungibleCollectionId, 'Fungible');
+ await transferFromExpectFail(fungibleCollectionId, newFungibleTokenId, bob, alice, charlie, 1);
+ });
+
+ it('[refungible] transferFrom for not approved address', async function() {
+ await requirePallets(this, [Pallets.ReFungible]);
+
+ const reFungibleCollectionId = await
+ createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
+ const newReFungibleTokenId = await createItemExpectSuccess(alice, reFungibleCollectionId, 'ReFungible');
+ await transferFromExpectFail(
+ reFungibleCollectionId,
+ newReFungibleTokenId,
+ bob,
+ alice,
+ charlie,
+ 1,
+ );
+ });
+
+ it('[nft] transferFrom incorrect token count', async () => {
+ const nftCollectionId = await createCollectionExpectSuccess();
+ const newNftTokenId = await createItemExpectSuccess(alice, nftCollectionId, 'NFT');
+ await approveExpectSuccess(nftCollectionId, newNftTokenId, alice, bob.address);
+
+ await transferFromExpectFail(nftCollectionId, newNftTokenId, bob, alice, charlie, 2);
});
- it('transferFrom incorrect token count', async () => {
- await usingApi(async () => {
- // nft
- const nftCollectionId = await createCollectionExpectSuccess();
- const newNftTokenId = await createItemExpectSuccess(alice, nftCollectionId, 'NFT');
- await approveExpectSuccess(nftCollectionId, newNftTokenId, alice, bob.address);
+ it('[fungible] transferFrom incorrect token count', async () => {
+ const fungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});
+ const newFungibleTokenId = await createItemExpectSuccess(alice, fungibleCollectionId, 'Fungible');
+ await approveExpectSuccess(fungibleCollectionId, newFungibleTokenId, alice, bob.address);
+ await transferFromExpectFail(fungibleCollectionId, newFungibleTokenId, bob, alice, charlie, 2);
+ });
- await transferFromExpectFail(nftCollectionId, newNftTokenId, bob, alice, charlie, 2);
+ it('[refungible] transferFrom incorrect token count', async function() {
+ await requirePallets(this, [Pallets.ReFungible]);
- // fungible
- const fungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});
- const newFungibleTokenId = await createItemExpectSuccess(alice, fungibleCollectionId, 'Fungible');
- await approveExpectSuccess(fungibleCollectionId, newFungibleTokenId, alice, bob.address);
- await transferFromExpectFail(fungibleCollectionId, newFungibleTokenId, bob, alice, charlie, 2);
- // reFungible
- const reFungibleCollectionId = await
- createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
- const newReFungibleTokenId = await createItemExpectSuccess(alice, reFungibleCollectionId, 'ReFungible');
- await approveExpectSuccess(reFungibleCollectionId, newReFungibleTokenId, alice, bob.address);
- await transferFromExpectFail(
- reFungibleCollectionId,
- newReFungibleTokenId,
- bob,
- alice,
- charlie,
- 2,
- );
- });
+ const reFungibleCollectionId = await
+ createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
+ const newReFungibleTokenId = await createItemExpectSuccess(alice, reFungibleCollectionId, 'ReFungible');
+ await approveExpectSuccess(reFungibleCollectionId, newReFungibleTokenId, alice, bob.address);
+ await transferFromExpectFail(
+ reFungibleCollectionId,
+ newReFungibleTokenId,
+ bob,
+ alice,
+ charlie,
+ 2,
+ );
});
- it('execute transferFrom from account that is not owner of collection', async () => {
+ it('[nft] execute transferFrom from account that is not owner of collection', async () => {
await usingApi(async (api, privateKeyWrapper) => {
const dave = privateKeyWrapper('//Dave');
- // nft
const nftCollectionId = await createCollectionExpectSuccess();
const newNftTokenId = await createItemExpectSuccess(alice, nftCollectionId, 'NFT');
try {
@@ -230,8 +243,13 @@
}
// await transferFromExpectFail(nftCollectionId, newNftTokenId, Dave, Alice, Charlie, 1);
+ });
+ });
- // fungible
+ it('[fungible] execute transferFrom from account that is not owner of collection', async () => {
+ await usingApi(async (api, privateKeyWrapper) => {
+ const dave = privateKeyWrapper('//Dave');
+
const fungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});
const newFungibleTokenId = await createItemExpectSuccess(alice, fungibleCollectionId, 'Fungible');
try {
@@ -241,7 +259,14 @@
// tslint:disable-next-line:no-unused-expression
expect(e).to.be.exist;
}
- // reFungible
+ });
+ });
+
+ it('[refungible] execute transferFrom from account that is not owner of collection', async function() {
+ await requirePallets(this, [Pallets.ReFungible]);
+
+ await usingApi(async (api, privateKeyWrapper) => {
+ const dave = privateKeyWrapper('//Dave');
const reFungibleCollectionId = await
createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
const newReFungibleTokenId = await createItemExpectSuccess(alice, reFungibleCollectionId, 'ReFungible');
@@ -276,7 +301,9 @@
});
});
- it('transferFrom burnt token before approve ReFungible', async () => {
+ it('transferFrom burnt token before approve ReFungible', async function() {
+ await requirePallets(this, [Pallets.ReFungible]);
+
await usingApi(async () => {
const reFungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
await setCollectionLimitsExpectSuccess(alice, reFungibleCollectionId, {ownerCanTransfer: true});
@@ -308,7 +335,9 @@
});
});
- it('transferFrom burnt token after approve ReFungible', async () => {
+ it('transferFrom burnt token after approve ReFungible', async function() {
+ await requirePallets(this, [Pallets.ReFungible]);
+
await usingApi(async () => {
const reFungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
const newReFungibleTokenId = await createItemExpectSuccess(alice, reFungibleCollectionId, 'ReFungible');
tests/src/util/helpers.tsdiffbeforeafterboth--- a/tests/src/util/helpers.ts
+++ b/tests/src/util/helpers.ts
@@ -28,6 +28,7 @@
import {hexToStr, strToUTF16, utf16ToStr} from './util';
import {UpDataStructsRpcCollection, UpDataStructsCreateItemData, UpDataStructsProperty} from '@polkadot/types/lookup';
import {UpDataStructsTokenChild} from '../interfaces';
+import {Context} from 'mocha';
chai.use(chaiAsPromised);
const expect = chai.expect;
@@ -38,6 +39,66 @@
Ethereum: string,
};
+
+export enum Pallets {
+ Inflation = 'inflation',
+ RmrkCore = 'rmrkcore',
+ RmrkEquip = 'rmrkequip',
+ ReFungible = 'refungible',
+ Fungible = 'fungible',
+ NFT = 'nonfungible',
+ Scheduler = 'scheduler',
+}
+
+export async function isUnique(): Promise<boolean> {
+ return usingApi(async api => {
+ const chain = await api.rpc.system.chain();
+
+ return chain.eq('UNIQUE');
+ });
+}
+
+export async function isQuartz(): Promise<boolean> {
+ return usingApi(async api => {
+ const chain = await api.rpc.system.chain();
+
+ return chain.eq('QUARTZ');
+ });
+}
+
+let modulesNames: any;
+export function getModuleNames(api: ApiPromise): string[] {
+ if (typeof modulesNames === 'undefined')
+ modulesNames = api.runtimeMetadata.asLatest.pallets.map(m => m.name.toString().toLowerCase());
+ return modulesNames;
+}
+
+export async function missingRequiredPallets(requiredPallets: string[]): Promise<string[]> {
+ return await usingApi(async api => {
+ const pallets = getModuleNames(api);
+
+ return requiredPallets.filter(p => !pallets.includes(p));
+ });
+}
+
+export async function checkPalletsPresence(requiredPallets: string[]): Promise<boolean> {
+ return (await missingRequiredPallets(requiredPallets)).length == 0;
+}
+
+export async function requirePallets(mocha: Context, requiredPallets: string[]) {
+ const missingPallets = await missingRequiredPallets(requiredPallets);
+
+ if (missingPallets.length > 0) {
+ const skippingTestMsg = `\tSkipping test "${mocha.test?.title}".`;
+ const missingPalletsMsg = `\tThe following pallets are missing:\n\t- ${missingPallets.join('\n\t- ')}`;
+ const skipMsg = `${skippingTestMsg}\n${missingPalletsMsg}`;
+
+ console.error('\x1b[38:5:208m%s\x1b[0m', skipMsg);
+
+ mocha.skip();
+ }
+}
+
export function normalizeAccountId(input: string | AccountId | CrossAccountId | IKeyringPair): CrossAccountId {
if (typeof input === 'string') {
if (input.length >= 47) {