Browser + TonConnect
End-to-end integration of chop into a React dapp using the official TonConnect kit. Twenty lines of glue code; no backend required on your side.
Install
npm install @tonconnect/ui-react1. Add a manifest
TonConnect needs a manifest at a public URL describing your app. Drop this in public/tonconnect-manifest.json on your dapp:
{
"url": "https://your-dapp.com",
"name": "Your dapp name",
"iconUrl": "https://your-dapp.com/logo.png"
}2. Wrap your app
import { TonConnectUIProvider } from '@tonconnect/ui-react';
export default function RootLayout({ children }) {
return (
<html>
<body>
<TonConnectUIProvider
manifestUrl="https://your-dapp.com/tonconnect-manifest.json"
>
{children}
</TonConnectUIProvider>
</body>
</html>
);
}3. Connect button + swap call
'use client';
import {
TonConnectButton,
useTonAddress,
useTonConnectUI,
} from '@tonconnect/ui-react';
export function Swap() {
const address = useTonAddress();
const [tonConnectUI] = useTonConnectUI();
async function swap() {
if (!address) {
tonConnectUI.openModal();
return;
}
const res = await fetch('https://chop.ag/api/v1/tx', {
method: 'POST',
headers: { 'content-type': 'application/json' },
body: JSON.stringify({
assetIn: 'TON',
assetOut: 'EQCxE6mUtQJKFnGfaROTKOt1lZbDiiX1kCixRv7Nw2Id_sDs',
amountIn: '1000000000', // 1 TON
slippageBps: 100,
userAddress: address,
}),
}).then((r) => r.json());
await tonConnectUI.sendTransaction(res.tonConnect);
}
return (
<>
<TonConnectButton />
<button onClick={swap}>Swap 1 TON for USDT</button>
</>
);
}Quote-then-build
For a polished swap UI, hit /v1/quote on debounced input changes to render a live preview, then call /v1/tx only when the user clicks Swap. The TX endpoint re-quotes internally, so the slippage limits will be fresh:
// On amount/token change (debounced ~300ms):
const { quotes, bestRoute } = await api.quote({ assetIn, assetOut, amountIn });
// On click:
const tx = await api.tx({ assetIn, assetOut, amountIn, userAddress });
await tonConnectUI.sendTransaction(tx.tonConnect);Error handling
sendTransaction throws if the user cancels the wallet’s signing modal, or if the wallet rejects (insufficient balance, etc.). Wrap in try/catch and show a friendly message — the user is always one click away from the wallet sheet.
try {
await tonConnectUI.sendTransaction(tx.tonConnect);
} catch (err) {
if (err.code === 300) /* user rejected */ return;
toast.error('Swap failed: ' + err.message);
}Verifying success
TonConnect resolves as soon as the wallet broadcasts — not when the swap settles. To know the user actually received output, poll their Jetton wallet balance after ~10 seconds and look for the delta. The chop API does not currently return a transaction hash; that’s on the wallet.
For the alternative server-side broadcast flow, see Server-side wallet.