Solidity Smart Contracts Design Patterns

Alexander Vitanov
6 min readFeb 24, 2018

--

Source: http://www.fanpop.com/clubs/patterns-backgrounds-wallpaper/images/39761762/title/triangles-pattern-photo

Design patterns have proven to be the go-to solution for many common programming scenarios. They are not only generic, but also easy to extend and tweak to one’s needs. Let’s take a look at some useful Solidity Design patterns that will probably come in handy when writing smart contracts during the development of you killer DApp.

We will look at the following patterns:

  1. Contract Self Destruction
  2. Factory Contract
  3. Name Registry
  4. Mapping Iterator
  5. Sending ether from contract: Withdrawal pattern

Contract Self Destruction

Used for terminating a contract, which means removing it forever from the blockchain. Once destroyed, it’s not possible to invoke functions on the contract and no transactions will be logged in the ledger. Now comes the question “Why would I ever destroy my contract?”. There are multiple reasons, such as dealing with timed contracts or contracts that must be terminated once a milestone has been reached. Some examples are Loan contracts which could be destroyed after the loan is paid off, or a Bidding contract which is time based and must be terminated after the bidding is over (considering we won’t need them for other purposes, like referring to history, which could easily be done by filtering events they have emitted).

Some things to keep in mind when dealing with a contract that has been destroyed:

  1. Transactions will fail
  2. Any funds sent to the contract will be lost

In order to prevent the loss of funds you should remove all references of dead contracts and/or call get() before sending funds to make sure the contract still exists. Now let’s take a look at the code:

contract SelfDesctructionContract {   public address owner;
public string someValue;
modifier ownerRestricted {
require(owner == msg.sender);
_;
}
// constructor
function SelfDesctructionContract() {
owner = msg.sender;
}
// a simple setter function
function setSomeValue(string value){
someValue = value;
}
// you can call it anything you want
function destroyContract() ownerRestricted {
suicide(owner);
}
}

As you can tell, destroyContract() is responsible for the destruction.

Notice how we used ownerRestricted modifier, which we defined earlier, to only allow the owner of the contract to destroy it (something you would most likely want, too).

Factory Contract

Factory contract is used to create and deploy “child” contracts. Those child contracts can be referred to as “assets” which in the real life could represent, say, a house or a car.

The factory is used for storing the child contracts’ addresses so that they can be extracted whenever necessary. Why wouldn’t I just store them in my web app database you might ask? By storing them in the contract they remain in the blockchain and they are pretty much safe there, while data corruption in your database might wipe the asset contracts’ addresses which will lead to losing references to those contracts. Also, you must keep track of all newly created contracts and update your database.

A common use case for the Factory contract is selling assets and keeping track of those assets (eg. who is the owner). To sell an asset you add the payable modifier to the functions responsible for deploying the assets. Here’s the code:

contract CarShop {   address[] carAssets;   function createChildContract(string brand, string model) public     payable {
// insert check if the sent ether is enough to cover the car asset ...
address newCarAsset = new CarAsset(brand, model, msg.sender);
carAssets.push(newCarAsset);
}
function getDeployedChildContracts() public view returns (address[]) {
return carAssets;
}
}contract CarAsset { string public brand;
string public model;
address public owner;
function CarAsset(string _brand, string _model, address _owner) public {
brand = _brand;
model = _model;
owner = _owner;
}
}

The line address newCarAsset = new CarAsset(...) fires a transaction which deploys the child contract and returns the address for that contract. The only connection between the factory contract and the assets is the variable address[] carAssets; , so make sure you store the addresses of the child contracts.

Name Registry

Imagine you are building a DApp which has a dependency on multiple contracts, for example a blockchain copy of Amazon store, which makes use of ClothesFactoryContract, GamesFactoryContract, BooksFactoryContract, etc.. Now imagine keeping all those addresses inside your app’s code. What if those addresses change over time or even more annoying, while developing you are deploying all those contracts every time you make changes and you have to keep track of their addresses. This is where Name Registry comes into play. This pattern allows you to only keep the address of one contract, instead of tens, hundreds or even thousands, as your DApp grows in scale. It works by storing a mapping contract name => contract address so each address can be looked up from within the DApp by callinggetAddress("ClothesFactory"). The benefit of storing names mapped to addresses is that with the introduction of new versions of some contracts the DApp will not be affected in any way since the only thing we modify is just the address of the mapping. Code:

contract NameRegistry {   struct ContractDetails {
address owner;
address contractAddress;
uint16 version;
}
mapping(string => ContractDetails) registry; function registerName(string name, address addr, uint16 ver) returns (bool) {
// versions should start from 1
require(ver >= 1);

ContractDetails memory info = registry[name];
require(info.owner == msg.sender);
// create info if it doesn't exist in the registry
if (info.contractAddress == address(0)) {
info = ContractDetails({
owner: msg.sender,
contractAddress: addr,
version: ver
});
} else {
info.version = ver;
info.contractAddress = addr;
}
// update record in the registry
registry[name] = info;
return true;
} function getContractDetails(string name) constant returns(address, uint16) {
return (registry[name].contractAddress, registry[name].version);
}
}

Your DApp will use getContractDetails(name) to get the address and version of the specified contract.

Mapping Iterator

Many times we need to iterate a mapping, but since mappings in Solidity cannot be iterated and they only store values, the Mapping Iterator pattern turns out to be extremely useful. Some things to keep in mind are that as elements count goes up the complexity of iteration will increase, as well as the storage cost, so avoid iterating when possible. Implementation:

contract MappingIterator {   mapping(string => address) elements;
string[] keys;
function put(string key, address addr) returns (bool) {
bool exists = elements[key] != address(0)
if (!exists) {
keys.push(key);
}
elements[key] = addr;
return true;
}
function getKeyCount() constant returns (uint) {
return keys.length;
}
function getElementAtIndex(uint index) returns (address) {
return elements[keys[index]];
}
function getElement(string name) returns (address) {
return elements[name];
}
}

A common error in put() could be iterating the keys to check for existence instead of doing it like this elements[key] == address(0) . While it’s not exactly an error, it is not desirable since iteration becomes costly as keys array grows in size and, you know, iteration should be avoided when possible.

Withdrawal Pattern

Imagine you sell car tires. All the tires you’ve sold turn out to be faulty in some fashion and you offer a refund to everyone who paid for them. Let’s say you keep track of all buyers in a contract and you have a refund function which iterates through your buyers list and sends back the money to each one of them. You have a choice - use buyerAddress.transfer() or buyerAddress.send() . The difference between both functions is that transfer() will throw an exception if something goes wrong with the transaction while send() will not throw but simply return a boolean false . Why is this important? Let’s say most buyers are external accounts (i.e. individuals), but some buyers are other contracts (perhaps businesses). Assume that among those buyer contracts there is one contract whose developers made a mistake in its fallback function and it throws an exception when invoked (fallback functions are default functions in contracts that are invoked if a transaction is sent to the contract without specifying any methods). Now as soon as we invoke contractWithError.transfer() in our refund function an exception will be thrown and iteration will be stopped. Therefore, transaction is reverted and none of the buyers gets their refund. They are blocked.

While refunding all buyers in one invocation can be implemented using send() , it is instead better to expose withdrawFunds() function which will refund callers on demand, individually. Thus, the erroneous contract will not block the rest of the buyers and will only receive funds when the fallback function code is fixed. Here is the code for the second approach:

contract WithdrawalContract {   mapping(address => uint) buyers;   function buy() payable {
require(msg.value > 0);
buyers[msg.sender] = msg.value;
}
function withdraw() {
uint amount = buyers[msg.sender];
require(amount > 0);
buyers[msg.sender] = 0;
require(msg.sender.send(amount));
}
}

Thanks for reading, if you have suggestions for other useful patterns let me know in the comments!

--

--

Alexander Vitanov
Alexander Vitanov

Responses (7)