Smart Contract Tutorial (1) — Ethereum Solidity

Jaher
Haderech_DEV
Published in
3 min readApr 28, 2022

Introduction

EVM(Ethereum Virtual Machine) diagram

In Ethereum, Smart contracts are stored in a block as bytecodes format. When a transaction which has purpose to use a smart contract is transferred to a node, then its bytecodes are executed by the EVM(Ethereum Virtual Machine).

The most widely used smart contract languages are Solidity and Vyper in Ethereum.

  • Solidity : Most popular, has been used for a long time and is constantly being updated.
  • Vyper : Highly influenced by Python, a Contract-Oriented language.

This tutorial describes the followings:
1. How to run a local testnet.
2. How to build Solidity example contract.
3. How to deploy & interact with deployed contract.

Installation Geth CLI

  • Ubuntu
$ add-apt-repository -y ppa:ethereum/ethereum
$ apt-get update
$ apt-get install ethereum
  • MacOs
$ brew tab ethereum/ethereum
$ brew install ethereum

Run Local Testnet

Create genesis block

  • Create signer account. Do not forget password you typed.
$ geth account new --datadir /tmp/testnet
  • Create genesis.json
    - chainId : Testnet ID
    - ethash : Use PoW algorithm
    - difficulty : The difficulty of problem for mining a block. 0x200000 means there is a 1 / 2²¹ chance to mining a block.
    - gasLimit : The maximum gas any blocks on this chain can support.
    - alloc : set initial balance to address
$ vi genesis.json  
{
"config": {
"chainId": 15,
"homesteadBlock": 0,
"byzantiumBlock": 0,
"constantinopleBlock": 0,
"petersburgBlock": 0,
"istanbulBlock": 0,
"eip150Block": 0,
"eip155Block": 0,
"eip158Block": 0,
"ethash": {}
},
"difficulty": "0x200000",
"gasLimit": "8000000",
"alloc": {
"17b27648b14af118df79155d268c07063a3e1c15": {
"balance": "100000000000"
},
"e43691995fa6abc96d29aece2213d7efe73fefb6": {
"balance": "400000"
}
}
}

Initialize and run

$ geth init --datadir /tmp/testnet genesis.json
$ geth --datadir /tmp/testnet --networkid 15 --nodiscover --maxpeers=0 --mine --miner.threads=1 --miner.etherbase=0x17b27648b14af118df79155d268c07063a3e1c15 --http --allow-insecure-unlock

Start Console

There are two ways to use console command line:

  1. start geth with console
    add “console” after flags same as above running command

$ geth <other-flags...> console

2. or run this command in another terminal

$ geth attach /tmp/testnet/geth.ipc <http://127.0.0.1:30303>

console example :

Welcome to the Geth JavaScript console!instance: Geth/v1.10.17-stable/darwin-amd64/go1.18
coinbase: 0x17b27648b14af118df79155d268c07063a3e1c15
at block: 0 (Thu Jan 01 1970 07:30:00 GMT+0730 (+0730))
datadir: /tmp/testnet
modules: admin:1.0 debug:1.0 eth:1.0 ethash:1.0 miner:1.0 net:1.0 personal:1.0 rpc:1.0 txpool:1.0 web3:1.0
To exit, press ctrl-d or type exit
> eth.getBalance("17b27648b14af118df79155d268c07063a3e1c15")
300000
> eth.getBalance("e43691995fa6abc96d29aece2213d7efe73fefb6")
400000

Unlock account

You need unlock account to send transaction which requires account sign

  • Args
    1. Account address
    2. Account password
    3. Unlock duration (If set 0, then it unlocks until testnet stop)

On geth console:

> personal.unlockAccount("0x17B27648B14Af118df79155d268C07063A3E1C15", <password>, 0)

Write & Deploy contract

Install Solidity

  • Ubuntu
$ sudo add-apt-repository ppa:ethereum/ethereum
$ sudo apt update
$ sudo apt install solc
  • MacOs
$ brew update
$ brew upgrade
$ brew tap ethereum/ethereum
$ brew install solidity

check version

$ solc --version
solc, the solidity compiler commandline interface
Version: 0.8.13+commit.abaa5c0e.Darwin.appleclang

If you want see other way to install solidity, visit official document page (https://docs.soliditylang.org/en/latest/installing-solidity.html)

Write contract

Example from https://solidity-by-example.org/app/ether-wallet

pragma solidity ^0.8.10;contract EtherWallet {
address payable public owner;
constructor() {
owner = payable(msg.sender);
}
receive() external payable {} function withdraw(uint _amount) external {
require(msg.sender == owner, "caller is not owner");
payable(msg.sender).transfer(_amount);
}
function getBalance() external view returns (uint) {
return address(this).balance;
}
}
  • Compile
    Binary & ABI will be used at deploy, interact contract
$ solc <contract_file_name>.sol --optimize --bin --abi======= ethWallet.sol:EtherWallet =======
Binary:
608060405234801561001057600080fd5b50600080546001600160a01b03191633179055610192806100326000396000f3fe6080604052600436106100385760003560e01c806312065fe0146100445780632e1a7d4d146100645780638da5cb5b1461008657600080fd5b3661003f57005b600080fd5b34801561005057600080fd5b506040514781526020015b60405180910390f35b34801561007057600080fd5b5061008461007f366004610143565b6100be565b005b34801561009257600080fd5b506000546100a6906001600160a01b031681565b6040516001600160a01b03909116815260200161005b565b6000546001600160a01b031633146101125760405162461bcd60e51b815260206004820152601360248201527231b0b63632b91034b9903737ba1037bbb732b960691b604482015260640160405180910390fd5b604051339082156108fc029083906000818181858888f1935050505015801561013f573d6000803e3d6000fd5b5050565b60006020828403121561015557600080fd5b503591905056fea264697066735822122009fbca2bd319bb9a2b5d8011e29f9b126fb2e41670f6e1a20c73961c413e34dc64736f6c634300080d0033
Contract JSON ABI
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"getBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address payable","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]

Deploy contract

On geth console:

> eth.sendTransaction({
from: "0x17B27648B14Af118df79155d268C07063A3E1C15",
data: <Contract_Binary>})

You must check the address of contract on geth log

INFO [04-14|00:39:07.225] Submitted contract creation              hash=0x2d4df5ae1ce9775aee23321c7b26ad3c18137e84ab1807b80fbebfbca5755aef from=0x17B27648B14Af118df79155d268C07063A3E1C15 nonce=3 contract=**0x81572Ae421E40aB680C62f49e7A42CE17E29e0BE** value=0

Interacting with the deployed contract

Check contract address & account balance

> eth.sendTransaction({from: '0x17B27648B14Af118df79155d268C07063A3E1C15', to: '0x81572Ae421E40aB680C62f49e7A42CE17E29e0BE**'**, value: '10000000000000000000'}) 
...
after transaction is included in a block
...
> eth.getBalance('0x81572Ae421E40aB680C62f49e7A42CE17E29e0BE')
10000000000000000000
> var contractAbi = eth.contract(<Contract JSON ABI>)
> var myContract = contractAbi.at('0x81572Ae421E40aB680C62f49e7A42CE17E29e0BE**'**)
> var getData = myContract.withdraw.getData(10000000000000000000);
> eth.sendTransaction({to: "0x81572Ae421E40aB680C62f49e7A42CE17E29e0BE", from: "0x17b27648b14af118df79155d268c07063a3e1c15", data: getData});
...
after transaction is included in a block
...
> eth.getBalance('0x81572Ae421E40aB680C62f49e7A42CE17E29e0BE')
0

References

https://ethereum.org/en/developers/docs/evm/
https://geth.ethereum.org/docs/
https://ethereum.org/en/developers/tutorials/
https://web3js.readthedocs.io/en/v1.2.11/index.html
https://gist.github.com/giladoved/bb62116be3a6d4e5fc02ee3266afc6ce
https://ethereum.stackexchange.com/questions/8736/how-to-call-my-contracts-function-using-sendtransaction

--

--