diff --git a/tokens/src/lib.rs b/tokens/src/lib.rs index bd056d9ac..5d6c4075e 100644 --- a/tokens/src/lib.rs +++ b/tokens/src/lib.rs @@ -1355,11 +1355,17 @@ impl fungibles::MutateHold for Pallet { source: &T::AccountId, dest: &T::AccountId, amount: Self::Balance, - _best_effort: bool, + best_effort: bool, on_hold: bool, ) -> Result { let status = if on_hold { Status::Reserved } else { Status::Free }; - Self::repatriate_reserved(asset_id, source, dest, amount, status) + ensure!( + amount <= >::balance_on_hold(asset_id, source) || best_effort, + Error::::BalanceTooLow + ); + let gap = Self::repatriate_reserved(asset_id, source, dest, amount, status)?; + // return actual transferred amount + Ok(amount.saturating_sub(gap)) } } diff --git a/tokens/src/tests.rs b/tokens/src/tests.rs index d6f4df954..95efe1faa 100644 --- a/tokens/src/tests.rs +++ b/tokens/src/tests.rs @@ -2081,15 +2081,61 @@ fn fungibles_mutate_hold_trait_should_work() { >::hold(DOT, &ALICE, 200), Error::::BalanceTooLow ); + assert_eq!(>::balance_on_hold(DOT, &ALICE), 0); assert_ok!(>::hold(DOT, &ALICE, 100)); + assert_eq!(>::balance_on_hold(DOT, &ALICE), 100); assert_eq!( - >::release(DOT, &ALICE, 50, true), - Ok(50) + >::release(DOT, &ALICE, 40, false), + Ok(40) + ); + assert_eq!(>::balance_on_hold(DOT, &ALICE), 60); + + // exceed hold amount when not in best_effort + assert_noop!( + >::release(DOT, &ALICE, 61, false), + Error::::BalanceTooLow ); + + // exceed hold amount when in best_effort assert_eq!( - >::transfer_held(DOT, &ALICE, &BOB, 100, true, true), - Ok(50) + >::release(DOT, &ALICE, 61, true), + Ok(60) + ); + assert_eq!(>::balance_on_hold(DOT, &ALICE), 0); + + assert_ok!(>::hold(DOT, &ALICE, 70)); + assert_eq!(>::balance_on_hold(DOT, &ALICE), 70); + assert_eq!(>::balance(DOT, &BOB), 100); + assert_eq!(>::balance_on_hold(DOT, &BOB), 0); + assert_eq!( + >::transfer_held(DOT, &ALICE, &BOB, 5, false, false), + Ok(5) + ); + assert_eq!(>::balance_on_hold(DOT, &ALICE), 65); + assert_eq!(>::balance(DOT, &BOB), 105); + assert_eq!(>::balance_on_hold(DOT, &BOB), 0); + assert_eq!( + >::transfer_held(DOT, &ALICE, &BOB, 5, false, true), + Ok(5) + ); + assert_eq!(>::balance_on_hold(DOT, &ALICE), 60); + assert_eq!(>::balance(DOT, &BOB), 110); + assert_eq!(>::balance_on_hold(DOT, &BOB), 5); + + // exceed hold amount when not in best_effort + assert_noop!( + >::transfer_held(DOT, &ALICE, &BOB, 61, false, true), + Error::::BalanceTooLow + ); + + // exceed hold amount when in best_effort + assert_eq!( + >::transfer_held(DOT, &ALICE, &BOB, 61, true, true), + Ok(60) ); + assert_eq!(>::balance_on_hold(DOT, &ALICE), 0); + assert_eq!(>::balance(DOT, &BOB), 170); + assert_eq!(>::balance_on_hold(DOT, &BOB), 65); }); }