@@ -260,7 +260,13 @@ func TestInboundCEASmartContractRecipient(t *testing.T) {
260260 })
261261
262262 t .Run ("executeUniversalTx PCTx is recorded for smart contract recipient" , func (t * testing.T ) {
263- chainApp , ctx , vals , inbound , coreVals , _ := setupInboundCEASmartContractTest (t , 4 )
263+ chainApp , ctx , vals , inbound , coreVals , contractAddr := setupInboundCEASmartContractTest (t , 4 )
264+
265+ // Fund the smart contract with upc so gas fee deduction succeeds
266+ contractAccAddr := sdk .AccAddress (contractAddr .Bytes ())
267+ fundCoins := sdk .NewCoins (sdk .NewInt64Coin ("upc" , 1_000_000_000 ))
268+ require .NoError (t , chainApp .BankKeeper .MintCoins (ctx , "mint" , fundCoins ))
269+ require .NoError (t , chainApp .BankKeeper .SendCoinsFromModuleToAccount (ctx , "mint" , contractAccAddr , fundCoins ))
264270
265271 for i := 0 ; i < 3 ; i ++ {
266272 valAddr , err := sdk .ValAddressFromBech32 (coreVals [i ].OperatorAddress )
@@ -283,13 +289,51 @@ func TestInboundCEASmartContractRecipient(t *testing.T) {
283289 require .Empty (t , callPcTx .ErrorMsg )
284290 })
285291
286- t .Run ("EOA recipient receives deposit and executeUniversalTx call" , func (t * testing.T ) {
292+ t .Run ("gas fees deducted from smart contract recipient after executeUniversalTx" , func (t * testing.T ) {
293+ chainApp , ctx , vals , inbound , coreVals , contractAddr := setupInboundCEASmartContractTest (t , 4 )
294+
295+ // Fund the smart contract with upc so fee deduction can succeed
296+ contractAccAddr := sdk .AccAddress (contractAddr .Bytes ())
297+ fundCoins := sdk .NewCoins (sdk .NewInt64Coin ("upc" , 1_000_000_000 ))
298+ require .NoError (t , chainApp .BankKeeper .MintCoins (ctx , "mint" , fundCoins ))
299+ require .NoError (t , chainApp .BankKeeper .SendCoinsFromModuleToAccount (ctx , "mint" , contractAccAddr , fundCoins ))
300+
301+ balanceBefore := chainApp .BankKeeper .GetBalance (ctx , contractAccAddr , "upc" )
302+
303+ // Reach quorum
304+ for i := 0 ; i < 3 ; i ++ {
305+ valAddr , err := sdk .ValAddressFromBech32 (coreVals [i ].OperatorAddress )
306+ require .NoError (t , err )
307+ coreValAcc := sdk .AccAddress (valAddr ).String ()
308+
309+ err = utils .ExecVoteInbound (t , ctx , chainApp , vals [i ], coreValAcc , inbound )
310+ require .NoError (t , err )
311+ }
312+
313+ // Verify executeUniversalTx PCTx has gas_used > 0
314+ utxKey := uexecutortypes .GetInboundUniversalTxKey (* inbound )
315+ utx , found , err := chainApp .UexecutorKeeper .GetUniversalTx (ctx , utxKey )
316+ require .NoError (t , err )
317+ require .True (t , found )
318+ require .GreaterOrEqual (t , len (utx .PcTx ), 2 , "should have deposit + executeUniversalTx PCTxs" )
319+
320+ callPcTx := utx .PcTx [1 ]
321+ require .Equal (t , "SUCCESS" , callPcTx .Status )
322+ require .Greater (t , callPcTx .GasUsed , uint64 (0 ), "executeUniversalTx should report gas used" )
323+
324+ // Verify upc balance decreased (gas was deducted)
325+ balanceAfter := chainApp .BankKeeper .GetBalance (ctx , contractAccAddr , "upc" )
326+ require .True (t , balanceAfter .Amount .LT (balanceBefore .Amount ),
327+ "smart contract upc balance should decrease after gas fee deduction (before=%s, after=%s)" ,
328+ balanceBefore .Amount , balanceAfter .Amount )
329+ })
330+
331+ t .Run ("EOA recipient receives deposit only, no executeUniversalTx" , func (t * testing.T ) {
287332 chainApp , ctx , vals , _ , coreVals , _ := setupInboundCEASmartContractTest (t , 4 )
288333 usdcAddress := utils .GetDefaultAddresses ().ExternalUSDCAddr
289334 testAddress := utils .GetDefaultAddresses ().DefaultTestAddr
290335
291- // TargetAddr2 is a plain EOA — deposit lands there and executeUniversalTx is called
292- // (calling to an EOA in EVM succeeds with empty output)
336+ // TargetAddr2 is a plain EOA (no contract code deployed)
293337 eoaRecipient := utils .GetDefaultAddresses ().TargetAddr2
294338
295339 validUP := & uexecutortypes.UniversalPayload {
@@ -335,8 +379,15 @@ func TestInboundCEASmartContractRecipient(t *testing.T) {
335379 require .NoError (t , err )
336380 require .True (t , found )
337381
338- // Expect 2 PCTxs: deposit + executeUniversalTx
339- require .GreaterOrEqual (t , len (utx .PcTx ), 2 , "should have deposit and executeUniversalTx PCTxs" )
382+ // EOA recipient: deposit PCTx only, no executeUniversalTx PCTx
383+ // (code size check skips executeUniversalTx for EOAs, but payload execution via UEA may still run)
384+ require .GreaterOrEqual (t , len (utx .PcTx ), 1 , "should have at least deposit PCTx for EOA recipient" )
385+
386+ // Verify no executeUniversalTx-specific PCTx (the smart contract call path is skipped)
387+ // The deposit PCTx should succeed
388+ require .Equal (t , "SUCCESS" , utx .PcTx [0 ].Status , "deposit should succeed for EOA recipient" )
389+
390+ // No outbound should be created from executeUniversalTx (which was skipped)
340391 require .Equal (t , "SUCCESS" , utx .PcTx [0 ].Status , "deposit should succeed for EOA recipient" )
341392
342393 // isCEA path never creates a revert outbound
0 commit comments