#![warn(missing_docs)]
#![cfg_attr(not(feature = "std"), no_std)]
pub use extension::{
BatchCallUnpacker, ExtensionCallData, ExtensionCallInfo, ExtensionConfig,
RuntimeWithUtilityPallet,
};
pub use registration::{ExplicitOrAccountParams, Registration, StakeAndSlash};
use bp_runtime::{ChainId, StorageDoubleMapKeyProvider};
use frame_support::{traits::tokens::Preservation, Blake2_128Concat, Identity};
use scale_info::TypeInfo;
use sp_runtime::{
codec::{Codec, Decode, DecodeWithMemTracking, Encode, EncodeLike, MaxEncodedLen},
traits::AccountIdConversion,
TypeId,
};
use sp_std::{fmt::Debug, marker::PhantomData};
mod extension;
mod registration;
#[derive(
Copy,
Clone,
Debug,
Decode,
DecodeWithMemTracking,
Encode,
Eq,
PartialEq,
TypeInfo,
MaxEncodedLen,
)]
pub enum RewardsAccountOwner {
ThisChain,
BridgedChain,
}
#[derive(
Copy,
Clone,
Debug,
Decode,
DecodeWithMemTracking,
Encode,
Eq,
PartialEq,
TypeInfo,
MaxEncodedLen,
)]
pub struct RewardsAccountParams<LaneId> {
owner: RewardsAccountOwner,
bridged_chain_id: ChainId,
lane_id: LaneId,
}
impl<LaneId: Decode + Encode> RewardsAccountParams<LaneId> {
pub const fn new(
lane_id: LaneId,
bridged_chain_id: ChainId,
owner: RewardsAccountOwner,
) -> Self {
Self { lane_id, bridged_chain_id, owner }
}
pub const fn lane_id(&self) -> &LaneId {
&self.lane_id
}
}
impl<LaneId: Decode + Encode> TypeId for RewardsAccountParams<LaneId> {
const TYPE_ID: [u8; 4] = *b"brap";
}
pub trait PaymentProcedure<Relayer, Reward, RewardBalance> {
type Error: Debug;
type Beneficiary: Clone + Debug + Decode + Encode + Eq + TypeInfo;
fn pay_reward(
relayer: &Relayer,
reward: Reward,
reward_balance: RewardBalance,
beneficiary: Self::Beneficiary,
) -> Result<(), Self::Error>;
}
impl<Relayer, Reward, RewardBalance> PaymentProcedure<Relayer, Reward, RewardBalance> for () {
type Error = &'static str;
type Beneficiary = ();
fn pay_reward(
_: &Relayer,
_: Reward,
_: RewardBalance,
_: Self::Beneficiary,
) -> Result<(), Self::Error> {
Ok(())
}
}
pub struct PayRewardFromAccount<T, Relayer, LaneId, RewardBalance>(
PhantomData<(T, Relayer, LaneId, RewardBalance)>,
);
impl<T, Relayer, LaneId, RewardBalance> PayRewardFromAccount<T, Relayer, LaneId, RewardBalance>
where
Relayer: Decode + Encode,
LaneId: Decode + Encode,
{
pub fn rewards_account(params: RewardsAccountParams<LaneId>) -> Relayer {
params.into_sub_account_truncating(b"rewards-account")
}
}
impl<T, Relayer, LaneId, RewardBalance>
PaymentProcedure<Relayer, RewardsAccountParams<LaneId>, RewardBalance>
for PayRewardFromAccount<T, Relayer, LaneId, RewardBalance>
where
T: frame_support::traits::fungible::Mutate<Relayer>,
T::Balance: From<RewardBalance>,
Relayer: Clone + Debug + Decode + Encode + Eq + TypeInfo,
LaneId: Decode + Encode,
{
type Error = sp_runtime::DispatchError;
type Beneficiary = Relayer;
fn pay_reward(
_: &Relayer,
reward_kind: RewardsAccountParams<LaneId>,
reward: RewardBalance,
beneficiary: Self::Beneficiary,
) -> Result<(), Self::Error> {
T::transfer(
&Self::rewards_account(reward_kind),
&beneficiary.into(),
reward.into(),
Preservation::Expendable,
)
.map(drop)
}
}
pub struct RelayerRewardsKeyProvider<AccountId, Reward, RewardBalance>(
PhantomData<(AccountId, Reward, RewardBalance)>,
);
impl<AccountId, Reward, RewardBalance> StorageDoubleMapKeyProvider
for RelayerRewardsKeyProvider<AccountId, Reward, RewardBalance>
where
AccountId: 'static + Codec + EncodeLike + Send + Sync,
Reward: Codec + EncodeLike + Send + Sync,
RewardBalance: 'static + Codec + EncodeLike + Send + Sync,
{
const MAP_NAME: &'static str = "RelayerRewards";
type Hasher1 = Blake2_128Concat;
type Key1 = AccountId;
type Hasher2 = Identity;
type Key2 = Reward;
type Value = RewardBalance;
}
pub trait RewardLedger<Relayer, Reward, RewardBalance> {
fn register_reward(relayer: &Relayer, reward: Reward, reward_balance: RewardBalance);
}
#[cfg(test)]
mod tests {
use super::*;
use bp_messages::{HashedLaneId, LaneIdType, LegacyLaneId};
use sp_runtime::{app_crypto::Ss58Codec, testing::H256};
#[test]
fn different_lanes_are_using_different_accounts() {
assert_eq!(
PayRewardFromAccount::<(), H256, HashedLaneId, ()>::rewards_account(
RewardsAccountParams::new(
HashedLaneId::try_new(1, 2).unwrap(),
*b"test",
RewardsAccountOwner::ThisChain
)
),
hex_literal::hex!("627261700074657374b1d3dccd8b3c3a012afe265f3e3c4432129b8aee50c9dc")
.into(),
);
assert_eq!(
PayRewardFromAccount::<(), H256, HashedLaneId, ()>::rewards_account(
RewardsAccountParams::new(
HashedLaneId::try_new(1, 3).unwrap(),
*b"test",
RewardsAccountOwner::ThisChain
)
),
hex_literal::hex!("627261700074657374a43e8951aa302c133beb5f85821a21645f07b487270ef3")
.into(),
);
}
#[test]
fn different_directions_are_using_different_accounts() {
assert_eq!(
PayRewardFromAccount::<(), H256, HashedLaneId, ()>::rewards_account(
RewardsAccountParams::new(
HashedLaneId::try_new(1, 2).unwrap(),
*b"test",
RewardsAccountOwner::ThisChain
)
),
hex_literal::hex!("627261700074657374b1d3dccd8b3c3a012afe265f3e3c4432129b8aee50c9dc")
.into(),
);
assert_eq!(
PayRewardFromAccount::<(), H256, HashedLaneId, ()>::rewards_account(
RewardsAccountParams::new(
HashedLaneId::try_new(1, 2).unwrap(),
*b"test",
RewardsAccountOwner::BridgedChain
)
),
hex_literal::hex!("627261700174657374b1d3dccd8b3c3a012afe265f3e3c4432129b8aee50c9dc")
.into(),
);
}
#[test]
fn pay_reward_from_account_for_legacy_lane_id_works() {
let test_data = vec![
(
LegacyLaneId([0, 0, 0, 1]),
b"bhks",
RewardsAccountOwner::ThisChain,
(0_u16, "13E5fui97x6KTwNnSjaEKZ8s7kJNot5F3aUsy3jUtuoMyUec"),
),
(
LegacyLaneId([0, 0, 0, 1]),
b"bhks",
RewardsAccountOwner::BridgedChain,
(0_u16, "13E5fui9Ka9Vz4JbGN3xWjmwDNxnxF1N9Hhhbeu3VCqLChuj"),
),
(
LegacyLaneId([0, 0, 0, 1]),
b"bhpd",
RewardsAccountOwner::ThisChain,
(2_u16, "EoQBtnwtXqnSnr9cgBEJpKU7NjeC9EnR4D1VjgcvHz9ZYmS"),
),
(
LegacyLaneId([0, 0, 0, 1]),
b"bhpd",
RewardsAccountOwner::BridgedChain,
(2_u16, "EoQBtnx69txxumxSJexVzxYD1Q4LWAuWmRq8LrBWb27nhYN"),
),
(
LegacyLaneId([0, 0, 0, 2]),
b"bhwd",
RewardsAccountOwner::ThisChain,
(4_u16, "SNihsskf7bFhnHH9HJFMjWD3FJ96ESdAQTFZUAtXudRQbaH"),
),
(
LegacyLaneId([0, 0, 0, 2]),
b"bhwd",
RewardsAccountOwner::BridgedChain,
(4_u16, "SNihsskrjeSDuD5xumyYv9H8sxZEbNkG7g5C5LT8CfPdaSE"),
),
(
LegacyLaneId([0, 0, 0, 2]),
b"bhro",
RewardsAccountOwner::ThisChain,
(4_u16, "SNihsskf7bF2vWogkC6uFoiqPhd3dUX6TGzYZ1ocJdo3xHp"),
),
(
LegacyLaneId([0, 0, 0, 2]),
b"bhro",
RewardsAccountOwner::BridgedChain,
(4_u16, "SNihsskrjeRZ3ScWNfq6SSnw2N3BzQeCAVpBABNCbfmHENB"),
),
];
for (lane_id, bridged_chain_id, owner, (expected_ss58, expected_account)) in test_data {
assert_eq!(
expected_account,
sp_runtime::AccountId32::new(PayRewardFromAccount::<
[u8; 32],
[u8; 32],
LegacyLaneId,
(),
>::rewards_account(RewardsAccountParams::new(
lane_id,
*bridged_chain_id,
owner
)))
.to_ss58check_with_version(expected_ss58.into())
);
}
}
}