Bicrypto 6.7.4

28 August 2026

This release has upgrade notes. Read them before updating — they describe behaviour changes that need your attention.

WALLETSDEPOSITSDATABASEEMAILCONFIGURATIONDEPENDENCIES

Core v6.7.4

Release Date: August 28, 2026 Tags: WALLETS, DEPOSITS, DATABASE, EMAIL, CONFIGURATION, DEPENDENCIES

Overview

A configuration-safety and wallet-ledger release. There is no schema change and no migration to run.

One thing wants a decision before you upgrade rather than after. The backend now checks DB_PORT at start-up instead of handing it to the driver and hoping, so a value that is not a plain whole number stops the backend booting where it previously connected you to whatever was listening on port 3306. Look at that line in your .env first. Second, if you suppress outbound mail with MAIL_DISABLED=on, the notification queue has been ignoring that and sending anyway — after this update it genuinely stops, which is a real change on a staging clone of production data.

The rest is the ecosystem credit path. Crediting a wallet could silently skip its per-chain trackers and then write the gap into the audit trail as a genuine zero movement. Customer balances and withdrawals were never affected. Read Upgrade Notes first.

Update Instructions

pnpm updator

There is no schema change in this release — no new table, no seeder, and nothing to run by hand. Restart the backend when the update completes.

The one thing to do before that restart is check DB_PORT in your .env, in Upgrade Notes below. It is the only value in this release that can stop the backend starting, and it is a ten-second check.


Upgrade Notes

Check DB_PORT before you restart

The backend used to read this value with Number() and pass the result straight to the database driver. Number("3307abc") is not a number at all, and the driver quietly fell back to its own default — so an operator who mistyped the port reached a different database server than the one they named, and nothing anywhere said so. Guessing is defensible when a wrong guess costs a failed connection. It is not defensible when it costs you the wrong database.

The value is now parsed strictly, and the backend refuses to start on one it cannot use, naming the value it rejected.

  • Changed DB_PORT must be a whole number between 1 and 65535, or left unset. Unset, blank or whitespace still means 3306, so a stock install needs no change at all.
  • Check the line before you restart. These started the platform before and refuse it now: a decimal point (3307.0), a hex value (0x0CEB), 0, and anything with characters attached (3307abc — which was reaching 3306, not 3307).

This completes for the main database connection what 6.7.3 did for the backup and restore endpoints.

MAIL_DISABLED=on was not stopping queued mail

The platform carried two copies of the outbound-mail kill switch, and they had drifted apart. The exported one accepts true, 1, yes and on, and ignores surrounding whitespace. The copy inside the notification queue accepted neither on nor a value with spaces around it. Because the environment documentation lists on as valid, an operator who used it suppressed mail on the direct send path and failed open in the queue, inside the same process.

  • Fixed there is now one definition, imported by both paths. MAIL_DISABLED=on and values with surrounding whitespace suppress queued mail as documented.
  • If you have been running a staging or test clone with MAIL_DISABLED=on, assume queued mail has been going to the real addresses in that database — password resets, verification codes and withdrawal confirmations among them.

Ecosystem credits could skip the per-chain trackers, then misreport it

An ecosystem wallet records the same money three times: the wallet balance, a per-chain entry in the wallet's address JSON, and a per-chain wallet_data row. The first is authoritative and is what withdrawals and the maximum-withdrawal calculation read, so customer balances and withdrawal limits were never affected by this. The other two are trackers.

On a credit, if either tracker was missing, the code skipped it and carried on, while the debit path had been creating the missing row since its own drift fix. The trackers fell behind on the credit side only, and the gap grew with deposit volume. The audit trail was worse than incomplete: both chain-balance figures stay at their starting zero and are written into the transaction metadata and the audit row, so a credit that never touched a tracker was recorded as a genuine 0 → 0 movement, indistinguishable from one that really moved nothing.

  • Fixed a credit now creates the missing per-chain row from a sibling row on the same wallet, and where that is impossible it still credits the wallet and records the gap instead of asserting a zero movement.
  • This release repairs the code, not existing rows. Per-chain figures written before this update are not recalculated, and an audit row from before this update showing a 0 → 0 chain movement may not be a real one — treat it as unknown rather than as evidence that nothing moved.

Changed

Ten environment keys the backend reads are now written down

Every one of these has a working default, which is why none of them had to be declared — and also why there was no way to discover them. Installs that do not use the ecosystem or futures extensions can ignore the Scylla block entirely; nothing reads Scylla until one of those is enabled.

  • Changed .env.example documents ten keys that were read but declared nowhere: eight SCYLLA_* settings (contact points, the spot and futures keyspaces, credentials, datacenter, and connections per host), LOG_LEVEL, and REDIS_DB — each with the value the backend actually falls back to.
  • Changed NO_COLOR and FORCE_COLOR are described but deliberately left out as settings. They are read by bare truthiness, so NO_COLOR="false" disables colour rather than enabling it, and a line in that file would be an invitation to write exactly that.
  • The file also records that SCYLLA_ENABLED switches off only on the literal string false; 0, no and off all leave it enabled.

backend/package-lock.json is gone

The backend is a pnpm workspace member and nothing read this file, but it was a trap rather than a harmless leftover: it could not reproduce the tree the platform ships. Of the backend's 73 declared dependencies, exactly one carried a resolvable version in it — seven were missing altogether, and the other 65 appeared only as links into a pnpm store path. Running npm ci in that directory would have installed a materially different dependency tree, and would have dropped every security pin in the workspace overrides, which npm does not read. Refreshing the file would have preserved the trap; deleting it removes the door.

  • Removed backend/package-lock.json. Install from the repository root with pnpm install, exactly as before.

Two unused logging dependencies no longer ship

  • Removed winston and winston-daily-rotate-file — declared as dependencies, listed in the software bill of materials, and imported nowhere in the backend. The backend SBOM goes from 75 components to 73.

Three stale endpoint copies no longer ship

Editor leftovers named index.get.ts.tmp, index.get.ts.fix and index.post.ts.backup, sitting beside the ecosystem ledger list, the NFT token list, and the investment duration create endpoint. No route behaviour changes and nothing was serving them: the route loader registers a file only when it ends in the real source extension. They were stale forks of three live endpoints shipping inside the distributed bundle, one regression in that guard away from mattering.

  • Removed three stale endpoint copies from the API tree.

Fixed

Wallet creation could advertise a chain it could not track

This is where the credit-side drift came from. When a wallet was created, the chain's entry in the address JSON was written before its per-chain row was inserted, inside a block that logs a failure and moves on to the next chain. A failed insert therefore left the wallet advertising a chain it had no tracker row for, and every later deposit on that chain moved the authoritative balance alone.

  • Fixed the address entry is written only once its per-chain row exists, so a chain the wallet cannot track is a chain it does not advertise. Partial success across chains is preserved as before — a wallet that builds three chains out of four still gets the three.
  • Fixed the failure is logged against the wallet, and says the chain has been omitted while the others continue, instead of reporting a failure at any stage as a failure to generate the address.