Skip to content

parseFillLogs throws TypeError on empty logs array instead of returning undefined #268

@Nexory

Description

@Nexory

Summary

parseFillLogs in packages/sdk/src/actions/waitForFillTx.ts reads logs[0] unconditionally at the top of the function body to build blockData. When the caller passes an empty logs array (a valid scenario — no fill logs found yet), the function throws a TypeError (Cannot read properties of undefined) instead of returning undefined. The function's implicit contract — it returns undefined when no matching log is found — is already honored for the non-empty-but-no-match path, but the empty-array path is never reached.

What I observed

packages/sdk/src/actions/waitForFillTx.ts, lines 164–166:

const blockData = {
  depositTxHash: logs[0]!.blockHash!,   // throws if logs is []
  depositTxBlock: logs[0]!.blockNumber!,
};

The blockData object is only used inside the two if (v3_5Log) / if (v3Log) branches that follow. If neither branch is taken (no match), the function falls through and returns undefined implicitly — but only after blockData has already been constructed. An empty array causes a crash before any filtering logic runs.

Impact

Any caller that passes an empty or pre-filtered logs: [] (e.g., a batch receipt with no fill events for the given deposit, or a defensive call site guarding against race conditions) receives an unhandled TypeError rather than the expected undefined. Since the function is exported and used as a utility, callers not wrapped in try/catch will surface this as an unhandled exception. The waitForFillTx path itself propagates the error to the rejection handler at line 142–144, which may silently stall the wait loop.

Suggested fix

Move the blockData construction inside the match branches (or guard with an early return):

export function parseFillLogs(logs: Log[], filter?: ...) {
+  if (logs.length === 0) return undefined;
+
   const blockData = {
     depositTxHash: logs[0]!.blockHash!,
     depositTxBlock: logs[0]!.blockNumber!,
   };
   // ...rest unchanged
}

Alternatively, defer blockData construction to just before each return block so it only runs when a match exists, avoiding the non-empty-but-wrong-logs edge case as well.

Notes

Related to toolkit Tier-A audit finding #8. The non-null assertions (!) signal the author assumed a non-empty array, but the call-site contract does not enforce that precondition.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions