이더리움 맛보기 #1

오상택
26 min readDec 3, 2018

--

목차

  • 학습 목표
  • 지식의 저주
  • 개발자와 유저의 벽
  • Smart Contract 에서 Hello World
  • 토큰 발행
  • 크라우드 세일
  • web3.js를 이용한 서비스 구현
  • 탈중앙화? 중앙화?
  • 앞으로의 블록체인은?

학습 목표

  1. Hello World
  2. 토큰 발행
  3. 토큰 세일
  4. web3.js 를 이용한 서비스 구축
  5. 블록체인 개념

지식의 저주

혹시 지식의 저주에 걸리진 않으셨나요?

지식의 저주란?

다른 사람의 행동이나 반응을 예상할 때, 자기가 알고 있는 지식을 다른 사람도 알 것 이라는 고정관념에 매몰되어 나타나는 왜곡된 인식이다.

토니 스타크는 타노스라는 무서운 존재를 알고 있는데 다른 사람도 알 것 이라 생각하고 모르는 것 같으면 짜증을 내곤 한다

개발자와 유저의 벽

  • Top-down 과 Bottom-up

보통 개발자들은 블록체인을 Bottom-up 방식으로 공부한다
예를들면 암호학, 아키텍쳐, 네트워크 등

그러나 유저들은 Top-down으로 접근한다
일단 서비스를 이용하고
어떻게 이용이 가능한지 확인하고 점차 공부하게 된다

개발자와 유저의 동상이몽
오늘은 Top-down 방식으로 강의
자세한 건(암호학, 알고리즘, 아키텍쳐, 네트워크, 코어 등)스킵하고 쓰는 법 코딩하는 법 강의
자세한 블록체인은 유튜브에게 영광을 돌림
오늘 다 못하고 2탄도 준비

Prologue

블록체인이란?

모두가 접속 가능한 DB
모두가 유지보수 하고 유지보수의 대가를 받는다 (마이닝)
계정 대신에 누구나 발급가능한 Private Key

스마트 컨트랙트란?

DB의 데이터를 사용하는 프로그램 코드
DB에 소스 코드를 올려 실행한다
dApp의 Back-end

결국 DB와 Serverless Computing 이다

Tools

https://metamask.io/

  • 크롬 익스텐션
  • 계정관리 (지갑이라고도 불림)

http://remix.ethereum.org

  • 스마트 컨트랙트 Compile & Deploy & Run

https://etherscan.io/

  • 이더리움 탐색기 (모든 데이터 검색 가능) & Run

Hello World

remix 에서 소스코드를 올리고 이더리움 블록체인에 배포한다

배포한 Smart Contract 를 Etherscan에서 확인한다

pragma solidity ^0.4.21;

contract Greeter {

function greet() public view returns (string memory) {
return 'hello world';
}

function bye() public view returns (string memory) {
return 'bye world';
}
}

ERC-20 토큰 발행

Ethereum wiki https://theethereum.wiki/w/index.php/ERC20_Token_Standard

ERC20 은 인터페이스다

// ----------------------------------------------------------------------------
// ERC Token Standard #20 Interface
// https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md
// ----------------------------------------------------------------------------
contract ERC20Interface {
function totalSupply() public constant returns (uint);
function balanceOf(address tokenOwner) public constant returns (uint balance);
function allowance(address tokenOwner, address spender) public constant returns (uint remaining);
function transfer(address to, uint tokens) public returns (bool success);
function approve(address spender, uint tokens) public returns (bool success);
function transferFrom(address from, address to, uint tokens) public returns (bool success);

event Transfer(address indexed from, address indexed to, uint tokens);
event Approval(address indexed tokenOwner, address indexed spender, uint tokens);
}

Sample Erc20

pragma solidity ^0.4.24;// ----------------------------------------------------------------------------
// 'FIXED' 'Example Fixed Supply Token' token contract
//
// Symbol : FIXED
// Name : Example Fixed Supply Token
// Total supply: 1,000,000.000000000000000000
// Decimals : 18
//
// Enjoy.
//
// (c) BokkyPooBah / Bok Consulting Pty Ltd 2018. The MIT Licence.
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// Safe maths
// ----------------------------------------------------------------------------
library SafeMath {
function add(uint a, uint b) internal pure returns (uint c) {
c = a + b;
require(c >= a);
}
function sub(uint a, uint b) internal pure returns (uint c) {
require(b <= a);
c = a - b;
}
function mul(uint a, uint b) internal pure returns (uint c) {
c = a * b;
require(a == 0 || c / a == b);
}
function div(uint a, uint b) internal pure returns (uint c) {
require(b > 0);
c = a / b;
}
}
// ----------------------------------------------------------------------------
// ERC Token Standard #20 Interface
// https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md
// ----------------------------------------------------------------------------
contract ERC20Interface {
function totalSupply() public constant returns (uint);
function balanceOf(address tokenOwner) public constant returns (uint balance);
function allowance(address tokenOwner, address spender) public constant returns (uint remaining);
function transfer(address to, uint tokens) public returns (bool success);
function approve(address spender, uint tokens) public returns (bool success);
function transferFrom(address from, address to, uint tokens) public returns (bool success);
event Transfer(address indexed from, address indexed to, uint tokens);
event Approval(address indexed tokenOwner, address indexed spender, uint tokens);
}
// ----------------------------------------------------------------------------
// Contract function to receive approval and execute function in one call
//
// Borrowed from MiniMeToken
// ----------------------------------------------------------------------------
contract ApproveAndCallFallBack {
function receiveApproval(address from, uint256 tokens, address token, bytes data) public;
}
// ----------------------------------------------------------------------------
// Owned contract
// ----------------------------------------------------------------------------
contract Owned {
address public owner;
address public newOwner;
event OwnershipTransferred(address indexed _from, address indexed _to);constructor() public {
owner = msg.sender;
}
modifier onlyOwner {
require(msg.sender == owner);
_;
}
function transferOwnership(address _newOwner) public onlyOwner {
newOwner = _newOwner;
}
function acceptOwnership() public {
require(msg.sender == newOwner);
emit OwnershipTransferred(owner, newOwner);
owner = newOwner;
newOwner = address(0);
}
}
// ----------------------------------------------------------------------------
// ERC20 Token, with the addition of symbol, name and decimals and a
// fixed supply
// ----------------------------------------------------------------------------
contract FixedSupplyToken is ERC20Interface, Owned {
using SafeMath for uint;
string public symbol;
string public name;
uint8 public decimals;
uint _totalSupply;
mapping(address => uint) balances;
mapping(address => mapping(address => uint)) allowed;
// ------------------------------------------------------------------------
// Constructor
// ------------------------------------------------------------------------
constructor() public {
symbol = "FIXED";
name = "Example Fixed Supply Token";
decimals = 18;
_totalSupply = 1000000 * 10**uint(decimals);
balances[owner] = _totalSupply;
emit Transfer(address(0), owner, _totalSupply);
}
// ------------------------------------------------------------------------
// Total supply
// ------------------------------------------------------------------------
function totalSupply() public view returns (uint) {
return _totalSupply.sub(balances[address(0)]);
}
// ------------------------------------------------------------------------
// Get the token balance for account `tokenOwner`
// ------------------------------------------------------------------------
function balanceOf(address tokenOwner) public view returns (uint balance) {
return balances[tokenOwner];
}
// ------------------------------------------------------------------------
// Transfer the balance from token owner's account to `to` account
// - Owner's account must have sufficient balance to transfer
// - 0 value transfers are allowed
// ------------------------------------------------------------------------
function transfer(address to, uint tokens) public returns (bool success) {
balances[msg.sender] = balances[msg.sender].sub(tokens);
balances[to] = balances[to].add(tokens);
emit Transfer(msg.sender, to, tokens);
return true;
}
// ------------------------------------------------------------------------
// Token owner can approve for `spender` to transferFrom(...) `tokens`
// from the token owner's account
//
// https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20-token-standard.md
// recommends that there are no checks for the approval double-spend attack
// as this should be implemented in user interfaces
// ------------------------------------------------------------------------
function approve(address spender, uint tokens) public returns (bool success) {
allowed[msg.sender][spender] = tokens;
emit Approval(msg.sender, spender, tokens);
return true;
}
// ------------------------------------------------------------------------
// Transfer `tokens` from the `from` account to the `to` account
//
// The calling account must already have sufficient tokens approve(...)-d
// for spending from the `from` account and
// - From account must have sufficient balance to transfer
// - Spender must have sufficient allowance to transfer
// - 0 value transfers are allowed
// ------------------------------------------------------------------------
function transferFrom(address from, address to, uint tokens) public returns (bool success) {
balances[from] = balances[from].sub(tokens);
allowed[from][msg.sender] = allowed[from][msg.sender].sub(tokens);
balances[to] = balances[to].add(tokens);
emit Transfer(from, to, tokens);
return true;
}
// ------------------------------------------------------------------------
// Returns the amount of tokens approved by the owner that can be
// transferred to the spender's account
// ------------------------------------------------------------------------
function allowance(address tokenOwner, address spender) public view returns (uint remaining) {
return allowed[tokenOwner][spender];
}
// ------------------------------------------------------------------------
// Token owner can approve for `spender` to transferFrom(...) `tokens`
// from the token owner's account. The `spender` contract function
// `receiveApproval(...)` is then executed
// ------------------------------------------------------------------------
function approveAndCall(address spender, uint tokens, bytes data) public returns (bool success) {
allowed[msg.sender][spender] = tokens;
emit Approval(msg.sender, spender, tokens);
ApproveAndCallFallBack(spender).receiveApproval(msg.sender, tokens, this, data);
return true;
}
// ------------------------------------------------------------------------
// Don't accept ETH
// ------------------------------------------------------------------------
function () public payable {
revert();
}
// ------------------------------------------------------------------------
// Owner can transfer out any accidentally sent ERC20 tokens
// ------------------------------------------------------------------------
function transferAnyERC20Token(address tokenAddress, uint tokens) public onlyOwner returns (bool success) {
return ERC20Interface(tokenAddress).transfer(owner, tokens);
}
}

스마트 컨트랙트 오픈 소스 총집합 https://github.com/OpenZeppelin/openzeppelin-solidity

CorwdSale

/**
* @dev Crowdsale
**/
contract Crowdsale {
using SafeMath for uint256;

// The token being sold
FixedSupplyToken public token;

// address where funds are collected
address public wallet;

// how many token units a buyer gets per wei
uint256 public rate;

// amount of raised money in wei
uint256 public weiRaised;


/**
* event for token purchase logging
* @param purchaser who paid for the tokens
* @param beneficiary who got the tokens
* @param value weis paid for purchase
* @param amount amount of tokens purchased
*/
event TokenPurchase(address indexed purchaser, address indexed beneficiary, uint256 value, uint256 amount);

/**
* @param _rate Number of token units a buyer gets per wei
* @param _wallet Address where collected funds will be forwarded to
* @param _token Address of the token being sold
*/
constructor(uint256 _rate, address _wallet,
FixedSupplyToken _token) public {
require(_rate > 0);
require(_wallet != address(0));
require(_token != address(0));

rate = _rate;
wallet = _wallet;
token = _token;
}

// fallback function can be used to buy tokens
function() external payable {
buyTokens(msg.sender);
}

// low level token purchase function
function buyTokens(address _beneficiary) public payable {
require(_beneficiary != 0x0);


uint256 weiAmount = msg.value;

// calculate token amount to be created
uint256 tokens = weiAmount.mul(rate);

// update state
weiRaised = weiRaised.add(weiAmount);

//transfer token
token.transfer(_beneficiary, tokens);

//
emit TokenPurchase(msg.sender, _beneficiary, weiAmount, tokens);

forwardFunds();
}

// send ether to the fund collection wallet
// override to create custom fund forwarding mechanisms
function forwardFunds() internal {
wallet.transfer(msg.value);
}

}

Web3.js 를 이용한 서비스 구현

https://github.com/ethereum/web3.js/

var contract = web3.eth.contract(JSON.parse(this.abi)).at(this.address);


let decimals = Math.pow(10, this.decimal);
let amountValue = this.amount * decimals;


var data = contract.transfer(this.toaddress, amountValue, {gasPrice: '21000000000'},
function (a, result) {
console.log(a);
console.log(result);
}
);

abi?

Application Binary Interface
remix(컴파일러) 에서 구할 수 있음

탈중앙화? 중앙화?

사연 1. 오너가 수수료를 지불하고 토큰 송금이 가능하게 해주세요
(토큰을 오너가 조작 가능하게 해주세요)
0xb7750808512ecb926042bf0f249321aad6c8a7e9

사연2. 거래소

앞으로의 블록체인은?

TPS(Transaction Per Seconds)

참고로 비자카드 TPS 3,526

EOS

어느 정도의 중앙화가 이뤄진 것 같음 (DPOS)
UX가 좋지 않아…
어려워… 뭐야 이거 무서워…

ERC721

Non-fungible token (대체 불가능 토큰?)
동일한 토큰에 대해서 각각 다른 가치를 가짐
예, 고양이, 강아지

CryptoKitty
https://www.cryptokitties.co/

Cryptomus
https://cryptomus.io/

Side Chain

  1. Plasma
  2. RootStock
  3. Alpha

참고 :

Ethereum 2.0

https://medium.com/rocket-pool/ethereum-2-0-whos-building-it-54a735442e

--

--