[Solidity] ERC-20

DoDodo·2023년 5월 22일
0

오늘 순서
(1) ERC-20 transfer 구현
(2) ERC-30 trasnferFrom, Approved 구현
(3) WETH

9개의 method
2개의 event

정의 - event, 실행 - emit

// SPDX-License-Identifier: MIT
pragma solidity 0.8.20;

contract Token {
    // 대부분 사용하는 dataType = mapping임

    //9개의 method
    // 1. name("Wrapped Ether") = getValue 형식
    // 2. symbol("WETH") = getValue
    // 3. decimals(18) // 자릿수
    // 4. totalSupply // 지금까지 얼마나 토큰이 발행되었는가
    // 5. balaceOf()  // 계정마다 얼마나 토큰을 갖고 있는지 input address -> output uint
    // 6. transfer() // 보내는 사람은 무조건 나, 내가 남한테 얼마큼 보낼 것이다 **(중요) 내 토큰 얼마나 전송했어
    // 7. transferFrom() // 대리인이 내 코인을 전송하는 기능, 권한을 주면 유니스왑에서 내 토큰을 알아서 가져가는 것
    // 8. approve() // 권한을 주는 함수 ** (중요)
    // 9. allowance() // 얼마큼 위임되어있냐, 누구에게 얼마큼 권한이 있는지 확인 input: owner, Spender(사용할 사람) -> output amount(uint)


    // name symbol decimals 어떻게 저장되어야 할까?
    // mapping타입의 balances 변수 , 특정 유저가 얼마만큼의 토큰을 보유하고 있는가


    // function name() public view returns (string memory) {
    //     return  "doyeon Token";
    // } 변수 선언과 같은 의미

    string public name = "doyeon Token";
    string public symbol = "DYT";
    uint public decimals = 18;
    uint public totalSupply = 0; //민팅된게 없음

    mapping(address owner => uint amount) public balances; // key는 주소, value는 갖고있는 토큰의 amount    
    mapping(address owner => mapping(address spender => uint amount)) public allowances; 
    //allowances[myEOA][uniswap Pair] = 1000;

    // 이벤트 선언, indexed 하면 더 빨라짐!! value = amount
    event Transfer(address indexed _from, address indexed _to, uint _amout); // transfer(), transferFrom() 에서 emit
    event Approval(address indexed _owner, address indexed _spender, uint _value); //approve() 에서 emit
   


    // 지갑 안에 토큰이 있는게 아닌가? 
    // 우리 account에는 논스 밸런스 스토리지 코드해시만 있는데, 토큰을 홀딩하고있는 정보는 다른 컨트랙에 있음
    // 컨트랙트 주소에는 스토리지가 있음, [stroage] balances[dokite.eth] = 100; 
    // 느낌상 내 지갑에서 나가는 것 같지만, 나와 상관 없는 컨트랙에서 숫자가 빠져나갈 뿐인 것 ???? 이해가 안 감



    // transfer의 실행 주체는 owner다 : address owner = msg.sender;
    function transfer(address _to, uint _value) public returns (bool success) {
        address owner = msg.sender;
        // 발생하지 말아야 할 예외처리
        // 1. 잔고보다 더 많이 보내려 한다면? : 이 사람이 갖고있는 토큰 개수가 보내려는 토큰보다 많은가? - require 사용
        require( balances[owner] >= _value);
        // 2. 실제 전송: 내 잔액에서 (-) , 받는 사람 잔액 (+)
        balances[owner] -= _value;
        balances[_to] += _value;

        // Transfer Event Emit 실행
        emit Transfer(owner, _to, _value);

        // return true 끝
        return true;
        


        // **만약**
        // 100개를 전송한다 할때 , 90개는 전송하고 10개는 내가 갖도록 구현(커뮤니티에 주도록)한다면??
        // address feeAccount = 0x ; // 커뮤니티 주소
        // address owner = msg.sender;
        // require( balances[owner] >= _value);
        // balances[owner] -= _value;

        // uint fee = amount / 10;
        // uint amountWithoutFee = amount - fee;

        // balance[feeAccount] += fee;
        // balance[to] += amountWithoutFee;

        // emit Transfer(owner, _to, _value);
        // return true;


    }

    // transferFrom의 실행 주체는 owner가 아닌 spender(uniswap의 weth/pepe exchange(pair) 이 토큰들을 스왑하는 컨트랙트, 
    // exchange의 동작 방식, 유저가 유니스왑 컨트랙트에 스왑하고싶다고 어떤 함수 호츨, 
    // 이 토큰을 직접 보내는게 아닌, 유니스왑 컨트랙이 가져갈 수 있도록 권한을 주는 거임 -> 유니스왑이 transferFrom을 실행함

    // 실행 주체 : sender
    function transferFrom(
        address _from,  // 내 eoa 계정(owner)
        address _to,   // exchange 
        uint _value   // amount
        ) public returns (bool success) {
            // 발생하지 말아야할 예외처리
            // 1. spender에게 권한이 있는가 = owner가 spender한테 권한을 줬는가? = 할당받은 양이 보내려는 amount보다 많아야 한다, 
            require(allowances[_from][_to] >= _value); // spender = msg.sender임, owner가 spender에게 할당한 양이 _value보다 많은가, msg.sender가 함수 실행 주체?? 
            // 2. owner(from)의 잔액이 충분한가? 
            require(balances[_from] >= _value); 
          
            // 데이터 업데이트
            // 1. 잔고 업데이트 from(-) to(+)
            balances[_from] -= _value;
            balances[_to] += _value;
            // 2. allowances양 변경 - 1000개 권한중 200 개 쓰면 800권한이 남았다
            allowances[_from][_to] -= _value;

            // Event Emit
            emit Transfer(_from, _to, _value);
            
            // return true
            return true;
    }


    // approve는 언제 씀?
    // 스왑할때 
    // 1. 내 토큰을 eth로 바꿀때, approved -> max값 넣고 next -> approved 완 - uniswap 디앱은 pepe토큰의 approve 함수를 호출한다
    // 2. 유니스왑의 컨트랙트가 pepe의 transferFrom을 호츨해서 내 거에서 pepe를 가져감

    // 실행 주체 : owner
    function approve(
        address _to,
        uint _value
    ) public returns (bool success) {
        address owner = msg.sender;
        allowances[owner][_to] = _value;

        emit Approval(owner, _to, _value);

        return true;
    }

    function balanceOf(
        address _owner
    ) public view returns (uint balance) {
        return balances[_owner];
    }

    function allowance(
        address _owner,
        address _spender
    ) public view returns(uint remaining){
        return allowances[_owner][_spender];
    }


    // WETH - wrapped ether는 왜 나왔는가?  erc-20 + deposit, withdraw
    // deposit 이더리움을 넣으면 민팅한다 - balance오름,이벤트 발생, total supply늘어남
    // withdraw 

    // 이더를 보낸다 address.transfer 뿐
    // erc 20 에서는 contract.transfer, contract.transferFrom

    // ether to token
    // 기본적으로 이더를 받아야하고
    function deposit() public payable returns (bool success) {
        
        // msg.value = 내가 바꾸고 싶은 값
        // msg.sender = 바꾸는 주체, 토큰을 받을 주체
        uint amount = msg.value;
        address owner = msg.sender;

        // 0.5ETH를 넣으면 0.5WETH를 발행(민팅)
        // 1. 잔액 변경
        balances[owner] += amount; 
        // 2. totalSupply 조정
        totalSupply += amount;
        // 3. 이벤트 발생
        emit Transfer(address(0), owner, amount);
        // 4. Vault Balance 0.5ETH  

        return true;
    }


    // token to ether
    // 특정 개수의 수량으로 이더를 출금하는 함수
    function withdraw(uint amount) public returns (bool success) {
        
        // amount WETH -> ETH로 바꿈
        // owner의 밸런스가 amount보다 많은가? 
        address owner = msg.sender;
        require(balances[owner] >= amount);
        // 1. WETH를 받는다 = balances 감소됨
            // 선택의 문제
            // WETH를 소각한다는 관점 - owner의 balance를 줄인다 = totalSupply를 줄인다
            // WETH의 소유자를 컨트랙트로 바꾸는 관점 - weth의 소유자를 컨트랙트 자기 자신(address(this))으로 바꾼다, totalSupply는 바뀌지 않음?????
        balances[owner] -= amount;
        // 2. totalSupply 발행량 조절
        totalSupply -= amount;
        // 3. transfer이벤트 발생
        emit Transfer(owner,address(0), amount);
        // 4. ETH 출금 : payable(msg.sender).transfer()
        payable(owner).transfer(amount);
        // 5. return true
        return true;

    }


//ERC-721 구현해보기***
//ERC-1155 코드 보기

  
}

0개의 댓글