Smart Contract Development: Design, Testing, Audits and Operations
How we design, test and operate Solidity contracts: upgradeability trade-offs, fuzzing and formal review, independent audits, multisig admin keys and incident response.
You need code that holds or moves value on a public blockchain: a token with a vesting schedule, an escrow, a vault, a marketplace, a treasury. Smart contract development differs from most software work in three ways. The code is public, attackers are rewarded with whatever it holds, and a deployed mistake may be impossible to patch. So most of the effort goes into design, testing and review, not into writing Solidity.
Good looks like this: a small contract with a written specification; invariants that are fuzzed and, where the stakes justify it, formally verified; at least one independent audit; admin powers that are few, documented and held by a multisig behind a timelock; and a rehearsed plan for the day something goes wrong.
What we build on-chain
- Tokens that follow established standards, such as ERC-20 for fungible tokens and ERC-721 or ERC-1155 for NFTs, with minting rules, vesting and distribution.
- Escrow and payment flows that release funds when agreed conditions are met.
- Vaults and staking contracts, following ERC-4626 where it fits, with reward accounting that survives rounding and edge cases.
- Marketplaces, auctions and royalty logic.
- Governance and treasury contracts: voting, timelocks and controlled spending.
- Smart accounts and modules for wallets that need spending limits, recovery or sponsored fees.
A contract is rarely the whole product. It needs an indexer, a backend, admin tools and an interface people can use, which we cover in blockchain development, and usually a wallet, the subject of crypto wallet development. If you are launching a token, cryptocurrency development covers the wider picture around it.
Choosing a chain and a language
We default to Solidity on the EVM, meaning Ethereum, its layer-2 rollups and other EVM-compatible networks. The EVM has the most mature tooling, well-reviewed libraries such as OpenZeppelin Contracts, the broadest wallet support and the largest pool of independent auditors. Vyper is a reasonable alternative for teams that value its deliberately smaller language.
Other chains fit other needs. Solana suits high-frequency, low-value activity, but its Rust programs use a different account model, in which missing account validation is a classic bug. Move-based chains build asset safety into the type system, with smaller ecosystems around them. App-specific chains make sense when you need your own fee model or validator set, and they bring real operational work. Choose the chain where your users, assets and liquidity already are, not the one with the best headline throughput.
Sometimes the honest answer is no chain at all. If every participant already trusts one operator, if the data must stay private, or if transactions must be reversible, a conventional backend with an audit log is simpler, cheaper and easier to change.
Upgradeability or immutability
This is the first real design decision, and no option is free.

- Immutable contracts give users the strongest guarantee: the rules cannot change. A bug is permanent, and fixing it means deploying a new contract and migrating users and funds.
- Upgradeable proxies, in transparent, UUPS or beacon form, let you fix bugs and add features. The upgrade authority becomes a trust assumption and an attack target, and storage layout needs discipline: append-only variables or namespaced storage, initializers instead of constructors, locked initializers on implementation contracts, and automated layout checks before every upgrade.
- Middle paths often serve best: an immutable core with parameters adjustable only within hard-coded bounds, replaceable peripheral modules, or upgradeability behind a timelock with a plan to remove it once the system has matured.
Pausing is a useful circuit breaker, but a pause key is also power over users’ funds, so it deserves the same governance as an upgrade key.
Testing, fuzzing and formal review
Work starts with a written specification and a list of invariants: total shares equal the sum of all balances, no account can withdraw more than it deposited plus earned rewards, only the timelock can change fees. Testing then comes in layers:

- Unit and integration tests in Foundry or Hardhat, covering every function, revert path and role.
- Fork tests that run against real deployed contracts, such as oracles and exchanges, using live chain state.
- Fuzzing and invariant testing with Foundry, Echidna or Medusa, which throw long random sequences of calls at the system and check that the invariants still hold.
- Static analysis with tools such as Slither on every commit, and mutation testing to confirm that the tests actually catch deliberately injected bugs.
- Formal verification or symbolic testing, with tools such as the Certora Prover, Halmos or the Solidity compiler’s SMTChecker, for the few properties where a counterexample would be catastrophic.
Code review targets the known bug classes: reentrancy, broken access control, oracle and price manipulation, rounding errors, signature replay, front-running exposure, unsafe external calls and loops that grow without bound. We build on audited libraries instead of reimplementing standards, and follow patterns such as checks-effects-interactions by default.
Independent audits and gas optimization
We write and test contracts; independent firms audit them. Reviewing your own code is necessary, but it is not an audit. We prepare the handoff carefully, with a frozen commit, the specification, documentation, the test suite and a list of known risks, because auditors who understand the system find deeper issues.
For contracts that will hold significant value, we recommend a second independent audit or a public audit contest after the first audit. The auditors review the fixes, the reports get published, and a bug bounty runs after launch. An audit lowers risk; it does not certify safety.
Gas optimization comes after correctness. Storage writes dominate costs, so we pack variables, use constants and immutables, prefer calldata for external inputs, use custom errors, emit events for data needed only off-chain and avoid loops that grow with the number of users. On rollups, fees include a share of the cost of publishing data to the base layer, so compact calldata can matter as much as execution. Gas snapshots in continuous integration catch regressions. We do not trade clarity for small savings in security-critical code, and inline assembly needs a strong reason and extra review.
Admin keys, multisig and incident response
Every privileged role, whether it upgrades, pauses, mints, sets parameters or withdraws fees, is a way to lose funds. We keep the list short, split roles so no single key can do everything, and never leave a role on a single externally owned account. Privileged roles sit with a multisig such as Safe, whose signers use hardware wallets held by different people in different places, with a threshold that survives a lost key and resists one compromised signer.
Upgrades and parameter changes pass through a timelock, so users can see changes coming and exit if they disagree. Signers verify what they sign independently of the web interface, because compromised interfaces have tricked multisig signers into approving malicious transactions. Key ceremonies and signer duties are documented.
Incident response is prepared before launch:
- Monitoring that alerts on admin calls, large outflows, oracle deviations and unusual call patterns.
- A runbook stating who can pause, how quickly and with which keys.
- A communication plan for users and partners.
- Contacts at security response groups, exchanges and stablecoin issuers, which can sometimes freeze stolen funds.
- A post-mortem and a remediation plan once the incident is contained.
We rehearse the runbook on a testnet, because the first time you use it should not be during a real incident.
How a smart contract development engagement works
We start with the specification and a threat model, written with your team by a business analyst and the engineers who will build the contracts. Implementation proceeds in short iterations with tests written alongside the code, followed by internal review, testnet deployment and integration with the frontend and backend.
The external audit comes next, then fixes and re-review, then a scripted mainnet deployment with verified source code and monitoring switched on. You receive the repository, specification, test and fuzzing suites, deployment scripts, runbooks and audit reports, with regular demos and written progress reports throughout.
Frequently asked questions
Can you audit our existing contracts?
We can review them, fix what we find and prepare them for audit. The audit itself should come from an independent firm that did not write or fix the code, and we will help you scope it.
Should our contracts be upgradeable?
If the logic is simple and well tested, immutability is a strong promise to users. If the system is complex or young, a timelocked upgrade path controlled by a multisig is usually wiser, with a plan to reduce that power over time.
Which chain should we deploy on?
The one where your users, assets and partners already are. For many products that means Ethereum or one of its layer-2 networks, and we recommend other chains when their trade-offs genuinely suit the product.
What happens if a bug is found after deployment?
The runbook takes over: assess, pause if the design allows it, fix through an upgrade or a migration, and communicate clearly. How much you can do depends on design decisions made long before launch, which is why we make them deliberately.
When should we book an audit?
Early. Reputable auditors are often booked well in advance, so we recommend reserving a slot as soon as the scope is clear and planning the code freeze around it.
If you are planning a contract that will hold real value, involve the people who will test and operate it from the first design conversation. Tell us about your product, and we will tell you how we would build it, and whether it needs a blockchain at all.