# Inbound transactions submitted to the InTxTracker that contain multiple ZetaSent and Deposited events are not processed correctly by the observers resulting in a loss of funds

InTxTracker observer loops break after the first ZetaSent/Deposited event, so multi-event inbound transactions only vote on one event, losing locked/burned funds.

- Payout: Contest reward
- Severity: medium
- Program: ZetaChain
- Credited: berndartmueller
- Disclosed: 2024-09-06
- Write-up quality: 7/10
- Original: https://github.com/code-423n4/2023-11-zetachain-findings/issues/396
- Library page: https://bugbountylibrary.com/r/c4%3A2023-11-zetachain%3AM-19
- Tags: domain:web3 impact:funds-loss kind:contest platform:code4rena sev:medium tech:evm technique:source-review vuln:business-logic

**Target:** ZetaChain zetaclient inbound tracker (CheckReceiptForCoinTypeZeta/ERC20)
**Root cause:** The observer's receipt-parsing loops use a `break` after successfully building the first MsgVoteOnObservedInboundTx, so subsequent ZetaSent/Deposited events in the same tx are never voted on.
**Steps:**
1. User's inbound tx is missed by observers; user submits it via `MsgAddToInTxTracker` with a Merkle proof.
2. Tx `To` is the connector/custody contract and contains multiple `ZetaSent` or `Deposited` events (e.g. via `onZetaMessage` callback re-calling `ZetaConnectorEth.send`, or repeated `ERC20Custody.deposit`).
3. Observer runs `CheckReceiptForCoinTypeZeta`/`CheckReceiptForCoinTypeERC20`, iterates `receipt.Logs`, builds vote msg for first matching event, then `break`s.
4. Remaining events are never voted on; corresponding locked/burned Zeta or deposited ERC-20 is not credited on ZetaChain.
**How found:** Code review of the observer receipt-parsing loops in `inbound_tracker.go`, spotting the `break` at line 161/195 that exits after the first successfully parsed event; then reasoning about how a single tx to the connector can emit multiple events via the `onZetaMessage` callback.
**Exploitation:** Attacker/user crafts an inbound tx whose destination contract, in its `onZetaMessage` callback, calls `ZetaConnectorEth.send` multiple times (or calls `ERC20Custody.deposit` repeatedly), emitting several events. After the tx is missed and resubmitted via `MsgAddToInTxTracker`, only the first event is observed and voted, stranding the other locked/burned funds.
**Insight:** When auditing event-scanning/observer loops, check for early `break`/`return` after the first match — multi-event transactions (callbacks, batch deposits) silently drop later events, and the loss only surfaces on the resubmission path.
