Ecosystem 6.3.5
29 July 2026
This release has upgrade notes. Read them before updating — they describe behaviour changes that need your attention.
Ecosystem v6.3.5
Release Date: July 29, 2026 Tags: SECURITY, CRITICAL FIXES, ORDER BOOK, SETTLEMENT, MARKET CONTROLS, BITCOIN, DEPOSITS, TRON, WITHDRAWALS, ADMIN, AUDIT, KYC, AI MARKET MAKER, PERFORMANCE, APPEARANCE
Overview
Version 6.3.5 is the result of a full end-to-end review of the ecosystem addon — the on-chain wallet layer and the native order book that trades against it.
It fixes a critical order-book defect: roughly half of all ecosystem order-book updates were being written to the wrong place. That is why filled and cancelled orders kept resting in the book as phantom liquidity, and why some trades were missing from the chart.
Four further findings are serious. A market buy crossing more than one price level ran out of reserved funds half way through, stranding the rest of the buyer's money. Five simultaneous orders from one user jammed the database. Switching a market off did not stop anyone trading on it. And eight admin screens answered signed-out callers.
Two of those are platform-wide rather than ecosystem-specific: the database jam affected every wallet operation on the installation, and six of the eight unprotected screens are core.
Requires Core v6.5.8.
Update Instructions
pnpm updatorNo migration or seeder is required. Nothing in this release changes the schema.
After updating, run the order-book reconciliation to clear anything left behind by the old keyspace behaviour:
node backend/scripts/rebuild-eco-orderbook.mjsUpgrade Notes
Compatibility
- No database changes, no migration, no seeder.
- A market buy now reserves against the worst price its sweep can touch rather than the average. The buyer's net cost is unchanged — the difference is refunded fill by fill — but the balance required at the moment of placement is higher on a thin book.
- Disabled markets now refuse orders. If a market was switched off but expected to keep trading, re-enable it.
- The database connection pool defaults to 25 connections (previously 5). On an installation with a low database connection limit, or several backend threads, set
DB_POOL_MAXaccordingly. - BTC, LTC, DOGE and DASH deposits are now credited only once they reach the confirmation depth your chain configuration specifies — 3 for Bitcoin, 6 for the others — rather than at a single confirmation. Deposits take correspondingly longer to appear, which is the intended behaviour.
- Ecosystem deposit verification now runs every 60 seconds rather than every 10.
- Where the KYC requirement for trading is switched on, it now applies to ecosystem order placement as well. Users below the required verification level will be refused until they verify. Installations that leave the requirement off are unaffected.
- Four ecosystem admin dropdowns now require a view permission in addition to a sign-in. A role that could create master wallets or markets without holding the matching view permission will lose those dropdowns until it is added.
Breaking Changes
None. Existing markets, orders and wallets are unaffected.
Added
Order book reconciliation
- Added detection and cleanup of price levels stranded by the misrouted-update defect. Only symbols that trade on the ecosystem and not on futures are touched — where a symbol trades on both, a misrouted level is indistinguishable from real futures liquidity, so those are left alone.
- Changed the documentation: the matching engine's own reconciliation does run at startup and every 5 minutes, and it works from an in-memory queue, so the reconciliation script remains the authority when the two disagree. It no longer skips AI-managed symbols — see Fixed.
KYC verification can now gate ecosystem order placement
- Added where an operator has switched on the KYC requirement for trading, a user who has not reached the required verification level can no longer place ecosystem orders, including stop orders. Ecosystem order placement ignored KYC completely before this, so the requirement did nothing there.
Per-period profit and loss for AI market maker bots
Every real fill an AI market maker bot takes on the ecosystem book is now recorded in its trade ledger. A bot's stored profit figure is a lifetime running total with no history, and nothing had ever written to the per-fill ledger — so the today, this-week and this-month figures on the market maker P&L screen were structurally zero.
- Added fills are recorded as they happen, so those figures populate from this release onward. Existing history cannot be backfilled.
Bitcoin and Litecoin deposit scanning survives an unreachable explorer
The default block explorer is served from a single network that some ISPs and hosting firewalls silently drop. The connection simply hangs until it times out, so a provider working everywhere else looked like a hard outage and BTC deposit scanning stopped.
- Added automatic failover across several independent mirrors of the same service, for mainnet, testnet4, testnet3 and signet. Any of them can serve the whole provider.
- Added a preference for whichever mirror last answered, so later requests do not re-pay the dead-primary timeout.
- Fixed web pages being parsed as data. Some hosts answer with their website instead of an error, which became invalid block heights and silently empty transaction lists. These are now treated as a dead mirror, and one well-known explorer is excluded from the list entirely for this behaviour.
- Changed error handling so server errors and rate limits move to the next mirror, while a genuine answer from the service (unknown transaction, rejected broadcast) is passed through unchanged — every mirror would say the same.
- Added
BTC_MEMPOOL_API_URLandLTC_MEMPOOL_API_URL(comma-separated), which replace the built-in mirror list entirely if you run your own explorer.
Ecosystem menu restructure
- Added an Overview entry for the ecosystem dashboard.
- Added Custom EVM Chains to the menu. The page existed but had no menu entry at all.
- Changed the menu into groups: Blockchains (Requirements, Custom EVM Chains), Wallets (Wallets, UTXO, Ledgers) and Trading (Markets, Tokens), replacing the previous flat list.
Also in this release
- Added the Core v6.5.8 withdrawal two-factor requirement to ecosystem withdrawals, checked before any balance is touched. No effect unless an admin enables the setting.
Changed
Wallets left behind by a network change logged an error every cycle
A Bitcoin-style address encodes the network it belongs to, so an explorer will always reject one that does not match. A wallet whose address was generated under a different network setting — most often a mainnet address on an installation later switched to testnet — therefore failed every single request, once a minute from the deposit scanner and every 30 seconds from the deposit monitor, indefinitely. Real failures were buried in the noise.
- Added a network check before any explorer request, covering BTC, LTC, DOGE and DASH. An address that definitely belongs to another network is skipped instead of retried.
- Changed the log output to one warning per address for the life of the process, naming the wallet, the address, the configured network and the two ways to resolve it, rather than one error per scan.
- Changed the deposit monitor to stop rather than keep polling an address whose confirmations it can never see.
Affected wallets keep their existing address — this change stops the noise, it does not migrate anything. A wallet can only move to the configured network by being regenerated, and its stored key is the only copy in existence, so never delete one whose address still holds funds without moving them out first.
Chain Requirements page
- Changed the explorer reachability check to test the same mirrors in the same order and report the one the platform would actually use. A dead primary is now a warning as long as a mirror answers, instead of a failure.
- Fixed the check accepting a web page as a live mirror.
- Added the new mirror-list settings to the documented environment variables.
Appearance
- Changed the public ecosystem markets page to follow the site theme. It was built on a fixed green palette regardless of the installation's configured colours, so a rebranded installation had one green page. Its hero, stat tiles, search and filter controls, market list, row hover, Trade buttons and closing call-to-action now use theme colours, and stat numbers are set in a tabular figure style so they no longer shift as they update.
- Changed the ecosystem admin screens — overview, blockchain requirements, custom EVM chains, markets and tokens — to use the shared theme instead of hardcoded colours, so they follow the installation's configured accent and its light and dark palettes. Two changes an operator will notice: chain cards lose their per-chain brand colours, and the overview's stat tiles change shape and typography.
Fixed
Order book updates were being written to the wrong place
Roughly half the time, an order book update landed somewhere the ecosystem never reads. Half of all fill and cancel updates never touched the level the user was looking at, so filled liquidity stayed in the book indefinitely. Chart candles had the same problem, which is how the ecosystem chart silently lost trades.
- Fixed every order book and candle update now names its destination explicitly, and a mistake of this kind now fails loudly rather than silently going to the wrong place.
Order book reads came from a stale copy
Reads came from a secondary copy that updates asynchronously and never self-heals — one was observed serving 6 of 10 real price levels. Because every read is followed by a write, a stale read then rewrote the real level: a missing level wiped other users' resting liquidity, and an inflated one meant the next cancel could only remove part of it, leaving a ghost level with no order behind it.
- Fixed reads now come from the authoritative book, at no extra cost.
Cancel-all left every cancelled order alive inside the matching engine
Cancelling all of your open orders marked them cancelled and returned your funds, but the matching engine kept a live copy of each one in memory. The order could still be matched afterwards, and the 5-minute cleanup wrote its price level back into the public order book, where it reappeared as depth nobody could ever trade against. The operator kill-switch and the batch cancel used by Hummingbot read orders the same way and failed the same way.
- Fixed a cancel-all now removes every one of those orders from the engine as well as from the book.
- Unaffected: cancelling a single order from the trade screen, which always worked.
A market buy across more than one price level stranded the buyer's funds
A market buy reserved funds based on the average price of its sweep. The cheap levels at the top of the book released more of the reservation than they consumed, so by the time the sweep reached the deeper, dearer levels there was not enough left to pay for them. The order stopped part-filled, stayed open, and the rest of the reservation sat locked until the user noticed and cancelled it. A market buy of 8 against asks of 5 at 2 and 5 at 6 filled 5 and stranded 10.52.
- Fixed a market buy now reserves against the worst price its sweep can touch, so the reservation always covers what each fill consumes and drains cleanly to zero.
- Unchanged: what the buyer actually pays. The larger reservation is returned fill by fill as price improvement, exactly as before — only the temporary hold is bigger.
- Fixed the fee is still quoted from the realistic average price, so the larger reservation does not overcharge the trade.
Bitcoin-family deposits were credited at one confirmation, and one unconfirmed deposit stalled crediting for half an hour
Two problems in the same check. Deposits were credited after a single confirmation, well below the depth the platform's own chain configuration calls for — 3 for Bitcoin, 6 for Litecoin, Dogecoin and Dash. And the check then waited up to 30 minutes for that confirmation without releasing the deposit-verification pass, so every other user's pending deposit sitting behind it in the queue went uncredited until it gave up.
- Fixed the configured confirmation depth is now enforced per chain, and the check answers immediately with what the chain currently reports. Verification runs every 60 seconds, so a deposit that is not yet deep enough is simply re-checked on the next pass instead of blocking the one it is in.
- Applies to BTC, LTC, DOGE and DASH deposits.
Five simultaneous wallet operations jammed the database
Every wallet operation — credit, debit, hold, release, transfer, wallet creation — asked for a second database connection while still holding its first. With the previous default of five connections, five concurrent wallet operations took every connection and then each waited for one that could not exist. Nothing progressed until the wait timed out roughly 60 seconds later. Observed as five orders placed at once from one account: one succeeded and four returned "Failed to update wallet balance. Order rolled back." This affected every wallet path on the platform, not only ecosystem trading.
- Fixed no second connection is taken. The audit record now also correctly reflects operations that were rolled back.
- Fixed the connection pool is now configured explicitly —
DB_POOL_MAX(default 25), plusDB_POOL_MIN,DB_POOL_ACQUIRE_MSandDB_POOL_IDLE_MS— instead of inheriting a five-connection default that leaves no room for the site plus its background jobs.
Eight admin screens answered anyone, signed in or not
Eight admin screens named the permission they needed but never actually required a sign-in, so the permission did nothing at all. Two belong to this addon (master-wallet balances and transactions). The other six are core, and one of them ran any named background job for a completely signed-out caller — with a second one alongside it listing every job name to choose from. Also public: the admin patch notes and a currency lookup.
- Fixed all eight now require both a sign-in and the permission.
- Fixed four ecosystem admin dropdowns (market, token, custodial wallet, master wallet) required a sign-in but no permission, so any signed-in user could read them. They now require the matching view permission.
If your installation is internet-facing, treat the background-job trigger as exposed until this update is applied.
Admin order lists ignored the user filter and showed every user's orders
The ecosystem and futures order lists on a user's detail screen in the admin CRM were meant to show only the user being inspected. The filter that scoped them to that user was silently discarded, so both answered with every order on the platform, one page at a time. Any admin opening one user's profile was shown other users' trading activity.
- Fixed both are scoped to the user being viewed again.
Three admin actions had never worked
The master-wallet balance refresh, the master-wallet transaction history and the token-holder list looked alive but answered with a server error on every call. They have never worked.
- Fixed all three now work — and require the authority to run them.
Disabling a market did not stop trading on it
A market switched off by an operator — a delisting, a compromised token, an emergency freeze — disappeared from the interface while continuing to accept and match orders from anyone who knew the pair. Stop orders could also still be placed on it.
- Fixed both regular and stop orders are refused on a disabled market. Exits stay open by design: cancelling an order and reclaiming its funds still works, so closing a market never traps money.
Order book updates stopped for every depth except the first
The server only sends an order book update when the book has actually changed, but it tracked "has this changed" once per market rather than once per depth. Whichever depth was served first claimed that record, and every other depth then looked unchanged forever — a client watching at any other depth stopped receiving updates entirely and kept displaying price levels that had already been removed. The server-side forced refresh meant to unstick this cleared nothing, so it never recovered.
- Fixed change tracking is now per market and depth, and the forced refresh clears all of them.
Fills left phantom depth resting for up to five minutes
Under a specific timing, a fill could not find its own level to reduce, so the level stayed in the book as depth with no order behind it — liquidity the engine can never fill. The public book advertised it, and it fed two money decisions: the size of a market order's reservation, and the reference price a stop order is armed against. It was cleaned up eventually, but "eventually" was up to five minutes.
- Fixed the level is now repaired from the real open orders as soon as that trading cycle completes. The repair leaves an AI market maker's display levels alone, since those legitimately have no order behind them.
The money decisions read the display book instead of the real one
The addon distinguishes the display order book from the order-backed one precisely because the AI market maker writes synthetic levels the matching engine can never fill against — and order placement, the most money-critical path in the addon, was reading the display book. A market order's reservation was sized from depth that does not exist, so it could be accepted and then fail to fill; a market sell was priced from a level at which no trade can occur; and a limit order that only "crossed" a synthetic level was charged the taker rate for liquidity it never took.
- Fixed every book read on the placement and stop-order paths now uses the real, order-backed book.
A cancel issued with a slightly-off timestamp silently did nothing
An order's creation time is part of how it is stored and found. A cancel that reconstructed that time even a millisecond off found no order, recorded it as "already filled", and returned without reducing the order book or writing the cancelled status — while the caller reported the cancel as done and the level stayed resting in the book. The miss was recorded only in debug logging, so it was invisible in normal operation.
- Fixed a miss now looks the order up by its identifier and re-runs the cancel against the real creation time. A genuine miss is logged as a warning.
Full order book scans silently stopped after the first batch
The engine's startup snapshot of the order book and its 5-minute cleanup sweep both read only the first batch of results and treated it as the whole book. On a busy installation everything past that batch was invisible — it could not be matched against, and stranded levels there could never be cleaned up.
- Fixed both now read the book through to the end.
The 5-minute cleanup now runs on AI-managed markets
The engine's periodic order book cleanup switched itself off entirely for any market run by the AI market maker, because it could not tell the AI's synthetic display levels apart from order-backed ones and would have deleted both. A real user's stranded price level on such a market therefore survived indefinitely — and a market that merely idled, was paused, or failed to start stayed excluded just the same while quoting nothing.
- Fixed the AI's own levels are now identifiable and are removed from consideration; everything else on the market is cleaned normally. On an older book where those levels cannot be told apart, the cleanup still skips the market rather than risk deleting live AI depth.
An unrecognised order side created a permanently stuck order
An order with an unrecognised side was checked against one wallet and charged against another, then written to the book — where it rested forever, because the matching engine only ever considers buys and sells.
- Fixed anything that is not a buy or a sell is refused before a single token is held.
Stop orders were not held to the market's limits
A stop above the market's maximum size, outside its price band, or below its minimum value was accepted and rested normally. It failed only when it triggered — so the protection a trader was relying on silently did not fire, at exactly the moment it was meant to.
- Fixed stops are now checked against the same limits as ordinary orders, at the price they will actually rest at once triggered.
Deleting a market refunded copy-trading orders to the wrong wallet
Deleting an ecosystem market cancels and refunds every order resting on it. For an order funded from a copy-trading allocation, the refund was credited to the user's ecosystem wallet while the original hold stayed locked on the copy-trading wallet — the funds were both duplicated and lost in one step.
- Fixed the refund now returns to the wallet the order was funded from.
- Applies to market deletion only. Orders cancelled by the user, or by any other path, always refunded correctly.
Most TON withdrawal addresses were rejected before they were ever checked
A basic character filter ran ahead of the real address check and allowed only letters and digits. Roughly four in five TON addresses contain a - or _ and were turned away with "Invalid address format", and the raw address form was rejected every time. TON withdrawals were largely impossible.
- Fixed the filter now admits the characters the supported chains actually use, while still rejecting everything dangerous. The real per-chain address check is unchanged.
- Fixed an address could previously widen its own internal lookup because of a special character. It cannot now.
Trading fees never reached the per-chain ledger
The platform's balance was credited correctly, but the per-chain record was silently skipped — so the per-chain ledger drifted below the wallet balance by the full amount of every trading fee ever collected.
- Fixed fees are now recorded against the right chain. Where the chain cannot be determined the fee is recorded without one, rather than against the wrong one.
Withdrawing to your own deposit address quietly did not withdraw
A user who pasted their own deposit address got a success message, a transfer fee deduction, and no transaction. Nothing left the platform and nothing said so.
- Fixed an address belonging to the caller's own account is refused with an explanation.
Both money doors reported every failure as a server error
The withdrawal and wallet-transfer screens rewrote every failure as a generic server error — an invalid address, too many decimal places, an unknown token, insufficient funds, a recipient who does not exist. The user could not tell "you cannot afford this" from "the server broke", and had nothing to act on.
- Fixed real, specific messages are shown. Genuinely unexpected failures still report as a server error.
An unlisted deposit worker kept crediting after the ecosystem extension was disabled
Opening a deposit page started a background verification worker under a name the scheduled-job registry does not know. It could not be seen, triggered or stopped from the admin scheduled-jobs screen, and switching the ecosystem extension off did not stop it crediting deposits.
- Fixed that worker is gone. The registered ecosystem deposit verification job is now the only path that credits these deposits, and an operator can see, trigger and stop it.
- Changed deposit verification therefore runs every 60 seconds rather than every 10.
Two backend processes could sweep the same deposit addresses at once
The background deposit scanner renewed its shared lock once every 25 addresses. A single address can take tens of seconds of deliberate rate-limit waiting, so the 30-second lock frequently expired mid-sweep while the process carried on scanning. A second process then picked up the same work, and the two together sent roughly double the request rate the per-chain limits exist to enforce — the kind of thing that gets an installation banned from a free public node.
- Fixed the lock is renewed on elapsed time rather than an address count, and a process that finds it has lost the lock stops its sweep. Previously the result of the renewal was ignored entirely, so a lost lock never stopped anything.
Deposit scanning re-verified transfers it had already credited, for days
The EVM deposit sweep re-reads the same block window on every pass and had no check for transfers it had already credited. Each one was re-fetched and re-verified against the chain on every single scan for as long as the address stayed in the working set, only to be discarded as a duplicate at the end.
- Fixed an already-credited transfer is recognised and skipped before any of that work happens — the same check the Bitcoin-style scanner already had.
A real trade could overwrite the published settlement price for that minute
Binary rise/fall contracts settle on the 1-minute candle close of the expiry minute, and the Binary AI Engine publishes that close. A genuine ecosystem trade landing in the same minute overwrote it, so the contract settled on one price while the chart showed another.
- Fixed a published close is preserved when one exists, and the trade updates volume as normal. The candle's high and low now also stretch to cover the published close, so it can no longer render as a wick outside its own candle.
- Applies to installations running the Binary AI Engine against an ecosystem market. If the published close cannot be read the trade price is written exactly as before — a trade never fails because of this.
The per-market page had never worked
Every request for a single market's details answered with a server error.
- Fixed it now returns the market's real details — currency, pair, trending/hot flags, metadata and status.
The single-token details lookup had never worked
Every request for one ecosystem token's details answered with a server error. It asked for a chain that nothing could ever supply, so the lookup always ran with an empty value and was refused.
- Fixed it now returns the token's details, and the chain must be supplied alongside the currency. A currency code on its own does not identify a token — 1INCH exists on SOL, BSC and ETH.
Chart requests accepted any interval
An unrecognised interval was not "no data" — it was a guaranteed miss that the chart rendered as empty with no indication anything was wrong.
- Fixed the interval is checked against the supported set, the symbol is required, and the date range is checked.
Performance
- Fixed backend startup taking about two seconds longer than it needed to. Connecting to the trading database always waited two seconds before its first attempt, even though the port had just been confirmed open, and the matching engine loaded its candle history only after the order book reconciliation had finished, one after the other. The wait is gone and the candle loads now run alongside the reconciliation, so every healthy installation boots noticeably sooner. The retry backoff for a database that accepts a connection before it is ready to serve is unchanged.
Also in this release
- Fixed the 5-minute cleanup rebuilding cancelled and fully-filled orders back into the book as price levels. It rebuilt levels from the engine's in-memory order list without checking that those orders were still open, so anything that left a cancelled or filled order in that list was written back as real depth and re-created every five minutes — an operator who deleted the phantom level by hand watched it come back. Only open orders with something left to fill now contribute to a rebuilt level; anything else is skipped and logged as a warning. The defect that left cancelled orders in that list is fixed above.
- Fixed a native TRX withdrawal being accepted from a wallet with no signing key on record, where it can never be fulfilled — unlike TRC20 tokens, it cannot be sourced from a pooled wallet. The balance was debited, the payout failed in the queue, and the money came back as a refund some time later. It is now refused before the balance is touched. TRC20 withdrawals from the same wallet are unaffected and are still sourced from the pooled wallet.
- Fixed two scheduled jobs issuing the identical stuck-withdrawal recovery sweep at the same time. Each had its own concurrency guard, so on every 30-minute boundary both ran together and sent duplicate block explorer lookups against the same stalled withdrawals. They now share a single pass — both still report their own results, and the work happens once. The recovery run at startup is deliberately kept separate, because it sweeps with no age limit.
- Fixed TRON gas top-ups bouncing withdrawals into a retry on slow test networks. The confirmation window was 30 seconds, which frequently expired on congested test networks even though the top-up landed moments later. It is now 90 seconds. Mainnet behaviour is unchanged.
- Fixed internal tracking entries growing without bound on an installation running with
ECOSYSTEM_BACKGROUND_SCAN=false. Every visit to a deposit page still added an entry to two tracking lists that only the scanner itself ever trims, and with the scanner off nothing trimmed them. Nothing is registered now while the scanner is disabled. - Fixed one tile on the admin UTXO analytics screen showing an untranslated placeholder instead of its title, in every language including English. It now reads Average Amount.