# Liquidity Providing Guide (React)

This guide will walk you through creating a basic liquidity provision app using the STON.fi SDK and API in a **React** project. We'll integrate wallet connectivity with **TonConnect** (via `@tonconnect/ui-react`) to allow users to connect their TON wallet and provide liquidity to pools. The guide is beginner-friendly and assumes minimal React experience.

> **Note**: In this demo, we will leverage **Tailwind CSS** for styling instead of using custom CSS. The setup for Tailwind CSS is already included in the instructions below, so you don't need to set it up separately.

> **Note**: You can use any package manager (npm, yarn, pnpm, or bun) to set up your React project. In this tutorial, we'll demonstrate with **pnpm**.

***

## Table of Contents

1. [Introduction](#id-1.-introduction)
2. [Setting Up the Project](#id-2.-setting-up-the-project)
3. [Connecting the Wallet](#id-3.-connecting-the-wallet)
4. [Fetching Available Assets](#id-4.-fetching-available-assets)
5. [Simulating Liquidity Provision](#id-5.-simulating-liquidity-provision)
6. [Building the Transaction](#id-6.-building-the-transaction)
7. [Executing the Provision](#id-7.-executing-the-provision)
8. [Testing Your Provision](#id-8.-testing-your-provision)
9. [Conclusion](#id-9.-conclusion)
10. [Live Demo](#id-10.-live-demo)
11. [Next steps](#id-11.-next-steps)
12. [Advanced Example App](#id-12.-advanced-example-app)
13. [Using AI Agents for Automated Implementation](#id-13.-using-ai-agents-for-automated-implementation)

***

## 1. Introduction

In this quickstart, we will build a minimal React app to:

* Connect to a TON wallet (via **TonConnect UI**).
* Fetch available tokens from STON.fi (via **`@ston-fi/api`**).
* Simulate liquidity provision (to see expected LP tokens).
* Execute a liquidity provision transaction on-chain (via **`@ston-fi/sdk`**).

We will use:

* **`@ston-fi/sdk`** – Helps build the payload for the actual liquidity provision transaction.
* **`@ston-fi/api`** – Lets us fetch asset lists and run liquidity provision simulations.
* **`@tonconnect/ui-react`** – Provides a React-based TON wallet connect button and utilities.

***

## 2. Setting Up the Project

### 2.1 Create a React App

First, check if you have pnpm installed:

```bash
pnpm --version
```

If pnpm is not installed, install it globally:

```bash
npm install -g pnpm
```

Create a new React + Vite project:

```bash
pnpm create vite --template react-ts
```

Provide a project name (e.g., `stonfi-liquidity-app`) and then:

```bash
cd stonfi-liquidity-app
```

### 2.2 Installing the Required Packages

In your project directory, install the required packages:

```bash
pnpm add @ston-fi/sdk @ston-fi/api @tonconnect/ui-react @ton/ton
```

Install Tailwind CSS and the Node.js polyfills plugin for Vite:

```bash
pnpm add tailwindcss @tailwindcss/vite vite-plugin-node-polyfills
```

Configure Vite by updating `vite.config.ts`. This setup only polyfills `buffer`, keeping the bundle lean while still exposing `Buffer` for TON libraries:

```typescript
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import tailwindcss from "@tailwindcss/vite";
import { nodePolyfills } from "vite-plugin-node-polyfills";

export default defineConfig({
  plugins: [
    react(),
    tailwindcss(),
    nodePolyfills({
      include: ["buffer"],
      globals: {
        Buffer: true,
      },
    }),
  ],
});
```

In `src/index.css`, import Tailwind:

```css
@import "tailwindcss";
```

You can also remove `src/App.css` (we don't need it), and remove the import statement `import './App.css'` from `src/App.tsx`.

After making these changes, you can verify that your app still runs correctly by starting the development server:

```bash
pnpm install
pnpm dev
```

Open <http://localhost:5173>. If you see a Vite/React starter page, everything is working correctly.

***

## 3. Connecting the Wallet

### 3.1 Add the TonConnect Provider

Open `src/main.tsx` and wrap your app in `TonConnectUIProvider`:

```typescript
import React from "react";
import ReactDOM from "react-dom/client";
import { TonConnectUIProvider } from "@tonconnect/ui-react";
import "./index.css";
import App from "./App.tsx";

ReactDOM.createRoot(document.getElementById("root")!).render(
  <React.StrictMode>
    <TonConnectUIProvider 
    // For demo purposes, we're using a static manifest URL
    // Replace with your own: manifestUrl={`${window.location.origin}/tonconnect-manifest.json`}
    manifestUrl="https://gist.githubusercontent.com/mrruby/243180339f492a052aefc7a666cb14ee/raw/"
    >

      <App />
    </TonConnectUIProvider>
  </React.StrictMode>
);
```

> **Note**: For the purposes of this demo, we're serving the manifest from a static source. In a real application, you should replace this with your own manifest URL that you'll create in the next step.

### 3.2 Create the TonConnect Manifest

Create a file named `tonconnect-manifest.json` in your `public` folder:

```json
{
    "url": "https://stonfi-liquidity-demo.example.com",
    "name": "STON.fi Liquidity Provider",
    "iconUrl": "https://stonfi-liquidity-demo.example.com/icon-192x192.png"
}
```

Update with your own app name, domain, and icon.

### 3.3 Add the Connect Wallet Button

In `src/App.tsx`, import and add the `TonConnectButton`:

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

function App() {
  return (
    <div className="flex flex-col items-center justify-center min-h-screen p-6">
      <h1 className="text-2xl font-bold mb-4">STON.fi Liquidity Demo</h1>
      <TonConnectButton />
    </div>
  );
}

export default App;
```

***

## 4. Fetching Available Assets

Let's fetch token data from STON.fi using `StonApiClient`. We'll filter by liquidity tags to keep the list manageable.

First, add new imports to the top of `src/App.tsx`:

```typescript
import { useEffect, useState } from "react";
import { TonConnectButton } from "@tonconnect/ui-react";
import { StonApiClient, AssetTag, type AssetInfoV2  } from "@ston-fi/api";
```

Initialize the STON.fi API client:

```typescript
const stonApiClient = new StonApiClient();
```

Add state variables for token management:

```typescript
function App() {
  const [tokens, setTokens] = useState<AssetInfoV2[]>([]);
  const [tokenA, setTokenA] = useState<AssetInfoV2 | undefined>();
  const [tokenB, setTokenB] = useState<AssetInfoV2 | undefined>();
  const [amountA, setAmountA] = useState("");
  const [amountB, setAmountB] = useState("");
```

Add the token fetching logic:

```typescript
  // Fetch assets at startup
  useEffect(() => {
    const fetchTokens = async () => {
      try {
        const assets = await stonApiClient.queryAssets({
          // Query only assets with medium or higher liquidity to ensure tradability
          condition: `${AssetTag.LiquidityVeryHigh} | ${AssetTag.LiquidityHigh} | ${AssetTag.LiquidityMedium}`,
        });

        setTokens(assets);

        // Initialize default selections
        setTokenA(assets[0]);
        setTokenB(assets[1]);
      } catch (err) {
        console.error("Failed to fetch tokens:", err);
      }
    };
    fetchTokens();
  }, []);
```

Add the token change handler:

```typescript
  // Factory function for creating onChange handlers for token dropdowns
  // Uses composition to create reusable handlers for both token selectors
  const handleTokenChange =
    (setter: typeof setTokenA | typeof setTokenB) =>
    (event: { target: { value: string } }) => {
      const selected = tokens.find(
        (t) => t.contractAddress === event.target.value
      );
      if (selected) {
        setter(selected);
      }
    };
```

Replace the return statement with the enhanced UI:

```typescript
  return (
    <div className="flex flex-col items-center justify-center min-h-screen bg-gradient-to-b from-blue-50 to-indigo-100 p-6">
      <div className="max-w-md w-full bg-white rounded-lg shadow p-6 space-y-6">
        {/* Application header with branding and wallet connection */}
        <div className="flex justify-between items-center">
          <h1 className="text-2xl font-bold text-indigo-700">
            STON.fi Liquidity
          </h1>
          <TonConnectButton />
        </div>
        <hr className="border-gray-200" />

        {/* Main application interface (conditional on token data availability) */}
        {tokens.length > 0 ? (
          <>
            {/* Token A selection dropdown */}
            <div>
              <label className="block mb-1 text-sm font-medium text-gray-600">
                Token A
              </label>
              <select
                className="w-full p-2 border rounded"
                onChange={handleTokenChange(setTokenA)}
                value={tokenA?.contractAddress || ""}
              >
                {tokens.map((tok) => (
                  <option key={tok.contractAddress} value={tok.contractAddress}>
                    {tok.meta?.symbol ?? "Token"}
                  </option>
                ))}
              </select>
            </div>

            {/* Token B selection dropdown */}
            <div>
              <label className="block mb-1 text-sm font-medium text-gray-600">
                Token B
              </label>
              <select
                className="w-full p-2 border rounded"
                onChange={handleTokenChange(setTokenB)}
                value={tokenB?.contractAddress || ""}
              >
                {tokens.map((token) => (
                  <option
                    key={token.contractAddress}
                    value={token.contractAddress}
                  >
                    {token.meta?.symbol ?? "Token"}
                  </option>
                ))}
              </select>
            </div>

            {/* Amount input fields (side by side layout) */}
            <div className="flex space-x-4">
              <div className="flex-1">
                <label className="block mb-1 text-sm font-medium text-gray-600">
                  Amount A
                </label>
                <input
                  type="number"
                  className="w-full p-2 border rounded"
                  placeholder="0.0"
                  value={amountA}
                  onChange={(e) => setAmountA(e.target.value)}
                />
              </div>
              <div className="flex-1">
                <label className="block mb-1 text-sm font-medium text-gray-600">
                  Amount B
                </label>
                <input
                  type="number"
                  className="w-full p-2 border rounded"
                  placeholder="0.0"
                  value={amountB}
                  onChange={(e) => setAmountB(e.target.value)}
                />
              </div>
            </div>
          </>
        ) : (
          <p>Loading tokens...</p>
        )}
      </div>
    </div>
  );
}
```

***

## 5. Simulating Liquidity Provision

We'll call the simulateLiquidityProvision function on the StonApiClient to get simulation results.

Add additional imports to the top of the file:

```typescript
import { useTonAddress } from "@tonconnect/ui-react";
import { type LiquidityProvisionSimulation } from "@ston-fi/api";
import { fromNano } from "@ton/ton";
```

Add utility functions for converting token amounts:

```typescript
// Convert floating point string amount into integer base units string
// Essential for blockchain transactions which use integer arithmetic
function toBaseUnits(amount: string, decimals?: number) {
  return Math.floor(parseFloat(amount) * 10 ** (decimals ?? 9)).toString();
}

// Convert integer base units back to a fixed 2-decimal string for display
function fromBaseUnits(baseUnits: string, decimals?: number) {
  return (parseInt(baseUnits) / 10 ** (decimals ?? 9)).toFixed(2);
}
```

Add wallet address and simulation state:

```typescript
function App() {
  const walletAddress = useTonAddress();
  
  // ... existing state variables ...
  
  const [simulation, setSimulation] = useState<
    LiquidityProvisionSimulation | Error | undefined
  >();
```

Add useEffect to reset simulation when tokens change:

```typescript
  // Reset simulation when tokens change
  useEffect(() => {
    setSimulation(undefined);
  }, [tokenA, tokenB]);
```

Add the simulation handler after the existing handleTokenChange function:

```typescript
  const handleSimulationClick = async () => {
    if (!tokenA || !tokenB || !amountA || !amountB) {
      alert("Please select tokens and enter amounts");
      return;
    }

    try {
      // Retrieve available pools for tokens pair
      const pools = (
        await stonApiClient.getPoolsByAssetPair({
          asset0Address: tokenA.contractAddress,
          asset1Address: tokenB.contractAddress,
        })
      ).filter((pool) => !pool.deprecated);

      const pool = pools[0];

      // Retrieve simulation depending on pool availability
      const simulation = pool
        ? await stonApiClient.simulateLiquidityProvision({
            provisionType: "Balanced",
            tokenA: tokenA.contractAddress,
            tokenB: tokenB.contractAddress,
            tokenAUnits: toBaseUnits(amountA, tokenA?.meta?.decimals),
            poolAddress: pool.address,
            slippageTolerance: "0.001",
            walletAddress,
          })
        : await stonApiClient.simulateLiquidityProvision({
            provisionType: "Initial",
            tokenA: tokenA.contractAddress,
            tokenB: tokenB.contractAddress,
            tokenAUnits: toBaseUnits(amountA, tokenA?.meta?.decimals),
            tokenBUnits: toBaseUnits(amountB, tokenB?.meta?.decimals),
            slippageTolerance: "0.001",
            walletAddress,
          });

      setSimulation(simulation);
      setAmountB(fromBaseUnits(simulation.tokenBUnits, tokenB?.meta?.decimals));
    } catch (e) {
      setSimulation(new Error(e instanceof Error ? e.message : String(e)));
    }
  };
```

Add the simulation button after the amount input fields:

```typescript
            <div className="flex space-x-4">
              <div className="flex-1">
                <label className="block mb-1 text-sm font-medium text-gray-600">
                  Amount A
                </label>
                <input
                  type="number"
                  className="w-full p-2 border rounded"
                  placeholder="0.0"
                  value={amountA}
                  onChange={(e) => setAmountA(e.target.value)}
                />
              </div>
              <div className="flex-1">
                <label className="block mb-1 text-sm font-medium text-gray-600">
                  Amount B
                </label>
                <input
                  type="number"
                  className="w-full p-2 border rounded"
                  placeholder="0.0"
                  value={amountB}
                  onChange={(e) => setAmountB(e.target.value)}
                />
              </div>
            </div>

            {/* Simulation trigger button with validation */}
            <button
              onClick={handleSimulationClick}
              className="w-full bg-indigo-500 hover:bg-indigo-600 text-white font-medium py-2 rounded"
            >
              Simulate
            </button>
```

Add the simulation results display after the simulate button:

```typescript
            {simulation ? (
              simulation instanceof Error ? (
                <p className="text-red-600 text-sm">{simulation.message}</p>
              ) : (
                <>
                  <div className="p-4 bg-gray-50 rounded border border-gray-200 text-sm overflow-x-auto break-all max-w-full">
                    <p className="font-semibold text-gray-800">
                      Simulation Result
                    </p>
                    <ul className="list-disc list-inside mt-2 space-y-1 text-gray-700">
                      {Object.entries({
                        "Provision Type": simulation.provisionType,
                        "Pool Address": simulation.poolAddress,
                        "Router (inline metadata)": simulation.router?.address,
                        "Token A": simulation.tokenA,
                        "Token B": simulation.tokenB,
                        "Token A Units": fromBaseUnits(
                          simulation.tokenAUnits,
                          tokenA?.meta?.decimals
                        ),
                        "Token B Units": fromBaseUnits(
                          simulation.tokenBUnits,
                          tokenB?.meta?.decimals
                        ),
                        "LP Account": simulation.lpAccountAddress,
                        "Estimated LP": fromNano(simulation.estimatedLpUnits),
                        "Min LP": fromNano(simulation.minLpUnits),
                        "Price Impact": simulation.priceImpact,
                      }).map(([label, value]) => (
                        <li key={label}>
                          <span className="font-medium">{label}:</span>{" "}
                          <span className="break-all">{value}</span>
                        </li>
                      ))}
                    </ul>
                  </div>
                </>
              )
            ) : null}
```

***

## 6. Building the Transaction

Go to [TON Center](https://toncenter.com/) and get your API key.

Then create a `.env` file in the root of your project and add your API key there:

```bash
VITE_TON_API_KEY=your_api_key_here
```

Now let's build the transaction using `@ston-fi/sdk`:

Add new imports to top of file and initialize TON JSON-RPC client:

```typescript
import { useTonConnectUI } from "@tonconnect/ui-react";
import { dexFactory } from "@ston-fi/sdk";
import { TonClient, fromNano } from "@ton/ton";

// TON JSON-RPC client for blockchain interactions
const tonApiClient = new TonClient({
  endpoint: "https://toncenter.com/api/v2/jsonRPC",
  apiKey: import.meta.env.VITE_TON_API_KEY,
});
```

Add `handleProvideLiquidityClick` callback after `handleSimulationClick` callback:

```typescript
const [tonConnectUI] = useTonConnectUI();

const handleProvideLiquidityClick = async () => {
  if (!simulation || simulation instanceof Error) {
    alert("Simulation is not valid");
    return;
  }

  const tonAsset = tokens.find((token) => token.kind === "Ton");
  if (!tonAsset) {
    alert("TON asset info not found");
    return;
  }

  try {
    const routerInfo = simulation.router;
    const { Router, pTON } = dexFactory(routerInfo);
    const router = tonApiClient.open(Router.create(routerInfo.address));
    const pTon = pTON.create(routerInfo.ptonMasterAddress);

    const isTonAsset = (contractAddress: string) =>
      contractAddress === tonAsset.contractAddress;

    const buildTransaction = async (args: {
      sendAmount: string;
      sendTokenAddress: string;
      otherTokenAddress: string;
    }) => {
      const params = {
        userWalletAddress: walletAddress,
        minLpOut: simulation.minLpUnits,
        sendAmount: args.sendAmount,
        otherTokenAddress: isTonAsset(args.otherTokenAddress)
          ? pTon.address
          : args.otherTokenAddress,
      };

      // TON requires proxy contract, Jettons use direct transfer
      if (isTonAsset(args.sendTokenAddress)) {
        return await router.getProvideLiquidityTonTxParams({
          ...params,
          proxyTon: pTon,
        });
      } else {
        return await router.getProvideLiquidityJettonTxParams({
          ...params,
          sendTokenAddress: args.sendTokenAddress,
        });
      }
    };

    // Generate transaction parameters for both tokens
    // Different methods are used for TON vs Jetton tokens due to blockchain mechanics
    const txParams = await Promise.all([
      buildTransaction({
        sendAmount: simulation.tokenAUnits,
        sendTokenAddress: simulation.tokenA,
        otherTokenAddress: simulation.tokenB,
      }),
      buildTransaction({
        sendAmount: simulation.tokenBUnits,
        sendTokenAddress: simulation.tokenB,
        otherTokenAddress: simulation.tokenA,
      }),
    ]);

    // Format transaction messages for TonConnect sendTransaction interface
    const messages = txParams.map((txParam) => ({
      address: txParam.to.toString(),
      amount: txParam.value.toString(),
      payload: txParam.body?.toBoc().toString("base64"),
    }));

    // Trigger TonConnect modal for user transaction approval
    await tonConnectUI.sendTransaction({
      validUntil: Date.now() + 5 * 60 * 1000, // Transaction valid for 5 minutes
      messages,
    });
  } catch (e) {
    alert(`Error: ${e}`);
  }
};
```

Add Provide Liquidity button after the simulation results div:

```typescript
                    {Object.entries({
                      "Provision Type": simulation.provisionType,
                      "Pool Address": simulation.poolAddress,
                      "Router (inline metadata)": simulation.router?.address,
                      "Token A": simulation.tokenA,
                      "Token B": simulation.tokenB,
                      "Token A Units": fromBaseUnits(
                        simulation.tokenAUnits,
                        tokenA?.meta?.decimals
                      ),
                      "Token B Units": fromBaseUnits(
                        simulation.tokenBUnits,
                        tokenB?.meta?.decimals
                      ),
                      "LP Account": simulation.lpAccountAddress,
                      "Estimated LP": fromNano(simulation.estimatedLpUnits),
                      "Min LP": fromNano(simulation.minLpUnits),
                      "Price Impact": simulation.priceImpact,
                    }).map(([label, value]) => (
                      <li key={label}>
                        <span className="font-medium">{label}:</span>{" "}
                        <span className="break-all">{value}</span>
                      </li>
                    ))}
                  </ul>
                </div>

                <button
                  onClick={handleProvideLiquidityClick}
                  className="w-full bg-green-500 hover:bg-green-600 text-white font-medium py-2 rounded mt-4"
                >
                  Provide Liquidity
                </button>
                </>

              )
            ) : null}
```

***

## 7. Executing the Provision

After clicking "Provide Liquidity", your wallet will prompt you to confirm and sign. The transaction will:

1. Send token A and token B to the router contract
2. Add liquidity to the pool
3. Mint LP tokens to your LP wallet

***

## 8. Testing Your Provision

1. Start the dev server:

```bash
pnpm dev
```

2. Open <http://localhost:5173>
3. Connect your TON wallet
4. Select two tokens and enter amounts
5. Simulate to see expected LP tokens
6. Click "Provide Liquidity" to execute the transaction
7. Check your wallet for the new LP tokens

***

## 9. Conclusion

You've built a minimal React app that:

* Connects to a TON wallet
* Fetches tokens from STON.fi
* Simulates liquidity provision
* Handles both new and existing pools
* Executes the provision transaction

***

## 10. Live Demo

With this Replit demo, you can:

* Open the project directly in your browser
* Fork the Replit to make your own copy
* Run the application to see it in action
* Explore and modify the code to learn how it works
* Experiment with different features and UI changes

{% embed url="<https://replit.com/@stonfi/stonfi-liquidity-app?embed=true>" %}

Alternatively, you can run this example locally by cloning the GitHub repository:

```bash
git clone https://github.com/mrruby/stonfi-liquidity-app.git
cd omniston-swap-app
pnpm install
pnpm dev
```

This will start the development server and you can access the app at `http://localhost:5173`.

Also remeber to add your TON API key to the `.env` file from [Building the Transaction](#id-6.-building-the-transaction) step.

***

## 11. Next steps

For more advanced features you can add:

* Dynamic slippage controls
* [Burn liquidity](https://docs.ston.fi/developer-section/dex/sdk/v2/burn-lp-tokens) read about it in the SDK docs
* See the [SDK Liquidity docs](https://docs.ston.fi/developer-section/dex/sdk/v2/provide-liquidity) for more details

Learn more: [STON.fi Liquidity Pools and TON Integration](https://blog.ston.fi/ston-fi-liquidity-pools-ton-integration/)

## 12. Advanced Example App

For those seeking a feature-rich, more advanced approach, we also have a Next.js demo app that:

* Uses Next.js for a scalable framework
* Utilizes hooks and providers for an elegant architecture
* Demonstrates better error handling, robust state management, and additional STON.fi features

You can explore the code in our repository:

[STON.fi SDK Next.js Demo App](https://github.com/ston-fi/sdk/tree/main/examples/next-js-app)

Or see it in action at our live demo:

[SDK Demo App](https://sdk-demo-app.ston.fi/liquidity/provide)

## 13. Using AI Agents for Automated Implementation

For developers looking to accelerate their development process, you can leverage **AI coding agents** to automatically implement the liquidity provision functionality described in this guide. While we showcase **Gemini CLI** in our example (due to its generous free tier), you can use any AI coding assistant such as **Claude Code**, **GitHub Copilot**, **Cursor Agent**, or similar tools.

### 13.1 Why AI Agents?

Modern AI coding agents can:

* Understand complex documentation and implement complete features
* Set up project structure and dependencies automatically
* Handle common configuration and setup errors
* Provide working implementations in minutes instead of hours

### 13.2 Setting Up with Gemini CLI (Example)

We'll demonstrate with Gemini CLI, but the approach works with any AI agent that can read documentation and execute commands.

#### 13.2.1 Installing Gemini CLI

1. Install the Gemini CLI by following the instructions at: <https://github.com/google-gemini/gemini-cli>
2. Authenticate with your Google account when prompted. The free tier includes:
   * 60 model requests per minute
   * 1,000 model requests per day

#### 13.2.2 Setting Up the Implementation Guide

1. Download the appropriate guide file from the gist: <https://gist.github.com/mrruby/3de1cedace13457b3fd6964186cfcb2e>
   * **For Claude Code**: Download `AGENTS.md` and rename it to `CLAUDE.md`
   * **For other AI agents** (Gemini CLI, GitHub Copilot, Cursor, etc.): Use `AGENTS.md` as-is
2. Create a new directory for your project and place the guide file inside it:

   ```bash
   mkdir my-liquidity-app
   cd my-liquidity-app
   # Place CLAUDE.md (for Claude Code) or AGENTS.md (for other agents) here
   ```

#### 13.2.3 Running the Automated Implementation

1. From within your project directory, run the Gemini CLI:

   ```bash
   gemini
   ```
2. When the CLI interface opens, type:

   ```
   Implement liquidity provision according to Liquidity Provision Quickstart Guide in AGENTS.md  
   ```
3. The AI agent will:
   * Ask for permission to use commands like `pnpm`, `npm`, etc.
   * Automatically create the project structure
   * Install all necessary dependencies
   * Implement the complete liquidity provision functionality
   * Set up the UI components and styling
4. **Important**: After the implementation completes, you must manually configure your TON API key:
   * Go to [TON Center](https://toncenter.com/) and get your API key
   * Create a `.env` file in the root of your project
   * Add your API key: `VITE_TON_API_KEY=your_api_key_here`
   * AI agents cannot handle this step as it requires your personal API credentials
5. If any errors occur during the process:
   * Simply paste the error message back to the AI agent
   * It will analyze and fix the issue automatically
   * In most cases, the implementation completes successfully in one shot

### 13.3 Using Other AI Agents

The same approach works with other AI coding assistants:

* **Claude Code**: Download `AGENTS.md` and rename it to `CLAUDE.md`, then place it in your project and ask Claude Code to implement the guide
* **GitHub Copilot**: Use the `AGENTS.md` file as-is, open the guide in your editor and use Copilot Chat to implement step by step
* **Cursor Agent**: Use the `AGENTS.md` file as-is, load the documentation and request full implementation via Cursor's agent mode
* **Custom Tools**: Any AI assistant with file access and command execution capabilities can follow the guide using the `AGENTS.md` file

> **Note**: The `AGENTS.md` file contains instructions compatible with all AI agents (Gemini CLI, GitHub Copilot, Cursor, etc.). However, Claude Code requires the file to be named `CLAUDE.md` to be automatically recognized, so you must rename `AGENTS.md` to `CLAUDE.md` when using Claude Code.

### 13.4 Benefits of Using AI Agents

* **Speed**: Get a working implementation in minutes instead of hours
* **Accuracy**: AI agents follow the quickstart guide precisely
* **Error Handling**: Automatically resolve most common setup issues
* **Learning Tool**: Watch how the implementation unfolds step by step
* **Customization**: After the initial setup, you can modify the generated code to fit your specific needs
* **Cost-Effective**: Many AI coding tools offer free tiers (like Gemini CLI) or are included in existing subscriptions

### 13.5 Best Practices

1. **Review the Code**: Always review AI-generated code before using it in production
2. **Understand the Flow**: Use the generated code as a learning tool to understand liquidity provision
3. **Customize**: Adapt the generated code to your specific requirements
4. **Test Thoroughly**: Test the implementation with small amounts before processing larger transactions
5. **Security**: Never commit API keys or mnemonics to version control

This approach is particularly useful for:

* Developers new to the TON ecosystem
* Quick prototyping and proof-of-concepts
* Learning by example with a working implementation
* Avoiding common setup pitfalls and configuration errors
* Exploring different implementation approaches rapidly
