Intro
While developing a smart contract, I needed to store several addresses in persistent storage. At first this looked trivial, but then a simple question came up: how many addresses can I actually fit into a single cell?
Since TON storage is measured in bits and cells, and both storage and message forwarding cost gas, answering this question precisely matters. To do that, we need to look at how addresses are defined and serialized at the TL-b level.
TL-b schemes
All address formats used in TON are defined in block.tlb. The relevant schemes are:
addr_none$00 = MsgAddressExt;
addr_extern$01 len:(## 9) external_address:(bits len)
= MsgAddressExt;
anycast_info$_ depth:(#<= 30) { depth >= 1 }
rewrite_pfx:(bits depth) = Anycast;
addr_std$10 anycast:(Maybe Anycast)
workchain_id:int8 address:bits256 = MsgAddressInt;
addr_var$11 anycast:(Maybe Anycast) addr_len:(## 9)
workchain_id:int32 address:(bits addr_len) = MsgAddressInt;
_ _:MsgAddressInt = MsgAddress;
_ _:MsgAddressExt = MsgAddress;
Address constructors
There are exactly four address constructors:
addr_noneaddr_externaddr_stdaddr_var
Theoretical aspects: calculating address size
In this section we calculate exact bit sizes based strictly on the TL-B definitions.
addr_none
addr_none$00 = MsgAddressExt;
- Constructor tag
$00→ 2 bits
Exact size: 2 bits
addr_extern
addr_extern$01 len:(## 9) external_address:(bits len)
Components:
- Constructor tag
$01→ 2 bits -
len:(## 9)→ 9 bits -
external_address:(bits len)→ len bits, wherelen ∈ [0, 511]
Exact size formula:
2 + 9 + len = 11 + len bits
Minimum size: len = 0 → 11 bits
Maximum size: len = 511 → 522 bits
addr_std
addr_std$10 anycast:(Maybe Anycast) workchain_id:int8 address:bits256
Breakdown:
- Constructor tag
$10→ 2 bits -
anycast:(Maybe Anycast)- Presence flag → 1 bit
- If present:
-
depth:(#<=30)→ 5 bits -
rewrite_pfx:(bits depth)→ depth bits, wheredepth ∈ [1, 30]
-
-
workchain_id:int8→ 8 bits -
address:bits256→ 256 bits
Exact size formula:
2 + 1 + (anycast ? (5 + depth) : 0) + 8 + 256
Without anycast (presence bit = 0):
2 + 1 + 8 + 256 = 267 bits
With anycast, maximum depth = 30:
2 + 1 + (5 + 30) + 8 + 256 = 302 bits
addr_var
addr_var$11 anycast:(Maybe Anycast) addr_len:(## 9)
workchain_id:int32 address:(bits addr_len)
Components:
- Constructor tag
$11→ 2 bits -
anycast:(Maybe Anycast)- Presence flag → 1 bit
- If present:
-
depth:(#<=30)→ 5 bits -
rewrite_pfx:(bits depth)→ depth bits
-
addr_len:(## 9)→ 9 bits -
workchain_id:int32→ 32 bits -
address:(bits addr_len)→ addr_len bits, whereaddr_len ∈ [0, 511]
Exact size formula:
2 + 1 + (anycast ? (5 + depth) : 0) + 9 + 32 + addr_len
Without anycast, maximum address length:
2 + 1 + 9 + 32 + 511 = 555 bits
With anycast, maximum depth = 30 and maximum address length:
2 + 1 + (5 + 30) + 9 + 32 + 511 = 590 bits
Practical assumptions (what really happens on mainnet)
Anycast is not used
Since TVM version 10, anycast addresses:
- are not allowed as message destinations,
- are not allowed in account addresses,
- are no longer supported by address parsing and rewrite instructions.
In practice, this means the Maybe Anycast flag is always 0, and the Anycast payload is never present.
addr_var is not used
Currently active workchains (masterchain and basechain):
- use
addr_std, - use 256-bit account IDs,
- use small workchain IDs.
addr_var exists for future extensions and is not used in real contracts today.
Practical address sizes
Internal address (addr_std, real usage)
2 (tag)
+ 1 (anycast flag)
+ 8 (workchain_id)
+ 256 (account_id)
= 267 bits
Exact size: 267 bits
This size is fixed.
External address (addr_extern, maximum)
2 (tag)
+ 9 (length)
+ 511 (payload)
= 522 bits
Summary
- TON defines four address constructors:
addr_none,addr_extern,addr_std, andaddr_var. - Theoretical address sizes range from 2 bits to 590 bits.
- On mainnet today:
- Anycast is unused.
-
addr_varis unused. - All internal addresses are
addr_std.
As a result, the practical internal address size is fixed and exactly:
➡️ 267 bits
Knowing this exact value is essential when designing compact storage layouts, estimating gas costs, and deciding how many addresses can fit into a single cell.
Top comments (0)