TIL 38 - ERC-20 직접 뜯어 소화시키기(WEMIX Testnet 배포)

프동프동·2023년 2월 10일
0

TIL

목록 보기
38/46
post-thumbnail

ERC-20

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract ERC20{
  event Transfer();
  event Approval();
  function name() public view returns (string memory){

  }
  function symbol() public view returns (string memory){

  }
  function decimals() public view returns (uint8){

  }
  function totalSupply() public view returns (uint256){
    
  }
  function balanceOf(address account) public view returns (uint256){

  }
  function transfer(address to, uint256 amount) public returns (bool){

  }
  function allowance(address owner, address spender)public returns (uint256){

  }
  function approve(address spender, uint256 amount) public returns (bool){

  }
  function transferFrom(address from, address to, uint256 amount) public returns (bool){
    
  }
}

데이터 조회

  • name()
  • symbol()
  • decimals()
  • totalSupply()

데이터 이동 처리

  • transfer()
  • allowance()
  • approve()
  • transferFrom()

변수

사용자의 주소와 잔액 정보 관리를 위한 mapping

// 사용자의 잔액 정보 관리를 하기 위한 mapping
mapping(address => uint) private _balances;

사용자가 내 돈을 다른 사용자에게 이동을 할 수 있는 권한을 주기 위한 mapping

// 어느정도의 금액을 이동시킬 수 있는지 설정하기 위함
// _allowances 는 approve()와 transferFrom()으로 설정이된다.
mapping(address =>mapping(address=>uint)) private _allowances;
  • transfer(to, amount)
    • 내가 to에게 amount만큼 금액을 보내는 함수
  • transferFrom(from, to, amount)
    • from이 to에게 amount만큼 금액을 보내는 함수
      • c가 a의 돈을 b에게 이동시킬 때 사용할 수 있다.
      • 받는 사람이 일반적으로 호출한다.

토큰의 전체 발행량

uint256 private _totalSupply;

해당 토큰 컨트랙트의 명칭

string private _name;

해당 토큰의 심볼명

string private _symbol;

부동소수점 처리를 위한 변수

uint8 private _decimals;
  • 이더리움은 소수점 아래 18자리 까지 사용한다.
    • 0.000000000000000001 Ether = 1 Wei
    • Ether = 100000000000000000 Wei
  • 비트코인은 소수점 아래 8자리 까지 사용한다.
    • 0.00000001 BTC = 1 Satoshi
    • 1 BTC = 100000000 Satoshi

이벤트

event Transfer( address indexed from,  address indexed to, uint amount);
  • from이 to에게 얼마를 보냈는지 event상에서 기록해주기 위해 사용한다.
  • indexed는 log상 데이터를 찾기 쉽게 하기 위해 사용
    • 이벤트들을 필터하여 사용자가 원하는 이벤트만을 가지고 올수 있게 한다.
event Approval( address indexed  from, address indexed to, uint amount);
  • Approval은 사용자의 권한을 인증해주는 함수이다.

생성자

constructor(string memory _name_, string memory _symbol_, uint8 _decimals){
    _name = _name_;
    _symbol = _symbol_;
    _decimals = _decimals_;
    _totalSupply = 10000000 * 10 **(18);
  }
  • _totalSupply = 10000000 * 10 **(18);
    • 10,000,000개를 발행하기 위함

Modifier

checkBalance() : msg.sender의 잔액이 보내기에 충분한지 확인하는 함수

modifier checkBalance(uint amount){
    require(_balances[msg.sender]> amount, "Not sufficient balance");
    _;
}

함수

name() : 설정된 토큰 컨트랙트의 name을 반환한다.

function name() public view returns (string memory){
    return _name;
}
  • 단순히 컨트랙트의 name을 반환한다.
  • public : 공개 함수
  • view : 상태를 변경하지 않는 읽기 전용 함수
    • pure : 스토리지에서 변수를 읽거나 쓰지 않는 함수
    • payable : 이더를 받을 수 있는 함수
  • returns (string memory) : 반환값으로 메모리에 선언된 (함수 내에 선언된) 값을 리턴하겠다라는 의미
    • memory : 프로그램이 동작하는 동안에만 임시적으로 값을 기억하고, 종료되면 값을 잃는 데이터 영역
      • string을 쓰기 위해서는 memory 키워드를 사용해서 일시적으로 저장해야한다.
        • string은 레퍼런스 타입이기에 memory 키워드와 함께 사용한다.
      • 함수의 파라미터, 리턴값, 레퍼런스 타입이 주로 저장된다.
    • storage : 블록체인에 기록되어 영구적으로 값이 저장되는 데이터 영역
      • 대부분의 변수, 함수들이 저장되며 영구적으로 저장되기에 가스비가 비싸다
    • calldata : external function의 파라미터에서 사용된다.
      • calldata를 파라미터로 받게되면 값은 변경할 수 없고 읽기만 가능하다.
    • stack : evm에서 stack data를 관리할 때 쓰는 영역
      • 함수를 실행할 때 로컬 변수 같은 것들을 잠시 저장할 때 EVM이 사용한다.

symbol() : 설정된 토큰의 심볼을 반환한다.

function symbol() public view returns (string memory){
    return _symbol;
  }
  • 단순히 컨트랙트에 등록된 토큰의 Symbol을 반환한다.

decimals() : 설정된 decimal 값을 반환한다.

function decimals() public view returns (uint8){
    return _decimals
  }

totalSupply() : 설정된 토큰의 총 발행량을 반환한다.

function totalSupply() public view returns (uint256){
    return _totalSupply;
}

balanceOf() : 주소를 통해 해당 주소의 잔액을 가져올 수 있다.

function balanceOf(address account) public view returns (uint256){
    return _balances[account];
}

transfer() : 컨트랙트를 호출한 사람이 to에게 토큰을 전송할 때 사용한다.

function transfer(address to, uint256 amount) public checkBalance(amount) returns (bool){
    // 보내는 사람(컨트랙트를 호출한 사람)의 잔액이 충분한 양이 있는지 확인한다.
    // require(_balances[msg.sender]> amount, "Not sufficient balance");
		// approve()와 중복되기에 modifier를 사용해서 처리한다.		

    // balance의 값을 업데이트 시켜주는 형식
    // 1. 보내는 사람(컨트랙트를 호출한 사람)의 잔액에서 요청한 잔액만큼 뺴준다.
    _balances[msg.sender] -= amount;
    // 2. 받는 사람 주소에 뺸만큼 더해주면 된다.
    _balances[to] += amount; 
    // erc-20은 잔액관리를 CA에서 한다.
    // 그래서 잔액정보가 업데이트만 된다.
    // Transfer 함수가 실행되었음을 이벤트로 알린다
    emit Transfer(msg.sender, to, amount);
    // 성공하였으니 true 값 반환
    return true;
  }
  • to에게 amount만큼 토큰을 전송한다.
  • ERC - 20은 잔액관리를 CA에서 하기에 잔액정보가 업데이트만 된다.
  • 보내는 순서
    1. 자신이 보내고자 하는 토큰의 개수보다 많이 가지고 있는지 체크한다.(조건 체크)
    2. 자신(msg.sender)의 잔고에서 보내고자하는 토큰의 개수(amount)만큼 뺀다.
    3. 받는 자(to)의 잔고에 뺀 만큼 넣어준다.
    4. 전송이 완료되었으니 이벤트로 알려준다.

approve() : 내 돈(msg.sender)을 다른사람이 꺼내 쓸 수 있도록 권한 설정

function approve(address spender, uint256 amount) public checkBalance(amount) returns (bool){
    // 권한을 허용할 만큼 내 잔액이 있는지 확인
    //require(_balances[msg.sender]> amount, "Not sufficient balance");
    // transfer()와 중복되기에 modifier를 사용해서 처리한다.

    // 내 돈(msg.sender), 꺼내갈 수 있게 허락할 사람(spender), 꺼내갈 수 있는 금액
    _allowances[msg.sender][spender] = amount;
    // 이벤트로 기록
    emit Approval(msg.sender, spender, amount);
    // 성공하였으니 true
    return true;
}
  • msg.sender의 돈을 spender에게 꺼내 쓸 수 있도록 권한을 설정할 수 있다.
    • 거래소 등에서 관리할 수 있도록 하기 위함
  • 순서
    1. 권한을 허용할 만큼 내 잔액이 있는지 확인 (조건 체크)
    2. 내 돈(msg.sender), 꺼내갈 수 있게 허락할 사람(spender), 꺼내갈 수 있는 금액 설정
    3. 이벤트로 기록

allowance() : 어느 정도의 금액을 다른사람이 꺼내 쓸 수있도록 설정 하였는지 확인하는 함수

function allowance(address owner, address spender)public view returns (uint256){
    return _allowances[owner][spender];
}

transferFrom() : from이 to에게 돈을 보낼 때 사용한다.

받는 사람이 일반적으로 호출한다.

// from이 to에게 돈을 보낼때
  // 받는 사람이 일반적으로 호출한다.
  function transferFrom(address from, address to, uint256 amount) public returns (bool){
    // form이 가진 돈이 충분한 양인지 확인
    require(_balances[from]> amount, "Not sufficient balance");
    // 설정한 금액이 실제 전송하고자 하는 금액보다 많은지 확인
    require(_allowances[from][to]>amount,"Not allowed amount");
    // 허용을 요청한 사람이 msg.sender와 동일한지 확인(권한을 가진 사람이 요청을 하는지 확인)
    require(to == msg.sender, "Not allowed user");
    _balances[from] -= amount;
    _balances[to] += amount;
    // 이동되었음을 알리는 이벤트
    emit Transfer(from, to, amount);
    // 성공하였으니 true 값 반환
    return true;
  }

전체 소스 코드

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract ERC20{
  // 사용자의 주소와 잔액 정보 관리를 하기 위한 mapping
  mapping(address => uint256) private _balances;
  // 사용자가 내 돈을 다른 사용자에게 이동을 할 수 있는 권한을 주는 mapping
  // 어느정도의 금액을 이동시킬 수 있는지 설정하기 위함
  // _allowances 는 approve()와 transferFrom()으로 설정이된다.
  mapping(address =>mapping(address=>uint256)) private _allowances;
  // 토큰의 전체 발행량
  uint256 private _totalSupply;
  // 해당 토큰 컨트랙트의 명칭
  string private _name;
  // 해당 토큰의 심볼명
  string private _symbol;
  // 몇자리까지를 사용할 것인지(이더리움은 소수점 아래 18자리까지 사용한다.)
  uint8 private _decimals; 

  // from이 to에게 얼마를 보냈는지 event상에서 기록해주기 위해 사용한다. indexed는 log상 데이터를 찾기 쉽게 하기 위해 사용
  event Transfer( address indexed from,  address indexed to, uint amount);
  // 사용자의 권한을 인증해주는 함수
  event Approval( address indexed  from, address indexed to, uint amount);

  modifier checkBalance(uint amount){
    require(_balances[msg.sender]> amount, "Not sufficient balance");
    _;
  }
  constructor(string memory _name_, string memory _symbol_, uint8 _decimals_){
    _name = _name_;
    _symbol = _symbol_;
    _decimals = _decimals_;
    _totalSupply = 10000000 * 10 **(18);
  }
  function name() public view returns (string memory){
    return _name;
  }
  function symbol() public view returns (string memory){
    return _symbol;
  }
  function decimals() public view returns (uint8){
    return _decimals;
  }
  function totalSupply() public view returns (uint256){
    return _totalSupply;
  }
  function balanceOf(address account) public view returns (uint256){
    return _balances[account];
  }
  // 내가 누구에게 돈을 보낼 때
  function transfer(address to, uint256 amount) public checkBalance(amount) returns (bool){
    // 보내는 사람(컨트랙트를 호출한 사람)의 잔액이 충분한 양이 있는지 확인한다.
    // require(_balances[msg.sender]> amount, "Not sufficient balance");

    // balance의 값을 업데이트 시켜주는 형식
    // 1. 보내는 사람(컨트랙트를 호출한 사람)의 잔액에서 요청한 잔액만큼 뺴준다.
    _balances[msg.sender] -= amount;
    // 2. 받는 사람 주소에 뺸만큼 더해주면 된다.
    _balances[to] += amount; 
    // erc-20은 잔액관리를 CA에서 한다.
    // 그래서 잔액정보가 업데이트만 된다.
    // Transfer 함수가 실행되었음을 이벤트로 알린다
    emit Transfer(msg.sender, to, amount);
    // 성공하였으니 true 값 반환
    return true;
  }
  function allowance(address owner, address spender)public view returns (uint256){
    return _allowances[owner][spender];
  }
  function approve(address spender, uint256 amount) public checkBalance(amount) returns (bool){
    // 권한을 허용할 만큼 내 잔액이 있는지 확인
    // require(_balances[msg.sender]> amount, "Not sufficient balance");
    //  내돈(msg.sender)을 다른사람이 얼마만큼 꺼내쓸수 있도록 권한 설정
    // 내 돈(msg.sender), 꺼내갈 수 있게 허락할 사람(spender), 꺼내갈 수 있는 금액
    _allowances[msg.sender][spender] = amount;
    // 이벤트로 기록
    emit Approval(msg.sender, spender, amount);
    // 성공하였으니 true
    return true;
  }
  // from이 to에게 돈을 보낼때
  // 받는 사람이 일반적으로 호출한다.
  function transferFrom(address from, address to, uint256 amount) public returns (bool){
    // form이 가진 돈이 충분한 양인지 확인
    require(_balances[from]> amount, "Not sufficient balance");
    // 설정한 금액이 실제 전송하고자 하는 금액보다 많은지 확인
    require(_allowances[from][to]>amount,"Not allowed amount");
    // 허용을 요청한 사람이 msg.sender와 동일한지 확인(권한을 가진 사람이 요청을 하는지 확인)
    require(to == msg.sender, "Not allowed user");
    _balances[from] -= amount;
    _balances[to] += amount;
    // 이동되었음을 알리는 이벤트
    emit Transfer(from, to, amount);
    // 성공하였으니 true 값 반환
    return true;
  }
}

WEMIX Testnet 배포

=====================

   Deploying 'ERC20'
   -----------------
   > transaction hash:    0x426145b7e93d1c358bc75fc471f83754d15aa63aa9f37110eb1f26ce8bc6ec48
   > Blocks: 0            Seconds: 0
   > contract address:    0x07FCA98DB62Cd4CEc02B67a5d5A6924ab9f49832
   > block number:        15064486
   > block timestamp:     1673116729
   > account:             0xDc45fE9fF7aF3522bB2B88a602670Ab4bE2C6f91
   > balance:             9.861130299998611303
   > gas used:            1009886 (0xf68de)
   > gas price:           100.000000001 gwei
   > value sent:          0 ETH
   > total cost:          0.100988600001009886 ETH

   > Saving artifacts
   -------------------------------------
   > Total cost:     0.100988600001009886 ETH

Summary
=======
> Total deployments:   1
> Final cost:          0.100988600001009886 ETH

WEMIX3.0 Explorer (Testnet)

profile
좋은 개발자가 되고싶은

0개의 댓글