diff --git a/Cargo.lock b/Cargo.lock index f8e2df769..d6f2ed916 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4853,7 +4853,7 @@ dependencies = [ [[package]] name = "hydradx" -version = "14.0.0" +version = "14.0.1" dependencies = [ "async-trait", "clap 4.5.4", @@ -4996,7 +4996,7 @@ dependencies = [ [[package]] name = "hydradx-runtime" -version = "261.0.0" +version = "262.0.0" dependencies = [ "cumulus-pallet-aura-ext", "cumulus-pallet-parachain-system", diff --git a/node/Cargo.toml b/node/Cargo.toml index 42f1fad24..b259aa2a3 100644 --- a/node/Cargo.toml +++ b/node/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "hydradx" -version = "14.0.0" +version = "14.0.1" description = "Hydration node" authors = ["GalacticCouncil"] edition = "2021" diff --git a/node/src/service.rs b/node/src/service.rs index 231d773fc..3d6d92512 100644 --- a/node/src/service.rs +++ b/node/src/service.rs @@ -20,8 +20,8 @@ #![allow(clippy::all)] use hydradx_runtime::{ - apis::RuntimeApi, opaque::{Block, Hash}, + RuntimeApi, }; use std::{sync::Arc, time::Duration}; diff --git a/runtime/hydradx/Cargo.toml b/runtime/hydradx/Cargo.toml index ef58b2c8f..1c4e838b9 100644 --- a/runtime/hydradx/Cargo.toml +++ b/runtime/hydradx/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "hydradx-runtime" -version = "261.0.0" +version = "262.0.0" authors = ["GalacticCouncil"] edition = "2021" license = "Apache 2.0" diff --git a/runtime/hydradx/src/apis.rs b/runtime/hydradx/src/apis.rs deleted file mode 100644 index 3c9de5bbb..000000000 --- a/runtime/hydradx/src/apis.rs +++ /dev/null @@ -1,692 +0,0 @@ -// This file is part of HydraDX-node. - -// Copyright (C) 2020-2023 Intergalactic, Limited (GIB). -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use crate::*; -use frame_support::{ - genesis_builder_helper::{build_state, get_preset}, - sp_runtime::{ - traits::Convert, - transaction_validity::{TransactionSource, TransactionValidity}, - ApplyExtrinsicResult, ExtrinsicInclusionMode, FixedPointNumber, - }, - weights::WeightToFee as _, -}; -use hydradx_traits::NativePriceOracle; -use polkadot_xcm::{IntoVersion, VersionedAssetId, VersionedAssets, VersionedLocation, VersionedXcm}; -use primitives::constants::chain::CORE_ASSET_ID; -use sp_api::impl_runtime_apis; -use sp_core::OpaqueMetadata; -use xcm_fee_payment_runtime_api::Error as XcmPaymentApiError; - -impl_runtime_apis! { - impl sp_api::Core for Runtime { - fn version() -> RuntimeVersion { - VERSION - } - - fn execute_block(block: Block) { - Executive::execute_block(block) - } - - fn initialize_block(header: &::Header) -> ExtrinsicInclusionMode { - Executive::initialize_block(header) - } - } - - impl sp_api::Metadata for Runtime { - fn metadata() -> OpaqueMetadata { - OpaqueMetadata::new(Runtime::metadata().into()) - } - - fn metadata_at_version(version: u32) -> Option { - Runtime::metadata_at_version(version) - } - - fn metadata_versions() -> sp_std::vec::Vec { - Runtime::metadata_versions() - } - } - - 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) - } - } - - impl sp_transaction_pool::runtime_api::TaggedTransactionQueue for Runtime { - fn validate_transaction( - source: TransactionSource, - tx: ::Extrinsic, - block_hash: ::Hash, - ) -> TransactionValidity { - Executive::validate_transaction(source, tx, block_hash) - } - } - - impl sp_offchain::OffchainWorkerApi for Runtime { - fn offchain_worker(header: &::Header) { - Executive::offchain_worker(header) - } - } - - impl sp_session::SessionKeys for Runtime { - fn decode_session_keys( - encoded: Vec, - ) -> Option, sp_core::crypto::KeyTypeId)>> { - opaque::SessionKeys::decode_into_raw_public_keys(&encoded) - } - - fn generate_session_keys(seed: Option>) -> Vec { - opaque::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 { - pallet_aura::Authorities::::get().into_inner() - } - } - - impl cumulus_primitives_core::CollectCollationInfo for Runtime { - fn collect_collation_info(header: &::Header) -> cumulus_primitives_core::CollationInfo { - ParachainSystem::collect_collation_info(header) - } - } - - #[cfg(feature = "try-runtime")] - impl frame_try_runtime::TryRuntime for Runtime { - fn on_runtime_upgrade(checks: frame_try_runtime::UpgradeCheckSelect) -> (Weight, Weight) { - log::info!("try-runtime::on_runtime_upgrade."); - let weight = Executive::try_runtime_upgrade(checks).unwrap(); - (weight, BlockWeights::get().max_block) - } - - fn execute_block( - block: Block, - state_root_check: bool, - signature_check: bool, - select: frame_try_runtime::TryStateSelect, - ) -> Weight { - Executive::try_execute_block(block, state_root_check, signature_check, select).unwrap() - } - } - - - 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, - ) -> pallet_transaction_payment_rpc_runtime_api::RuntimeDispatchInfo { - TransactionPayment::query_info(uxt, len) - } - - fn query_fee_details( - uxt: ::Extrinsic, - len: u32, - ) -> pallet_transaction_payment_rpc_runtime_api::FeeDetails { - TransactionPayment::query_fee_details(uxt, len) - } - - fn query_weight_to_fee(weight: Weight) -> Balance { - TransactionPayment::weight_to_fee(weight) - } - fn query_length_to_fee(length: u32) -> Balance { - TransactionPayment::length_to_fee(length) - } - } - - // Frontier RPC support - 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 (gas_price, _) = ::FeeCalculator::min_gas_price(); - gas_price - } - - fn account_code_at(address: H160) -> Vec { - pallet_evm::AccountCodes::::get(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); - pallet_evm::AccountStorages::::get(address, H256::from_slice(&tmp[..])) - } - - 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 mut config = ::config().clone(); - config.estimate = estimate; - - let is_transactional = false; - let validate = true; - - // Estimated encoded transaction size must be based on the heaviest transaction - // type (EIP1559Transaction) to be compatible with all transaction types. - let mut estimated_transaction_len = data.len() + - // pallet ethereum index: 1 - // transact call index: 1 - // Transaction enum variant: 1 - // chain_id 8 bytes - // nonce: 32 - // max_priority_fee_per_gas: 32 - // max_fee_per_gas: 32 - // gas_limit: 32 - // action: 21 (enum varianrt + call address) - // value: 32 - // access_list: 1 (empty vec size) - // 65 bytes signature - 258; - - if access_list.is_some() { - estimated_transaction_len += access_list.encoded_size(); - } - - let gas_limit = gas_limit.min(u64::MAX.into()).low_u64(); - let without_base_extrinsic_weight = true; - - let (weight_limit, proof_size_base_cost) = - match ::GasWeightMapping::gas_to_weight( - gas_limit, - without_base_extrinsic_weight - ) { - weight_limit if weight_limit.proof_size() > 0 => { - (Some(weight_limit), Some(estimated_transaction_len as u64)) - } - _ => (None, None), - }; - - // don't allow calling EVM RPC or Runtime API from a bound address - if EVMAccounts::bound_account_id(from).is_some() { - return Err(pallet_evm_accounts::Error::::BoundAddressCannotBeUsed.into()) - }; - - ::Runner::call( - from, - to, - data, - value, - gas_limit.unique_saturated_into(), - max_fee_per_gas, - max_priority_fee_per_gas, - nonce, - access_list.unwrap_or_default(), - is_transactional, - validate, - weight_limit, - proof_size_base_cost, - &config, - ) - .map_err(|err| err.error.into()) - } - - 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; - let validate = true; - - // Reused approach from Moonbeam since Frontier implementation doesn't support this - let mut estimated_transaction_len = data.len() + - // to: 20 - // from: 20 - // value: 32 - // gas_limit: 32 - // nonce: 32 - // 1 byte transaction action variant - // chain id 8 bytes - // 65 bytes signature - 210; - if max_fee_per_gas.is_some() { - estimated_transaction_len += 32; - } - if max_priority_fee_per_gas.is_some() { - estimated_transaction_len += 32; - } - if access_list.is_some() { - estimated_transaction_len += access_list.encoded_size(); - } - - let gas_limit = gas_limit.min(u64::MAX.into()).low_u64(); - let without_base_extrinsic_weight = true; - - let (weight_limit, proof_size_base_cost) = - match ::GasWeightMapping::gas_to_weight( - gas_limit, - without_base_extrinsic_weight - ) { - weight_limit if weight_limit.proof_size() > 0 => { - (Some(weight_limit), Some(estimated_transaction_len as u64)) - } - _ => (None, None), - }; - - // don't allow calling EVM RPC or Runtime API from a bound address - if EVMAccounts::bound_account_id(from).is_some() { - return Err(pallet_evm_accounts::Error::::BoundAddressCannotBeUsed.into()) - }; - - // the address needs to have a permission to deploy smart contract - if !EVMAccounts::can_deploy_contracts(from) { - return Err(pallet_evm_accounts::Error::::AddressNotWhitelisted.into()) - }; - - #[allow(clippy::or_fun_call)] // suggestion not helpful here - ::Runner::create( - from, - data, - value, - gas_limit.unique_saturated_into(), - max_fee_per_gas, - max_priority_fee_per_gas, - nonce, - Vec::new(), - is_transactional, - validate, - weight_limit, - proof_size_base_cost, - config - .as_ref() - .unwrap_or(::config()), - ) - .map_err(|err| err.error.into()) - } - - fn current_transaction_statuses() -> Option> { - pallet_ethereum::CurrentTransactionStatuses::::get() - } - - fn current_block() -> Option { - pallet_ethereum::CurrentBlock::::get() - } - - fn current_receipts() -> Option> { - pallet_ethereum::CurrentReceipts::::get() - } - - fn current_all() -> ( - Option, - Option>, - Option>, - ) { - ( - pallet_ethereum::CurrentBlock::::get(), - pallet_ethereum::CurrentReceipts::::get(), - pallet_ethereum::CurrentTransactionStatuses::::get(), - ) - } - - fn extrinsic_filter(xts: Vec<::Extrinsic>) -> Vec { - xts.into_iter() - .filter_map(|xt| match xt.0.function { - RuntimeCall::Ethereum(pallet_ethereum::Call::transact { transaction }) => Some(transaction), - _ => None, - }) - .collect::>() - } - - fn elasticity() -> Option { - None - } - - fn gas_limit_multiplier_support() {} - - fn pending_block( - xts: Vec<::Extrinsic>, - ) -> (Option, Option>) { - for ext in xts.into_iter() { - let _ = Executive::apply_extrinsic(ext); - } - - Ethereum::on_finalize(System::block_number() + 1); - - ( - pallet_ethereum::CurrentBlock::::get(), - pallet_ethereum::CurrentTransactionStatuses::::get() - ) - } - - fn initialize_pending_block(header: &::Header) { - Executive::initialize_block(header); - } - } - - impl fp_rpc::ConvertTransactionRuntimeApi for Runtime { - fn convert_transaction(transaction: EthereumTransaction) -> ::Extrinsic { - UncheckedExtrinsic::new_unsigned(pallet_ethereum::Call::::transact { transaction }.into()) - } - } - - impl pallet_evm_accounts_rpc_runtime_api::EvmAccountsApi for Runtime { - fn evm_address(account_id: AccountId) -> H160 { - EVMAccounts::evm_address(&account_id) - } - fn bound_account_id(evm_address: H160) -> Option { - EVMAccounts::bound_account_id(evm_address) - } - fn account_id(evm_address: H160) -> AccountId { - EVMAccounts::account_id(evm_address) - } - } - - impl xcm_fee_payment_runtime_api::XcmPaymentApi for Runtime { - fn query_acceptable_payment_assets(xcm_version: polkadot_xcm::Version) -> Result, XcmPaymentApiError> { - if !matches!(xcm_version, 3 | 4) { - return Err(XcmPaymentApiError::UnhandledXcmVersion); - } - - let mut asset_locations = vec![ - AssetLocation(polkadot_xcm::v3::MultiLocation { - parents: 1, - interior: [ - polkadot_xcm::v3::Junction::Parachain(ParachainInfo::get().into()), - polkadot_xcm::v3::Junction::GeneralIndex(CORE_ASSET_ID.into()), - ] - .into(), - }), - AssetLocation(polkadot_xcm::v3::MultiLocation { - parents: 0, - interior: [ - polkadot_xcm::v3::Junction::GeneralIndex(CORE_ASSET_ID.into()), - ] - .into(), - })]; - - let mut asset_registry_locations: Vec = pallet_asset_registry::LocationAssets::::iter_keys().collect(); - asset_locations.append(&mut asset_registry_locations); - - let versioned_locations = asset_locations.iter().map(|loc| VersionedAssetId::V3(polkadot_xcm::v3::AssetId::Concrete(loc.0))); - - Ok(versioned_locations - .filter_map(|asset| asset.into_version(xcm_version).ok()) - .collect()) - } - - fn query_weight_to_asset_fee(weight: Weight, asset: VersionedAssetId) -> Result { - let v4_xcm_asset_id = asset.into_version(4).map_err(|_| XcmPaymentApiError::VersionedConversionFailed)?; - - // get nested polkadot_xcm::AssetId type - let xcm_asset_id: &polkadot_xcm::v4::AssetId = v4_xcm_asset_id.try_as().map_err(|_| XcmPaymentApiError::WeightNotComputable)?; - - let asset_id: AssetId = CurrencyIdConvert::convert(xcm_asset_id.clone().0).ok_or(XcmPaymentApiError::AssetNotFound)?; - - let price = MultiTransactionPayment::price(asset_id).ok_or(XcmPaymentApiError::WeightNotComputable)?; - - let fee = WeightToFee::weight_to_fee(&weight); - - let converted_fee = price.checked_mul_int(fee).ok_or(XcmPaymentApiError::WeightNotComputable)?; - - Ok(converted_fee) - } - - fn query_xcm_weight(message: VersionedXcm<()>) -> Result { - PolkadotXcm::query_xcm_weight(message) - } - - fn query_delivery_fees(destination: VersionedLocation, message: VersionedXcm<()>) -> Result { - PolkadotXcm::query_delivery_fees(destination, message) - } - } - - #[cfg(feature = "runtime-benchmarks")] - impl frame_benchmarking::Benchmark for Runtime { - fn benchmark_metadata(extra: bool) -> ( - Vec, - Vec, - ) { - use frame_benchmarking::{Benchmarking, BenchmarkList}; - use frame_support::traits::StorageInfoTrait; - use orml_benchmarking::list_benchmark as orml_list_benchmark; - - use frame_system_benchmarking::Pallet as SystemBench; - use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsiscsBenchmark; - - let mut list = Vec::::new(); - - list_benchmarks!(list, extra); - - orml_list_benchmark!(list, extra, pallet_currencies, benchmarking::currencies); - orml_list_benchmark!(list, extra, orml_tokens, benchmarking::tokens); - orml_list_benchmark!(list, extra, orml_vesting, benchmarking::vesting); - orml_list_benchmark!(list, extra, pallet_transaction_multi_payment, benchmarking::multi_payment); - orml_list_benchmark!(list, extra, pallet_duster, benchmarking::duster); - orml_list_benchmark!(list, extra, pallet_omnipool, benchmarking::omnipool); - orml_list_benchmark!(list, extra, pallet_route_executor, benchmarking::route_executor); - orml_list_benchmark!(list, extra, pallet_dca, benchmarking::dca); - orml_list_benchmark!(list, extra, pallet_xyk, benchmarking::xyk); - orml_list_benchmark!(list, extra, pallet_dynamic_evm_fee, benchmarking::dynamic_evm_fee); - orml_list_benchmark!(list, extra, pallet_xyk_liquidity_mining, benchmarking::xyk_liquidity_mining); - - let storage_info = AllPalletsWithSystem::storage_info(); - - (list, storage_info) - } - - fn dispatch_benchmark( - config: frame_benchmarking::BenchmarkConfig - ) -> Result, sp_runtime::RuntimeString> { - use frame_benchmarking::{BenchmarkError, Benchmarking, BenchmarkBatch}; - use frame_support::traits::TrackedStorageKey; - use orml_benchmarking::add_benchmark as orml_add_benchmark; - use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsiscsBenchmark; - use frame_system_benchmarking::Pallet as SystemBench; - use cumulus_primitives_core::ParaId; - use primitives::constants::chain::CORE_ASSET_ID; - use sp_std::sync::Arc; - - impl frame_system_benchmarking::Config for Runtime { - fn setup_set_code_requirements(code: &sp_std::vec::Vec) -> Result<(), BenchmarkError> { - ParachainSystem::initialize_for_set_code_benchmark(code.len() as u32); - Ok(()) - } - - fn verify_set_code() { - System::assert_last_event(cumulus_pallet_parachain_system::Event::::ValidationFunctionStored.into()); - } - } - - frame_support::parameter_types! { - pub const RandomParaId: ParaId = ParaId::new(22_222_222); - pub const ExistentialDeposit: u128 = 1_000_000_000_000; - pub AssetLocation: Location = Location::new(0, cumulus_primitives_core::Junctions::X1( - Arc::new([ - cumulus_primitives_core::Junction::GeneralIndex(CORE_ASSET_ID.into()) - ]) - )); - } - - use polkadot_xcm::latest::prelude::{Location, AssetId, Fungible, Asset, Assets, Parent, ParentThen, Parachain}; - - impl pallet_xcm::benchmarking::Config for Runtime { - type DeliveryHelper = (); - - fn reachable_dest() -> Option { - Some(Parent.into()) - } - - fn teleportable_asset_and_dest() -> Option<(Asset, Location)> { - None - } - - fn reserve_transferable_asset_and_dest() -> Option<(Asset, Location)> { - ParachainSystem::open_outbound_hrmp_channel_for_benchmarks_or_tests( - RandomParaId::get() - ); - - Some(( - Asset { - fun: Fungible(ExistentialDeposit::get()), - id: AssetId(AssetLocation::get()) - }, - ParentThen(Parachain(RandomParaId::get().into()).into()).into(), - )) - } - - fn set_up_complex_asset_transfer() -> Option<(Assets, u32, Location, Box)> { - ParachainSystem::open_outbound_hrmp_channel_for_benchmarks_or_tests( - RandomParaId::get() - ); - - let destination = ParentThen(Parachain(RandomParaId::get().into()).into()).into(); - - let fee_asset: Asset = ( - AssetLocation::get(), - ExistentialDeposit::get(), - ).into(); - - let who = frame_benchmarking::whitelisted_caller(); - let balance = 10 * ExistentialDeposit::get(); - let _ = >::make_free_balance_be(&who, balance ); - - assert_eq!(Balances::free_balance(&who), balance); - - let transfer_asset: Asset = ( - AssetLocation::get(), - ExistentialDeposit::get(), - ).into(); - - let assets: Assets = vec![fee_asset.clone(), transfer_asset].into(); - - let fee_index: u32 = 0; - - let verify: Box = Box::new(move || { - assert!(Balances::free_balance(&who) <= balance - ExistentialDeposit::get()); - }); - - Some((assets, fee_index, destination, verify)) - } - - fn get_asset() -> Asset { - Asset { - id: AssetId(Location::here()), - fun: Fungible(ExistentialDeposit::get()), - } - } - } - - let whitelist: Vec = vec![ - // Block Number - hex!("26aa394eea5630e07c48ae0c9558cef702a5c1b19ab7a04f536c519aca4983ac").to_vec().into(), - // Total Issuance - hex!("c2261276cc9d1f8598ea4b6a74b15c2f57c875e4cff74148e4628f264b974c80").to_vec().into(), - // Execution Phase - hex!("26aa394eea5630e07c48ae0c9558cef7ff553b5a9862a516939d82b3d3d8661a").to_vec().into(), - // Event Count - hex!("26aa394eea5630e07c48ae0c9558cef70a98fdbe9ce6c55837576c60c7af3850").to_vec().into(), - // System Events - hex!("26aa394eea5630e07c48ae0c9558cef780d41e5e16056765bc8461851072c9d7").to_vec().into(), - ]; - - let mut batches = Vec::::new(); - let params = (&config, &whitelist); - - add_benchmarks!(params, batches); - - orml_add_benchmark!(params, batches, pallet_currencies, benchmarking::currencies); - orml_add_benchmark!(params, batches, orml_tokens, benchmarking::tokens); - orml_add_benchmark!(params, batches, orml_vesting, benchmarking::vesting); - orml_add_benchmark!(params, batches, pallet_transaction_multi_payment, benchmarking::multi_payment); - orml_add_benchmark!(params, batches, pallet_duster, benchmarking::duster); - orml_add_benchmark!(params, batches, pallet_omnipool, benchmarking::omnipool); - orml_add_benchmark!(params, batches, pallet_route_executor, benchmarking::route_executor); - orml_add_benchmark!(params, batches, pallet_dca, benchmarking::dca); - orml_add_benchmark!(params, batches, pallet_xyk, benchmarking::xyk); - orml_add_benchmark!(params, batches, pallet_dynamic_evm_fee, benchmarking::dynamic_evm_fee); - orml_add_benchmark!(params, batches, pallet_xyk_liquidity_mining, benchmarking::xyk_liquidity_mining); - - if batches.is_empty() { return Err("Benchmark not found for this pallet.".into()) } - Ok(batches) - } - } - - impl sp_genesis_builder::GenesisBuilder for Runtime { - fn build_state(config: Vec) -> sp_genesis_builder::Result { - build_state::(config) - } - - fn get_preset(id: &Option) -> Option> { - get_preset::(id, |_| None) - } - - fn preset_names() -> Vec { - Default::default() - } - } -} diff --git a/runtime/hydradx/src/lib.rs b/runtime/hydradx/src/lib.rs index 334e65987..0d3a6be45 100644 --- a/runtime/hydradx/src/lib.rs +++ b/runtime/hydradx/src/lib.rs @@ -31,7 +31,6 @@ mod tests; mod benchmarking; pub mod weights; -pub mod apis; mod assets; pub mod evm; mod governance; @@ -73,6 +72,7 @@ pub use pallet_genesis_history::Chain; pub use primitives::{ AccountId, Amount, AssetId, Balance, BlockNumber, CollectionId, Hash, Index, ItemId, Price, Signature, }; +use sp_api::impl_runtime_apis; pub use sp_consensus_aura::sr25519::AuthorityId as AuraId; /// Opaque types. These are used by the CLI to instantiate machinery that don't need to know @@ -108,9 +108,9 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("hydradx"), impl_name: create_runtime_str!("hydradx"), authoring_version: 1, - spec_version: 261, + spec_version: 262, impl_version: 0, - apis: apis::RUNTIME_API_VERSIONS, + apis: RUNTIME_API_VERSIONS, transaction_version: 1, state_version: 1, }; @@ -419,3 +419,675 @@ impl fp_rpc::ConvertTransaction for TransactionConv sp_runtime::OpaqueExtrinsic::decode(&mut &encoded[..]).expect("Encoded extrinsic is always valid") } } + +use frame_support::{ + genesis_builder_helper::{build_state, get_preset}, + sp_runtime::{ + traits::Convert, transaction_validity::TransactionSource, ApplyExtrinsicResult, ExtrinsicInclusionMode, + FixedPointNumber, + }, + weights::WeightToFee as _, +}; +use polkadot_xcm::{IntoVersion, VersionedAssetId, VersionedAssets, VersionedLocation, VersionedXcm}; +use primitives::constants::chain::CORE_ASSET_ID; +use sp_core::OpaqueMetadata; +use xcm_fee_payment_runtime_api::Error as XcmPaymentApiError; + +impl_runtime_apis! { + impl sp_api::Core for Runtime { + fn version() -> RuntimeVersion { + VERSION + } + + fn execute_block(block: Block) { + Executive::execute_block(block) + } + + fn initialize_block(header: &::Header) -> ExtrinsicInclusionMode { + Executive::initialize_block(header) + } + } + + impl sp_api::Metadata for Runtime { + fn metadata() -> OpaqueMetadata { + OpaqueMetadata::new(Runtime::metadata().into()) + } + + fn metadata_at_version(version: u32) -> Option { + Runtime::metadata_at_version(version) + } + + fn metadata_versions() -> sp_std::vec::Vec { + Runtime::metadata_versions() + } + } + + 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) + } + } + + impl sp_transaction_pool::runtime_api::TaggedTransactionQueue for Runtime { + fn validate_transaction( + source: TransactionSource, + tx: ::Extrinsic, + block_hash: ::Hash, + ) -> TransactionValidity { + Executive::validate_transaction(source, tx, block_hash) + } + } + + impl sp_offchain::OffchainWorkerApi for Runtime { + fn offchain_worker(header: &::Header) { + Executive::offchain_worker(header) + } + } + + impl sp_session::SessionKeys for Runtime { + fn decode_session_keys( + encoded: Vec, + ) -> Option, sp_core::crypto::KeyTypeId)>> { + opaque::SessionKeys::decode_into_raw_public_keys(&encoded) + } + + fn generate_session_keys(seed: Option>) -> Vec { + opaque::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 { + pallet_aura::Authorities::::get().into_inner() + } + } + + impl cumulus_primitives_core::CollectCollationInfo for Runtime { + fn collect_collation_info(header: &::Header) -> cumulus_primitives_core::CollationInfo { + ParachainSystem::collect_collation_info(header) + } + } + + #[cfg(feature = "try-runtime")] + impl frame_try_runtime::TryRuntime for Runtime { + fn on_runtime_upgrade(checks: frame_try_runtime::UpgradeCheckSelect) -> (Weight, Weight) { + log::info!("try-runtime::on_runtime_upgrade."); + let weight = Executive::try_runtime_upgrade(checks).unwrap(); + (weight, BlockWeights::get().max_block) + } + + fn execute_block( + block: Block, + state_root_check: bool, + signature_check: bool, + select: frame_try_runtime::TryStateSelect, + ) -> Weight { + Executive::try_execute_block(block, state_root_check, signature_check, select).unwrap() + } + } + + + 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, + ) -> pallet_transaction_payment_rpc_runtime_api::RuntimeDispatchInfo { + TransactionPayment::query_info(uxt, len) + } + + fn query_fee_details( + uxt: ::Extrinsic, + len: u32, + ) -> pallet_transaction_payment_rpc_runtime_api::FeeDetails { + TransactionPayment::query_fee_details(uxt, len) + } + + fn query_weight_to_fee(weight: Weight) -> Balance { + TransactionPayment::weight_to_fee(weight) + } + fn query_length_to_fee(length: u32) -> Balance { + TransactionPayment::length_to_fee(length) + } + } + + // Frontier RPC support + 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 (gas_price, _) = ::FeeCalculator::min_gas_price(); + gas_price + } + + fn account_code_at(address: H160) -> Vec { + pallet_evm::AccountCodes::::get(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); + pallet_evm::AccountStorages::::get(address, H256::from_slice(&tmp[..])) + } + + 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 mut config = ::config().clone(); + config.estimate = estimate; + + let is_transactional = false; + let validate = true; + + // Estimated encoded transaction size must be based on the heaviest transaction + // type (EIP1559Transaction) to be compatible with all transaction types. + let mut estimated_transaction_len = data.len() + + // pallet ethereum index: 1 + // transact call index: 1 + // Transaction enum variant: 1 + // chain_id 8 bytes + // nonce: 32 + // max_priority_fee_per_gas: 32 + // max_fee_per_gas: 32 + // gas_limit: 32 + // action: 21 (enum varianrt + call address) + // value: 32 + // access_list: 1 (empty vec size) + // 65 bytes signature + 258; + + if access_list.is_some() { + estimated_transaction_len += access_list.encoded_size(); + } + + let gas_limit = gas_limit.min(u64::MAX.into()).low_u64(); + let without_base_extrinsic_weight = true; + + let (weight_limit, proof_size_base_cost) = + match ::GasWeightMapping::gas_to_weight( + gas_limit, + without_base_extrinsic_weight + ) { + weight_limit if weight_limit.proof_size() > 0 => { + (Some(weight_limit), Some(estimated_transaction_len as u64)) + } + _ => (None, None), + }; + + // don't allow calling EVM RPC or Runtime API from a bound address + if EVMAccounts::bound_account_id(from).is_some() { + return Err(pallet_evm_accounts::Error::::BoundAddressCannotBeUsed.into()) + }; + + ::Runner::call( + from, + to, + data, + value, + gas_limit.unique_saturated_into(), + max_fee_per_gas, + max_priority_fee_per_gas, + nonce, + access_list.unwrap_or_default(), + is_transactional, + validate, + weight_limit, + proof_size_base_cost, + &config, + ) + .map_err(|err| err.error.into()) + } + + 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; + let validate = true; + + // Reused approach from Moonbeam since Frontier implementation doesn't support this + let mut estimated_transaction_len = data.len() + + // to: 20 + // from: 20 + // value: 32 + // gas_limit: 32 + // nonce: 32 + // 1 byte transaction action variant + // chain id 8 bytes + // 65 bytes signature + 210; + if max_fee_per_gas.is_some() { + estimated_transaction_len += 32; + } + if max_priority_fee_per_gas.is_some() { + estimated_transaction_len += 32; + } + if access_list.is_some() { + estimated_transaction_len += access_list.encoded_size(); + } + + let gas_limit = gas_limit.min(u64::MAX.into()).low_u64(); + let without_base_extrinsic_weight = true; + + let (weight_limit, proof_size_base_cost) = + match ::GasWeightMapping::gas_to_weight( + gas_limit, + without_base_extrinsic_weight + ) { + weight_limit if weight_limit.proof_size() > 0 => { + (Some(weight_limit), Some(estimated_transaction_len as u64)) + } + _ => (None, None), + }; + + // don't allow calling EVM RPC or Runtime API from a bound address + if EVMAccounts::bound_account_id(from).is_some() { + return Err(pallet_evm_accounts::Error::::BoundAddressCannotBeUsed.into()) + }; + + // the address needs to have a permission to deploy smart contract + if !EVMAccounts::can_deploy_contracts(from) { + return Err(pallet_evm_accounts::Error::::AddressNotWhitelisted.into()) + }; + + #[allow(clippy::or_fun_call)] // suggestion not helpful here + ::Runner::create( + from, + data, + value, + gas_limit.unique_saturated_into(), + max_fee_per_gas, + max_priority_fee_per_gas, + nonce, + Vec::new(), + is_transactional, + validate, + weight_limit, + proof_size_base_cost, + config + .as_ref() + .unwrap_or(::config()), + ) + .map_err(|err| err.error.into()) + } + + fn current_transaction_statuses() -> Option> { + pallet_ethereum::CurrentTransactionStatuses::::get() + } + + fn current_block() -> Option { + pallet_ethereum::CurrentBlock::::get() + } + + fn current_receipts() -> Option> { + pallet_ethereum::CurrentReceipts::::get() + } + + fn current_all() -> ( + Option, + Option>, + Option>, + ) { + ( + pallet_ethereum::CurrentBlock::::get(), + pallet_ethereum::CurrentReceipts::::get(), + pallet_ethereum::CurrentTransactionStatuses::::get(), + ) + } + + fn extrinsic_filter(xts: Vec<::Extrinsic>) -> Vec { + xts.into_iter() + .filter_map(|xt| match xt.0.function { + RuntimeCall::Ethereum(pallet_ethereum::Call::transact { transaction }) => Some(transaction), + _ => None, + }) + .collect::>() + } + + fn elasticity() -> Option { + None + } + + fn gas_limit_multiplier_support() {} + + fn pending_block( + xts: Vec<::Extrinsic>, + ) -> (Option, Option>) { + for ext in xts.into_iter() { + let _ = Executive::apply_extrinsic(ext); + } + + Ethereum::on_finalize(System::block_number() + 1); + + ( + pallet_ethereum::CurrentBlock::::get(), + pallet_ethereum::CurrentTransactionStatuses::::get() + ) + } + + fn initialize_pending_block(header: &::Header) { + Executive::initialize_block(header); + } + } + + impl fp_rpc::ConvertTransactionRuntimeApi for Runtime { + fn convert_transaction(transaction: EthereumTransaction) -> ::Extrinsic { + UncheckedExtrinsic::new_unsigned(pallet_ethereum::Call::::transact { transaction }.into()) + } + } + + impl pallet_evm_accounts_rpc_runtime_api::EvmAccountsApi for Runtime { + fn evm_address(account_id: AccountId) -> H160 { + EVMAccounts::evm_address(&account_id) + } + fn bound_account_id(evm_address: H160) -> Option { + EVMAccounts::bound_account_id(evm_address) + } + fn account_id(evm_address: H160) -> AccountId { + EVMAccounts::account_id(evm_address) + } + } + + impl xcm_fee_payment_runtime_api::XcmPaymentApi for Runtime { + fn query_acceptable_payment_assets(xcm_version: polkadot_xcm::Version) -> Result, XcmPaymentApiError> { + if !matches!(xcm_version, 3 | 4) { + return Err(XcmPaymentApiError::UnhandledXcmVersion); + } + + let mut asset_locations = vec![ + AssetLocation(polkadot_xcm::v3::MultiLocation { + parents: 1, + interior: [ + polkadot_xcm::v3::Junction::Parachain(ParachainInfo::get().into()), + polkadot_xcm::v3::Junction::GeneralIndex(CORE_ASSET_ID.into()), + ] + .into(), + }), + AssetLocation(polkadot_xcm::v3::MultiLocation { + parents: 0, + interior: [ + polkadot_xcm::v3::Junction::GeneralIndex(CORE_ASSET_ID.into()), + ] + .into(), + })]; + + let mut asset_registry_locations: Vec = pallet_asset_registry::LocationAssets::::iter_keys().collect(); + asset_locations.append(&mut asset_registry_locations); + + let versioned_locations = asset_locations.iter().map(|loc| VersionedAssetId::V3(polkadot_xcm::v3::AssetId::Concrete(loc.0))); + + Ok(versioned_locations + .filter_map(|asset| asset.into_version(xcm_version).ok()) + .collect()) + } + + fn query_weight_to_asset_fee(weight: Weight, asset: VersionedAssetId) -> Result { + let v4_xcm_asset_id = asset.into_version(4).map_err(|_| XcmPaymentApiError::VersionedConversionFailed)?; + + // get nested polkadot_xcm::AssetId type + let xcm_asset_id: &polkadot_xcm::v4::AssetId = v4_xcm_asset_id.try_as().map_err(|_| XcmPaymentApiError::WeightNotComputable)?; + + let asset_id: AssetId = CurrencyIdConvert::convert(xcm_asset_id.clone().0).ok_or(XcmPaymentApiError::AssetNotFound)?; + + let price = MultiTransactionPayment::price(asset_id).ok_or(XcmPaymentApiError::WeightNotComputable)?; + + let fee = WeightToFee::weight_to_fee(&weight); + + let converted_fee = price.checked_mul_int(fee).ok_or(XcmPaymentApiError::WeightNotComputable)?; + + Ok(converted_fee) + } + + fn query_xcm_weight(message: VersionedXcm<()>) -> Result { + PolkadotXcm::query_xcm_weight(message) + } + + fn query_delivery_fees(destination: VersionedLocation, message: VersionedXcm<()>) -> Result { + PolkadotXcm::query_delivery_fees(destination, message) + } + } + + #[cfg(feature = "runtime-benchmarks")] + impl frame_benchmarking::Benchmark for Runtime { + fn benchmark_metadata(extra: bool) -> ( + Vec, + Vec, + ) { + use frame_benchmarking::{Benchmarking, BenchmarkList}; + use frame_support::traits::StorageInfoTrait; + use orml_benchmarking::list_benchmark as orml_list_benchmark; + + use frame_system_benchmarking::Pallet as SystemBench; + use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsiscsBenchmark; + + let mut list = Vec::::new(); + + list_benchmarks!(list, extra); + + orml_list_benchmark!(list, extra, pallet_currencies, benchmarking::currencies); + orml_list_benchmark!(list, extra, orml_tokens, benchmarking::tokens); + orml_list_benchmark!(list, extra, orml_vesting, benchmarking::vesting); + orml_list_benchmark!(list, extra, pallet_transaction_multi_payment, benchmarking::multi_payment); + orml_list_benchmark!(list, extra, pallet_duster, benchmarking::duster); + orml_list_benchmark!(list, extra, pallet_omnipool, benchmarking::omnipool); + orml_list_benchmark!(list, extra, pallet_route_executor, benchmarking::route_executor); + orml_list_benchmark!(list, extra, pallet_dca, benchmarking::dca); + orml_list_benchmark!(list, extra, pallet_xyk, benchmarking::xyk); + orml_list_benchmark!(list, extra, pallet_dynamic_evm_fee, benchmarking::dynamic_evm_fee); + orml_list_benchmark!(list, extra, pallet_xyk_liquidity_mining, benchmarking::xyk_liquidity_mining); + + let storage_info = AllPalletsWithSystem::storage_info(); + + (list, storage_info) + } + + fn dispatch_benchmark( + config: frame_benchmarking::BenchmarkConfig + ) -> Result, sp_runtime::RuntimeString> { + use frame_benchmarking::{BenchmarkError, Benchmarking, BenchmarkBatch}; + use frame_support::traits::TrackedStorageKey; + use orml_benchmarking::add_benchmark as orml_add_benchmark; + use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsiscsBenchmark; + use frame_system_benchmarking::Pallet as SystemBench; + use cumulus_primitives_core::ParaId; + use primitives::constants::chain::CORE_ASSET_ID; + use sp_std::sync::Arc; + + impl frame_system_benchmarking::Config for Runtime { + fn setup_set_code_requirements(code: &sp_std::vec::Vec) -> Result<(), BenchmarkError> { + ParachainSystem::initialize_for_set_code_benchmark(code.len() as u32); + Ok(()) + } + + fn verify_set_code() { + System::assert_last_event(cumulus_pallet_parachain_system::Event::::ValidationFunctionStored.into()); + } + } + + frame_support::parameter_types! { + pub const RandomParaId: ParaId = ParaId::new(22_222_222); + pub const ExistentialDeposit: u128 = 1_000_000_000_000; + pub AssetLocation: Location = Location::new(0, cumulus_primitives_core::Junctions::X1( + Arc::new([ + cumulus_primitives_core::Junction::GeneralIndex(CORE_ASSET_ID.into()) + ]) + )); + } + + use polkadot_xcm::latest::prelude::{Location, AssetId, Fungible, Asset, Assets, Parent, ParentThen, Parachain}; + + impl pallet_xcm::benchmarking::Config for Runtime { + type DeliveryHelper = (); + + fn reachable_dest() -> Option { + Some(Parent.into()) + } + + fn teleportable_asset_and_dest() -> Option<(Asset, Location)> { + None + } + + fn reserve_transferable_asset_and_dest() -> Option<(Asset, Location)> { + ParachainSystem::open_outbound_hrmp_channel_for_benchmarks_or_tests( + RandomParaId::get() + ); + + Some(( + Asset { + fun: Fungible(ExistentialDeposit::get()), + id: AssetId(AssetLocation::get()) + }, + ParentThen(Parachain(RandomParaId::get().into()).into()).into(), + )) + } + + fn set_up_complex_asset_transfer() -> Option<(Assets, u32, Location, Box)> { + ParachainSystem::open_outbound_hrmp_channel_for_benchmarks_or_tests( + RandomParaId::get() + ); + + let destination = ParentThen(Parachain(RandomParaId::get().into()).into()).into(); + + let fee_asset: Asset = ( + AssetLocation::get(), + ExistentialDeposit::get(), + ).into(); + + let who = frame_benchmarking::whitelisted_caller(); + let balance = 10 * ExistentialDeposit::get(); + let _ = >::make_free_balance_be(&who, balance ); + + assert_eq!(Balances::free_balance(&who), balance); + + let transfer_asset: Asset = ( + AssetLocation::get(), + ExistentialDeposit::get(), + ).into(); + + let assets: Assets = vec![fee_asset.clone(), transfer_asset].into(); + + let fee_index: u32 = 0; + + let verify: Box = Box::new(move || { + assert!(Balances::free_balance(&who) <= balance - ExistentialDeposit::get()); + }); + + Some((assets, fee_index, destination, verify)) + } + + fn get_asset() -> Asset { + Asset { + id: AssetId(Location::here()), + fun: Fungible(ExistentialDeposit::get()), + } + } + } + + let whitelist: Vec = vec![ + // Block Number + hex!("26aa394eea5630e07c48ae0c9558cef702a5c1b19ab7a04f536c519aca4983ac").to_vec().into(), + // Total Issuance + hex!("c2261276cc9d1f8598ea4b6a74b15c2f57c875e4cff74148e4628f264b974c80").to_vec().into(), + // Execution Phase + hex!("26aa394eea5630e07c48ae0c9558cef7ff553b5a9862a516939d82b3d3d8661a").to_vec().into(), + // Event Count + hex!("26aa394eea5630e07c48ae0c9558cef70a98fdbe9ce6c55837576c60c7af3850").to_vec().into(), + // System Events + hex!("26aa394eea5630e07c48ae0c9558cef780d41e5e16056765bc8461851072c9d7").to_vec().into(), + ]; + + let mut batches = Vec::::new(); + let params = (&config, &whitelist); + + add_benchmarks!(params, batches); + + orml_add_benchmark!(params, batches, pallet_currencies, benchmarking::currencies); + orml_add_benchmark!(params, batches, orml_tokens, benchmarking::tokens); + orml_add_benchmark!(params, batches, orml_vesting, benchmarking::vesting); + orml_add_benchmark!(params, batches, pallet_transaction_multi_payment, benchmarking::multi_payment); + orml_add_benchmark!(params, batches, pallet_duster, benchmarking::duster); + orml_add_benchmark!(params, batches, pallet_omnipool, benchmarking::omnipool); + orml_add_benchmark!(params, batches, pallet_route_executor, benchmarking::route_executor); + orml_add_benchmark!(params, batches, pallet_dca, benchmarking::dca); + orml_add_benchmark!(params, batches, pallet_xyk, benchmarking::xyk); + orml_add_benchmark!(params, batches, pallet_dynamic_evm_fee, benchmarking::dynamic_evm_fee); + orml_add_benchmark!(params, batches, pallet_xyk_liquidity_mining, benchmarking::xyk_liquidity_mining); + + if batches.is_empty() { return Err("Benchmark not found for this pallet.".into()) } + Ok(batches) + } + } + + impl sp_genesis_builder::GenesisBuilder for Runtime { + fn build_state(config: Vec) -> sp_genesis_builder::Result { + build_state::(config) + } + + fn get_preset(id: &Option) -> Option> { + get_preset::(id, |_| None) + } + + fn preset_names() -> Vec { + Default::default() + } + } +}