@@ -936,3 +936,101 @@ fn debug_tnt_delegation_verify_nomination_issue() {
936936 assert_eq ! ( delegation. amount, delegate_amount) ;
937937 } ) ;
938938}
939+
940+ #[ test]
941+ fn delegation_unstake_bug_with_nomination_pending ( ) {
942+ // Test case that reproduces the bug where delegation unstake calculation
943+ // incorrectly includes nomination unstake requests
944+ new_test_ext ( ) . execute_with ( || {
945+ let delegator: AccountId = Bob . into ( ) ;
946+ let operator: AccountId = Alice . into ( ) ;
947+ // Use the same asset that nominations use: Asset::Custom(Zero::zero()) which is
948+ // Asset::Custom(0)
949+ let asset = Asset :: Custom ( 0 ) ;
950+ let delegation_amount = 500 ;
951+ let nomination_amount = 300 ;
952+ let _delegation_unstake_amount = 200 ;
953+ let nomination_unstake_amount = 100 ;
954+
955+ // Setup operator
956+ assert_ok ! ( MultiAssetDelegation :: join_operators(
957+ RuntimeOrigin :: signed( operator. clone( ) ) ,
958+ 10_000
959+ ) ) ;
960+
961+ // Create tokens and deposits for delegator
962+ create_and_mint_tokens ( 0 , delegator. clone ( ) , delegation_amount) ;
963+ assert_ok ! ( MultiAssetDelegation :: deposit(
964+ RuntimeOrigin :: signed( delegator. clone( ) ) ,
965+ asset. clone( ) ,
966+ delegation_amount,
967+ None ,
968+ None ,
969+ ) ) ;
970+
971+ // Create a regular delegation
972+ assert_ok ! ( MultiAssetDelegation :: delegate(
973+ RuntimeOrigin :: signed( delegator. clone( ) ) ,
974+ operator. clone( ) ,
975+ asset. clone( ) ,
976+ delegation_amount,
977+ Default :: default ( ) ,
978+ ) ) ;
979+
980+ // Setup nomination for native restaking
981+ assert_ok ! ( Staking :: bond(
982+ RuntimeOrigin :: signed( delegator. clone( ) ) ,
983+ nomination_amount,
984+ pallet_staking:: RewardDestination :: Staked
985+ ) ) ;
986+ assert_ok ! ( Staking :: nominate( RuntimeOrigin :: signed( delegator. clone( ) ) , vec![
987+ operator. clone( )
988+ ] ) ) ;
989+
990+ // Create nomination delegation (simulate native restaking)
991+ assert_ok ! ( MultiAssetDelegation :: delegate_nomination(
992+ RuntimeOrigin :: signed( delegator. clone( ) ) ,
993+ operator. clone( ) ,
994+ nomination_amount,
995+ Default :: default ( ) ,
996+ ) ) ;
997+
998+ // Schedule nomination unstake first
999+ assert_ok ! ( MultiAssetDelegation :: schedule_nomination_unstake(
1000+ RuntimeOrigin :: signed( delegator. clone( ) ) ,
1001+ operator. clone( ) ,
1002+ nomination_unstake_amount,
1003+ Default :: default ( ) ,
1004+ ) ) ;
1005+
1006+ // Verify nomination unstake request exists
1007+ let metadata = MultiAssetDelegation :: delegators ( delegator. clone ( ) ) . unwrap ( ) ;
1008+ assert_eq ! ( metadata. delegator_unstake_requests. len( ) , 1 ) ;
1009+ let nomination_request = & metadata. delegator_unstake_requests [ 0 ] ;
1010+ assert ! ( nomination_request. is_nomination) ;
1011+ assert_eq ! ( nomination_request. amount, nomination_unstake_amount) ;
1012+
1013+ // Now try to schedule regular delegation unstake for the full amount
1014+ // This should succeed as we have 500 - 0 = 500 available for delegation
1015+ assert_ok ! ( MultiAssetDelegation :: schedule_delegator_unstake(
1016+ RuntimeOrigin :: signed( delegator. clone( ) ) ,
1017+ operator. clone( ) ,
1018+ asset. clone( ) ,
1019+ delegation_amount,
1020+ ) ) ;
1021+
1022+ // Verify both unstake requests exist
1023+ let metadata = MultiAssetDelegation :: delegators ( delegator. clone ( ) ) . unwrap ( ) ;
1024+ assert_eq ! ( metadata. delegator_unstake_requests. len( ) , 2 ) ;
1025+
1026+ // Check first request is nomination
1027+ let first_request = & metadata. delegator_unstake_requests [ 0 ] ;
1028+ assert ! ( first_request. is_nomination) ;
1029+ assert_eq ! ( first_request. amount, nomination_unstake_amount) ;
1030+
1031+ // Check second request is delegation
1032+ let second_request = & metadata. delegator_unstake_requests [ 1 ] ;
1033+ assert ! ( !second_request. is_nomination) ;
1034+ assert_eq ! ( second_request. amount, delegation_amount) ;
1035+ } ) ;
1036+ }
0 commit comments