Lines
0 %
Functions
Branches
100 %
// Copyright 2019-2025 PureStake Inc.
// This file is part of Moonbeam.
// Moonbeam 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.
// Moonbeam 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 Moonbeam. If not, see <http://www.gnu.org/licenses/>.
// We want to avoid including the rococo-runtime here.
// TODO: whenever a conclusion is taken from https://github.com/paritytech/substrate/issues/8158
use cumulus_primitives_core::{relay_chain::HrmpChannelId, ParaId};
use pallet_xcm_transactor::relay_indices::RelayChainIndices;
use parity_scale_codec::{Decode, Encode};
use sp_runtime::traits::{AccountIdLookup, StaticLookup};
use sp_runtime::AccountId32;
use sp_std::vec::Vec;
#[derive(Encode, Decode)]
pub enum RelayCall {
#[codec(index = 6u8)]
Stake(StakeCall),
#[codec(index = 24u8)]
// the index should match the position of the module in `construct_runtime!`
Utility(UtilityCall),
#[codec(index = 60u8)]
Hrmp(HrmpCall),
}
pub enum StakeCall {
#[codec(index = 0u16)]
// the index should match the position of the dispatchable in the target pallet
Bond(
#[codec(compact)] cumulus_primitives_core::relay_chain::Balance,
pallet_staking::RewardDestination<AccountId32>,
),
#[codec(index = 1u16)]
BondExtra(#[codec(compact)] cumulus_primitives_core::relay_chain::Balance),
#[codec(index = 2u16)]
Unbond(#[codec(compact)] cumulus_primitives_core::relay_chain::Balance),
#[codec(index = 3u16)]
WithdrawUnbonded(u32),
#[codec(index = 4u16)]
Validate(pallet_staking::ValidatorPrefs),
#[codec(index = 5u16)]
Nominate(Vec<<AccountIdLookup<AccountId32, ()> as StaticLookup>::Source>),
#[codec(index = 6u16)]
Chill,
#[codec(index = 7u16)]
SetPayee(pallet_staking::RewardDestination<AccountId32>),
#[codec(index = 8u16)]
SetController,
#[codec(index = 19u16)]
Rebond(#[codec(compact)] cumulus_primitives_core::relay_chain::Balance),
// Utility call encoding, needed for xcm transactor pallet
pub enum UtilityCall {
#[codec(index = 1u8)]
AsDerivative(u16),
// HRMP call encoding, needed for xcm transactor pallet
pub enum HrmpCall {
#[codec(index = 0u8)]
InitOpenChannel(ParaId, u32, u32),
AcceptOpenChannel(ParaId),
#[codec(index = 2u8)]
CloseChannel(HrmpChannelId),
CancelOpenRequest(HrmpChannelId, u32),
pub struct KusamaEncoder;
impl xcm_primitives::UtilityEncodeCall for KusamaEncoder {
fn encode_call(self, call: xcm_primitives::UtilityAvailableCalls) -> Vec<u8> {
match call {
xcm_primitives::UtilityAvailableCalls::AsDerivative(a, b) => {
let mut call = RelayCall::Utility(UtilityCall::AsDerivative(a.clone())).encode();
// If we encode directly we inject the call length,
// so we just append the inner call after encoding the outer
call.append(&mut b.clone());
call
impl xcm_primitives::HrmpEncodeCall for KusamaEncoder {
fn hrmp_encode_call(
call: xcm_primitives::HrmpAvailableCalls,
) -> Result<Vec<u8>, xcm::latest::Error> {
xcm_primitives::HrmpAvailableCalls::InitOpenChannel(a, b, c) => Ok(RelayCall::Hrmp(
HrmpCall::InitOpenChannel(a.clone(), b.clone(), c.clone()),
)
.encode()),
xcm_primitives::HrmpAvailableCalls::AcceptOpenChannel(a) => {
Ok(RelayCall::Hrmp(HrmpCall::AcceptOpenChannel(a.clone())).encode())
xcm_primitives::HrmpAvailableCalls::CloseChannel(a) => {
Ok(RelayCall::Hrmp(HrmpCall::CloseChannel(a.clone())).encode())
xcm_primitives::HrmpAvailableCalls::CancelOpenRequest(a, b) => {
Ok(RelayCall::Hrmp(HrmpCall::CancelOpenRequest(a.clone(), b.clone())).encode())
impl xcm_primitives::StakeEncodeCall for KusamaEncoder {
fn encode_call(call: xcm_primitives::AvailableStakeCalls) -> Vec<u8> {
xcm_primitives::AvailableStakeCalls::Bond(b, c) => {
RelayCall::Stake(StakeCall::Bond(b, c)).encode()
xcm_primitives::AvailableStakeCalls::BondExtra(a) => {
RelayCall::Stake(StakeCall::BondExtra(a)).encode()
xcm_primitives::AvailableStakeCalls::Unbond(a) => {
RelayCall::Stake(StakeCall::Unbond(a)).encode()
xcm_primitives::AvailableStakeCalls::WithdrawUnbonded(a) => {
RelayCall::Stake(StakeCall::WithdrawUnbonded(a)).encode()
xcm_primitives::AvailableStakeCalls::Validate(a) => {
RelayCall::Stake(StakeCall::Validate(a)).encode()
xcm_primitives::AvailableStakeCalls::Chill => {
RelayCall::Stake(StakeCall::Chill).encode()
xcm_primitives::AvailableStakeCalls::SetPayee(a) => {
RelayCall::Stake(StakeCall::SetPayee(a.into())).encode()
xcm_primitives::AvailableStakeCalls::SetController => {
RelayCall::Stake(StakeCall::SetController).encode()
xcm_primitives::AvailableStakeCalls::Rebond(a) => {
RelayCall::Stake(StakeCall::Rebond(a.into())).encode()
xcm_primitives::AvailableStakeCalls::Nominate(a) => {
let nominated: Vec<<AccountIdLookup<AccountId32, ()> as StaticLookup>::Source> =
a.iter().map(|add| (*add).clone().into()).collect();
RelayCall::Stake(StakeCall::Nominate(nominated)).encode()
/// Kusama pallet and extrinsic indices
pub const KUSAMA_RELAY_INDICES: RelayChainIndices = RelayChainIndices {
staking: 6u8,
utility: 24u8,
hrmp: 60u8,
bond: 0u8,
bond_extra: 1u8,
unbond: 2u8,
withdraw_unbonded: 3u8,
validate: 4u8,
nominate: 5u8,
chill: 6u8,
set_payee: 7u8,
set_controller: 8u8,
rebond: 19u8,
as_derivative: 1u8,
init_open_channel: 0u8,
accept_open_channel: 1u8,
close_channel: 2u8,
cancel_open_request: 6u8,
};
//
// #[cfg(test)]
// mod tests {
// use super::*;
// use crate::kusama::KusamaEncoder;
// use frame_support::traits::PalletInfo;
// use sp_runtime::Perbill;
// use xcm_primitives::{StakeEncodeCall, UtilityEncodeCall};
// #[test]
// fn test_as_derivative() {
// let mut expected_encoded: Vec<u8> = Vec::new();
// let index = <kusama_runtime::Runtime as frame_system::Config>::PalletInfo::index::<
// kusama_runtime::Utility,
// >()
// .unwrap() as u8;
// expected_encoded.push(index);
// let mut expected = pallet_utility::Call::<kusama_runtime::Runtime>::as_derivative {
// index: 1,
// call: kusama_runtime::RuntimeCall::Staking(pallet_staking::Call::<
// kusama_runtime::Runtime,
// >::chill {})
// .into(),
// }
// .encode();
// expected_encoded.append(&mut expected);
// let call_bytes = <KusamaEncoder as StakeEncodeCall>::encode_call(
// xcm_primitives::AvailableStakeCalls::Chill,
// );
// assert_eq!(
// xcm_primitives::UtilityEncodeCall::encode_call(
// KusamaEncoder,
// xcm_primitives::UtilityAvailableCalls::AsDerivative(1, call_bytes.clone())
// ),
// expected_encoded.clone()
// sp_io::TestExternalities::default().execute_with(|| {
// // Pallet-xcm-transactor default encoder returns same result
// // insert storage item as per migration to set the storage item
// pallet_xcm_transactor::RelayIndices::<moonriver_runtime::Runtime>::put(
// KUSAMA_RELAY_INDICES,
// <pallet_xcm_transactor::Pallet::<
// moonriver_runtime::Runtime> as UtilityEncodeCall
// >::encode_call(
// pallet_xcm_transactor::Pallet(
// sp_std::marker::PhantomData::<moonriver_runtime::Runtime>::default()),
// xcm_primitives::UtilityAvailableCalls::AsDerivative(1, call_bytes)
// expected_encoded
// });
// fn test_stake_bond() {
// kusama_runtime::Staking,
// let mut expected = pallet_staking::Call::<kusama_runtime::Runtime>::bond {
// value: 100u32.into(),
// payee: pallet_staking::RewardDestination::Controller,
// <KusamaEncoder as StakeEncodeCall>::encode_call(
// xcm_primitives::AvailableStakeCalls::Bond(
// 100u32.into(),
// pallet_staking::RewardDestination::Controller
// )
// moonriver_runtime::Runtime> as StakeEncodeCall
// fn test_stake_bond_extra() {
// let mut expected = pallet_staking::Call::<kusama_runtime::Runtime>::bond_extra {
// max_additional: 100u32.into(),
// xcm_primitives::AvailableStakeCalls::BondExtra(100u32.into(),)
// fn test_stake_unbond() {
// let mut expected = pallet_staking::Call::<kusama_runtime::Runtime>::unbond {
// xcm_primitives::AvailableStakeCalls::Unbond(100u32.into(),)
// fn test_stake_withdraw_unbonded() {
// let mut expected = pallet_staking::Call::<kusama_runtime::Runtime>::withdraw_unbonded {
// num_slashing_spans: 100u32,
// xcm_primitives::AvailableStakeCalls::WithdrawUnbonded(100u32,)
// fn test_stake_validate() {
// let validator_prefs = pallet_staking::ValidatorPrefs {
// commission: Perbill::from_percent(5),
// blocked: true,
// };
// let mut expected = pallet_staking::Call::<kusama_runtime::Runtime>::validate {
// prefs: validator_prefs.clone(),
// xcm_primitives::AvailableStakeCalls::Validate(validator_prefs.clone())
// xcm_primitives::AvailableStakeCalls::Validate(validator_prefs)
// fn test_stake_nominate() {
// let relay_account: AccountId32 = [1u8; 32].into();
// let mut expected = pallet_staking::Call::<kusama_runtime::Runtime>::nominate {
// targets: vec![relay_account.clone().into()],
// xcm_primitives::AvailableStakeCalls::Nominate(vec![relay_account.clone().into()])
// xcm_primitives::AvailableStakeCalls::Nominate(vec![
// relay_account.into()
// ])
// fn test_stake_chill() {
// let mut expected = pallet_staking::Call::<kusama_runtime::Runtime>::chill {}.encode();
// xcm_primitives::AvailableStakeCalls::Chill
// fn test_set_payee() {
// let mut expected = pallet_staking::Call::<kusama_runtime::Runtime>::set_payee {
// xcm_primitives::AvailableStakeCalls::SetPayee(
// fn test_set_controller() {
// let mut expected =
// pallet_staking::Call::<kusama_runtime::Runtime>::set_controller {}.encode();
// xcm_primitives::AvailableStakeCalls::SetController
// fn test_rebond() {
// let mut expected = pallet_staking::Call::<kusama_runtime::Runtime>::rebond {
// xcm_primitives::AvailableStakeCalls::Rebond(100u32.into())
// fn test_hrmp_init() {
// kusama_runtime::Hrmp,
// let mut expected = polkadot_runtime_parachains::hrmp::Call::<
// kusama_runtime::Runtime
// >::hrmp_init_open_channel {
// recipient: 1000u32.into(),
// proposed_max_capacity: 100u32,
// proposed_max_message_size: 100u32,
// <KusamaEncoder as xcm_primitives::HrmpEncodeCall>::hrmp_encode_call(
// xcm_primitives::HrmpAvailableCalls::InitOpenChannel(
// 1000u32.into(),
// 100u32.into()
// Ok(expected_encoded.clone())
// moonriver_runtime::Runtime> as xcm_primitives::HrmpEncodeCall
// >::hrmp_encode_call(
// Ok(expected_encoded)
// fn test_hrmp_accept() {
// >::hrmp_accept_open_channel {
// sender: 1000u32.into()
// xcm_primitives::HrmpAvailableCalls::AcceptOpenChannel(1000u32.into(),)
// fn test_hrmp_close() {
// >::hrmp_close_channel {
// channel_id: HrmpChannelId {
// sender: 1000u32.into(),
// recipient: 1001u32.into()
// xcm_primitives::HrmpAvailableCalls::CloseChannel(HrmpChannelId {
// })
// fn test_hrmp_cancel() {
// let channel_id = HrmpChannelId {
// sender: 1u32.into(),
// recipient: 1u32.into(),
// let open_requests: u32 = 1;
// >::hrmp_cancel_open_request {
// channel_id: channel_id.clone(),
// open_requests
// xcm_primitives::HrmpAvailableCalls::CancelOpenRequest(
// channel_id.clone(),