---
name: arceus-launchpad
description: Launch, trade, and earn from ERC-20 tokens on Arceus — the token launchpad on Arc (Circle's L1, chain 5042). Liquidity is burned at launch, the creator's buy tax is 100% theirs, and every action here is permissionless. Use this skill when an agent needs to launch a token, buy/sell one, flush creator earnings, or read pad state on Arc.
---

# Arceus Launchpad — Agent Skill

Arceus launches ERC-20 tokens on Arc with one transaction: token deployed,
Uniswap v3 pool opened at a $3,000 market cap, and the LP position **burned to
`0xdEaD`** — verifiable with `ownerOf`, irreversible by anyone including the
platform. There is no launch fee. The creator sets a buy tax (1–10%) at launch
and keeps 100% of it; a 0.5% protocol skim rides beside it and buys-and-burns
$ARCEUS. Sells and wallet transfers are never taxed.

Everything below was executed against the live chain before being written down.

## Chain: Arc (5042)

| | |
|---|---|
| Chain ID | `5042` |
| Native currency | USDC, **18 decimals** (gas is USDC) |
| Public RPC | `https://rpc.arc-scan.org` |
| Explorer | `https://arc-scan.org` |

Two Arc quirks every integration must respect:

1. **Native USDC has 18 decimals.** `msg.value` of 1 USDC is `1e18`.
2. **The USDC "module" at `0x3600000000000000000000000000000000000000` is the
   ERC-20 view of the same native balance, at 6 decimals.** Same money, two
   views: receiving native credits your module balance (÷1e12), transferring
   module debits your native. Pools pair against the module, so on-chain pool
   amounts are 6-decimal.

## Contracts

| Contract | Address |
|---|---|
| ArceusPadV3 (launchpad) | `0xE20a9aEFE7A8c4e58EcAB04afD0D6bc54663Aee4` |
| ArceusRouterV3 (trading) | `0xA1F03418F84b772dc5190e1DDa621fe63b29bbd1` |
| ArceusTreasury (buyback-burn) | `0xeA35371aDFd2FEd05F96715446f32c906eF73631` |
| $ARCEUS token | `0x3B7C2b72C002d9662e5A74470066Ecd8aFa08356` |
| USDC module | `0x3600000000000000000000000000000000000000` |

No contract here has an owner function, setter, or proxy. What you read is
what runs forever.

## Launching a token — the easy way (start here)

Do not hand-encode anything. Ask the site for the exact calldata and send it:

```
GET https://www.arceus.live/api/launch-calldata?name=MyToken&symbol=MTK&taxBps=500
```

Returns `{ to, value, data, salt, gasHint }` — the same encoder the site
itself uses built it, so it cannot be mis-encoded. Then one send:

```bash
cast send <to> <data> --value <value>   --rpc-url https://rpc.arc-scan.org --private-key $KEY
```

Optional query params: `description`, `logoUrl`, `website`, `twitter`,
`telegram`, `earlyBuyUsdc` (decimal, becomes msg.value), `antiSnipe=false`,
`salt` (32-byte hex; random otherwise). That is the entire integration:
one GET, one signed transaction.

Collecting earnings works the same way:

```
GET https://www.arceus.live/api/collect-calldata?token=0xYOURTOKEN
```

Returns `{ to, value, data, pendingUsdc }` — check `pendingUsdc` to decide
whether the send is worth its gas, then send. Anyone may send it; the
creator is paid in USDC regardless of who pays the gas.

## Launching by hand (advanced)

Call `launchTokenTax` on the pad. Launch is free; send value only if you want
an atomic first buy.

```solidity
function launchTokenTax(
    LaunchParams p,     // see struct below
    bytes32 salt,       // any random 32 bytes (CREATE2 salt)
    address referrer,   // pass address(0)
    uint256 earlyBuyEth,// optional first buy, native 18-dec USDC; 0 for none
    uint256 taxBps      // MUST be 100, 300, 500 or 1000 (1%, 3%, 5%, 10%)
) payable returns (address token, bytes32 poolId);

struct LaunchParams {
    string name; string symbol;
    uint256 supply;        // use 1_000_000_000e18 (1B, the site standard)
    uint256 maxWalletBps;  // anti-snipe: 200 = 2% max wallet for 15 min; 0 = off
    string logoUrl; string website; string twitter; string telegram; string description;
}
```

**The nine launch fields are ONE tuple.** Encoding them as nine flat
arguments produces the wrong selector and an empty revert with no reason
string — the single most common integration mistake. If your `eth_call`
reverts with no data, check your selector first: correct is `0x08ed28be`.

Rules the contract enforces:
- `msg.value` must equal `earlyBuyEth` exactly (launch itself costs nothing).
- `taxBps` must be one of the four presets. There is no tax-free launch: with
  the LP burned, the tax is the only thing that pays the creator.
- The tax rate is immutable forever after launch.

The wallet that sends the launch is the **creator**: all flushed tax goes to
it. In one transaction the pad deploys the token, opens the pool, deposits the
full supply, burns the LP NFT to `0xdEaD`, executes your early buy (if any),
and arms anti-snipe (if any).

### Example with cast

```bash
# Empty strings inside the tuple must be "" — bare commas break the parser.
cast send 0xE20a9aEFE7A8c4e58EcAB04afD0D6bc54663Aee4 \
  "launchTokenTax((string,string,uint256,uint256,string,string,string,string,string),bytes32,address,uint256,uint256)" \
  '(MyToken,MTK,1000000000000000000000000000,200,"https://example.com/logo.png","","","","launched by an agent")' \
  0x$(openssl rand -hex 32) \
  0x0000000000000000000000000000000000000000 \
  0 \
  500 \
  --rpc-url https://rpc.arc-scan.org --private-key $KEY
```

Parser-proof alternative: build the calldata first with `cast calldata`
(same signature and arguments) — the hex must start with `08ed28be` — then
broadcast it raw: `cast send $PAD $CALLDATA --rpc-url … --private-key $KEY`.

Budget note: a launch consumes about 6.75M gas (~0.27 USDC at 40 gwei).
Keep at least 0.4 USDC in the wallet so the estimate's headroom never
bounces the send.

Read your new token back from the registry (last entry):

```bash
cast call 0xE20a9aEFE7A8c4e58EcAB04afD0D6bc54663Aee4 \
  "getAllTokens()(address[])" --rpc-url https://rpc.arc-scan.org
```

## Trading

Buy and sell through ArceusRouterV3. Amounts are native 18-decimal USDC on
the way in; token amounts are standard 18-decimal.

```solidity
function buy(address token, uint256 minOut) payable returns (uint256 tokensOut);
function sell(address token, uint256 amountIn, uint256 minOut) returns (uint256 usdcOut); // usdcOut is 18-dec
```

- **Buy**: send USDC as `msg.value`. On delivery the token skims
  `taxBps + 50` bps (the tax + protocol skim), so you receive
  `poolOutput × (10000 − taxBps − 50) / 10000`. `minOut` compares against the
  pool's pre-skim output.
- **Sell**: approve the router for the token first, then sell. **Sells are
  never taxed.** Payout arrives as native USDC.
- Quote by simulating the call (`eth_call`) — Arc's v3 has no quoter, but a
  simulated `buy`/`sell` returns the exact figure.

```bash
# buy 5 USDC of a token, no slippage floor
cast send 0xA1F03418F84b772dc5190e1DDa621fe63b29bbd1 \
  "buy(address,uint256)" $TOKEN 0 \
  --value 5000000000000000000 \
  --rpc-url https://rpc.arc-scan.org --private-key $KEY
```

## Creator earnings: flush

Tax accrues **as tokens inside the token contract**. Anyone may settle it:

```solidity
// on the TOKEN contract:
function flush() returns (uint256 sold, uint256 usdcOut);
```

`flush()` sells the pile into the pool (capped at 1% of pool reserves per call
to bound price impact) and pays USDC out immediately: the creator's share in
full, the protocol's 0.5% slice to the treasury. The caller pays only gas —
flushing someone else's token simply pays them.

Pending amount before flushing: simulate `flush()` with `eth_call`; the
creator's cut of `usdcOut` is `usdcOut × taxBps / (taxBps + 50)`.

## Reading state

All on the pad, keyed by token address:

```solidity
function getAllTokens() view returns (address[]);
function tokenInfo(address) view returns (
    address tokenAddress, uint256 lpTokenId, address creator, uint256 createdAt,
    int24 tickLower, int24 tickUpper, uint256 supply, uint256 maxWalletBps, bool tokenIsToken0);
function tokenMetadata(address) view returns (
    string logoUrl, string website, string twitter, string telegram, string description);
function poolOf(address) view returns (address);           // the token's v3 pool
function totalUsdcFeesToCreator(address) view returns (uint256); // 18-dec, lifetime
function graduationStatus(address) view returns (uint256 bought, uint256 threshold, bool graduated);
```

And on each token: `taxBps()`, `protocolTaxBps()`, `totalFlushedUsdc6()`,
`creator()`, `pool()`.

**Price** from the pool's `slot0()`: `ratio = (sqrtPriceX96 / 2^96)^2` is
token1-raw per token0-raw. The module carries 6 decimals against the token's
18, so the whole-unit USDC price is `1e12 / ratio` when USDC is token0
(addresses below `0x3600…` sort first) and `ratio × 1e12` when the token is
token0. Verify which side with `tokenInfo(...).tokenIsToken0`.

**Trust check** any agent can run before touching a token:

```bash
# the LP is burned iff this answers 0x…dEaD
cast call 0x39654A85A4C05127f5Fd6ED22CAeC077A0fB1377 \
  "ownerOf(uint256)(address)" $LP_TOKEN_ID --rpc-url https://rpc.arc-scan.org
```

(`0x3965…1377` is Arc's Uniswap v3 NonfungiblePositionManager; get
`LP_TOKEN_ID` from `tokenInfo`.)

## Economics summary

| Flow | Rate | Destination |
|---|---|---|
| Buy tax | 1–10% of every buy (creator's choice, immutable) | 100% to the creator, in USDC via flush |
| Protocol skim | 0.5% of every buy | Treasury: 2/3 buys & burns $ARCEUS, 1/3 operations |
| Sells | 0 | — |
| Wallet transfers | 0 | — |
| Launch fee | 0 | — |
| Pool fee | 0.01% (dust tier) | Strands at the burned position, by design |

## HTTP endpoints (no RPC tooling needed)

| | |
|---|---|
| `GET /api/launch-calldata` | Ready-to-send launch calldata: pass name/symbol/taxBps, get { to, value, data }. The mis-encoding-proof path |
| `GET /api/collect-calldata` | Ready-to-send collect calldata for a token, with the pending-USDC estimate |
| `GET /api/tokens` | The entire grid as one JSON document per token: address, name, symbol, creator, pad, router, taxBps, marketCap, supply, feesToCreator, pendingFees (bigints as strings), graduation, lastBuyBlock, links. Cached ~60s |
| `GET /agents/abi.json` | Full JSON ABIs (pad, router, token) with addresses — paste straight into viem/ethers |
| `GET /SKILL.md` | This file |
| `GET /llms.txt` | Machine-readable index of all of the above |

## Launching with viem

```ts
import { createWalletClient, createPublicClient, http, parseEther } from "viem";
import { privateKeyToAccount } from "viem/accounts";

const chain = {
  id: 5042, name: "Arc",
  nativeCurrency: { name: "USDC", symbol: "USDC", decimals: 18 },
  rpcUrls: { default: { http: ["https://rpc.arc-scan.org"] } },
};
const account = privateKeyToAccount(process.env.KEY);
const wallet = createWalletClient({ account, chain, transport: http() });
const pub = createPublicClient({ chain, transport: http() });

// abi from https://www.arceus.live/agents/abi.json -> contracts.ArceusPadV3
const { request, result } = await pub.simulateContract({
  account,
  address: "0xE20a9aEFE7A8c4e58EcAB04afD0D6bc54663Aee4",
  abi: padAbi,
  functionName: "launchTokenTax",
  args: [
    { name: "My Token", symbol: "MTK", supply: parseEther("1000000000"),
      maxWalletBps: 200n, logoUrl: "https://…", website: "", twitter: "",
      telegram: "", description: "launched by an agent" },
    `0x${crypto.getRandomValues(new Uint8Array(32)).reduce((s, b) => s + b.toString(16).padStart(2, "0"), "")}`,
    "0x0000000000000000000000000000000000000000",
    0n,      // earlyBuyEth
    500n,    // 5% tax
  ],
  value: 0n, // must equal earlyBuyEth
});
const [token, poolId] = result;   // simulate first — you know the address before you pay gas
const hash = await wallet.writeContract(request);
```

## Error dictionary

Every revert here is a short literal string. What each one means:

| Revert | Meaning | Fix |
|---|---|---|
| `bad tax` | taxBps is not 100/300/500/1000 | use a preset |
| `bad value: fee + earlyBuy` | msg.value ≠ earlyBuyEth | match them exactly |
| `bad supply` / `bad maxWallet` | zero supply / cap > 100% | fix params |
| `pool price mismatch` | someone pre-created the pool at a hostile price | retry with a new salt |
| `max wallet` | anti-snipe cap hit (first 15 min) | buy less, or wait out the window |
| `nothing to flush` | tax pile is empty | nothing to collect yet |
| `pool too shallow` | flush cap (1% of reserves) rounds to zero | wait for liquidity/volume |
| `Token not found` | address not launched by this pad | check /api/tokens |
| `only launchpad` / `configured` | calling token plumbing directly | don't — the pad owns setup |

## Safety notes for agents

- Simulate (`eth_call`) any state-changing call before sending it; every
  revert reason here is short and literal (`"bad tax"`, `"nothing to flush"`).
- Gas is USDC: a launch costs roughly 0.3 USDC of gas at typical prices, a
  buy or flush a few cents.
- Anti-snipe (if the creator armed it) caps any wallet to `maxWalletBps` of
  supply for 15 minutes after launch — size first buys accordingly.
- Nothing on this pad takes custody: tokens flow wallet↔pool, earnings flow
  contract→creator. If a call would send funds anywhere else, it is not this
  pad.

Site: https://www.arceus.live · Telegram: https://t.me/arceuspad · X: https://x.com/Arceuspad
