-
Notifications
You must be signed in to change notification settings - Fork 1
Reward relayer on BH for S->E transfer #162
Changes from all commits
3a79d45
9401e17
b1d88ef
7a8a3a5
de84596
6ad15ae
aa503e0
62c0868
e13d082
d765b37
80537ed
486431d
3bb7f78
238d898
eca425f
c88fe86
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -107,33 +107,45 @@ 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}, | ||
outbound::{Fee, GasMeter, QueuedMessage, VersionedQueuedMessage}, | ||
BasicOperatingMode, ChannelId, | ||
}; | ||
use snowbridge_outbound_queue_merkle_tree::merkle_root; | ||
pub use snowbridge_outbound_queue_merkle_tree::MerkleProof; | ||
use sp_core::{H256, U256}; | ||
use sp_core::H256; | ||
use sp_runtime::{ | ||
traits::{CheckedDiv, Hash}, | ||
DigestItem, Saturating, | ||
traits::{AccountIdConversion, Hash, Zero}, | ||
DigestItem, | ||
}; | ||
use sp_std::prelude::*; | ||
pub use types::{CommittedMessage, ProcessMessageOriginOf}; | ||
pub use weights::WeightInfo; | ||
|
||
pub use pallet::*; | ||
type BalanceOf<T> = | ||
<<T as pallet::Config>::Token as Inspect<<T as frame_system::Config>::AccountId>>::Balance; | ||
|
||
#[frame_support::pallet] | ||
pub mod pallet { | ||
use super::*; | ||
use frame_support::pallet_prelude::*; | ||
use frame_support::{ | ||
pallet_prelude::*, | ||
traits::{ | ||
fungible::{Inspect, Mutate}, | ||
tokens::Preservation, | ||
}, | ||
PalletId, | ||
}; | ||
use frame_system::pallet_prelude::*; | ||
use snowbridge_core::PricingParameters; | ||
use sp_arithmetic::FixedU128; | ||
use snowbridge_core::{PayRewardError, PricingParameters}; | ||
use sp_arithmetic::traits::SaturatedConversion; | ||
|
||
#[pallet::pallet] | ||
pub struct Pallet<T>(_); | ||
|
@@ -173,6 +185,11 @@ pub mod pallet { | |
|
||
/// Weight information for extrinsics in this pallet | ||
type WeightInfo: WeightInfo; | ||
|
||
/// Message relayers are rewarded with this asset | ||
type Token: Mutate<Self::AccountId> + Inspect<Self::AccountId>; | ||
|
||
type PotId: Get<PalletId>; | ||
} | ||
|
||
#[pallet::event] | ||
|
@@ -243,6 +260,10 @@ pub mod pallet { | |
#[pallet::getter(fn operating_mode)] | ||
pub type OperatingMode<T: Config> = StorageValue<_, BasicOperatingMode, ValueQuery>; | ||
|
||
/// Fee locked by message hash | ||
#[pallet::storage] | ||
pub type LockedFee<T: Config> = StorageMap<_, Twox64Concat, H256, u128, ValueQuery>; | ||
|
||
#[pallet::hooks] | ||
impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> | ||
where | ||
|
@@ -280,6 +301,18 @@ pub mod pallet { | |
Self::deposit_event(Event::OperatingModeChanged { mode }); | ||
Ok(()) | ||
} | ||
|
||
#[pallet::call_index(1)] | ||
#[pallet::weight({100_000})] | ||
pub fn add_fees( | ||
origin: OriginFor<T>, | ||
message_id: H256, | ||
fee_amount: BalanceOf<T>, | ||
) -> DispatchResult { | ||
let who = ensure_signed(origin)?; | ||
Self::lock_fee(message_id, fee_amount, Some(who))?; | ||
Ok(()) | ||
} | ||
Comment on lines
+307
to
+315
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Essentially just a transfer from the sender origin to the pallet account. |
||
} | ||
|
||
impl<T: Config> Pallet<T> { | ||
|
@@ -374,39 +407,10 @@ pub mod pallet { | |
/// Calculate total fee in native currency to cover all costs of delivering a message to the | ||
/// remote destination. See module-level documentation for more details. | ||
pub(crate) fn calculate_fee( | ||
gas_used_at_most: u64, | ||
params: PricingParameters<T::Balance>, | ||
_gas_used_at_most: u64, | ||
_params: PricingParameters<T::Balance>, | ||
) -> Fee<T::Balance> { | ||
// Remote fee in ether | ||
let fee = Self::calculate_remote_fee( | ||
gas_used_at_most, | ||
params.fee_per_gas, | ||
params.rewards.remote, | ||
); | ||
|
||
// downcast to u128 | ||
let fee: u128 = fee.try_into().defensive_unwrap_or(u128::MAX); | ||
|
||
// multiply by multiplier and convert to local currency | ||
let fee = FixedU128::from_inner(fee) | ||
.saturating_mul(params.multiplier) | ||
.checked_div(¶ms.exchange_rate) | ||
.expect("exchange rate is not zero; qed") | ||
.into_inner(); | ||
|
||
// adjust fixed point to match local currency | ||
let fee = Self::convert_from_ether_decimals(fee); | ||
|
||
Fee::from((Self::calculate_local_fee(), fee)) | ||
} | ||
|
||
/// Calculate fee in remote currency for dispatching a message on Ethereum | ||
pub(crate) fn calculate_remote_fee( | ||
gas_used_at_most: u64, | ||
fee_per_gas: U256, | ||
reward: U256, | ||
) -> U256 { | ||
fee_per_gas.saturating_mul(gas_used_at_most.into()).saturating_add(reward) | ||
Fee::from((Self::calculate_local_fee(), T::Balance::zero())) | ||
Comment on lines
409
to
+413
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Will remove price params on chain and the remote portion of the fee. |
||
} | ||
|
||
/// The local component of the message processing fees in native currency | ||
|
@@ -416,13 +420,52 @@ pub mod pallet { | |
) | ||
} | ||
|
||
// 1 DOT has 10 digits of precision | ||
// 1 KSM has 12 digits of precision | ||
// 1 ETH has 18 digits of precision | ||
pub(crate) fn convert_from_ether_decimals(value: u128) -> T::Balance { | ||
let decimals = ETHER_DECIMALS.saturating_sub(T::Decimals::get()) as u32; | ||
let denom = 10u128.saturating_pow(decimals); | ||
value.checked_div(denom).expect("divisor is non-zero; qed").into() | ||
pub fn account_id() -> T::AccountId { | ||
T::PotId::get().into_account_truncating() | ||
} | ||
|
||
pub(crate) fn lock_fee( | ||
message_id: H256, | ||
fee_amount: BalanceOf<T>, | ||
who: Option<T::AccountId>, | ||
) -> DispatchResult { | ||
if let Some(payer) = who { | ||
T::Token::transfer( | ||
&payer, | ||
&Self::account_id(), | ||
fee_amount, | ||
Preservation::Preserve, | ||
)?; | ||
} else { | ||
T::Token::mint_into(&Self::account_id(), fee_amount)?; | ||
} | ||
Comment on lines
+440
to
+441
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Mint the fee(in DOT) to pallet account of OutboundQueue. |
||
|
||
<LockedFee<T>>::try_mutate(message_id, |amount| -> DispatchResult { | ||
*amount = amount.saturating_add(fee_amount.saturated_into::<u128>()); | ||
Ok(()) | ||
})?; | ||
Ok(()) | ||
} | ||
|
||
pub(crate) fn unlock_fee( | ||
message_id: H256, | ||
beneficiary: [u8; 32], | ||
) -> Result<(), PayRewardError> | ||
where | ||
<T as frame_system::Config>::AccountId: From<[u8; 32]>, | ||
{ | ||
let amount: BalanceOf<T> = <LockedFee<T>>::get(message_id).saturated_into(); | ||
|
||
T::Token::transfer( | ||
&Self::account_id(), | ||
&beneficiary.into(), | ||
amount, | ||
Preservation::Preserve, | ||
) | ||
.map_err(|_| PayRewardError::UnlockFailed)?; | ||
|
||
<LockedFee<T>>::remove(message_id); | ||
Ok(()) | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The storage map with Fee(in DOT) locked by MessageId.