CRYPTO TRAIN
v0.115.10

Writing

An absence and a refusal

2 October 2026 · figures measured 2 October 2026

Ask eight swap providers about an order that was never created. All eight say no. Seven of them are saying the same thing — we have never heard of that order — and one is saying something else entirely.

Telling those two apart is not a nicety. It is the difference between a lookup that works and happens to find nothing, and a lookup that has never worked at all.

The same question, eight times

One made-up order id, put to every provider through the same code path, in one pass:

ProviderWhat came back
GhostSwap404 swap not found
SideShift404 Order not found / NOT_FOUND
ChangellyTransaction not found
ChangeNOW404 Not Found
SimpleSwap404 Exchange not found
StealthEX404 NotFound: Exchange not found
PegasusSwap404 Transaction not found
FixedFloatIncorrect data

Seven of those name the order as the thing that is missing. The eighth does not mention the order at all. It is a complaint about the request.

Why the last row is a different answer

That provider's order lookup takes two things: the order id, and a token it hands back once, at the moment the order is created. The token is not a convenience. Without it the request is incomplete, and an incomplete request is refused before anything is looked up.

So the reply is the same whether the order exists or not. A real order with no token and an imaginary order with no token produce identical answers, which means that answer carries no information about the order whatsoever.

What a wrapper does to this

Most integration code catches a failed lookup and throws something tidy — status check failed, could not fetch, unavailable. One sentence, every cause. It reads well in a log and it destroys the only distinction that matters here.

Flattened that way, the table above becomes eight identical lines. A provider that is working correctly and an endpoint that can never succeed look the same, and nothing in the system is in a position to notice. The fix is unglamorous: report what the provider said, including its status code, and keep the wording it chose.

It costs three lines and it is the difference between a diagnosis and a shrug.

The same shape, one level up

A browser polling for a status has the identical problem in a different costume. The usual pattern updates the screen when a response arrives and looks healthy, and does nothing otherwise. A refusal is a response — it arrives, it parses, it simply is not a success — so it satisfies neither the update branch nor the error branch.

The result is a page that shows the stage an exchange started at and never moves, with no error anywhere, for as long as somebody watches it. Nothing is broken on screen. Nothing is reported. The exchange just appears to be taking a very long time.

Why this is a swap problem in particular

A router that prices eight providers speaks eight dialects of the same few ideas. They disagree about status codes, about whether an error belongs in the body or the HTTP line, about whether a missing thing is a 404 or a 200 carrying a code. Every one of those mappings was learned from a refusal rather than from documentation.

That is survivable while the differences are cosmetic. It stops being survivable the moment one provider's refusal means something structurally different from the other seven, because by then the code has usually decided that all refusals are the same thing.

Method

One order id that no provider could have issued was put to each provider's own status endpoint through the same server-side path a real lookup uses, in a single pass, on the date above. The wording in the table is theirs, trimmed only where a message ran past the column. No order was created and nothing was sent to any chain.

The refusals providers give when a transfer is too small are a separate catalogue, with its own variety: eight ways to say no covers those.

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.