# Referral Fees

This guide explains how referral fees are applied in the **Omniston liquidity‑aggregation protocol** when trades route through **DEX v1, DEX v2, DeDust, Tonco, or Escrow**.

> **Quick start:** Looking for code examples? Jump to [Platform-specific implementation guides](#platform-specific-implementation-guides) for SDK and API integration samples.

***

## Specifying Referral Parameters

When you request a quote you can attach referral data so that a share of the swap fee is redirected to your address.

### Top-level referral parameters

| Parameter          | Description                                |
| ------------------ | ------------------------------------------ |
| `referrer_address` | TON address that receives the referral fee |
| `referrer_fee_bps` | Fee rate in basis‑points (1 bps = 0.01 %)  |

### Settlement parameters

| Parameter               | Description                                                                                                                                                                                                              |
| ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `flexible_referrer_fee` | Boolean flag (inside `settlementParams`) allowing resolvers to lower the effective referrer fee when it yields a better swap rate. Defaults to `false`. See [Flexible Referrer Fee](#flexible-referrer-fee) for details. |

**Example JSON in a quote request**

```json
{
  "referrer_address": {
    "blockchain": 607,
    "address": "EQCXSs2xZ2dhk9TAxzGzXra2EbG_S2SqyN8Tfi6fJ82EYiVj"
  },
  "referrer_fee_bps": 10,
  "settlement_params": {
    "flexible_referrer_fee": true
  }
}
```

### Platform-specific implementation guides

For detailed implementation examples and code samples:

* [**Node.js SDK**](https://docs.ston.fi/developer-section/sdk/nodejs#send-a-quote-request) - TypeScript/JavaScript integration with referral parameters
* [**React SDK**](https://docs.ston.fi/developer-section/sdk/react#send-a-quote-request) - React hooks and components for referral tracking
* [**gRPC API**](https://docs.ston.fi/developer-section/swap/grpc#typical-flow-traders) - Direct gRPC integration for custom implementations
* [**WebSocket API**](https://docs.ston.fi/developer-section/swap#subscription-method-quote) - Real-time quote streaming with referral support

***

## Flexible Referrer Fee

The `flexible_referrer_fee` parameter (part of `settlementParams` / `RequestSettlementParams`) allows the Omniston protocol to automatically adjust your referral fee downward when doing so would provide a better swap rate for the user.

### Why this feature exists

This feature was designed to solve a specific compatibility issue between different DEX versions:

* **DEX v1** has a fixed maximum referral fee of **0.1%** (10 bps) enforced by the pool contract
* **DEX v2, DeDust, Tonco, and Escrow** support configurable fees from **0.01% to 1%**

**The problem:** Suppose you set a referral fee of **0.3%** (30 bps) in your quote request. If the best swap rate happens to be through a **DEX v1 pool**, that route would normally be excluded because v1 cannot support a 0.3% referral fee. This forces the protocol to use a suboptimal route through v2, DeDust, Tonco, or Escrow—even if the v1 pool offers a significantly better rate for the user.

**The solution:** When you enable `flexible_referrer_fee: true`, the protocol can automatically reduce your referral fee from 0.3% to 0.1% when routing through v1 pools. This allows the user to benefit from the best available rate while you still earn the maximum referral fee that v1 supports.

### Usage guidelines

* Defaults to `false`—you must explicitly enable it
* Only affects routes where a lower fee would unlock a better rate
* Your referral fee will never be increased, only decreased when beneficial
* Most useful when setting referral fees above 0.1% (10 bps)

**Example scenario:**

```json
{
  "referrer_address": { "blockchain": 607, "address": "EQC..." },
  "referrer_fee_bps": 30,
  "settlement_params": {
    "flexible_referrer_fee": true
  }
}
```

With this configuration:

* If the best rate is through v2/DeDust/Tonco/Escrow: you receive the full **0.3%**
* If the best rate is through v1: your fee is automatically reduced to **0.1%**, but the user gets a better swap rate

***

## Referral Fees with DEX v1

| Characteristic | Details                                                   |
| -------------- | --------------------------------------------------------- |
| **Fee rate**   | Fixed 0.1 % (10 bps) enforced by the pool contract        |
| **Settlement** | Paid on‑chain in the *same* swap tx to `referrer_address` |

Nothing else is required—fees arrive automatically.

***

## Referral Fees with DEX v2

### 1 · How fees are accumulated

* Fee rate is configurable from **0.01 % to 1 %** per swap.
* Instead of being paid instantly, fees are deposited into a **Vault** (one vault per *token × referral‑address* pair).

### 2 · Withdrawing your fees

DEX v2 referral fees are stored in a special vault and must be claimed manually.

**To claim your fees:**

1. Go to the vault interface by visiting the following link: <https://sdk-demo-app.ston.fi/vault>
2. Connect your wallet to the site.
3. Once connected, the interface will display all available referral fees you can claim.
4. Find the fee you'd like to claim and click the "Claim" button.
5. A transaction will be sent to your wallet — confirm it.
6. After confirmation, the claimed referral fees will appear in your wallet.

**For automated withdrawals via SDK/code:**

For a fully-working reference open the **Vault withdrawal demo** inside our SDK mono-repo:

<https://github.com/ston-fi/sdk/tree/main/examples/next-js-app/app/vault>

### How it works in practice

* Suppose a trader swaps **A → B** and a referral fee is specified.
* During that swap the **Router** deploys (or re-uses) a **Vault** whose address is derived deterministically from the **pool address** and the **router address**.
* The API can automatically discover all your vaults using the `/v1/wallets/{addr_str}/fee_vaults` endpoint, eliminating the need to manually track pool addresses.
* With the vault addresses retrieved, instantiate a `Router` from the SDK and call the helper (e.g. `withdrawFees()`) to collect the accumulated tokens via TonConnect or any preferred wallet integration.

The linked example shows this discover → instantiate → withdraw flow end-to-end, including robust TypeScript patterns and TonConnect wiring.

> **Note**\
> For TON-denominated fees in **DEX v2**, the `tokenMinter` is the *pTON* master address (`ptonMasterAddress`).

***

## Referral Fees with Tonco

For Tonco swaps, we use the same referral fee mechanism as DeDust through the **stand-alone Fee-Vault Minter contract**. The flow is identical to DeDust:

1. Find your personal vault using the same methods described in the DeDust section
2. Collect fees by sending a message to your vault with `collectFees()`
3. TON fees are credited instantly, while jetton fees accumulate in your vault

Refer to the DeDust section below for detailed implementation instructions.

> **API status** At the moment, Omniston does not expose Tonco referral fees via the public REST API. To track these fees you should use the on-chain flow described above or your own indexer until the omni-fees API is released.

***

## Referral Fees with DeDust

For DeDust swaps, we implement our own referral fee mechanism through a **stand-alone Fee-Vault Minter contract**. This flow bypasses the Router used in Ston.fi DEX v2, so **the existing SDK helpers cannot be used**—you must call the contract methods directly on-chain.

> **Important Update:** We have deployed a new Fee-Vault Minter contract at `EQCcJf2KFlH9xIx3dztytxxRFk3KQZKEYBr-f0nFIO1h3dvv`. New fees will be directed to this new contract. Users can claim fees from previous contracts (`EQD5TIvGT6NxphRDKX9wRUkJOHyE0VTuTGdVSGA5N_b62naH`, `EQBCAUfvMMSn-WHP0bKDs4wUVOK1r55OuHJIq25_QnVFCFye`, and `EQAAoyu0C-aMYGPVEoMfuAge2-meJWeO5KLJKrKWJAJAKXGL`) and the new contract.

> **Implementation Note:** The code examples below demonstrate **on-chain contract calls** using the TON blockchain. These are **not part of the STON.fi SDK**. To use them, you need:
>
> 1. **TON development environment** - Use [Blueprint](https://github.com/ton-org/blueprint) framework with `@ton/core` and `@ton/ton` packages
> 2. **Contract wrappers** - You must implement wrapper classes (`FeeVaultMinter`, `FeeVaultContract`) for the fee vault contracts. For `JettonMaster`, you can use the one from `@ton/ton`
> 3. **RPC access** - A TON RPC provider like [toncenter.com](https://toncenter.com) for blockchain queries
>
> If you prefer not to write contract wrappers, see the [Low-level RPC approach](#low-level-rpc-approach) section below.

### 1 · Find your personal vault

Each jetton has its own vault contract. To find your vault address for a specific jetton:

1. **Get the Fee-Vault Minter's jetton wallet address** Every **Fee-Vault Minter** owns a *regular jetton wallet*. Retrieve it via `jettonMaster.getWalletAddress(feeVaultMinter.address)`.
2. **Query your personal vault** by calling `feeVaultMinter.getVaultAddress({ owner: <your_wallet>, jettonWallet: <feeVaultMinterWallet> })`.

```ts
// --- TypeScript example ------------------------------------------------------
import { Address } from '@ton/core';
import { JettonMaster } from '@ton/ton';
// FeeVaultMinter, FeeVaultContract are custom wrappers you must implement

// Old Fee-Vault Minters (for claiming existing fees):
// - EQD5TIvGT6NxphRDKX9wRUkJOHyE0VTuTGdVSGA5N_b62naH
// - EQBCAUfvMMSn-WHP0bKDs4wUVOK1r55OuHJIq25_QnVFCFye
// - EQAAoyu0C-aMYGPVEoMfuAge2-meJWeO5KLJKrKWJAJAKXGL
// New Fee-Vault Minter (for new fees): EQCcJf2KFlH9xIx3dztytxxRFk3KQZKEYBr-f0nFIO1h3dvv
const feeVaultMinterAddress = Address.parse("EQCcJf2KFlH9xIx3dztytxxRFk3KQZKEYBr-f0nFIO1h3dvv");
const feeVaultMinter = provider.open(
  FeeVaultMinter.createFromAddress(feeVaultMinterAddress),
);

const jettonMasterAddress = Address.parse("USDT_jetton_master_address");
const ownerAddress = Address.parse("your_wallet_address"); // same as referrer_address in quote request

// JettonMaster from @ton/ton (sometimes called "Jetton Minter")
const jettonMaster = provider.open(JettonMaster.create(jettonMasterAddress));
const feeVaultMinterWallet = await jettonMaster.getWalletAddress(feeVaultMinter.address);

const vaultAddress = await feeVaultMinter.getVaultAddress({
  owner: ownerAddress,
  jettonWallet: feeVaultMinterWallet,
});

// Need more than just the address? Query on-chain data with getVaultData():
const vault = provider.open(FeeVaultContract.createFromAddress(vaultAddress));
const vaultData = await vault.getVaultData();
// vaultData.balance, vaultData.lastCollectTime, …
```

The getter returns:

* **`0:0`** – no fees accrued yet for this jetton
* **vault address** – your dedicated Fee-Vault contract for this jetton

> Vault addresses are derived deterministically based on both the referrer address and jetton address.

### 2 · Collect the fees

1. Send an internal message to **your vault** calling `collectFees()` (no payload) with about **0.3 TON** attached for gas.
2. The vault immediately transfers the accumulated fee-tokens to **your wallet** and resets its balance.
3. For TON fees, they are credited instantly to the **referrer address** during the swap transaction.

The complete flow consists of **two or three on-chain calls**:

| Step            | Contract         | Method                          | Purpose                                  |
| --------------- | ---------------- | ------------------------------- | ---------------------------------------- |
| Read            | Fee-Vault Minter | `getVaultAddress(user, jetton)` | Get your vault address                   |
| Read (optional) | Your Fee-Vault   | `getVaultData()`                | Check balance before collecting          |
| Write           | Your Fee-Vault   | `collectFees()`                 | Transfer accumulated fees to your wallet |

### Low-level RPC Approach

If you don't want to set up Blueprint or write contract wrappers, you can query vault data directly using RPC calls to any TON API provider (e.g., [toncenter.com](https://toncenter.com)).

> **Slice encoding:** Stack items of type `tvm.Slice` must be base64-encoded BOC (bag of cells). To convert an address to a slice:
>
> ```ts
> import { beginCell, Address } from '@ton/core';
> const addr = Address.parse("EQ...");
> const sliceBoc = beginCell().storeAddress(addr).endCell().toBoc().toString('base64');
> ```

**Step 1: Get the Fee-Vault Minter's jetton wallet address**

Call `get_wallet_address` on the Jetton Master contract:

```bash
curl -X POST "https://toncenter.com/api/v2/runGetMethod" \
  -H "Content-Type: application/json" \
  -d '{
    "address": "<JETTON_MASTER_ADDRESS>",
    "method": "get_wallet_address",
    "stack": [["tvm.Slice", "<FEE_VAULT_MINTER_ADDRESS_AS_SLICE_BOC>"]]
  }'
```

**Step 2: Get your vault address**

Call `get_vault_address` on the Fee-Vault Minter:

```bash
curl -X POST "https://toncenter.com/api/v2/runGetMethod" \
  -H "Content-Type: application/json" \
  -d '{
    "address": "<FEE_VAULT_MINTER_ADDRESS>",
    "method": "get_vault_address",
    "stack": [
      ["tvm.Slice", "<YOUR_WALLET_ADDRESS_AS_SLICE_BOC>"],
      ["tvm.Slice", "<FEE_VAULT_MINTER_WALLET_AS_SLICE_BOC>"]
    ]
  }'
```

**Step 3: Query vault data**

Call `get_vault_data` on your vault:

```bash
curl -X POST "https://toncenter.com/api/v2/runGetMethod" \
  -H "Content-Type: application/json" \
  -d '{
    "address": "<YOUR_VAULT_ADDRESS>",
    "method": "get_vault_data",
    "stack": []
  }'
```

The response contains cells that encode: owner address, jetton wallet address, balance, and minter address.

> **Tip:** You can view vault data directly on [tonviewer.com](https://tonviewer.com) by navigating to your vault address and clicking "Methods" to run `get_vault_data`.

### Verifying Your Vault Address

To confirm your vault address is correct:

1. **Compute the vault address** using the code example above
2. **Open your swap transaction** on [tonviewer.com](https://tonviewer.com) and expand the transaction trace
3. **Find the vault address** in the trace - it should match the address computed from your code
4. **Navigate to your vault** on tonviewer: `https://tonviewer.com/<vault_address>?section=method`
5. **Run `get_vault_data`** - this returns the same data structure as `vault.getVaultData()` in the code example:
   * Owner address (your referrer address)
   * Jetton wallet address
   * Balance (accumulated fees)
   * Minter address

If the data matches your expected values, your vault address derivation is correct.

> **API status** At the moment, Omniston does not expose DeDust referral fees via the public REST API. To track these fees you should use the on-chain flow described above or your own indexer until the omni-fees API is released.

***

## Referral Fees with Escrow

For Escrow swaps, referral fees are collected through a dedicated **Escrow Minter contract**. While the mechanism is conceptually similar to DeDust, Escrow uses **different vault contracts with different interfaces**—these are not the same vaults used by the cross-dex protocol.

> **SDK Note:** The SDK wrappers (`EscrowMinter`/`EscrowVault`) are not yet available in the SDK. The examples below use direct contract calls.

> **Implementation Note:** Like DeDust, Escrow fee collection requires **on-chain contract calls** that are **not part of the STON.fi SDK**. You need:
>
> 1. **TON development environment** - Use [Blueprint](https://github.com/ton-org/blueprint) framework with `@ton/core` and `@ton/ton` packages
> 2. **Contract wrappers** - You must implement wrapper classes (`EscrowMinter`, `EscrowVault`) for the escrow contracts. For `JettonMaster`, you can use the one from `@ton/ton`
> 3. **RPC access** - A TON RPC provider like [toncenter.com](https://toncenter.com) for blockchain queries
>
> The [Low-level RPC approach](#low-level-rpc-approach) described in the DeDust section also applies here - just substitute the Escrow Minter address and use the appropriate get-methods.

### 1 · Find your personal vault

Each jetton has its own vault contract. To find your vault address for a specific jetton:

1. **Get the Escrow Minter's jetton wallet address** Retrieve it via `jettonMaster.getWalletAddress(escrowMinter.address)`.
2. **Query your personal vault** by calling `escrowMinter.getVaultAddress(escrowMinterWallet, ownerAddress)`.

```ts
// --- TypeScript example ------------------------------------------------------
import { Address } from '@ton/core';
import { JettonMaster } from '@ton/ton';
// EscrowMinter, EscrowVault are custom wrappers you must implement

// Official Escrow Minter deployment address (mainnet)
const escrowMinterAddress = Address.parse('EQAhedmtkPnKnQRlkkK3aEUDqGMg4Ewwz0LPj18HwLasAJdp');
const escrowMinter = provider.open(EscrowMinter.createFromAddress(escrowMinterAddress));

const jettonMasterAddress = Address.parse('USDT_jetton_master_address');
const ownerAddress = Address.parse('your_wallet_address'); // same as referrer_address in quote request

// JettonMaster from @ton/ton (sometimes called "Jetton Minter")
const jettonMaster = provider.open(JettonMaster.create(jettonMasterAddress));

const escrowMinterWallet = await jettonMaster.getWalletAddress(escrowMinter.address);
const vaultAddress = await escrowMinter.getVaultAddress(escrowMinterWallet, ownerAddress);
const escrowVault = provider.open(EscrowVault.createFromAddress(vaultAddress));

const vaultData = await escrowVault.getVaultData();
// {
//      minter: Address;
//      jettonWallet: Address;
//      balance: bigint;
//      owner: Address;
// }
```

The getter returns:

* **null or zero address (`0:0`)** – no fees accrued yet for this jetton
* **vault address** – your dedicated Escrow Fee-Vault contract for this jetton

### 2 · Withdraw the fees

To withdraw accumulated fees, call `sendVaultWithdrawTokens()` on your vault:

```ts
// amount is in jetton base units; adjust for decimals (e.g., 1_000_000n = 1 USDT for 6-decimal tokens)
const amount = 1_000_000n; // 1 USDT

if (vaultData.owner.toString() !== ownerAddress.toString()) {
    throw new Error('Sender is not the owner of the vault');
}
if (vaultData.balance < amount) {
    throw new Error('Not enough tokens in the vault');
}

await escrowVault.sendVaultWithdrawTokens(provider.sender(), toNano('0.2'), { // ~0.2 TON for gas (may vary)
    queryId: 0n,
    amount: amount,
    excesses: ownerAddress,
    withdrawForwardParams: null,
});
```

The complete flow consists of **three or four on-chain calls**:

| Step            | Contract       | Method                                       | Purpose                                        |
| --------------- | -------------- | -------------------------------------------- | ---------------------------------------------- |
| Read            | Jetton Master  | `getWalletAddress(escrowMinter.address)`     | Get Escrow Minter's jetton wallet              |
| Read            | Escrow Minter  | `getVaultAddress(escrowMinterWallet, owner)` | Get your vault address                         |
| Read (optional) | Your Fee-Vault | `getVaultData()`                             | Check balance and ownership before withdrawing |
| Write           | Your Fee-Vault | `sendVaultWithdrawTokens()`                  | Transfer accumulated fees to your wallet       |

> **API status** At the moment, Omniston does not expose Escrow referral fees via the public REST API. To track these fees you should use the on-chain flow described above or your own indexer until the omni-fees API is released.

***

## Summary

| Protocol   | Fee mechanism                                           | Range      | How to receive funds                                       |
| ---------- | ------------------------------------------------------- | ---------- | ---------------------------------------------------------- |
| **DEX v1** | Direct payment inside the swap tx                       | 0.1 %      | Automatic                                                  |
| **DEX v2** | Fees accrue in a vault (*token × referrer*)             | 0.01 – 1 % | UI or code withdrawal                                      |
| **DeDust** | Token-aware vaults (one per jetton)                     | 0.01 – 1 % | TON: instant, Jettons: `getVaultAddress` → `collectFees()` |
| **Tonco**  | Token-aware vaults (same flow as DeDust)                | 0.01 – 1 % | TON: instant, Jettons: `getVaultAddress` → `collectFees()` |
| **Escrow** | Token-aware vaults (different contracts than cross-dex) | 0.01 – 1 % | `getVaultAddress` → `sendVaultWithdrawTokens()`            |

## Stats & Vaults API Endpoints

In addition to on-chain reading or direct contract calls, you can track and manage referral fees using our REST API.

> **Scope note** These endpoints expose referral data **only for STON.fi DEX pools**. They **do not** return Omniston-level referral data for routes executed on **DeDust, Tonco, or Escrow**. A dedicated API for omni referral fees (covering DeDust/Tonco/Escrow volume) is planned but not available yet. Referral-fee vault endpoints (`fee_vaults`, `fee_accruals`, `fee_withdrawals`) apply only to **DEX v2**, because vaults do not exist in DEX v1.

* **GET** `/v1/wallets/{addr_str}/fee_vaults`\
  Lists all referral fee vaults for **STON.fi DEX v2** (one vault per `referrer × token`).\
  DEX v1 does not use vaults, so this endpoint will not show v1-only referral activity.
* **GET** `/v1/stats/fee_accruals`\
  Returns one row per referral-fee accrual recorded in **STON.fi DEX v2 referral fee vaults**.\
  The underlying dataset is built from vault operations filtered by owner and time range, so **DEX v1 referral fees (paid directly to referrer wallets) are not included**.
* **GET** `/v1/stats/fee_withdrawals`\
  Shows withdrawals from **DEX v2** referral fee vaults.\
  There are no v1 entries here, as DEX v1 referral fees are never stored in vaults.
* **GET** `/v1/stats/fees`\
  Returns aggregated referral fee metrics (e.g. total accrued USD value) over a time period.\
  Use the Swagger docs for the exact filters supported (e.g. by referrer, token, or time range).
* **Swagger UI** Access the interactive API documentation at <https://api.ston.fi/swagger-ui/#/>.

***

### Additional Resources

**Implementation guides:**

* [Node.js SDK - Quote Requests](https://docs.ston.fi/developer-section/sdk/nodejs#send-a-quote-request)
* [React SDK - Quote Requests](https://docs.ston.fi/developer-section/sdk/react#send-a-quote-request)
* [gRPC API - Trader Flow](https://docs.ston.fi/developer-section/swap/grpc#typical-flow-traders)
* [WebSocket API - Quote Subscription](https://docs.ston.fi/developer-section/swap#subscription-method-quote)

**Other resources:**

* [Omniston Quick‑start](https://docs.ston.fi/developer-section/quickstart/omniston)
* [Contact Support](https://docs.ston.fi/help/contact)
