Skip to content

Commit 0842df3

Browse files
authored
🔧 Change XCM execution fee destination to treasury (#323)
## What? - When buying execution with the XCM instruction`BuyExecution`, make the amount spent go to the treasury instead of being burnt ## Why? 💸 ## How? - Modify the traders assigned to `XcmConfig::Trader` - Put another custom generic inside `FixedRateOfFungible` and `UsingComponents` which sends to treasury instead of burning ## Testing? In integration tests, `xcm_config::execution_fees_go_to_treasury`
1 parent 24f1285 commit 0842df3

File tree

6 files changed

+136
-16
lines changed

6 files changed

+136
-16
lines changed

integration-tests/src/constants.rs

+7-3
Original file line numberDiff line numberDiff line change
@@ -548,7 +548,7 @@ pub mod polimec {
548548
use super::*;
549549
use crate::{PolimecNet, PolimecOrigin, PolimecRuntime};
550550
use pallet_funding::AcceptedFundingAsset;
551-
use polimec_runtime::PayMaster;
551+
use polimec_runtime::{PayMaster, TreasuryAccount};
552552
use xcm::v3::Parent;
553553
use xcm_emulator::TestExt;
554554

@@ -622,7 +622,7 @@ pub mod polimec {
622622

623623
funded_accounts.extend(accounts::init_balances().iter().cloned().map(|k| (k, INITIAL_DEPOSIT)));
624624
funded_accounts.extend(collators::initial_authorities().iter().cloned().map(|(acc, _)| (acc, 20_005 * PLMC)));
625-
funded_accounts.push((get_account_id_from_seed::<sr25519::Public>("TREASURY_STASH"), 20_005 * PLMC));
625+
funded_accounts.push((TreasuryAccount::get(), 20_005 * PLMC));
626626
funded_accounts.push((PayMaster::get(), 20_005 * PLMC));
627627

628628
let genesis_config = polimec_runtime::RuntimeGenesisConfig {
@@ -640,7 +640,11 @@ pub mod polimec {
640640
(usdt_asset_id, "Local USDT".as_bytes().to_vec(), "USDT".as_bytes().to_vec(), 6),
641641
(usdc_asset_id, "Local USDC".as_bytes().to_vec(), "USDC".as_bytes().to_vec(), 6),
642642
],
643-
accounts: vec![],
643+
accounts: vec![
644+
(dot_asset_id, TreasuryAccount::get(), 0_0_010_000_000u128),
645+
(usdt_asset_id, TreasuryAccount::get(), 0_0_010_000_000u128),
646+
(usdc_asset_id, TreasuryAccount::get(), 0_0_010_000_000u128),
647+
],
644648
},
645649
parachain_info: polimec_runtime::ParachainInfoConfig { parachain_id: PARA_ID.into(), ..Default::default() },
646650
session: polimec_runtime::SessionConfig {

integration-tests/src/tests/credentials.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,10 @@ use polimec_common::credentials::{Did, InvestorType};
2121
use polimec_common_test_utils::{get_fake_jwt, get_mock_jwt_with_cid, get_test_jwt};
2222
use polimec_runtime::PLMC;
2323
use sp_runtime::{
24-
bounded_vec,
2524
generic::Era,
2625
traits::SignedExtension,
2726
transaction_validity::{InvalidTransaction::Payment, TransactionValidityError},
28-
AccountId32, BoundedVec, DispatchError,
27+
AccountId32, DispatchError,
2928
};
3029
use tests::defaults::*;
3130

integration-tests/src/tests/governance.rs

+6-3
Original file line numberDiff line numberDiff line change
@@ -386,6 +386,8 @@ fn election_phragmen_works() {
386386
<PolimecRuntime as pallet_elections_phragmen::Config>::MaxCandidates::get() as usize
387387
);
388388

389+
let prev_treasury_balance = Balances::balance(&Treasury::account_id());
390+
389391
for (i, voter) in vec![ALICE, BOB, CHARLIE, DAVE, EVE, FERDIE, ALICE_STASH, BOB_STASH].into_iter().enumerate() {
390392
let voter = PolimecNet::account_id_of(voter);
391393
assert_ok!(Elections::vote(
@@ -411,10 +413,11 @@ fn election_phragmen_works() {
411413
{
412414
assert_eq!(Balances::total_balance(candidate), ED);
413415
}
416+
let post_treasury_balance = Balances::balance(&Treasury::account_id());
417+
let net_treasury_balance = post_treasury_balance - prev_treasury_balance;
414418
assert_eq!(
415-
Balances::balance(&Treasury::account_id()),
416-
(<PolimecRuntime as pallet_elections_phragmen::Config>::MaxCandidates::get() as u128 - 15) * 1000 * PLMC +
417-
ED
419+
net_treasury_balance,
420+
(<PolimecRuntime as pallet_elections_phragmen::Config>::MaxCandidates::get() as u128 - 15) * 1000 * PLMC
418421
)
419422
});
420423
}

integration-tests/src/tests/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,4 @@ mod governance;
2222
mod oracle;
2323
mod reserve_backed_transfers;
2424
mod vest;
25+
mod xcm_config;
+113
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
use crate::{PolimecAccountId, PolimecBalances, PolimecCall, PolimecForeignAssets, PolimecNet, PolimecRuntime, ALICE};
2+
use parity_scale_codec::Encode;
3+
use polimec_runtime::{xcm_config::SupportedAssets, TreasuryAccount};
4+
use sp_runtime::traits::MaybeEquivalence;
5+
use xcm::prelude::*;
6+
use xcm_emulator::{Chain, TestExt};
7+
pub fn fake_message_hash<T>(message: &Xcm<T>) -> XcmHash {
8+
message.using_encoded(sp_io::hashing::blake2_256)
9+
}
10+
#[test]
11+
fn execution_fees_go_to_treasury() {
12+
let dot_amount = MultiAsset { id: Concrete(MultiLocation::parent()), fun: Fungible(100_0_000_000_000) };
13+
let usdt_amount = MultiAsset {
14+
id: Concrete(MultiLocation {
15+
parents: 1,
16+
interior: X3(Parachain(1000), PalletInstance(50), GeneralIndex(1984)),
17+
}),
18+
fun: Fungible(100_000_000),
19+
};
20+
let usdc_amount = MultiAsset {
21+
id: Concrete(MultiLocation {
22+
parents: 1,
23+
interior: X3(Parachain(1000), PalletInstance(50), GeneralIndex(1337)),
24+
}),
25+
fun: Fungible(100_000_000),
26+
};
27+
28+
let beneficiary: PolimecAccountId = [0u8; 32].into();
29+
30+
let assert_reserve_asset_fee_goes_to_treasury = |multi_asset: MultiAsset| {
31+
let asset_multilocation =
32+
if let Concrete(asset_multilocation) = multi_asset.id { asset_multilocation } else { unreachable!() };
33+
let asset_id = SupportedAssets::convert(&asset_multilocation).unwrap();
34+
let asset_amount = if let Fungible(amount) = multi_asset.fun { amount } else { unreachable!() };
35+
36+
let xcm = Xcm::<PolimecCall>(vec![
37+
ReserveAssetDeposited(vec![multi_asset.clone()].into()),
38+
ClearOrigin,
39+
BuyExecution { fees: multi_asset, weight_limit: Unlimited },
40+
DepositAsset {
41+
assets: WildMultiAsset::All.into(),
42+
beneficiary: MultiLocation::new(0, X1(AccountId32 { network: None, id: beneficiary.clone().into() })),
43+
},
44+
])
45+
.into();
46+
PolimecNet::execute_with(|| {
47+
let prev_treasury_balance = PolimecForeignAssets::balance(asset_id, TreasuryAccount::get());
48+
let prev_beneficiary_balance = PolimecForeignAssets::balance(asset_id, beneficiary.clone());
49+
50+
let outcome = <PolimecRuntime as pallet_xcm::Config>::XcmExecutor::execute_xcm(
51+
MultiLocation::new(1, X1(Parachain(1000))),
52+
xcm.clone(),
53+
fake_message_hash(&xcm),
54+
Weight::MAX,
55+
);
56+
assert!(outcome.ensure_complete().is_ok());
57+
58+
let post_treasury_balance = PolimecForeignAssets::balance(asset_id, TreasuryAccount::get());
59+
let post_beneficiary_balance = PolimecForeignAssets::balance(asset_id, beneficiary.clone());
60+
61+
let net_treasury_balance = post_treasury_balance - prev_treasury_balance;
62+
let net_beneficiary_balance = post_beneficiary_balance - prev_beneficiary_balance;
63+
64+
let net_total = net_treasury_balance + net_beneficiary_balance;
65+
66+
assert_eq!(net_total, asset_amount);
67+
assert!(net_treasury_balance > 0);
68+
});
69+
};
70+
71+
let assert_plmc_fee_goes_to_treasury = || {
72+
let asset_amount = 100_0_000_000_000;
73+
let multi_asset = MultiAsset { id: Concrete(MultiLocation::here()), fun: Fungible(asset_amount) };
74+
75+
let xcm = Xcm::<PolimecCall>(vec![
76+
WithdrawAsset(vec![multi_asset.clone()].into()),
77+
BuyExecution { fees: multi_asset, weight_limit: Unlimited },
78+
DepositAsset {
79+
assets: WildMultiAsset::All.into(),
80+
beneficiary: MultiLocation::new(0, X1(AccountId32 { network: None, id: beneficiary.clone().into() })),
81+
},
82+
])
83+
.into();
84+
PolimecNet::execute_with(|| {
85+
let prev_treasury_balance = PolimecBalances::free_balance(TreasuryAccount::get());
86+
let prev_beneficiary_balance = PolimecBalances::free_balance(beneficiary.clone());
87+
88+
let outcome = <PolimecRuntime as pallet_xcm::Config>::XcmExecutor::execute_xcm(
89+
MultiLocation::new(0, X1(AccountId32 { network: None, id: PolimecNet::account_id_of(ALICE).into() })),
90+
xcm.clone(),
91+
fake_message_hash(&xcm),
92+
Weight::MAX,
93+
);
94+
assert!(outcome.ensure_complete().is_ok());
95+
96+
let post_treasury_balance = PolimecBalances::free_balance(TreasuryAccount::get());
97+
let post_beneficiary_balance = PolimecBalances::free_balance(beneficiary.clone());
98+
99+
let net_treasury_balance = post_treasury_balance - prev_treasury_balance;
100+
let net_beneficiary_balance = post_beneficiary_balance - prev_beneficiary_balance;
101+
102+
let net_total = net_treasury_balance + net_beneficiary_balance;
103+
104+
assert_eq!(net_total, asset_amount);
105+
assert!(net_treasury_balance > 0);
106+
});
107+
};
108+
109+
assert_reserve_asset_fee_goes_to_treasury(dot_amount);
110+
assert_reserve_asset_fee_goes_to_treasury(usdt_amount);
111+
assert_reserve_asset_fee_goes_to_treasury(usdc_amount);
112+
assert_plmc_fee_goes_to_treasury();
113+
}

runtimes/polimec/src/xcm_config.rs

+8-8
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@
1616

1717
use super::{
1818
AccountId, AllPalletsWithSystem, AssetId as AssetIdPalletAssets, Balance, Balances, EnsureRoot, ForeignAssets,
19-
ParachainInfo, ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, Vec, WeightToFee,
20-
XcmpQueue,
19+
ParachainInfo, ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, Treasury,
20+
TreasuryAccount, Vec, WeightToFee, XcmpQueue,
2121
};
2222
use core::marker::PhantomData;
2323
use frame_support::{
@@ -31,7 +31,6 @@ use polimec_xcm_executor::{
3131
XcmExecutor,
3232
};
3333
use polkadot_parachain_primitives::primitives::Sibling;
34-
use polkadot_runtime_common::impls::ToAuthor;
3534
use sp_runtime::traits::MaybeEquivalence;
3635
use xcm::latest::prelude::*;
3736
use xcm_builder::{
@@ -261,7 +260,8 @@ pub type Reserves = AssetHubAssetsAsReserve;
261260
/// ForeignAssetsAdapter is a FungiblesAdapter that allows for transacting foreign assets.
262261
/// Currently we only support DOT, USDT and USDC.
263262
pub type AssetTransactors = (FungibleTransactor, ForeignAssetsAdapter);
264-
263+
pub type TakeRevenueToTreasury =
264+
cumulus_primitives_utility::XcmFeesTo32ByteAccount<AssetTransactors, AccountId, TreasuryAccount>;
265265
pub struct XcmConfig;
266266
impl polimec_xcm_executor::Config for XcmConfig {
267267
type Aliasers = ();
@@ -290,10 +290,10 @@ impl polimec_xcm_executor::Config for XcmConfig {
290290
type SubscriptionService = PolkadotXcm;
291291
type Trader = (
292292
// TODO: weight to fee has to be carefully considered. For now use default
293-
UsingComponents<WeightToFee, HereLocation, AccountId, Balances, ToAuthor<Runtime>>,
294-
FixedRateOfFungible<UsdtTraderParams, ()>,
295-
FixedRateOfFungible<DotTraderParams, ()>,
296-
FixedRateOfFungible<UsdcTraderParams, ()>,
293+
UsingComponents<WeightToFee, HereLocation, AccountId, Balances, Treasury>,
294+
FixedRateOfFungible<UsdtTraderParams, TakeRevenueToTreasury>,
295+
FixedRateOfFungible<DotTraderParams, TakeRevenueToTreasury>,
296+
FixedRateOfFungible<UsdcTraderParams, TakeRevenueToTreasury>,
297297
);
298298
type UniversalAliases = Nothing;
299299
type UniversalLocation = UniversalLocation;

0 commit comments

Comments
 (0)