Idioms of Solidity Smart Contract Programming
Solidity is a new and highly experimental programming language for writing Ethereum-flavoured smart contracts. When Solidity first came out, nobody likely knew how to write smart contracts. One could learn the syntax and semantics of the language, but it was impossible to refer to other idioms.
Fortunately, as developers started to write smart contracts over time, several patterns and idioms have emerged. For example, smart contract developers realized that they tended to write the same life cycle management and access control code again and again. So they started to create a reusable library that could be imported by other smart contracts.
The most popular library is OpenZeppelin. It provides secure, tested and community-audited code that can be reused. In this post, we will look at some of the most common idioms of Solidity smart contract programming through OpenZeppelin library.
Ownership
Many smart contracts have functions that only its owner can call. A common way of implementing this is to assign the value of msg.sender
to a state variable. Then functions that need access control check if msg.sender
is equal to the stored owner and throw if they do not match.
OpenZeppelin’s Ownable
contract captures the essence of this idiom. onlyOwner
modifier provided by Ownable
throws if it is called by any account other than the owner. A smart contract inheriting Ownable
can simply add onlyOwner
modifier to the functions that need access control.
contract Ownable { address public owner; function Ownable() { owner = msg.sender; } modifier onlyOwner() { require(msg.sender == owner); _; }}
Ownable
also provides transferOwnership
function which transfers control to a new owner. It emits OwnershipTransferred
event once the ownership is successfully transferred.
Lifecycle management
In addition to the ownership management, a lot of smart contracts need to be destroyed when they are no longer needed. selfdestruct
operation removes the code from the blockchain and sends the remaining Ether stored at the contract address to a designated target. As this operation must be called by the owner of the contract, OpenZeppelin provides Destructible
contract which is inherited from Ownable
. Its member function destroy
transfers the current balance to the owner while its sibling member destroyAndSend
transfers the current balance to the given recipient.
contract Destructible is Ownable { function Destructible() payable { } function destroy() onlyOwner { selfdestruct(owner); } function destroyAndSend(address _recipient) onlyOwner { selfdestruct(_recipient); }}
Another common idiom regarding the lifecycle management of a contract is circuit breaker. Any non-trivial contract has errors in it. Peer review and code auditing cannot guarantee the absence of bugs since new bugs and security risks are being constantly discovered. Therefore, you must be able to respond to bugs and vulnerabilities.
Circuit breaker provides a way of pausing a contract when things go wrong. OpenZeppelin’s Pausable
contract is the implementation of circuit breaker idiom. Functions decorated with whenNotPaused
modifier throw when the contract is paused by calling pause
function. When you discover your smart contract is under attack, you can buy time to upgrade the contract by immediately pausing the contract.
contract Pausable is Ownable { event Pause(); event Unpause(); bool public paused = false; modifier whenNotPaused() { require(!paused); _; } modifier whenPaused() { require(paused); _; } function pause() onlyOwner whenNotPaused { paused = true; Pause(); } function unpause() onlyOwner whenPaused { paused = false; Unpause(); }}
In this post, we covered only the most common idioms that are used in almost all contracts. This is not the end of story. There are other idioms for common smart contract usages such as crowdsale and token. If you are interested in knowing more, refer to the source code of OpenZeppelin.
Originally Posted by CodeChain Team on Wed, Oct 18, 2017