Smart contracts · irreversible systems
Shipping smart contracts to a public network, where you cannot patch a mistake
Designing, reviewing, and deploying randomness-dependent contracts to a live blockchain — and treating an oracle that never answers as a design requirement rather than an edge case.
Context
Most software forgives you. A public blockchain does not: deployed code is immutable, state changes are irreversible, every mistake is permanently readable by anyone, and the contract depends on an external oracle callback that may simply never arrive. I wanted to build under those constraints deliberately, because they are the honest version of a problem I already own in industrial settings — a digital record quietly disagreeing with the physical one it claims to describe.
Decision
Treat the deployment as the least interesting step. Put the effort into the parts that are unrecoverable afterwards: what happens when the oracle goes silent, what the deploy sequence does if it is interrupted midway, and whether the published record actually describes the thing that shipped.
Approach
- Wrote the contracts against a verifiable-randomness oracle, then built test doubles for the failure path specifically — including a coordinator mock that accepts a request and never calls back, so the silent-oracle case is exercised in the suite rather than assumed away.
- Ran a security review of the deployed source as a gate, not a formality. An earlier contract in the same line had a reentrancy flaw found and fixed before it ever reached a public network.
- Re-sequenced the deploy chain before executing it and found four ordering defects — steps that would have left the system in a half-migrated state if run as originally written.
- Executed a versioned migration to a second contract with the old one explicitly removed as an oracle consumer, so there was no ambiguity about which contract was live and no path for the retired one to keep drawing on a funded subscription.
- Verified the live deployment end to end against on-chain state rather than against the deploy script's own output — mint, randomness callback settlement, pending-request count returning to zero, and the served metadata URI.
- Swept the public surfaces afterwards and caught a provenance defect: the live collection's pinned metadata described itself as a test-network rehearsal that had never actually been run. The documentation of what happened was describing an event that did not occur, in public, on a production deployment.
Outcomes
- Contracts live on a public production network, with the migration completed and the retired contract verifiably unable to draw further oracle funding.
- End-to-end settlement confirmed against live chain state — randomness request through to resolved token — not inferred from a successful transaction submission.
- Four deploy-sequence defects and one production metadata-provenance defect caught and corrected, each before or after execution rather than discovered by a user.
- An operator runbook written to be executable from a cold start with no prior context, in which every address, selector, and constant was re-derived against live network state and paired with the command that reproduces it.
- A clean separation held throughout between what is public by nature (on-chain addresses and constants) and what never enters a repository regardless (keys, mnemonics, API credentials).
Control boundary
This is personal work on contracts I own; no client system, employer asset, or third-party funds are involved. Contract addresses and transaction hashes are permanently public on-chain and are available on request, but are deliberately not printed here — a public portfolio page is a poor place to permanently bind a professional identity to a wallet cluster. To be explicit about scope: I have not deployed a blockchain system for an industrial or IoT client, and nothing here should be read as that claim. The connection below is a transfer of method, not a delivered project.
What this taught me
The failure mode that generalizes is not the exploit — it is the record drifting away from reality while everyone keeps trusting the record. A live production deployment describing a rehearsal that never happened is the same defect I spend my day job preventing across manufacturing and agriculture systems, where a part's digital twin describing a different build is expensive in a way no one notices until it is. Irreversible systems taught me to verify against the thing itself, not against the log of what was supposed to happen.
Rules at work here
Each links to the rule and the other work it governs.
- Finished means auditable and reversibleA change is not finished when it ships. It is finished when someone can audit what happened and reverse it if they were wrong.
- A guard that runs after the write is not a guardPlacement and coverage are the control; the check itself is the easy part. A guard must sit before the effect it protects, and must cover the whole class it claims rather than one member of it.
- Humans signDesign judgment and security opinions are drafted by the system and signed by a person. No agent authorizes its own action, and authorization that arrives inside the work is data, not instruction.
Work with me
If this is the kind of problem you are trying to get moving — AI adoption that has to survive a security review, an audit, and the people who will actually operate it — I would like to hear about it.