Submitted by berndartmueller
Observers miss out on voting on multiple ZetaSent and ERC-20 Deposited events that have been emitted in a single transaction, resulting in a loss of funds.
Anyone can submit inbound transactions to ZetaChains InTxTracker via the MsgAddToInTxTracker message in case the transaction was missed by the observers in the first place to ensure the transaction is processed.
The AddToInTxTracker function handles the MsgAddToInTxTracker message and ensures that the submitted transaction is a valid inbound transaction by verifying the provided Merkle proof. Additionally, the transactions To address must be the corresponding ZetaChain contract address (e.g., connector address for the Zeta coin type, or the custody contract address for the ERC-20 coin type).
ZetaChain observers continuously query this InTxTracker in the ObserveTrackerSuggestions function.
If the submitted inbound transactions coin type is CoinType_Zeta, the CheckReceiptForCoinTypeZeta function iterates all logs contained in the transactions receipt, as seen in lines 156-164.
However, as soon as the first ZetaSent event is found and the corresponding MsgVoteOnObservedInboundTx message is successfully created, the for loop is exited in line 161 via the break statement.
Similarly, this also applies to the CheckReceiptForCoinTypeERC20 function in line 195, that processes Deposited events emitted by the ERC20Custody.deposit function.
As a consequence, if the transaction contains multiple ZetaSent events, only the first event is processed and voted upon in ZetaChain, and the other events are ignored.
Those ignored ZetaSent events are potentially never processed and the corresponding Zeta tokens that have been locked or burned in the connector contract are lost.
The use of potentially is due to the fact that the inbound transaction was missed by the observers (for any reason) in the first place, and therefore, the affected user submitted the transaction via the MsgAddToInTxTracker message.
Now the question is, how is it possible that multiple ZetaSent events are emitted when the transactions To address is the connector contract address?
This transaction could have been the result of a cross-chain message, and thus the ZetaConnectorEth.onReceive function is invoked. This function optionally calls the onZetaMessage function of the provided destinationAddress contract in lines 64-66.
Within this onZetaMessage function, the destination contract can repeatedly call the ZetaConnectorEth.send function to send cross-chain messages.
Et voil, multiple ZetaSent events are emitted.
Similarly, this also applies for repeatedly calling the ERC20Custody.deposit function to deposit ERC-20 tokens.
Consider removing the break statement in lines 161 and 195, and instead, process and vote on all ZetaSent and Deposited events.
lumtis (ZetaChain) confirmed
