Skip to content

Commit

Permalink
Respect all asset's existential deposit (zeitgeistpm#930)
Browse files Browse the repository at this point in the history
* Respect all asset's existential deposit

* Use 1 instead of 0 when no ED is desired

* Set ED of all asset to the ED of ZTG

* Add dust removal whitelist tests

* Order runtime tests and always use real Runtime

* Use more concise code

Co-authored-by: Malte Kliemann <[email protected]>

Co-authored-by: Malte Kliemann <[email protected]>
  • Loading branch information
sea212 and maltekliemann authored Jan 20, 2023
1 parent 3e07be6 commit 1247ddd
Show file tree
Hide file tree
Showing 6 changed files with 100 additions and 79 deletions.
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions runtime/battery-station/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ zrml-swaps-runtime-api = { default-features = false, path = "../../zrml/swaps/ru

[dev-dependencies]
sp-io = { branch = "moonbeam-polkadot-v0.9.29", git = "https://github.com/zeitgeistpm/substrate" }
test-case = "2.0.2"
xcm-emulator = { branch = "moonbeam-polkadot-v0.9.29", git = "https://github.com/zeitgeistpm/xcm-simulator" }

[features]
Expand Down
26 changes: 24 additions & 2 deletions runtime/battery-station/src/parameters.rs
Original file line number Diff line number Diff line change
Expand Up @@ -372,11 +372,33 @@ parameter_types! {
}

parameter_type_with_key! {
// Well, not every asset is a currency ¯\_(ツ)_/¯
// Existential deposits used by orml-tokens.
// Only native ZTG and foreign assets should have an existential deposit.
// Winning outcome tokens are redeemed completely by the user, losing outcome tokens
// are cleaned up automatically. In case of scalar outcomes, the market account can have dust.
// Unless LPs use `pool_exit_with_exact_asset_amount`, there can be some dust pool shares remaining.
// Explicit match arms are used to ensure new asset types are respected.
pub ExistentialDeposits: |currency_id: CurrencyId| -> Balance {
match currency_id {
Asset::CategoricalOutcome(_,_) => ExistentialDeposit::get(),
Asset::CombinatorialOutcome => ExistentialDeposit::get(),
Asset::PoolShare(_) => ExistentialDeposit::get(),
Asset::ScalarOutcome(_,_) => ExistentialDeposit::get(),
#[cfg(feature = "parachain")]
Asset::ForeignAsset(id) => {
let maybe_metadata = <
orml_asset_registry::Pallet<super::Runtime> as orml_traits::asset_registry::Inspect
>::metadata(&Asset::ForeignAsset(*id));

if let Some(metadata) = maybe_metadata {
return metadata.existential_deposit;
}

1
}
#[cfg(not(feature = "parachain"))]
Asset::ForeignAsset(_) => ExistentialDeposit::get(),
Asset::Ztg => ExistentialDeposit::get(),
_ => 0
}
};
}
Expand Down
123 changes: 48 additions & 75 deletions runtime/common/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1828,67 +1828,11 @@ macro_rules! create_common_tests {
{} => {
#[cfg(test)]
mod common_tests {
mod fee_multiplier {
use crate::parameters::{MinimumMultiplier, SlowAdjustingFeeUpdate, TargetBlockFullness};
use frame_support::{
parameter_types,
weights::{DispatchClass, Weight},
};
mod fees {
use crate::*;
use frame_support::weights::{DispatchClass, Weight};
use sp_core::H256;
use sp_runtime::{
testing::Header,
traits::{BlakeTwo256, Convert, IdentityLookup},
Perbill,
};

type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic<Runtime>;
type Block = frame_system::mocking::MockBlock<Runtime>;

frame_support::construct_runtime!(
pub enum Runtime where
Block = Block,
NodeBlock = Block,
UncheckedExtrinsic = UncheckedExtrinsic,
{
System: frame_system::{Pallet, Call, Config, Storage, Event<T>}
}
);

parameter_types! {
pub const BlockHashCount: u64 = 250;
pub const AvailableBlockRatio: Perbill = Perbill::one();
pub BlockLength: frame_system::limits::BlockLength =
frame_system::limits::BlockLength::max(2 * 1024);
pub BlockWeights: frame_system::limits::BlockWeights =
frame_system::limits::BlockWeights::simple_max(Weight::from_ref_time(1024));
}

impl frame_system::Config for Runtime {
type BaseCallFilter = frame_support::traits::Everything;
type BlockWeights = BlockWeights;
type BlockLength = ();
type DbWeight = ();
type Origin = Origin;
type Index = u64;
type BlockNumber = u64;
type Call = Call;
type Hash = H256;
type Hashing = BlakeTwo256;
type AccountId = u64;
type Lookup = IdentityLookup<Self::AccountId>;
type Header = Header;
type Event = Event;
type BlockHashCount = BlockHashCount;
type Version = ();
type PalletInfo = PalletInfo;
type AccountData = ();
type OnNewAccount = ();
type OnKilledAccount = ();
type SystemWeightInfo = ();
type SS58Prefix = ();
type OnSetCode = ();
type MaxConsumers = frame_support::traits::ConstU32<16>;
}
use sp_runtime::traits::Convert;

fn run_with_system_weight<F>(w: Weight, mut assertions: F)
where
Expand All @@ -1903,10 +1847,28 @@ macro_rules! create_common_tests {
}

#[test]
fn multiplier_can_grow_from_zero() {
fn treasury_receives_correct_amount_of_fees_and_tips() {
let mut t: sp_io::TestExternalities =
frame_system::GenesisConfig::default().build_storage::<Runtime>().unwrap().into();
t.execute_with(|| {
let fee_balance = 3 * ExistentialDeposit::get();
let fee_imbalance = Balances::issue(fee_balance);
let tip_balance = 7 * ExistentialDeposit::get();
let tip_imbalance = Balances::issue(tip_balance);
assert_eq!(Balances::free_balance(Treasury::account_id()), 0);
DealWithFees::on_unbalanceds(vec![fee_imbalance, tip_imbalance].into_iter());
assert_eq!(
Balances::free_balance(Treasury::account_id()),
fee_balance + tip_balance,
);
});
}

#[test]
fn fee_multiplier_can_grow_from_zero() {
let minimum_multiplier = MinimumMultiplier::get();
let target = TargetBlockFullness::get()
* BlockWeights::get().get(DispatchClass::Normal).max_total.unwrap();
* RuntimeBlockWeights::get().get(DispatchClass::Normal).max_total.unwrap();
// if the min is too small, then this will not change, and we are doomed forever.
// the weight is 1/100th bigger than target.
run_with_system_weight(target * 101 / 100, || {
Expand All @@ -1916,28 +1878,39 @@ macro_rules! create_common_tests {
}
}

mod deal_with_fees {
mod dust_removal {
use crate::*;
use frame_support::PalletId;
use test_case::test_case;

#[test_case(AuthorizedPalletId::get(); "authorized")]
#[test_case(CourtPalletId::get(); "court")]
#[test_case(LiquidityMiningPalletId::get(); "liquidity_mining")]
#[test_case(PmPalletId::get(); "prediction_markets")]
#[test_case(SimpleDisputesPalletId::get(); "simple_disputes")]
#[test_case(SwapsPalletId::get(); "swaps")]
#[test_case(TreasuryPalletId::get(); "treasury")]
fn whitelisted_pallet_accounts_dont_get_reaped(pallet_id: PalletId) {
let mut t: sp_io::TestExternalities =
frame_system::GenesisConfig::default().build_storage::<Runtime>().unwrap().into();
t.execute_with(|| {
let pallet_main_account: AccountId = pallet_id.into_account_truncating();
let pallet_sub_account: AccountId = pallet_id.into_sub_account_truncating(42);
assert!(DustRemovalWhitelist::contains(&pallet_main_account));
assert!(DustRemovalWhitelist::contains(&pallet_sub_account));
});
}

#[test]
fn treasury_receives_correct_amount_of_fees_and_tips() {
fn non_whitelisted_accounts_get_reaped() {
let mut t: sp_io::TestExternalities =
frame_system::GenesisConfig::default().build_storage::<Runtime>().unwrap().into();
t.execute_with(|| {
let fee_balance = 3 * ExistentialDeposit::get();
let fee_imbalance = Balances::issue(fee_balance);
let tip_balance = 7 * ExistentialDeposit::get();
let tip_imbalance = Balances::issue(tip_balance);
assert_eq!(Balances::free_balance(Treasury::account_id()), 0);
DealWithFees::on_unbalanceds(vec![fee_imbalance, tip_imbalance].into_iter());
assert_eq!(
Balances::free_balance(Treasury::account_id()),
fee_balance + tip_balance,
);
let not_whitelisted = AccountId::from([0u8; 32]);
assert!(!DustRemovalWhitelist::contains(&not_whitelisted))
});
}
}
}

}
}
1 change: 1 addition & 0 deletions runtime/zeitgeist/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ zrml-swaps-runtime-api = { default-features = false, path = "../../zrml/swaps/ru

[dev-dependencies]
sp-io = { branch = "moonbeam-polkadot-v0.9.29", git = "https://github.com/zeitgeistpm/substrate" }
test-case = "2.0.2"
xcm-emulator = { branch = "moonbeam-polkadot-v0.9.29", git = "https://github.com/zeitgeistpm/xcm-simulator" }

[features]
Expand Down
26 changes: 24 additions & 2 deletions runtime/zeitgeist/src/parameters.rs
Original file line number Diff line number Diff line change
Expand Up @@ -372,11 +372,33 @@ parameter_types! {
}

parameter_type_with_key! {
// Well, not every asset is a currency ¯\_(ツ)_/¯
// Existential deposits used by orml-tokens.
// Only native ZTG and foreign assets should have an existential deposit.
// Winning outcome tokens are redeemed completely by the user, losing outcome tokens
// are cleaned up automatically. In case of scalar outcomes, the market account can have dust.
// Unless LPs use `pool_exit_with_exact_asset_amount`, there can be some dust pool shares remaining.
// Explicit match arms are used to ensure new asset types are respected.
pub ExistentialDeposits: |currency_id: CurrencyId| -> Balance {
match currency_id {
Asset::CategoricalOutcome(_,_) => ExistentialDeposit::get(),
Asset::CombinatorialOutcome => ExistentialDeposit::get(),
Asset::PoolShare(_) => ExistentialDeposit::get(),
Asset::ScalarOutcome(_,_) => ExistentialDeposit::get(),
#[cfg(feature = "parachain")]
Asset::ForeignAsset(id) => {
let maybe_metadata = <
orml_asset_registry::Pallet<super::Runtime> as orml_traits::asset_registry::Inspect
>::metadata(&Asset::ForeignAsset(*id));

if let Some(metadata) = maybe_metadata {
return metadata.existential_deposit;
}

1
}
#[cfg(not(feature = "parachain"))]
Asset::ForeignAsset(_) => ExistentialDeposit::get(),
Asset::Ztg => ExistentialDeposit::get(),
_ => 0
}
};
}
Expand Down

0 comments on commit 1247ddd

Please sign in to comment.