Smart contract development
Written for the reviewer, not the demo.
Solidity built the way an independent firm wants to receive it: tests written beside the code, invariants documented as they are found, static analysis gating every commit. One public reference system on Base Sepolia, unaudited, and we say so.
N° 01The thesis
Contracts are written to be reviewed
Most contract projects are written for months and tested in the last two weeks. The suite that results covers the paths the author already believed in, the specification is assembled afterwards by reading the code, and the first two days of the audit are spent working out what the system was supposed to do. You pay for those two days at review rates.
We write it the other way around. Tests go in beside the code, so a function that is awkward to test gets restructured while restructuring is still cheap. Invariants are recorded as they are discovered rather than reconstructed at the end. Solhint and Slither run on every commit instead of the week before a deadline, which turns a static-analysis finding into a two-line correction rather than a refactor under time pressure.
What ships is more than contracts. Alongside the code go a written specification, a role and trust matrix, the invariant list mapped to the tests that exercise it, a threat model, the known issues stated plainly, and deployment and role-handover runbooks. We are not an audit firm and we do not sign anything off. The point of that package is that an independent reviewer can spend the engagement looking for bugs instead of reconstructing intent.
N° 02Testing
Unit tests check what you thought of
A unit test exercises a path the author had in mind. That is necessary and it is not enough, because the defects that matter in a contract system are rarely inside a single call. They live in an ordering: subscribe, transfer, claim, refund, with a pause somewhere in the middle and a role rotated halfway through.
Stateful fuzzing goes after the orderings nobody imagined. A handler drives random but legal sequences of calls against the deployed system, and after every step a set of properties is asserted — total supply equals the sum of balances, escrow always covers outstanding refunds, no holder can claim twice from one distribution. The reference build runs seven invariants as stateful campaigns at 256 random sequences each, alongside 131 tests at 98.3% line coverage and zero Slither findings at medium severity or above.
Then we check the check. Mutation testing means reintroducing a defect deliberately and confirming that the specific test which should catch it actually fails. An invariant that passes because it asserts nothing is worse than no invariant at all: it produces the number that goes in the report and none of the protection behind it. This is the cheapest step in the process and the one most often skipped.
N° 03How a fix is handled
Two of the eleven came from a fix
An adversarial review of our own reference build returned eleven defects. Two of them were never in the original code. They arrived in the patch for another finding, which means the review process caught a problem and the repair created two more.
That is the part a development process is usually not built for. A fix carries the authority of a solved problem: it touches code the reviewer has already read, it lands late when the schedule is tight, and it is merged with less scrutiny than the code it replaces. So a patch is read as adversarially as the original, checked against the same invariant list rather than only the assertion that failed, and put through the whole suite instead of the one test that went red.
Every defect then leaves a regression test behind, named for the failure rather than the function, so the same shape cannot return quietly three commits later. None of this makes the build audited. It is not, it sits on Base Sepolia rather than mainnet, and we say so wherever it appears. What the work does is shrink the set of problems a paid reviewer has to find for you, which is the only sensible thing to do with that budget.
N° 04Upgradeability
No proxy, which is a real trade
The reference build has no upgrade path. Once deployed, the bytecode is the bytecode. Studios that sell immutability as a virtue tend to skip the cost: a defect discovered after launch cannot be patched, it has to be fixed in a fresh deployment with every holder migrated across, and migration is a governance problem long before it is an engineering one.
The argument for it is that a proxy is a second system with its own failure modes. Storage layout becomes something a carelessly declared variable can corrupt, the initializer becomes something that can be front-run, and the upgrade key becomes the most valuable key in the project — an address that can swap the logic sitting underneath everyone's balances. For a token representing a regulated security, that asks holders to trust a key rather than code they can read.
Which side to take depends on what fails worse for you. A single offering with a fixed rule set is better off immutable and small. A platform issuing for years across regulation that will move should probably be upgradeable, and then it needs a timelock, a multisig, and a published upgrade procedure rather than a proxy owned by the deployer. We will tell you which we think fits and why. The decision is yours to make.
N° 05Decided at architecture time
Four choices made before the first test
01
Which chain the code assumes
Contracts port across EVM chains. The gas assumptions written into them do not. A pull-based claim that is rational on Base is irrational on Ethereum L1 once a position is small enough that the fee exceeds the payment, and by the time anyone measures that, the distribution design is load-bearing. So the chain is settled before the first contract rather than after the first testnet deploy.
02
What the code depends on
OpenZeppelin at a pinned version, unforked. A locally modified copy of a widely reviewed library is the worst case for a reader: it looks familiar, so it gets skimmed at the speed of familiar code, and the edit that matters is in the file nobody opened. Where behavior has to differ we extend rather than edit, so the difference is a small file that can be read on its own.
03
Whether to implement the standard
Our reference build is ERC-3643 shaped rather than ERC-3643 compliant, and we document the gap rather than gloss it — same three-way split of identity, rules and token with enforcement in the transfer hook, but issue and redeem in place of mint and burn, an eligibility check that returns a reason alongside the boolean, and no ONCHAINID layer. Implementing the standard exactly is a week-one decision because it fixes the interfaces every other contract is written against.
04
Where the keys sit
Privileged functions are split across four roles with deliberately different blast radii, so the key that can move one holding is not the key that can pause the system. Each role is also tested from the wrong address, because a permission nobody has tried to violate is a permission nobody has checked. Handover to your multisig is announced and waits three days rather than landing in a single transaction, since a role transfer that goes wrong in one step goes wrong permanently.
Investment
Fixed scope. No drift.
From $30,000 — a contract set, tested, documented, and ready for review.
- Contracts with tests written alongside the code
- Documented invariants with stateful fuzz campaigns
- Mutation testing on the documented invariants
- Solhint and Slither gating CI from the first commit
- Written specification and role and trust matrix
- Threat model, known-issues list and audit scope
- Testnet deployment with verified source
- Deployment and role-handover runbooks
- Fixed-scope proposal after technical discovery
- 30-day defect warranty
Questions
The answers we give most often.
- What coverage do you target?
- Above 95% line coverage on the contract layer; the reference build sits at 98.3% across 131 tests. That number is worth less than it looks. Coverage tells you a line executed, not that anything would have failed had the line been wrong — a test with no assertion covers code perfectly. So we report branch coverage next to it, keep a documented invariant list, and mutation-test the invariants themselves. If a studio is selling you a coverage percentage, ask what the assertions actually check.
- Do you write the tests, or do we?
- We do, and they are part of the build rather than a line item you can remove to save money. Contract tests are not a QA pass over finished work; they are how the design gets pressure-tested while changing it is still cheap. If your team wants to own the suite afterwards that works well: the handover includes the fuzzing handler and the property definitions, not just the assertions, so you can extend the campaigns rather than only the unit tests. What we will not do is write untested contracts at a discount.
- What happens if an audit finds something?
- We fix it, and the fix gets reviewed as hard as the code it repairs. Two of the eleven defects in our own reference build were introduced by a fix, so this is not a hypothetical. Findings at high or critical severity in code we wrote are remediated inside the warranty window at no charge. Findings that turn out to be a requirement that moved — a different exemption, a rule the counsel changed — are quoted as work, and we say which is which in writing with the firm's report as the reference.
- Do you build upgradeable contracts?
- When the project needs them, and we will argue the case with you first. Our default is immutable and small, because a smaller trust surface is easier to review and easier to hold. Where the rule set will genuinely change over years, a proxy is the right answer and it comes with a timelock, a multisig, and a written upgrade procedure. An upgrade key held by one deployer address is worse than no upgradeability, because it looks like safety while being a single point of total control.
- Which chains do you work on?
- EVM chains, with Base as the default for anything with per-holder claims. Ethereum L1 is fine where positions are large enough that gas per claim is noise, and worth the cost where the counterparty expects it. The contracts are portable across EVM chains; the gas assumptions built into them are not, which is why the choice is made before the architecture rather than after. Solana is a different language and a different account model — a rewrite rather than a port, and we will tell you to hire people who do that full time.
- Can you take over an existing codebase?
- Often, starting with a paid assessment of one to two weeks. We read the contracts, write the specification that should already exist, get the test suite running, and run static analysis to see what falls out. The output is a document saying what the system actually does, where we think it is wrong, and whether extending it costs less than replacing it. Sometimes the answer is replace, and we would rather say that in week two than in month four. The assessment stands on its own, and taking it to another team is a reasonable outcome.
Next step
Tests written after the code only prove the code does what it does.
Tell us what the contracts have to enforce, who will hold the privileged keys, and whether a review is already booked.
