From rozo-intents
Send cross-chain crypto payments via Rozo API. Handles USDC and USDT payouts across EVM chains (Ethereum, Arbitrum, Base, BSC, Polygon), Solana, and Stellar. Use when user says "pay", "send", "transfer", "payout" with crypto amounts, chain names, or wallet addresses. Also handles QR code screenshots containing payment URIs (EIP-681, Solana Pay, Stellar URI). Auto-detects wallet type, auto-selects token (USDC preferred), confirms details before sending.
How this skill is triggered — by the user, by Claude, or both
Slash command
/rozo-intents:send-paymentThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
All `node scripts/dist/*.js` commands below MUST run from the **plugin root**
All node scripts/dist/*.js commands below MUST run from the plugin root
(the directory containing .claude-plugin/plugin.json), not from this
skill's directory. When installed as a Claude Code plugin, the plugin root
is ${CLAUDE_PLUGIN_ROOT}. If that env var isn't set, cd to the directory
that contains scripts/dist/, skills/, and .claude-plugin/.
Read version.json at the plugin root for the current thresholds:
freeConfirmThresholdUsd (default 1.0) — silent auto-execute cutoffsingleConfirmThresholdUsd (default 10.0) — narrated auto-execute cutoffBehavior matrix (the amount below is destAmount in USD):
| Amount | Confirmation | Agent narration | Dryrun fee check |
|---|---|---|---|
≤ freeConfirm | None — auto-execute | Silent — report only result | Skip (fee = 0) |
≤ singleConfirm | None — auto-execute | Narrate steps, no yes/no | Skip (fee = 0) |
> singleConfirm | One yes/no with full details | Full summary + prompt | Run --dryrun for exact fee |
Rozo charges no fee for transactions at or below singleConfirmThresholdUsd
(business rule). For amounts in that range you can skip the --dryrun step
entirely and go straight to create-payment.js without --dryrun.
Chain ambiguity is NOT a confirmation question. If the user gives an EVM address without specifying a chain, you MUST ask which chain regardless of amount. Wrong chain = lost funds. Only the yes/no confirmation is skipped for small amounts, never correctness checks (chain selection, trustline check, insufficient balance).
Process cross-chain crypto payments via the Rozo API. Follow steps sequentially.
The user may provide payment info as text OR as a QR code screenshot.
If the user shares a QR code image:
node scripts/dist/parse-qr.js "<qr_content>"
ethereum:...), Solana Pay (solana:...), Stellar URI (web+stellar:pay?...), and plain addressesIf the user provides text: Extract from the user's message:
Do NOT ask the user which token. The token is auto-selected based on balance (see Step 4).
Amount limits: Minimum $0.01, maximum $10,000 per transaction. If the amount is outside this range, inform the user and stop:
"Amount must be between $0.01 and $10,000."
Identify the destination chain from the address format:
| Address Pattern | Detected Chain | Action |
|---|---|---|
0x + 40 hex characters | EVM (ambiguous) | MUST ask which chain |
Base58 encoded, 32-44 chars, no 0x prefix | Solana (chain 900) | Auto-detect |
Starts with G, 56 characters, Base32 | Stellar G-wallet (chain 1500) | Auto-detect, check trustline |
Starts with C, 56 characters, Base32 | Stellar C-wallet (chain 1500) | Auto-detect, use contract payment flow |
CRITICAL rules:
EVM address detected but chain not specified — ALWAYS ask:
"Which chain should I send to? Supported EVM payout chains: Ethereum, Arbitrum, Base, BSC, Polygon"
Stellar G-wallet — check asset trustline before proceeding:
node scripts/dist/check-stellar-trustline.js --address <G_wallet_address>
node scripts/dist/check-stellar-trustline.js --address <G_wallet_address> --asset EURC
Default asset is USDC. Also supports EURC.
"This Stellar address does not have a [USDC/EURC] trustline. The recipient must add the trustline before they can receive funds."
Stellar C-wallet — use stellar_payin_contracts intent:
receiverAddressContract) and memo (receiverMemoContract)pay() function with the amount and memoThe user pays from their own wallet. They may have:
If the source wallet/chain is not clear, ask:
"Which wallet are you paying from? (e.g., Base wallet, Solana wallet, Stellar wallet)"
Consult references/supported-chains.md for the correct token addresses per chain.
Fetch all USDC and USDT balances for the user's wallet in a single call:
node scripts/dist/check-balance.js --address <wallet_address>
The API auto-detects the chain type from the address and returns all token balances across all supported chains.
Token selection priority:
Note: USDT payout is only supported on EVM chains (Ethereum, Arbitrum, Base, BSC, Polygon). If the destination is Solana or Stellar and USDC is insufficient, inform the user that only USDC payouts are supported for that chain.
After fetching, tell the user their balance:
"Your wallet has [X] USDC and [Y] USDT on [chain]. Using [token] for this payment."
Look at the thresholds from the "Confirmation Thresholds" section above.
If amount ≤ singleConfirmThresholdUsd (default $10):
amount ≤ freeConfirmThresholdUsd (default $1): stay silent, proceed straight to Step 6.freeConfirm < amount ≤ singleConfirm: narrate what you're doing ("Sending 5 USDC on Base to 0x…, no fee, creating payment now…") but do not ask yes/no. Proceed to Step 6.If amount > singleConfirmThresholdUsd:
Get the exact fee first via a dryrun:
node scripts/dist/create-payment.js \
--source-chain <chain_id_or_name> \
--source-token <USDC|USDT> \
--dest-chain <chain_id_or_name> \
--dest-address <address> \
--dest-token <USDC|USDT> \
--dest-amount <amount> \
--dryrun
Then present a full confirmation summary:
Your wallet has [balance] [token] on [source_chain].
Payment Summary:
- Sending: [amount] [token]
- To: [destination_address] ([chain_name])
- From: [source_wallet] ([source_chain])
- Fee: [fee] [token] ([feePercentage])
- Total deducted: [amount + fee] [token]
Confirm? (yes/no)
Only proceed to Step 6 if the user confirms. Default payment type is
exactOut — recipient gets the exact amount, fee added on top.
node scripts/dist/create-payment.js \
--source-chain <chain_id_or_name> \
--source-token <USDC|USDT> \
--dest-chain <chain_id_or_name> \
--dest-address <address> \
--dest-token <USDC|USDT> \
--dest-amount <amount> \
--dest-memo <memo_if_stellar_c_wallet>
--source-chain and --dest-chain accept either numeric chain IDs (8453,
1500, 900) or lowercase chain names (base, stellar, solana,
ethereum, arbitrum, bsc, polygon). Use whichever the user gave you.
After success, the API returns a receiverAddress and (for Stellar /
Solana) a receiverMemo. The memo is a routing detail — do not mention
it to the user unless they ask. The user should see a clean summary:
Creating payment... done.
Payment ID: <uuid>
Rozo usually confirms end-to-end within 10–15 seconds. Poll with:
node scripts/dist/get-payment.js --id <payment_id>
(You can also use --payment-id <uuid>, --tx-hash <hash>, or
--receiver-address <addr> --receiver-memo <memo> — see the
payment-status sub-skill.)
Do not use sleep between polls — some harnesses block it. Just re-run
the command immediately.
Watch for status to reach payment_payout_completed or payment_completed.
When it does, present a final summary with the destination txHash linked
to the appropriate block explorer (Basescan, Stellar Expert, Solscan, etc.).
For amounts ≤ singleConfirmThresholdUsd, keep the final report to one or
two lines:
✓ Sent 0.10 USDC to 0x5772…8897 on Base.
tx: https://basescan.org/tx/0x621a…75c3
User: "Pay 10 USDC on Base to 0x1234567890abcdef1234567890abcdef12345678"
User: "Send 50 to GC56BXCNEWL6JSGKHD3RJ5HJRNKFEJQ53D3YY3SMD6XK7YPDI75BQ7FD"
User: "Transfer 100 to 0xABCDEF1234567890ABCDEF1234567890ABCDEF12"
User: "Pay 25 USDC to CABCDEFGHIJKLMNOPQRSTUVWXYZ234567ABCDEFGHIJKLMNOPQRSTUV"
stellar_payin_contracts intentpay() with amount and memoUser shares QR image. Decoded: ethereum:0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913/transfer?address=0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed&uint256=1000000
0x5aAe..., 1.00 USDCUser shares QR image. Decoded: solana:9wFFmGphb7ys1gxkZUJ3pDQDkF1iVjU8D6S6A9VySbT9?amount=10.25&spl-token=EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v
User shares QR image. Decoded: web+stellar:pay?destination=GC56BX...&amount=100&asset_code=USDC
User shares QR containing: 0x742d35Cc6634C0532925a3b8D4C9db96C4b4d8b6
User says: "Send 50 to this address"
Cause: Duplicate orderId. Solution: Generate a new orderId and retry.
Cause: Not funded in time. Solution: Create a new payment.
Cause: Payout chain/address issue. Solution: Verify destination and retry.
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 rozoai/rozo-intents-skills --plugin rozo-intents