Formal Verification: The Math That Makes Smart Contracts Safe

Smart contracts have emerged as the financial backbone of the decentralized world and hold billions of dollars in funds, sometimes at the very same time. This brings a lot of risks and a single mistake in the logic can cause a protocol to lose all its liquidity within seconds. Once again, because blockchains are immutable, there is no simple "undo" button on mistakes. An industry shift is taking place, from basic peer reviews of programming code to Formal Verification. Formal Verification enables developers to mathematically prove their contracts operated as intended, removing whole classes of vulnerabilities before any code is deployed.

Why Smart Contracts are Vulnerable

Even the smartest engineers in the world make mistakes. In regular software, a bug might crash the app; In Web3, the same bug will make a bank go bankrupt. The real problem is never a typo, even if you might imagine it to be! The problem always lies in the complexity of interacting systems. If something is just a bit out of order, you may be able to convince a contract to release funds it was not meant to, or if an external oracle updates a price only a microsecond too late, you may open an arbitrage window, and drain a liquidity pool.

These bugs are often not visible to the naked eye: a "safe" looking contract is still capable of hiding structural logical bugs that only arise in extreme edge cases. The most famous of these or bugs is probably the reentrancy bug, where a function may execute at no more than one time that function gets interrupted before it is final, and starts executing again, and a transaction can occur before that function is finished executing its first loop.

This is why smart contracts do not fail because the developer didn't think hard enough, they fail because the web of interactions is such a complex mess that assisted human reasoning is unable to keep up.

What is Formal Verification?

Formal verification is changing the security model from one of "testing" to one of "proving." Security mechanisms are often implemented without formally verifying the code, relying on "testing," where you run random inputs on the code to see if it breaks, much like test-flying a plane. In formal verification, we do the opposite; we use "mathematical reasoning" to prove that the code cannot break, much like you can take physics equations and use them to prove that the shape of the wing is aerodynamically sound.

The basis of the process is Invariants. An invariant is a fact that is always true, regardless of anything that happens in a contract. For example, with an ERC-20 token, the "Total Supply" should always equal the sum of all user balances. Therefore, if a formal verification engine could prove that this state holds in every state of the contract, then you don't have to test for infinite minting bugs; you have proven mathematically that those bugs cannot exist.

How the Process Works

Formal verification entails developers converting their code into mathematical models typically in the form of either propositional or predicate logic. The developers will then write a "Specification", which serves as a blueprint of exactly how the contract is allowed to behave. The verification engine then acts as a tireless adversary attempting to find a mathematical proof that the code violates the specification.

This has been shown to work particularly well at enforcing hard rules:

  • Solvency Proving the assets of a vault could never be less than its liabilities.
  • Access Control Proving only a specific address could ever call a sensitive function.
  • Atomicity-State Guarantees that a transaction either fully occurs or does not occur at all, which helps to mitigate the risk of reentrancy.

Real-World Examples: The Promise and The Peril

The cryptographic history illustrates two simple messages, one of why that technology matters.

2016 The DAO Hack: This was one of the most public hacks to happen due to a classic reentrancy bug. Formal verification would have prevented this, as things like "a user's balance must be set to zero before the funds get sent" can be defined as an invariant. The tool would mark across the specific contract's code that it was mathematically possible to not complete successfully. This could have saved tens of millions of dollars and at least prevented the split of the Ethereum network.

2021 Compound Finance: As a good example of the limitations of the tech here, Compound is one of those protocols that utilize formal verification quite heavily. However, during an upgrade, a bug allowed users to claim $80 million in COMP tokens that they had not earned in 2021. The verification tool did not "break" in this case; it "proved" that the code met the specification. The specification was the problem; there was initialization logic that should have happened during the upgrade that was not part of the specification itself. Therefore, the math was right, but the human part was wrong.

Issues and Limitations

It is important to understand that a "verified" contract is not a "secure" contract. Proof is only as good as the questions that you ask. If a developer forgot to include an important property that the upgrade shouldn't reset the reward timer, then the tool will miss that mistake. There will be a sense of "blindness" created because the developers believed in a sense of security where they saw a green check mark but did not realize they had missed checking an important door.

Formal verification is extremely expensive and academically rigorous. The technology requires specialized skills in formal logic that most Solidity developers do not have. To make things even more complicated, formal verification only protects against risks inside the code, but not against risks that are outside of the code. Risks like:

  • Oracle Failures: If the price feed is manipulated the contract will execute "correctly" with bad data
  • Compiler Bugs: Errors with going from code to machine language
  • Governance Attacks: Where a malicious proposal is voted on by humans and passed

Conclusion

Formal verification takes us from being in the realm of "hoping" the code works to "knowing" it works. By adding mathematical proof into the development lifecycle we can reduce the risk of catastrophic failure by an order of magnitude. However, formal verification is not a magic bullet, it is just an extremely powerful tool in the right hands. As the industry matures, formal verification will become less of a luxury and more of a requirement, and we can significantly move toward a world where code is truly law, and the law is absolute.

 

This article is contributed by an external writer: Razel Jade Hijastro.
 

Disclaimer: The content created by LBank Creators represents their personal perspectives. LBank does not endorse any content on this page. Readers should do their own research before taking any actions related to the company and carry full responsibility for their decisions, nor can this article be considered as investment advice.

Tren