Pages

Solidity in depth series part #1

 

Introduction

Ethereum is a decentralized, open-source blockchain with smart contract functionality. Ether is the native cryptocurrency of the platform. After Bitcoin, it is the largest cryptocurrency by market capitalization.Ethereum has its own programming language, called Solidity. As a blockchain network, Ethereum is a decentralized public ledger for verifying and recording transactions. 


Basics of Solidity and Ethereum


Variables and Math operations

Solidity is a statically typed language, which means that variable's datatype must be specified upon declaration.

There are 3 types of variables in Solidity

  1. State Variables : values permanently stored in contract storage
  2. Local Variables : values stored in memory, impermanently. Declared inside a function
  3. Global Variables : special variables which exists in global namespace


Global Variables in Solidity

blockhash(uint blockNumber) returns (bytes32) : Hash of the given block - only works for 256 most recent, excluding current, blocks

block.coinbase (address payable): Current block miner's address

block.difficulty (uint): Current block difficulty

block.gaslimit (uint): Current block gaslimit

block.number (uint): Current block number

block.timestamp (uint): Current block timestamp as seconds since unix epoch

gasleft() returns (uint256): Remaining gas

msg.data (bytes calldata): Complete calldata

msg.sender (address payable): Sender of the message (current caller)

msg.sig (bytes4): First four bytes of the calldata (function identifier)

msg.value (uint): Number of wei sent with the message

now (uint): Current block timestamp

tx.gasprice (uint): Gas price of the transaction

tx.origin (address payable): Sender of the transaction


Storage vs Memory

In solidity there are two locations to store variables, in storage and in memory. Memory in Solidity is a temporary place to store data whereas Storage holds data between function calls. The Solidity Smart Contract can use any amount of memory during the execution but once the execution stops, the Memory is completely wiped off for the next execution. Whereas Storage on the other hand is persistent, each execution of the Smart contract has access to the data previously stored on the storage area.

It is always better to use Memory for intermediate calculations and store the final result in Storage.

  • State variables and Local Variables of structs, array are always stored in storage by default.
  • Function arguments are in memory.
  • Whenever a new instance of an array is created using the keyword ‘memory’, a new copy of that variable is created. Changing the array value of the new instance does not affect the original array.


Storing time in solidity

Solidity provides some native units for dealing with time.

The variable now will return the current unix timestamp of the latest block (the number of seconds that have passed since January 1st 1970).

Solidity also contains the time units seconds, minutes, hours, days, weeks and years. These will convert to a uint of the number of seconds in that length of time. So 1 minutes is 60, 1 hours is 3600 (60 seconds x 60 minutes), 1 days is 86400 (24 hours x 60 minutes x 60 seconds), etc.

Here's an example of how these time units can be useful:

uint lastUpdated;

// Set `lastUpdated` to `now`
function updateTimestamp() public {
lastUpdated = now;
}

// Will return `true` if 5 minutes have passed since `updateTimestamp` was
// called, `false` if 5 minutes have not passed
function fiveMinutesHavePassed() public view returns (bool) {
return (now >= (lastUpdated + 5 minutes));
}


Variable conversions in solidity

... 


Exercise:

What will be the value in the numbers array after this code has run once?

contract helloGeeks
{
int[] public numbers;
function Numbers() public
{
numbers.push(1);
numbers.push(2);
int[] memory myArray = numbers;

myArray[0] = 0;
}
}

Write a function for generating random number in solidity using global variables


Data Structures


Structs

Array 

dynamic and fixed, public array gets their own getter functions

Array of structs


add to array


uint[] public numbers;

numbers.push(12)


getting length of an array

uint length_of_array = numbers.push(99)


Mappings

key-value store for storing and retrieving data

mapping (address => uint) luckyNumber;



function setMyNumber(uint _myNumber) public {

luckyNumber[msg.sender] = _myNumber;

}



function myNumberIs() public view returns (uint) {

// Retrieve the value stored in the sender's address

// Will be `0` if the sender hasn't called `setMyNumber` yet

return luckyNumber[msg.sender];

}


When to use an array and when to use a mapping ?

Use an array to iterate over objects and use a mapping for quick lookups.


Addresses in Ethereum

The Ethereum blockchain is made up of accounts, which you can think of like bank accounts. An account has a balance of Ether (the currency used on the Ethereum blockchain), and you can send and receive Ether payments to other accounts, just like your bank account can wire transfer money to other bank accounts.


Each account has an address, which you can think of like a bank account number. It's a unique identifier that points to that account, and it looks like this:


retrieving address inside a function using a global variable msg.sender



Functions


public and private


Internal and External

internal is the same as private, except that it's also accessible to contracts that inherit from this contract. 

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.


Pure and View

Pass arguments by value vs passing reference


Constructors

Special function that has the same name as the contract. It will get executed only one time, when the contract is first created.


Function Modifiers:

Modifiers are kind of half-functions that are used to modify other functions, usually to check some requirements prior to execution.


<modifier example>



Working with Events

//declare the event

event AdditionEvent(uint a, uint b, uint sum);

//trigger the event

function add(uint _a, uint _b) public returns(uint){
uint sum = _a + _b;
// fire the event
emit AdditionEvent(_a, _b, sum);
return sum;
}

//listen to the event
MyContract.AdditionEvent(function(error, result){
console.log(result);
});


event Transfer(address indexed from, address indexed to, uint256 value);

Q What does the "indexed" keyword do in the below line of code? I'm guessing it just tells the event object that the following input should be logged?

The indexed parameters for logged events will allow you to search for these events using the indexed parameters as filters.


Q Can we use it other places ie outside of events?

The indexed keyword is only relevant to logged events.


Require in solidity

Revert in solidity



Working with web3.js


Exercise : Write a function to compare two strings in solidity.

function sayHiToVitalik(string memory _name) public returns (string memory) {
  // 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(abi.encodePacked(_name)) == keccak256(abi.encodePacked("Vitalik")));
  // If it's true, proceed with the function:
  return "Hi!";
}


Contracts

Inheritance

contract Groot {
function catchphrase() public returns (string memory) {
return "I am groot";
}
}

contract BabyGroot is Doge {
function anotherCatchphrase() public returns (string memory) {
return "I am smol groot";
}
}


Multifile Inheritance

import "./Groot.sol";

contract BabyGroot is Groot {
    ...
}


Interacting with another contracts by declaring an interface

// sample contract luckynumber.sol
contract LuckyNumber {
mapping(address => uint) numbers;

function setNum(uint _num) public {
numbers[msg.sender] = _num;
}

function getNum(address _myAddress) public view returns (uint) {
return numbers[_myAddress];
}
}

// declaring inheritance in another contract MyContract.sol
contract NumberInterface {
function getNum(address _myAddress) public view returns (uint);
}

// using the above declared interface
contract MyContract {
address NumberInterfaceAddress = 0xab38...
// ^ The address of the FavoriteNumber contract on Ethereum
NumberInterface numberContract = NumberInterface(NumberInterfaceAddress);
// Now `numberContract` is pointing to the other contract

function someFunction() public {
// Now we can call `getNum` from that contract:
uint num = numberContract.getNum(msg.sender);
// ...and do something with `num` here
}
}



Gas optimization tips


Struct Packing to save gas

struct options{
uint amount;
uint price;
uint expiry;
bool exercised;
}
uint defaults to uint256 , and bool is uint8 in solidity
so the above struct occupies 4 storage slots of size 256bits each.
struct options{
uint128 amount;
uint64 price;
uint64 expiry;
bool exercised;
}
After some modifications we are able to pack the amount and price variable as well as the expiry and exercised variable together. So that the options struct now occupies only 2 storage slots.
Further optimization is possible
struct options{
uint64 amount;
uint56 price; // <-----------
uint64 expiry;
bool exercised;
}
By changing the price variable from uint64 to uint56 we are able to pack the whole struct in just one storage space since 64+56+64+8 = 256

uint56 is more than enough for price, as it can fit numbers from 0 to 2**56 - 1.

So now the options struct only costs one storage slot worth of gas.



Security Best Practices

An important security practice is to examine all your public and external functions, and try to think of ways users might abuse them. Remember — unless these functions have a modifier like onlyOwner, any user can call them and pass them any data they want to.

Solidity Gotchas


compile learnings from interview questions etc


underflow and overflow in solidity


Source

https://docs.soliditylang.org/en/v0.5.5/structure-of-a-contract.html#:~:text=State%20variables%20are%20variables%20whose,State%20variable%20%2F%2F%20...%20%7D


https://www.tutorialspoint.com/solidity/solidity_types.htm


https://www.bitdegree.org/learn/solidity-types


https://www.geeksforgeeks.org/solidity-types/