@@ -731,3 +731,72 @@ fn named_multi_reservable_repatriate_all_reserved_named_works() {
731731 } ) ) ;
732732 } ) ;
733733}
734+
735+ #[ test]
736+ fn slash_hook_works ( ) {
737+ ExtBuilder :: default ( )
738+ . balances ( vec ! [ ( ALICE , DOT , 100 ) ] )
739+ . build ( )
740+ . execute_with ( || {
741+ let initial_hook_calls = OnSlashHook :: < Runtime > :: calls ( ) ;
742+
743+ // slashing zero tokens is a no-op
744+ assert_eq ! ( Tokens :: slash( DOT , & ALICE , 0 ) , 0 ) ;
745+ assert_eq ! ( OnSlashHook :: <Runtime >:: calls( ) , initial_hook_calls) ;
746+
747+ assert_eq ! ( Tokens :: slash( DOT , & ALICE , 50 ) , 0 ) ;
748+ assert_eq ! ( OnSlashHook :: <Runtime >:: calls( ) , initial_hook_calls + 1 ) ;
749+
750+ // `slash` calls the hook even if no amount was slashed
751+ assert_eq ! ( Tokens :: slash( DOT , & ALICE , 100 ) , 50 ) ;
752+ assert_eq ! ( OnSlashHook :: <Runtime >:: calls( ) , initial_hook_calls + 2 ) ;
753+ } ) ;
754+ }
755+
756+ #[ test]
757+ fn slash_hook_works_for_reserved ( ) {
758+ ExtBuilder :: default ( )
759+ . balances ( vec ! [ ( ALICE , DOT , 100 ) ] )
760+ . build ( )
761+ . execute_with ( || {
762+ let initial_slash_hook_calls = OnSlashHook :: < Runtime > :: calls ( ) ;
763+
764+ assert_ok ! ( Tokens :: reserve( DOT , & ALICE , 50 ) ) ;
765+ // slashing zero tokens is a no-op
766+ assert_eq ! ( Tokens :: slash_reserved( DOT , & ALICE , 0 ) , 0 ) ;
767+ assert_eq ! ( OnSlashHook :: <Runtime >:: calls( ) , initial_slash_hook_calls) ;
768+
769+ assert_eq ! ( Tokens :: slash_reserved( DOT , & ALICE , 50 ) , 0 ) ;
770+ assert_eq ! ( OnSlashHook :: <Runtime >:: calls( ) , initial_slash_hook_calls + 1 ) ;
771+
772+ // `slash_reserved` calls the hook even if no amount was slashed
773+ assert_eq ! ( Tokens :: slash_reserved( DOT , & ALICE , 50 ) , 50 ) ;
774+ assert_eq ! ( OnSlashHook :: <Runtime >:: calls( ) , initial_slash_hook_calls + 2 ) ;
775+ } ) ;
776+ }
777+
778+ #[ test]
779+ fn slash_hook_works_for_reserved_named ( ) {
780+ ExtBuilder :: default ( )
781+ . balances ( vec ! [ ( ALICE , DOT , 100 ) ] )
782+ . build ( )
783+ . execute_with ( || {
784+ let initial_slash_hook_calls = OnSlashHook :: < Runtime > :: calls ( ) ;
785+
786+ assert_ok ! ( Tokens :: reserve_named( & RID_1 , DOT , & ALICE , 10 ) ) ;
787+ // slashing zero tokens is a no-op
788+ assert_eq ! ( Tokens :: slash_reserved_named( & RID_1 , DOT , & ALICE , 0 ) , 0 ) ;
789+ assert_eq ! ( OnSlashHook :: <Runtime >:: calls( ) , initial_slash_hook_calls) ;
790+
791+ assert_eq ! ( Tokens :: slash_reserved_named( & RID_1 , DOT , & ALICE , 10 ) , 0 ) ;
792+ assert_eq ! ( OnSlashHook :: <Runtime >:: calls( ) , initial_slash_hook_calls + 1 ) ;
793+
794+ // `slash_reserved_named` calls `slash_reserved` under-the-hood with a
795+ // value to slash based on the account's balance. Because the account's
796+ // balance is currently zero, `slash_reserved` will be a no-op and
797+ // the OnSlash hook will not be called.
798+ assert_eq ! ( Tokens :: slash_reserved_named( & RID_1 , DOT , & ALICE , 50 ) , 50 ) ;
799+ // Same value as previously because of the no-op
800+ assert_eq ! ( OnSlashHook :: <Runtime >:: calls( ) , initial_slash_hook_calls + 1 ) ;
801+ } ) ;
802+ }
0 commit comments