> ## Documentation Index
> Fetch the complete documentation index at: https://companyname-a7d5b98e-cex-integration-docs.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# How to integrate TON into a Centralized Exchange (CEX)

This guide walks you through integrating Toncoin (TON) into your centralized exchange infrastructure. You’ll learn how to:

* Create and fund a testnet wallet
* Deploy and sync a liteserver node
* Connect SDKs to your own node and Toncenter API
* Simulate trace flows and handle deposit or withdrawal logic
* Monitor transaction finality and infrastructure health

This guide is designed for backend engineers working on CEX infrastructure from MVP integration to production readiness.

## Prerequisites

Before starting the integration process, make sure your environment meets the following:

### System requirements

* macOS, Linux, or WSL (Windows Subsystem for Linux)
* Git and curl installed
* Telegram account (used for faucet access)

### Node hardware requirements

* **CPU:** 16 cores minimum
* **RAM:** 128 GB
* **Storage:** 1 TB+ NVMe SSD (64,000+ IOPS)
* **Bandwidth:** 1 Gbps, 16 TB monthly traffic budget
* **Network:** Static public IP address

### Provider requirements

For production, use self-hosted or dedicated bare-metal servers. If using cloud, choose from the [recommended providers](https://docs.ton.org/v3/guidelines/nodes/running-nodes/full-node#recommended-providers) list and ensure consistent IOPS, high throughput, and a fixed public IP.

## Hot wallet setup

Before integrating TON into your backend, you’ll need a hot wallet to run test transactions.

A *hot wallet* is a cryptocurrency wallet that stays connected to the internet, enabling fast transactions. This differs from a *cold wallet*, which remains offline for long-term storage and maximum security. There are different ways to create hot wallets in TON, and you can choose any method that fits your workflow, but for simplicity, we will use **Tonkeeper**.

<Note>Testnet wallets should only be used for development. For production, switch to mainnet to ensure accurate fee calculation, transaction finality, and live trace verification.</Note>

### Create wallet with Tonkeeper

Tonkeeper is a widely used TON mobile wallet that allows you to create a working address in minutes, which you can later import into your SDK for automated testing.

To use Tonkeeper:

1. Download the [Tonkeeper mobile app](https://tonkeeper.com/).
2. Go to **Settings → Wallets → Add Wallet → Testnet Account**.
3. Save the 24-word seed phrase securely and copy the generated wallet address.

Your TON wallet address can be represented in two formats:

* **Base64 address** – A user-friendly, encoded version designed for readability and safety.
  This format includes a checksum to help prevent errors when copying or sending funds. <br />
  **Example (Base64):** `UQBlXWdp1eP7W8RGeaH4vM86Y/8rT1hY+7XfF1t4dKQ=`

* **Raw HEX address** – The low-level representation containing the workchain ID and account ID.
  This is the direct blockchain reference to your wallet’s smart contract and is used in technical or SDK-based operations. <br />
  **Example (Raw HEX):** `-1:fcb91a3a3816d0f7b8c2c76108b8a9bc5a6b7a55bd79f8ab101c52db29232260`

You can use the [TON Address Tool](https://ton.org/address) to convert between formats and view mainnet or testnet variations.

### Request testnet Toncoin

Every transaction on TON requires a small amount of Toncoin to cover **network gas** and **forwarding fees**.
Before you can test deposits, withdrawals, or fee estimation, you’ll need to fund your hot wallet with testnet TON.

There are two main ways to do this:

#### Option A – Request from TON team (Recommended)

For CEX integration testing, the most reliable method is to request Testnet funds directly from the [TON Support team on Telegram](https://t.me/tonblockchain).
This way, you’ll have enough balance to run tests continuously without frequent top-ups.

#### Option B – Telegram faucet (Quick Start)

If you only need a small amount for initial or manual testing, use the public faucet:

1. Open Telegram and start the [`@test_giver_ton_bot`](https://t.me/test_giver_ton_bot).
2. Paste your testnet wallet address. The bot will send **2 TON** to your address.

<Warning>You can only request once per hour. For repeated or automated testing, use <b>Option A</b> to get a larger Testnet allocation and avoid interruptions.</Warning>

### Verify balance via explorer

After requesting TON, confirm that your wallet has been funded by using one of these official testnet explorers:

* [Tonviewer (testnet)](https://testnet.tonviewer.com)
* [Tonscan (testnet)](https://testnet.tonscan.org)

Paste your wallet address into the search bar. You should see:

* **Balance:** `2 TON` (or more, if you’ve made repeated requests)
* **Address:** (your wallet address)
* **State:** `uninit` or `inactive`

<Note>If you see `nonexist`, it means the balance of the account is 0 or the contract does not have any data.</Note>

## Core infrastructure: nodes and indexers

To support deposits and withdrawals on TON, your exchange backend needs reliable access to both **read blockchain state** (balances, account status, confirmations) and **write transactions** (relaying signed deposits, withdrawals, or contract calls). This requires running a **node with liteserver enabled**.

### Node modes

A node can operate in two modes:

| Mode             | Description                                                                                                        | Suitable for                                                                            | Limitations                                                                                                  | Example Use Case                                                                                                       |
| ---------------- | ------------------------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------- |
| **Non-archival** | Keeps only recent blockchain state; older history is pruned automatically.                                         | Everyday deposit and withdrawal processing where only the latest account state matters. | Cannot retrieve or verify old transactions. History beyond the retention window is unavailable.              | Verifying a user deposit made in the last few blocks before crediting their balance.                                   |
| **Archival**     | Stores the full blockchain history. Can optionally use TTL/expiry settings to limit how long old data is retained. | Compliance, audits, dispute resolution, or reconstructing account history months later. | Higher storage and infrastructure requirements. If TTL is configured, very old history may still be dropped. | A regulator requests proof of deposits from one year ago, or a customer disputes a withdrawal made six months earlier. |

<Tip>
  For production exchanges, an **archival node** is strongly preferred. It ensures access to the full transaction history, which is critical for compliance and customer support. Non-archival nodes can serve lightweight setups but impose strict limits on historical queries.
</Tip>

### Deployment options

You can provision a node in two ways:

* **Run your own node** : Install MyTonCtrl in archival or non-archival mode on dedicated infrastructure. Provides full control over synchronization, networking, and security policies.
* **Rent a dedicated node** : Providers such as TON Center offer fully configured archival and non-archival nodes. This removes operational overhead while still giving you API access to the blockchain.

### API layers

Nodes expose a liteserver endpoint, but it uses a low-level binary protocol that is not practical for exchange integration. Instead, TON Center APIs provide higher-level, developer-friendly access:

* **v2 API** : Real-time account state and transaction submission over HTTP/JSON. Optimized for deposit and withdrawal flows where balances and finality must be verified quickly.
* **v3 API** : Indexed blockchain history (transactions, traces, receipts) powered by the TON Indexer and PostgreSQL. Essential for large-scale queries, compliance reporting, and customer dispute resolution.

<Info>
  **Best Practice**

  * Use **v2** for operational flows (deposits, withdrawals, balance checks).
  * Use **v3** for historical data, compliance, and large-scale reporting.
  * Cross-check critical fields (e.g. transaction hash, block height, finality) across both APIs to combine cryptographic trust with query efficiency.
</Info>

## Install archival node with liteserver

Follow these steps to install and configure an archival node with liteserver using MyTonCtrl.

### Step 1 - Prepare storage (ZFS)

1. Install ZFS:

```shell theme={null}
sudo apt install zfsutils-linux
```

2. Create a pool on your dedicated `<disk>` named `data`:

```shell theme={null}
sudo zpool create data <disk>
```

3. Enable compression:

```shell theme={null}
sudo zfs set compression=lz4 data
```

4. Create a dataset and mount it at `/var/ton-work`:

```shell theme={null}
sudo zfs create data/ton-work
sudo zfs set mountpoint=/var/ton-work data/ton-work
```

### Step 2 - Install MyTonCtrl

Download and run the installer:

```bash theme={null}
wget https://raw.githubusercontent.com/ton-blockchain/mytonctrl/master/scripts/install.sh
sudo bash install.sh
```

During setup:

* Select **`liteserver`** mode and choose the network.
* When prompted `Do you want to download archive blocks via TON Storage?`, enter **`1`** to set up an **archive node**.
* Run installation **in the background** when asked, as archive sync can take several days.

### Step 3 - Run and sync

After installation, the node will download and import all blocks. This may take **weeks** depending on hardware.

### Step 4 - Verify sync status

Check synchronization with MyTonCtrl:

```bash theme={null}
mytonctrl
MyTonCtrl> last
```

Example output:

```txt theme={null}
last_masterchain_block: (seqno: 20498563)
peers: 7
is_working: true
```

There,

* `last_masterchain_block`: latest block your node has synced
* `peers`: number of connected nodes (ideally >3)
* `is_working`: confirms the node is actively syncing

To confirm the node isn’t lagging, compare block height against a public explorer:

* [Tonviewer (testnet)](https://testnet.tonviewer.com)
* [Tonscan (testnet)](https://testnet.tonscan.org)

If your node is within 1–2 blocks, it’s considered healthy.

#### Optional — Cross-check with Toncenter API

You can also verify your node’s sync against Toncenter’s v3 API:

* Endpoint: `/api/v3/masterchainInfo`
* Swagger UI: [Toncenter API v3](https://toncenter.com/api/v3/index.html#/blockchain/api_v3_get_masterchain_info)

Example response:

```json theme={null}
{
  "last": {
    "seqno": 20498563,
    "shard": "-9223372036854775808",
    "workchain": -1
  }
}
```

<Info>
  If `peers = 0` or `is_working = false`, check that the correct ports are open, the `-d` flag was used during install, and your server has a static IP with stable internet.
</Info>

## Step 6 - Connect SDKs to your liteserver

Once your node is running and synced, you can connect to it using SDKs in your backend. This allows you to:

* Query account states
* Track transactions
* Fetch traces

### Generate your config file

Inside the MyTonCtrl CLI, run:

```txt theme={null}
MyTonCtrl> clcf
```

This generates a config file at:
`/usr/bin/ton/local.config.json`

Copy this file into your project directory (or rename it to `config.json`).

### Per-language SDK setup

<AccordionGroup>
  <Accordion title="Golang (tonutils-go)">
    ```bash theme={null}
    go get github.com/xssnick/tonutils-go
    go get github.com/xssnick/tonutils-go/lite
    go get github.com/xssnick/tonutils-go/ton
    ```

    ```go theme={null}
    package main

    import (
        "context"
        "encoding/json"
        "io/ioutil"
        "log"

        "github.com/xssnick/tonutils-go/liteclient"
        "github.com/xssnick/tonutils-go/ton"
    )

    func main() {
        client := liteclient.NewConnectionPool()

        // Load config
        content, err := ioutil.ReadFile("./config.json")
        if err != nil {
            log.Fatal("Failed to open config:", err)
        }

        var config liteclient.GlobalConfig
        if err := json.Unmarshal(content, &config); err != nil {
            log.Fatal("Failed to parse config:", err)
        }

        // Connect to node
        if err := client.AddConnectionsFromConfig(context.Background(), &config); err != nil {
            log.Fatal("Connection failed:", err)
        }

        api := ton.NewAPIClient(client)

        master, err := api.GetMasterchainInfo(context.Background())
        if err != nil {
            log.Fatal("Masterchain query failed:", err)
        }

        log.Println("Masterchain info:", master)
    }
    ```
  </Accordion>

  <Accordion title="Python (pytoniq)">
    ```bash theme={null}
    pip install pytonlib
    ```

    ```python theme={null}
    from pytoniq import LiteClient

    async def main():
        # Choose testnet or load custom config
        client = LiteClient.from_mainnet_config(
            ls_i=0,
            trust_level=2,
            timeout=15
        )

        await client.connect()
        info = await client.get_masterchain_info()
        print(info)
        await client.close()

    # You can also use a context manager:
    # async with LiteClient.from_mainnet_config(...) as client:
    #     await client.get_masterchain_info()

    # To connect to your own config:
    # client = await LiteClient.from_file("config.json")
    ```
  </Accordion>

  <Accordion title="JavaScript (ton-lite-client)">
    ```bash theme={null}
    npm install ton-core ton-lite-client
    ```

    ```js theme={null}
    import { LiteSingleEngine } from 'ton-lite-client/dist/engines/single.js'
    import { LiteRoundRobinEngine } from 'ton-lite-client/dist/engines/roundRobin.js'
    import { Lite } from 'ton-lite-client/dist/index.js'
    import config from './config.json' assert {type: 'json'}

    function intToIP(int) {
        return [
            (int >> 24) & 255,
            (int >> 16) & 255,
            (int >> 8) & 255,
            int & 255
        ].join(".");
    }

    const server = config.liteservers[0];

    async function main() {
        const engine = new LiteRoundRobinEngine([
            new LiteSingleEngine({
                host: `tcp://${intToIP(server.ip)}:${server.port}`,
                publicKey: Buffer.from(server.id.key, 'base64'),
            }),
        ]);

        const client = new Lite({ engine });
        const master = await client.getMasterchainInfo();
        console.log("Masterchain info:", master);
    }

    main();
    ```
  </Accordion>
</AccordionGroup>

You’re now connected. Your backend is querying live data from your own node’s liteserver. This gives you full control over how and when data is fetched.
