ton-connect/kit/ton-appkit
Claude Code and agent skill by ton-connect/kit
- community
Checking that the SKILL.md file is still in the repository.
Use this skill whenever the user is building an app with @ton/appkit or @ton/appkit-react as a library consumer: setup, TonConnect wallet connection, balances, sending TON/jettons/NFTs, swaps, staking, signing, real-time WebSocket updates, cache invalidation, mainnet/testnet switching, SSR/Next.js hydration, Telegram Mini App returns, iOS deep links, or debugging stale wallet/network/transaction behavior. Do not use for contributing code to the @ton/kit monorepo itself; use kit-dev for repo-internal development tasks.
Install
npx vskill@latest install ton-connect/kit/ton-appkitSKILL.md
AppKit Guide
Guide developers consuming @ton/appkit + @ton/appkit-react in their TON apps. Assume React, TypeScript, and TanStack Query basics, but explain TON/AppKit-specific decisions clearly.
For contributing to the @ton/kit monorepo, use kit-dev instead. This skill is for library-consumer answers: code the user's app would write, not package internals.
Response workflow
- Classify the task first. If the user wants a complete feature quickly, prefer drop-in components. If they describe custom UX, use hooks. If they report stale data, real-time, network, or SSR symptoms, start with the relevant gotcha before writing code.
- Give runnable integration shape. Include provider setup when the bug could come from missing
QueryClientProvider,AppKitProvider, connector config, CSS import, or streaming providers. Avoid isolated hook snippets that omit required context. - Use AppKit semantics exactly. Balances are already-formatted decimal strings (TON or jetton units — never raw nano), transfer amounts are human-readable strings, mutations do not automatically invalidate caches, streaming is opt-in, and wallet state is client-only for SSR.
- Name the tradeoff. Drop-in components are fastest and safest; hooks are for custom UX and require explicit loading/error/cache handling.
What do you want to do?
| Task | Path | |
|---|---|---|
| Set up a new app | pnpm create ton-appkit (scaffolds React+Vite project) or Quick Setup below | |
| Wallet connect/disconnect | <TonConnectButton /> or useConnect/useDisconnect | |
| Show TON balance | useBalance() + optionally useWatchBalance() for live updates | |
| Send TON | <SendTonButton /> or useTransferTon() | |
| Send jettons (USDT, etc.) | <SendJettonButton /> or useTransferJetton() | |
| Show NFTs | useNfts() + <NftItem /> | |
| Swap tokens | <SwapWidget /> or useSwapQuote + useBuildSwapTransaction + useSendTransaction | |
| Stake TON | <StakingWidget /> or staking hooks | |
| Buy TON/jettons with crypto (onramp) | <CryptoOnrampWidget /> or onramp hooks (useCryptoOnrampProviders + useCryptoOnrampQuote + useCreateCryptoOnrampDeposit + useCryptoOnrampStatus) | |
| Use a custom (app-defined) provider | useCustomProvider<T>(id) | |
| Sign message | useSignText / useSignBinary / useSignCell | |
| Mainnet/testnet support | Configure both networks + useDefaultNetwork() + explicit network params | |
| Real-time updates | Register streaming provider + mount useWatchBalance / useWatchTransactions | |
| Fix Next.js hydration | 'use client' providers + mount gate or dynamic import | |
| Refresh balance after send | queryClient.invalidateQueries({ queryKey: ['balance'] }) | |
| Clear stale data on disconnect | queryClient.removeQueries for wallet-scoped keys |
Drop-in components (<TonConnectButton />, <SendTonButton />, <SwapWidget />, etc.) are the fastest path. Use hooks only for custom UX.
For extended swap/staking/jetton recipes, see skill-reference/recipes.md.
Packages
- `@ton/appkit` — core SDK:
AppKitclass, actions, connectors (TonConnect), DeFi managers. - `@ton/appkit-react` — React hooks,
AppKitProvider, UI components. - `@tanstack/react-query` — required peer dependency.
Quick Setup
For Next.js: add 'use client' to the providers file and gate wallet-dependent UI until mount, or use dynamic(() => import(...), { ssr: false }). There is no `ssr` flag on `AppKitConfig` — the SSR boundary is purely a React/Next concern, not an AppKit option. Wallet state (useAddress, balances, etc.) is client-only by construction; render a stable placeholder on the server and swap in wallet-dependent UI after useEffect/mount.
Browser polyfills (Vite / Webpack / Rspack)
@ton/core (transitive dep) uses Node's Buffer and process. Browser bundlers don't include these by default — without polyfills you get a white screen and `ReferenceError: Buffer is not defined` at runtime.
For Vite, install vite-plugin-node-polyfills and add it to vite.config.ts:
If the plugin clashes with your project (e.g. nested workspace, alias resolution warnings), use a manual polyfill instead — pnpm add buffer process, then create src/polyfills.ts:
Import ./polyfills as the first line of `main.tsx` (before any AppKit code).
Next.js: no polyfill needed — Next's Webpack config handles Node globals automatically.
First-touch send: self-transfer
For a safe end-to-end test of the send flow, use useAddress() as the recipient — the user sends 0.01 TON to themselves. Validates wallet, network, signing, and on-chain confirmation without risk:
For real recipients, paste a TON address from Tonkeeper (UQ… non-bounceable for wallets, EQ… bounceable for contracts). Random/made-up strings without valid checksums make Tonkeeper's simulator say "no changes to your account" and refuse to sign.
Hooks Reference
Hooks come from @ton/appkit-react. Queries return TanStack { data, isLoading, isError, error }. Mutations return { mutate, mutateAsync, isPending, error, data, reset }.
Wallet
useConnectors() · useConnect() · useDisconnect() · useSelectedWallet() · useAddress() · useConnectedWallets()
useConnect() returns a mutation; call it with mutate({ connectorId }), passing the connector's id from useConnectors() (not the connector object itself). On iOS, the deep link that opens the wallet only fires if connect() runs in the same synchronous tick as the user's click — any await before it kills the user-activation token and the wallet won't open.
If you need side effects, fire-and-forget them (no await) or run them in mutation: { onSuccess }.
Balance & assets
useBalance()/useBalanceByAddress({ address, network? })— returns a decimal TON string already formatted with 9 decimals (e.g."0.500000000"for a wallet holding 0.5 TON). It is NOT raw nano and NOT abigint. Render directly or format withIntl.NumberFormat; do not pass it throughformatUnits(_, 9)again — that re-slices on the decimal point and yields garbage like"0..500000000". Passnetworkexplicitly for cross-network reads:useBalanceByAddress({ address, network: Network.testnet() }).useWatchBalance()/useWatchBalanceByAddress(...)— real-time updates (requires streaming provider)useJettons()— returns{ jettons: Jetton[], addressBook }. Usedata?.jettons, notdatadirectly. EachJetton.balanceis already formatted via the jetton's owndecimalsNumber(e.g."1.5"for 1.5 USDT) — same rule: don't re-format withformatUnits. Image URLs live underinfo.image.smallUrl/info.image.url(note theUrlsuffix).useJettonBalanceByAddress({ jettonAddress, ownerAddress, jettonDecimals?, network? })— note the param isownerAddress, notaddress. Returns a pre-formatted decimal string in the jetton's own units (e.g."1.5"for 1.5 USDT). IfjettonDecimalsisn't passed, AppKit looks it up from jetton metadata (one extra read). Same rule asuseBalance: don't pass the result throughformatUnitsagain.useJettonInfo({ address, network? })—addressis the jetton master contract address. Returns{ name, symbol, decimals?, image, … } | null.useJettonWalletAddress({ jettonAddress, ownerAddress, network? })— resolves the owner's individual jetton-wallet contract address for a given jetton.useWatchJettons()/useWatchJettonsByAddress(...)— real-time jetton list updates (requires streaming provider).useWatchBalanceByAddress({ address, network? })— real-time balance for an arbitrary address.useNfts()— returns{ nfts: NFT[], addressBook? }. Usedata?.nfts, notdatadirectly.useNft({ address })(addressis the NFT item's own contract address — NOTtokenAddress)
Sending
useTransferTon() · useTransferJetton() · useTransferNft() · useSendTransaction()
Call with mutate({ recipientAddress, amount: '0.5', comment? }). Amount is a human-readable string — AppKit converts using token decimals. The mutation's data resolves to SendTransactionResponse = { boc, normalizedBoc, normalizedHash } (object, not a bare string).
Param names differ per asset — easy to get wrong from intuition:
- TON:
mutate({ recipientAddress, amount, comment? }) - Jetton:
mutate({ jettonAddress, recipientAddress, amount, comment? })—jettonAddressis the jetton master contract. - NFT:
mutate({ nftAddress, recipientAddress, amount?, comment? })— `nftAddress` (NOTtokenAddress!) is the individual NFT item's contract address (nft.addressfromuseNfts()). Optionalamountis the forward TON (gas/notification), defaults are sensible. There is no<SendNftButton />drop-in — compose from the hook.
Signing
useSignText() · useSignBinary() · useSignCell()
Network
useNetwork() (selected wallet's network, undefined if not connected) · useDefaultNetwork() returns [defaultNetwork, setDefaultNetwork] · useNetworks() · useBlockNumber()
For mainnet/testnet apps, configure both networks and make reads explicit when the UI lets users choose a network:
This is the start of the file. Read the full SKILL.md on GitHub.
Security
- Security scanPassed, 88 of 100Pattern checks on the skill's files.
- Model reviewNot runA model review is scheduled for the next rescan.
Quality evaluation
- Task evaluationNot runNo evaluation yet. Run one in Skill Studio.
Source
- SKILL.md in the repositoryCheckingpackages/appkit/skills/ton-appkit/SKILL.md
Popularity
- Repository stars
- 51
- Repository forks
- 24
- 7-day trend score
- 20
Stars and forks are for the whole GitHub repository, not this skill alone. Not refreshed yet.
Works with
Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.
- Claude Code
- Cursor
- GitHub Copilot
- Windsurf
- Codex
- Gemini CLI
- Cline
- Amp
- Roo Code
- Goose
- Continue
- Kilo Code
- Junie
- Trae
- OpenHands
- Qwen Code
- AI Agent
- Tabnine Chat
- Sourcegraph Cody
- Amazon Q
- Firebase Genkit
- Sweep
- Devin
- Phind
- Mentat
- Claude Desktop
- Aider
- GPT Pilot
- Plandex
- bolt.new
- v0
- Replit Agent
- Anse
- TypingMind
- BetterChatGPT
- LibreChat
- Warp AI
- Pieces
- Fig AI
Embed badge
[](https://verified-skill.com/skills/ton-connect/kit/ton-appkit)