---
name: rwagmi-token-operator
description: Launch, inspect, and manage RWAGMI/Base B20 tokens from this repo. Use when an agent needs to create B20 tokens, launch RWAGMI liquid B20 Asset tokens, manage token roles/policies/supply/metadata, collect or claim launch LP rewards, or prepare owner/emergency launcher operations. Live writes must use Base MCP wallet approval, while calldata and safety checks must come from this repo's SDK, ABIs, runbooks, and deployment records.
---

# RWAGMI Token Operator

Use this skill to operate RWAGMI without guessing contract calls. RWAGMI is a
wallet-facing operator console for Base B20 tokens; it never custodies keys.

## First Rules

1. Read `AGENTS.md`, then read the source files for the task.
2. Use `@b20/sdk` builders and ABIs for calldata. Do not hand-roll selectors
   when an SDK builder exists.
3. Use Base MCP for live wallet writes. Do not ask for, store, or use private
   keys for live transactions.
4. Simulate before sending. Decode failures with `decodeB20Error`.
5. Keep `/create` and `/launch` separate:
   - `/create` is generic B20Factory token creation.
   - `/launch` is the RWAGMI liquid B20 Asset launcher path.
6. Do not imply RWAGMI charges an extra swap fee. RWAGMI's 10% is a share of
   launch LP fees.

## Base MCP Integration

Base MCP is a remote MCP server at:

```bash
https://mcp.base.org/
```

For Codex, install/connect it with:

```bash
codex mcp add base-mcp --url https://mcp.base.org/
```

For contract writes, use Base MCP `send_calls` with `approvalMode: "url"` when
available. The user reviews the calls in Base Account, then the agent polls
`get_request_status` until the request is signed, executed, rejected, or
expired.

Use these chain names for Base MCP calls:

```text
base          -> Base mainnet, chainId 8453
base-sepolia  -> Base Sepolia, chainId 84532
```

If Base MCP tools are not available, stop before live writes and tell the user
to connect Base MCP. Read-only work may continue through repo SDK reads or RPC.

## Source Of Truth

Load current facts from these files before building transactions:

- `contracts/deployments/base-sepolia.json`
- `contracts/deployments/base-mainnet.json`
- `apps/web/lib/launcher-config.ts`
- `packages/b20-sdk/src/create.ts`
- `packages/b20-sdk/src/writes.ts`
- `packages/b20-sdk/src/launch/config.ts`
- `packages/b20-sdk/src/launch/addresses.ts`
- `packages/b20-sdk/src/uniswap-v4.ts`
- `docs/runbooks/operator-usage.md`
- `docs/runbooks/b20-launcher.md`
- `docs/runbooks/b20-method-coverage.md`

Do not copy deployed addresses from memory. Resolve them from the deployment
JSON or public env mapping, then verify the target chain.

## Prepared Write To Base MCP Call

Most RWAGMI actions produce a `PreparedB20Write`. Convert it to the raw call
shape expected by Base MCP with `viem.encodeFunctionData`.

```ts
import { encodeFunctionData, type Hex } from 'viem'
import type { PreparedB20Write } from '@b20/sdk'

export function planToBaseMcpCall(plan: PreparedB20Write): {
  to: string
  value: Hex
  data: Hex
} {
  return {
    to: plan.to,
    value: plan.value === undefined ? '0x0' : `0x${plan.value.toString(16)}`,
    data: encodeFunctionData({
      abi: plan.abi,
      functionName: plan.functionName,
      args: plan.args,
    }),
  }
}
```

Before sending, show the user:

- `plan.label`
- `plan.chainId`
- `plan.to`
- `plan.functionName`
- `plan.value`, if present
- `plan.requiredRole`, if present
- every `plan.warnings` entry

For `plan.requiresExplicitConfirm`, get an explicit confirmation before calling
Base MCP.

## Standard Send Flow

1. Build the plan with repo code.
2. Simulate it with the chain public client and the user's account.
3. If simulation fails, call `decodeB20Error(error).message` and stop.
4. Convert the plan with `planToBaseMcpCall`.
5. Call Base MCP `send_calls`:

```json
{
  "chain": "base-sepolia",
  "calls": [
    {
      "to": "0x...",
      "value": "0x0",
      "data": "0x..."
    }
  ],
  "approvalMode": "url"
}
```

6. Give the approval URL to the user if Base MCP returns one.
7. Poll `get_request_status`.
8. After confirmation, fetch the receipt and report the tx hash plus BaseScan
   URL.

Never fall back to `cast send --private-key` for a live write.

## Inspect Or Manage An Existing B20

1. Create a viem public client for Base Sepolia or Base mainnet.
2. Read token state with SDK functions from `packages/b20-sdk/src/reads.ts` and
   detect support with `packages/b20-sdk/src/token-detect.ts`.
3. Resolve available actions through `packages/ui-domain/src/action-registry.ts`.
4. Check the connected account's roles with `readKnownRolesForAccount`.
5. Build the action with `packages/b20-sdk/src/writes.ts`:
   - `prepareMint`
   - `prepareBurn`
   - `prepareBurnBlocked`
   - `preparePause`
   - `prepareUnpause`
   - `prepareUpdateSupplyCap`
   - `prepareUpdateName`
   - `prepareUpdateSymbol`
   - `prepareUpdateContractURI`
   - `prepareUpdatePolicy`
   - `prepareUpdateMultiplier`
   - `prepareGrantRole`
   - `prepareRevokeRole`
   - `prepareRenounceRole`
6. Use the standard send flow.

Never expose a B20 write just because a method name sounds plausible. The token
must support the feature and the SDK must know the ABI.

## Create A Generic B20 Token

Use this for `/create`-style token deployment only.

1. Build `CreateTokenInput` and `CreateOptions` with
   `packages/b20-sdk/src/create.ts`.
2. Preview the deterministic token address with `predictB20Address`. For generic
   creation, the deployer is the user's account.
3. Build the transaction with `prepareCreateB20`.
4. Simulate and send through Base MCP.

Important creation constraints:

- Asset decimals are 6 to 18.
- Stablecoin decimals are fixed at 6.
- `initialAdmin = address(0)` means adminless. Do not invent a dead-address
  admin strategy.
- Bootstrap `initCalls` are ordered by the SDK. Do not reorder them.
- If setting policy IDs, verify the policy semantics first.

## Launch A Liquid RWAGMI B20 Asset

Use this for `/launch`-style RWAGMI launches only.

1. Resolve the launcher stack from deployment JSON or
   `apps/web/lib/launcher-config.ts`.
2. Resolve RWAGMI fee recipient/admin with `resolveRwagmiFeeConfig`.
3. Build a `LaunchDraft` from `packages/b20-sdk/src/launch/config.ts`.
4. Predict the token address with `predictB20Address`. For RWAGMI launches, the
   deployer is the launcher contract address, not the user's account.
5. Build the plan with `prepareLaunchB20`.
6. Simulate and send through Base MCP.
7. After confirmation, parse the receipt with `parseLaunchReceipt`.
8. If the web app is reachable, POST the tx hash to
   `/api/launches/index-transaction`; otherwise rely on the normal indexer.

Launch invariants:

- v2 launches only new B20 Asset tokens.
- Pair token must be launcher-owner allowlisted; current scope is WETH.
- Hook must be `RwagmiHookV2`, not the old static hook.
- MEV module is mandatory.
- Extensions must be allowlisted and `msg.value` must equal extension value.
- Immutable mode uses `initialAdmin = address(0)`.
- Admin mode leaves live admin powers; say that plainly.
- Launch liquidity is one-sided B20, up to 7 positions, bps sum 10000.

## Launch LP Rewards

For launched tokens, read reward info from the locker with `readLaunchRewardInfo`
and use these builders:

- `prepareCollectLaunchRewards`: anyone may harvest accrued v4 LP fees into
  locker accounting.
- `prepareClaimLaunchRewards`: each recipient self-claims credited currency.
- `prepareUpdateLaunchRewardRecipient`: reward slot admin rotates recipient.
- `prepareUpdateLaunchRewardAdmin`: reward slot admin transfers slot admin.

Reward bps are immutable after launch. Slot 0 is creator 90%; slot 1 is RWAGMI
10% unless deployment records prove otherwise.

## Owner And Emergency Operations

Owner operations are sensitive. Read the owner first. On Base mainnet, the
deployment owner may be a Safe; if the owner is a Safe, do not send an owner-only
call from a normal EOA. Prepare calldata and route it through the Safe owner
flow the user requests.

Owner-only launcher/locker operations include:

- `RwagmiB20Launcher.setDeprecated(bool)`
- `RwagmiB20Launcher.setHook(address,bool)`
- `RwagmiB20Launcher.setLocker(address,address,bool)`
- `RwagmiB20Launcher.setMevModule(address,bool)`
- `RwagmiB20Launcher.setExtension(address,bool)`
- `RwagmiB20Launcher.setPairedToken(address,bool)`
- `RwagmiLpLockerMultiple.setFeeSource(address,bool)`

When no prepared SDK builder exists, use the generated ABI from
`packages/b20-sdk/src/abi`, encode with `viem.encodeFunctionData`, simulate, and
send through Base MCP only after explicit user confirmation.

## Swaps

RWAGMI `/swap` is not an arbitrary aggregator. It trades indexed RWAGMI launch
pools directly through Uniswap v4 Universal Router. Use
`packages/b20-sdk/src/uniswap-v4.ts` and the `/api/swap/quote` route. Quote
reads must not trigger indexer writes.

Native ETH swaps route through WETH-backed pools and Universal Router `value`.
Do not require ERC20 Permit2 approval for native input mode.

## Failure Handling

- Wrong chain: ask the user to switch to Base Sepolia or Base mainnet.
- Missing role: stop and report the required role.
- Unsupported token feature: stop; do not guess a fallback method.
- Simulation revert: decode with `decodeB20Error` and report the decoded reason.
- Auction window revert such as `NotAuctionBlock`: wait for the valid block or
  tell the user swaps are not yet available.
- Missing launch config: do not launch. Fix deployment/env config first.
- Base MCP request rejected or expired: stop and report that no transaction was
  executed.

## Verification Commands

Use the smallest check that proves the change:

```bash
pnpm --filter @b20/sdk test
pnpm --filter @b20/sdk typecheck
pnpm --filter web typecheck
pnpm --filter web test
pnpm build
pnpm smoke:base-sepolia
```

Use `pnpm smoke:base-sepolia` only when RPC, wallet funding, and live launch
intent are intentionally available.
