Before start reading this, Please read my previous article Where I explained what is what is ethereum.
Languages for writing Ethereum smart-contract :
The two primary languages which are used to write Ethereum smart contracts are Serpent and Solidity. Serpent is the older language which has become out of date as of September, 2017. Solidity, which is a javascript based language, has now become the recommended language for writing smart contracts. Security vulnerabilities have also been found in Serpent recently, which makes it an unattractive platform for development. Some key features of these languages are:
Solidity — Solidity is a contract-oriented, high-level language whose syntax is similar to that of JavaScript and it is designed to target the Ethereum Virtual Machine (EVM).
Serpent — Serpent is a high-level language designed for writing Ethereum contracts. It is very similar to Python, but as of September, 2017, Solidity is the preferred language of development for Ethereum developers
Upcoming Smart contract languages
Solidity is currently the most popular language for smart contracts. There are a few upcoming smart contract languages which can become important in the future:
Viper — Viper focuses on security and language and compiler simplicity. It has a python-like indentation scheme.
Lisk — Lasik uses javascript as a smart contract language.
Chain — Chain provides enterprise-grade blockchain infrastructure with SDKs in popular languages such as Ruby, Java, and NodeJS.
Start Development with solidity :
Version Pragma
All solidity source code should start with a “version pragma” — a declaration of the version of the Solidity compiler this code should use.
pragma solidity ^0.4.19;
This is to prevent issues with future compiler versions potentially introducing changes that would break your code.
Contracts
A contract is the fundamental building block of Ethereum applications — all variables and functions belong to a contract, and this will be the starting point of project.
An empty contract named HelloWorld would look like this:
contract HelloWorld {}
SOLIDITY COMMENTS
Solidity features single line // and multi line /*….*/ comments.
Data Types :
Unsigned Integers: uint
The uint data type is an unsigned integer, meaning its value must be non-negative. There’s also an int data type for signed integers.
Note: In Solidity, uint is actually an alias for uint256, a 256-bit unsigned integer. You can declare uints with less bits — uint8, uint16, uint32, etc.. But in general you want to simply use uint except in specific cases.
// you can also initialize the uint during the declaration like thisuint x = 45;//if you make it constant by using the constant keyword like thisint constant variable1 = 8;// then it cannot be changed after instantiation as it will be considered as constant by the compiler
address :
Holds a 20 byte value (size of an Ethereum address). Address types also have members and serve as a base for all contracts.
Members of Addresses
balance and send
It is possible to query the balance of an address using the property balance and to send Ether (in units of wei) to an address using the send function:
address x = 0x123;address myAddress = this;if (x.balance < 10 && myAddress.balance >= 10) x.send(10);
Boolean
// boolean variable can be declared by bool keyword like thisbool b = true;
String :
// this is how string is definedstring n = “hello”;
Byte :
byte a; // byte is same as bytes1bytes2 b;bytes32 c;// dynamically sized bytes can also be declared like thisbytes m;
Array :
// this is a static array whose length is 5 fixedbytes32[5] nicknames;// dynamic array whose length can be changed at any time can be specified like thisbytes32[] names;
Mappings
Mappings are another way of storing organized data in Solidity.
Defining a mapping looks like this:
// For a financial app, storing a uint that holds the user’s account balance:mapping (address => uint) public accountBalance;// Or could be used to store / lookup usernames based on userIdmapping (uint => string) userIdToName;
A mapping is essentially a key-value store for storing and looking up data. In the first example, the key is an address and the value is a uint, and in the second example the key is a uint and the value a string.
enum:
Enums are one way to create a user-defined type in Solidity.
// Lets see Enums which are often used for state machine like thisenum State { Created, Locked, Inactive };// post this a variable can be Declared like thisState public state;// Initializing the state can be done like thisstate = State.Created;// It is important to note that enums can be explicitly converted to ints like thisuint createdState = uint(State.Locked);
struct :
A struct in solidity is just a custom type that you can define. You define the struct with a name and associated properties inside of it.
struct Person {uint age;string name;}Person[] public people;
Now we’re going to explore how to create new Persons and add them to our people array.
// create a New Person:Person satoshi = Person(172, “Satoshi”);// Add that person to the Array:people.push(satoshi);
We can also combine these together and do them in one line of code to keep things clean:
people.push(Person(16, “Vitalik”));
State Variables
State variables are permanently stored in contract storage. This means they’re written to the Ethereum blockchain. Think of them like writing to a DB.
Example:
contract Example {// This will be stored permanently in the blockchainuint myUnsignedInteger = 100;}
In this example contract, we created a uint called myUnsignedInteger and set it equal to 100.
Loop in solidity :
If -else:
// if-else can be used like thisif(input1 == 2)a = 1;elsea = 0;
Conditional Operator :
// Conditional Operator can be used like thisbool isTrue = (a == 1)? true: false;// will show an error because//there is no type conversion from non-boolean to booleanif (1) {//some work}
For loop :
// for loop can be used like thisfor(uint i=0; i<=50; i++){a++;if(a == 4) break;}
While loop :
// while can be used like thiswhile(input1 >= 0){if(input1 == 5)continue;input1 = input1–1;a++;}
Do-while loop :
// do while can be used like thisdo{a — ;} (while a>0);
Visibility in solidity :
4 types of visibility in solidity :
- Public
- Private
- Internal
- External
Public : In Solidity, functions are public by default. This means anyone (or any other contract) can call your contract’s function and execute its code.
Private : Private functions are only visible for the contract they are defined in and not in derived contracts.
Let’s look at how to declare a private function:
uint[] numbers;function _addToArray(uint _number) private {numbers.push(_number) {}
Note : It’s convention to start private function names with an underscore (_).
Internal : internal is the same as private, except that it’s also accessible to contracts that inherit from this contract.
Example of internal function :
contract Sandwich {uint private sandwichesEaten = 0;function eat() internal {sandwichesEaten++;}}contract BLT is Sandwich {uint private baconSandwichesEaten = 0;function eatWithBacon() public returns (string) {baconSandwichesEaten++;// We can call this here because it’s internaleat();}}
External : external is similar to public, except that these functions can ONLY be called outside the contract — they can’t be called by other functions inside that contract.
Note : As for state variables, external cannot be used, and by default they are internal.
constructor: a function with the same name as the contract
pragma solidity ^0.4.15;contract PrivateConstructor {string public title;function PrivateConstructor() {title = “Private Constructor”;}}
Note : contract constructor should be only public or internal.
What is msg.sender and msg.value ?
msg.sender :
A contract’s msg.sender is the address currently interacting with the contract. Be it a human or another contract.
So if a human is interacting with a contract, msg.sender is the address of the person. And if another contract (B) is interacting with the contract, the contract (B)’s address becomes msg.sender.
msg.value : msg.value is a way to see what was sent to the contract.
Return Values
To return a value from a function, the declaration looks like this:
string greeting = “What’s up dog”;function sayHello() public returns (string) {return greeting;}
Note : In Solidity, the function declaration contains the type of the return value (in this case string).
Events :
Events are a way for our contract to communicate that something happened on the blockchain to your app front-end, which can be ‘listening’ for certain events and take action when they happen.
Example:
// declare the eventevent IntegersAdded(uint x, uint y, uint result);function add(uint _x, uint _y) public {uint result = _x + _y;// fire an event to let the app know the function was called:IntegersAdded(_x, _y, result);return result;}
Your app front-end could then listen for the event. A javascript implementation would look something like:
YourContract.IntegersAdded(function(error, result) {// do something with result}
Function modifiers
View :
The above function doesn’t actually change state in Solidity — e.g. it doesn’t change any values or write anything.
So in this case we could declare it as a view function, meaning it’s only viewing the data but not modifying it:
function sayHello() public view returns (string) {
Pure :
Solidity also contains pure functions, which means you’re not even accessing any data in the app. Consider the following:
function _multiply(uint a, uint b) private pure returns (uint) {return a * b;}
This function doesn’t even read from the state of the app — its return value depends only on its function parameters. So in this case we would declare the function as pure.
Payable Keyword in Solidity :
Note : Use Payable as Keyword, not function name
It’s impossible to have payable() as a function name as it is a reserved keyword.
Payable is a modifier that can be added to a function. You may use payable only in addition to existing functions like:
function deposit() payable {};function register(address sender) payable {};function () payable {}
Usually, there is a no name function to accept ether to be sent to a contract which is called a fallback function:
function () payable {};
But you may have more than one payable annotated functions that are used to perform a different tasks.
Example: How to register deposit to your contract:
function deposit() payable {deposits[msg.sender] += msg.value;};
Note: If a function is not marked payable and you try to send Ether to it , the function will reject your transaction.
Inheritance :
One feature of Solidity that makes this more manageable is contract inheritance:
contract Doge {function catchphrase() public returns (string) {return “So Wow CryptoDoge”;}}contract BabyDoge is Doge {function anotherCatchphrase() public returns (string) {return “Such Moon BabyDoge”;}}
BabyDoge inherits from Doge. That means if you compile and deploy BabyDoge, it will have access to both catchphrase() and anotherCatchphrase() (and any other public functions we may define on Doge).
Multiple inheritance :
in Solidity, your contract can inherit from multiple contracts as follows:
contract SatoshiNakamoto is chirag, kapil {}
As you can see, when using multiple inheritance, you just separate the multiple contracts you’re inheriting from with a comma, ,. In this case, our contract is inheriting from chirag and kapil.
import :
When you have multiple files and you want to import one file into another, Solidity uses the import keyword:
import “./someothercontract.sol”;contract newContract is SomeOtherContract {}
So if we had a file named someothercontract.sol in the same directory as this contract (that’s what the ./ means), it would get imported by the compiler.
require :
require function will throw an error and stop executing if some condition is not true:
function sayHiToVitalik(string _name) public returns (string) {// Compares if _name equals “Vitalik”. Throws an error and exits if not true.// (Side note: Solidity doesn’t have native string comparison, so we// compare their keccak256 hashes to see if the strings are equal)require(keccak256(_name) == keccak256(“Vitalik”));// If it’s true, proceed with the function:return “Hi!”;}
If you call this function with sayHiToVitalik(“Vitalik”), it will return “Hi!”. If you call it with any other input, it will throw an error and not execute.
Thus require is quite useful for verifying certain conditions that must be true before running a function.
assert :
assert is similar to require but require will refund the user the rest of their gas when function fails whereas assert will not.
c = a+b;assert(c > b);
Function Modifiers
A function modifier looks just like a function, but uses the keyword modifier instead of the keyword function. And it can’t be called directly like a function can — instead we can attach the modifier’s name at the end of a function definition to change that function’s behavior.
Let’s take a closer look by examining onlyOwner:
/*** @dev Throws if called by any account other than the owner.*/modifier onlyOwner() {require(msg.sender == owner);_;}
We would use this modifier as follows:
contract MyContract is Ownable {event LaughManiacally(string laughter);// Note the usage of `onlyOwner` below:function likeABoss() external onlyOwner {LaughManiacally(“Hahahahaha”);}}
Notice the onlyOwner modifier on the likeABoss function. When you call likeABoss, the code inside onlyOwner executes first. Then when it hits the _; statement in onlyOwner, it goes back and executes the code inside likeABoss.
So while there are other ways you can use modifiers, one of the most common use-cases is to add quick require check before a function executes.
In the case of onlyOwner, adding this modifier to a function makes it so only the owner of the contract (you, if you deployed it) can call that function.
Function modifiers with arguments
function modifiers can also take arguments. For example:
// A mapping to store a user’s age:mapping (uint => uint) public age;// Modifier that requires this user to be older than a certain age:modifier olderThan(uint _age, uint _userId) {require(age[_userId] >= _age);_;}// Must be older than 16 to drive a car (in the US, at least).// We can call the `olderThan` modifier with arguments like so:function driveCar(uint _userId) public olderThan(16, _userId) {// Some function logic}
You can see here that the olderThan modifier takes arguments just like a function does. And that the driveCar function passes its arguments to the modifier.
Typecasting
Sometimes you need to convert between data types. Take the following example:
uint8 a = 5;uint b = 6;// throws an error because a * b returns a uint, not uint8:uint8 c = a * b;// we have to typecast b as a uint8 to make it work:uint8 c = a * uint8(b);
In the above, a * b returns a uint, but we were trying to store it as a uint8, which could cause potential problems. By casting it as a uint8, it works and the compiler won’t throw an error.
What is overflow and underflow ?
An overflow/underflow happens when an arithmetic operation reach the maximum or minimum size of the type.
Overflow :
uint8 number = 255;number++;
In this case we caused to overflow so number is so like a clock going from 23:59 to 00:00.
Underflow : If we subtract 1 from uint that equals to 0 it will now equal to 255.
Safemath :
Openzeppelin has created a library called safemath that prevents these issue.
Safemath has 4 function :
- add
- sub
- mul
- div
Example :
contract MyContract {using SafeMath for uint256;uint256 result;function SafeAdd(uint256 a, uint256 b) {result = 0;result = a.add(b);}}
When using the SafeMath library, the results of this operations will be checked and an error will be thrown stopping the execution of your smart contract.
Sample of smart contract :
pragma solidity ^0.4.18;contract TodoList {
TodoItem[] public todoItems;struct TodoItem {
bytes32 value;
bool active;
}function addTodoItem(bytes32 _value) returns (bool success) {
TodoItem memory todoItem;
todoItem.value = _value;
todoItem.active = false;todoItems.push(todoItem);
return true;
}function getTodoItems() constant returns (bytes32[], bool[]) {
uint length = todoItems.length;bytes32[] memory values = new bytes32[](length);
bool[] memory actives = new bool[](length);for (uint i = 0; i < length; i++) {
values[i] = todoItems[i].value;
actives[i] = todoItems[i].active;
}return (values, actives);
}function deleteTodoItem(uint index) returns (bool success) {
if (index >= todoItems.length) return;for (uint i = index; i < todoItems.length — 1; i++){
todoItems[i] = todoItems[i+1];
}delete todoItems[todoItems.length — 1];
todoItems.length — ;
return true;
}
}
To deploy you contract please read my next article where I explained deploy smart contract in various ways.