From cross-crossd
This skill should be used when the user asks to bridge tokens between BSC (56) and CROSS Chain (612055) via the CrossDefi backend (`bridge-api.crosstoken.io`). Any pair listed in `/bridge/pairs` is executable; the CROSSD product also publishes a canonical 8-pair UX surface (§1.1) that is surfaced as informational metadata (`canonical`, `canonicalKind`) but does NOT gate execution. Lists pairs, quotes with full fee + native-gas breakdown, polls bridge status, reads history, and **executes** the bridge with an accurate per-tx native-gas guard. Triggers on phrases like "BSC에서 CROSS로 브릿지", "CROSS 체인 브릿지", "USDT BSC→USDT CROSS", "USDT BSC→CROSSD", "CROSSD를 CROSS로 스왑", "crossdefi bridge", "list crossd pairs", "check bridge status", "permit-hash status", "execute bridge", "send bridge tx".
How this skill is triggered — by the user, by Claude, or both
Slash command
/cross-crossd:cross-crossdThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
A distributable skill that lets Claude drive the **CrossDefi swap-bridge** backend across **BSC (chain id 56)** and **CROSS Chain (612055)** — the same backend that powers `https://www.crossdefi.io/swap-bridge`. Execution path is **EOA + viem + raw HTTPS** — no browser automation, no ERC-4337.
package-lock.jsonpackage.jsonreferences/cross-crossd.mdscripts/_abi.mjsscripts/_api.mjsscripts/_bridge-router-abi.jsonscripts/_chain.mjsscripts/_guard.mjsscripts/_signer.mjsscripts/_supported_pairs.mjsscripts/bridge.mjsscripts/history.mjsscripts/pairs.mjsscripts/quote.mjsscripts/status.mjsscripts/tokens.mjsA distributable skill that lets Claude drive the CrossDefi swap-bridge backend across BSC (chain id 56) and CROSS Chain (612055) — the same backend that powers https://www.crossdefi.io/swap-bridge. Execution path is EOA + viem + raw HTTPS — no browser automation, no ERC-4337.
Scope (v0.3.0): Both read-path (
pairs,tokens,quote,status,history) and write-path (bridge) ship. The authoritative gate is/bridge/pairs(the live CrossDefi backend); any pair listed there is executable. The CROSSD product also publishes a canonical 8-pair UX surface (§1.1) which is surfaced as informational metadata so callers can label requests, but it is NOT a hard gate.
bridge.mjsauto-picks one of three on-chain sub-paths per the live frontend:
- native — from-token is the chain's native asset. Encodes
bridgeToken(...)calldata, sends the tx withmsg.value = value + gasFee + exFee. Returns the on-chain tx hash.- permit — from-token supports EIP-2612 (
nonces(address)view succeeds). Signs EIP-712 typed data offline, POSTs to/bridge/permit. The backend submits the on-chainpermitBridgeToken(...); the user pays no source-chain gas. Returns thepermitId.- approve — non-permit ERC-20. Approves the bridge router (exact amount by default;
--max-approvefor unlimited), then sendsbridgeToken(...)withmsg.value = 0. Returns both tx hashes.Sub-path override:
--path=native|permit|approve.Authoritative native-gas guard — before any signing, the skill builds the full source-chain tx plan, runs
eth_estimateGasfor each entry, multiplies byeth_gasPricewith a 1.2× headroom, adds anymsg.value, and refuses withinsufficient_gasif the wallet's native balance can't cover the total. The error envelope surfaces a per-tx breakdown (gasShortage.perTx) so the user sees exactly how much they need (e.g. "BNB short 0.0000388").Deeper protocol details (chain map, endpoint table, native sentinel
0x…0001, derivation provenance) live inreferences/cross-crossd.md.
The crossdefi.io product surfaces exactly these 8 directed pairs in its UI. Each request through quote.mjs / bridge.mjs is annotated with canonical and canonicalKind when it matches one of these rows. This is informational only — non-canonical pairs that exist in /bridge/pairs (e.g. USDT(BSC) → USDT(CROSS Chain)) are fully executable.
| # | FROM | → | TO | canonicalKind | In /bridge/pairs |
|---|---|---|---|---|---|
| 1 | 612055-0x…0001 CROSS (CROSS Chain native) | → | 56-0x6bf6…a510 CROSS (BSC BEP20) | bridge | ✅ |
| 2 | 612055-0x…0001 CROSS (CROSS Chain native) | → | 612055-0xff42…d452 CROSSD (CROSS Chain) | swap | ❌ (same-chain) |
| 3 | 56-0x6bf6…a510 CROSS (BSC BEP20) | → | 612055-0x…0001 CROSS (CROSS Chain native) | bridge | ✅ |
| 4 | 612055-0xff42…d452 CROSSD (CROSS Chain) | → | 612055-0x…0001 CROSS (CROSS Chain native) | swap | ❌ (same-chain) |
| 5 | 612055-0xff42…d452 CROSSD (CROSS Chain) | → | 56-0x55d3…7955 USDT (BSC) | swap-bridge | ❌ (multi-step) |
| 6 | 56-0x55d3…7955 USDT (BSC) | → | 612055-0xff42…d452 CROSSD (CROSS Chain) | swap-bridge | ❌ (multi-step) |
| 7 | 612055-0x1c37…a85c USDT (CROSS Chain) | → | 612055-0xff42…d452 CROSSD (CROSS Chain) | swap | ❌ (same-chain) |
| 8 | 612055-0x1c37…a85c USDT (CROSS Chain) | → | 56-0x55d3…7955 USDT (BSC) | bridge | ✅ |
In /bridge/pairs but not in the canonical 8 (still executable; the skill will sign):
| FROM | → | TO | notes |
|---|---|---|---|
56-0x55d3…7955 USDT (BSC) | → | 612055-0x1c37…a85c USDT (CROSS Chain) | direct USDT cross-chain bridge — no swap leg |
612055-0x1c37…a85c USDT (CROSS Chain) | → | 56-0x55d3…7955 USDT (BSC) | (same as canonical #8; symmetric direction is also listed in /bridge/pairs) |
Run node scripts/pairs.mjs to see the canonical list alongside the live /bridge/pairs catalog.
Activate when the user wants to:
56-0x6bf6…a510 mean?"valueWei, gasFeeWei, exFeeWei, totalPayableWei, minimumValueWei, belowMinimum flag, and in-chain swap-pool routing/bridge/permit-hash/{id} (single-shot or with --watch <sec>) — flips from "pending" to a terminal statusPOST /bridge/historypermitId (permit path)Trigger phrases (Korean + English, ≥ 6 each):
"BSC에서 CROSS로 브릿지" / "BSC CROSS를 CROSS 체인으로 보내줘""CROSS 체인 → BSC로 보내" / "USDT BSC → CROSSD""USDT를 CROSSD로 바꿔줘" / "CROSSD를 CROSS로 스왑""CROSSD 견적" / "crossdefi 견적""내 브릿지 진행상황" / "브릿지 상태 확인""브릿지 페어 목록" / "CROSSD 지원 자산 목록""bridge BSC CROSS to CROSS Chain" / "bridge from BSC to CROSS""USDT BSC to CROSSD" / "swap CROSSD into CROSS""crossdefi swap" / "crossdefi bridge""list crossd supported pairs" / "show crossd pair catalog""check bridge status" / "bridge status <permitId>""permit-hash status" / "poll permit hash"If the user pastes a crossdefi.io/swap-bridge?from=…&to=… URL, extract the from and to fragments (they are already in chainId-tokenAddress form) and route them verbatim to quote.mjs / bridge.mjs.
If they ask to execute ("send the bridge tx", "USDT BSC를 USDT CROSS로 보내줘"):
node scripts/quote.mjs <FROM> <TO> <AMOUNT> first.executable:
true — surface fees.totalPayableHuman + etaSeconds (and canonical/canonicalKind if the pair matches the documented UX), ask the user to confirm, then run node scripts/bridge.mjs <FROM> <TO> <AMOUNT> --confirm. The sub-path (native / permit / approve) is auto-detected; pass --path=… only if the user asks to override.false with canonicalKind: "swap" or "swap-bridge" — surface the quote envelope's note field. The route is in CrossDefi's UX but isn't a single /bridge/pairs entry (same-chain swap or multi-step). bridge.mjs will refuse with unsupported_pair. Tell the user the route needs the swap-router workstream (not yet shipped) and stop./bridge/pairs at all (e.g. a Kaia route, an unknown token), the skill emits unsupported_pair. Suggest node scripts/pairs.mjs so the user can see the live catalog + the canonical 8.Run these checks in order. Stop and report to the user at the first failure.
node --version # require >= 20
Then ensure the script's deps are installed (one-time):
SKILL_DIR="$HOME/.claude/skills/cross-crossd"
[ -d "$SKILL_DIR/node_modules" ] || (cd "$SKILL_DIR" && npm install --silent)
Read-path commands (pairs, tokens, quote, status) work without signer configuration. Only history and bridge need local signer configuration.
Resolve the EOA in this order. Never echo wallet secrets back to the user, never write them into the conversation transcript, never log them, and never ask the user to paste them into chat.
process.env.PRIVATE_KEY — inherited by the spawned process, not typed into the chat transcript or shell argv.
./.env in the user's current working directory — read PRIVATE_KEY and (optionally) WALLET_ADDRESS, BSC_RPC_URL, CROSS_RPC_URL, MAX_BRIDGE_NOTIONAL, CONFIRM_THRESHOLD.
$HOME/.claude/skills/cross-crossd/.env — same vars, used as the personal default.
Missing signer config — if all three sources lack PRIVATE_KEY and the requested subcommand needs it, stop. Tell the user to create ~/.claude/skills/cross-crossd/.env locally with:
PRIVATE_KEY=<0x-prefixed-64-hex-secret>
MAX_BRIDGE_NOTIONAL=10
CONFIRM_THRESHOLD=1
Then ask them to re-run the request. Do not collect the secret in chat, and do not pass it on the command line.
For personal testing, the default env backend reads the key from local
environment variables or a gitignored .env file. For team, hosted-agent, or
production funds, prefer Vault Transit, KMS, or HSM-backed signing so the raw
key is not exported to the agent runtime.
Validation: the value must match ^0x[0-9a-fA-F]{64}$. Reject otherwise without retrying silently. Read-path subcommands NEVER prompt for a PK.
Read-path scripts cannot lose funds. The rails below are enforced verbatim by bridge.mjs (via _guard.mjs) for every write path:
eth_chainId equals the <FROM> chain id encoded in the URL fragment.MAX_BRIDGE_NOTIONAL cap — env var; if set, abort if the token-unit amount exceeds it.CONFIRM_THRESHOLD + --confirm gate — any bridge above this notional aborts with {ok:false, error:"awaiting_confirm", parsedIntent} exit 2 unless --confirm is passed. Default 1 token unit./bridge/pairs aborts with unsupported_pair BEFORE any signing. (The 8-pair canonical list in §1.1 is informational only — it does not gate.)valueWei < cfg.minimumValue (from /bridge/token-config) aborts with below_minimum.enforceNativeGasForTxs) — after path detection, the skill builds the full source-chain tx plan, runs eth_estimateGas for each entry, computes Σ(estimatedGas × gasPrice) × 1.2 + Σ(msg.value), and aborts with insufficient_gas if the wallet's native balance can't cover the total. The envelope surfaces a per-tx breakdown (gasShortage.perTx) including labels (approve, bridgeToken), estimated gas per tx, and the exact shortfall in human units (e.g. "BNB short 0.0000388"). For the permit path there are zero source-chain txs and this guard is a no-op.approve path) — defaults to exact-amount approval; opt-in --max-approve flag for unlimited.WALLET_ADDRESS mismatch warning — non-null signerWarn field when env-declared address ≠ PK-derived address. Surface to user before continuing.All subcommands run via Bash and emit a single JSON object on stdout (no decorative prose). Parse the envelope and report key fields back. Stderr stays empty unless DEBUG=1.
cd "$HOME/.claude/skills/cross-crossd"
node scripts/<subcommand>.mjs [args]
<FROM> and <TO> use the same chainId-tokenAddress syntax as the website URL. Only the five tokens below appear in the whitelist (§1.1):
612055-0x0000000000000000000000000000000000000001 — CROSS (CROSS Chain native) (sentinel address)56-0x6bf62ca91e397b5a7d1d6bce97d9092065d7a510 — CROSS (BSC BEP20)612055-0xff42c13d927a6b9265236619161accb227b6d452 — CROSSD (CROSS Chain)56-0x55d398326f99059ff775485246999027b3197955 — USDT (BSC)612055-0x1c37d4f44ed3ec86d96868001cfa89e97112a85c — USDT (CROSS Chain)| User says (KR / EN) | Subcommand | Canonical row |
|---|---|---|
| "CROSSD 지원 자산 목록" / "list crossd pairs" | node scripts/pairs.mjs | — |
| "BSC 토큰 보여줘" / "list BSC bridge tokens" | node scripts/tokens.mjs --chain 56 | — |
| "CROSS 체인 토큰" / "tokens on CROSS chain" | node scripts/tokens.mjs --chain 612055 | — |
| "내 진행상황 12345" / "permit-hash status 12345" | node scripts/status.mjs 12345 | — |
| "트랜잭션 0x… 추적" / "track tx 0x…" | node scripts/status.mjs --tx 0x… | — |
| "내 history" / "show bridge history" | node scripts/history.mjs (PK from .env) | — |
| "CROSS native 5개 BSC로 보내" / "bridge 5 native CROSS to BSC" | node scripts/bridge.mjs 612055-0x0000…0001 56-0x6bf6…a510 5 --confirm | #1 bridge (native) |
| "BSC CROSS 5개 CROSS 체인으로" / "bridge 5 BSC-CROSS to CROSS Chain" | node scripts/bridge.mjs 56-0x6bf6…a510 612055-0x0000…0001 5 --confirm | #3 bridge (permit) |
| "USDT CROSS 10개 BSC로" / "bridge 10 USDT from CROSS to BSC" | node scripts/bridge.mjs 612055-0x1c37…a85c 56-0x55d3…7955 10 --confirm | #8 bridge (approve) |
| "USDT BSC 5개 CROSS 체인으로" / "bridge 5 USDT from BSC to CROSS" | node scripts/bridge.mjs 56-0x55d3…7955 612055-0x1c37…a85c 5 --confirm | off-canonical (in /bridge/pairs) |
| "CROSS native → CROSSD 견적" / "quote CROSS to CROSSD" | node scripts/quote.mjs 612055-0x0000…0001 612055-0xff42…d452 5 (quote only — same-chain swap) | #2 swap |
| "CROSSD → CROSS 견적" / "quote CROSSD to CROSS" | node scripts/quote.mjs 612055-0xff42…d452 612055-0x0000…0001 5 (quote only) | #4 swap |
| "CROSSD → USDT BSC 견적" / "quote CROSSD to USDT BSC" | node scripts/quote.mjs 612055-0xff42…d452 56-0x55d3…7955 5 (quote only) | #5 swap-bridge |
| "USDT BSC → CROSSD 견적" / "quote USDT BSC to CROSSD" | node scripts/quote.mjs 56-0x55d3…7955 612055-0xff42…d452 5 (quote only) | #6 swap-bridge |
| "USDT CROSS → CROSSD 견적" / "quote USDT CROSS to CROSSD" | node scripts/quote.mjs 612055-0x1c37…a85c 612055-0xff42…d452 5 (quote only) | #7 swap |
pairs — emit the canonical 8-pair UX surface plus the raw /bridge/pairs catalog. The canonical list is informational; the catalog is the executable gate. Read-only, no PK needed.tokens --chain <id> — iterates the unique localToken set on <id> from /bridge/pairs and resolves metadata via wallet-server/v1/public/token/info. Read-only.quote <FROM> <TO> <AMOUNT> — canonical-route lookup + /bridge/pairs existence + /bridge/tx-time ETA + /bridge/token-config (query shape {from,to,token} returns minimumValue, gasFee, exFeeRate) + per-amount fee math + /bridge/swap-pools + token-info. Read-only. Emits canonical, canonicalKind, and executable. Pairs not in /bridge/pairs fail with unsupported_pair; canonical swap/swap-bridge rows succeed with executable: false and a note.status <permitId> [--watch <sec>] | --tx <hash> — /bridge/permit-hash/{id} (one-shot or polling, max 60 polls) OR /bridge/check-cached-tx-hashes for raw tx hashes.history [--owner <0x…>] [--page N] [--size N] [--sort desc] [--status <s>] — POST /bridge/history. Owner defaults to PK-derived address.bridge <FROM> <TO> <AMOUNT> [--confirm] [--max-approve] [--path=native|permit|approve] — signs any pair in /bridge/pairs. Builds the full source-chain tx plan, runs accurate per-tx gas estimation (enforceNativeGasForTxs), and refuses with insufficient_gas (with gasShortage breakdown) if the wallet's native balance can't cover the total. Auto-detects the sub-path (native / permit / approve). Pairs not in /bridge/pairs (including canonical swap/swap-bridge rows) fail with unsupported_pair.After every action, surface to the user:
parsedIntent fieldpairs: canonicalRoutesCount, the canonical 8 rows, and the live bridgeApiCatalog chain count + total pairstokens: count + first few {symbol, address, decimals} rowsquote: executable boolean, canonical/canonicalKind (if present), fees.totalPayableHuman + fees.belowMinimum, etaSeconds, any warnings, the note field if present (for executable: false canonical swap/swap-bridge rows).status: the literal status string and whether it's terminal.history: count + per-row {from, to, amount, status, txHash}.bridge: the mode (native/permit/approve), parsedIntent.path, parsedIntent.gasReport.estimatedGasCostHuman + balanceHuman (so the user sees gas cost vs balance), and the pollHint. For permit, surface the permitId; for native/approve, surface txHash/approveTxHash+bridgeTxHash and the explorerUrl(s).Never include the PK or full env contents in the report. If the envelope contains a non-null signerWarn, surface the mismatch to the user before declaring success.
For awaiting_confirm errors (exit code 2), summarize the parsed intent, ask the user explicitly for "yes / 진행", and only re-invoke with --confirm on confirmation.
For insufficient_gas, surface the gasShortage block in human units: balanceHuman, requiredHuman, shortHuman, plus nativeSymbol (e.g. "BNB"). Per-tx breakdown lives at gasShortage.perTx (labels: approve, bridgeToken). Tell the user exactly how much native gas they need to add.
For unsupported_pair, suggest running node scripts/pairs.mjs so the user can see the canonical 8-pair UX list AND the live /bridge/pairs catalog.
This skill folder is the unit of distribution. Recipients:
cross-crossd/ folder into ~/.claude/skills/cd ~/.claude/skills/cross-crossd && npm install once (or let the skill do it on first use)history / bridge) create ~/.claude/skills/cross-crossd/.env from .env.example, or let the skill prompt them on first runCross-link: deeper details (chain registry, endpoint table, native sentinel handling, derivation provenance) live in references/cross-crossd.md. Lazy-load it only when an endpoint returns an unfamiliar shape.
Creates, edits, and optimizes skills for Claude Code, including drafting, evaluating with test prompts, iterating on performance, and improving skill descriptions for better triggering accuracy.
npx claudepluginhub to-nexus/cross-skills-suite --plugin cross-crossd