--- 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" } --- /dev/null +++ b/common-types/Cargo.toml @@ -0,0 +1,50 @@ +[package] +authors = ['Unique Network '] +description = 'Unique Runtime Common' +edition = '2021' +homepage = 'https://unique.network' +license = 'All Rights Reserved' +name = 'common-types' +repository = 'https://github.com/UniqueNetwork/unique-chain' +version = '0.9.24' + +[features] +default = ['std'] +std = [ + 'sp-std/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.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/common-types/src/lib.rs @@ -0,0 +1,86 @@ +// 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)] + +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/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.common-types] +path = "../../common-types" [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 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 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 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" } +common-types = { path = "../../common-types" } 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,10 @@ use sc_service::TransactionPool; use std::{collections::BTreeMap, sync::Arc}; -use unique_runtime_common::types::{ +use common_types::opaque::{ Hash, AccountId, RuntimeInstance, Index, Block, BlockNumber, Balance, }; + // RMRK use up_data_structs::{ RmrkCollectionInfo, RmrkInstanceInfo, RmrkResourceInfo, RmrkPropertyInfo, RmrkBaseInfo, --- a/runtime/common/Cargo.toml +++ /dev/null @@ -1,121 +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', -] - -opal-runtime = [] -quartz-runtime = [] -unique-runtime = [] - -refungible = [] - -[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,140 @@ +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::{ + constants::*, + dispatch::CollectionDispatchT, + ethereum::{EvmSponsorshipHandler}, + config::sponsoring::DefaultSponsoringRateLimit, + DealWithFees, + }, + Runtime, + Aura, + Balances, + Event, + ChainId, +}; +use pallet_evm::{ + EnsureAddressTruncated, + HashedAddressMapping, +}; + +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,33 @@ +// 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 substrate; +pub mod ethereum; +pub mod sponsoring; +pub mod pallets; +pub mod parachain; +pub mod xcm; +pub mod orml; + +pub use { + substrate::*, + ethereum::*, + sponsoring::*, + pallets::*, + parachain::*, + self::xcm::*, + orml::*, +}; --- /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_common::constants::*, + Runtime, Event, RelayChainBlockNumberProvider, +}; +use common_types::{AccountId, Balance}; + +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,100 @@ +// 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, constants::WEIGHT_PER_SECOND}, + parameter_types, +}; +use sp_runtime::traits::AccountIdConversion; +use crate::{ + runtime_common::{ + constants::*, + dispatch::CollectionDispatchT, + config::{ + substrate::TreasuryModuleId, + ethereum::EvmCollectionHelpersAddress, + }, + weights::CommonWeights, + RelayChainBlockNumberProvider, + }, + Runtime, + Event, + Call, + Balances, +}; +use common_types::{AccountId, Balance, BlockNumber}; +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,66 @@ +// 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 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,52 @@ +// 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_common::constants::*, + Runtime, + Event, + XcmpQueue, + DmpQueue, +}; + +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,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 crate::{ + runtime_common::{ + constants::*, + sponsoring::UniqueSponsorshipHandler, + }, + Runtime, +}; +use common_types::BlockNumber; + +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,250 @@ +// 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, + constants::*, + }, + Runtime, + Event, + Call, + Origin, + PalletInfo, + System, + Balances, + Treasury, + SS58Prefix, + Version, +}; +use common_types::*; + +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,308 @@ +// 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::{ + constants::*, + config::substrate::LinearFee + }, + Runtime, + Call, + Event, + Origin, + Balances, + ParachainInfo, + ParachainSystem, + PolkadotXcm, + XcmpQueue, +}; +use common_types::{AccountId, Balance}; + +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 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,187 @@ +// 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)? + } + #[cfg(feature = "refungible")] + CollectionMode::ReFungible => >::init_collection(sender, data)?, + + #[cfg(not(feature = "refungible"))] + CollectionMode::ReFungible => { + return Err(DispatchError::Other("Refunginle pallet is not supported")) + } + }; + 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,25 @@ +// 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 sponsoring; +pub mod transaction_converter; +pub mod self_contained_call; + +pub use { + sponsoring::*, + transaction_converter::*, + self_contained_call::*, +}; --- /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,130 @@ +// 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,46 @@ +// 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,17 @@ +use crate::{ + runtime_common::{ + config::ethereum::CrossAccountId, + ethereum::TransactionConverter + }, + Runtime, +}; +use 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,171 @@ +// 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 constants; +mod construct_runtime; +mod dispatch; +mod runtime_apis; +mod sponsoring; +mod weights; +mod config; +mod instance; +mod ethereum; +mod scheduler; + +pub use { + constants::*, + dispatch::*, + sponsoring::*, + weights::*, + config::*, + instance::*, + ethereum::*, +}; + +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 common_types::{AccountId, BlockNumber}; + +/// 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,708 @@ +// 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 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)) + } + } + + #[allow(unused_variables)] + 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 Ok(Default::default()); + } + + 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 Ok(Default::default()) + } + + 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 Ok(Default::default()) + } + + 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 Ok(Default::default()) + } + + 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 Ok(Default::default()) + } + + 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 Ok(Default::default()) + } + + 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 Ok(Default::default()) + } + + 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 Ok(Default::default()) + } + + 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 Ok(Default::default()) + } + + fn base(base_id: RmrkBaseId) -> Result>, DispatchError> { + #[cfg(feature = "rmrk")] + return pallet_proxy_rmrk_equip::rpc::base::(base_id); + + #[cfg(not(feature = "rmrk"))] + return Ok(Default::default()) + } + + 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 Ok(Default::default()) + } + + 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"))] + Ok(Default::default()) + } + + 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 Ok(Default::default()) + } + } + + 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,144 @@ +// 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 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::::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/construct_runtime/mod.rs +++ /dev/null @@ -1,74 +0,0 @@ -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, - } - } - } -} --- a/runtime/common/src/construct_runtime/util.rs +++ /dev/null @@ -1,206 +0,0 @@ -#[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)*) - } - }; -} --- a/runtime/common/src/dispatch.rs +++ /dev/null @@ -1,187 +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)? - } - #[cfg(feature = "refungible")] - CollectionMode::ReFungible => >::init_collection(sender, data)?, - - #[cfg(not(feature = "refungible"))] - CollectionMode::ReFungible => { - return Err(DispatchError::Other("Refunginle pallet is not supported")) - } - }; - 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,26 +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 construct_runtime; -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,678 +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)) - } - } - - #[allow(unused_variables)] - 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 Ok(Default::default()); - } - - 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 Ok(Default::default()) - } - - 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 Ok(Default::default()) - } - - 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 Ok(Default::default()) - } - - 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 Ok(Default::default()) - } - - 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 Ok(Default::default()) - } - - 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 Ok(Default::default()) - } - - 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 Ok(Default::default()) - } - - 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 Ok(Default::default()) - } - - fn base(base_id: RmrkBaseId) -> Result>, DispatchError> { - #[cfg(feature = "rmrk")] - return pallet_proxy_rmrk_equip::rpc::base::(base_id); - - #[cfg(not(feature = "rmrk"))] - return Ok(Default::default()) - } - - 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 Ok(Default::default()) - } - - 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"))] - Ok(Default::default()) - } - - 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 Ok(Default::default()) - } - } - - 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,139 +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}; - -#[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::() - } -} --- /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 @@ -113,13 +113,15 @@ 'xcm/std', 'xcm-builder/std', 'xcm-executor/std', - 'unique-runtime-common/std', + 'common-types/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 = ['scheduler', 'rmrk'] +opal-runtime = ['rmrk', 'scheduler'] scheduler = [] rmrk = [] @@ -400,7 +402,7 @@ [dependencies] log = { version = "0.4.16", default-features = false } -unique-runtime-common = { path = "../common", default-features = false, features = ['refungible'] } +common-types = { path = "../../common-types", default-features = false } scale-info = { version = "2.0.1", default-features = false, features = [ "derive", ] } @@ -430,6 +432,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,174 +25,20 @@ #[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; -#[cfg(feature = "scheduler")] -use fp_self_contained::*; - -#[cfg(feature = "scheduler")] -use sp_runtime::{ - traits::{Applyable, Member}, - generic::Era, - DispatchErrorWithPostInfo, -}; -// #[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}, - 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::{ - 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 sp_runtime::create_runtime_str; -#[cfg(feature = "scheduler")] -use pallet_unique_scheduler::DispatchCall; +use common_types::*; -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, -}; +#[path = "../../common/mod.rs"] +mod runtime_common; -// 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::{ - BlockNumberProvider, Dispatchable, PostDispatchInfoOf, DispatchInfoOf, Saturating, - CheckedConversion, - }, - transaction_validity::TransactionValidityError, - SaturatedConversion, -}; - -// pub use pallet_timestamp::Call as TimestampCall; -pub use sp_consensus_aura::sr25519::AuthorityId as AuraId; - -// Polkadot imports -use pallet_xcm::XcmPassthrough; -use polkadot_parachain::primitives::Sibling; -use xcm::v1::{BodyId, Junction::*, MultiLocation, NetworkId, Junctions::*}; -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::{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::{ - construct_runtime, 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 = "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 { @@ -205,1096 +51,16 @@ transaction_version: 1, 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]; -} -*/ - -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; -} - -#[cfg(feature = "rmrk")] -impl pallet_proxy_rmrk_core::Config for Runtime { - type WeightInfo = pallet_proxy_rmrk_core::weights::SubstrateWeight; - type Event = Event; -} - -#[cfg(feature = "rmrk")] -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; - -#[cfg(feature = "scheduler")] -use frame_support::traits::NamedReservableCurrency; -#[cfg(feature = "scheduler")] -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), - ) -} - -#[cfg(feature = "scheduler")] -pub struct SchedulerPaymentExecutor; - -#[cfg(feature = "scheduler")] -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) - } -} - -#[cfg(feature = "scheduler")] -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!(opal); - -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!(); - -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) - } -} cumulus_pallet_parachain_system::register_validate_block!( Runtime = Runtime, --- a/runtime/tests/Cargo.toml +++ b/runtime/tests/Cargo.toml @@ -4,7 +4,6 @@ edition = "2021" [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 +36,7 @@ "derive", ] } scale-info = "*" + +common-types = { path = "../../common-types", default-features = false } +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;