Newer
Older
// Copyright 2020-2021 Parity Technologies (UK) Ltd.
// This file is part of Polkadot.
// Polkadot 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.
// Polkadot 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 <http://www.gnu.org/licenses/>.
//! Pallet to handle XCM messages.
#![cfg_attr(not(feature = "std"), no_std)]
#[cfg(test)]
mod mock;
#[cfg(test)]
mod tests;
use codec::{Decode, Encode, EncodeLike, MaxEncodedLen};
use frame_support::traits::{Contains, EnsureOrigin, Get, OriginTrait};
use scale_info::TypeInfo;
use sp_runtime::{
traits::{BadOrigin, Saturating},
RuntimeDebug,
};
use sp_std::{boxed::Box, marker::PhantomData, prelude::*, result::Result, vec};
use xcm::{latest::Weight as XcmWeight, prelude::*};
use xcm_executor::traits::ConvertOrigin;
use frame_support::PalletId;
#[frame_support::pallet]
pub mod pallet {
use super::*;
Gavin Wood
committed
use frame_support::{
dispatch::{Dispatchable, GetDispatchInfo, PostDispatchInfo},
pallet_prelude::*,
Gavin Wood
committed
};
use frame_system::{pallet_prelude::*, Config as SysConfig};
use sp_core::H256;
use sp_runtime::traits::{AccountIdConversion, BlakeTwo256, BlockNumberProvider, Hash};
use xcm_executor::{
traits::{
ClaimAssets, DropAssets, InvertLocation, OnResponse, VersionChangeNotifier,
WeightBounds,
},
parameter_types! {
/// An implementation of `Get<u32>` which just returns the latest XCM version which we can
/// support.
pub const CurrentXcmVersion: u32 = XCM_VERSION;
}
#[pallet::pallet]
#[pallet::generate_store(pub(super) trait Store)]
#[pallet::without_storage_info]
pub struct Pallet<T>(_);
#[pallet::config]
/// The module configuration trait.
pub trait Config: frame_system::Config {
/// The overarching event type.
type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
/// Required origin for sending XCM messages. If successful, it resolves to `MultiLocation`
/// which exists as an interior location within this chain's XCM context.
type SendXcmOrigin: EnsureOrigin<
<Self as SysConfig>::RuntimeOrigin,
Success = MultiLocation,
>;
/// The type used to actually dispatch an XCM to its destination.
type XcmRouter: SendXcm;
/// Required origin for executing XCM messages, including the teleport functionality. If successful,
/// then it resolves to `MultiLocation` which exists as an interior location within this chain's XCM
type ExecuteXcmOrigin: EnsureOrigin<
<Self as SysConfig>::RuntimeOrigin,
Success = MultiLocation,
>;
/// Our XCM filter which messages to be executed using `XcmExecutor` must pass.
type XcmExecuteFilter: Contains<(MultiLocation, Xcm<<Self as SysConfig>::RuntimeCall>)>;
type XcmExecutor: ExecuteXcm<<Self as SysConfig>::RuntimeCall>;
/// Our XCM filter which messages to be teleported using the dedicated extrinsic must pass.
type XcmTeleportFilter: Contains<(MultiLocation, Vec<MultiAsset>)>;
/// Our XCM filter which messages to be reserve-transferred using the dedicated extrinsic must pass.
type XcmReserveTransferFilter: Contains<(MultiLocation, Vec<MultiAsset>)>;
/// Means of measuring the weight consumed by an XCM message locally.
type Weigher: WeightBounds<<Self as SysConfig>::RuntimeCall>;
/// Means of inverting a location.
type LocationInverter: InvertLocation;
Gavin Wood
committed
/// The outer `Origin` type.
type RuntimeOrigin: From<Origin> + From<<Self as SysConfig>::RuntimeOrigin>;
Gavin Wood
committed
/// The outer `Call` type.
Gavin Wood
committed
+ GetDispatchInfo
+ IsType<<Self as frame_system::Config>::RuntimeCall>
+ Dispatchable<
RuntimeOrigin = <Self as Config>::RuntimeOrigin,
PostInfo = PostDispatchInfo,
>;
const VERSION_DISCOVERY_QUEUE_SIZE: u32;
/// The latest supported version that we advertise. Generally just set it to
/// `pallet_xcm::CurrentXcmVersion`.
type AdvertisedXcmVersion: Get<XcmVersion>;
/// The maximum number of distinct assets allowed to be transferred in a single helper extrinsic.
const MAX_ASSETS_FOR_TRANSFER: usize = 2;
#[pallet::event]
#[pallet::generate_deposit(pub(super) fn deposit_event)]
pub enum Event<T: Config> {
Gavin Wood
committed
/// Execution of an XCM message was attempted.
///
/// \[ outcome \]
Gavin Wood
committed
/// A XCM message was sent.
///
/// \[ origin, destination, message \]
Sent(MultiLocation, MultiLocation, Xcm<()>),
Gavin Wood
committed
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
/// Query response received which does not match a registered query. This may be because a
/// matching query was never registered, it may be because it is a duplicate response, or
/// because the query timed out.
///
/// \[ origin location, id \]
UnexpectedResponse(MultiLocation, QueryId),
/// Query response has been received and is ready for taking with `take_response`. There is
/// no registered notification call.
///
/// \[ id, response \]
ResponseReady(QueryId, Response),
/// Query response has been received and query is removed. The registered notification has
/// been dispatched and executed successfully.
///
/// \[ id, pallet index, call index \]
Notified(QueryId, u8, u8),
/// Query response has been received and query is removed. The registered notification could
/// not be dispatched because the dispatch weight is greater than the maximum weight
/// originally budgeted by this runtime for the query result.
///
/// \[ id, pallet index, call index, actual weight, max budgeted weight \]
NotifyOverweight(QueryId, u8, u8, Weight, Weight),
/// Query response has been received and query is removed. There was a general error with
/// dispatching the notification call.
///
/// \[ id, pallet index, call index \]
NotifyDispatchError(QueryId, u8, u8),
/// Query response has been received and query is removed. The dispatch was unable to be
/// decoded into a `Call`; this might be due to dispatch function having a signature which
/// is not `(origin, QueryId, Response)`.
///
/// \[ id, pallet index, call index \]
NotifyDecodeFailed(QueryId, u8, u8),
/// Expected query response has been received but the origin location of the response does
/// not match that expected. The query remains registered for a later, valid, response to
/// be received and acted upon.
///
/// \[ origin location, id, expected location \]
InvalidResponder(MultiLocation, QueryId, Option<MultiLocation>),
Gavin Wood
committed
/// Expected query response has been received but the expected origin location placed in
/// storage by this runtime previously cannot be decoded. The query remains registered.
Gavin Wood
committed
///
/// This is unexpected (since a location placed in storage in a previously executing
/// runtime should be readable prior to query timeout) and dangerous since the possibly
/// valid response will be dropped. Manual governance intervention is probably going to be
/// needed.
///
/// \[ origin location, id \]
InvalidResponderVersion(MultiLocation, QueryId),
/// Received query response has been read and removed.
///
/// \[ id \]
ResponseTaken(QueryId),
/// Some assets have been placed in an asset trap.
///
/// \[ hash, origin, assets \]
Loading full blame...