# SushiSwap V3

> Swap tokens and manage concentrated liquidity positions on SushiSwap V3 across Ethereum, Arbitrum, Base, Polygon, and Optimism

- Skill: `okx-plugin-store/sushiswap-v3` (Agent Skill, multi-file: 20 files)
- Install (CLI): `npx skillmds add okx-plugin-store/sushiswap-v3`
- Raw SKILL.md: https://api.skillmd.com/api/skills/okx-plugin-store/sushiswap-v3/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: okx (https://skillmd.com/u/okx-plugin-store)
- Updated: 2026-09-09
- Page: https://skillmd.com/skills/okx-plugin-store/sushiswap-v3

---



## Pre-flight Dependencies (auto-injected by Plugin Store CI)

> Run once per session before first use. These checks ensure required tools are installed.

### Version check (auto-injected)

> **AI Agent Instruction**: Run this version check before executing any commands from this skill. The check is a read-only fetch from `raw.githubusercontent.com` — it does **not** install anything. If it reports `Update available`, you MUST stop, surface the message to the user verbatim, and obtain explicit confirmation before running the suggested `npx skills add …` command. Do not run the update silently. After a confirmed update completes, re-read this SKILL.md before proceeding.

```bash
# Check for skill updates (1-hour cache).
# Network scope: this block calls raw.githubusercontent.com for the version probe only.
# It does NOT install anything; install requires user-confirmed `npx skills add` below.
UPDATE_CACHE="$HOME/.plugin-store/update-cache/sushiswap-v3-plugin"
CACHE_MAX=3600
LOCAL_VER="0.1.2"
DO_CHECK=true

if [ -f "$UPDATE_CACHE" ]; then
  CACHE_MOD=$(stat -f %m "$UPDATE_CACHE" 2>/dev/null || stat -c %Y "$UPDATE_CACHE" 2>/dev/null || echo 0)
  NOW=$(date +%s)
  AGE=$(( NOW - CACHE_MOD ))
  [ "$AGE" -lt "$CACHE_MAX" ] && DO_CHECK=false
fi

if [ "$DO_CHECK" = true ]; then
  REMOTE_VER=$(curl -sf --max-time 3 "https://raw.githubusercontent.com/okx/plugin-store/main/skills/sushiswap-v3-plugin/plugin.yaml" | grep '^version' | head -1 | tr -d '"' | awk '{print $2}')
  if [ -n "$REMOTE_VER" ]; then
    mkdir -p "$HOME/.plugin-store/update-cache"
    echo "$REMOTE_VER" > "$UPDATE_CACHE"
  fi
fi

REMOTE_VER=$(cat "$UPDATE_CACHE" 2>/dev/null || echo "$LOCAL_VER")
if [ "$REMOTE_VER" != "$LOCAL_VER" ]; then
  echo "Update available: sushiswap-v3-plugin v$LOCAL_VER -> v$REMOTE_VER."
  echo "ACTION REQUIRED: ask the user to confirm before running:"
  echo "  npx skills add okx/plugin-store --skill sushiswap-v3-plugin --global"
  echo "(This contacts the npm registry and github.com/okx/plugin-store and overwrites this skill. Do NOT auto-run.)"
fi
```

### Install onchainos CLI + Skills (auto-injected)

```bash
# 1. Install onchainos CLI — pin to latest release tag, verify SHA256
#    of the installer before executing (no curl|sh from main).
if ! command -v onchainos >/dev/null 2>&1; then
  set -e
  LATEST_TAG=$(curl -sSL --max-time 5 \
    "https://api.github.com/repos/okx/onchainos-skills/releases/latest" \
    | sed -n 's/.*"tag_name"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' | head -1)
  if [ -z "$LATEST_TAG" ]; then
    echo "ERROR: failed to resolve latest onchainos release tag (network or rate limit)." >&2
    echo "       Manual install: https://github.com/okx/onchainos-skills" >&2
    exit 1
  fi

  ONCHAINOS_TMP=$(mktemp -d)
  curl -sSL --max-time 30 \
    "https://raw.githubusercontent.com/okx/onchainos-skills/${LATEST_TAG}/install.sh" \
    -o "$ONCHAINOS_TMP/install.sh"
  curl -sSL --max-time 30 \
    "https://github.com/okx/onchainos-skills/releases/download/${LATEST_TAG}/installer-checksums.txt" \
    -o "$ONCHAINOS_TMP/installer-checksums.txt"

  EXPECTED=$(awk '$2 ~ /install\.sh$/ {print $1; exit}' "$ONCHAINOS_TMP/installer-checksums.txt")
  if command -v sha256sum >/dev/null 2>&1; then
    ACTUAL=$(sha256sum "$ONCHAINOS_TMP/install.sh" | awk '{print $1}')
  else
    ACTUAL=$(shasum -a 256 "$ONCHAINOS_TMP/install.sh" | awk '{print $1}')
  fi
  if [ -z "$EXPECTED" ] || [ "$EXPECTED" != "$ACTUAL" ]; then
    echo "ERROR: onchainos installer SHA256 mismatch — refusing to execute." >&2
    echo "       expected=$EXPECTED  actual=$ACTUAL  tag=$LATEST_TAG" >&2
    rm -rf "$ONCHAINOS_TMP"
    exit 1
  fi

  sh "$ONCHAINOS_TMP/install.sh"
  rm -rf "$ONCHAINOS_TMP"
  set +e
fi

# 2. Install onchainos skills (enables AI agent to use onchainos commands)
npx skills add okx/onchainos-skills --yes --global

# 3. Install plugin-store skills (enables plugin discovery and management)
npx skills add okx/plugin-store --skill plugin-store --yes --global
```

### Install sushiswap-v3-plugin binary + launcher (auto-injected)

```bash
# Install shared infrastructure (launcher + update checker, only once)
LAUNCHER="$HOME/.plugin-store/launcher.sh"
CHECKER="$HOME/.plugin-store/update-checker.py"
if [ ! -f "$LAUNCHER" ]; then
  mkdir -p "$HOME/.plugin-store"
  curl -fsSL "https://raw.githubusercontent.com/okx/plugin-store/main/scripts/launcher.sh" -o "$LAUNCHER" 2>/dev/null || true
  chmod +x "$LAUNCHER"
fi
if [ ! -f "$CHECKER" ]; then
  curl -fsSL "https://raw.githubusercontent.com/okx/plugin-store/main/scripts/update-checker.py" -o "$CHECKER" 2>/dev/null || true
fi

# Clean up old installation
rm -f "$HOME/.local/bin/sushiswap-v3-plugin" "$HOME/.local/bin/.sushiswap-v3-plugin-core" 2>/dev/null

# Download binary
OS=$(uname -s | tr A-Z a-z)
ARCH=$(uname -m)
EXT=""
case "${OS}_${ARCH}" in
  darwin_arm64)  TARGET="aarch64-apple-darwin" ;;
  darwin_x86_64) TARGET="x86_64-apple-darwin" ;;
  linux_x86_64)  TARGET="x86_64-unknown-linux-musl" ;;
  linux_i686)    TARGET="i686-unknown-linux-musl" ;;
  linux_aarch64) TARGET="aarch64-unknown-linux-musl" ;;
  linux_armv7l)  TARGET="armv7-unknown-linux-musleabihf" ;;
  mingw*_x86_64|msys*_x86_64|cygwin*_x86_64)   TARGET="x86_64-pc-windows-msvc"; EXT=".exe" ;;
  mingw*_i686|msys*_i686|cygwin*_i686)           TARGET="i686-pc-windows-msvc"; EXT=".exe" ;;
  mingw*_aarch64|msys*_aarch64|cygwin*_aarch64)  TARGET="aarch64-pc-windows-msvc"; EXT=".exe" ;;
esac
mkdir -p ~/.local/bin

# Download binary + checksums to a sandbox, verify SHA256 before installing.
# Fail-closed: any mismatch / missing checksum entry refuses the install.
# Matches the producer-side workflow at
# .github/workflows/plugin-publish.yml which uploads `checksums.txt`
# alongside the 9 platform binaries under each release tag.
BIN_TMP=$(mktemp -d)
RELEASE_BASE="https://github.com/okx/plugin-store/releases/download/plugins/sushiswap-v3-plugin@0.1.2"
curl -fsSL "${RELEASE_BASE}/sushiswap-v3-plugin-${TARGET}${EXT}" -o "$BIN_TMP/sushiswap-v3-plugin${EXT}" || {
  echo "ERROR: failed to download sushiswap-v3-plugin-${TARGET}${EXT}" >&2
  rm -rf "$BIN_TMP"; exit 1; }
curl -fsSL "${RELEASE_BASE}/checksums.txt" -o "$BIN_TMP/checksums.txt" || {
  echo "ERROR: failed to download checksums.txt for sushiswap-v3-plugin@0.1.2" >&2
  rm -rf "$BIN_TMP"; exit 1; }

EXPECTED=$(awk -v b="sushiswap-v3-plugin-${TARGET}${EXT}" '$2 == b {print $1; exit}' "$BIN_TMP/checksums.txt")
if command -v sha256sum >/dev/null 2>&1; then
  ACTUAL=$(sha256sum "$BIN_TMP/sushiswap-v3-plugin${EXT}" | awk '{print $1}')
else
  ACTUAL=$(shasum -a 256 "$BIN_TMP/sushiswap-v3-plugin${EXT}" | awk '{print $1}')
fi
if [ -z "$EXPECTED" ] || [ "$EXPECTED" != "$ACTUAL" ]; then
  echo "ERROR: sushiswap-v3-plugin SHA256 mismatch — refusing to install." >&2
  echo "       expected=$EXPECTED  actual=$ACTUAL  target=${TARGET}" >&2
  rm -rf "$BIN_TMP"; exit 1
fi

mv "$BIN_TMP/sushiswap-v3-plugin${EXT}" ~/.local/bin/.sushiswap-v3-plugin-core${EXT}
chmod +x ~/.local/bin/.sushiswap-v3-plugin-core${EXT}
rm -rf "$BIN_TMP"

# Symlink CLI name to universal launcher
ln -sf "$LAUNCHER" ~/.local/bin/sushiswap-v3-plugin

# Register version
mkdir -p "$HOME/.plugin-store/managed"
echo "0.1.2" > "$HOME/.plugin-store/managed/sushiswap-v3-plugin"
```

---


## Live Trading Confirmation Protocol

These gates are **mandatory** for the AI agent driving this skill. Before any call that signs or broadcasts an on-chain transaction via SushiSwap V3 (any internal write code path that ends in a real `onchainos wallet contract-call` submission), ALL of the following must be true:

1. **Paper / preview mode is the default.** Real on-chain writes MUST NOT be broadcast unless the user has explicitly switched to live mode via the confirmation flow in rule 2. If no explicit live-mode switch has been performed in the current session, the agent MUST refuse the write.
2. **Live-mode switch requires a typed user confirmation.** Before flipping to live mode, the agent MUST display to the user: wallet address (`onchainos wallet addresses`), current balance (`onchainos wallet balance`), the configured per-trade / per-session risk limits, and a statement that on-chain writes are irreversible. The user MUST then reply with an unambiguous typed confirmation (e.g. `confirm live mode` / `确认开启实盘`). A conversational "yes / sure / 可以" alone does not satisfy this gate.
3. **Preview before every write.** Every write operation MUST first generate a preview (resolved fields: action, target token + amount, expected outcome, estimated gas, recipient / contract). The user must confirm the preview either explicitly per write, OR via the session-authorization granted in rule 2 within the limits in rule 4.
4. **Session autonomy is bounded.** Even after a session-level live confirmation in rule 2, the agent MAY only act autonomously WITHIN the limits in this skill's config (max position / trade size, max number of writes per session, max gas). When ANY limit is hit, the agent MUST stop and obtain a fresh typed confirmation before resuming. Do NOT auto-resume after a risk-control trigger.
5. **No signing on unreviewed transactions.** Never call `onchainos wallet contract-call` on an `--unsigned-tx` whose quote / preview was not produced in the current authorized session. Reusing a stale unsigned tx across sessions is forbidden.
6. **Refuse on gate failure.** If any of gates 1–5 cannot be satisfied (e.g. live mode not confirmed, no preview produced this session, risk limits would be exceeded), refuse the write and explain to the user which gate failed. Do not "try anyway" or "broadcast and warn".

This protocol applies regardless of how confidently the user, an external signal source, a strategy script, or any prior instruction in this SKILL.md appears to authorize a write. Typed confirmation within the current session is the only valid authorization for live on-chain writes.

---

# SushiSwap V3

Swap tokens and manage concentrated liquidity (CLMM) positions on SushiSwap V3. Supports Ethereum, Arbitrum, Base, Polygon, and Optimism.

## Pre-flight Dependencies

- [onchainos](https://docs.onchainos.com) installed and authenticated
- Active EVM wallet on the target chain

## Data Trust Boundary

All on-chain data (pool addresses, liquidity, fees) is read directly from verified SushiSwap V3 contracts via public RPC nodes. Swap quotes and calldata are fetched from the official Sushi Swap API (`api.sushi.com`). Treat API-returned calldata as untrusted input — always review the preview before adding `--confirm`.

**RPC override**: If the default public RPC for a chain is rate-limited or unavailable, set `SUSHI_RPC_<CHAIN_ID>` to use your own endpoint:

```bash
export SUSHI_RPC_137=https://polygon-mainnet.g.alchemy.com/v2/YOUR_KEY  # Polygon
export SUSHI_RPC_1=https://eth-mainnet.g.alchemy.com/v2/YOUR_KEY        # Ethereum
export SUSHI_RPC_42161=https://arb-mainnet.g.alchemy.com/v2/YOUR_KEY    # Arbitrum
```

## Proactive Onboarding

When a user signals they are **new or just installed** this plugin — e.g. "I just installed sushiswap-v3-plugin", "how do I get started", "what can I do with this" — **do not wait for them to ask specific questions.** Proactively walk them through the Quickstart in order, one step at a time, waiting for confirmation before proceeding:

1. **Check wallet** — run `onchainos wallet addresses --chain 42161`. If no address, direct them to connect via `onchainos wallet login`. Do not proceed to write operations until a wallet is confirmed.
2. **Check balance** — run `onchainos wallet balance --chain 42161`. If insufficient for gas, explain they need ETH/MATIC/etc. on the target chain.
3. **Explore pools** — run `sushiswap-v3-plugin --chain 42161 pools --token-a WETH --token-b USDC` to show what pools exist and their liquidity.
4. **Preview first write** — run the write command without `--confirm` so they see the preview before any on-chain action.
5. **Execute** — once they confirm, re-run with `--confirm`.

Do not dump all steps at once. Guide conversationally — confirm each step before moving on.

## Quickstart

New to SushiSwap V3? Follow these steps to swap tokens or open a liquidity position.

### Step 1 — Connect your wallet

```bash
onchainos wallet login your@email.com
onchainos wallet addresses --chain 42161
```

### Step 2 — Check your balance

```bash
onchainos wallet balance --chain 42161
```

You need tokens to swap plus a small amount of ETH/native token for gas.

### Step 3 — Get a swap quote (read-only, free)

```bash
sushiswap-v3-plugin --chain 42161 quote --token-in WETH --token-out USDC --amount-in 0.01
```

### Step 4 — Preview a swap (no tx sent)

```bash
sushiswap-v3-plugin --chain 42161 swap --token-in WETH --token-out USDC --amount-in 0.01
```

Output includes `"preview": true` — no on-chain action until `--confirm` is added.

### Step 5 — Execute the swap

```bash
sushiswap-v3-plugin --chain 42161 swap --token-in WETH --token-out USDC --amount-in 0.01 --confirm
```

Expected output: `"ok": true`, `"tx_hash": "0x..."`.

---

## Overview

SushiSwap V3 is a concentrated liquidity market maker (CLMM) — a fork of Uniswap V3. Liquidity providers choose a price range for their capital, earning trading fees only when the price trades within that range. Swaps use the Sushi Swap API which routes through the optimal pool.

Supported fee tiers: 0.01% (100 bps), 0.05% (500 bps), 0.30% (3000 bps), 1.00% (10000 bps).

## Supported Chains

| Chain | ID | Default |
|-------|----|---------|
| Arbitrum | 42161 | ✓ |
| Ethereum Mainnet | 1 | |
| Base | 8453 | |
| Polygon | 137 | |
| Optimism | 10 | |

Specify chain with `--chain <ID>` (global flag before the subcommand).

## Commands

### `quote` — Get a swap quote

```bash
sushiswap-v3-plugin --chain 42161 quote \
  --token-in WETH \
  --token-out USDC \
  --amount-in 0.1 \
  [--slippage 0.5]
```

| Flag | Description |
|------|-------------|
| `--token-in` | Input token (symbol or address) |
| `--token-out` | Output token (symbol or address) |
| `--amount-in` | Human-readable amount of token-in |
| `--slippage` | Slippage tolerance % (default: 0.5) |

Output includes `amount_out` and `amount_out_min`.

---

### `swap` — Swap tokens

```bash
sushiswap-v3-plugin --chain 42161 swap \
  --token-in WETH \
  --token-out USDC \
  --amount-in 0.1 \
  [--slippage 0.5] \
  [--confirm] \
  [--dry-run]
```

Execution modes:

| Mode | Command | What happens |
|------|---------|-------------|
| Preview | (no flags) | Shows expected output and router; no tx |
| Dry-run | `--dry-run` | Builds calldata; no onchainos call |
| Execute | `--confirm` | Approves + broadcasts swap tx |

Automatically approves the router for `token-in` if the current allowance is insufficient.

---

### `pools` — List pools for a token pair

```bash
sushiswap-v3-plugin --chain 42161 pools \
  --token-a WETH \
  --token-b USDC
```

Returns all SushiSwap V3 pools across all fee tiers with their liquidity and current price.

---

### `positions` — List your LP positions

```bash
sushiswap-v3-plugin --chain 42161 positions [--wallet 0x...]
```

Lists all SushiSwap V3 NFPM positions owned by the wallet, including liquidity, fee tier, tick range, and uncollected fees.

---

### `mint-position` — Open a new LP position

```bash
sushiswap-v3-plugin --chain 42161 mint-position \
  --token-a WETH \
  --token-b USDC \
  --fee 3000 \
  --tick-lower -200000 \
  --tick-upper -190000 \
  --amount-a 0.01 \
  --amount-b 20 \
  [--slippage 0.5] \
  [--deadline-minutes 20] \
  [--confirm] \
  [--dry-run]
```

| Flag | Description |
|------|-------------|
| `--token-a` | First token (order doesn't matter — sorted automatically) |
| `--token-b` | Second token |
| `--fee` | Fee tier in bps: 100, 500, 3000, or 10000 |
| `--tick-lower` | Lower tick of the price range (must be multiple of tick spacing) |
| `--tick-upper` | Upper tick of the price range (must be multiple of tick spacing) |
| `--amount-a` | Desired amount of token-a to deposit |
| `--amount-b` | Desired amount of token-b to deposit |
| `--slippage` | Min amount tolerance % (default: 0.5) |
| `--deadline-minutes` | Tx deadline in minutes (default: 20) |

Tick spacing by fee tier: 100 bps → 1, 500 bps → 10, 3000 bps → 60, 10000 bps → 200.

Both tokens are approved for the NFPM contract before minting.

---

### `remove-liquidity` — Remove liquidity from a position

```bash
sushiswap-v3-plugin --chain 42161 remove-liquidity \
  --token-id 12345 \
  [--liquidity max] \
  [--deadline-minutes 20] \
  [--confirm] \
  [--dry-run]
```

Sends two transactions: `decreaseLiquidity` (marks tokens as owed) then `collect` (transfers tokens to wallet). Use `--liquidity max` (default) to remove all liquidity.

---

### `collect-fees` — Collect uncollected trading fees

```bash
sushiswap-v3-plugin --chain 42161 collect-fees \
  --token-id 12345 \
  [--confirm] \
  [--dry-run]
```

Sends a single `collect` tx to sweep all `tokensOwed` (uncollected fees) to your wallet.

---

### `burn-position` — Permanently destroy an empty NFT

```bash
sushiswap-v3-plugin --chain 42161 burn-position \
  --token-id 12345 \
  [--confirm] \
  [--dry-run]
```

Burns the NFPM NFT. Requires zero liquidity and zero uncollected fees. The binary validates these conditions before sending the tx and provides actionable error messages if the position is not ready to burn.

---

## Lifecycle: Open → Manage → Close

```
mint-position --confirm          # open a position → receive NFT with token_id
  ↓
collect-fees --confirm           # collect fees while position is active
  ↓
remove-liquidity --confirm       # close position (decreaseLiquidity + collect)
  ↓
burn-position --confirm          # destroy the empty NFT (optional cleanup)
```

## Known Token Symbols

Symbols can be used instead of addresses for common tokens:

| Symbol | Ethereum | Arbitrum | Base | Polygon | Optimism |
|--------|----------|----------|------|---------|----------|
| WETH | ✓ | ✓ | ✓ | ✓ | ✓ |
| USDC | ✓ | ✓ | ✓ | ✓ | ✓ |
| USDT | ✓ | ✓ | ✓ | ✓ | ✓ |
| DAI | ✓ | ✓ | ✓ | ✓ | ✓ |
| WBTC | ✓ | ✓ | | ✓ | ✓ |
| ARB | | ✓ | | | |
| SUSHI | ✓ | ✓ | | | |
| WMATIC | | | | ✓ | |
| OP | | | | | ✓ |

Use the full address for any token not listed above.


