diff --git a/polkadot/xcm/pallet-xcm/src/lib.rs b/polkadot/xcm/pallet-xcm/src/lib.rs index 37cc7df81b11b..d4392fb514561 100644 --- a/polkadot/xcm/pallet-xcm/src/lib.rs +++ b/polkadot/xcm/pallet-xcm/src/lib.rs @@ -97,6 +97,8 @@ pub trait WeightInfo { fn new_query() -> Weight; fn take_response() -> Weight; fn claim_assets() -> Weight; + fn add_authorized_alias() -> Weight; + fn remove_authorized_alias() -> Weight; } /// fallback implementation @@ -181,6 +183,14 @@ impl WeightInfo for TestWeightInfo { fn claim_assets() -> Weight { Weight::from_parts(100_000_000, 0) } + + fn add_authorized_alias() -> Weight { + Weight::from_parts(100_000, 0) + } + + fn remove_authorized_alias() -> Weight { + Weight::from_parts(100_000, 0) + } } #[frame_support::pallet] @@ -199,6 +209,9 @@ pub mod pallet { /// An implementation of `Get` which just returns the latest XCM version which we can /// support. pub const CurrentXcmVersion: u32 = XCM_VERSION; + + /// The maximum number of distinct locations allowed as authorized aliases for a local origin. + pub const MaxAuthorizedAliases: u32 = 10; } const STORAGE_VERSION: StorageVersion = StorageVersion::new(1); @@ -574,6 +587,9 @@ pub mod pallet { /// Local XCM execution incomplete. #[codec(index = 24)] LocalExecutionIncomplete, + /// Too many locations authorized to alias origin. + #[codec(index = 25)] + TooManyAuthorizedAliases, } impl From for Error { @@ -793,6 +809,17 @@ pub mod pallet { #[pallet::storage] pub(crate) type RecordedXcm = StorageValue<_, Xcm<()>>; + /// Map of authorized aliasers of local origins. Each local location can authorize a list of + /// other locations to alias into it. + #[pallet::storage] + pub(super) type AuthorizedAliases = StorageMap< + _, + Blake2_128Concat, + Location, + BoundedVec, + ValueQuery, + >; + #[pallet::genesis_config] pub struct GenesisConfig { #[serde(skip)] @@ -1425,6 +1452,51 @@ pub mod pallet { weight_limit, ) } + + /// Authorize another `aliaser` location to alias into the local `origin` making this call. + /// + /// Usually useful to allow your local account to be aliased into from a remote location + /// also under your control (like your account on another chain). + /// + /// WARNING: make sure the caller `origin` (you) trusts the `aliaser` location to act in + /// their/your name. Once authorized using this call, the `aliaser` can freely impersonate + /// `origin` in XCM programs executed on the local chain. + #[pallet::call_index(14)] + pub fn add_authorized_alias( + origin: OriginFor, + aliaser: Box, + ) -> DispatchResult { + let origin = T::ExecuteXcmOrigin::ensure_origin(origin)?; + let aliaser = (*aliaser).try_into().map_err(|()| Error::::BadVersion)?; + ensure!(origin != aliaser, Error::::BadLocation); + let mut authorized_aliases = AuthorizedAliases::::get(&origin); + if !authorized_aliases.contains(&aliaser) { + authorized_aliases + .try_push(aliaser) + .map_err(|_| Error::::TooManyAuthorizedAliases)?; + AuthorizedAliases::::insert(&origin, authorized_aliases); + } + Ok(()) + } + + /// Remove a previously authorized `aliaser` from the list of locations that can alias into + /// the local `origin` making this call. + #[pallet::call_index(15)] + pub fn remove_authorized_alias( + origin: OriginFor, + aliaser: Box, + ) -> DispatchResult { + let origin = T::ExecuteXcmOrigin::ensure_origin(origin)?; + let to_remove = (*aliaser).try_into().map_err(|()| Error::::BadVersion)?; + ensure!(origin != to_remove, Error::::BadLocation); + let mut authorized_aliases = AuthorizedAliases::::get(&origin); + let original_length = authorized_aliases.len(); + authorized_aliases.retain(|alias| to_remove.ne(alias)); + if original_length != authorized_aliases.len() { + AuthorizedAliases::::insert(&origin, authorized_aliases); + } + Ok(()) + } } } @@ -3432,12 +3504,12 @@ where /// Filter for `(origin: Location, target: Location)` to find whether `target` has explicitly /// authorized `origin` to alias it. /// -/// TODO: how to authorize?. -pub struct AuthorizedAliases; -impl ContainsPair for AuthorizedAliases { +/// Note: users can authorize other locations to alias them by using +/// `pallet_xcm::add_authorized_alias()`. +pub struct AuthorizedAliases(PhantomData); +impl ContainsPair for AuthorizedAliases { fn contains(origin: &Location, target: &Location) -> bool { - // TODO: use storage - return false + pallet::AuthorizedAliases::::get(&origin).contains(target) } }