Skip to content

Commit af2ea25

Browse files
authored
Merge pull request #1358 from galacticcouncil/fix/dust-account-whitelist
fix: dust account
2 parents 0541e65 + aef72e3 commit af2ea25

11 files changed

Lines changed: 208 additions & 173 deletions

File tree

Cargo.lock

Lines changed: 3 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

integration-tests/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "runtime-integration-tests"
3-
version = "1.68.0"
3+
version = "1.69.0"
44
description = "Integration tests"
55
authors = ["GalacticCouncil"]
66
edition = "2021"

integration-tests/src/aave_router.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1372,15 +1372,15 @@ fn check_atoken_transfer_with_rounding_error() {
13721372
assert_eq!(Currencies::free_balance(ADOT, &BOB.into()), first_transfer_amount);
13731373

13741374
let adot_contract = HydraErc20Mapping::asset_address(ADOT);
1375+
assert_ok!(EVMAccounts::bind_evm_address(RuntimeOrigin::signed(ALICE.into())));
1376+
let alice_dot_balance_before = Currencies::free_balance(DOT, &ALICE.into());
13751377
assert_ok!(AaveTradeExecutor::<hydradx_runtime::Runtime>::withdraw_all_to(
13761378
adot_contract,
13771379
&BOB.into(),
13781380
&ALICE.into()
13791381
));
1380-
assert_eq!(
1381-
Currencies::free_balance(ADOT, &ALICE.into()),
1382-
alice_balance + first_transfer_amount
1383-
);
1382+
assert_eq!(Currencies::free_balance(ADOT, &BOB.into()), 0);
1383+
assert!(Currencies::free_balance(DOT, &ALICE.into()) > alice_dot_balance_before);
13841384
})
13851385
}
13861386

integration-tests/src/dust.rs

Lines changed: 72 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -386,6 +386,9 @@ mod atoken_dust {
386386
assert_ok!(EVMAccounts::bind_evm_address(hydradx_runtime::RuntimeOrigin::signed(
387387
ALICE.into()
388388
)));
389+
assert_ok!(EVMAccounts::bind_evm_address(hydradx_runtime::RuntimeOrigin::signed(
390+
Treasury::account_id()
391+
)));
389392

390393
let alice_dot_balance_before = 8999999999999998;
391394
assert_eq!(
@@ -407,14 +410,23 @@ mod atoken_dust {
407410
0
408411
);
409412

413+
let treasury_dot_balance_before =
414+
Currencies::free_balance(crate::aave_router::DOT, &Treasury::account_id());
415+
410416
assert_ok!(Duster::dust_account(
411417
hydradx_runtime::RuntimeOrigin::signed(ALICE.into()),
412418
ALICE.into(),
413419
ADOT,
414420
));
415421

416422
assert_eq!(Currencies::free_balance(ADOT, &ALICE.into()), 0);
417-
assert_eq!(Currencies::free_balance(ADOT, &Treasury::account_id()), 1);
423+
// Treasury receives underlying DOT, not ADOT, as Treasury doesnt need AToken
424+
assert_eq!(Currencies::free_balance(ADOT, &Treasury::account_id()), 0);
425+
assert_eq!(
426+
Currencies::free_balance(crate::aave_router::DOT, &Treasury::account_id()),
427+
treasury_dot_balance_before + 1
428+
);
429+
418430
//Alice DOT (adot underlying asset) balance should remain the same after dusting
419431
assert_eq!(
420432
Currencies::free_balance(crate::aave_router::DOT, &ALICE.into()),
@@ -423,6 +435,60 @@ mod atoken_dust {
423435
});
424436
}
425437

438+
#[test]
439+
fn dust_account_should_work_for_unbound_evm_account_when_atoken_balance_below_ed() {
440+
TestNet::reset();
441+
442+
crate::aave_router::with_atoken(|| {
443+
let ed = 10000;
444+
set_ed(ADOT, ed);
445+
//Needed because withdraw_all_to sends the assets to treasury which should be a known bounded account
446+
assert_ok!(EVMAccounts::bind_evm_address(hydradx_runtime::RuntimeOrigin::signed(
447+
Treasury::account_id()
448+
)));
449+
450+
let alice_dot_balance_before = Currencies::free_balance(crate::aave_router::DOT, &ALICE.into());
451+
assert_eq!(Currencies::free_balance(ADOT, &ALICE.into()), START_BALANCE);
452+
453+
// Make account fall below ED
454+
assert_ok!(Currencies::transfer(
455+
hydradx_runtime::RuntimeOrigin::signed(ALICE.into()),
456+
BOB.into(),
457+
ADOT,
458+
START_BALANCE - 1
459+
));
460+
461+
assert_eq!(
462+
hydradx_runtime::Currencies::free_balance(ADOT, &Treasury::account_id()),
463+
0
464+
);
465+
466+
let treasury_dot_balance_before =
467+
Currencies::free_balance(crate::aave_router::DOT, &Treasury::account_id());
468+
469+
// Act
470+
assert_ok!(Duster::dust_account(
471+
hydradx_runtime::RuntimeOrigin::signed(ALICE.into()),
472+
ALICE.into(),
473+
ADOT,
474+
));
475+
476+
assert_eq!(Currencies::free_balance(ADOT, &ALICE.into()), 0);
477+
// Treasury receives underlying DOT, not ADOT
478+
assert_eq!(Currencies::free_balance(ADOT, &Treasury::account_id()), 0);
479+
assert_eq!(
480+
Currencies::free_balance(crate::aave_router::DOT, &Treasury::account_id()),
481+
treasury_dot_balance_before + 1
482+
);
483+
484+
// Alice DOT (underlying asset) balance should remain the same after dusting
485+
assert_eq!(
486+
Currencies::free_balance(crate::aave_router::DOT, &ALICE.into()),
487+
alice_dot_balance_before
488+
);
489+
});
490+
}
491+
426492
#[test]
427493
fn no_dusting_when_atoken_balance_above_ed() {
428494
TestNet::reset();
@@ -456,6 +522,11 @@ mod atoken_dust {
456522
let ed_range = 1_u128..(START_BALANCE - 1);
457523

458524
crate::aave_router::with_atoken_rollback(|| {
525+
//Needed because withdraw_all_to sends the assets to treasury which should be a known bounded account
526+
assert_ok!(EVMAccounts::bind_evm_address(hydradx_runtime::RuntimeOrigin::signed(
527+
Treasury::account_id()
528+
)));
529+
459530
// We run prop test this way to use the same state of the chain for all run without loading the snapshot again in every run
460531
let mut runner = TestRunner::new(Config {
461532
cases: successfull_cases,

pallets/duster/Cargo.toml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "pallet-duster"
3-
version = "3.6.0"
3+
version = "3.7.0"
44
description = "Account duster"
55
authors = ["GalacticCouncil"]
66
edition = "2021"
@@ -36,7 +36,6 @@ frame-system = { workspace = true }
3636
frame-benchmarking = { workspace = true, optional = true }
3737

3838
[dev-dependencies]
39-
lazy_static = { workspace = true }
4039
sp-io = { workspace = true }
4140
sp-core = { workspace = true }
4241
pallet-balances = { workspace = true }
@@ -63,6 +62,7 @@ std = [
6362
"scale-info/std",
6463
"orml-tokens/std",
6564
"hydradx-traits/std",
66-
"pallet-balances/std"
65+
"pallet-balances/std",
66+
"pallet-currencies/std"
6767
]
6868
try-runtime = ["frame-support/try-runtime"]

pallets/duster/src/lib.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,8 @@ pub mod pallet {
164164
/// IF account balance is < min. existential deposit of given currency, and account is allowed to
165165
/// be dusted, the remaining balance is transferred to treasury account.
166166
///
167-
/// In case of AToken, we perform an erc20 dust, which does a wihtdraw all then supply atoken on behalf of the dust receiver
167+
/// In case of AToken, we perform an erc20 dust, which does a wihtdraw all to the treasury account
168+
/// Note that in this case, the treasury will just receive the underlying token, not the atoken variant.
168169
///
169170
/// The transaction fee is returned back in case of successful dusting.
170171
///
@@ -194,10 +195,7 @@ pub mod pallet {
194195
let dust_dest_account = T::TreasuryAccountId::get();
195196

196197
if T::Erc20Support::is_atoken(currency_id) {
197-
//Temporarily adding the account to whitelist to prevent ED error when AToken is withdrawn from contract
198-
Self::add_account(&account)?;
199198
T::Erc20Support::on_dust(&account, &dust_dest_account, currency_id)?;
200-
Self::remove_account(&account)?;
201199
} else {
202200
Self::transfer_dust(&account, &dust_dest_account, currency_id, dust)?;
203201
}

pallets/duster/src/mock.rs

Lines changed: 17 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,12 @@ use pallet_currencies::fungibles::FungibleCurrencies;
1919
use primitives::EvmAddress;
2020
use sp_runtime::{
2121
traits::{BlakeTwo256, IdentityLookup},
22-
BuildStorage,
22+
AccountId32, BuildStorage,
2323
};
2424
use sp_std::cell::RefCell;
2525
use sp_std::vec::Vec;
2626

27-
type AccountId = u64;
27+
type AccountId = AccountId32;
2828
pub type AssetId = u32;
2929
type Balance = u128;
3030
type Amount = i128;
@@ -35,19 +35,17 @@ pub const ATOKEN_ED: u128 = 1000u128;
3535

3636
type Block = frame_system::mocking::MockBlock<Test>;
3737

38-
lazy_static::lazy_static! {
39-
pub static ref ALICE: AccountId = 100;
40-
pub static ref BOB: AccountId = 200;
41-
pub static ref DUSTER: AccountId = 300;
42-
pub static ref TREASURY: AccountId = 400;
43-
}
38+
pub const ALICE: AccountId = AccountId32::new([1u8; 32]);
39+
pub const BOB: AccountId = AccountId32::new([2u8; 32]);
40+
pub const DUSTER: AccountId = AccountId32::new([3u8; 32]);
41+
pub const TREASURY: AccountId = AccountId32::new([4u8; 32]);
4442

4543
thread_local! {
4644
pub static ATOKEN_IDS: RefCell<Vec<AssetId>> = const { RefCell::new(vec![]) };
4745
}
4846

4947
parameter_types! {
50-
pub TreasuryAccount: AccountId = *TREASURY;
48+
pub TreasuryAccount: AccountId = TREASURY;
5149
}
5250

5351
frame_support::construct_runtime!(
@@ -76,13 +74,13 @@ parameter_types! {
7674
}
7775

7876
thread_local! {
79-
pub static KILLED: RefCell<Vec<u64>> = const { RefCell::new(vec![]) };
77+
pub static KILLED: RefCell<Vec<AccountId32>> = const { RefCell::new(vec![]) };
8078
}
8179

8280
pub struct RecordKilled;
83-
impl OnKilledAccount<u64> for RecordKilled {
84-
fn on_killed_account(who: &u64) {
85-
KILLED.with(|r| r.borrow_mut().push(*who))
81+
impl OnKilledAccount<AccountId32> for RecordKilled {
82+
fn on_killed_account(who: &AccountId32) {
83+
KILLED.with(|r| r.borrow_mut().push(who.clone()))
8684
}
8785
}
8886

@@ -97,7 +95,7 @@ impl system::Config for Test {
9795
type Block = Block;
9896
type Hash = H256;
9997
type Hashing = BlakeTwo256;
100-
type AccountId = u64;
98+
type AccountId = AccountId32;
10199
type Lookup = IdentityLookup<Self::AccountId>;
102100
type RuntimeEvent = RuntimeEvent;
103101
type BlockHashCount = BlockHashCount;
@@ -190,8 +188,8 @@ impl Erc20OnDust<AccountId, AssetId> for ATokenDusterMock {
190188
let balance = Tokens::free_balance(currency_id, account);
191189
if balance < ATOKEN_ED {
192190
Tokens::transfer(
193-
RuntimeOrigin::signed(*account),
194-
*dust_dest_account,
191+
RuntimeOrigin::signed(account.clone()),
192+
dust_dest_account.clone(),
195193
currency_id,
196194
balance,
197195
)?;
@@ -221,7 +219,7 @@ impl pallet_currencies::Config for Test {
221219
type NativeCurrency = BasicCurrencyAdapter<Test, Balances, Amount, u32>;
222220
type Erc20Currency = MockErc20Currency<Test>;
223221
type BoundErc20 = MockBoundErc20<Test>;
224-
type ReserveAccount = ();
222+
type ReserveAccount = TreasuryAccount;
225223
type GetNativeCurrencyId = NativeCurrencyId;
226224
type RegistryInspect = MockBoundErc20<Test>;
227225
type WeightInfo = ();
@@ -252,7 +250,7 @@ impl Default for ExtBuilder {
252250
fn default() -> Self {
253251
Self {
254252
endowed_accounts: vec![],
255-
native_balances: vec![(*TREASURY, 1_000_000)],
253+
native_balances: vec![(TREASURY, 1_000_000)],
256254
}
257255
}
258256
}
@@ -284,7 +282,7 @@ impl ExtBuilder {
284282
.unwrap();
285283

286284
duster::GenesisConfig::<Test> {
287-
account_whitelist: vec![*TREASURY],
285+
account_whitelist: vec![TREASURY],
288286
}
289287
.assimilate_storage(&mut t)
290288
.unwrap();

0 commit comments

Comments
 (0)