Almost every interface convention you use was designed for software that knew what had happened.
A form submits. A spinner turns. A checkmark appears. The checkmark means done, and it has meant done for thirty years, which is why users stopped reading the words next to it a long time ago.
Then we started shipping systems where the result is not known at the moment the screen updates, and kept the checkmark.
Two Kinds of Uncertainty, One Failure
They are worth separating, because they break differently.
The answer may be wrong. A model produces plausible output with no inherent guarantee of correctness. The system has an answer. Whether it is true is a different question that the system often cannot settle.
The operation may not have happened yet. Distributed settlement produces outcomes that are provisional for a while. Accepted, then included, then confirmed, then eventually final. The early states can still unwind.
One is a correctness problem and the other is a timing problem. They converge on the same interface failure: the screen asserts something definite about a state that is not yet definite, and the user acts on the assertion.
The damage compounds. Users calibrate on the interface, not on the architecture diagram. Show a reliable looking checkmark often enough and people stop verifying, precisely as you move them onto a system where verifying matters.
The States Your Interface Is Probably Missing
On Ethereum, blocks arrive roughly every twelve seconds. A transaction in a block has one confirmation, and each subsequent block adds another. Finality is something else entirely: validators vote on checkpoints at epoch boundaries, an epoch being thirty two slots or about six and a half minutes, and finalisation normally lands around two epochs later, in the region of thirteen minutes.
Between inclusion and finality the transaction is real but not settled. Single block reorganisations do happen when a proposer publishes late. Under unusual conditions the chain can keep producing blocks while failing to finalise them at all, which has occurred briefly on mainnet.
Most dApp interfaces compress all of that into two states: pending, then success. The states that actually matter are missing:
Submitted but not included. The transaction is in the mempool. It may sit there. It may be replaced. It may never land.
Included but not settled. Real, visible on a block explorer, and still capable of unwinding.
Failed after acceptance. The transaction was accepted, executed, and reverted. Gas was consumed. Nothing happened. This state is almost never designed and it is the one that generates support tickets.
For each, the interface should answer one question in plain language: what may the user do now? Finality matters because it gates action. If someone should not ship goods, release a document or treat funds as received until settlement, say so at the point of the decision, not in the docs.
Show the Basis, Not a Score
On the probabilistic side, the common pattern is an answer with no visible provenance, which leaves the user judging it by how reasonable it sounds. Fluency is not correlated with correctness, so that is not a judgement at all.
Showing the source material beats showing a confidence number, for a simple reason: a source can be checked and a number cannot. A reviewer shown the actual passage can assess whether it supports the claim. A reviewer shown “87 percent confident” has been handed something that looks quantitative, is hard to calibrate, and gets read as an endorsement.
And put it at the point of action. If the output feeds a button, the basis for that output belongs on the same surface as the button, not one navigation step away.
Signing Is Where UX Becomes Security
This is the part of nondeterministic UX that is not really a UX problem.
Any surface asking a user to approve a transaction should show what is actually being authorised in terms they can evaluate. A large share of loss in this space has come from users approving payloads that their wallet displayed accurately and that meant nothing to the reader. Blind signing is a design failure before it is a user error.
Two things follow. Keys stay scoped and under threshold approval, so that a single bad approval has a bounded blast radius rather than an unbounded one. And the control itself lives in the contract, not the client: a disabled button is a suggestion, and eligibility and transfer restrictions belong to be enforced at transfer time, under something like ERC-3643 with KYC and AML checks wired into identity. The interface can make a control legible. It cannot be the control.
That contract logic goes through independent audit before it holds value, with time budgeted to fix findings rather than acknowledge them. Interface polish on top of unaudited logic is decoration.
When Blockchain Is the Wrong Tool Here
We build these systems, so take this section as the one written against our own interest.
A great many “blockchain UX problems” are not UX problems. They are the visible symptom of an architecture chosen without a reason that required it.
Settlement uncertainty is a genuine cost. It costs design effort, support load, user comprehension, and conversion. That cost is worth paying when something actually requires a shared ledger: multiple organisations writing to one record, no neutral party available to hold it, real disputes about history. Absent that, you have bought a hard UX problem and received nothing for it.
Before designing the pending states, it is worth asking whether they need to exist. A conventional database with signed audit logging gives you tamper evidence, settles instantly, has no reorganisation semantics to explain, and lets you keep the checkmark honest. For a large share of requirements, that is the better product.
If the answer comes back that a ledger genuinely is required, design the states properly. If it does not, you have just removed the problem rather than solved it.
The Honest Alternative: Hide It
For many products, the best interface for nondeterminism is one that does not expose it.
Wait for settlement server side and show success when it is actually true. Run the probabilistic step in the background and surface only verified results. Use an intermediated model where that suits the users and your regulatory position.
Each of these removes a class of UX problem by removing the user’s exposure to the uncertainty. The trade is real: latency, some transparency, and in custodial arrangements a materially different trust model. Neither choice is automatically correct.
What is not defensible is the middle position most products reach by accident, which is exposing the user to uncertainty while presenting an interface that denies it exists.
Scope the Unhappy Paths Before They Get Cut
In deterministic software, error handling is an edge case. In nondeterministic software, it is normal operation, and the recovery path carries real traffic.
It is also the first thing cut when a scope conversation gets tight, because it looks like polish. It is not polish. Three questions, answered during design rather than after launch:
How does a user discover something was wrong, given it will usually look fine? How do they correct it without involving support? And what happens to anything downstream that already consumed the incorrect result?
That third one is deferred most often and costs most to answer late. A correction that cannot propagate is not a correction.
Whatever you build, keep the parts that outlast the model and the chain: the state machine, the copy, the recovery flows, the deterministic controls, the keys. Those are the system. If they live with a vendor, your ability to change either layer leaves when they do.
RWaltz is a technology partner building blockchain, AI, and enterprise software, including smart contracts, tokenization platforms, and custom integrations. Our approach is security-first and build-to-own: honest scoping, independent audits, and client-owned IP and keys, so what we deliver belongs to you.
📖 Read the full blog: https://www.rwaltz.com/blogs/designing-ux-for-nondeterministic-software
Connect with RWaltz:
LinkedIn: https://www.linkedin.com/company/rwaltzsoftware
X (Twitter): https://twitter.com/rwaltzsoftware
Facebook: https://www.facebook.com/RWaltz-Software-PvtLtd-255590135349493
Telegram: https://t.me/RWaltzCrypto
GitHub: https://github.com/rwaltzsoftware
Clutch: https://clutch.co/profile/rwaltz-software
Website: https://www.rwaltz.com
Top comments (0)