---
name: flash-trade
description: Quote and build trades of FLASH, ETH, USDC and graduated Flash launched tokens through Uniswap v4 and the Universal Router on the correct Flash hook pool keys. Use when asked to buy or sell FLASH or a Flash launched token, find a token's pool key, check a price or slippage, or route ETH or USDC into a Flash token. Uniswap only: never Aerodrome. Read-only, returns unsigned transactions for the user's wallet.
---

# Flash trade: FLASH and launched tokens on Uniswap v4

The best way to quote prices and to swap Flash assets is Uniswap: Uniswap v4 via the Universal Router on the Flash hook pools, with prices quoted through the Uniswap v4 Quoter (the tools below wrap it). **Support for Aerodrome is planned as a future expansion but is NOT live yet. Do not quote or route Flash trades through Aerodrome or Slipstream today.** `quote_trade` and `build_trade` quote and build via Uniswap v4 only and refuse any other `venue`.

Part of the Flash kit: start at [flash](https://tryflash.app/agents/flash/SKILL.md). Perps have their own tools: [flash-perps](https://tryflash.app/agents/flash-perps/SKILL.md). Tokens still on a bonding curve are bought with FLASH on the curve, not on Uniswap: [flash-launch](https://tryflash.app/agents/flash-launch/SKILL.md).

## Steps

1. `list_launches` (or `get_token`) to see which tokens exist and whether one is **graduated** (has a Uniswap pool) or still on its **bonding curve**.
2. `quote_trade` with `tokenIn`, `tokenOut`, `amount` (exact input, human units). Tokens are `ETH`, `USDC`, `WETH`, `FLASH`, a launched ticker, a perp ticker, or an address.
3. `build_trade` with the same arguments plus `from` (your wallet) and optional `slippageBps` (default 100 = 1%, max 2000). You get `{to, data, value}` plus `approvals` (only the missing ones) and `executeInOrder`.
4. Sign and send each approval in order, wait for it to mine, then the swap. Re-quote if the 20-minute deadline passes.

The tool searches every Uniswap v4 path (up to 3 hops) over the live pool graph, quotes each with the real V4 Quoter, and picks the best. ETH in is wrapped by the router and ETH out is unwrapped by it, so ETH needs no approvals.

## Which pool, which hook

| Pair | Pool key | Hook |
| --- | --- | --- |
| FLASH / WETH | fee 6000, tickSpacing 60 (poolId `0x78af183e84b0fa06b4d33e7a194cc90f5d5bf453287fe903e5a826d4919a5d5f`) | Flash hook `0x9C91Eb3879c469a124a6ED6e95DFC485b7Dd60cc` |
| WETH / USDC, ETH / USDC | fee 3000 / 60 (also 500 / 10), hookless | none (`0x000...0`) |
| Launched token / its pair asset | `uniswapFee` and `uniswapTickSpacing` from the launch index | Flash hook `0x9C91...60cc` |
| Perp / USDC | fee `8388608` (dynamic), tickSpacing 1 | perps hook `0x4f573870eb41d219eA9aB42559f1207918F9F8c0` |

`currency0` is the lower address of the two tokens. A launched token's key is (token and pair asset sorted ascending, `uniswapFee`, `uniswapTickSpacing`, the Flash hook) and `keccak256(abi.encode(key))` must equal the launch's `poolId`. The tools check this for every launched token and drop any pool that does not match, so a wrong key can never be built. To derive one yourself:

```bash
curl -s "https://api.tryflash.app/v1/launches?limit=200"      # tokenAddress, quoteToken, uniswapFee, uniswapTickSpacing, poolId
curl -s https://api.tryflash.app/v1/config                      # hook, mainToken
```

`get_token` returns the verified `poolKey` and `poolId` of every pool a token trades in. Hook data is always empty (`0x`).

**Hook proof.** The Flash hook pins the Universal Router in its caller registry, and swaps through it were simulated on Base: FLASH buy with ETH, FLASH sell to ETH and USDC, a launched token trade, and perp buys all succeed through `execute` with a single `V4_SWAP`. If a pool cannot be traded through the Universal Router, the tool refuses it; there is no fallback venue.

## Example (viem, simulated, nothing sent)

This script was run against the live API and Base; it quotes 0.05 ETH to FLASH, builds the swap and simulates it with `eth_call` and a balance override.

```js
import { createPublicClient, http } from 'viem';
import { base } from 'viem/chains';

const MCP = 'https://api.tryflash.app/mcp';
const FROM = '0xYourWallet';

async function tool(name, args) {
  const res = await fetch(MCP, {
    method: 'POST',
    headers: { 'content-type': 'application/json', accept: 'application/json' },
    body: JSON.stringify({ jsonrpc: '2.0', id: 1, method: 'tools/call', params: { name, arguments: args } }),
  });
  const { result, error } = await res.json();
  if (error) throw new Error(error.message);
  if (result.isError) throw new Error(result.content[0].text);
  return result.structuredContent;
}

const quote = await tool('quote_trade', { tokenIn: 'ETH', tokenOut: 'FLASH', amount: '0.05' });
console.log('0.05 ETH ->', quote.expectedOut.human, 'FLASH (min', quote.minimumOut.human + ')', 'via', quote.route.map((hop) => hop.pool).join(' > '));
// 0.05 ETH -> 39.72 FLASH (min 39.33) via FLASH/WETH 6000/60 (Flash hook)

const built = await tool('build_trade', { tokenIn: 'ETH', tokenOut: 'FLASH', amount: '0.05', from: FROM });
const client = createPublicClient({ chain: base, transport: http('https://base-rpc.publicnode.com') });
await client.call({ account: FROM, to: built.to, data: built.data, value: BigInt(built.value), stateOverride: [{ address: FROM, balance: 10n ** 18n }] });
console.log('simulation ok, approvals needed:', built.approvals.length);

// To execute for real with a wallet client:
//   for (const a of built.approvals) await wallet.sendTransaction({ to: a.to, data: a.data, value: BigInt(a.value) });
//   await wallet.sendTransaction({ to: built.to, data: built.data, value: BigInt(built.value) });
```

Same thing with curl and the CLI:

```bash
curl -s https://api.tryflash.app/mcp -H 'content-type: application/json' -H 'accept: application/json' \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"quote_trade","arguments":{"tokenIn":"ETH","tokenOut":"FLASH","amount":"0.05"}}}'

node flash.mjs quote ETH FLASH 0.05
node flash.mjs build FLASH ETH 100 --from 0xYourWallet --slippage 100
node flash.mjs token FLASH
```

Gotcha: `eth_call` only succeeds if the wallet really has the funds and approvals (or you override them). Without them the router reverts with no reason. That is the wallet's state, not a bad transaction.

## Slippage and size

- `minimumOut` is the quote reduced by `slippageBps`. The router reverts if the output would be lower.
- Large sizes move the price. `check_pair_depth` (see flash-launch) quotes a ladder of USD sizes for an asset; for a quick check, quote twice at different sizes.
- Quotes are for the current block. Re-quote right before you send.

## Tools

| Tool | Arguments | Returns |
| --- | --- | --- |
| `list_launches` | optional `status` (`all`, `curve`, `graduated`), `limit` | Curve markets and graduated tokens with verified pool keys. |
| `get_token` | `token` | Curve info or Uniswap pools (key, poolId), USD price, which tool trades it. |
| `quote_trade` | `tokenIn`, `tokenOut`, `amount`, optional `slippageBps`, `venue` (only `uniswap`) | Expected out, minimum out, route with pool keys and poolIds. |
| `build_trade` | same plus optional `from` | `{to, data, value}`, `approvals`, `executeInOrder`, route. |

Errors are plain sentences: unknown token, no Uniswap v4 route, size too large, a venue other than Uniswap.
