diff --git a/universalClient/chains/evm/event_confirmer.go b/universalClient/chains/evm/event_confirmer.go index 719b6f97..b46f5c7f 100644 --- a/universalClient/chains/evm/event_confirmer.go +++ b/universalClient/chains/evm/event_confirmer.go @@ -145,6 +145,19 @@ func (ec *EventConfirmer) processPendingEvents(ctx context.Context) error { continue } + // eth_getLogs only returns logs from txs with receipt status 1, so this + // branch should never fire on a healthy RPC. Kept as defense-in-depth and + // for symmetry with the SVM confirmer, which has a real path here. + if receipt.Status != 1 { + if _, updateErr := ec.chainStore.UpdateEventStatus(event.EventID, store.StatusPending, store.StatusReverted); updateErr != nil { + ec.logger.Error(). + Err(updateErr). + Str("event_id", event.EventID). + Msg("failed to mark failed-tx event as REVERTED") + } + continue + } + // Check if transaction is confirmed based on confirmation type requiredConfirmations := ec.getRequiredConfirmations(event.ConfirmationType) confirmations := latestBlock - receipt.BlockNumber.Uint64() + 1 diff --git a/universalClient/chains/svm/event_confirmer.go b/universalClient/chains/svm/event_confirmer.go index 192f06ba..23ca6fe9 100644 --- a/universalClient/chains/svm/event_confirmer.go +++ b/universalClient/chains/svm/event_confirmer.go @@ -158,6 +158,19 @@ func (ec *EventConfirmer) processPendingEvents(ctx context.Context) error { continue } + // Solana preserves meta.logMessages even when meta.err is set, so a Program + // data: line from a failed tx can reach the listener. Mark such events + // REVERTED here so they never promote to CONFIRMED and trigger a vote. + if tx.Meta.Err != nil { + if _, updateErr := ec.chainStore.UpdateEventStatus(event.EventID, store.StatusPending, store.StatusReverted); updateErr != nil { + ec.logger.Error(). + Err(updateErr). + Str("event_id", event.EventID). + Msg("failed to mark failed-tx event as REVERTED") + } + continue + } + // Get transaction slot txSlot := tx.Slot if txSlot == 0 {