diff --git a/integration-tests/src/constants.rs b/integration-tests/src/constants.rs index f14796e94..3a3ca9439 100644 --- a/integration-tests/src/constants.rs +++ b/integration-tests/src/constants.rs @@ -548,7 +548,7 @@ pub mod polimec { use super::*; use crate::{PolimecNet, PolimecOrigin, PolimecRuntime}; use pallet_funding::AcceptedFundingAsset; - use polimec_runtime::PayMaster; + use polimec_runtime::{PayMaster, TreasuryAccount}; use xcm::v3::Parent; use xcm_emulator::TestExt; @@ -622,7 +622,7 @@ pub mod polimec { funded_accounts.extend(accounts::init_balances().iter().cloned().map(|k| (k, INITIAL_DEPOSIT))); funded_accounts.extend(collators::initial_authorities().iter().cloned().map(|(acc, _)| (acc, 20_005 * PLMC))); - funded_accounts.push((get_account_id_from_seed::("TREASURY_STASH"), 20_005 * PLMC)); + funded_accounts.push((TreasuryAccount::get(), 20_005 * PLMC)); funded_accounts.push((PayMaster::get(), 20_005 * PLMC)); let genesis_config = polimec_runtime::RuntimeGenesisConfig { @@ -640,7 +640,11 @@ pub mod polimec { (usdt_asset_id, "Local USDT".as_bytes().to_vec(), "USDT".as_bytes().to_vec(), 6), (usdc_asset_id, "Local USDC".as_bytes().to_vec(), "USDC".as_bytes().to_vec(), 6), ], - accounts: vec![], + accounts: vec![ + (dot_asset_id, TreasuryAccount::get(), 0_0_010_000_000u128), + (usdt_asset_id, TreasuryAccount::get(), 0_0_010_000_000u128), + (usdc_asset_id, TreasuryAccount::get(), 0_0_010_000_000u128), + ], }, parachain_info: polimec_runtime::ParachainInfoConfig { parachain_id: PARA_ID.into(), ..Default::default() }, session: polimec_runtime::SessionConfig { diff --git a/integration-tests/src/tests/credentials.rs b/integration-tests/src/tests/credentials.rs index 5430fc568..cbc4087bd 100644 --- a/integration-tests/src/tests/credentials.rs +++ b/integration-tests/src/tests/credentials.rs @@ -21,11 +21,10 @@ use polimec_common::credentials::{Did, InvestorType}; use polimec_common_test_utils::{get_fake_jwt, get_mock_jwt_with_cid, get_test_jwt}; use polimec_runtime::PLMC; use sp_runtime::{ - bounded_vec, generic::Era, traits::SignedExtension, transaction_validity::{InvalidTransaction::Payment, TransactionValidityError}, - AccountId32, BoundedVec, DispatchError, + AccountId32, DispatchError, }; use tests::defaults::*; diff --git a/integration-tests/src/tests/governance.rs b/integration-tests/src/tests/governance.rs index 381ab3dce..971cc9515 100644 --- a/integration-tests/src/tests/governance.rs +++ b/integration-tests/src/tests/governance.rs @@ -386,6 +386,8 @@ fn election_phragmen_works() { ::MaxCandidates::get() as usize ); + let prev_treasury_balance = Balances::balance(&Treasury::account_id()); + for (i, voter) in vec![ALICE, BOB, CHARLIE, DAVE, EVE, FERDIE, ALICE_STASH, BOB_STASH].into_iter().enumerate() { let voter = PolimecNet::account_id_of(voter); assert_ok!(Elections::vote( @@ -411,10 +413,11 @@ fn election_phragmen_works() { { assert_eq!(Balances::total_balance(candidate), ED); } + let post_treasury_balance = Balances::balance(&Treasury::account_id()); + let net_treasury_balance = post_treasury_balance - prev_treasury_balance; assert_eq!( - Balances::balance(&Treasury::account_id()), - (::MaxCandidates::get() as u128 - 15) * 1000 * PLMC + - ED + net_treasury_balance, + (::MaxCandidates::get() as u128 - 15) * 1000 * PLMC ) }); } diff --git a/integration-tests/src/tests/mod.rs b/integration-tests/src/tests/mod.rs index 0888699c3..6453b6c40 100644 --- a/integration-tests/src/tests/mod.rs +++ b/integration-tests/src/tests/mod.rs @@ -22,3 +22,4 @@ mod governance; mod oracle; mod reserve_backed_transfers; mod vest; +mod xcm_config; diff --git a/integration-tests/src/tests/xcm_config.rs b/integration-tests/src/tests/xcm_config.rs new file mode 100644 index 000000000..94a28b2d7 --- /dev/null +++ b/integration-tests/src/tests/xcm_config.rs @@ -0,0 +1,113 @@ +use crate::{PolimecAccountId, PolimecBalances, PolimecCall, PolimecForeignAssets, PolimecNet, PolimecRuntime, ALICE}; +use parity_scale_codec::Encode; +use polimec_runtime::{xcm_config::SupportedAssets, TreasuryAccount}; +use sp_runtime::traits::MaybeEquivalence; +use xcm::prelude::*; +use xcm_emulator::{Chain, TestExt}; +pub fn fake_message_hash(message: &Xcm) -> XcmHash { + message.using_encoded(sp_io::hashing::blake2_256) +} +#[test] +fn execution_fees_go_to_treasury() { + let dot_amount = MultiAsset { id: Concrete(MultiLocation::parent()), fun: Fungible(100_0_000_000_000) }; + let usdt_amount = MultiAsset { + id: Concrete(MultiLocation { + parents: 1, + interior: X3(Parachain(1000), PalletInstance(50), GeneralIndex(1984)), + }), + fun: Fungible(100_000_000), + }; + let usdc_amount = MultiAsset { + id: Concrete(MultiLocation { + parents: 1, + interior: X3(Parachain(1000), PalletInstance(50), GeneralIndex(1337)), + }), + fun: Fungible(100_000_000), + }; + + let beneficiary: PolimecAccountId = [0u8; 32].into(); + + let assert_reserve_asset_fee_goes_to_treasury = |multi_asset: MultiAsset| { + let asset_multilocation = + if let Concrete(asset_multilocation) = multi_asset.id { asset_multilocation } else { unreachable!() }; + let asset_id = SupportedAssets::convert(&asset_multilocation).unwrap(); + let asset_amount = if let Fungible(amount) = multi_asset.fun { amount } else { unreachable!() }; + + let xcm = Xcm::(vec![ + ReserveAssetDeposited(vec![multi_asset.clone()].into()), + ClearOrigin, + BuyExecution { fees: multi_asset, weight_limit: Unlimited }, + DepositAsset { + assets: WildMultiAsset::All.into(), + beneficiary: MultiLocation::new(0, X1(AccountId32 { network: None, id: beneficiary.clone().into() })), + }, + ]) + .into(); + PolimecNet::execute_with(|| { + let prev_treasury_balance = PolimecForeignAssets::balance(asset_id, TreasuryAccount::get()); + let prev_beneficiary_balance = PolimecForeignAssets::balance(asset_id, beneficiary.clone()); + + let outcome = ::XcmExecutor::execute_xcm( + MultiLocation::new(1, X1(Parachain(1000))), + xcm.clone(), + fake_message_hash(&xcm), + Weight::MAX, + ); + assert!(outcome.ensure_complete().is_ok()); + + let post_treasury_balance = PolimecForeignAssets::balance(asset_id, TreasuryAccount::get()); + let post_beneficiary_balance = PolimecForeignAssets::balance(asset_id, beneficiary.clone()); + + let net_treasury_balance = post_treasury_balance - prev_treasury_balance; + let net_beneficiary_balance = post_beneficiary_balance - prev_beneficiary_balance; + + let net_total = net_treasury_balance + net_beneficiary_balance; + + assert_eq!(net_total, asset_amount); + assert!(net_treasury_balance > 0); + }); + }; + + let assert_plmc_fee_goes_to_treasury = || { + let asset_amount = 100_0_000_000_000; + let multi_asset = MultiAsset { id: Concrete(MultiLocation::here()), fun: Fungible(asset_amount) }; + + let xcm = Xcm::(vec![ + WithdrawAsset(vec![multi_asset.clone()].into()), + BuyExecution { fees: multi_asset, weight_limit: Unlimited }, + DepositAsset { + assets: WildMultiAsset::All.into(), + beneficiary: MultiLocation::new(0, X1(AccountId32 { network: None, id: beneficiary.clone().into() })), + }, + ]) + .into(); + PolimecNet::execute_with(|| { + let prev_treasury_balance = PolimecBalances::free_balance(TreasuryAccount::get()); + let prev_beneficiary_balance = PolimecBalances::free_balance(beneficiary.clone()); + + let outcome = ::XcmExecutor::execute_xcm( + MultiLocation::new(0, X1(AccountId32 { network: None, id: PolimecNet::account_id_of(ALICE).into() })), + xcm.clone(), + fake_message_hash(&xcm), + Weight::MAX, + ); + assert!(outcome.ensure_complete().is_ok()); + + let post_treasury_balance = PolimecBalances::free_balance(TreasuryAccount::get()); + let post_beneficiary_balance = PolimecBalances::free_balance(beneficiary.clone()); + + let net_treasury_balance = post_treasury_balance - prev_treasury_balance; + let net_beneficiary_balance = post_beneficiary_balance - prev_beneficiary_balance; + + let net_total = net_treasury_balance + net_beneficiary_balance; + + assert_eq!(net_total, asset_amount); + assert!(net_treasury_balance > 0); + }); + }; + + assert_reserve_asset_fee_goes_to_treasury(dot_amount); + assert_reserve_asset_fee_goes_to_treasury(usdt_amount); + assert_reserve_asset_fee_goes_to_treasury(usdc_amount); + assert_plmc_fee_goes_to_treasury(); +} diff --git a/runtimes/polimec/src/lib.rs b/runtimes/polimec/src/lib.rs index 209ab0ace..eb65db967 100644 --- a/runtimes/polimec/src/lib.rs +++ b/runtimes/polimec/src/lib.rs @@ -27,12 +27,13 @@ use frame_support::{ traits::{ fungible::{Credit, HoldConsideration, Inspect}, tokens::{self, PayFromAccount, UnityAssetBalanceConversion}, - AsEnsureOriginWithArg, ConstU32, Contains, EitherOfDiverse, InstanceFilter, LinearStoragePrice, PrivilegeCmp, - TransformOrigin, + AsEnsureOriginWithArg, ConstU32, Contains, Currency, EitherOfDiverse, InstanceFilter, LinearStoragePrice, + PrivilegeCmp, TransformOrigin, }, weights::{ConstantMultiplier, Weight}, }; use frame_system::{EnsureRoot, EnsureRootWithSuccess, EnsureSigned, EnsureSignedBy}; +use pallet_balances::NegativeImbalance; use pallet_democracy::GetElectorate; use pallet_funding::DaysToBlocks; @@ -551,6 +552,12 @@ impl tokens::imbalance::OnUnbalanced> for ToTreasury { let _ = >::resolve(&treasury_account, amount); } } +impl tokens::imbalance::OnUnbalanced> for ToTreasury { + fn on_nonzero_unbalanced(amount: NegativeImbalance) { + let treasury_account = Treasury::account_id(); + >::resolve_creating(&treasury_account, amount); + } +} parameter_types! { pub TreasuryAccount: AccountId = Treasury::account_id(); @@ -1132,6 +1139,7 @@ impl pallet_dispenser::Config for Runtime { // Create the runtime by composing the FRAME pallets that were previously configured. construct_runtime!( pub enum Runtime + { // System support stuff. System: frame_system = 0, diff --git a/runtimes/polimec/src/xcm_config.rs b/runtimes/polimec/src/xcm_config.rs index a8e4c1b7e..657b758c0 100644 --- a/runtimes/polimec/src/xcm_config.rs +++ b/runtimes/polimec/src/xcm_config.rs @@ -16,8 +16,8 @@ use super::{ AccountId, AllPalletsWithSystem, AssetId as AssetIdPalletAssets, Balance, Balances, EnsureRoot, ForeignAssets, - ParachainInfo, ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, Vec, WeightToFee, - XcmpQueue, + ParachainInfo, ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, ToTreasury, + Treasury, TreasuryAccount, Vec, WeightToFee, XcmpQueue, }; use core::marker::PhantomData; use frame_support::{ @@ -31,7 +31,6 @@ use polimec_xcm_executor::{ XcmExecutor, }; use polkadot_parachain_primitives::primitives::Sibling; -use polkadot_runtime_common::impls::ToAuthor; use sp_runtime::traits::MaybeEquivalence; use xcm::latest::prelude::*; use xcm_builder::{ @@ -261,7 +260,8 @@ pub type Reserves = AssetHubAssetsAsReserve; /// ForeignAssetsAdapter is a FungiblesAdapter that allows for transacting foreign assets. /// Currently we only support DOT, USDT and USDC. pub type AssetTransactors = (FungibleTransactor, ForeignAssetsAdapter); - +pub type TakeRevenueToTreasury = + cumulus_primitives_utility::XcmFeesTo32ByteAccount; pub struct XcmConfig; impl polimec_xcm_executor::Config for XcmConfig { type Aliasers = (); @@ -290,10 +290,10 @@ impl polimec_xcm_executor::Config for XcmConfig { type SubscriptionService = PolkadotXcm; type Trader = ( // TODO: weight to fee has to be carefully considered. For now use default - UsingComponents>, - FixedRateOfFungible, - FixedRateOfFungible, - FixedRateOfFungible, + UsingComponents, + FixedRateOfFungible, + FixedRateOfFungible, + FixedRateOfFungible, ); type UniversalAliases = Nothing; type UniversalLocation = UniversalLocation;