Exchange Engine 6.4.9
2 September 2026
This release has upgrade notes. Read them before updating — they describe behaviour changes that need your attention.
Ecosystem v6.4.9
Release Date: September 2, 2026 Tags: DIAGNOSTICS, WITHDRAWALS, BITCOIN, MONERO, SOLANA, CONFIGURATION, ECOSYSTEM
Overview
A diagnostics release with one withdrawal fix. Monero address validation was
refusing valid stagenet and testnet addresses as Invalid Monero address. If you
run any chain off its main network, read the Upgrade Notes. The rest of the
release changes whether the chain requirements screen tells you the truth.
Two of its live checks were reporting failures on installs that were working.
A self-hosted Bitcoin Core node that bitcoin-cli could talk to came back as
Bitcoin Core RPC (getblockchaininfo): fetch failed, and a Monero pair that was
crediting deposits came back as 401 after Digest auth — bad XMR_RPC_USER / XMR_RPC_PASSWORD. Both were faults in the test, not in the chain. An operator
who trusted either one would have gone looking for a problem that was not there;
one who learned to ignore them lost the screen entirely.
They are fixed, and the messages they print now name the address, the socket error and the thing to change. A new row reports currencies being hidden from the deposit picker because their token's network label disagrees with the chain's configured network — until now the only trace of that was a line in the log.
Requires Core v6.7.5.
Update Instructions
# 1. Update the addon in Admin → System → Extensions
# 2. Restart the backend
pnpm updatorNo schema change, no seeder, nothing to repair. Re-run Admin → Ecosystem → Blockchains → Requirements afterwards.
Upgrade Notes
A currency missing from the deposit picker, with nothing on screen to say why
A currency is offered for deposit only while its token's network label agrees
with that chain's {CHAIN}_NETWORK. The rule is right — a deposit against a
mismatched row could never be credited, because the monitor is watching a
different network — but its only output was a line in the backend log.
In 6.4.8 that rule began applying to the four chains that had been exempt from
it: Solana, Tron, TON and Monero. On an install running one of them off its
main network, token rows still labelled mainnet quietly stopped being offered,
and nothing on any screen connected the disappearance to the label. That change
shipped without a note; this is it.
- Added a token-network row to the chain requirements screen for those four chains, naming each currency being withheld and the two values that disagree.
- If a currency has vanished from your deposit picker, open Admin →
Ecosystem → Blockchains → Requirements and read the new row for that
chain. Correct whichever side is wrong — the token's network field, or the
chain's
{CHAIN}_NETWORK.
Monero withdrawals to stagenet and testnet addresses were refused
Address validation matched only the first character of the address against a set
chosen by XMR_NETWORK, read that key without trimming it, and treated anything
it did not recognise as mainnet. A valid stagenet address was refused as
Invalid Monero address — blaming the customer's address for a server setting.
- Fixed Monero validation to decode the address and read the network from the address itself, and to distinguish a wrong-network address from a malformed one.
- If withdrawals have been refused this way, no funds moved and there is nothing
to repair — set
XMR_NETWORKto the network your daemon runs and retry.
Chain requirements rows that change verdict
Read these only if a chain requirements row changes verdict after you update — a row that was red and turns green was a false alarm, and a row that stays red is now telling you why.
- A Bitcoin Core row that was failing may go green. The old check reported
every transport failure as
fetch failedwith no address attached. If the cause was that the backend was dialling the mainnet port while your node runs a test network, the row now says so before you run the test. - A Monero row that was failing may go green. The old check answered the
daemon's authentication challenge on a second TCP connection, which
monerodrefuses whatever the password is. Credentials that were reported as wrong were never wrong. - A Monero chain with
XMR_<NETWORK>_RPCset now has every daemon in the list probed, not just one. A second daemon that is stale, unreachable or on the wrong network has always been dialled by the running platform; it is now visible on the screen as well. pnpm btc-node:setupwrites a differentbitcoin.confthan it used to. If you run it on an existing install it will now match the file toBTC_NETWORK— see Changed.
Fixed
Monero addresses judged by their first character
Monero's address prefix is network-specific, and validation chose which prefixes
to accept from XMR_NETWORK — comparing a single character, looking that key up
without trimming it, and standing in the mainnet set for any value it did not
recognise. Two things followed. A valid stagenet or testnet address was refused
on any install whose XMR_NETWORK did not arrive spelled exactly as expected,
reported as Invalid Monero address so the operator went to inspect an address
that was correct. And a mistyped address that happened to begin with the right
character passed the form, to be refused later by the wallet service.
- Fixed validation to decode the address, verify the checksum Monero appends to it, and take the network from the address itself.
- Fixed
XMR_NETWORKto be trimmed and case-folded here the way the deposit currency list already read it, so the two can no longer disagree about which network the install runs. - Changed an address for the wrong network to be refused as exactly that, naming both networks, instead of as a malformed address.
A Bitcoin Core node that answers bitcoin-cli reported as "fetch failed"
The node RPC check reported the bare string fetch failed for every transport
failure. That text is what the HTTP client produces when it cannot open a
connection; the real cause — connect ECONNREFUSED 127.0.0.1:8332, and the
address it was refused on — is carried underneath it and was being discarded.
An operator comparing that against a working bitcoin-cli on the same box had
nothing to reconcile the two with, because the screen never said which address
it had tried.
The most common cause was invisible for the same reason. bitcoin-cli reads
bitcoin.conf; the backend reads BTC_NODE_HOST and BTC_NODE_PORT. Bitcoin
Core serves testnet4 on 48332, testnet3 on 18332 and signet on 38332, while
BTC_NODE_PORT defaults to 8332 on every network — so a testnet install with
the port left unset had a working CLI and a backend knocking on a closed door.
- Fixed the Bitcoin Core RPC check to report the underlying socket error and
the
host:portit happened on, and to add the port a test network implies when.envis still on 8332. - Fixed a
401to explain thatbitcoin-cliauthenticates frombitcoin.confor the cookie file and the backend can use neither, so.envneeds therpcuser=/rpcpassword=pair or anrpcauth=user. - Fixed a
403to name both refusals Bitcoin Core answers with an identical empty response —rpcallowip=andrpcwhitelist=— rather than asserting the first. - Fixed a request that never answers so it reads as a timeout with its budget rather than as an unreachable host.
- Added a warning on the requirements report itself, before any test is run,
when
BTC_NETWORKnames a test network andBTC_NODE_PORTis unset or 8332.
The estimatesmartfee and ZMQ rows failed for a cause already reported above them
One unreachable node produced three red rows. The fee and ZMQ probes call the same RPC endpoint as the check above them, so they failed for the same reason and said so in three different ways, none of which named the cause.
- Fixed the
estimatesmartfee(6)and ZMQ rows to be skipped, not failed, when thegetblockchaininfocall itself failed. One cause now shows as one red row.
Monero credentials reported as wrong while deposits were being credited
The Monero checks reported 401 after Digest auth — bad XMR_RPC_USER / XMR_RPC_PASSWORD against credentials the deposit monitor was using without
complaint.
monerod and monero-wallet-rpc hold the HTTP Digest session — the nonce and
its request counter — on the TCP connection that issued the challenge, and
treat an otherwise valid answer arriving on any other connection as stale. The
diagnostics were built on a pooled HTTP client that gave no guarantee the retry
would reuse the socket, so the correct password was refused. The addon's own
client has always reused its connection, which is why the same credentials
worked everywhere else on the platform.
- Fixed both Monero probes to answer the challenge on the connection that issued it, the way the addon does.
- Added a distinction the screen could not previously draw: a challenge the service marks stale is reported as the connection being closed or re-routed between the two requests — a reverse proxy or load balancer — and only a genuine mismatch is reported as the credentials.
- Fixed an unreachable Monero service to name the socket error and the
host:port, and to say that a working local tool proves the process is up rather than that.envpoints at it.
A single daemon probed where the platform uses a pool
With XMR_<NETWORK>_RPC set, the addon builds a failover pool. The check probed
one address and declared the chain healthy on that evidence, so a second daemon
that was unreachable, unsynchronised or on the wrong network stayed invisible
until it served a query.
- Fixed the Monero daemon check to probe every endpoint in the list, report how many answered, and name any that failed.
- Added a failure when the endpoints in one pool disagree about which network
they are on, and made a network mismatch on any of them reach the
XMR_NETWORKcomparison rather than being masked by a healthy sibling. - Fixed the daemon row to name the key it took its list from, so the row and
the
.envline you need to edit agree.
An https:// Monero URL rejected as unusable when the service dials it anyway
The Monero client passes only the host, port and path to a plain HTTP
connection and never reads the scheme, so https://host:18081/json_rpc reaches a
stock daemon exactly as http:// does. Only a URL with no port is genuinely
broken, because it then resolves to port 80.
- Fixed the URL rule to refuse only the case that cannot work —
https://with no port the parser keeps, which includes an explicit:443— and to warn on the rest that the URL claims TLS the connection never negotiates.
Changed
Currencies withheld from the deposit picker now have a row of their own
The eligibility rule 6.4.1 introduced decides whether a currency can be offered at all, and 6.4.8 extended it to the four chains served by their own service. Neither release gave it a place on the requirements screen, so the one verdict that removes a currency from the customer's view was the one verdict an operator could not see.
- Added a token-network check for Solana, Tron, TON and Monero that lists every enabled token row whose network label disagrees with the chain's configured network, and is therefore hidden from the deposit currency list. It reads the same rule the list itself filters on, so the screen cannot drift from what it is explaining.
pnpm btc-node:setup writes a configuration that matches BTC_NETWORK
The setup script wrote a mainnet bitcoin.conf and BTC_NODE_PORT=8332
whatever network the platform was configured for. Off mainnet that produced
exactly the failure above: a node on one port, a backend on another.
It is also the file's own trap. Bitcoin Core reads rpcport= — along with
port, bind, rpcbind, addnode, connect and wallet — from the top of
bitcoin.conf for mainnet only; on any other chain a top-level value is
ignored and the chain default applies. A port written at the top of the file
therefore looks correct and does nothing.
- Changed the script to read
BTC_NETWORKfrom.envfirst and write the chain flag, the RPC port inside that chain's own[testnet4]/[test]/[signet]section, and a matchingBTC_NODE_PORT. - Changed it to read and rewrite
.envthrough the same parser the backend uses, so anexport KEY=, a spacedKEY =or a duplicated key resolves the same way for both. It refuses to write a file that would not read back as intended rather than reporting success. - Changed it to stop and say so when
BTC_NETWORKholds a value the platform does not accept, instead of configuring a node for mainnet.
Environment rows that described keys as decorative
Three keys on the requirements screen were labelled display-only after the
services had begun reading them. SOL_<NETWORK>_RPC and XMR_<NETWORK>_RPC
each replace an endpoint the platform actually dials, and a screen that calls
them decorative invites an operator to leave a stale value in one.
- Changed the
XMR_<NETWORK>_RPCrow to state that it replacesXMR_DAEMON_RPC_URLfor every daemon query, and added the_FALLBACKrow beside it. - Changed the
SOL_<NETWORK>_RPCrow the same way, and keyed it to the cluster the service resolved to rather than the value typed intoSOL_NETWORK— so an install that fell through to devnet sees the key that is really read. - Changed the
XMR_NETWORKrow to say it names the daemon-list key as well as driving address validation, and theXMR_DAEMON_RPC_URLrow to say it is still the addressmonero-wallet-rpcis first pointed at. - Changed the message a failing Bitcoin Core row prints about the fallback to mempool.space. The provider is chosen once and cached for the life of the process, and the deposit scanner and the withdrawal path choose at different moments, so a restart is required either way — the old wording implied the platform would return to the node on its own.