Three ways to write one address
Under the hood every TON address is two numbers: a workchain (0 for the basechain, -1 for the masterchain) and the 256-bit hash of the contract's initial state. The raw form writes exactly that, 0:83dfd552…0f31a8. It is unambiguous and it is what get-methods and low-level tooling expect, but it has no checksum: one wrong character is a different, perfectly valid-looking address.
The user-friendly form packs the same two numbers into 36 bytes — a flag byte, the workchain, the hash and a 2-byte CRC16 checksum — and writes them as 48 base64 characters. The checksum is why a typo fails validation instead of sending coins into the void, and the flag byte is why the string starts with EQ, UQ, kQ or 0Q:
| Prefix | Flag | Meaning |
|---|---|---|
EQ |
0x11 |
bounceable, mainnet |
UQ |
0x51 |
non-bounceable, mainnet |
kQ |
0x91 |
bounceable, testnet |
0Q |
0xd1 |
non-bounceable, testnet |
The same 36 bytes can be written with two base64 alphabets: standard (+ and /) and URL-safe (- and _). Wallets and explorers use the URL-safe one. The tool accepts both and prints both.
Bounceable or not: what the flag does
EQ and UQ are not two addresses. They point at the same contract and the same balance; the flag only tells the sender's wallet what to put in the bounce bit of the outgoing message.
A bounceable transfer says: if the destination cannot process this message — the contract is not deployed, it throws, it runs out of gas — send the coins back to me, minus fees. That is the right default for sending to smart contracts, which is why explorers and DEX interfaces show EQ addresses.
A non-bounceable transfer stays on the destination account even when there is no code there to handle it. That is the right form for wallets, and the only right form for the first deposit to a new wallet: a fresh wallet contract is deployed by its own first outgoing transaction, so until then there is nothing at the address to accept a bounceable message, and the coins come straight back. The address formats article walks through the whole story with examples.
What the validator checks
For a user-friendly address: the length (48 characters), the alphabet, the CRC16 checksum over the first 34 bytes, and the flag byte. For a raw address: the workchain range and exactly 64 hex digits. Each check has its own message, so a truncated paste and a typo look different.
What it cannot check is the chain: whether an account at that address is deployed, has a balance, or is the contract you think it is. That needs a node — a getAccountState call through a liteserver — or an explorer.
Batch mode
Switch to batch, paste one address per line, and every line is converted and validated independently. Invalid lines stay in place with their error, so a list of a thousand deposit addresses can be checked in one paste and the bad ones found by line number. Everything happens in your browser; the list is never uploaded.
