@@ -3126,7 +3126,7 @@ mod sponsored_paymaster {
31263126 }
31273127
31283128 #[ test]
3129- fn signed_dispatch_permit_should_fail_with_call_execution_error_when_inner_call_reverts_and_not_pause ( ) {
3129+ fn signed_dispatch_permit_should_commit_and_consume_nonce_when_inner_call_reverts ( ) {
31303130 TestNet :: reset ( ) ;
31313131
31323132 Hydra :: execute_with ( || {
@@ -3163,10 +3163,13 @@ mod sponsored_paymaster {
31633163 s,
31643164 ) ;
31653165
3166- let err = result. expect_err ( "inner-call revert must produce an error" ) ;
3166+ // Inner call reverts, but the signed branch commits like the unsigned
3167+ // path: the extrinsic returns Ok and the permit nonce is consumed.
3168+ assert_ok ! ( result) ;
31673169 assert_eq ! (
3168- err. error,
3169- pallet_transaction_multi_payment:: Error :: <Runtime >:: EvmPermitCallExecutionError . into( ) ,
3170+ pallet_evm_precompile_call_permit:: NoncesStorage :: get( from) ,
3171+ U256 :: one( ) ,
3172+ "revert must still consume the permit nonce" ,
31703173 ) ;
31713174 assert_dispatch_permit_not_paused ( ) ;
31723175 } ) ;
@@ -3472,7 +3475,7 @@ mod sponsored_paymaster {
34723475 }
34733476
34743477 #[ test]
3475- fn signed_dispatch_permit_should_restore_previous_fee_payer_override_on_real_run_failure ( ) {
3478+ fn signed_dispatch_permit_should_restore_previous_fee_payer_override_on_real_run_revert ( ) {
34763479 TestNet :: reset ( ) ;
34773480
34783481 Hydra :: execute_with ( || {
@@ -3511,12 +3514,13 @@ mod sponsored_paymaster {
35113514 r,
35123515 s,
35133516 ) ;
3514- assert ! ( result. is_err( ) ) ;
3517+ // Revert now commits (Ok); the override is still restored to the outer value.
3518+ assert_ok ! ( result) ;
35153519
35163520 assert_eq ! (
35173521 hydradx_runtime:: evm:: evm_fee_payer( ) ,
35183522 Some ( outer) ,
3519- "outer override must survive the early-return path" ,
3523+ "outer override must be restored after the revert-commit path" ,
35203524 ) ;
35213525
35223526 hydradx_runtime:: evm:: clear_evm_fee_payer ( ) ;
@@ -3592,15 +3596,13 @@ mod sponsored_paymaster {
35923596 } ) ;
35933597 }
35943598
3595- // Signed-branch divergence from unsigned: when the inner call reverts,
3596- // `do_dispatch_permit_signed` returns Err. FRAME wraps every dispatchable
3597- // in a storage layer, so the Err rolls back the `NoncesStorage` increment
3598- // that `T::EvmPermit::dispatch_permit` performed before checking
3599- // `exit_reason`. Net effect: the user keeps their permit nonce and can
3600- // re-submit the same signed payload (unsigned path does NOT roll back
3601- // and therefore consumes the nonce on revert).
3599+ // Signed branch matches the unsigned path on revert: when the inner call
3600+ // reverts, `do_dispatch_permit_signed` returns Ok(post_info), committing the
3601+ // `NoncesStorage` increment that `T::EvmPermit::dispatch_permit` performed
3602+ // before checking `exit_reason`. Net effect: the permit nonce is consumed,
3603+ // so the same signed payload cannot be replayed.
36023604 #[ test]
3603- fn adversarial_signed_dispatch_permit_should_leave_permit_nonce_unchanged_on_real_run_revert ( ) {
3605+ fn signed_dispatch_permit_should_consume_permit_nonce_on_real_run_revert ( ) {
36043606 TestNet :: reset ( ) ;
36053607
36063608 Hydra :: execute_with ( || {
@@ -3639,23 +3641,24 @@ mod sponsored_paymaster {
36393641 r,
36403642 s,
36413643 ) ;
3642- assert ! ( result. is_err ( ) ) ;
3644+ assert_ok ! ( result) ;
36433645
36443646 let nonce_after = pallet_evm_precompile_call_permit:: NoncesStorage :: get ( alith) ;
36453647 assert_eq ! (
3646- nonce_after, nonce_before,
3647- "call-permit nonce MUST NOT advance — Err rolls back the runner's nonce bump"
3648+ nonce_after,
3649+ nonce_before + U256 :: one( ) ,
3650+ "call-permit nonce MUST advance — Ok commits the runner's nonce bump"
36483651 ) ;
36493652 assert_dispatch_permit_not_paused ( ) ;
36503653 } ) ;
36513654 }
36523655
3653- // Failed signed dispatches must cost the signer full declared weight (no
3654- // custom refund). This is an anti-grief property: an attacker spamming
3655- // invalid permits pays the same as a legitimate paymaster spamming valid
3656- // ones, so griefing is uniformly expensive.
3656+ // A RunnerError (account never charged) is the one path the signed branch
3657+ // still fails hard on: it returns Err with default post info, costing the
3658+ // signer full declared weight (no refund). Anti-grief — spamming permits the
3659+ // runner rejects is as expensive as any legitimate sponsored dispatch .
36573660 #[ test]
3658- fn signed_dispatch_permit_should_use_default_post_info_on_real_run_failure ( ) {
3661+ fn signed_dispatch_permit_should_use_default_post_info_on_runner_error ( ) {
36593662 TestNet :: reset ( ) ;
36603663
36613664 Hydra :: execute_with ( || {
@@ -3674,10 +3677,12 @@ mod sponsored_paymaster {
36743677 asset_in : HDX ,
36753678 asset_out : DAI ,
36763679 amount : 1_000_000_000 ,
3677- min_buy_amount : u128 :: MAX ,
3680+ min_buy_amount : 0 ,
36783681 } ) ;
3682+ // Sign for u64::MAX gas so the permit validates, then the runner rejects
3683+ // it (gas_limit exceeds the block gas limit) → EvmPermitRunnerError.
36793684 let ( from, data, gas_limit, deadline, v, r, s) =
3680- build_permit_for_call ( & inner_call, 1_000_000 , U256 :: from ( 1_000_000_000_000u128 ) ) ;
3685+ build_permit_for_call ( & inner_call, u64 :: MAX , U256 :: from ( 1_000_000_000_000u128 ) ) ;
36813686
36823687 let result = MultiTransactionPayment :: dispatch_permit (
36833688 RuntimeOrigin :: signed ( paymaster) ,
@@ -3692,10 +3697,10 @@ mod sponsored_paymaster {
36923697 s,
36933698 ) ;
36943699
3695- let err = result. expect_err ( "expected real-run failure " ) ;
3700+ let err = result. expect_err ( "expected runner error " ) ;
36963701 assert_eq ! (
36973702 err. error,
3698- pallet_transaction_multi_payment:: Error :: <Runtime >:: EvmPermitCallExecutionError . into( ) ,
3703+ pallet_transaction_multi_payment:: Error :: <Runtime >:: EvmPermitRunnerError . into( ) ,
36993704 ) ;
37003705 // actual_weight = None → SignedExtension uses declared weight, no refund.
37013706 assert_eq ! ( err. post_info. actual_weight, None ) ;
0 commit comments