four-flap-meme-sdk
Version:
SDK for Flap bonding curve and four.meme TokenManager
2,337 lines (1,779 loc) • 139 kB
Markdown
# four-flap-meme-sdk 中文文档
本 SDK 面向 **four.meme** 与 **Flap Protocol** 两大平台,提供完整的「登录/上传/创建/交易/报价/读取状态」全链路集成。本文档专为**完全零基础**用户设计,无需任何平台使用经验,我们将详细讲解每个概念、方法和参数。
## 为什么使用这个 SDK?
这个 SDK 能帮你:
- **发行代币**:只需几行代码就能在 four.meme 或 Flap Protocol 上发币
- **交易代币**:使用联合曲线机制(bonding curve)进行买卖
- **查询状态**:实时获取代币价格和市场数据
- **理解平台**:全面掌握两大 DeFi 发币平台的运作原理
## 运行要求
- **Node.js**: 18 或更高版本(使用原生 fetch API)
- **模块类型**: ESM (NodeNext)
- **依赖库**:
- `ethers@^6` - 以太坊交互库
## 安装
```bash
npm i four-flap-meme-sdk ethers
```
可选(使用 Pinata 上传 IPFS)
```bash
npm i pinata
```
## 浏览器环境支持
SDK 已内置 Cloudflare Workers 代理,**浏览器环境可直接使用,无需额外配置 CORS**:
```typescript
import { FourClient } from 'four-flap-meme-sdk';
// 直接创建,默认使用已配置好的 CORS 代理
const fourClient = new FourClient();
```
---
## 目录
### 📘 平台概览
- [four.meme 是什么?](#fourmeme-是什么)
- [Flap Protocol 是什么?](#flap-protocol-是什么)
- [理解联合曲线](#理解联合曲线)
- [内盘与外盘](#内盘与外盘)
### 🎯 four.meme
- [平台架构](#fourmeme-平台架构)
- [代币发行流程](#代币发行流程)
- [一键发行(最简单)](#一键发行代币)
- [分步发行(高级)](#分步发行)
- [代币交易](#在fourmeme上交易)
- [价格估算](#价格估算)
- [买入代币](#买入代币)
- [卖出代币](#卖出代币)
- [自动路由(V1/V2)](#自动路由)
- [错误处理](#错误处理)
- [MPC 专属代币](#mpc-专属代币)
- [完整 API 参考](#fourmeme-api-参考)
### 🚀 Flap Protocol
- [平台架构](#flap-平台架构)
- [读取代币状态](#读取代币状态)
- [CDPV2 联合曲线](#cdpv2-联合曲线)
- [价格报价](#flap-价格报价)
- [代币兑换](#代币兑换)
- [创建代币](#在flap上创建代币)
- [靓号地址](#靓号地址)
- [上传代币元数据](#上传代币元数据)
- [错误处理](#flap-错误处理)
- [常量定义](#flap-常量定义)
- [完整 API 参考](#flap-api-参考)
### 🔐 48.club 私有交易
- [48.club 是什么?](#48club-是什么)
- [私有交易的优势](#私有交易的优势)
- [Four.meme 私有交易](#fourmeme-私有交易)
- [Flap Protocol 私有交易](#flap-protocol-私有交易)
- [48SP 模式与配置](#48sp-模式与配置)
- [底层 48.club API](#底层-48club-api)
### 📚 附录
- [常量与地址](#常量与地址)
- [BigInt 与单位](#bigint-与单位)
- [常用模式](#常用模式)
- [常见问题](#常见问题)
### 🔎 获取代币 LP 信息(内盘/外盘一键识别)
SDK 提供 `inspectTokenLP(token, opts)` 工具:输入代币地址,自动识别该代币属于 four 内盘、Flap 内盘,或 Pancake V2/V3 外盘;若为外盘则返回与 WBNB/USDT 的交易对与储备量;若为内盘则返回曲线储备/供应量等可展示数据。
最小用法(BSC)
```typescript
import { inspectTokenLP } from 'four-flap-meme-sdk';
const info = await inspectTokenLP('0xToken', {
chain: 'BSC',
rpcUrl: 'https://bsc-dataseed.binance.org',
flapChain: 'BSC', // 需要识别 Flap 时传入
});
console.log(info);
```
可选:通过路由自动解析工厂地址
```typescript
const info = await inspectTokenLP('0xToken', {
chain: 'BSC',
rpcUrl,
routerV2: '0x10ED43C718714eb63d5aA57B78B54704E256024E', // Pancake V2 Router
routerV3: '0x13f4EA83D0bd40E75C8222255bc855a974568Dd4', // Pancake V3 Router
// 或直接 factoryV2/factoryV3 覆盖
});
```
返回结构示例
```typescript
// four 内盘
{ platform: 'FOUR', four: { helper: '0x...', reserveNative: '123456...', offerTokens: '7890...', lastPrice: '1234...' } }
// flap 内盘
{ platform: 'FLAP', flap: { quoteToken: '0x...', reserveNative: '...', circulatingSupply: '...', price: '...' } }
// 外盘 V2
{ platform: 'PANCAKE_V2', v2: {
wbnbPair: { address: '0x...', reserveToken: '...', reserveWBNB: '...' },
usdtPair: { address: '0x...', reserveToken: '...', reserveUSDT: '...' }
}}
// 外盘 V3(多费档)
{ platform: 'PANCAKE_V3', v3: [
{ base: 'WBNB', fee: 500, pool: '0x...', tokenBalance: '...', baseBalance: '...' },
{ base: 'USDT', fee: 2500, pool: '0x...', tokenBalance: '...', baseBalance: '...' }
]}
```
---
# 平台概览
## four.meme 是什么?
**four.meme** 是一个代币发行平台,使用**联合曲线**(bonding curve)机制在 DEX 上市前进行价格发现。
### 核心概念:
1. **联合曲线阶段**:
- 代币刚创建时,不在 DEX 上
- 价格由数学公式(联合曲线)决定
- 随着购买增加,价格自动上涨
- 随着卖出增加,价格自动下降
2. **迁移到 DEX**:
- 当筹集足够资金(达到阈值)时,代币"毕业"
- 自动在 PancakeSwap(BSC)上添加流动性
- 之后像普通 DEX 代币一样交易
3. **版本说明**:
- **V1 (TokenManager)**: 原始版本,仍在使用
- **V2 (TokenManager2)**: 改进版本,功能更多
- **Helper3**: 辅助合约,用于价格估算和交易路由
### 为什么使用 four.meme?
- **公平发行**: 所有人以相同的联合曲线价格购买
- **防止 Rug Pull**: 流动性自动添加到 DEX
- **早期参与**: 在 DEX 上市前以较低价格买入
---
## Flap Protocol 是什么?
**Flap Protocol** 是另一个代币发行平台,具有高级联合曲线功能(CDPV2 曲线)。
### 核心特性:
1. **高级联合曲线 (CDPV2)**:
- 更灵活的曲线参数:`r`、`h`、`k`
- 更好的价格发现机制
- 可自定义迁移阈值
2. **多链支持**:
- BSC(币安智能链)
- Base
- X Layer
- Morph
3. **报价代币选项**:
- 可使用原生代币(BNB、ETH)发行
- 可使用 ERC20 代币(USDT 等)发行
4. **税费与迁移器选项**:
- 设置自定义税率
- 选择 V2 或 V3 迁移器进入 DEX
---
## 理解联合曲线
### 什么是联合曲线?
**联合曲线**是一个数学公式,根据供应量决定代币价格。
#### 简单例子:
想象一个代币有这样的规则:
- 前 1000 个代币:每个 $0.01
- 接下来 1000 个:每个 $0.02
- 再接下来 1000 个:每个 $0.03
- 依此类推...
**联合曲线**用平滑的公式实现这一点,而不是分段。
### 公式 (CDPV2):
```
价格 = k / (1,000,000,000 + h - 供应量)²
```
其中:
- `k`: 常数,影响整体价格水平
- `h`: 高度调整(曲线偏移)
- `供应量`: 当前流通供应量
### 为什么重要:
- **早期买家**: 获得更低价格
- **价格上涨**: 随供应增长自动上涨
- **可预测**: 任何人都可以计算价格
- **防操纵**: 不会像 DEX 订单那样被抢跑
---
## 内盘与外盘
在代币发行平台中,有两个重要的交易阶段概念:
### 🔵 内盘(Bonding Curve 阶段)
**定义**:代币在联合曲线上交易的阶段,尚未迁移到 DEX。
**特点**:
- ✅ **价格由公式决定**:使用数学曲线(如 CDPV2)计算价格
- ✅ **流动性锁定**:所有资金锁定在平台合约中
- ✅ **防止 Rug Pull**:开发者无法提取流动性
- ✅ **公平价格发现**:所有人以相同曲线价格买卖
- ✅ **即时成交**:不需要订单簿或对手方
- ✅ **可预测性**:可以精确计算买入/卖出价格
**在 four.meme 和 Flap Protocol 上**:
- 代币刚创建时处于内盘阶段
- 使用 `FourClient` 或 `FlapPortalWriter` 进行交易
- 价格随着买卖自动调整
- 示例:`status = 1`(可交易状态)
**内盘交易示例**:
```typescript
// 在内盘(联合曲线)上买入代币
const txHash = await writer.swapExactInput({
inputToken: ZERO_ADDRESS,
outputToken: tokenAddress,
inputAmount: parseEther('1.0'),
minOutputAmount: minAmount
});
```
### 🟢 外盘(DEX 阶段)
**定义**:代币已"毕业"并迁移到去中心化交易所(DEX)的阶段。
**特点**:
- ✅ **市场定价**:价格由供需关系决定,不再使用曲线
- ✅ **DEX 流动性池**:在 PancakeSwap、Uniswap 等 DEX 上交易
- ✅ **自由交易**:可以在任何支持的 DEX 和聚合器上交易
- ✅ **更大流动性**:通常流动性更深,滑点更小
- ✅ **标准 ERC20**:像普通代币一样交易
**迁移条件**:
- four.meme:当筹集的资金达到特定阈值(如 24 BNB)
- Flap Protocol:当储备金达到 `dexThresh`(可配置)
**迁移后**:
- 平台合约自动将流动性添加到 DEX
- 联合曲线关闭,无法再通过平台交易
- 代币状态变为 `status = 4`(已迁移到 DEX)
**外盘交易示例**:
```typescript
// 代币已迁移到 DEX,使用 DEX 路由交易
// 例如使用 Uniswap SDK 或 PancakeSwap SDK
import { SwapRouter } from '@uniswap/v3-sdk';
// ... 使用标准 DEX 交易方法
```
### 📊 内盘 vs 外盘对比
| 特性 | 内盘(Bonding Curve) | 外盘(DEX) |
|------|----------------------|------------|
| **价格机制** | 数学公式(联合曲线) | 市场供需 |
| **流动性来源** | 平台合约 | DEX 流动性池 |
| **交易方式** | 通过平台合约 | 通过 DEX(PancakeSwap/Uniswap) |
| **价格可预测性** | 高(可精确计算) | 低(市场波动) |
| **滑点** | 取决于曲线参数 | 取决于流动性深度 |
| **阶段** | 早期阶段 | 成熟阶段 |
| **SDK 使用** | `FourClient` / `FlapPortalWriter` | DEX SDK(Uniswap/PancakeSwap) |
| **代币状态** | `status = 1` | `status = 4` |
### 🔄 从内盘到外盘的迁移过程
1. **内盘阶段**:代币在联合曲线上交易
2. **达到阈值**:储备金达到迁移阈值
3. **自动迁移**:平台合约自动触发迁移
4. **添加流动性**:将储备金和代币添加到 DEX
5. **外盘阶段**:代币在 DEX 上自由交易
**如何检查代币在哪个阶段?**
```typescript
import { FlapPortal } from 'four-flap-meme-sdk';
const portal = new FlapPortal({ chain: 'BSC', rpcUrl });
const state = await portal.getTokenV5(tokenAddress);
if (state.status === 1) {
console.log('✅ 内盘:代币在联合曲线上交易');
console.log('储备金:', state.reserve);
console.log('迁移阈值:', state.dexSupplyThresh);
} else if (state.status === 4) {
console.log('✅ 外盘:代币已迁移到 DEX');
console.log('请在 PancakeSwap/Uniswap 上交易');
}
```
**重要提示**:
- ⚠️ 代币迁移到 DEX 后,无法再通过平台合约交易
- ⚠️ 迁移是单向的,不可逆转
- ⚠️ 迁移后需要使用 DEX 交易工具(如 PancakeSwap、Uniswap)
---
# four.meme 平台指南
## four.meme 平台架构
four.meme 有**三个主要组件**:
### 1. **REST API**(后端)
- 用户认证(nonce + 签名)
- 图片上传(代币图标)
- 代币元数据管理
- 创建参数生成
### 2. **智能合约**(链上)
- **TokenManagerV1**: 原始代币管理器
- **TokenManagerV2**: 改进的代币管理器
- **TokenManagerHelper3**: 辅助合约(价格估算和路由)
### 3. **本 SDK**(你的接口)
- 简化所有 REST API 调用
- 封装智能合约交互
- 提供 V1/V2 统一接口
---
## 代币发行流程
在 four.meme 上发行代币需要 **5个步骤**:
```
1. 生成 Nonce → 从服务器获取随机字符串
2. 签名消息 → 用钱包签名证明所有权
3. 登录 → 获取访问令牌
4. 上传图片 → 上传代币 logo/图标
5. 链上创建 → 部署代币合约
```
### 为什么需要这个流程?
- **认证**: 证明你拥有钱包
- **安全**: 访问令牌防止未授权操作
- **元数据**: 服务器存储代币链下信息
- **去中心化**: 实际代币在链上,不受服务器控制
---
## 一键发行代币
### 最简单的方式
使用 `createTokenFlow()` 自动处理全部 5 个步骤:
```typescript
import { createTokenFlow } from 'four-flap-meme-sdk';
const result = await createTokenFlow({
rpcUrl: 'https://bsc-dataseed.binance.org',
privateKey: '0x...你的私钥',
networkCode: 'BSC',
// 可选:提供已上传的图片 URL
imgUrl: 'https://...',
// 或者:上传新图片
image: imageBlob,
// 或者:使用本地文件路径由 SDK 读取上传(二选一)
// imagePath: '/absolute/path/to/logo.png',
// 可选:覆盖默认初始金额 b0(默认 '8' BNB)
// b0Amount: '8',
payload: {
name: '我的超棒代币', // 全名
shortName: 'MAT', // 符号(代码)
desc: '一个革命性的代币', // 描述
label: 'Meme', // 类别
preSale: '0', // 预购金额:'0' = 不购买,'0.5' = 购买 0.5 BNB
onlyMPC: false, // MPC 专属模式(后面解释)
// 可选的社交链接
webUrl: 'https://example.com',
twitterUrl: 'https://twitter.com/...',
telegramUrl: 'https://t.me/...',
}
});
console.log('代币已创建!');
console.log('交易哈希:', result.txReceipt.transactionHash);
console.log('你的地址:', result.accountAddress);
```
### 参数说明:
| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| `rpcUrl` | string | ✅ | 区块链 RPC 端点(BSC、Arbitrum 等)|
| `privateKey` | string | ✅ | 你的钱包私钥(请保密!)|
| `networkCode` | 'BSC' | ✅ | 目前仅支持 BSC |
| `baseUrl` | string | ❌ | four.meme API 地址(默认:https://four.meme/meme-api)|
| `image` | Blob | ❌* | 要上传的图片文件(*如无 imgUrl 则必填)|
| `imgUrl` | string | ❌* | 已上传的图片 URL(*如无 image 则必填)|
| `imagePath` | string | ❌* | 本地图片文件路径(与 image/imgUrl 互斥,三选一)|
| `b0Amount` | string | ❌ | 初始金额(BNB),默认 '8',会与 `preSale` 一起发送 |
### Payload 字段:
| 字段 | 类型 | 必填 | 说明 |
|------|------|------|------|
| `name` | string | ✅ | 代币全名(如"比特币")|
| `shortName` | string | ✅ | 代币符号(如"BTC")|
| `desc` | string | ✅ | 代币描述 |
| `label` | string | ✅ | 类别:'Meme'、'AI'、'Defi'、'Games'、'Infra'、'De-Sci'、'Social'、'Depin'、'Charity'、'Others' |
| `preSale` | string | ✅ | BNB 预购金额(发币时自己先购买)。例:'0' = 不购买,'0.1' = 购买 0.1 BNB,'1' = 购买 1 BNB |
| `onlyMPC` | boolean | ❌ | 如为 true,仅 MPC 钱包可购买(防机器人)|
| `launchTime` | number | ❌ | 发行时间戳(毫秒,默认:当前时间)|
| `webUrl` | string | ❌ | 项目网站 |
| `twitterUrl` | string | ❌ | Twitter/X 账号 |
| `telegramUrl` | string | ❌ | Telegram 群组/频道 |
### 返回值:
```typescript
{
accountAddress: string, // 你的钱包地址
accessToken: string, // JWT 令牌(用于后续 API 调用)
imgUrl: string, // 上传的图片 URL
api: {
createArg: string, // 发送到合约的编码参数
signature: string, // 服务器验证签名
},
txReceipt: any, // 区块链交易回执
tokenAddress?: string // 可选:新创建代币地址(若可从事件解析)
}
```
---
## 分步发行
### 高级用户
如需更多控制,可使用单独的方法:
### 步骤 1: 生成 Nonce
```typescript
import { FourClient } from 'four-flap-meme-sdk';
const four = new FourClient();
const nonce = await four.generateNonce({
accountAddress: '0x...你的地址',
verifyType: 'LOGIN',
networkCode: 'BSC'
});
```
**作用**: 从服务器获取随机 nonce(防止重放攻击)。
### 步骤 2: 签名登录消息
```typescript
import { buildLoginMessage } from 'four-flap-meme-sdk';
import { Wallet } from 'ethers';
const wallet = new Wallet(privateKey);
const message = buildLoginMessage(nonce); // "You are sign in Meme {nonce}"
const signature = await wallet.signMessage(message);
```
**作用**: 创建签名消息,证明你拥有该钱包。
### 步骤 3: 登录获取访问令牌
```typescript
const accessToken = await four.loginDex({
region: 'WEB',
langType: 'ZH',
walletName: 'MetaMask',
verifyInfo: {
address: '0x...你的地址',
networkCode: 'BSC',
signature: signature,
verifyType: 'LOGIN'
}
});
```
**作用**: 用签名换取访问令牌(类似 session cookie)。
### 步骤 4: 上传图片
```typescript
const imgUrl = await four.uploadImage(accessToken, imageBlob);
```
**作用**: 上传代币 logo 到 four.meme 的 CDN,返回 URL。
### 步骤 5: 获取创建参数
```typescript
const { createArg, signature } = await four.createToken(accessToken, {
name: '我的代币',
shortName: 'MTK',
desc: '描述',
imgUrl: imgUrl,
launchTime: Date.now(),
label: 'Meme',
lpTradingFee: 0.0025, // 固定为 0.25%
preSale: '0',
onlyMPC: false,
webUrl: 'https://...',
twitterUrl: 'https://...',
telegramUrl: 'https://...',
});
```
**作用**: 服务器生成并签名链上代币创建参数。
### 步骤 6: 链上创建代币
```typescript
import { createTokenOnChain } from 'four-flap-meme-sdk';
const receipt = await createTokenOnChain({
chain: 'BSC',
rpcUrl: 'https://bsc-dataseed.binance.org',
signerPrivateKey: privateKey,
args: createArg,
signature: signature,
});
console.log('代币已在交易中创建:', receipt.transactionHash);
```
**作用**: 向 TokenManager2 合约发送交易,部署你的代币。
---
## 在four.meme上交易
代币创建后,任何人都可以使用联合曲线买卖它。
### 交易流程概览
```
1. 估算价格(可选) → 查看能获得多少
2. 检查授权(仅卖出) → 允许 TokenManager 花费你的代币
3. 执行交易 → 买入或卖出
```
---
### 价格估算
**交易前**,应先估算成本/收益:
#### 估算买入价格
```typescript
import { tryBuy } from 'four-flap-meme-sdk';
// 选项 1: 用特定 BNB 金额买入(按资金)
const estimate = await tryBuy(
'BSC',
rpcUrl,
tokenAddress,
0n, // amount = 0 表示"按资金买入"
1n * 10n ** 18n // 1 BNB
);
console.log('你将大约获得:', estimate.estimatedAmount);
console.log('成本:', estimate.estimatedCost);
console.log('手续费:', estimate.estimatedFee);
// 选项 2: 买入特定代币数量
const estimate2 = await tryBuy(
'BSC',
rpcUrl,
tokenAddress,
10_000n * 10n ** 18n, // 买入 10,000 个代币
0n // funds = 0 表示"按数量买入"
);
console.log('将花费:', estimate2.estimatedCost, 'wei');
```
**返回值说明**:
```typescript
{
tokenManager: string, // 使用哪个 TokenManager 合约(V1 或 V2)
quote: string, // 报价代币地址(通常是 WBNB)
estimatedAmount: bigint, // 你将获得的代币数
estimatedCost: bigint, // 总成本(wei,含手续费)
estimatedFee: bigint, // 交易手续费(wei)
amountMsgValue: bigint, // 作为 msg.value 发送的 BNB
amountApproval: bigint, // 需要授权的金额(如使用报价代币)
amountFunds: bigint // 合约调用中使用的实际资金
}
```
#### 估算卖出价格
```typescript
import { trySell } from 'four-flap-meme-sdk';
const estimate = await trySell(
'BSC',
rpcUrl,
tokenAddress,
1_000n * 10n ** 18n // 卖出 1,000 个代币
);
console.log('你将获得:', estimate.funds, 'wei');
console.log('手续费:', estimate.fee, 'wei');
```
**返回值**:
```typescript
{
tokenManager: string, // 使用哪个 TokenManager
quote: string, // 报价代币地址
funds: bigint, // 你将获得的 BNB(扣除手续费后)
fee: bigint // 交易手续费
}
```
---
### 买入代币
有**三种方式**买入代币:
#### 方法 1: 简单买入(推荐)
使用 `buyTokenWithFunds()` 直接在 V2 上按资金买入:
```typescript
import { buyTokenWithFunds } from 'four-flap-meme-sdk';
await buyTokenWithFunds(
'BSC',
rpcUrl,
privateKey,
tokenAddress,
1n * 10n ** 18n, // 1 BNB
0n, // minAmount(滑点保护,可设 >0)
yourAddress // 可选接收地址
);
```
**参数说明**:
- `type: 'funds'`: 指定花费多少 BNB
- `type: 'amount'`: 指定买入多少代币
- `minAmount`/`maxFunds`: 滑点保护(防止价格变动导致不利交易)
- `to`: 可选接收地址(默认为你的地址)
- `origin`: 可选来源代码(用于推荐跟踪,默认:0n)
#### 方法 2: 直接买入(高级)
如果已知是 V2,使用 `buyTokenWithFunds()`:
```typescript
import { tryBuy, buyTokenWithFunds } from 'four-flap-meme-sdk';
// 首先,估算
const estimate = await tryBuy('BSC', rpcUrl, tokenAddress, 0n, 1n * 10n ** 18n);
// 然后买入
await buyTokenWithFunds(
'BSC',
rpcUrl,
privateKey,
tokenAddress,
estimate.amountFunds, // 使用估算的资金
0n, // minAmount(滑点)
yourAddress // 接收者
);
```
#### 方法 3: 使用 TM1/TM2 类(专家)
最大控制:
```typescript
import { TM2 } from 'four-flap-meme-sdk';
// 使用链枚举(SDK 自动处理合约地址)
const tm2 = TM2.connectByChain('BSC', rpcUrl);
// 按数量买入
await tm2.buyToken(
tokenAddress,
1_000n * 10n ** 18n, // 买入 1,000 个代币
2n * 10n ** 18n // 最多 2 BNB
);
// 按资金买入(AMAP = As Much As Possible 尽可能多)
await tm2.buyTokenAMAP(
tokenAddress,
1n * 10n ** 18n, // 花费 1 BNB
0n // 最少 0 个代币(无滑点保护)
);
```
---
### 卖出代币
卖出需要先**授权代币**(让 TokenManager 花费你的代币)。
#### 完整卖出流程
```typescript
import { ensureSellApproval, tradeSell } from 'four-flap-meme-sdk';
const tokenAddress = '0x...';
const amountToSell = 1_000n * 10n ** 18n; // 1,000 个代币
// 步骤 1: 授权 TokenManager 花费你的代币
await ensureSellApproval(
'BSC',
rpcUrl,
privateKey,
tokenAddress,
yourAddress,
amountToSell
);
// 步骤 2: 卖出
await tradeSell(
'BSC',
rpcUrl,
privateKey,
tokenAddress,
{
type: 'direct',
amount: amountToSell,
minFunds: 0n // 最少获得 BNB
}
);
```
**为什么需要授权?**
ERC20 代币卖出需要**两笔交易**:
1. **授权**: 给予 TokenManager 权限
2. **卖出**: 实际转移并获得 BNB
这是 ERC20 代币的安全特性。
#### 路由卖出(第三方应用)
如果你在构建路由器/聚合器:
```typescript
await tradeSell(
'BSC',
rpcUrl,
privateKey,
tokenAddress,
{
type: 'router',
from: userAddress, // 从用户钱包卖出
amount: amountToSell,
minFunds: 0n,
feeRate: 100n, // 1% 手续费(基点:100 = 1%)
feeRecipient: routerAddress // 手续费接收地址
}
);
```
---
### 自动路由
**什么是自动路由?**
four.meme 有两个版本(V1 和 V2),**接口不同**。SDK 提供统一方法,能:
1. 检测代币使用哪个版本
2. 调用正确的合约
3. 自动处理参数差异
#### 使用自动路由
```typescript
import { tradeBuy, tradeSell } from 'four-flap-meme-sdk';
// 对 V1 和 V2 代币都有效(当前签名不包含私钥)
await tradeBuy('BSC', rpcUrl, token, params);
await tradeSell('BSC', rpcUrl, token, params);
```
**幕后工作**:
1. 调用 `Helper3.getTokenInfo(token)`
2. 检查 `version` 字段(1 或 2)
3. 路由到 TM1 或 TM2
4. 自动适配参数
---
## 错误处理
four.meme 交易可能因各种原因失败。SDK 提供错误代码解析:
```typescript
import { parseFourError } from 'four-flap-meme-sdk';
try {
await tradeBuy('BSC', rpcUrl, token, params);
} catch (error) {
const { code, message } = parseFourError(error);
if (code === 'Slippage') {
console.error('价格变动太大!尝试增加滑点容忍度');
} else if (code === 'More BNB') {
console.error('发送的 BNB 不足:', message);
} else {
console.error('错误:', code, message);
}
}
```
### 错误代码参考
| 代码 | 描述 | 解决方案 |
|------|------|----------|
| `GW` | 金额未对齐到 GWEI | 四舍五入到 GWEI(除以 10^9)|
| `ZA` | 目标地址是零地址 | 提供有效接收地址 |
| `TO` | 不能发送到 PancakePair | 不要使用 LP 地址作为接收者 |
| `Slippage` | 价格变动太大 | 增加 minAmount/maxFunds 容忍度 |
| `More BNB` | msg.value 中 BNB 不足 | 发送更多 BNB 或检查估算 |
| `FR` | 手续费率 > 5% | 路由器手续费率必须 ≤ 5% |
| `SO` | 订单太小 | 增加交易金额 |
---
## MPC 专属代币
**什么是 MPC 专属?**
four.meme 上的某些代币标记为 **"MPC-only"**,意味着:
- 只有 **MPC 钱包**(多方计算钱包)可以购买
- 这是一个**防机器人**功能
- 普通 EOA(外部拥有账户)钱包被阻止
### 为什么使用 MPC 专属?
- **防止机器人**: 机器人通常使用简单的 EOA 钱包
- **公平发行**: 给真人用户更好的机会
- **减少操纵**: 更难被狙击或抢跑
### 如何检测 MPC 专属代币
#### 链上检测(推荐)
```typescript
import { isExclusiveOnChain } from 'four-flap-meme-sdk';
const isMPCOnly = await isExclusiveOnChain({
chain: 'BSC', // SDK 自动使用正确的代理合约地址
tokenAddress: '0x...',
rpcUrl: rpcUrl
});
if (isMPCOnly) {
console.log('此代币是 MPC 专属!');
console.log('你需要 MPC 钱包来交易');
}
```
**工作原理**: 检查代币的 `template` 字段。如果 `template & 0x10000 > 0`,则为 MPC 专属。
#### 链下检测(使用 API)
```typescript
import { isExclusiveOffChain, FourClient } from 'four-flap-meme-sdk';
const four = new FourClient();
const isMPCOnly = await isExclusiveOffChain(
(addr) => four.getTokenByAddress(addr),
tokenAddress
);
```
**工作原理**: 检查 API 响应中 `version === 'V8'`。
---
## four.meme API 参考
### FourClient 类
#### 构造函数
```typescript
const four = new FourClient({
baseUrl?: string // 默认:'https://four.meme/meme-api'
});
```
---
### 认证方法
#### generateNonce()
获取登录签名的随机 nonce。
```typescript
const nonce = await four.generateNonce({
accountAddress: string, // 你的钱包地址
verifyType: 'LOGIN', // 固定值
networkCode: 'BSC' // 固定值(目前)
});
```
**返回**: `Promise<string>` - nonce 字符串
---
#### buildLoginMessage()
构建要签名的登录消息。
```typescript
import { buildLoginMessage } from 'four-flap-meme-sdk';
const message = buildLoginMessage(nonce); // 返回:"You are sign in Meme {nonce}"
```
---
#### loginDex()
用签名换取访问令牌。
```typescript
const accessToken = await four.loginDex({
region: 'WEB', // 固定值
langType: 'EN' | 'ZH', // 语言偏好
walletName: string, // 如 'MetaMask'、'WalletConnect'
verifyInfo: {
address: string, // 你的钱包地址
networkCode: 'BSC', // 固定值
signature: string, // 签名 nonce 消息的签名
verifyType: 'LOGIN' // 固定值
}
});
```
**返回**: `Promise<string>` - JWT 访问令牌
---
### 代币管理方法
#### uploadImage()
上传代币图片到 CDN。
```typescript
const imgUrl = await four.uploadImage(
accessToken: string, // 来自 loginDex()
file: Blob // 图片文件(JPEG、PNG 等)
);
```
**返回**: `Promise<string>` - 图片 URL
---
#### createToken()
获取链上代币创建的签名参数。
```typescript
const { createArg, signature } = await four.createToken(
accessToken: string, // 来自 loginDex()
{
name: string, // 代币全名
shortName: string, // 代币符号
desc: string, // 描述
imgUrl: string, // 来自 uploadImage() 的图片 URL
launchTime: number, // 毫秒时间戳
label: string, // 类别(Meme、AI 等)
lpTradingFee: 0.0025, // 固定为 0.25%
preSale: string, // 预售金额(如 '0'、'0.1')
onlyMPC?: boolean, // MPC 专属标志
webUrl?: string, // 可选网站
twitterUrl?: string, // 可选 Twitter
telegramUrl?: string // 可选 Telegram
}
);
```
**返回**: `Promise<{ createArg: string, signature: string }>`
---
#### getTokenByAddress()
通过合约地址获取代币元数据。
```typescript
const tokenInfo = await four.getTokenByAddress(
address: string, // 代币合约地址
accessToken?: string // 可选访问令牌
);
```
**返回**: 代币元数据对象,包含 `name`、`symbol`、`imgUrl`、`version` 等字段。
---
#### getTokensByAddresses()(批量)
并发按地址数组批量获取 four.meme 代币元数据(任一失败不会中断,会在对应项返回 `{ address, error }`)。
```typescript
import { FourClient } from 'four-flap-meme-sdk';
const four = new FourClient();
const list = await four.getTokensByAddresses(
['0xA...', '0xB...', '0xC...'], // 代币地址数组
/* 可选 */ accessToken // four.meme 的访问令牌(无则传 undefined)
);
// 返回: any[],每一项为 tokenInfo 或 { address, error }
```
---
#### getTokenById()
通过代币 ID 获取代币元数据。
```typescript
const tokenInfo = await four.getTokenById(
id: string | number, // four.meme 的代币 ID
accessToken?: string // 可选访问令牌
);
```
---
#### getPublicConfig()
获取 four.meme 平台配置。
```typescript
const config = await four.getPublicConfig();
```
---
### 链上方法
#### createTokenOnChain()
在链上部署代币合约。
```typescript
import { createTokenOnChain } from 'four-flap-meme-sdk';
const { receipt, tokenAddress } = await createTokenOnChain({
chain: 'BSC', // 链名称
rpcUrl: string, // 区块链 RPC 端点
signerPrivateKey: string, // 你的私钥
args: BytesLike, // 来自 four.createToken()
signature: BytesLike, // 来自 four.createToken()
valueWei?: bigint // 可选发送的 BNB(用于预售)
});
console.log('已提交交易:', receipt.hash);
if (tokenAddress) console.log('代币地址:', tokenAddress);
```
**返回**: `{ receipt: TransactionReceipt, tokenAddress?: string }`
---
### 交易方法
#### tryBuy()
估算买入成本而不执行。
```typescript
import { tryBuy } from 'four-flap-meme-sdk';
const estimate = await tryBuy(
chain: 'BSC' | 'BASE' | 'ARBITRUM_ONE', // 链名称
rpcUrl: string,
token: string, // 代币地址
amount: bigint, // 代币数量(0 = 按资金买入)
funds: bigint // BNB 金额(0 = 按数量买入)
);
```
**返回**: `TryBuyResult` 对象,包含估算详情
---
#### trySell()
估算卖出收益而不执行。
```typescript
import { trySell } from 'four-flap-meme-sdk';
const estimate = await trySell(
chain: 'BSC' | 'BASE' | 'ARBITRUM_ONE', // 链名称
rpcUrl: string,
token: string,
amount: bigint // 要卖出的代币数量
);
```
**返回**: `TrySellResult`,包含 funds 和 fee
---
#### buyTokenWithFunds()
用特定 BNB 金额买入代币(V2 AMAP 方法)。
```typescript
import { buyTokenWithFunds } from 'four-flap-meme-sdk';
await buyTokenWithFunds(
chain: 'BSC', // 链名称
rpcUrl: string,
signerPrivateKey: string,
token: string,
funds: bigint, // 要花费的 BNB 金额
minAmount: bigint, // 最少接收代币数
to?: string, // 可选接收者
origin?: bigint // 可选来源代码(默认:0n)
);
```
---
#### sellToken()
卖出代币换 BNB(V2 方法)。
```typescript
import { sellToken } from 'four-flap-meme-sdk';
await sellToken(
chain: 'BSC', // 链名称
rpcUrl: string,
signerPrivateKey: string,
token: string,
amount: bigint, // 要卖出的代币数量
minFunds: bigint, // 最少接收 BNB
origin?: bigint // 可选来源代码(默认:0n)
);
```
**注意**: 需要先授权代币(先使用 `ensureSellApproval`)
---
#### tradeBuy()
自动路由买入方法(适用于 V1 和 V2)。
```typescript
import { tradeBuy } from 'four-flap-meme-sdk';
await tradeBuy(
chain: 'BSC' | 'BASE' | 'ARBITRUM_ONE', // 链名称
rpcUrl: string, // 区块链 RPC 节点
token: string, // 代币地址
params: {
type: 'funds' | 'amount', // 交易类型:按资金/按数量
funds?: bigint, // 当 type==='funds':花费的 BNB(wei)
minAmount?: bigint, // 当 type==='funds':最少接收代币(滑点保护)
amount?: bigint, // 当 type==='amount':买入代币数量(最小单位)
maxFunds?: bigint, // 当 type==='amount':最多花费 BNB(滑点保护)
to?: string, // 可选接收地址
origin?: bigint // 可选来源代码(默认 0n)
}
);
```
---
#### tradeSell()
自动路由卖出方法(适用于 V1 和 V2)。
```typescript
import { tradeSell } from 'four-flap-meme-sdk';
await tradeSell(
chain: 'BSC' | 'BASE' | 'ARBITRUM_ONE', // 链名称
rpcUrl: string, // 区块链 RPC 节点
token: string, // 代币地址
params: {
type: 'direct' | 'router', // 直接卖出 或 路由代卖
amount: bigint, // 卖出数量(最小单位)
minFunds?: bigint, // 最少接收 BNB(滑点保护)
from?: string, // 当 type==='router':用户钱包地址
feeRate?: bigint, // 当 type==='router':手续费基点(100=1%)
feeRecipient?: string // 当 type==='router':手续费接收地址
}
);
```
---
### 实用方法
#### 批量校验私钥
批量校验一组私钥是否合规(格式 + 椭圆曲线有效性)。
```typescript
import { validatePrivateKeys } from 'four-flap-meme-sdk';
const result = validatePrivateKeys([
// 支持多种输入形式:
'0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', // 标准 0x + 64 hex
'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb', // 无 0x 前缀
'c'.repeat(63) // 奇数/不足 64 位会自动左侧补零
]);
// 返回: Array<{ privateKey: string; valid: boolean; address?: string; normalized?: string; error?: string }>
// - valid 为 true:包含解析出的 address 与规范化后的 normalized(0x+64hex)
// - valid 为 false:给出 error(如 'INVALID_FORMAT' 或具体错误信息)
```
校验与规范化规则:
- 自动去掉可选的 0x 前缀;
- 验证是否为纯十六进制,长度不超过 64;
- 若为奇数或不足 64 位,将在左侧补 0 直至 64 位;
- 最终使用 `ethers.Wallet` 构造验证曲线有效性;
- 通过时返回规范化私钥 `normalized` 与地址 `address`。
#### 批量生成钱包地址与私钥
用于开发/测试环境快速生成指定数量的钱包。
```typescript
import { generateWallets } from 'four-flap-meme-sdk';
const wallets = generateWallets(5);
// 返回示例:
// [
// { address: '0xabc...', privateKey: '0x...' },
// { address: '0xdef...', privateKey: '0x...' },
// ...
// ]
```
注意:仅用于开发/测试。生产环境请安全保管私钥,不要明文存储或上传。
#### 使用 Multicall3 批量查询代币余额
```typescript
import { getTokenBalancesWithMulticall } from 'four-flap-meme-sdk';
const rpcUrl = 'https://bsc-dataseed.binance.org'; // 区块链 RPC 节点
const token = '0x...ERC20'; // 要查询的 ERC20 代币地址
const holders = ['0x...A', '0x...B', '0x...C']; // 持有人地址数组
// 简化签名:自动按链选择 Multicall3(未知链回退 ca11...ca11)
const results = await getTokenBalancesWithMulticall(
rpcUrl, // RPC 节点
token, // 代币地址
holders // 持有人地址数组
);
// results: [{ address, balance, success }, ...]
```
可选:如需显式覆盖 Multicall3 地址(向后兼容重载):
```typescript
const multicall3 = '0xYourMulticall3Address'; // 显式 Multicall3 合约地址
const results = await getTokenBalancesWithMulticall(
rpcUrl, // RPC 节点
multicall3, // Multicall3 合约地址
token, // 代币地址
holders // 持有人地址数组
);
```
说明:SDK 会根据网络 chainId 自动选择标准 Multicall3 地址(`0xca11bde05977b3631167028862be2a173976ca11`),无需手动传入。
新增:多代币 + 原生余额(推荐新用法)
```typescript
import { getTokenBalancesWithMulticall, type MultiTokenBalancesResult } from 'four-flap-meme-sdk';
const rpcUrl = 'https://bsc-dataseed.binance.org'; // 区块链 RPC 节点
const chain = 'BSC' as const; // 链名称:'BSC' | 'BASE' | 'XLAYER' | 'MORPH' | 'ARBITRUM_ONE'
const tokenAddresses = [ // 要同时查询的代币地址数组
'0x...ERC20_A',
'0x...ERC20_B'
];
const holders = ['0x...A', '0x...B', '0x...C']; // 持有人地址数组
const results: MultiTokenBalancesResult[] = await getTokenBalancesWithMulticall(
rpcUrl,
chain, // 链名称(用于自动选择 Multicall3 标准地址)
tokenAddresses, // 多个代币地址
holders // 要查询的持有人地址数组
);
// 结果结构:每个地址包含原生币余额与各代币余额(数组形式,顺序与 tokenAddresses 一致)
// [
// {
// address: '0x...A',
// native: '1.23456789', // 原生币余额(ETH/BNB 单位,字符串)
// tokens: [
// { token: '0x...ERC20_A', balance: '1.0' },
// { token: '0x...ERC20_B', balance: '2.5' }
// ],
// success: true
// },
// ...
// ]
```
也可不传 chain(自动按 RPC 网络识别 Multicall3 地址):
```typescript
const results2 = await getTokenBalancesWithMulticall(
rpcUrl,
tokenAddresses, // 多个代币地址
holders // 要查询的持有人地址数组
);
```
说明:
- 该新签名会同时返回每个地址的原生币余额(native)与传入数组中各代币的余额(tokens 映射)。
- Multicall3 地址将按 `chain` 自动选择;未知链将回退到标准地址 `0xca11...ca11`。
- 若某些解码失败,对应条目的 `success` 为 `false`,余额字段回退为 `0n`。
也可直接传 `chainId`(数字):
```typescript
const results3 = await getTokenBalancesWithMulticall(
rpcUrl,
56, // chainId(示例:BSC 主网 56)
tokenAddresses,
holders
);
```
#### 代币授权方法
SDK 提供了**多种授权方法**,以支持不同的 TokenManager 版本(V1/V2)和平台(four.meme/Flap Protocol)。
##### Four.meme 代币授权
**V1 代币授权**:
```typescript
import { checkSellApprovalV1, ensureSellApprovalV1 } from 'four-flap-meme-sdk';
// 检查 V1 授权状态(只读)
const status = await checkSellApprovalV1(
'BSC', // 支持:'BSC' | 'BASE' | 'ARBITRUM_ONE'
rpcUrl,
tokenAddress,
ownerAddress,
amount
);
// 确保 V1 授权(如需要则发送交易)
const result = await ensureSellApprovalV1(
'BSC',
rpcUrl,
privateKey,
tokenAddress,
ownerAddress,
amount
);
```
**V2 代币授权**:
```typescript
import { checkSellApprovalV2, ensureSellApprovalV2 } from 'four-flap-meme-sdk';
// 检查 V2 授权状态(只读)
const status = await checkSellApprovalV2(
'BSC', // 支持:'BSC' | 'BASE' | 'ARBITRUM_ONE'
rpcUrl,
tokenAddress,
ownerAddress,
amount
);
// 确保 V2 授权(如需要则发送交易)
const result = await ensureSellApprovalV2(
'BSC',
rpcUrl,
privateKey,
tokenAddress,
ownerAddress,
amount
);
```
**通用方法(默认使用 V2)**:
```typescript
import { checkSellApproval, ensureSellApproval } from 'four-flap-meme-sdk';
// 检查授权(默认使用 V2)
const status = await checkSellApproval(
'BSC',
rpcUrl,
tokenAddress,
ownerAddress,
amount
);
// 确保授权(默认使用 V2)
const result = await ensureSellApproval(
'BSC',
rpcUrl,
privateKey,
tokenAddress,
ownerAddress,
amount
);
```
##### Flap Protocol 代币授权
```typescript
import {
checkFlapSellApproval,
ensureFlapSellApproval,
checkFlapSellApprovalBatch,
ensureFlapSellApprovalBatch
} from 'four-flap-meme-sdk';
// 检查 Flap 授权状态(只读)
const status = await checkFlapSellApproval(
'BSC', // 支持:'BSC' | 'BASE' | 'XLAYER' | 'MORPH'
rpcUrl,
tokenAddress,
ownerAddress,
amount
);
// 确保 Flap 授权(如需要则发送交易)
const result = await ensureFlapSellApproval(
'BSC',
rpcUrl,
privateKey,
tokenAddress,
ownerAddress,
amount
);
```
批量检查/授权(默认按上限授权,无需传数额):
```typescript
// 批量检查(owners: 地址数组;默认 required = 2^256 - 1)
const checkList = await checkFlapSellApprovalBatch(
'BSC',
rpcUrl,
tokenAddress,
[ownerA, ownerB]
);
// checkList: Array<{ owner, isApproved, currentAllowance, requiredAllowance }>
// 批量授权(privateKeys: 每个地址对应的私钥;默认授权上限)
const approveResults = await ensureFlapSellApprovalBatch(
'BSC',
rpcUrl,
[pkA, pkB], // 拥有者私钥数组
tokenAddress // 目标代币地址
);
// approveResults: Array<{ owner, alreadyApproved, currentAllowance, requiredAllowance, txReceipt? }>
```
**返回值**:
所有 `check*` 方法返回:
```typescript
{
isApproved: boolean, // 如果已授权则为 true
currentAllowance: bigint, // 当前授权额度
requiredAllowance: bigint // 所需授权额度
}
```
所有 `ensure*` 方法返回:
```typescript
{
alreadyApproved: boolean, // 如果不需要发送交易则为 true
currentAllowance: bigint,
requiredAllowance: bigint,
txReceipt?: TransactionReceipt // 仅在发送了授权交易时存在
}
```
**完整工作流示例**:
**Four.meme V2 代币卖出**:
```typescript
// 1. 检查授权状态(快速,只读)
const status = await checkSellApprovalV2('BSC', rpcUrl, token, wallet, amount);
if (!status.isApproved) {
// 2. 如需要则发送授权交易
console.log('正在授权...');
await ensureSellApprovalV2('BSC', rpcUrl, privateKey, token, wallet, amount);
}
// 3. 执行卖出
await tradeSell('BSC', rpcUrl, token, { type: 'direct', amount, minFunds: 0n });
```
**Flap Protocol 代币卖出**:
```typescript
// 1. 检查授权状态
const status = await checkFlapSellApproval('BSC', rpcUrl, token, wallet, amount);
if (!status.isApproved) {
// 2. 授权给 Flap Portal
await ensureFlapSellApproval('BSC', rpcUrl, privateKey, token, wallet, amount);
}
// 3. 执行卖出
const writer = new FlapPortalWriter({ chain: 'BSC', rpcUrl }, privateKey);
await writer.swapExactInput({
inputToken: token,
outputToken: ZERO_ADDRESS,
inputAmount: amount,
minOutputAmount: 0n,
permitData: '0x'
});
```
**UI 集成示例**:
```typescript
// 根据授权状态更新 UI
const status = await checkSellApprovalV2('BSC', rpcUrl, tokenAddr, walletAddr, sellAmount);
if (status.isApproved) {
showButton('立即卖出', 'green');
} else {
showButton('需要授权', 'orange');
showInfo(`当前额度: ${status.currentAllowance}, 需要: ${status.requiredAllowance}`);
}
```
**重要提示**:
- ⚠️ **V1 和 V2 使用不同的代理合约** - 必须授权给正确的版本
- ⚠️ **Four.meme 和 Flap 使用不同的合约** - 不能混用授权方法
- ✅ **通用方法默认使用 V2** 以保持向后兼容
- ✅ **建议新代码使用明确版本的方法**(`V1`/`V2`)
---
#### parseFourError()
解析 four.meme 错误代码。
```typescript
import { parseFourError } from 'four-flap-meme-sdk';
const { code, message } = parseFourError(error);
```
**返回**: `{ code?: FourErrorCode, message: string }`
---
#### isExclusiveOnChain()
检查代币是否为 MPC 专属(链上)。
```typescript
import { isExclusiveOnChain } from 'four-flap-meme-sdk';
const isExclusive = await isExclusiveOnChain({
chain: 'BSC', // 仅支持 BSC(TokenManagerV2)
tokenAddress: string,
rpcUrl: string
});
```
---
#### isExclusiveOffChain()
检查代币是否为 MPC 专属(通过 API)。
```typescript
import { isExclusiveOffChain } from 'four-flap-meme-sdk';
const isExclusive = await isExclusiveOffChain(
getTokenInfo: (addr: string) => Promise<{ version?: string }>,
tokenAddress: string
);
```
---
# Flap Protocol 指南
## Flap 平台架构
Flap Protocol 是新一代代币发行平台,具有以下核心特性:
### 核心组件:
1. **Portal 合约**: 所有操作的主入口点
2. **CDPV2 联合曲线**: 高级数学曲线,具有三个参数(r、h、k)
3. **多网络支持**: BSC、Base、X Layer、Morph
4. **灵活配置**: 自定义税费、报价代币、迁移设置
5. **可配置费率**: 不同链可设置不同的买入/卖出手续费率
### Flap 上的代币生命周期:
```
1. 创建代币 → 使用 CDPV2 曲线部署
2. 交易阶段 → 在联合曲线上买卖
3. 进度跟踪 → 监控储备与阈值
4. 迁移 → 达到阈值时自动迁移到 DEX
```
---
## 读取代币状态
Flap 有**四个版本**的代币状态读取方法:
### 版本对比
| 方法 | 返回 | 用途 |
|------|------|------|
| `getTokenV2()` | 基本状态(7 个字段)| 旧版兼容 |
| `getTokenV3()` | + 报价代币信息(9 个字段)| 报价代币支持 |
| `getTokenV4()` | + 扩展ID(10 个字段)| 扩展功能支持 |
| `getTokenV5()` | + 完整 CDPV2 参数(12 个字段)| 完整信息(推荐)|
### 读取代币状态(V5 - 推荐)
```typescript
import { FlapPortal } from 'four-flap-meme-sdk';
// 使用链枚举(SDK 自动处理合约地址和默认费率)
const portal = new FlapPortal({
chain: 'BSC', // 支持: 'BSC' | 'BASE' | 'XLAYER' | 'MORPH'
rpcUrl: 'https://bsc-dataseed.binance.org'
});
const state = await portal.getTokenV5('0x...代币地址');
console.log('代币状态:', state.status); // 0=无效, 1=可交易, 4=DEX
console.log('储备(wei):', state.reserve); // 曲线中的当前 BNB
console.log('供应量:', state.circulatingSupply); // 流通中的代币
console.log('价格:', state.price); // 当前价格(wei)
console.log('曲线参数:', state.r, state.h, state.k); // CDPV2 参数
console.log('DEX 阈值:', state.dexSupplyThresh); // 迁移所需供应量
console.log('报价代币:', state.quoteTokenAddress); // 0x0 = 原生代币
```
### 状态字段说明
```typescript
{
status: number, // 0=无效, 1=可交易, 2=决斗中, 3=已杀死, 4=DEX
reserve: bigint, // 曲线中的当前储备(wei)
circulatingSupply: bigint, // 流通中的代币(wei,18 位小数)
price: bigint, // 当前价格(每个代币的 wei)
tokenVersion: number, // 代币实现版本
r: bigint, // CDPV2 参数 r(储备偏移)
h: bigint, // CDPV2 参数 h(高度调整)
k: bigint, // CDPV2 参数 k(曲线常数)
dexSupplyThresh: bigint, // DEX 迁移的供应阈值
quoteTokenAddress: Address, // 原生代币为 0x0,或 ERC20 地址
nativeToQuoteSwapEnabled: boolean, // 可否将原生币兑换为报价币
extensionID: bytes32 // 扩展标识符
}
```
---
## CDPV2 联合曲线
**CDPV2**(恒定动态价格 V2)曲线是 Flap 价格机制的核心。
### 理解 CDPV2 参数
#### 参数 `r`(储备偏移)
- **是什么**: 起始储备金额
- **效果**: 更高的 `r` = 更高的初始价格
- **典型值**: 0.1 ETH(0.1 × 10^18 wei)
#### 参数 `h`(高度调整)
- **是什么**: 移动供应曲线
- **效果**: 调整曲线开始的位置
- **典型值**: 0(无偏移)
#### 参数 `k`(曲线常数)
- **是什么**: 决定价格增长率
- **效果**: 更高的 `k` = 整体价格更高
- **典型值**: r × 10^9(10 亿 × r)
### CDPV2 公式
```
供应量 (S) = 1,000,000,000 + h - k / (R + r)
储备 (R) = k / (1,000,000,000 + h - S) - r
价格 (P) = k / (1,000,000,000 + h - S)²
```
其中:
- S = 流通供应量
- R = 储备(曲线中的 BNB/ETH)
- P = 每个代币的价格
### 使用 CDPV2 类
```typescript
import { CDPV2 } from 'four-flap-meme-sdk';
// 创建 r=0.1, h=0, k=1e8 的曲线
const curve = CDPV2.getCurve(0.1, 0, 1e8);
// 计算 10 ETH 储备所需的供应量
const supply = curve.estimateSupply('10');
console.log('10 ETH 时的供应量:', supply.toString());
// 计算 8 亿供应所需的储备
const reserve = curve.estimateReserve('800000000');
console.log('8 亿供应时的储备:', reserve.toString());
// 获取 8 亿供应时的当前价格
const price = curve.price('800000000');
console.log('8 亿供应时的价格:', price.toString());
// 获取 FDV(完全稀释估值)
const fdv = curve.fdv('800000000');
console.log('FDV:', fdv.toString());
```
### 计算进度
**进度** = 代币距离 DEX 迁移有多近
```typescript
import { FlapPortal } from 'four-flap-meme-sdk';
const portal = new FlapPortal({
chain: 'BSC',
rpcUrl: 'https://bsc-dataseed.binance.org'
});
const state = await portal.getTokenV5(tokenAddress);
const { price, progress } = portal.computePriceAndProgress(state);
console.log('当前价格:', price, '每个代币的 ETH');
console.log('进度:', progress); // '0.0000' 到 '1.0000'(0% 到 100%)
```
**进度含义**:
- `0.0000`: 刚发行
- `0.5000`: 距 DEX 迁移一半
- `1.0000`: 准备 DEX 迁移
- 进度 = (当前储备)/(阈值所需储备)
---
## Flap 价格报价
SDK 提供了 **两种报价方式**,各有优势:
| 特性 | 离线报价 | 链上报价 |
|------|---------|---------|
| **方法** | `quoteBuy()` / `quoteSell()` | `quoteExactInput()` |
| **速度** | ⚡️ 极快(本地计算) | 🐢 较慢(RPC 调用) |
| **准确度** | 📊 高(99.9%+) | 🎯 100% 精确 |
| **费用** | 💰 免费 | 💸 消耗 RPC 配额 |
| **适用场景** | UI 实时显示、快速预览 | 交易前最终确认 |
| **依赖** | 需要代币状态 | 只需要代币地址 |
### 方式 1:离线报价(推荐用于 UI)⚡️
**优势**:
- ⚡️ **极快**:本地计算,0 延迟
- 💰 **免费**:不消耗 RPC 配额
- 📊 **准确**:使用与链上相同的公式和费率
- 🎨 **实时**:适合用户输入时的实时更新
**方法**:`quoteBuy()` / `quoteSell()`
**原理**:
- 基于 CDPV2 联合曲线公式进行本地计算
- 自动扣除平台手续费(可配置)
- 与链上实际结果 99.9%+ 一致
```typescript
import { FlapPortal } from 'four-flap-meme-sdk';
// 🌟 使用链枚举,SDK 自动应用该链的默认费率
const portal = new FlapPortal({
chain: 'BSC', // SDK 自动使用 BSC 的默认费率:买入 1%, 卖出 1%
rpcUrl: 'https://bsc-dataseed.binance.org'
});
// 如果需要覆盖默认费率:
// const portal = new FlapPortal({
// chain: 'BSC',
// rpcUrl: 'https://bsc-dataseed.binance.org',
// buyFeeRate: 0.015, // 自定义买入费率 1.5%
// sellFeeRate: 0.015 // 自定义卖出费率 1.5%
// });
// 1. 获取代币状态(只需一次)
const tokenAddress = '0x...' as any;
const state = await portal.getTokenV5(tokenAddress);
// 2. 离线买入报价:花 1 BNB 能得到多少代币
const tokenAmount = portal.quoteBuy(state, '1.0');
console.log('💰 买入报价:');
console.log(' 支付: 1.0 BNB');
console.log(' 手续费: 0.01 BNB (1%)');
console.log(' 实际用于购买: 0.99 BNB');
console.log(' 预计获得:', tokenAmount, '个代币');
// 3. 离线卖出报价:卖 1000000 个代币能得到多少 BNB
const ethAmount = portal.quoteSell(state, '1000000');
console.log('\n💸 卖出报价:');
console.log(' 卖出: 1000000 个代币');
console.log(' 按曲线计算后扣除 1% 手续费');
console.log(' 实际收到:', ethAmount, 'BNB');
```
**实际应用 - UI 实时更新**:
```typescript
// 场景:用户在输入框输入金额,实时显示报价
let cachedState: TokenStateV5;
async function init() {
// 初始化时获取一次代币状态
cachedState = await portal.getTokenV5(tokenAddress);
}
function onUserInputChange(inputValue: string) {
// 用户输入时,立即计算并显示(无延迟)
const outputAmount = portal.quoteBuy(cachedState, inputValue);
updateUI(`您将获得约 ${formatNumber(outputAmount)} 个代币`);
// 可选:定期刷新 cachedState(如每 10 秒)以保持准确性
}
```
### 方式 2:链上报价(精确)🎯
**优势**:
- 🎯 **100% 精确**:直接调用链上合约模拟
- ✅ **实时状态**:使用最新的链上数据
- 🔒 **可靠**:交易前的最终确认
**劣势**:
- 🐢 需要 RPC 调用(较慢)
- 💸 消耗 RPC 配额
**方法**:`quoteExactInput()` / `previewBuy()` / `previewSell()`
```typescript
const portal = new FlapPortal({
chain: 'BSC', // 链名称:'BSC' | 'BASE' | 'XLAYER' | 'MORPH'
rpcUrl: 'https://bsc-dataseed.binance.org' // 区块链 RPC 节点
});
// 方法 A: 通用报价(支持任意 input/output token 组合)
const outputAmount = await portal.quoteExactInput({
inputToken: '0x0000000000000000000000000000000000000000' as any, // 输入代币地址:0x0 代表原生币(BNB/ETH)
outputToken: tokenAddress, // 输出代币地址:目标代币
inputAmount: 1n * 10n ** 18n // 输入金额(wei):示例为 1 BNB
});
console.log('精确报价 - 你将获得:', formatEther(outputAmount), '个代币');
// 方法 B: 专用买入报价(更简洁)
const tokenAmount = await portal.previewBuy(
tokenAddress, // 目标代币地址
1n * 10n ** 18n // 输入原生币金额(wei):示例为 1 BNB
);
console.log('买入报价 - 你将获得:', formatEther(tokenAmount), '个代币');
// 方法 C: 专用卖出报价(更简洁)
const ethAmount = await portal.previewSell(
tokenAddress, // 待卖出的代币地址
1000n * 10n ** 18n // 卖出数量(代币最小单位,18 位小数):示例 1000 个
);
console.log('卖出报价 - 你将获得:', formatEther(ethAmount), 'BNB');
```
### 📋 使用建议
**推荐流程**:
```typescript
import { FlapPortal, FlapPortalWriter, ZERO_ADDRESS } from 'four-flap-meme-sdk';
import { parseEther, formatEther } from 'ethers';
const rpcUrl = 'https://bsc-dataseed.binance.org';
const tokenAddress = '0x...'; // 代币地址
const zeroAddress = ZERO_ADDRESS;
// 创建只读实例用于报价
const portal = new FlapPortal({ chain: 'BSC', rpcUrl });
// 1️⃣ UI 显示阶段:使用离线报价(快速)
const state = await portal.getTokenV5(tokenAddress);
const estimatedOutput = portal.quoteBuy(state, userInput);
showToUser(`预计获得: ${estimatedOutput} 个代币`);
// 2️⃣ 用户点击"确认交易"时:使用链上报价(精确)
const exactOutput = await portal.quoteExactInput({
inputToken: zeroAddress,
outputToken: tokenAddress,
inputAmount: parseEther(userInput)
});
showConfirmDialog(`确切获得: ${formatEther(exactOutput)} 个代币`);
// 3️⃣ 执行交易 - 创建 Writer 实例
const writer = new FlapPortalWriter(
{ chain: 'BSC', rpcUrl },
'YOUR_PRIVATE_KEY'
);
await writer.swapExactInput({
inputToken: zeroAddress,
outputToken: tokenAddress,
inputAmount: parseEther(userInput),
minOutputAmount: exactOutput * 99n / 100n // 允许 1% 滑点
});
```
**费率说明**:
离线报价的手续费率取决于创建 `FlapPortal` 时的配置:
```typescript
// 🌟 推荐:使用链枚举,自动应用该链的实际费率
const portal1 = new FlapPortal({
chain: 'BSC', // 自动使用 BSC 实际费率:买入 1%, 卖出 1%
rpcUrl
});
const portal2 = new FlapPortal({
chain: 'MORPH', // 自动使用 MORPH 实际费率:买入 2.5%, 卖出 2.5%
rpcUrl
});
// 如需自定义费率:
const portal3 = new FlapPortal({
chain: 'BSC',
rpcUrl,
buyFeeRate: 0.015, // 覆盖默认费率
sellFeeRate: 0.015
});
```
---
## 代币兑换
Flap Protocol 提供了多种交易方法,适用于不同场景:
### 方法 1: 简化买卖方法(推荐新手)
```typescript
import { FlapPortalWriter } from 'four-flap-meme-sdk';
// 使用链枚举(SDK 自动处理合约地址)
const writer = new FlapPortalWriter(
{
chain: 'BSC',
rpcUrl: 'https://bsc-dataseed.binance.org'
},
'0x...你的私钥'
);
// 买入代币(返回 TransactionReceipt)
const buyReceipt = await writer.buy(
tokenAddress, // 代币地址
yourAddress, // 接收地址
950n * 10n ** 18n, // 最少获得 950 个代币(5% 滑点)
1n * 10n ** 18n // 发送 1 BNB
);
console.log('买入交易:', buyReceipt.hash);
// 卖出代币(返回 TransactionReceipt)
const sellReceipt = await writer.sell(
tokenAddress, // 代币地址
1000n * 10n ** 18n, // 卖出 1000 个代币
95n * 10n ** 16n // 最少获得 0.95 BNB(5% 滑点)
);
console.log('卖出交易:', sellReceipt.hash);
```
### 方法 2: 通用兑换方法(高级用户)
```typescript
import { FlapPortalWriter, ZERO_ADDRESS } from 'four-flap-meme-sdk';
// 创建 Writer 实例
const writer = new FlapPortalWriter(
{ chain: 'BSC', rpcUrl: 'https://bsc-dataseed.binance.org' },
'YOUR_PRIVATE_KEY'
);
// 用 1 BNB 买入代币(返回 TransactionReceipt)
const receipt = await writer.swapExactInput(
{
inputToken: ZERO_ADDRESS, // BNB
outputToken: tokenAddress, // 要买的代币
inputAmount: 1n * 10n ** 18n, // 1 BNB
minOutputAmount: 950n * 10n ** 18n, // 最少代币(滑点)
permitData: '0x' // 无 permit(可选)
},
1n * 10n ** 18n // msg.value = 1 BNB
);
console.log('兑换交易:', receipt.hash);
```
### 方法 3: 创建后立即买入
当前版本未提供 buyOnCreation 接口。建议:创建完成后按常规买入流程执行一次买入交易(可结合私有交易/Bundle 保证原子性)。
### 使用 Permit 兑换(高级)
**Permit** 允许在无需事先授权交易的情况下花费 ERC20 代币。SDK 提供了自动签名方法:
```typescript
import { buildPermitPiggybackAuto, FlapPortalWriter } from 'four-flap-meme-sdk';
// SDK 自动签名 Permit 并使用正确的 Portal 代理地址
const permitData = await buildPermitPiggybackAuto(
'BSC', // 链名称(SDK 自动使用该链的 Portal 地址)
privateKey, // 你的私钥
tokenAddress, // ERC20 代币地址
amount, // 授权金额
deadline, // 截止时间戳
nonce // Permit nonce(从代币合约获取)
);
// 然后使用 permit 兑换(无需额外授权交易!)
const writer = new FlapPortalWriter({ chain: 'BSC', rpcUrl }, privateKey);
await writer.swapExactInput({
inputToken: tokenAddress,
outputToken: targetToken,
inputAmount: amount,
minOutputAmount: 0n,
permitData // ✅ 授权 + 兑换一笔交易完成
});
```
---
## 在Flap上创建代币
### 步骤 1:上传元数据到 IPFS
Flap Protocol 未公开 IPFS 上传端点,你需要使用第三方 IPFS 服务上传代币元数据。
#### 推荐:使用 Pinata(最简单)
```typescript
import { PinataSDK } from "pinata-web3";
// 初始化 Pinata
const pinata = new PinataSDK({
pinataJwt: process.env.PINATA_JWT, // 从 https://pinata.cloud 获取
});
// 1. 上传图片
const imageUpload = await pinata.upload.file(imageFile);
const imageCid = imageUpload.IpfsHash;
// 2. 构建并上传元数据 JSON
const metadata = {
image: imageCid, // 图片的 CID
description: "我的代币描述",
creator: yourAddress,
website: "https://example.com",
twitter: "https://x.com/mytoken",
telegram: "https://t.me/mytoken",
buy: null,
sell: null
};
const jsonUpload = await pinata.upload.json(metadata);
const cid = jsonUpload.IpfsHash; // 这就是要传给合约的 CID
console.log('元数据 CID:', cid);
```
#### 其他 IPFS 服务
- **Web3.Storage**(免费):https://web3.storage/
- **Infura IPFS**:https://infura.io/
- **NFT.Storage**(免费):https://nft.storage/
- **自己的 IPFS 节点**:运行 `ipfs daemon`
### 步骤 2:创建代币
使用步骤 1 获得的 CID 创建代币。
#### newTokenV2 - 标准创建
```typescript
import { FlapPortalWriter, ZERO_ADDRESS } from 'four-flap-meme-sdk';
const writer = new FlapPortalWriter(
{
chain: 'BSC',
rpcUrl: 'https://bsc-dataseed.binance.org'
},
privateKey
);
const receipt = await writer.newTokenV2({
// 基本信息
name: '我的代币',
symbol: 'MTK',
meta: cid, // 步骤 1 中获得的 IPFS CID
// 代币设置
dexThresh: 1, // 1 = FOUR_FIFTHS (80%)
migratorType: 0, // 0 = V3_MIGRATOR
salt: '0x0000...', // CREATE2 的随机盐(使用 predictVanityTokenAddressByChain 计算)
taxRate: 0, // 基点税率(0 = 无税)
// 💰 创建时购买(可选)
quoteToken: ZERO_ADDRESS, // 0x0 = 使用原生代币(BNB/ETH)购买
quoteAmt: 1n * 10n ** 18n, // 创建时购买 1 BNB/ETH 的代币
beneficiary: yourAddress, // 购买的代币发送到这个地址
msgValue: 1n * 10n ** 18n, // 发送 1 BNB/ETH(与 quoteAmt 相同)
// 可选
permitData: '0x', // Permit 数据(如使用 ERC20 代币购买)
});
console.log('代币已创建:', receipt.transactionHash);
console.log('已自动购买代币发送到:', yourAddress);
```
**💡 创建时购买说明**:
`newTokenV2` 支持在创建代币的同时购买代币,这是一个原子操作:
1. **不购买**(只创建):
```typescript
quoteToken: ZERO_ADDRESS,
quoteAmt: 0n, // 设置为 0 表示不购买
beneficiary: yourAddress,
msgValue: 0n // 不发送 BNB/ETH
```
2. **创建 + 购买**(使用原生币):
```typescript
quoteToken: ZERO_ADDRESS, // 0x0 = 使用 BNB/ETH
quoteAmt: 1n * 10n ** 18n, // 购买 1 BNB/ETH 的代币
beneficiary: yourAddress, // 购买的代币发送到这里
msgValue: 1n * 10n ** 18n // 必须与 quoteAmt 相同
```
3. **创建 + 购买**(使用 ERC20 代币):
```typescript
quoteToken: '0x...USDT', // 使用 USDT 购买
quoteAmt: 100n * 10n ** 18n, // 购买 100 USDT 的代币
beneficiary: yourAddress,
permitData: '0x...', // 必须提供 Permit 签名
msgValue: 0n // 使用 ERC20 时不需要发送原生币
```
**优势**:
- ✅ **原子操作**:创建和购买在同一笔交易完成
- ✅ **节省 gas**:比分两笔交易便宜
- ✅ **防抢跑**:确保创建者能获得初始代币
- ✅ **灵活**:可以使用原生币或 ERC20 代币购买
---
#### newTokenV3 - 支持扩展功能
V3 版本支持扩展功能,可用于未来的协议升级:
```typescript
const receipt = await writer.newTokenV3({
// 基本信息
name: '我的代币 V3',
symbol: 'MTK3',
meta: cid, // 步骤 1 中获得的 IPFS CID
// 代币设置
dexThresh: 1,
salt: '0x0000...',
taxRate: 0,
migratorType: 0,
quoteToken: ZERO_ADDRESS,
quoteAmt: 1n * 10n ** 18n,
beneficiary: yourAddress,
permitData: '0x',
msgValue: 1n * 10n ** 18n,
// V3 新增参数
extensionID: '0x0000...', // 扩展功能 ID
extensionData: '0x' // 扩展功能数据(可选)
});
console.log('V3 代币已创建:', receipt.transactionHash);
```
**完整示例**:创建代币 + 初始购买(解决靓号地址错误)
```typescript
import {
FlapPortalWriter,
FlapPortal,
predictVanityTokenAddressByChain,
ZERO_ADDRESS
} from 'four-flap-meme-sdk';
// 1. 获取当前 nonce(可选,仅做信息展示)
const portal = new FlapPortal({
chain: 'BSC',
rpcUrl: 'https://bsc-dataseed.binance.org'
});
const nonce = await portal.nonce();
// 2. 预测符合靓号要求的地址和 salt(新版 API 仅需 salt)
// 方式A:自行提供 salt(bytes32 或任意字符串)
const salt = '0x000000000000000000000000000000000000000000000000000000000000abcd';
const predictedAddress = predictVanityTokenAddressByChain('BSC', salt, false);
console.log('✅ 预测地址:', predictedAddress); // 例如以 8888 结尾
console.log('✅ 使用 salt:', salt);
// 3. 创建代币 + 初始购买
const writer = new FlapPortalWriter(
{ chain: 'BSC', rpcUrl: 'https://bsc-dataseed.binance.org' },
privateKey
);
const receipt = await writer.newTokenV2({
name: 'My Token',
symbol: 'MTK',
meta: metaCid, // IPFS CID
dexThresh: 1,
salt: salt, // ✅ 使用预测的 salt,避免 VanityAddressRequirementNotMet 错误
taxRate: 0,
migratorType: 0,
// 创建时购买 0.5 BNB 的代币
quoteToken: ZERO_ADDRESS,
quoteAmt: 5n * 10n ** 17n, // 0.5 BNB
beneficiary: yourAddress,
msgValue: 5n * 10n ** 17n // 发送 0.5 BNB
});
console.log('✅ 代币创建成功:', receipt.transactionHash);
console.log('✅ 代币地址:', predictedAddress);
console.log('✅ 已购买 0.5 BNB 的代币到:', yourAddress);
```
---
### 参数详情
#### dexThresh(迁移阈值)
决定在什么供应量时代币迁移到 DEX:
| 值 | 名称 | 阈值 | 描述 |
|----|------|------|------|
| 0 | TWO_THIRDS | 66.67% | 在最大供应量的 2/