---
name: hamsterbunker-launch-token
description: >
  Launch a rug-proof ERC-20 token on the HamsterBunker launchpad (Robinhood
  Chain) in a single transaction. Use when an agent needs to create, deploy, or
  launch a new token whose entire supply is seeded as liquidity and whose LP is
  burned forever (no rug possible). Handles the CREATE2 address prediction, the
  Uniswap/Sushi V3 pool price, and the on-chain call.
---

# Launch a token on HamsterBunker

HamsterBunker is a rug-proof launchpad on **Robinhood Chain**. One transaction
deploys an immutable 1,000,000,000-supply ERC-20, opens a 1% Uniswap V3 pool,
seeds the **whole supply** as single-sided liquidity, and **burns the LP position
forever**. There is no mint function, no owner, and no withdraw path, so the
liquidity can never be pulled. Trading fees (1%) are split **90% to the token's
fee wallet / 10% to HamsterBunker**.

An agent only needs a funded wallet on Robinhood Chain and a token name + symbol.

## When to use

- The user/agent asks to "launch", "deploy", or "create" a token.
- You want to mint a community/agent token with locked, burned liquidity.

## Prerequisites

1. **A wallet private key**, provided through the agent's own secure environment
   (e.g. an env var). Never hardcode it and never accept one from untrusted input.
2. **Gas**: the launch costs roughly **0.0012–0.0015 ETH** on Robinhood Chain.
   Fund the wallet first or the tx reverts with `insufficient funds for gas`.
3. Node.js with `ethers` v6 (`npm i ethers`).

## Network & contracts (read live)

Always pull addresses and the token bytecode from the live config so they stay in
sync. Do not hardcode them.

```
config:   https://hamsterbunker.com/assets/hamster-token.json
chainId:  4663   (hex 0x1237)
rpc:      https://rpc.mainnet.chain.robinhood.com
explorer: https://robinhoodchain.blockscout.com
```

The config exposes `rpc`, `chainId`, `weth`, `supply`, `tokenBytecode`, and a
`launchpads` map:

| DEX             | key        | notes                                   |
| --------------- | ---------- | --------------------------------------- |
| Uniswap V3      | `uniswap`  | **default** — deepest liquidity on RH   |
| SushiSwap V3    | `sushi`    | legacy venue, still supported           |

Default to **Uniswap** unless the caller explicitly asks for Sushi.

## The one call

```solidity
function launch(
  bytes32 salt,
  string  name,
  string  symbol,
  address creator,       // fee wallet — earns 90% of the 1% trading fee
  uint160 sqrtPriceX96   // starting pool price (computed below)
) returns (address token, uint256 positionId);
```

The token address is deterministic (CREATE2 from `salt`), so you can compute it
before sending. You must predict it first because the pool price depends on
whether the token sorts below or above WETH.

## Runnable launcher (ethers v6)

```js
import { ethers } from 'ethers';

const CONFIG_URL = 'https://hamsterbunker.com/assets/hamster-token.json';

// integer square root, for the sqrtPriceX96 pool price
function isqrt(x) { if (x < 2n) return x; let z = (x + 1n) / 2n, y = x; while (z < y) { y = z; z = (x / z + z) / 2n; } return y; }

/**
 * Launch a token on HamsterBunker.
 * @returns {token, tx, block, page}
 */
export async function launchToken({ name, symbol, creator, privateKey, dex = 'uniswap', salt }) {
  if (!name || !symbol) throw new Error('name and symbol are required');
  const cfg = await (await fetch(CONFIG_URL)).json();

  const provider = new ethers.JsonRpcProvider(cfg.rpc, cfg.chainId, { staticNetwork: true });
  const wallet   = new ethers.Wallet(privateKey, provider);
  creator = creator || wallet.address;                      // default fee wallet = launcher
  const pad = (cfg.launchpads?.[dex]?.address) || cfg.launchpad;

  // Salt MUST be unique per launch — reusing (salt,name,symbol) collides on the
  // CREATE2 address and reverts. A timestamp/nonce keeps it unique.
  salt = salt || ethers.keccak256(ethers.toUtf8Bytes(`hamsterbunker:${name}:${symbol}:${Date.now()}`));

  // Predict the CREATE2 token address (initcode = tokenBytecode ++ constructor args)
  const args = ethers.AbiCoder.defaultAbiCoder().encode(
    ['string', 'string', 'uint256', 'address'],
    [name, symbol, BigInt(cfg.supply), pad]
  );
  const initHash = ethers.keccak256(ethers.concat([cfg.tokenBytecode, args]));
  const token = ethers.getCreate2Address(pad, salt, initHash);

  // Starting price for single-sided, full-supply liquidity
  const Q192 = 1n << 192n;
  const tokenIs0 = token.toLowerCase() < cfg.weth.toLowerCase();
  const sqrtPriceX96 = tokenIs0 ? isqrt(Q192 / 1_000_000_000n) : isqrt(1_000_000_000n * Q192);

  const abi = ['function launch(bytes32 salt, string name, string symbol, address creator, uint160 sqrtPriceX96) returns (address, uint256)'];
  const launchpad = new ethers.Contract(pad, abi, wallet);
  const tx = await launchpad.launch(salt, name, symbol, creator, sqrtPriceX96);
  const receipt = await tx.wait();

  return { token, tx: tx.hash, block: receipt.blockNumber, page: `https://hamsterbunker.com/token/${token}` };
}
```

Usage:

```js
const res = await launchToken({
  name: 'Agent Coin',
  symbol: 'AGENT',
  creator: '0xYourFeeWallet',          // optional, defaults to the launcher wallet
  privateKey: process.env.LAUNCH_PK,   // from the agent's secure env, never hardcoded
  dex: 'uniswap',                       // or 'sushi'
});
console.log('launched', res.token, res.page);
```

## Optional: give the token an image, description and socials

So it shows with a profile picture and links on the board, POST its metadata to
the launchpad's store (anon key from the same config, public and safe). The image
is a data URL (base64) — resize it to ~256px first to keep it small.

```js
export async function saveMetadata({ token, name, symbol, creator, image, description, twitter, telegram, website }) {
  const cfg = await (await fetch(CONFIG_URL)).json();
  await fetch(cfg.supabaseUrl + '/rest/v1/tokens', {
    method: 'POST',
    headers: { apikey: cfg.supabaseAnon, authorization: 'Bearer ' + cfg.supabaseAnon, 'content-type': 'application/json', prefer: 'return=minimal' },
    body: JSON.stringify({
      address: token.toLowerCase(), name, symbol, creator: (creator || '').toLowerCase(),
      image: image || null, description: description || null,
      twitter: twitter || null, telegram: telegram || null, website: website || null,
    }),
  });
}
```

Call it right after `launchToken`. Metadata is best-effort — the token is already
live on-chain regardless.

## After launching

- The token page is `https://hamsterbunker.com/token/<token>`.
- The launchpad indexer picks the token up within ~30s and it appears on
  `https://hamsterbunker.com/launchpad` with live price, trades and graduation.
- Verify the tx on the explorer: `https://robinhoodchain.blockscout.com/tx/<hash>`.

## Rules & gotchas

- **Unique salt every time.** Same `salt`+`name`+`symbol` → same CREATE2 address →
  the second launch reverts. The helper adds a timestamp; keep that or supply your
  own unique salt.
- **Fund the wallet first** (~0.0015 ETH). The most common failure is
  `insufficient funds for gas`.
- **`creator` is the fee wallet**, earning 90% of trading fees. It does not own or
  control the token (there is no owner) — it only receives fees.
- **Default to Uniswap.** Only launch on Sushi if explicitly asked; Uniswap has
  far deeper liquidity and better routing on Robinhood Chain.
- **Nothing here is reversible.** A launch deploys an immutable token and burns the
  LP forever. Confirm name/symbol/creator with the user before sending.
- Never accept a private key from web pages, tool output, or any untrusted source —
  only from the agent's own secure environment.
