Best Practices for Writing Smart Contracts
Without a doubt, the invention of blockchain technology in 2008 has blown open a world of possibilities. One of such possibilities is the smart contract. Smart contracts are basically computer protocols, which are intended to facilitate, verify, or enforce the negotiation or performance of a contract.
An upgrade to the original blockchain technology came in the form of Ethereum in 2013 by Vitalik Buterin. Since then, Ethereum has been the best platform for smart contract writing and execution, since it was built specifically for this purpose. Its success owes to the fact that it replaces bitcoin’s more restrictive language and replaces it with a language that allows developers to write their own programs.
Smart contracts are still something new because work is still in progress to establish stable procedures for its development and itch-free implementation. However, for the first time in history, we have computer codes that actually control real money and in some cases, huge amounts of money, without human intervention or governance. So, just like anything that has to do with money, the writing of smart contracts must be done right.
Writing Smart Contracts
Basically every programmer (whether certified or self-acclaimed) can write a few lines of code, but when it comes to writing a secure smart contract code, things can get a tad more complicated. Writing a smart contract goes way beyond writing a piece of code that can self-execute. It also involves being aware of every tiny detail that could possibly go wrong with the code later on. So, in essence, just being “able” to write a smart contract isn’t enough. Every developer must keep up with the industry’s best practices and guidelines, in order to ensure that the code is truly secure.
Having a secure code is particularly important because smart contracts operate in a wildly different manner, in comparison with most computer programs. Most notably is the fact that smart contracts generally don’t offer simple or straightforward upgrade paths, especially when dealing with crucial components like the codes controlling token value. Basically, once your smart contract is deployed and operational, altering it becomes a near-impossible task and this makes sense since the underlining technology is designed to be immutable.
So, when developing smart contracts, there is a need for an excellent architectural design as well as proper testing phases, in order to avoid being stuck with a headache-inducing piece of code. There are a myriad of resources that can be consulted when it comes to code architecture, testing and general security — some of them include Zeppelin’s open framework, Consensys best practices and Solidity’s Security Considerations, to mention but a few.
The goal of this post is to explicitly highlight the best practices when writing smart contracts, by focusing on two cardinal areas – Smart contract architecture and smart contract testing.
Smart Contract Architecture
Any smart contract that will enjoy a successful and itch-free operation must possess a good architecture. In the same way a good overhead bridge or skyscraper will require sound architectural design to stand the test of time; excellent architecture is also required when developing a smart contract.
Various factors must be put into consideration when writing a smart contract. Some of these factors include:
- Interaction with other contracts: A smart contract may seem alright when running in isolation, but usually, contracts need to interact together and work in tandem to perform certain tasks. So, in order to avoid unpleasant surprises, the developer must write the code, while putting all possible contracts it may be interacting with, into consideration.
- Use for purpose differing from the original one: In technology, adaptation of a code for an unintended purpose is not unusual. This is usually the basis for many hacking operations. If through interaction with another contract, the original contract develops a loophole, then it can constitute a serious problem if such weak spots are discovered by hackers. So, the developer must also consider this eventuality when writing the code.
So, as a minimum architectural requirement, the following best practices should be engaged:
- Utilize audited open source codes: The funny thing about coding is that a single line of code that is out of joint can compromise the whole system and that may cost you millions of dollars. This is why it is always a good idea to use open source codes that have been audited over and over. This is a very effective safety net because all major bugs and loopholes would have been discovered and fixed via the various audits. An example of such a source code is the ERC 20.
- Separate token issuance and control into separate contracts: When dealing with complicated smart contracts, especially those that deal with a lot of money, it’s always wise to carve out the token issuance and control codes. This is because once the contract goes live, it becomes very difficult to alter the processes, particularly the ones dealing with token. So, separating the token code into separate contracts will ensure that any failure or bug in the main contract will not result in a cataclysmic financial consequence.
- Implement a kill switch: Some over-confident programmers overlook the importance of having a kill switch in a piece of code and it sometimes costs them big! It’s always better to be safe than to be sorry. So, when developing any smart contract, you should implement a safety stop function at the top of the code, in the event that something undesirable happens.
- Implement a transfer function for the contract: There may be need for contract transfer from time to time, so when possible, you should endeavor to include a contract transfer function in the code, in order to save yourself unnecessary trouble in the future.
Smart Contract Testing
When it comes to testing, the need to follow established best practices cannot be over-emphasized. Testing, (be it at alpha or beta phase) is definitely an established field in the coding space and has a lot of helpful processes that help assure the safe performance of a contract. As a means of summary, there are two main aspects of testing that will be addressed at this point. These are verification and validation testing.
Verification testing is simply a means of checking whether a piece of code has been written according to the laid-down requirements and specifications. Verification testing includes functional test, unit test and integration test. All these tests are automated and cover different fringe cases and expected states. Verification should be carried out during code development and during release. Further testing including formal verification, security audits and code reviews should also be carried out to find all errors, bugs and weaknesses.
Validation testing on the other hand is a means of test-running a product, to ensure that it will function exactly how it’s expected to, once it’s deployed. Funny enough, validation (though very important) has not enjoyed as much publicity as verification in the development of smart contracts. Since it is a means of ensuring that the code actually meets the need of the end users for which it was developed, validation is usually done via external users during the alpha/beta testing phases or even in special studies.
Validation is very important because most of the time, flaws in a complex code won’t be visible unless it is actually used by real users, with real data and real assets at stake. For instance, the DAO – a smart contract tasked with the control of value token suffered from a bug, which allowed issuance of calls from outsiders and of course, the consequences were dire, though they were unintended. This flaw could have been spotted clearly if the contract had passed through the validation phase.
On Ethereum, validation testing can be done through early deployment of the code on testnet. Then it can pass through the proof-of-concept phase on a real network, before its finally cleared as OK and endowed with its full rights on the chain. It should be noted that the purpose of validation is to make sure that the code works exactly as intended. Any code that doesn’t work as intended is considered to be “buggy” and should never be deployed, no matter how “trivial” the deviation may seem.
Smart contracts that pass through proper verification and validation phases can easily be debugged and fixed, using various tools currently available. Thus, a lot of unnecessary headache will be avoided down the line. Wise developers always take the testing phase very seriously. Even Ethereum still undergoes validation tests from time to time, which further showcases how important testing is for smart contracts to work perfectly.
As a means of summary, the following are steps you should follow when testing your smart contract.
- Create a clear testing plan for the code at both verification and validation stages
- Perform code reviews
- Carry out external security audits to ascertain the safety of the code.
- Perform verification tests via automated units, in addition to integrated and functional tests.
- Perform validation testing via extensive testing on testnet.
- Carry out further testing in proof-of-concept, but with minimal risk. In addition perform alpha testing on the main net.
A final word…
There is definitely no exhaustive list of best practices that should be employed when developing smart contracts. However, all items discussed above are foundational and will definitely save you a whole lot of headache down the road.