Skip to content

Commit

Permalink
Deposit xcm fees to treasury (#1036)
Browse files Browse the repository at this point in the history
* wip

* Fist version working

* Test trader and assets to treasury for para-to-para too

* Clean non-affecting changes

* Make a struct in xcm_primitives with the required bounds

* Remove comment

* Add a bit of docu

* IsZero import trait

* PR suggestions

* Apply more pr suggestions

* We cannot lod error since xcmerror does not implement dbug

Co-authored-by: librelois <c@elo.tf>
  • Loading branch information
girazoki and librelois authored Dec 2, 2021
1 parent 623f74d commit d6e6c1d
Show file tree
Hide file tree
Showing 6 changed files with 217 additions and 27 deletions.
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

0 comments on commit d6e6c1d

Please sign in to comment.