Exchange Engine 6.6.1
Latest20 October 2026
Ecosystem v6.6.1
Release Date: October 20, 2026 Tags: DEPOSITS, SCANNER, DELIVERY, CONVERT, MARKET ORDERS
Overview
A deposit no longer waits for the slow scan because its live monitor failed to start. When a customer opens a deposit page, the platform starts a live monitor on their address and puts the address on the background scanner's fast lane, which rescans it every two minutes for 72 hours. The second step ran after the first, so a monitor that could not start (a provider down for that one second, a Solana subscription refused) left the address off the fast lane, and a deposit that followed was left to the slow lane: every fifteen minutes, and twice that after a timeout. The address is now put on the fast lane first.
A deposit page that was open also never heard the confirmation of a deposit that waited for the pending-deposit check, on an Ethereum-style chain or on Solana, because the check announced it under the chain's own spelling of the address and not the one the page had asked for. And Instant Convert can now pay a customer's own deposit address, the Ecosystem half of its new delivery to the customer's own wallet.
A market buy is no longer cancelled with nothing bought because a market maker's own quotes cross. One account never trades with itself, so the matching walk skips a pair that is one account's bid and ask. It skipped it by throwing the older order away for every other account's order sorted behind the newer one, and a customer's market buy then met only the maker's much dearer asks, was refused at them for being above its price cap, and was cancelled with nothing filled while a cheaper ask rested. The walk now skips the pair and nothing else.
Separately, a market buy's price cap now has room: it was exactly the deepest ask, so a one-tick move of the book cancelled the order with nothing filled. It is now that ask plus 1% (ECO_MARKET_BUY_BAND_BPS).
No new requirement: Core v6.8.6, as before.
Update Instructions
pnpm updatorNo schema change, no seeder. One optional .env setting is new, ECO_MARKET_BUY_BAND_BPS, and its default needs nothing. The backend restarts at the end. Update Instant Convert v6.0.5 in the same window to open deliveries.
Added
Paying a customer's own deposit address
Instant Convert's Send pays real coins from the house's own address, and it refused every address held on the platform, so a native coin, an SPL token or a token on several chains could never be received into a customer's own wallet. Instant Convert v6.0.5 pays that one destination, the customer's own deposit address, and the background deposit scanner credits the wallet as it credits any deposit. This add-on supplies the parts that must be right for that to be safe.
- Added to the withdrawal policy a purpose for it. A delivery is accepted only when the address is the same customer's own wallet in the same currency; any other address, a system account's included, is refused, and the withdrawal fee is not charged. The destination checks a Send runs (the platform's master wallet, the custodial contracts, a token's contract, an address with code, an exchange deposit address) still apply.
- Added to the house payout a guard for the same case. An address held by a wallet is paid only when every wallet that holds it belongs to the customer the delivery is for, and none is a system account; an address no wallet holds is refused. A Send keeps refusing every address held on the platform.
- Added the check of whether a chain's deposit can be credited, so Instant Convert offers a delivery only where it would be: the background scanner is on and owned by this backend, the chain is not handed to the Rust deposit worker, the token is enabled on a network this deployment runs, and the chain's monitor can credit a deposit into the wallet. A chain that fails any of these is not offered. When a delivery quote is refused the log says why; why the asset list leaves a chain out is logged only with
LOG_LEVEL=debug. - Added the opening of the customer's Ecosystem wallet in the coin, with the deposit addresses a deposit page would issue, and the registration of the address on the scanner's fast lane when the payout is signed and again when it is sent, so the credit follows the confirmation by minutes and not by the slow lane's quarter hour.
- An older Ecosystem add-on cannot pay such an address, and Instant Convert checks for this one before it offers or pays a delivery, so an update of Instant Convert alone changes nothing.
Changed
A market buy's price cap has room
A market BUY's stored price is a cap: the deepest ask its sweep reached in the book it saw, from which the hold is sized. The matching engine refuses any fill above it (a fill above the hold would be paid out of nothing) and cancels what a market order has not filled after its first pass. The cap was exactly that ask, so a book that moved up by one tick between the order being priced and being matched left it nothing it was allowed to take. The same exact cap also cut a sweep of two levels short on a book that did not move at all: the deepest fill consumed its share of the hold to the last digit, the rounding of that share decided, and the settlement guard refused it ("Buyer has insufficient locked funds"), leaving the first level bought and the rest cancelled. Both are reproduced in the engine's tests. Neither is what cancelled the XMR/USDC market buys reported on October 24: that was the matching walk, under Fixed below.
- Changed the cap to the deepest ask plus a band, 1% by default, rounded up to the market's price precision and never above the market's maximum price. The hold is sized from it and every fill refunds its own price improvement as it settles, so the buyer pays the asks' price; the fee is still quoted from the realistic sweep. A book that moves by more than the band still cancels the order.
- Added
ECO_MARKET_BUY_BAND_BPSto set the band in basis points:0turns it off (the exact cap, as before), the most taken is 1000 (10%), and an unreadable value is read as the default. See the environment reference. - A buyer whose balance covers the exact sweep and its fee but not the banded hold keeps the exact cap: the band is never a new minimum balance.
- Orders already open keep the cap they were placed with.
- Core v6.8.7's Pro trade order row shows a market order's average fill price and says why it ended short.
Fixed
A market buy was cancelled with nothing bought while a cheaper ask rested
Ecosystem testers reported two market buys of XMR/USDC (0.02 and 0.01) that read CANCELLED with 0.000000 filled at 595.67, in the minutes when a limit buy at 600 filled against the same 595.67 ask. The platform's log showed the buyer being refused at 615.08 and at 616.01, each time against a cap of 595.67 (Refusing unfunded buy fill), with the 595.67 ask resting: the book had not moved. The market maker on that market had been stopped on October 18 with its last ladder still resting (an ask at 595.67, one at 601.54 and two bids) and was started again on October 24 at a higher price, so its fresh bids at 596.90 and 590.84 sat above its own stale ask: a crossed book that cannot trade, because one account never fills against itself.
- Fixed the matching walk. A pair that is one account's (or one market-maker house's) bid and ask was skipped by moving past the OLDER order for the rest of the pass. A market order sorts by the price cap it was written with, so a customer's market buy sat behind the maker's fresh bid, and by the time it was reached the walk had thrown the stale ask away; the next pair (the bid against the maker's 601.54, which does not cross) moved both sides on again, and the first ask the buyer met was 615.08.
- The walk now skips the pair and nothing else. The newer order looks past the older for a counterparty that is a different account, within the next 256 orders on the other side, and the older order stays where it is for the orders sorted after the newer. An order that finds nobody is passed over, and a market order sorted deep on its side is still reached.
- One account's bid still never trades against its own ask, and an order that cannot be settled is still retired alone.
- Orders a market maker left resting when it was stopped are still resting. They no longer cost another account a fill, but they are not a price anyone should rely on: cancel them, and have the bot cancel its open orders when it stops.
The Ecosystem Orders list answered 500 to every filter
An operator reported that searching the Ecosystem Orders list "fails without any specific error". The unfiltered list loaded; every filter (a symbol, a status, both) answered HTTP 500, drawn as "There was a problem fetching the data". The list counted the matching rows with a count(*) over the whole orders table before it read any. On siryx the table holds 1.16 million orders, and the database gave up on a filtered count after its ten-second limit every time (the same count without a filter answers in 3.5 seconds), although the rows themselves read in a fraction of a second.
- Fixed the list helper that the Ecosystem Orders list and the Futures orders and positions lists share. The total now comes from the read that works: a scan that reaches the end of the table has counted every match, and one that stops short (the row cap, the page cap or a 15-second time budget) says so with
pagination.truncatedand draws the list from what it read. A real count is still asked for where it is cheap (one user's orders, or no filter), with a four-second limit, and its failure is a warning in the log, not an error on the page. - Fixed a scan whose later page fails after earlier pages were read: it keeps what it read instead of failing the whole list.
- Added a short memory of the last few scans: turning the page of a search, or making the same search twice, shares one read for 20 seconds, and at most two scans run at once on the backend, so a search box that sends a request for every keystroke cannot queue whole-table scans behind the order engine.
- Added
ECO_LIST_SCAN_BUDGET_MS,ECO_LIST_COUNT_BUDGET_MS,ECO_LIST_CACHE_MSandECO_LIST_MAX_SCANS. See the environment reference.
A list that stopped short is a prefix of the table in the database's own order, not the newest rows: narrow the search (a user, a symbol) when the response says truncated.
A deposit waited for the slow scan when its live monitor failed to start
- Fixed the order. The address is registered with the scanner's fast lane right after the deposit page asks for it, before the live monitor is created, and a registration error still never fails the request. A monitor that cannot start now leaves the address on the fast lane.
- The scanner's cadence is unchanged: the slow lane (
ECOSYSTEM_SCAN_PASSIVE_INTERVAL_MS, default fifteen minutes) is the baseline guarantee, not the fix.
The deposit page heard nothing for a deposit that waited for the pending check
- Fixed the pending-deposit check announcing a confirmation under the address in the chain's own spelling (mixed case on an Ethereum-style chain, case-sensitive on Solana). The page subscribes with a lower-case address and the notification broker compares the key byte for byte, so the credit and its notification were right and the page that was open on that coin never heard it. The address is lower-cased whichever field it arrives in.
The Requirements page checked monerod with the wallet RPC's login
- Fixed the Monero rows of the blockchain Requirements page. They asked
monerodandmonero-wallet-rpcwith the one pair,XMR_RPC_USERandXMR_RPC_PASSWORD, so amonerodwith a login of its own showed as refusing the platform even when the platform could use it. Themonerodrow now uses the daemon's login,XMR_DAEMON_RPC_USERandXMR_DAEMON_RPC_PASSWORDwhen both are set (the Monero add-on v6.2.4 adds them) and the one pair when they are not, and a refused login names the keys it tried. The wallet RPC row is unchanged. - Added both daemon settings to the page's list of Monero settings, with a warning when only one of the two is set.