diff --git a/Cargo.lock b/Cargo.lock index 288a7ca4444b..27059644e577 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -19219,6 +19219,7 @@ dependencies = [ "frame-benchmarking", "frame-support", "frame-system", + "pallet-balances", "pallet-message-queue", "parity-scale-codec", "scale-info", @@ -19231,6 +19232,8 @@ dependencies = [ "sp-keyring", "sp-runtime", "sp-std 14.0.0", + "staging-xcm", + "staging-xcm-executor", ] [[package]] diff --git a/bridges/snowbridge/pallets/inbound-queue/src/lib.rs b/bridges/snowbridge/pallets/inbound-queue/src/lib.rs index 5730b5f34032..55c5079f5d59 100644 --- a/bridges/snowbridge/pallets/inbound-queue/src/lib.rs +++ b/bridges/snowbridge/pallets/inbound-queue/src/lib.rs @@ -290,8 +290,8 @@ pub mod pallet { let _ = match message { VersionedMessage::V1(MessageV1 { command: Command::RewardRelay { message_id, relay_address }, - .. - }) => T::Payer::reward_relay(message_id, relay_address) + chain_id, + }) => T::Payer::reward_relay(chain_id, message_id, relay_address) .map_err(|e| Error::::PayReward(e)), _ => Ok(()), }?; diff --git a/bridges/snowbridge/pallets/outbound-queue/Cargo.toml b/bridges/snowbridge/pallets/outbound-queue/Cargo.toml index 15c6c3a5b32b..2aef9c7ebd2a 100644 --- a/bridges/snowbridge/pallets/outbound-queue/Cargo.toml +++ b/bridges/snowbridge/pallets/outbound-queue/Cargo.toml @@ -33,44 +33,52 @@ bridge-hub-common = { path = "../../../../cumulus/parachains/runtimes/bridge-hub snowbridge-core = { path = "../../primitives/core", default-features = false, features = ["serde"] } snowbridge-outbound-queue-merkle-tree = { path = "merkle-tree", default-features = false } ethabi = { package = "ethabi-decode", version = "1.0.0", default-features = false } +xcm = { package = "staging-xcm", path = "../../../../polkadot/xcm", default-features = false } +xcm-executor = { package = "staging-xcm-executor", path = "../../../../polkadot/xcm/xcm-executor", default-features = false } [dev-dependencies] pallet-message-queue = { path = "../../../../substrate/frame/message-queue", default-features = false } sp-keyring = { path = "../../../../substrate/primitives/keyring" } +pallet-balances = { path = "../../../../substrate/frame/balances" } [features] default = ["std"] std = [ - "bridge-hub-common/std", - "codec/std", - "ethabi/std", - "frame-benchmarking/std", - "frame-support/std", - "frame-system/std", - "pallet-message-queue/std", - "scale-info/std", - "serde/std", - "snowbridge-core/std", - "snowbridge-outbound-queue-merkle-tree/std", - "sp-arithmetic/std", - "sp-core/std", - "sp-io/std", - "sp-runtime/std", - "sp-std/std", + "bridge-hub-common/std", + "codec/std", + "ethabi/std", + "frame-benchmarking/std", + "frame-support/std", + "frame-system/std", + "pallet-message-queue/std", + "scale-info/std", + "serde/std", + "snowbridge-core/std", + "snowbridge-outbound-queue-merkle-tree/std", + "sp-arithmetic/std", + "sp-core/std", + "sp-io/std", + "sp-runtime/std", + "sp-std/std", + "xcm-executor/std", + "xcm/std", ] runtime-benchmarks = [ - "bridge-hub-common/runtime-benchmarks", - "frame-benchmarking", - "frame-benchmarking/runtime-benchmarks", - "frame-support/runtime-benchmarks", - "frame-system/runtime-benchmarks", - "pallet-message-queue/runtime-benchmarks", - "snowbridge-core/runtime-benchmarks", - "sp-runtime/runtime-benchmarks", + "bridge-hub-common/runtime-benchmarks", + "frame-benchmarking", + "frame-benchmarking/runtime-benchmarks", + "frame-support/runtime-benchmarks", + "frame-system/runtime-benchmarks", + "pallet-balances/runtime-benchmarks", + "pallet-message-queue/runtime-benchmarks", + "snowbridge-core/runtime-benchmarks", + "sp-runtime/runtime-benchmarks", + "xcm-executor/runtime-benchmarks", ] try-runtime = [ - "frame-support/try-runtime", - "frame-system/try-runtime", - "pallet-message-queue/try-runtime", - "sp-runtime/try-runtime", + "frame-support/try-runtime", + "frame-system/try-runtime", + "pallet-balances/try-runtime", + "pallet-message-queue/try-runtime", + "sp-runtime/try-runtime", ] diff --git a/bridges/snowbridge/pallets/outbound-queue/src/lib.rs b/bridges/snowbridge/pallets/outbound-queue/src/lib.rs index 30bb0fece179..c9dfb5199821 100644 --- a/bridges/snowbridge/pallets/outbound-queue/src/lib.rs +++ b/bridges/snowbridge/pallets/outbound-queue/src/lib.rs @@ -107,9 +107,13 @@ use bridge_hub_common::{AggregateMessageOrigin, CustomDigestItem}; use codec::Decode; use frame_support::{ storage::StorageStreamIter, - traits::{tokens::Balance, Contains, Defensive, EnqueueMessage, Get, ProcessMessageError}, + traits::{ + fungible::Inspect, tokens::Balance, Contains, Defensive, EnqueueMessage, Get, + ProcessMessageError, + }, weights::{Weight, WeightToFee}, }; +pub use pallet::*; use snowbridge_core::{ outbound::{Fee, GasMeter, QueuedMessage, VersionedQueuedMessage, ETHER_DECIMALS}, BasicOperatingMode, ChannelId, @@ -124,16 +128,22 @@ use sp_runtime::{ use sp_std::prelude::*; pub use types::{CommittedMessage, ProcessMessageOriginOf}; pub use weights::WeightInfo; +use xcm::prelude::{Junction::*, Location, NetworkId}; +use xcm_executor::traits::ConvertLocation; -pub use pallet::*; +type BalanceOf = + <::Token as Inspect<::AccountId>>::Balance; #[frame_support::pallet] pub mod pallet { use super::*; - use frame_support::pallet_prelude::*; + use frame_support::{ + pallet_prelude::*, + traits::fungible::{Inspect, Mutate}, + }; use frame_system::pallet_prelude::*; - use snowbridge_core::PricingParameters; - use sp_arithmetic::FixedU128; + use snowbridge_core::{PayRewardError, PricingParameters}; + use sp_arithmetic::{traits::SaturatedConversion, FixedU128}; #[pallet::pallet] pub struct Pallet(_); @@ -173,6 +183,9 @@ pub mod pallet { /// Weight information for extrinsics in this pallet type WeightInfo: WeightInfo; + + /// Message relayers are rewarded with this asset + type Token: Mutate + Inspect; } #[pallet::event] @@ -437,11 +450,27 @@ pub mod pallet { Ok(()) } - pub(crate) fn unlock_fee(message_id: H256, _relay: H160) -> DispatchResult { - let _fee = >::get(message_id); - // Todo: mint fee to the sovereign of the beneficiary - // let sovereign: AccountId = sovereign_of(_relay); - // T::Token::mint_into(sovereign,_fee); + pub(crate) fn unlock_fee( + chain_id: u64, + message_id: H256, + relay: H160, + ) -> Result<(), PayRewardError> + where + ::AccountId: From<[u8; 32]>, + { + let fee: BalanceOf = >::get(message_id).saturated_into(); + + let account = snowbridge_core::SovereignIdOf::convert_location(&Location::new( + 2, + [ + GlobalConsensus(NetworkId::Ethereum { chain_id }), + AccountKey20 { network: None, key: relay.into() }, + ], + )) + .ok_or(PayRewardError::AccountIdConversionFailed)?; + let sovereign_account: T::AccountId = account.into(); + + T::Token::mint_into(&sovereign_account, fee).map_err(|_| PayRewardError::CantMint)?; >::remove(message_id); Ok(()) } diff --git a/bridges/snowbridge/pallets/outbound-queue/src/mock.rs b/bridges/snowbridge/pallets/outbound-queue/src/mock.rs index 491fd73f5b07..a251550fc951 100644 --- a/bridges/snowbridge/pallets/outbound-queue/src/mock.rs +++ b/bridges/snowbridge/pallets/outbound-queue/src/mock.rs @@ -16,23 +16,26 @@ use snowbridge_core::{ }; use sp_core::{ConstU32, ConstU8, H160, H256}; use sp_runtime::{ - traits::{BlakeTwo256, IdentityLookup, Keccak256}, - AccountId32, BuildStorage, FixedU128, + traits::{BlakeTwo256, IdentifyAccount, IdentityLookup, Keccak256, Verify}, + BuildStorage, FixedU128, MultiSignature, }; use sp_std::marker::PhantomData; type Block = frame_system::mocking::MockBlock; -type AccountId = AccountId32; frame_support::construct_runtime!( pub enum Test { System: frame_system::{Pallet, Call, Storage, Event}, + Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, MessageQueue: pallet_message_queue::{Pallet, Call, Storage, Event}, OutboundQueue: crate::{Pallet, Storage, Event}, } ); +pub type Signature = MultiSignature; +pub type AccountId = <::Signer as IdentifyAccount>::AccountId; + #[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { type BaseCallFilter = Everything; @@ -45,10 +48,30 @@ impl frame_system::Config for Test { type Lookup = IdentityLookup; type RuntimeEvent = RuntimeEvent; type PalletInfo = PalletInfo; + type AccountData = pallet_balances::AccountData; type Nonce = u64; type Block = Block; } +parameter_types! { + pub const ExistentialDeposit: u128 = 1; +} +impl pallet_balances::Config for Test { + type MaxLocks = (); + type MaxReserves = (); + type ReserveIdentifier = [u8; 8]; + type Balance = u128; + type RuntimeEvent = RuntimeEvent; + type DustRemoval = (); + type ExistentialDeposit = ExistentialDeposit; + type AccountStore = System; + type WeightInfo = (); + type FreezeIdentifier = (); + type MaxFreezes = (); + type RuntimeHoldReason = (); + type RuntimeFreezeReason = (); +} + parameter_types! { pub const HeapSize: u32 = 32 * 1024; pub const MaxStale: u32 = 32; @@ -93,6 +116,7 @@ impl crate::Config for Test { type Channels = Everything; type WeightToFee = IdentityFee; type WeightInfo = (); + type Token = Balances; } fn setup() { diff --git a/bridges/snowbridge/pallets/outbound-queue/src/send_message_impl.rs b/bridges/snowbridge/pallets/outbound-queue/src/send_message_impl.rs index f2af722a56e8..fd47cfa2645d 100644 --- a/bridges/snowbridge/pallets/outbound-queue/src/send_message_impl.rs +++ b/bridges/snowbridge/pallets/outbound-queue/src/send_message_impl.rs @@ -119,9 +119,12 @@ impl SendMessageFeeProvider for Pallet { } } -impl PayMaster for Pallet { +impl PayMaster for Pallet +where + ::AccountId: From<[u8; 32]>, +{ /// The local component of the message processing fees in native currency - fn reward_relay(message_id: H256, relay: H160) -> Result<(), PayRewardError> { - Self::unlock_fee(message_id, relay).map_err(|_| PayRewardError::Other) + fn reward_relay(chain_id: u64, message_id: H256, relay: H160) -> Result<(), PayRewardError> { + Self::unlock_fee(chain_id, message_id, relay) } } diff --git a/bridges/snowbridge/primitives/core/src/lib.rs b/bridges/snowbridge/primitives/core/src/lib.rs index cbba9ea23b06..10edfb12df51 100644 --- a/bridges/snowbridge/primitives/core/src/lib.rs +++ b/bridges/snowbridge/primitives/core/src/lib.rs @@ -168,16 +168,20 @@ pub type AgentIdOf = HashedDescription Result<(), PayRewardError>; + fn reward_relay(chain_id: u64, message_id: H256, relay: H160) -> Result<(), PayRewardError>; } impl PayMaster for () { - fn reward_relay(_: H256, _: H160) -> Result<(), PayRewardError> { + fn reward_relay(_: u64, _: H256, _: H160) -> Result<(), PayRewardError> { Ok(()) } } + +pub type SovereignIdOf = + HashedDescription<[u8; 32], (DescribeHere, DescribeFamily)>; diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_ethereum_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_ethereum_config.rs index e4e724d4b85c..0ff0c69ebe49 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_ethereum_config.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_ethereum_config.rs @@ -106,6 +106,7 @@ impl snowbridge_pallet_outbound_queue::Config for Runtime { type WeightInfo = crate::weights::snowbridge_pallet_outbound_queue::WeightInfo; type PricingParameters = EthereumSystem; type Channels = EthereumSystem; + type Token = Balances; } #[cfg(any(feature = "std", feature = "fast-runtime", feature = "runtime-benchmarks", test))] diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/bridge_to_ethereum_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/bridge_to_ethereum_config.rs index 3f51274eee69..5ab6ece4e306 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/bridge_to_ethereum_config.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/bridge_to_ethereum_config.rs @@ -108,6 +108,7 @@ impl snowbridge_pallet_outbound_queue::Config for Runtime { type WeightInfo = crate::weights::snowbridge_pallet_outbound_queue::WeightInfo; type PricingParameters = EthereumSystem; type Channels = EthereumSystem; + type Token = Balances; } #[cfg(any(feature = "std", feature = "fast-runtime", feature = "runtime-benchmarks", test))]