Smart Contracts

It's one thing to buy and sell crypto, but Ethereum lets you implement your business logic straight on the blockchain with its Smart Contracts. Here's how.

Smart Contracts

Smart Contracts are one of the hottest things that are currently available on the Blockchains. Bitcoin enables you to implement only a simple Smart Contract with basic conditions, but Ethereum delivers a fully operative programming language that you can use to manage a business.

In this chapter, I would like to explain what a Smart Contract is, how it works, how to write one, and where you can find ready to use solutions. I'm going to assume that you are already a programmer who knows JavaScript and has no problems with reading similar code. I will skip some code explanations like private/public modifiers or string typing.

What is a Smart Contract

In the real world, we sign many contracts — when we set up cable television, buy a new phone or even a house or flat. Every one of those contracts has something in common — we pay to get something, or we give something to be paid. But, there is a huge group of contracts — I would call them agreements — we are so familiar with that we do not even notice that we are talking about them.

One of my favorite examples of simple cash distribution is when you give your friend 10 USD and ask him to share it with five colleagues evenly. He says ‘OK’, and you expect that everybody will receive an equal 2 USD. That is an agreement between you and the broker.

How hard could it be? As always, something may go wrong. One of the receivers can be favored by the broker and receive 3 USD, so another one receives only 1 USD. You did not agree to that.

Smart Contracts solve this kind of problems (and more) by automation. The contract’s creator can specify all the rules in the contract, and nobody can change it — literally nobody. If you want to change any condition, a new Smart Contract needs to be created.

In our specific case, the Smart Contract works as the broker between you and all interested parties. Every transaction made to the contract will be evenly distributed between saved addresses (in our case 5). Thus, if you create a contract with 5 saved addresses, or if you send those addresses as additional information to the contract, and transfer 10 ETH to this Smart Contract, it will immediately transfer 2 ETH to each receiver.

Because this guide is intended for developers, here is an example we can find in the real world. Some applications that help during the software development process, like IDEs or a database management systems, require you to buy annual access to it. Every year, I have to sign some kind of a contract between me and the software company to extend the license for another year.

So, the definition of this contract has a couple of conditions: If I do not have a license, or if its expiry date is close or passed, and if I agree with the license agreement, and I have paid, either I will receive a new one or my current license will be extended for another year. This looks pretty simple to a developer — just a couple of if conditions. And it is so simple. When you think like a programmer, most of the questions are of a true/false nature, and so are the contracts.

Smart Contracts in Ethereum work in the same way. Imagine that you can accept ETH payments for the software license and automate the process of extending the due date for next year.

How Smart Contracts Work

In Ethereum, there are two different types of accounts — the one you already know and use, that is a personal account, and the Smart Contract account which, as the personal one, has its own address and balance. But the Smart Contract does not have a private key that allows you to control the funds on it. Whatever happens in this account is controlled by the code inside. Moreover, this code cannot be changed — ever. So, if you haven't noticed a bug in your Smart Contract, and it is published, you cannot just fix it and deploy. A new Smart Contract needs to be created. Smart Contracts are immutable.

Smart Contracts can do the same things a personal account can — they can send or receive Ethers or some other virtual tokens or information. But remember, every transaction in Ethereum requires Gas to be mined, and the Gas costs Ethers. So. each Smart contract transaction requires Ethers (which is paid not by the Smart Contract itself but rather by the users).

One interesting property of Smart Contracts is that they can communicate with each other and interact. However, those actions and interactions are usually executed on the Blockchain. However, we may require that some of the information necessary to resolve some conditions in a Smart Contract are retrieved from the Internet.

Smart Contracts are designed to operate on data provided by the blockchain and usually do neither communicate nor allow communication with the external world. However, one type of Smart Contracts allows the use of external APIs — the Oracle Smart Contract.

Digital Tokens

Digital Tokens are something I would call a cryptocurrency inside another cryptocurrency. Many ICO projects (Initial Coin Offering) offer tokens in exchange for funds for their businesses. An ICO is something between a stock exchange and Kickstarter. Newly created or existing businesses are looking for opportunities for raising money to start operating or expand their operations. In exchange, they offer tokens. The tokens can be shared, exchanged, sold or bought as stock papers. Usually, the tokens start with an initial value, e.g., 1 USD per token, and after the company is developed, the token value can rise or fall.

Writing token contracts is hard, because there are many edge cases to handle, and there is no room for mistakes. Parity is one of the biggest software companies that provide solutions for Smart Contracts. They have published a contract called ERC20, which is widely used to share and distribute digital tokens. A list of those tokens can be found at https://etherscan.io/tokens.

Getting Started with Smart Contracts

Solidity

Solidity is a statically typed programming language specifically designed to write Smart Contracts that can run on the Ethereum Virtual Machine. It is quite similar to JavaScript to make it easier to learn for web developers.

Mist

The Mist browser is the tool of choice to browse and use Dapps founded by Ethereum. We will need this piece of software to publish our first Smart Contract. To download Mist, we need to go to the release page at https://github.com/ethereum/mist/releases and download the latest version available for our operating system. I use Ubuntu, so that’ll be Mist 0.9.3 (at the time of writing) in a deb-package.

TIP: At the release page you will find two applications — the Ethereum Wallet, which is designed for personal usage, and Mist, which includes the Ethereum Wallet and additional features, like publishing Smart Contracts. Please remember to download Mist.

When you open Mist for the first time, it will ask you which Ethereum network you would like to use — let’s stick to Rinkeby TestNet, because it will synchronize with the Blockchain a lot faster than LiveNet, and we will avoid losing Ethers during development. To switch networks, you need to go to the top menu, select Develop, then Network, and chose the network you are interested in. You can find the currently selected network in the bottom left corner of the application.

Remix IDE

Writing Smart Contracts can be much easier with a proper IDE (Integrated Development Environment). Solidity documentation strongly recommends using the Remix IDE, which is available online at https://remix.ethereum.org/. Also, Remix can be installed on a local machine. Full instructions are available at https://solidity.readthedocs.io/en/develop/installing-solidity.html#remix.

TIP: Ethereum also offers plugins for other development tools. A full list of those can be found at http://solidity.readthedocs.io/en/develop/.

This IDE provides a bunch of useful tools, such as a compiler, analysis tool or debugger. We can easily track what happens in the contract during every test without publishing it to the blockchain. When you open the web page for the first time, a Smart Contract example called Ballot will be presented to you. It implements a voting system.

Exercise : Please review the Ballot Smart Contract. Do you recognize some structures, the constructor, or methods? Take a look at the syntax and the methods names, and explain how this Smart Contract works.

Your first Smart Contract


pragma solidity ^0.4.0;
contract Payroll {
  function Payroll() payable{

  }

  function () payable{

  }

  function withdraw() payable {

  }
}

Constructor Function

A constructor function is called only once when the Contract is Created. It sets up the prerequisites for the Smart Contract, like setting the initial token amount, etc.

Fallback Function

Whenever somebody sends Ethers to your Smart Contracts without any additional information and without calling any specific method in the Smart Contracts, this method will be called. You can return funds to the sender, use a default method or distribute them as you wish.

Withdraw Function

This function is used to make a transfer and collect goods, Ethers or tokens from the Smart Contract. The Smart Contract does not need to send new transaction right away when you push Ethers into it. It can work as a database. Consider digital tokens and how they work. You can buy tokens by sending Ethers to the Smart Contract and exchange them back by calling the withdraw method.

Without this method, withdrawing Ethers from a Contract is impossible, because it does not have a private key that can be used to make a transfer.

Payable Keyword

You may notice some functions have an optional keyword payable after the name. If you add this keyword, the Smart Contract will be able to operate with Ethers. You can attach Ethers to the Smart Contract, send a transfer with Ethers to it or withdraw Ethers. Without this keyword, Mist would throw an exception if you tried to create a non-payable Smart Contract with attached Ethers.

By default, Contracts do not accept any money. The payable keyword should be added after every function that should be able to operate with money.

Business Logic

Let me explain the business logic from this example. I have created an example Smart Contract that allows you, as the owner, to manage the company’s salaries, which will be distributed by Ethereum. The general idea is to make the Smart Contract owner able to send only one transfer to the Smart Contract and then, every employee, should be able to withdraw their salary.

It works a little bit different than with fiat currency because when you receive a traditional bank transfer with salary, you usually do not need to ask for it once again. If we try to move our example to traditional banking, we end up with one account where the company sends a big transfer with all the salaries, and you need to go to the bank and ask them to pay you from this account when you need your money. Moreover, you will need to pay the fee. Sounds awful, huh?

But it does make sense when you take into consideration a couple of factors and possibilities that Smart Contracts provide. Let’s assume that we run a website strictly focused on IT, programming languages, or even the Blockchain. Everyone can become an author on this service and each article is paid an equal $300 in Ethers. So far, it is a real-life example. But now, let me demonstrate how a Smart Contract would handle the authors' payments.

As the owner of the Smart Contracts and the website, we should be able to add a new author’s address to the database of earned payments. All saved addresses should be able to withdraw their payments whenever they want to.


pragma solidity ^0.4.0;

contract Payroll {
  uint totalReceived = 0;
  address owner;
  mapping (address => uint) public salaryAmount;
  mapping (address => uint) public withdrawnSalary;
  function Payroll() payable public {
    updateTotalReceived();
    owner = msg.sender;
  }

  function () payable public {
    updateTotalReceived();
  }

  function updateTotalReceived() internal {
    totalReceived += msg.value;
  }

  function addAddress(address _salaryAddress, uint _salary) isOwner public {
    if (msg.sender == owner) {
      salaryAmount[_salaryAddress] = _salary;
    }
  }

  modifier isOwner() {
    require(msg.sender == owner);
    _;
  }

  modifier canWithdraw() {
    require(salaryAmount[msg.sender] > 0);
    _;
  }

  function withdraw() canWithdraw public  {
    uint amountPaid = withdrawnSalary[msg.sender];
    uint senderSalary = salaryAmount[msg.sender];
    uint salaryToPay = senderSalary - amountPaid;

    if (salaryToPay > 0) {
      withdrawnSalary[msg.sender] = amountPaid + salaryToPay;
      msg.sender.transfer(salaryToPay);
    }
  }
}

This code takes care of a couple of things that are necessary to avoid unpleasant situations when the smart contract is deployed, and we lose control of it. Let's go through all the steps and explain what happens, and why.

Creating a Contract

As any other objects or classes in other programming languages, Smart Contracts have constructors too. The contractor's name is the same as the contract's name, and it does not accept any arguments. However, if you add a payable keyword, it will accept Ethers that you can send as the creator. Otherwise, the Smart Contract cannot be created with Ethers.


function Payroll() payable public {
  updateTotalReceived();
  owner = msg.sender;
}

In the constructor, we call two actions — first, we update the total amount of Ethers received by our contract. We should keep this value to establish if we can send a payment or not.

The second action is to save the owner. Some of the methods or functions may be prohibited for everybody except the owner. Solidity provides a nice and clever way to select which methods have limited permissions — we can use modifiers .

TIP: The payable keyword enables sending Ethers to this smart contract. If you do not add this keyword to the constructor or the fallback function, you will not be able to send any money to the Smart Contract. However, there is a way to hack it. Every Smart Contract can destroy itself by calling a selfdestruct function which can send all the Ethers from this Smart Contract to another. If you destruct your own contract, you can send Ethers to another contract that does not allow that.

Require and assert

Those two functions are working in the same way as a simple if statement that may throw an error and stop executing the Smart Contract code. Require and Assert methods do the same thing, but when you use assert and the conditions are met, the Smart Contract won't execute, but the transaction will consume gas, i.e., take some of the sender’s money. The require function returns the gas if the Smart Contract cannot be executed.

Msg object

Solidity supports a couple of global variables that store information about the current transaction. Those are msg, block, and tx. The msg object is one of the most important and useful ones because there we can find information about the sender, funds, or data that was sent to the contract.

  • msg.data (bytes): complete calldata
  • msg.gas (uint): remaining gas
  • msg.sender (address): message sender (current call)
  • msg.sig (bytes4): first four bytes of the calldata (i.e., function identifier)
  • msg.value (uint): number of wei sent with the message

Modifiers

A modifier is a special kind of function that can be called between or after any other function. Inside a modifier, we use an underscore function that determines where the other method’s code should be put. In our code we have two modifiers:


modifier isOwner() {
  require(msg.sender == owner);
  _;
}

modifier canWithdraw() {
  require(salaryAmount[msg.sender] > 0);
  _;
}

The isOwner modifier checks if the transaction sender is the same address that created this specific Smart Contract. The second, canWithdraw, checks if the sender’s token or Ether’s balance is greater than 0.

The underscore function determines where the code of the calling function goes. If we add our modifier to the end of the function declaration, the modifier code will change the behavior.


function withdraw() canWithdraw public  {

In this case, the code that will be executed will look like this:


uint amountPaid = withdrawnSalary[msg.sender];
  require(salaryAmount[msg.sender] > 0);
  uint senderSalary = salaryAmount[msg.sender];
  uint salaryToPay = senderSalary - amountPaid;

  if (salaryToPay > 0) {
    withdrawnSalary[msg.sender] = amountPaid + salaryToPay;
    msg.sender.transfer(salaryToPay);
  }

The first condition is a part of modifier function, and the rest of the code is copied to the place where the underscore function was called.

Addresses

There are a couple of aspects about addresses I should mention. You probably noticed that in the withdraw function, Ethers are sent to the sender by calling his own function, transfer . That can happen because an address is not only a string but a fully working object with the following functions inside:

  • .balance (uint256): balance of the Address in Wei
  • .transfer(uint256 amount): send given amount of Wei to Address, throws on failure
  • .send(uint256 amount) returns (bool): send given amount of Wei to Address, returns false on failure
  • .call(...) returns (bool): issue low-level CALL, returns false on failure
  • .callcode(...) returns (bool): issue low-level CALLCODE, returns false on failure
  • .delegatecall(...) returns (bool): issue low-level DELEGATECALL, returns false on failure

The most important ones for basic usage are balance and transfer.

Mappings

In my opinion, mappings are arrays of a kind that has no specific order. Usually, you can iterate through an array, but this is impossible with mappings. You can only check what value is assigned to a specific key, if any. Mapping types are declared as mapping(KeyType => ValueType).


mapping (address => uint) public salaryAmount;

In our example, the salaryAmount mapping object is an empty array, but when you check what is inside some key, like salaryAmount(msg.sender), it will return a default value for the uint type, which is 0.

You can assign a new value to this key like in any other array:


salaryAmount[msg.sender] += msg.value;

This line will add an amount of sent Ethers to the sender’s account. Now, if check what is inside this key once again, it will not return 0 but the value we assigned — msg.value.

Structs

From time to time, there is a need for a more sophisticated object that stores only a piece of information without additional business logic. Solidity provides a struct type that can store other kinds of information.


Contract Sample {
  struct Voter { // Struct
    uint weight;
    bool voted;
    address delegate;
    uint vote;
  }
}

As you can see, structs contain other types inside. They are really useful if you connect them with the mapping type:


mapping(address => Voter) sampleVoterMapping;


The mapping object will have the Voter struct assigned to the keys.

Calling Another Contract

A good piece code is divided into single-responsibility components. You have probably noticed that Smart Contracts, from a programmer’s point of view, are quite similar to classes in other languages. We can create new objects — instances of other Smart Contracts — use or inject them.

The simplest usage example is to create two Smart Contracts (classes) next to each other and just create a new object inside the second one.


contract ContractA {
  uint counter public;
  function add() public {
    counter++;
  }
}

contract ContractB {
  ContractA createdContract public;

  function ContractB() public {
    createdContract = new ContractA();
  }

  function add() {
    createdContract.add();
  }
}

In this example, ContractB will create an instance of ContractA in a public variable. ContractA is responsible only for one thing — counting add function calls. We can call this function from inside ContractB.

But this solution will not enable us to change the behavior of a Smart Contract when something goes wrong or when we would like to change the calculations. So, let’s change the code in a way that will accept a change of the instance of ContractA. We will treat ContractA not as a fully working contract but as an interface.


contract ContractA {
  function add() public;
}

contract ContractB {
  ContractA createdContract public;
  function setContract(address contractAddress) onlyOwner public {
    createdContract = ContractA(contractAddress);
  }

  function add() {
    createdContract.add();
  }
}

At this point, we need to assume that a similar Smart Contract with the same interface to the ContractA contract is already deployed to the blockchain and has its own address. In this case, we will be able to pass this address to the setContract function which will create a new instance for us, which can be used as in the previous example. Please notice the small difference that we do not use the operator new before we create a ContractA object. It is not necessary when we create an instance from the address.

In this example, as the owner, we can change the behavior of already deployed Smart Contracts by creating a new contract that implements the interface from ContractA and passing its address to the setContract function.

Deploying a Smart Contract

When you are ready and want to publish your new Smart Contract, you need to login to Mist and go to the ‘send’ tab. Publishing a new Smart Contract requires you to have at least 1 Ether on your account. On TestNet, you can ask for a transfer from https://faucet.rinkeby.io/.

Once you receive your Ethers — it takes a couple of seconds — you will be able to add you Smart Contract. Use the button +Add Wallet Contract.

After that, you need to choose which of your personal accounts you would like to deploy the Contract and call it from. Deploying a Smart Contract works like every other transaction and requires a fee.

After this step, Mint will open a simple text editor with a parser, that will help you write the contract. You can paste the example we created and choose the contract’s name from the select box on the right.

While you are creating a new Smart Contract, you can also determine how many Ethers you would like to transfer to it. This is why the constructor allows adding the payable keyword after its declaration.

If any troubles occur while parsing the code, an error should be displayed on the right site where the drop-down with contract names is now. When the code is more sophisticated and complicated, it can require the creation of more than one contract at the same time. That is why there is a list where you need to select which Smart Contract in the code is the main contract that will be available on newly generated addresses.

TIP: Account addresses are randomly generated in the blockchain, but the Smart Contract addresses are generated based on two factors — the origin account address of the Smart Contract and a nonce. The Nonce is defined as the number of transactions made from the account. So, you can predict what the next address of a newly created Smart Contract will be.

The very last step of publishing your Smart Contract is to pass your password and accept the fee — Gas price. Usually, the Gas is automatically calculated by Mint, but from time to time it happens that it cannot be calculated and it is set to zero. Mint will inform you that it is impossible to create a Smart Contract without Gas, so you need to set it manually. As you can see in the screenshot, I chose 3000 Gas.

Operate on Contracts

After a couple of moments, the Smart Contract will be created and mined, and it will be added to your Smart Contract list. Now you can test and operate on it and check if everything works as you expected.

Because you have created this specific Smart Contract and we added a line of code in the constructor that makes you the owner, you will be able to run all methods permitted only for the owner. Other accounts will be able to see those functions, but if they try to use them, an error will be thrown, and the code will not execute.

From the dropdown list on the right side of the screen, you can pick a function you would like to execute, and if it accepts any arguments, Mint will present a short form that will pass all parameters to the code. When you are ready, you can send and accept the transaction. Like any other transaction, this will require Gas to execute.

Every transaction you execute will be listed inside the Smart Contract. After it is mined, you should be able to see if any of the public variables in the Smart Contract changed. All public variables are automatically presented in Mint and are used to check the current state of the contract.

TIP: We have created our own Smart Contract, so we did not need to provide any additional information to Mint about the contract’s structure. But, if you try to use others' contracts, you can use the function "Watch Contract" in Mint. This will require you to provide an address, name, and ABI code. The ABI code is a generated JSON text that describes a contract’s structure, which is hidden by default.

Conclusion

In this final chapter, I have explained what the Smart Contract is, and how to write, deploy and operate your own. However, the hardest part is securing the contract. Ethereum has a long history of troubles and vulnerabilities found in Smart Contracts — stolen tokens, removed data, etc. Now that you know how to deal with the basics, I recommend that you polish your skills by exercising.

Ethernaut is a Solidity wargame divided into a couple of puzzles that you need to solve. Your goal is to find the vulnerability in every one of the six presented Smart Contracts and hack them. The game is available at https://ethernaut.zeppelin.solutions/, and I must admit, you can learn by hacking.

Have fun!

04 Milestones

SCALE YOUR DEVELOPMENT TEAM

We help you execute projects by providing trusted Blockchain developers who can join your team and immediately start delivering high-quality code.

Hire Blockchain Developers