MMashDiv

Monero Blockchain

Private XMR custody for the Ecosystem addon — why Monero needs a long-running wallet RPC and a fully synced daemon of your own, how its one-wallet-file-per-user model differs from every other chain the platform custodies, and why every backend process takes turns on that one wallet RPC.

6 min readUpdated 1 October 2026monero, xmr, custody, wallet-rpc, monerod, session-lock

The Monero Blockchain addon adds XMR to Ecosystem's custody set: per-user deposit addresses, confirmation-aware deposit crediting, and signed withdrawals, all through your own Monero infrastructure.

That last clause is the whole story. Every other chain Ecosystem supports reads from somebody else's node — an RPC provider, an explorer API, a public cluster. Monero has no such thing, by design. There is no public API that will tell you which transactions belong to an address, because on Monero nobody can compute that without the wallet's view key. So the addon does not talk to a service. It talks to your monerod and your monero-wallet-rpc, both of which you install, run and keep alive yourself.

Budget for that before you buy. A synced Monero node is a permanent ~250 GB of SSD and two daemons that must be running whenever the platform is.

What it requires

Requirement Why If it is missing
Bicrypto core — v6.7.9 or later for Monero 6.2.1 Everything. The addon also loads shared helpers that only exist from that core release The extension cannot be enabled. On a core older than that, the addon's code does not load and the diagnostics report it as not installed — see Troubleshooting
Ecosystem addon — v6.5.3 or later for Monero 6.2.1 Wallets, deposits, withdrawals, markets — Monero is a chain inside Ecosystem, not a standalone product. From v6.5.3 its withdrawal queue also refuses, on its own, to refund a withdrawal whose relay was claimed Nothing to plug into
A licence for this product Product ID 54578959. Activation writes lic/54578959.lic The status toggle refuses with 403
monerod, fully synchronised Wallet sync (through the wallet RPC), fee estimation, confirmations, broadcasting Down: no deposit is detected; a new withdrawal is refused on the form before anything is debited ("Failed to withdraw: Failed to estimate Monero fee: …"); a withdrawal already queued fails and is refunded. Reachable by the wallet RPC but not by the backend: deposits keep crediting, and withdrawals fail as above. Still synchronising: deposits appear only as it catches up, and a withdrawal that reaches its relay ends in manual review
monero-wallet-rpc, started with --wallet-dir Wallet creation, balances, transfers — every operation Down: no deposit is detected, and new withdrawals are still accepted and debited — the request needs only the daemon — then each fails with "Wallet RPC is not responding. Please ensure monero-wallet-rpc is running on …" and is refunded. Down when the service starts in a process: the chain is also marked inactive there, and wallet creation, balance reads and history refuse until it answers
Redis — the platform's own The session lock every backend process takes before it touches the wallet RPC No wallet-rpc session starts: deposits are not checked and withdrawals wait
The Ecosystem vault, unlocked The wallet mnemonic is encrypted before it is stored Address generation fails

Note what is not in that list: ScyllaDB. Ecosystem needs it for order books and candles, so you will have it, but Monero deposits, balances and withdrawals do not touch it.

Monero is not like the other chains

Read this section before you read anything else. Almost every operational surprise on this chain traces back to one of these four facts.

There is one wallet file per user wallet. On EVM chains a single master wallet's HD material derives an unlimited number of addresses and one provider watches them all. Monero has no such derivation here. When a user first opens the XMR deposit page, the platform calls create_wallet on monero-wallet-rpc with the ECO wallet's UUID as the filename, re-opens the file to confirm what it read, and stores the resulting address and mnemonic. The master wallet is a wallet file too, named master_wallet. Your --wallet-dir therefore grows by one wallet file per customer who has ever looked at the XMR deposit page.

Subaddresses are not used. Every wallet operates on account_index: 0 and its primary address. There is no create_address call anywhere in the product. The address a user is shown is a standard mainnet address beginning with 4.

Every backend process takes turns on one wallet RPC. monero-wallet-rpc can have only one wallet open at a time, and it answers every wallet call from whichever wallet is open. The default deployment runs two backend processes that both use it — the web process (live deposit checks, new withdrawals as they are requested, admin balance reads) and the cron process (the background deposit scanner, the withdrawal watchdog with every retry and any withdrawal still waiting after three minutes, the dormant-wallet refresh). So each operation is one session — open, prove, work, close — under a cluster-wide Redis lock, and the sessions queue. On top of the lock, every session proves the wallet it is talking to: the address get_address returns must be exactly the one on record, before every read and every spend, and every incoming transfer must be paid to that wallet. A session that finds anything else refuses instead of crediting or sending. This is the single biggest difference in feel — Monero operations are measured in seconds to minutes, not milliseconds, and they queue. It also means two rules for you: restart the web and cron processes together, and never drive the live wallet RPC by hand. Deposits and confirmations has the details.

The daemon is your explorer. Confirmation counts, fee estimates and sync state all come from monerod, and so does every broadcast. A daemon that is down or still synchronising does not degrade the chain gracefully. Deposits silently stop arriving. A new withdrawal needs the daemon at the moment the customer submits it — the request prices itself with a fee estimate first — so with the daemon down the form refuses and nothing is debited. And a daemon that answers but reports synchronized: false refuses to broadcast, which leaves a withdrawal that got as far as its relay in manual review rather than failed — see Withdrawals.

XMR is the only asset

Monero has no token layer, so there is exactly one Ecosystem token row on this chain and its contractType is NATIVE. You create it through the token import flow with a blank contract, not the deploy flow — see Tokens and markets.

There are no custodial wallets on Monero either. Custodial contracts exist only for EVM tokens that cannot pay their own gas; XMR deposits always go to the user's own wallet address regardless of how the token row is flagged.

The token row's network label is checked against XMR_NETWORK (mainnet when unset), as on every other chain: a row labelled for another network, or not labelled at all, is not offered, and XMR disappears from the deposit currency list. Give the row the network XMR_NETWORK names — mainnet on mainnet — and spell it identically in both places, in lowercase: this comparison is exact, letter for letter and case for case. XMR_NETWORK="MAINNET" still validates withdrawals as mainnet, but it no longer matches a row labelled mainnet. The same mismatch can also happen through the daemon — see Configuring the RPC connection.

Three gates, checked in order

Activation is not a single switch. When the Monero service starts in a process, it evaluates:

  1. Licence. lic/54578959.lic must be a licence this server can read — it has to decode here, not merely exist. The file is read each time this gate runs.
  2. Database row. ecosystem_blockchain where productId = 54578959 must have status = true. It ships false.
  3. Wallet RPC reachability. A get_version call against XMR_WALLET_RPC_URL. If it throws, the chain is marked inactive, and wallet creation, balance reads and transaction history refuse with "Chain 'Monero' is not active."

While the chain is inactive, every use of the service runs the gates again, so operations resume once the fault is fixed.

The gates guard less than "inactive" suggests. Wallet creation, balance and history reads, background scans and pool-backing sends check them. Live deposit checks do not, and neither do withdrawals — not when the request is made, and not when the handler sends it.

Switching the chain off is not a stop button. The status toggle writes the ecosystem_blockchain row and nothing else. A process whose Monero service is already active never reads that row again until it restarts, and because no part of a withdrawal reads it, XMR withdrawals are accepted, debited and sent with the chain switched off, before a restart and after one. To refuse new withdrawal requests, disable the XMR token instead — see Withdrawals.

The daemon check is deliberately not a gate — an unreachable monerod logs a warning and the chain stays nominally active. That is a trap, not a kindness: the chain looks enabled while no deposit can be detected. Always confirm the daemon separately.

The backend does not point the wallet RPC at a daemon when it starts: that call, set_daemon, acts on whichever wallet happens to be open. Start monero-wallet-rpc with --daemon-address, and with --daemon-login when monerod requires an RPC login. When a session's refresh fails with a daemon error, the backend re-points that session's wallet at the daemon it last got an answer from itself — XMR_DAEMON_RPC_URL on a single-daemon install, or the entry of the XMR_<NETWORK>_RPC list that last answered — with the credentials from XMR_RPC_USER / XMR_RPC_PASSWORD, and retries once.

Where to go next

Install and enable

Build the node, write the systemd units, wait out the sync, activate the licence and create the master wallet.

Configuring the RPC connection

The environment variables, the session lock, HTTP Digest auth, the daemon the wallet RPC syncs against, the network match, and the two keys that are read by nothing.

Deposits and confirmations

How a wallet file becomes a credited balance, the one wallet RPC every process shares, the identity checks, the six-confirmation rule, and the monitor lifecycle.

Withdrawals

Where the network fee comes from, the 90-second wait for the wallet RPC, locked outputs, the pre-relay claim, and why an unknown relay outcome is never refunded.

Environment reference

Every key the runtime reads, its default, the lock timings, and what breaks without them.

Troubleshooting

Sync and daemon faults, the session lock, identity refusals, wallet-open failures, stuck deposits, deferred and held withdrawals.