diff --git a/skills/zerion/SKILL.md b/skills/zerion/SKILL.md
index 273d2a5..1065ac5 100644
--- a/skills/zerion/SKILL.md
+++ b/skills/zerion/SKILL.md
@@ -1,6 +1,6 @@
---
name: zerion
-description: "Crypto wallet API + CLI for AI agents. Single entry point for wallet analysis (portfolio, positions, history, PnL), on-chain trading (swap, bridge, send), off-chain signing (EIP-191, EIP-712), wallet management (create/import/backup), agent tokens + policies for autonomous trading, and partner integrations (0x, Bankr, Li.Fi, Moonpay, Uniswap, Vaults.fyi, Trails, Umbra, Somnia, Monad, Sendai). Use this skill for any crypto wallet, DeFi, or on-chain task. Deep docs load on demand from `capabilities/` and `partners/`."
+description: "Crypto wallet API + CLI for AI agents. Single entry point for wallet analysis (portfolio, positions, history, PnL), on-chain trading (swap, bridge, send), off-chain signing (EIP-191, EIP-712), wallet management (create/import/backup), agent tokens + policies for autonomous trading, and partner integrations (0x, Bankr, Li.Fi, Moonpay, OpenOcean, Uniswap, Vaults.fyi, Trails, Umbra, Somnia, Monad, Sendai). Use this skill for any crypto wallet, DeFi, or on-chain task. Deep docs load on demand from `capabilities/` and `partners/`."
license: MIT
allowed-tools: Bash, Read
---
@@ -94,6 +94,7 @@ These cover specialized flows on top of the core CLI. User must **name the partn
| Moonpay (onramp) | Fiat → crypto onramp | `partners/moonpay-onramp.md` |
| Moonpay (Iron) | Iron stablecoin flows | `partners/moonpay-iron.md` |
| Moonpay (Predict) | Prediction market integration | `partners/moonpay-predict.md` |
+| OpenOcean Swap | Find the best swap routes across 40+ chains | `partners/openocean-swap.md` |
| Sendai ideas | Crypto idea discovery + validation, competitor mapping, DeFi TVL research | `partners/sendai-ideas.md` |
| Somnia (blockchain) | Somnia L1 ops | `partners/somnia-blockchain.md` |
| Somnia (reactivity) | Somnia reactive smart contracts | `partners/somnia-reactivity.md` |
diff --git a/skills/zerion/partners/openocean-swap.md b/skills/zerion/partners/openocean-swap.md
new file mode 100644
index 0000000..ab7b454
--- /dev/null
+++ b/skills/zerion/partners/openocean-swap.md
@@ -0,0 +1,308 @@
+# Zerion + OpenOcean Swap
+
+**Purpose:** Find the best swap quotes and build swap transactions across 40+ chains (EVM, Solana, Sui) using OpenOcean, then execute the swap and verify the updated portfolio and DeFi positions using Zerion CLI.
+
+## Setup
+
+### Helper Functions
+
+运行交易前,请在终端定义以下辅助函数,以便后续步骤调用:
+
+```bash
+# derive the RPC URL from the chain name
+get_rpc() {
+ case $1 in
+ base) echo "https://mainnet.base.org" ;;
+ ethereum|eth|mainnet) echo "https://eth.llamarpc.com" ;;
+ arbitrum|arb) echo "https://arb1.arbitrum.io/rpc" ;;
+ optimism|op) echo "https://mainnet.optimism.io" ;;
+ polygon|matic|poly) echo "https://polygon-rpc.com" ;;
+ avalanche|avax) echo "https://api.avax.network/ext/bc/C/rpc" ;;
+ bsc|binance-smart-chain) echo "https://bsc-dataseed.binance.org" ;;
+ gnosis|xdai) echo "https://rpc.gnosischain.com" ;;
+ scroll) echo "https://rpc.scroll.io" ;;
+ linea) echo "https://rpc.linea.build" ;;
+ zksync-era|zksync) echo "https://mainnet.era.zksync.io" ;;
+ zora) echo "https://rpc.zora.energy" ;;
+ blast) echo "https://rpc.blast.io" ;;
+ monad) echo "https://monad-testnet.blockpi.network/v1/rpc/public" ;;
+ *) echo "https://mainnet.base.org" ;;
+ esac
+}
+
+# Auto-approve helper (safely handles USDT-like zero-reset requirements)
+auto_approve() {
+ local token=$1 router=$2 amount_wei=$3
+ echo "checking allowance..."
+ local allowance=$(cast call --rpc-url $ETH_RPC_URL $token \
+ "allowance(address,address)(uint256)" $WALLET $router)
+ if [ "$allowance" -lt "$amount_wei" ]; then
+ if [ "$allowance" -gt 0 ]; then
+ echo "allowance non-zero but insufficient, resetting to 0 first (USDT protection)..."
+ cast send --rpc-url $ETH_RPC_URL \
+ --account "$CAST_ACCOUNT" --password "$CAST_PASSWORD" \
+ $token "approve(address,uint256)" $router 0
+ fi
+ echo "approving..."
+ cast send --rpc-url $ETH_RPC_URL \
+ --account "$CAST_ACCOUNT" --password "$CAST_PASSWORD" \
+ $token "approve(address,uint256)" $router $amount_wei
+ else
+ echo "allowance sufficient"
+ fi
+}
+```
+
+## When to use
+
+- "Swap [amount] [token] to [token] on [chain]" (e.g., "swap 0.1 ETH to USDC on Base")
+- "Swap X for Y" / "Convert X to Y" / "Trade X for Y"
+- "Find the best swap route for 0.1 ETH to USDC on Base"
+- "Swap native tokens using OpenOcean"
+- "Get quote and execute ERC20 swap on Arbitrum"
+- "Compare routes and execute a transaction using Foundry cast"
+
+## Key Commands
+
+**OpenOcean Skills (invoke in agent context):**
+- `/quote` — Get the best swap quote and route from OpenOcean Aggregator
+- `/swap-build` — Build the swap transaction calldata with slippage protection
+- `/swap-execute` — Broadcast the built transaction using Foundry `cast`
+
+**OpenOcean API (direct REST calls):**
+- `GET https://open-api.openocean.finance/v4/:chain/quote` — Discover best quote
+- `GET https://open-api.openocean.finance/v4/:chain/swap` — Get quote + calldata
+
+**Zerion CLI (shell):**
+- `zerion wallet list` — Find the agent's wallet address and details
+- `zerion positions
` — Pre-swap token balance checks and post-swap verification
+- `zerion portfolio ` — Verify overall portfolio changes after the swap
+
+## Requirements
+
+- OpenOcean AI skills: `npx skills add openocean-finance/OpenOcean-skills`
+- Zerion CLI: `npm install -g zerion-cli`
+- Zerion API key: `export ZERION_API_KEY="zk_..."`
+- For execution: [Foundry](https://getfoundry.sh/) (`cast`) installed and configured with your wallet credentials/RPC URL.
+- `jq`: `brew install jq` / `apt install jq` (used for parsing JSON outputs)
+
+## Wallet Setup
+
+> **Critical:** OpenOcean `/swap-execute` and Foundry `cast` require access to the transaction signer key, which is managed separately from Zerion CLI's local OWS keystore. For the flow to work end-to-end, both tools must reference the same wallet address and key.
+
+**Import your EVM key into Zerion CLI:**
+```bash
+zerion wallet import --name agent-bot --evm-key
+```
+
+**Import the same private key into Foundry `cast` (encrypted keystore — required by security hooks):**
+```bash
+cast wallet import agent-bot --interactive
+```
+Using the cast keystore keeps both layers encrypted. **Note: Direct use of `--private-key` is blocked by pre-tool security hooks. You must use Keystores.**
+
+**Agent Interactive Password Retrieval:**
+When running scripts, if the Keystore is password-protected, the Agent must:
+1. Call `AskUserQuestion("请输入 Keystore 'agent-bot' 的密码:")` to securely retrieve the password.
+2. Store the password in a temporary variable: `export CAST_PASSWORD="user_input"`
+3. Define the account name: `export CAST_ACCOUNT="agent-bot"`
+
+Set your signing wallet address variable:
+```bash
+export WALLET=
+```
+
+## Workflow
+
+### 1. Pre-flight Balance and Wallet Check
+Before performing a swap, use Zerion CLI to retrieve the default wallet address and confirm that the wallet has sufficient funds for both the swap amount and gas.
+
+```bash
+# 1. Get and export wallet address
+export WALLET=$(zerion wallet list --json | jq -r '.wallets[0].evmAddress')
+
+# 2. Set chain and derive RPC
+CHAIN="base"
+export ETH_RPC_URL=$(get_rpc $CHAIN)
+
+# 3. Check token balances and positions
+zerion positions $WALLET --chain $CHAIN
+```
+
+### 2. Discover the Best Quote (OpenOcean)
+Use either the OpenOcean `/quote` skill or the REST API to find the optimal execution route and expected output amount.
+
+> **⚠️ Pitfall:** The `gasPrice` parameter is **required** by the API — fetch it dynamically with `cast gas-price`. The `amount` parameter must be a **decimal string** (e.g. `"0.0001"`), NOT raw wei — passing wei units makes the API return garbled amounts.
+
+**Option A: Using OpenOcean Quote Skill**
+```
+/quote 1 ETH to USDC on base
+```
+
+**Option B: Using OpenOcean REST API**
+```bash
+CHAIN="base" # chain name
+IN="0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE" # native ETH
+OUT="0x833589fCD6eDb6E08f4c7C32D4f71b54bda02913" # USDC on Base
+AMOUNT="0.0001" # decimal, NOT wei
+
+ETH_RPC_URL=$(get_rpc $CHAIN)
+GAS_PRICE=$(cast gas-price --rpc-url $ETH_RPC_URL)
+
+curl -s "https://open-api.openocean.finance/v4/${CHAIN}/quote?inTokenAddress=${IN}&outTokenAddress=${OUT}&amount=${AMOUNT}&gasPrice=${GAS_PRICE}" | jq '.data | {inToken, outToken, outAmount, dexes}'
+```
+
+### 3. Build the Swap Transaction
+Use `/swap-build` or the REST API `/swap` endpoint to build the transaction payload. Note that the sender's wallet address must be specified in the `account` parameter to generate valid calldata.
+
+> **⚠️ Pitfall:** The `account` parameter is required. The response fields live under `data.to`, `data.data`, `data.value`, `data.estimatedGas`, `data.chainId` — always use the `.data` prefix.
+
+**Option A: Using OpenOcean Swap Build Skill**
+```
+/swap-build 1 ETH to USDC on base from slippage 100
+```
+
+**Option B: Using OpenOcean REST API**
+```bash
+SWAP=$(curl -s "https://open-api.openocean.finance/v4/${CHAIN}/swap?inTokenAddress=${IN}&outTokenAddress=${OUT}&amount=${AMOUNT}&gasPrice=${GAS_PRICE}&slippage=1&account=${WALLET}")
+
+TO=$(echo "$SWAP" | jq -r '.data.to')
+VALUE=$(echo "$SWAP" | jq -r '.data.value')
+DATA=$(echo "$SWAP" | jq -r '.data.data')
+GAS=$(echo "$SWAP" | jq -r '.data.estimatedGas | tonumber | . * 1.5 | floor')
+CHAIN_ID=$(echo "$SWAP" | jq -r '.data.chainId')
+```
+
+### 4. Execute the Swap
+
+> **Native ETH swaps skip approval** — only ERC-20 inputs trigger the approve step.
+>
+> **MANDATORY CONFIRMATION GATE:** Before broadcasting any transaction (approval or swap), the Agent MUST present a summary of the action (tokens, amounts, chain, estimated gas, recipient) and call `AskUserQuestion` to get explicit user approval.
+
+For ERC-20 token inputs, the OpenOcean Router must be approved to spend your tokens before the swap can succeed. The `auto_approve` helper (defined in the Setup section) checks allowance and sends an approve transaction if needed before broadcasting the swap.
+
+To get `$AMOUNT_WEI` from a decimal amount:
+```bash
+DECIMALS=$(cast call --rpc-url $ETH_RPC_URL $TOKEN "decimals()(uint8)")
+AMOUNT_WEI=$(echo "scale=0; $AMOUNT * 10^$DECIMALS / 1" | bc)
+```
+
+> **⚠️ Pitfall:** `cast send` uses `--gas-limit` (NOT `--gas`) to set the gas limit. Using `--gas` causes `unexpected argument '--gas' found`.
+
+**Option A: Using OpenOcean Swap Execute Skill**
+```
+/swap-execute
+```
+
+**Option B: Using Foundry `cast` directly (Keystore Account)**
+
+**Prerequisites Check**: Confirm `CAST_ACCOUNT` and `CAST_PASSWORD` are loaded. If not, ask the user.
+
+```bash
+# Auto-approve if input is ERC-20 (not native ETH)
+IN_TOKEN_ADDR="0x..." # the input token address
+if [ "$IN_TOKEN_ADDR" != "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE" ]; then
+ auto_approve $IN_TOKEN_ADDR $TO $AMOUNT_WEI
+fi
+
+# Convert hex value to decimal (cast --value requires decimal wei)
+VALUE_DEC=$(python3 -c "print(int('$VALUE', 16))" 2>/dev/null || echo "$VALUE")
+
+# Execute the swap
+cast send --rpc-url $ETH_RPC_URL \
+ --account "$CAST_ACCOUNT" \
+ --password "$CAST_PASSWORD" \
+ --value "$VALUE_DEC" \
+ --gas-limit $GAS \
+ --chain $CHAIN_ID \
+ $TO $DATA
+```
+
+> **⚠️ Plaintext Private Keys (Blocked)**: Direct use of `--private-key` is blocked by pre-tool security hooks (`.claude/hooks/validate-forge-cast.sh`) to prevent accidental private key leaks in command logs. You must use `--account` and `--password` instead.
+
+### 5. Post-Swap Verification (Zerion CLI)
+Once the transaction is broadcast, monitor the transaction status. After confirmation, verify the updated balances and positions using the Zerion CLI.
+
+```bash
+# Verify new positions and token balances
+zerion positions $WALLET --chain $CHAIN
+
+# Verify total portfolio value and PnL changes
+zerion portfolio $WALLET
+zerion pnl $WALLET
+```
+
+# === 6. End-to-End Example (Base, 0.0001 ETH → USDC)
+
+```bash
+# === 1. Setup ===
+CHAIN="base"
+export ETH_RPC_URL=$(get_rpc $CHAIN)
+export CAST_ACCOUNT="agent-bot"
+# Retrieve password interactively via AskUserQuestion and export:
+# export CAST_PASSWORD="user_password"
+
+# === 2. Get wallet address ===
+WALLET=$(zerion wallet list --json | jq -r '.wallets[0].evmAddress')
+zerion positions $WALLET --chain $CHAIN
+
+# === 3. Get quote (gasPrice fetched from RPC) ===
+IN="0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE"
+OUT="0x833589fCD6eDb6E08f4c7C32D4f71b54bda02913"
+AMOUNT="0.0001"
+GAS_PRICE=$(cast gas-price --rpc-url $ETH_RPC_URL)
+
+curl -s "https://open-api.openocean.finance/v4/${CHAIN}/quote?inTokenAddress=${IN}&outTokenAddress=${OUT}&amount=${AMOUNT}&gasPrice=${GAS_PRICE}" | jq '.data | {outAmount, dexes: [.dexes[].dexCode]}'
+
+# === 4. Build swap tx ===
+SWAP=$(curl -s "https://open-api.openocean.finance/v4/${CHAIN}/swap?inTokenAddress=${IN}&outTokenAddress=${OUT}&amount=${AMOUNT}&gasPrice=${GAS_PRICE}&slippage=1&account=${WALLET}")
+
+TO=$(echo "$SWAP" | jq -r '.data.to')
+VALUE=$(echo "$SWAP" | jq -r '.data.value')
+DATA=$(echo "$SWAP" | jq -r '.data.data')
+GAS=$(echo "$SWAP" | jq -r '.data.estimatedGas | tonumber | . * 1.5 | floor')
+CHAIN_ID=$(echo "$SWAP" | jq -r '.data.chainId')
+
+# === 5. Auto-approve + execute ===
+if [ "$IN" != "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE" ]; then
+ DECIMALS=$(cast call --rpc-url $ETH_RPC_URL $IN "decimals()(uint8)")
+ AMOUNT_WEI=$(echo "scale=0; $AMOUNT * 10^$DECIMALS / 1" | bc)
+ auto_approve $IN $TO $AMOUNT_WEI
+fi
+
+# Convert hex value to decimal
+VALUE_DEC=$(python3 -c "print(int('$VALUE', 16))" 2>/dev/null || echo "$VALUE")
+
+# Execute swap (Confirmation gate required before executing)
+cast send --rpc-url $ETH_RPC_URL \
+ --account "$CAST_ACCOUNT" \
+ --password "$CAST_PASSWORD" \
+ --value "$VALUE_DEC" \
+ --gas-limit $GAS \
+ --chain $CHAIN_ID \
+ $TO $DATA
+
+# === 6. Verify ===
+zerion positions $WALLET --chain $CHAIN
+```
+
+## Common Blockers
+
+| Issue | Cause | Fix |
+|---|---|---|
+| Keystore or Key Mismatch | The address used to build OpenOcean swap does not match cast signer key | Ensure the EVM address in `zerion wallet list` and your cast account point to the exact same private key. |
+| ERC-20 Swap Reverts | Insufficient spending allowance for OpenOcean Router | The auto-approve helper checks and approves the Router before execution. If it still reverts, the allowance may have been set too low — increase the approved amount. |
+| Approve tx fails | Token has special approve behavior (USDT requires reset to 0 first) | The optimized `auto_approve` helper resets to 0 automatically. If using other tools, manually approve 0 first: `cast send $TOKEN "approve(address,uint256)" $ROUTER 0`, then retry with the desired amount. |
+| Price Slippage Revert | Market price moved faster than the slippage limit (default 1%) | Increase the slippage percentage in the `/swap-build` request (e.g. `slippage 200` for 2%). |
+| Token Decimals Mismatch | Amount passed in raw units was computed with wrong decimals | Double check the decimals of the input token using the OpenOcean token list or the `/references/token-registry.md` before converting. |
+| API 400: `gasPrice` required | Missing `gasPrice` query parameter | Fetch gas price from RPC: `GAS_PRICE=$(cast gas-price --rpc-url $ETH_RPC_URL)`. |
+| Unknown chain RPC | Chain not in `get_rpc` mapping, or public RPC rate-limited | Set `ETH_RPC_URL` explicitly before running, or add the chain to the `get_rpc` function. |
+| Garbled amounts from API | `amount` passed in wei instead of decimal string | Pass amount as a human-readable decimal string (e.g. `"0.0001"`), NOT raw wei. |
+| `cast send` error: `unexpected argument '--gas' found` | `cast` uses `--gas-limit`, not `--gas` | Replace `--gas` with `--gas-limit`. |
+| `ETH_RPC_URL` not set | `get_rpc` not called before `cast` | Run `export ETH_RPC_URL=$(get_rpc $CHAIN)` first, or set it manually. |
+| Non-EVM Swap Execution | Trying to execute Solana/Sui swaps using EVM execution tools | Use chain-specific wallet clients (e.g., Solana web3.js/Sui SDK) instead of `cast` for non-EVM transaction signing and broadcasting. |
+
+## Related Skills
+
+- **capabilities/analyze.md** — Portfolio and positions tracking to check balances pre- and post-swap.
+- **capabilities/wallet.md** — Wallet management to retrieve default keys and addresses.