October 24, 2018

Solidity grammar

❑ The deployed Ethereum smart contract(DApp) is immutable.
❑ Solidity file extension.: *.sol
❑ Version pragma: It is the starting source code of a DApp, and tells you the version of Solidity.

pragma solidity ^0.4.24;


❑ Contract: The basic components of the Ethereum DApp. All variables and functions are in the Contract.

Contract HelloWorld {
}


❑ State variables are permanently stored in Contract storage.
❑ exponential operator(x^2) : x ** 2
❑ Data type : int, uint(Unsigned integer) == uint256, uint8, uint16, uint32, struct, string, array, mapping, address.
❍ uint
- Generally, uint8 uses the same storage space as uint256.
- But, uint8 in a struct uses less space than uint256.

❍ Struct struct Person { uint age; string name; }
// The continuous uint32 is packed when it stored. : struct abc2 { uint32 a; uint32 b; }
// The spaced uint32 is packed when it stored : struct abc2 { uint32 a; uint c; uint32 b; }

❍ Array uint[2] arr1; // A fixed array of uints.
string[5] arr2; // A fixed array of strings. 
Person[] people // A dynamic array of Person structs. 
uint[] arr3; // A dynamic array of uints. 
uint[] memory values = new uint[](3); // Allocate memory. 
values.push(1); // The push function returns the current length of the array. 
values.push(2); 
values.length // Length of the array.

❍ mapping : The data type of the "key => value" format.
// account => data.
mapping (address => uint) public favoriteNumber;

// The update of a mapping value.
favoriteNumber[msg.sender] = _Anumber;

// The call of a mapping value.
favoriteNumber[msg.sender]


❍ address: The datatype that stores the Ethernet address (0x~~~~~~~~~).
* The address refers to a specific user(Wallet) or smart contract.

❑ Function modifier: It is the syntax to control the function of a function.
* Generally, It is used to verify that the requirements are fulfilled before the function is executed.
* There are "Visibility modifier", "State modifier", "Custom modifier" etc.
* Several modifiers can be used together.
❑ Visibility modifier: It is the syntax that specifies where variables/functions can be called.
❍ Private [Variable | Function] : It is the Variables/functions that only functions in the Contract can call.
❍ Public [Variable | Function] : It is the Variables/functions that other Contract can call.
* If you do not specify a "visibility modifier", the Solidity function is declared public.
* When a public variable is declared, a public "getter()" function with the same name is created internally.
❍ Internal [Variable | Function] : It is "private modifier" but, It is also accessible from contracts that inherit the defined Contract.
❍ External [Variable | Function] : It is "public modifier" but, It is only accessible from outside the Contract.

// The dynamic array of Zombie structs. Other Contracts can use this array.
Zombie[] public zombies;


// The method of making a private function.
// The underbar character is used to mean a local variable/function. "_name" and "_dna" are local variables. "_createZombie" is a private function.
function _createZombie(string _name, uint _dna) private {}


❑ State modifier: It is the syntax that specifies how the Solidity source code interacts with the blockchain.
* "external [View | Pure]" function does not consume gas because it does not access the block.
❍ View: The read-only function. It just read stored data.
* Query occurred. No transaction occurred.
❍ Pure: The function that calculates and returns a value using a parameter. The side-effect(Changing variable's value)does not occur.

// This function returns a uint value.
// This function is a view function.
function _generateRandomDna(string _str) private view returns (uint) {}


❑ Custom modifier: It is the user-defined syntax.

// When the "setLevelUpFee()" function is called, the "onlyOwner()" modifier is executed first.
// The "onlyOwner()" modifier allows only the contract owner for use the function.
modifier onlyOwner() {
    require(msg.sender == owner);
    _; // Return to the function that called modifier.
}
function setLevelUpFee(uint _fee) external onlyOwner {
    levelUpFee = _fee;
}

// Modifier can use parameters.
modifier aboveLevel(uint _level, uint _zombieId) {
    require(zombies[_zombieId].level >= _level);
    _;
}

function changeName(uint _zombieId, string _newName) external aboveLevel(2, _zombieId) {
}


❑ Payable modifier: It is the syntax that is used in ETH coin transfer.
* The ETH that is transferred to a Contract is kept in the Contract.

[Contract]
contract OnlineStore {
    function buySomething() external payable {
        // Checking that 0.001 ETH is transmitted from the client when executing the function.
        // The data type of 0.001 ether is uint.
        require(msg.value == 0.001 ether);
    }

    // The source code for ETH withdrawals stored in the contract.
    function withdraw() external onlyOwner {
         // this.balance : The total ETH balance stored in the contract.
        owner.transfer(this.balance);
    }
}

[Client]
// The client source code written in web3.js.
// You can only send "value" to the function for which the payable modifier is set.
OnlineStore.buySomething({from: web3.eth.defaultAccount, value: web3.utils.toWei(0.001)});


❑ keccak256(): It is the SHA3-based hash function that returns a hexadecimal value of 256 bits.

// Generating a SHA-3 value.
// 6e91ec6b618bb462a4a6ee5aa2cb0e9cf30f7a052bb467b0ba58b8748c00d2e5
keccak256("aaaab");
// b1f078126895a1424524de5321b339ab00408010b7cf0e6ed451514981e58aa9
keccak256("aaaac");

// How to generate random numbers using hash values(0 to 99).
// Timestamp of current time(now), a msg.sender and the temporary value(nonce) are needed.
// Because a malicious node may try to write to a block only when the desired value comes out, this code is vulnerable.
uint randNonce = 0;
uint random = uint(keccak256(now, msg.sender, randNonce)) % 100;
randNonce++;
uint random2 = uint(keccak256(now, msg.sender, randNonce)) % 100;


❑ Typecasting

uint8 a1 = 5;
uint a2 = 6;

// uint256 → uint8
uint8 a3 = uint8(a2);


❑ Fallback function : No-name function. It is the function that is called when calling a function that does not exist in the contract. The fallback function prevents the error caused by not executing.

function () {
}


❑ event: It is the syntax that occurs logs.

// The declaring the log to be generated.
event NewZombie(uint zombieId, string name, uint dna);

// Each time the "_createZombie()" function is called, logs of "id", "_name", "_dna" values are generated.
function _createZombie(string _name, uint _dna) private {
    NewZombie(id, _name, _dna);
}


❑ msg.value: The amount of ETH sent.
❑ msg.sender: The person or the smart contract that called the current function.
❑ require: It is the syntax to raise an error message and stop execution when the condition is not true.

// Checking that "_name"'s value is the same as "abc".
// Solidity has no default string comparing function.
require(keccak256(_name) == keccak256("abc"));

// If the above condition is true, the following source code will be executed:
return "Hi!";


❑ Inheritance

contract Doge {
    function catchphrase() public returns (string) {
        return "So Wow CryptoDoge";
    }
}

// "BabyDoge" contract inherits "Doge" and "ERC721" contract.
contract BabyDoge is Doge, ERC721 {
    function anotherCatchphrase() public returns (string) {
        return "Such Moon BabyDoge";
    }
}


❑ import : The syntax to load solidity files(*.sol).

import "./someothercontract.sol";


❑ Storage: The variable that is used to store a value permanently in the blockchain.
* High cost syntax.
* [Array].push() changes the size of the array.
❑ Memory: The variable that is used to store a value temporarily.
* Low cost syntax compared to storage.
* [Array].push() doesn't change the size of the array.
❑ Without storage/memory syntax, If the storage/memory syntax doesn't exist, state variables(the Variables declared outside functions) are stored in storage, and variables in functions are stored in memory.

contract SandwichFactory {
    struct Sandwich {
        string name;
        string status;
    }

    Sandwich[] sandwiches;

    function eatSandwich(uint _index) public {

        // "mySandwich" is a pointer pointing "sandwiches [_index]".
        Sandwich storage mySandwich = sandwiches[_index];

        // This changes the storage's "status" value permanently.
        mySandwich.status = "Eaten!";

        // "anotherSandwich" copies the value of "sandwiches [_index]".
        Sandwich memory anotherSandwich = sandwiches[_index + 1];

        // This changes the "status" value of memory.
        anotherSandwich.status = "Eaten!";
    }
}


❑ Interface: The syntax to use a contract that you do not own.

// The interface declaration has the same format as a contract.
contract KittyInterface {

    // Copy the function from the name until the returns syntax and put a semicolon at the end.
    function getKitty(uint256 _id) external view returns (
        bool isGestating,
        bool isReady,
        uint256 cooldownIndex,
        uint256 nextActionAt,
        uint256 siringWithId,
        uint256 birthTime,
        uint256 matronId,
        uint256 sireId,
        uint256 generation,
        uint256 genes
    );
}


contract test {
    // The address of the smart contract to use.
    address ckAddress = 0x06012c8cf97BEaD5deAe237070F9587f8E7A266d;

    // This initializes the interface.
    KittyInterface kittyContract = KittyInterface(ckAddress);

    // Now you can use the smart contract.
    // This stores the last of the 10 returned values in "kittyDna".
    uint kittyDna;
    (,,,,,,,,,kittyDna) = kittyContract.getKitty(_kittyId);
}


❑ Constructor: The function with the same name as the contract. It is executed once when the contract is created.

contract Ownable {
    function Ownable() public {
        owner = msg.sender;
    }
}


❑ Time(The value related in the time.)

/*
now // Returns UNIX timestamp(32 Bits uint).
seconds
minutes // Minute of the current time converted in seconds.
5 minutes // 300(60*5)
hours
1 hours // 3600(60*60)
days
weaks
years
*/

uint lastUpdated;
function updateTimestamp() public {
    lastUpdated = now;
}

// It returns "true" if it has been 5 minutes since the "updateTimestamp" function was called.
function fiveMinutesHavePassed() public view returns (bool) {
    return (now >= (lastUpdated + 5 minutes));
}


❑ For

for(uint i=0; i<10; i++) {
}


❑ If

if (var1 == var2) {
} else {
}


❑ ERC721 token
❍ function balanceOf(): It returns the number of tokens held by "_owner".

function balanceOf(address _owner) public view returns (uint256 _balance) {
    return ownerZombieCount[_owner];
}


❍ function ownerOf(): It returns the address that owns "_tokenId".

function ownerOf(uint256 _tokenId) public view returns (address _owner) {
    return zombieToOwner[_tokenId];
}


❍ function transfer(): It transfers the token from "_from" address to "_to" address.

function _transfer(address _from, address _to, uint256 _tokenId) private {
    ownerZombieCount[_to]++;
    ownerZombieCount[_from]--;
    zombieToOwner[_tokenId] = _to;

    Transfer(_from, _to, _tokenId); // The event defined by ERC721.
}

// The modifier that checks access permission to a token.
modifier onlyOwnerOf(uint _zombieId) {
    require(msg.sender == zombieToOwner[_zombieId]);
_;
}

function transfer(address _to, uint256 _tokenId) public onlyOwnerOf(_tokenId) {
    _transfer(msg.sender, _to, _tokenId);
}


❍ function approve(): It approves tokens that is transferred.

function approve(address _to, uint256 _tokenId) public onlyOwnerOf(_tokenId) {
    zombieApprovals[_tokenId] = _to;
    Approval(msg.sender, _to, _tokenId); // The event defined by ERC721.
}


❍ function takeOwnership(): It calls "_transfer()" after ensuring that the "msg.sender" is approved to have a token.

function takeOwnership(uint256 _tokenId) public {
    require(zombieApprovals[_tokenId] == msg.sender);
    address owner = ownerOf(_tokenId);

    // Since msg.sender calls this function, it becomes a recipient.
    _transfer(owner, msg.sender, _tokenId);
}


❑ The Library is a special kind of contract In Solidity.
❑ Library SafeMath

library SafeMath {

    // Be careful not to input any values other than uint256(e.g. uint16, uint32 etc.).
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a + b;

        // Check overflow..
        // "require()" and "assert()" are equivalent in that they return an error when the condition is not satisfied.
        // "require()" returns the remaining gas when the condition is not satisfied, but "assert()" doesn't return the remaining gas.
        assert(c >= a);
        return c;
    }
}

contract abc {
    // This applies the SafeMath library to the data type.
    using SafeMath for uint;

    uint a = 5;
    // The variable "a" is entered as the first argument of "add()".
    uint b = a.add(3); // 5 + 3 = 8
    uint c = a.mul(2); // 5 * 2 = 10
}


❑ Comment: Natspec comment is the standard comment format in Solidity.
❍ // @title: The title of a comment.
❍ // @autor: The author of a comment.
❍ // @notice: The description of a source code.
❍ // @dev: The description for developers.
❍ // @param: The parameter used by the function..
❍ // @return: The value returned by the function.