Send, receive, and track Nano (XNO) transactions via xno-mcp tools or the xno-skills CLI, including address validation and QR generation.
Documents
agenta-monero
Try itUse when making or receiving Monero (XMR) payments. Generates addresses, sends payments, checks balances, verifies transactions, generates and verifies payment proofs, estimates fees, sweeps funds, and manages wallet operations via a self-hosted monero-wallet-rpc node. Keywords: monero, xmr, cryptocurrency, payments, wallet, send, receive, payment proof.
What it does
Use when making or receiving Monero (XMR) payments. Generates addresses, sends payments, checks balances, verifies transactions, generates and verifies payment proofs, estimates fees, sweeps funds, and manages wallet operations via a self-hosted monero-wallet-rpc node. Keywords: monero, xmr, cryptocurrency, payments, wallet, send, receive, payment proof.
The skill document
Agenta-Monero
Shell wrappers over monero-wallet-rpc for autonomous Monero (XMR) payments. All scripts emit JSON to stdout (success) or a structured error JSON to stderr; they compose into receive/send/verify/sweep workflows. Money math is integer piconeros internally; XMR decimal strings appear in output.
WARNING — IRREVERSIBLE FINANCIAL OPERATIONS
- Monero transactions are irreversible. Once broadcast, funds cannot be recovered.
send_xmr.shandsweep_all.shrequire--confirmto broadcast. Without it, they refuse to relay. Use--dry-runto preview without--confirm.sweep_all.shtransfers all unlocked funds from the wallet (or subaddress) to a single destination. A mistaken or maliciously triggered sweep can drain the entire balance.- Always validate the recipient address (
validate_address.sh) and confirm the amount before executing a send or sweep.- The
.envfile containsMONERO_WALLET_PASSWORDand RPC credentials. It is created withchmod 600, but on multi-user systems, shared CI, or agent workspaces with broad read access, an attacker who reads.envcan access the wallet and move funds. Secure the file and the system accordingly.
Use when: generating receive addresses, sending/sweeping XMR, checking balance, verifying an incoming payment or a payment proof, estimating fees, or reconciling transactions by hash.
Prerequisites
- Install Monero CLI tools (≥ 0.18.0): download from https://getmonero.org/downloads/ — you need at minimum
monero-wallet-rpc. Also create a wallet file:monero-wallet-cli --generate-new-wallet ~/Monero/wallets/main --password 'PASS'(write down the 25-word seed). - Bash ≥ 4,
curl,jq,flock(util-linux) — standard on Linux/macOS (brew install jqon macOS). - First-time setup: run
./scripts/interactive_setup.sh(interactive prompts) or tell the Hermes agent "Set up the Agenta-Monero skill" (agent-driven; see First-Time Setup below). Both paths generate RPC credentials, write.env, startmonero-wallet-rpc, and verify readiness. - After setup, every script runs from the skill root. Invoke
./setup.shagain after changing.env.
Permissions & Capabilities
This skill performs the following actions. Operators should review these before approving or invoking the skill in automated workflows:
| Capability | Details |
|---|---|
| Shell execution | Runs curl, jq, flock, monero-wallet-rpc, and standard shell utilities |
| File writes | .env (chmod 600), .netrc (chmod 600, ephemeral), PID/port files, lock files, refresh timestamp |
| Process management | Starts and stops monero-wallet-rpc as a background daemon (PID tracked in $MONERO_LOCK_DIR) |
| Network access | HTTP POST to $MONERO_RPC_URL/json_rpc (localhost by default; can be configured for remote) |
| Credential access | Reads .env for RPC user/password and wallet password; writes .netrc for curl auth; never emits credentials in stdout |
All credential files are created with restrictive permissions (0600 for files, 0700 for the lock directory). The .env file is parsed safely (never sourced) and shell metacharacters are rejected.
First-Time Setup
When a user asks to set up the Agenta-Monero skill, follow this workflow.
Path A — Agent-driven (recommended):
- Ask: "What's the path to your wallet file?"
- Ask: "What's the wallet password?"
- Ask: "Local daemon or remote node?"
- If remote: "What's the daemon address? (e.g. node.example.com:18081)"
- Check:
command -v monero-wallet-rpc— if missing, print install guidance (https://getmonero.org/downloads/) and stop. - Run:
./scripts/interactive_setup.sh --wallet-path "PATH" --wallet-password "PASS" --network mainnet --daemon-type local [--daemon-address "HOST:PORT" if remote] --force - Read the JSON output. If
ready:true→ done. Ifready:false→ checkwarningsand troubleshoot. - To check wallet-rpc status later:
./scripts/wallet_rpc_status.sh. To stop it:./scripts/stop_wallet_rpc.sh.
Path B — Manual interactive script:
Tell the user to run ./scripts/interactive_setup.sh and follow the prompts.
Both paths:
- Generate random RPC credentials (12-char user, 24-char password).
- Write
.env(chmod 600) with all values includingMONERO_WALLET_PASSWORD.- Caution:
.envpersists on disk and contains the wallet password. On multi-user systems or CI, ensure the file is not world-readable, not committed to version control, and not included in backups or log captures.
- Caution:
- Start
monero-wallet-rpcas a background process (PID stored in$MONERO_LOCK_DIR/wallet-rpc.pid). - Run
./setup.shand report readiness. - Credentials are not emitted in stdout JSON. They exist only in
.env(chmod 600). If the user needs to see them, read from.envdirectly.
Quick reference
One compact block per operation. Load references/rpc-reference.md when you need exact JSON-RPC params, full output field lists, or per-operation refresh classification.
create_address.sh --label "Payment from Alice" [--account 0] -> {address, address_index, account}
send_xmr.sh --address ADDR --amount "1.5" -> {tx_hash, fee, amount[, tx_key]}
[--priority 0] [--get-tx-key] [--dry-run] [--confirm]
[--dest '[{"address":"A","amount":"1.0"}]']
estimate_fee.sh --address ADDR --amount "1.5" [--priority 0] -> {fee, amount, priority, num_destinations}
sweep_all.sh --address ADDR [--account 0] [--subaddress N]-->{tx_hash, fee, amount}
[--priority 0] [--dry-run] [--confirm]
check_balance.sh [--account 0] -> {balance, unlocked_balance, blocks_to_unlock, time_to_unlock, account}
get_transfer.sh --tx-hash HASH -> {tx_hash, amount, fee, direction, confirmations, address, address_index, timestamp, confirmed, unlock_time}
verify_payment.sh --tx-hash HASH | --address ADDR --expected-amount "1.5" -> {verified, confirmations, tx_hash, address, address_index, confirmed, amount}
get_tx_proof.sh --tx-hash HASH --address ADDR -> {tx_hash, address, proof}
check_tx_proof.sh --tx-hash HASH --address ADDR --proof PROOF -> {verified, confirmations, amount, tx_hash, address}
list_incoming.sh [--confirmed-only|--all] [--since-block N] -> [{tx_hash, amount, confirmations, address, address_index, timestamp, confirmed, unlock_time}]
[--since-timestamp N] [--limit 100] [--account 0]
list_outgoing.sh [--since-block N] [--since-timestamp N] -> [{tx_hash, amount, fee, timestamp, address, address_index, unlock_time}]
[--limit 100] [--account 0]
list_addresses.sh [--account 0] -> [{index, address, label, balance, unlocked_balance}]
validate_address.sh --address ADDR -> {valid, network, network_match, subaddress, integrated}
sync_status.sh -> {height, daemon_connected, wallet_version}
Concrete output examples (stdout; success is one JSON object per line):
// create_address.sh
{"address":"88bc...","address_index":5,"account":0}
// send_xmr.sh --address ... --amount "1.5"
{"tx_hash":"7663438...","fee":"0.0000869","amount":"1.5"}
// estimate_fee.sh --address ... --amount "1.5"
{"fee":"0.0000869","amount":"1.5","priority":0,"num_destinations":1}
// sweep_all.sh --address DEST --dry-run
{"tx_hash":"","fee":"0.0000869","amount":"8.2"}
// check_balance.sh
{"balance":"10.5","unlocked_balance":"8.2","blocks_to_unlock":42,"time_to_unlock":30240,"account":0}
// get_transfer.sh --tx-hash ...
{"tx_hash":"c36258a...","amount":"1.5","fee":"0.0000435","direction":"in","confirmations":15,"address":"77Vx9cs...","address_index":3,"timestamp":1535918400,"confirmed":true,"unlock_time":0}
// verify_payment.sh --tx-hash ...
{"verified":true,"confirmations":12,"tx_hash":"c36258a...","address":"77Vx9cs...","address_index":3,"confirmed":true,"amount":"1.5"}
// get_tx_proof.sh --tx-hash ... --address ...
{"tx_hash":"c36258a...","address":"77Vx9cs...","proof":"ProofV1..."}
// check_tx_proof.sh --tx-hash ... --address ... --proof ...
{"verified":true,"confirmations":15,"amount":"1.5","tx_hash":"c36258a...","address":"77Vx9cs..."}
// validate_address.sh --address ...
{"valid":true,"network":"mainnet","network_match":true,"subaddress":false,"integrated":false}
// sync_status.sh
{"height":1523651,"daemon_connected":true,"wallet_version":196613}
// list_incoming.sh (array element)
{"tx_hash":"c36258a...","amount":"1.5","confirmations":15,"address":"77Vx9cs...","address_index":3,"timestamp":1535918400,"confirmed":true,"unlock_time":0}
Amounts in outputs are XMR decimal strings (e.g. "1.5"). --dry-run and estimate_fee preview without broadcasting.
Gotchas (verified facts — get these right)
- No
syncRPC. The wallet refreshes from the daemon viarefresh, which can take seconds-to-minutes. Refresh is operation-aware: balance/transfer/verify ops auto-refresh; address-management,validate_address,estimate_fee,get_tx_proof, andsync_statusdo not. Override with--no-refreshon any auto-refresh op (--no-refreshworks in any argument position). blocks_to_unlock/time_to_unlockare nativeget_balancefields. Read them directly — never derive them.check_balancesurfaces both. They are0when no funds are locked, ornullif the wallet omits them — treat0/nullas "nothing locked".- Priority values:
0=default, 1=unimportant, 2=normal, 3=elevated, 4=priority. The default is0(wallet decides). Do not default to1— that literally means "unimportant". Send/sweep/estimate accept--priority 0-4. - Single
/json_rpcendpoint. Every wallet method this skill uses — includingget_heightandget_version— is POSTed to$MONERO_RPC_URL/json_rpc. There is no root-path call anywhere. validate_addressuses real RPC fields. The RPC is called withany_net_type:trueso the realnettypeis returned;network_matchis derived client-side by comparingnettypetoMONERO_NETWORK. There is nochecksum_validfield (the checksum is part ofvalid). This keepsINVALID_ADDRESS(bad format/checksum) distinct fromNETWORK_MISMATCH(valid but wrong network).- Money is integer piconeros (1 XMR = 10^12). Never use floating-point for amounts. All arithmetic is integer piconero; the XMR decimal strings in output come from the scripts' string-based conversion. Amounts must be positive and have <=12 decimals.
- Sends and sweeps are not idempotent and are NOT auto-retried. On timeout/uncertain result, check
get_transfer.sh --tx-hashbefore retrying (see retry-safety workflow). Use--dry-run/estimate_feeto preview. - Credentials use netrc (never
curl -u);.envis parsed, never sourced. The netrc lives at$MONERO_LOCK_DIR/.netrc(mode0600). All user values are passed to the RPC viajq --arg/--argjson— never by string interpolation.
Workflows
Workflows are rendered as checklists. Money/identity paths (send, sweep, verify) are prescriptive: follow the order. Every destructive workflow ends with a verify-after-act step.
Receive a Payment
-
scripts/create_address.sh --label "Payment from Alice"— note the returnedaddress. - Share
addresswith the payer. -
scripts/check_balance.sh(orscripts/list_incoming.sh --since-block). -
scripts/verify_payment.sh --address "ADDR" --expected-amount "1.5"— wait untilverified:true. -
scripts/get_tx_proof.sh --tx-hash "HASH" --address "ADDR"— hand the payer theprooffor their records.
Send a Payment (plan -> validate -> execute)
Irreversible:
send_xmr.shrequires--confirmto broadcast. Use--dry-runto preview without--confirm. Always validate the address and confirm the amount before executing.
- Plan:
scripts/estimate_fee.sh --address "RECIPIENT" --amount "2.5"— previewfee. - Validate:
scripts/validate_address.sh --address "RECIPIENT"— confirmvalid:trueandnetwork_match:true. - Balance:
scripts/check_balance.sh— confirmunlocked_balance >= 2.5. - Preview (optional):
scripts/send_xmr.sh --address "RECIPIENT" --amount "2.5" --dry-run— confirm fee/amount without broadcasting. - Execute:
scripts/send_xmr.sh --address "RECIPIENT" --amount "2.5" --confirm— note thetx_hash. - Verify:
scripts/get_transfer.sh --tx-hash ""— confirm it was recorded (andconfirmedonce enough blocks pass).
Send a Payment — retry safety (DECISION GATE)
Sends are not idempotent. Never retry blindly on timeout. Run this gate first:
- Attempt:
scripts/send_xmr.sh --address "RECIPIENT" --amount "2.5" --confirm. - If it returns a
tx_hash(success) -> done; do NOT re-send. - If it times out / returns an uncertain result, whether you can use
get_transferdepends on having a hash:- You have a
tx_hash(from the send response, or a prior attempt you're unsure about) -> callscripts/get_transfer.sh --tx-hash ""and branch on the error code:TX_NOT_FOUND-> the transaction is genuinely absent from the wallet -> safe to retry the send.RPC_UNREACHABLE-> the wallet RPC / daemon could not be reached -> the transaction status is unknown, not absent -> do NOT retry the send; fix connectivity (sync_status.sh, restartmonero-wallet-rpc/monerod) and re-checkget_transferbefore doing anything else.- any success result -> the tx exists -> do NOT re-send.
- You have NO
tx_hash(pure transport failure /RPC_UNREACHABLEwith no payload) -> there is nothing to look up; status is unknown. Do NOT retry the send. Fix connectivity first, then reconcile withscripts/list_outgoing.sh(match by amount/timestamp) to detect any tx that may have been created before re-evaluating.
- You have a
Verify a Payment Proof
- Collect from the payer:
tx_hash,address, andproofstring. -
scripts/check_tx_proof.sh --tx-hash "HASH" --address "ADDR" --proof "PROOF". - Act on
verified:true=> proof is cryptographically valid (readamount,confirmations).false/PROOF_INVALID=> reject and ask the payer to re-issue.
Sweep Funds (plan -> validate -> execute)
Irreversible and high-impact:
sweep_all.shrequires--confirmto broadcast. Use--dry-runto preview without--confirm. A mistaken address can drain the entire wallet.
-
scripts/check_balance.sh— readunlocked_balance(the sweepable amount). -
scripts/validate_address.sh --address "DESTINATION"—valid:true+network_match:true. -
scripts/sweep_all.sh --address "DESTINATION" --dry-run— previewamount+feewithout sending. -
scripts/sweep_all.sh --address "DESTINATION" --confirm— execute; notetx_hash. - (Optional)
scripts/get_transfer.sh --tx-hash ""— confirm. Same retry-safety caveat as sends applies.
Check for Payments (with filtering)
-
scripts/sync_status.sh— confirmdaemon_connected:trueand thatheightis recent (else data may be stale).list_incomingauto-refreshes unlessMONERO_AUTO_REFRESH=falseor you pass--no-refresh; if auto-refresh is off and you need fresh data, re-enable it (there is no standalone refresh script). -
scripts/list_incoming.sh --since-block --limit 50— recent incoming transfers. - Read
confirmations/confirmedper row (threshold =MONERO_CONFIRMATIONS, default10). - To pin a specific payment:
scripts/verify_payment.sh --tx-hash "HASH"(or--address+--expected-amount).
Error codes
Every error is a JSON object on stderr plus a non-zero exit. It is compact (single-line) — but always parse it with jq, never line-by-line. The object has exactly error, code, and message (the suggestion key is reserved in the emitter but not currently populated; use the table below for recovery text):
{
"error": true,
"code": "TX_NOT_FOUND",
"message": "no transfer found for txid 7663438…"
}
Load references/error-runbook.md when a script returns an error code and you need detailed, per-code recovery steps.
| Code | Meaning | Retryable | One-line recovery |
|---|---|---|---|
CONFIG_MISSING | Required env var / arg not set | No | Run ./setup.sh; supply the missing --flag. |
CONFIG_INVALID | .env has bad syntax/metachars | No | Inspect .env; fix malformed lines; do not source it. |
CONFIRM_REQUIRED | --confirm not provided for destructive operation | No | Add --confirm to broadcast, or --dry-run to preview without broadcasting. |
RPC_UNREACHABLE | Cannot reach monero-wallet-rpc | Yes | Start/check monero-wallet-rpc; re-check. (Do NOT treat a send timeout with this code as "tx absent".) |
WALLET_NOT_LOADED | Wallet name != loaded wallet | No | open_wallet the right wallet; check MONERO_WALLET_NAME. |
WALLET_LOCKED | Wallet file locked elsewhere | No | Find/kill the holder (lsof | grep wallet.keys) or wait. |
DAEMON_DISCONNECTED | Wallet RPC can't reach daemon | Yes | Check/restart monerod. |
INSUFFICIENT_BALANCE | Not enough unlocked funds | No | check_balance.sh; wait for unlocks or reduce amount. |
AMOUNT_INVALID | Amount <=0 / >12 decimals / >balance | No | Correct the amount string. |
INVALID_ADDRESS | Bad format/checksum | No | Re-check the address; do not use. |
NETWORK_MISMATCH | Valid address, wrong network | No | Use an address for MONERO_NETWORK (mainnet/stagenet). |
INVALID_INPUT | Bad flag value (e.g. priority 0-4, tx-hash, label) | No | Correct the argument value. |
SYNC_FAILED / REFRESH_FAILED | Wallet sync/refresh failed | Yes | sync_status.sh; may need to restart wallet RPC. |
TX_RELAY_FAILED | Tx created but not broadcast | No | get_transfer.sh --tx-hash; may need manual relay. |
RATE_LIMITED | Lock acquisition timed out / daemon busy | Yes | Wait; reduce call frequency. |
TX_NOT_FOUND | Hash unknown to this wallet | No | Re-check the hash; for sends this means "safe to retry" (see retry-safety). |
PROOF_INVALID | Payment proof verification failed | No | Reject; ask payer to re-issue proof. |
Transient codes (RPC_UNREACHABLE, DAEMON_DISCONNECTED, SYNC_FAILED, REFRESH_FAILED, RATE_LIMITED) surface immediately — they are not auto-retried by the scripts. The retry helper (lib/retry.sh) exists and is unit-tested, but is not currently applied to any script RPC call (all scripts call rpc_call directly). send_xmr/sweep_all are intentionally never retried (non-idempotent). get_transfer and check_tx_proof are intentionally direct so they don't mask the retry-safety probe / proof classification. If a read-only op returns a transient code, the agent should retry it itself (never retry sends/sweeps — drive those via the decision gate above).
Refresh & concurrency
- Refresh: controlled by
MONERO_AUTO_REFRESH(defaulttrue) andMONERO_REFRESH_MIN_INTERVAL(default30s; a refresh is skipped if one happened within this window). Auto-refreshing ops accept--no-refreshto skip. The last-refresh timestamp lives in$MONERO_LOCK_DIR/.last_refresh. - Concurrency: every script takes an exclusive
flockon$MONERO_LOCK_DIR/agenta-monero.lock(timeoutMONERO_LOCK_TIMEOUT, default60s) before any RPC; lock contention surfaces asRATE_LIMITED. The lock is released on exit, coordinating multiple local agent processes against the wallet RPC's own serialization.
Load references/env-reference.md when you need the full environment-variable table (connection, network, refresh, retry, concurrency, TLS knobs) or the complete refresh-strategy / retry-backoff details.
Related skills
Query Bitcoin (BTC L1) blockchain data with USD pricing — wallet balances, address info, transaction details, UTXO analysis, fee estimation, mempool stats, and live network health. Uses Mempool.space REST API (https://mempool.space/docs/api/rest). No API key required.
Generate and manage Hierarchical Deterministic (HD) crypto wallets for 200+ cryptocurrencies (Bitcoin, Ethereum, and many more) using the Python `hdwallet` library, via either its CLI or its Python API.
Create a Shieldz crypto payment link or tip jar for a wallet the USER explicitly provides, and read payment status back. Use ONLY when the user directly asks...
Run a customer research inbox with sourced reports
Reference client for paying x402 (USDC/EVM) and L402 (Lightning) HTTP 402 paywalls. Detects payment requirements, signs/settles payments only with explicitly...