Skip to main content
T TON Adoption
← Glossary
NODE/03 · Term

seqno

Sequence number on a TON wallet: 32-bit counter / nonce the contract increments on every outgoing transaction to defend against replay attacks.

Aliases: sequence number, ton seqno

seqno (sequence number) is a 32-bit counter stored in every TON wallet’s data cell, incremented by 1 after every outgoing transaction. Signed messages include seqno in the body; if the seqno in the signed message doesn’t equal the current one in storage, the contract rejects the transaction with THROWIFNOT 33.

Why it matters

  • Replay protection: an attacker can’t replay your old transaction — its seqno is already used.
  • Ordering guarantee: transactions execute strictly in ascending seqno order.

SDK usage

@ton/ton SDK reads seqno from the contract before sending:

const seqno = await walletContract.getSeqno();
await walletContract.sendTransfer({ seqno, secretKey, messages: [...] });

Wallet V5 introduced an extended model: extensions can have their own seqno-namespace and sign independently of the main owner.

What to do if a transaction “gets stuck”

If sendTransfer returned but no transaction shows up in the explorer for 30+ seconds, the possible causes:

  1. External message rejected by the validator (low fee, bad signature). The seqno in storage did not increment — you can safely retry with the same seqno.
  2. Network is congested — message is in the queue, wait another 15-30 seconds.
  3. Race condition with another signature — if a parallel call (e.g. a second wallet window) sent a transaction with the same seqno, yours will be rejected with throw 33.

Check via API:

const stored = await walletContract.getSeqno();
if (stored === seqno) {
  // transaction didn't go through — safe to retry
} else if (stored > seqno) {
  // transaction was included (or a parallel send happened)
}

Never “guess” a seqno manually — always read the fresh value before each signature.

Batch sends

One seqno covers a single external message, but inside it you can ship up to 4 outgoing messages (Wallet V4) or up to 255 (Wallet V5 batch mode). They all execute atomically within one transaction; if any one fails in the compute phase — the whole batch reverts.

Wallet V5 namespaces — in detail

In Wallet V5 the data layout is richer: alongside the main signature_auth_seqno there are separate counters for every signed extension. This enables:

  • Multi-sig with multiple keys, no race conflicts.
  • Delegating sign authority to a dApp (via TON Connect 2) within a limited namespace.
  • Gasless flows: a relayer pays gas, the user only signs the operation body.

When working with a V5 wallet, always use getSeqno({ extensionId }) if you are an extension, otherwise you’ll catch a 33-throw from someone else’s namespace.

Related terms