diff --git a/.github/workflows/linter.yml b/.github/workflows/linter.yml
index 6987d8a89..908987a1e 100644
--- a/.github/workflows/linter.yml
+++ b/.github/workflows/linter.yml
@@ -143,7 +143,7 @@ jobs:
- name: Run CSpell on changed files
# This action also annotates the PR
- uses: streetsidesoftware/cspell-action@9cd41bb518a24fefdafd9880cbab8f0ceba04d28 # 8.3.0
+ uses: streetsidesoftware/cspell-action@de2a73e963e7443969755b648a1008f77033c5b2 # 8.4.0
with:
check_dot_files: explicit
suggestions: true
diff --git a/content/foundations/meta.json b/content/foundations/meta.json
index 3b4ce920b..7c30ff654 100644
--- a/content/foundations/meta.json
+++ b/content/foundations/meta.json
@@ -16,6 +16,7 @@
"shards",
"limits",
"config",
+ "network",
"web3",
"proofs",
"system",
diff --git a/content/foundations/network/adnl-tcp.mdx b/content/foundations/network/adnl-tcp.mdx
new file mode 100644
index 000000000..319620173
--- /dev/null
+++ b/content/foundations/network/adnl-tcp.mdx
@@ -0,0 +1,314 @@
+---
+title: "ADNL over TCP: liteserver communication"
+sidebarTitle: "ADNL TCP"
+---
+
+ADNL over TCP is used for communication with liteservers. A fixed-size handshake initializes a stateful encrypted stream; subsequent frames contain keepalive frames, authentication messages, or `adnl.message.query` and `adnl.message.answer` objects.
+
+## Required connection data
+
+A client obtains the liteserver IP address, TCP port, and Ed25519 public key from a trusted configuration such as the [`liteservers` section of the global configuration](https://ton-blockchain.github.io/global.config.json). The `ip` field stores an unsigned 32-bit IPv4 value, and `id.key` stores the base64-encoded public key.
+
+The server's 256-bit ADNL short ID is the SHA-256 hash of the boxed [TL](https://core.telegram.org/mtproto/TL) serialization of its public key.
+
+## TCP frame structure
+
+After the handshake, each encrypted frame has this plaintext structure:
+
+| Field | Size | Description |
+| ---------- | ----------------: | -------------------------------------------- |
+| `size` | 4 bytes (LE) | Total frame size, excluding this field |
+| `nonce` | 32 bytes | Random prefix bytes against checksum attacks |
+| `payload` | `size - 64` bytes | TL object data or empty keepalive |
+| `checksum` | 32 bytes | SHA-256 of `nonce \|\| payload` |
+
+The `size` field and frame body are encrypted with the connection's continuing AES-CTR state, where the `size` is between 64 and 16,777,216 bytes, inclusive. A frame with `size = 64` has an empty payload that acts as a transport [keepalive message](https://en.wikipedia.org/wiki/Keepalive).
+
+The receiver decrypts the frame, independently computes SHA-256 over `nonce || payload`, and closes the connection on a mismatch.
+
+## Transport handshake
+
+The client generates 160 cryptographically random bytes called `aes_params`, used for both send (client → server) and receive (server → client) directions. Each direction uses a 32-byte key and a 16-byte nonce.
+
+The `aes_params` is serialized as follows:
+
+| Field | Size | Client use | Server use |
+| ---------- | -------: | ----------------------------- | ----------------------------- |
+| `rx_key` | 32 bytes | Receive key | Send key |
+| `tx_key` | 32 bytes | Send key | Receive key |
+| `rx_nonce` | 16 bytes | Receive initialization vector | Send initialization vector |
+| `tx_nonce` | 16 bytes | Send initialization vector | Receive initialization vector |
+| `padding` | 64 bytes | Random padding | Random padding |
+
+All 160 bytes must be unpredictable because they are used to establish the connection's cipher state.
+
+The client encrypts `aes_params` to the server identity with TON's Ed25519 envelope encryption. The encryptor generates a fresh ephemeral Ed25519 key pair, derives an X25519 shared secret from the ephemeral private key and server public key, and encrypts `aes_params` with AES-256-CTR.
+
+The 256-byte unencrypted handshake envelope has this layout:
+
+| Field | Size | Description |
+| ---------------------------- | --------: | --------------------------------------- |
+| Server ADNL short ID | 32 bytes | Selects the server identity private key |
+| Ephemeral Ed25519 public key | 32 bytes | Generated for this handshake |
+| `SHA-256(aes_params)` | 32 bytes | Verifies the decrypted parameters |
+| Encrypted `aes_params` | 160 bytes | AES-CTR ciphertext |
+
+The server selects the destination identity from the first field, decrypts the remaining 224 bytes, verifies the hash, and initializes its directional ciphers. It then sends an encrypted empty frame. Receipt of that frame confirms that the server decrypted `aes_params` and initialized the matching cipher state.
+
+
+ Implementation in the TON monorepo:
+
+ - [Outbound handshake](https://github.com/ton-blockchain/ton/blob/v2026.06/adnl/adnl-ext-client.cpp#L121-L160)
+ - [Ed25519 envelope encryption](https://github.com/ton-blockchain/ton/blob/v2026.06/keys/encryptor.cpp#L31-L110)
+
+
+## Handshake encryption
+
+Let `secret` be the 32-byte X25519 shared secret, and let `hash` be the result of applying SHA-256 to `aes_params`. The envelope cipher is then derived as follows:
+
+```text
+key = secret[0..16] || hash[16..32]
+iv = hash[0..4] || secret[20..32]
+```
+
+The ranges use a zero-based, end-exclusive convention. AES-CTR uses the resulting 32-byte key and 16-byte initialization vector.
+
+## Client identity authentication
+
+Transport-key establishment authenticates the server to a client that already trusts the configured server public key. The blockchain then authenticates the client's independently generated Ed25519 identity through the encrypted stream:
+
+```tl
+tcp.authentificate nonce:bytes = tcp.Message;
+tcp.authentificationNonce nonce:bytes = tcp.Message;
+tcp.authentificationComplete key:PublicKey signature:bytes = tcp.Message;
+```
+
+The identifiers preserve the spelling used by the TL schema.
+
+The authentication exchange is:
+
+1. The client sends `tcp.authentificate` with a nonempty client nonce.
+1. The server appends 256 random bytes internally and returns those bytes in `tcp.authentificationNonce`.
+1. The client signs `client_nonce || server_nonce` with its Ed25519 identity private key.
+1. The client sends its public key and signature in `tcp.authentificationComplete`.
+1. The server accepts the client identity only after verifying the signature over both nonces.
+
+## Keepalive and timeout behavior
+
+TON uses traffic-driven timers rather than a fixed 5-second ping interval:
+
+- A client sends one [`tcp.ping`](https://github.com/ton-blockchain/ton/blob/v2026.06/tl/generate/scheme/ton_api.tl#L35) after 10 seconds without inbound traffic.
+- A client closes the connection after 20 seconds without inbound traffic.
+- A server closes the connection after 60 seconds without inbound traffic.
+- A valid [`tcp.pong`](https://github.com/ton-blockchain/ton/blob/v2026.06/tl/generate/scheme/ton_api.tl#L23) or any other received frame resets the applicable timer.
+
+The numeric constructor ID (schema ID) of `tcp.ping` is `0x4d082b9a`. Its little-endian wire bytes are `9a 2b 08 4d`.
+
+```tl
+tcp.ping random_id:long = tcp.Pong;
+```
+
+The `tcp.pong` has the identical schema and returns the same `random_id`:
+
+```tl
+tcp.pong random_id:long = tcp.Pong;
+```
+
+Example ADNL ping frame:
+
+| Field | Size | Value |
+| -------------- | -------: | ------------------------------- |
+| `size` | 4 bytes | 76 (`64 + 4 + 8`) |
+| `nonce` | 32 bytes | Random |
+| Constructor ID | 4 bytes | `9a2b084d` |
+| `random_id` | 8 bytes | Random `uint64` |
+| `checksum` | 32 bytes | SHA-256 of `nonce \|\| payload` |
+
+## Security properties
+
+- The trusted server public key binds the handshake to the expected server identity.
+- The ephemeral key and random `aes_params` produce new transport keys for each connection.
+- The 64-byte padding field in `aes_params` is unused by the current cipher initialization but remains random and encrypted.
+- Client authentication signs both nonces, binding the proof to the current encrypted connection.
+- The post-handshake construction uses AES-CTR with an encrypted random prefix and a SHA-256 checksum without a separate authentication key. It is protocol-specific and is not an authenticated-encryption scheme such as AES-GCM.
+- Cipher state is continuous across frame boundaries. Reusing keys and initialization vectors or resetting counters breaks confidentiality.
+
+## Liteserver query envelopes
+
+A liteserver request uses 2 nested TL functions:
+
+```tl
+// ADNL query
+adnl.message.query query_id:int256 query:bytes = adnl.Message;
+
+// Liteserver method query
+liteServer.query data:bytes = Object;
+```
+
+There, `query_id` is a random 256-bit value used to correlate the answer with the outstanding query request.
+
+The liteserver method is serialized inside `liteServer.query.data`. The boxed `liteServer.query` is then serialized inside `adnl.message.query.query` bytes.
+
+| Constructor | Numeric ID | Little-endian wire bytes |
+| --------------------- | ------------ | ------------------------ |
+| `adnl.message.query` | `0xb48bf97a` | `7a f9 8b b4` |
+| `adnl.message.answer` | `0x0fac8416` | `16 84 ac 0f` |
+| `liteServer.query` | `0x798c06df` | `df 06 8c 79` |
+
+### Masterchain information, `getMasterchainInfo`
+
+The masterchain block is required as an input for many subsequent requests.
+
+```tl
+liteServer.getMasterchainInfo = liteServer.MasterchainInfo;
+
+liteServer.masterchainInfo
+ last:tonNode.blockIdExt
+ state_root_hash:int256
+ init:tonNode.zeroStateIdExt
+ = liteServer.MasterchainInfo;
+```
+
+The request constructor's numeric ID is `0x89b5e62e`, whose wire bytes are `2e e6 b5 89`. The response constructor's numeric ID is `0x85832881`, whose wire bytes are `81 28 83 85`.
+
+The following frame illustrates nested TL `bytes` values. Each `bytes` value contains its own length prefix and padding to a 4-byte boundary:
+
+```text
+74000000 -> frame size: 116 bytes
+5fb13e11977cb5cff0fbf7f23f674d734cb7c4bf01322c5e6b928c5d8ea09cfd -> random prefix
+ 7af98bb4 -> adnl.message.query wire bytes
+ 77c1545b96fa136b8e01cc08338bec47e8a43215492dda6d4d7e286382bb00c4 -> query_id
+ 0c -> query length: 12 bytes
+ df068c79 -> liteServer.query wire bytes
+ 04 -> data length: 4 bytes
+ 2ee6b589 -> getMasterchainInfo wire bytes
+ 000000 -> data padding
+ 000000 -> query padding
+ac2253594c86bd308ed631d57a63db4ab21279e9382e416128b58ee95897e164 -> SHA-256
+```
+
+The response is wrapped in `adnl.message.answer` and contains `liteServer.masterchainInfo` with `last:tonNode.blockIdExt`, `state_root_hash:int256`, and `init:tonNode.zeroStateIdExt`.
+
+Example response:
+
+```text
+20010000 -> frame size: 288 bytes
+5558b3227092e39782bd4ff9ef74bee875ab2b0661cf17efdfcd4da4e53e78e6 -> random prefix
+ 1684ac0f -> adnl.message.answer wire bytes
+ 77c1545b96fa136b8e01cc08338bec47e8a43215492dda6d4d7e286382bb00c4 -> query_id
+ b8 -> answer length: 184 bytes
+ 81288385 -> liteServer.masterchainInfo wire bytes
+ ffffffff -> workchain
+ 0000000000000080 -> shard
+ 27405801 -> seqno
+ e585a47bd5978f6a4fb2b56aa2082ec9deac33aaae19e78241b97522e1fb43d4 -> root_hash
+ 876851b60521311853f59c002d46b0bd80054af4bce340787a00bd04e0123517 -> file_hash
+ 8b4d3b38b06bb484015faf9821c3ba1c609a25b74f30e1e585b8c8e820ef0976 -> state_root_hash
+ ffffffff -> workchain
+ 17a3a92992aabea785a7a090985a265cd31f323d849da51239737e321fb05569 -> root_hash
+ 5e994fcf4d425c0a6ce6a792594b7173205f740a39cd56f537defd28b48a0f6e -> file_hash
+ 000000 -> answer padding
+520c46d1ea4daccdf27ae21750ff4982d59a30672b3ce8674195e8a23e270d21 -> SHA-256
+```
+
+### Run a get method, `runSmcMethod`
+
+Calls a get method of a smart contract:
+
+```tl
+liteServer.runSmcMethod
+ mode:#
+ id:tonNode.blockIdExt
+ account:liteServer.accountId
+ method_id:long
+ params:bytes
+ = liteServer.RunMethodResult;
+```
+
+| Field | Type | Meaning |
+| ----------- | ---------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| `mode` | `uint32` | Response-field bitmask |
+| `id` | [`tonNode.blockIdExt`](https://github.com/ton-blockchain/ton/blob/v2026.06/tl/generate/scheme/lite_api.tl#L19) | Reference masterchain block from `getMasterchainInfo` |
+| `account` | [`liteServer.accountId`](https://github.com/ton-blockchain/ton/blob/v2026.06/tl/generate/scheme/lite_api.tl#L27) | Workchain and 256-bit account ID (address) |
+| `method_id` | `long` | [CRC-16-XMODEM](https://en.wikipedia.org/wiki/Cyclic_redundancy_check) of the method name, with bitwise AND with `0xffff` and bitwise OR with `0x10000` |
+| `params` | `bytes` | TVM stack serialized as a [BoC](/foundations/serialization/boc) |
+
+When `mode` has the bit 2 set to `1`, the response includes the `result` field, which is a [BoC](/foundations/serialization/boc)-serialized stack with returned values.
+
+With `mode = 4`, the response includes both `exit_code` and `result`. [Exit codes](/tvm/exit-codes) `0` and `1` represent successful TVM termination.
+
+The `params` and `result` stacks use this TL-B representation:
+
+```tlb
+vm_stack#_ depth:(## 24) stack:(VmStackList depth) = VmStack;
+vm_stk_cons#_ {n:#} rest:^(VmStackList n) tos:VmStackValue = VmStackList (n + 1);
+vm_stk_nil#_ = VmStackList 0;
+```
+
+Stack elements are stored in reverse order: each `vm_stk_cons` stores the rest of the stack by reference and the current top-of-stack value inline.
+
+
+ When constructing the serialized stack manually, elements must appear in reverse order from their Tolk parameter list because the last argument is at the top of the stack. Return values should follow the same reverse-order stack representation.
+
+
+
+ Get method query [implementation in `tonutils-go`](https://github.com/xssnick/tonutils-go/blob/749603ab237d058cac5be4c42d36a52064db8b58/ton/runmethod.go#L51-L53).
+
+
+### Account state, `getAccountState`
+
+Obtains the state of the account:
+
+```tl
+liteServer.getAccountState
+ id:tonNode.blockIdExt
+ account:liteServer.accountId
+ = liteServer.AccountState;
+
+liteServer.accountState
+ id:tonNode.blockIdExt
+ shardblk:tonNode.blockIdExt
+ shard_proof:bytes
+ proof:bytes
+ state:bytes
+ = liteServer.AccountState;
+```
+
+In the response, the `state` field contains a [bag of cells](/foundations/serialization/boc) whose root follows the `Account` TL-B schema:
+
+```tlb
+account_none$0 = Account;
+account$1 addr:MsgAddressInt storage_stat:StorageInfo storage:AccountStorage = Account;
+```
+
+Read the prefix bit to distinguish `account_none$0` from `account$1`. For `account$1`, read the address, storage information, and `AccountStorage` fields sequentially. The balance is stored in `AccountStorage.balance`, whose `grams:Grams` field is a `VarUInteger 16`.
+
+The response also includes shard and account proofs. A client that relies on trustless results must verify those proofs against a trusted masterchain block instead of accepting `state` alone. The [liteserver-proof verification guide](/foundations/proofs/verifying-liteserver-proofs) describes that process.
+
+## Key ID calculation
+
+The key ID is the SHA-256 hash of the boxed TL serialization of the public key. For Ed25519 keys:
+
+```tl
+pub.ed25519 key:int256 = PublicKey;
+```
+
+The numeric constructor ID is `0x4813b4c6`, whose wire bytes are `c6 b4 13 48`. The key ID is therefore `SHA-256([0xc6, 0xb4, 0x13, 0x48] || public_key)`.
+
+Other key schemas are:
+
+```tl
+pub.aes key:int256 = PublicKey; // ID: 2dbcadd4
+pub.overlay name:bytes = PublicKey; // ID: 34ba45cb
+pub.unenc data:bytes = PublicKey; // ID: b61f450a
+pk.aes key:int256 = PrivateKey; // ID: a5e85137
+```
+
+Their constructor wire bytes are `d4adbc2d`, `cb45ba34`, `0a451fb6`, and `3751e8a5`, respectively. These byte sequences are the little-endian encodings of the numeric constructor IDs, **not** the numeric IDs themselves.
+
+## See also
+
+- [Implementation of ADNL over TCP](https://github.com/ton-blockchain/ton/tree/v2026.06/adnl)
+- [Liteserver TL schema](https://github.com/ton-blockchain/ton/blob/v2026.06/tl/generate/scheme/lite_api.tl)
+- [ADNL overview](/foundations/network/adnl)
+- [ADNL over UDP](/foundations/network/adnl-udp)
diff --git a/content/foundations/network/adnl-udp.mdx b/content/foundations/network/adnl-udp.mdx
new file mode 100644
index 000000000..cd26e627e
--- /dev/null
+++ b/content/foundations/network/adnl-udp.mdx
@@ -0,0 +1,276 @@
+---
+title: "ADNL over UDP: internode communication"
+sidebarTitle: "ADNL UDP"
+---
+
+ADNL over UDP is the protocol used by TON nodes to communicate with each other. It serves as the foundation for higher-level protocols such as the [distributed hash table (DHT)](https://github.com/ton-blockchain/ton/tree/v2026.06/dht) and [Reliable Large Datagram Protocol (RLDP)](https://github.com/ton-blockchain/ton/tree/v2026.06/rldp2).
+
+Unlike [ADNL over TCP](/foundations/network/adnl-tcp), the UDP implementation uses channels for ongoing communication and establishes the connection when the first data exchange occurs. Initial packets use public-key encryption and identity signatures, while established channels use directional symmetric keys.
+
+## Transport limits
+
+TON applies these limits before or during packet construction:
+
+| Limit | Size | Purpose |
+| ------------------- | ----------: | --------------------------------------------------------------- |
+| ADNL message MTU | 1,024 bytes | Maximum `adnl.Message` size without fragmentation |
+| UDP transport MTU | 1,440 bytes | Maximum UDP payload passed to the network manager |
+| Reassembled message | 8,192 bytes | Maximum serialized message accepted through `adnl.message.part` |
+
+ADNL over UDP remains an unreliable datagram protocol — although sequence numbers reject duplicates and stale packets, the missing packages are not retransmitted.
+
+## Peer endpoint discovery
+
+A sender needs the peer's full public key, 256-bit ADNL short identifier, and a usable endpoint. Static bootstrap entries are available in the [`dht.nodes` section of the global configuration](https://ton-blockchain.github.io/global.config.json). Nodes can subsequently update peer information through address lists and the DHT.
+
+For `adnl.address.udp`, `ip` is an unsigned 32-bit IPv4 value and `port` is a 16-bit UDP port encoded in a TL `int` field.
+
+For example, a `dht.nodes` entry can contain:
+
+```json
+{
+ "@type": "dht.node",
+ "id": {
+ "@type": "pub.ed25519",
+ "key": "fZnkoIAxrTd4xeBgVpZFRm5SvVvSx7eN3Vbe8c83YMk="
+ },
+ "addr_list": {
+ "addrs": [
+ {
+ "@type": "adnl.address.udp",
+ "ip": 1091897261,
+ "port": 15813
+ }
+ ]
+ }
+}
+```
+
+To connect to a node, [lite-client](#interacting-with-ton-nodes):
+
+1. Takes its public `key`, `ip` address, and the `port`.
+1. Decodes the Ed25519 public key from base64 `key`.
+1. Converts the `ip` value to dotted-decimal format. For example, `1091897261` becomes `65.21.7.173`.
+1. Combines the IP address with the port. For example, `65.21.7.173:15813`.
+1. Establishes a UDP connection with the resulting `IP:PORT` address.
+
+## Packet contents
+
+UDP envelopes encrypt a boxed `adnl.packetContents` object:
+
+```tl
+adnl.packetContents
+ rand1:bytes -- random 7 or 15 bytes
+ flags:# -- bit flags for field presence
+ from:flags.0?PublicKey -- sender's public key
+ from_short:flags.1?adnl.id.short -- sender's ID
+ message:flags.2?adnl.Message -- single message
+ messages:flags.3?(vector adnl.Message) -- multiple messages
+ address:flags.4?adnl.addressList -- sender's address list
+ priority_address:flags.5?adnl.addressList -- priority address list
+ seqno:flags.6?long -- packet sequence number
+ confirm_seqno:flags.7?long -- last received seqno
+ recv_addr_list_version:flags.8?int -- address version
+ recv_priority_addr_list_version:flags.9?int -- priority address version
+ reinit_date:flags.10?int -- connection reinitialization date
+ dst_reinit_date:flags.10?int -- peer's reinitialization date
+ signature:flags.11?bytes -- ed25519 signature
+ rand2:bytes -- random 7 or 15 bytes
+ = adnl.PacketContents
+```
+
+`rand1` and `rand2` are independently generated 7-byte or 15-byte values. A packet can contain either `message` or `messages`, but not both. Both reinitialization dates are present when flag bit 10 is set.
+
+## Envelope before channel establishment
+
+A UDP packet sent before channel establishment has this wire layout:
+
+| Field | Size | Description |
+| ---------------------------- | -------: | ------------------------------------------------------ |
+| Destination ADNL short ID | 32 bytes | SHA-256 of the destination identity's boxed public key |
+| Ephemeral Ed25519 public key | 32 bytes | Fresh key generated by the public-key encryptor |
+| Plaintext hash | 32 bytes | SHA-256 of the serialized `adnl.packetContents` |
+| Encrypted packet contents | Variable | AES-CTR encryption of `adnl.packetContents` |
+
+The last 3 fields are the output of TON's Ed25519 encryptor. It derives a shared secret from the ephemeral private key and the destination identity public key. The destination uses its identity private key and the transmitted ephemeral public key to derive the same secret.
+
+The sender signs the boxed packet contents with the source identity private key. Signature calculation clears `signature` and flag bit 11, serializes the remaining object, and signs those bytes. The sender then inserts the signature and serializes the object again before encryption.
+
+The receiver performs these checks before delivering messages:
+
+1. Decrypts the envelope with the private key selected by the destination short ID.
+1. Verifies the plaintext SHA-256 value.
+1. Parses `adnl.packetContents` and validates its flags.
+1. Resolves the source public key and verifies the packet signature.
+1. Applies re-initialization, sequence-number, acknowledgment, and address-list checks.
+
+
+ [Ed25519 envelope implementation in the TON monorepo](https://github.com/ton-blockchain/ton/blob/v2026.06/keys/encryptor.cpp#L31-L110) defines the exact key and initialization-vector derivation.
+
+
+## Channel negotiation
+
+Peers negotiate channels with these messages:
+
+```tl
+adnl.message.createChannel
+ key:int256
+ date:int
+ = adnl.Message;
+
+adnl.message.confirmChannel
+ key:int256
+ peer_key:int256
+ date:int
+ = adnl.Message;
+```
+
+There, `key` is a freshly generated Ed25519 channel public key and `date` is its Unix creation time. In `confirmChannel`, `peer_key` must equal the public key proposed by the peer — confirmations for another or superseded key are rejected.
+
+A typical first packet contains `createChannel` and an application message such as `adnl.message.query`. The application message is not required to be a query — channel negotiation is appended to whichever messages are queued for the peer.
+
+The numeric constructor ID of `adnl.message.createChannel` is `0xe673c3bb`, and its little-endian wire bytes are `bb c3 73 e6`. Constructor IDs elsewhere on this page follow the same numeric-ID and wire-byte distinction.
+
+Serialized `createChannel` example:
+
+```text
+bbc373e6 -- createChannel constructor wire bytes
+d59d8e3991be20b54dde8b78b3af18b379a62fa30e64af361c75452f6af019d7 -- key
+555c8763 -- date
+```
+
+An accompanying query uses this schema:
+
+```tl
+adnl.message.query query_id:int256 query:bytes = adnl.Message;
+```
+
+The actual request, such as `dht.getSignedAddressList`, is serialized inside `query`. Its sample encoding is:
+
+```text
+7af98bb4 -- adnl.message.query constructor wire bytes
+d7be82afbc80516ebca39784b8e2209886a69601251571444514b7f17fcd8875 -- random query_id
+04 ed4879a9 000000 -- query: 4-byte payload and 3-byte padding
+```
+
+For this exchange, the peer responds with `adnl.message.confirmChannel`, which provides its channel public key, and `adnl.message.answer`, which carries the query response.
+
+## Channel key derivation
+
+Each peer derives a 32-byte shared secret from its channel private key and the other peer's channel public key. Two AES keys are then defined:
+
+```text
+shared_key = shared secret
+reversed_key = shared secret with its 32 bytes reversed
+```
+
+Direction is selected by comparing the peers' ADNL short identity IDs as unsigned 256-bit values. The comparison does not use channel-key IDs.
+
+| Condition | Outgoing encryption key | Incoming decryption key |
+| ----------------------------- | ----------------------- | ----------------------- |
+| Local ADNL ID \< peer ADNL ID | `reversed_key` | `shared_key` |
+| Local ADNL ID > peer ADNL ID | `shared_key` | `reversed_key` |
+
+The incoming and outgoing channel IDs are the ADNL short IDs of their respective AES keys.
+
+
+ [Channel implementation in the TON monorepo](https://github.com/ton-blockchain/ton/blob/v2026.06/adnl/adnl-channel.cpp#L30-L64) defines the derivation and comparison.
+
+
+## Channel packet envelope
+
+An established channel packet has this wire layout:
+
+| Field | Size | Description |
+| ------------------------- | -------: | ----------------------------------------------- |
+| Outgoing channel ID | 32 bytes | ADNL short ID of the directional AES key |
+| Plaintext hash | 32 bytes | SHA-256 of the serialized `adnl.packetContents` |
+| Encrypted packet contents | Variable | AES-CTR encryption of `adnl.packetContents` |
+
+Channel packets omit the source identity and signature because possession of the directional key authenticates the sender. They normally omit reinitialization dates. They can still contain a single message or message vector, sequence fields, address lists, priority address lists, and received-version fields.
+
+## Sequence and session state
+
+- `seqno` identifies a packet within the current reinitialization epoch. TON tracks the highest received number plus a 64-packet mask. It rejects duplicates and packets more than 63 positions behind the highest accepted number.
+
+- `confirm_seqno` acknowledges the highest packet number accepted from the peer. A value greater than the highest locally sent sequence number is invalid. Acknowledgment updates state but does not cause ADNL to retransmit missing packets.
+
+- `reinit_date` identifies the sender's epoch, and `dst_reinit_date` states which destination epoch the sender has observed. A newer valid peer epoch resets channel, sequence, acknowledgment, address-version, and partial-message state. Reinitialization metadata is carried in signed packets sent outside a channel.
+
+## Address-list propagation
+
+Packets can advertise ordinary and priority address lists. The `recv_addr_list_version` fields tell the peer which versions have already been received, allowing it to omit unchanged lists.
+
+```tl
+adnl.addressList
+ addrs:(vector adnl.Address)
+ version:int
+ reinit_date:int
+ priority:int
+ expire_at:int
+ = adnl.AddressList;
+```
+
+Supported address variants include IPv4 UDP, IPv6 UDP, ADNL tunnels, reverse connectivity, and IPv4 QUIC endpoints. Nodes reject address lists whose serialized representation exceeds the implementation limit.
+
+## Message types
+
+### Query and answer, `adnl.message.query`
+
+```tl
+adnl.message.query query_id:int256 query:bytes = adnl.Message;
+adnl.message.answer query_id:int256 answer:bytes = adnl.Message;
+```
+
+`query_id` correlates one answer with one outstanding query. Higher-level protocol data is serialized inside `query` or `answer`.
+
+### Part, `adnl.message.part`
+
+```tl
+adnl.message.part
+ hash:int256
+ total_size:int
+ offset:int
+ data:bytes
+ = adnl.Message;
+```
+
+The blockchain fragments the complete boxed serialization of an `adnl.Message`, not only its application payload. Reassembly has these constraints:
+
+- The first accepted part has offset `0`.
+- Parts for a message arrive contiguously and in order.
+- Only one hash is assembled per peer at a time.
+- `total_size` does not exceed 8,192 bytes.
+- The final SHA-256 value equals `hash`.
+- The reassembled bytes parse as one boxed `adnl.Message`.
+
+### Custom, `adnl.message.custom`
+
+```tl
+adnl.message.custom data:bytes = adnl.Message;
+```
+
+`custom` delegates the payload to a subscribed higher-level protocol. RLDP uses custom messages because its transfer protocol does not follow a single-request, single-response exchange.
+
+### No-operation, `adnl.message.nop`
+
+```tl
+adnl.message.nop = adnl.Message;
+```
+
+`nop` carries no application data.
+
+### Reinitialization, `adnl.message.reinit`
+
+```tl
+adnl.message.reinit date:int = adnl.Message;
+```
+
+`reinit` asks the peer to adopt a newer session epoch — stale dates have no effect.
+
+## See also
+
+- [ADNL packet schema in the TON monorepo](https://github.com/ton-blockchain/ton/blob/v2026.06/tl/generate/scheme/ton_api.tl#L77-L119)
+- [UDP peer state machine in the TON monorepo](https://github.com/ton-blockchain/ton/blob/v2026.06/adnl/adnl-peer.cpp)
+- [ADNL overview](/foundations/network/adnl)
+- [ADNL over TCP](/foundations/network/adnl-tcp)
diff --git a/content/foundations/network/adnl.mdx b/content/foundations/network/adnl.mdx
new file mode 100644
index 000000000..d30f8f45e
--- /dev/null
+++ b/content/foundations/network/adnl.mdx
@@ -0,0 +1,61 @@
+---
+title: "Abstract Datagram Network Layer"
+sidebarTitle: "ADNL"
+---
+
+The Abstract Datagram Network Layer (ADNL) is the core networking protocol of the TON network. It is a peer-to-peer, unreliable datagram protocol that operates over both [UDP](https://en.wikipedia.org/wiki/User_Datagram_Protocol) and [TCP](https://en.wikipedia.org/wiki/Transmission_Control_Protocol).
+
+Higher-level protocols such as [Reliable Large Datagram Protocol (RLDP)](https://github.com/ton-blockchain/ton/tree/v2026.06/rldp2) and the [distributed hash table (DHT)](https://github.com/ton-blockchain/ton/tree/v2026.06/dht) are built on top of ADNL.
+
+## ADNL address
+
+Each participant in the network has a 256-bit ADNL address. ADNL allows sending and receiving [datagrams](https://en.wikipedia.org/wiki/Datagram) using only these addresses, hiding the underlying IP addresses and ports.
+
+An ADNL address is derived as:
+
+```text
+address = SHA-256(type_id || public_key)
+```
+
+The hash input is the complete boxed TL serialization of the public key, and the `type_id` is a `uint32` constructor ID serialized in little-endian order. For example, the Ed25519 public-key constructor has numeric ID `0x4813b4c6`, so its wire bytes are `c6 b4 13 48` followed by the 32-byte public key. The corresponding private key must be known to receive and decrypt messages sent to a given address.
+
+
+ ADNL generates, stores, and transmits Ed25519 keys over the network. For the [X25519 key agreement](https://en.wikipedia.org/wiki/Curve25519), TON internally converts the Ed25519 public key to a Montgomery public coordinate and derives an X25519 scalar from the Ed25519 private seed. Do not generate an unrelated X25519 key pair and relabel it as Ed25519.
+
+ - [Shared-secret implementation in the TON monorepo](https://github.com/ton-blockchain/ton/blob/v2026.06/crypto/Ed25519.cpp#L299-L370)
+ - [Conversion example in Kotlin](https://github.com/andreypfau/curve25519-kotlin/blob/f008dbc2c0ebc3ed6ca5d3251ffb7cf48edc91e2/src/commonMain/kotlin/curve25519/MontgomeryPoint.kt#L39)
+
+
+## Peer identity
+
+Each peer must have at least one identity. A peer may have multiple identities, but this is not required. Each identity consists of a key pair used for [Diffie-Hellman key exchange](https://en.wikipedia.org/wiki/Diffie%E2%80%93Hellman_key_exchange) between peers.
+
+## Neighbor tables
+
+A TON ADNL node maintains a neighbor table with information about known nodes, including their abstract addresses, public keys, IP addresses, and UDP ports. The node updates this table over time as it discovers new peers from query responses and removes outdated entries.
+
+Address lists can advertise IPv4 UDP, IPv6 UDP, ADNL tunnel, reverse-connectivity, and IPv4 QUIC endpoints. Each list also carries `version`, `reinit_date`, `priority`, and `expire_at` fields. The version fields let peers omit address lists that the receiver has already observed.
+
+## P2P protocol (ADNL over UDP)
+
+ADNL over UDP is used by TON nodes to communicate with each other. Communication begins simultaneously with the first data exchange: the initiator sends a create-channel message and the peer confirms creation. Encryption keys for the channel are derived through Elliptic-curve Diffie-Hellman (ECDH) from the peers' channel keys.
+
+UDP packets sent outside a channel are encrypted to the destination identity and signed by the source identity. After channel establishment, peers use directional symmetric keys and omit the per-packet signature.
+
+Sequence numbers suppress duplicate and old packets, while acknowledgments report the highest accepted sequence number. ADNL does not retransmit missing datagrams. Protocols that require reliable or larger transfers use a higher-level protocol such as [RLDP](https://github.com/ton-blockchain/ton/tree/v2026.06/rldp2).
+
+See [ADNL UDP](/foundations/network/adnl-udp) for channel establishment, packet structure, and message types.
+
+## Client-server protocol (ADNL over TCP)
+
+ADNL over TCP is used by clients to communicate with [liteservers](/nodes/overview). The client generates random AES-CTR session parameters and encrypts them to the server identity with a fresh ephemeral key. After the exchange, both sides use two AES-CTR cipher states to encrypt framed messages with SHA-256 integrity checks. The liteserver then authenticates the client's independently generated Ed25519 identity over the encrypted connection.
+
+See [ADNL TCP](/foundations/network/adnl-tcp) for the full handshake flow, packet structure, liteserver query examples, and security considerations.
+
+## See also
+
+- [ADNL implementation in TON monorepo](https://github.com/ton-blockchain/ton/tree/v2026.06/adnl)
+- [ADNL in The Open Network whitepaper](/foundations/whitepapers/ton/#3-1-abstract-datagram-network-layer)
diff --git a/content/foundations/network/meta.json b/content/foundations/network/meta.json
new file mode 100644
index 000000000..2057155fc
--- /dev/null
+++ b/content/foundations/network/meta.json
@@ -0,0 +1,9 @@
+{
+ "$schema": "../../../meta-schema.json",
+ "title": "Network protocols",
+ "pages": [
+ "adnl",
+ "adnl-tcp",
+ "adnl-udp"
+ ]
+}
diff --git a/docs.json b/docs.json
index adf33ac92..5079b8a27 100644
--- a/docs.json
+++ b/docs.json
@@ -695,12 +695,12 @@
},
{
"source": "/v3/documentation/network/protocols/adnl/overview",
- "destination": "https://old-docs.ton.org/v3/documentation/network/protocols/adnl/overview",
+ "destination": "/foundations/network/adnl",
"permanent": true
},
{
"source": "/v3/documentation/network/protocols/adnl/low-level",
- "destination": "https://old-docs.ton.org/v3/documentation/network/protocols/adnl/low-level",
+ "destination": "/foundations/network/adnl",
"permanent": true
},
{
@@ -725,17 +725,17 @@
},
{
"source": "/learn/overviews/adnl",
- "destination": "https://old-docs.ton.org/learn/overviews/adnl",
+ "destination": "/foundations/network/adnl",
"permanent": true
},
{
"source": "/v3/documentation/network/protocols/adnl/tcp",
- "destination": "https://old-docs.ton.org/v3/documentation/network/protocols/adnl/tcp",
+ "destination": "/foundations/network/adnl-tcp",
"permanent": true
},
{
"source": "/v3/documentation/network/protocols/adnl/udp",
- "destination": "https://old-docs.ton.org/v3/documentation/network/protocols/adnl/udp",
+ "destination": "/foundations/network/adnl-udp",
"permanent": true
},
{
@@ -1205,7 +1205,7 @@
},
{
"source": "/v3/guidelines/dapps/apis-sdks/ton-adnl-apis",
- "destination": "https://old-docs.ton.org/v3/guidelines/dapps/apis-sdks/ton-adnl-apis",
+ "destination": "/api/overview",
"permanent": true
},
{
@@ -2215,22 +2215,22 @@
},
{
"source": "/learn/networking/adnl",
- "destination": "https://old-docs.ton.org/v3/documentation/network/protocols/adnl/overview",
+ "destination": "/foundations/network/adnl",
"permanent": true
},
{
"source": "/learn/networking/low-level-adnl",
- "destination": "https://old-docs.ton.org/v3/documentation/network/protocols/adnl/low-level",
+ "destination": "/foundations/network/adnl",
"permanent": true
},
{
"source": "/develop/network/adnl-tcp",
- "destination": "https://old-docs.ton.org/v3/documentation/network/protocols/adnl/tcp",
+ "destination": "/foundations/network/adnl-tcp",
"permanent": true
},
{
"source": "/develop/network/adnl-udp",
- "destination": "https://old-docs.ton.org/v3/documentation/network/protocols/adnl/udp",
+ "destination": "/foundations/network/adnl-udp",
"permanent": true
},
{
@@ -2620,17 +2620,17 @@
},
{
"source": "/v3/documentation/network/protocols/adnl/low-level-adnl",
- "destination": "https://old-docs.ton.org/v3/documentation/network/protocols/adnl/low-level",
+ "destination": "/foundations/network/adnl",
"permanent": true
},
{
"source": "/v3/documentation/network/protocols/adnl/adnl-tcp",
- "destination": "https://old-docs.ton.org/v3/documentation/network/protocols/adnl/tcp",
+ "destination": "/foundations/network/adnl-tcp",
"permanent": true
},
{
"source": "/v3/documentation/network/protocols/adnl/adnl-udp",
- "destination": "https://old-docs.ton.org/v3/documentation/network/protocols/adnl/udp",
+ "destination": "/foundations/network/adnl-udp",
"permanent": true
},
{
diff --git a/src/dictionaries/two-letter-words-ban.txt b/src/dictionaries/two-letter-words-ban.txt
index 1b2dbd4cb..2839d30b1 100644
--- a/src/dictionaries/two-letter-words-ban.txt
+++ b/src/dictionaries/two-letter-words-ban.txt
@@ -1052,7 +1052,6 @@
!lD
!le
!Le
-!LE
!lE
!lf
!Lf