#![no_std]
extern crate alloc;
use derivative::Derivative;
use parity_scale_codec::{Decode, Encode, Error as CodecError, Input, MaxEncodedLen};
use scale_info::TypeInfo;
pub mod v2;
pub mod v3;
pub mod lts {
pub use super::v3::*;
}
pub mod latest {
pub use super::v3::*;
}
mod double_encoded;
pub use double_encoded::DoubleEncoded;
#[cfg(test)]
mod tests;
pub const MAX_XCM_DECODE_DEPTH: u32 = 8;
pub type Version = u32;
#[derive(Clone, Eq, PartialEq, Debug)]
pub enum Unsupported {}
impl Encode for Unsupported {}
impl Decode for Unsupported {
fn decode<I: Input>(_: &mut I) -> Result<Self, CodecError> {
Err("Not decodable".into())
}
}
pub trait IntoVersion: Sized {
fn into_version(self, version: Version) -> Result<Self, ()>;
fn into_latest(self) -> Result<Self, ()> {
self.into_version(latest::VERSION)
}
}
pub trait TryAs<T> {
fn try_as(&self) -> Result<&T, ()>;
}
macro_rules! versioned_type {
($(#[$attr:meta])* pub enum $n:ident {
$(#[$index3:meta])+
V3($v3:ty),
}) => {
#[derive(Derivative, Encode, Decode, TypeInfo)]
#[derivative(
Clone(bound = ""),
Eq(bound = ""),
PartialEq(bound = ""),
Debug(bound = "")
)]
#[codec(encode_bound())]
#[codec(decode_bound())]
$(#[$attr])*
pub enum $n {
$(#[$index3])*
V3($v3),
}
impl $n {
pub fn try_as<T>(&self) -> Result<&T, ()> where Self: TryAs<T> {
<Self as TryAs<T>>::try_as(&self)
}
}
impl TryAs<$v3> for $n {
fn try_as(&self) -> Result<&$v3, ()> {
match &self {
Self::V3(ref x) => Ok(x),
}
}
}
impl IntoVersion for $n {
fn into_version(self, n: Version) -> Result<Self, ()> {
Ok(match n {
3 => Self::V3(self.try_into()?),
_ => return Err(()),
})
}
}
impl<T: Into<$v3>> From<T> for $n {
fn from(x: T) -> Self {
$n::V3(x.into())
}
}
impl TryFrom<$n> for $v3 {
type Error = ();
fn try_from(x: $n) -> Result<Self, ()> {
use $n::*;
match x {
V3(x) => Ok(x),
}
}
}
impl MaxEncodedLen for $n {
fn max_encoded_len() -> usize {
<$v3>::max_encoded_len()
}
}
};
($(#[$attr:meta])* pub enum $n:ident {
$(#[$index2:meta])+
V2($v2:ty),
$(#[$index3:meta])+
V3($v3:ty),
}) => {
#[derive(Derivative, Encode, Decode, TypeInfo)]
#[derivative(
Clone(bound = ""),
Eq(bound = ""),
PartialEq(bound = ""),
Debug(bound = "")
)]
#[codec(encode_bound())]
#[codec(decode_bound())]
$(#[$attr])*
pub enum $n {
$(#[$index2])*
V2($v2),
$(#[$index3])*
V3($v3),
}
impl $n {
pub fn try_as<T>(&self) -> Result<&T, ()> where Self: TryAs<T> {
<Self as TryAs<T>>::try_as(&self)
}
}
impl TryAs<$v2> for $n {
fn try_as(&self) -> Result<&$v2, ()> {
match &self {
Self::V2(ref x) => Ok(x),
_ => Err(()),
}
}
}
impl TryAs<$v3> for $n {
fn try_as(&self) -> Result<&$v3, ()> {
match &self {
Self::V3(ref x) => Ok(x),
_ => Err(()),
}
}
}
impl IntoVersion for $n {
fn into_version(self, n: Version) -> Result<Self, ()> {
Ok(match n {
1 | 2 => Self::V2(self.try_into()?),
3 => Self::V3(self.try_into()?),
_ => return Err(()),
})
}
}
impl From<$v2> for $n {
fn from(x: $v2) -> Self {
$n::V2(x)
}
}
impl<T: Into<$v3>> From<T> for $n {
fn from(x: T) -> Self {
$n::V3(x.into())
}
}
impl TryFrom<$n> for $v2 {
type Error = ();
fn try_from(x: $n) -> Result<Self, ()> {
use $n::*;
match x {
V2(x) => Ok(x),
V3(x) => x.try_into(),
}
}
}
impl TryFrom<$n> for $v3 {
type Error = ();
fn try_from(x: $n) -> Result<Self, ()> {
use $n::*;
match x {
V2(x) => x.try_into(),
V3(x) => Ok(x),
}
}
}
impl MaxEncodedLen for $n {
fn max_encoded_len() -> usize {
<$v3>::max_encoded_len()
}
}
};
}
versioned_type! {
pub enum VersionedAssetId {
#[codec(index = 3)]
V3(v3::AssetId),
}
}
versioned_type! {
pub enum VersionedResponse {
#[codec(index = 2)]
V2(v2::Response),
#[codec(index = 3)]
V3(v3::Response),
}
}
versioned_type! {
pub enum VersionedNetworkId {
#[codec(index = 2)]
V2(v2::NetworkId),
#[codec(index = 3)]
V3(v3::NetworkId),
}
}
versioned_type! {
pub enum VersionedJunction {
#[codec(index = 2)]
V2(v2::Junction),
#[codec(index = 3)]
V3(v3::Junction),
}
}
versioned_type! {
#[derive(Ord, PartialOrd)]
pub enum VersionedMultiLocation {
#[codec(index = 1)] V2(v2::MultiLocation),
#[codec(index = 3)]
V3(v3::MultiLocation),
}
}
versioned_type! {
pub enum VersionedInteriorMultiLocation {
#[codec(index = 2)] V2(v2::InteriorMultiLocation),
#[codec(index = 3)]
V3(v3::InteriorMultiLocation),
}
}
versioned_type! {
pub enum VersionedMultiAsset {
#[codec(index = 1)] V2(v2::MultiAsset),
#[codec(index = 3)]
V3(v3::MultiAsset),
}
}
versioned_type! {
pub enum VersionedMultiAssets {
#[codec(index = 1)] V2(v2::MultiAssets),
#[codec(index = 3)]
V3(v3::MultiAssets),
}
}
#[derive(Derivative, Encode, Decode, TypeInfo)]
#[derivative(Clone(bound = ""), Eq(bound = ""), PartialEq(bound = ""), Debug(bound = ""))]
#[codec(encode_bound())]
#[codec(decode_bound())]
#[scale_info(bounds(), skip_type_params(RuntimeCall))]
pub enum VersionedXcm<RuntimeCall> {
#[codec(index = 2)]
V2(v2::Xcm<RuntimeCall>),
#[codec(index = 3)]
V3(v3::Xcm<RuntimeCall>),
}
impl<C> IntoVersion for VersionedXcm<C> {
fn into_version(self, n: Version) -> Result<Self, ()> {
Ok(match n {
2 => Self::V2(self.try_into()?),
3 => Self::V3(self.try_into()?),
_ => return Err(()),
})
}
}
impl<RuntimeCall> From<v2::Xcm<RuntimeCall>> for VersionedXcm<RuntimeCall> {
fn from(x: v2::Xcm<RuntimeCall>) -> Self {
VersionedXcm::V2(x)
}
}
impl<RuntimeCall> From<v3::Xcm<RuntimeCall>> for VersionedXcm<RuntimeCall> {
fn from(x: v3::Xcm<RuntimeCall>) -> Self {
VersionedXcm::V3(x)
}
}
impl<RuntimeCall> TryFrom<VersionedXcm<RuntimeCall>> for v2::Xcm<RuntimeCall> {
type Error = ();
fn try_from(x: VersionedXcm<RuntimeCall>) -> Result<Self, ()> {
use VersionedXcm::*;
match x {
V2(x) => Ok(x),
V3(x) => x.try_into(),
}
}
}
impl<Call> TryFrom<VersionedXcm<Call>> for v3::Xcm<Call> {
type Error = ();
fn try_from(x: VersionedXcm<Call>) -> Result<Self, ()> {
use VersionedXcm::*;
match x {
V2(x) => x.try_into(),
V3(x) => Ok(x),
}
}
}
pub trait WrapVersion {
fn wrap_version<RuntimeCall>(
dest: &latest::MultiLocation,
xcm: impl Into<VersionedXcm<RuntimeCall>>,
) -> Result<VersionedXcm<RuntimeCall>, ()>;
}
impl WrapVersion for () {
fn wrap_version<RuntimeCall>(
_: &latest::MultiLocation,
xcm: impl Into<VersionedXcm<RuntimeCall>>,
) -> Result<VersionedXcm<RuntimeCall>, ()> {
Ok(xcm.into())
}
}
pub struct AlwaysV2;
impl WrapVersion for AlwaysV2 {
fn wrap_version<RuntimeCall>(
_: &latest::MultiLocation,
xcm: impl Into<VersionedXcm<RuntimeCall>>,
) -> Result<VersionedXcm<RuntimeCall>, ()> {
Ok(VersionedXcm::<RuntimeCall>::V2(xcm.into().try_into()?))
}
}
pub struct AlwaysV3;
impl WrapVersion for AlwaysV3 {
fn wrap_version<Call>(
_: &latest::MultiLocation,
xcm: impl Into<VersionedXcm<Call>>,
) -> Result<VersionedXcm<Call>, ()> {
Ok(VersionedXcm::<Call>::V3(xcm.into().try_into()?))
}
}
pub type AlwaysLatest = AlwaysV3;
pub type AlwaysLts = AlwaysV3;
pub mod prelude {
pub use super::{
latest::prelude::*, AlwaysLatest, AlwaysLts, AlwaysV2, AlwaysV3, IntoVersion, Unsupported,
Version as XcmVersion, VersionedAssetId, VersionedInteriorMultiLocation,
VersionedMultiAsset, VersionedMultiAssets, VersionedMultiLocation, VersionedResponse,
VersionedXcm, WrapVersion,
};
}
pub mod opaque {
pub mod v2 {
pub use crate::v2::*;
pub use crate::v2::opaque::{Instruction, Xcm};
}
pub mod v3 {
pub use crate::v3::*;
pub use crate::v3::opaque::{Instruction, Xcm};
}
pub mod latest {
pub use super::v3::*;
}
pub mod lts {
pub use super::v3::*;
}
pub type VersionedXcm = super::VersionedXcm<()>;
}
pub trait GetWeight<W> {
fn weight(&self) -> latest::Weight;
}
#[test]
fn conversion_works() {
use latest::prelude::*;
let _: VersionedMultiAssets = (Here, 1u128).into();
}