diff --git a/pallets/asset-index/src/lib.rs b/pallets/asset-index/src/lib.rs index 277805a9fa..2c1756515e 100644 --- a/pallets/asset-index/src/lib.rs +++ b/pallets/asset-index/src/lib.rs @@ -747,10 +747,15 @@ pub mod pallet { .ok_or_else(|| ArithmeticError::Overflow.into()) } - /// Adds liquid asset + /// Adds liquid asset units /// - /// - If asset not exists, create asset /// - If asset exists, deposit more units into matched asset + /// + /// This function is a no-op if: + /// - The `units` to be converted is zero, this would be analogous to + /// [`LocalTreasury::withdraw`] + /// - The `amount` of index tokens to be received is less than the required ED and the + /// account does not exist. fn do_add_asset( recipient: T::AccountId, asset_id: T::AssetId, @@ -763,7 +768,7 @@ pub mod pallet { return Ok(()); } - // transfer the caller's fund into the treasury account + // transfer the caller's funds into the treasury account in exchange for index tokens Self::add_liquid(&recipient, asset_id, units, amount)?; Self::deposit_event(Event::AssetAdded(asset_id, units, recipient, amount)); @@ -789,7 +794,7 @@ pub mod pallet { Self::remove_liquid(&who, asset_id, units, index_tokens, recipient.clone())?; Self::deposit_event(Event::AssetRemoved(asset_id, units, who, recipient, index_tokens)); - Ok(().into()) + Ok(()) } /// The fee model depends on how long LP contributions remained in the index. @@ -858,7 +863,7 @@ pub mod pallet { /// /// *NOTE*: /// - This does not account for fees - /// - This is a noop for `redeem == 0` + /// - This is a no-op for `redeem == 0` pub fn liquid_asset_redemptions( redeem: u128, ) -> Result, DispatchError> { diff --git a/pallets/asset-index/src/mock.rs b/pallets/asset-index/src/mock.rs index 40bbaa0c86..278aaf2567 100644 --- a/pallets/asset-index/src/mock.rs +++ b/pallets/asset-index/src/mock.rs @@ -12,7 +12,7 @@ use pallet_price_feed::PriceFeedBenchmarks; use crate as pallet_asset_index; use frame_support::{ ord_parameter_types, parameter_types, - traits::{GenesisBuild, LockIdentifier, StorageMapShim}, + traits::{GenesisBuild, LockIdentifier}, PalletId, }; use frame_system as system; @@ -79,7 +79,7 @@ impl system::Config for Test { type DbWeight = (); type Version = (); type PalletInfo = PalletInfo; - type AccountData = (); + type AccountData = pallet_balances::AccountData; type OnNewAccount = (); type OnKilledAccount = (); type SystemWeightInfo = (); @@ -97,7 +97,7 @@ ord_parameter_types! { // param types for balances parameter_types! { pub const MaxLocks: u32 = 1024; - pub static ExistentialDeposit: Balance = 0; + pub static ExistentialDeposit: Balance = 2; } impl pallet_balances::Config for Test { @@ -105,12 +105,7 @@ impl pallet_balances::Config for Test { type DustRemoval = (); type Event = Event; type ExistentialDeposit = ExistentialDeposit; - type AccountStore = StorageMapShim< - pallet_balances::Account, - system::Provider, - AccountId, - pallet_balances::AccountData, - >; + type AccountStore = System; type WeightInfo = (); type MaxLocks = MaxLocks; type MaxReserves = (); @@ -118,8 +113,12 @@ impl pallet_balances::Config for Test { } parameter_type_with_key! { - pub ExistentialDeposits: |_asset_id: AssetId| -> Balance { - Zero::zero() + pub ExistentialDeposits: |asset_id: AssetId| -> Balance { + if *asset_id == ED_ASSET_ID { + Balance::MAX / 2 + } else { + Zero::zero() + } }; } @@ -199,8 +198,9 @@ impl pallet_asset_index::Config for Test { pub const PINT_ASSET_ID: AssetId = 0u32; pub const ASSET_A_ID: AssetId = 1u32; pub const ASSET_B_ID: AssetId = 2u32; -pub const SAFT_ASSET_ID: AssetId = 99u32; pub const UNKNOWN_ASSET_ID: AssetId = 3u32; +pub const SAFT_ASSET_ID: AssetId = 99u32; +pub const ED_ASSET_ID: AssetId = 99999999u32; pub const ASSET_A_PRICE_MULTIPLIER: Balance = 2; pub const ASSET_B_PRICE_MULTIPLIER: Balance = 3; diff --git a/pallets/asset-index/src/tests.rs b/pallets/asset-index/src/tests.rs index 32d17ebe7c..9dbe4a2134 100644 --- a/pallets/asset-index/src/tests.rs +++ b/pallets/asset-index/src/tests.rs @@ -2,7 +2,7 @@ // SPDX-License-Identifier: LGPL-3.0-only use frame_support::{assert_noop, assert_ok, traits::Currency as _}; -use orml_traits::MultiCurrency; +use orml_traits::{GetByKey, MultiCurrency}; use rand::Rng; use sp_runtime::{traits::Zero, FixedPointNumber}; use xcm::v0::MultiLocation; @@ -648,3 +648,26 @@ fn can_withdraw() { assert_eq!(pending.assets.len(), 2); }) } + +#[test] +fn add_asset_less_than_existential_deposit_is_noop() { + new_test_ext_with_balance(vec![]).execute_with(|| { + assert_ok!(AssetIndex::register_asset( + Origin::signed(ACCOUNT_ID), + ED_ASSET_ID, + AssetAvailability::Liquid(MultiLocation::Null) + )); + + let ed = ExistentialDeposits::get(&ED_ASSET_ID); + assert_ok!(Currency::deposit(ED_ASSET_ID, &ACCOUNT_ID, ed)); + + // index token payout less than ED is a no-op + assert_ok!(AssetIndex::add_asset( + Origin::signed(ACCOUNT_ID), + ED_ASSET_ID, + ed, + ExistentialDeposit::get().saturating_sub(1) + )); + assert!(AssetIndex::index_token_balance(&ACCOUNT_ID).is_zero()); + }); +}