---
# System prepended metadata

title: "\U0001F680 Thena 后端接入指南"

---

# 🚀 Thena 后端接入指南

> **面向后端开发者** | TypeScript + ethers.js v5

---

## 📋 快速导航

- [核心概念](#-核心概念)
- [合约地址](#-合约地址)
- [Quoter 报价](#-quoter-报价)
- [SwapX 交易](#-swapx-交易)
- [重要规范](#-重要规范)
- [快速上手](#-快速上手)

---

## 🎯 核心概念

### Thena 三种池类型

| 池类型 | 特点 | 适用场景 | 手续费 |
|:------|:-----|:---------|:------|
| 🔷 **Thena V3** | Algebra 集中流动性<br/>动态手续费 | 大额交易<br/>流动性集中 | **动态** |
| 🔶 **Thena Stable** | Curve 稳定币算法<br/>低滑点 | 稳定币交易<br/>(USDT/USDC) | **低** |
| 🔵 **Thena V2** | 传统 AMM (x*y=k) | 一般代币对 | **固定** |

### 枚举值对照表

```typescript
// 🔹 Quoter 使用的 PoolType
enum PoolType {
  THENA_STABLE = 9,   // Stable 池
  THENA_V3 = 10,      // V3 池
  THENA_V2 = 11       // V2 池
}

// 🔹 SwapX 使用的 SwapType
enum SwapType {
  THENA_STABLE = 3,   // Stable 池
  THENA_V3 = 4,       // V3 池
  THENA_V2 = 5        // V2 池
}
```

---

## 📍 合约地址

### BSC Mainnet 部署地址

```typescript
// ✅ 核心合约 (已部署)
export const CONTRACTS = {
  SWAPX:  "0x5145556d28db18ce643785a2cb7dc0fa8731011a",  // SwapX Router
  QUOTER: "0x5b18De3582e5eFDDFe8e9EA3fc38EaA191A72759",  // Quoter (已验证)
  
  // 🏭 Thena 工厂合约
  THENA_V3_FACTORY:     "0x30055F87716d3DFD0E5198C27024481099fB4A98",
  THENA_STABLE_FACTORY: "0xAFD89d21BdB66d00817d4153E055830B1c2B3970",
  
  // 💰 常用代币
  WBNB:  "0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c",
  THENA: "0xF4C8E32EaDEC4BFe97E0F595AdD0f4450a863a11",
  ETH:   "0x2170Ed0880ac9A755fd29B2688956BD959F933F8",
  USDT:  "0x55d398326f99059fF775485246999027B3197955"
};

// 🌐 RPC 节点
export const BSC_RPC = "https://bsc-dataseed1.binance.org/";
```

### 🔍 获取池地址

```typescript
// V3 池 (通过 ThenaV3Factory)
const poolV3 = await ThenaV3Factory.poolByPair(tokenA, tokenB);

// Stable 池 (stable = true)
const poolStable = await ThenaStableFactory.getPair(tokenA, tokenB, true);

// V2 池 (stable = false)
const poolV2 = await ThenaStableFactory.getPair(tokenA, tokenB, false);
```

---

## 📊 Quoter 报价

> **核心功能**：获取交易的预期输出金额（只读查询，不消耗 gas）

### 📐 数据结构

```typescript
interface Route {
  poolType: PoolType;    // 池类型 (9=Stable, 10=V3, 11=V2)
  tokenIn: string;       // 输入代币地址
  tokenOut: string;      // 输出代币地址
  fee: number;           // ⚠️ 固定为 0
  tickSpacing: number;   // 固定为 0
  hook: string;          // 固定为 AddressZero
  amountIn: string;      // 输入金额 (Wei)
  hookData: string;      // 固定为 "0x"
}
```

### 🔹 单路径报价

```typescript
const quoter = new ethers.Contract(QUOTER_ADDRESS, QUOTER_ABI, provider);

const route = {
  poolType: PoolType.THENA_V3,
  tokenIn: TOKEN_A,
  tokenOut: TOKEN_B,
  fee: 0,  // ⚠️ 所有池类型都设为 0
  tickSpacing: 0,
  hook: ethers.constants.AddressZero,
  amountIn: ethers.utils.parseEther("1"),
  hookData: "0x"
};

// 🎯 获取报价 (使用 callStatic)
const amountOut = await quoter.callStatic.quoteExactIn([route]);
console.log("预期输出:", ethers.utils.formatEther(amountOut));
```

### 🔹 多跳报价

```typescript
// 示例：ETH -> WBNB (V3) -> THENA (Stable)
const routes = [
  { poolType: PoolType.THENA_V3, tokenIn: ETH, tokenOut: WBNB, fee: 0, ... },
  { poolType: PoolType.THENA_STABLE, tokenIn: WBNB, tokenOut: THENA, fee: 0, ... }
];

const finalAmountOut = await quoter.callStatic.quoteExactIn(routes);
```

### 🔹 批量报价（找最优路径）

```typescript
// 🎯 一次性比较三种池类型
const routeBatches = [
  [{ poolType: PoolType.THENA_V3, ... }],      // V3
  [{ poolType: PoolType.THENA_STABLE, ... }],  // Stable
  [{ poolType: PoolType.THENA_V2, ... }]       // V2
];

const amountOuts = await quoter.callStatic.multicall(routeBatches);

// 找出最大输出
const bestIndex = amountOuts.reduce((max, curr, idx, arr) => 
  curr.gt(arr[max]) ? idx : max, 0
);
console.log(`最优路径: ${["V3", "Stable", "V2"][bestIndex]}`);
```

---

## 💱 SwapX 交易

> **核心功能**：执行代币交易（支持单跳和多跳）

### 📐 数据结构

```typescript
interface SwapDesc {
  swapType: SwapType;    // 交易类型 (3=Stable, 4=V3, 5=V2)
  tokenIn: string;       // 输入代币 (address(0) = 原生 BNB)
  tokenOut: string;      // 输出代币 (address(0) = 原生 BNB)
  poolAddress: string;   // 池地址
  fee: number;           // ⚠️ 固定为 0
  tickSpacing: number;   // 固定为 0
  hooks: string;         // 固定为 AddressZero
  hookData: string;      // 固定为 "0x"
}
```

### 🔹 基础交易流程

```typescript
const swapX = new ethers.Contract(SWAPX_ADDRESS, SWAPX_ABI, signer);

// 📝 步骤 1: ERC20 代币需要先授权
if (tokenIn !== ethers.constants.AddressZero) {
  await tokenContract.approve(SWAPX_ADDRESS, amountIn);
}

// 📝 步骤 2: 构建交易描述
const swapDesc = {
  swapType: SwapType.THENA_V3,
  tokenIn: TOKEN_A,
  tokenOut: TOKEN_B,
  poolAddress: POOL_ADDRESS,
  fee: 0,
  tickSpacing: 0,
  hooks: ethers.constants.AddressZero,
  hookData: "0x"
};

// 📝 步骤 3: 计算最小输出 (滑点保护)
const minAmountOut = expectedAmountOut.mul(9900).div(10000); // 1% 滑点

// 📝 步骤 4: 执行交易
const tx = await swapX.swap(
  [swapDesc],    // SwapDesc 数组 (支持多跳)
  tokenIn,       // feeToken (从哪个代币扣手续费)
  amountIn,
  minAmountOut,
  {
    value: isNativeBNB ? amountIn : 0,  // 原生 BNB 需要传 value
    gasLimit: 300000
  }
);

// 📝 步骤 5: 等待确认
const receipt = await tx.wait();
console.log("✅ 交易成功:", receipt.transactionHash);
```

### 🔹 原生 BNB 交易

```typescript
// BNB -> ERC20
await swapX.swap(
  [{ 
    tokenIn: ethers.constants.AddressZero,  // address(0) = BNB
    tokenOut: TOKEN_ADDRESS,
    ...
  }],
  ethers.constants.AddressZero,
  amountIn,
  minOut,
  { value: amountIn }  // ⚠️ 必须传 value
);

// ERC20 -> BNB
await token.approve(SWAPX, amountIn);  // 需要授权
await swapX.swap(
  [{ 
    tokenIn: TOKEN_ADDRESS,
    tokenOut: ethers.constants.AddressZero,  // address(0) = BNB
    ...
  }],
  TOKEN_ADDRESS,
  amountIn,
  minOut
);
```

---

## ⚡ 重要规范

### 🎯 核心要点

<table>
<tr>
<td width="50%">

#### ✅ 必须遵守

- **所有池的 `fee` 参数都设为 `0`**
- 原生 BNB 用 `address(0)` 表示
- Quoter 必须用 `callStatic` 调用
- ERC20 交易前必须先授权
- 金额使用 Wei 单位

</td>
<td width="50%">

#### 💡 推荐做法

- 使用 `multicall` 批量报价
- 设置合理滑点保护
- Gas limit 增加 20% buffer
- 监控交易事件获取实际输出
- 大额交易建议分批执行

</td>
</tr>
</table>

### 📊 代币地址处理

| 场景 | tokenIn | tokenOut | 注意事项 |
|:-----|:--------|:---------|:---------|
| 🟢 ERC20 → ERC20 | 代币地址 | 代币地址 | ✅ 需要授权 |
| 🔵 BNB → ERC20 | `address(0)` | 代币地址 | ✅ 传 `value` |
| 🔴 ERC20 → BNB | 代币地址 | `address(0)` | ✅ 需要授权 |

### 🎚️ 滑点设置

```typescript
const SLIPPAGE = {
  STABLE:   0.001,  // 0.1% - 稳定币对
  V3:       0.005,  // 0.5% - V3 池
  V2:       0.01,   // 1.0% - V2 池
  VOLATILE: 0.02    // 2.0% - 高波动
};

// 计算公式
const minOut = expectedOut.mul(Math.floor((1 - slippage) * 10000)).div(10000);
```

### ⛽ Gas 配置

```typescript
const GAS_LIMIT = {
  SINGLE_HOP: 300000,   // 单跳
  MULTI_HOP:  500000    // 多跳
};

// 动态估算
const estimate = await swapX.estimateGas.swap(...);
const gasLimit = estimate.mul(120).div(100);  // +20% buffer
```

---

## 🚦 注意事项

### 🔴 常见错误

| 错误信息 | 原因 | 解决方法 |
|:---------|:-----|:---------|
| `insufficient funds` | 余额不足 | 检查账户余额 |
| `min return not reached` | 滑点过大 | 增加滑点容忍度或重试 |
| `INSUFFICIENT_ALLOWANCE` | 授权不足 | 增加授权额度 |
| `pool not found` | 池不存在 | 检查代币地址或池类型 |
| `Transaction too old` | 截止时间过期 | 重新发起交易 |

### ⚠️ 关键提醒

<table>
<tr>
<td>

**🔸 手续费参数**
- ⚠️ **所有 Thena 池 `fee` 都设为 `0`**
- Thena V3 使用动态手续费
- 不需要手动指定费率

</td>
<td>

**🔸 池地址获取**
- V3: `poolByPair(tokenA, tokenB)`
- Stable: `getPair(tokenA, tokenB, true)`
- V2: `getPair(tokenA, tokenB, false)`

</td>
</tr>
<tr>
<td>

**🔸 报价方法**
- ✅ 使用 `callStatic.quoteExactIn()`
- ❌ 不能直接调用 `quoteExactIn()`
- Quoter 通过 revert 返回结果

</td>
<td>

**🔸 原生代币**
- BNB = `address(0)`
- 自动处理 wrap/unwrap
- 传 `value` 参数

</td>
</tr>
</table>

---

## 🎓 快速上手

### 示例 1: Thena V3 交易

```typescript
// 1️⃣ 初始化
const provider = new ethers.providers.JsonRpcProvider(BSC_RPC);
const signer = new ethers.Wallet(PRIVATE_KEY, provider);
const quoter = new ethers.Contract(QUOTER_ADDRESS, QUOTER_ABI, provider);
const swapX = new ethers.Contract(SWAPX_ADDRESS, SWAPX_ABI, signer);

// 2️⃣ 获取池地址
const factory = new ethers.Contract(THENA_V3_FACTORY, FACTORY_ABI, provider);
const pool = await factory.poolByPair(tokenA, tokenB);

// 3️⃣ 报价
const route = { 
  poolType: PoolType.THENA_V3, 
  tokenIn: tokenA, 
  tokenOut: tokenB, 
  fee: 0, 
  amountIn: ethers.utils.parseEther("1"),
  tickSpacing: 0,
  hook: ethers.constants.AddressZero,
  hookData: "0x"
};
const expectedOut = await quoter.callStatic.quoteExactIn([route]);

// 4️⃣ 授权
const token = new ethers.Contract(tokenA, ERC20_ABI, signer);
await token.approve(SWAPX_ADDRESS, amountIn);

// 5️⃣ 交易
const minOut = expectedOut.mul(9950).div(10000); // 0.5% 滑点
await swapX.swap(
  [{ swapType: SwapType.THENA_V3, tokenIn: tokenA, tokenOut: tokenB, poolAddress: pool, fee: 0, tickSpacing: 0, hooks: ethers.constants.AddressZero, hookData: "0x" }],
  tokenA,
  amountIn,
  minOut,
  { gasLimit: 300000 }
);
```

### 示例 2: 找最优路径

```typescript
// 🎯 批量比较三种池类型
const amountIn = ethers.utils.parseEther("1");
const routes = [
  [{ poolType: PoolType.THENA_V3, tokenIn, tokenOut, fee: 0, amountIn, ... }],
  [{ poolType: PoolType.THENA_STABLE, tokenIn, tokenOut, fee: 0, amountIn, ... }],
  [{ poolType: PoolType.THENA_V2, tokenIn, tokenOut, fee: 0, amountIn, ... }]
];

const results = await quoter.callStatic.multicall(routes);
const bestIdx = results.reduce((max, curr, i, arr) => curr.gt(arr[max]) ? i : max, 0);

console.log("最优池:", ["V3", "Stable", "V2"][bestIdx]);
console.log("预期输出:", ethers.utils.formatEther(results[bestIdx]));
```

### 示例 3: BNB 交易

```typescript
// BNB -> Token
await swapX.swap(
  [{ 
    swapType: SwapType.THENA_V3,
    tokenIn: ethers.constants.AddressZero,  // BNB
    tokenOut: TOKEN_ADDRESS,
    poolAddress: pool,
    fee: 0,
    tickSpacing: 0,
    hooks: ethers.constants.AddressZero,
    hookData: "0x"
  }],
  ethers.constants.AddressZero,
  amountIn,
  minOut,
  { 
    value: amountIn,  // ⚠️ 必须传 value
    gasLimit: 300000 
  }
);
```

---

## 📚 参考资源

- 🌐 [Thena 官方文档](https://docs.thena.fi/)
- 📖 [ethers.js v5 文档](https://docs.ethers.io/v5/)
- 🔍 [BSC 浏览器](https://bscscan.com/)
- 🔗 [Quoter 合约](https://bscscan.com/address/0x5b18De3582e5eFDDFe8e9EA3fc38EaA191A72759)
- 🔗 [SwapX 合约](https://bscscan.com/address/0x5145556d28db18ce643785a2cb7dc0fa8731011a)

---

<div align="center">

**📝 文档版本**: v1.0  
**📅 最后更新**: 2025-01-12  
**💡 技术支持**: 参考合约源码或联系开发团队

</div>
