CRYPTO TRAIN
v0.115.20

Writing

The fee that meant two things

8 October 2026 · figures measured 8 October 2026

A row in a ledger: an amount sent, a provider, a date, and nothing at all in the fee column. The question somebody asked of it months later was simple — did this customer pay the deposit themselves, or did the app send it for them?

The blank fee looks like the answer. It is not an answer, because it is produced by two different things.

One blank, two causes

A router that signs the sending transaction can take its cut as a second output on that transaction. One that hands over a deposit address and lets the customer pay from their own wallet cannot — there is no transaction of its own to take anything from.

So a blank fee means the customer paid by hand. It also means the fee was switched off for everybody, which is a setting, not a property of that exchange at all.

What the row showsWhat it could mean
A feeThe app signed and sent it, and took its share
No feeThe customer paid the address themselves
No feeThe fee was off at the time, for every exchange

Two rows of that table are the same row. A reader cannot tell them apart, and neither can anything computed from them.

Why the shortcut looked safe

It is not a careless design. At the time the record was written, every exchange that took no fee really had been paid by hand, because the fee was always on. The inference was sound for exactly as long as that stayed true.

That is the shape worth noticing. An inference from a side effect is usually correct when it is written — nobody writes one that is wrong on the day. It fails later, when the other cause appears, and it fails silently, because the record still contains a plausible value.

A second one, in the same ledger

The same records carried a status, and it was only ever written while somebody had the exchange open on screen. Close the tab and nothing further is heard.

So an absent status meant an exchange still in flight, or one that finished unobserved, or one nobody could ask about. Three states, one blank — and the one blank reads, to anybody scanning the column, as something that did not happen.

Of ten real exchanges, nine could not say which of them had been paid by hand. Not because the information was hard to obtain: at the moment each exchange was created, the app knew exactly which it was. It simply was not written down.

The rule

If you want to know something later, record it at the moment you know it. A value that can be derived from other values is only derivable while the derivation holds, and nothing warns you on the day it stops.

The counter-argument is real and worth stating: a field that duplicates something already implied is a field that can disagree with it. That is a genuine cost. It is smaller than the cost of a record that cannot answer the question it exists to answer — and the disagreement, when it happens, is at least visible.

What it fixes, and what it does not

Recording it from now on does nothing for what is already stored. The exchanges written before the field existed are not retroactively knowable; they show nothing, and nothing is the honest thing for them to show. A blank that means "not known" is a different blank from one that means "no fee", and separating those two was most of the repair.

Which is the quiet part of this kind of fix. The ledger does not get better. It gets honest about which of its rows it cannot speak for, and stops producing new ones it cannot speak for either.

Method

Drawn from this deployment's own exchange records on the date above — the real ones, with demo runs excluded. No customer details appear here: no ids, no addresses, no networks. What is kept and for how long is set out on the privacy page.

Plan an exchange

Every figure above can be checked against the providers yourself — no account, no sign-up, and nothing is held for you at any point.