Ethereum Smart Contracts 101: Hello World

in #ethereum7 years ago (edited)

What are Smart Contracts?


A smart contract is a computer program which is intended to facilitate, verify, or enforce a negotiation/contract that was done in real life.


Image

Image Credits: Blockgeeks.com

With a smart contract many kinds of contractual clauses can be made partially or fully self-executing, self-enforcing, or both. The main motive of smart contracts is to provide security that is better to traditional contracts and to cut other transactional costs associated with traditional contracting. Smart contracts on Ethereum network run on something called Ethereum Virtual Machine (EVM) which for visualization purposes is similar to JVM in Java.

The Decentralized Applications (ĐApps) running on the Ethereum network are nothing more than a bunch of Complex Smart Contracts.

To start with Smart Contracts, you'll need the below mentioned tools.

Tools


Mist Browser

Screen Shot 2017-09-21 at 6.17.11 PM.png

Mist Browser is a DApp browser, built on top of Chromium Browser.

Download Latest Version of Mist from Github Releases Page.

Note: Mist has Ethereum Wallet built into it, so no need to download wallet seperately, just the Ethereum Mist would do.

Setting up Mist:

  1. Install the Mist Browser:
     - Mac Setup: Open the dmg file by double clicking it, and install it by dragging the Mist icon to Applications folder.
     - Linux Setup: sudo dpkg -i Mist-linux64-0-9-0.deb
     - Windows Setup: Run the installer and follow installation instructions.
  2. After installation run Mist, it will prompt you to select either Main Network or Test Network, select Test Network.
  3. On first run, Mist will download the entire blockchain of the test network, which has almost 1 Million blocks, so be patient.
  4. Since we're developing our Smart Contract, we'll use the Test Network, so that we don't have to spend any real money while learning.
  5. Mist currently has two test networks Rinkeby and Ropsten, we're going to use Rinkeby, because obtaining free Test Ether on Rinkeby is much easier.

Obtaining Test Ether

To create Smart Contracts, you're going to need some Ethereum on the Rinkeby test network, which can be obtained by following these steps:
Screen Shot 2017-09-22 at 7.43.55 PM.png

  1. Create a public gist on Github [Link].
  2. Copy your Main Account wallet address from Mist, and paste it in the gist content. Name and Description of the gist does not matter.
  3. Go to the Faucet site, paste your gist address and claim your Test Ether (18.75 Per 3 days).
  4. You'll get the Test Ether when the next block is discovered on the network (30s to 2 mins).

Remix IDE

Screen Shot 2017-09-22 at 3.16.53 PM.png

Remix IDE is available as an Online IDE as well as it's bundled with the Mist Browser you downloaed.

Online Version: Remix IDE

Mist Remix IDE: Go to Develop -> Open Remix IDE.

The First Smart Contract


Let's suppose there is a company which wants to pay it's employees equal share of the total earnings, using a Smart Contract.


Basic Requirements:

  • A way to receive money in the smart contract.
  • A way by which employees can withdraw their funds.
  • Equal division of the funds between employees.
  • Checking that the person trying to withdraw is actually one of the employees.
  • Keeping track of how much an employee has already withdrawn from his share.

Let's Create the Smart Contract

Structure of a Smart Contract



pragma something;       <--- Solidity Version information for compiler

contract ContractName{

  constructor(){}       <--- Initialization stuff goes here

  fallback(){}          <--- Called whenever someone sends Ether

  someFunction1(){}     <--- Normal function

  someFunction2(){}     <--- Normal function

}


There are a couple of types of functions which are required in a smart contract:

  • Constructor Function: The function which is called only once, when you deploy the smart contract. For example it can be used to receive the initial Ether sent to it, at the time of deployment.
  • Fallback Function: The function without a name (literally no name, defined as function (){ code... }) which is invoked when someone sends Ether to the address of your smart contract. In the lack of this function, Ether sent to the smart contract will be rejected.

There's also this thing called a Function Modifiers which are used to change the behaviour of a function, though they're not essential. For example, modifiers can check a condition prior to executing a function.


The Actual Contract Code

Copy Friendly Version: PayEmployees.sol

//The contract should start with the Solidity version it is written for.
pragma solidity ^0.4.0;

contract PayEmployees {

  address[] employees = [0xdd870fa1b7c4700f2bd7f44238821c26f7392148, 0x583031d1113ad414f02576bd6afabfb302140225];
  uint totalReceived = 0;
  mapping(address => uint) withdrawnAmounts;

  //Defining constructor as payable allows it to receive ethereum at the time of creation.
  function PayEmployees() payable{
    updateTotalReceived();
  }

  //fallback function, invoked ethereum is sent to the smart contract's address.
  function () payable {
    updateTotalReceived();
  }

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

  //Function modifiers are used to imply restrictions on the function calls.
  modifier canWithdraw() {
    bool contains = false;

    for(uint i =0; i < employees.length; i++) {
      if(employees[i] == msg.sender) {
        contains = true;
        break;
      }
    }
    require(contains);

    //This "_;" will be replaced by the actual function body 
    _;
  }

  //this function uses canWithdraw modifier to check whether the address belongs to one of the employees.
  function withdraw() canWithdraw {
    uint amountAllocated = totalReceived/employees.length;
    uint amountWithdrawn = withdrawnAmounts[msg.sender];
    uint amount = amountAllocated - amountWithdrawn;
    withdrawnAmounts[msg.sender] = amountWithdrawn + amount;

    if(amount > 0){
      msg.sender.transfer(amount);
    }
  }
}


Breaking Down the Code

Let's take a look what it's all about.

pragma solidity ^0.4.0;

contract PayEmployees {

  address[] employees = [0xdd870fa1b7c4700f2bd7f44238821c26f7392148, 0x583031d1113ad414f02576bd6afabfb302140225];
  uint totalReceived = 0;
  mapping(address => uint) withdrawnAmounts;
  ...



Pragma in general refers to an instruction which tells the compiler it how it should treat the code. In our smart contract the first line pragma solidity ^0.4.0; simply tells that the smart contract is written for Solidity version 0.4.0 or anything newer that does not break or alter the functionality (up to, but not including, version 0.5.0)

The next line creates a contract named PayEmployees. A contract is similar to a class, it's basically a collection of code containing variables and functions.

Data Types in Solidity:

  • uint - unsigned integer of 256 bits.
  • address - holds a 20 byte value i.e size of an Ethereum address.
  • mapping(_KeyType => _ValueType) - a map for mapping some key, values.

We need a list of the wallet addresses of all our employees, address[] employees creates an array in which we store the wallet addresses.

Constructor Function

...
  function PayEmployees() payable{
    updateTotalReceived();
  }
...


This is the constructor, the function which is called only once, when we deploy the contract on the network. In our case, we're just updating the variable which stores the total ether received by our smart contract, to include the ether transferred to it at the time of deployment.

The payable keyword signifies that the function can receive money. Removing this keyword will make the smart contract reject the payment sent to it at the time of initialization.

Fallback Function

...
  function () payable {
    updateTotalReceived();
  }
...


A fallback function is invoked whenever someone sends ether to the address of our contract's address. We've marked it as payable because who doesn't want money?

A Normal Function

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



Just because we wanted another function to update the totalReceived variable. We could've done without this function, but it would've meant writing two identical statements in the constructor and fallback function, programmers don't do that. (Yeah yeah, I know, we did the same thing by invoking the fuction twice, but it is supposed to be better.)

Also, msg is a variable containing all the details of the transaction, msg.value the number of wei (smallest unit of ether) sent, msg.sender is the address of the sender.

Modifiers

...
  modifier canWithdraw() {
    bool contains = false;

    for(uint i =0; i < employees.length; i++) {
      if(employees[i] == msg.sender) {
        contains = true;
      }
    }

    require(contains); //this should be true for the function to proceed to the next line.
    _;
  }
...



Modifiers are there to change the behaviour of functions. For example, modifiers can check a condition prior to executing a function. In a Function Modifier, solidity replaces the _; by the body of the function, which in this case will be the withdraw() function's body.

We're including a modifier in this smart contract just for the sake of familiarising ourselves with it, it's just checking one by one that the address which wants to invoke the withdraw() function is actually present in our array of employee addresses. The same could've been easily achieved by writing a similar check inside of our withdraw() function.

A better example would have been if we had 3 different kinds of withdraw() functions, each doing something differently, and each needed to check whether the address belongs to an employee, we won't have to write the same condition to verify that 3 times.

Withdrawing Ether

...
  function withdraw() canWithdraw {
    uint amountAllocated = totalReceived/employees.length;
    uint amountWithdrawn = withdrawnAmounts[msg.sender];
    uint amount = amountAllocated - amountWithdrawn;
    withdrawnAmounts[msg.sender] = amountWithdrawn + amount;

    if(amount > 0){
      msg.sender.transfer(amount);
    }
  }
}



Just a simple withdraw function that does the following things:

  • Checks whether an employee or not, using the function modifier.
  • Keeps a track of the amounts the employees have withdrawn previously.
  • If the employee has already withdrawn his share, and the smart contract has received money after that, then the employee will be able to withdraw just the newly created share.
  • Transfers the amount, to the address requesting ether.

Note: Every operation in a smart contract costs gas to execute, so you should minimize the number of operations in your smart contracts. We'll learn more about this in the coming tutorials.


Deploying And Interacting with the Smart Contract


Deploying on the Ethereum Network

We have coded our first smart contract, the employees will be so pissed if we don't deploy it on the network.

  • Create two or more wallets for your employees and change the addresses in the employees array in the code.
  • Open up Mist -> Contracts -> Deploy New Contract
  • Paste the contract code in the SOLIDITY CONTRACT SOURCE CODE field and select the contract PayEmployees to deploy.
  • Select an account to deploy the contract from, and change the AMOUNT field to however much you want to send to the smart contract initially.
  • Leave the gas at suggested, and just deploy already!

Screen Shot 2017-09-22 at 7.14.59 PM.png

wait for it...

Screen Shot 2017-09-22 at 7.20.11 PM.png

Interacting with the Smart Contract

  • To withdraw money to the employee accounts you created in the beginning, go to Contracts -> Custom Contracts and select your smart contract.
  • Just select the address you want to use while interacting with the smart contract, and select the function you want to invoke (withdraw() in this case) and click Execute. The smart contract will send the Ether and employee wallet balance should update in a minute or two.
  • You can send the address of this contract to your employees, so that they know such a contract exists and they can withdraw money from it.

Screen Shot 2017-09-22 at 7.27.23 PM.png

  • To refill the smart contract with some more Ether, just send the Ether to it's address, and our fallback function should take care of the rest.
  • Congratulations, you just created your first smart contract.

That's it for the Getting Started With Smart Contracts. Let's hope you enjoyed and understood how the pieces come together. Feel free to comment any improvements or doubts you have.

Sort:  

Tell me what am I doing wrong?

Hi @bartosz546, Can you show me your contract code?

I just copy paste your code. I made it again. Still Fails.
The error tells:
Intristic gas too low.

@bartosz546, That's strange. I verified the code just now by redeploying the exact same code. I'm pretty sure, you must have taken care of all these things, but just to verify:

  • The account from which you are trying to deploy the contract has sufficient ethers (gas + initial value you want to send)
  • You have updated the employee wallet addresses in the code with your own before deploying.
  • The employee wallet addresses have enough funds to execute the withdraw function (because to call the withdraw method, you'll need to spend some gas)
  • Try increasing the Maximum gas fee value in the screenshot by clicking the blue colored "0".

If things still don't work, please send me your exact code, with the updated variables.

Ok, I found solution I was trying to execute contract from account I deployed it, but it is not employee.

I like your tutorial. Have some problems with finding good ones.

Amazing work!

Very well written with good examples!! :)

Thank you, I'm in process of improving it, there are still a few things I missed, like the basic structure of a smart contract. Will update it in a few hours, based on the feedback.

This looks great. Very detailed (but I'm not familiar with this field so everything is jargon to me haha). Are all of these instructions and screenshots yours (no references at all)? Do make an introduceyourself post about you, so people would know you more, it actually helps.

Thank you @deveerei, and Yes, all the screenshots are mine. I'll do an introduction post later sometime.

That will be really great. Do that and make another awesome post like this. I'll check out your blog again. Or try to reach me on Discord, @deveerei is my name there too.

This post recieved an upvote from minnowpond. If you would like to recieve upvotes from minnowpond on all your posts, simply FOLLOW @minnowpond

Thank you. This was exactly what i was looking for. Let me know when you push out some more stuff.

Coin Marketplace

STEEM 0.29
TRX 0.11
JST 0.033
BTC 63945.57
ETH 3135.76
USDT 1.00
SBD 4.00