Skip to content

Bug in BytesEncoder::serialize causes payload corruption for ≥3-cell LZ messages on TON #219

Description

@cardanobuybot

Summary

BytesEncoder::serialize in the TON SDK has a cell-tower flattening bug that loses the head cell and duplicates cell[1] when the tower contains 3 or more cells. Any LZ OApp on TON emitting payloads of 3+ cells (~224+ bytes) sends a corrupt lzMessage.

Affected File

packages/layerzero-v2/ton/contracts/protocol/msglibs/BytesEncoder.fc — function serialize.

Description

The loop uses secondLast = self.at(idx) which re-reads the just-processed index, so iteration never reaches at(0). The head cell (first 127 bytes, containing the ABI msgType/offset/length prefix) is lost and cell[1] is duplicated in its place.

Bug only manifests for towers of 3+ cells. Two-cell payloads (≤224 bytes) are unaffected, which makes the bug invisible for small messages and explains why it has gone undetected.

Reproduction

Sent a 256-byte ABI-encoded payload (8 slots, 3 cells) from a TON OApp:

  • Expected outbound lzMessage first byte: 0x01 (msgType)
  • Actual: 0x030112ae… — the 0x03 is the last byte of nonce=3 positioned at offset 127, confirming the head cell is missing from the wire format.

Full repro with sandbox test:
https://github.com/cardanobuybot/tonstable/blob/fix/bytesencoder-3cell-payload-corruption/tests/OAppEncoder.spec.ts

Suggested Fix

Replace the broken loop with a single while (idx > 0) walk that folds at(idx) down to at(0) inclusive. Implemented locally via vendored copy:
https://github.com/cardanobuybot/tonstable/blob/fix/bytesencoder-3cell-payload-corruption/contracts/oapp/lz/protocol/msglibs/BytesEncoder.fc

After fix, both 2-cell and 3-cell payloads serialize correctly (verified via sandbox tests).

Impact

Any TON OApp emitting payloads ≥3 cells produces corrupt messages. On mainnet (active workers), this would cause downstream verification or decode to fail for every such message. On testnet the bug is masked when the path's worker rejects the message before decode.

Environment

  • LZ V2 TON SDK (packages/layerzero-v2/ton)
  • TON Testnet (EID 40343) → Arbitrum Sepolia (EID 40231)

Happy to submit a PR with the fix if it would be helpful — just let me know preferred location and style.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions