基于绑定曲线的 Monad 代币launchpad。交易代币、发行代币、监控事件——全部使用纯 viem。
什么是 NadFun?
NadFun 是 Monad 区块链上的去中心化代币 launchpad。主要特性:
- 绑定曲线交易:代币从绑定曲线开始。随着更多人购买,价格上涨。
- 毕业机制:当曲线达到目标储备时,代币毕业到 DEX(Uniswap V3)。
- 代币创建:任何人都可以发行带有图像、元数据和可选初始购买的代币。
- 实时事件:实时流式传输代币交易、创建和 DEX 交换。
- 历史数据:查询过去事件用于分析和监控。
技能文档
本技能指南分为多个模块。从概述开始,然后深入特定指南:
| 模块 | 用途 | 受众 |
|---|
| SKILL.md(本文档) | 架构、常量、设置 | 所有人 |
| QUOTE.md | 价格报价、曲线状态 | 交易者、分析师 |
| TRADING.md | 购买、出售、许可签名 | 交易者、机器人 |
| TOKEN.md | 余额、元数据、转账 | 应用开发者 |
| CREATE.md | 代币创建、图像上传 | 代币创建者 |
| INDEXER.md | 历史事件查询 | 分析、仪表盘 |
| AGENT-API.md | 交易数据、代币信息的 REST API | AI 智能体、机器人 |
有关 API 下载/端点/头部使用,请参阅
AGENT-API.md。
注意: 要获取 API 密钥,您必须首先通过钱包签名登录 nad.fun。请参阅下面的 认证 部分了解登录流程,然后使用会话 cookie 通过 POST /api-key 创建 API 密钥。
技能文件
| 文件 | URL |
|---|
| ABI.md | https://nad.fun/abi.md |
| AGENT-API.md | https://nad.fun/agent-api.md |
| CREATE.md | https://nad.fun/create.md |
| INDEXER.md | https://nad.fun/indexer.md |
| QUOTE.md | https://nad.fun/quote.md |
| TOKEN.md | https://nad.fun/token.md |
| TRADING.md | https://nad.fun/trading.md |
| WALLET.md | https://nad.fun/wallet.md |
mkdir -p ~/.nadfun/skills
curl -s https://nad.fun/skill.md > ~/.nadfun/skills/SKILL.md
curl -s https://nad.fun/abi.md > ~/.nadfun/skills/ABI.md
curl -s https://nad.fun/agent-api.md > ~/.nadfun/skills/AGENT-API.md
curl -s https://nad.fun/create.md > ~/.nadfun/skills/CREATE.md
curl -s https://nad.fun/indexer.md > ~/.nadfun/skills/INDEXER.md
curl -s https://nad.fun/quote.md > ~/.nadfun/skills/QUOTE.md
curl -s https://nad.fun/token.md > ~/.nadfun/skills/TOKEN.md
curl -s https://nad.fun/trading.md > ~/.nadfun/skills/TRADING.md
curl -s https://nad.fun/wallet.md > ~/.nadfun/skills/WALLET.md
快速信息
- 网络:测试网(链 10143)或主网(链 143)
- 语言:TypeScript/JavaScript
- 纯 viem:所有示例使用 viem 直接调用合约
- 费用:通过 REST 端点检查 API 获取部署费用
网络常量
所有地址和端点都在这里。网络变化时更新此配置。
const NETWORK = "testnet" // 'testnet' | 'mainnet'const CONFIG = {
testnet: {
chainId: 10143,
rpcUrl: "https://monad-testnet.drpc.org",
apiUrl: "https://dev-api.nad.fun", // For token creation
// Contract addresses
DEX_ROUTER: "0x5D4a4f430cA3B1b2dB86B9cFE48a5316800F5fb2",
BONDING_CURVE_ROUTER: "0x865054F0F6A288adaAc30261731361EA7E908003",
LENS: "0xB056d79CA5257589692699a46623F901a3BB76f1",
CURVE: "0x1228b0dc9481C11D3071E7A924B794CfB038994e",
WMON: "0x5a4E0bFDeF88C9032CB4d24338C5EB3d3870BfDd",
V3_FACTORY: "0xd0a37cf728CE2902eB8d4F6f2afc76854048253b",
CREATOR_TREASURY: "0x24dFf9B68fA36f8400302e2babC3e049eA19459E",
},
mainnet: {
chainId: 143,
rpcUrl: "https://monad-mainnet.drpc.org",
apiUrl: "https://api.nadapp.net",
// Contract addresses
DEX_ROUTER: "0x0B79d71AE99528D1dB24A4148b5f4F865cc2b137",
BONDING_CURVE_ROUTER: "0x6F6B8F1a20703309951a5127c45B49b1CD981A22",
LENS: "0x7e78A8DE94f21804F7a17F4E8BF9EC2c872187ea",
CURVE: "0xA7283d07812a02AFB7C09B60f8896bCEA3F90aCE",
WMON: "0x3bd359C1119dA7Da1D913D1C4D2B7c461115433A",
V3_FACTORY: "0x6B5F564339DbAD6b780249827f2198a841FEB7F3",
CREATOR_TREASURY: "0x42e75B4B96d7000E7Da1e0c729Cec8d2049B9731",
},
}[NETWORK]
基本设置
每个技能指南都假设您从 viem 开始。以下是基础设置:
import { createPublicClient, createWalletClient, http, privateKeyToAccount } from "viem"const NETWORK = "testnet"
const CONFIG = {
/ from above /
}[NETWORK]
// Create clients
const publicClient = createPublicClient({
chain: {
id: CONFIG.chainId,
name: "Monad",
nativeCurrency: { name: "MON", symbol: "MON", decimals: 18 },
rpcUrls: { default: { http: [CONFIG.rpcUrl] } },
},
transport: http(CONFIG.rpcUrl),
})
const account = privateKeyToAccount("0x...")
const walletClient = createWalletClient({
account,
chain: publicClient.chain,
transport: http(CONFIG.rpcUrl),
})
这是您的基础。所有其他模块都构建在此之上。
认证(登录流程)
要访问受会话保护的端点(API 密钥管理、账户设置等),您需要通过钱包签名进行认证。
登录流程
import { createWalletClient, http, privateKeyToAccount } from "viem"const account = privateKeyToAccount("0x...")
const walletClient = createWalletClient({
account,
chain: {
id: CONFIG.chainId,
name: "Monad",
nativeCurrency: { name: "MON", symbol: "MON", decimals: 18 },
rpcUrls: { default: { http: [CONFIG.rpcUrl] } },
},
transport: http(CONFIG.rpcUrl),
})
// Step 1: Request nonce
const nonceRes = await fetch(${CONFIG.apiUrl}/auth/nonce, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ address: account.address }),
})
const { nonce } = await nonceRes.json()
// Step 2: Sign the nonce
const signature = await walletClient.signMessage({ message: nonce })
// Step 3: Create session
const sessionRes = await fetch(${CONFIG.apiUrl}/auth/session, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
signature,
nonce,
chain_id: CONFIG.chainId,
}),
})
// Extract session cookie from response headers
const sessionCookie = sessionRes.headers.get("set-cookie")
const { account_info } = await sessionRes.json()
console.log("Logged in as:", account_info.account_id)
使用会话 Cookie
// Use session cookie for authenticated requests
const headers = { Cookie: sessionCookie }// Example: Create API Key (requires session)
const apiKeyRes = await fetch(${CONFIG.apiUrl}/api-key, {
method: "POST",
headers: { ...headers, "Content-Type": "application/json" },
body: JSON.stringify({ name: "My Bot", expires_in_days: 365 }),
})
const { api_key } = await apiKeyRes.json()
console.log("API Key:", api_key) // Store this securely!
登出
await fetch(${CONFIG.apiUrl}/auth/delete_session, {
method: "DELETE",
headers: { Cookie: sessionCookie },
})
TypeScript 接口
interface AuthNonceRequest {
address: string
}interface AuthNonceResponse {
nonce: string
}
interface AuthSessionRequest {
signature: string
nonce: string
chain_id: number
wallet_address?: string // Optional
}
interface AuthSessionResponse {
account_info: {
account_id: string
nickname: string
bio: string
image_uri: string
}
}
核心概念
绑定曲线
NadFun 上的代币从绑定曲线开始。曲线定义价格和可用性:
- 真实储备:池中实际的 MON 和代币
- 虚拟储备:曲线计算的初始伪储备
- K 常数:维持 xy=k 价格公式
- 目标:需要卖出多少代币才能毕业
使用 getCurveState(token) 获取曲线状态 → 参见 QUOTE.md
毕业
当足够多的代币被购买时:
- 曲线达到目标储备
- 流动性转移到 Uniswap V3 池
- 代币从绑定曲线过渡到 DEX
isGraduated(token) 返回 true
使用 getProgress(token) 检查进度(0-10000 = 0-100%)
动作 ID
代币创建中的 actionId 参数标识动作类型:
调用
create 函数时始终使用
actionId: 1。
许可签名
EIP-2612 允许钱包签署批准交易,而不是发送单独的 approve() 调用:
- 生成签名:
generatePermitSignature(token, spender, amount, deadline)
- 在交易中使用:
sellPermit({ ...params, ...signature })
- 无需单独批准——节省 gas
详情请参阅 TRADING.md。
常见模式
模式 1:简单交易
// Get quote (3 args: token, amountIn, isBuy)
const [router, amountOut] = await publicClient.readContract({
address: LENS,
abi: lensAbi,
functionName: "getAmountOut",
args: [token, amountIn, true], // true = buy
})// Buy with slippage protection (1 tuple arg)
const minOut = (amountOut BigInt(995)) / BigInt(1000) // 0.5% slippage
const deadline = BigInt(Math.floor(Date.now() / 1000) + 300)
const tx = await walletClient.writeContract({
address: router, // Use router returned from getAmountOut
abi: bondingCurveRouterAbi,
functionName: "buy",
args: [
{
amountOutMin: minOut,
token: token,
to: account.address,
deadline: deadline,
},
],
value: amountIn,
})
完整示例请参阅 TRADING.md。
模式 2:发行代币
import { bondingCurveRouterAbi } from "./abis/router"// Requires API_KEY and deployFeeAmount (see CREATE.md for feeConfig())
// 1. Upload image to Agent API (raw binary, NOT formData)
const imageRes = await fetch(${CONFIG.apiUrl}/agent/token/image, {
method: "POST",
headers: {
"X-API-Key": API_KEY,
"Content-Type": "image/png", // or 'image/jpeg', 'image/webp', 'image/svg+xml'
},
body: imageBuffer, // raw binary data (Buffer, Blob, or ArrayBuffer)
})
const { image_uri: imageUri } = await imageRes.json()
// 2. Upload metadata to Agent API
const metadataRes = await fetch(${CONFIG.apiUrl}/agent/token/metadata, {
method: "POST",
headers: { "Content-Type": "application/json", "X-API-Key": API_KEY },
body: JSON.stringify({
name: "My Token",
symbol: "MYT",
description: "A test token",
image: imageUri,
}),
})
const { metadata_uri: metadataUri } = await metadataRes.json()
// 3. Deploy token via contract
const tx = await walletClient.writeContract({
address: BONDING_CURVE_ROUTER,
abi: bondingCurveRouterAbi,
functionName: "create",
args: [
{
actionId: 1, // Token creation
name: "My Token",
symbol: "MYT",
metadataUri: metadataUri,
// ... other params
},
],
value: deployFeeAmount,
})
完整示例请参阅 CREATE.md。
模式 3:监听事件
import { parseAbiItem } from "viem"// Subscribe to new token creations
const unsubscribe = publicClient.watchContractEvent({
address: BONDING_CURVE_ROUTER,
abi: [parseAbiItem("event TokenCreated(address indexed token, address creator)")],
onLogs: (logs) => {
for (const log of logs) {
console.log("New token created:", log.args.token)
console.log("Creator:", log.args.creator)
}
},
})
// Later, cleanup
await unsubscribe()
类型安全
viem 返回精确的类型。这是一个关键优势:
// result type is precisely bigint (not bigint | undefined)
使用 viem 类型助手进行类型安全转换:
import { Address, Hex } from "viem"
import { parseEther, formatEther } from "viem"// Amounts
const wei = parseEther("1") // string -> bigint
const eth = formatEther(1000000000000000000n) // bigint -> string
// Addresses
const addr: Address = "0x..." // Validated address type
// Signatures
const sig: Hex = "0x..." // Hex string type
常见 ABI 错误
与智能合约交互时,您可能会遇到特定错误。以下是常见 ABI 相关错误及其处理方法:
| 错误 | 含义 |
|---|
InsufficientAmount | 输出小于 amountOutMin |
InsufficientAmountOut | 输出金额不足 |
DeadlineExpired | 截止时间已过 |
Unauthorized | 调用者未授权 |
AlreadyGraduated | 代币已毕业到 DEX |
BondingCurveLocked | 曲线在毕业期间锁定 |
InvalidProof | Merkle 证明验证失败(特定于索赔) |
AlreadyClaimed | 此证明的金额已领取(特定于索赔) |
NotClaimable | 代币尚不符合索赔条件(特定于索赔) |
InsufficientBalance | 国库 MON 余额不足(特定于索赔) |
使用 viem 检查错误类型:
import { ContractFunctionExecutionError } from 'viem'try {
await contract.write.buy([...]) // or any contract interaction
} catch (error) {
if (error instanceof ContractFunctionExecutionError) {
console.log(error.shortMessage) // "InsufficientAmount", etc.
}
}
The Monad token launchpad with bonding curves. Trade tokens, launch your own, monitor events—all with pure viem.
What is NadFun?
NadFun is a decentralized token launchpad on the Monad blockchain. Key features:
- Bonding Curve Trading: Tokens start on a bonding curve. Price increases as more people buy.
- Graduation: When curve reaches target reserves, token graduates to DEX (Uniswap V3).
- Token Creation: Anyone can launch a token with image, metadata, and optional initial buy.
- Real-time Events: Stream token trades, creations, and DEX swaps as they happen.
- Historical Data: Query past events for analytics and monitoring.
Skills Documentation
This skill guide is split into focused modules. Start with the overview, then dive into specific guides:
| Module | Purpose | Audience |
|---|
| SKILL.md (this file) | Architecture, constants, setup | Everyone |
| QUOTE.md | Price quotes, curve state | Traders, analyzers |
| TRADING.md | Buy, sell, permit signatures | Traders, bots |
| TOKEN.md | Balances, metadata, transfers | App developers |
| CREATE.md | Token creation, image upload | Token creators |
| INDEXER.md | Historical event querying | Analytics, dashboards |
| AGENT-API.md | REST API for trading data, token info | AI agents, bots |
For API download/endpoints/header usage, see
AGENT-API.md.
Note: To obtain an API key, you must first login to nad.fun via wallet signature. See the Authentication section below for the login flow, then use the session cookie to create an API key via POST /api-key.
Skill Files
| File | URL |
|---|
| ABI.md | https://nad.fun/abi.md |
| AGENT-API.md | https://nad.fun/agent-api.md |
| CREATE.md | https://nad.fun/create.md |
| INDEXER.md | https://nad.fun/indexer.md |
| QUOTE.md | https://nad.fun/quote.md |
| TOKEN.md | https://nad.fun/token.md |
| TRADING.md | https://nad.fun/trading.md |
| WALLET.md | https://nad.fun/wallet.md |
mkdir -p ~/.nadfun/skills
curl -s https://nad.fun/skill.md > ~/.nadfun/skills/SKILL.md
curl -s https://nad.fun/abi.md > ~/.nadfun/skills/ABI.md
curl -s https://nad.fun/agent-api.md > ~/.nadfun/skills/AGENT-API.md
curl -s https://nad.fun/create.md > ~/.nadfun/skills/CREATE.md
curl -s https://nad.fun/indexer.md > ~/.nadfun/skills/INDEXER.md
curl -s https://nad.fun/quote.md > ~/.nadfun/skills/QUOTE.md
curl -s https://nad.fun/token.md > ~/.nadfun/skills/TOKEN.md
curl -s https://nad.fun/trading.md > ~/.nadfun/skills/TRADING.md
curl -s https://nad.fun/wallet.md > ~/.nadfun/skills/WALLET.md
Quick Facts
- Network: Testnet (chain 10143) or Mainnet (chain 143)
- Language: TypeScript/JavaScript
- Pure viem: All examples use direct contract calls with viem
- Fees: Check API for deploy fees via REST endpoint
Network Constants
All addresses and endpoints are here. Update this when network changes.
const NETWORK = "testnet" // 'testnet' | 'mainnet'const CONFIG = {
testnet: {
chainId: 10143,
rpcUrl: "https://monad-testnet.drpc.org",
apiUrl: "https://dev-api.nad.fun", // For token creation
// Contract addresses
DEX_ROUTER: "0x5D4a4f430cA3B1b2dB86B9cFE48a5316800F5fb2",
BONDING_CURVE_ROUTER: "0x865054F0F6A288adaAc30261731361EA7E908003",
LENS: "0xB056d79CA5257589692699a46623F901a3BB76f1",
CURVE: "0x1228b0dc9481C11D3071E7A924B794CfB038994e",
WMON: "0x5a4E0bFDeF88C9032CB4d24338C5EB3d3870BfDd",
V3_FACTORY: "0xd0a37cf728CE2902eB8d4F6f2afc76854048253b",
CREATOR_TREASURY: "0x24dFf9B68fA36f8400302e2babC3e049eA19459E",
},
mainnet: {
chainId: 143,
rpcUrl: "https://monad-mainnet.drpc.org",
apiUrl: "https://api.nadapp.net",
// Contract addresses
DEX_ROUTER: "0x0B79d71AE99528D1dB24A4148b5f4F865cc2b137",
BONDING_CURVE_ROUTER: "0x6F6B8F1a20703309951a5127c45B49b1CD981A22",
LENS: "0x7e78A8DE94f21804F7a17F4E8BF9EC2c872187ea",
CURVE: "0xA7283d07812a02AFB7C09B60f8896bCEA3F90aCE",
WMON: "0x3bd359C1119dA7Da1D913D1C4D2B7c461115433A",
V3_FACTORY: "0x6B5F564339DbAD6b780249827f2198a841FEB7F3",
CREATOR_TREASURY: "0x42e75B4B96d7000E7Da1e0c729Cec8d2049B9731",
},
}[NETWORK]
Basic Setup
Every skill guide assumes you start with viem. Here's the foundation:
import { createPublicClient, createWalletClient, http, privateKeyToAccount } from "viem"const NETWORK = "testnet"
const CONFIG = {
/ from above /
}[NETWORK]
// Create clients
const publicClient = createPublicClient({
chain: {
id: CONFIG.chainId,
name: "Monad",
nativeCurrency: { name: "MON", symbol: "MON", decimals: 18 },
rpcUrls: { default: { http: [CONFIG.rpcUrl] } },
},
transport: http(CONFIG.rpcUrl),
})
const account = privateKeyToAccount("0x...")
const walletClient = createWalletClient({
account,
chain: publicClient.chain,
transport: http(CONFIG.rpcUrl),
})
This is your foundation. All other modules build on top of this.
Authentication (Login Flow)
To access session-protected endpoints (API key management, account settings, etc.), you need to authenticate via wallet signature.
Login Flow
import { createWalletClient, http, privateKeyToAccount } from "viem"const account = privateKeyToAccount("0x...")
const walletClient = createWalletClient({
account,
chain: {
id: CONFIG.chainId,
name: "Monad",
nativeCurrency: { name: "MON", symbol: "MON", decimals: 18 },
rpcUrls: { default: { http: [CONFIG.rpcUrl] } },
},
transport: http(CONFIG.rpcUrl),
})
// Step 1: Request nonce
const nonceRes = await fetch(${CONFIG.apiUrl}/auth/nonce, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ address: account.address }),
})
const { nonce } = await nonceRes.json()
// Step 2: Sign the nonce
const signature = await walletClient.signMessage({ message: nonce })
// Step 3: Create session
const sessionRes = await fetch(${CONFIG.apiUrl}/auth/session, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
signature,
nonce,
chain_id: CONFIG.chainId,
}),
})
// Extract session cookie from response headers
const sessionCookie = sessionRes.headers.get("set-cookie")
const { account_info } = await sessionRes.json()
console.log("Logged in as:", account_info.account_id)
Using Session Cookie
// Use session cookie for authenticated requests
const headers = { Cookie: sessionCookie }// Example: Create API Key (requires session)
const apiKeyRes = await fetch(${CONFIG.apiUrl}/api-key, {
method: "POST",
headers: { ...headers, "Content-Type": "application/json" },
body: JSON.stringify({ name: "My Bot", expires_in_days: 365 }),
})
const { api_key } = await apiKeyRes.json()
console.log("API Key:", api_key) // Store this securely!
Logout
await fetch(${CONFIG.apiUrl}/auth/delete_session, {
method: "DELETE",
headers: { Cookie: sessionCookie },
})
TypeScript Interfaces
interface AuthNonceRequest {
address: string
}interface AuthNonceResponse {
nonce: string
}
interface AuthSessionRequest {
signature: string
nonce: string
chain_id: number
wallet_address?: string // Optional
}
interface AuthSessionResponse {
account_info: {
account_id: string
nickname: string
bio: string
image_uri: string
}
}
Core Concepts
Bonding Curve
Tokens on NadFun start on a bonding curve. The curve defines price and availability:
- Real reserves: Actual MON and tokens in the pool
- Virtual reserves: Initial pseudo-reserves for curve math
- K constant: Maintains x\y=k formula for price
- Target: How many tokens must be sold to graduate
Get curve state with getCurveState(token) → see QUOTE.md
Graduation
When enough tokens are bought:
- Curve reaches target reserve
- Liquidity moves to Uniswap V3 pool
- Token transitions from bonding curve to DEX
isGraduated(token) returns true
Check progress with getProgress(token) (0-10000 = 0-100%)
Action IDs
The actionId parameter in token creation identifies the type of action:
| actionId | Description |
|---|
| 1 | Token Creation |
Always use
actionId: 1 when calling the
create function.
Permit Signatures
EIP-2612 lets wallets sign approval transactions instead of sending separate approve() calls:
- Generate signature:
generatePermitSignature(token, spender, amount, deadline)
- Use in trade:
sellPermit({ ...params, ...signature })
- No separate approve needed—saves gas
See TRADING.md for details.
Common Patterns
Pattern 1: Simple Trade
// Get quote (3 args: token, amountIn, isBuy)
const [router, amountOut] = await publicClient.readContract({
address: LENS,
abi: lensAbi,
functionName: "getAmountOut",
args: [token, amountIn, true], // true = buy
})// Buy with slippage protection (1 tuple arg)
const minOut = (amountOut BigInt(995)) / BigInt(1000) // 0.5% slippage
const deadline = BigInt(Math.floor(Date.now() / 1000) + 300)
const tx = await walletClient.writeContract({
address: router, // Use router returned from getAmountOut
abi: bondingCurveRouterAbi,
functionName: "buy",
args: [
{
amountOutMin: minOut,
token: token,
to: account.address,
deadline: deadline,
},
],
value: amountIn,
})
See TRADING.md for full examples.
Pattern 2: Launch Token
import { bondingCurveRouterAbi } from "./abis/router"// Requires API_KEY and deployFeeAmount (see CREATE.md for feeConfig())
// 1. Upload image to Agent API (raw binary, NOT formData)
const imageRes = await fetch(${CONFIG.apiUrl}/agent/token/image, {
method: "POST",
headers: {
"X-API-Key": API_KEY,
"Content-Type": "image/png", // or 'image/jpeg', 'image/webp', 'image/svg+xml'
},
body: imageBuffer, // raw binary data (Buffer, Blob, or ArrayBuffer)
})
const { image_uri: imageUri } = await imageRes.json()
// 2. Upload metadata to Agent API
const metadataRes = await fetch(${CONFIG.apiUrl}/agent/token/metadata, {
method: "POST",
headers: { "Content-Type": "application/json", "X-API-Key": API_KEY },
body: JSON.stringify({
name: "My Token",
symbol: "MTK",
description: "My awesome token",
image_uri: imageUri,
}),
})
const { metadata_uri: metadataUri } = await metadataRes.json()
// 3. Mine salt via Agent API
const saltRes = await fetch(${CONFIG.apiUrl}/agent/salt, {
method: "POST",
headers: { "Content-Type": "application/json", "X-API-Key": API_KEY },
body: JSON.stringify({
creator: account.address,
name: "My Token",
symbol: "MTK",
metadata_uri: metadataUri,
}),
})
const { salt } = await saltRes.json()
// 4. Create token on-chain
const tx = await walletClient.writeContract({
address: BONDING_CURVE_ROUTER,
abi: bondingCurveRouterAbi,
functionName: "create",
args: [
{
name: "My Token",
symbol: "MTK",
tokenURI: metadataUri,
amountOut: 0n, // Set > 0n for initial buy amount (in tokens)
salt: salt,
actionId: 1, // Token creation action identifier (always 1 for create)
},
],
value: deployFeeAmount, // plus optional initial buy MON if amountOut > 0
gas, // Use estimated gas (see below)
})
console.log("Transaction:", tx)
// Gas estimation (recommended over hardcoded values)
const gasEstimate = await publicClient.estimateContractGas({
address: CONFIG.BONDING_CURVE_ROUTER,
abi: bondingCurveRouterAbi,
functionName: "create",
args: [
{ name: "My Token", symbol: "MTK", tokenURI: metadataUri, amountOut: 0n, salt, actionId: 1 },
],
value: deployFeeAmount,
account: account.address,
})
const gas = (gasEstimate 120n) / 100n // 20% buffer for safety
See CREATE.md for step-by-step.
Prompts for AI Agents
Use these prompts to guide your work:
Trading
- "Get a price quote for token X with 0.1 MON"
- "Buy 0.1 MON of token X with 1% slippage"
- "Sell all tokens with permit signature"
- "Check if token has graduated"
Token Info
- "Get metadata for token address X"
- "Check my MON balance"
- "Get available tokens to buy before graduation"
Creation
- "Launch a token called MyToken (MTK) with this image"
- "Mine a vanity address for my token"
- "Check token creation fees"
Analysis
- "Calculate graduation progress for token X"
- "Get the bonding curve state for token X"
- "Track all swaps on the graduated token"
- "Analyze token creation rate"
Required Files
For integration, you'll need:
abis/
├── curve.ts # Bonding curve contract ABI
├── lens.ts # Price quote ABI
├── router.ts # DEX router ABI
├── token.ts # ERC20 token ABI
└── v3.ts # Uniswap V3 ABIsconstants.ts # Network configs, contract addresses
All ABIs are documented in ABI.md.
ABI Import Guide
Each ABI can be copied from ABI.md. Reference the correct section:
Example import pattern:
// Copy the ABI from ABI.md into your project
import { bondingCurveRouterAbi } from "./abis/router"
import { lensAbi } from "./abis/lens"
Installation
npm install viem
# or
pnpm add viem
# or
yarn add viem
Dependencies
{
"viem": "^2.0.0"
}
Pure viem. No other blockchain libraries needed.
Troubleshooting
"No such contract"
You're on the wrong network. Check NETWORK constant matches your setup.
"Token not graduated yet"
Query getProgress() via Lens contract. Returns 0-10000. Need 10000 (100%) to graduate.
"Transaction reverted"
- Check amountOutMin—slippage might be too high or curve moved
- Verify deadline—transaction took too long
- Check allowance—approve token before sell
Next Steps
Pick a guide based on what you need:
- Building a dex bot? → TRADING.md
- Creating a dashboard? → INDEXER.md + QUOTE.md
- Launching tokens? → CREATE.md
- Token info queries? → TOKEN.md
Each guide has complete examples ready to copy.
General Development Practices & Troubleshooting
Type Safety Tips
Always use the as const assertion when working with ABIs in viem. All ABIs in this module are pre-declared with as const for full type inference:
// Types are automatically narrowed
const result = await contract.read.getAmountOut([...])
// result type is precisely bigint (not bigint | undefined)
Use viem type helpers for type-safe conversions:
import { Address, Hex } from "viem"
import { parseEther, formatEther } from "viem"// Amounts
const wei = parseEther("1") // string -> bigint
const eth = formatEther(1000000000000000000n) // bigint -> string
// Addresses
const addr: Address = "0x..." // Validated address type
// Signatures
const sig: Hex = "0x..." // Hex string type
Common ABI Errors
When interacting with smart contracts, you might encounter specific errors. Here's a table of common ABI-related errors and how to approach them:
| Error | Meaning |
|---|
InsufficientAmount | Output less than amountOutMin |
InsufficientAmountOut | Insufficient output amount |
DeadlineExpired | Deadline has passed |
Unauthorized | Caller not authorized |
AlreadyGraduated | Token already graduated to DEX |
BondingCurveLocked | Curve locked during graduation |
InvalidProof | Merkle proof verification failed (specific to claims) |
AlreadyClaimed | Amount already claimed for this proof (specific to claims) |
NotClaimable | Token not eligible for claims yet (specific to claims) |
InsufficientBalance | Treasury has insufficient MON balance (specific to claims) |
Check error types in viem with:
import { ContractFunctionExecutionError } from 'viem'try {
await contract.write.buy([...]) // or any contract interaction
} catch (error) {
if (error instanceof ContractFunctionExecutionError) {
console.log(error.shortMessage) // "InsufficientAmount", etc.
}
}