DEV Community

Cover image for How to Connect TON Connect to a STON.fi dApp

How to Connect TON Connect to a STON.fi dApp

A practical React integration that connects a TON wallet, reads the wallet state, builds a STON.fi swap, and hands the transaction back to the wallet for approval.

Connecting TON Connect to a STON.fi dApp means giving your application a standard way to discover the user's TON wallet, read the connected address, and request transaction signatures without ever handling the user's private keys.

For a STON.fi swap interface, the flow is straightforward: TON Connect manages the wallet session, the STON.fi API simulates the swap, the STON.fi SDK builds the contract message, and TON Connect asks the wallet to sign and broadcast it. The dApp coordinates these pieces, but the wallet remains the signing authority throughout the process.

What TON Connect actually does in a STON.fi dApp

How integration works on STON.fi

It helps to separate wallet connectivity from DEX logic.

STON.fi does not need your application to obtain a seed phrase or private key. Instead, TON Connect creates a communication layer between the dApp and a compatible wallet. After the person chooses a wallet and approves the connection, your frontend receives account information that can be used when preparing STON.fi transactions.

A typical integration has four responsibilities:

  • TON Connect manages connection, reconnection, wallet selection, and transaction requests.
  • STON.fi API supplies current asset and swap simulation information.
  • STON.fi SDK converts swap parameters into contract transaction data.
  • The wallet reviews, signs, and broadcasts the transaction.

The official STON.fi React quickstart uses exactly this division of responsibilities, combining @tonconnect/ui-react, @ston-fi/api, and @ston-fi/sdk.

The wallet connection therefore does not perform a swap by itself. It gives your STON.fi integration the address and signing channel needed to perform one.

Set up the React dependencies

Set up the React dependencies on STON.fi

For a React dApp, install the TON Connect React package together with the STON.fi SDK and API client.

npm install @tonconnect/ui-react @ston-fi/sdk @ston-fi/api
Enter fullscreen mode Exit fullscreen mode

Depending on the rest of your application, you may also use TON libraries for blockchain utilities and amount conversion.

The important architectural point is to keep the responsibilities separate. Avoid implementing wallet-specific connection code for Tonkeeper, MyTonWallet, or other individual wallets when TON Connect already provides a common interface.

The official TON documentation describes @tonconnect/ui-react as the React binding around TON Connect UI. It provides the application provider, the standard wallet button, and hooks for accessing the connection and wallet state.

Create the TON Connect manifest first

Every TON Connect dApp needs a manifest that tells wallets which application is requesting the connection.

Create:

public/tonconnect-manifest.json
Enter fullscreen mode Exit fullscreen mode

A minimal version looks like this:

{
  "url": "https://your-dapp.example",
  "name": "My STON.fi dApp",
  "iconUrl": "https://your-dapp.example/icon-180.png"
}
Enter fullscreen mode Exit fullscreen mode

You can also provide privacy policy and terms URLs when appropriate.

The manifest is not just decoration. Wallets fetch it to identify your application before presenting the connection request. The URL and icon should therefore point to real public resources when you deploy the dApp.

Before debugging your React code, open the manifest URL directly in a browser:

https://your-dapp.example/tonconnect-manifest.json
Enter fullscreen mode Exit fullscreen mode

If it cannot be fetched there, a wallet may not be able to fetch it either.

A useful deployment checklist is:

  • Serve the manifest over HTTPS in production.
  • Use your real dApp domain.
  • Make the icon publicly accessible.
  • Keep the application name recognizable.
  • Do not copy another project's manifest unchanged.

For local development, STON.fi's React guide demonstrates serving the manifest from the application's public directory and pointing the provider at the current origin.

Add TON Connect to the React component tree

Add TON connect to React on STON.fi

The next step is to wrap the application in TonConnectUIProvider.

For a Vite-based React project, your entry file can look like this:

import React from "react";
import ReactDOM from "react-dom/client";
import { TonConnectUIProvider } from "@tonconnect/ui-react";
import App from "./App";

ReactDOM.createRoot(document.getElementById("root")!).render(
  <React.StrictMode>
    <TonConnectUIProvider
      manifestUrl={`${window.location.origin}/tonconnect-manifest.json`}
    >
      <App />
    </TonConnectUIProvider>
  </React.StrictMode>
);
Enter fullscreen mode Exit fullscreen mode

Everything that calls TON Connect React hooks must be rendered beneath this provider.

You can then add the standard connection button:

import { TonConnectButton } from "@tonconnect/ui-react";

export function Header() {
  return (
    <header>
      <TonConnectButton />
    </header>
  );
}
Enter fullscreen mode Exit fullscreen mode

Clicking it opens the TON Connect wallet picker. After a successful connection, the same component reflects the connected state automatically.

You can build your own button and call openModal() if your design requires a custom interface, but starting with TonConnectButton removes unnecessary connection logic while you build the rest of the STON.fi integration.

Read the connected wallet correctly

Read the wallet state on STON.fi correctly

A STON.fi swap needs the connected wallet address because that address becomes part of the transaction parameters.

TON Connect exposes it through hooks:

import {
  useIsConnectionRestored,
  useTonAddress,
  useTonWallet
} from "@tonconnect/ui-react";

export function WalletStatus() {
  const restored = useIsConnectionRestored();
  const wallet = useTonWallet();
  const address = useTonAddress();

  if (!restored) {
    return <p>Restoring wallet connection...</p>;
  }

  if (!wallet) {
    return <p>Connect a wallet to continue.</p>;
  }

  return <p>Connected: {address}</p>;
}
Enter fullscreen mode Exit fullscreen mode

useIsConnectionRestored() deserves special attention. TON Connect attempts to restore an existing session when the application loads. Until that process finishes, a missing wallet does not necessarily mean that the person is disconnected. Redirecting or disabling your interface too early can create a visible connection flicker or incorrect state. TON's documentation specifically recommends waiting for restoration before making that decision.

For your swap interface, that gives you a simple state model:

  1. Connection state is still being restored.
  2. No wallet is connected.
  3. A wallet is connected and the swap interface can use its address.

Do not confuse wallet connection with authentication. If your backend needs cryptographic proof that a person controls an address, TON Connect also supports ton_proof. A plain connected address is useful for transaction construction, but it should not automatically become a trusted login credential for a sensitive backend session.

Connect the wallet state to a STON.fi swap

Build and send a swap on STON.fi

Now the two systems meet.

For production STON.fi swaps, the current v2 documentation recommends an API-driven approach rather than hardcoding a router address. Your dApp first simulates the swap, receives router metadata, creates the matching SDK contracts, and then builds the transaction parameters.

Conceptually, the flow is:

Connected wallet
      |
      v
STON.fi swap simulation
      |
      v
Router metadata
      |
      v
STON.fi SDK builds transaction
      |
      v
TON Connect sendTransaction()
      |
      v
Wallet approval
      |
      v
TON blockchain
Enter fullscreen mode Exit fullscreen mode

Here is a focused example for a TON-to-jetton swap:

import { useTonAddress, useTonConnectUI } from "@tonconnect/ui-react";
import { StonApiClient } from "@ston-fi/api";
import { Client, dexFactory, toUnits } from "@ston-fi/sdk";

const stonApi = new StonApiClient();

const tonClient = new Client({
  endpoint: "https://toncenter.com/api/v2/jsonRPC"
});

export function SwapButton() {
  const userAddress = useTonAddress();
  const [tonConnectUI] = useTonConnectUI();

  const swap = async () => {
    if (!userAddress) {
      throw new Error("Connect a wallet first");
    }

    const simulation = await stonApi.simulateSwap({
      offerAddress: "ton",
      askAddress: "<jetton-master-address>",
      offerUnits: toUnits("1", 9).toString(),
      slippageTolerance: "0.01"
    });

    const routerInfo = simulation.router;
    const dexContracts = dexFactory(routerInfo);

    const router = tonClient.open(
      dexContracts.Router.create(routerInfo.address)
    );

    const proxyTon = dexContracts.pTON.create(
      routerInfo.ptonMasterAddress
    );

    const txParams = await router.getSwapTonToJettonTxParams({
      userWalletAddress: userAddress,
      offerAmount: simulation.offerUnits,
      askJettonAddress: simulation.askAddress,
      minAskAmount: simulation.minAskUnits,
      proxyTon,
      queryId: BigInt(Date.now())
    });

    await tonConnectUI.sendTransaction({
      validUntil: Math.floor(Date.now() / 1000) + 300,
      network: "-239",
      messages: [
        {
          address: txParams.to.toString(),
          amount: txParams.value.toString(),
          payload: txParams.body?.toBoc().toString("base64")
        }
      ]
    });
  };

  return (
    <button disabled={!userAddress} onClick={swap}>
      Swap with STON.fi
    </button>
  );
}
Enter fullscreen mode Exit fullscreen mode

The exact token addresses and input amounts should come from your interface rather than hardcoded production values.

The current STON.fi v2 guidance is especially important here: the REST API returns router information with the simulation result, and dexFactory() lets the SDK construct contracts appropriate for that router. This avoids making your integration depend on one manually selected production router.

What happens when sendTransaction() runs?

The STON.fi SDK does not need to sign anything.

Its job is to produce parameters such as the destination address, attached TON value, and serialized payload. Your code converts those values into a TON Connect transaction request.

TON Connect then presents that request to the wallet.

For raw transaction messages, the important fields are:

Field Purpose
address Contract or wallet receiving the message
amount TON value attached in the smallest unit
payload Base64 encoded contract message body
validUntil Unix timestamp after which the request is invalid
network TON network expected by the dApp

According to the current TON Connect transaction specification, validUntil uses Unix seconds. For mainnet, the network identifier is -239; testnet uses -3. TON also recommends specifying the network explicitly so a request is rejected if the connected wallet is on a different network.

When the wallet approves the request, it signs and broadcasts the transaction. Your frontend never receives the private key.

That boundary is one of the most important design principles in the integration:

STON.fi prepares the DEX action. TON Connect transports the signing request. The wallet authorizes it.

Avoid the integration mistakes that cause most problems

The basic connection takes only a small amount of code. Most problems appear around state management, transaction construction, or assumptions about the network.

Before shipping, check these areas.

Do not hardcode production routing when the STON.fi API can provide it. Current STON.fi v2 documentation recommends simulating first and using the router object returned by the API with dexFactory().

Do not treat a stale simulation as a guaranteed execution price. Pool conditions can change between simulation and wallet confirmation. Use the minimum output calculated for the swap and refresh quotes when appropriate.

Do not mix milliseconds and Unix seconds in validUntil. The current TON Connect request format expects seconds.

Do not enable the swap while the wallet state is unresolved. Wait for connection restoration and require an address before generating transaction parameters.

Do not manually ask for a seed phrase. A normal TON Connect integration has no reason to request one.

Do not assume sendTransaction() means the complete swap succeeded. It means the wallet accepted the request and broadcast the signed message. Your interface should separately track the resulting on-chain execution if it needs a final success state.

There is another TON-specific detail worth remembering. Smart contract interactions can involve multiple messages, and execution across recipient contracts is not automatically equivalent to one atomic operation. STON.fi documentation also describes refund behavior for swaps when execution conditions are not satisfied.

For a production interface, show transaction states such as submitted, processing, completed, and failed instead of changing the button directly from "Swap" to "Success" as soon as the wallet returns.

A practical STON.fi integration checklist

STON.fi integration checklist

At this point, you can test the entire connection as one continuous workflow.

  1. Load the dApp and wait for TON Connect session restoration.
  2. Connect a compatible TON wallet.
  3. Confirm that your application receives the correct address.
  4. Select a source asset, destination asset, and amount.
  5. Request a fresh STON.fi swap simulation.
  6. Review the expected output and minimum output in your interface.
  7. Build the matching transaction through the STON.fi SDK.
  8. Pass the resulting message to tonConnectUI.sendTransaction().
  9. Review the transaction inside the wallet before signing.
  10. Track the resulting blockchain operation rather than relying only on the frontend request state.

STON.fi's official developer documentation recommends using its SDK together with TON Connect for production application interaction instead of manually constructing low-level contract BOCs unless you have a specialized reason to do so.

The practical takeaway is simple: keep wallet connection, quote generation, transaction construction, and transaction signing as separate layers. Once those boundaries are clear, TON Connect becomes a small but critical bridge between your STON.fi frontend and the wallet that actually authorizes the swap.

Frequently Asked Questions

Does STON.fi require TON Connect?

A frontend can interact with TON contracts through other technical signing setups, but TON Connect is the standard wallet connection approach for user-facing TON dApps. STON.fi's own React swap quickstart integrates @tonconnect/ui-react with the STON.fi API and SDK, making it the natural approach for a browser-based application where users sign transactions with their own wallets.

Does TON Connect give my dApp the user's private key?

No. TON Connect creates a connection with the wallet and lets the dApp submit signing requests. The private key remains under the wallet's control. Your application receives account information and transaction responses, not the seed phrase or private signing key. A dApp asking users to enter their seed phrase is not following the normal TON Connect model.

Do I need a tonconnect-manifest.json file?

Yes. The manifest identifies your dApp to compatible wallets and includes information such as the application URL, name, and icon. Host it at a publicly accessible URL and pass that URL to TonConnectUIProvider. Optional fields can also point to your terms of use and privacy policy.

Should I use useTonAddress() or useTonWallet()?

Use whichever matches the information you need. A STON.fi transaction often needs the connected address, so useTonAddress() is convenient. useTonWallet() gives you the broader connected wallet object. It is also useful to combine them with useIsConnectionRestored() so your interface does not mistake an unfinished restoration attempt for a disconnected wallet.

Is connecting a wallet the same as authenticating a user?

No. A wallet connection gives your frontend an account and a communication session. If you need secure backend authentication, TON Connect supports ton_proof, where the wallet signs proof data that your server verifies. You generally do not need to introduce backend authentication merely to let a connected wallet review and sign a normal STON.fi transaction.

Why should a STON.fi dApp simulate the swap before building the transaction?

Simulation gives your application current execution information, including expected amounts, minimum output, and router metadata. Current STON.fi v2 documentation recommends an API-driven production flow in which the simulation result determines the router passed to dexFactory(). That is safer for maintainability than tying the integration permanently to one hardcoded router address.

Can I use the STON.fi REST API for testnet swaps?

The current STON.fi v2 SDK documentation states that the REST API at api.ston.fi serves mainnet data. You can test TON Connect itself and lower-level contract integrations separately, but do not assume the production API-driven STON.fi simulation flow automatically maps to testnet. Follow the specific STON.fi testnet documentation when testing contract operations there.

What should I verify before letting someone sign a STON.fi swap?

Check that the wallet is connected, the simulation is fresh, the source and destination assets are correct, the amount uses the correct token decimals, the minimum output reflects the intended slippage tolerance, and the transaction is being sent on the expected network. Then let the wallet provide the final approval step instead of attempting to sign anything inside your frontend.

Sources and Further Reading

  • TON Connect, Get started - Official introduction to manifests and TON Connect integration paths
  • TON Connect, Connect a wallet - Official documentation for the provider, wallet button, connection restoration, wallet state, and ton_proof
  • TON Connect, Send a transaction - Official request format for sendTransaction(), including validUntil, network selection, and raw messages
  • TON Connect React API - Reference for TonConnectUIProvider, TonConnectButton, useTonConnectUI, useTonAddress, and wallet hooks
  • STON.fi Swap Guide (React) - Official end-to-end example combining TON Connect, the STON.fi API, and the STON.fi SDK
  • STON.fi SDK v2 Swap - Official production guidance for simulation, dynamic router selection, dexFactory(), and v2 swap construction
  • STON.fi SDK - Overview of the TypeScript and JavaScript SDK and current DEX contract integration tools
  • STON.fi REST API Reference - Official API overview covering swap simulation, swap status, pools, assets, and related DEX data
  • STON.fi DEX v2 Smart Contracts - Contract-level documentation and the recommendation to use the official SDK with TON Connect for production application integrations

Top comments (1)

Collapse
 
ivan_cryptovazimazima profile image
Ivan “Crypto Vazima” Zimanov

Hello! If you find an error in the text, please point it out in the comments to help others who encounter the same problem! Thank you in advance for your help and support!