# Danubio Token Launcher — Agent Skill

## Overview
Danubio is a permissionless token launcher on HyperEVM. Call one function to deploy an ERC-20 with permanent liquidity on KittenSwap (Algebra Integral). No API keys. No approvals. Just a contract call.

## Quick Start

### Launch a token (2 lines)
```javascript
const launcher = new ethers.Contract('0x2ccD3b07b105800480668C482625454E0e26ad27', [
  'function launch(string name, string symbol) external payable returns (address token, address pool)'
], signer);

const tx = await launcher.launch('MyToken', 'MTKN', { gasLimit: 10_000_000n });
const receipt = await tx.wait();
```

### What happens on-chain
1. 1B supply ERC-20 deployed
2. KittenSwap Algebra pool created (paired with KITTEN token)
3. 980M tokens (98%) deposited as single-sided liquidity at ~$3K FDV
4. LP NFT locked permanently in LPLocker (cannot be withdrawn)
5. 20M tokens (2%) sent to caller as creator allocation
6. Trading fees accrue in locked LP, collectable by protocol

## Contract Addresses (HyperEVM — Chain ID 999)

| Contract | Address |
|---|---|
| TokenLauncher (KITTEN pairs) | `0x2ccD3b07b105800480668C482625454E0e26ad27` |
| TokenLauncher (WHYPE pairs) | `0x9005A8504069b1Bd94A98C64F447b93Ed742bF6c` |
| KittenSwap Factory | `0x5f95E92c338e6453111Fc55ee66D4AafccE661A7` |
| KittenSwap Router | `0x4e73E421480a7E0C24fB3c11019254edE194f736` |
| KittenSwap NFPM | `0x9ea4459c8DefBF561495d95414b9CF1E2242a3E2` |
| KITTEN Token | `0x618275F8EFE54c2afa87bfB9F210A52F0fF89364` |
| WHYPE | `0x5555555555555555555555555555555555555555` |

## RPC
```
https://rpc.hyperliquid.xyz/evm
```

## ABI

### TokenLauncher
```json
[
  {
    "name": "launch",
    "type": "function",
    "stateMutability": "payable",
    "inputs": [
      { "name": "name", "type": "string" },
      { "name": "symbol", "type": "string" }
    ],
    "outputs": [
      { "name": "token", "type": "address" },
      { "name": "pool", "type": "address" }
    ]
  },
  {
    "name": "launchCount",
    "type": "function",
    "stateMutability": "view",
    "inputs": [],
    "outputs": [{ "name": "", "type": "uint256" }]
  },
  {
    "name": "getLaunch",
    "type": "function",
    "stateMutability": "view",
    "inputs": [{ "name": "id", "type": "uint256" }],
    "outputs": [
      {
        "name": "",
        "type": "tuple",
        "components": [
          { "name": "token", "type": "address" },
          { "name": "pool", "type": "address" },
          { "name": "handleHash", "type": "bytes32" },
          { "name": "claimedBy", "type": "address" },
          { "name": "name", "type": "string" },
          { "name": "symbol", "type": "string" },
          { "name": "handle", "type": "string" },
          { "name": "nftId", "type": "uint256" },
          { "name": "timestamp", "type": "uint256" }
        ]
      }
    ]
  },
  {
    "name": "poolForToken",
    "type": "function",
    "stateMutability": "view",
    "inputs": [{ "name": "token", "type": "address" }],
    "outputs": [{ "name": "pool", "type": "address" }]
  }
]
```

### Buy (swap KITTEN → launched token)
```json
[
  {
    "name": "exactInputSingle",
    "type": "function",
    "stateMutability": "payable",
    "inputs": [
      {
        "name": "params",
        "type": "tuple",
        "components": [
          { "name": "tokenIn", "type": "address" },
          { "name": "tokenOut", "type": "address" },
          { "name": "deployer", "type": "address" },
          { "name": "recipient", "type": "address" },
          { "name": "deadline", "type": "uint256" },
          { "name": "amountIn", "type": "uint256" },
          { "name": "amountOutMinimum", "type": "uint256" },
          { "name": "limitSqrtPrice", "type": "uint160" }
        ]
      }
    ],
    "outputs": [{ "name": "amountOut", "type": "uint256" }]
  }
]
```

## Agent Workflows

### 1. Launch a token
```javascript
import { ethers } from 'ethers';

const provider = new ethers.JsonRpcProvider('https://rpc.hyperliquid.xyz/evm');
const wallet = new ethers.Wallet(PRIVATE_KEY, provider);

const launcher = new ethers.Contract(
  '0x2ccD3b07b105800480668C482625454E0e26ad27',
  ['function launch(string name, string symbol) external payable returns (address token, address pool)'],
  wallet
);

const tx = await launcher.launch('AgentToken', 'AGENT', { gasLimit: 10_000_000n });
const receipt = await tx.wait();

// Parse token address from logs
const iface = new ethers.Interface([
  'event TokenLaunched(uint256 indexed launchId, address indexed token, address indexed pool, string handle, string name, string symbol, uint256 creatorAmount, uint256 nftId)'
]);

for (const log of receipt.logs) {
  try {
    const parsed = iface.parseLog({ topics: log.topics, data: log.data });
    if (parsed?.name === 'TokenLaunched') {
      console.log('Token:', parsed.args.token);
      console.log('Pool:', parsed.args.pool);
    }
  } catch {}
}
```

### 2. Buy a launched token with KITTEN
```javascript
const KITTEN = '0x618275F8EFE54c2afa87bfB9F210A52F0fF89364';
const ROUTER = '0x4e73E421480a7E0C24fB3c11019254edE194f736';
const TOKEN = '0x...'; // launched token address

// Step 1: Approve KITTEN to router
const kitten = new ethers.Contract(KITTEN, [
  'function approve(address,uint256) returns (bool)'
], wallet);
await (await kitten.approve(ROUTER, ethers.MaxUint256)).wait();

// Step 2: Swap
const router = new ethers.Contract(ROUTER, [
  'function exactInputSingle((address,address,address,address,uint256,uint256,uint256,uint160)) external payable returns (uint256)'
], wallet);

// Determine sort order for limitSqrtPrice
const tokenIsToken0 = TOKEN.toLowerCase() < KITTEN.toLowerCase();
const limitSqrtPrice = tokenIsToken0
  ? 1461446703485210103287273052203988822378723970341n  // MAX_SQRT_RATIO - 1
  : 4295128740n;                                         // MIN_SQRT_RATIO + 1

const amountIn = ethers.parseEther('1000'); // 1000 KITTEN
const deadline = Math.floor(Date.now() / 1000) + 300;

const tx = await router.exactInputSingle({
  tokenIn: KITTEN,
  tokenOut: TOKEN,
  deployer: ethers.ZeroAddress,
  recipient: wallet.address,
  deadline,
  amountIn,
  amountOutMinimum: 0n,
  limitSqrtPrice,
}, { gasLimit: 500_000n });

await tx.wait();
```

### 3. Buy with native HYPE (swap HYPE → KITTEN → Token)
```javascript
// First swap HYPE → KITTEN
const WHYPE = '0x5555555555555555555555555555555555555555';
const amount = ethers.parseEther('0.05'); // 0.05 HYPE

await (await router.exactInputSingle({
  tokenIn: WHYPE,
  tokenOut: KITTEN,
  deployer: ethers.ZeroAddress,
  recipient: wallet.address,
  deadline: Math.floor(Date.now() / 1000) + 300,
  amountIn: amount,
  amountOutMinimum: 0n,
  limitSqrtPrice: 4295128740n, // WHYPE is token0, selling → MIN
}, { value: amount, gasLimit: 500_000n })).wait();

// Then swap KITTEN → Token (see workflow 2)
```

### 4. Read all launches
```javascript
const launcher = new ethers.Contract(
  '0x2ccD3b07b105800480668C482625454E0e26ad27',
  [
    'function launchCount() view returns (uint256)',
    'function getLaunches(uint256 offset, uint256 limit) view returns (tuple(address token, address pool, bytes32 handleHash, address claimedBy, string name, string symbol, string handle, uint256 nftId, uint256 timestamp)[])'
  ],
  provider
);

const count = await launcher.launchCount();
const launches = await launcher.getLaunches(0, count);
launches.forEach(l => console.log(`$${l.symbol} — ${l.token}`));
```

### 5. Check token price via DexScreener
```
GET https://api.dexscreener.com/token-pairs/v1/hyperevm/{tokenAddress}
```
Returns: price, liquidity, volume, 24h change. No API key needed.

## Gas & Costs
- Launch: ~9.5M gas → ~0.002 HYPE (~$0.06)
- Swap: ~250K gas → ~0.0003 HYPE (~$0.01)
- No launch fee (contract fee = 0)

## Token Specifications
- Standard: ERC-20
- Total supply: 1,000,000,000 (1B)
- Decimals: 18
- Pool: 980,000,000 (98%) → KittenSwap Algebra pool
- Creator: 20,000,000 (2%) → sent to launcher's address
- LP: Permanently locked in LPLocker, cannot be withdrawn
- Starting FDV: ~$3,000 USD
- Quote token: KITTEN (`0x618275F8EFE54c2afa87bfB9F210A52F0fF89364`)

## Important Notes
- `launch()` is public — any address can call it
- No launch fee currently (can be set by owner via `setFee()`)
- Token names limited to 2-50 characters, symbols 2-10 letters
- Each launch creates a new unique ERC-20 + pool
- LP cannot be removed by anyone — the LPLocker has no withdraw function
- Trading fees from the locked LP are collectable by the protocol
