Skill flagged — suspicious patterns detected

ClawHub Security flagged this skill as suspicious. Review the scan results before using.

nadfun

Decentralized Monad token launchpad with bonding curve trading, token creation, real-time event streaming, and historical data querying via pure viem calls.

MIT-0 · Free to use, modify, and redistribute. No attribution required.
4 · 1.4k · 3 current installs · 3 all-time installs
MIT-0
Security Scan
VirusTotalVirusTotal
Suspicious
View report →
OpenClawOpenClaw
Benign
medium confidence
Purpose & Capability
The SKILL.md and associated files describe a token launchpad (bonding curves, token creation, indexing, trading) and all referenced endpoints, ABIs, and RPCs match that purpose. Required binaries/env in registry metadata are empty but that is plausible for an instruction-only skill.
Instruction Scope
The runtime instructions include commands to curl documentation files from https://nad.fun into ~/.nadfun/skills and many code examples that require a private key (process.env.PRIVATE_KEY) and an API key (X-API-Key). The docs also show examples that print private keys in console (even though a security note advises not to). These instructions are within the domain of a blockchain wallet/launchpad skill but they ask the user/agent to fetch remote content and to handle sensitive secrets — which merits caution.
Install Mechanism
No formal install spec in the registry (instruction-only). The SKILL.md recommends curl commands that download files from nad.fun and write them to ~/.nadfun/skills. Downloading remote docs is expected for a docs-driven skill, but it writes content from an external host to disk — verify the domain before running.
!
Credentials
The skill documentation repeatedly references PRIVTE_KEY / NAD_API_KEY / session cookies for wallet login and API key management, which are necessary for creating tokens and signing transactions. However, the skill metadata declares no required environment variables or primary credential. This mismatch means the skill will functionally require sensitive secrets even though none are declared — users should not expose private keys/session cookies or paste them into untrusted environments.
Persistence & Privilege
The skill does not request always: true and does not include an install script that modifies other skills or agent-wide settings. It is instruction-only and will not persist code automatically beyond any files the user chooses to curl/save.
Assessment
This is an instruction-only NadFun integration guide (no code executed by the registry). Before running anything: 1) Do NOT run the curl commands blindly — inspect the remote URLs (https://nad.fun, https://dev-api.nad.fun, https://api.nadapp.net) in a browser first. 2) Never paste your real private key or session cookie into examples; use a throwaway/test key on testnet or a hardware wallet for signing. 3) When the docs ask for an API key or session cookie, create a scoped key with minimal permissions and set expiration/rotate it. 4) Avoid running examples that print private keys to logs. 5) If you plan to save downloaded files, keep them in a directory you control and review their contents before executing any scripts. If you want stronger assurance, request the publisher/site source code or host-signed releases (GitHub/official releases) instead of raw curl downloads.

Like a lobster shell, security has layers — review code before you run it.

Current versionv1.0.0
Download zip
latestvk972e3ww4srew8s5x0cz8nhvdn80dkrw

License

MIT-0
Free to use, modify, and redistribute. No attribution required.

SKILL.md

SKILL.md - NadFun Integration Guide

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:

ModulePurposeAudience
SKILL.md (this file)Architecture, constants, setupEveryone
QUOTE.mdPrice quotes, curve stateTraders, analyzers
TRADING.mdBuy, sell, permit signaturesTraders, bots
TOKEN.mdBalances, metadata, transfersApp developers
CREATE.mdToken creation, image uploadToken creators
INDEXER.mdHistorical event queryingAnalytics, dashboards
AGENT-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.

Skill Files

FileURL
ABI.mdhttps://nad.fun/abi.md
AGENT-API.mdhttps://nad.fun/agent-api.md
CREATE.mdhttps://nad.fun/create.md
INDEXER.mdhttps://nad.fun/indexer.md
QUOTE.mdhttps://nad.fun/quote.md
TOKEN.mdhttps://nad.fun/token.md
TRADING.mdhttps://nad.fun/trading.md
WALLET.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

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:

  1. Curve reaches target reserve
  2. Liquidity moves to Uniswap V3 pool
  3. Token transitions from bonding curve to DEX
  4. 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:

actionIdDescription
1Token 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:

  1. Generate signature: generatePermitSignature(token, spender, amount, deadline)
  2. Use in trade: sellPermit({ ...params, ...signature })
  3. 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 ABIs

constants.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:

ABIABI.md SectionPurpose
bondingCurveRouterAbiBondingCurveRouter ABIToken creation, buy/sell
lensAbiLens ABIPrice quotes, getAmountOut
curveAbiCurve ABICurve state, graduation check
tokenAbiToken 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"

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"

  1. Check amountOutMin—slippage might be too high or curve moved
  2. Verify deadline—transaction took too long
  3. 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:

ErrorMeaning
InsufficientAmountOutput less than amountOutMin
InsufficientAmountOutInsufficient output amount
DeadlineExpiredDeadline has passed
UnauthorizedCaller not authorized
AlreadyGraduatedToken already graduated to DEX
BondingCurveLockedCurve locked during graduation
InvalidProofMerkle 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.
  }
}

Files

9 total
Select a file
Select a file to preview.

Comments

Loading comments…