XCM Workshop

Students will first go through, learn, and use all the fundamental building blocks for XCM:

  1. Location / Topography
    • Learn how to construct relative and absolute locations for common objects and types used in XCM.
  2. Assets and Filters
    • Learn how to represent various types of assets like fungible tokens and non-fungible tokens.
    • Constructing asset filters to target pools of assets.
  3. Asset Holding
    • Learn how we can manage multiple assets in memory using the AssetsInHolding abstraction.
  4. Instructions
    • Construct common XCM messages through individual XCM instructions.
  5. The XCM Executor
    • Learn how the XCM Executor actually functions, and loosely implement a few common instructions needed to complete end to end scenarios.
  6. Pallet XCM
    • Learn how Pallet XCM provides a simple to access wrapper to the underlying XCM Executor to perform common tasks like send, execute, and teleport transfers.

Prerequisite Knowledge

Before we can even start teaching the low level concepts of XCM, we need to provide some high level knowledge about Polkadot, cross consensus messages, and tokens, and more...

Parachains

Truthfully, we cannot in fine detail go over Polkadot and Parachains in this workshop. That would be its own educational endeavour.

However, for the context of understanding common end to end scenarios that we will try to cover in this XCM Workshop, you will need to have a basic understanding of Parachains in the Polkadot Ecosystem.

System Parachains

Polkadot uses parachains to scale itself through the creation of "system parachains".

System parachains use the same parachain technology stack used to create and secure self-sovereign parachains. But in this case, rather than these parachains being their own sovereign entity,

A very relevant example of this is the Asset Hub. This is a System Parachain for

Transfers

We can argue that one of the native operations of any blockchain is to transfer assets and keep track of the ownership of those assets. Within a single consensus system, this is a solved problem.

However, in a multi-chain, multi-token, multi-consensus ecosystem, this is a problem still being solved.

Within the XCM world, we have established two different kinds of transfers which can be used across consensus systems, and based on their trust assumptions.

Teleport Transfers

In high trust scenarios, we

Teleport:

Destroying an asset (or amount of funds/token/currency) in one place and minting a corresponding amount in a second place. Imagine the teleporter from Star Trek. The two places need not be equivalent in nature (e.g. could be a UTXO chain that destroys assets and an account-based chain that mints them). Neither place acts as a reserve or derivative for the other. Though the nature of the tokens may be different, neither place is more canonical than the other. This is only possible if there is a bilateral trust relationship both of the STF and the validity/finality/availability between them.

Reserved Backed Transfers

XCM

Principles

XCM is designed around four 'A's:

  • Asynchronous: XCM messages in no way assume that the sender will be blocking on its completion.
  • Absolute: XCM messages are guaranteed to be delivered and interpreted accurately, in order and in a timely fashion.
  • Asymmetric: XCM messages do not have results. Any results must be separately communicated to the sender with an additional message.
  • Agnostic: XCM makes no assumptions about the nature of the Consensus System between which messages are being passed.

Messages

XCM Virtual Machine

#![allow(unused)]
fn main() {
//! # Fundamentals Lesson 1
use crate::constants::ALICE;
use frame_support::parameter_types;
use xcm::latest::prelude::*;

// Relay A Topography:
//                   ┌───────────┐
//                   │  Relay A  │
//                   │  Polkadot │
//                   └─────┬─────┘
//                         │
//              ┌──────────┴──────────┐
//              │                     │
//        ┌─────┴─────┐         ┌─────┴──────┐
//        │ AssetHub  │         │  Moonbeam  │
//        │  Id 1000  │         │  Id 2004   │
//        └─────┬─────┘         └──────┬─────┘
//              │                      │
//       ┌──────┴──────┐               ├───────────┐
//       │             │               │           │
// ┌─────┴─────┐ ┌─────┴──────┐ ┌──────┴────┐ ┌────┴───────┐
// │   Alice   │ │  Pallet    │ │    Bob    │ │  Pallet    │
// │ AcctKey32 │ │  Assets    │ │ AcctKey20 │ │   EVM      │
// │           │ │            │ │           │ │            │
// │ 0x11111...│ │ Pallet #50 │ │ 0x22222...│ │ Pallet #51 │
// └───────────┘ └─────┬──────┘ └───────────┘ └─────┬──────┘
//                     │                            │
//               ┌─────┴─────┐               ┌──────┴─────┐
//               │   Asset   │               │   Smart    │
//               │   USDT    │               │ Contract   │
//               │           │               │            │
//               │  Id 1984  │               │ 0x55555... │
//               └───────────┘               └────────────┘

/// All these locations are relative to the Polkadot Relay Chain.
pub mod relative_to_polkadot_relay {
	use super::*;

	parameter_types! {
		// The Polkadot parachain A with id 1000.
		pub PolkadotPara1000: Location = todo!();
		// The Polkadot parachain B with id 2004.
		pub PolkadotPara2004: Location = todo!();
		// The Polkadot relay chain.
		pub PolkadotRelay: Location = todo!();
		// A 32 byte account on para 1000 with all bytes equal to 1 (Alice).
		pub AliceBytes: [u8; 32] = ALICE.into();
		pub PolkadotPara1000Alice: Location = todo!();
		// The location of the `Assets` pallet on the relay chain.
		pub PolkadotRelayBalancesPallet: Location = todo!();
		// The asset with index `1984` of the Assets pallet on polkadot parachain with id 1000.
		pub PolkadotPara1000Asset1984: Location = todo!();
		// The Kusama parachain with id 1000.
		pub KusamaPara1000: Location = todo!();
	}
}

/// All these locations are relative to a Polkadot parachain with id 1000.
pub mod relative_to_polkadot_para_1000 {
	use super::*;

	parameter_types! {
		// The Polkadot parachain with id 1000.
		pub PolkadotPara1000: Location = todo!();
		// The Polkadot parachain with id 2004.
		pub PolkadotPara2004: Location = todo!();
		// The Polkadot relay chain.
		pub PolkadotRelay: Location = todo!();
		// A 32 byte account on para 1000.
		pub AliceBytes: [u8; 32] = todo!();
		pub PolkadotPara1000Alice: Location = todo!();
		// The location of the `Balances` pallet on the relay chain.
		pub PolkadotRelayBalancesPallet: Location = todo!();
		// The asset with index `1984` of the Assets pallet on the Polkadot parachain with id 1000.
		pub PolkadotPara1000Asset1984: Location = todo!();
		// The Kusama parachain with id 1000.
		pub KusamaPara1000: Location = todo!();
	}
}

/// All these locations are relative to an EVM Smart Contract on Parachain B, secured by Polkadot.
pub mod relative_to_polkadot_para_2000_sc {
	use super::*;

	parameter_types! {
		// TODO
	}
}

// Relay B Topography:
//                ┌───────────┐
//                │  Relay B  │
//                │  Kusama   │
//                └─────┬─────┘
//                      │
//       ┌──────────────┼──────────────┐
//       │              │              │
// ┌─────┴─────┐  ┌─────┴─────┐  ┌─────┴─────┐
// │ AssetHub  │  │  User 1   │  │           │
// │  Id 1000  │  │ AcctKey32 │  │ Plurality │
// └─────┬─────┘  │           │  │           │
//       │        │ 0x11111...│  │           │
// ┌─────┴──────┐ └───────────┘  └───────────┘
// │  Pallet    │
// │    NFT     │
// │            │
// │ Pallet #52 │
// └─────┬──────┘
//       │
// ┌─────┴─────┐
// │    NFT    │
// │  Kitties  │
// │           │
// │  Id 1984  │
// └───────────┘

/// All these locations are relative to the Kusama Relay Chain.
pub mod relative_to_kusama_relay {
	use super::*;

	parameter_types! {
		// TODO
	}
}

/// All these locations are relative to a Kusama parachain with id 1000.
pub mod relative_to_kusama_para_1000 {
	use super::*;

	parameter_types! {
		// TODO
	}
}

// Absolute Topography
//                    ┌ ─ ─ ─ ─ ─┐
//                      Absolute
//                      Location
//                    └ ─ ─ ┬ ─ ─┘
//                          │
//      ┌─────────────┬─────┴─────┬────────────┐
//      │             │           │            │
// ┌────┴─────┐ ┌─────┴────┐ ┌────┴─────┐ ┌────┴─────┐
// │ Relay A  │ │ Relay B  │ │          │ │          │
// │ Polkadot │ │ Kusama   │ │ Bitcoin  │ │ Ethereum │
// └────┬─────┘ └─────┬────┘ └────┬─────┘ └─────┬────┘
//      │             │           │             │
//     ...           ...         ...           ...

/// All these locations are absolute.
/// Absolute locations have no parents and always start with the `GlobalConsensus` junction.
pub mod absolute {
	use super::*;

	parameter_types! {
		// The Polkadot parachain with id 1000.
		pub PolkadotPara1000: Location = todo!();
		// The Polkadot parachain with id 2004.
		pub PolkadotPara2004: Location = todo!();
		// The Polkadot relay chain.
		pub PolkadotRelay: Location = todo!();
		// A 32 byte account on para 1000.
		pub AliceBytes: [u8; 32] = ALICE.into();
		pub PolkadotPara1000Alice: Location = todo!();
		// The location of the `Balances` pallet on the relay chain.
		pub PolkadotRelayBalancesPallet: Location = todo!();
		// The asset with index `1984` of the Assets pallet on the Polkadot parachain with id 1000.
		pub PolkadotPara1000Asset1984: Location = todo!();
		// The Kusama parachain with id 1000.
		pub KusamaPara1000: Location = todo!();
	}
}

pub mod manipulation {
	use super::*;
	use sp_runtime::AccountId32;

	// Extract the account id from a Location, if it is the last junction in the Location.
	pub fn extract_last_account_id(location: Location) -> Option<AccountId32> {
		todo!("{:?}", location)
	}

	// From the perspective of a parachain, check if another location is a sibling parachain, and
	// return the id.
	pub fn check_sibling_parachains(maybe_sibling: Location) -> Option<u32> {
		todo!("{:?}", maybe_sibling)
	}

	// Append `who` to the current `origin`.
	pub fn descend_origin(origin: &mut Location, who: Location) -> Result<(), XcmError> {
		todo!("{:?} {:?}", origin, who)
	}
}
}
#![allow(unused)]
fn main() {
//! # Fundamentals Lesson 1
use crate::constants::ALICE;
use frame_support::parameter_types;
use xcm::latest::prelude::*;

// Relay A Topography:
//                   ┌───────────┐
//                   │  Relay A  │
//                   │  Polkadot │
//                   └─────┬─────┘
//                         │
//              ┌──────────┴──────────┐
//              │                     │
//        ┌─────┴─────┐         ┌─────┴──────┐
//        │ AssetHub  │         │  Moonbeam  │
//        │  Id 1000  │         │  Id 2004   │
//        └─────┬─────┘         └──────┬─────┘
//              │                      │
//       ┌──────┴──────┐               ├───────────┐
//       │             │               │           │
// ┌─────┴─────┐ ┌─────┴──────┐ ┌──────┴────┐ ┌────┴───────┐
// │   Alice   │ │  Pallet    │ │    Bob    │ │  Pallet    │
// │ AcctKey32 │ │  Assets    │ │ AcctKey20 │ │   EVM      │
// │           │ │            │ │           │ │            │
// │ 0x11111...│ │ Pallet #50 │ │ 0x22222...│ │ Pallet #51 │
// └───────────┘ └─────┬──────┘ └───────────┘ └─────┬──────┘
//                     │                            │
//               ┌─────┴─────┐               ┌──────┴─────┐
//               │   Asset   │               │   Smart    │
//               │   USDT    │               │ Contract   │
//               │           │               │            │
//               │  Id 1984  │               │ 0x55555... │
//               └───────────┘               └────────────┘

/// All these locations are relative to the Polkadot Relay Chain.
pub mod relative_to_polkadot_relay {
	use super::*;

	parameter_types! {
		// The Polkadot parachain A with id 1000.
		pub PolkadotPara1000: Location = Parachain(1000).into();
		// The Polkadot parachain B with id 2004.
		pub PolkadotPara2004: Location = Parachain(2004).into();
		// The Polkadot relay chain.
		pub PolkadotRelay: Location = Here.into();
		// A 32 byte account on para 1000 with all bytes equal to 1 (Alice).
		pub AliceBytes: [u8; 32] = ALICE.into();
		pub PolkadotPara1000Alice: Location = Location::new(0, [Parachain(1000), AliceBytes::get().into()]);
		// The location of the `Assets` pallet on the relay chain.
		pub PolkadotPara1000AssetsPallet: Location = [Parachain(1000), PalletInstance(50)].into();
		// The asset with index `1984` of the Assets pallet on polkadot parachain with id 1000.
		pub PolkadotPara1000Asset1984: Location = (Parachain(1000), PalletInstance(50), GeneralIndex(1984)).into();
		// The Kusama parachain with id 1000.
		pub KusamaPara1000: Location = (Parent, GlobalConsensus(Kusama), Parachain(1000)).into();
	}
}

/// All these locations are relative to a Polkadot parachain with id 1000.
pub mod relative_to_polkadot_para_1000 {
	use super::*;

	parameter_types! {
		// The Polkadot parachain with id 1000.
		pub PolkadotPara1000: Location = Here.into();
		// The Polkadot parachain with id 2004.
		pub PolkadotPara2004: Location = (Parent, Parachain(2004)).into();
		// The Polkadot relay chain.
		pub PolkadotRelay: Location = Parent.into();
		// A 32 byte account on para 1000.
		pub AliceBytes: [u8; 32] = ALICE.into();
		pub PolkadotPara1000Alice: Location = Location::new(0, [AliceBytes::get().into()]);
		// The location of the `Balances` pallet on the relay chain.
		pub PolkadotPara1000AssetsPallet: Location = (PalletInstance(50)).into();
		// The asset with index `1984` of the Assets pallet on the Polkadot parachain with id 1000.
		pub PolkadotPara1000Asset1984: Location = (PalletInstance(50), GeneralIndex(1984)).into();
		// The Kusama parachain with id 1000.
		pub KusamaPara1000: Location = (Parent, Parent, GlobalConsensus(Kusama), Parachain(1000)).into();
	}
}

/// All these locations are relative to an EVM Smart Contract on Parachain B, secured by Polkadot.
pub mod relative_to_polkadot_para_2000_sc {
	use super::*;

	parameter_types! {
		// TODO
	}
}

// Relay B Topography:
//                ┌───────────┐
//                │  Relay B  │
//                │  Kusama   │
//                └─────┬─────┘
//                      │
//       ┌──────────────┼──────────────┐
//       │              │              │
// ┌─────┴─────┐  ┌─────┴─────┐  ┌─────┴─────┐
// │ AssetHub  │  │  User 1   │  │           │
// │  Id 1000  │  │ AcctKey32 │  │ Plurality │
// └─────┬─────┘  │           │  │           │
//       │        │ 0x11111...│  │           │
// ┌─────┴──────┐ └───────────┘  └───────────┘
// │  Pallet    │
// │    NFT     │
// │            │
// │ Pallet #52 │
// └─────┬──────┘
//       │
// ┌─────┴─────┐
// │    NFT    │
// │  Kitties  │
// │           │
// │  Id 1984  │
// └───────────┘

/// All these locations are relative to the Kusama Relay Chain.
pub mod relative_to_kusama_relay {
	use super::*;

	parameter_types! {
		// TODO
	}
}

/// All these locations are relative to a Kusama parachain with id 1000.
pub mod relative_to_kusama_para_1000 {
	use super::*;

	parameter_types! {
		// TODO
	}
}

// Absolute Topography
//                    ┌ ─ ─ ─ ─ ─┐
//                      Absolute
//                      Location
//                    └ ─ ─ ┬ ─ ─┘
//                          │
//      ┌─────────────┬─────┴─────┬────────────┐
//      │             │           │            │
// ┌────┴─────┐ ┌─────┴────┐ ┌────┴─────┐ ┌────┴─────┐
// │ Relay A  │ │ Relay B  │ │          │ │          │
// │ Polkadot │ │ Kusama   │ │ Bitcoin  │ │ Ethereum │
// └────┬─────┘ └─────┬────┘ └────┬─────┘ └─────┬────┘
//      │             │           │             │
//     ...           ...         ...           ...

/// All these locations are absolute.
/// Absolute locations have no parents and always start with the `GlobalConsensus` junction.
pub mod absolute {
	use super::*;

	parameter_types! {
		// The Polkadot parachain with id 1000.
		pub PolkadotPara1000: Location = [GlobalConsensus(Polkadot), Parachain(1000)].into();
		// The Polkadot parachain with id 2004.
		pub PolkadotPara2004: Location = [GlobalConsensus(Polkadot), Parachain(2004)].into();
		// The Polkadot relay chain.
		pub PolkadotRelay: Location = [GlobalConsensus(Polkadot)].into();
		// A 32 byte account on para 1000.
		pub AliceBytes: [u8; 32] = ALICE.into();
		pub PolkadotPara1000Alice: Location = [GlobalConsensus(Polkadot), Parachain(1000), AliceBytes::get().into()].into();
		// The location of the `Balances` pallet on the relay chain.
		pub PolkadotPara1000AssetsPallet: Location = [GlobalConsensus(Polkadot), Parachain(1000), PalletInstance(50)].into();
		// The asset with index `1984` of the Assets pallet on the Polkadot parachain with id 1000.
		pub PolkadotPara1000Asset1984: Location = [GlobalConsensus(Polkadot), Parachain(1000), PalletInstance(50), GeneralIndex(1984)].into();
		// The Kusama parachain with id 1000.
		pub KusamaPara1000: Location = [GlobalConsensus(Kusama), Parachain(1000)].into();
	}
}

pub mod manipulation {
	use super::*;
	use sp_runtime::AccountId32;

	// Extract the account id from a Location, if it is the last junction in the Location.
	pub fn extract_last_account_id(location: Location) -> Option<AccountId32> {
		match location.last() {
			Some(Junction::AccountId32 { id, .. }) => Some((*id).into()),
			_ => None,
		}
	}

	// From the perspective of a parachain, check if another location is a sibling parachain, and
	// return the id.
	pub fn check_sibling_parachains(maybe_sibling: Location) -> Option<u32> {
		match maybe_sibling.unpack() {
			(1, [Parachain(id)]) => Some(*id),
			_ => None,
		}
	}

	// Append `who` to the current `origin`.
	pub fn descend_origin(origin: &mut Location, who: Location) -> Result<(), XcmError> {
		(*origin).append_with(who).map_err(|_| XcmError::LocationFull)
	}
}
}
diff --git a/fundamentals/src/location.rs b/fundamentals/src/location.rs
index 8b13789..b5ebea9 100644
--- a/fundamentals/src/location.rs
+++ b/fundamentals/src/location.rs
@@ -1 +1,193 @@
+//! # Fundamentals Lesson 1
+use crate::constants::ALICE;
+use frame_support::parameter_types;
+use xcm::latest::prelude::*;
 
+// Relay A Topography:
+//                   ┌───────────┐
+//                   │  Relay A  │
+//                   │  Polkadot │
+//                   └─────┬─────┘
+//                         │
+//              ┌──────────┴──────────┐
+//              │                     │
+//        ┌─────┴─────┐         ┌─────┴──────┐
+//        │ AssetHub  │         │  Moonbeam  │
+//        │  Id 1000  │         │  Id 2004   │
+//        └─────┬─────┘         └──────┬─────┘
+//              │                      │
+//       ┌──────┴──────┐               ├───────────┐
+//       │             │               │           │
+// ┌─────┴─────┐ ┌─────┴──────┐ ┌──────┴────┐ ┌────┴───────┐
+// │   Alice   │ │  Pallet    │ │    Bob    │ │  Pallet    │
+// │ AcctKey32 │ │  Assets    │ │ AcctKey20 │ │   EVM      │
+// │           │ │            │ │           │ │            │
+// │ 0x11111...│ │ Pallet #50 │ │ 0x22222...│ │ Pallet #51 │
+// └───────────┘ └─────┬──────┘ └───────────┘ └─────┬──────┘
+//                     │                            │
+//               ┌─────┴─────┐               ┌──────┴─────┐
+//               │   Asset   │               │   Smart    │
+//               │   USDT    │               │ Contract   │
+//               │           │               │            │
+//               │  Id 1984  │               │ 0x55555... │
+//               └───────────┘               └────────────┘
+
+/// All these locations are relative to the Polkadot Relay Chain.
+pub mod relative_to_polkadot_relay {
+	use super::*;
+
+	parameter_types! {
+		// The Polkadot parachain A with id 1000.
+		pub PolkadotPara1000: Location = todo!();
+		// The Polkadot parachain B with id 2004.
+		pub PolkadotPara2004: Location = todo!();
+		// The Polkadot relay chain.
+		pub PolkadotRelay: Location = todo!();
+		// A 32 byte account on para 1000 with all bytes equal to 1 (Alice).
+		pub AliceBytes: [u8; 32] = ALICE.into();
+		pub PolkadotPara1000Alice: Location = todo!();
+		// The location of the `Assets` pallet on the relay chain.
+		pub PolkadotRelayBalancesPallet: Location = todo!();
+		// The asset with index `1984` of the Assets pallet on polkadot parachain with id 1000.
+		pub PolkadotPara1000Asset1984: Location = todo!();
+		// The Kusama parachain with id 1000.
+		pub KusamaPara1000: Location = todo!();
+	}
+}
+
+/// All these locations are relative to a Polkadot parachain with id 1000.
+pub mod relative_to_polkadot_para_1000 {
+	use super::*;
+
+	parameter_types! {
+		// The Polkadot parachain with id 1000.
+		pub PolkadotPara1000: Location = todo!();
+		// The Polkadot parachain with id 2004.
+		pub PolkadotPara2004: Location = todo!();
+		// The Polkadot relay chain.
+		pub PolkadotRelay: Location = todo!();
+		// A 32 byte account on para 1000.
+		pub AliceBytes: [u8; 32] = todo!();
+		pub PolkadotPara1000Alice: Location = todo!();
+		// The location of the `Balances` pallet on the relay chain.
+		pub PolkadotRelayBalancesPallet: Location = todo!();
+		// The asset with index `1984` of the Assets pallet on the Polkadot parachain with id 1000.
+		pub PolkadotPara1000Asset1984: Location = todo!();
+		// The Kusama parachain with id 1000.
+		pub KusamaPara1000: Location = todo!();
+	}
+}
+
+/// All these locations are relative to an EVM Smart Contract on Parachain B, secured by Polkadot.
+pub mod relative_to_polkadot_para_2000_sc {
+	use super::*;
+
+	parameter_types! {
+		// TODO
+	}
+}
+
+// Relay B Topography:
+//                ┌───────────┐
+//                │  Relay B  │
+//                │  Kusama   │
+//                └─────┬─────┘
+//                      │
+//       ┌──────────────┼──────────────┐
+//       │              │              │
+// ┌─────┴─────┐  ┌─────┴─────┐  ┌─────┴─────┐
+// │ AssetHub  │  │  User 1   │  │           │
+// │  Id 1000  │  │ AcctKey32 │  │ Plurality │
+// └─────┬─────┘  │           │  │           │
+//       │        │ 0x11111...│  │           │
+// ┌─────┴──────┐ └───────────┘  └───────────┘
+// │  Pallet    │
+// │    NFT     │
+// │            │
+// │ Pallet #52 │
+// └─────┬──────┘
+//       │
+// ┌─────┴─────┐
+// │    NFT    │
+// │  Kitties  │
+// │           │
+// │  Id 1984  │
+// └───────────┘
+
+/// All these locations are relative to the Kusama Relay Chain.
+pub mod relative_to_kusama_relay {
+	use super::*;
+
+	parameter_types! {
+		// TODO
+	}
+}
+
+/// All these locations are relative to a Kusama parachain with id 1000.
+pub mod relative_to_kusama_para_1000 {
+	use super::*;
+
+	parameter_types! {
+		// TODO
+	}
+}
+
+// Absolute Topography
+//                    ┌ ─ ─ ─ ─ ─┐
+//                      Absolute
+//                      Location
+//                    └ ─ ─ ┬ ─ ─┘
+//                          │
+//      ┌─────────────┬─────┴─────┬────────────┐
+//      │             │           │            │
+// ┌────┴─────┐ ┌─────┴────┐ ┌────┴─────┐ ┌────┴─────┐
+// │ Relay A  │ │ Relay B  │ │          │ │          │
+// │ Polkadot │ │ Kusama   │ │ Bitcoin  │ │ Ethereum │
+// └────┬─────┘ └─────┬────┘ └────┬─────┘ └─────┬────┘
+//      │             │           │             │
+//     ...           ...         ...           ...
+
+/// All these locations are absolute.
+/// Absolute locations have no parents and always start with the `GlobalConsensus` junction.
+pub mod absolute {
+	use super::*;
+
+	parameter_types! {
+		// The Polkadot parachain with id 1000.
+		pub PolkadotPara1000: Location = todo!();
+		// The Polkadot parachain with id 2004.
+		pub PolkadotPara2004: Location = todo!();
+		// The Polkadot relay chain.
+		pub PolkadotRelay: Location = todo!();
+		// A 32 byte account on para 1000.
+		pub AliceBytes: [u8; 32] = ALICE.into();
+		pub PolkadotPara1000Alice: Location = todo!();
+		// The location of the `Balances` pallet on the relay chain.
+		pub PolkadotRelayBalancesPallet: Location = todo!();
+		// The asset with index `1984` of the Assets pallet on the Polkadot parachain with id 1000.
+		pub PolkadotPara1000Asset1984: Location = todo!();
+		// The Kusama parachain with id 1000.
+		pub KusamaPara1000: Location = todo!();
+	}
+}
+
+pub mod manipulation {
+	use super::*;
+	use sp_runtime::AccountId32;
+
+	// Extract the account id from a Location, if it is the last junction in the Location.
+	pub fn extract_last_account_id(location: Location) -> Option<AccountId32> {
+		todo!("{:?}", location)
+	}
+
+	// From the perspective of a parachain, check if another location is a sibling parachain, and
+	// return the id.
+	pub fn check_sibling_parachains(maybe_sibling: Location) -> Option<u32> {
+		todo!("{:?}", maybe_sibling)
+	}
+
+	// Append `who` to the current `origin`.
+	pub fn descend_origin(origin: &mut Location, who: Location) -> Result<(), XcmError> {
+		todo!("{:?} {:?}", origin, who)
+	}
+}
diff --git a/fundamentals/src/location.rs b/fundamentals/src/location.rs
index b5ebea9..a7f912f 100644
--- a/fundamentals/src/location.rs
+++ b/fundamentals/src/location.rs
@@ -38,20 +38,20 @@ pub mod relative_to_polkadot_relay {
 
 	parameter_types! {
 		// The Polkadot parachain A with id 1000.
-		pub PolkadotPara1000: Location = todo!();
+		pub PolkadotPara1000: Location = Parachain(1000).into();
 		// The Polkadot parachain B with id 2004.
-		pub PolkadotPara2004: Location = todo!();
+		pub PolkadotPara2004: Location = Parachain(2004).into();
 		// The Polkadot relay chain.
-		pub PolkadotRelay: Location = todo!();
+		pub PolkadotRelay: Location = Here.into();
 		// A 32 byte account on para 1000 with all bytes equal to 1 (Alice).
 		pub AliceBytes: [u8; 32] = ALICE.into();
-		pub PolkadotPara1000Alice: Location = todo!();
+		pub PolkadotPara1000Alice: Location = Location::new(0, [Parachain(1000), AliceBytes::get().into()]);
 		// The location of the `Assets` pallet on the relay chain.
-		pub PolkadotRelayBalancesPallet: Location = todo!();
+		pub PolkadotPara1000AssetsPallet: Location = [Parachain(1000), PalletInstance(50)].into();
 		// The asset with index `1984` of the Assets pallet on polkadot parachain with id 1000.
-		pub PolkadotPara1000Asset1984: Location = todo!();
+		pub PolkadotPara1000Asset1984: Location = (Parachain(1000), PalletInstance(50), GeneralIndex(1984)).into();
 		// The Kusama parachain with id 1000.
-		pub KusamaPara1000: Location = todo!();
+		pub KusamaPara1000: Location = (Parent, GlobalConsensus(Kusama), Parachain(1000)).into();
 	}
 }
 
@@ -61,20 +61,20 @@ pub mod relative_to_polkadot_para_1000 {
 
 	parameter_types! {
 		// The Polkadot parachain with id 1000.
-		pub PolkadotPara1000: Location = todo!();
+		pub PolkadotPara1000: Location = Here.into();
 		// The Polkadot parachain with id 2004.
-		pub PolkadotPara2004: Location = todo!();
+		pub PolkadotPara2004: Location = (Parent, Parachain(2004)).into();
 		// The Polkadot relay chain.
-		pub PolkadotRelay: Location = todo!();
+		pub PolkadotRelay: Location = Parent.into();
 		// A 32 byte account on para 1000.
-		pub AliceBytes: [u8; 32] = todo!();
-		pub PolkadotPara1000Alice: Location = todo!();
+		pub AliceBytes: [u8; 32] = ALICE.into();
+		pub PolkadotPara1000Alice: Location = Location::new(0, [AliceBytes::get().into()]);
 		// The location of the `Balances` pallet on the relay chain.
-		pub PolkadotRelayBalancesPallet: Location = todo!();
+		pub PolkadotPara1000AssetsPallet: Location = (PalletInstance(50)).into();
 		// The asset with index `1984` of the Assets pallet on the Polkadot parachain with id 1000.
-		pub PolkadotPara1000Asset1984: Location = todo!();
+		pub PolkadotPara1000Asset1984: Location = (PalletInstance(50), GeneralIndex(1984)).into();
 		// The Kusama parachain with id 1000.
-		pub KusamaPara1000: Location = todo!();
+		pub KusamaPara1000: Location = (Parent, Parent, GlobalConsensus(Kusama), Parachain(1000)).into();
 	}
 }
 
@@ -154,20 +154,20 @@ pub mod absolute {
 
 	parameter_types! {
 		// The Polkadot parachain with id 1000.
-		pub PolkadotPara1000: Location = todo!();
+		pub PolkadotPara1000: Location = [GlobalConsensus(Polkadot), Parachain(1000)].into();
 		// The Polkadot parachain with id 2004.
-		pub PolkadotPara2004: Location = todo!();
+		pub PolkadotPara2004: Location = [GlobalConsensus(Polkadot), Parachain(2004)].into();
 		// The Polkadot relay chain.
-		pub PolkadotRelay: Location = todo!();
+		pub PolkadotRelay: Location = [GlobalConsensus(Polkadot)].into();
 		// A 32 byte account on para 1000.
 		pub AliceBytes: [u8; 32] = ALICE.into();
-		pub PolkadotPara1000Alice: Location = todo!();
+		pub PolkadotPara1000Alice: Location = [GlobalConsensus(Polkadot), Parachain(1000), AliceBytes::get().into()].into();
 		// The location of the `Balances` pallet on the relay chain.
-		pub PolkadotRelayBalancesPallet: Location = todo!();
+		pub PolkadotPara1000AssetsPallet: Location = [GlobalConsensus(Polkadot), Parachain(1000), PalletInstance(50)].into();
 		// The asset with index `1984` of the Assets pallet on the Polkadot parachain with id 1000.
-		pub PolkadotPara1000Asset1984: Location = todo!();
+		pub PolkadotPara1000Asset1984: Location = [GlobalConsensus(Polkadot), Parachain(1000), PalletInstance(50), GeneralIndex(1984)].into();
 		// The Kusama parachain with id 1000.
-		pub KusamaPara1000: Location = todo!();
+		pub KusamaPara1000: Location = [GlobalConsensus(Kusama), Parachain(1000)].into();
 	}
 }
 
@@ -177,17 +177,23 @@ pub mod manipulation {
 
 	// Extract the account id from a Location, if it is the last junction in the Location.
 	pub fn extract_last_account_id(location: Location) -> Option<AccountId32> {
-		todo!("{:?}", location)
+		match location.last() {
+			Some(Junction::AccountId32 { id, .. }) => Some((*id).into()),
+			_ => None,
+		}
 	}
 
 	// From the perspective of a parachain, check if another location is a sibling parachain, and
 	// return the id.
 	pub fn check_sibling_parachains(maybe_sibling: Location) -> Option<u32> {
-		todo!("{:?}", maybe_sibling)
+		match maybe_sibling.unpack() {
+			(1, [Parachain(id)]) => Some(*id),
+			_ => None,
+		}
 	}
 
 	// Append `who` to the current `origin`.
 	pub fn descend_origin(origin: &mut Location, who: Location) -> Result<(), XcmError> {
-		todo!("{:?} {:?}", origin, who)
+		(*origin).append_with(who).map_err(|_| XcmError::LocationFull)
 	}
 }
#![allow(unused)]
fn main() {
//! # Fundamentals Lesson 2
//!
//! All locations in this module are relative to Polkadot parachain 2000.

use frame_support::parameter_types;
use xcm::latest::prelude::*;

// Polkadot Topography
//
//                              ┌───────────┐
//                              │  Relay A  │
//                              │  Polkadot │
//                              └─────┬─────┘
//                                    │
//                         ┌──────────┴──────────┐
//                         │                     │
//                   ┌─────┴─────┐         ┌─────┴─────┐
//                   │  AssetHub │         │  HydraDx  │
//                   │  Id 1000  │         │  Id 2034  │
//                   └─────┬─────┘         └───────────┘
//                         │
//                  ┌──────┴──────┐
//                  │             │
//           ┌──────┴─────┐ ┌─────┴──────┐
//           │   Pallet   │ │   Pallet   │
//           │   Assets   │ │    NFT     │
//           │            │ │            │
//           │ Pallet #50 │ │ Pallet #52 │
//           └─────┬──────┘ └─────┬──────┘
//                 │              │
//       ┌─────────┴───┐          └────┬──────────────┐
//       │             │               │              │
// ┌─────┴─────┐ ┌─────┴─────┐  ┌──────┴─────┐ ┌──────┴─────┐
// │   Asset   │ │   Asset   │  │ Collection │ │ Collection │
// │   USDC    │ │   USDT    │  │   Kitties  │ │  Zombies   │
// │           │ │           │  │            │ │            │
// │ Id 1337   │ │  Id 1984  │  │    Id 3    │ │    Id 66   │
// └───────────┘ └───────────┘  └────────────┘ └────────────┘

const DOT_DECIMALS: u32 = 10;
const USDT_DECIMALS: u32 = 6;

// Fungible Tokens
// Construct these assets from the perspective of AssetHub (1000).
parameter_types! {
	// `Assets` instance that contains no assets.
	pub EmptyAssets: Assets = todo!();
	// USDT.
	pub Usdt: AssetId = todo!();
	// The native token of the relay chain, i.e. DOT.
	pub DotToken: AssetId = todo!();
	// 100 USDT.
	pub OneHundredUsdt: Asset = todo!();
	// Some amount of the native token of the relay chain.
	pub OneHundredDot: Asset = todo!();
}

// Non-Fungible Tokens
// Construct these assets from the perspective of AssetHub (1000).
parameter_types! {
	// Location of NFT collection with id 3 inside of the NFT pallet in Polkadot parachain 1000.
	pub NftLocation: Location = todo!();
	// The NFT with id 69 inside of that collection.
	pub Nft: Asset = todo!();
}

// Asset Filters
parameter_types! {
	// A filter which will capture all possible assets.
	pub AllAssetsFilter: AssetFilter = todo!();
	// A filter specific for the DOT Token.
	pub DotFilter: AssetFilter = todo!();
	// A filter specific for USDT.
	pub UsdtFilter: AssetFilter = todo!();
}
}
#![allow(unused)]
fn main() {
//! # Fundamentals Lesson 2
//!
//! All locations in this module are relative to Polkadot parachain 2000.

use frame_support::parameter_types;
use xcm::latest::prelude::*;

// Polkadot Topography
//
//                              ┌───────────┐
//                              │  Relay A  │
//                              │  Polkadot │
//                              └─────┬─────┘
//                                    │
//                         ┌──────────┴──────────┐
//                         │                     │
//                   ┌─────┴─────┐         ┌─────┴─────┐
//                   │  AssetHub │         │  HydraDx  │
//                   │  Id 1000  │         │  Id 2034  │
//                   └─────┬─────┘         └───────────┘
//                         │
//                  ┌──────┴──────┐
//                  │             │
//           ┌──────┴─────┐ ┌─────┴──────┐
//           │   Pallet   │ │   Pallet   │
//           │   Assets   │ │    NFT     │
//           │            │ │            │
//           │ Pallet #50 │ │ Pallet #52 │
//           └─────┬──────┘ └─────┬──────┘
//                 │              │
//       ┌─────────┴───┐          └────┬──────────────┐
//       │             │               │              │
// ┌─────┴─────┐ ┌─────┴─────┐  ┌──────┴─────┐ ┌──────┴─────┐
// │   Asset   │ │   Asset   │  │ Collection │ │ Collection │
// │   USDC    │ │   USDT    │  │   Kitties  │ │  Zombies   │
// │           │ │           │  │            │ │            │
// │ Id 1337   │ │  Id 1984  │  │    Id 3    │ │    Id 66   │
// └───────────┘ └───────────┘  └────────────┘ └────────────┘

const DOT_DECIMALS: u32 = 10;
const USDT_DECIMALS: u32 = 6;

// Fungible Tokens
// Construct these assets from the perspective of AssetHub (1000).
parameter_types! {
	// `Assets` instance that contains no assets.
	pub EmptyAssets: Assets = vec![].into();
	// USDT.
	pub Usdt: AssetId = (PalletInstance(50), GeneralIndex(1984)).into();
	// The native token of the relay chain, i.e. DOT.
	pub DotToken: AssetId = Parent.into();
	// 100 USDT.
	pub OneHundredUsdt: Asset = (Usdt::get(), 100u128 * 10u128.pow(USDT_DECIMALS)).into();
	// Some amount of the native token of the relay chain.
	pub OneHundredDot: Asset = (DotToken::get(), 100u128 * 10u128.pow(DOT_DECIMALS)).into();
}

// Non-Fungible Tokens
// Construct these assets from the perspective of AssetHub (1000).
parameter_types! {
	// Location of NFT collection with id 3 inside of the NFT pallet in Polkadot parachain 1000.
	pub NftLocation: Location = [PalletInstance(52), GeneralIndex(3)].into();
	// The NFT with id 69 inside of that collection.
	pub Nft: Asset = (NftLocation::get(), 69u64).into();
}

// Asset Filters
parameter_types! {
	// A filter which will capture all possible assets.
	pub AllAssetsFilter: AssetFilter = AssetFilter::Wild(WildAsset::All);
	// A filter specific for the DOT Token.
	pub DotFilter: AssetFilter = OneHundredDot::get().into();
	// A filter specific for USDT.
	pub UsdtFilter: AssetFilter = OneHundredUsdt::get().into();
}
}
diff --git a/fundamentals/src/asset.rs b/fundamentals/src/asset.rs
index 8b13789..3f1774c 100644
--- a/fundamentals/src/asset.rs
+++ b/fundamentals/src/asset.rs
@@ -1 +1,75 @@
+//! # Fundamentals Lesson 2
+//!
+//! All locations in this module are relative to Polkadot parachain 2000.
 
+use frame_support::parameter_types;
+use xcm::latest::prelude::*;
+
+// Polkadot Topography
+//
+//                              ┌───────────┐
+//                              │  Relay A  │
+//                              │  Polkadot │
+//                              └─────┬─────┘
+//                                    │
+//                         ┌──────────┴──────────┐
+//                         │                     │
+//                   ┌─────┴─────┐         ┌─────┴─────┐
+//                   │  AssetHub │         │  HydraDx  │
+//                   │  Id 1000  │         │  Id 2034  │
+//                   └─────┬─────┘         └───────────┘
+//                         │
+//                  ┌──────┴──────┐
+//                  │             │
+//           ┌──────┴─────┐ ┌─────┴──────┐
+//           │   Pallet   │ │   Pallet   │
+//           │   Assets   │ │    NFT     │
+//           │            │ │            │
+//           │ Pallet #50 │ │ Pallet #52 │
+//           └─────┬──────┘ └─────┬──────┘
+//                 │              │
+//       ┌─────────┴───┐          └────┬──────────────┐
+//       │             │               │              │
+// ┌─────┴─────┐ ┌─────┴─────┐  ┌──────┴─────┐ ┌──────┴─────┐
+// │   Asset   │ │   Asset   │  │ Collection │ │ Collection │
+// │   USDC    │ │   USDT    │  │   Kitties  │ │  Zombies   │
+// │           │ │           │  │            │ │            │
+// │ Id 1337   │ │  Id 1984  │  │    Id 3    │ │    Id 66   │
+// └───────────┘ └───────────┘  └────────────┘ └────────────┘
+
+const DOT_DECIMALS: u32 = 10;
+const USDT_DECIMALS: u32 = 6;
+
+// Fungible Tokens
+// Construct these assets from the perspective of AssetHub (1000).
+parameter_types! {
+	// `Assets` instance that contains no assets.
+	pub EmptyAssets: Assets = todo!();
+	// USDT.
+	pub Usdt: AssetId = todo!();
+	// The native token of the relay chain, i.e. DOT.
+	pub DotToken: AssetId = todo!();
+	// 100 USDT.
+	pub OneHundredUsdt: Asset = todo!();
+	// Some amount of the native token of the relay chain.
+	pub OneHundredDot: Asset = todo!();
+}
+
+// Non-Fungible Tokens
+// Construct these assets from the perspective of AssetHub (1000).
+parameter_types! {
+	// Location of NFT collection with id 3 inside of the NFT pallet in Polkadot parachain 1000.
+	pub NftLocation: Location = todo!();
+	// The NFT with id 69 inside of that collection.
+	pub Nft: Asset = todo!();
+}
+
+// Asset Filters
+parameter_types! {
+	// A filter which will capture all possible assets.
+	pub AllAssetsFilter: AssetFilter = todo!();
+	// A filter specific for the DOT Token.
+	pub DotFilter: AssetFilter = todo!();
+	// A filter specific for USDT.
+	pub UsdtFilter: AssetFilter = todo!();
+}
diff --git a/fundamentals/src/asset.rs b/fundamentals/src/asset.rs
index 3f1774c..c3004bb 100644
--- a/fundamentals/src/asset.rs
+++ b/fundamentals/src/asset.rs
@@ -44,32 +44,32 @@ const USDT_DECIMALS: u32 = 6;
 // Construct these assets from the perspective of AssetHub (1000).
 parameter_types! {
 	// `Assets` instance that contains no assets.
-	pub EmptyAssets: Assets = todo!();
+	pub EmptyAssets: Assets = vec![].into();
 	// USDT.
-	pub Usdt: AssetId = todo!();
+	pub Usdt: AssetId = (PalletInstance(50), GeneralIndex(1984)).into();
 	// The native token of the relay chain, i.e. DOT.
-	pub DotToken: AssetId = todo!();
+	pub DotToken: AssetId = Parent.into();
 	// 100 USDT.
-	pub OneHundredUsdt: Asset = todo!();
+	pub OneHundredUsdt: Asset = (Usdt::get(), 100u128 * 10u128.pow(USDT_DECIMALS)).into();
 	// Some amount of the native token of the relay chain.
-	pub OneHundredDot: Asset = todo!();
+	pub OneHundredDot: Asset = (DotToken::get(), 100u128 * 10u128.pow(DOT_DECIMALS)).into();
 }
 
 // Non-Fungible Tokens
 // Construct these assets from the perspective of AssetHub (1000).
 parameter_types! {
 	// Location of NFT collection with id 3 inside of the NFT pallet in Polkadot parachain 1000.
-	pub NftLocation: Location = todo!();
+	pub NftLocation: Location = [PalletInstance(52), GeneralIndex(3)].into();
 	// The NFT with id 69 inside of that collection.
-	pub Nft: Asset = todo!();
+	pub Nft: Asset = (NftLocation::get(), 69u64).into();
 }
 
 // Asset Filters
 parameter_types! {
 	// A filter which will capture all possible assets.
-	pub AllAssetsFilter: AssetFilter = todo!();
+	pub AllAssetsFilter: AssetFilter = AssetFilter::Wild(WildAsset::All);
 	// A filter specific for the DOT Token.
-	pub DotFilter: AssetFilter = todo!();
+	pub DotFilter: AssetFilter = OneHundredDot::get().into();
 	// A filter specific for USDT.
-	pub UsdtFilter: AssetFilter = todo!();
+	pub UsdtFilter: AssetFilter = OneHundredUsdt::get().into();
 }
#![allow(unused)]
fn main() {
//! # Fundamentals lesson 3: Assets Holding
//!
//! Create and managing an in-memory asset holding for the XCM Executor.

use sp_runtime::Saturating;
use sp_std::{
	collections::{btree_map::BTreeMap, btree_set::BTreeSet},
	mem,
	prelude::*,
};
use xcm::latest::prelude::*;

/// Map of non-wildcard fungible and non-fungible assets held in the holding register.
#[derive(Default, Clone, Debug, Eq, PartialEq)]
pub struct AssetsInHolding {
	/// The fungible assets.
	pub fungible: BTreeMap<AssetId, u128>,

	/// The non-fungible assets.
	pub non_fungible: BTreeSet<(AssetId, AssetInstance)>,
}

impl From<Vec<Asset>> for AssetsInHolding {
	fn from(assets: Vec<Asset>) -> AssetsInHolding {
		let mut result = Self::default();
		for asset in assets.into_iter() {
			result.subsume(asset)
		}
		result
	}
}

impl From<Assets> for AssetsInHolding {
	fn from(assets: Assets) -> AssetsInHolding {
		assets.into_inner().into()
	}
}

impl AssetsInHolding {
	/// New value, containing no assets.
	pub fn new() -> Self {
		Self::default()
	}

	/// Mutate `self` to contain the given `asset`, saturating if necessary.
	pub fn subsume(&mut self, asset: Asset) {
		/* TODO:
			- For fungible assets:
				- Check if we already have some existing assets in the holding.
				- If we do, `saturating_add` to the existing amount.
				- If we don't, `insert` the asset into the `BTreeMap`.
			- For non-fungible assets:
				- Simply insert the `asset.id` and `instance` into the `BTreeSet`.

		*/
		todo!("{:?}", asset)
	}

	/// Mutate `self` to contain all given `assets`, saturating if necessary.
	/// NOTE: This function can be written more optimally given the fact that assets in the holding
	/// are always in order.
	pub fn subsume_assets(&mut self, mut assets: AssetsInHolding) {
		/* TODO:
			- For each `(key, value)` in `assets.fungible`.
				- If the asset already exists `self.fungible`, `saturating_accrue` the new `value`.
				- If it is new, `insert` the new asset.
			- For non-fungible assets, take `self.non_fungible` and `append` the `assets.non_fungible`.
			- Then clear `assets.fungible` and `assets.non_fungible`.
		*/
		todo!("{:?}", assets)
	}

	/// Mutates `self` to its original value less `mask` and returns `true` iff it contains at least
	/// `mask`.
	///
	/// Returns `Ok` with the non-wildcard equivalence of `mask` taken and mutates `self` to its
	/// value minus `mask` if `self` contains `asset`, and return `Err` otherwise.
	pub fn saturating_take(&mut self, asset: AssetFilter) -> AssetsInHolding {
		let mut taken = AssetsInHolding::new();

		match asset {
			AssetFilter::Wild(All) => {
				/* TODO: Match on and return all assets.
					- Create a new `AssetsInHolding` called `new_holding`
					- use `mem::swap` to swap this with `self`
					- return the `new_holding`
				*/
				todo!()
			},
			AssetFilter::Definite(assets) =>
				for asset in assets.into_inner() {
					match asset {
						Asset { fun: Fungible(amount), id } => {
							/* TODO:
								- Check if there is any of this asset in the holding.
								- Get the `min` amount between the filter and what is in holding.
								- Reduce the holding by that amount.
								- Check if we should `remove` the asset from the holding when it's value goes to zero.
								- Finally, `subsume` these assets into `taken`.
							*/
							todo!("{:?} {:?}", amount, id)
						},
						Asset { fun: NonFungible(instance), id } => {
							/* TODO:
								- Try to `remove` the asset from `self.non_fungible`
								- If the asset was there, move it to `taken`
							*/
							todo!("{:?} {:?}", instance, id)
						},
					}
				},
				_ => unimplemented!("Handling other asset filters is not included to simplify the scope of the project.")
		}

		taken
	}

	/// A consuming iterator over all assets.
	pub fn into_assets_iter(self) -> impl Iterator<Item = Asset> {
		self.fungible
			.into_iter()
			.map(|(id, amount)| Asset { fun: Fungible(amount), id })
			.chain(
				self.non_fungible
					.into_iter()
					.map(|(id, instance)| Asset { fun: NonFungible(instance), id }),
			)
	}
}
}
#![allow(unused)]
fn main() {
//! # Fundamentals lesson 3: Assets Holding
//!
//! Create and managing an in-memory asset holding for the XCM Executor.

use sp_runtime::Saturating;
use sp_std::{
	collections::{btree_map::BTreeMap, btree_set::BTreeSet},
	mem,
	prelude::*,
};
use xcm::latest::prelude::*;

/// Map of non-wildcard fungible and non-fungible assets held in the holding register.
#[derive(Default, Clone, Debug, Eq, PartialEq)]
pub struct AssetsInHolding {
	/// The fungible assets.
	pub fungible: BTreeMap<AssetId, u128>,

	/// The non-fungible assets.
	pub non_fungible: BTreeSet<(AssetId, AssetInstance)>,
}

impl From<Vec<Asset>> for AssetsInHolding {
	fn from(assets: Vec<Asset>) -> AssetsInHolding {
		let mut result = Self::default();
		for asset in assets.into_iter() {
			result.subsume(asset)
		}
		result
	}
}

impl From<Assets> for AssetsInHolding {
	fn from(assets: Assets) -> AssetsInHolding {
		assets.into_inner().into()
	}
}

impl AssetsInHolding {
	/// New value, containing no assets.
	pub fn new() -> Self {
		Self::default()
	}

	/// Mutate `self` to contain the given `asset`, saturating if necessary.
	pub fn subsume(&mut self, asset: Asset) {
		match asset.fun {
			Fungible(amount) =>
				if let Some(existing_amount) = self.fungible.get_mut(&asset.id) {
					*existing_amount = existing_amount.saturating_add(amount);
				} else {
					self.fungible.insert(asset.id, amount);
				},
			NonFungible(instance) => {
				self.non_fungible.insert((asset.id, instance));
			},
		}
	}

	/// Mutate `self` to contain all given `assets`, saturating if necessary.
	/// NOTE: This function can be written more optimally given the fact that assets in the holding
	/// are always in order.
	pub fn subsume_assets(&mut self, mut assets: AssetsInHolding) {
		// Loop through all fungible assets in `assets` and add them to `self`
		for (key, value) in assets.fungible.iter_mut() {
			if let Some(existing_value) = self.fungible.get_mut(key) {
				// If the asset already exists in `self`, add the values, saturating if necessary
				existing_value.saturating_accrue(*value);
			} else {
				// Otherwise, insert the new asset into `self`
				self.fungible.insert(key.clone(), *value);
			}
		}

		// Append all non-fungible assets from `assets` to `self`
		self.non_fungible.append(&mut assets.non_fungible);

		// Clear the original `assets` collections as they are now part of `self`
		assets.fungible.clear();
		assets.non_fungible.clear();
	}

	/// Mutates `self` to its original value less `mask` and returns `true` iff it contains at least
	/// `mask`.
	///
	/// Returns `Ok` with the non-wildcard equivalence of `mask` taken and mutates `self` to its
	/// value minus `mask` if `self` contains `asset`, and return `Err` otherwise.
	pub fn saturating_take(&mut self, asset: AssetFilter) -> AssetsInHolding {
		let mut taken = AssetsInHolding::new();

		match asset {
			AssetFilter::Wild(All) => {
				let mut new_holding = AssetsInHolding::new();
				mem::swap(&mut *self, &mut new_holding);
				return new_holding
			},
			AssetFilter::Definite(assets) =>
				for asset in assets.into_inner() {
					match asset {
						Asset { fun: Fungible(amount), id } => {
							let amount = if let Some(self_amount) = self.fungible.get_mut(&id) {
								let amount = amount.min(*self_amount);
								*self_amount -= amount;
								if *self_amount == 0 {
									self.fungible.remove(&id);
								}
								amount
							} else {
								0
							};
							if amount > 0 {
								taken.subsume(Asset::from((id, amount)));
							}
						},
						Asset { fun: NonFungible(instance), id } => {
							let id_instance = (id, instance);
							if self.non_fungible.remove(&id_instance) {
								taken.subsume(id_instance.into());
							}
						},
					}
				},
				_ => unimplemented!("Handling other asset filters is not included to simplify the scope of the project.")
		}

		taken
	}

	/// A consuming iterator over all assets.
	pub fn into_assets_iter(self) -> impl Iterator<Item = Asset> {
		self.fungible
			.into_iter()
			.map(|(id, amount)| Asset { fun: Fungible(amount), id })
			.chain(
				self.non_fungible
					.into_iter()
					.map(|(id, instance)| Asset { fun: NonFungible(instance), id }),
			)
	}
}
}
diff --git a/fundamentals/src/holding.rs b/fundamentals/src/holding.rs
index 8b13789..8b9c09b 100644
--- a/fundamentals/src/holding.rs
+++ b/fundamentals/src/holding.rs
@@ -1 +1,129 @@
+//! # Fundamentals lesson 3: Assets Holding
+//!
+//! Create and managing an in-memory asset holding for the XCM Executor.
 
+use sp_runtime::Saturating;
+use sp_std::{
+	collections::{btree_map::BTreeMap, btree_set::BTreeSet},
+	mem,
+	prelude::*,
+};
+use xcm::latest::prelude::*;
+
+/// Map of non-wildcard fungible and non-fungible assets held in the holding register.
+#[derive(Default, Clone, Debug, Eq, PartialEq)]
+pub struct AssetsInHolding {
+	/// The fungible assets.
+	pub fungible: BTreeMap<AssetId, u128>,
+
+	/// The non-fungible assets.
+	pub non_fungible: BTreeSet<(AssetId, AssetInstance)>,
+}
+
+impl From<Vec<Asset>> for AssetsInHolding {
+	fn from(assets: Vec<Asset>) -> AssetsInHolding {
+		let mut result = Self::default();
+		for asset in assets.into_iter() {
+			result.subsume(asset)
+		}
+		result
+	}
+}
+
+impl From<Assets> for AssetsInHolding {
+	fn from(assets: Assets) -> AssetsInHolding {
+		assets.into_inner().into()
+	}
+}
+
+impl AssetsInHolding {
+	/// New value, containing no assets.
+	pub fn new() -> Self {
+		Self::default()
+	}
+
+	/// Mutate `self` to contain the given `asset`, saturating if necessary.
+	pub fn subsume(&mut self, asset: Asset) {
+		/* TODO:
+			- For fungible assets:
+				- Check if we already have some existing assets in the holding.
+				- If we do, `saturating_add` to the existing amount.
+				- If we don't, `insert` the asset into the `BTreeMap`.
+			- For non-fungible assets:
+				- Simply insert the `asset.id` and `instance` into the `BTreeSet`.
+
+		*/
+		todo!("{:?}", asset)
+	}
+
+	/// Mutate `self` to contain all given `assets`, saturating if necessary.
+	/// NOTE: This function can be written more optimally given the fact that assets in the holding
+	/// are always in order.
+	pub fn subsume_assets(&mut self, mut assets: AssetsInHolding) {
+		/* TODO:
+			- For each `(key, value)` in `assets.fungible`.
+				- If the asset already exists `self.fungible`, `saturating_accrue` the new `value`.
+				- If it is new, `insert` the new asset.
+			- For non-fungible assets, take `self.non_fungible` and `append` the `assets.non_fungible`.
+			- Then clear `assets.fungible` and `assets.non_fungible`.
+		*/
+		todo!("{:?}", assets)
+	}
+
+	/// Mutates `self` to its original value less `mask` and returns `true` iff it contains at least
+	/// `mask`.
+	///
+	/// Returns `Ok` with the non-wildcard equivalence of `mask` taken and mutates `self` to its
+	/// value minus `mask` if `self` contains `asset`, and return `Err` otherwise.
+	pub fn saturating_take(&mut self, asset: AssetFilter) -> AssetsInHolding {
+		let mut taken = AssetsInHolding::new();
+
+		match asset {
+			AssetFilter::Wild(All) => {
+				/* TODO: Match on and return all assets.
+					- Create a new `AssetsInHolding` called `new_holding`
+					- use `mem::swap` to swap this with `self`
+					- return the `new_holding`
+				*/
+				todo!()
+			},
+			AssetFilter::Definite(assets) =>
+				for asset in assets.into_inner() {
+					match asset {
+						Asset { fun: Fungible(amount), id } => {
+							/* TODO:
+								- Check if there is any of this asset in the holding.
+								- Get the `min` amount between the filter and what is in holding.
+								- Reduce the holding by that amount.
+								- Check if we should `remove` the asset from the holding when it's value goes to zero.
+								- Finally, `subsume` these assets into `taken`.
+							*/
+							todo!("{:?} {:?}", amount, id)
+						},
+						Asset { fun: NonFungible(instance), id } => {
+							/* TODO:
+								- Try to `remove` the asset from `self.non_fungible`
+								- If the asset was there, move it to `taken`
+							*/
+							todo!("{:?} {:?}", instance, id)
+						},
+					}
+				},
+				_ => unimplemented!("Handling other asset filters is not included to simplify the scope of the project.")
+		}
+
+		taken
+	}
+
+	/// A consuming iterator over all assets.
+	pub fn into_assets_iter(self) -> impl Iterator<Item = Asset> {
+		self.fungible
+			.into_iter()
+			.map(|(id, amount)| Asset { fun: Fungible(amount), id })
+			.chain(
+				self.non_fungible
+					.into_iter()
+					.map(|(id, instance)| Asset { fun: NonFungible(instance), id }),
+			)
+	}
+}
diff --git a/fundamentals/src/holding.rs b/fundamentals/src/holding.rs
index 8b9c09b..657ad56 100644
--- a/fundamentals/src/holding.rs
+++ b/fundamentals/src/holding.rs
@@ -44,30 +44,40 @@ impl AssetsInHolding {
 
 	/// Mutate `self` to contain the given `asset`, saturating if necessary.
 	pub fn subsume(&mut self, asset: Asset) {
-		/* TODO:
-			- For fungible assets:
-				- Check if we already have some existing assets in the holding.
-				- If we do, `saturating_add` to the existing amount.
-				- If we don't, `insert` the asset into the `BTreeMap`.
-			- For non-fungible assets:
-				- Simply insert the `asset.id` and `instance` into the `BTreeSet`.
-
-		*/
-		todo!("{:?}", asset)
+		match asset.fun {
+			Fungible(amount) =>
+				if let Some(existing_amount) = self.fungible.get_mut(&asset.id) {
+					*existing_amount = existing_amount.saturating_add(amount);
+				} else {
+					self.fungible.insert(asset.id, amount);
+				},
+			NonFungible(instance) => {
+				self.non_fungible.insert((asset.id, instance));
+			},
+		}
 	}
 
 	/// Mutate `self` to contain all given `assets`, saturating if necessary.
 	/// NOTE: This function can be written more optimally given the fact that assets in the holding
 	/// are always in order.
 	pub fn subsume_assets(&mut self, mut assets: AssetsInHolding) {
-		/* TODO:
-			- For each `(key, value)` in `assets.fungible`.
-				- If the asset already exists `self.fungible`, `saturating_accrue` the new `value`.
-				- If it is new, `insert` the new asset.
-			- For non-fungible assets, take `self.non_fungible` and `append` the `assets.non_fungible`.
-			- Then clear `assets.fungible` and `assets.non_fungible`.
-		*/
-		todo!("{:?}", assets)
+		// Loop through all fungible assets in `assets` and add them to `self`
+		for (key, value) in assets.fungible.iter_mut() {
+			if let Some(existing_value) = self.fungible.get_mut(key) {
+				// If the asset already exists in `self`, add the values, saturating if necessary
+				existing_value.saturating_accrue(*value);
+			} else {
+				// Otherwise, insert the new asset into `self`
+				self.fungible.insert(key.clone(), *value);
+			}
+		}
+
+		// Append all non-fungible assets from `assets` to `self`
+		self.non_fungible.append(&mut assets.non_fungible);
+
+		// Clear the original `assets` collections as they are now part of `self`
+		assets.fungible.clear();
+		assets.non_fungible.clear();
 	}
 
 	/// Mutates `self` to its original value less `mask` and returns `true` iff it contains at least
@@ -80,32 +90,33 @@ impl AssetsInHolding {
 
 		match asset {
 			AssetFilter::Wild(All) => {
-				/* TODO: Match on and return all assets.
-					- Create a new `AssetsInHolding` called `new_holding`
-					- use `mem::swap` to swap this with `self`
-					- return the `new_holding`
-				*/
-				todo!()
+				let mut new_holding = AssetsInHolding::new();
+				mem::swap(&mut *self, &mut new_holding);
+				return new_holding
 			},
 			AssetFilter::Definite(assets) =>
 				for asset in assets.into_inner() {
 					match asset {
 						Asset { fun: Fungible(amount), id } => {
-							/* TODO:
-								- Check if there is any of this asset in the holding.
-								- Get the `min` amount between the filter and what is in holding.
-								- Reduce the holding by that amount.
-								- Check if we should `remove` the asset from the holding when it's value goes to zero.
-								- Finally, `subsume` these assets into `taken`.
-							*/
-							todo!("{:?} {:?}", amount, id)
+							let amount = if let Some(self_amount) = self.fungible.get_mut(&id) {
+								let amount = amount.min(*self_amount);
+								*self_amount -= amount;
+								if *self_amount == 0 {
+									self.fungible.remove(&id);
+								}
+								amount
+							} else {
+								0
+							};
+							if amount > 0 {
+								taken.subsume(Asset::from((id, amount)));
+							}
 						},
 						Asset { fun: NonFungible(instance), id } => {
-							/* TODO:
-								- Try to `remove` the asset from `self.non_fungible`
-								- If the asset was there, move it to `taken`
-							*/
-							todo!("{:?} {:?}", instance, id)
+							let id_instance = (id, instance);
+							if self.non_fungible.remove(&id_instance) {
+								taken.subsume(id_instance.into());
+							}
 						},
 					}
 				},
#![allow(unused)]
fn main() {
//! # Fundamentals Lesson 4
//!
//! Instructions are the fundamental building block of XCM programs.
//! Let's look at the most basic ones.

use xcm::latest::prelude::*;

use crate::constants::ALICE;

/// A message containing only a simple `ClearOrigin` instruction.
/// This instruction clears the origin of the sender, meaning after this point,
/// no special privileges are granted.
pub fn clear_origin_message() -> Xcm<()> {
	let message = todo!();

	message
}

/// Put all your knowledge of assets to the test.
/// Use the `WithdrawAsset` instruction to withdraw 100 planks
/// of the relay native token, i.e. DOT.
/// The XCM program is executed on a parachain.
/// This program won't do anything with the funds.
pub fn withdraw_asset() -> Xcm<()> {
	let assets: Assets = (Parent, 100u128).into();
	let message = todo!("{:?}", assets);

	message
}

/// Let's do something with the funds.
/// This time, incorporate the `DepositAsset` instruction right after
/// withdrawing the assets.
/// Use the same assets.
/// Deposit all the assets to `ALICE`.
/// Remember how to use wildcards.
pub fn withdraw_and_deposit() -> Xcm<()> {
	let assets: Assets = (Parent, 100u128).into();
	let message = todo!("{:?}", assets);

	message
}

/// Normally, we charge fees for execution on the Blockchain.
/// XCM programs specify paying this fee with the `BuyExecution` instruction.
/// We're missing paying execution fees in the previous example.
/// Use up to 10% of the assets to pay for execution.
/// You're going to have to first convert `ALICE` into bytes.
/// Bonus points: Use the builder pattern.
pub fn withdraw_and_deposit_paying_fees() -> Xcm<()> {
	let alice_bytes: [u8; 32] = ALICE.into();
	let message = todo!("{:?}", alice_bytes);

	message
}
}
#![allow(unused)]
fn main() {
//! # Fundamentals Lesson 4
//!
//! Instructions are the fundamental building block of XCM programs.
//! Let's look at the most basic ones.

use xcm::latest::prelude::*;

use crate::constants::ALICE;

/// A message containing only a simple `ClearOrigin` instruction.
/// This instruction clears the origin of the sender, meaning after this point,
/// no special privileges are granted.
pub fn clear_origin_message() -> Xcm<()> {
	let message = Xcm(vec![ClearOrigin]);

	message
}

/// Put all your knowledge of assets to the test.
/// Use the `WithdrawAsset` instruction to withdraw 100 planks
/// of the relay native token, i.e. DOT.
/// The XCM program is executed on a parachain.
/// This program won't do anything with the funds.
pub fn withdraw_asset() -> Xcm<()> {
	let assets: Assets = (Parent, 100u128).into();
	let message = Xcm(vec![WithdrawAsset(assets)]);

	message
}

/// Let's do something with the funds.
/// This time, incorporate the `DepositAsset` instruction right after
/// withdrawing the assets.
/// Use the same assets.
/// Deposit all the assets to `ALICE`.
/// Remember how to use wildcards.
pub fn withdraw_and_deposit() -> Xcm<()> {
	let assets: Assets = (Parent, 100u128).into();
	let message = Xcm(vec![
		WithdrawAsset(assets),
		DepositAsset {
			assets: All.into(),
			beneficiary: AccountId32 { id: ALICE.into(), network: None }.into(),
		},
	]);

	message
}

/// Normally, we charge fees for execution on the Blockchain.
/// XCM programs specify paying this fee with the `BuyExecution` instruction.
/// We're missing paying execution fees in the previous example.
/// Use up to 10% of the assets to pay for execution.
/// You're going to have to first convert `ALICE` into bytes.
/// Bonus points: Use the builder pattern.
pub fn withdraw_and_deposit_paying_fees() -> Xcm<()> {
	let alice_bytes: [u8; 32] = ALICE.into();
	let message = Xcm::builder()
		.withdraw_asset((Parent, 100u128))
		.buy_execution((Parent, 10u128), Unlimited)
		.deposit_asset(All, alice_bytes)
		.build();

	message
}
}
diff --git a/fundamentals/src/instruction.rs b/fundamentals/src/instruction.rs
index 8b13789..4a8bbfd 100644
--- a/fundamentals/src/instruction.rs
+++ b/fundamentals/src/instruction.rs
@@ -1 +1,55 @@
+//! # Fundamentals Lesson 4
+//!
+//! Instructions are the fundamental building block of XCM programs.
+//! Let's look at the most basic ones.
 
+use xcm::latest::prelude::*;
+
+use crate::constants::ALICE;
+
+/// A message containing only a simple `ClearOrigin` instruction.
+/// This instruction clears the origin of the sender, meaning after this point,
+/// no special privileges are granted.
+pub fn clear_origin_message() -> Xcm<()> {
+	let message = todo!();
+
+	message
+}
+
+/// Put all your knowledge of assets to the test.
+/// Use the `WithdrawAsset` instruction to withdraw 100 planks
+/// of the relay native token, i.e. DOT.
+/// The XCM program is executed on a parachain.
+/// This program won't do anything with the funds.
+pub fn withdraw_asset() -> Xcm<()> {
+	let assets: Assets = (Parent, 100u128).into();
+	let message = todo!("{:?}", assets);
+
+	message
+}
+
+/// Let's do something with the funds.
+/// This time, incorporate the `DepositAsset` instruction right after
+/// withdrawing the assets.
+/// Use the same assets.
+/// Deposit all the assets to `ALICE`.
+/// Remember how to use wildcards.
+pub fn withdraw_and_deposit() -> Xcm<()> {
+	let assets: Assets = (Parent, 100u128).into();
+	let message = todo!("{:?}", assets);
+
+	message
+}
+
+/// Normally, we charge fees for execution on the Blockchain.
+/// XCM programs specify paying this fee with the `BuyExecution` instruction.
+/// We're missing paying execution fees in the previous example.
+/// Use up to 10% of the assets to pay for execution.
+/// You're going to have to first convert `ALICE` into bytes.
+/// Bonus points: Use the builder pattern.
+pub fn withdraw_and_deposit_paying_fees() -> Xcm<()> {
+	let alice_bytes: [u8; 32] = ALICE.into();
+	let message = todo!("{:?}", alice_bytes);
+
+	message
+}
diff --git a/fundamentals/src/instruction.rs b/fundamentals/src/instruction.rs
index 4a8bbfd..c4c5ab5 100644
--- a/fundamentals/src/instruction.rs
+++ b/fundamentals/src/instruction.rs
@@ -11,7 +11,7 @@ use crate::constants::ALICE;
 /// This instruction clears the origin of the sender, meaning after this point,
 /// no special privileges are granted.
 pub fn clear_origin_message() -> Xcm<()> {
-	let message = todo!();
+	let message = Xcm(vec![ClearOrigin]);
 
 	message
 }
@@ -23,7 +23,7 @@ pub fn clear_origin_message() -> Xcm<()> {
 /// This program won't do anything with the funds.
 pub fn withdraw_asset() -> Xcm<()> {
 	let assets: Assets = (Parent, 100u128).into();
-	let message = todo!("{:?}", assets);
+	let message = Xcm(vec![WithdrawAsset(assets)]);
 
 	message
 }
@@ -36,7 +36,13 @@ pub fn withdraw_asset() -> Xcm<()> {
 /// Remember how to use wildcards.
 pub fn withdraw_and_deposit() -> Xcm<()> {
 	let assets: Assets = (Parent, 100u128).into();
-	let message = todo!("{:?}", assets);
+	let message = Xcm(vec![
+		WithdrawAsset(assets),
+		DepositAsset {
+			assets: All.into(),
+			beneficiary: AccountId32 { id: ALICE.into(), network: None }.into(),
+		},
+	]);
 
 	message
 }
@@ -49,7 +55,11 @@ pub fn withdraw_and_deposit() -> Xcm<()> {
 /// Bonus points: Use the builder pattern.
 pub fn withdraw_and_deposit_paying_fees() -> Xcm<()> {
 	let alice_bytes: [u8; 32] = ALICE.into();
-	let message = todo!("{:?}", alice_bytes);
+	let message = Xcm::builder()
+		.withdraw_asset((Parent, 100u128))
+		.buy_execution((Parent, 10u128), Unlimited)
+		.deposit_asset(All, alice_bytes)
+		.build();
 
 	message
 }

The XCM Executor

Start of XCM Executor

#![allow(unused)]
fn main() {
//! # Fundamentals lesson 5: XCM Executor
//!
//! Create your own executor for XCM.

use super::holding::*;

use sp_std::{marker::PhantomData, prelude::*};
use xcm::latest::prelude::*;
use xcm_executor::traits::{ProcessTransaction, TransactAsset};

pub trait XcmConfig {
	/// How to withdraw and deposit an asset.
	type AssetTransactor: TransactAsset;
	/// Transactional processor for XCM instructions.
	type TransactionalProcessor: ProcessTransaction;
}

/// The heart of the XCM Virtual Machine.
pub struct XcmExecutor<Config: XcmConfig> {
	/// The asset holding registrar, where we keep track of assets being processed by the XCM
	/// Executor.
	pub holding: AssetsInHolding,
	/// Contextual data pertaining to a specific list of XCM instructions. Most relevant the
	/// `origin` of the XCM Message.
	pub context: XcmContext,
	/// Just a placeholder to allow Rust to let us keep `Config`.
	_config: PhantomData<Config>,
}

/// The implementation of the XCM Executor and how it processes XCM.
impl<Config: XcmConfig> XcmExecutor<Config> {
	/// Crete an initialize a new XCM Executor.
	pub fn new(origin: impl Into<Location>) -> Self {
		let origin = origin.into();
		// In our version of the XCM Executor, we ignore `message_id` and `topic`.
		let context =
			XcmContext { origin: Some(origin), message_id: Default::default(), topic: None };
		Self { holding: Default::default(), context, _config: PhantomData }
	}

	/// Process an entire XCM program, instruction by instruction.
	pub fn process(&mut self, xcm: Xcm<()>) -> Result<(), XcmError> {
		log::trace!(target: "xcm::process", "xcm: {:?}", xcm);
		for instruction in xcm.0.into_iter() {
			self.process_instruction(instruction)?;
		}
		Ok(())
	}

	/// Simple helper function to access the `origin` from the XCM Executor `context`.
	pub fn origin_ref(&self) -> Option<&Location> {
		self.context.origin.as_ref()
	}

	/// Process a single XCM instruction, mutating the state of the XCM virtual machine.
	fn process_instruction(&mut self, instr: Instruction<()>) -> Result<(), XcmError> {
		log::trace!(target: "xcm::process_instruction", "=== {:?}", instr);
		match instr {
			// Clear the origin.
			//
			// This may be used by the XCM author to ensure that later instructions cannot command
			// the authority of the origin (e.g. if they are being relayed from an untrusted
			// source, as often the case with `ReserveAssetDeposited`).
			ClearOrigin => {
				todo!()
			},
			// Appends `who` to the current XCM Executor `origin` location.
			DescendOrigin(who) => {
				todo!("{:?}", who)
			},
			// Withdraw asset(s) (`assets`) from the ownership of `origin` and place equivalent
			// assets under the ownership of `beneficiary`.
			//
			// - `assets`: The asset(s) to be withdrawn.
			// - `beneficiary`: The new owner for the assets.
			TransferAsset { assets, beneficiary } => {
				todo!("{:?} {:?}", assets, beneficiary)
			},
			// Withdraw asset(s) (`assets`) from the ownership of `origin` and place them into the
			// Holding Register.
			//
			// - `assets`: The asset(s) to be withdrawn into holding.
			WithdrawAsset(assets) => {
				todo!("{:?}", assets)
			},
			// Reduce Holding by up to the given assets.
			//
			// Holding is reduced by as much as possible up to the assets in the parameter. It is
			// not an error if the Holding does not contain the assets (to make this an error, use
			// `ExpectAsset` prior).
			BurnAsset(assets) => {
				todo!("{:?}", assets)
			},
			// Remove the asset(s) (`assets`) from the Holding Register and place equivalent assets
			// under the ownership of `beneficiary` within this consensus system.
			//
			// - `assets`: The asset(s) to remove from holding.
			// - `beneficiary`: The new owner for the assets.
			DepositAsset { assets, beneficiary } => {
				todo!("{:?} {:?}", assets, beneficiary)
			},
			// Asset(s) (`assets`) have been destroyed on the `origin` system and equivalent assets
			// should be created and placed into the Holding Register.
			//
			// - `assets`: The asset(s) that are minted into the Holding Register.
			ReceiveTeleportedAsset(assets) => {
				todo!("{:?}", assets)
			},
			// In this workshop, we won't be implementing every instruction, just the ones above...
			// Our executor will simply panic if you try to execute other instructions.
			_ => unimplemented!(),
		}
	}
}

/// A public trait allowing other systems to access and use the `XcmExecutor`.
pub trait ExecuteXcm {
	/// Execute an XCM from a given `origin`.
	fn execute(origin: impl Into<Location>, xcm: Xcm<()>) -> XcmResult;
}

impl<Config: XcmConfig> ExecuteXcm for XcmExecutor<Config> {
	/// Execute an XCM from a given `origin`.
	fn execute(origin: impl Into<Location>, xcm: Xcm<()>) -> XcmResult {
		log::trace!(target: "xcm::execute", "xcm: {:?}", xcm);
		todo!("{:?}", origin.into())
	}
}
}
diff --git a/fundamentals/src/xcm_executor.rs b/fundamentals/src/xcm_executor.rs
index 8b13789..9c6cb16 100644
--- a/fundamentals/src/xcm_executor.rs
+++ b/fundamentals/src/xcm_executor.rs
@@ -1 +1,128 @@
+//! # Fundamentals lesson 5: XCM Executor
+//!
+//! Create your own executor for XCM.
 
+use super::holding::*;
+
+use sp_std::{marker::PhantomData, prelude::*};
+use xcm::latest::prelude::*;
+use xcm_executor::traits::{ProcessTransaction, TransactAsset};
+
+pub trait XcmConfig {
+	/// How to withdraw and deposit an asset.
+	type AssetTransactor: TransactAsset;
+	/// Transactional processor for XCM instructions.
+	type TransactionalProcessor: ProcessTransaction;
+}
+
+/// The heart of the XCM Virtual Machine.
+pub struct XcmExecutor<Config: XcmConfig> {
+	/// The asset holding registrar, where we keep track of assets being processed by the XCM
+	/// Executor.
+	pub holding: AssetsInHolding,
+	/// Contextual data pertaining to a specific list of XCM instructions. Most relevant the
+	/// `origin` of the XCM Message.
+	pub context: XcmContext,
+	/// Just a placeholder to allow Rust to let us keep `Config`.
+	_config: PhantomData<Config>,
+}
+
+/// The implementation of the XCM Executor and how it processes XCM.
+impl<Config: XcmConfig> XcmExecutor<Config> {
+	/// Crete an initialize a new XCM Executor.
+	pub fn new(origin: impl Into<Location>) -> Self {
+		let origin = origin.into();
+		// In our version of the XCM Executor, we ignore `message_id` and `topic`.
+		let context =
+			XcmContext { origin: Some(origin), message_id: Default::default(), topic: None };
+		Self { holding: Default::default(), context, _config: PhantomData }
+	}
+
+	/// Process an entire XCM program, instruction by instruction.
+	pub fn process(&mut self, xcm: Xcm<()>) -> Result<(), XcmError> {
+		log::trace!(target: "xcm::process", "xcm: {:?}", xcm);
+		for instruction in xcm.0.into_iter() {
+			self.process_instruction(instruction)?;
+		}
+		Ok(())
+	}
+
+	/// Simple helper function to access the `origin` from the XCM Executor `context`.
+	pub fn origin_ref(&self) -> Option<&Location> {
+		self.context.origin.as_ref()
+	}
+
+	/// Process a single XCM instruction, mutating the state of the XCM virtual machine.
+	fn process_instruction(&mut self, instr: Instruction<()>) -> Result<(), XcmError> {
+		log::trace!(target: "xcm::process_instruction", "=== {:?}", instr);
+		match instr {
+			// Clear the origin.
+			//
+			// This may be used by the XCM author to ensure that later instructions cannot command
+			// the authority of the origin (e.g. if they are being relayed from an untrusted
+			// source, as often the case with `ReserveAssetDeposited`).
+			ClearOrigin => {
+				todo!()
+			},
+			// Appends `who` to the current XCM Executor `origin` location.
+			DescendOrigin(who) => {
+				todo!("{:?}", who)
+			},
+			// Withdraw asset(s) (`assets`) from the ownership of `origin` and place equivalent
+			// assets under the ownership of `beneficiary`.
+			//
+			// - `assets`: The asset(s) to be withdrawn.
+			// - `beneficiary`: The new owner for the assets.
+			TransferAsset { assets, beneficiary } => {
+				todo!("{:?} {:?}", assets, beneficiary)
+			},
+			// Withdraw asset(s) (`assets`) from the ownership of `origin` and place them into the
+			// Holding Register.
+			//
+			// - `assets`: The asset(s) to be withdrawn into holding.
+			WithdrawAsset(assets) => {
+				todo!("{:?}", assets)
+			},
+			// Reduce Holding by up to the given assets.
+			//
+			// Holding is reduced by as much as possible up to the assets in the parameter. It is
+			// not an error if the Holding does not contain the assets (to make this an error, use
+			// `ExpectAsset` prior).
+			BurnAsset(assets) => {
+				todo!("{:?}", assets)
+			},
+			// Remove the asset(s) (`assets`) from the Holding Register and place equivalent assets
+			// under the ownership of `beneficiary` within this consensus system.
+			//
+			// - `assets`: The asset(s) to remove from holding.
+			// - `beneficiary`: The new owner for the assets.
+			DepositAsset { assets, beneficiary } => {
+				todo!("{:?} {:?}", assets, beneficiary)
+			},
+			// Asset(s) (`assets`) have been destroyed on the `origin` system and equivalent assets
+			// should be created and placed into the Holding Register.
+			//
+			// - `assets`: The asset(s) that are minted into the Holding Register.
+			ReceiveTeleportedAsset(assets) => {
+				todo!("{:?}", assets)
+			},
+			// In this workshop, we won't be implementing every instruction, just the ones above...
+			// Our executor will simply panic if you try to execute other instructions.
+			_ => unimplemented!(),
+		}
+	}
+}
+
+/// A public trait allowing other systems to access and use the `XcmExecutor`.
+pub trait ExecuteXcm {
+	/// Execute an XCM from a given `origin`.
+	fn execute(origin: impl Into<Location>, xcm: Xcm<()>) -> XcmResult;
+}
+
+impl<Config: XcmConfig> ExecuteXcm for XcmExecutor<Config> {
+	/// Execute an XCM from a given `origin`.
+	fn execute(origin: impl Into<Location>, xcm: Xcm<()>) -> XcmResult {
+		log::trace!(target: "xcm::execute", "xcm: {:?}", xcm);
+		todo!("{:?}", origin.into())
+	}
+}
#![allow(unused)]
fn main() {
//! # Fundamentals lesson 5: XCM Executor
//!
//! Create your own executor for XCM.

use super::holding::*;

use sp_std::{marker::PhantomData, prelude::*};
use xcm::latest::prelude::*;
use xcm_executor::traits::{ProcessTransaction, TransactAsset};

pub trait XcmConfig {
	/// How to withdraw and deposit an asset.
	type AssetTransactor: TransactAsset;
	/// Transactional processor for XCM instructions.
	type TransactionalProcessor: ProcessTransaction;
}

/// The heart of the XCM Virtual Machine.
pub struct XcmExecutor<Config: XcmConfig> {
	/// The asset holding registrar, where we keep track of assets being processed by the XCM
	/// Executor.
	pub holding: AssetsInHolding,
	/// Contextual data pertaining to a specific list of XCM instructions. Most relevant the
	/// `origin` of the XCM Message.
	pub context: XcmContext,
	/// Just a placeholder to allow Rust to let us keep `Config`.
	_config: PhantomData<Config>,
}

/// The implementation of the XCM Executor and how it processes XCM.
impl<Config: XcmConfig> XcmExecutor<Config> {
	/// Crete an initialize a new XCM Executor.
	pub fn new(origin: impl Into<Location>) -> Self {
		let origin = origin.into();
		// In our version of the XCM Executor, we ignore `message_id` and `topic`.
		let context =
			XcmContext { origin: Some(origin), message_id: Default::default(), topic: None };
		Self { holding: Default::default(), context, _config: PhantomData }
	}

	/// Process an entire XCM program, instruction by instruction.
	pub fn process(&mut self, xcm: Xcm<()>) -> Result<(), XcmError> {
		log::trace!(target: "xcm::process", "xcm: {:?}", xcm);
		for instruction in xcm.0.into_iter() {
			self.process_instruction(instruction)?;
		}
		Ok(())
	}

	/// Simple helper function to access the `origin` from the XCM Executor `context`.
	pub fn origin_ref(&self) -> Option<&Location> {
		self.context.origin.as_ref()
	}

	/// Process a single XCM instruction, mutating the state of the XCM virtual machine.
	fn process_instruction(&mut self, instr: Instruction<()>) -> Result<(), XcmError> {
		log::trace!(target: "xcm::process_instruction", "=== {:?}", instr);
		match instr {
			// Clear the origin.
			//
			// This may be used by the XCM author to ensure that later instructions cannot command
			// the authority of the origin (e.g. if they are being relayed from an untrusted
			// source, as often the case with `ReserveAssetDeposited`).
			ClearOrigin => {
				/* TODO: Simply set `self.context.origin` to `None` */
				todo!()
			},
			// Appends `who` to the current XCM Executor `origin` location.
			DescendOrigin(who) => {
				/* TODO:
					- Get the `self.context.origin`.
					- Access it `as_mut()`.
					- If `origin` is `None`, return `XcmError::BadOrigin`.
					- Then `append_with` `who`
					- If the append fails, return `XcmError::LocationFull`.
				*/
				todo!("{:?}", who)
			},
			// Withdraw asset(s) (`assets`) from the ownership of `origin` and place equivalent
			// assets under the ownership of `beneficiary`.
			//
			// - `assets`: The asset(s) to be withdrawn.
			// - `beneficiary`: The new owner for the assets.
			TransferAsset { assets, beneficiary } => {
				todo!("{:?} {:?}", assets, beneficiary)
			},
			// Withdraw asset(s) (`assets`) from the ownership of `origin` and place them into the
			// Holding Register.
			//
			// - `assets`: The asset(s) to be withdrawn into holding.
			WithdrawAsset(assets) => {
				todo!("{:?}", assets)
			},
			// Reduce Holding by up to the given assets.
			//
			// Holding is reduced by as much as possible up to the assets in the parameter. It is
			// not an error if the Holding does not contain the assets (to make this an error, use
			// `ExpectAsset` prior).
			BurnAsset(assets) => {
				todo!("{:?}", assets)
			},
			// Remove the asset(s) (`assets`) from the Holding Register and place equivalent assets
			// under the ownership of `beneficiary` within this consensus system.
			//
			// - `assets`: The asset(s) to remove from holding.
			// - `beneficiary`: The new owner for the assets.
			DepositAsset { assets, beneficiary } => {
				todo!("{:?} {:?}", assets, beneficiary)
			},
			// Asset(s) (`assets`) have been destroyed on the `origin` system and equivalent assets
			// should be created and placed into the Holding Register.
			//
			// - `assets`: The asset(s) that are minted into the Holding Register.
			ReceiveTeleportedAsset(assets) => {
				todo!("{:?}", assets)
			},
			// In this workshop, we won't be implementing every instruction, just the ones above...
			// Our executor will simply panic if you try to execute other instructions.
			_ => unimplemented!(),
		}
	}
}

/// A public trait allowing other systems to access and use the `XcmExecutor`.
pub trait ExecuteXcm {
	/// Execute an XCM from a given `origin`.
	fn execute(origin: impl Into<Location>, xcm: Xcm<()>) -> XcmResult;
}

impl<Config: XcmConfig> ExecuteXcm for XcmExecutor<Config> {
	/// Execute an XCM from a given `origin`.
	fn execute(origin: impl Into<Location>, xcm: Xcm<()>) -> XcmResult {
		log::trace!(target: "xcm::execute", "xcm: {:?}", xcm);
		todo!("{:?}", origin.into())
	}
}
}
#![allow(unused)]
fn main() {
//! # Fundamentals lesson 5: XCM Executor
//!
//! Create your own executor for XCM.

use super::holding::*;

use sp_std::{marker::PhantomData, prelude::*};
use xcm::latest::prelude::*;
use xcm_executor::traits::{ProcessTransaction, TransactAsset};

pub trait XcmConfig {
	/// How to withdraw and deposit an asset.
	type AssetTransactor: TransactAsset;
	/// Transactional processor for XCM instructions.
	type TransactionalProcessor: ProcessTransaction;
}

/// The heart of the XCM Virtual Machine.
pub struct XcmExecutor<Config: XcmConfig> {
	/// The asset holding registrar, where we keep track of assets being processed by the XCM
	/// Executor.
	pub holding: AssetsInHolding,
	/// Contextual data pertaining to a specific list of XCM instructions. Most relevant the
	/// `origin` of the XCM Message.
	pub context: XcmContext,
	/// Just a placeholder to allow Rust to let us keep `Config`.
	_config: PhantomData<Config>,
}

/// The implementation of the XCM Executor and how it processes XCM.
impl<Config: XcmConfig> XcmExecutor<Config> {
	/// Crete an initialize a new XCM Executor.
	pub fn new(origin: impl Into<Location>) -> Self {
		let origin = origin.into();
		// In our version of the XCM Executor, we ignore `message_id` and `topic`.
		let context =
			XcmContext { origin: Some(origin), message_id: Default::default(), topic: None };
		Self { holding: Default::default(), context, _config: PhantomData }
	}

	/// Process an entire XCM program, instruction by instruction.
	pub fn process(&mut self, xcm: Xcm<()>) -> Result<(), XcmError> {
		log::trace!(target: "xcm::process", "xcm: {:?}", xcm);
		for instruction in xcm.0.into_iter() {
			self.process_instruction(instruction)?;
		}
		Ok(())
	}

	/// Simple helper function to access the `origin` from the XCM Executor `context`.
	pub fn origin_ref(&self) -> Option<&Location> {
		self.context.origin.as_ref()
	}

	/// Process a single XCM instruction, mutating the state of the XCM virtual machine.
	fn process_instruction(&mut self, instr: Instruction<()>) -> Result<(), XcmError> {
		log::trace!(target: "xcm::process_instruction", "=== {:?}", instr);
		match instr {
			// Clear the origin.
			//
			// This may be used by the XCM author to ensure that later instructions cannot command
			// the authority of the origin (e.g. if they are being relayed from an untrusted
			// source, as often the case with `ReserveAssetDeposited`).
			ClearOrigin => {
				self.context.origin = None;
				Ok(())
			},
			// Appends `who` to the current XCM Executor `origin` location.
			DescendOrigin(who) => self
				.context
				.origin
				.as_mut()
				.ok_or(XcmError::BadOrigin)?
				.append_with(who)
				.map_err(|_| XcmError::LocationFull),
			// Withdraw asset(s) (`assets`) from the ownership of `origin` and place equivalent
			// assets under the ownership of `beneficiary`.
			//
			// - `assets`: The asset(s) to be withdrawn.
			// - `beneficiary`: The new owner for the assets.
			TransferAsset { assets, beneficiary } => {
				todo!("{:?} {:?}", assets, beneficiary)
			},
			// Withdraw asset(s) (`assets`) from the ownership of `origin` and place them into the
			// Holding Register.
			//
			// - `assets`: The asset(s) to be withdrawn into holding.
			WithdrawAsset(assets) => {
				todo!("{:?}", assets)
			},
			// Reduce Holding by up to the given assets.
			//
			// Holding is reduced by as much as possible up to the assets in the parameter. It is
			// not an error if the Holding does not contain the assets (to make this an error, use
			// `ExpectAsset` prior).
			BurnAsset(assets) => {
				todo!("{:?}", assets)
			},
			// Remove the asset(s) (`assets`) from the Holding Register and place equivalent assets
			// under the ownership of `beneficiary` within this consensus system.
			//
			// - `assets`: The asset(s) to remove from holding.
			// - `beneficiary`: The new owner for the assets.
			DepositAsset { assets, beneficiary } => {
				todo!("{:?} {:?}", assets, beneficiary)
			},
			// Asset(s) (`assets`) have been destroyed on the `origin` system and equivalent assets
			// should be created and placed into the Holding Register.
			//
			// - `assets`: The asset(s) that are minted into the Holding Register.
			ReceiveTeleportedAsset(assets) => {
				todo!("{:?}", assets)
			},
			// In this workshop, we won't be implementing every instruction, just the ones above...
			// Our executor will simply panic if you try to execute other instructions.
			_ => unimplemented!(),
		}
	}
}

/// A public trait allowing other systems to access and use the `XcmExecutor`.
pub trait ExecuteXcm {
	/// Execute an XCM from a given `origin`.
	fn execute(origin: impl Into<Location>, xcm: Xcm<()>) -> XcmResult;
}

impl<Config: XcmConfig> ExecuteXcm for XcmExecutor<Config> {
	/// Execute an XCM from a given `origin`.
	fn execute(origin: impl Into<Location>, xcm: Xcm<()>) -> XcmResult {
		log::trace!(target: "xcm::execute", "xcm: {:?}", xcm);
		todo!("{:?}", origin.into())
	}
}
}
diff --git a/fundamentals/src/xcm_executor.rs b/fundamentals/src/xcm_executor.rs
index 9c6cb16..74d0c79 100644
--- a/fundamentals/src/xcm_executor.rs
+++ b/fundamentals/src/xcm_executor.rs
@@ -62,10 +62,18 @@ impl<Config: XcmConfig> XcmExecutor<Config> {
 			// the authority of the origin (e.g. if they are being relayed from an untrusted
 			// source, as often the case with `ReserveAssetDeposited`).
 			ClearOrigin => {
+				/* TODO: Simply set `self.context.origin` to `None` */
 				todo!()
 			},
 			// Appends `who` to the current XCM Executor `origin` location.
 			DescendOrigin(who) => {
+				/* TODO:
+					- Get the `self.context.origin`.
+					- Access it `as_mut()`.
+					- If `origin` is `None`, return `XcmError::BadOrigin`.
+					- Then `append_with` `who`
+					- If the append fails, return `XcmError::LocationFull`.
+				*/
 				todo!("{:?}", who)
 			},
 			// Withdraw asset(s) (`assets`) from the ownership of `origin` and place equivalent
diff --git a/fundamentals/src/xcm_executor.rs b/fundamentals/src/xcm_executor.rs
index 74d0c79..57e1bd4 100644
--- a/fundamentals/src/xcm_executor.rs
+++ b/fundamentals/src/xcm_executor.rs
@@ -62,20 +62,17 @@ impl<Config: XcmConfig> XcmExecutor<Config> {
 			// the authority of the origin (e.g. if they are being relayed from an untrusted
 			// source, as often the case with `ReserveAssetDeposited`).
 			ClearOrigin => {
-				/* TODO: Simply set `self.context.origin` to `None` */
-				todo!()
+				self.context.origin = None;
+				Ok(())
 			},
 			// Appends `who` to the current XCM Executor `origin` location.
-			DescendOrigin(who) => {
-				/* TODO:
-					- Get the `self.context.origin`.
-					- Access it `as_mut()`.
-					- If `origin` is `None`, return `XcmError::BadOrigin`.
-					- Then `append_with` `who`
-					- If the append fails, return `XcmError::LocationFull`.
-				*/
-				todo!("{:?}", who)
-			},
+			DescendOrigin(who) => self
+				.context
+				.origin
+				.as_mut()
+				.ok_or(XcmError::BadOrigin)?
+				.append_with(who)
+				.map_err(|_| XcmError::LocationFull),
 			// Withdraw asset(s) (`assets`) from the ownership of `origin` and place equivalent
 			// assets under the ownership of `beneficiary`.
 			//
#![allow(unused)]
fn main() {
//! # Fundamentals lesson 5: XCM Executor
//!
//! Create your own executor for XCM.

use super::holding::*;

use sp_std::{marker::PhantomData, prelude::*};
use xcm::latest::prelude::*;
use xcm_executor::traits::{ProcessTransaction, TransactAsset};

pub trait XcmConfig {
	/// How to withdraw and deposit an asset.
	type AssetTransactor: TransactAsset;
	/// Transactional processor for XCM instructions.
	type TransactionalProcessor: ProcessTransaction;
}

/// The heart of the XCM Virtual Machine.
pub struct XcmExecutor<Config: XcmConfig> {
	/// The asset holding registrar, where we keep track of assets being processed by the XCM
	/// Executor.
	pub holding: AssetsInHolding,
	/// Contextual data pertaining to a specific list of XCM instructions. Most relevant the
	/// `origin` of the XCM Message.
	pub context: XcmContext,
	/// Just a placeholder to allow Rust to let us keep `Config`.
	_config: PhantomData<Config>,
}

/// The implementation of the XCM Executor and how it processes XCM.
impl<Config: XcmConfig> XcmExecutor<Config> {
	/// Crete an initialize a new XCM Executor.
	pub fn new(origin: impl Into<Location>) -> Self {
		let origin = origin.into();
		// In our version of the XCM Executor, we ignore `message_id` and `topic`.
		let context =
			XcmContext { origin: Some(origin), message_id: Default::default(), topic: None };
		Self { holding: Default::default(), context, _config: PhantomData }
	}

	/// Process an entire XCM program, instruction by instruction.
	pub fn process(&mut self, xcm: Xcm<()>) -> Result<(), XcmError> {
		log::trace!(target: "xcm::process", "xcm: {:?}", xcm);
		for instruction in xcm.0.into_iter() {
			self.process_instruction(instruction)?;
		}
		Ok(())
	}

	/// Simple helper function to access the `origin` from the XCM Executor `context`.
	pub fn origin_ref(&self) -> Option<&Location> {
		self.context.origin.as_ref()
	}

	/// Process a single XCM instruction, mutating the state of the XCM virtual machine.
	fn process_instruction(&mut self, instr: Instruction<()>) -> Result<(), XcmError> {
		log::trace!(target: "xcm::process_instruction", "=== {:?}", instr);
		match instr {
			// Clear the origin.
			//
			// This may be used by the XCM author to ensure that later instructions cannot command
			// the authority of the origin (e.g. if they are being relayed from an untrusted
			// source, as often the case with `ReserveAssetDeposited`).
			ClearOrigin => {
				self.context.origin = None;
				Ok(())
			},
			// Appends `who` to the current XCM Executor `origin` location.
			DescendOrigin(who) => self
				.context
				.origin
				.as_mut()
				.ok_or(XcmError::BadOrigin)?
				.append_with(who)
				.map_err(|_| XcmError::LocationFull),
			// Withdraw asset(s) (`assets`) from the ownership of `origin` and place equivalent
			// assets under the ownership of `beneficiary`.
			//
			// - `assets`: The asset(s) to be withdrawn.
			// - `beneficiary`: The new owner for the assets.
			TransferAsset { assets, beneficiary } => {
				/* TODO:
					- Process everything inside a `TransactionalProcessor`.
					- Get the `origin` from `self.origin_ref()`.
					- For each `asset` in `assets`
						- Use `AssetTransactor` and `transfer_asset` to the `beneficiary`.
					- If everything works well, return `Ok(())`
				*/
				todo!("{:?} {:?}", assets, beneficiary)
			},
			// Withdraw asset(s) (`assets`) from the ownership of `origin` and place them into the
			// Holding Register.
			//
			// - `assets`: The asset(s) to be withdrawn into holding.
			WithdrawAsset(assets) => {
				todo!("{:?}", assets)
			},
			// Reduce Holding by up to the given assets.
			//
			// Holding is reduced by as much as possible up to the assets in the parameter. It is
			// not an error if the Holding does not contain the assets (to make this an error, use
			// `ExpectAsset` prior).
			BurnAsset(assets) => {
				todo!("{:?}", assets)
			},
			// Remove the asset(s) (`assets`) from the Holding Register and place equivalent assets
			// under the ownership of `beneficiary` within this consensus system.
			//
			// - `assets`: The asset(s) to remove from holding.
			// - `beneficiary`: The new owner for the assets.
			DepositAsset { assets, beneficiary } => {
				todo!("{:?} {:?}", assets, beneficiary)
			},
			// Asset(s) (`assets`) have been destroyed on the `origin` system and equivalent assets
			// should be created and placed into the Holding Register.
			//
			// - `assets`: The asset(s) that are minted into the Holding Register.
			ReceiveTeleportedAsset(assets) => {
				todo!("{:?}", assets)
			},
			// In this workshop, we won't be implementing every instruction, just the ones above...
			// Our executor will simply panic if you try to execute other instructions.
			_ => unimplemented!(),
		}
	}
}

/// A public trait allowing other systems to access and use the `XcmExecutor`.
pub trait ExecuteXcm {
	/// Execute an XCM from a given `origin`.
	fn execute(origin: impl Into<Location>, xcm: Xcm<()>) -> XcmResult;
}

impl<Config: XcmConfig> ExecuteXcm for XcmExecutor<Config> {
	/// Execute an XCM from a given `origin`.
	fn execute(origin: impl Into<Location>, xcm: Xcm<()>) -> XcmResult {
		log::trace!(target: "xcm::execute", "xcm: {:?}", xcm);
		todo!("{:?}", origin.into())
	}
}
}
#![allow(unused)]
fn main() {
//! # Fundamentals lesson 5: XCM Executor
//!
//! Create your own executor for XCM.

use super::holding::*;

use sp_std::{marker::PhantomData, prelude::*};
use xcm::latest::prelude::*;
use xcm_executor::traits::{ProcessTransaction, TransactAsset};

pub trait XcmConfig {
	/// How to withdraw and deposit an asset.
	type AssetTransactor: TransactAsset;
	/// Transactional processor for XCM instructions.
	type TransactionalProcessor: ProcessTransaction;
}

/// The heart of the XCM Virtual Machine.
pub struct XcmExecutor<Config: XcmConfig> {
	/// The asset holding registrar, where we keep track of assets being processed by the XCM
	/// Executor.
	pub holding: AssetsInHolding,
	/// Contextual data pertaining to a specific list of XCM instructions. Most relevant the
	/// `origin` of the XCM Message.
	pub context: XcmContext,
	/// Just a placeholder to allow Rust to let us keep `Config`.
	_config: PhantomData<Config>,
}

/// The implementation of the XCM Executor and how it processes XCM.
impl<Config: XcmConfig> XcmExecutor<Config> {
	/// Crete an initialize a new XCM Executor.
	pub fn new(origin: impl Into<Location>) -> Self {
		let origin = origin.into();
		// In our version of the XCM Executor, we ignore `message_id` and `topic`.
		let context =
			XcmContext { origin: Some(origin), message_id: Default::default(), topic: None };
		Self { holding: Default::default(), context, _config: PhantomData }
	}

	/// Process an entire XCM program, instruction by instruction.
	pub fn process(&mut self, xcm: Xcm<()>) -> Result<(), XcmError> {
		log::trace!(target: "xcm::process", "xcm: {:?}", xcm);
		for instruction in xcm.0.into_iter() {
			self.process_instruction(instruction)?;
		}
		Ok(())
	}

	/// Simple helper function to access the `origin` from the XCM Executor `context`.
	pub fn origin_ref(&self) -> Option<&Location> {
		self.context.origin.as_ref()
	}

	/// Process a single XCM instruction, mutating the state of the XCM virtual machine.
	fn process_instruction(&mut self, instr: Instruction<()>) -> Result<(), XcmError> {
		log::trace!(target: "xcm::process_instruction", "=== {:?}", instr);
		match instr {
			// Clear the origin.
			//
			// This may be used by the XCM author to ensure that later instructions cannot command
			// the authority of the origin (e.g. if they are being relayed from an untrusted
			// source, as often the case with `ReserveAssetDeposited`).
			ClearOrigin => {
				self.context.origin = None;
				Ok(())
			},
			// Appends `who` to the current XCM Executor `origin` location.
			DescendOrigin(who) => self
				.context
				.origin
				.as_mut()
				.ok_or(XcmError::BadOrigin)?
				.append_with(who)
				.map_err(|_| XcmError::LocationFull),
			// Withdraw asset(s) (`assets`) from the ownership of `origin` and place equivalent
			// assets under the ownership of `beneficiary`.
			//
			// - `assets`: The asset(s) to be withdrawn.
			// - `beneficiary`: The new owner for the assets.
			TransferAsset { assets, beneficiary } => {
				Config::TransactionalProcessor::process(|| {
					// Take `assets` from the origin account (on-chain) and place into dest account.
					let origin = self.origin_ref().ok_or(XcmError::BadOrigin)?;
					// Transfer each asset using the `AssetTransactor`.
					for asset in assets.inner() {
						Config::AssetTransactor::transfer_asset(
							&asset,
							origin,
							&beneficiary,
							&self.context,
						)?;
					}
					Ok(())
				})
			},
			// Withdraw asset(s) (`assets`) from the ownership of `origin` and place them into the
			// Holding Register.
			//
			// - `assets`: The asset(s) to be withdrawn into holding.
			WithdrawAsset(assets) => {
				todo!("{:?}", assets)
			},
			// Reduce Holding by up to the given assets.
			//
			// Holding is reduced by as much as possible up to the assets in the parameter. It is
			// not an error if the Holding does not contain the assets (to make this an error, use
			// `ExpectAsset` prior).
			BurnAsset(assets) => {
				todo!("{:?}", assets)
			},
			// Remove the asset(s) (`assets`) from the Holding Register and place equivalent assets
			// under the ownership of `beneficiary` within this consensus system.
			//
			// - `assets`: The asset(s) to remove from holding.
			// - `beneficiary`: The new owner for the assets.
			DepositAsset { assets, beneficiary } => {
				todo!("{:?} {:?}", assets, beneficiary)
			},
			// Asset(s) (`assets`) have been destroyed on the `origin` system and equivalent assets
			// should be created and placed into the Holding Register.
			//
			// - `assets`: The asset(s) that are minted into the Holding Register.
			ReceiveTeleportedAsset(assets) => {
				todo!("{:?}", assets)
			},
			// In this workshop, we won't be implementing every instruction, just the ones above...
			// Our executor will simply panic if you try to execute other instructions.
			_ => unimplemented!(),
		}
	}
}

/// A public trait allowing other systems to access and use the `XcmExecutor`.
pub trait ExecuteXcm {
	/// Execute an XCM from a given `origin`.
	fn execute(origin: impl Into<Location>, xcm: Xcm<()>) -> XcmResult;
}

impl<Config: XcmConfig> ExecuteXcm for XcmExecutor<Config> {
	/// Execute an XCM from a given `origin`.
	fn execute(origin: impl Into<Location>, xcm: Xcm<()>) -> XcmResult {
		log::trace!(target: "xcm::execute", "xcm: {:?}", xcm);
		todo!("{:?}", origin.into())
	}
}
}
diff --git a/fundamentals/src/xcm_executor.rs b/fundamentals/src/xcm_executor.rs
index 57e1bd4..97ba170 100644
--- a/fundamentals/src/xcm_executor.rs
+++ b/fundamentals/src/xcm_executor.rs
@@ -79,6 +79,13 @@ impl<Config: XcmConfig> XcmExecutor<Config> {
 			// - `assets`: The asset(s) to be withdrawn.
 			// - `beneficiary`: The new owner for the assets.
 			TransferAsset { assets, beneficiary } => {
+				/* TODO:
+					- Process everything inside a `TransactionalProcessor`.
+					- Get the `origin` from `self.origin_ref()`.
+					- For each `asset` in `assets`
+						- Use `AssetTransactor` and `transfer_asset` to the `beneficiary`.
+					- If everything works well, return `Ok(())`
+				*/
 				todo!("{:?} {:?}", assets, beneficiary)
 			},
 			// Withdraw asset(s) (`assets`) from the ownership of `origin` and place them into the
diff --git a/fundamentals/src/xcm_executor.rs b/fundamentals/src/xcm_executor.rs
index 97ba170..f84c243 100644
--- a/fundamentals/src/xcm_executor.rs
+++ b/fundamentals/src/xcm_executor.rs
@@ -79,14 +79,20 @@ impl<Config: XcmConfig> XcmExecutor<Config> {
 			// - `assets`: The asset(s) to be withdrawn.
 			// - `beneficiary`: The new owner for the assets.
 			TransferAsset { assets, beneficiary } => {
-				/* TODO:
-					- Process everything inside a `TransactionalProcessor`.
-					- Get the `origin` from `self.origin_ref()`.
-					- For each `asset` in `assets`
-						- Use `AssetTransactor` and `transfer_asset` to the `beneficiary`.
-					- If everything works well, return `Ok(())`
-				*/
-				todo!("{:?} {:?}", assets, beneficiary)
+				Config::TransactionalProcessor::process(|| {
+					// Take `assets` from the origin account (on-chain) and place into dest account.
+					let origin = self.origin_ref().ok_or(XcmError::BadOrigin)?;
+					// Transfer each asset using the `AssetTransactor`.
+					for asset in assets.inner() {
+						Config::AssetTransactor::transfer_asset(
+							&asset,
+							origin,
+							&beneficiary,
+							&self.context,
+						)?;
+					}
+					Ok(())
+				})
 			},
 			// Withdraw asset(s) (`assets`) from the ownership of `origin` and place them into the
 			// Holding Register.
#![allow(unused)]
fn main() {
//! # Fundamentals lesson 5: XCM Executor
//!
//! Create your own executor for XCM.

use super::holding::*;

use sp_std::{marker::PhantomData, prelude::*};
use xcm::latest::prelude::*;
use xcm_executor::traits::{ProcessTransaction, TransactAsset};

pub trait XcmConfig {
	/// How to withdraw and deposit an asset.
	type AssetTransactor: TransactAsset;
	/// Transactional processor for XCM instructions.
	type TransactionalProcessor: ProcessTransaction;
}

/// The heart of the XCM Virtual Machine.
pub struct XcmExecutor<Config: XcmConfig> {
	/// The asset holding registrar, where we keep track of assets being processed by the XCM
	/// Executor.
	pub holding: AssetsInHolding,
	/// Contextual data pertaining to a specific list of XCM instructions. Most relevant the
	/// `origin` of the XCM Message.
	pub context: XcmContext,
	/// Just a placeholder to allow Rust to let us keep `Config`.
	_config: PhantomData<Config>,
}

/// The implementation of the XCM Executor and how it processes XCM.
impl<Config: XcmConfig> XcmExecutor<Config> {
	/// Crete an initialize a new XCM Executor.
	pub fn new(origin: impl Into<Location>) -> Self {
		let origin = origin.into();
		// In our version of the XCM Executor, we ignore `message_id` and `topic`.
		let context =
			XcmContext { origin: Some(origin), message_id: Default::default(), topic: None };
		Self { holding: Default::default(), context, _config: PhantomData }
	}

	/// Process an entire XCM program, instruction by instruction.
	pub fn process(&mut self, xcm: Xcm<()>) -> Result<(), XcmError> {
		log::trace!(target: "xcm::process", "xcm: {:?}", xcm);
		for instruction in xcm.0.into_iter() {
			self.process_instruction(instruction)?;
		}
		Ok(())
	}

	/// Simple helper function to access the `origin` from the XCM Executor `context`.
	pub fn origin_ref(&self) -> Option<&Location> {
		self.context.origin.as_ref()
	}

	/// Process a single XCM instruction, mutating the state of the XCM virtual machine.
	fn process_instruction(&mut self, instr: Instruction<()>) -> Result<(), XcmError> {
		log::trace!(target: "xcm::process_instruction", "=== {:?}", instr);
		match instr {
			// Clear the origin.
			//
			// This may be used by the XCM author to ensure that later instructions cannot command
			// the authority of the origin (e.g. if they are being relayed from an untrusted
			// source, as often the case with `ReserveAssetDeposited`).
			ClearOrigin => {
				self.context.origin = None;
				Ok(())
			},
			// Appends `who` to the current XCM Executor `origin` location.
			DescendOrigin(who) => self
				.context
				.origin
				.as_mut()
				.ok_or(XcmError::BadOrigin)?
				.append_with(who)
				.map_err(|_| XcmError::LocationFull),
			// Withdraw asset(s) (`assets`) from the ownership of `origin` and place equivalent
			// assets under the ownership of `beneficiary`.
			//
			// - `assets`: The asset(s) to be withdrawn.
			// - `beneficiary`: The new owner for the assets.
			TransferAsset { assets, beneficiary } => {
				Config::TransactionalProcessor::process(|| {
					// Take `assets` from the origin account (on-chain) and place into dest account.
					let origin = self.origin_ref().ok_or(XcmError::BadOrigin)?;
					// Transfer each asset using the `AssetTransactor`.
					for asset in assets.inner() {
						Config::AssetTransactor::transfer_asset(
							&asset,
							origin,
							&beneficiary,
							&self.context,
						)?;
					}
					Ok(())
				})
			},
			// Withdraw asset(s) (`assets`) from the ownership of `origin` and place them into the
			// Holding Register.
			//
			// - `assets`: The asset(s) to be withdrawn into holding.
			WithdrawAsset(assets) => {
				/* TODO:
					- Process everything inside a `TransactionalProcessor`.
					- Get the `origin` or return `XcmError::BadOrigin`.
					- For each `asset` in `assets`
						- Use the `AssetTransactor` to `withdraw_asset`.
					- `and_then`, if everything goes okay...
					- `subsume_assets` into the `self.holding`
				*/
				todo!("{:?}", assets)
			},
			// Reduce Holding by up to the given assets.
			//
			// Holding is reduced by as much as possible up to the assets in the parameter. It is
			// not an error if the Holding does not contain the assets (to make this an error, use
			// `ExpectAsset` prior).
			BurnAsset(assets) => {
				/* TODO: Simply `saturating_take` `assets` from the `self.holding`. */
				todo!("{:?}", assets)
			},
			// Remove the asset(s) (`assets`) from the Holding Register and place equivalent assets
			// under the ownership of `beneficiary` within this consensus system.
			//
			// - `assets`: The asset(s) to remove from holding.
			// - `beneficiary`: The new owner for the assets.
			DepositAsset { assets, beneficiary } => {
				todo!("{:?} {:?}", assets, beneficiary)
			},
			// Asset(s) (`assets`) have been destroyed on the `origin` system and equivalent assets
			// should be created and placed into the Holding Register.
			//
			// - `assets`: The asset(s) that are minted into the Holding Register.
			ReceiveTeleportedAsset(assets) => {
				todo!("{:?}", assets)
			},
			// In this workshop, we won't be implementing every instruction, just the ones above...
			// Our executor will simply panic if you try to execute other instructions.
			_ => unimplemented!(),
		}
	}
}

/// A public trait allowing other systems to access and use the `XcmExecutor`.
pub trait ExecuteXcm {
	/// Execute an XCM from a given `origin`.
	fn execute(origin: impl Into<Location>, xcm: Xcm<()>) -> XcmResult;
}

impl<Config: XcmConfig> ExecuteXcm for XcmExecutor<Config> {
	/// Execute an XCM from a given `origin`.
	fn execute(origin: impl Into<Location>, xcm: Xcm<()>) -> XcmResult {
		log::trace!(target: "xcm::execute", "xcm: {:?}", xcm);
		todo!("{:?}", origin.into())
	}
}
}
#![allow(unused)]
fn main() {
//! # Fundamentals lesson 5: XCM Executor
//!
//! Create your own executor for XCM.

use super::holding::*;

use sp_std::{marker::PhantomData, prelude::*};
use xcm::latest::prelude::*;
use xcm_executor::traits::{ProcessTransaction, TransactAsset};

pub trait XcmConfig {
	/// How to withdraw and deposit an asset.
	type AssetTransactor: TransactAsset;
	/// Transactional processor for XCM instructions.
	type TransactionalProcessor: ProcessTransaction;
}

/// The heart of the XCM Virtual Machine.
pub struct XcmExecutor<Config: XcmConfig> {
	/// The asset holding registrar, where we keep track of assets being processed by the XCM
	/// Executor.
	pub holding: AssetsInHolding,
	/// Contextual data pertaining to a specific list of XCM instructions. Most relevant the
	/// `origin` of the XCM Message.
	pub context: XcmContext,
	/// Just a placeholder to allow Rust to let us keep `Config`.
	_config: PhantomData<Config>,
}

/// The implementation of the XCM Executor and how it processes XCM.
impl<Config: XcmConfig> XcmExecutor<Config> {
	/// Crete an initialize a new XCM Executor.
	pub fn new(origin: impl Into<Location>) -> Self {
		let origin = origin.into();
		// In our version of the XCM Executor, we ignore `message_id` and `topic`.
		let context =
			XcmContext { origin: Some(origin), message_id: Default::default(), topic: None };
		Self { holding: Default::default(), context, _config: PhantomData }
	}

	/// Process an entire XCM program, instruction by instruction.
	pub fn process(&mut self, xcm: Xcm<()>) -> Result<(), XcmError> {
		log::trace!(target: "xcm::process", "xcm: {:?}", xcm);
		for instruction in xcm.0.into_iter() {
			self.process_instruction(instruction)?;
		}
		Ok(())
	}

	/// Simple helper function to access the `origin` from the XCM Executor `context`.
	pub fn origin_ref(&self) -> Option<&Location> {
		self.context.origin.as_ref()
	}

	/// Process a single XCM instruction, mutating the state of the XCM virtual machine.
	fn process_instruction(&mut self, instr: Instruction<()>) -> Result<(), XcmError> {
		log::trace!(target: "xcm::process_instruction", "=== {:?}", instr);
		match instr {
			// Clear the origin.
			//
			// This may be used by the XCM author to ensure that later instructions cannot command
			// the authority of the origin (e.g. if they are being relayed from an untrusted
			// source, as often the case with `ReserveAssetDeposited`).
			ClearOrigin => {
				self.context.origin = None;
				Ok(())
			},
			// Appends `who` to the current XCM Executor `origin` location.
			DescendOrigin(who) => self
				.context
				.origin
				.as_mut()
				.ok_or(XcmError::BadOrigin)?
				.append_with(who)
				.map_err(|_| XcmError::LocationFull),
			// Withdraw asset(s) (`assets`) from the ownership of `origin` and place equivalent
			// assets under the ownership of `beneficiary`.
			//
			// - `assets`: The asset(s) to be withdrawn.
			// - `beneficiary`: The new owner for the assets.
			TransferAsset { assets, beneficiary } => {
				Config::TransactionalProcessor::process(|| {
					// Take `assets` from the origin account (on-chain) and place into dest account.
					let origin = self.origin_ref().ok_or(XcmError::BadOrigin)?;
					// Transfer each asset using the `AssetTransactor`.
					for asset in assets.inner() {
						Config::AssetTransactor::transfer_asset(
							&asset,
							origin,
							&beneficiary,
							&self.context,
						)?;
					}
					Ok(())
				})
			},
			// Withdraw asset(s) (`assets`) from the ownership of `origin` and place them into the
			// Holding Register.
			//
			// - `assets`: The asset(s) to be withdrawn into holding.
			WithdrawAsset(assets) => {
				Config::TransactionalProcessor::process(|| {
					let origin = self.origin_ref().ok_or(XcmError::BadOrigin)?;
					// Take `assets` from the origin account (on-chain)...
					for asset in assets.inner() {
						Config::AssetTransactor::withdraw_asset(
							asset,
							origin,
							Some(&self.context),
						)?;
					}
					Ok(())
				})
				.and_then(|_| {
					// ...and place into holding.
					self.holding.subsume_assets(assets.into());
					Ok(())
				})
			},
			// Reduce Holding by up to the given assets.
			//
			// Holding is reduced by as much as possible up to the assets in the parameter. It is
			// not an error if the Holding does not contain the assets (to make this an error, use
			// `ExpectAsset` prior).
			BurnAsset(assets) => {
				self.holding.saturating_take(assets.into());
				Ok(())
			},
			// Remove the asset(s) (`assets`) from the Holding Register and place equivalent assets
			// under the ownership of `beneficiary` within this consensus system.
			//
			// - `assets`: The asset(s) to remove from holding.
			// - `beneficiary`: The new owner for the assets.
			DepositAsset { assets, beneficiary } => {
				todo!("{:?} {:?}", assets, beneficiary)
			},
			// Asset(s) (`assets`) have been destroyed on the `origin` system and equivalent assets
			// should be created and placed into the Holding Register.
			//
			// - `assets`: The asset(s) that are minted into the Holding Register.
			ReceiveTeleportedAsset(assets) => {
				todo!("{:?}", assets)
			},
			// In this workshop, we won't be implementing every instruction, just the ones above...
			// Our executor will simply panic if you try to execute other instructions.
			_ => unimplemented!(),
		}
	}
}

/// A public trait allowing other systems to access and use the `XcmExecutor`.
pub trait ExecuteXcm {
	/// Execute an XCM from a given `origin`.
	fn execute(origin: impl Into<Location>, xcm: Xcm<()>) -> XcmResult;
}

impl<Config: XcmConfig> ExecuteXcm for XcmExecutor<Config> {
	/// Execute an XCM from a given `origin`.
	fn execute(origin: impl Into<Location>, xcm: Xcm<()>) -> XcmResult {
		log::trace!(target: "xcm::execute", "xcm: {:?}", xcm);
		todo!("{:?}", origin.into())
	}
}
}
diff --git a/fundamentals/src/xcm_executor.rs b/fundamentals/src/xcm_executor.rs
index f84c243..f97757d 100644
--- a/fundamentals/src/xcm_executor.rs
+++ b/fundamentals/src/xcm_executor.rs
@@ -99,6 +99,14 @@ impl<Config: XcmConfig> XcmExecutor<Config> {
 			//
 			// - `assets`: The asset(s) to be withdrawn into holding.
 			WithdrawAsset(assets) => {
+				/* TODO:
+					- Process everything inside a `TransactionalProcessor`.
+					- Get the `origin` or return `XcmError::BadOrigin`.
+					- For each `asset` in `assets`
+						- Use the `AssetTransactor` to `withdraw_asset`.
+					- `and_then`, if everything goes okay...
+					- `subsume_assets` into the `self.holding`
+				*/
 				todo!("{:?}", assets)
 			},
 			// Reduce Holding by up to the given assets.
@@ -107,6 +115,7 @@ impl<Config: XcmConfig> XcmExecutor<Config> {
 			// not an error if the Holding does not contain the assets (to make this an error, use
 			// `ExpectAsset` prior).
 			BurnAsset(assets) => {
+				/* TODO: Simply `saturating_take` `assets` from the `self.holding`. */
 				todo!("{:?}", assets)
 			},
 			// Remove the asset(s) (`assets`) from the Holding Register and place equivalent assets
diff --git a/fundamentals/src/xcm_executor.rs b/fundamentals/src/xcm_executor.rs
index f97757d..d50d85a 100644
--- a/fundamentals/src/xcm_executor.rs
+++ b/fundamentals/src/xcm_executor.rs
@@ -99,15 +99,23 @@ impl<Config: XcmConfig> XcmExecutor<Config> {
 			//
 			// - `assets`: The asset(s) to be withdrawn into holding.
 			WithdrawAsset(assets) => {
-				/* TODO:
-					- Process everything inside a `TransactionalProcessor`.
-					- Get the `origin` or return `XcmError::BadOrigin`.
-					- For each `asset` in `assets`
-						- Use the `AssetTransactor` to `withdraw_asset`.
-					- `and_then`, if everything goes okay...
-					- `subsume_assets` into the `self.holding`
-				*/
-				todo!("{:?}", assets)
+				Config::TransactionalProcessor::process(|| {
+					let origin = self.origin_ref().ok_or(XcmError::BadOrigin)?;
+					// Take `assets` from the origin account (on-chain)...
+					for asset in assets.inner() {
+						Config::AssetTransactor::withdraw_asset(
+							asset,
+							origin,
+							Some(&self.context),
+						)?;
+					}
+					Ok(())
+				})
+				.and_then(|_| {
+					// ...and place into holding.
+					self.holding.subsume_assets(assets.into());
+					Ok(())
+				})
 			},
 			// Reduce Holding by up to the given assets.
 			//
@@ -115,8 +123,8 @@ impl<Config: XcmConfig> XcmExecutor<Config> {
 			// not an error if the Holding does not contain the assets (to make this an error, use
 			// `ExpectAsset` prior).
 			BurnAsset(assets) => {
-				/* TODO: Simply `saturating_take` `assets` from the `self.holding`. */
-				todo!("{:?}", assets)
+				self.holding.saturating_take(assets.into());
+				Ok(())
 			},
 			// Remove the asset(s) (`assets`) from the Holding Register and place equivalent assets
 			// under the ownership of `beneficiary` within this consensus system.
#![allow(unused)]
fn main() {
//! # Fundamentals lesson 5: XCM Executor
//!
//! Create your own executor for XCM.

use super::holding::*;

use sp_std::{marker::PhantomData, prelude::*};
use xcm::latest::prelude::*;
use xcm_executor::traits::{ProcessTransaction, TransactAsset};

pub trait XcmConfig {
	/// How to withdraw and deposit an asset.
	type AssetTransactor: TransactAsset;
	/// Transactional processor for XCM instructions.
	type TransactionalProcessor: ProcessTransaction;
}

/// The heart of the XCM Virtual Machine.
pub struct XcmExecutor<Config: XcmConfig> {
	/// The asset holding registrar, where we keep track of assets being processed by the XCM
	/// Executor.
	pub holding: AssetsInHolding,
	/// Contextual data pertaining to a specific list of XCM instructions. Most relevant the
	/// `origin` of the XCM Message.
	pub context: XcmContext,
	/// Just a placeholder to allow Rust to let us keep `Config`.
	_config: PhantomData<Config>,
}

/// The implementation of the XCM Executor and how it processes XCM.
impl<Config: XcmConfig> XcmExecutor<Config> {
	/// Crete an initialize a new XCM Executor.
	pub fn new(origin: impl Into<Location>) -> Self {
		let origin = origin.into();
		// In our version of the XCM Executor, we ignore `message_id` and `topic`.
		let context =
			XcmContext { origin: Some(origin), message_id: Default::default(), topic: None };
		Self { holding: Default::default(), context, _config: PhantomData }
	}

	/// Process an entire XCM program, instruction by instruction.
	pub fn process(&mut self, xcm: Xcm<()>) -> Result<(), XcmError> {
		log::trace!(target: "xcm::process", "xcm: {:?}", xcm);
		for instruction in xcm.0.into_iter() {
			self.process_instruction(instruction)?;
		}
		Ok(())
	}

	/// Simple helper function to access the `origin` from the XCM Executor `context`.
	pub fn origin_ref(&self) -> Option<&Location> {
		self.context.origin.as_ref()
	}

	/// Process a single XCM instruction, mutating the state of the XCM virtual machine.
	fn process_instruction(&mut self, instr: Instruction<()>) -> Result<(), XcmError> {
		log::trace!(target: "xcm::process_instruction", "=== {:?}", instr);
		match instr {
			// Clear the origin.
			//
			// This may be used by the XCM author to ensure that later instructions cannot command
			// the authority of the origin (e.g. if they are being relayed from an untrusted
			// source, as often the case with `ReserveAssetDeposited`).
			ClearOrigin => {
				self.context.origin = None;
				Ok(())
			},
			// Appends `who` to the current XCM Executor `origin` location.
			DescendOrigin(who) => self
				.context
				.origin
				.as_mut()
				.ok_or(XcmError::BadOrigin)?
				.append_with(who)
				.map_err(|_| XcmError::LocationFull),
			// Withdraw asset(s) (`assets`) from the ownership of `origin` and place equivalent
			// assets under the ownership of `beneficiary`.
			//
			// - `assets`: The asset(s) to be withdrawn.
			// - `beneficiary`: The new owner for the assets.
			TransferAsset { assets, beneficiary } => {
				Config::TransactionalProcessor::process(|| {
					// Take `assets` from the origin account (on-chain) and place into dest account.
					let origin = self.origin_ref().ok_or(XcmError::BadOrigin)?;
					// Transfer each asset using the `AssetTransactor`.
					for asset in assets.inner() {
						Config::AssetTransactor::transfer_asset(
							&asset,
							origin,
							&beneficiary,
							&self.context,
						)?;
					}
					Ok(())
				})
			},
			// Withdraw asset(s) (`assets`) from the ownership of `origin` and place them into the
			// Holding Register.
			//
			// - `assets`: The asset(s) to be withdrawn into holding.
			WithdrawAsset(assets) => {
				Config::TransactionalProcessor::process(|| {
					let origin = self.origin_ref().ok_or(XcmError::BadOrigin)?;
					// Take `assets` from the origin account (on-chain)...
					for asset in assets.inner() {
						Config::AssetTransactor::withdraw_asset(
							asset,
							origin,
							Some(&self.context),
						)?;
					}
					Ok(())
				})
				.and_then(|_| {
					// ...and place into holding.
					self.holding.subsume_assets(assets.into());
					Ok(())
				})
			},
			// Reduce Holding by up to the given assets.
			//
			// Holding is reduced by as much as possible up to the assets in the parameter. It is
			// not an error if the Holding does not contain the assets (to make this an error, use
			// `ExpectAsset` prior).
			BurnAsset(assets) => {
				self.holding.saturating_take(assets.into());
				Ok(())
			},
			// Remove the asset(s) (`assets`) from the Holding Register and place equivalent assets
			// under the ownership of `beneficiary` within this consensus system.
			//
			// - `assets`: The asset(s) to remove from holding.
			// - `beneficiary`: The new owner for the assets.
			DepositAsset { assets, beneficiary } => {
				/* TODO:
					- Make a clone of `self.holding` into a variable `old_holding`.
					- Start a new `TransactionalProcessor`, storing the `result`.
						- `saturating_take` the `assets` into a variable `deposited.
						- For `asset` in `deposited`
							- Use `AssetTransactor` to `deposit_asset` to the `beneficiary`.
					- If anything goes wrong, we should reset `self.holding` to `old_holding`.
					- Return the `result`
				*/
				todo!("{:?} {:?}", assets, beneficiary)
			},
			// Asset(s) (`assets`) have been destroyed on the `origin` system and equivalent assets
			// should be created and placed into the Holding Register.
			//
			// - `assets`: The asset(s) that are minted into the Holding Register.
			ReceiveTeleportedAsset(assets) => {
				/* TODO:
					- Process everything inside `TransactionalProcessor`.
						- Get the `origin` or return `XcmError::BadOrigin`.
						- For `asset` in `assets`:
							- Use `AssetTransactor` to see if we `can_check_in`.
							- Then actually `check_in` those assets.
					- `and_then`, if everything goes okay...
					- `subsume_assets` into the `self.holding`.
				*/
				todo!("{:?}", assets)
			},
			// In this workshop, we won't be implementing every instruction, just the ones above...
			// Our executor will simply panic if you try to execute other instructions.
			_ => unimplemented!(),
		}
	}
}

/// A public trait allowing other systems to access and use the `XcmExecutor`.
pub trait ExecuteXcm {
	/// Execute an XCM from a given `origin`.
	fn execute(origin: impl Into<Location>, xcm: Xcm<()>) -> XcmResult;
}

impl<Config: XcmConfig> ExecuteXcm for XcmExecutor<Config> {
	/// Execute an XCM from a given `origin`.
	fn execute(origin: impl Into<Location>, xcm: Xcm<()>) -> XcmResult {
		log::trace!(target: "xcm::execute", "xcm: {:?}", xcm);
		todo!("{:?}", origin.into())
	}
}
}
#![allow(unused)]
fn main() {
//! # Fundamentals lesson 5: XCM Executor
//!
//! Create your own executor for XCM.

use super::holding::*;

use sp_std::{marker::PhantomData, prelude::*};
use xcm::latest::prelude::*;
use xcm_executor::traits::{ProcessTransaction, TransactAsset};

pub trait XcmConfig {
	/// How to withdraw and deposit an asset.
	type AssetTransactor: TransactAsset;
	/// Transactional processor for XCM instructions.
	type TransactionalProcessor: ProcessTransaction;
}

/// The heart of the XCM Virtual Machine.
pub struct XcmExecutor<Config: XcmConfig> {
	/// The asset holding registrar, where we keep track of assets being processed by the XCM
	/// Executor.
	pub holding: AssetsInHolding,
	/// Contextual data pertaining to a specific list of XCM instructions. Most relevant the
	/// `origin` of the XCM Message.
	pub context: XcmContext,
	/// Just a placeholder to allow Rust to let us keep `Config`.
	_config: PhantomData<Config>,
}

/// The implementation of the XCM Executor and how it processes XCM.
impl<Config: XcmConfig> XcmExecutor<Config> {
	/// Crete an initialize a new XCM Executor.
	pub fn new(origin: impl Into<Location>) -> Self {
		let origin = origin.into();
		// In our version of the XCM Executor, we ignore `message_id` and `topic`.
		let context =
			XcmContext { origin: Some(origin), message_id: Default::default(), topic: None };
		Self { holding: Default::default(), context, _config: PhantomData }
	}

	/// Process an entire XCM program, instruction by instruction.
	pub fn process(&mut self, xcm: Xcm<()>) -> Result<(), XcmError> {
		log::trace!(target: "xcm::process", "xcm: {:?}", xcm);
		for instruction in xcm.0.into_iter() {
			self.process_instruction(instruction)?;
		}
		Ok(())
	}

	/// Simple helper function to access the `origin` from the XCM Executor `context`.
	pub fn origin_ref(&self) -> Option<&Location> {
		self.context.origin.as_ref()
	}

	/// Process a single XCM instruction, mutating the state of the XCM virtual machine.
	fn process_instruction(&mut self, instr: Instruction<()>) -> Result<(), XcmError> {
		log::trace!(target: "xcm::process_instruction", "=== {:?}", instr);
		match instr {
			// Clear the origin.
			//
			// This may be used by the XCM author to ensure that later instructions cannot command
			// the authority of the origin (e.g. if they are being relayed from an untrusted
			// source, as often the case with `ReserveAssetDeposited`).
			ClearOrigin => {
				self.context.origin = None;
				Ok(())
			},
			// Appends `who` to the current XCM Executor `origin` location.
			DescendOrigin(who) => self
				.context
				.origin
				.as_mut()
				.ok_or(XcmError::BadOrigin)?
				.append_with(who)
				.map_err(|_| XcmError::LocationFull),
			// Withdraw asset(s) (`assets`) from the ownership of `origin` and place equivalent
			// assets under the ownership of `beneficiary`.
			//
			// - `assets`: The asset(s) to be withdrawn.
			// - `beneficiary`: The new owner for the assets.
			TransferAsset { assets, beneficiary } => {
				Config::TransactionalProcessor::process(|| {
					// Take `assets` from the origin account (on-chain) and place into dest account.
					let origin = self.origin_ref().ok_or(XcmError::BadOrigin)?;
					// Transfer each asset using the `AssetTransactor`.
					for asset in assets.inner() {
						Config::AssetTransactor::transfer_asset(
							&asset,
							origin,
							&beneficiary,
							&self.context,
						)?;
					}
					Ok(())
				})
			},
			// Withdraw asset(s) (`assets`) from the ownership of `origin` and place them into the
			// Holding Register.
			//
			// - `assets`: The asset(s) to be withdrawn into holding.
			WithdrawAsset(assets) => {
				Config::TransactionalProcessor::process(|| {
					let origin = self.origin_ref().ok_or(XcmError::BadOrigin)?;
					// Take `assets` from the origin account (on-chain)...
					for asset in assets.inner() {
						Config::AssetTransactor::withdraw_asset(
							asset,
							origin,
							Some(&self.context),
						)?;
					}
					Ok(())
				})
				.and_then(|_| {
					// ...and place into holding.
					self.holding.subsume_assets(assets.into());
					Ok(())
				})
			},
			// Reduce Holding by up to the given assets.
			//
			// Holding is reduced by as much as possible up to the assets in the parameter. It is
			// not an error if the Holding does not contain the assets (to make this an error, use
			// `ExpectAsset` prior).
			BurnAsset(assets) => {
				self.holding.saturating_take(assets.into());
				Ok(())
			},
			// Remove the asset(s) (`assets`) from the Holding Register and place equivalent assets
			// under the ownership of `beneficiary` within this consensus system.
			//
			// - `assets`: The asset(s) to remove from holding.
			// - `beneficiary`: The new owner for the assets.
			DepositAsset { assets, beneficiary } => {
				let old_holding = self.holding.clone();
				let result = Config::TransactionalProcessor::process(|| {
					// Take assets from the holding registrar...
					let deposited = self.holding.saturating_take(assets);
					// ... and deposit them to the `beneficiary`.
					for asset in deposited.into_assets_iter() {
						Config::AssetTransactor::deposit_asset(
							&asset,
							&beneficiary,
							Some(&self.context),
						)?;
					}
					Ok(())
				});
				// If we were unable to execute `deposit_asset` in the `AssetTransactor`, we reset
				// the XCM Executor holding registrar since no operations took place.
				if Config::TransactionalProcessor::IS_TRANSACTIONAL && result.is_err() {
					self.holding = old_holding;
				}
				result
			},
			// Asset(s) (`assets`) have been destroyed on the `origin` system and equivalent assets
			// should be created and placed into the Holding Register.
			//
			// - `assets`: The asset(s) that are minted into the Holding Register.
			ReceiveTeleportedAsset(assets) => {
				Config::TransactionalProcessor::process(|| {
					let origin = self.origin_ref().ok_or(XcmError::BadOrigin)?;
					// check whether we trust origin to teleport this asset to us via config trait.
					for asset in assets.inner() {
						// We should check that the asset can actually be teleported in (for this to
						// be in error, there would need to be an accounting violation by one of the
						// trusted chains, so it's unlikely, but we don't want to punish a possibly
						// innocent chain/user).
						Config::AssetTransactor::can_check_in(origin, asset, &self.context)?;
						Config::AssetTransactor::check_in(origin, asset, &self.context);
					}
					Ok(())
				})
				.and_then(|_| {
					// ...and place into holding.
					self.holding.subsume_assets(assets.into());
					Ok(())
				})
			},
			// In this workshop, we won't be implementing every instruction, just the ones above...
			// Our executor will simply panic if you try to execute other instructions.
			_ => unimplemented!(),
		}
	}
}

/// A public trait allowing other systems to access and use the `XcmExecutor`.
pub trait ExecuteXcm {
	/// Execute an XCM from a given `origin`.
	fn execute(origin: impl Into<Location>, xcm: Xcm<()>) -> XcmResult;
}

impl<Config: XcmConfig> ExecuteXcm for XcmExecutor<Config> {
	/// Execute an XCM from a given `origin`.
	fn execute(origin: impl Into<Location>, xcm: Xcm<()>) -> XcmResult {
		log::trace!(target: "xcm::execute", "xcm: {:?}", xcm);
		todo!("{:?}", origin.into())
	}
}
}
diff --git a/fundamentals/src/xcm_executor.rs b/fundamentals/src/xcm_executor.rs
index d50d85a..540086f 100644
--- a/fundamentals/src/xcm_executor.rs
+++ b/fundamentals/src/xcm_executor.rs
@@ -132,6 +132,15 @@ impl<Config: XcmConfig> XcmExecutor<Config> {
 			// - `assets`: The asset(s) to remove from holding.
 			// - `beneficiary`: The new owner for the assets.
 			DepositAsset { assets, beneficiary } => {
+				/* TODO:
+					- Make a clone of `self.holding` into a variable `old_holding`.
+					- Start a new `TransactionalProcessor`, storing the `result`.
+						- `saturating_take` the `assets` into a variable `deposited.
+						- For `asset` in `deposited`
+							- Use `AssetTransactor` to `deposit_asset` to the `beneficiary`.
+					- If anything goes wrong, we should reset `self.holding` to `old_holding`.
+					- Return the `result`
+				*/
 				todo!("{:?} {:?}", assets, beneficiary)
 			},
 			// Asset(s) (`assets`) have been destroyed on the `origin` system and equivalent assets
@@ -139,6 +148,15 @@ impl<Config: XcmConfig> XcmExecutor<Config> {
 			//
 			// - `assets`: The asset(s) that are minted into the Holding Register.
 			ReceiveTeleportedAsset(assets) => {
+				/* TODO:
+					- Process everything inside `TransactionalProcessor`.
+						- Get the `origin` or return `XcmError::BadOrigin`.
+						- For `asset` in `assets`:
+							- Use `AssetTransactor` to see if we `can_check_in`.
+							- Then actually `check_in` those assets.
+					- `and_then`, if everything goes okay...
+					- `subsume_assets` into the `self.holding`.
+				*/
 				todo!("{:?}", assets)
 			},
 			// In this workshop, we won't be implementing every instruction, just the ones above...
diff --git a/fundamentals/src/xcm_executor.rs b/fundamentals/src/xcm_executor.rs
index 540086f..f03d79b 100644
--- a/fundamentals/src/xcm_executor.rs
+++ b/fundamentals/src/xcm_executor.rs
@@ -132,32 +132,50 @@ impl<Config: XcmConfig> XcmExecutor<Config> {
 			// - `assets`: The asset(s) to remove from holding.
 			// - `beneficiary`: The new owner for the assets.
 			DepositAsset { assets, beneficiary } => {
-				/* TODO:
-					- Make a clone of `self.holding` into a variable `old_holding`.
-					- Start a new `TransactionalProcessor`, storing the `result`.
-						- `saturating_take` the `assets` into a variable `deposited.
-						- For `asset` in `deposited`
-							- Use `AssetTransactor` to `deposit_asset` to the `beneficiary`.
-					- If anything goes wrong, we should reset `self.holding` to `old_holding`.
-					- Return the `result`
-				*/
-				todo!("{:?} {:?}", assets, beneficiary)
+				let old_holding = self.holding.clone();
+				let result = Config::TransactionalProcessor::process(|| {
+					// Take assets from the holding registrar...
+					let deposited = self.holding.saturating_take(assets);
+					// ... and deposit them to the `beneficiary`.
+					for asset in deposited.into_assets_iter() {
+						Config::AssetTransactor::deposit_asset(
+							&asset,
+							&beneficiary,
+							Some(&self.context),
+						)?;
+					}
+					Ok(())
+				});
+				// If we were unable to execute `deposit_asset` in the `AssetTransactor`, we reset
+				// the XCM Executor holding registrar since no operations took place.
+				if Config::TransactionalProcessor::IS_TRANSACTIONAL && result.is_err() {
+					self.holding = old_holding;
+				}
+				result
 			},
 			// Asset(s) (`assets`) have been destroyed on the `origin` system and equivalent assets
 			// should be created and placed into the Holding Register.
 			//
 			// - `assets`: The asset(s) that are minted into the Holding Register.
 			ReceiveTeleportedAsset(assets) => {
-				/* TODO:
-					- Process everything inside `TransactionalProcessor`.
-						- Get the `origin` or return `XcmError::BadOrigin`.
-						- For `asset` in `assets`:
-							- Use `AssetTransactor` to see if we `can_check_in`.
-							- Then actually `check_in` those assets.
-					- `and_then`, if everything goes okay...
-					- `subsume_assets` into the `self.holding`.
-				*/
-				todo!("{:?}", assets)
+				Config::TransactionalProcessor::process(|| {
+					let origin = self.origin_ref().ok_or(XcmError::BadOrigin)?;
+					// check whether we trust origin to teleport this asset to us via config trait.
+					for asset in assets.inner() {
+						// We should check that the asset can actually be teleported in (for this to
+						// be in error, there would need to be an accounting violation by one of the
+						// trusted chains, so it's unlikely, but we don't want to punish a possibly
+						// innocent chain/user).
+						Config::AssetTransactor::can_check_in(origin, asset, &self.context)?;
+						Config::AssetTransactor::check_in(origin, asset, &self.context);
+					}
+					Ok(())
+				})
+				.and_then(|_| {
+					// ...and place into holding.
+					self.holding.subsume_assets(assets.into());
+					Ok(())
+				})
 			},
 			// In this workshop, we won't be implementing every instruction, just the ones above...
 			// Our executor will simply panic if you try to execute other instructions.
#![allow(unused)]
fn main() {
//! # Fundamentals lesson 5: XCM Executor
//!
//! Create your own executor for XCM.

use super::holding::*;

use sp_std::{marker::PhantomData, prelude::*};
use xcm::latest::prelude::*;
use xcm_executor::traits::{ProcessTransaction, TransactAsset};

pub trait XcmConfig {
	/// How to withdraw and deposit an asset.
	type AssetTransactor: TransactAsset;
	/// Transactional processor for XCM instructions.
	type TransactionalProcessor: ProcessTransaction;
}

/// The heart of the XCM Virtual Machine.
pub struct XcmExecutor<Config: XcmConfig> {
	/// The asset holding registrar, where we keep track of assets being processed by the XCM
	/// Executor.
	pub holding: AssetsInHolding,
	/// Contextual data pertaining to a specific list of XCM instructions. Most relevant the
	/// `origin` of the XCM Message.
	pub context: XcmContext,
	/// Just a placeholder to allow Rust to let us keep `Config`.
	_config: PhantomData<Config>,
}

/// The implementation of the XCM Executor and how it processes XCM.
impl<Config: XcmConfig> XcmExecutor<Config> {
	/// Crete an initialize a new XCM Executor.
	pub fn new(origin: impl Into<Location>) -> Self {
		let origin = origin.into();
		// In our version of the XCM Executor, we ignore `message_id` and `topic`.
		let context =
			XcmContext { origin: Some(origin), message_id: Default::default(), topic: None };
		Self { holding: Default::default(), context, _config: PhantomData }
	}

	/// Process an entire XCM program, instruction by instruction.
	pub fn process(&mut self, xcm: Xcm<()>) -> Result<(), XcmError> {
		log::trace!(target: "xcm::process", "xcm: {:?}", xcm);
		for instruction in xcm.0.into_iter() {
			self.process_instruction(instruction)?;
		}
		Ok(())
	}

	/// Simple helper function to access the `origin` from the XCM Executor `context`.
	pub fn origin_ref(&self) -> Option<&Location> {
		self.context.origin.as_ref()
	}

	/// Process a single XCM instruction, mutating the state of the XCM virtual machine.
	fn process_instruction(&mut self, instr: Instruction<()>) -> Result<(), XcmError> {
		log::trace!(target: "xcm::process_instruction", "=== {:?}", instr);
		match instr {
			// Clear the origin.
			//
			// This may be used by the XCM author to ensure that later instructions cannot command
			// the authority of the origin (e.g. if they are being relayed from an untrusted
			// source, as often the case with `ReserveAssetDeposited`).
			ClearOrigin => {
				self.context.origin = None;
				Ok(())
			},
			// Appends `who` to the current XCM Executor `origin` location.
			DescendOrigin(who) => self
				.context
				.origin
				.as_mut()
				.ok_or(XcmError::BadOrigin)?
				.append_with(who)
				.map_err(|_| XcmError::LocationFull),
			// Withdraw asset(s) (`assets`) from the ownership of `origin` and place equivalent
			// assets under the ownership of `beneficiary`.
			//
			// - `assets`: The asset(s) to be withdrawn.
			// - `beneficiary`: The new owner for the assets.
			TransferAsset { assets, beneficiary } => {
				Config::TransactionalProcessor::process(|| {
					// Take `assets` from the origin account (on-chain) and place into dest account.
					let origin = self.origin_ref().ok_or(XcmError::BadOrigin)?;
					// Transfer each asset using the `AssetTransactor`.
					for asset in assets.inner() {
						Config::AssetTransactor::transfer_asset(
							&asset,
							origin,
							&beneficiary,
							&self.context,
						)?;
					}
					Ok(())
				})
			},
			// Withdraw asset(s) (`assets`) from the ownership of `origin` and place them into the
			// Holding Register.
			//
			// - `assets`: The asset(s) to be withdrawn into holding.
			WithdrawAsset(assets) => {
				Config::TransactionalProcessor::process(|| {
					let origin = self.origin_ref().ok_or(XcmError::BadOrigin)?;
					// Take `assets` from the origin account (on-chain)...
					for asset in assets.inner() {
						Config::AssetTransactor::withdraw_asset(
							asset,
							origin,
							Some(&self.context),
						)?;
					}
					Ok(())
				})
				.and_then(|_| {
					// ...and place into holding.
					self.holding.subsume_assets(assets.into());
					Ok(())
				})
			},
			// Reduce Holding by up to the given assets.
			//
			// Holding is reduced by as much as possible up to the assets in the parameter. It is
			// not an error if the Holding does not contain the assets (to make this an error, use
			// `ExpectAsset` prior).
			BurnAsset(assets) => {
				self.holding.saturating_take(assets.into());
				Ok(())
			},
			// Remove the asset(s) (`assets`) from the Holding Register and place equivalent assets
			// under the ownership of `beneficiary` within this consensus system.
			//
			// - `assets`: The asset(s) to remove from holding.
			// - `beneficiary`: The new owner for the assets.
			DepositAsset { assets, beneficiary } => {
				let old_holding = self.holding.clone();
				let result = Config::TransactionalProcessor::process(|| {
					// Take assets from the holding registrar...
					let deposited = self.holding.saturating_take(assets);
					// ... and deposit them to the `beneficiary`.
					for asset in deposited.into_assets_iter() {
						Config::AssetTransactor::deposit_asset(
							&asset,
							&beneficiary,
							Some(&self.context),
						)?;
					}
					Ok(())
				});
				// If we were unable to execute `deposit_asset` in the `AssetTransactor`, we reset
				// the XCM Executor holding registrar since no operations took place.
				if Config::TransactionalProcessor::IS_TRANSACTIONAL && result.is_err() {
					self.holding = old_holding;
				}
				result
			},
			// Asset(s) (`assets`) have been destroyed on the `origin` system and equivalent assets
			// should be created and placed into the Holding Register.
			//
			// - `assets`: The asset(s) that are minted into the Holding Register.
			ReceiveTeleportedAsset(assets) => {
				Config::TransactionalProcessor::process(|| {
					let origin = self.origin_ref().ok_or(XcmError::BadOrigin)?;
					// check whether we trust origin to teleport this asset to us via config trait.
					for asset in assets.inner() {
						// We should check that the asset can actually be teleported in (for this to
						// be in error, there would need to be an accounting violation by one of the
						// trusted chains, so it's unlikely, but we don't want to punish a possibly
						// innocent chain/user).
						Config::AssetTransactor::can_check_in(origin, asset, &self.context)?;
						Config::AssetTransactor::check_in(origin, asset, &self.context);
					}
					Ok(())
				})
				.and_then(|_| {
					// ...and place into holding.
					self.holding.subsume_assets(assets.into());
					Ok(())
				})
			},
			// In this workshop, we won't be implementing every instruction, just the ones above...
			// Our executor will simply panic if you try to execute other instructions.
			_ => unimplemented!(),
		}
	}
}

/// A public trait allowing other systems to access and use the `XcmExecutor`.
pub trait ExecuteXcm {
	/// Execute an XCM from a given `origin`.
	fn execute(origin: impl Into<Location>, xcm: Xcm<()>) -> XcmResult;
}

impl<Config: XcmConfig> ExecuteXcm for XcmExecutor<Config> {
	/// Execute an XCM from a given `origin`.
	fn execute(origin: impl Into<Location>, xcm: Xcm<()>) -> XcmResult {
		log::trace!(target: "xcm::execute", "xcm: {:?}", xcm);
		/* TODO:
			- Convert the `origin` `into` a `Location`.
			- Create a new mutable instance of the XCM Executor as `vm`.
			- Use the `vm` to `process` the `xcm`.
		*/
		todo!("{:?}", origin.into())
	}
}
}
#![allow(unused)]
fn main() {
//! # Fundamentals lesson 5: XCM Executor
//!
//! Create your own executor for XCM.

use super::holding::*;

use sp_std::{marker::PhantomData, prelude::*};
use xcm::latest::prelude::*;
use xcm_executor::traits::{ProcessTransaction, TransactAsset};

pub trait XcmConfig {
	/// How to withdraw and deposit an asset.
	type AssetTransactor: TransactAsset;
	/// Transactional processor for XCM instructions.
	type TransactionalProcessor: ProcessTransaction;
}

/// The heart of the XCM Virtual Machine.
pub struct XcmExecutor<Config: XcmConfig> {
	/// The asset holding registrar, where we keep track of assets being processed by the XCM
	/// Executor.
	pub holding: AssetsInHolding,
	/// Contextual data pertaining to a specific list of XCM instructions. Most relevant the
	/// `origin` of the XCM Message.
	pub context: XcmContext,
	/// Just a placeholder to allow Rust to let us keep `Config`.
	_config: PhantomData<Config>,
}

/// The implementation of the XCM Executor and how it processes XCM.
impl<Config: XcmConfig> XcmExecutor<Config> {
	/// Crete an initialize a new XCM Executor.
	pub fn new(origin: impl Into<Location>) -> Self {
		let origin = origin.into();
		// In our version of the XCM Executor, we ignore `message_id` and `topic`.
		let context =
			XcmContext { origin: Some(origin), message_id: Default::default(), topic: None };
		Self { holding: Default::default(), context, _config: PhantomData }
	}

	/// Process an entire XCM program, instruction by instruction.
	pub fn process(&mut self, xcm: Xcm<()>) -> Result<(), XcmError> {
		log::trace!(target: "xcm::process", "xcm: {:?}", xcm);
		for instruction in xcm.0.into_iter() {
			self.process_instruction(instruction)?;
		}
		Ok(())
	}

	/// Simple helper function to access the `origin` from the XCM Executor `context`.
	pub fn origin_ref(&self) -> Option<&Location> {
		self.context.origin.as_ref()
	}

	/// Process a single XCM instruction, mutating the state of the XCM virtual machine.
	fn process_instruction(&mut self, instr: Instruction<()>) -> Result<(), XcmError> {
		log::trace!(target: "xcm::process_instruction", "=== {:?}", instr);
		match instr {
			// Clear the origin.
			//
			// This may be used by the XCM author to ensure that later instructions cannot command
			// the authority of the origin (e.g. if they are being relayed from an untrusted
			// source, as often the case with `ReserveAssetDeposited`).
			ClearOrigin => {
				self.context.origin = None;
				Ok(())
			},
			// Appends `who` to the current XCM Executor `origin` location.
			DescendOrigin(who) => self
				.context
				.origin
				.as_mut()
				.ok_or(XcmError::BadOrigin)?
				.append_with(who)
				.map_err(|_| XcmError::LocationFull),
			// Withdraw asset(s) (`assets`) from the ownership of `origin` and place equivalent
			// assets under the ownership of `beneficiary`.
			//
			// - `assets`: The asset(s) to be withdrawn.
			// - `beneficiary`: The new owner for the assets.
			TransferAsset { assets, beneficiary } => {
				Config::TransactionalProcessor::process(|| {
					// Take `assets` from the origin account (on-chain) and place into dest account.
					let origin = self.origin_ref().ok_or(XcmError::BadOrigin)?;
					// Transfer each asset using the `AssetTransactor`.
					for asset in assets.inner() {
						Config::AssetTransactor::transfer_asset(
							&asset,
							origin,
							&beneficiary,
							&self.context,
						)?;
					}
					Ok(())
				})
			},
			// Withdraw asset(s) (`assets`) from the ownership of `origin` and place them into the
			// Holding Register.
			//
			// - `assets`: The asset(s) to be withdrawn into holding.
			WithdrawAsset(assets) => {
				Config::TransactionalProcessor::process(|| {
					let origin = self.origin_ref().ok_or(XcmError::BadOrigin)?;
					// Take `assets` from the origin account (on-chain)...
					for asset in assets.inner() {
						Config::AssetTransactor::withdraw_asset(
							asset,
							origin,
							Some(&self.context),
						)?;
					}
					Ok(())
				})
				.and_then(|_| {
					// ...and place into holding.
					self.holding.subsume_assets(assets.into());
					Ok(())
				})
			},
			// Reduce Holding by up to the given assets.
			//
			// Holding is reduced by as much as possible up to the assets in the parameter. It is
			// not an error if the Holding does not contain the assets (to make this an error, use
			// `ExpectAsset` prior).
			BurnAsset(assets) => {
				self.holding.saturating_take(assets.into());
				Ok(())
			},
			// Remove the asset(s) (`assets`) from the Holding Register and place equivalent assets
			// under the ownership of `beneficiary` within this consensus system.
			//
			// - `assets`: The asset(s) to remove from holding.
			// - `beneficiary`: The new owner for the assets.
			DepositAsset { assets, beneficiary } => {
				let old_holding = self.holding.clone();
				let result = Config::TransactionalProcessor::process(|| {
					// Take assets from the holding registrar...
					let deposited = self.holding.saturating_take(assets);
					// ... and deposit them to the `beneficiary`.
					for asset in deposited.into_assets_iter() {
						Config::AssetTransactor::deposit_asset(
							&asset,
							&beneficiary,
							Some(&self.context),
						)?;
					}
					Ok(())
				});
				// If we were unable to execute `deposit_asset` in the `AssetTransactor`, we reset
				// the XCM Executor holding registrar since no operations took place.
				if Config::TransactionalProcessor::IS_TRANSACTIONAL && result.is_err() {
					self.holding = old_holding;
				}
				result
			},
			// Asset(s) (`assets`) have been destroyed on the `origin` system and equivalent assets
			// should be created and placed into the Holding Register.
			//
			// - `assets`: The asset(s) that are minted into the Holding Register.
			ReceiveTeleportedAsset(assets) => {
				Config::TransactionalProcessor::process(|| {
					let origin = self.origin_ref().ok_or(XcmError::BadOrigin)?;
					// check whether we trust origin to teleport this asset to us via config trait.
					for asset in assets.inner() {
						// We should check that the asset can actually be teleported in (for this to
						// be in error, there would need to be an accounting violation by one of the
						// trusted chains, so it's unlikely, but we don't want to punish a possibly
						// innocent chain/user).
						Config::AssetTransactor::can_check_in(origin, asset, &self.context)?;
						Config::AssetTransactor::check_in(origin, asset, &self.context);
					}
					Ok(())
				})
				.and_then(|_| {
					// ...and place into holding.
					self.holding.subsume_assets(assets.into());
					Ok(())
				})
			},
			// In this workshop, we won't be implementing every instruction, just the ones above...
			// Our executor will simply panic if you try to execute other instructions.
			_ => unimplemented!(),
		}
	}
}

/// A public trait allowing other systems to access and use the `XcmExecutor`.
pub trait ExecuteXcm {
	/// Execute an XCM from a given `origin`.
	fn execute(origin: impl Into<Location>, xcm: Xcm<()>) -> XcmResult;
}

impl<Config: XcmConfig> ExecuteXcm for XcmExecutor<Config> {
	/// Execute an XCM from a given `origin`.
	fn execute(origin: impl Into<Location>, xcm: Xcm<()>) -> XcmResult {
		log::trace!(target: "xcm::execute", "xcm: {:?}", xcm);
		let origin: Location = origin.into();
		let mut vm = Self::new(origin);
		vm.process(xcm)
	}
}
}
diff --git a/fundamentals/src/xcm_executor.rs b/fundamentals/src/xcm_executor.rs
index f03d79b..168bda0 100644
--- a/fundamentals/src/xcm_executor.rs
+++ b/fundamentals/src/xcm_executor.rs
@@ -194,6 +194,11 @@ impl<Config: XcmConfig> ExecuteXcm for XcmExecutor<Config> {
 	/// Execute an XCM from a given `origin`.
 	fn execute(origin: impl Into<Location>, xcm: Xcm<()>) -> XcmResult {
 		log::trace!(target: "xcm::execute", "xcm: {:?}", xcm);
+		/* TODO:
+			- Convert the `origin` `into` a `Location`.
+			- Create a new mutable instance of the XCM Executor as `vm`.
+			- Use the `vm` to `process` the `xcm`.
+		*/
 		todo!("{:?}", origin.into())
 	}
 }
diff --git a/fundamentals/src/xcm_executor.rs b/fundamentals/src/xcm_executor.rs
index 168bda0..f7e8d2e 100644
--- a/fundamentals/src/xcm_executor.rs
+++ b/fundamentals/src/xcm_executor.rs
@@ -194,11 +194,8 @@ impl<Config: XcmConfig> ExecuteXcm for XcmExecutor<Config> {
 	/// Execute an XCM from a given `origin`.
 	fn execute(origin: impl Into<Location>, xcm: Xcm<()>) -> XcmResult {
 		log::trace!(target: "xcm::execute", "xcm: {:?}", xcm);
-		/* TODO:
-			- Convert the `origin` `into` a `Location`.
-			- Create a new mutable instance of the XCM Executor as `vm`.
-			- Use the `vm` to `process` the `xcm`.
-		*/
-		todo!("{:?}", origin.into())
+		let origin: Location = origin.into();
+		let mut vm = Self::new(origin);
+		vm.process(xcm)
 	}
 }

Pallet XCM

Start of Pallet XCM Section

#![allow(unused)]
fn main() {
//! # Fundamentals lesson 6: Pallet XCM
//!
//! Implement the core functionality of Pallet XCM

use crate::xcm_executor::ExecuteXcm;
use frame_support::pallet_prelude::*;
use frame_system::pallet_prelude::*;
use xcm::{prelude::*, VersionedAssets, VersionedLocation, VersionedXcm};

pub use pallet::*;

#[frame_support::pallet]
pub mod pallet {
	use super::*;

	#[pallet::pallet]
	pub struct Pallet<T>(_);

	#[pallet::config]
	pub trait Config: frame_system::Config {
		/// Something to execute an XCM message.
		type XcmExecutor: ExecuteXcm;
		/// Required origin for executing XCM messages, including the teleport functionality. If
		/// successful, then it resolves to `Location` which exists as an interior location
		/// within this chain's XCM context.
		type ExecuteXcmOrigin: EnsureOrigin<
			<Self as frame_system::Config>::RuntimeOrigin,
			Success = Location,
		>;
		/// Required origin for sending XCM messages. If successful, it resolves to `Location`
		/// which exists as an interior location within this chain's XCM context.
		type SendXcmOrigin: EnsureOrigin<
			<Self as frame_system::Config>::RuntimeOrigin,
			Success = Location,
		>;
		/// The type used to actually dispatch an XCM to its destination.
		type XcmRouter: SendXcm;
		/// This chain's Universal Location.
		type UniversalLocation: Get<InteriorLocation>;
	}

	#[pallet::error]
	pub enum Error<T> {
		/// The version of the `Versioned` value used is not able to be interpreted.
		BadVersion,
		/// Origin is invalid for sending.
		InvalidOrigin,
		/// Could not re-anchor the assets to declare the fees for the destination chain.
		CannotReanchor,
		/// A general error indicating something went wrong with the XCM Executor.
		ExecutorError,
		/// A general error indicating something went wrong with the XCM Router.
		RouterError,
	}

	#[pallet::call]
	impl<T: Config> Pallet<T> {
		/// Execute an XCM from a local, signed, origin.
		#[pallet::call_index(0)]
		#[pallet::weight(Weight::default())]
		pub fn execute(
			origin: OriginFor<T>,
			message: Box<VersionedXcm<()>>,
			_max_weight: Weight,
		) -> DispatchResult {
			let message = (*message).try_into().map_err(|()| Error::<T>::BadVersion)?;
			// Actually execute the XCM.
			Self::do_execute(origin, message)
		}

		/// Send an XCM to another consensus system.
		#[pallet::call_index(1)]
		#[pallet::weight(Weight::default())]
		pub fn send(
			origin: OriginFor<T>,
			dest: Box<VersionedLocation>,
			message: Box<VersionedXcm<()>>,
		) -> DispatchResult {
			let dest = Location::try_from(*dest).map_err(|()| Error::<T>::BadVersion)?;
			let message: Xcm<()> = (*message).try_into().map_err(|()| Error::<T>::BadVersion)?;
			// Actually send the XCM.
			Self::do_send(origin, dest, message)
		}

		/// Teleport some assets from the local chain to some destination chain.
		#[pallet::call_index(2)]
		#[pallet::weight(Weight::default())]
		pub fn teleport_assets(
			origin: OriginFor<T>,
			dest: Box<VersionedLocation>,
			beneficiary: Box<VersionedLocation>,
			assets: Box<VersionedAssets>,
			fee_asset_item: u32,
		) -> DispatchResult {
			let dest: Location = (*dest).try_into().map_err(|()| Error::<T>::BadVersion)?;
			let beneficiary: Location =
				(*beneficiary).try_into().map_err(|()| Error::<T>::BadVersion)?;
			let assets: Assets = (*assets).try_into().map_err(|()| Error::<T>::BadVersion)?;
			// Actually teleport the assets.
			Self::do_teleport_assets(origin, dest, beneficiary, assets, fee_asset_item)
		}

		/// Transfer some assets from the local chain to the destination chain through their local,
		/// destination or remote reserve.
		#[pallet::call_index(3)]
		#[pallet::weight(Weight::default())]
		pub fn reserve_transfer_assets(
			origin: OriginFor<T>,
			dest: Box<VersionedLocation>,
			beneficiary: Box<VersionedLocation>,
			assets: Box<VersionedAssets>,
			fee_asset_item: u32,
		) -> DispatchResult {
			let dest: Location = (*dest).try_into().map_err(|()| Error::<T>::BadVersion)?;
			let beneficiary: Location =
				(*beneficiary).try_into().map_err(|()| Error::<T>::BadVersion)?;
			let assets: Assets = (*assets).try_into().map_err(|()| Error::<T>::BadVersion)?;
			// Actually reserve transfer the assets.
			Self::do_reserve_transfer_assets(origin, dest, beneficiary, assets, fee_asset_item)
		}
	}
}

impl<T: Config> Pallet<T> {
	pub fn do_execute(origin: OriginFor<T>, message: Xcm<()>) -> DispatchResult {
		todo!("{:?}", message)
	}

	/// Relay an XCM `message` from a given `interior` location in this context to a given `dest`
	/// location.
	pub fn do_send(origin: OriginFor<T>, dest: Location, mut message: Xcm<()>) -> DispatchResult {
		todo!("{:?} {:?}", dest, message)
	}

	pub fn do_teleport_assets(
		origin: OriginFor<T>,
		dest: Location,
		beneficiary: Location,
		assets: Assets,
		// The index into `assets` of the item which should be used to pay fees.
		// We don't use this in our naive implementation.
		_fee_asset_item: u32,
	) -> DispatchResult {
		todo!("{:?} {:?} {:?}", dest, beneficiary, assets)
	}

	pub fn do_reserve_transfer_assets(
		_origin: OriginFor<T>,
		_dest: Location,
		_beneficiary: Location,
		_assets: Assets,
		_fee_asset_item: u32,
	) -> DispatchResult {
		// There are 3 different reserve transfer scenarios:
		// - A local reserve transfer: reserve-transfer `asset` to `dest`, using local chain as
		//   reserve.
		// - A destination reserve transfer: reserve-transfer `asset` to `dest`, using `dest` as
		//   reserve.
		// - A remote reserve transfer: reserve-transfer `asset` to `dest`, using remote chain
		//   `Location` as reserve.
		//
		// This is a lot to do in this workshop, but a welcome challenge for the reader to
		// implement.
		unimplemented!()
	}
}
}
diff --git a/fundamentals/src/pallet_xcm.rs b/fundamentals/src/pallet_xcm.rs
index 8b13789..7be7118 100644
--- a/fundamentals/src/pallet_xcm.rs
+++ b/fundamentals/src/pallet_xcm.rs
@@ -1 +1,166 @@
+//! # Fundamentals lesson 6: Pallet XCM
+//!
+//! Implement the core functionality of Pallet XCM
 
+use crate::xcm_executor::ExecuteXcm;
+use frame_support::pallet_prelude::*;
+use frame_system::pallet_prelude::*;
+use xcm::{prelude::*, VersionedAssets, VersionedLocation, VersionedXcm};
+
+pub use pallet::*;
+
+#[frame_support::pallet]
+pub mod pallet {
+	use super::*;
+
+	#[pallet::pallet]
+	pub struct Pallet<T>(_);
+
+	#[pallet::config]
+	pub trait Config: frame_system::Config {
+		/// Something to execute an XCM message.
+		type XcmExecutor: ExecuteXcm;
+		/// Required origin for executing XCM messages, including the teleport functionality. If
+		/// successful, then it resolves to `Location` which exists as an interior location
+		/// within this chain's XCM context.
+		type ExecuteXcmOrigin: EnsureOrigin<
+			<Self as frame_system::Config>::RuntimeOrigin,
+			Success = Location,
+		>;
+		/// Required origin for sending XCM messages. If successful, it resolves to `Location`
+		/// which exists as an interior location within this chain's XCM context.
+		type SendXcmOrigin: EnsureOrigin<
+			<Self as frame_system::Config>::RuntimeOrigin,
+			Success = Location,
+		>;
+		/// The type used to actually dispatch an XCM to its destination.
+		type XcmRouter: SendXcm;
+		/// This chain's Universal Location.
+		type UniversalLocation: Get<InteriorLocation>;
+	}
+
+	#[pallet::error]
+	pub enum Error<T> {
+		/// The version of the `Versioned` value used is not able to be interpreted.
+		BadVersion,
+		/// Origin is invalid for sending.
+		InvalidOrigin,
+		/// Could not re-anchor the assets to declare the fees for the destination chain.
+		CannotReanchor,
+		/// A general error indicating something went wrong with the XCM Executor.
+		ExecutorError,
+		/// A general error indicating something went wrong with the XCM Router.
+		RouterError,
+	}
+
+	#[pallet::call]
+	impl<T: Config> Pallet<T> {
+		/// Execute an XCM from a local, signed, origin.
+		#[pallet::call_index(0)]
+		#[pallet::weight(Weight::default())]
+		pub fn execute(
+			origin: OriginFor<T>,
+			message: Box<VersionedXcm<()>>,
+			_max_weight: Weight,
+		) -> DispatchResult {
+			let message = (*message).try_into().map_err(|()| Error::<T>::BadVersion)?;
+			// Actually execute the XCM.
+			Self::do_execute(origin, message)
+		}
+
+		/// Send an XCM to another consensus system.
+		#[pallet::call_index(1)]
+		#[pallet::weight(Weight::default())]
+		pub fn send(
+			origin: OriginFor<T>,
+			dest: Box<VersionedLocation>,
+			message: Box<VersionedXcm<()>>,
+		) -> DispatchResult {
+			let dest = Location::try_from(*dest).map_err(|()| Error::<T>::BadVersion)?;
+			let message: Xcm<()> = (*message).try_into().map_err(|()| Error::<T>::BadVersion)?;
+			// Actually send the XCM.
+			Self::do_send(origin, dest, message)
+		}
+
+		/// Teleport some assets from the local chain to some destination chain.
+		#[pallet::call_index(2)]
+		#[pallet::weight(Weight::default())]
+		pub fn teleport_assets(
+			origin: OriginFor<T>,
+			dest: Box<VersionedLocation>,
+			beneficiary: Box<VersionedLocation>,
+			assets: Box<VersionedAssets>,
+			fee_asset_item: u32,
+		) -> DispatchResult {
+			let dest: Location = (*dest).try_into().map_err(|()| Error::<T>::BadVersion)?;
+			let beneficiary: Location =
+				(*beneficiary).try_into().map_err(|()| Error::<T>::BadVersion)?;
+			let assets: Assets = (*assets).try_into().map_err(|()| Error::<T>::BadVersion)?;
+			// Actually teleport the assets.
+			Self::do_teleport_assets(origin, dest, beneficiary, assets, fee_asset_item)
+		}
+
+		/// Transfer some assets from the local chain to the destination chain through their local,
+		/// destination or remote reserve.
+		#[pallet::call_index(3)]
+		#[pallet::weight(Weight::default())]
+		pub fn reserve_transfer_assets(
+			origin: OriginFor<T>,
+			dest: Box<VersionedLocation>,
+			beneficiary: Box<VersionedLocation>,
+			assets: Box<VersionedAssets>,
+			fee_asset_item: u32,
+		) -> DispatchResult {
+			let dest: Location = (*dest).try_into().map_err(|()| Error::<T>::BadVersion)?;
+			let beneficiary: Location =
+				(*beneficiary).try_into().map_err(|()| Error::<T>::BadVersion)?;
+			let assets: Assets = (*assets).try_into().map_err(|()| Error::<T>::BadVersion)?;
+			// Actually reserve transfer the assets.
+			Self::do_reserve_transfer_assets(origin, dest, beneficiary, assets, fee_asset_item)
+		}
+	}
+}
+
+impl<T: Config> Pallet<T> {
+	pub fn do_execute(origin: OriginFor<T>, message: Xcm<()>) -> DispatchResult {
+		todo!("{:?}", message)
+	}
+
+	/// Relay an XCM `message` from a given `interior` location in this context to a given `dest`
+	/// location.
+	pub fn do_send(origin: OriginFor<T>, dest: Location, mut message: Xcm<()>) -> DispatchResult {
+		todo!("{:?} {:?}", dest, message)
+	}
+
+	pub fn do_teleport_assets(
+		origin: OriginFor<T>,
+		dest: Location,
+		beneficiary: Location,
+		assets: Assets,
+		// The index into `assets` of the item which should be used to pay fees.
+		// We don't use this in our naive implementation.
+		_fee_asset_item: u32,
+	) -> DispatchResult {
+		todo!("{:?} {:?} {:?}", dest, beneficiary, assets)
+	}
+
+	pub fn do_reserve_transfer_assets(
+		_origin: OriginFor<T>,
+		_dest: Location,
+		_beneficiary: Location,
+		_assets: Assets,
+		_fee_asset_item: u32,
+	) -> DispatchResult {
+		// There are 3 different reserve transfer scenarios:
+		// - A local reserve transfer: reserve-transfer `asset` to `dest`, using local chain as
+		//   reserve.
+		// - A destination reserve transfer: reserve-transfer `asset` to `dest`, using `dest` as
+		//   reserve.
+		// - A remote reserve transfer: reserve-transfer `asset` to `dest`, using remote chain
+		//   `Location` as reserve.
+		//
+		// This is a lot to do in this workshop, but a welcome challenge for the reader to
+		// implement.
+		unimplemented!()
+	}
+}
#![allow(unused)]
fn main() {
//! # Fundamentals lesson 6: Pallet XCM
//!
//! Implement the core functionality of Pallet XCM

use crate::xcm_executor::ExecuteXcm;
use frame_support::pallet_prelude::*;
use frame_system::pallet_prelude::*;
use xcm::{prelude::*, VersionedAssets, VersionedLocation, VersionedXcm};

pub use pallet::*;

#[frame_support::pallet]
pub mod pallet {
	use super::*;

	#[pallet::pallet]
	pub struct Pallet<T>(_);

	#[pallet::config]
	pub trait Config: frame_system::Config {
		/// Something to execute an XCM message.
		type XcmExecutor: ExecuteXcm;
		/// Required origin for executing XCM messages, including the teleport functionality. If
		/// successful, then it resolves to `Location` which exists as an interior location
		/// within this chain's XCM context.
		type ExecuteXcmOrigin: EnsureOrigin<
			<Self as frame_system::Config>::RuntimeOrigin,
			Success = Location,
		>;
		/// Required origin for sending XCM messages. If successful, it resolves to `Location`
		/// which exists as an interior location within this chain's XCM context.
		type SendXcmOrigin: EnsureOrigin<
			<Self as frame_system::Config>::RuntimeOrigin,
			Success = Location,
		>;
		/// The type used to actually dispatch an XCM to its destination.
		type XcmRouter: SendXcm;
		/// This chain's Universal Location.
		type UniversalLocation: Get<InteriorLocation>;
	}

	#[pallet::error]
	pub enum Error<T> {
		/// The version of the `Versioned` value used is not able to be interpreted.
		BadVersion,
		/// Origin is invalid for sending.
		InvalidOrigin,
		/// Could not re-anchor the assets to declare the fees for the destination chain.
		CannotReanchor,
		/// A general error indicating something went wrong with the XCM Executor.
		ExecutorError,
		/// A general error indicating something went wrong with the XCM Router.
		RouterError,
	}

	#[pallet::call]
	impl<T: Config> Pallet<T> {
		/// Execute an XCM from a local, signed, origin.
		#[pallet::call_index(0)]
		#[pallet::weight(Weight::default())]
		pub fn execute(
			origin: OriginFor<T>,
			message: Box<VersionedXcm<()>>,
			_max_weight: Weight,
		) -> DispatchResult {
			let message = (*message).try_into().map_err(|()| Error::<T>::BadVersion)?;
			// Actually execute the XCM.
			Self::do_execute(origin, message)
		}

		/// Send an XCM to another consensus system.
		#[pallet::call_index(1)]
		#[pallet::weight(Weight::default())]
		pub fn send(
			origin: OriginFor<T>,
			dest: Box<VersionedLocation>,
			message: Box<VersionedXcm<()>>,
		) -> DispatchResult {
			let dest = Location::try_from(*dest).map_err(|()| Error::<T>::BadVersion)?;
			let message: Xcm<()> = (*message).try_into().map_err(|()| Error::<T>::BadVersion)?;
			// Actually send the XCM.
			Self::do_send(origin, dest, message)
		}

		/// Teleport some assets from the local chain to some destination chain.
		#[pallet::call_index(2)]
		#[pallet::weight(Weight::default())]
		pub fn teleport_assets(
			origin: OriginFor<T>,
			dest: Box<VersionedLocation>,
			beneficiary: Box<VersionedLocation>,
			assets: Box<VersionedAssets>,
			fee_asset_item: u32,
		) -> DispatchResult {
			let dest: Location = (*dest).try_into().map_err(|()| Error::<T>::BadVersion)?;
			let beneficiary: Location =
				(*beneficiary).try_into().map_err(|()| Error::<T>::BadVersion)?;
			let assets: Assets = (*assets).try_into().map_err(|()| Error::<T>::BadVersion)?;
			// Actually teleport the assets.
			Self::do_teleport_assets(origin, dest, beneficiary, assets, fee_asset_item)
		}

		/// Transfer some assets from the local chain to the destination chain through their local,
		/// destination or remote reserve.
		#[pallet::call_index(3)]
		#[pallet::weight(Weight::default())]
		pub fn reserve_transfer_assets(
			origin: OriginFor<T>,
			dest: Box<VersionedLocation>,
			beneficiary: Box<VersionedLocation>,
			assets: Box<VersionedAssets>,
			fee_asset_item: u32,
		) -> DispatchResult {
			let dest: Location = (*dest).try_into().map_err(|()| Error::<T>::BadVersion)?;
			let beneficiary: Location =
				(*beneficiary).try_into().map_err(|()| Error::<T>::BadVersion)?;
			let assets: Assets = (*assets).try_into().map_err(|()| Error::<T>::BadVersion)?;
			// Actually reserve transfer the assets.
			Self::do_reserve_transfer_assets(origin, dest, beneficiary, assets, fee_asset_item)
		}
	}
}

impl<T: Config> Pallet<T> {
	/// Execute an XCM locally on this chain on behalf of `origin`.
	pub fn do_execute(origin: OriginFor<T>, message: Xcm<()>) -> DispatchResult {
		// Use `ExecuteXcmOrigin` to "ensure" that `origin` is able to execute a local XCM
		// and assign the resulting location to `execute_origin`.
		// Use `XcmExecutor` to `execute` the call, and if an error occurs, return `ExecutorError`.
		todo!("{:?}", message)
	}

	/// Relay an XCM `message` from a given `interior` location in this context to a given `dest`
	/// location.
	pub fn do_send(origin: OriginFor<T>, dest: Location, mut message: Xcm<()>) -> DispatchResult {
		todo!("{:?} {:?}", dest, message)
	}

	pub fn do_teleport_assets(
		origin: OriginFor<T>,
		dest: Location,
		beneficiary: Location,
		assets: Assets,
		// The index into `assets` of the item which should be used to pay fees.
		// We don't use this in our naive implementation.
		_fee_asset_item: u32,
	) -> DispatchResult {
		todo!("{:?} {:?} {:?}", dest, beneficiary, assets)
	}

	pub fn do_reserve_transfer_assets(
		_origin: OriginFor<T>,
		_dest: Location,
		_beneficiary: Location,
		_assets: Assets,
		_fee_asset_item: u32,
	) -> DispatchResult {
		// There are 3 different reserve transfer scenarios:
		// - A local reserve transfer: reserve-transfer `asset` to `dest`, using local chain as
		//   reserve.
		// - A destination reserve transfer: reserve-transfer `asset` to `dest`, using `dest` as
		//   reserve.
		// - A remote reserve transfer: reserve-transfer `asset` to `dest`, using remote chain
		//   `Location` as reserve.
		//
		// This is a lot to do in this workshop, but a welcome challenge for the reader to
		// implement.
		unimplemented!()
	}
}
}
#![allow(unused)]
fn main() {
//! # Fundamentals lesson 6: Pallet XCM
//!
//! Implement the core functionality of Pallet XCM

use crate::xcm_executor::ExecuteXcm;
use frame_support::pallet_prelude::*;
use frame_system::pallet_prelude::*;
use xcm::{prelude::*, VersionedAssets, VersionedLocation, VersionedXcm};

pub use pallet::*;

#[frame_support::pallet]
pub mod pallet {
	use super::*;

	#[pallet::pallet]
	pub struct Pallet<T>(_);

	#[pallet::config]
	pub trait Config: frame_system::Config {
		/// Something to execute an XCM message.
		type XcmExecutor: ExecuteXcm;
		/// Required origin for executing XCM messages, including the teleport functionality. If
		/// successful, then it resolves to `Location` which exists as an interior location
		/// within this chain's XCM context.
		type ExecuteXcmOrigin: EnsureOrigin<
			<Self as frame_system::Config>::RuntimeOrigin,
			Success = Location,
		>;
		/// Required origin for sending XCM messages. If successful, it resolves to `Location`
		/// which exists as an interior location within this chain's XCM context.
		type SendXcmOrigin: EnsureOrigin<
			<Self as frame_system::Config>::RuntimeOrigin,
			Success = Location,
		>;
		/// The type used to actually dispatch an XCM to its destination.
		type XcmRouter: SendXcm;
		/// This chain's Universal Location.
		type UniversalLocation: Get<InteriorLocation>;
	}

	#[pallet::error]
	pub enum Error<T> {
		/// The version of the `Versioned` value used is not able to be interpreted.
		BadVersion,
		/// Origin is invalid for sending.
		InvalidOrigin,
		/// Could not re-anchor the assets to declare the fees for the destination chain.
		CannotReanchor,
		/// A general error indicating something went wrong with the XCM Executor.
		ExecutorError,
		/// A general error indicating something went wrong with the XCM Router.
		RouterError,
	}

	#[pallet::call]
	impl<T: Config> Pallet<T> {
		/// Execute an XCM from a local, signed, origin.
		#[pallet::call_index(0)]
		#[pallet::weight(Weight::default())]
		pub fn execute(
			origin: OriginFor<T>,
			message: Box<VersionedXcm<()>>,
			_max_weight: Weight,
		) -> DispatchResult {
			let message = (*message).try_into().map_err(|()| Error::<T>::BadVersion)?;
			// Actually execute the XCM.
			Self::do_execute(origin, message)
		}

		/// Send an XCM to another consensus system.
		#[pallet::call_index(1)]
		#[pallet::weight(Weight::default())]
		pub fn send(
			origin: OriginFor<T>,
			dest: Box<VersionedLocation>,
			message: Box<VersionedXcm<()>>,
		) -> DispatchResult {
			let dest = Location::try_from(*dest).map_err(|()| Error::<T>::BadVersion)?;
			let message: Xcm<()> = (*message).try_into().map_err(|()| Error::<T>::BadVersion)?;
			// Actually send the XCM.
			Self::do_send(origin, dest, message)
		}

		/// Teleport some assets from the local chain to some destination chain.
		#[pallet::call_index(2)]
		#[pallet::weight(Weight::default())]
		pub fn teleport_assets(
			origin: OriginFor<T>,
			dest: Box<VersionedLocation>,
			beneficiary: Box<VersionedLocation>,
			assets: Box<VersionedAssets>,
			fee_asset_item: u32,
		) -> DispatchResult {
			let dest: Location = (*dest).try_into().map_err(|()| Error::<T>::BadVersion)?;
			let beneficiary: Location =
				(*beneficiary).try_into().map_err(|()| Error::<T>::BadVersion)?;
			let assets: Assets = (*assets).try_into().map_err(|()| Error::<T>::BadVersion)?;
			// Actually teleport the assets.
			Self::do_teleport_assets(origin, dest, beneficiary, assets, fee_asset_item)
		}

		/// Transfer some assets from the local chain to the destination chain through their local,
		/// destination or remote reserve.
		#[pallet::call_index(3)]
		#[pallet::weight(Weight::default())]
		pub fn reserve_transfer_assets(
			origin: OriginFor<T>,
			dest: Box<VersionedLocation>,
			beneficiary: Box<VersionedLocation>,
			assets: Box<VersionedAssets>,
			fee_asset_item: u32,
		) -> DispatchResult {
			let dest: Location = (*dest).try_into().map_err(|()| Error::<T>::BadVersion)?;
			let beneficiary: Location =
				(*beneficiary).try_into().map_err(|()| Error::<T>::BadVersion)?;
			let assets: Assets = (*assets).try_into().map_err(|()| Error::<T>::BadVersion)?;
			// Actually reserve transfer the assets.
			Self::do_reserve_transfer_assets(origin, dest, beneficiary, assets, fee_asset_item)
		}
	}
}

impl<T: Config> Pallet<T> {
	/// Execute an XCM locally on this chain on behalf of `origin`.
	pub fn do_execute(origin: OriginFor<T>, message: Xcm<()>) -> DispatchResult {
		let execute_origin: Location = T::ExecuteXcmOrigin::ensure_origin(origin)?;
		T::XcmExecutor::execute(execute_origin, message).map_err(|_| Error::<T>::ExecutorError)?;
		Ok(())
	}

	/// Relay an XCM `message` from a given `interior` location in this context to a given `dest`
	/// location.
	pub fn do_send(origin: OriginFor<T>, dest: Location, mut message: Xcm<()>) -> DispatchResult {
		todo!("{:?} {:?}", dest, message)
	}

	pub fn do_teleport_assets(
		origin: OriginFor<T>,
		dest: Location,
		beneficiary: Location,
		assets: Assets,
		// The index into `assets` of the item which should be used to pay fees.
		// We don't use this in our naive implementation.
		_fee_asset_item: u32,
	) -> DispatchResult {
		todo!("{:?} {:?} {:?}", dest, beneficiary, assets)
	}

	pub fn do_reserve_transfer_assets(
		_origin: OriginFor<T>,
		_dest: Location,
		_beneficiary: Location,
		_assets: Assets,
		_fee_asset_item: u32,
	) -> DispatchResult {
		// There are 3 different reserve transfer scenarios:
		// - A local reserve transfer: reserve-transfer `asset` to `dest`, using local chain as
		//   reserve.
		// - A destination reserve transfer: reserve-transfer `asset` to `dest`, using `dest` as
		//   reserve.
		// - A remote reserve transfer: reserve-transfer `asset` to `dest`, using remote chain
		//   `Location` as reserve.
		//
		// This is a lot to do in this workshop, but a welcome challenge for the reader to
		// implement.
		unimplemented!()
	}
}
}
diff --git a/fundamentals/src/pallet_xcm.rs b/fundamentals/src/pallet_xcm.rs
index 7be7118..c3ea023 100644
--- a/fundamentals/src/pallet_xcm.rs
+++ b/fundamentals/src/pallet_xcm.rs
@@ -122,7 +122,11 @@ pub mod pallet {
 }
 
 impl<T: Config> Pallet<T> {
+	/// Execute an XCM locally on this chain on behalf of `origin`.
 	pub fn do_execute(origin: OriginFor<T>, message: Xcm<()>) -> DispatchResult {
+		// Use `ExecuteXcmOrigin` to "ensure" that `origin` is able to execute a local XCM
+		// and assign the resulting location to `execute_origin`.
+		// Use `XcmExecutor` to `execute` the call, and if an error occurs, return `ExecutorError`.
 		todo!("{:?}", message)
 	}
 
diff --git a/fundamentals/src/pallet_xcm.rs b/fundamentals/src/pallet_xcm.rs
index c3ea023..baec7b7 100644
--- a/fundamentals/src/pallet_xcm.rs
+++ b/fundamentals/src/pallet_xcm.rs
@@ -124,10 +124,9 @@ pub mod pallet {
 impl<T: Config> Pallet<T> {
 	/// Execute an XCM locally on this chain on behalf of `origin`.
 	pub fn do_execute(origin: OriginFor<T>, message: Xcm<()>) -> DispatchResult {
-		// Use `ExecuteXcmOrigin` to "ensure" that `origin` is able to execute a local XCM
-		// and assign the resulting location to `execute_origin`.
-		// Use `XcmExecutor` to `execute` the call, and if an error occurs, return `ExecutorError`.
-		todo!("{:?}", message)
+		let execute_origin: Location = T::ExecuteXcmOrigin::ensure_origin(origin)?;
+		T::XcmExecutor::execute(execute_origin, message).map_err(|_| Error::<T>::ExecutorError)?;
+		Ok(())
 	}
 
 	/// Relay an XCM `message` from a given `interior` location in this context to a given `dest`
#![allow(unused)]
fn main() {
//! # Fundamentals lesson 6: Pallet XCM
//!
//! Implement the core functionality of Pallet XCM

use crate::xcm_executor::ExecuteXcm;
use frame_support::pallet_prelude::*;
use frame_system::pallet_prelude::*;
use xcm::{prelude::*, VersionedAssets, VersionedLocation, VersionedXcm};

pub use pallet::*;

#[frame_support::pallet]
pub mod pallet {
	use super::*;

	#[pallet::pallet]
	pub struct Pallet<T>(_);

	#[pallet::config]
	pub trait Config: frame_system::Config {
		/// Something to execute an XCM message.
		type XcmExecutor: ExecuteXcm;
		/// Required origin for executing XCM messages, including the teleport functionality. If
		/// successful, then it resolves to `Location` which exists as an interior location
		/// within this chain's XCM context.
		type ExecuteXcmOrigin: EnsureOrigin<
			<Self as frame_system::Config>::RuntimeOrigin,
			Success = Location,
		>;
		/// Required origin for sending XCM messages. If successful, it resolves to `Location`
		/// which exists as an interior location within this chain's XCM context.
		type SendXcmOrigin: EnsureOrigin<
			<Self as frame_system::Config>::RuntimeOrigin,
			Success = Location,
		>;
		/// The type used to actually dispatch an XCM to its destination.
		type XcmRouter: SendXcm;
		/// This chain's Universal Location.
		type UniversalLocation: Get<InteriorLocation>;
	}

	#[pallet::error]
	pub enum Error<T> {
		/// The version of the `Versioned` value used is not able to be interpreted.
		BadVersion,
		/// Origin is invalid for sending.
		InvalidOrigin,
		/// Could not re-anchor the assets to declare the fees for the destination chain.
		CannotReanchor,
		/// A general error indicating something went wrong with the XCM Executor.
		ExecutorError,
		/// A general error indicating something went wrong with the XCM Router.
		RouterError,
	}

	#[pallet::call]
	impl<T: Config> Pallet<T> {
		/// Execute an XCM from a local, signed, origin.
		#[pallet::call_index(0)]
		#[pallet::weight(Weight::default())]
		pub fn execute(
			origin: OriginFor<T>,
			message: Box<VersionedXcm<()>>,
			_max_weight: Weight,
		) -> DispatchResult {
			let message = (*message).try_into().map_err(|()| Error::<T>::BadVersion)?;
			// Actually execute the XCM.
			Self::do_execute(origin, message)
		}

		/// Send an XCM to another consensus system.
		#[pallet::call_index(1)]
		#[pallet::weight(Weight::default())]
		pub fn send(
			origin: OriginFor<T>,
			dest: Box<VersionedLocation>,
			message: Box<VersionedXcm<()>>,
		) -> DispatchResult {
			let dest = Location::try_from(*dest).map_err(|()| Error::<T>::BadVersion)?;
			let message: Xcm<()> = (*message).try_into().map_err(|()| Error::<T>::BadVersion)?;
			// Actually send the XCM.
			Self::do_send(origin, dest, message)
		}

		/// Teleport some assets from the local chain to some destination chain.
		#[pallet::call_index(2)]
		#[pallet::weight(Weight::default())]
		pub fn teleport_assets(
			origin: OriginFor<T>,
			dest: Box<VersionedLocation>,
			beneficiary: Box<VersionedLocation>,
			assets: Box<VersionedAssets>,
			fee_asset_item: u32,
		) -> DispatchResult {
			let dest: Location = (*dest).try_into().map_err(|()| Error::<T>::BadVersion)?;
			let beneficiary: Location =
				(*beneficiary).try_into().map_err(|()| Error::<T>::BadVersion)?;
			let assets: Assets = (*assets).try_into().map_err(|()| Error::<T>::BadVersion)?;
			// Actually teleport the assets.
			Self::do_teleport_assets(origin, dest, beneficiary, assets, fee_asset_item)
		}

		/// Transfer some assets from the local chain to the destination chain through their local,
		/// destination or remote reserve.
		#[pallet::call_index(3)]
		#[pallet::weight(Weight::default())]
		pub fn reserve_transfer_assets(
			origin: OriginFor<T>,
			dest: Box<VersionedLocation>,
			beneficiary: Box<VersionedLocation>,
			assets: Box<VersionedAssets>,
			fee_asset_item: u32,
		) -> DispatchResult {
			let dest: Location = (*dest).try_into().map_err(|()| Error::<T>::BadVersion)?;
			let beneficiary: Location =
				(*beneficiary).try_into().map_err(|()| Error::<T>::BadVersion)?;
			let assets: Assets = (*assets).try_into().map_err(|()| Error::<T>::BadVersion)?;
			// Actually reserve transfer the assets.
			Self::do_reserve_transfer_assets(origin, dest, beneficiary, assets, fee_asset_item)
		}
	}
}

impl<T: Config> Pallet<T> {
	/// Execute an XCM locally on this chain on behalf of `origin`.
	pub fn do_execute(origin: OriginFor<T>, message: Xcm<()>) -> DispatchResult {
		let execute_origin: Location = T::ExecuteXcmOrigin::ensure_origin(origin)?;
		T::XcmExecutor::execute(execute_origin, message).map_err(|_| Error::<T>::ExecutorError)?;
		Ok(())
	}

	/// Relay an XCM `message` from a given `interior` location in this context to a given `dest`
	/// location.
	pub fn do_send(origin: OriginFor<T>, dest: Location, mut message: Xcm<()>) -> DispatchResult {
		/* TODO:
			- Use `SendXcmOrigin` to "ensure" that `origin` is valid to send XCM, and assign the resulting location to `origin_location`.
			- Convert `origin_location` to `interior: Junctions`, else return `InvalidOrigin`.
			- If `interior` is not equal to `Junctions::Here`, insert into the XCM `DescendOrigin(interior)`.
			- Use `XcmRouter` to `validate` the `dest` and `message` is valid, and create a `ticket`, else you should return a `RouterError`.
			- Finally, use the `XcmRouter` to `deliver` the `ticket`, else return `RouterError`.
		*/
		todo!("{:?} {:?}", dest, message)
	}

	pub fn do_teleport_assets(
		origin: OriginFor<T>,
		dest: Location,
		beneficiary: Location,
		assets: Assets,
		// The index into `assets` of the item which should be used to pay fees.
		// We don't use this in our naive implementation.
		_fee_asset_item: u32,
	) -> DispatchResult {
		todo!("{:?} {:?} {:?}", dest, beneficiary, assets)
	}

	pub fn do_reserve_transfer_assets(
		_origin: OriginFor<T>,
		_dest: Location,
		_beneficiary: Location,
		_assets: Assets,
		_fee_asset_item: u32,
	) -> DispatchResult {
		// There are 3 different reserve transfer scenarios:
		// - A local reserve transfer: reserve-transfer `asset` to `dest`, using local chain as
		//   reserve.
		// - A destination reserve transfer: reserve-transfer `asset` to `dest`, using `dest` as
		//   reserve.
		// - A remote reserve transfer: reserve-transfer `asset` to `dest`, using remote chain
		//   `Location` as reserve.
		//
		// This is a lot to do in this workshop, but a welcome challenge for the reader to
		// implement.
		unimplemented!()
	}
}
}
#![allow(unused)]
fn main() {
//! # Fundamentals lesson 6: Pallet XCM
//!
//! Implement the core functionality of Pallet XCM

use crate::xcm_executor::ExecuteXcm;
use frame_support::pallet_prelude::*;
use frame_system::pallet_prelude::*;
use xcm::{prelude::*, VersionedAssets, VersionedLocation, VersionedXcm};

pub use pallet::*;

#[frame_support::pallet]
pub mod pallet {
	use super::*;

	#[pallet::pallet]
	pub struct Pallet<T>(_);

	#[pallet::config]
	pub trait Config: frame_system::Config {
		/// Something to execute an XCM message.
		type XcmExecutor: ExecuteXcm;
		/// Required origin for executing XCM messages, including the teleport functionality. If
		/// successful, then it resolves to `Location` which exists as an interior location
		/// within this chain's XCM context.
		type ExecuteXcmOrigin: EnsureOrigin<
			<Self as frame_system::Config>::RuntimeOrigin,
			Success = Location,
		>;
		/// Required origin for sending XCM messages. If successful, it resolves to `Location`
		/// which exists as an interior location within this chain's XCM context.
		type SendXcmOrigin: EnsureOrigin<
			<Self as frame_system::Config>::RuntimeOrigin,
			Success = Location,
		>;
		/// The type used to actually dispatch an XCM to its destination.
		type XcmRouter: SendXcm;
		/// This chain's Universal Location.
		type UniversalLocation: Get<InteriorLocation>;
	}

	#[pallet::error]
	pub enum Error<T> {
		/// The version of the `Versioned` value used is not able to be interpreted.
		BadVersion,
		/// Origin is invalid for sending.
		InvalidOrigin,
		/// Could not re-anchor the assets to declare the fees for the destination chain.
		CannotReanchor,
		/// A general error indicating something went wrong with the XCM Executor.
		ExecutorError,
		/// A general error indicating something went wrong with the XCM Router.
		RouterError,
	}

	#[pallet::call]
	impl<T: Config> Pallet<T> {
		/// Execute an XCM from a local, signed, origin.
		#[pallet::call_index(0)]
		#[pallet::weight(Weight::default())]
		pub fn execute(
			origin: OriginFor<T>,
			message: Box<VersionedXcm<()>>,
			_max_weight: Weight,
		) -> DispatchResult {
			let message = (*message).try_into().map_err(|()| Error::<T>::BadVersion)?;
			// Actually execute the XCM.
			Self::do_execute(origin, message)
		}

		/// Send an XCM to another consensus system.
		#[pallet::call_index(1)]
		#[pallet::weight(Weight::default())]
		pub fn send(
			origin: OriginFor<T>,
			dest: Box<VersionedLocation>,
			message: Box<VersionedXcm<()>>,
		) -> DispatchResult {
			let dest = Location::try_from(*dest).map_err(|()| Error::<T>::BadVersion)?;
			let message: Xcm<()> = (*message).try_into().map_err(|()| Error::<T>::BadVersion)?;
			// Actually send the XCM.
			Self::do_send(origin, dest, message)
		}

		/// Teleport some assets from the local chain to some destination chain.
		#[pallet::call_index(2)]
		#[pallet::weight(Weight::default())]
		pub fn teleport_assets(
			origin: OriginFor<T>,
			dest: Box<VersionedLocation>,
			beneficiary: Box<VersionedLocation>,
			assets: Box<VersionedAssets>,
			fee_asset_item: u32,
		) -> DispatchResult {
			let dest: Location = (*dest).try_into().map_err(|()| Error::<T>::BadVersion)?;
			let beneficiary: Location =
				(*beneficiary).try_into().map_err(|()| Error::<T>::BadVersion)?;
			let assets: Assets = (*assets).try_into().map_err(|()| Error::<T>::BadVersion)?;
			// Actually teleport the assets.
			Self::do_teleport_assets(origin, dest, beneficiary, assets, fee_asset_item)
		}

		/// Transfer some assets from the local chain to the destination chain through their local,
		/// destination or remote reserve.
		#[pallet::call_index(3)]
		#[pallet::weight(Weight::default())]
		pub fn reserve_transfer_assets(
			origin: OriginFor<T>,
			dest: Box<VersionedLocation>,
			beneficiary: Box<VersionedLocation>,
			assets: Box<VersionedAssets>,
			fee_asset_item: u32,
		) -> DispatchResult {
			let dest: Location = (*dest).try_into().map_err(|()| Error::<T>::BadVersion)?;
			let beneficiary: Location =
				(*beneficiary).try_into().map_err(|()| Error::<T>::BadVersion)?;
			let assets: Assets = (*assets).try_into().map_err(|()| Error::<T>::BadVersion)?;
			// Actually reserve transfer the assets.
			Self::do_reserve_transfer_assets(origin, dest, beneficiary, assets, fee_asset_item)
		}
	}
}

impl<T: Config> Pallet<T> {
	/// Execute an XCM locally on this chain on behalf of `origin`.
	pub fn do_execute(origin: OriginFor<T>, message: Xcm<()>) -> DispatchResult {
		let execute_origin: Location = T::ExecuteXcmOrigin::ensure_origin(origin)?;
		T::XcmExecutor::execute(execute_origin, message).map_err(|_| Error::<T>::ExecutorError)?;
		Ok(())
	}

	/// Relay an XCM `message` from a given `interior` location in this context to a given `dest`
	/// location.
	pub fn do_send(origin: OriginFor<T>, dest: Location, mut message: Xcm<()>) -> DispatchResult {
		let origin_location = T::SendXcmOrigin::ensure_origin(origin)?;
		let interior: Junctions =
			origin_location.try_into().map_err(|_| Error::<T>::InvalidOrigin)?;
		if interior != Junctions::Here {
			message.0.insert(0, DescendOrigin(interior));
		}
		let (ticket, _) = T::XcmRouter::validate(&mut Some(dest), &mut Some(message))
			.map_err(|_| Error::<T>::RouterError)?;
		let _message_id = T::XcmRouter::deliver(ticket).map_err(|_| Error::<T>::RouterError)?;
		Ok(())
	}

	pub fn do_teleport_assets(
		origin: OriginFor<T>,
		dest: Location,
		beneficiary: Location,
		assets: Assets,
		// The index into `assets` of the item which should be used to pay fees.
		// We don't use this in our naive implementation.
		_fee_asset_item: u32,
	) -> DispatchResult {
		todo!("{:?} {:?} {:?}", dest, beneficiary, assets)
	}

	pub fn do_reserve_transfer_assets(
		_origin: OriginFor<T>,
		_dest: Location,
		_beneficiary: Location,
		_assets: Assets,
		_fee_asset_item: u32,
	) -> DispatchResult {
		// There are 3 different reserve transfer scenarios:
		// - A local reserve transfer: reserve-transfer `asset` to `dest`, using local chain as
		//   reserve.
		// - A destination reserve transfer: reserve-transfer `asset` to `dest`, using `dest` as
		//   reserve.
		// - A remote reserve transfer: reserve-transfer `asset` to `dest`, using remote chain
		//   `Location` as reserve.
		//
		// This is a lot to do in this workshop, but a welcome challenge for the reader to
		// implement.
		unimplemented!()
	}
}
}
diff --git a/fundamentals/src/pallet_xcm.rs b/fundamentals/src/pallet_xcm.rs
index baec7b7..7169462 100644
--- a/fundamentals/src/pallet_xcm.rs
+++ b/fundamentals/src/pallet_xcm.rs
@@ -132,6 +132,13 @@ impl<T: Config> Pallet<T> {
 	/// Relay an XCM `message` from a given `interior` location in this context to a given `dest`
 	/// location.
 	pub fn do_send(origin: OriginFor<T>, dest: Location, mut message: Xcm<()>) -> DispatchResult {
+		/* TODO:
+			- Use `SendXcmOrigin` to "ensure" that `origin` is valid to send XCM, and assign the resulting location to `origin_location`.
+			- Convert `origin_location` to `interior: Junctions`, else return `InvalidOrigin`.
+			- If `interior` is not equal to `Junctions::Here`, insert into the XCM `DescendOrigin(interior)`.
+			- Use `XcmRouter` to `validate` the `dest` and `message` is valid, and create a `ticket`, else you should return a `RouterError`.
+			- Finally, use the `XcmRouter` to `deliver` the `ticket`, else return `RouterError`.
+		*/
 		todo!("{:?} {:?}", dest, message)
 	}
 
diff --git a/fundamentals/src/pallet_xcm.rs b/fundamentals/src/pallet_xcm.rs
index 7169462..2df57c9 100644
--- a/fundamentals/src/pallet_xcm.rs
+++ b/fundamentals/src/pallet_xcm.rs
@@ -132,14 +132,16 @@ impl<T: Config> Pallet<T> {
 	/// Relay an XCM `message` from a given `interior` location in this context to a given `dest`
 	/// location.
 	pub fn do_send(origin: OriginFor<T>, dest: Location, mut message: Xcm<()>) -> DispatchResult {
-		/* TODO:
-			- Use `SendXcmOrigin` to "ensure" that `origin` is valid to send XCM, and assign the resulting location to `origin_location`.
-			- Convert `origin_location` to `interior: Junctions`, else return `InvalidOrigin`.
-			- If `interior` is not equal to `Junctions::Here`, insert into the XCM `DescendOrigin(interior)`.
-			- Use `XcmRouter` to `validate` the `dest` and `message` is valid, and create a `ticket`, else you should return a `RouterError`.
-			- Finally, use the `XcmRouter` to `deliver` the `ticket`, else return `RouterError`.
-		*/
-		todo!("{:?} {:?}", dest, message)
+		let origin_location = T::SendXcmOrigin::ensure_origin(origin)?;
+		let interior: Junctions =
+			origin_location.try_into().map_err(|_| Error::<T>::InvalidOrigin)?;
+		if interior != Junctions::Here {
+			message.0.insert(0, DescendOrigin(interior));
+		}
+		let (ticket, _) = T::XcmRouter::validate(&mut Some(dest), &mut Some(message))
+			.map_err(|_| Error::<T>::RouterError)?;
+		let _message_id = T::XcmRouter::deliver(ticket).map_err(|_| Error::<T>::RouterError)?;
+		Ok(())
 	}
 
 	pub fn do_teleport_assets(
#![allow(unused)]
fn main() {
//! # Fundamentals lesson 6: Pallet XCM
//!
//! Implement the core functionality of Pallet XCM

use crate::xcm_executor::ExecuteXcm;
use frame_support::pallet_prelude::*;
use frame_system::pallet_prelude::*;
use xcm::{prelude::*, VersionedAssets, VersionedLocation, VersionedXcm};

pub use pallet::*;

#[frame_support::pallet]
pub mod pallet {
	use super::*;

	#[pallet::pallet]
	pub struct Pallet<T>(_);

	#[pallet::config]
	pub trait Config: frame_system::Config {
		/// Something to execute an XCM message.
		type XcmExecutor: ExecuteXcm;
		/// Required origin for executing XCM messages, including the teleport functionality. If
		/// successful, then it resolves to `Location` which exists as an interior location
		/// within this chain's XCM context.
		type ExecuteXcmOrigin: EnsureOrigin<
			<Self as frame_system::Config>::RuntimeOrigin,
			Success = Location,
		>;
		/// Required origin for sending XCM messages. If successful, it resolves to `Location`
		/// which exists as an interior location within this chain's XCM context.
		type SendXcmOrigin: EnsureOrigin<
			<Self as frame_system::Config>::RuntimeOrigin,
			Success = Location,
		>;
		/// The type used to actually dispatch an XCM to its destination.
		type XcmRouter: SendXcm;
		/// This chain's Universal Location.
		type UniversalLocation: Get<InteriorLocation>;
	}

	#[pallet::error]
	pub enum Error<T> {
		/// The version of the `Versioned` value used is not able to be interpreted.
		BadVersion,
		/// Origin is invalid for sending.
		InvalidOrigin,
		/// Could not re-anchor the assets to declare the fees for the destination chain.
		CannotReanchor,
		/// A general error indicating something went wrong with the XCM Executor.
		ExecutorError,
		/// A general error indicating something went wrong with the XCM Router.
		RouterError,
	}

	#[pallet::call]
	impl<T: Config> Pallet<T> {
		/// Execute an XCM from a local, signed, origin.
		#[pallet::call_index(0)]
		#[pallet::weight(Weight::default())]
		pub fn execute(
			origin: OriginFor<T>,
			message: Box<VersionedXcm<()>>,
			_max_weight: Weight,
		) -> DispatchResult {
			let message = (*message).try_into().map_err(|()| Error::<T>::BadVersion)?;
			// Actually execute the XCM.
			Self::do_execute(origin, message)
		}

		/// Send an XCM to another consensus system.
		#[pallet::call_index(1)]
		#[pallet::weight(Weight::default())]
		pub fn send(
			origin: OriginFor<T>,
			dest: Box<VersionedLocation>,
			message: Box<VersionedXcm<()>>,
		) -> DispatchResult {
			let dest = Location::try_from(*dest).map_err(|()| Error::<T>::BadVersion)?;
			let message: Xcm<()> = (*message).try_into().map_err(|()| Error::<T>::BadVersion)?;
			// Actually send the XCM.
			Self::do_send(origin, dest, message)
		}

		/// Teleport some assets from the local chain to some destination chain.
		#[pallet::call_index(2)]
		#[pallet::weight(Weight::default())]
		pub fn teleport_assets(
			origin: OriginFor<T>,
			dest: Box<VersionedLocation>,
			beneficiary: Box<VersionedLocation>,
			assets: Box<VersionedAssets>,
			fee_asset_item: u32,
		) -> DispatchResult {
			let dest: Location = (*dest).try_into().map_err(|()| Error::<T>::BadVersion)?;
			let beneficiary: Location =
				(*beneficiary).try_into().map_err(|()| Error::<T>::BadVersion)?;
			let assets: Assets = (*assets).try_into().map_err(|()| Error::<T>::BadVersion)?;
			// Actually teleport the assets.
			Self::do_teleport_assets(origin, dest, beneficiary, assets, fee_asset_item)
		}

		/// Transfer some assets from the local chain to the destination chain through their local,
		/// destination or remote reserve.
		#[pallet::call_index(3)]
		#[pallet::weight(Weight::default())]
		pub fn reserve_transfer_assets(
			origin: OriginFor<T>,
			dest: Box<VersionedLocation>,
			beneficiary: Box<VersionedLocation>,
			assets: Box<VersionedAssets>,
			fee_asset_item: u32,
		) -> DispatchResult {
			let dest: Location = (*dest).try_into().map_err(|()| Error::<T>::BadVersion)?;
			let beneficiary: Location =
				(*beneficiary).try_into().map_err(|()| Error::<T>::BadVersion)?;
			let assets: Assets = (*assets).try_into().map_err(|()| Error::<T>::BadVersion)?;
			// Actually reserve transfer the assets.
			Self::do_reserve_transfer_assets(origin, dest, beneficiary, assets, fee_asset_item)
		}
	}
}

impl<T: Config> Pallet<T> {
	/// Execute an XCM locally on this chain on behalf of `origin`.
	pub fn do_execute(origin: OriginFor<T>, message: Xcm<()>) -> DispatchResult {
		let execute_origin: Location = T::ExecuteXcmOrigin::ensure_origin(origin)?;
		T::XcmExecutor::execute(execute_origin, message).map_err(|_| Error::<T>::ExecutorError)?;
		Ok(())
	}

	/// Relay an XCM `message` from a given `interior` location in this context to a given `dest`
	/// location.
	pub fn do_send(origin: OriginFor<T>, dest: Location, mut message: Xcm<()>) -> DispatchResult {
		let origin_location = T::SendXcmOrigin::ensure_origin(origin)?;
		let interior: Junctions =
			origin_location.try_into().map_err(|_| Error::<T>::InvalidOrigin)?;
		if interior != Junctions::Here {
			message.0.insert(0, DescendOrigin(interior));
		}
		let (ticket, _) = T::XcmRouter::validate(&mut Some(dest), &mut Some(message))
			.map_err(|_| Error::<T>::RouterError)?;
		let _message_id = T::XcmRouter::deliver(ticket).map_err(|_| Error::<T>::RouterError)?;
		Ok(())
	}

	pub fn do_teleport_assets(
		origin: OriginFor<T>,
		dest: Location,
		beneficiary: Location,
		assets: Assets,
		// The index into `assets` of the item which should be used to pay fees.
		// We don't use this in our naive implementation.
		_fee_asset_item: u32,
	) -> DispatchResult {
		/* The Teleport Instruction is broken up into a local and destination XCM. */
		/* Create a `local_execute_xcm` which does:
			- `WithdrawAsset`
			- `BurnAsset`
		*/

		/* For the XCM on the destination:
			- We need to adjust the location of the assets to match the destination
			- For this, we need to `reanchor` the assets using the `dest` and local `context`
			- For `context`, you should use the `UniversalLocation`.
		*/

		/* Then prepare a `xcm_on_dest` which is composed of:
			- `ReceiveTeleportedAsset` - using `reanchored_assets`
			- `ClearOrigin`
			- `DepositAsset` - using the asset filter `Wild(All)`
		*/

		/* Finally, we just need to:
			- `do_execute` our `local_execute_xcm`
			- `do_send` our `xcm_on_dest` to `dest`
		*/
		todo!("{:?} {:?} {:?}", dest, beneficiary, assets)
	}

	pub fn do_reserve_transfer_assets(
		_origin: OriginFor<T>,
		_dest: Location,
		_beneficiary: Location,
		_assets: Assets,
		_fee_asset_item: u32,
	) -> DispatchResult {
		// There are 3 different reserve transfer scenarios:
		// - A local reserve transfer: reserve-transfer `asset` to `dest`, using local chain as
		//   reserve.
		// - A destination reserve transfer: reserve-transfer `asset` to `dest`, using `dest` as
		//   reserve.
		// - A remote reserve transfer: reserve-transfer `asset` to `dest`, using remote chain
		//   `Location` as reserve.
		//
		// This is a lot to do in this workshop, but a welcome challenge for the reader to
		// implement.
		unimplemented!()
	}
}
}
#![allow(unused)]
fn main() {
//! # Fundamentals lesson 6: Pallet XCM
//!
//! Implement the core functionality of Pallet XCM

use crate::xcm_executor::ExecuteXcm;
use frame_support::pallet_prelude::*;
use frame_system::pallet_prelude::*;
use xcm::{prelude::*, VersionedAssets, VersionedLocation, VersionedXcm};

pub use pallet::*;

#[frame_support::pallet]
pub mod pallet {
	use super::*;

	#[pallet::pallet]
	pub struct Pallet<T>(_);

	#[pallet::config]
	pub trait Config: frame_system::Config {
		/// Something to execute an XCM message.
		type XcmExecutor: ExecuteXcm;
		/// Required origin for executing XCM messages, including the teleport functionality. If
		/// successful, then it resolves to `Location` which exists as an interior location
		/// within this chain's XCM context.
		type ExecuteXcmOrigin: EnsureOrigin<
			<Self as frame_system::Config>::RuntimeOrigin,
			Success = Location,
		>;
		/// Required origin for sending XCM messages. If successful, it resolves to `Location`
		/// which exists as an interior location within this chain's XCM context.
		type SendXcmOrigin: EnsureOrigin<
			<Self as frame_system::Config>::RuntimeOrigin,
			Success = Location,
		>;
		/// The type used to actually dispatch an XCM to its destination.
		type XcmRouter: SendXcm;
		/// This chain's Universal Location.
		type UniversalLocation: Get<InteriorLocation>;
	}

	#[pallet::error]
	pub enum Error<T> {
		/// The version of the `Versioned` value used is not able to be interpreted.
		BadVersion,
		/// Origin is invalid for sending.
		InvalidOrigin,
		/// Could not re-anchor the assets to declare the fees for the destination chain.
		CannotReanchor,
		/// A general error indicating something went wrong with the XCM Executor.
		ExecutorError,
		/// A general error indicating something went wrong with the XCM Router.
		RouterError,
	}

	#[pallet::call]
	impl<T: Config> Pallet<T> {
		/// Execute an XCM from a local, signed, origin.
		#[pallet::call_index(0)]
		#[pallet::weight(Weight::default())]
		pub fn execute(
			origin: OriginFor<T>,
			message: Box<VersionedXcm<()>>,
			_max_weight: Weight,
		) -> DispatchResult {
			let message = (*message).try_into().map_err(|()| Error::<T>::BadVersion)?;
			// Actually execute the XCM.
			Self::do_execute(origin, message)
		}

		/// Send an XCM to another consensus system.
		#[pallet::call_index(1)]
		#[pallet::weight(Weight::default())]
		pub fn send(
			origin: OriginFor<T>,
			dest: Box<VersionedLocation>,
			message: Box<VersionedXcm<()>>,
		) -> DispatchResult {
			let dest = Location::try_from(*dest).map_err(|()| Error::<T>::BadVersion)?;
			let message: Xcm<()> = (*message).try_into().map_err(|()| Error::<T>::BadVersion)?;
			// Actually send the XCM.
			Self::do_send(origin, dest, message)
		}

		/// Teleport some assets from the local chain to some destination chain.
		#[pallet::call_index(2)]
		#[pallet::weight(Weight::default())]
		pub fn teleport_assets(
			origin: OriginFor<T>,
			dest: Box<VersionedLocation>,
			beneficiary: Box<VersionedLocation>,
			assets: Box<VersionedAssets>,
			fee_asset_item: u32,
		) -> DispatchResult {
			let dest: Location = (*dest).try_into().map_err(|()| Error::<T>::BadVersion)?;
			let beneficiary: Location =
				(*beneficiary).try_into().map_err(|()| Error::<T>::BadVersion)?;
			let assets: Assets = (*assets).try_into().map_err(|()| Error::<T>::BadVersion)?;
			// Actually teleport the assets.
			Self::do_teleport_assets(origin, dest, beneficiary, assets, fee_asset_item)
		}

		/// Transfer some assets from the local chain to the destination chain through their local,
		/// destination or remote reserve.
		#[pallet::call_index(3)]
		#[pallet::weight(Weight::default())]
		pub fn reserve_transfer_assets(
			origin: OriginFor<T>,
			dest: Box<VersionedLocation>,
			beneficiary: Box<VersionedLocation>,
			assets: Box<VersionedAssets>,
			fee_asset_item: u32,
		) -> DispatchResult {
			let dest: Location = (*dest).try_into().map_err(|()| Error::<T>::BadVersion)?;
			let beneficiary: Location =
				(*beneficiary).try_into().map_err(|()| Error::<T>::BadVersion)?;
			let assets: Assets = (*assets).try_into().map_err(|()| Error::<T>::BadVersion)?;
			// Actually reserve transfer the assets.
			Self::do_reserve_transfer_assets(origin, dest, beneficiary, assets, fee_asset_item)
		}
	}
}

impl<T: Config> Pallet<T> {
	/// Execute an XCM locally on this chain on behalf of `origin`.
	pub fn do_execute(origin: OriginFor<T>, message: Xcm<()>) -> DispatchResult {
		let execute_origin: Location = T::ExecuteXcmOrigin::ensure_origin(origin)?;
		T::XcmExecutor::execute(execute_origin, message).map_err(|_| Error::<T>::ExecutorError)?;
		Ok(())
	}

	/// Relay an XCM `message` from a given `interior` location in this context to a given `dest`
	/// location.
	pub fn do_send(origin: OriginFor<T>, dest: Location, mut message: Xcm<()>) -> DispatchResult {
		let origin_location = T::SendXcmOrigin::ensure_origin(origin)?;
		let interior: Junctions =
			origin_location.try_into().map_err(|_| Error::<T>::InvalidOrigin)?;
		if interior != Junctions::Here {
			message.0.insert(0, DescendOrigin(interior));
		}
		let (ticket, _) = T::XcmRouter::validate(&mut Some(dest), &mut Some(message))
			.map_err(|_| Error::<T>::RouterError)?;
		let _message_id = T::XcmRouter::deliver(ticket).map_err(|_| Error::<T>::RouterError)?;
		Ok(())
	}

	pub fn do_teleport_assets(
		origin: OriginFor<T>,
		dest: Location,
		beneficiary: Location,
		assets: Assets,
		// The index into `assets` of the item which should be used to pay fees.
		// We don't use this in our naive implementation.
		_fee_asset_item: u32,
	) -> DispatchResult {
		// XCM instructions to be executed on local chain
		let local_execute_xcm: Xcm<()> = Xcm(vec![
			// withdraw assets to be teleported
			WithdrawAsset(assets.clone()),
			// burn assets on local chain
			BurnAsset(assets.clone()),
		]);

		// Changing the asset location to be in the context of the destination chain.
		let context = T::UniversalLocation::get();
		let mut reanchored_assets = assets;
		reanchored_assets
			.reanchor(&dest, &context)
			.map_err(|_| Error::<T>::CannotReanchor)?;

		// XCM instructions to be executed on destination chain
		let xcm_on_dest: Xcm<()> = Xcm(vec![
			// teleport `assets` in from origin chain
			ReceiveTeleportedAsset(reanchored_assets),
			// following instructions are not exec'ed on behalf of origin chain anymore
			ClearOrigin,
			// deposit all remaining assets in holding to `beneficiary` location
			DepositAsset { assets: Wild(All), beneficiary },
		]);

		// Execute the local XCM instructions.
		Self::do_execute(origin.clone(), local_execute_xcm)?;
		// Send the destination XCM instructions.
		Self::do_send(origin, dest, xcm_on_dest)?;

		Ok(())
	}

	pub fn do_reserve_transfer_assets(
		_origin: OriginFor<T>,
		_dest: Location,
		_beneficiary: Location,
		_assets: Assets,
		_fee_asset_item: u32,
	) -> DispatchResult {
		// There are 3 different reserve transfer scenarios:
		// - A local reserve transfer: reserve-transfer `asset` to `dest`, using local chain as
		//   reserve.
		// - A destination reserve transfer: reserve-transfer `asset` to `dest`, using `dest` as
		//   reserve.
		// - A remote reserve transfer: reserve-transfer `asset` to `dest`, using remote chain
		//   `Location` as reserve.
		//
		// This is a lot to do in this workshop, but a welcome challenge for the reader to
		// implement.
		unimplemented!()
	}
}
}
diff --git a/fundamentals/src/pallet_xcm.rs b/fundamentals/src/pallet_xcm.rs
index 2df57c9..ccf515a 100644
--- a/fundamentals/src/pallet_xcm.rs
+++ b/fundamentals/src/pallet_xcm.rs
@@ -153,6 +153,28 @@ impl<T: Config> Pallet<T> {
 		// We don't use this in our naive implementation.
 		_fee_asset_item: u32,
 	) -> DispatchResult {
+		/* The Teleport Instruction is broken up into a local and destination XCM. */
+		/* Create a `local_execute_xcm` which does:
+			- `WithdrawAsset`
+			- `BurnAsset`
+		*/
+
+		/* For the XCM on the destination:
+			- We need to adjust the location of the assets to match the destination
+			- For this, we need to `reanchor` the assets using the `dest` and local `context`
+			- For `context`, you should use the `UniversalLocation`.
+		*/
+
+		/* Then prepare a `xcm_on_dest` which is composed of:
+			- `ReceiveTeleportedAsset` - using `reanchored_assets`
+			- `ClearOrigin`
+			- `DepositAsset` - using the asset filter `Wild(All)`
+		*/
+
+		/* Finally, we just need to:
+			- `do_execute` our `local_execute_xcm`
+			- `do_send` our `xcm_on_dest` to `dest`
+		*/
 		todo!("{:?} {:?} {:?}", dest, beneficiary, assets)
 	}
 
diff --git a/fundamentals/src/pallet_xcm.rs b/fundamentals/src/pallet_xcm.rs
index ccf515a..1a88020 100644
--- a/fundamentals/src/pallet_xcm.rs
+++ b/fundamentals/src/pallet_xcm.rs
@@ -153,29 +153,37 @@ impl<T: Config> Pallet<T> {
 		// We don't use this in our naive implementation.
 		_fee_asset_item: u32,
 	) -> DispatchResult {
-		/* The Teleport Instruction is broken up into a local and destination XCM. */
-		/* Create a `local_execute_xcm` which does:
-			- `WithdrawAsset`
-			- `BurnAsset`
-		*/
-
-		/* For the XCM on the destination:
-			- We need to adjust the location of the assets to match the destination
-			- For this, we need to `reanchor` the assets using the `dest` and local `context`
-			- For `context`, you should use the `UniversalLocation`.
-		*/
-
-		/* Then prepare a `xcm_on_dest` which is composed of:
-			- `ReceiveTeleportedAsset` - using `reanchored_assets`
-			- `ClearOrigin`
-			- `DepositAsset` - using the asset filter `Wild(All)`
-		*/
-
-		/* Finally, we just need to:
-			- `do_execute` our `local_execute_xcm`
-			- `do_send` our `xcm_on_dest` to `dest`
-		*/
-		todo!("{:?} {:?} {:?}", dest, beneficiary, assets)
+		// XCM instructions to be executed on local chain
+		let local_execute_xcm: Xcm<()> = Xcm(vec![
+			// withdraw assets to be teleported
+			WithdrawAsset(assets.clone()),
+			// burn assets on local chain
+			BurnAsset(assets.clone()),
+		]);
+
+		// Changing the asset location to be in the context of the destination chain.
+		let context = T::UniversalLocation::get();
+		let mut reanchored_assets = assets;
+		reanchored_assets
+			.reanchor(&dest, &context)
+			.map_err(|_| Error::<T>::CannotReanchor)?;
+
+		// XCM instructions to be executed on destination chain
+		let xcm_on_dest: Xcm<()> = Xcm(vec![
+			// teleport `assets` in from origin chain
+			ReceiveTeleportedAsset(reanchored_assets),
+			// following instructions are not exec'ed on behalf of origin chain anymore
+			ClearOrigin,
+			// deposit all remaining assets in holding to `beneficiary` location
+			DepositAsset { assets: Wild(All), beneficiary },
+		]);
+
+		// Execute the local XCM instructions.
+		Self::do_execute(origin.clone(), local_execute_xcm)?;
+		// Send the destination XCM instructions.
+		Self::do_send(origin, dest, xcm_on_dest)?;
+
+		Ok(())
 	}
 
 	pub fn do_reserve_transfer_assets(