From 282c701e6ebe8afb6ad7e8a7535312527ef9b832 Mon Sep 17 00:00:00 2001 From: Yaroslav Bolyukin Date: Thu, 11 Aug 2022 13:18:31 +0000 Subject: [PATCH] Merge pull request #462 from UniqueNetwork/fix/pallets_disabled --- --- 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 = [ --- 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" } --- 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' --- 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; --- 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) => { --- 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::{ --- 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" } --- 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, --- a/pallets/common/src/lib.rs +++ b/pallets/common/src/lib.rs @@ -535,7 +535,8 @@ /// Can't transfer tokens to ethereum zero address AddressIsZero, - /// Target collection doesn't support this operation + + /// The oprtation is not supported UnsupportedOperation, /// Insufficient funds to perform an action @@ -1353,8 +1354,8 @@ /// Indicates unsupported methods by returning [Error::UnsupportedOperation]. #[macro_export] macro_rules! unsupported { - () => { - Err(>::UnsupportedOperation.into()) + ($runtime:path) => { + Err($crate::Error::<$runtime>::UnsupportedOperation.into()) }; } --- /dev/null +++ b/primitives/common/Cargo.toml @@ -0,0 +1,56 @@ +[package] +authors = ['Unique Network '] +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" --- /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 . + +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; +} --- /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 . + +#![cfg_attr(not(feature = "std"), no_std)] + +pub mod constants; +pub mod types; --- /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 . + +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; + + /// Opaque block type. + pub type Block = generic::Block; + + pub trait RuntimeInstance { + type CrossAccountId: pallet_evm::account::CrossAccountId + + Send + + Sync + + 'static; + + type TransactionConverter: fp_rpc::ConvertTransaction + + 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 = <::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; --- a/runtime/common/Cargo.toml +++ /dev/null @@ -1,115 +0,0 @@ -[package] -authors = ['Unique Network '] -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" } --- /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; + +impl pallet_evm::account::Config for Runtime { + type CrossAccountId = CrossAccountId; + type EvmAddressMapping = pallet_evm::HashedAddressMapping; + 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 / ::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(core::marker::PhantomData); +impl> FindAuthor for EthereumFindAuthor { + fn find_author<'a, I>(digests: I) -> Option + where + I: 'a + IntoIterator, + { + 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; + type CallOrigin = EnsureAddressTruncated; + type WithdrawOrigin = EnsureAddressTruncated; + type AddressMapping = HashedAddressMapping; + type PrecompilesType = (); + type PrecompilesValue = (); + type Currency = Balances; + type Event = Event; + type OnMethodCall = ( + pallet_evm_migration::OnMethodCall, + pallet_evm_contract_helpers::HelpersOnMethodCall, + CollectionDispatchT, + pallet_unique::eth::CollectionHelpersOnMethodCall, + ); + type OnCreate = pallet_evm_contract_helpers::HelpersOnCreate; + type ChainId = ChainId; + type Runner = pallet_evm::runner::stack::Runner; + type OnChargeTransaction = pallet_evm::EVMCurrencyAdapter; + type TransactionValidityHack = pallet_evm_transaction_payment::TransactionValidityHack; + type FindAuthor = EthereumFindAuthor; +} + +impl pallet_evm_migration::Config for Runtime { + type WeightInfo = pallet_evm_migration::weights::SubstrateWeight; +} + +impl pallet_ethereum::Config for Runtime { + type Event = Event; + type StateRoot = pallet_ethereum::IntermediateStateRoot; +} + +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; +} --- /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 . + +pub mod ethereum; +pub mod orml; +pub mod pallets; +pub mod parachain; +pub mod sponsoring; +pub mod substrate; +pub mod xcm; --- /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 . + +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; + type MinVestedTransfer = MinVestedTransfer; + type VestedTransferOrigin = EnsureSigned; + type WeightInfo = (); + type MaxVestingSchedules = MaxVestingSchedules; + type BlockNumberProvider = RelayChainBlockNumberProvider; +} --- /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 . + +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; + type Event = Event; + type Currency = Balances; + type CollectionCreationPrice = CollectionCreationPrice; + type TreasuryAccountId = TreasuryAccountId; + type CollectionDispatch = CollectionDispatchT; + + type EvmTokenAddressMapping = EvmTokenAddressMapping; + type CrossTokenAddressMapping = CrossTokenAddressMapping; + type ContractAddress = EvmCollectionHelpersAddress; +} + +impl pallet_structure::Config for Runtime { + type Event = Event; + type Call = Call; + type WeightInfo = pallet_structure::weights::SubstrateWeight; +} + +impl pallet_fungible::Config for Runtime { + type WeightInfo = pallet_fungible::weights::SubstrateWeight; +} +impl pallet_refungible::Config for Runtime { + type WeightInfo = pallet_refungible::weights::SubstrateWeight; +} +impl pallet_nonfungible::Config for Runtime { + type WeightInfo = pallet_nonfungible::weights::SubstrateWeight; +} + +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; +} + +impl pallet_unique::Config for Runtime { + type Event = Event; + type WeightInfo = pallet_unique::weights::SubstrateWeight; + type CommonWeightInfo = CommonWeights; + type RefungibleExtensionsWeightInfo = CommonWeights; +} --- /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 . + +use crate::{Runtime, Event}; + +impl pallet_proxy_rmrk_core::Config for Runtime { + type WeightInfo = pallet_proxy_rmrk_core::weights::SubstrateWeight; + type Event = Event; +} + +impl pallet_proxy_rmrk_equip::Config for Runtime { + type WeightInfo = pallet_proxy_rmrk_equip::weights::SubstrateWeight; + type Event = Event; +} --- /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 . + +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 = Some(10); + pub const Preimage: Option = Some(10); +} + +/// Used the compare the privilege of an origin inside the scheduler. +pub struct OriginPrivilegeCmp; + +impl PrivilegeCmp for OriginPrivilegeCmp { + fn cmp_privilege(_left: &OriginCaller, _right: &OriginCaller) -> Option { + 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; + type MaxScheduledPerBlock = MaxScheduledPerBlock; + type WeightInfo = (); + type CallExecutor = SchedulerPaymentExecutor; + type OriginPrivilegeCmp = OriginPrivilegeCmp; + type PreimageProvider = (); + type NoPreimagePostponement = NoPreimagePostponement; +} --- /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 . + +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; + type OnSystemEvent = (); + // type DownwardMessageHandlers = cumulus_primitives_utility::UnqueuedDmpAsParent< + // MaxDownwardMessageWeight, + // XcmExecutor, + // 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 {} --- /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 . + +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, + pallet_evm_transaction_payment::BridgeSponsorshipHandler, +); + +impl pallet_charge_transaction::Config for Runtime { + type SponsorshipHandler = SponsorshipHandler; +} --- /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 . + +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; + /// 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; + /// 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; + /// 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; + /// 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; + /// 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; +} + +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(sp_std::marker::PhantomData); + +impl WeightToFeePolynomial for LinearFee +where + T: BaseArithmetic + From + Copy + Unsigned, +{ + type Balance = T; + + fn polynomial() -> WeightToFeeCoefficients { + 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; + type LengthToFee = ConstantMultiplier; + type OperationalFeeMultiplier = OperationalFeeMultiplier; + type WeightToFee = LinearFee; + 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; + type RejectOrigin = EnsureRoot; + 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; + 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; +} --- /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 . + +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, + // Sibling parachain origins convert to AccountId via the `ParaId::into`. + SiblingParachainConvertsVia, + // Straight up local `AccountId32` origins just alias directly to `AccountId`. + AccountId32Aliases, +); + +pub struct OnlySelfCurrency; +impl> MatchesFungible for OnlySelfCurrency { + fn matches_fungible(a: &MultiAsset) -> Option { + 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,); + +/// 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, + // ..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, + // Native converter for Relay-chain (Parent) location; will converts to a `Relay` origin when + // recognised. + RelayChainAsNative, + // Native converter for sibling Parachains; will convert to a `SiblingPara` origin when + // recognised. + SiblingParachainAsNative, + // Superuser converter for the Relay-chain (Parent) location. This will allow it to issue a + // transaction from the Root origin. + ParentAsSuperuser, + // Native signed account converter; this just converts an `AccountId32` origin into a normal + // `Origin::Signed` origin of the same 32-byte value. + SignedAccountId32AsNative, + // Xcm origins can be represented natively under the Xcm pallet's Xcm origin. + XcmPassthrough, +); + +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 { parents: 1, interior: Here } | + MultiLocation { parents: 1, interior: X1(Plurality { id: BodyId::Unit, .. }) } + }; +} + +pub type Barrier = ( + TakeWeightCredit, + AllowTopLevelPaidExecutionFrom, + // ^^^ Parent & its unit plurality gets free execution +); + +pub struct UsingOnlySelfCurrencyComponents< + WeightToFee: WeightToFeePolynomial, + AssetId: Get, + AccountId, + Currency: CurrencyT, + OnUnbalanced: OnUnbalancedT, +>( + Weight, + Currency::Balance, + PhantomData<(WeightToFee, AssetId, AccountId, Currency, OnUnbalanced)>, +); +impl< + WeightToFee: WeightToFeePolynomial, + AssetId: Get, + AccountId, + Currency: CurrencyT, + OnUnbalanced: OnUnbalancedT, + > WeightTrader + for UsingOnlySelfCurrencyComponents +{ + fn new() -> Self { + Self(0, Zero::zero(), PhantomData) + } + + fn buy_weight(&mut self, weight: Weight, payment: Assets) -> Result { + 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 { + 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, + AssetId: Get, + AccountId, + Currency: CurrencyT, + OnUnbalanced: OnUnbalancedT, + > Drop + for UsingOnlySelfCurrencyComponents +{ + 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; + type Barrier = Barrier; + type Weigher = FixedWeightBounds; + type Trader = + UsingOnlySelfCurrencyComponents, 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; + type XcmRouter = XcmRouter; + type ExecuteXcmOrigin = EnsureXcmOrigin; + type XcmExecuteFilter = Everything; + type XcmExecutor = XcmExecutor; + type XcmTeleportFilter = Everything; + type XcmReserveTransferFilter = Everything; + type Weigher = FixedWeightBounds; + type LocationInverter = LocationInverter; + 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; +} + +impl cumulus_pallet_xcmp_queue::Config for Runtime { + type WeightInfo = (); + type Event = Event; + type XcmExecutor = XcmExecutor; + type ChannelInfo = ParachainSystem; + type VersionWrapper = (); + type ExecuteOverweightOrigin = frame_system::EnsureRoot; + type ControllerOrigin = EnsureRoot; + type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin; +} + +impl cumulus_pallet_dmp_queue::Config for Runtime { + type Event = Event; + type XcmExecutor = XcmExecutor; + type ExecuteOverweightOrigin = frame_system::EnsureRoot; +} --- /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 . + +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; +} --- /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 . + +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, ValidateUnsigned} = 20, + ParachainInfo: parachain_info::{Pallet, Storage, Config} = 21, + + Aura: pallet_aura::{Pallet, Config} = 22, + AuraExt: cumulus_pallet_aura_ext::{Pallet, Config} = 23, + + Balances: pallet_balances::{Pallet, Call, Storage, Config, Event} = 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} = 34, + Sudo: pallet_sudo::{Pallet, Call, Storage, Config, Event} = 35, + System: frame_system::{Pallet, Call, Storage, Config, Event} = 36, + Vesting: orml_vesting::{Pallet, Storage, Call, Event, Config} = 37, + // Vesting: pallet_vesting::{Pallet, Call, Config, Storage, Event} = 37, + // Contracts: pallet_contracts::{Pallet, Call, Storage, Event} = 38, + + // XCM helpers. + XcmpQueue: cumulus_pallet_xcmp_queue::{Pallet, Call, Storage, Event} = 50, + PolkadotXcm: pallet_xcm::{Pallet, Call, Event, Origin} = 51, + CumulusXcm: cumulus_pallet_xcm::{Pallet, Call, Event, Origin} = 52, + DmpQueue: cumulus_pallet_dmp_queue::{Pallet, Call, Storage, Event} = 53, + + // Unique Pallets + Inflation: pallet_inflation::{Pallet, Call, Storage} = 60, + Unique: pallet_unique::{Pallet, Call, Storage, Event} = 61, + + #[runtimes(opal)] + Scheduler: pallet_unique_scheduler::{Pallet, Call, Storage, Event} = 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} = 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} = 70, + + #[runtimes(opal)] + RmrkCore: pallet_proxy_rmrk_core::{Pallet, Call, Storage, Event} = 71, + + #[runtimes(opal)] + RmrkEquip: pallet_proxy_rmrk_equip::{Pallet, Call, Storage, Event} = 72, + + // Frontier + EVM: pallet_evm::{Pallet, Config, Call, Storage, Event} = 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, + } + } + } +} --- /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 . + +#[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)*) + } + }; +} --- /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 . + +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 +where + T: pallet_fungible::Config + pallet_nonfungible::Config + pallet_refungible::Config, +{ + Fungible(FungibleHandle), + Nonfungible(NonfungibleHandle), + Refungible(RefungibleHandle), +} +impl CollectionDispatch for CollectionDispatchT +where + T: pallet_common::Config + + pallet_unique::Config + + pallet_fungible::Config + + pallet_nonfungible::Config + + pallet_refungible::Config, +{ + fn create( + sender: T::CrossAccountId, + data: CreateCollectionData, + ) -> Result { + let id = match data.mode { + CollectionMode::NFT => >::init_collection(sender, data, false)?, + CollectionMode::Fungible(decimal_points) => { + // check params + ensure!( + decimal_points <= MAX_DECIMAL_POINTS, + pallet_unique::Error::::CollectionDecimalPointLimitExceeded + ); + >::init_collection(sender, data)? + } + + #[cfg(feature = "refungible")] + CollectionMode::ReFungible => >::init_collection(sender, data)?, + + #[cfg(not(feature = "refungible"))] + CollectionMode::ReFungible => return unsupported!(T), + }; + Ok(id) + } + + fn destroy(sender: T::CrossAccountId, collection: CollectionHandle) -> 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) -> 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 { + 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 { + match self { + Self::Fungible(h) => h, + Self::Nonfungible(h) => h, + Self::Refungible(h) => h, + } + } +} + +impl pallet_evm::OnMethodCall for CollectionDispatchT +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(>::contains_key) + .unwrap_or(false) + } + fn get_code(target: &H160) -> Option> { + if let Some(collection_id) = map_eth_to_id(target) { + let collection = >::get(collection_id)?; + Some( + match collection.mode { + CollectionMode::NFT => >::CODE, + CollectionMode::Fungible(_) => >::CODE, + CollectionMode::ReFungible => >::CODE, + } + .to_owned(), + ) + } else if let Some((collection_id, _token_id)) = + ::EvmTokenAddressMapping::address_to_token(target) + { + let collection = >::get(collection_id)?; + if collection.mode != CollectionMode::ReFungible { + return None; + } + // TODO: check token existence + Some(>::CODE.to_owned()) + } else { + None + } + } + fn call(handle: &mut impl PrecompileHandle) -> Option { + if let Some(collection_id) = map_eth_to_id(&handle.code_address()) { + let collection = + >::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)) = + ::EvmTokenAddressMapping::address_to_token( + &handle.code_address(), + ) { + let collection = + >::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 + } + } +} --- /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 . + +pub mod self_contained_call; +pub mod sponsoring; +pub mod transaction_converter; --- /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 . + +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> { + match self { + Call::Ethereum(call) => call.check_self_contained(), + _ => None, + } + } + + fn validate_self_contained( + &self, + info: &Self::SignedInfo, + dispatch_info: &DispatchInfoOf, + len: usize, + ) -> Option { + match self { + Call::Ethereum(call) => call.validate_self_contained(info, dispatch_info, len), + _ => None, + } + } + + fn pre_dispatch_self_contained( + &self, + info: &Self::SignedInfo, + ) -> Option> { + match self { + Call::Ethereum(call) => call.pre_dispatch_self_contained(info), + _ => None, + } + } + + fn apply_self_contained( + self, + info: Self::SignedInfo, + ) -> Option>> { + match self { + call @ Call::Ethereum(pallet_ethereum::Call::transact { .. }) => Some(call.dispatch( + Origin::from(pallet_ethereum::RawOrigin::EthereumTransaction(info)), + )), + _ => None, + } + } +} --- /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 . + +//! 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, + pallet_evm_contract_helpers::HelpersContractSponsoring, +); + +pub struct UniqueEthSponsorshipHandler(PhantomData<*const T>); +impl + SponsorshipHandler)> for UniqueEthSponsorshipHandler +{ + fn get_sponsor(who: &T::CrossAccountId, call: &(H160, Vec)) -> Option { + let collection_id = map_eth_to_id(&call.0)?; + let collection = >::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 = >::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::( + &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::(&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::( + &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::(&collection, &from, &token_id).map(|()| sponsor) + } + UniqueNFTCall::ERC721(ERC721Call::Approve { token_id, .. }) => { + let token_id: TokenId = token_id.try_into().ok()?; + withdraw_approve::(&collection, who.as_sub(), &token_id) + .map(|()| sponsor) + } + _ => None, + } + } + CollectionMode::Fungible(_) => { + let call = >::parse(method_id, &mut reader).ok()??; + #[allow(clippy::single_match)] + match call { + UniqueFungibleCall::ERC20(ERC20Call::Transfer { .. }) => { + withdraw_transfer::(&collection, who, &TokenId::default()) + .map(|()| sponsor) + } + UniqueFungibleCall::ERC20(ERC20Call::TransferFrom { from, .. }) => { + let from = T::CrossAccountId::from_eth(from); + withdraw_transfer::(&collection, &from, &TokenId::default()) + .map(|()| sponsor) + } + UniqueFungibleCall::ERC20(ERC20Call::Approve { .. }) => { + withdraw_approve::(&collection, who.as_sub(), &TokenId::default()) + .map(|()| sponsor) + } + _ => None, + } + } + _ => None, + }?)) + } +} --- /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 . + +use codec::{Encode, Decode}; +use crate::{opaque, Runtime, UncheckedExtrinsic}; + +pub struct TransactionConverter; + +impl fp_rpc::ConvertTransaction for TransactionConverter { + fn convert_transaction(&self, transaction: pallet_ethereum::Transaction) -> UncheckedExtrinsic { + UncheckedExtrinsic::new_unsigned( + pallet_ethereum::Call::::transact { transaction }.into(), + ) + } +} + +impl fp_rpc::ConvertTransaction for TransactionConverter { + fn convert_transaction( + &self, + transaction: pallet_ethereum::Transaction, + ) -> opaque::UncheckedExtrinsic { + let extrinsic = UncheckedExtrinsic::new_unsigned( + pallet_ethereum::Call::::transact { transaction }.into(), + ); + let encoded = extrinsic.encode(); + opaque::UncheckedExtrinsic::decode(&mut &encoded[..]) + .expect("Encoded extrinsic is always valid") + } +} --- /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 + } +} --- /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 . + +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; +/// Block header type as expected by this runtime. +pub type Header = generic::Header; +/// Block type as expected by this runtime. +pub type Block = generic::Block; +/// A Block signed with a Justification +pub type SignedBlock = generic::SignedBlock; +/// BlockId type as expected by this runtime. +pub type BlockId = generic::BlockId; + +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; + +pub type SignedExtra = ( + frame_system::CheckSpecVersion, + // system::CheckTxVersion, + frame_system::CheckGenesis, + frame_system::CheckEra, + frame_system::CheckNonce, + frame_system::CheckWeight, + ChargeTransactionPayment, + //pallet_contract_helpers::ContractHelpersExtension, + pallet_ethereum::FakeTransactionFinalizer, +); + +/// Unchecked extrinsic type as expected by this runtime. +pub type UncheckedExtrinsic = + fp_self_contained::UncheckedExtrinsic; + +/// Extrinsic type that has already been checked. +pub type CheckedExtrinsic = fp_self_contained::CheckedExtrinsic; + +/// Executive: handles dispatch to the various modules. +pub type Executive = frame_executive::Executive< + Runtime, + Block, + frame_system::ChainContext, + Runtime, + AllPalletsReversedWithSystemFirst, +>; + +type NegativeImbalance = >::NegativeImbalance; + +pub struct DealWithFees; +impl OnUnbalanced for DealWithFees { + fn on_unbalanceds(mut fees_then_tips: impl Iterator) { + 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(sp_std::marker::PhantomData); + +impl BlockNumberProvider + for RelayChainBlockNumberProvider +{ + type BlockNumber = BlockNumber; + + fn current_block_number() -> Self::BlockNumber { + cumulus_pallet_parachain_system::Pallet::::validation_data() + .map(|d| d.relay_parent_number) + .unwrap_or_default() + } +} + +pub(crate) struct CheckInherents; + +impl cumulus_pallet_parachain_system::CheckInherents 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 { + /// Transfer tokens to the given account from the Parachain account. + TransferToken(XAccountId, XBalance), +} --- /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 . + +#[macro_export] +macro_rules! dispatch_unique_runtime { + ($collection:ident.$method:ident($($name:ident),*)) => {{ + let collection = ::CollectionDispatch::dispatch(>::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 for Runtime { + fn account_tokens(collection: CollectionId, account: CrossAccountId) -> Result, DispatchError> { + dispatch_unique_runtime!(collection.account_tokens(account)) + } + fn collection_tokens(collection: CollectionId) -> Result, DispatchError> { + dispatch_unique_runtime!(collection.collection_tokens()) + } + fn token_exists(collection: CollectionId, token: TokenId) -> Result { + dispatch_unique_runtime!(collection.token_exists(token)) + } + + fn token_owner(collection: CollectionId, token: TokenId) -> Result, DispatchError> { + dispatch_unique_runtime!(collection.token_owner(token)) + } + + fn token_owners(collection: CollectionId, token: TokenId) -> Result, DispatchError> { + dispatch_unique_runtime!(collection.token_owners(token)) + } + + fn topmost_token_owner(collection: CollectionId, token: TokenId) -> Result, DispatchError> { + let budget = up_data_structs::budget::Value::new(10); + + Ok(Some(>::find_topmost_owner(collection, token, &budget)?)) + } + fn token_children(collection: CollectionId, token: TokenId) -> Result, DispatchError> { + Ok(>::token_children_ids(collection, token)) + } + fn collection_properties( + collection: CollectionId, + keys: Option>> + ) -> Result, 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>> + ) -> Result, 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>> + ) -> Result, 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>> + ) -> Result, 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 { + dispatch_unique_runtime!(collection.total_supply()) + } + fn account_balance(collection: CollectionId, account: CrossAccountId) -> Result { + dispatch_unique_runtime!(collection.account_balance(account)) + } + fn balance(collection: CollectionId, account: CrossAccountId, token: TokenId) -> Result { + dispatch_unique_runtime!(collection.balance(account, token)) + } + fn allowance( + collection: CollectionId, + sender: CrossAccountId, + spender: CrossAccountId, + token: TokenId, + ) -> Result { + dispatch_unique_runtime!(collection.allowance(sender, spender, token)) + } + + fn adminlist(collection: CollectionId) -> Result, DispatchError> { + Ok(>::adminlist(collection)) + } + fn allowlist(collection: CollectionId) -> Result, DispatchError> { + Ok(>::allowlist(collection)) + } + fn allowed(collection: CollectionId, user: CrossAccountId) -> Result { + Ok(>::allowed(collection, user)) + } + fn last_token_id(collection: CollectionId) -> Result { + dispatch_unique_runtime!(collection.last_token_id()) + } + fn collection_by_id(collection: CollectionId) -> Result>, DispatchError> { + Ok(>::rpc_collection(collection)) + } + fn collection_stats() -> Result { + Ok(>::collection_stats()) + } + fn next_sponsored(collection: CollectionId, account: CrossAccountId, token: TokenId) -> Result, DispatchError> { + Ok( as SponsorshipPredict>::predict( + collection, + account, + token + )) + } + + fn effective_collection_limits(collection: CollectionId) -> Result, DispatchError> { + Ok(>::effective_collection_limits(collection)) + } + + fn total_pieces(collection: CollectionId, token_id: TokenId) -> Result, DispatchError> { + dispatch_unique_runtime!(collection.total_pieces(token_id)) + } + } + + impl rmrk_rpc::RmrkApi< + Block, + AccountId, + RmrkCollectionInfo, + RmrkInstanceInfo, + RmrkResourceInfo, + RmrkPropertyInfo, + RmrkBaseInfo, + RmrkPartType, + RmrkTheme + > for Runtime { + fn last_collection_idx() -> Result { + #[cfg(feature = "rmrk")] + return pallet_proxy_rmrk_core::rpc::last_collection_idx::(); + + #[cfg(not(feature = "rmrk"))] + return unsupported!(); + } + + #[allow(unused_variables)] + fn collection_by_id(collection_id: RmrkCollectionId) -> Result>, DispatchError> { + #[cfg(feature = "rmrk")] + return pallet_proxy_rmrk_core::rpc::collection_by_id::(collection_id); + + #[cfg(not(feature = "rmrk"))] + return unsupported!(); + } + + #[allow(unused_variables)] + fn nft_by_id(collection_id: RmrkCollectionId, nft_by_id: RmrkNftId) -> Result>, DispatchError> { + #[cfg(feature = "rmrk")] + return pallet_proxy_rmrk_core::rpc::nft_by_id::(collection_id, nft_by_id); + + #[cfg(not(feature = "rmrk"))] + return unsupported!(); + } + + #[allow(unused_variables)] + fn account_tokens(account_id: AccountId, collection_id: RmrkCollectionId) -> Result, DispatchError> { + #[cfg(feature = "rmrk")] + return pallet_proxy_rmrk_core::rpc::account_tokens::(account_id, collection_id); + + #[cfg(not(feature = "rmrk"))] + return unsupported!(); + } + + #[allow(unused_variables)] + fn nft_children(collection_id: RmrkCollectionId, nft_id: RmrkNftId) -> Result, DispatchError> { + #[cfg(feature = "rmrk")] + return pallet_proxy_rmrk_core::rpc::nft_children::(collection_id, nft_id); + + #[cfg(not(feature = "rmrk"))] + return unsupported!(); + } + + #[allow(unused_variables)] + fn collection_properties( + collection_id: RmrkCollectionId, + filter_keys: Option> + ) -> Result, DispatchError> { + #[cfg(feature = "rmrk")] + return pallet_proxy_rmrk_core::rpc::collection_properties::(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> + ) -> Result, DispatchError> { + #[cfg(feature = "rmrk")] + return pallet_proxy_rmrk_core::rpc::nft_properties::(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, DispatchError> { + #[cfg(feature = "rmrk")] + return pallet_proxy_rmrk_core::rpc::nft_resources::(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, DispatchError> { + #[cfg(feature = "rmrk")] + return pallet_proxy_rmrk_core::rpc::nft_resource_priority::(collection_id, nft_id, resource_id); + + #[cfg(not(feature = "rmrk"))] + return unsupported!(); + } + + #[allow(unused_variables)] + fn base(base_id: RmrkBaseId) -> Result>, DispatchError> { + #[cfg(feature = "rmrk")] + return pallet_proxy_rmrk_equip::rpc::base::(base_id); + + #[cfg(not(feature = "rmrk"))] + return unsupported!(); + } + + #[allow(unused_variables)] + fn base_parts(base_id: RmrkBaseId) -> Result, DispatchError> { + #[cfg(feature = "rmrk")] + return pallet_proxy_rmrk_equip::rpc::base_parts::(base_id); + + #[cfg(not(feature = "rmrk"))] + return unsupported!(); + } + + #[allow(unused_variables)] + fn theme_names(base_id: RmrkBaseId) -> Result, DispatchError> { + #[cfg(feature = "rmrk")] + return pallet_proxy_rmrk_equip::rpc::theme_names::(base_id); + + #[cfg(not(feature = "rmrk"))] + return unsupported!(); + } + + #[allow(unused_variables)] + fn theme( + base_id: RmrkBaseId, + theme_name: RmrkThemeName, + filter_keys: Option> + ) -> Result, DispatchError> { + #[cfg(feature = "rmrk")] + return pallet_proxy_rmrk_equip::rpc::theme::(base_id, theme_name, filter_keys); + + #[cfg(not(feature = "rmrk"))] + return unsupported!(); + } + } + + impl sp_api::Core for Runtime { + fn version() -> RuntimeVersion { + VERSION + } + + fn execute_block(block: Block) { + Executive::execute_block(block) + } + + fn initialize_block(header: &::Header) { + Executive::initialize_block(header) + } + } + + impl sp_api::Metadata for Runtime { + fn metadata() -> OpaqueMetadata { + OpaqueMetadata::new(Runtime::metadata().into()) + } + } + + impl sp_block_builder::BlockBuilder for Runtime { + fn apply_extrinsic(extrinsic: ::Extrinsic) -> ApplyExtrinsicResult { + Executive::apply_extrinsic(extrinsic) + } + + fn finalize_block() -> ::Header { + Executive::finalize_block() + } + + fn inherent_extrinsics(data: sp_inherents::InherentData) -> Vec<::Extrinsic> { + data.create_extrinsics() + } + + fn check_inherents( + block: Block, + data: sp_inherents::InherentData, + ) -> sp_inherents::CheckInherentsResult { + data.check_extrinsics(&block) + } + + // fn random_seed() -> ::Hash { + // RandomnessCollectiveFlip::random_seed().0 + // } + } + + impl sp_transaction_pool::runtime_api::TaggedTransactionQueue for Runtime { + fn validate_transaction( + source: TransactionSource, + tx: ::Extrinsic, + hash: ::Hash, + ) -> TransactionValidity { + Executive::validate_transaction(source, tx, hash) + } + } + + impl sp_offchain::OffchainWorkerApi for Runtime { + fn offchain_worker(header: &::Header) { + Executive::offchain_worker(header) + } + } + + impl fp_rpc::EthereumRuntimeRPCApi for Runtime { + fn chain_id() -> u64 { + ::ChainId::get() + } + + fn account_basic(address: H160) -> EVMAccount { + let (account, _) = EVM::account_basic(&address); + account + } + + fn gas_price() -> U256 { + let (price, _) = ::FeeCalculator::min_gas_price(); + price + } + + fn account_code_at(address: H160) -> Vec { + EVM::account_codes(address) + } + + fn author() -> H160 { + >::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, + value: U256, + gas_limit: U256, + max_fee_per_gas: Option, + max_priority_fee_per_gas: Option, + nonce: Option, + estimate: bool, + access_list: Option)>>, + ) -> Result { + let config = if estimate { + let mut config = ::config().clone(); + config.estimate = true; + Some(config) + } else { + None + }; + + let is_transactional = false; + ::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(|| ::config()), + ).map_err(|err| err.error.into()) + } + + #[allow(clippy::redundant_closure)] + fn create( + from: H160, + data: Vec, + value: U256, + gas_limit: U256, + max_fee_per_gas: Option, + max_priority_fee_per_gas: Option, + nonce: Option, + estimate: bool, + access_list: Option)>>, + ) -> Result { + let config = if estimate { + let mut config = ::config().clone(); + config.estimate = true; + Some(config) + } else { + None + }; + + let is_transactional = false; + ::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(|| ::config()), + ).map_err(|err| err.error.into()) + } + + fn current_transaction_statuses() -> Option> { + Ethereum::current_transaction_statuses() + } + + fn current_block() -> Option { + Ethereum::current_block() + } + + fn current_receipts() -> Option> { + Ethereum::current_receipts() + } + + fn current_all() -> ( + Option, + Option>, + Option> + ) { + ( + Ethereum::current_block(), + Ethereum::current_receipts(), + Ethereum::current_transaction_statuses() + ) + } + + fn extrinsic_filter(xts: Vec<::Extrinsic>) -> Vec { + xts.into_iter().filter_map(|xt| match xt.0.function { + Call::Ethereum(pallet_ethereum::Call::transact { transaction }) => Some(transaction), + _ => None + }).collect() + } + + fn elasticity() -> Option { + None + } + } + + impl fp_rpc::ConvertTransactionRuntimeApi for Runtime { + fn convert_transaction(transaction: pallet_ethereum::Transaction) -> ::Extrinsic { + UncheckedExtrinsic::new_unsigned( + pallet_ethereum::Call::::transact { transaction }.into(), + ) + } + } + + impl sp_session::SessionKeys for Runtime { + fn decode_session_keys( + encoded: Vec, + ) -> Option, KeyTypeId)>> { + SessionKeys::decode_into_raw_public_keys(&encoded) + } + + fn generate_session_keys(seed: Option>) -> Vec { + SessionKeys::generate(seed) + } + } + + impl sp_consensus_aura::AuraApi for Runtime { + fn slot_duration() -> sp_consensus_aura::SlotDuration { + sp_consensus_aura::SlotDuration::from_millis(Aura::slot_duration()) + } + + fn authorities() -> Vec { + Aura::authorities().to_vec() + } + } + + impl cumulus_primitives_core::CollectCollationInfo for Runtime { + fn collect_collation_info(header: &::Header) -> cumulus_primitives_core::CollationInfo { + ParachainSystem::collect_collation_info(header) + } + } + + impl frame_system_rpc_runtime_api::AccountNonceApi for Runtime { + fn account_nonce(account: AccountId) -> Index { + System::account_nonce(account) + } + } + + impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi for Runtime { + fn query_info(uxt: ::Extrinsic, len: u32) -> RuntimeDispatchInfo { + TransactionPayment::query_info(uxt, len) + } + fn query_fee_details(uxt: ::Extrinsic, len: u32) -> FeeDetails { + TransactionPayment::query_fee_details(uxt, len) + } + } + + /* + impl pallet_contracts_rpc_runtime_api::ContractsApi + for Runtime + { + fn call( + origin: AccountId, + dest: AccountId, + value: Balance, + gas_limit: u64, + input_data: Vec, + ) -> 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, + data: Vec, + salt: Vec, + ) -> pallet_contracts_primitives::ContractInstantiateResult + { + 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 { + Contracts::rent_projection(address) + } + } + */ + + #[cfg(feature = "runtime-benchmarks")] + impl frame_benchmarking::Benchmark for Runtime { + fn benchmark_metadata(extra: bool) -> ( + Vec, + Vec, + ) { + use frame_benchmarking::{list_benchmark, Benchmarking, BenchmarkList}; + use frame_support::traits::StorageInfoTrait; + + let mut list = Vec::::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, sp_runtime::RuntimeString> { + use frame_benchmarking::{Benchmarking, BenchmarkBatch, add_benchmark, TrackedStorageKey}; + + let allowlist: Vec = 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::::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 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) + } + } + } + } +} --- /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 . + +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, + frame_system::CheckGenesis, + frame_system::CheckEra, + frame_system::CheckNonce, + frame_system::CheckWeight, +); + +fn get_signed_extras(from: ::AccountId) -> SignedExtraScheduler { + ( + frame_system::CheckSpecVersion::::new(), + frame_system::CheckGenesis::::new(), + frame_system::CheckEra::::from(Era::Immortal), + frame_system::CheckNonce::::from(frame_system::Pallet::::account_nonce( + from, + )), + frame_system::CheckWeight::::new(), + // sponsoring transaction logic + // pallet_charge_transaction::ChargeTransactionPayment::::new(0), + ) +} + +pub struct SchedulerPaymentExecutor; + +impl + DispatchCall for SchedulerPaymentExecutor +where + ::Call: Member + + Dispatchable + + SelfContainedCall + + GetDispatchInfo + + From>, + SelfContainedSignedInfo: Send + Sync + 'static, + Call: From<::Call> + + From<::Call> + + SelfContainedCall, + sp_runtime::AccountId32: From<::AccountId>, +{ + fn dispatch_call( + signer: ::AccountId, + call: ::Call, + ) -> Result< + Result>, + 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::(&dispatch_info, 0) + } + + fn reserve_balance( + id: [u8; 16], + sponsor: ::AccountId, + call: ::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()); + + >::reserve_named( + &id, + &(sponsor.into()), + weight, + ) + } + + fn pay_for_call( + id: [u8; 16], + sponsor: ::AccountId, + call: ::Call, + ) -> Result { + let dispatch_info = call.get_dispatch_info(); + let weight: Balance = ChargeTransactionPayment::traditional_fee(0, &dispatch_info, 0); + Ok( + >::unreserve_named( + &id, + &(sponsor.into()), + weight, + ), + ) + } + + fn cancel_reserve( + id: [u8; 16], + sponsor: ::AccountId, + ) -> Result { + Ok( + >::unreserve_named( + &id, + &(sponsor.into()), + u128::MAX, + ), + ) + } +} --- /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 . + +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 Config for T where T: UniqueConfig + FungibleConfig + NonfungibleConfig + RefungibleConfig {} + +// TODO: permission check? +pub fn withdraw_set_token_property( + collection: &CollectionHandle, + who: &T::CrossAccountId, + item_id: &TokenId, + data_size: usize, +) -> Option<()> { + // preliminary sponsoring correctness check + match collection.mode { + CollectionMode::NFT => { + let owner = pallet_nonfungible::TokenData::::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 !>::get((collection.id, who, item_id)) { + return None; + } + } + } + + if data_size > collection.limits.sponsored_data_size() as usize { + return None; + } + + let block_number = >::block_number() as T::BlockNumber; + let limit = collection.limits.sponsored_data_rate_limit()?; + + if let Some(last_tx_block) = TokenPropertyBasket::::get(collection.id, item_id) { + let timeout = last_tx_block + limit.into(); + if block_number < timeout { + return None; + } + } + + >::insert(collection.id, item_id, block_number); + + Some(()) +} + +pub fn withdraw_transfer( + collection: &CollectionHandle, + who: &T::CrossAccountId, + item_id: &TokenId, +) -> Option<()> { + // preliminary sponsoring correctness check + match collection.mode { + CollectionMode::NFT => { + let owner = pallet_nonfungible::TokenData::::get((collection.id, item_id))?.owner; + if !owner.conv_eq(who) { + return None; + } + } + CollectionMode::Fungible(_) => { + if item_id != &TokenId::default() { + return None; + } + if >::get((collection.id, who)) == 0 { + return None; + } + } + CollectionMode::ReFungible => { + if !>::get((collection.id, who, item_id)) { + return None; + } + } + } + + // sponsor timeout + let block_number = >::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 => >::get(collection.id, item_id), + CollectionMode::Fungible(_) => { + >::get(collection.id, who.as_sub()) + } + CollectionMode::ReFungible => { + >::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 => >::insert(collection.id, item_id, block_number), + CollectionMode::Fungible(_) => { + >::insert(collection.id, who.as_sub(), block_number) + } + CollectionMode::ReFungible => >::insert( + (collection.id, item_id, who.as_sub()), + block_number, + ), + }; + + Some(()) +} + +pub fn withdraw_create_item( + collection: &CollectionHandle, + who: &T::CrossAccountId, + properties: &CreateItemData, +) -> Option<()> { + // sponsor timeout + let block_number = >::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) = >::get((collection.id, who.as_sub())) { + let timeout = last_tx_block + limit.into(); + if block_number < timeout { + return None; + } + } + + CreateItemBasket::::insert((collection.id, who.as_sub()), block_number); + + Some(()) +} + +pub fn withdraw_approve( + collection: &CollectionHandle, + who: &T::AccountId, + item_id: &TokenId, +) -> Option<()> { + // sponsor timeout + let block_number = >::block_number() as T::BlockNumber; + let limit = collection.limits.sponsor_approve_timeout(); + + let last_tx_block = match collection.mode { + CollectionMode::NFT => >::get(collection.id, item_id), + CollectionMode::Fungible(_) => >::get(collection.id, who), + CollectionMode::ReFungible => { + >::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 => >::insert(collection.id, item_id, block_number), + CollectionMode::Fungible(_) => { + >::insert(collection.id, who, block_number) + } + CollectionMode::ReFungible => { + >::insert((collection.id, item_id, who), block_number) + } + }; + + Some(()) +} + +fn load(id: CollectionId) -> Option<(T::AccountId, CollectionHandle)> { + let collection = CollectionHandle::new(id)?; + let sponsor = collection.sponsorship.sponsor().cloned()?; + Some((sponsor, collection)) +} + +pub struct UniqueSponsorshipHandler(PhantomData); +impl SponsorshipHandler for UniqueSponsorshipHandler +where + T: Config, + C: IsSubType>, +{ + fn get_sponsor(who: &T::AccountId, call: &C) -> Option { + match IsSubType::>::is_sub_type(call)? { + UniqueCall::set_token_properties { + collection_id, + token_id, + properties, + .. + } => { + let (sponsor, collection) = load::(*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::( + &collection, + &T::CrossAccountId::from_sub(who.clone()), + data, + ) + .map(|()| sponsor) + } + UniqueCall::transfer { + collection_id, + item_id, + .. + } => { + let (sponsor, collection) = load(*collection_id)?; + withdraw_transfer::( + &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::(&collection, from, item_id).map(|()| sponsor) + } + UniqueCall::approve { + collection_id, + item_id, + .. + } => { + let (sponsor, collection) = load(*collection_id)?; + withdraw_approve::(&collection, who, item_id).map(|()| sponsor) + } + _ => None, + } + } +} + +pub trait SponsorshipPredict { + fn predict(collection: CollectionId, account: T::CrossAccountId, token: TokenId) -> Option + where + u64: From<::BlockNumber>; +} + +pub struct UniqueSponsorshipPredict(PhantomData); + +impl SponsorshipPredict for UniqueSponsorshipPredict { + fn predict(collection_id: CollectionId, who: T::CrossAccountId, token: TokenId) -> Option + where + u64: From<::BlockNumber>, + { + let collection = >::try_get(collection_id).ok()?; + let _ = collection.sponsorship.sponsor()?; + + // sponsor timeout + let block_number = >::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 => >::get(collection.id, token), + CollectionMode::Fungible(_) => { + >::get(collection.id, who.as_sub()) + } + CollectionMode::ReFungible => { + >::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 => { + >::contains_key((collection.id, token)) + } + CollectionMode::Fungible(_) => token == TokenId::default(), + CollectionMode::ReFungible => { + >::contains_key((collection.id, token)) + } + }; + + if token_exists { + Some(0) + } else { + None + } + } +} --- 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 . - -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; -} --- 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 . - -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 -where - T: pallet_fungible::Config + pallet_nonfungible::Config + pallet_refungible::Config, -{ - Fungible(FungibleHandle), - Nonfungible(NonfungibleHandle), - Refungible(RefungibleHandle), -} -impl CollectionDispatch for CollectionDispatchT -where - T: pallet_common::Config - + pallet_unique::Config - + pallet_fungible::Config - + pallet_nonfungible::Config - + pallet_refungible::Config, -{ - fn create( - sender: T::CrossAccountId, - data: CreateCollectionData, - ) -> Result { - let id = match data.mode { - CollectionMode::NFT => >::init_collection(sender, data, false)?, - CollectionMode::Fungible(decimal_points) => { - // check params - ensure!( - decimal_points <= MAX_DECIMAL_POINTS, - pallet_unique::Error::::CollectionDecimalPointLimitExceeded - ); - >::init_collection(sender, data)? - } - CollectionMode::ReFungible => >::init_collection(sender, data)?, - }; - Ok(id) - } - - fn destroy(sender: T::CrossAccountId, collection: CollectionHandle) -> 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) -> 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 { - 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 { - match self { - Self::Fungible(h) => h, - Self::Nonfungible(h) => h, - Self::Refungible(h) => h, - } - } -} - -impl pallet_evm::OnMethodCall for CollectionDispatchT -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(>::contains_key) - .unwrap_or(false) - } - fn get_code(target: &H160) -> Option> { - if let Some(collection_id) = map_eth_to_id(target) { - let collection = >::get(collection_id)?; - Some( - match collection.mode { - CollectionMode::NFT => >::CODE, - CollectionMode::Fungible(_) => >::CODE, - CollectionMode::ReFungible => >::CODE, - } - .to_owned(), - ) - } else if let Some((collection_id, _token_id)) = - ::EvmTokenAddressMapping::address_to_token(target) - { - let collection = >::get(collection_id)?; - if collection.mode != CollectionMode::ReFungible { - return None; - } - // TODO: check token existence - Some(>::CODE.to_owned()) - } else { - None - } - } - fn call(handle: &mut impl PrecompileHandle) -> Option { - if let Some(collection_id) = map_eth_to_id(&handle.code_address()) { - let collection = - >::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)) = - ::EvmTokenAddressMapping::address_to_token( - &handle.code_address(), - ) { - let collection = - >::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 - } - } -} --- 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 . - -//! 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(PhantomData<*const T>); -impl - SponsorshipHandler)> for UniqueEthSponsorshipHandler -{ - fn get_sponsor(who: &T::CrossAccountId, call: &(H160, Vec)) -> Option { - let collection_id = map_eth_to_id(&call.0)?; - let collection = >::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 = >::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::( - &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::(&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::( - &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::(&collection, &from, &token_id).map(|()| sponsor) - } - UniqueNFTCall::ERC721(ERC721Call::Approve { token_id, .. }) => { - let token_id: TokenId = token_id.try_into().ok()?; - withdraw_approve::(&collection, who.as_sub(), &token_id) - .map(|()| sponsor) - } - _ => None, - } - } - CollectionMode::Fungible(_) => { - let call = >::parse(method_id, &mut reader).ok()??; - #[allow(clippy::single_match)] - match call { - UniqueFungibleCall::ERC20(ERC20Call::Transfer { .. }) => { - withdraw_transfer::(&collection, who, &TokenId::default()) - .map(|()| sponsor) - } - UniqueFungibleCall::ERC20(ERC20Call::TransferFrom { from, .. }) => { - let from = T::CrossAccountId::from_eth(from); - withdraw_transfer::(&collection, &from, &TokenId::default()) - .map(|()| sponsor) - } - UniqueFungibleCall::ERC20(ERC20Call::Approve { .. }) => { - withdraw_approve::(&collection, who.as_sub(), &TokenId::default()) - .map(|()| sponsor) - } - _ => None, - } - } - _ => None, - }?)) - } -} --- 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 . - -#![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; --- 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 . - -#[macro_export] -macro_rules! impl_common_runtime_apis { - ( - $( - #![custom_apis] - - $($custom_apis:tt)+ - )? - ) => { - impl_runtime_apis! { - $($($custom_apis)+)? - - impl up_rpc::UniqueApi for Runtime { - fn account_tokens(collection: CollectionId, account: CrossAccountId) -> Result, DispatchError> { - dispatch_unique_runtime!(collection.account_tokens(account)) - } - fn collection_tokens(collection: CollectionId) -> Result, DispatchError> { - dispatch_unique_runtime!(collection.collection_tokens()) - } - fn token_exists(collection: CollectionId, token: TokenId) -> Result { - dispatch_unique_runtime!(collection.token_exists(token)) - } - - fn token_owner(collection: CollectionId, token: TokenId) -> Result, DispatchError> { - dispatch_unique_runtime!(collection.token_owner(token)) - } - - fn token_owners(collection: CollectionId, token: TokenId) -> Result, DispatchError> { - dispatch_unique_runtime!(collection.token_owners(token)) - } - - fn topmost_token_owner(collection: CollectionId, token: TokenId) -> Result, DispatchError> { - let budget = up_data_structs::budget::Value::new(10); - - Ok(Some(>::find_topmost_owner(collection, token, &budget)?)) - } - fn token_children(collection: CollectionId, token: TokenId) -> Result, DispatchError> { - Ok(>::token_children_ids(collection, token)) - } - fn collection_properties( - collection: CollectionId, - keys: Option>> - ) -> Result, 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>> - ) -> Result, 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>> - ) -> Result, 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>> - ) -> Result, 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 { - dispatch_unique_runtime!(collection.total_supply()) - } - fn account_balance(collection: CollectionId, account: CrossAccountId) -> Result { - dispatch_unique_runtime!(collection.account_balance(account)) - } - fn balance(collection: CollectionId, account: CrossAccountId, token: TokenId) -> Result { - dispatch_unique_runtime!(collection.balance(account, token)) - } - fn allowance( - collection: CollectionId, - sender: CrossAccountId, - spender: CrossAccountId, - token: TokenId, - ) -> Result { - dispatch_unique_runtime!(collection.allowance(sender, spender, token)) - } - - fn adminlist(collection: CollectionId) -> Result, DispatchError> { - Ok(>::adminlist(collection)) - } - fn allowlist(collection: CollectionId) -> Result, DispatchError> { - Ok(>::allowlist(collection)) - } - fn allowed(collection: CollectionId, user: CrossAccountId) -> Result { - Ok(>::allowed(collection, user)) - } - fn last_token_id(collection: CollectionId) -> Result { - dispatch_unique_runtime!(collection.last_token_id()) - } - fn collection_by_id(collection: CollectionId) -> Result>, DispatchError> { - Ok(>::rpc_collection(collection)) - } - fn collection_stats() -> Result { - Ok(>::collection_stats()) - } - fn next_sponsored(collection: CollectionId, account: CrossAccountId, token: TokenId) -> Result, DispatchError> { - Ok(<$crate::sponsoring::UniqueSponsorshipPredict as - $crate::sponsoring::SponsorshipPredict>::predict( - collection, - account, - token)) - } - - fn effective_collection_limits(collection: CollectionId) -> Result, DispatchError> { - Ok(>::effective_collection_limits(collection)) - } - - fn total_pieces(collection: CollectionId, token_id: TokenId) -> Result, DispatchError> { - dispatch_unique_runtime!(collection.total_pieces(token_id)) - } - } - - impl sp_api::Core for Runtime { - fn version() -> RuntimeVersion { - VERSION - } - - fn execute_block(block: Block) { - Executive::execute_block(block) - } - - fn initialize_block(header: &::Header) { - Executive::initialize_block(header) - } - } - - impl sp_api::Metadata for Runtime { - fn metadata() -> OpaqueMetadata { - OpaqueMetadata::new(Runtime::metadata().into()) - } - } - - impl sp_block_builder::BlockBuilder for Runtime { - fn apply_extrinsic(extrinsic: ::Extrinsic) -> ApplyExtrinsicResult { - Executive::apply_extrinsic(extrinsic) - } - - fn finalize_block() -> ::Header { - Executive::finalize_block() - } - - fn inherent_extrinsics(data: sp_inherents::InherentData) -> Vec<::Extrinsic> { - data.create_extrinsics() - } - - fn check_inherents( - block: Block, - data: sp_inherents::InherentData, - ) -> sp_inherents::CheckInherentsResult { - data.check_extrinsics(&block) - } - - // fn random_seed() -> ::Hash { - // RandomnessCollectiveFlip::random_seed().0 - // } - } - - impl sp_transaction_pool::runtime_api::TaggedTransactionQueue for Runtime { - fn validate_transaction( - source: TransactionSource, - tx: ::Extrinsic, - hash: ::Hash, - ) -> TransactionValidity { - Executive::validate_transaction(source, tx, hash) - } - } - - impl sp_offchain::OffchainWorkerApi for Runtime { - fn offchain_worker(header: &::Header) { - Executive::offchain_worker(header) - } - } - - impl fp_rpc::EthereumRuntimeRPCApi for Runtime { - fn chain_id() -> u64 { - ::ChainId::get() - } - - fn account_basic(address: H160) -> EVMAccount { - let (account, _) = EVM::account_basic(&address); - account - } - - fn gas_price() -> U256 { - let (price, _) = ::FeeCalculator::min_gas_price(); - price - } - - fn account_code_at(address: H160) -> Vec { - EVM::account_codes(address) - } - - fn author() -> H160 { - >::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, - value: U256, - gas_limit: U256, - max_fee_per_gas: Option, - max_priority_fee_per_gas: Option, - nonce: Option, - estimate: bool, - access_list: Option)>>, - ) -> Result { - let config = if estimate { - let mut config = ::config().clone(); - config.estimate = true; - Some(config) - } else { - None - }; - - let is_transactional = false; - ::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(|| ::config()), - ).map_err(|err| err.error.into()) - } - - #[allow(clippy::redundant_closure)] - fn create( - from: H160, - data: Vec, - value: U256, - gas_limit: U256, - max_fee_per_gas: Option, - max_priority_fee_per_gas: Option, - nonce: Option, - estimate: bool, - access_list: Option)>>, - ) -> Result { - let config = if estimate { - let mut config = ::config().clone(); - config.estimate = true; - Some(config) - } else { - None - }; - - let is_transactional = false; - ::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(|| ::config()), - ).map_err(|err| err.error.into()) - } - - fn current_transaction_statuses() -> Option> { - Ethereum::current_transaction_statuses() - } - - fn current_block() -> Option { - Ethereum::current_block() - } - - fn current_receipts() -> Option> { - Ethereum::current_receipts() - } - - fn current_all() -> ( - Option, - Option>, - Option> - ) { - ( - Ethereum::current_block(), - Ethereum::current_receipts(), - Ethereum::current_transaction_statuses() - ) - } - - fn extrinsic_filter(xts: Vec<::Extrinsic>) -> Vec { - xts.into_iter().filter_map(|xt| match xt.0.function { - Call::Ethereum(pallet_ethereum::Call::transact { transaction }) => Some(transaction), - _ => None - }).collect() - } - - fn elasticity() -> Option { - None - } - } - - impl fp_rpc::ConvertTransactionRuntimeApi for Runtime { - fn convert_transaction(transaction: pallet_ethereum::Transaction) -> ::Extrinsic { - UncheckedExtrinsic::new_unsigned( - pallet_ethereum::Call::::transact { transaction }.into(), - ) - } - } - - impl sp_session::SessionKeys for Runtime { - fn decode_session_keys( - encoded: Vec, - ) -> Option, KeyTypeId)>> { - SessionKeys::decode_into_raw_public_keys(&encoded) - } - - fn generate_session_keys(seed: Option>) -> Vec { - SessionKeys::generate(seed) - } - } - - impl sp_consensus_aura::AuraApi for Runtime { - fn slot_duration() -> sp_consensus_aura::SlotDuration { - sp_consensus_aura::SlotDuration::from_millis(Aura::slot_duration()) - } - - fn authorities() -> Vec { - Aura::authorities().to_vec() - } - } - - impl cumulus_primitives_core::CollectCollationInfo for Runtime { - fn collect_collation_info(header: &::Header) -> cumulus_primitives_core::CollationInfo { - ParachainSystem::collect_collation_info(header) - } - } - - impl frame_system_rpc_runtime_api::AccountNonceApi for Runtime { - fn account_nonce(account: AccountId) -> Index { - System::account_nonce(account) - } - } - - impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi for Runtime { - fn query_info(uxt: ::Extrinsic, len: u32) -> RuntimeDispatchInfo { - TransactionPayment::query_info(uxt, len) - } - fn query_fee_details(uxt: ::Extrinsic, len: u32) -> FeeDetails { - TransactionPayment::query_fee_details(uxt, len) - } - } - - /* - impl pallet_contracts_rpc_runtime_api::ContractsApi - for Runtime - { - fn call( - origin: AccountId, - dest: AccountId, - value: Balance, - gas_limit: u64, - input_data: Vec, - ) -> 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, - data: Vec, - salt: Vec, - ) -> pallet_contracts_primitives::ContractInstantiateResult - { - 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 { - Contracts::rent_projection(address) - } - } - */ - - #[cfg(feature = "runtime-benchmarks")] - impl frame_benchmarking::Benchmark for Runtime { - fn benchmark_metadata(extra: bool) -> ( - Vec, - Vec, - ) { - use frame_benchmarking::{list_benchmark, Benchmarking, BenchmarkList}; - use frame_support::traits::StorageInfoTrait; - - let mut list = Vec::::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, sp_runtime::RuntimeString> { - use frame_benchmarking::{Benchmarking, BenchmarkBatch, add_benchmark, TrackedStorageKey}; - - let allowlist: Vec = 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::::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 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) - } - } - } - } -} --- 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 . - -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 Config for T where T: UniqueConfig + FungibleConfig + NonfungibleConfig + RefungibleConfig {} - -// TODO: permission check? -pub fn withdraw_set_token_property( - collection: &CollectionHandle, - who: &T::CrossAccountId, - item_id: &TokenId, - data_size: usize, -) -> Option<()> { - // preliminary sponsoring correctness check - match collection.mode { - CollectionMode::NFT => { - let owner = pallet_nonfungible::TokenData::::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 !>::get((collection.id, who, item_id)) { - return None; - } - } - } - - if data_size > collection.limits.sponsored_data_size() as usize { - return None; - } - - let block_number = >::block_number() as T::BlockNumber; - let limit = collection.limits.sponsored_data_rate_limit()?; - - if let Some(last_tx_block) = TokenPropertyBasket::::get(collection.id, item_id) { - let timeout = last_tx_block + limit.into(); - if block_number < timeout { - return None; - } - } - - >::insert(collection.id, item_id, block_number); - - Some(()) -} - -pub fn withdraw_transfer( - collection: &CollectionHandle, - who: &T::CrossAccountId, - item_id: &TokenId, -) -> Option<()> { - // preliminary sponsoring correctness check - match collection.mode { - CollectionMode::NFT => { - let owner = pallet_nonfungible::TokenData::::get((collection.id, item_id))?.owner; - if !owner.conv_eq(who) { - return None; - } - } - CollectionMode::Fungible(_) => { - if item_id != &TokenId::default() { - return None; - } - if >::get((collection.id, who)) == 0 { - return None; - } - } - CollectionMode::ReFungible => { - if !>::get((collection.id, who, item_id)) { - return None; - } - } - } - - // sponsor timeout - let block_number = >::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 => >::get(collection.id, item_id), - CollectionMode::Fungible(_) => { - >::get(collection.id, who.as_sub()) - } - CollectionMode::ReFungible => { - >::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 => >::insert(collection.id, item_id, block_number), - CollectionMode::Fungible(_) => { - >::insert(collection.id, who.as_sub(), block_number) - } - CollectionMode::ReFungible => >::insert( - (collection.id, item_id, who.as_sub()), - block_number, - ), - }; - - Some(()) -} - -pub fn withdraw_create_item( - collection: &CollectionHandle, - who: &T::CrossAccountId, - properties: &CreateItemData, -) -> Option<()> { - // sponsor timeout - let block_number = >::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) = >::get((collection.id, who.as_sub())) { - let timeout = last_tx_block + limit.into(); - if block_number < timeout { - return None; - } - } - - CreateItemBasket::::insert((collection.id, who.as_sub()), block_number); - - Some(()) -} - -pub fn withdraw_approve( - collection: &CollectionHandle, - who: &T::AccountId, - item_id: &TokenId, -) -> Option<()> { - // sponsor timeout - let block_number = >::block_number() as T::BlockNumber; - let limit = collection.limits.sponsor_approve_timeout(); - - let last_tx_block = match collection.mode { - CollectionMode::NFT => >::get(collection.id, item_id), - CollectionMode::Fungible(_) => >::get(collection.id, who), - CollectionMode::ReFungible => { - >::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 => >::insert(collection.id, item_id, block_number), - CollectionMode::Fungible(_) => { - >::insert(collection.id, who, block_number) - } - CollectionMode::ReFungible => { - >::insert((collection.id, item_id, who), block_number) - } - }; - - Some(()) -} - -fn load(id: CollectionId) -> Option<(T::AccountId, CollectionHandle)> { - let collection = CollectionHandle::new(id)?; - let sponsor = collection.sponsorship.sponsor().cloned()?; - Some((sponsor, collection)) -} - -pub struct UniqueSponsorshipHandler(PhantomData); -impl SponsorshipHandler for UniqueSponsorshipHandler -where - T: Config, - C: IsSubType>, -{ - fn get_sponsor(who: &T::AccountId, call: &C) -> Option { - match IsSubType::>::is_sub_type(call)? { - UniqueCall::set_token_properties { - collection_id, - token_id, - properties, - .. - } => { - let (sponsor, collection) = load::(*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::( - &collection, - &T::CrossAccountId::from_sub(who.clone()), - data, - ) - .map(|()| sponsor) - } - UniqueCall::transfer { - collection_id, - item_id, - .. - } => { - let (sponsor, collection) = load(*collection_id)?; - withdraw_transfer::( - &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::(&collection, from, item_id).map(|()| sponsor) - } - UniqueCall::approve { - collection_id, - item_id, - .. - } => { - let (sponsor, collection) = load(*collection_id)?; - withdraw_approve::(&collection, who, item_id).map(|()| sponsor) - } - _ => None, - } - } -} - -pub trait SponsorshipPredict { - fn predict(collection: CollectionId, account: T::CrossAccountId, token: TokenId) -> Option - where - u64: From<::BlockNumber>; -} - -pub struct UniqueSponsorshipPredict(PhantomData); - -impl SponsorshipPredict for UniqueSponsorshipPredict { - fn predict(collection_id: CollectionId, who: T::CrossAccountId, token: TokenId) -> Option - where - u64: From<::BlockNumber>, - { - let collection = >::try_get(collection_id).ok()?; - let _ = collection.sponsorship.sponsor()?; - - // sponsor timeout - let block_number = >::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 => >::get(collection.id, token), - CollectionMode::Fungible(_) => { - >::get(collection.id, who.as_sub()) - } - CollectionMode::ReFungible => { - >::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 => { - >::contains_key((collection.id, token)) - } - CollectionMode::Fungible(_) => token == TokenId::default(), - CollectionMode::ReFungible => { - >::contains_key((collection.id, token)) - } - }; - - if token_exists { - Some(0) - } else { - None - } - } -} --- 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 . - -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; - -/// Opaque block type. -pub type Block = generic::Block; - -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 = <::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 - + Send - + Sync - + 'static; - - type TransactionConverter: fp_rpc::ConvertTransaction - + Send - + Sync - + 'static; - - fn get_transaction_converter() -> Self::TransactionConverter; -} --- 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 . - -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)* )) => { - >::$method($($args)*) - .max(>::$method($($args)*)) - .max(>::$method($($args)*)) - }; -} - -pub struct CommonWeights(PhantomData) -where - T: FungibleConfig + NonfungibleConfig + RefungibleConfig; -impl CommonWeightInfo for CommonWeights -where - T: FungibleConfig + NonfungibleConfig + RefungibleConfig, -{ - fn create_item() -> Weight { - dispatch_weight::() + max_weight_of!(create_item()) - } - - fn create_multiple_items(data: &[CreateItemData]) -> Weight { - dispatch_weight::() + max_weight_of!(create_multiple_items(data)) - } - - fn create_multiple_items_ex(data: &CreateItemExData) -> Weight { - dispatch_weight::() + max_weight_of!(create_multiple_items_ex(data)) - } - - fn burn_item() -> Weight { - dispatch_weight::() + max_weight_of!(burn_item()) - } - - fn set_collection_properties(amount: u32) -> Weight { - dispatch_weight::() + max_weight_of!(set_collection_properties(amount)) - } - - fn delete_collection_properties(amount: u32) -> Weight { - dispatch_weight::() + max_weight_of!(delete_collection_properties(amount)) - } - - fn set_token_properties(amount: u32) -> Weight { - dispatch_weight::() + max_weight_of!(set_token_properties(amount)) - } - - fn delete_token_properties(amount: u32) -> Weight { - dispatch_weight::() + max_weight_of!(delete_token_properties(amount)) - } - - fn set_token_property_permissions(amount: u32) -> Weight { - dispatch_weight::() + max_weight_of!(set_token_property_permissions(amount)) - } - - fn transfer() -> Weight { - dispatch_weight::() + max_weight_of!(transfer()) - } - - fn approve() -> Weight { - dispatch_weight::() + max_weight_of!(approve()) - } - - fn transfer_from() -> Weight { - dispatch_weight::() + max_weight_of!(transfer_from()) - } - - fn burn_from() -> Weight { - dispatch_weight::() + 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 RefungibleExtensionsWeightInfo for CommonWeights -where - T: FungibleConfig + NonfungibleConfig + RefungibleConfig, -{ - fn repartition() -> Weight { - dispatch_weight::() + <::WeightInfo>::repartition_item() - } -} --- /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 . + +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 = >::$method($($args)*) + .max(>::$method($($args)*)); + + #[cfg(feature = "refungible")] + let max_weight = max_weight.max(>::$method($($args)*)); + + max_weight + }}; +} + +#[cfg(not(feature = "refungible"))] +pub trait CommonWeightConfigs: FungibleConfig + NonfungibleConfig {} + +#[cfg(not(feature = "refungible"))] +impl CommonWeightConfigs for T {} + +#[cfg(feature = "refungible")] +pub trait CommonWeightConfigs: FungibleConfig + NonfungibleConfig + RefungibleConfig {} + +#[cfg(feature = "refungible")] +impl CommonWeightConfigs for T {} + +pub struct CommonWeights(PhantomData); + +impl CommonWeightInfo for CommonWeights +where + T: CommonWeightConfigs, +{ + fn create_item() -> Weight { + dispatch_weight::() + max_weight_of!(create_item()) + } + + fn create_multiple_items(data: &[CreateItemData]) -> Weight { + dispatch_weight::() + max_weight_of!(create_multiple_items(data)) + } + + fn create_multiple_items_ex(data: &CreateItemExData) -> Weight { + dispatch_weight::() + max_weight_of!(create_multiple_items_ex(data)) + } + + fn burn_item() -> Weight { + dispatch_weight::() + max_weight_of!(burn_item()) + } + + fn set_collection_properties(amount: u32) -> Weight { + dispatch_weight::() + max_weight_of!(set_collection_properties(amount)) + } + + fn delete_collection_properties(amount: u32) -> Weight { + dispatch_weight::() + max_weight_of!(delete_collection_properties(amount)) + } + + fn set_token_properties(amount: u32) -> Weight { + dispatch_weight::() + max_weight_of!(set_token_properties(amount)) + } + + fn delete_token_properties(amount: u32) -> Weight { + dispatch_weight::() + max_weight_of!(delete_token_properties(amount)) + } + + fn set_token_property_permissions(amount: u32) -> Weight { + dispatch_weight::() + max_weight_of!(set_token_property_permissions(amount)) + } + + fn transfer() -> Weight { + dispatch_weight::() + max_weight_of!(transfer()) + } + + fn approve() -> Weight { + dispatch_weight::() + max_weight_of!(approve()) + } + + fn transfer_from() -> Weight { + dispatch_weight::() + max_weight_of!(transfer_from()) + } + + fn burn_from() -> Weight { + dispatch_weight::() + 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 RefungibleExtensionsWeightInfo for CommonWeights +where + T: FungibleConfig + NonfungibleConfig + RefungibleConfig, +{ + fn repartition() -> Weight { + dispatch_weight::() + <::WeightInfo>::repartition_item() + } +} + +#[cfg(not(feature = "refungible"))] +impl RefungibleExtensionsWeightInfo for CommonWeights +where + T: FungibleConfig + NonfungibleConfig, +{ + fn repartition() -> Weight { + dispatch_weight::() + } +} --- 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 --- 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; -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 { - /// 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 = >::NegativeImbalance; - -pub struct DealWithFees; -impl OnUnbalanced for DealWithFees { - fn on_unbalanceds(mut fees_then_tips: impl Iterator) { - 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 / ::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; - type EvmAddressMapping = pallet_evm::HashedAddressMapping; - 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; - type CallOrigin = EnsureAddressTruncated; - type WithdrawOrigin = EnsureAddressTruncated; - type AddressMapping = HashedAddressMapping; - type PrecompilesType = (); - type PrecompilesValue = (); - type Currency = Balances; - type Event = Event; - type OnMethodCall = ( - pallet_evm_migration::OnMethodCall, - pallet_evm_contract_helpers::HelpersOnMethodCall, - CollectionDispatchT, - pallet_unique::eth::CollectionHelpersOnMethodCall, - ); - type OnCreate = pallet_evm_contract_helpers::HelpersOnCreate; - type ChainId = ChainId; - type Runner = pallet_evm::runner::stack::Runner; - type OnChargeTransaction = pallet_evm::EVMCurrencyAdapter; - type TransactionValidityHack = pallet_evm_transaction_payment::TransactionValidityHack; - type FindAuthor = EthereumFindAuthor; -} - -impl pallet_evm_migration::Config for Runtime { - type WeightInfo = pallet_evm_migration::weights::SubstrateWeight; -} - -pub struct EthereumFindAuthor(core::marker::PhantomData); -impl> FindAuthor for EthereumFindAuthor { - fn find_author<'a, I>(digests: I) -> Option - where - I: 'a + IntoIterator, - { - 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; -} - -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; - /// 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; - /// 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; - /// 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; - /// 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; - /// 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; -} - -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::> 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() / ( - ::WeightInfo::on_initialize_per_queue_item(1) - - ::WeightInfo::on_initialize_per_queue_item(0) - )) / 5) as u32; - pub Schedule: pallet_contracts::Schedule = 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; - type WeightInfo = pallet_contracts::weights::SubstrateWeight; - type ChainExtension = NFTExtension; - type DeletionQueueDepth = DeletionQueueDepth; - type DeletionWeightLimit = DeletionWeightLimit; - type Schedule = Schedule; - type CallStack = [pallet_contracts::Frame; 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(sp_std::marker::PhantomData); - -impl WeightToFeePolynomial for LinearFee -where - T: BaseArithmetic + From + Copy + Unsigned, -{ - type Balance = T; - - fn polynomial() -> WeightToFeeCoefficients { - 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; - type LengthToFee = ConstantMultiplier; - type OperationalFeeMultiplier = OperationalFeeMultiplier; - type WeightToFee = LinearFee; - 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; - type RejectOrigin = EnsureRoot; - 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; - type MaxApprovals = MaxApprovals; -} - -impl pallet_sudo::Config for Runtime { - type Event = Event; - type Call = Call; -} - -pub struct RelayChainBlockNumberProvider(sp_std::marker::PhantomData); - -impl BlockNumberProvider - for RelayChainBlockNumberProvider -{ - type BlockNumber = BlockNumber; - - fn current_block_number() -> Self::BlockNumber { - cumulus_pallet_parachain_system::Pallet::::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; - type MinVestedTransfer = MinVestedTransfer; - type VestedTransferOrigin = EnsureSigned; - type WeightInfo = (); - type MaxVestingSchedules = MaxVestingSchedules; - type BlockNumberProvider = RelayChainBlockNumberProvider; -} - -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; - type OnSystemEvent = (); - // type DownwardMessageHandlers = cumulus_primitives_utility::UnqueuedDmpAsParent< - // MaxDownwardMessageWeight, - // XcmExecutor, - // 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, - // Sibling parachain origins convert to AccountId via the `ParaId::into`. - SiblingParachainConvertsVia, - // Straight up local `AccountId32` origins just alias directly to `AccountId`. - AccountId32Aliases, -); - -pub struct OnlySelfCurrency; -impl> MatchesFungible for OnlySelfCurrency { - fn matches_fungible(a: &MultiAsset) -> Option { - 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, - // Native converter for Relay-chain (Parent) location; will converts to a `Relay` origin when - // recognised. - RelayChainAsNative, - // Native converter for sibling Parachains; will convert to a `SiblingPara` origin when - // recognised. - SiblingParachainAsNative, - // Superuser converter for the Relay-chain (Parent) location. This will allow it to issue a - // transaction from the Root origin. - ParentAsSuperuser, - // Native signed account converter; this just converts an `AccountId32` origin into a normal - // `Origin::Signed` origin of the same 32-byte value. - SignedAccountId32AsNative, - // Xcm origins can be represented natively under the Xcm pallet's Xcm origin. - XcmPassthrough, -); - -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 { parents: 1, interior: Here } | - MultiLocation { parents: 1, interior: X1(Plurality { id: BodyId::Unit, .. }) } - }; -} - -pub type Barrier = ( - TakeWeightCredit, - AllowTopLevelPaidExecutionFrom, - // ^^^ Parent & its unit plurality gets free execution -); - -pub struct UsingOnlySelfCurrencyComponents< - WeightToFee: WeightToFeePolynomial, - AssetId: Get, - AccountId, - Currency: CurrencyT, - OnUnbalanced: OnUnbalancedT, ->( - Weight, - Currency::Balance, - PhantomData<(WeightToFee, AssetId, AccountId, Currency, OnUnbalanced)>, -); -impl< - WeightToFee: WeightToFeePolynomial, - AssetId: Get, - AccountId, - Currency: CurrencyT, - OnUnbalanced: OnUnbalancedT, - > WeightTrader - for UsingOnlySelfCurrencyComponents -{ - fn new() -> Self { - Self(0, Zero::zero(), PhantomData) - } - - fn buy_weight(&mut self, weight: Weight, payment: Assets) -> Result { - 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 { - 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, - AssetId: Get, - AccountId, - Currency: CurrencyT, - OnUnbalanced: OnUnbalancedT, - > Drop - for UsingOnlySelfCurrencyComponents -{ - 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; - type Barrier = Barrier; - type Weigher = FixedWeightBounds; - type Trader = - UsingOnlySelfCurrencyComponents, 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,); - -/// 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, - // ..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; - type XcmRouter = XcmRouter; - type ExecuteXcmOrigin = EnsureXcmOrigin; - type XcmExecuteFilter = Everything; - type XcmExecutor = XcmExecutor; - type XcmTeleportFilter = Everything; - type XcmReserveTransferFilter = Everything; - type Weigher = FixedWeightBounds; - type LocationInverter = LocationInverter; - 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; -} - -impl cumulus_pallet_xcmp_queue::Config for Runtime { - type WeightInfo = (); - type Event = Event; - type XcmExecutor = XcmExecutor; - type ChannelInfo = ParachainSystem; - type VersionWrapper = (); - type ExecuteOverweightOrigin = frame_system::EnsureRoot; - type ControllerOrigin = EnsureRoot; - type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin; -} - -impl cumulus_pallet_dmp_queue::Config for Runtime { - type Event = Event; - type XcmExecutor = XcmExecutor; - type ExecuteOverweightOrigin = frame_system::EnsureRoot; -} - -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; - type Event = Event; - type Currency = Balances; - type CollectionCreationPrice = CollectionCreationPrice; - type TreasuryAccountId = TreasuryAccountId; - type CollectionDispatch = CollectionDispatchT; - - type EvmTokenAddressMapping = EvmTokenAddressMapping; - type CrossTokenAddressMapping = CrossTokenAddressMapping; - type ContractAddress = EvmCollectionHelpersAddress; -} - -impl pallet_structure::Config for Runtime { - type Event = Event; - type Call = Call; - type WeightInfo = pallet_structure::weights::SubstrateWeight; -} - -impl pallet_fungible::Config for Runtime { - type WeightInfo = pallet_fungible::weights::SubstrateWeight; -} -impl pallet_refungible::Config for Runtime { - type WeightInfo = pallet_refungible::weights::SubstrateWeight; -} -impl pallet_nonfungible::Config for Runtime { - type WeightInfo = pallet_nonfungible::weights::SubstrateWeight; -} - -impl pallet_proxy_rmrk_core::Config for Runtime { - type WeightInfo = pallet_proxy_rmrk_core::weights::SubstrateWeight; - type Event = Event; -} - -impl pallet_proxy_rmrk_equip::Config for Runtime { - type WeightInfo = pallet_proxy_rmrk_equip::weights::SubstrateWeight; - type Event = Event; -} - -impl pallet_unique::Config for Runtime { - type Event = Event; - type WeightInfo = pallet_unique::weights::SubstrateWeight; - type CommonWeightInfo = CommonWeights; - type RefungibleExtensionsWeightInfo = CommonWeights; -} - -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; -} - -parameter_types! { - pub MaximumSchedulerWeight: Weight = Perbill::from_percent(50) * - RuntimeBlockWeights::get().max_block; - pub const MaxScheduledPerBlock: u32 = 50; -} - -type ChargeTransactionPayment = pallet_charge_transaction::ChargeTransactionPayment; -use frame_support::traits::NamedReservableCurrency; - -fn get_signed_extras(from: ::AccountId) -> SignedExtraScheduler { - ( - frame_system::CheckSpecVersion::::new(), - frame_system::CheckGenesis::::new(), - frame_system::CheckEra::::from(Era::Immortal), - frame_system::CheckNonce::::from(frame_system::Pallet::::account_nonce( - from, - )), - frame_system::CheckWeight::::new(), - // sponsoring transaction logic - // pallet_charge_transaction::ChargeTransactionPayment::::new(0), - ) -} - -pub struct SchedulerPaymentExecutor; -impl - DispatchCall for SchedulerPaymentExecutor -where - ::Call: Member - + Dispatchable - + SelfContainedCall - + GetDispatchInfo - + From>, - SelfContainedSignedInfo: Send + Sync + 'static, - Call: From<::Call> - + From<::Call> - + SelfContainedCall, - sp_runtime::AccountId32: From<::AccountId>, -{ - fn dispatch_call( - signer: ::AccountId, - call: ::Call, - ) -> Result< - Result>, - TransactionValidityError, - > { - let dispatch_info = call.get_dispatch_info(); - let extrinsic = fp_self_contained::CheckedExtrinsic::< - AccountId, - Call, - SignedExtraScheduler, - SelfContainedSignedInfo, - > { - signed: - CheckedSignature::::Signed( - signer.clone().into(), - get_signed_extras(signer.into()), - ), - function: call.into(), - }; - - extrinsic.apply::(&dispatch_info, 0) - } - - fn reserve_balance( - id: [u8; 16], - sponsor: ::AccountId, - call: ::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()); - - >::reserve_named( - &id, - &(sponsor.into()), - weight, - ) - } - - fn pay_for_call( - id: [u8; 16], - sponsor: ::AccountId, - call: ::Call, - ) -> Result { - let dispatch_info = call.get_dispatch_info(); - let weight: Balance = ChargeTransactionPayment::traditional_fee(0, &dispatch_info, 0); - Ok( - >::unreserve_named( - &id, - &(sponsor.into()), - weight, - ), - ) - } - - fn cancel_reserve( - id: [u8; 16], - sponsor: ::AccountId, - ) -> Result { - Ok( - >::unreserve_named( - &id, - &(sponsor.into()), - u128::MAX, - ), - ) - } -} - -parameter_types! { - pub const NoPreimagePostponement: Option = Some(10); - pub const Preimage: Option = Some(10); -} - -/// Used the compare the privilege of an origin inside the scheduler. -pub struct OriginPrivilegeCmp; - -impl PrivilegeCmp for OriginPrivilegeCmp { - fn cmp_privilege(_left: &OriginCaller, _right: &OriginCaller) -> Option { - 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; - type MaxScheduledPerBlock = MaxScheduledPerBlock; - type WeightInfo = (); - type CallExecutor = SchedulerPaymentExecutor; - type OriginPrivilegeCmp = OriginPrivilegeCmp; - type PreimageProvider = (); - type NoPreimagePostponement = NoPreimagePostponement; -} - -type EvmSponsorshipHandler = ( - UniqueEthSponsorshipHandler, - pallet_evm_contract_helpers::HelpersContractSponsoring, -); - -type SponsorshipHandler = ( - UniqueSponsorshipHandler, - //pallet_contract_helpers::ContractSponsorshipHandler, - pallet_evm_transaction_payment::BridgeSponsorshipHandler, -); - -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, ValidateUnsigned} = 20, - ParachainInfo: parachain_info::{Pallet, Storage, Config} = 21, - - Aura: pallet_aura::{Pallet, Config} = 22, - AuraExt: cumulus_pallet_aura_ext::{Pallet, Config} = 23, - - Balances: pallet_balances::{Pallet, Call, Storage, Config, Event} = 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} = 34, - Sudo: pallet_sudo::{Pallet, Call, Storage, Config, Event} = 35, - System: frame_system::{Pallet, Call, Storage, Config, Event} = 36, - Vesting: orml_vesting::{Pallet, Storage, Call, Event, Config} = 37, - // Vesting: pallet_vesting::{Pallet, Call, Config, Storage, Event} = 37, - // Contracts: pallet_contracts::{Pallet, Call, Storage, Event} = 38, - - // XCM helpers. - XcmpQueue: cumulus_pallet_xcmp_queue::{Pallet, Call, Storage, Event} = 50, - PolkadotXcm: pallet_xcm::{Pallet, Call, Event, Origin} = 51, - CumulusXcm: cumulus_pallet_xcm::{Pallet, Call, Event, Origin} = 52, - DmpQueue: cumulus_pallet_dmp_queue::{Pallet, Call, Storage, Event} = 53, - - // Unique Pallets - Inflation: pallet_inflation::{Pallet, Call, Storage} = 60, - Unique: pallet_unique::{Pallet, Call, Storage, Event} = 61, - Scheduler: pallet_unique_scheduler::{Pallet, Call, Storage, Event} = 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} = 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} = 70, - RmrkCore: pallet_proxy_rmrk_core::{Pallet, Call, Storage, Event} = 71, - RmrkEquip: pallet_proxy_rmrk_equip::{Pallet, Call, Storage, Event} = 72, - - // Frontier - EVM: pallet_evm::{Pallet, Config, Call, Storage, Event} = 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 for TransactionConverter { - fn convert_transaction(&self, transaction: pallet_ethereum::Transaction) -> UncheckedExtrinsic { - UncheckedExtrinsic::new_unsigned( - pallet_ethereum::Call::::transact { transaction }.into(), - ) - } -} - -impl fp_rpc::ConvertTransaction for TransactionConverter { - fn convert_transaction( - &self, - transaction: pallet_ethereum::Transaction, - ) -> opaque::UncheckedExtrinsic { - let extrinsic = UncheckedExtrinsic::new_unsigned( - pallet_ethereum::Call::::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; -/// Block header type as expected by this runtime. -pub type Header = generic::Header; -/// Block type as expected by this runtime. -pub type Block = generic::Block; -/// A Block signed with a Justification -pub type SignedBlock = generic::SignedBlock; -/// BlockId type as expected by this runtime. -pub type BlockId = generic::BlockId; -/// The SignedExtension to the basic transaction logic. -pub type SignedExtra = ( - frame_system::CheckSpecVersion, - // system::CheckTxVersion, - frame_system::CheckGenesis, - frame_system::CheckEra, - frame_system::CheckNonce, - frame_system::CheckWeight, - ChargeTransactionPayment, - //pallet_contract_helpers::ContractHelpersExtension, - pallet_ethereum::FakeTransactionFinalizer, -); -pub type SignedExtraScheduler = ( - frame_system::CheckSpecVersion, - frame_system::CheckGenesis, - frame_system::CheckEra, - frame_system::CheckNonce, - frame_system::CheckWeight, -); -/// Unchecked extrinsic type as expected by this runtime. -pub type UncheckedExtrinsic = - fp_self_contained::UncheckedExtrinsic; -/// Extrinsic type that has already been checked. -pub type CheckedExtrinsic = fp_self_contained::CheckedExtrinsic; -/// Executive: handles dispatch to the various modules. -pub type Executive = frame_executive::Executive< - Runtime, - Block, - frame_system::ChainContext, - 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> { - match self { - Call::Ethereum(call) => call.check_self_contained(), - _ => None, - } - } - - fn validate_self_contained( - &self, - info: &Self::SignedInfo, - dispatch_info: &DispatchInfoOf, - len: usize, - ) -> Option { - match self { - Call::Ethereum(call) => call.validate_self_contained(info, dispatch_info, len), - _ => None, - } - } - - fn pre_dispatch_self_contained( - &self, - info: &Self::SignedInfo, - ) -> Option> { - match self { - Call::Ethereum(call) => call.pre_dispatch_self_contained(info), - _ => None, - } - } - - fn apply_self_contained( - self, - info: Self::SignedInfo, - ) -> Option>> { - 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 = ::CollectionDispatch::dispatch(>::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, - RmrkInstanceInfo, - RmrkResourceInfo, - RmrkPropertyInfo, - RmrkBaseInfo, - RmrkPartType, - RmrkTheme - > for Runtime { - fn last_collection_idx() -> Result { - pallet_proxy_rmrk_core::rpc::last_collection_idx::() - } - - fn collection_by_id(collection_id: RmrkCollectionId) -> Result>, DispatchError> { - pallet_proxy_rmrk_core::rpc::collection_by_id::(collection_id) - } - - fn nft_by_id(collection_id: RmrkCollectionId, nft_by_id: RmrkNftId) -> Result>, DispatchError> { - pallet_proxy_rmrk_core::rpc::nft_by_id::(collection_id, nft_by_id) - } - - fn account_tokens(account_id: AccountId, collection_id: RmrkCollectionId) -> Result, DispatchError> { - pallet_proxy_rmrk_core::rpc::account_tokens::(account_id, collection_id) - } - - fn nft_children(collection_id: RmrkCollectionId, nft_id: RmrkNftId) -> Result, DispatchError> { - pallet_proxy_rmrk_core::rpc::nft_children::(collection_id, nft_id) - } - - fn collection_properties(collection_id: RmrkCollectionId, filter_keys: Option>) -> Result, DispatchError> { - pallet_proxy_rmrk_core::rpc::collection_properties::(collection_id, filter_keys) - } - - fn nft_properties(collection_id: RmrkCollectionId, nft_id: RmrkNftId, filter_keys: Option>) -> Result, DispatchError> { - pallet_proxy_rmrk_core::rpc::nft_properties::(collection_id, nft_id, filter_keys) - } - - fn nft_resources(collection_id: RmrkCollectionId, nft_id: RmrkNftId) -> Result, DispatchError> { - pallet_proxy_rmrk_core::rpc::nft_resources::(collection_id, nft_id) - } - - fn nft_resource_priority(collection_id: RmrkCollectionId, nft_id: RmrkNftId, resource_id: RmrkResourceId) -> Result, DispatchError> { - pallet_proxy_rmrk_core::rpc::nft_resource_priority::(collection_id, nft_id, resource_id) - } - - fn base(base_id: RmrkBaseId) -> Result>, DispatchError> { - pallet_proxy_rmrk_equip::rpc::base::(base_id) - } - - fn base_parts(base_id: RmrkBaseId) -> Result, DispatchError> { - pallet_proxy_rmrk_equip::rpc::base_parts::(base_id) - } - - fn theme_names(base_id: RmrkBaseId) -> Result, DispatchError> { - pallet_proxy_rmrk_equip::rpc::theme_names::(base_id) - } - - fn theme(base_id: RmrkBaseId, theme_name: RmrkThemeName, filter_keys: Option>) -> Result, DispatchError> { - pallet_proxy_rmrk_equip::rpc::theme::(base_id, theme_name, filter_keys) - } - } -} - -struct CheckInherents; - -impl cumulus_pallet_parachain_system::CheckInherents 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, --- 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 --- 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; - -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 { - /// 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 = >::NegativeImbalance; - -pub struct DealWithFees; -impl OnUnbalanced for DealWithFees { - fn on_unbalanceds(mut fees_then_tips: impl Iterator) { - 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 / ::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; - type EvmAddressMapping = HashedAddressMapping; - 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; - type CallOrigin = EnsureAddressTruncated; - type WithdrawOrigin = EnsureAddressTruncated; - type AddressMapping = HashedAddressMapping; - type PrecompilesType = (); - type PrecompilesValue = (); - type Currency = Balances; - type Event = Event; - type OnMethodCall = ( - pallet_evm_migration::OnMethodCall, - pallet_evm_contract_helpers::HelpersOnMethodCall, - CollectionDispatchT, - pallet_unique::eth::CollectionHelpersOnMethodCall, - ); - type OnCreate = pallet_evm_contract_helpers::HelpersOnCreate; - type ChainId = ChainId; - type Runner = pallet_evm::runner::stack::Runner; - type OnChargeTransaction = pallet_evm::EVMCurrencyAdapter; - type TransactionValidityHack = pallet_evm_transaction_payment::TransactionValidityHack; - type FindAuthor = EthereumFindAuthor; -} - -impl pallet_evm_migration::Config for Runtime { - type WeightInfo = pallet_evm_migration::weights::SubstrateWeight; -} - -pub struct EthereumFindAuthor(core::marker::PhantomData); -impl> FindAuthor for EthereumFindAuthor { - fn find_author<'a, I>(digests: I) -> Option - where - I: 'a + IntoIterator, - { - 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; -} - -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; - /// 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; - /// 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; - /// 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; - /// 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; - /// 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; -} - -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::> 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() / ( - ::WeightInfo::on_initialize_per_queue_item(1) - - ::WeightInfo::on_initialize_per_queue_item(0) - )) / 5) as u32; - pub Schedule: pallet_contracts::Schedule = 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; - type WeightInfo = pallet_contracts::weights::SubstrateWeight; - type ChainExtension = NFTExtension; - type DeletionQueueDepth = DeletionQueueDepth; - type DeletionWeightLimit = DeletionWeightLimit; - type Schedule = Schedule; - type CallStack = [pallet_contracts::Frame; 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(sp_std::marker::PhantomData); - -impl WeightToFeePolynomial for LinearFee -where - T: BaseArithmetic + From + Copy + Unsigned, -{ - type Balance = T; - - fn polynomial() -> WeightToFeeCoefficients { - 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; - type LengthToFee = ConstantMultiplier; - type OperationalFeeMultiplier = OperationalFeeMultiplier; - type WeightToFee = LinearFee; - 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; - type RejectOrigin = EnsureRoot; - 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; - type MaxApprovals = MaxApprovals; -} - -impl pallet_sudo::Config for Runtime { - type Event = Event; - type Call = Call; -} - -pub struct RelayChainBlockNumberProvider(sp_std::marker::PhantomData); - -impl BlockNumberProvider - for RelayChainBlockNumberProvider -{ - type BlockNumber = BlockNumber; - - fn current_block_number() -> Self::BlockNumber { - cumulus_pallet_parachain_system::Pallet::::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; - type MinVestedTransfer = MinVestedTransfer; - type VestedTransferOrigin = EnsureSigned; - type WeightInfo = (); - type MaxVestingSchedules = MaxVestingSchedules; - type BlockNumberProvider = RelayChainBlockNumberProvider; -} - -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; - type OnSystemEvent = (); - // type DownwardMessageHandlers = cumulus_primitives_utility::UnqueuedDmpAsParent< - // MaxDownwardMessageWeight, - // XcmExecutor, - // 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, - // Sibling parachain origins convert to AccountId via the `ParaId::into`. - SiblingParachainConvertsVia, - // Straight up local `AccountId32` origins just alias directly to `AccountId`. - AccountId32Aliases, -); - -pub struct OnlySelfCurrency; -impl> MatchesFungible for OnlySelfCurrency { - fn matches_fungible(a: &MultiAsset) -> Option { - 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, - // Native converter for Relay-chain (Parent) location; will converts to a `Relay` origin when - // recognised. - RelayChainAsNative, - // Native converter for sibling Parachains; will convert to a `SiblingPara` origin when - // recognised. - SiblingParachainAsNative, - // Superuser converter for the Relay-chain (Parent) location. This will allow it to issue a - // transaction from the Root origin. - ParentAsSuperuser, - // Native signed account converter; this just converts an `AccountId32` origin into a normal - // `Origin::Signed` origin of the same 32-byte value. - SignedAccountId32AsNative, - // Xcm origins can be represented natively under the Xcm pallet's Xcm origin. - XcmPassthrough, -); - -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 { parents: 1, interior: Here } | - MultiLocation { parents: 1, interior: X1(Plurality { id: BodyId::Unit, .. }) } - }; -} - -pub type Barrier = ( - TakeWeightCredit, - AllowTopLevelPaidExecutionFrom, - // ^^^ Parent & its unit plurality gets free execution -); - -pub struct UsingOnlySelfCurrencyComponents< - WeightToFee: WeightToFeePolynomial, - AssetId: Get, - AccountId, - Currency: CurrencyT, - OnUnbalanced: OnUnbalancedT, ->( - Weight, - Currency::Balance, - PhantomData<(WeightToFee, AssetId, AccountId, Currency, OnUnbalanced)>, -); -impl< - WeightToFee: WeightToFeePolynomial, - AssetId: Get, - AccountId, - Currency: CurrencyT, - OnUnbalanced: OnUnbalancedT, - > WeightTrader - for UsingOnlySelfCurrencyComponents -{ - fn new() -> Self { - Self(0, Zero::zero(), PhantomData) - } - - fn buy_weight(&mut self, weight: Weight, payment: Assets) -> Result { - 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 { - 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, - AssetId: Get, - AccountId, - Currency: CurrencyT, - OnUnbalanced: OnUnbalancedT, - > Drop - for UsingOnlySelfCurrencyComponents -{ - 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; - type Barrier = Barrier; - type Weigher = FixedWeightBounds; - type Trader = - UsingOnlySelfCurrencyComponents, 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,); - -/// 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, - // ..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; - type XcmRouter = XcmRouter; - type ExecuteXcmOrigin = EnsureXcmOrigin; - type XcmExecuteFilter = Everything; - type XcmExecutor = XcmExecutor; - type XcmTeleportFilter = Everything; - type XcmReserveTransferFilter = Everything; - type Weigher = FixedWeightBounds; - type LocationInverter = LocationInverter; - 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; -} - -impl cumulus_pallet_xcmp_queue::Config for Runtime { - type WeightInfo = (); - type Event = Event; - type XcmExecutor = XcmExecutor; - type ChannelInfo = ParachainSystem; - type VersionWrapper = (); - type ExecuteOverweightOrigin = frame_system::EnsureRoot; - type ControllerOrigin = EnsureRoot; - type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin; -} - -impl cumulus_pallet_dmp_queue::Config for Runtime { - type Event = Event; - type XcmExecutor = XcmExecutor; - type ExecuteOverweightOrigin = frame_system::EnsureRoot; -} - -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; - type Event = Event; - type Currency = Balances; - type CollectionCreationPrice = CollectionCreationPrice; - type TreasuryAccountId = TreasuryAccountId; - type CollectionDispatch = CollectionDispatchT; - - type EvmTokenAddressMapping = EvmTokenAddressMapping; - type CrossTokenAddressMapping = CrossTokenAddressMapping; - type ContractAddress = EvmCollectionHelpersAddress; -} - -impl pallet_structure::Config for Runtime { - type Event = Event; - type Call = Call; - type WeightInfo = pallet_structure::weights::SubstrateWeight; -} - -impl pallet_fungible::Config for Runtime { - type WeightInfo = pallet_fungible::weights::SubstrateWeight; -} -impl pallet_refungible::Config for Runtime { - type WeightInfo = pallet_refungible::weights::SubstrateWeight; -} -impl pallet_nonfungible::Config for Runtime { - type WeightInfo = pallet_nonfungible::weights::SubstrateWeight; -} - -impl pallet_proxy_rmrk_core::Config for Runtime { - type WeightInfo = pallet_proxy_rmrk_core::weights::SubstrateWeight; - type Event = Event; -} - -impl pallet_proxy_rmrk_equip::Config for Runtime { - type WeightInfo = pallet_proxy_rmrk_equip::weights::SubstrateWeight; - type Event = Event; -} - -impl pallet_unique::Config for Runtime { - type Event = Event; - type WeightInfo = pallet_unique::weights::SubstrateWeight; - type CommonWeightInfo = CommonWeights; - type RefungibleExtensionsWeightInfo = CommonWeights; -} - -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; -} - -parameter_types! { - pub MaximumSchedulerWeight: Weight = Perbill::from_percent(50) * - RuntimeBlockWeights::get().max_block; - pub const MaxScheduledPerBlock: u32 = 50; -} - -type ChargeTransactionPayment = pallet_charge_transaction::ChargeTransactionPayment; -use frame_support::traits::NamedReservableCurrency; - -fn get_signed_extras(from: ::AccountId) -> SignedExtraScheduler { - ( - frame_system::CheckSpecVersion::::new(), - frame_system::CheckGenesis::::new(), - frame_system::CheckEra::::from(Era::Immortal), - frame_system::CheckNonce::::from(frame_system::Pallet::::account_nonce( - from, - )), - frame_system::CheckWeight::::new(), - // sponsoring transaction logic - // pallet_charge_transaction::ChargeTransactionPayment::::new(0), - ) -} - -pub struct SchedulerPaymentExecutor; -impl - DispatchCall for SchedulerPaymentExecutor -where - ::Call: Member - + Dispatchable - + SelfContainedCall - + GetDispatchInfo - + From>, - SelfContainedSignedInfo: Send + Sync + 'static, - Call: From<::Call> - + From<::Call> - + SelfContainedCall, - sp_runtime::AccountId32: From<::AccountId>, -{ - fn dispatch_call( - signer: ::AccountId, - call: ::Call, - ) -> Result< - Result>, - TransactionValidityError, - > { - let dispatch_info = call.get_dispatch_info(); - let extrinsic = fp_self_contained::CheckedExtrinsic::< - AccountId, - Call, - SignedExtraScheduler, - SelfContainedSignedInfo, - > { - signed: - CheckedSignature::::Signed( - signer.clone().into(), - get_signed_extras(signer.into()), - ), - function: call.into(), - }; - - extrinsic.apply::(&dispatch_info, 0) - } - - fn reserve_balance( - id: [u8; 16], - sponsor: ::AccountId, - call: ::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()); - - >::reserve_named( - &id, - &(sponsor.into()), - weight.into(), - ) - } - - fn pay_for_call( - id: [u8; 16], - sponsor: ::AccountId, - call: ::Call, - ) -> Result { - let dispatch_info = call.get_dispatch_info(); - let weight: Balance = ChargeTransactionPayment::traditional_fee(0, &dispatch_info, 0); - Ok( - >::unreserve_named( - &id, - &(sponsor.into()), - weight.into(), - ), - ) - } - - fn cancel_reserve( - id: [u8; 16], - sponsor: ::AccountId, - ) -> Result { - Ok( - >::unreserve_named( - &id, - &(sponsor.into()), - u128::MAX, - ), - ) - } -} - -parameter_types! { - pub const NoPreimagePostponement: Option = Some(10); - pub const Preimage: Option = Some(10); -} - -/// Used the compare the privilege of an origin inside the scheduler. -pub struct OriginPrivilegeCmp; - -impl PrivilegeCmp for OriginPrivilegeCmp { - fn cmp_privilege(_left: &OriginCaller, _right: &OriginCaller) -> Option { - 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; - type MaxScheduledPerBlock = MaxScheduledPerBlock; - type WeightInfo = (); - type CallExecutor = SchedulerPaymentExecutor; - type OriginPrivilegeCmp = OriginPrivilegeCmp; - type PreimageProvider = (); - type NoPreimagePostponement = NoPreimagePostponement; -} - -type EvmSponsorshipHandler = ( - UniqueEthSponsorshipHandler, - pallet_evm_contract_helpers::HelpersContractSponsoring, -); -type SponsorshipHandler = ( - UniqueSponsorshipHandler, - //pallet_contract_helpers::ContractSponsorshipHandler, - pallet_evm_transaction_payment::BridgeSponsorshipHandler, -); - -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, ValidateUnsigned} = 20, - ParachainInfo: parachain_info::{Pallet, Storage, Config} = 21, - - Aura: pallet_aura::{Pallet, Config} = 22, - AuraExt: cumulus_pallet_aura_ext::{Pallet, Config} = 23, - - Balances: pallet_balances::{Pallet, Call, Storage, Config, Event} = 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} = 34, - Sudo: pallet_sudo::{Pallet, Call, Storage, Config, Event} = 35, - System: frame_system::{Pallet, Call, Storage, Config, Event} = 36, - Vesting: orml_vesting::{Pallet, Storage, Call, Event, Config} = 37, - // Vesting: pallet_vesting::{Pallet, Call, Config, Storage, Event} = 37, - // Contracts: pallet_contracts::{Pallet, Call, Storage, Event} = 38, - - // XCM helpers. - XcmpQueue: cumulus_pallet_xcmp_queue::{Pallet, Call, Storage, Event} = 50, - PolkadotXcm: pallet_xcm::{Pallet, Call, Event, Origin} = 51, - CumulusXcm: cumulus_pallet_xcm::{Pallet, Call, Event, Origin} = 52, - DmpQueue: cumulus_pallet_dmp_queue::{Pallet, Call, Storage, Event} = 53, - - // Unique Pallets - Inflation: pallet_inflation::{Pallet, Call, Storage} = 60, - Unique: pallet_unique::{Pallet, Call, Storage, Event} = 61, - Scheduler: pallet_unique_scheduler::{Pallet, Call, Storage, Event} = 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} = 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} = 70, - RmrkCore: pallet_proxy_rmrk_core::{Pallet, Call, Storage, Event} = 71, - RmrkEquip: pallet_proxy_rmrk_equip::{Pallet, Call, Storage, Event} = 72, - - // Frontier - EVM: pallet_evm::{Pallet, Config, Call, Storage, Event} = 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 for TransactionConverter { - fn convert_transaction(&self, transaction: pallet_ethereum::Transaction) -> UncheckedExtrinsic { - UncheckedExtrinsic::new_unsigned( - pallet_ethereum::Call::::transact { transaction }.into(), - ) - } -} - -impl fp_rpc::ConvertTransaction for TransactionConverter { - fn convert_transaction( - &self, - transaction: pallet_ethereum::Transaction, - ) -> opaque::UncheckedExtrinsic { - let extrinsic = UncheckedExtrinsic::new_unsigned( - pallet_ethereum::Call::::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; -/// Block header type as expected by this runtime. -pub type Header = generic::Header; -/// Block type as expected by this runtime. -pub type Block = generic::Block; -/// A Block signed with a Justification -pub type SignedBlock = generic::SignedBlock; -/// BlockId type as expected by this runtime. -pub type BlockId = generic::BlockId; -/// The SignedExtension to the basic transaction logic. -pub type SignedExtra = ( - frame_system::CheckSpecVersion, - // system::CheckTxVersion, - frame_system::CheckGenesis, - frame_system::CheckEra, - frame_system::CheckNonce, - frame_system::CheckWeight, - ChargeTransactionPayment, - //pallet_contract_helpers::ContractHelpersExtension, - pallet_ethereum::FakeTransactionFinalizer, -); - -pub type SignedExtraScheduler = ( - frame_system::CheckSpecVersion, - frame_system::CheckGenesis, - frame_system::CheckEra, - frame_system::CheckNonce, - frame_system::CheckWeight, - // pallet_charge_transaction::ChargeTransactionPayment, -); -/// Unchecked extrinsic type as expected by this runtime. -pub type UncheckedExtrinsic = - fp_self_contained::UncheckedExtrinsic; -/// Extrinsic type that has already been checked. -pub type CheckedExtrinsic = fp_self_contained::CheckedExtrinsic; -/// Executive: handles dispatch to the various modules. -pub type Executive = frame_executive::Executive< - Runtime, - Block, - frame_system::ChainContext, - 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> { - match self { - Call::Ethereum(call) => call.check_self_contained(), - _ => None, - } - } - - fn validate_self_contained( - &self, - info: &Self::SignedInfo, - dispatch_info: &DispatchInfoOf, - len: usize, - ) -> Option { - match self { - Call::Ethereum(call) => call.validate_self_contained(info, dispatch_info, len), - _ => None, - } - } - - fn pre_dispatch_self_contained( - &self, - info: &Self::SignedInfo, - ) -> Option> { - match self { - Call::Ethereum(call) => call.pre_dispatch_self_contained(info), - _ => None, - } - } - - fn apply_self_contained( - self, - info: Self::SignedInfo, - ) -> Option>> { - 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 = ::CollectionDispatch::dispatch(>::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, - RmrkInstanceInfo, - RmrkResourceInfo, - RmrkPropertyInfo, - RmrkBaseInfo, - RmrkPartType, - RmrkTheme - > for Runtime { - fn last_collection_idx() -> Result { - pallet_proxy_rmrk_core::rpc::last_collection_idx::() - } - - fn collection_by_id(collection_id: RmrkCollectionId) -> Result>, DispatchError> { - pallet_proxy_rmrk_core::rpc::collection_by_id::(collection_id) - } - - fn nft_by_id(collection_id: RmrkCollectionId, nft_by_id: RmrkNftId) -> Result>, DispatchError> { - pallet_proxy_rmrk_core::rpc::nft_by_id::(collection_id, nft_by_id) - } - - fn account_tokens(account_id: AccountId, collection_id: RmrkCollectionId) -> Result, DispatchError> { - pallet_proxy_rmrk_core::rpc::account_tokens::(account_id, collection_id) - } - - fn nft_children(collection_id: RmrkCollectionId, nft_id: RmrkNftId) -> Result, DispatchError> { - pallet_proxy_rmrk_core::rpc::nft_children::(collection_id, nft_id) - } - - fn collection_properties(collection_id: RmrkCollectionId, filter_keys: Option>) -> Result, DispatchError> { - pallet_proxy_rmrk_core::rpc::collection_properties::(collection_id, filter_keys) - } - - fn nft_properties(collection_id: RmrkCollectionId, nft_id: RmrkNftId, filter_keys: Option>) -> Result, DispatchError> { - pallet_proxy_rmrk_core::rpc::nft_properties::(collection_id, nft_id, filter_keys) - } - - fn nft_resources(collection_id: RmrkCollectionId, nft_id: RmrkNftId) -> Result, DispatchError> { - pallet_proxy_rmrk_core::rpc::nft_resources::(collection_id, nft_id) - } - - fn nft_resource_priority(collection_id: RmrkCollectionId, nft_id: RmrkNftId, resource_id: RmrkResourceId) -> Result, DispatchError> { - pallet_proxy_rmrk_core::rpc::nft_resource_priority::(collection_id, nft_id, resource_id) - } - - fn base(base_id: RmrkBaseId) -> Result>, DispatchError> { - pallet_proxy_rmrk_equip::rpc::base::(base_id) - } - - fn base_parts(base_id: RmrkBaseId) -> Result, DispatchError> { - pallet_proxy_rmrk_equip::rpc::base_parts::(base_id) - } - - fn theme_names(base_id: RmrkBaseId) -> Result, DispatchError> { - pallet_proxy_rmrk_equip::rpc::theme_names::(base_id) - } - - fn theme(base_id: RmrkBaseId, theme_name: RmrkThemeName, filter_keys: Option>) -> Result, DispatchError> { - pallet_proxy_rmrk_equip::rpc::theme::(base_id, theme_name, filter_keys) - } - } -} - -struct CheckInherents; - -impl cumulus_pallet_parachain_system::CheckInherents 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, --- 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' } --- 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; type Block = frame_system::mocking::MockBlock; --- 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 --- 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; - -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 { - /// 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 = >::NegativeImbalance; - -pub struct DealWithFees; -impl OnUnbalanced for DealWithFees { - fn on_unbalanceds(mut fees_then_tips: impl Iterator) { - 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 / ::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; - type EvmAddressMapping = pallet_evm::HashedAddressMapping; - 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; - type CallOrigin = EnsureAddressTruncated; - type WithdrawOrigin = EnsureAddressTruncated; - type AddressMapping = HashedAddressMapping; - type PrecompilesType = (); - type PrecompilesValue = (); - type Currency = Balances; - type Event = Event; - type OnMethodCall = ( - pallet_evm_migration::OnMethodCall, - pallet_evm_contract_helpers::HelpersOnMethodCall, - CollectionDispatchT, - pallet_unique::eth::CollectionHelpersOnMethodCall, - ); - type OnCreate = pallet_evm_contract_helpers::HelpersOnCreate; - type ChainId = ChainId; - type Runner = pallet_evm::runner::stack::Runner; - type OnChargeTransaction = pallet_evm::EVMCurrencyAdapter; - type TransactionValidityHack = pallet_evm_transaction_payment::TransactionValidityHack; - type FindAuthor = EthereumFindAuthor; -} - -impl pallet_evm_migration::Config for Runtime { - type WeightInfo = pallet_evm_migration::weights::SubstrateWeight; -} - -pub struct EthereumFindAuthor(core::marker::PhantomData); -impl> FindAuthor for EthereumFindAuthor { - fn find_author<'a, I>(digests: I) -> Option - where - I: 'a + IntoIterator, - { - 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; -} - -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; - /// 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; - /// 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; - /// 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; - /// 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; - /// 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; -} - -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::> 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() / ( - ::WeightInfo::on_initialize_per_queue_item(1) - - ::WeightInfo::on_initialize_per_queue_item(0) - )) / 5) as u32; - pub Schedule: pallet_contracts::Schedule = 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; - type WeightInfo = pallet_contracts::weights::SubstrateWeight; - type ChainExtension = NFTExtension; - type DeletionQueueDepth = DeletionQueueDepth; - type DeletionWeightLimit = DeletionWeightLimit; - type Schedule = Schedule; - type CallStack = [pallet_contracts::Frame; 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(sp_std::marker::PhantomData); - -impl WeightToFeePolynomial for LinearFee -where - T: BaseArithmetic + From + Copy + Unsigned, -{ - type Balance = T; - - fn polynomial() -> WeightToFeeCoefficients { - 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; - type LengthToFee = ConstantMultiplier; - type OperationalFeeMultiplier = OperationalFeeMultiplier; - type WeightToFee = LinearFee; - 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; - type RejectOrigin = EnsureRoot; - 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; - type MaxApprovals = MaxApprovals; -} - -impl pallet_sudo::Config for Runtime { - type Event = Event; - type Call = Call; -} - -pub struct RelayChainBlockNumberProvider(sp_std::marker::PhantomData); - -impl BlockNumberProvider - for RelayChainBlockNumberProvider -{ - type BlockNumber = BlockNumber; - - fn current_block_number() -> Self::BlockNumber { - cumulus_pallet_parachain_system::Pallet::::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; - type MinVestedTransfer = MinVestedTransfer; - type VestedTransferOrigin = EnsureSigned; - type WeightInfo = (); - type MaxVestingSchedules = MaxVestingSchedules; - type BlockNumberProvider = RelayChainBlockNumberProvider; -} - -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; - type OnSystemEvent = (); - // type DownwardMessageHandlers = cumulus_primitives_utility::UnqueuedDmpAsParent< - // MaxDownwardMessageWeight, - // XcmExecutor, - // 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, - // Sibling parachain origins convert to AccountId via the `ParaId::into`. - SiblingParachainConvertsVia, - // Straight up local `AccountId32` origins just alias directly to `AccountId`. - AccountId32Aliases, -); - -pub struct OnlySelfCurrency; -impl> MatchesFungible for OnlySelfCurrency { - fn matches_fungible(a: &MultiAsset) -> Option { - 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, - // Native converter for Relay-chain (Parent) location; will converts to a `Relay` origin when - // recognised. - RelayChainAsNative, - // Native converter for sibling Parachains; will convert to a `SiblingPara` origin when - // recognised. - SiblingParachainAsNative, - // Superuser converter for the Relay-chain (Parent) location. This will allow it to issue a - // transaction from the Root origin. - ParentAsSuperuser, - // Native signed account converter; this just converts an `AccountId32` origin into a normal - // `Origin::Signed` origin of the same 32-byte value. - SignedAccountId32AsNative, - // Xcm origins can be represented natively under the Xcm pallet's Xcm origin. - XcmPassthrough, -); - -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 { parents: 1, interior: Here } | - MultiLocation { parents: 1, interior: X1(Plurality { id: BodyId::Unit, .. }) } - }; -} - -pub type Barrier = ( - TakeWeightCredit, - AllowTopLevelPaidExecutionFrom, - // ^^^ Parent & its unit plurality gets free execution -); - -pub struct UsingOnlySelfCurrencyComponents< - WeightToFee: WeightToFeePolynomial, - AssetId: Get, - AccountId, - Currency: CurrencyT, - OnUnbalanced: OnUnbalancedT, ->( - Weight, - Currency::Balance, - PhantomData<(WeightToFee, AssetId, AccountId, Currency, OnUnbalanced)>, -); -impl< - WeightToFee: WeightToFeePolynomial, - AssetId: Get, - AccountId, - Currency: CurrencyT, - OnUnbalanced: OnUnbalancedT, - > WeightTrader - for UsingOnlySelfCurrencyComponents -{ - fn new() -> Self { - Self(0, Zero::zero(), PhantomData) - } - - fn buy_weight(&mut self, weight: Weight, payment: Assets) -> Result { - 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 { - 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, - AssetId: Get, - AccountId, - Currency: CurrencyT, - OnUnbalanced: OnUnbalancedT, - > Drop - for UsingOnlySelfCurrencyComponents -{ - 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; - type Barrier = Barrier; - type Weigher = FixedWeightBounds; - type Trader = - UsingOnlySelfCurrencyComponents, 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,); - -/// 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, - // ..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; - type XcmRouter = XcmRouter; - type ExecuteXcmOrigin = EnsureXcmOrigin; - type XcmExecuteFilter = Everything; - type XcmExecutor = XcmExecutor; - type XcmTeleportFilter = Everything; - type XcmReserveTransferFilter = Everything; - type Weigher = FixedWeightBounds; - type LocationInverter = LocationInverter; - 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; -} - -impl cumulus_pallet_xcmp_queue::Config for Runtime { - type WeightInfo = (); - type Event = Event; - type XcmExecutor = XcmExecutor; - type ChannelInfo = ParachainSystem; - type VersionWrapper = (); - type ExecuteOverweightOrigin = frame_system::EnsureRoot; - type ControllerOrigin = EnsureRoot; - type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin; -} - -impl cumulus_pallet_dmp_queue::Config for Runtime { - type Event = Event; - type XcmExecutor = XcmExecutor; - type ExecuteOverweightOrigin = frame_system::EnsureRoot; -} - -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; - type Event = Event; - type Currency = Balances; - type CollectionCreationPrice = CollectionCreationPrice; - type TreasuryAccountId = TreasuryAccountId; - type CollectionDispatch = CollectionDispatchT; - - type EvmTokenAddressMapping = EvmTokenAddressMapping; - type CrossTokenAddressMapping = CrossTokenAddressMapping; - type ContractAddress = EvmCollectionHelpersAddress; -} - -impl pallet_structure::Config for Runtime { - type Event = Event; - type Call = Call; - type WeightInfo = pallet_structure::weights::SubstrateWeight; -} - -impl pallet_fungible::Config for Runtime { - type WeightInfo = pallet_fungible::weights::SubstrateWeight; -} -impl pallet_refungible::Config for Runtime { - type WeightInfo = pallet_refungible::weights::SubstrateWeight; -} -impl pallet_nonfungible::Config for Runtime { - type WeightInfo = pallet_nonfungible::weights::SubstrateWeight; -} - -impl pallet_unique::Config for Runtime { - type Event = Event; - type WeightInfo = pallet_unique::weights::SubstrateWeight; - type CommonWeightInfo = CommonWeights; - type RefungibleExtensionsWeightInfo = CommonWeights; -} - -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; -} - -parameter_types! { - pub MaximumSchedulerWeight: Weight = Perbill::from_percent(50) * - RuntimeBlockWeights::get().max_block; - pub const MaxScheduledPerBlock: u32 = 50; -} - -type ChargeTransactionPayment = pallet_charge_transaction::ChargeTransactionPayment; -use frame_support::traits::NamedReservableCurrency; - -fn get_signed_extras(from: ::AccountId) -> SignedExtraScheduler { - ( - frame_system::CheckSpecVersion::::new(), - frame_system::CheckGenesis::::new(), - frame_system::CheckEra::::from(Era::Immortal), - frame_system::CheckNonce::::from(frame_system::Pallet::::account_nonce( - from, - )), - frame_system::CheckWeight::::new(), - // sponsoring transaction logic - // pallet_charge_transaction::ChargeTransactionPayment::::new(0), - ) -} - -pub struct SchedulerPaymentExecutor; -impl - DispatchCall for SchedulerPaymentExecutor -where - ::Call: Member - + Dispatchable - + SelfContainedCall - + GetDispatchInfo - + From>, - SelfContainedSignedInfo: Send + Sync + 'static, - Call: From<::Call> - + From<::Call> - + SelfContainedCall, - sp_runtime::AccountId32: From<::AccountId>, -{ - fn dispatch_call( - signer: ::AccountId, - call: ::Call, - ) -> Result< - Result>, - TransactionValidityError, - > { - let dispatch_info = call.get_dispatch_info(); - let extrinsic = fp_self_contained::CheckedExtrinsic::< - AccountId, - Call, - SignedExtraScheduler, - SelfContainedSignedInfo, - > { - signed: - CheckedSignature::::Signed( - signer.clone().into(), - get_signed_extras(signer.into()), - ), - function: call.into(), - }; - - extrinsic.apply::(&dispatch_info, 0) - } - - fn reserve_balance( - id: [u8; 16], - sponsor: ::AccountId, - call: ::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()); - - >::reserve_named( - &id, - &(sponsor.into()), - weight, - ) - } - - fn pay_for_call( - id: [u8; 16], - sponsor: ::AccountId, - call: ::Call, - ) -> Result { - let dispatch_info = call.get_dispatch_info(); - let weight: Balance = ChargeTransactionPayment::traditional_fee(0, &dispatch_info, 0); - Ok( - >::unreserve_named( - &id, - &(sponsor.into()), - weight, - ), - ) - } - - fn cancel_reserve( - id: [u8; 16], - sponsor: ::AccountId, - ) -> Result { - Ok( - >::unreserve_named( - &id, - &(sponsor.into()), - u128::MAX, - ), - ) - } -} - -parameter_types! { - pub const NoPreimagePostponement: Option = Some(10); - pub const Preimage: Option = Some(10); -} - -/// Used the compare the privilege of an origin inside the scheduler. -pub struct OriginPrivilegeCmp; - -impl PrivilegeCmp for OriginPrivilegeCmp { - fn cmp_privilege(_left: &OriginCaller, _right: &OriginCaller) -> Option { - 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; - type MaxScheduledPerBlock = MaxScheduledPerBlock; - type WeightInfo = (); - type CallExecutor = SchedulerPaymentExecutor; - type OriginPrivilegeCmp = OriginPrivilegeCmp; - type PreimageProvider = (); - type NoPreimagePostponement = NoPreimagePostponement; -} - -type EvmSponsorshipHandler = ( - UniqueEthSponsorshipHandler, - pallet_evm_contract_helpers::HelpersContractSponsoring, -); -type SponsorshipHandler = ( - UniqueSponsorshipHandler, - //pallet_contract_helpers::ContractSponsorshipHandler, - pallet_evm_transaction_payment::BridgeSponsorshipHandler, -); - -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, ValidateUnsigned} = 20, - ParachainInfo: parachain_info::{Pallet, Storage, Config} = 21, - - Aura: pallet_aura::{Pallet, Config} = 22, - AuraExt: cumulus_pallet_aura_ext::{Pallet, Config} = 23, - - Balances: pallet_balances::{Pallet, Call, Storage, Config, Event} = 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} = 34, - Sudo: pallet_sudo::{Pallet, Call, Storage, Config, Event} = 35, - System: frame_system::{Pallet, Call, Storage, Config, Event} = 36, - Vesting: orml_vesting::{Pallet, Storage, Call, Event, Config} = 37, - // Vesting: pallet_vesting::{Pallet, Call, Config, Storage, Event} = 37, - // Contracts: pallet_contracts::{Pallet, Call, Storage, Event} = 38, - - // XCM helpers. - XcmpQueue: cumulus_pallet_xcmp_queue::{Pallet, Call, Storage, Event} = 50, - PolkadotXcm: pallet_xcm::{Pallet, Call, Event, Origin} = 51, - CumulusXcm: cumulus_pallet_xcm::{Pallet, Call, Event, Origin} = 52, - DmpQueue: cumulus_pallet_dmp_queue::{Pallet, Call, Storage, Event} = 53, - - // Unique Pallets - Inflation: pallet_inflation::{Pallet, Call, Storage} = 60, - Unique: pallet_unique::{Pallet, Call, Storage, Event} = 61, - Scheduler: pallet_unique_scheduler::{Pallet, Call, Storage, Event} = 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} = 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} = 70, - - // Frontier - EVM: pallet_evm::{Pallet, Config, Call, Storage, Event} = 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 for TransactionConverter { - fn convert_transaction(&self, transaction: pallet_ethereum::Transaction) -> UncheckedExtrinsic { - UncheckedExtrinsic::new_unsigned( - pallet_ethereum::Call::::transact { transaction }.into(), - ) - } -} - -impl fp_rpc::ConvertTransaction for TransactionConverter { - fn convert_transaction( - &self, - transaction: pallet_ethereum::Transaction, - ) -> opaque::UncheckedExtrinsic { - let extrinsic = UncheckedExtrinsic::new_unsigned( - pallet_ethereum::Call::::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; -/// Block header type as expected by this runtime. -pub type Header = generic::Header; -/// Block type as expected by this runtime. -pub type Block = generic::Block; -/// A Block signed with a Justification -pub type SignedBlock = generic::SignedBlock; -/// BlockId type as expected by this runtime. -pub type BlockId = generic::BlockId; -/// The SignedExtension to the basic transaction logic. -pub type SignedExtra = ( - frame_system::CheckSpecVersion, - // system::CheckTxVersion, - frame_system::CheckGenesis, - frame_system::CheckEra, - frame_system::CheckNonce, - frame_system::CheckWeight, - pallet_charge_transaction::ChargeTransactionPayment, - //pallet_contract_helpers::ContractHelpersExtension, - pallet_ethereum::FakeTransactionFinalizer, -); -pub type SignedExtraScheduler = ( - frame_system::CheckSpecVersion, - frame_system::CheckGenesis, - frame_system::CheckEra, - frame_system::CheckNonce, - frame_system::CheckWeight, - // pallet_charge_transaction::ChargeTransactionPayment, -); -/// Unchecked extrinsic type as expected by this runtime. -pub type UncheckedExtrinsic = - fp_self_contained::UncheckedExtrinsic; -/// Extrinsic type that has already been checked. -pub type CheckedExtrinsic = fp_self_contained::CheckedExtrinsic; -/// Executive: handles dispatch to the various modules. -pub type Executive = frame_executive::Executive< - Runtime, - Block, - frame_system::ChainContext, - 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> { - match self { - Call::Ethereum(call) => call.check_self_contained(), - _ => None, - } - } - - fn validate_self_contained( - &self, - info: &Self::SignedInfo, - dispatch_info: &DispatchInfoOf, - len: usize, - ) -> Option { - match self { - Call::Ethereum(call) => call.validate_self_contained(info, dispatch_info, len), - _ => None, - } - } - - fn pre_dispatch_self_contained( - &self, - info: &Self::SignedInfo, - ) -> Option> { - match self { - Call::Ethereum(call) => call.pre_dispatch_self_contained(info), - _ => None, - } - } - - fn apply_self_contained( - self, - info: Self::SignedInfo, - ) -> Option>> { - 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 = ::CollectionDispatch::dispatch(>::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, - RmrkInstanceInfo, - RmrkResourceInfo, - RmrkPropertyInfo, - RmrkBaseInfo, - RmrkPartType, - RmrkTheme - > for Runtime { - fn last_collection_idx() -> Result { - Ok(Default::default()) - } - - fn collection_by_id(_collection_id: RmrkCollectionId) -> Result>, DispatchError> { - Ok(Default::default()) - } - - fn nft_by_id(_collection_id: RmrkCollectionId, _nft_by_id: RmrkNftId) -> Result>, DispatchError> { - Ok(Default::default()) - } - - fn account_tokens(_account_id: AccountId, _collection_id: RmrkCollectionId) -> Result, DispatchError> { - Ok(Default::default()) - } - - fn nft_children(_collection_id: RmrkCollectionId, _nft_id: RmrkNftId) -> Result, DispatchError> { - Ok(Default::default()) - } - - fn collection_properties(_collection_id: RmrkCollectionId, _filter_keys: Option>) -> Result, DispatchError> { - Ok(Default::default()) - } - - fn nft_properties(_collection_id: RmrkCollectionId, _nft_id: RmrkNftId, _filter_keys: Option>) -> Result, DispatchError> { - Ok(Default::default()) - } - - fn nft_resources(_collection_id: RmrkCollectionId, _nft_id: RmrkNftId) -> Result, DispatchError> { - Ok(Default::default()) - } - - fn nft_resource_priority(_collection_id: RmrkCollectionId, _nft_id: RmrkNftId, _resource_id: RmrkResourceId) -> Result, DispatchError> { - Ok(Default::default()) - } - - fn base(_base_id: RmrkBaseId) -> Result>, DispatchError> { - Ok(Default::default()) - } - - fn base_parts(_base_id: RmrkBaseId) -> Result, DispatchError> { - Ok(Default::default()) - } - - fn theme_names(_base_id: RmrkBaseId) -> Result, DispatchError> { - Ok(Default::default()) - } - - fn theme(_base_id: RmrkBaseId, _theme_name: RmrkThemeName, _filter_keys: Option>) -> Result, DispatchError> { - Ok(Default::default()) - } - } -} - -struct CheckInherents; - -impl cumulus_pallet_parachain_system::CheckInherents 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, --- 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'); --- 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}); --- 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'); --- 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'}}); }); --- 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; --- 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); --- 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) => { --- 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); }); --- 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 +}); --- 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 . -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 +}); --- 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 . -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'); --- 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 +}); --- 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'); --- 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:[]}}); --- 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'); --- 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: {}}))) --- 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}}); --- 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'; --- 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 } }); }); --- 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 @@ }); }); }); + --- 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, --- 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 () => { --- 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'; --- 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, --- 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, --- 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'; --- 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'; --- 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'; --- 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 () => { --- 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'; --- 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 () => { --- 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'; --- 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'; --- 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'; --- 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]); }); }); --- 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; --- 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 () => { --- 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'; --- 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'; --- 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'; --- 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); }); --- 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'); --- 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'); --- 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 { + return usingApi(async api => { + const chain = await api.rpc.system.chain(); + + return chain.eq('UNIQUE'); + }); +} + +export async function isQuartz(): Promise { + 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 { + return await usingApi(async api => { + const pallets = getModuleNames(api); + + return requiredPallets.filter(p => !pallets.includes(p)); + }); +} + +export async function checkPalletsPresence(requiredPallets: string[]): Promise { + 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) { -- gitstuff