create-token
# Nad.fun Token Creation Flow
## Prerequisite: monad-development Skill
Before proceeding, check if the `monad-development` skill is installed. If it is not available, install it using ClawHub:
```bash
clawhub search "monad"
```
Find and install the `monad-development` skill from the results. This skill is required for wallet management and on-chain actions in Step 3 and Step 4.
---
Help the user create a token on Nad.fun by following the 4-step sequential process below. Each step depends on the output of the previous step.
## API Base URL
**Production:** `https://api.nadapp.net`
## Contract Addresses
```
BondingCurveRouter = "0x6F6B8F1a20703309951a5127c45B49b1CD981A22"
Lens = "0x7e78A8DE94f21804F7a17F4E8BF9EC2c872187ea"
```
---
## Step 1: Upload Image
**POST** `/agent/token/image`
- **Content-Type:** `image/png`, `image/jpeg`, `image/webp`, or `image/svg+xml`
- **Body:** Raw binary image data (max 5MB)
- **Returns:** `image_uri` (CDN URL) and `is_nsfw` (boolean)
```js
const imageResponse = await fetch("https://api.nadapp.net/agent/token/image", {
method: "POST",
headers: { "Content-Type": imageFile.type },
body: imageFile,
});
const { image_uri, is_nsfw } = await imageResponse.json();
```
### Error Codes
| Status | Description |
|--------|-------------|
| 400 | Invalid image format or missing image |
| 413 | Image exceeds 5MB limit |
| 500 | NSFW check failed or upload failed |
---
## Step 2: Upload Metadata
**POST** `/agent/token/metadata`
- **Content-Type:** `application/json`
- **Requires:** `image_uri` from Step 1
### Request Body
**Required fields:**
| Field | Type | Constraints |
|-------|------|-------------|
| `image_uri` | string | Must be from `https://storage.nadapp.net/` |
| `name` | string | 1-32 characters |
| `symbol` | string | 1-10 characters, alphanumeric only (`/^[a-zA-Z0-9]+$/`) |
**Optional fields:**
| Field | Type | Constraints |
|-------|------|-------------|
| `description` | string or null | Max 500 characters |
| `website` | string or null | Must start with `https://` |
| `twitter` | string or null | Must contain `x.com` and start with `https://` |
| `telegram` | string or null | Must contain `t.me` and start with `https://` |
```js
const metadataResponse = await fetch("https://api.nadapp.net/agent/token/metadata", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
image_uri,
name: "My Token",
symbol: "MTK",
description: "An awesome token for the Nad.fun",
website: "https://mytoken.com",
twitter: "https://x.com/mytoken",
telegram: "https://t.me/mytoken",
}),
});
const { metadata_uri } = await metadataResponse.json();
```
### Error Codes
| Status | Description |
|--------|-------------|
| 400 | NSFW status unknown, invalid data, or validation failed |
| 500 | Upload to storage or database failed |
---
## Step 3: Mine Salt
**POST** `/agent/salt`
- **Content-Type:** `application/json`
- **Requires:** `metadata_uri` from Step 2
- Produces a vanity token address ending in `7777`
### Request Body
| Field | Type | Description |
|-------|------|-------------|
| `creator` | string | Creator's wallet address (EVM format) |
| `name` | string | Token name (must match metadata) |
| `symbol` | string | Token symbol (must match metadata) |
| `metadata_uri` | string | Metadata URI from Step 2 |
```js
const saltResponse = await fetch("https://api.nadapp.net/agent/salt", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
creator: walletAddress,
name: "My Token",
symbol: "MTK",
metadata_uri: metadataUri,
}),
});
const { salt, address } = await saltResponse.json();
```
- **Returns:** `salt` (bytes32 hex) and `address` (token address with `7777` suffix)
### Error Codes
| Status | Description |
|--------|-------------|
| 400 | Invalid parameters |
| 408 | Timeout - max iterations reached |
| 500 | Internal server error |
---
## Step 4: Create Token On-Chain
Call `BondingCurveRouter.create()` with the data from previous steps.
### TokenCreationParams
```solidity
struct TokenCreationParams {
string name;
string symbol;
string tokenURI; // metadata_uri from Step 2
uint256 amountOut; // 0 for no initial buy, or use Lens.getInitialBuyAmountOut(amountIn)
bytes32 salt; // salt from Step 3
uint8 actionId; // always 1 (graduate to Capricorn V3)
}
```
```solidity
function create(TokenCreationParams calldata params) external payable returns (address token, address pool);
```
### Option A: Create Without Initial Buy
Send only the deploy fee as `msg.value`.
```js
const curve = new ethers.Contract(BONDING_CURVE_ADDRESS, BONDING_CURVE_ABI, signer);
const [deployFee,,] = await curve.feeConfig();
const params = {
name, symbol,
tokenURI: metadata_uri,
amountOut: 0,
salt,
actionId: 1,
};
const tx = await router.create(params, { value: deployFee });
await tx.wait();
```
### Option B: Create With Initial Buy
Send `deployFee + amountIn` as `msg.value`. Use `Lens.getInitialBuyAmountOut(amountIn)` for `amountOut`.
```js
const lens = new ethers.Contract(LENS_ADDRESS, LENS_ABI, signer);
const expectedAmountOut = await lens.getInitialBuyAmountOut(amountIn);
const [deployFee,,] = await curve.feeConfig();
const params = {
name, symbol,
tokenURI: metadata_uri,
amountOut: expectedAmountOut,
salt,
actionId: 1,
};
const tx = await router.create(params, { value: deployFee + amountIn });
await tx.wait();
```
---
## Wallet for On-Chain Actions
For Step 3 (salt mining) and Step 4 (on-chain deployment), use the wallet from the `monad-development` skill. That skill handles all wallet configuration, private key management, and RPC setup. Use the signer and wallet address it provides when calling the salt API (`creator` field) and when sending the `BondingCurveRouter.create()` transaction.
---
## Important Rules
1. **Sequential process** - Each step depends on the previous step's output.
2. **NSFW validation** - Images are auto-checked in Step 1; the flag carries into metadata.
3. **URL validation** - All URLs must use HTTPS. Twitter must use `x.com`, Telegram must use `t.me`.
4. **Image domain restriction** - Only `https://storage.nadapp.net/` image URIs are accepted in metadata.
5. **Salt mining** - May timeout if the vanity address pattern can't be found within iteration limits.
6. **actionId** - Always use `1` (graduate to Capricorn V3).
## When Generating Code
- Use `ethers` v6 syntax by default unless the user specifies otherwise.
- Always handle errors for each API call before proceeding to the next step.
- The `salt` from Step 3 and `metadata_uri` from Step 2 are both needed for Step 4.
- For initial buy, always query `Lens.getInitialBuyAmountOut()` to get the correct `amountOut`.
标签
skill
ai