# Refund Liquidity (v2)

Refund tokens that were sent to an LP account but were not added to the pool.

> The production-ready approach is **API-driven**. Use the STON.fi API to resolve router metadata, construct contracts via `dexFactory`, and let the SDK derive the correct on-chain calls. This avoids hardcoding addresses and remains forward-compatible with router updates.

## Mainnet workflow

1. Determine the router and LP account that needs the refund. You can fetch them from the simulation result, from `getPoolsByAssetPair`, or from `getWalletLpAccounts` on the STON.fi API.
2. Fetch the router metadata with `getRouter(routerAddress)` and build the contract instances dynamically.
3. Call `getRefundTxParams` on the LP account to obtain the message you need to send on-chain.

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

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

const apiClient = new StonApiClient();

const routerMetadata = await apiClient.getRouter("<router address>");
const dexContracts = dexFactory(routerMetadata);

const lpAccount = tonClient.open(
  dexContracts.LpAccount.create("<lp account address>"),
);

// Optional: inspect the pending balances before refunding
const lpAccountData = await lpAccount.getLpAccountData();
console.log({
  routerAddress: lpAccountData.routerAddress?.toString(),
  poolAddress: lpAccountData.poolAddress?.toString(),
  tokenABalance: lpAccountData.amount0.toString(),
  tokenBBalance: lpAccountData.amount1.toString(),
});

const refundTxParams = await lpAccount.getRefundTxParams({
  queryId: 12345,
});
```

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

### Deriving the LP account address

If you only know the assets and the user wallet:

```typescript
const [poolInfo] = await apiClient.getPoolsByAssetPair({
  asset0Address: "<token A address or 'ton'>",
  asset1Address: "<token B address>",
});

if (!poolInfo) {
  throw new Error("Liquidity pool not found for the provided asset pair");
}

const routerMetadata = await apiClient.getRouter(poolInfo.routerAddress);
const dexContracts = dexFactory(routerMetadata);

const pool = tonClient.open(
  dexContracts.Pool.create(poolInfo.address),
);

const lpAccountAddress = (
  await pool.getLpAccountAddress({ ownerAddress: "<your wallet address>" })
).toString();
```

You can then pass `lpAccountAddress` into the main workflow above.

> **TON pools**: When a pool includes TON, the router metadata exposes `ptonMasterAddress`. `dexFactory` automatically wires the correct pool/LP implementations—no manual proxy setup is required.

## Testnet refund (manual setup)

Only rely on testnet for experimentation. Because `api.ston.fi` is mainnet-only, you must hardcode contract addresses, mint or source the testnet jettons (TesREED/TestBlue), and create funded pools before you can refund LP accounts.

```typescript
import { TonClient } from "@ton/ton";
import { DEX } 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 pool = client.open(
  await router.getPool({
    token0: "kQDLvsZol3juZyOAVG8tWsJntOxeEZWEaWCbbSjYakQpuYN5", // TesREED jetton (testnet)
    token1: "kQB_TOJSB7q3-Jm1O8s0jKFtqLElZDPjATs5uJGsujcjznq3", // TestBlue jetton (testnet)
  }),
);

const lpAccount = client.open(
  await pool.getLpAccount({ ownerAddress: "<your testnet wallet>" }),
);

const txParams = await lpAccount.getRefundTxParams({
  queryId: 12345,
});
```

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