# Swap (v2)

{% hint style="info" %}
**Learn More**

* **Quickstart Guide**: See our [Swap Quickstart](https://docs.ston.fi/developer-section/quickstart/swap) for a complete React application example
* **Blog**: [Easy DeFi for TON Projects: STON.fi Integration](https://blog.ston.fi/easy-defi-for-ton-projects-stonfi-integration/)
  {% endhint %}

> The production-ready pattern is **API-driven**. Always let the STON.fi API dictate which router to use, and work against the mainnet endpoint. This keeps your integration compatible with future router upgrades and avoids hardcoding contract addresses.

## Mainnet-first workflow

STON.fi’s REST API (`api.ston.fi`) only serves mainnet data, so every production swap should follow this flow:

1. Simulate the swap to obtain routing metadata (expected amounts, vault info, and the full router object).
2. Feed `simulationResult.router` directly into `dexFactory()` to build contracts dynamically.
3. Generate the swap transaction parameters with the router helpers.

```typescript
import { dexFactory, Client } from "@ston-fi/sdk";
import { StonApiClient } from "@ston-fi/api";

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

const apiClient = new StonApiClient();

// 1. Simulate the swap to discover routing details
const simulationResult = await apiClient.simulateSwap({
  offerAddress: "<from asset address or 'ton'>",
  askAddress: "<to asset address>",
  offerUnits: "<amount in blockchain units>",
  slippageTolerance: "0.01",
});

// 2. Router metadata ships with the simulation result
const { router: routerInfo } = simulationResult;
const dexContracts = dexFactory(routerInfo);

// 3. Open the router contract
const router = tonClient.open(
  dexContracts.Router.create(routerInfo.address)
);

// Optional helper when TON is part of the route
const proxyTon = dexContracts.pTON.create(routerInfo.ptonMasterAddress);
```

The `simulationResult` object contains `offerUnits`, `minAskUnits`, `offerAddress`, `askAddress`, and `router`. Reuse those values when building the actual swap transaction to ensure the signed transaction matches the simulated path.

> **Referral Fees**: You can specify a referral fee in your swap if needed. For bigger context, see the [Omniston referral fees guide](https://docs.ston.fi/omniston/referral-fees#referral-fees-with-dex-v2) (although Omniston-oriented, the linked paragraph details how DEX V2 referral fees operate).

## Swap TON to jetton

```typescript
const txParams = await router.getSwapTonToJettonTxParams({
  userWalletAddress: "<your wallet address>",
  offerAmount: simulationResult.offerUnits,
  minAskAmount: simulationResult.minAskUnits,
  askJettonAddress: simulationResult.askAddress,
  proxyTon,
  // Optional referral parameters:
  referralAddress: "<your referral TON address>",
  referralValue: 10, // e.g. 10 => 0.1% fee
  queryId: 12345,
});
```

Send the resulting parameters using your preferred wallet integration. See our [transaction sending guide](https://docs.ston.fi/developer-section/common/transaction-sending) for wallet-specific examples.

## Swap jetton to jetton

```typescript
const txParams = await router.getSwapJettonToJettonTxParams({
  userWalletAddress: "<your wallet address>",
  offerJettonAddress: simulationResult.offerAddress,
  askJettonAddress: simulationResult.askAddress,
  offerAmount: simulationResult.offerUnits,
  minAskAmount: simulationResult.minAskUnits,
  // Optional referral parameters:
  referralAddress: "<your referral TON address>",
  referralValue: 25, // e.g. 25 => 0.25% fee
  queryId: 12345,
});
```

## Swap jetton to TON

```typescript
const txParams = await router.getSwapJettonToTonTxParams({
  userWalletAddress: "<your wallet address>",
  offerJettonAddress: simulationResult.offerAddress,
  offerAmount: simulationResult.offerUnits,
  minAskAmount: simulationResult.minAskUnits,
  proxyTon, // reuse from the common setup
  // Optional referral parameters:
  referralAddress: "<your referral TON address>",
  referralValue: 50, // e.g. 50 => 0.5% fee
  queryId: 12345,
});
```

Use the [transaction sending guide](https://docs.ston.fi/developer-section/common/transaction-sending) to broadcast the transaction. TonConnect, Tonkeeper SDK, custodial signers, and other libraries all accept the `txParams` generated above.

## Testnet swaps (manual setup)

If you really need to exercise v2 swaps on the TON testnet, you must fall back to hardcoded contracts because `api.ston.fi` serves mainnet only. Liquidity is scarce, so plan to source or mint the jettons yourself, create the required liquidity pools, and fund them before trying to swap.

To mirror the three swap types from the mainnet example, testers often run the following sequence on testnet:

1. swap 1 TON to TesREED (ton -> jetton)
2. swap TesREED to TestBlue (jetton -> jetton)
3. swap TestBlue back to TON (jetton -> ton)

```typescript
import { TonClient, toNano } from "@ton/ton";
import { DEX, pTON } from "@ston-fi/sdk";

const client = new TonClient({
  endpoint: "https://testnet.toncenter.com/api/v2/jsonRPC",
});

const router = client.open(
  DEX.v2_1.Router.CPI.create("kQALh-JBBIKK7gr0o4AVf9JZnEsFndqO0qTCyT-D-yBsWk0v") // CPI Router v2.1.0 (testnet)
);

const proxyTon = pTON.v2_1.create("kQACS30DNoUQ7NfApPvzh7eBmSZ9L4ygJ-lkNWtba8TQT-Px"); // pTON v2.1.0 (testnet)

const txParams = await router.getSwapTonToJettonTxParams({
  userWalletAddress: "<your testnet wallet>",
  proxyTon,
  offerAmount: toNano("1"),
  askJettonAddress: "kQDLvsZol3juZyOAVG8tWsJntOxeEZWEaWCbbSjYakQpuYN5", // TesREED jetton (testnet)
  minAskAmount: "1",
});
```

This manual approach is strictly **for testing**. Switch back to the API-driven workflow for anything mainnet facing.
