The best smart contracts are boring. That is not a stylistic preference — it is the whole methodology.
Every line of custom logic is a line nobody outside your team has reviewed, running in public, holding value, immutable once deployed. The objective is to write as few of those lines as possible.
Start from audited standards
OpenZeppelin’s implementations of ERC-20, ERC-721, ERC-1155, access control and upgradeability patterns have been reviewed, attacked and used more times than anything you could write from scratch.
Using them is not laziness. It is the single highest-leverage security decision available, because it moves the majority of your code into territory that thousands of engineers have already examined.
Custom code earns its place where your logic genuinely differs — distribution rules, transfer restrictions, the settlement mechanics specific to your protocol. Those parts get the full review attention precisely because everything around them is already proven.
Minimal surface
Every feature is attack surface. Every admin function is a key that can be compromised. Every upgrade path is a mechanism someone could hijack.
Practical consequences:
- Immutable where possible. Upgradeability is a liability as well as a convenience, and it should be a deliberate decision rather than a default.
- No unused functions. Code that exists gets called eventually.
- Explicit access control on every state-changing function, with no exceptions.
- Fewest possible external calls, each one treated as hostile.
Testing that means something
Unit tests confirm the happy path and are the least interesting part.
Fuzz tests throw random inputs at functions looking for states you did not consider. They find real bugs consistently.
Invariant tests assert properties that must always hold — total supply equals the sum of balances, no user can withdraw more than deposited — and then try very hard to break them. This is where protocol-level logic errors surface.
Fork tests run against real mainnet state with real integrations, catching assumptions about external protocols that are wrong in production and correct in a clean local environment.
The gap between a project with thorough invariant testing and one with only unit tests is enormous and invisible from the outside.
The recurring failure modes
The textbook categories — reentrancy, access control mistakes, arithmetic edge cases — are largely solved by standards and modern compiler behaviour.
The losses that actually happen are protocol logic errors: an oracle that can be manipulated within a single block, a liquidation path that behaves pathologically under extreme prices, an incentive that can be gamed by someone who reads the code more carefully than the team did.
These do not appear on vulnerability checklists because they are specific to what you built. They are found by people who think adversarially about your particular design, which is exactly what a good audit buys.
Audits: who, how many, and who pays for remediation
Two independent third-party firms is the baseline for anything holding meaningful value. Two, because different firms find different things, and the overlap is smaller than you would expect.
Formal verification on top for components where a bug is unrecoverable — settlement invariants, supply logic on a stablecoin, liquidation maths.
We coordinate the firms; we do not audit our own code. A development company auditing its own work is a conflict of interest presented as a service.
Budget and schedule for remediation and re-review. Finding issues is the fast half.
Deployment discipline
Verify source on the block explorer immediately. Deploy from a multisig or MPC-controlled address, never a single hot key. Rehearse on a testnet fork with the exact deployment script you will use.
Have a bug bounty live before meaningful value arrives, and monitoring that alerts on the behaviour you would want to know about within minutes rather than hours.
Immutable means immutable. Everything expensive to get wrong has to be right the first time, which is the entire argument for boring code.
Common questions
What makes a smart contract secure?
Minimal custom code built on audited standards, comprehensive testing including fuzzing and invariant tests, independent third-party review, and a deliberate absence of cleverness. The contracts that hold value safely are usually boring. Every line of custom logic is a line that has never been reviewed by anyone outside your team, which is why the smallest custom surface that does the job is the safest one.
How many audits does a smart contract need?
Two independent third-party audits is the standard baseline for anything holding meaningful value, plus formal verification on components where a bug is unrecoverable. Budget for remediation as well as the audits themselves - finding issues is the straightforward half, and fixing them properly then getting the fix re-reviewed is where the time goes.
What are the most common smart contract vulnerabilities?
Reentrancy, access control errors, arithmetic assumptions that break at the edges, oracle manipulation, and unchecked external calls. Most are well-understood and avoided entirely by building on audited standard implementations rather than writing your own. The vulnerabilities that cause the largest losses tend to be logic errors specific to the protocol rather than the textbook categories.
Should you use OpenZeppelin or write custom contracts?
Start from OpenZeppelin or an equivalent audited standard wherever one fits, and write custom code only where your logic genuinely differs. Those implementations have been reviewed more times than anything a single team could match. Custom earns its place in the parts that are actually yours - distribution rules, transfer restrictions, settlement logic - sitting on proven foundations.
Does Corum8 write smart contracts?
Yes, in Solidity, Rust and Move. We build minimal contracts on audited standards, write unit fuzz and invariant tests, coordinate two independent third-party audits, handle remediation and re-review, and deploy with verification. We do not audit our own code - that is a conflict of interest.