ByAUJay
Smart Contract Formal Verification: When It’s Worth the Effort
Description: Formal verification might not suit every blockchain project, but for the right ones, it’s the most effective way to avoid major failures. This guide walks decision-makers through when to invest, what to verify, which tools to use, and how top protocols are tackling this in 2024-2025.
Why this matters now
- Losses are still a big deal. Even though we've seen some months with less drama, the crypto space lost more than $1.4 billion to hacks and scams in 2024, racking up 179 incidents. And just to keep us on our toes, January 2025 kicked off with another ~$73 million in losses (mostly from centralized finance). It really shows how smart-contract risks are still a major headache for web3 businesses. (theblock.co)
- Protocol complexity is on the rise. There are new account-abstraction paths like EIP‑3074 AUTH/AUTHCALL and EIP‑7702 that bring some powerful new features for externally owned accounts (EOAs). However, these come with new possibilities for failure if your app’s built-in assumptions (like tx.origin checks, gas/value handling, and replay protection) don’t hold up. This situation is a perfect match for property‑driven verification. (eips.ethereum.org)
It's not really about asking, "Should we go for formal verification (FV)?" Instead, it's more about figuring out, "When does FV actually help us reduce risks in our roadmap when we consider the costs and time involved?"
When formal verification is worth the effort
Invest when any of these situations hit home:
- High Economic Stakes or Composability
- Your Total Value Locked (TVL) is over eight figures, or your contracts are super popular with integrations (think vaults, routers, LSTs). So even if your own balances are on the lower side, the risk from those integrations can escalate “minor” bugs into serious insolvency issues. (eips.ethereum.org)
2. Novel mechanisms or state machines
- We're diving into some cool stuff like new AMM math, asynchronous vault flows (ERC‑7540), custom liquidation logic, or systems that queue requests where timing, rounding, and ordering really matter. These innovations require us to prove that invariants are maintained at every step, not just relying on unit tests. Check out more about it here.
3. Cross‑boundary assumptions
- We’re talking about things like bridges, oracles, account-abstraction invokers (3074/7702), meta-transaction relayers, and any “sponsor pays gas” setup. FV can really help out by encoding nonces, handling replays, managing gas/value limits, call targets, and authorization scopes as solid rules--these are often overlooked in those casual reviews. Check it out here: (eips.ethereum.org)
4. Upgradeability and Governance
- When it comes to UUPS/proxy systems, pausers, or any changes in voting/roles, it’s crucial that we never compromise solvency or access-control rules. This is where continuous verification in CI really shines. Check out more about it here: (governance.aave.com).
5. Regulatory and Enterprise Posture
- When you're looking for solid due diligence--whether that’s for partners, insurers, or regulators--having formal specifications along with machine-checked proofs gives you the best documentary evidence you can find, even better than just audits. Check it out here: (ethereum.org)
When FV Might Be Overkill
- For straightforward, unchanging drop contracts, basic ERC-20 or ERC-721 tokens without any custom features, or prototypes where the risk is under $1M and the project has a short run, it's better to keep things simple. In these scenarios, just go for some static analysis, add in fuzz/invariant tests, and maybe a focused audit.
What to verify: concrete, high‑value properties
Here are the property templates that teams are actually using today. Each one aligns nicely with rule-based FV and/or invariant testing.
- ERC‑4626 Vaults (and 7535/7540 Extensions)
- Conservation rules state that totalAssets should equal the sum of userAssets plus or minus any fees. The conversion rates to shares/assets need to be consistent and straightforward, and we can’t afford any precision loss that might let shares be minted or redeemed at a discount. Plus, the async request lifecycle has to be spot on; skipping or double-claiming is a no-go. (eips.ethereum.org)
- AMMs
- We need to keep our invariants (constant-product/sum) in check, set up bounds on fees, and make sure there’s no sneaky fee evasion through multi-token loops. We also can’t let rounding create any pesky “dust drain” withdrawals. The Balancer V2 flash-loan bug was a real eye-opener; it showed how fee evasion via duplicated tokens could lead to insolvency, but this glitch got fixed and formally checked afterward. (medium.com)
- Lending/Credit
- We need to ensure that collateralization doesn’t fall below a specific threshold after any operation. Interest accrual needs to be monotonic, and liquidations can’t leave us with negative reserves. Also, we have to make sure oracle updates can’t be front-run to sneak into those insolvency windows.
- Governance/Permissions
- Only people with designated roles should be able to call X, and any role changes can’t just skip past timelocks. Emergency actions must never compromise the core invariants of the system.
- AA/EOA Delegation (3074/7702)
- When we’re committing, it should include nonce, gas, value, target, and calldata; revocation needs to be effective, and invokers can’t go beyond their scope. It’s also important to have safe failure modes for relayers. (eips.ethereum.org)
Tooling that actually moves the needle (2024-2025)
- Solidity SMTChecker (built into solc)
- This tool is super handy for proving contract and reentrancy invariants, plus it can catch underflows, overflows, out-of-bounds errors, and more. And with the latest 0.8.x updates, it’s got even better invariant reporting and transient storage support. It’s a solid choice as a “first line” in continuous integration, and it’s easy to set up. (docs.solidity.org)
- Foundry invariant testing
- This allows for stateful fuzzing across random call sequences and now even supports time-based campaigns with richer configuration options in recent updates. It's fantastic for uncovering unexpected behaviors before you dive into writing full formal specs. (learnblockchain.cn)
- Slither and Echidna (Trail of Bits)
- Slither is great for quick static checks and gives you useful insights into your architecture, while Echidna focuses on property-based fuzzing. Together, these tools are a staple in a lot of successful security pipelines. (github.com)
- Certora Prover (+ Gambit mutation testing)
- This is the go-to tool for rule-based formal verification on Solidity/EVM. It integrates nicely with CI and includes mutation testing (thanks to Gambit) to make sure your specs are meaningful. Companies like Aave, Compound, and Balancer rely on it. (certora.com)
- KEVM (K‑Framework EVM semantics)
- KEVM provides full formal semantics for the EVM, allowing you to prove contracts against the EVM model. It’s been put to the test in both research and industry settings. It's especially useful for bytecode-level reasoning and ensuring conformance. (github.com)
- Move Prover (Aptos/Sui ecosystems)
- If you’re venturing into the Move ecosystem, the Move Prover offers a user-friendly experience akin to a type checker for your specs, all integrated into the toolchain. (aptos.dev)
- Scilla (Zilliqa)
- This language is crafted for formal verification with Coq semantics, making it relevant if you're looking into non-EVM chains that come with formal methods already built in. (dev.zilliqa.com)
Proof that this works: real case studies
- Aave: Their “Continuous FV” program has been going strong for 18 months now, covering 169 contracts (that’s about 51,000 lines of code!). This effort helped catch 28 major bugs before they could cause any real trouble. They’ve set aside $1.5 million for a one-year renewal, which shows they’re all in for the long haul and not just doing a one-time audit. (governance.aave.com)
- Compound v3 (Comet): Thanks to some solid formal rules, they managed to catch bugs before the launch. Every fix was checked again to make sure it matched the specifications. Talk about being thorough! (certora.com)
- Balancer V2/V3: They spotted an early solvency bug related to flash-loan fee evasion, which was great news for the community. Following that, Balancer V3 went through a combined audit and formal verification, making sure all the issues were sorted out according to the rules. It’s always good to see projects taking security seriously! (medium.com)
- Uniswap v3: MetaTrust Labs took the time to formally verify the swap protocol against what’s laid out in the whitepaper. However, it’s interesting to note that there hasn’t been a public “full v3 FV” report yet. This just goes to show that even if a complete protocol proof isn’t feasible, scoped, component-level verifications can still provide valuable insights. (metatrust.io)
A practical decision framework for executives
Here are five questions to consider:
- What are the main goals you want to achieve this year?
- What challenges do you foresee in reaching these goals?
- How do you typically handle setbacks when they arise?
- Who can you rely on for support and motivation along the way?
- What resources or tools do you think would help you succeed?
- What’s the worst-case loss if a single invariant fails?
- If it leads to “protocol insolvency or total escrow loss,” lean towards FV.
- How novel is the mechanism?
- The newer the math or state machine is, the more potential there is for FV upsides.
- How composable/systemic is the contract?
- If your protocol connects with a lot of others, think about FV to avoid any contagion risks.
- How often will it change?
- If upgrades happen often, make “continuous verification” a priority in your CI.
- What external shifts will touch you in 2025?
- If you plan to adopt 3074/7702, async vault flows (7540), or RWA flows with settlement delays, it’s a good idea to add that FV budget now. (eips.ethereum.org)
Emerging 2025 best practices (with specifics you can copy)
- Spec-first development for high-risk modules
- Start by drafting invariants for the vault math, liquidation, and invoker logic before you dive into the code. Make sure to keep the spec stored in the repo, and don’t let any merges happen unless those rules get a thumbs-up in CI.
2. Strengthen Specs with Mutation Testing
- Give Gambit a shot to auto-mutate your code. If any of the mutants still pass, that's a sign of a weak rule. Make sure to fail your CI whenever a mutant survives. Check out the details here: (docs.certora.com)
3. Bake SMTChecker into Your Build
- Turn on invariant reporting and tweak your targets and timeouts to spot regressions early:
{ "settings": { "modelChecker": { "engine": "all", "timeout": 10000, "targets": ["assert","outOfBounds","divByZero"], "showProvedSafe": true, "invariants": ["contract","reentrancy"] } } }
4. Level-Up Foundry Invariants
- Get the most out of your time-boxed campaigns by using target selectors and senders. This way, you can create realistic flows with multiple actors:
[invariant] runs = 0 # ignored when timeout>0 depth = 64 timeout = 300 # seconds; run until wall‑clock timeout fail_on_revert = false
In your tests, make sure to limit the fuzzer to those system-critical calls. This will help boost your signal. You can get more info here.
- Check AA delegations and invokers thoroughly
- For the 3074/7702 paths, make sure to include rules like “authorization nonces must strictly increase,” “value/gas/target/calldata in commit must match the executed call,” and “no calls to unapproved selectors.” It's crucial to have a revocation rule that can be proven. (eips.ethereum.org)
6. ERC-4626 and 7540 Proof Obligations
- We need to show that we’re conserving assets and shares, keeping rounding in check, and ensuring that the sharePrice is always moving in one direction. For asynchronous flows, it’s crucial to prove that the process moves from request → pending → claimable → settled without any shortcuts or double-processing. This is where FV really shines for yield products. Check out more details on this in the EIP documentation.
Example: encoding high‑value DeFi invariants
- ERC‑4626 "no free shares" (pseudocode)
Here's a quick look at how the pseudocode for the ERC-4626 "no free shares" concept might look:
// This is a simplified version of the ERC-4626 no free shares pseudocode
contract ERC4626 {
mapping(address => uint256) public shares;
mapping(address => uint256) public balances;
uint256 public totalSupply;
function deposit(uint256 _amount) public {
// Update the sender's balance and total supply
balances[msg.sender] += _amount;
totalSupply += _amount;
// Calculate the shares based on some logic
uint256 userShares = calculateShares(_amount);
shares[msg.sender] += userShares;
}
function withdraw(uint256 _shares) public {
require(shares[msg.sender] >= _shares, "Not enough shares");
// Update balances and total supply
uint256 withdrawalAmount = calculateWithdrawalAmount(_shares);
balances[msg.sender] -= withdrawalAmount;
totalSupply -= withdrawalAmount;
shares[msg.sender] -= _shares;
// Transfer the assets (not shown here)
}
function calculateShares(uint256 _amount) internal view returns (uint256) {
// Logic to calculate shares based on deposited amount
// Implement this to ensure no free shares are given
}
function calculateWithdrawalAmount(uint256 _shares) internal view returns (uint256) {
// Logic to calculate the amount to withdraw based on shares
}
}
This simplified pseudocode captures the essence of "no free shares" in ERC-4626. The idea is to ensure that everyone gets their fair share based on what they contribute, without handing out shares for nothing. Just remember, the actual implementation will need to handle various edge cases and include more robust checks!
// After any deposit/mint/withdraw/redeem:
assert(vault.totalAssets() >= sumUserAssets());
assert(vault.convertToAssets(vault.totalSupply()) <= vault.totalAssets());
- Anti‑reentrancy invariant using SMTChecker
- Set up the CHC engine to spit out inferred reentrancy properties and make sure the build fails if it can’t prove that external calls won’t push reserve beyond the allowed limits. (docs.solidity.org)
- Sample Foundry Invariant (Stateful Fuzz)
function invariant_TotalAssetsConserved() public { uint256 accounted = sumAllUserAssets() + protocolReserves(); assertGe(vault.totalAssets(), accounted); }
CVL-Style Rule Sketch for Delegated AA Calls (AUTH/AUTHCALL)
When it comes to delegated AA calls like AUTH and AUTHCALL, here's a quick overview of how the CVL-style rule sketch can work:
- Define the Context: The rule should begin with the necessary context that identifies the specific conditions under which the delegated AA calls are activated.
- Set the Conditions: You'll want to outline the criteria that must be met for an AUTH or AUTHCALL to be considered valid. This might include things like permissions, roles, or user states.
- Establish the Flow: Next, illustrate the expected flow of actions. It's helpful to map out what should happen step-by-step, making sure to include any checks or validations that occur along the way.
- Handle the Responses: Finally, you need to specify how the system should respond to successful or unsuccessful calls. This could mean issuing confirmations, returning error messages, or triggering other workflows.
Example Rule Sketch
Here’s a simple example to illustrate these points:
When a delegated AA call is made:
IF user has permission to initiate AUTH/AUTHCALL
THEN proceed with the call
ELSE return error: "Permission denied"
On success:
return confirmation of AUTH/AUTHCALL execution
On failure:
return error details
By structuring the rules in this way, you can ensure clarity and efficiency in handling delegated AA calls.
rule authcall_is_scoped(address user, address invoker, address target, bytes data, uint gas, uint value) {
// Pre: user authorizes invoker with commit(user, target, data, gas, value, nonce)
// Post: AUTHCALL cannot call other targets or change value/gas beyond commit
assert onlyCalls(target) && preserves(gas,value) && usesCurrentNonce(user);
}
Budgeting and timelines: what to expect
- Continuous FV programs: Communities are putting down around $1.5M to $2.0M each year for formal verification and ongoing reviews of large protocols like Aave and Compound. If you’re working with a startup, you probably won’t need that level of investment, but it’s definitely a solid reference point for high-quality programs. (governance.aave.com)
- Point-in-time FV engagements: You’re looking at about 3 to 8 weeks for a focused module, such as a vault or an interest rate model, as long as you come prepared with detailed specs. If you need to create specs from scratch, it might take a bit longer. To get the most out of it, mix this with audits and fuzzing for maximum coverage.
- Internal effort: You'll want to plan for 1 to 2 senior engineers to work together with the vendor on the specs. The fastest teams tend to assign a “spec owner” during the design phase rather than waiting until the code is already frozen.
Implementation checklist (copy/paste)
- Before diving into the code:
- Jot down English invariants for things like value flow, permissions, rounding, and lifecycle.
- Figure out what needs to stay the same (immutable) to keep things tidy and manageable--after all, FV is all about that immutability!
- While building:
- Enable SMTChecker with CHC invariants along with explicit targets.
- Incorporate Foundry invariants for end-to-end behaviors.
- Integrate Slither into the CI pipeline; tackle high-signal findings right away. (docs.solidity.org)
- Pre‑audit:
- Put together formal specifications for key modules; run a quick FV “pilot” on one module to identify any gaps in the specs.
- Leverage Gambit mutation tests to strengthen those specs. (docs.certora.com)
- Pre‑launch:
- Conduct FV + audit; make sure to double-check after every fix; clearly demonstrate no surprise upgrades.
- For 3074/7702, check invoker rules and wallet edge cases. (eips.ethereum.org)
- Post-launch:
- Keep an eye on every commit with ongoing verification; don’t let any merges slip through if there are invariant failures.
- Monitor EIP changes that tweak the assumptions (think async flows, AA). Check it out here: (eips.ethereum.org)
Pitfalls to avoid
- “Proved” but a bit vague
- A specification that skips over the value/gas/nonce constraints for AUTH/AUTHCALL can still pass the proof, but it might leave some risky gaps. That’s where mutation testing comes in handy to uncover those issues. Check it out here: (eips.ethereum.org)
- Moving Away from tx.origin Logic After EIP-3074
- Future versions should definitely include features that make sure we don’t depend on tx.origin for authorization anymore. (eips.ethereum.org)
- Async vault edge cases
- If we don’t have clear lifecycle proofs, async deposits and redemptions (ERC‑7540) might lead to some tricky situations, like double claims or funds getting stuck due to some unusual interleavings. (eips.ethereum.org)
What leading teams are doing differently in 2025
- Continuous, not episodic security: We’ve got formal rules running in CI, along with invariants and fuzzers. Check it out here.
- Component-level proofs: Sure, full-system proofs can be tricky, but if we verify those math-critical pieces (like swap math and share accounting), we can really cut down on tail risk. Just look at how Uniswap v3 nailed their swap verification. More details here.
- Spec as product docs: Teams are starting to treat specs like they’re living documents for their partners and integrators. This approach not only builds trust but also speeds up listings and integrations. You can read more about it here.
How 7Block Labs can help
- Let’s kick off some workshops to transform your English requirements into machine-checkable invariants.
- We’ll set up a CI-first environment that includes SMTChecker, Slither, Foundry invariants, and mutation testing, all hooked into your PRs in less than two weeks. Check out the details here: (docs.solidity.org).
- We’re focusing our efforts on the riskiest 10% of your code--think vault math, liquidation, and AA invokers--while providing you with clear metrics on coverage and mutation-kill rates.
- You’ll also get executive reports that break down proof coverage into tangible business risk reductions that your board will totally get.
If you’re thinking about diving into account-abstraction features (3074/7702), async vault flows (7540), or kicking off a new AMM/vault in 2025, it’s definitely a good idea to consider formal verification. The most successful projects usually start with their specs early, prove the math that just can’t go wrong, and keep the verification process going as the code changes over time. Check it out here: (eips.ethereum.org).
Sources and further reading
- 2024-2025 losses and trends: Check out this snapshot from January 2025 on crypto losses, hacks, and scams--it's over $1.4 billion! (theblock.co)
- EIPs: Don’t miss out on the details about ERC‑4626, 7535, 7540, as well as EIP‑3074 and EIP‑7702. (eips.ethereum.org)
- Solidity SMTChecker docs and releases: If you're diving into Solidity, you’ll want to check out the SMTChecker documentation and the latest releases. (docs.solidity.org)
- Tooling: Get familiar with some awesome tools like Slither and Echidna. Plus, don’t overlook Foundry invariants, Certora Prover, Gambit, and KEVM. (github.com)
- Case studies: Take a look at the case studies for Aave, Compound, and Balancer, along with the verification process for Uniswap v3 swaps. (governance.aave.com)
We'd love to take a look at your architecture and see when FV will start to pay off for you in your roadmap. Just get in touch with 7Block Labs to set up a scoping session!
Like what you're reading? Let's build together.
Get a free 30-minute consultation with our engineering team.
Related Posts
ByAUJay
Building 'Private Social Networks' with Onchain Keys
Creating Private Social Networks with Onchain Keys
ByAUJay
Tokenizing Intellectual Property for AI Models: A Simple Guide
## How to Tokenize “Intellectual Property” for AI Models ### Summary: A lot of AI teams struggle to show what their models have been trained on or what licenses they comply with. With the EU AI Act set to kick in by 2026 and new publisher standards like RSL 1.0 making things more transparent, it's becoming more crucial than ever to get this right.
ByAUJay
Creating 'Meme-Utility' Hybrids on Solana: A Simple Guide
## How to Create “Meme‑Utility” Hybrids on Solana Dive into this handy guide on how to blend Solana’s Token‑2022 extensions, Actions/Blinks, Jito bundles, and ZK compression. We’ll show you how to launch a meme coin that’s not just fun but also packs a punch with real utility, slashes distribution costs, and gets you a solid go-to-market strategy.

