Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Deposit xcm fees to treasury #1036

Merged
merged 13 commits into from
Dec 2, 2021
55 changes: 49 additions & 6 deletions primitives/xcm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,21 +19,20 @@
#![cfg_attr(not(feature = "std"), no_std)]

use frame_support::{
traits::{Get, OriginTrait},
traits::{tokens::fungibles::Mutate, Get, OriginTrait},
weights::{constants::WEIGHT_PER_SECOND, Weight},
};
use sp_runtime::traits::Zero;
use sp_std::borrow::Borrow;
use sp_std::{convert::TryInto, marker::PhantomData};
use xcm::latest::{
AssetId as xcmAssetId, Error as XcmError, Fungibility,
Junction::{AccountKey20, Parachain},
Junctions::*,
MultiAsset, MultiLocation, NetworkId,
};
use xcm_builder::TakeRevenue;
use xcm_executor::traits::FilterAssetLocation;
use xcm_executor::traits::WeightTrader;

use sp_std::borrow::Borrow;
use sp_std::{convert::TryInto, marker::PhantomData};
use xcm_executor::traits::{FilterAssetLocation, MatchesFungibles, WeightTrader};

use sp_std::vec::Vec;

Expand Down Expand Up @@ -215,6 +214,21 @@ impl<
}
}

/// Deal with spent fees, deposit them as dictated by R
impl<
AssetId: From<AssetType> + Clone,
AssetType: From<MultiLocation> + Clone,
AssetIdInfoGetter: UnitsToWeightRatio<AssetId>,
R: TakeRevenue,
> Drop for FirstAssetTrader<AssetId, AssetType, AssetIdInfoGetter, R>
{
fn drop(&mut self) {
if let Some((id, amount, _)) = self.1.clone() {
R::take_revenue((id, amount).into());
}
}
}

pub trait Reserve {
/// Returns assets reserve location.
fn reserve(&self) -> Option<MultiLocation>;
Expand Down Expand Up @@ -296,3 +310,32 @@ pub trait AccountIdToCurrencyId<Account, CurrencyId> {
// Get assetId from account
fn account_to_currency_id(account: Account) -> Option<CurrencyId>;
}

/// XCM fee depositor to which we implement the TakeRevenue trait
/// It receives a fungibles::Mutate implemented argument, a matcher to convert MultiAsset into
/// AssetId and amount, and the fee receiver account
pub struct XcmFeesToAccount<Assets, Matcher, AccountId, ReceiverAccount>(
PhantomData<(Assets, Matcher, AccountId, ReceiverAccount)>,
);
impl<
Assets: Mutate<AccountId>,
Matcher: MatchesFungibles<Assets::AssetId, Assets::Balance>,
AccountId: Clone,
ReceiverAccount: Get<AccountId>,
> TakeRevenue for XcmFeesToAccount<Assets, Matcher, AccountId, ReceiverAccount>
{
fn take_revenue(revenue: MultiAsset) {
match Matcher::matches_fungibles(&revenue) {
Ok((asset_id, amount)) => {
if !amount.is_zero() {
let ok = Assets::mint_into(asset_id, &ReceiverAccount::get(), amount).is_ok();
debug_assert!(ok, "`mint_into` cannot generally fail; qed");
}
}
Err(_) => log::debug!(
target: "xcm",
"take revenue failed matching fungible"
),
}
}
}
60 changes: 41 additions & 19 deletions runtime/moonbase/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ use fp_rpc::TransactionStatus;
use pallet_evm_precompile_assets_erc20::AccountIdAssetIdConversion;

use account::AccountId20;

use sp_runtime::traits::Hash as THash;

use frame_support::{
Expand Down Expand Up @@ -98,17 +97,19 @@ use sp_std::{
#[cfg(feature = "std")]
use sp_version::NativeVersion;
use sp_version::RuntimeVersion;
use xcm::v1::{
BodyId,
Junction::{PalletInstance, Parachain},
Junctions, MultiLocation, NetworkId,
};
use xcm::latest::prelude::*;

use nimbus_primitives::{CanAuthor, NimbusId};

mod precompiles;
use precompiles::{MoonbasePrecompiles, ASSET_PRECOMPILE_ADDRESS_PREFIX};

use xcm_primitives::{
AccountIdToCurrencyId, AccountIdToMultiLocation, AsAssetType, FirstAssetTrader,
MultiNativeAsset, SignedToAccountId20, UtilityAvailableCalls, UtilityEncodeCall,
XcmFeesToAccount, XcmTransact,
};

#[cfg(any(feature = "std", test))]
pub use sp_runtime::BuildStorage;

Expand Down Expand Up @@ -973,7 +974,7 @@ pub type FungiblesTransactor = FungiblesAdapter<
ConvertedConcreteAssetId<
AssetId,
Balance,
xcm_primitives::AsAssetType<AssetId, AssetType, AssetManager>,
AsAssetType<AssetId, AssetType, AssetManager>,
JustTry,
>,
),
Expand Down Expand Up @@ -1052,6 +1053,28 @@ pub type XcmBarrier = (
AllowSubscriptionsFrom<Everything>,
);

parameter_types! {
/// Xcm fees will go to the treasury account
pub XcmFeesAccount: AccountId = Treasury::account_id();
}

/// This is the struct that will handle the revenue from xcm fees
/// We do not burn anything because we want to mimic exactly what
/// the sovereign account has
pub type XcmFeesToAccount_ = XcmFeesToAccount<
Assets,
(
ConvertedConcreteAssetId<
AssetId,
Balance,
AsAssetType<AssetId, AssetType, AssetManager>,
JustTry,
>,
),
AccountId,
XcmFeesAccount,
>;

pub struct XcmExecutorConfig;
impl xcm_executor::Config for XcmExecutorConfig {
type Call = Call;
Expand All @@ -1060,7 +1083,7 @@ impl xcm_executor::Config for XcmExecutorConfig {
type AssetTransactor = AssetTransactors;
type OriginConverter = XcmOriginToTransactDispatchOrigin;
// Filter to the reserve withdraw operations
type IsReserve = xcm_primitives::MultiNativeAsset;
type IsReserve = MultiNativeAsset;
type IsTeleporter = (); // No teleport
type LocationInverter = LocationInverter<Ancestry>;
type Barrier = XcmBarrier;
Expand All @@ -1077,7 +1100,7 @@ impl xcm_executor::Config for XcmExecutorConfig {
Balances,
DealWithFees<Runtime>,
>,
xcm_primitives::FirstAssetTrader<AssetId, AssetType, AssetManager, ()>,
FirstAssetTrader<AssetId, AssetType, AssetManager, XcmFeesToAccount_>,
);
type ResponseHandler = PolkadotXcm;
type SubscriptionService = PolkadotXcm;
Expand All @@ -1092,8 +1115,7 @@ parameter_types! {
}

// Converts a Signed Local Origin into a MultiLocation
pub type LocalOriginToLocation =
xcm_primitives::SignedToAccountId20<Origin, AccountId, RelayNetwork>;
pub type LocalOriginToLocation = SignedToAccountId20<Origin, AccountId, RelayNetwork>;

/// The means for routing XCM messages which are not for local execution into the right message
/// queues.
Expand Down Expand Up @@ -1280,7 +1302,7 @@ pub enum CurrencyId {
OtherReserve(AssetId),
}

impl xcm_primitives::AccountIdToCurrencyId<AccountId, CurrencyId> for Runtime {
impl AccountIdToCurrencyId<AccountId, CurrencyId> for Runtime {
fn account_to_currency_id(account: AccountId) -> Option<CurrencyId> {
match account {
// the self-reserve currency is identified by the pallet-balances address
Expand Down Expand Up @@ -1326,9 +1348,9 @@ impl orml_xtokens::Config for Runtime {
type Event = Event;
type Balance = Balance;
type CurrencyId = CurrencyId;
type AccountIdToMultiLocation = xcm_primitives::AccountIdToMultiLocation<AccountId>;
type AccountIdToMultiLocation = AccountIdToMultiLocation<AccountId>;
type CurrencyIdConvert =
CurrencyIdtoMultiLocation<xcm_primitives::AsAssetType<AssetId, AssetType, AssetManager>>;
CurrencyIdtoMultiLocation<AsAssetType<AssetId, AssetType, AssetManager>>;
type XcmExecutor = XcmExecutor;
type SelfLocation = SelfLocation;
type Weigher = XcmWeigher;
Expand All @@ -1354,8 +1376,8 @@ impl TryFrom<u8> for Transactors {
}
}

impl xcm_primitives::UtilityEncodeCall for Transactors {
fn encode_call(self, call: xcm_primitives::UtilityAvailableCalls) -> Vec<u8> {
impl UtilityEncodeCall for Transactors {
fn encode_call(self, call: UtilityAvailableCalls) -> Vec<u8> {
match self {
// Shall we use westend for moonbase? The tests are probably based on rococo
// but moonbase-alpha is attached to westend-runtime I think
Expand All @@ -1364,7 +1386,7 @@ impl xcm_primitives::UtilityEncodeCall for Transactors {
}
}

impl xcm_primitives::XcmTransact for Transactors {
impl XcmTransact for Transactors {
fn destination(self) -> MultiLocation {
match self {
Transactors::Relay => MultiLocation::parent(),
Expand All @@ -1379,9 +1401,9 @@ impl xcm_transactor::Config for Runtime {
type DerivativeAddressRegistrationOrigin = EnsureRoot<AccountId>;
type SovereignAccountDispatcherOrigin = EnsureRoot<AccountId>;
type CurrencyId = CurrencyId;
type AccountIdToMultiLocation = xcm_primitives::AccountIdToMultiLocation<AccountId>;
type AccountIdToMultiLocation = AccountIdToMultiLocation<AccountId>;
type CurrencyIdToMultiLocation =
CurrencyIdtoMultiLocation<xcm_primitives::AsAssetType<AssetId, AssetType, AssetManager>>;
CurrencyIdtoMultiLocation<AsAssetType<AssetId, AssetType, AssetManager>>;
type XcmExecutor = XcmExecutor;
type XcmSender = XcmRouter;
type SelfLocation = SelfLocation;
Expand Down
1 change: 1 addition & 0 deletions runtime/moonbase/tests/xcm_mock/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ pub fn relay_ext() -> sp_io::TestExternalities {
pub type RelayChainPalletXcm = pallet_xcm::Pallet<relay_chain::Runtime>;
pub type ParachainPalletXcm = pallet_xcm::Pallet<parachain::Runtime>;
pub type Assets = pallet_assets::Pallet<parachain::Runtime>;
pub type Treasury = pallet_treasury::Pallet<parachain::Runtime>;
pub type AssetManager = pallet_asset_manager::Pallet<parachain::Runtime>;
pub type XTokens = orml_xtokens::Pallet<parachain::Runtime>;
pub type RelayBalances = pallet_balances::Pallet<relay_chain::Runtime>;
Expand Down
52 changes: 51 additions & 1 deletion runtime/moonbase/tests/xcm_mock/parachain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,16 @@ use frame_support::{
construct_runtime, parameter_types,
traits::{Everything, Get, Nothing, PalletInfo as PalletInfoTrait},
weights::Weight,
PalletId,
};

use frame_system::EnsureRoot;
use parity_scale_codec::{Decode, Encode};
use sp_core::H256;
use sp_runtime::{
testing::Header,
traits::{Hash, IdentityLookup},
Permill,
};
use sp_std::{convert::TryFrom, prelude::*};
use xcm::{latest::prelude::*, Version as XcmVersion, VersionedXcm};
Expand Down Expand Up @@ -218,6 +221,27 @@ pub type Barrier = (
// Subscriptions for version tracking are OK.
AllowSubscriptionsFrom<Everything>,
);

parameter_types! {
/// Xcm fees will go to the treasury account
pub XcmFeesAccount: AccountId = Treasury::account_id();
}

/// This is the struct that will handle the revenue from xcm fees
pub type XcmFeesToAccount_ = xcm_primitives::XcmFeesToAccount<
Assets,
(
ConvertedConcreteAssetId<
AssetId,
Balance,
xcm_primitives::AsAssetType<AssetId, AssetType, AssetManager>,
JustTry,
>,
),
AccountId,
XcmFeesAccount,
>;

parameter_types! {
// We cannot skip the native trader for some specific tests, so we will have to work with
// a native trader that charges same number of units as weight
Expand Down Expand Up @@ -249,7 +273,7 @@ impl Config for XcmConfig {
type Weigher = FixedWeightBounds<UnitWeightCost, Call, MaxInstructions>;
type Trader = (
FixedRateOfFungible<ParaTokensPerSecond, ()>,
xcm_primitives::FirstAssetTrader<AssetId, AssetType, AssetManager, ()>,
xcm_primitives::FirstAssetTrader<AssetId, AssetType, AssetManager, XcmFeesToAccount_>,
);

type ResponseHandler = PolkadotXcm;
Expand Down Expand Up @@ -313,6 +337,31 @@ impl orml_xtokens::Config for Runtime {
type LocationInverter = LocationInverter<Ancestry>;
}

parameter_types! {
pub const ProposalBond: Permill = Permill::from_percent(5);
pub const ProposalBondMinimum: Balance = 0;
pub const SpendPeriod: u64 = 0;
pub const TreasuryId: PalletId = PalletId(*b"pc/trsry");
pub const MaxApprovals: u32 = 100;
}

impl pallet_treasury::Config for Runtime {
type PalletId = TreasuryId;
type Currency = Balances;
type ApproveOrigin = EnsureRoot<AccountId>;
type RejectOrigin = EnsureRoot<AccountId>;
type Event = Event;
type OnSlash = Treasury;
type ProposalBond = ProposalBond;
type ProposalBondMinimum = ProposalBondMinimum;
type SpendPeriod = SpendPeriod;
type Burn = ();
type BurnDestination = ();
type MaxApprovals = MaxApprovals;
type WeightInfo = ();
type SpendFunds = ();
}

#[frame_support::pallet]
pub mod mock_msg_queue {
use super::*;
Expand Down Expand Up @@ -700,6 +749,7 @@ construct_runtime!(
XTokens: orml_xtokens::{Pallet, Call, Storage, Event<T>},
AssetManager: pallet_asset_manager::{Pallet, Call, Storage, Event<T>},
XcmTransactor: xcm_transactor::{Pallet, Call, Storage, Event<T>},
Treasury: pallet_treasury::{Pallet, Storage, Config, Event<T>, Call}
}
);

Expand Down
Loading