Skip to main content
A jetton transfer may include a forwardPayload to provide custom data for the transaction recipient. This is a convention, not a language feature.

Jetton payload schema

By definition, the TL-B format is (Either Cell ^Cell): one bit plus the corresponding data depending on the bit:
  • bit 0 indicates inline payload: all subsequent bits and references;
  • bit 1 indicates ref payload: the next reference.
When inline, the payload is positioned at the end of a message. Some existing jetton implementations do not follow the schema:
  • Some allow empty data, no bits at all, which is invalid because at least one bit must exist. An empty payload should be encoded as bit 0 – empty inline payload.
  • Some do not verify that no extra data remains after bit 1.
  • Error codes vary across implementations.

Canonical payload typing

TL-B (Either X Y) is a union type X | Y in Tolk. This can be defined as:
It is parsed and serialized according to the schema: either bit 0 + inline data, or bit 1 + ref. This approach can be used for assignment and client metadata. Trade-offs include:
  • consumes more gas due to runtime branching (IF bit 0);
  • does not verify that no extra data remains after bit 1.

Payload typing cases

The approach to representing a jetton forwardPayload depends on the intended usage and validation requirements.

Proxy data without validation

To proxy any data as-is, use RemainingBitsAndRefs:

Canonical union with validation

To validate a canonical union RemainingBitsAndRefs | cell, ensure that no extra data remains after a ref payload:

Validation with slices

If gas consumption is critical but validation is required, avoid allocating unions on the stack. Instead, validate a slice and keep it for further serialization:

Custom error codes

To throw custom error codes instead of an error with exit code 9, calling loadMaybeRef() is discouraged.

Dynamic assignment

Keeping a remainder reduces gas usage and enables validation, but it is less convenient when a payload must be assigned dynamically. The remainder is a plain slice containing an encoded union. For example, creating a ref payload from a cell requires manual construction.
Using RemainingBitsAndRefs | cell remains convenient for assignment but may incur additional gas costs.