// Copyright 2020 Parity Technologies (UK) Ltd.
// This file is part of Polkadot.
// Substrate 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.
// Substrate 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 Polkadot. If not, see .
//! Cross-Consensus Message format data structures.
// NOTE, this crate is meant to be used in many different environments, notably wasm, but not
// necessarily related to FRAME or even Substrate.
//
// Hence, `no_std` rather than sp-runtime.
#![no_std]
extern crate alloc;
use alloc::vec::Vec;
use core::{
convert::{TryFrom, TryInto},
result::Result,
};
use derivative::Derivative;
use parity_scale_codec::{Decode, Encode, Error as CodecError, Input};
pub mod v0;
pub mod v1;
pub mod v2;
pub mod latest {
pub use super::v2::*;
}
mod double_encoded;
pub use double_encoded::DoubleEncoded;
/// Maximum nesting level for XCM decoding.
pub const MAX_XCM_DECODE_DEPTH: u32 = 8;
#[derive(Clone, Eq, PartialEq, Debug)]
pub enum Unsupported {}
impl Encode for Unsupported {}
impl Decode for Unsupported {
fn decode(_: &mut I) -> Result {
Err("Not decodable".into())
}
}
/// A single `MultiLocation` value, together with its version code.
#[derive(Derivative, Encode, Decode)]
#[derivative(Clone(bound = ""), Eq(bound = ""), PartialEq(bound = ""), Debug(bound = ""))]
#[codec(encode_bound())]
#[codec(decode_bound())]
pub enum VersionedMultiLocation {
V0(v0::MultiLocation),
V1(v1::MultiLocation),
}
impl From for VersionedMultiLocation {
fn from(x: v0::MultiLocation) -> Self {
VersionedMultiLocation::V0(x)
}
}
impl> From for VersionedMultiLocation {
fn from(x: T) -> Self {
VersionedMultiLocation::V1(x.into())
}
}
impl TryFrom for v0::MultiLocation {
type Error = ();
fn try_from(x: VersionedMultiLocation) -> Result {
use VersionedMultiLocation::*;
match x {
V0(x) => Ok(x),
V1(x) => x.try_into(),
}
}
}
impl TryFrom for v1::MultiLocation {
type Error = ();
fn try_from(x: VersionedMultiLocation) -> Result {
use VersionedMultiLocation::*;
match x {
V0(x) => x.try_into(),
V1(x) => Ok(x),
}
}
}
/// A single `Response` value, together with its version code.
#[derive(Derivative, Encode, Decode)]
#[derivative(Clone(bound = ""), Eq(bound = ""), PartialEq(bound = ""), Debug(bound = ""))]
#[codec(encode_bound())]
#[codec(decode_bound())]
pub enum VersionedResponse {
V0(v0::Response),
V1(v1::Response),
V2(v2::Response),
}
impl From for VersionedResponse {
fn from(x: v0::Response) -> Self {
VersionedResponse::V0(x)
}
}
impl From for VersionedResponse {
fn from(x: v1::Response) -> Self {
VersionedResponse::V1(x)
}
}
impl> From for VersionedResponse {
fn from(x: T) -> Self {
VersionedResponse::V2(x.into())
}
}
impl TryFrom for v0::Response {
type Error = ();
fn try_from(x: VersionedResponse) -> Result {
use VersionedResponse::*;
match x {
V0(x) => Ok(x),
V1(x) => x.try_into(),
V2(x) => VersionedResponse::V1(x.try_into()?).try_into(),
}
}
}
impl TryFrom for v1::Response {
type Error = ();
fn try_from(x: VersionedResponse) -> Result {
use VersionedResponse::*;
match x {
V0(x) => x.try_into(),
V1(x) => Ok(x),
V2(x) => x.try_into(),
}
}
}
impl TryFrom for v2::Response {
type Error = ();
fn try_from(x: VersionedResponse) -> Result {
use VersionedResponse::*;
match x {
V0(x) => VersionedResponse::V1(x.try_into()?).try_into(),
V1(x) => x.try_into(),
V2(x) => Ok(x),
}
}
}
/// A single `MultiAsset` value, together with its version code.
#[derive(Derivative, Encode, Decode)]
#[derivative(Clone(bound = ""), Eq(bound = ""), PartialEq(bound = ""), Debug(bound = ""))]
#[codec(encode_bound())]
#[codec(decode_bound())]
pub enum VersionedMultiAsset {
V0(v0::MultiAsset),
V1(v1::MultiAsset),
}
impl From for VersionedMultiAsset {
fn from(x: v0::MultiAsset) -> Self {
VersionedMultiAsset::V0(x)
}
}
impl> From for VersionedMultiAsset {
fn from(x: T) -> Self {
VersionedMultiAsset::V1(x.into())
}
}
impl TryFrom for v0::MultiAsset {
type Error = ();
fn try_from(x: VersionedMultiAsset) -> Result {
use VersionedMultiAsset::*;
match x {
V0(x) => Ok(x),
V1(x) => x.try_into(),
}
}
}
impl TryFrom for v1::MultiAsset {
type Error = ();
fn try_from(x: VersionedMultiAsset) -> Result {
use VersionedMultiAsset::*;
match x {
V0(x) => x.try_into(),
V1(x) => Ok(x),
}
}
}
/// A single `MultiAssets` value, together with its version code.
#[derive(Derivative, Encode, Decode)]
#[derivative(Clone(bound = ""), Eq(bound = ""), PartialEq(bound = ""), Debug(bound = ""))]
#[codec(encode_bound())]
#[codec(decode_bound())]
pub enum VersionedMultiAssets {
V0(Vec),
V1(v1::MultiAssets),
}
impl VersionedMultiAssets {
pub fn into_version(self, n: u32) -> Result {
Ok(match n {
0 => Self::V0(self.try_into()?),
1 | 2 => Self::V1(self.try_into()?),
_ => return Err(()),
})
}
}
impl From> for VersionedMultiAssets {
fn from(x: Vec) -> Self {
VersionedMultiAssets::V0(x)
}
}
impl> From for VersionedMultiAssets {
fn from(x: T) -> Self {
VersionedMultiAssets::V1(x.into())
}
}
impl TryFrom for Vec {
type Error = ();
fn try_from(x: VersionedMultiAssets) -> Result {
use VersionedMultiAssets::*;
match x {
V0(x) => Ok(x),
V1(x) => x.try_into(),
}
}
}
impl TryFrom for v1::MultiAssets {
type Error = ();
fn try_from(x: VersionedMultiAssets) -> Result {
use VersionedMultiAssets::*;
match x {
V0(x) => x.try_into(),
V1(x) => Ok(x),
}
}
}
/// A single XCM message, together with its version code.
#[derive(Derivative, Encode, Decode)]
#[derivative(Clone(bound = ""), Eq(bound = ""), PartialEq(bound = ""), Debug(bound = ""))]
#[codec(encode_bound())]
#[codec(decode_bound())]
pub enum VersionedXcm {
V0(v0::Xcm),
V1(v1::Xcm),
V2(v2::Xcm),
}
impl From> for VersionedXcm {
fn from(x: v0::Xcm) -> Self {
VersionedXcm::V0(x)
}
}
impl From> for VersionedXcm {
fn from(x: v1::Xcm) -> Self {
VersionedXcm::V1(x)
}
}
impl From> for VersionedXcm {
fn from(x: v2::Xcm) -> Self {
VersionedXcm::V2(x)
}
}
impl TryFrom> for v0::Xcm {
type Error = ();
fn try_from(x: VersionedXcm) -> Result {
use VersionedXcm::*;
match x {
V0(x) => Ok(x),
V1(x) => x.try_into(),
V2(x) => V1(x.try_into()?).try_into(),
}
}
}
impl TryFrom> for v1::Xcm {
type Error = ();
fn try_from(x: VersionedXcm) -> Result {
use VersionedXcm::*;
match x {
V0(x) => x.try_into(),
V1(x) => Ok(x),
V2(x) => x.try_into(),
}
}
}
impl TryFrom> for v2::Xcm {
type Error = ();
fn try_from(x: VersionedXcm) -> Result {
use VersionedXcm::*;
match x {
V0(x) => V1(x.try_into()?).try_into(),
V1(x) => x.try_into(),
V2(x) => Ok(x),
}
}
}
/// Convert an `Xcm` datum into a `VersionedXcm`, based on a destination `MultiLocation` which will interpret it.
pub trait WrapVersion {
fn wrap_version(
dest: &latest::MultiLocation,
xcm: impl Into>,
) -> Result, ()>;
}
/// `()` implementation does nothing with the XCM, just sending with whatever version it was authored as.
impl WrapVersion for () {
fn wrap_version(
_: &latest::MultiLocation,
xcm: impl Into>,
) -> Result, ()> {
Ok(xcm.into())
}
}
/// `WrapVersion` implementation which attempts to always convert the XCM to version 0 before wrapping it.
pub struct AlwaysV0;
impl WrapVersion for AlwaysV0 {
fn wrap_version(
_: &latest::MultiLocation,
xcm: impl Into>,
) -> Result, ()> {
Ok(VersionedXcm::::V0(xcm.into().try_into()?))
}
}
/// `WrapVersion` implementation which attempts to always convert the XCM to version 1 before wrapping it.
pub struct AlwaysV1;
impl WrapVersion for AlwaysV1 {
fn wrap_version(
_: &latest::MultiLocation,
xcm: impl Into>,
) -> Result, ()> {
Ok(VersionedXcm::::V1(xcm.into().try_into()?))
}
}
/// `WrapVersion` implementation which attempts to always convert the XCM to version 1 before wrapping it.
pub struct AlwaysV2;
impl WrapVersion for AlwaysV2 {
fn wrap_version(
_: &latest::MultiLocation,
xcm: impl Into>,
) -> Result, ()> {
Ok(VersionedXcm::::V2(xcm.into().try_into()?))
}
}
/// `WrapVersion` implementation which attempts to always convert the XCM to the latest version before wrapping it.
pub type AlwaysLatest = AlwaysV1;
/// `WrapVersion` implementation which attempts to always convert the XCM to the release version before wrapping it.
pub type AlwaysRelease = AlwaysV0;
pub mod opaque {
pub mod v0 {
// Everything from v0
pub use crate::v0::*;
// Then override with the opaque types in v0
pub use crate::v0::opaque::{Order, Xcm};
}
pub mod v1 {
// Everything from v1
pub use crate::v1::*;
// Then override with the opaque types in v1
pub use crate::v1::opaque::{Order, Xcm};
}
pub mod v2 {
// Everything from v1
pub use crate::v2::*;
// Then override with the opaque types in v2
pub use crate::v2::opaque::{Instruction, Xcm};
}
pub mod latest {
pub use super::v2::*;
}
/// The basic `VersionedXcm` type which just uses the `Vec` as an encoded call.
pub type VersionedXcm = super::VersionedXcm<()>;
}