Blockchain

#25 메인 네트워크에서 작동하는 토큰 만들기

Sila 2022. 7. 20. 14:21

코인과 토큰을 혼용해서 쓰는 경우가 많고, 실제로 거래소 등에서 이들을 사고 팔고 할때는 이 둘의 차이가

 

그다지 중요하지 않다.

 

하지만 프로그래밍의 관점에서 볼 때 이 둘에게는 큰 차이점이 하나 존재하는데.

 

코인은 자신의 메인 네트워크를 가지고 있고, 토큰은 자신들의 네트워크 없이 다른 메인 네트워크를

 

이용해 이동하는 것들이다.

 

이더리움의 경우 이더리움의 메인네트워크가 있으며, 이는 일정한 규격을 지키는데,

 

(여기서 규격이란 객체가 typescript를 이용해 class 객체를 선언하는 것 처럼

 

어떠 어떠한 속성값을 가져야 한다는 것을 의미한다.)

 

이 이더리움 네트워크를 사용하는 다른 토큰들도 이 규격을 어느 정도 따라가게 된다.

 

이더리움의 규격은 ERC-20이라고 부른다.

 

오늘은 이런식으로 스마트 컨트랙트를 이용해 네트워크 내에서 지갑 간 주고 받을 수 있는 토큰을 만들어보자.

 

1. set up

이번 글에서는 네트워크는 ganache 네트워크, 컨트랙트 배포는 truffle을 사용한다.

 

우선 ganache를 실행하고 지갑과 개인키들을 다 복사해두자.

 

( 컨트랙트 배포는 여러 번 다시 하겠지만 네트워크는 끄지 않을 것이다. )

 

그리고 truffle 폴더를 만든 후 트러플을 실행하면 된다.

 

npx ganache-cli // ganache 네트워크 구동
npx truffle init // truffle set up

 

/*  truffle/contracts/ingToken.js  */

//SPDX-License-Identifier: MIT

pragma solidity ^0.8.15;

contract ingToken {
    mapping(address => uint256) public balances;
    
    string public name = 'ingToken';
    string public symbol = "ITK";
    uint8 public decimals = 18;
    uint256 public totalSupply = 10000000000 * 10 ** decimals;
    
    constructor() {
        
    }
}

 

우리가 토큰을 만들 때 그 토큰이 가져야 하는 속성과 값이 여러 개가 있다.

 

토큰의 이름과 심볼, 단위, 총 발행량이 있으며 이들은 상수이고 public으로 선언해주면 된다.

 

그 다음으로 들어가야하는 속성이 account 즉 지갑주소이다.

 

솔리디티에선 address라는 데이터 타입이 있는데 40자리의 지갑 주소를 value로 갖는 데이터이다.

 

string의 특수한 경우라고 생각하면 된다.

 

또 새로 등장하는 것은 mapping인데, 이는 객체를 생성할 때 key와 value의 데이터 타입을 정해주는 툴이라고 보면 된다.

 

위에서 쓴 것처럼

 

mapping( address => uint256 ) public balances;

 

라고 하면 balance라는 객체에는 address라는 key가 있고, 이 key의 value는 uint256 의 데이터 타입을 가진다.

 

총 발행량은 10^18개인데, 이는 전부 컨트랙트를 배포한 사람에게 준다.

 

이렇게 만든 컨트랙트를 truffle을 통해 배포한 다음,  다음처럼 부르기 쉽게 truffle console에서 바꾼 후, 

 

truffle migration

truffle console

abcToken.deployed().then(instance => it = instance)

it. // tab키 2번 press

 

가용한 함수들을 살펴보면 컨트랙트 안에 넣어준 name, symbol등을 불러올 수 있다.

 

it.name()
// 'abcToken'

 

이렇게 인스턴스 내에서 그 값이 변하지 않는 상수들은 그 이름을 그대로 이용해 상태를 가져올 수 있다.

 

다음으로 지갑의 토큰 잔액을 보는 함수를 추가해보자.

 

총 방행량은 10000000000 * 10^18 인데 이를 모두 컨트랙트를 배포한 사람에게 준다.

 

/*  truffle/contracts/abcToken.js  */

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

contract abcToken {
    mapping(address => uint256) public balances;

    string public name = "abcToken";
    string public symbol = "ABCK";
    uint8 public decimals = 18;
    uint256 public totalSupply = 10000000000 * 10**decimals;

    constructor() {
        balances[msg.sender] = totalSupply;
    }

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

 

이를 다시 배포한 후, 정말 토큰이 배포자에게 들어왔는지 메타마스크를 이용해 확인해보자.

 

메타마스크를 열고 토큰 가져오기를 클릭후, '토큰 계약 주소' 란에 컨트랙트의 CA값을 가져온다.

 

CA값을 넣어주면 토큰 기호와 토큰 십진수 값은 자동으로 메타마스크가 현재 네트워크에 요청을 보내

 

그 값을 찾아 넣어줄 것이다.

 

토큰을 추가한 후, 토큰이 잘 들어왔는지 확인해본다.

 

다음으로 토큰을 한 지갑에서 다른 지갑으로 보내는 함수를 컨트랙트에 추가해보자.

 

/*  truffle/contracts/abcToken.sol  */

// ...생략

contract abcToken {
    // ...생략
    
    event Transfer(address _from, address _to, uint256 _value);
    
    constructor() {
        balances[msg.sender] = totalSupply;
    }
    
    // ...중략
    
    function transfer(address _to, uint256 _value public returns (bool success) {
        require(balances[msg.sender] >= _value);
        // require안의 조건을 만족해야 다음 코드를 실행한다.
        balances[msg.sender] -= _value;
        // 보내는 사람의 잔고를 액수만큼 뺀다
        balances[_to] += _value;
        // 받는 사람의 잔고를 액수만큼 더한다
        emit Transfer(msg.sender, _to, _value);
        // event를 네트워크에 방출한다.
        return true;
    }
}