four-flap-meme-sdk
v1.4.80
Published
SDK for Flap bonding curve and four.meme TokenManager
Maintainers
Readme
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- 以太坊交互库
安装
npm i four-flap-meme-sdk ethers可选(使用 Pinata 上传 IPFS)
npm i pinata浏览器环境支持
SDK 已内置 Cloudflare Workers 代理,浏览器环境可直接使用,无需额外配置 CORS:
import { FourClient } from 'four-flap-meme-sdk';
// 直接创建,默认使用已配置好的 CORS 代理
const fourClient = new FourClient();目录
📘 平台概览
🎯 four.meme
🚀 Flap Protocol
🔐 48.club 私有交易
📚 附录
🔎 获取代币 LP 信息(内盘/外盘一键识别)
SDK 提供 inspectTokenLP(token, opts) 工具:输入代币地址,自动识别该代币属于 four 内盘、Flap 内盘,或 Pancake V2/V3 外盘;若为外盘则返回与 WBNB/USDT 的交易对与储备量;若为内盘则返回曲线储备/供应量等可展示数据。
最小用法(BSC)
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);可选:通过路由自动解析工厂地址
const info = await inspectTokenLP('0xToken', {
chain: 'BSC',
rpcUrl,
routerV2: '0x10ED43C718714eb63d5aA57B78B54704E256024E', // Pancake V2 Router
routerV3: '0x13f4EA83D0bd40E75C8222255bc855a974568Dd4', // Pancake V3 Router
// 或直接 factoryV2/factoryV3 覆盖
});返回结构示例
// 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 上市前进行价格发现。
核心概念:
联合曲线阶段:
- 代币刚创建时,不在 DEX 上
- 价格由数学公式(联合曲线)决定
- 随着购买增加,价格自动上涨
- 随着卖出增加,价格自动下降
迁移到 DEX:
- 当筹集足够资金(达到阈值)时,代币"毕业"
- 自动在 PancakeSwap(BSC)上添加流动性
- 之后像普通 DEX 代币一样交易
版本说明:
- V1 (TokenManager): 原始版本,仍在使用
- V2 (TokenManager2): 改进版本,功能更多
- Helper3: 辅助合约,用于价格估算和交易路由
为什么使用 four.meme?
- 公平发行: 所有人以相同的联合曲线价格购买
- 防止 Rug Pull: 流动性自动添加到 DEX
- 早期参与: 在 DEX 上市前以较低价格买入
Flap Protocol 是什么?
Flap Protocol 是另一个代币发行平台,具有高级联合曲线功能(CDPV2 曲线)。
核心特性:
高级联合曲线 (CDPV2):
- 更灵活的曲线参数:
r、h、k - 更好的价格发现机制
- 可自定义迁移阈值
- 更灵活的曲线参数:
多链支持:
- BSC(币安智能链)
- Base
- X Layer
- Morph
报价代币选项:
- 可使用原生代币(BNB、ETH)发行
- 可使用 ERC20 代币(USDT 等)发行
税费与迁移器选项:
- 设置自定义税率
- 选择 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(可交易状态)
内盘交易示例:
// 在内盘(联合曲线)上买入代币
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)
外盘交易示例:
// 代币已迁移到 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 |
🔄 从内盘到外盘的迁移过程
- 内盘阶段:代币在联合曲线上交易
- 达到阈值:储备金达到迁移阈值
- 自动迁移:平台合约自动触发迁移
- 添加流动性:将储备金和代币添加到 DEX
- 外盘阶段:代币在 DEX 上自由交易
如何检查代币在哪个阶段?
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 个步骤:
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 群组/频道 |
返回值:
{
accountAddress: string, // 你的钱包地址
accessToken: string, // JWT 令牌(用于后续 API 调用)
imgUrl: string, // 上传的图片 URL
api: {
createArg: string, // 发送到合约的编码参数
signature: string, // 服务器验证签名
},
txReceipt: any, // 区块链交易回执
tokenAddress?: string // 可选:新创建代币地址(若可从事件解析)
}分步发行
高级用户
如需更多控制,可使用单独的方法:
步骤 1: 生成 Nonce
import { FourClient } from 'four-flap-meme-sdk';
const four = new FourClient();
const nonce = await four.generateNonce({
accountAddress: '0x...你的地址',
verifyType: 'LOGIN',
networkCode: 'BSC'
});作用: 从服务器获取随机 nonce(防止重放攻击)。
步骤 2: 签名登录消息
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: 登录获取访问令牌
const accessToken = await four.loginDex({
region: 'WEB',
langType: 'ZH',
walletName: 'MetaMask',
verifyInfo: {
address: '0x...你的地址',
networkCode: 'BSC',
signature: signature,
verifyType: 'LOGIN'
}
});作用: 用签名换取访问令牌(类似 session cookie)。
步骤 4: 上传图片
const imgUrl = await four.uploadImage(accessToken, imageBlob);作用: 上传代币 logo 到 four.meme 的 CDN,返回 URL。
步骤 5: 获取创建参数
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: 链上创建代币
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. 执行交易 → 买入或卖出价格估算
交易前,应先估算成本/收益:
估算买入价格
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');返回值说明:
{
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 // 合约调用中使用的实际资金
}估算卖出价格
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');返回值:
{
tokenManager: string, // 使用哪个 TokenManager
quote: string, // 报价代币地址
funds: bigint, // 你将获得的 BNB(扣除手续费后)
fee: bigint // 交易手续费
}买入代币
有三种方式买入代币:
方法 1: 简单买入(推荐)
使用 buyTokenWithFunds() 直接在 V2 上按资金买入:
import { buyTokenWithFunds } from 'four-flap-meme-sdk';
await buyTokenWithFunds(
'BSC',
rpcUrl,
privateKey,
tokenAddress,
1n * 10n ** 18n, // 1 BNB
0n, // minAmount(滑点保护,可设 >0)
yourAddress // 可选接收地址
);参数说明:
type: 'funds': 指定花费多少 BNBtype: 'amount': 指定买入多少代币minAmount/maxFunds: 滑点保护(防止价格变动导致不利交易)to: 可选接收地址(默认为你的地址)origin: 可选来源代码(用于推荐跟踪,默认:0n)
方法 2: 直接买入(高级)
如果已知是 V2,使用 buyTokenWithFunds():
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 类(专家)
最大控制:
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 花费你的代币)。
完整卖出流程
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 代币卖出需要两笔交易:
- 授权: 给予 TokenManager 权限
- 卖出: 实际转移并获得 BNB
这是 ERC20 代币的安全特性。
路由卖出(第三方应用)
如果你在构建路由器/聚合器:
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 提供统一方法,能:
- 检测代币使用哪个版本
- 调用正确的合约
- 自动处理参数差异
使用自动路由
import { tradeBuy, tradeSell } from 'four-flap-meme-sdk';
// 对 V1 和 V2 代币都有效(当前签名不包含私钥)
await tradeBuy('BSC', rpcUrl, token, params);
await tradeSell('BSC', rpcUrl, token, params);幕后工作:
- 调用
Helper3.getTokenInfo(token) - 检查
version字段(1 或 2) - 路由到 TM1 或 TM2
- 自动适配参数
错误处理
four.meme 交易可能因各种原因失败。SDK 提供错误代码解析:
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 专属代币
链上检测(推荐)
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)
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 类
构造函数
const four = new FourClient({
baseUrl?: string // 默认:'https://four.meme/meme-api'
});认证方法
generateNonce()
获取登录签名的随机 nonce。
const nonce = await four.generateNonce({
accountAddress: string, // 你的钱包地址
verifyType: 'LOGIN', // 固定值
networkCode: 'BSC' // 固定值(目前)
});返回: Promise<string> - nonce 字符串
buildLoginMessage()
构建要签名的登录消息。
import { buildLoginMessage } from 'four-flap-meme-sdk';
const message = buildLoginMessage(nonce); // 返回:"You are sign in Meme {nonce}"loginDex()
用签名换取访问令牌。
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。
const imgUrl = await four.uploadImage(
accessToken: string, // 来自 loginDex()
file: Blob // 图片文件(JPEG、PNG 等)
);返回: Promise<string> - 图片 URL
createToken()
获取链上代币创建的签名参数。
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()
通过合约地址获取代币元数据。
const tokenInfo = await four.getTokenByAddress(
address: string, // 代币合约地址
accessToken?: string // 可选访问令牌
);返回: 代币元数据对象,包含 name、symbol、imgUrl、version 等字段。
getTokensByAddresses()(批量)
并发按地址数组批量获取 four.meme 代币元数据(任一失败不会中断,会在对应项返回 { address, error })。
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 获取代币元数据。
const tokenInfo = await four.getTokenById(
id: string | number, // four.meme 的代币 ID
accessToken?: string // 可选访问令牌
);getPublicConfig()
获取 four.meme 平台配置。
const config = await four.getPublicConfig();链上方法
createTokenOnChain()
在链上部署代币合约。
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()
估算买入成本而不执行。
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()
估算卖出收益而不执行。
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 方法)。
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 方法)。
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)。
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)。
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':手续费接收地址
}
);实用方法
批量校验私钥
批量校验一组私钥是否合规(格式 + 椭圆曲线有效性)。
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。
批量生成钱包地址与私钥
用于开发/测试环境快速生成指定数量的钱包。
import { generateWallets } from 'four-flap-meme-sdk';
const wallets = generateWallets(5);
// 返回示例:
// [
// { address: '0xabc...', privateKey: '0x...' },
// { address: '0xdef...', privateKey: '0x...' },
// ...
// ]注意:仅用于开发/测试。生产环境请安全保管私钥,不要明文存储或上传。
使用 Multicall3 批量查询代币余额
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 地址(向后兼容重载):
const multicall3 = '0xYourMulticall3Address'; // 显式 Multicall3 合约地址
const results = await getTokenBalancesWithMulticall(
rpcUrl, // RPC 节点
multicall3, // Multicall3 合约地址
token, // 代币地址
holders // 持有人地址数组
);说明:SDK 会根据网络 chainId 自动选择标准 Multicall3 地址(0xca11bde05977b3631167028862be2a173976ca11),无需手动传入。
新增:多代币 + 原生余额(推荐新用法)
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 地址):
const results2 = await getTokenBalancesWithMulticall(
rpcUrl,
tokenAddresses, // 多个代币地址
holders // 要查询的持有人地址数组
);说明:
- 该新签名会同时返回每个地址的原生币余额(native)与传入数组中各代币的余额(tokens 映射)。
- Multicall3 地址将按
chain自动选择;未知链将回退到标准地址0xca11...ca11。 - 若某些解码失败,对应条目的
success为false,余额字段回退为0n。
也可直接传 chainId(数字):
const results3 = await getTokenBalancesWithMulticall(
rpcUrl,
56, // chainId(示例:BSC 主网 56)
tokenAddresses,
holders
);代币授权方法
SDK 提供了多种授权方法,以支持不同的 TokenManager 版本(V1/V2)和平台(four.meme/Flap Protocol)。
Four.meme 代币授权
V1 代币授权:
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 代币授权:
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):
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 代币授权
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
);批量检查/授权(默认按上限授权,无需传数额):
// 批量检查(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* 方法返回:
{
isApproved: boolean, // 如果已授权则为 true
currentAllowance: bigint, // 当前授权额度
requiredAllowance: bigint // 所需授权额度
}所有 ensure* 方法返回:
{
alreadyApproved: boolean, // 如果不需要发送交易则为 true
currentAllowance: bigint,
requiredAllowance: bigint,
txReceipt?: TransactionReceipt // 仅在发送了授权交易时存在
}完整工作流示例:
Four.meme V2 代币卖出:
// 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 代币卖出:
// 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 集成示例:
// 根据授权状态更新 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 错误代码。
import { parseFourError } from 'four-flap-meme-sdk';
const { code, message } = parseFourError(error);返回: { code?: FourErrorCode, message: string }
isExclusiveOnChain()
检查代币是否为 MPC 专属(链上)。
import { isExclusiveOnChain } from 'four-flap-meme-sdk';
const isExclusive = await isExclusiveOnChain({
chain: 'BSC', // 仅支持 BSC(TokenManagerV2)
tokenAddress: string,
rpcUrl: string
});isExclusiveOffChain()
检查代币是否为 MPC 专属(通过 API)。
import { isExclusiveOffChain } from 'four-flap-meme-sdk';
const isExclusive = await isExclusiveOffChain(
getTokenInfo: (addr: string) => Promise<{ version?: string }>,
tokenAddress: string
);Flap Protocol 指南
Flap 平台架构
Flap Protocol 是新一代代币发行平台,具有以下核心特性:
核心组件:
- Portal 合约: 所有操作的主入口点
- CDPV2 联合曲线: 高级数学曲线,具有三个参数(r、h、k)
- 多网络支持: BSC、Base、X Layer、Morph
- 灵活配置: 自定义税费、报价代币、迁移设置
- 可配置费率: 不同链可设置不同的买入/卖出手续费率
Flap 上的代币生命周期:
1. 创建代币 → 使用 CDPV2 曲线部署
2. 交易阶段 → 在联合曲线上买卖
3. 进度跟踪 → 监控储备与阈值
4. 迁移 → 达到阈值时自动迁移到 DEX读取代币状态
Flap 有四个版本的代币状态读取方法:
版本对比
| 方法 | 返回 | 用途 |
|------|------|------|
| getTokenV2() | 基本状态(7 个字段)| 旧版兼容 |
| getTokenV3() | + 报价代币信息(9 个字段)| 报价代币支持 |
| getTokenV4() | + 扩展ID(10 个字段)| 扩展功能支持 |
| getTokenV5() | + 完整 CDPV2 参数(12 个字段)| 完整信息(推荐)|
读取代币状态(V5 - 推荐)
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 = 原生代币状态字段说明
{
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 类
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 迁移有多近
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%+ 一致
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 实时更新:
// 场景:用户在输入框输入金额,实时显示报价
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()
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');📋 使用建议
推荐流程:
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 时的配置:
// 🌟 推荐:使用链枚举,自动应用该链的实际费率
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: 简化买卖方法(推荐新手)
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: 通用兑换方法(高级用户)
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 提供了自动签名方法:
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(最简单)
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 - 标准创建
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 支持在创建代币的同时购买代币,这是一个原子操作:
不购买(只创建):
quoteToken: ZERO_ADDRESS, quoteAmt: 0n, // 设置为 0 表示不购买 beneficiary: yourAddress, msgValue: 0n // 不发送 BNB/ETH创建 + 购买(使用原生币):
quoteToken: ZERO_ADDRESS, // 0x0 = 使用 BNB/ETH quoteAmt: 1n * 10n ** 18n, // 购买 1 BNB/ETH 的代币 beneficiary: yourAddress, // 购买的代币发送到这里 msgValue: 1n * 10n ** 18n // 必须与 quoteAmt 相同创建 + 购买(使用 ERC20 代币):
quoteToken: '0x...USDT', // 使用 USDT 购买 quoteAmt: 100n * 10n ** 18n, // 购买 100 USDT 的代币 beneficiary: yourAddress, permitData: '0x...', // 必须提供 Permit 签名 msgValue: 0n // 使用 ERC20 时不需要发送原生币
优势:
- ✅ 原子操作:创建和购买在同一笔交易完成
- ✅ 节省 gas:比分两笔交易便宜
- ✅ 防抢跑:确保创建者能获得初始代币
- ✅ 灵活:可以使用原生币或 ERC20 代币购买
newTokenV3 - 支持扩展功能
V3 版本支持扩展功能,可用于未来的协议升级:
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);完整示例:创建代币 + 初始购买(解决靓号地址错误)
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/3 时迁移 | | 1 | FOUR_FIFTHS | 80% | 在最大供应量的 4/5 时迁移(推荐)| | 2 | HALF | 50% | 在最大供应量的 1/2 时迁移 | | 3 | _95_PERCENT | 95% | 在最大供应量的 95% 时迁移 | | 4 | _81_PERCENT | 81% | 在最大供应量的 81% 时迁移 | | 5 | _1_PERCENT | 1% | 在最大供应量的 1% 时迁移(测试)|
migratorType(DEX 版本)
| 值 | 名称 | DEX 版本 | |----|------|----------| | 0 | V3_MIGRATOR | Uniswap V3(推荐)| | 1 | V2_MIGRATOR | Uniswap V2 |
taxRate(转账税)
- 单位: 基点(1 bp = 0.01%)
- 范围: 0 到 10000(0% 到 100%)
- 示例: 250 = 转账时 2.5% 税
- 推荐: 大多数情况下使用 0(无税)
salt(CREATE2 盐)
- 用途: 确定性地址生成
- 类型: 32 字节十六进制字符串
- 用例: 靓号地址(见下一节)
靓号地址
靓号地址是具有自定义模式的代币地址,使代币更容易识别和记忆。
什么是靓号地址?
靓号地址是使用 CREATE2 机制,通过调整 salt 参数,使得生成的代币合约地址具有特定模式(通常是特定的结尾)。
Flap 平台的默认靓号后缀:
8888: 普通代币的默认靓号后缀(NORMAL)7777: 有税代币的默认靓号后缀(TAXED)
这两个后缀只是 Flap 平台的约定俗成,用于快速识别代币类型:
- 看到
8888结尾 → 可能是普通无税代币 - 看到
7777结尾 → 可能是有交易税的代币
你可以生成任何自定义的靓号地址:
- ✅
888- 更短,更容易找到 - ✅
8888- Flap 平台默认 - ✅
88888- 更长,更稀有(需要更多计算) - ✅
666,999,abc,def- 任何你想要的十六进制模式 - ✅
yourname- 甚至可以是英文单词(如果能找到)
计算复杂度:
- 每增加一位后缀,难度增加 16 倍(十六进制)
888(3位) ≈ 几千次迭代8888(4位) ≈ 几万次迭代88888(5位) ≈ 上百万次迭代888888(6位) ≈ 上千万次迭代
预测代币地址
import { predictVanityTokenAddressByChain } from 'four-flap-meme-sdk';
// 使用链名称(SDK 自动处理 Portal 和 TokenImpl 地址)
const predictedAddress = predictVanityTokenAddressByChain(
'BSC', // 链名称
salt // 32 字节盐
);
console.log('代币将部署在:', predictedAddress);
// 对于 BSC,如果创建有税代币,可以指定 taxed 参数
const predictedTaxedAddress = predictVanityTokenAddressByChain(
'BSC',
salt,
true // taxed = true
);寻找靓号盐
import { findSaltEndingByChain } from 'four-flap-meme-sdk';
// 示例 1: 寻找 Flap 平台默认的 8888 结尾(普通代币)
const result1 = await findSaltEndingByChain({
chain: 'BSC',
suffix: '8888', // Flap 平台默认(普通代币)
maxIterations: 1_000_000 // 通常几万次就能找到
});
console.log('找到地址:', result1.address); // 如: 0x...8888
console.log('使用盐:', result1.salt);
console.log('迭代次数:', result1.iterations);
// 示例 2: 寻找更短的靓号(更快)
const result2 = await findSaltEndingByChain({
chain: 'BSC',
suffix: '888', // 只需 3 位,更容易找到
maxIterations: 100_000 // 通常几千次就能找到
});
// 示例 3: 寻找自定义靓号
const result3 = await findSaltEndingByChain({
chain: 'BSC',
suffix: 'abc', // 自定义后缀
maxIterations: 100_000
});
// 示例 4: 寻找更长的靓号(需要更多时间)
const result4 = await findSaltEndingByChain({
chain: 'BSC',
suffix: '88888', // 5 位,更稀有
maxIterations: 10_000_000, // 可能需要数百万次迭代
seed: '0x0000000000000000000000000000000000000000000000000000000000000001' // 可选的起始盐
});
// 示例 5: 寻找有税代币的默认靓号(BSC 链)
const result5 = await findSaltEndingByChain({
chain: 'BSC',
suffix: '7777', // Flap 平台默认(有税代币)
taxed: true, // 指定为有税代币
maxIterations: 1_000_000
});
// 创建代币时使用找到的盐
import { FlapPortalWriter } from 'four-flap-meme-sdk';
const writer = new FlapPortalWriter(
{ chain: 'BSC', rpcUrl: 'https://bsc-dataseed.binance.org' },
'YOUR_PRIVATE_KEY'
);
await writer.newTokenV2({
name: 'My Token',
symbol: 'MTK',
imageFile: imageFile, // 图片文件(SDK 自动上传到 IPFS)
description: 'My awesome token',
website: 'https://example.com',
dexThresh: 0,
salt: result1.salt, // 使用找到的盐
taxRate: 0,
migratorType: 0,
quoteToken: '0x0000000000000000000000000000000000000000',
quoteAmt: 0n,
beneficiary: '0x1234...'
});重要提示:
- ⚠️ 靓号地址生成是 CPU 密集型操作
- ⚠️ 在生产环境中,建议 提前离线计算 好盐值
- ⚠️ 更长的后缀需要 指数级增长 的计算时间
- ⚠️ 建议使用 3-4 位 后缀,既有辨识度又不会太慢
- ✅
8888和7777只是 Flap 平台的约定,你可以使用 任何后缀 - ✅ 后缀是 十六进制 (0-9, a-f),大小写不敏感
上传代币元数据
SDK 提供 uploadTokenMeta(file, meta, apiUrl?) 工具方法,或可使用第三方 IPFS 服务(Pinata、Infura、Web3.Storage 等)。注意:FLAP_IPFS_API_URL 是占位符端点,可能不可用,推荐传入可用的自定义 GraphQL 端点。
import { uploadTokenMeta } from 'four-flap-meme-sdk';
const cid = await uploadTokenMeta(imageFile as File, {
description: '我的神奇代币',
creator: yourAddress,
website: 'https://example.com',
twitter: 'https://x.com/mytoken',
telegram: 'https://t.me/mytoken'
}, 'https://your-ipfs-graphql.example');使用 Pinata(可选)
你也可以直接使用 Pinata SDK 通过本 SDK 的 PinataClient 完成文件/JSON 上传,快速获取 CID。参考 Pinata Quickstart
import { PinataClient, ZERO_ADDRESS, pinFileToIPFSWithJWT, pinImageByPath, pinFileToIPFSWithJWTWeb, pinDataURLWithJWTWeb } from 'four-flap-meme-sdk';
// 1) 初始化(推荐在服务端使用环境变量存 JWT)
const pinata = new PinataClient({
jwt: process.env.PINATA_JWT as string,
gateway: 'example-gateway.mypinata.cloud' // 可选
});
// 2) 直接上传 JSON 获取 CID(也可用 uploadFile 上传图片 File)
const { cid: metaCid } = await pinata.uploadJSON({
image: 'ipfs://<image_cid>',
description: '我的代币描述',
creator: '0xYourAddress',
website: 'https://example.com'
});
// 3) 在创建代币时传入 meta: cid
const receipt = await writer.newTokenV2({
name: 'My Token',
symbol: 'MTK',
meta: metaCid,
dexThresh: 1,
salt: '0x...',
taxRate: 0,
migratorType: 0,
quoteToken: ZERO_ADDRESS,
quoteAmt: 1n * 10n ** 18n,
beneficiary: '0xYourAddress',
permitData: '0x',
msgValue: 1n * 10n ** 18n
});直接使用 Pinata REST(Node 与 Web)
// Node:本地路径或"流/Buffer"上传
const { cid } = await pinFileToIPFSWithJWT(PINATA_JWT, '/abs/path/img.png');
// 或:
const stream = fs.createReadStream('/abs/path/img.png');
const { cid } = await pinFileToIPFSWithJWT(PINATA_JWT, undefined, stream, 'img.png');
// Node:便捷(路径)
const cid2 = await pinImageByPath(PINATA_JWT, '/abs/path/img.png');
// Web:File/Blob 上传
const input = document.querySelector('input[type=file]') as HTMLInputElement;
const file = input.files![0];
const { cid: webCid } = await pinFileToIPFSWithJWTWeb(PINATA_JWT, file, file.name);
// Web:dataURL 上传(如 Canvas.toDataURL())
const { cid: dataUrlCid } = await pinDataURLWithJWTWeb(PINATA_JWT, dataUrl, 'image.png');手动上传元数据(高级用户)
如果需要在创建代币前单独上传元数据:
import { uploadTokenMeta } from 'four-flap-meme-sdk';
// 手动上传(使用 Flap 官方免费端点)
const cid = await uploadTokenMeta(
imageFile,
{
description: '我的神奇代币,做 XYZ',
creator: '0x1234...',
website: 'https://example.com',
twitter: 'https://x.com/mytoken',
telegram: 'https://t.me/mytoken'
}
);
console.log('元数据 CID:', cid); // 返回 IPFS CID 如: 'bafkreicwlkp...'
// 使用自定义 IPFS 端点(可选)
const customCid = await uploadTokenMeta(
imageFile,
{ description: '...', creator: '...' },
'https://your-custom-ipfs-endpoint.com/graphql'
);其他 IPFS 服务:
- Pinata:https://pinata.cloud/
- Infura IPFS:https://infura.io/
- Web3.Storage:https://web3.storage/
- NFT.Storage:https://nft.storage/
注意:第三方服务需要注册和配置,并且可能使用不同的 API 格式。
按地址获取发布元数据(CID/JSON)
如果你只知道 Flap 代币地址,想要取回"发布时上传到 IPFS 的元数据(CID 与 JSON)",SDK 直接读取代币合约的 metaURI()/meta()(不扫描区块);批量查询使用 Multicall3 并发读取。针对 CID 内容类型:
- JSON:返回
data - 图片等非 JSON:返回
imageUrl(网关直链)
import { getFlapMetaByAddress, getFlapMetasByAddresses } from 'four-flap-meme-sdk';
// 单个地址:返回 CID;若 CID 指向 JSON 则附带 data
const single = await getFlapMetaByAddress(
'BSC', // 链:'BSC' | 'BASE' | 'XLAYER' | 'MORPH'
'https://bsc-dataseed.binance.org', // RPC 节点
'0x...TokenAddress', // 代币地址
{ ipfsGateway: 'https://ipfs.io/ipfs/' } // 可选:自定义 IPFS 网关
);
// single?: { cid: string; data?: any }
// 批量地址:并发查询多个地址(内部使用 Multicall3)
const batch = await getFlapMetasByAddresses(
'BSC', // 链
'https://bsc-dataseed.binance.org', // RPC 节点
['0xA...', '0xB...'], // 代币地址数组
{
// 可选:自定义 Multicall3 地址;未提供时按链使用标准地址 ca11...ca11
// multicall3: '0xca11bde05977b3631167028862be2a173976ca11',
// 可选:自定义 IPFS 网关
// ipfsGateway: 'https://gateway.pinata.cloud/ipfs/'
}
);
// 返回: Array<{ token: string; cid?: string; data?: any; imageUrl?: string; error?: string }>说明:
- SDK 先读合约
metaURI(),失败再读meta();批量场景使用 Multicall3 分两轮完成(metaURI 优先、meta 兜底)。 - 单地址方法仅返回
cid与可选data;如需图片直链回退,请使用批量方法,它会在获取 JSON 失败时返回imageUrl回退;仅在网关获取失败或链上读取失败时返回error。 - 如果返回值形如
ipfs://...,SDK 会自动去前缀;可自定义ipfsGateway以选择更快的网关。
仅获取 CID(底层:getFlapMetaUrisWithMulticall)
如需更底层的 CID 获取(同时也会尝试预取 JSON 或回退图片 URL),可使用:
import { getFlapMetaUrisWithMulticall } from 'four-flap-meme-sdk';
import { JsonRpcProvider } from 'ethers';
const provider = new JsonRpcProvider('https://bsc-dataseed.binance.org');
const list = await getFlapMetaUrisWithMulticall(
provider,
'BSC',
['0xA...', '0xB...'],
/* 可选 */ undefined, // 覆盖 Multicall3 地址
/* 可选 */ 'https://ipfs.io/ipfs/' // 覆盖 IPFS 网关
);
// 返回: Array<{ token: string; cid?: string; data?: any; imageUrl?: string; error?: string }>Flap 错误处理
SDK 提供了专门的错误解析功能,帮助你理解交易失败的原因:
import {
FlapPortalWriter,
parseFlapError,
getFlapErrorMessage,
getFlapErrorMessageEn,
FlapErrorCode
} from 'four-flap-meme-sdk';
// 创建 Writer 实例
const writer = new FlapPortalWriter(
{ chain: 'BSC', rpcUrl: 'https://bsc-dataseed.binance.org' },
'YOUR_PRIVATE_KEY'
);
try {
await writer.swapExactInput({
inputToken: '0x0000000000000000000000000000000000000000',
outputToken: '0x...',
inputAmount: 1n * 10n ** 18n,
minOutputAmount: 950n * 10n ** 18n
}, 1n * 10n ** 18n);
} catch (error) {
const errorCode = parseFlapError(error);
const message = getFlapErrorMessage(errorCode); // 中文错误消息
console.error('交易失败:', message);
// 或使用英文
const messageEn = getFlapErrorMessageEn(errorCode);
console.error('Transaction failed:', messageEn);
}常见错误代码
| 错误代码 | 说明 | 解决方法 |
|---------|------|---------|
| TOKEN_ALREADY_EXISTS | 代币已存在 | 使用不同的盐值或参数 |
| TOKEN_NOT_TRADABLE | 代币不可交易 | 检查代币状态,可能已迁移 |
| ALREADY_ON_DEX | 代币已在 DEX 上 | 在 DEX 上交易而非 Portal |
| INSUFFICIENT_BALANCE | 余额不足 | 增加钱包余额或减少交易金额 |
| SLIPPAGE_EXCEEDED | 滑点过大 | 调整 minTokenAmount 或稍后重试 |
| PERMIT_EXPIRED | Permit 签名已过期 | 重新生成 Permit 签名 |
| INVALID_SIGNATURE | 无效的签名 | 检查签名参数 |
| INVALID_AMOUNT | 无效的金额 | 检查输入金额是否正确 |
| INVALID_QUOTE_TOKEN | 无效的报价代币 | 使用平台支持的报价代币 |
| INVALID_DEX_THRESH | 无效的 DEX 阈值 | 使用 0-5 的有效阈值 |
Flap 常量定义
SDK 提供了预定义的常量,简化配置:
import {
FlapPortal,
FLAP_DEFAULT_FEE_RATES,
FLAP_DEX_THRESHOLDS,
FLAP_TOTAL_SUPPLY,
FLAP_IPFS_API_URL,
FLAP_VANITY_SUFFIX
} from 'four-flap-meme-sdk';
// 创建 FlapPortal(SDK 自动管理合约地址)
const portal = new FlapPortal({ chain: 'BSC', rpcUrl: 'https://...' });
// 支持的链: 'BSC', 'BASE', 'MORPH', 'XLAYER'
// 默认手续费率
const { buy, sell } = FLAP_DEFAULT_FEE_RATES.BSC;
console.log(`买入费率: ${buy * 100}%, 卖出费率: ${sell * 100}%`);
// 输出: 买入费率: 1%, 卖出费率: 1%
// DEX 迁移阈值(百分比形式)
const thresh = FLAP_DEX_THRESHOLDS.FOUR_FIFTHS; // 0.8 (80%)
// 代币总供应量(1 billion with 18 decimals)
console.log('总供应量:', FLAP_TOTAL_SUPPLY);
// 输出: 1000000000000000000000000000n
// IPFS API URL
const ipfsUrl = FLAP_IPFS_API_URL; // 'https://api.flap.sh/graphql'
// 靓号地址后缀
const normalSuffix = FLAP_VANITY_SUFFIX.NORMAL; // '8888'
const taxedSuffix = FLAP_VANITY_SUFFIX.TAXED; // '7777'支持的链
当前支持的链及其默认配置:
| 链 | 买入费率 | 卖出费率 | |----|---------|---------| | BSC | 1% | 1% | | BASE | 2.5% | 2.5% | | MORPH | 2.5% | 2.5% | | XLAYER | 1.5% | 1.5% |
注意事项:
- 买入/卖出费率:由 Flap Protocol 平台收取的交易手续费
- 这些费用会在每次交易时自动扣除:
- 买入时:从你支付的 BNB/ETH 中扣除手续费,剩余部分用于购买代币
- 卖出时:从你应得的 BNB/ETH 中扣除手续费
- 这与代币的
beneficiary(受益人)费用不同:beneficiary接收的是迁移到 DEX 后的 LP 收益分成(V3 迁移器)或代币转账税(有税代币)- 平台交易手续费由 Flap Protocol 收取,用于平台运营
💰 示例计算:
假设在 BSC 上交易(手续费率 1%):
买入示例:
你支付: 1.0 BNB
扣除平台手续费: 0.01 BNB → Flap Protocol 收取
实际用于购买: 0.99 BNB → 按联合曲线价格购买代币卖出示例:
卖出代币后应得: 1.0 BNB (按联合曲线计算)
扣除平台手续费: 0.01 BNB → Flap Protocol 收取
你实际收到: 0.99 BNB假设在 BASE 或 MORPH 上交易(手续费率 2.5%):
买入示例:
你支付: 1.0 ETH
扣除平台手续费: 0.025 ETH → Flap Protocol 收取
实际用于购买: 0.975 ETH → 按联合曲线价格购买代币卖出示例:
卖出代币后应得: 1.0 ETH (按联合曲线计算)
扣除平台手续费: 0.025 ETH → Flap Protocol 收取
你实际收到: 0.975 ETH假设在 XLAYER 上交易(手续费率 1.5%):
买入示例:
你支付: 1.0 ETH
扣除平台手续费: 0.015 ETH → Flap Protocol 收取
实际用于购买: 0.985 ETH → 按联合曲线价格购买代币注意: 使用链枚举时会自动应用该链的默认费率,也可以覆盖:
const portal = new FlapPortal({
chain: 'BSC',
rpcUrl: 'https://bsc-dataseed.binance.org',
buyFeeRate: 0.015, // 可选:覆盖买入费率为 1.5%
sellFeeRate: 0.015 // 可选:覆盖卖出费率为 1.5%
});Flap API 参考
FlapPortal 类
构造函数
// 使用链枚举(自动处理地址和费率)
const portal = new FlapPortal({
chain: 'BSC' | 'BASE' | 'XLAYER' | 'MORPH', // 链名称
rpcUrl: string, // RPC 端点
buyFeeRate?: number, // 可选:覆盖默认买入费率
sellFeeRate?: number // 可选:覆盖默认卖出费率
});读取方法
getTokenV2()
获取基本代币状态(7 个字段)。
const state = await portal.getTokenV2(token: Address);
// 返回: TokenStateV2getTokenV3()
获取带报价代币信息的代币状态(9 个字段)。
const state = await portal.getTokenV3(token: Address);
// 返回: TokenStateV3getTokenV4()
获取包含扩展ID的代币状态(10 个字段)。
const state = await portal.getTokenV4(token: Address);
// 返回: TokenStateV4getTokenV5()
获取完整代币状态(12 个字段,推荐)。
const state = await portal.getTokenV5(token: Address);
// 返回: TokenStateV5计算方法
computePriceAndProgress()
计算当前价格和迁移进度。
const { price, progress } = portal.computePriceAndProgress(state: TokenStateV5);
// price: string(每个代币的 ETH)
// progress: string('0.0000' 到 '1.0000')quoteBuy()
链下买入报价(快速但近似)。
const tokensOut = portal.quoteBuy(
state: TokenStateV5,
inputEth: string // 可读格式的金额(如 '1')
);
// 返回: string(输出代币)quoteSell()
链下卖出报价(快速但近似)。
const ethOut = portal.quoteSell(
state: TokenStateV5,
inputToken: string // 可读格式的代币金额
);
// 返回: string(输出 ETH)quoteExactInput()
通过合约模拟的链上报价(精确)。
const outputAmount = await portal.quoteExactInput({
inputToken: Address,
outputToken: Address,
inputAmount: bigint
});
// 返回: Promise<bigint>previewBuy()
链上买入报价(专用方法)。
const tokenAmount = await portal.previewBuy(
token: Address,
ethAmount: bigint
);
// 返回: Promise<bigint> - 预计获得的代币数量previewSell()
链上卖出报价(专用方法)。
const ethAmount = await portal.previewSell(
token: Address,
tokenAmount: bigint
);
// 返回: Promise<bigint> - 预计获得的 ETH 数量getFeeRate()
获取平台手续费率。
const { buyFeeRate, sellFeeRate } = await portal.getFeeRate();
// 返回: Promise<{buyFeeRate: bigint, sellFeeRate: bigint}>
// 单位:basis points (bps), 例如 250 = 2.5%nonce()
获取合约的 nonce 值(用于代币创建计数)。
const nonce = await portal.nonce();
// 返回: Promise<bigint>version()
获取合约版本信息。
const version = await portal.version();
// 返回: Promise<string>getLocks()
获取代币的锁仓信息。
const locks = await portal.getLocks(token: Address);
// 返回: Promise<bigint[]> - 锁仓 ID 数组FlapPortalWriter 类
用于写操作(需要私钥)。
构造函数
// 使用链枚举(SDK 自动处理合约地址)
const writer = new FlapPortalWriter(
{
chain: 'BSC' | 'BASE' | 'XLAYER' | 'MORPH', // 链名称
rpcUrl: string // RPC 端点
},
privateKey: Hex
);buy()
买入代币(简化方法)。
const receip