Skip to content

Commit

Permalink
Add lock events to tokens pallet (#883)
Browse files Browse the repository at this point in the history
* Implement lock events in update_locks(...)

* Implement lock tests

* Replace depracted clippy rule name

* Move tests into correct test file

* Use correct Event type
  • Loading branch information
sea212 authored Jan 30, 2023
1 parent 05f0007 commit 2335795
Show file tree
Hide file tree
Showing 3 changed files with 136 additions and 1 deletion.
2 changes: 1 addition & 1 deletion scripts/run-clippy.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ COMMAND=$1

ALLOW_CLIPPY_RULES=(
"clippy::identity_op" # this helps the code to be consistant
"clippy::blacklisted-name" # TODO: allow them in test only
"clippy::disallowed_names" # TODO: allow them in test only
"clippy::ptr-arg" # TODO: decide if we want to fix those
"clippy::match_single_binding" # TODO: fix those
)
Expand Down
34 changes: 34 additions & 0 deletions tokens/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,18 @@ pub mod module {
currency_id: T::CurrencyId,
who: T::AccountId,
},
/// Some free balance was locked.
Locked {
currency_id: T::CurrencyId,
who: T::AccountId,
amount: T::Balance,
},
/// Some locked balance was freed.
Unlocked {
currency_id: T::CurrencyId,
who: T::AccountId,
amount: T::Balance,
},
}

/// The total issuance of a token type.
Expand Down Expand Up @@ -843,12 +855,18 @@ impl<T: Config> Pallet<T> {
who: &T::AccountId,
locks: &[BalanceLock<T::Balance>],
) -> DispatchResult {
// track lock delta
let mut total_frozen_prev = Zero::zero();
let mut total_frozen_after = Zero::zero();

// update account data
Self::mutate_account(who, currency_id, |account, _| {
total_frozen_prev = account.frozen;
account.frozen = Zero::zero();
for lock in locks.iter() {
account.frozen = account.frozen.max(lock.amount);
}
total_frozen_after = account.frozen;
});

// update locks
Expand Down Expand Up @@ -877,6 +895,22 @@ impl<T: Config> Pallet<T> {
}
}

if total_frozen_prev < total_frozen_after {
let amount = total_frozen_after.saturating_sub(total_frozen_prev);
Self::deposit_event(Event::Locked {
currency_id,
who: who.clone(),
amount,
});
} else if total_frozen_prev > total_frozen_after {
let amount = total_frozen_prev.saturating_sub(total_frozen_after);
Self::deposit_event(Event::Unlocked {
currency_id,
who: who.clone(),
amount,
});
}

Ok(())
}

Expand Down
101 changes: 101 additions & 0 deletions tokens/src/tests_events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@ use super::*;
use frame_support::assert_ok;
use mock::*;

fn events() -> Vec<RuntimeEvent> {
let evt = System::events().into_iter().map(|evt| evt.event).collect::<Vec<_>>();
System::reset_events();
evt
}

#[test]
fn pallet_multicurrency_deposit_events() {
ExtBuilder::default()
Expand Down Expand Up @@ -300,3 +306,98 @@ fn currency_adapter_pallet_currency_deposit_events() {
}));
});
}

#[test]
fn pallet_change_locks_events() {
ExtBuilder::default().build().execute_with(|| {
assert_ok!(Tokens::do_deposit(DOT, &ALICE, 100, false, false));
assert_ok!(Tokens::do_deposit(BTC, &ALICE, 100, false, false));
System::reset_events();

// Locks: [10/DOT]
assert_ok!(Tokens::set_lock(ID_1, DOT, &ALICE, 10));
assert!(events().contains(&RuntimeEvent::Tokens(crate::Event::Locked {
currency_id: DOT,
who: ALICE,
amount: 10
})));

// Locks: [15/DOT]
assert_ok!(Tokens::set_lock(ID_1, DOT, &ALICE, 15));
assert!(events().contains(&RuntimeEvent::Tokens(crate::Event::Locked {
currency_id: DOT,
who: ALICE,
amount: 5
})));

// Locks: [15/DOT, 20/BTC]
assert_ok!(Tokens::set_lock(ID_1, BTC, &ALICE, 20));
assert!(events().contains(&RuntimeEvent::Tokens(crate::Event::Locked {
currency_id: BTC,
who: ALICE,
amount: 20
})));

// Locks: [15/DOT, 20/BTC, 10/DOT]
assert_ok!(Tokens::set_lock(ID_2, DOT, &ALICE, 10));
for event in events() {
match event {
RuntimeEvent::Tokens(crate::Event::Locked { .. }) => assert!(false, "unexpected lock event"),
RuntimeEvent::Tokens(crate::Event::Unlocked { .. }) => assert!(false, "unexpected unlock event"),
_ => continue,
}
}

// Locks: [15/DOT, 20/BTC, 12/DOT]
assert_ok!(Tokens::set_lock(ID_2, DOT, &ALICE, 12));
for event in events() {
match event {
RuntimeEvent::Tokens(crate::Event::Locked { .. }) => assert!(false, "unexpected lock event"),
RuntimeEvent::Tokens(crate::Event::Unlocked { .. }) => assert!(false, "unexpected unlock event"),
_ => continue,
}
}

// Locks: [15/DOT, 20/BTC, 10/DOT]
assert_ok!(Tokens::set_lock(ID_2, DOT, &ALICE, 10));
for event in events() {
match event {
RuntimeEvent::Tokens(crate::Event::Locked { .. }) => assert!(false, "unexpected lock event"),
RuntimeEvent::Tokens(crate::Event::Unlocked { .. }) => assert!(false, "unexpected unlock event"),
_ => continue,
}
}

// Locks: [15/DOT, 20/BTC, 20/DOT]
assert_ok!(Tokens::set_lock(ID_2, DOT, &ALICE, 20));
assert!(events().contains(&RuntimeEvent::Tokens(crate::Event::Locked {
currency_id: DOT,
who: ALICE,
amount: 5
})));

// Locks: [15/DOT, 20/BTC, 16/DOT]
assert_ok!(Tokens::set_lock(ID_2, DOT, &ALICE, 16));
assert!(events().contains(&RuntimeEvent::Tokens(crate::Event::Unlocked {
currency_id: DOT,
who: ALICE,
amount: 4
})));

// Locks: [15/DOT, 12/BTC, 16/DOT]
assert_ok!(Tokens::set_lock(ID_1, BTC, &ALICE, 12));
assert!(events().contains(&RuntimeEvent::Tokens(crate::Event::Unlocked {
currency_id: BTC,
who: ALICE,
amount: 8
})));

// Locks: [15/DOT, 12/BTC]
assert_ok!(Tokens::remove_lock(ID_2, DOT, &ALICE));
assert!(events().contains(&RuntimeEvent::Tokens(crate::Event::Unlocked {
currency_id: DOT,
who: ALICE,
amount: 1
})));
});
}

0 comments on commit 2335795

Please sign in to comment.