Skip to content

fix: F-2026-18817 | read SVM gateway events from emit_cpi inner instructions - #357

Merged
Aman035 merged 5 commits into
audit-fixesfrom
F-2026-18817-events
Sep 1, 2026
Merged

fix: F-2026-18817 | read SVM gateway events from emit_cpi inner instructions#357
Aman035 merged 5 commits into
audit-fixesfrom
F-2026-18817-events

Conversation

@Aman035

@Aman035 Aman035 commented Sep 1, 2026

Copy link
Copy Markdown
Member

The gateway moved to emit_cpi, so events are inner instructions, not Program data: logs. Our listener only read logs, so it saw nothing. Confirmed on the dummy gateway: a real finalize has zero Program data: lines.

What changed

  • Read events from tx.Meta.InnerInstructions, keep only instructions the gateway itself ran, strip Anchor's 8-byte EVENT_IX_TAG. The remaining bytes are what the old log line carried, so the parsers are unchanged.
  • Skip failed transactions. A failed tx still lists what ran before it aborted, and all of it was rolled back.
  • Read gas_used per event type: 112 finalize, 112 rescue, 144 revert. It was 80 for all three, which lands inside wrapper_address. Matches develop.
  • Deleted gatewayEmittedLogs, logsTruncated, invokedProgram, isProgramExit. Attribution is now the inner instruction's program id, so the log-stack parsing is dead.

Three properties, each verified

  • Truncation proof: events live outside the log buffer, so a chatty destination CPI cannot drop one.
  • Forgery proof: to be attributed, the runtime must have invoked the gateway. Anchor's event handler then requires the __event_authority PDA to sign, and only the gateway can sign for it. Stronger than the log stack it replaces (F-2026-18198).
  • Error proof: a failed CPI aborts the caller, so a failed inner instruction always fails the transaction, and failed transactions are skipped.

Tests

  • Real devnet transaction pinned as a fixture: no Program data: line, event extracted, GasFeeUsed 5260057. In it gas_fee - gas_used == gas_to_refund, so the offsets check themselves.
  • Same payload from another program ignored, from the gateway stored.
  • Gateway resolved through an address lookup table, writable segment not mistaken for it.
  • Truncated logs still yield the event; failed transactions do not.
  • Per event type minimum lengths and offsets.
  • Mutation: 12 run, 12 caught, including dropping the emitter check.

@Aman035
Aman035 merged commit 7f9e50f into audit-fixes Sep 1, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant