diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 29e59c2ba..2094a5c56 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -4,11 +4,13 @@ on: pull_request: branches: - master + - polkadot-** paths-ignore: - '**/README.md' push: branches: - master + - polkadot-** paths-ignore: - '**/README.md' diff --git a/tokens/src/lib.rs b/tokens/src/lib.rs index 06fefa10c..d29e07421 100644 --- a/tokens/src/lib.rs +++ b/tokens/src/lib.rs @@ -1730,17 +1730,22 @@ impl fungibles::Transfer for Pallet { impl fungibles::Unbalanced for Pallet { fn set_balance(asset_id: Self::AssetId, who: &T::AccountId, amount: Self::Balance) -> DispatchResult { // Balance is the same type and will not overflow - Self::mutate_account(who, asset_id, |account, _| { - account.free = amount; + Self::mutate_account(who, asset_id, |account, _| -> DispatchResult { + // fungibles::Unbalanced::decrease_balance didn't check account.reserved + // free = new_balance - reserved + account.free = amount + .checked_sub(&account.reserved) + .ok_or(ArithmeticError::Underflow)?; Self::deposit_event(Event::BalanceSet { currency_id: asset_id, who: who.clone(), - free: amount, + free: account.free, reserved: account.reserved, }); - }); - Ok(()) + + Ok(()) + }) } fn set_total_issuance(asset_id: Self::AssetId, amount: Self::Balance) { diff --git a/tokens/src/tests_events.rs b/tokens/src/tests_events.rs index a03c3c0bf..400630d67 100644 --- a/tokens/src/tests_events.rs +++ b/tokens/src/tests_events.rs @@ -202,7 +202,7 @@ fn pallet_fungibles_unbalanced_deposit_events() { System::assert_last_event(Event::Tokens(crate::Event::BalanceSet { currency_id: DOT, who: ALICE, - free: 500, + free: 450, reserved: 50, })); diff --git a/tokens/src/tests_fungibles.rs b/tokens/src/tests_fungibles.rs index 69b862165..c424b3127 100644 --- a/tokens/src/tests_fungibles.rs +++ b/tokens/src/tests_fungibles.rs @@ -5,6 +5,7 @@ use super::*; use frame_support::{assert_noop, assert_ok}; use mock::*; +use sp_runtime::{ArithmeticError, TokenError}; #[test] fn fungibles_inspect_trait_should_work() { @@ -54,13 +55,119 @@ fn fungibles_unbalanced_trait_should_work() { .balances(vec![(ALICE, DOT, 100)]) .build() .execute_with(|| { + // set_balance assert_eq!(>::balance(DOT, &ALICE), 100); assert_ok!(>::set_balance(DOT, &ALICE, 10)); assert_eq!(>::balance(DOT, &ALICE), 10); + // set_total_issuance assert_eq!(>::total_issuance(DOT), 100); >::set_total_issuance(DOT, 10); assert_eq!(>::total_issuance(DOT), 10); + + // decrease_balance + assert_eq!(>::balance(DOT, &ALICE), 10); + assert_noop!( + >::decrease_balance(DOT, &ALICE, 20), + TokenError::NoFunds + ); + assert_eq!( + >::decrease_balance(DOT, &ALICE, 5), + Ok(5) + ); + assert_eq!(>::balance(DOT, &ALICE), 5); + // new balance < ExistentialDeposits, clean dust + assert_eq!( + >::decrease_balance(DOT, &ALICE, 4), + Ok(5) + ); + assert_eq!(>::balance(DOT, &ALICE), 0); + // set reserved + assert_ok!(>::set_balance(DOT, &ALICE, 100)); + assert_ok!(>::reserve(DOT, &ALICE, 50)); + assert_noop!( + >::decrease_balance(DOT, &ALICE, 60), + ArithmeticError::Underflow + ); + assert_eq!( + >::decrease_balance(DOT, &ALICE, 50), + Ok(50) + ); + assert_eq!(>::balance(DOT, &ALICE), 50); + assert_eq!( + >::unreserve(DOT, &ALICE, 50), + 0 + ); + assert_eq!(>::balance(DOT, &ALICE), 50); + + // decrease_balance_at_most + assert_ok!(>::set_balance(DOT, &ALICE, 10)); + assert_eq!(>::balance(DOT, &ALICE), 10); + assert_eq!( + >::decrease_balance_at_most(DOT, &ALICE, 20), + 10 + ); + assert_ok!(>::set_balance(DOT, &ALICE, 10)); + assert_eq!( + >::decrease_balance_at_most(DOT, &ALICE, 5), + 5 + ); + assert_eq!(>::balance(DOT, &ALICE), 5); + // new balance < ExistentialDeposits, clean dust + assert_eq!( + >::decrease_balance_at_most(DOT, &ALICE, 4), + 5 + ); + assert_eq!(>::balance(DOT, &ALICE), 0); + // set reserved + assert_ok!(>::set_balance(DOT, &ALICE, 100)); + assert_ok!(>::reserve(DOT, &ALICE, 50)); + assert_eq!( + >::decrease_balance_at_most(DOT, &ALICE, 60), + 0 + ); + assert_eq!( + >::decrease_balance_at_most(DOT, &ALICE, 50), + 50 + ); + assert_eq!(>::balance(DOT, &ALICE), 50); + assert_eq!( + >::unreserve(DOT, &ALICE, 50), + 0 + ); + assert_eq!(>::balance(DOT, &ALICE), 50); + + // increase_balance + assert_ok!(>::set_balance(DOT, &ALICE, 0)); + assert_noop!( + >::increase_balance(DOT, &ALICE, 1), + TokenError::BelowMinimum + ); + assert_eq!( + >::increase_balance(DOT, &ALICE, 2), + Ok(2) + ); + assert_eq!(>::balance(DOT, &ALICE), 2); + assert_noop!( + >::increase_balance(DOT, &ALICE, Balance::MAX), + ArithmeticError::Overflow + ); + + // increase_balance_at_most + assert_ok!(>::set_balance(DOT, &ALICE, 0)); + assert_eq!( + >::increase_balance_at_most(DOT, &ALICE, 1), + 0 + ); + assert_eq!( + >::increase_balance_at_most(DOT, &ALICE, 2), + 2 + ); + assert_eq!(>::balance(DOT, &ALICE), 2); + assert_eq!( + >::increase_balance_at_most(DOT, &ALICE, Balance::MAX), + Balance::MAX - 2 + ); }); }