From c29edc18ed0233b043f2481d16f9602a0930d7d8 Mon Sep 17 00:00:00 2001 From: Nadjib Date: Wed, 27 Nov 2024 16:57:46 +0100 Subject: [PATCH] feat: check all restricted balances are above minimum when redeeming (#5444) * feat: check all restricted balances are abiove minimum when redeeming * refactor: cargo fmt * chore: checking signed commit * fix: corrected logic and tests checking min restricted balances when redeeming * fix: remove wrong tests * fix: correct previous tests failing because of new restricted balance minimum checks --- state-chain/pallets/cf-funding/src/lib.rs | 10 ++++++++ state-chain/pallets/cf-funding/src/tests.rs | 26 ++++++++++++++++++--- 2 files changed, 33 insertions(+), 3 deletions(-) diff --git a/state-chain/pallets/cf-funding/src/lib.rs b/state-chain/pallets/cf-funding/src/lib.rs index db1c8e3531..2bdcb38241 100644 --- a/state-chain/pallets/cf-funding/src/lib.rs +++ b/state-chain/pallets/cf-funding/src/lib.rs @@ -243,6 +243,9 @@ pub mod pallet { /// When requesting a redemption, you must not have an amount below the minimum. BelowMinimumFunding, + /// When requesting a redemption, all restricted balances must be above the minimum. + RestrictedBalanceBelowMinimumFunding, + /// There are not enough unrestricted funds to process the redemption. InsufficientUnrestrictedFunds, @@ -407,6 +410,13 @@ pub mod pallet { // Use the full debit amount here - fees are paid by restricted funds by default. total_restricted_balance = *restricted_balance; restricted_balance.saturating_reduce(debit_amount); + // ensure that the remaining restricted balance is zero or above MinimumFunding + ensure!( + restricted_balance.is_zero() || + *restricted_balance >= MinimumFunding::::get(), + Error::::RestrictedBalanceBelowMinimumFunding + ); + if restricted_balance.is_zero() { restricted_balances.remove(&address); } diff --git a/state-chain/pallets/cf-funding/src/tests.rs b/state-chain/pallets/cf-funding/src/tests.rs index 8f0db0a4e2..05a8071fa6 100644 --- a/state-chain/pallets/cf-funding/src/tests.rs +++ b/state-chain/pallets/cf-funding/src/tests.rs @@ -527,9 +527,11 @@ fn redemption_expiry_removes_redemption() { ); // Success, can request redemption again since the last one expired. + // Note that restricted balance is REDEMPTION_TAX less after refund, so adjust the + // TO_REDEEM accordingly to make sure restricted balance is above minimum assert_ok!(Funding::redeem( RuntimeOrigin::signed(ALICE), - TO_REDEEM.into(), + (TO_REDEEM - REDEMPTION_TAX).into(), RESTRICTED_ADDRESS, Default::default() )); @@ -600,8 +602,8 @@ fn restore_restricted_balance_when_redemption_expires() { do_test(RedemptionAmount::Exact(RESTRICTED_AMOUNT)); // Redeem a little less than the restricted balance. do_test(RedemptionAmount::Exact(RESTRICTED_AMOUNT - 1)); - // Redeem signficantly less than the restricted balance. - do_test(RedemptionAmount::Exact(RESTRICTED_AMOUNT - REDEMPTION_TAX * 2)); + // Redeem significantly less than the restricted balance. Make sure rest is above minimum + do_test(RedemptionAmount::Exact(RESTRICTED_AMOUNT - REDEMPTION_TAX * 3)); } #[test] @@ -1160,6 +1162,24 @@ mod test_restricted_balances { None::> ), ]; + test_restricted_balances![ + restricted_balances_can_only_be_zero_or_above_minimum_after_redeeming, + NO_BOND, + // Succeed, with restricted balance1 = 0 + (RedemptionAmount::Exact(RESTRICTED_BALANCE_1), RESTRICTED_ADDRESS_1, None::>), + // Succeed, with restricted balance1 = MIN_FUNDING + ( + RedemptionAmount::Exact(RESTRICTED_BALANCE_1 - MIN_FUNDING - REDEMPTION_TAX), + RESTRICTED_ADDRESS_1, + None::> + ), + // Fails, because restricted balance1 would have been < MIN_FUNDING + ( + RedemptionAmount::Exact(RESTRICTED_BALANCE_1 - MIN_FUNDING - REDEMPTION_TAX + 1), + RESTRICTED_ADDRESS_1, + Some(Error::::RestrictedBalanceBelowMinimumFunding) + ), + ]; test_restricted_balances![ higher_than_restricted_amount_1_can_only_be_redeemed_to_restricted_address_2, NO_BOND,