Requirements
- Target platform
- OpenClaw
- Install method
- Manual import
- Extraction
- Extract archive
- Prerequisites
- OpenClaw
- Primary doc
- SKILL.md
Decentralized Monad token launchpad with bonding curve trading, token creation, real-time event streaming, and historical data querying via pure viem calls.
Decentralized Monad token launchpad with bonding curve trading, token creation, real-time event streaming, and historical data querying via pure viem calls.
Hand the extracted package to your coding agent with a concrete install brief instead of figuring it out manually.
I downloaded a skill package from Yavira. Read SKILL.md from the extracted folder and install it by following the included instructions. Tell me what you changed and call out any manual steps you could not complete.
I downloaded an updated skill package from Yavira. Read SKILL.md from the extracted folder, compare it with my current installation, and upgrade it while preserving any custom configuration unless the package docs explicitly say otherwise. Summarize what changed and any follow-up checks I should run.
The Monad token launchpad with bonding curves. Trade tokens, launch your own, monitor events—all with pure viem.
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.
This skill guide is split into focused modules. Start with the overview, then dive into specific guides: ModulePurposeAudienceSKILL.md (this file)Architecture, constants, setupEveryoneQUOTE.mdPrice quotes, curve stateTraders, analyzersTRADING.mdBuy, sell, permit signaturesTraders, botsTOKEN.mdBalances, metadata, transfersApp developersCREATE.mdToken creation, image uploadToken creatorsINDEXER.mdHistorical event queryingAnalytics, dashboardsAGENT-API.mdREST API for trading data, token infoAI 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.
FileURLABI.mdhttps://nad.fun/abi.mdAGENT-API.mdhttps://nad.fun/agent-api.mdCREATE.mdhttps://nad.fun/create.mdINDEXER.mdhttps://nad.fun/indexer.mdQUOTE.mdhttps://nad.fun/quote.mdTOKEN.mdhttps://nad.fun/token.mdTRADING.mdhttps://nad.fun/trading.mdWALLET.mdhttps://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
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
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]
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.
To access session-protected endpoints (API key management, account settings, etc.), you need to authenticate via wallet signature.
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)
// 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 }, })
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 } }
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
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%)
The actionId parameter in token creation identifies the type of action: actionIdDescription1Token Creation Always use actionId: 1 when calling the create function.
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.
// 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.
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.
Use these prompts to guide your work:
"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"
"Get metadata for token address X" "Check my MON balance" "Get available tokens to buy before graduation"
"Launch a token called MyToken (MTK) with this image" "Mine a vanity address for my token" "Check token creation fees"
"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"
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 ABIs constants.ts # Network configs, contract addresses All ABIs are documented in ABI.md.
Each ABI can be copied from ABI.md. Reference the correct section: ABIABI.md SectionPurposebondingCurveRouterAbiBondingCurveRouter ABIToken creation, buy/selllensAbiLens ABIPrice quotes, getAmountOutcurveAbiCurve ABICurve state, graduation checktokenAbiToken ABIERC20 operations, permit signing Example import pattern: // Copy the ABI from ABI.md into your project import { bondingCurveRouterAbi } from "./abis/router" import { lensAbi } from "./abis/lens"
npm install viem # or pnpm add viem # or yarn add viem
{ "viem": "^2.0.0" } Pure viem. No other blockchain libraries needed.
You're on the wrong network. Check NETWORK constant matches your setup.
Query getProgress() via Lens contract. Returns 0-10000. Need 10000 (100%) to graduate.
Check amountOutMin—slippage might be too high or curve moved Verify deadline—transaction took too long Check allowance—approve token before sell
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.
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
When interacting with smart contracts, you might encounter specific errors. Here's a table of common ABI-related errors and how to approach them: ErrorMeaningInsufficientAmountOutput less than amountOutMinInsufficientAmountOutInsufficient output amountDeadlineExpiredDeadline has passedUnauthorizedCaller not authorizedAlreadyGraduatedToken already graduated to DEXBondingCurveLockedCurve locked during graduationInvalidProofMerkle proof verification failed (specific to claims)AlreadyClaimedAmount already claimed for this proof (specific to claims)NotClaimableToken not eligible for claims yet (specific to claims)InsufficientBalanceTreasury 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. } }
Agent frameworks, memory systems, reasoning layers, and model-native orchestration.
Largest current source with strong distribution and engagement signals.