Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement Xcm interface for relaychain cross call #295

Open
wants to merge 14 commits into
base: feature/spp-wip
Choose a base branch
from
Open
52 changes: 52 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 2 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
<div align="center">
<h1>[Bit.Country] Metaverse.Network</h1>

## Start your own metaverse. An Ethereum-compatible Network for Metaverses & Games
## An Ethereum-compatible Blockchain Network Built using Substrate

[![Substrate version](https://img.shields.io/badge/Substrate-3.0.0-brightgreen?logo=Parity%20Substrate)](https://substrate.dev/)
[![Twitter URL](https://img.shields.io/twitter/url?style=social&url=https%3A%2F%2Ftwitter.com%2Fbitdotcountry)](https://twitter.com/bitdotcountry)
Expand All @@ -30,10 +30,7 @@ Development Note: It is still a WIP.

# 1. Introduction

Metaverse Network is an EVM-enabled blockchain network for user-created metaverses and games.

Everyone can start their own metaverse for their people with the 3D world, NFTs, play-to-earn & build communities to
earn, and takes community engagement to a new dimension on web3.0.
Metaverse.Network, featuring a seamlessly integrated enriched social layer, stands as an interesting blockchain ecosystem that extends support for both EVM (Ethereum Virtual Machine) and WASM (WebAssembly) smart contracts. This framework empowers developers to harness the network's capabilities in crafting decentralized applications (dApps) with unparalleled versatility and functionality.

# 2. Build

Expand Down
230 changes: 143 additions & 87 deletions modules/relaychain/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,127 +22,145 @@

#![cfg_attr(not(feature = "std"), no_std)]
#![allow(clippy::unused_unit)]
#![allow(clippy::large_enum_variant)]

use codec::{Decode, Encode, FullCodec};
use sp_runtime::traits::StaticLookup;

use frame_support::{traits::Get, weights::Weight, RuntimeDebug};
use module_support::CallBuilder;
use primitives::Balance;
use sp_std::{boxed::Box, marker::PhantomData, prelude::*, vec};

pub use cumulus_primitives_core::ParaId;
use xcm::latest::prelude::*;

use frame_system::Config;

#[derive(Encode, Decode, RuntimeDebug)]
pub enum BalancesCall<T: Config> {
#[codec(index = 3)]
TransferKeepAlive(<T::Lookup as StaticLookup>::Source, #[codec(compact)] Balance), /* TODO: because param type
* in relaychain is u64,
* need to confirm
* Balance(u128) is work. */
}

#[derive(Encode, Decode, RuntimeDebug)]
pub enum UtilityCall<RelayChainCall> {
#[codec(index = 1)]
AsDerivative(u16, RelayChainCall),
#[codec(index = 2)]
BatchAll(Vec<RelayChainCall>),
}

#[derive(Encode, Decode, RuntimeDebug)]
pub enum StakingCall {
#[codec(index = 1)]
BondExtra(#[codec(compact)] Balance), /* TODO: because param type in relaychain is u64, need to confirm
* Balance(u128) is work. */
#[codec(index = 2)]
Unbond(#[codec(compact)] Balance), /* TODO: because param type in relaychain is u64, need to confirm
* Balance(u128) is work. */
#[codec(index = 3)]
WithdrawUnbonded(u32),
}
use frame_support::traits::Get;
use sp_runtime::{traits::StaticLookup, RuntimeDebug};
use sp_std::{boxed::Box, marker::PhantomData, prelude::*};
use xcm::{prelude::*, v3::Weight as XcmWeight};

// #[cfg(feature = "with-pioneer-runtime")]
// #[cfg(feature = "kusama")]
// mod kusama {
// use crate::*;
use module_support::*;
use primitives::{AccountId, Balance};

/// The encoded index correspondes to Kusama's Runtime module configuration.
/// https://github.com/paritytech/polkadot/blob/444e96ae34bcec8362f0f947a07bd912b32ca48f/runtime/kusama/src/lib.rs#L1379
#[derive(Encode, Decode, RuntimeDebug)]
pub enum RelayChainCall<T: Config> {
pub enum KusamaRelayChainCall {
#[codec(index = 4)]
Balances(BalancesCall<T>),
Balances(BalancesCall),
#[codec(index = 6)]
Staking(StakingCall),
#[codec(index = 24)]
Utility(Box<UtilityCall<Self>>),
#[codec(index = 30)]
Proxy(Box<ProxyCall<Self>>),
#[codec(index = 99)]
XcmPallet(XcmCall),
}
// }

#[cfg(feature = "polkadot")]
mod polkadot {
use crate::*;

/// The encoded index correspondes to Polkadot's Runtime module configuration.
/// https://github.com/paritytech/polkadot/blob/84a3962e76151ac5ed3afa4ef1e0af829531ab42/runtime/polkadot/src/lib.rs#L1040
#[derive(Encode, Decode, RuntimeDebug)]
pub enum RelayChainCall<T: Config> {
#[codec(index = 5)]
Balances(BalancesCall<T>),
#[codec(index = 7)]
Staking(StakingCall),
#[codec(index = 26)]
Utility(Box<UtilityCall<Self>>),

impl RelayChainCall for KusamaRelayChainCall {
fn balances(call: BalancesCall) -> Self {
KusamaRelayChainCall::Balances(call)
}

fn staking(call: StakingCall) -> Self {
KusamaRelayChainCall::Staking(call)
}

fn utility(call: UtilityCall<Self>) -> Self {
KusamaRelayChainCall::Utility(Box::new(call))
}

fn proxy(call: ProxyCall<Self>) -> Self {
KusamaRelayChainCall::Proxy(Box::new(call))
}

fn xcm_pallet(call: XcmCall) -> Self {
KusamaRelayChainCall::XcmPallet(call)
}
}

// #[cfg(feature = "with-pioneer-runtime")]
// #[cfg(feature = "kusama")]
// pub use kusama::*;
/// The encoded index correspondes to Polkadot's Runtime module configuration.
/// https://github.com/paritytech/polkadot/blob/84a3962e76151ac5ed3afa4ef1e0af829531ab42/runtime/polkadot/src/lib.rs#L1040
#[derive(Encode, Decode, RuntimeDebug)]
pub enum PolkadotRelayChainCall {
#[codec(index = 5)]
Balances(BalancesCall),
#[codec(index = 7)]
Staking(StakingCall),
#[codec(index = 26)]
Utility(Box<UtilityCall<Self>>),
#[codec(index = 29)]
Proxy(Box<ProxyCall<Self>>),
#[codec(index = 99)]
XcmPallet(XcmCall),
}

impl RelayChainCall for PolkadotRelayChainCall {
fn balances(call: BalancesCall) -> Self {
PolkadotRelayChainCall::Balances(call)
}

fn staking(call: StakingCall) -> Self {
PolkadotRelayChainCall::Staking(call)
}

fn utility(call: UtilityCall<Self>) -> Self {
PolkadotRelayChainCall::Utility(Box::new(call))
}

fn proxy(call: ProxyCall<Self>) -> Self {
PolkadotRelayChainCall::Proxy(Box::new(call))
}

// #[cfg(feature = "polkadot")]
// pub use polkadot::*;
fn xcm_pallet(call: XcmCall) -> Self {
PolkadotRelayChainCall::XcmPallet(call)
}
}

pub struct RelayChainCallBuilder<T: Config, ParachainId: Get<ParaId>>(PhantomData<(T, ParachainId)>);
pub struct RelayChainCallBuilder<ParachainId, RCC>(PhantomData<(ParachainId, RCC)>);

impl<T: Config, ParachainId: Get<ParaId>> CallBuilder for RelayChainCallBuilder<T, ParachainId>
impl<ParachainId, RCC> CallBuilder for RelayChainCallBuilder<ParachainId, RCC>
where
T::AccountId: FullCodec,
RelayChainCall<T>: FullCodec,
ParachainId: Get<ParaId>,
RCC: RelayChainCall + FullCodec,
{
type AccountId = T::AccountId;
type AccountId = AccountId;
type Balance = Balance;
type RelayChainCall = RelayChainCall<T>;
type RelayChainCall = RCC;

fn utility_as_derivative_call(call: RCC, index: u16) -> RCC {
RCC::utility(UtilityCall::AsDerivative(index, call))
}

fn utility_batch_call(calls: Vec<Self::RelayChainCall>) -> Self::RelayChainCall {
RelayChainCall::Utility(Box::new(UtilityCall::BatchAll(calls)))
fn staking_bond_extra(amount: Self::Balance) -> RCC {
RCC::staking(StakingCall::BondExtra(amount))
}

fn utility_as_derivative_call(call: Self::RelayChainCall, index: u16) -> Self::RelayChainCall {
RelayChainCall::Utility(Box::new(UtilityCall::AsDerivative(index, call)))
fn staking_unbond(amount: Self::Balance) -> RCC {
RCC::staking(StakingCall::Unbond(amount))
}

fn staking_bond_extra(amount: Self::Balance) -> Self::RelayChainCall {
RelayChainCall::Staking(StakingCall::BondExtra(amount))
fn staking_withdraw_unbonded(num_slashing_spans: u32) -> RCC {
RCC::staking(StakingCall::WithdrawUnbonded(num_slashing_spans))
}

fn staking_unbond(amount: Self::Balance) -> Self::RelayChainCall {
RelayChainCall::Staking(StakingCall::Unbond(amount))
fn balances_transfer_keep_alive(to: Self::AccountId, amount: Self::Balance) -> RCC {
RCC::balances(BalancesCall::TransferKeepAlive(RelayChainLookup::unlookup(to), amount))
}

fn staking_withdraw_unbonded(num_slashing_spans: u32) -> Self::RelayChainCall {
RelayChainCall::Staking(StakingCall::WithdrawUnbonded(num_slashing_spans))
fn xcm_pallet_reserve_transfer_assets(
dest: MultiLocation,
beneficiary: MultiLocation,
assets: MultiAssets,
fee_assets_item: u32,
) -> RCC {
RCC::xcm_pallet(XcmCall::LimitedReserveTransferAssets(
dest.into_versioned(),
beneficiary.into_versioned(),
assets.into(),
fee_assets_item,
WeightLimit::Unlimited,
))
}

fn balances_transfer_keep_alive(to: Self::AccountId, amount: Self::Balance) -> Self::RelayChainCall {
RelayChainCall::Balances(BalancesCall::TransferKeepAlive(T::Lookup::unlookup(to), amount))
fn proxy_call(real: Self::AccountId, call: RCC) -> RCC {
RCC::proxy(ProxyCall::Proxy(RelayChainLookup::unlookup(real), None, call))
}

fn finalize_call_into_xcm_message(call: Self::RelayChainCall, extra_fee: Self::Balance, weight: Weight) -> Xcm<()> {
fn finalize_call_into_xcm_message(call: RCC, extra_fee: Self::Balance, weight: XcmWeight) -> Xcm<()> {
let asset = MultiAsset {
id: Concrete(MultiLocation::here()),
fun: Fungibility::Fungible(extra_fee),
Expand All @@ -158,14 +176,52 @@ where
require_weight_at_most: weight,
call: call.encode().into(),
},
RefundSurplus,
DepositAsset {
assets: All.into(),
//max_assets: u32::max_value(),
assets: AllCounted(1).into(), // there is only 1 asset on relaychain
beneficiary: MultiLocation {
parents: 0,
interior: X1(Parachain(ParachainId::get().into())),
},
},
])
}

fn finalize_multiple_calls_into_xcm_message(calls: Vec<(RCC, XcmWeight)>, extra_fee: Self::Balance) -> Xcm<()> {
let asset = MultiAsset {
id: Concrete(MultiLocation::here()),
fun: Fungibility::Fungible(extra_fee),
};

let transacts = calls
.iter()
.map(|(call, weight)| Transact {
origin_kind: OriginKind::SovereignAccount,
require_weight_at_most: *weight,
call: call.encode().into(),
})
.collect();

Xcm([
vec![
WithdrawAsset(asset.clone().into()),
BuyExecution {
fees: asset,
weight_limit: Unlimited,
},
],
transacts,
vec![
RefundSurplus,
DepositAsset {
assets: AllCounted(1).into(), // there is only 1 asset on relaychain
beneficiary: MultiLocation {
parents: 0,
interior: X1(Parachain(ParachainId::get().into())),
},
},
],
]
.concat())
}
}
Loading