나만의 코인을 만들어 봅시다. #1 - 개발환경 세팅 및 ERC20 코인 생성

in #jjangjjangman7 years ago

개구리코인, 김정은코인 등 온갖 잡코인이 범람하는 이 시기,
문득 개인 코인을 한 번 만들어 보고 싶어졌습니다.

그래서 아래 포스팅을 따라 이더리움 기반의 ERC20 토큰을 만들어 보았습니다.
반 년이 넘은 글이라 잘 안되는 내용이 있었는데,
메뉴얼이나 다른 자료를 조금 참고 하여 수정하였습니다.

How to create token and initial coin offering

(참고로 저는 전문 개발자도 아니며 개인적인 정리 차원에서 남기는 거라,
조금 어설프거나 틀린 내용이 있을 수 있습니다.
잘못된 내용이나 부가 설명은 댓글로 남겨주시면 고맙겠습니다^^ )

나만의 코인을 위한 재료들

  • 이더리움 smart contract 에 대한 약간의 지식
  • 잘 돌아가는 노트북
  • 커피. 그리고 반나절의 여유 시간

참고로 저는 ubuntu 에서 진행하였습니다.

환경설정

노트북에 우선 이더리움 스마트 컨트랙트를 개발을 위한 개발환경을 세팅해야 합니다.

  • node : nodejs 최신 버전
  • truffle : solidity를 위한 배포, 테스트 개발 환경 제공
  • zeppelin-solidity : ERC20 등의 표준을 제공하는 라이브러리

메인넷에 붙이려면 이더가 필요해서, 개발 환경에서만 만들었습니다.
원문에서는 ethereumjs-testrpc 를 추가로 설치했으니, truffle 4.0.x 부터 자체 테스트 환경이 있어서 제외하였습니다.

실행 순서.

$ npm install -g truffle
$ mkdir my-ico && cd my-ico
$ truffle init
$ npm install zeppelin-solidity

우선 각 자 환경에 맞는 nodejs를 설치합니다.

그 다음 truffle 설치하고 작업공간(my-ico)을 생성한 후,
truffle init 를 실행하면 기본 폴더와 각종 템플릿이 생성 됩니다.

$ npm install -g truffle
$ mkdir my-ico && cd my-ico
$ truffle init

contracts, migrations, test 폴더 생성을 확인할 수 있습니다.

truffle_folder_structure.png
이제 표준 라이브러리를 제공하는 zeppelin-solidity 설치합니다.

npm install zeppelin-solidity

아래 zeppelin 의 기본 라이브러리 들이 설치됩니다.

zeppelin 라이브러리

한 번 훑어보면, ERC20 같은 기본 토큰를 표현하는 리이브러리들도 보이네요.

이더리움에 작성하는 smart contract는 특정 주소에 배포이후에 수정도 안되며, 작은 버그도 매우 치명적일 수 있습니다. 특히 잘못된 계약 코드는 중대한 금전적 손해를 끼칠 수 있습니다. 이를 방지하기 위해서 zepplin-solidity는 표준 계약을 제공하고 있습니다.

표준 코인을 하나 만듭니다.

my-ico/contracts 폴더에 JHPCoin.sol 파일 하나를 만들고 아래 코드를 복사합니다.
표준 MintableToken을 하나 상속받아서 contract 를 생성하고,
Coin의 이름과 심볼을 설정하는 코드 입니다. ( 간단하죠?)

mintable의 뜻 : 화폐 발행이 가능한
MintableToken : crowdsale에서 이더를 받아서 그에 대응되는 양의 코인을 발행하는 형태의 토큰 계약

my-ico/contracts/JHPCoin.sol

pragma solidity ^0.4.17;

import 'zeppelin-solidity/contracts/token/ERC20/MintableToken.sol';

contract JHPCoin is MintableToken {
  string public name = "JHP PERSONAL COIN"; // 설명
  string public symbol = "JHP"; // 코인 심벌
  uint8 public decimals = 18; // 자리수

} // end of contract -------------------------------------------

CrowdSale 코드 작성

코인을 만들었으니, 이제 ICO하는 코드를 만들어 봐야겠네요.
contracts 폴더에 JHPCoinCrowdSale.sol 파일을 만들고 아래 코드를 복사합니다.

코드 내용은 단순합니다.
역시 zeppelin에서 만든 표준적인 crowdsale을 상속받는 내용입니다.

my-ico/contracts/JHPCoinCrowdSale.sol


pragma solidity ^0.4.17;

import './JHPCoin.sol';
import 'zeppelin-solidity/contracts/crowdsale/Crowdsale.sol';


contract JHPCoinCrowdsale is Crowdsale {

 // startTime : crowdSale 시작일
 // endTime :  종료일
 // rate : 이더-코인 교환비. 토큰 발행량 = 이더 x rate
 // wallet : crowdSale에 지급되는 이더를 받을 지갑
  function JHPCoinCrowdsale(uint256 _startTime, uint256 _endTime, uint256 _rate, address _wallet)
    Crowdsale(_startTime, _endTime, _rate, _wallet) {
  }

  // creates the token to be sold.
  // override this method to have crowdsale of a specific MintableToken token.
  function createTokenContract() internal returns (MintableToken) {
    return new JHPCoin();
  }
}

Truffle 환경에서 스마트 계약 deploy 코드 작성

crowdSale 관련 계약은 모두 작성하였습니다.
이제 truffle 환경에서 배포를 위한 코드를 작성해 보겠습니다.

우선 migrations 폴더에 2_deploy_contracts.js 파일을 만들어서 아래 코드를 복사합니다.

my-ico/migrations/2_deploy_contracts.js

const JHPCoinCrowdsale = artifacts.require("./JHPCoinCrowdsale.sol")

module.exports = function(deployer, network, accounts) {
  const startTime = web3.eth.getBlock(web3.eth.blockNumber).timestamp + 5 // 계약 생성 후 5초뒤에 시작!
  const endTime = startTime + (86400 * 20) // 20 days
  const rate = new web3.BigNumber(1000) // 이더 하나에 1000개의 토큰을 보냅니다.
  const wallet = accounts[0] // 테스트넷의 계정 0 지갑 할당. 실제 ICO면 자기 지갑을 넣어야 겠죠?,,

  deployer.deploy(JHPCoinCrowdsale, startTime, endTime, rate, wallet)
};

테스트 넷 환경 설정

우리는 원문의 solidity-testrpc 대신 truffle develop 로 개발넷을 만듭니다.
localhost 포트(9545)가 달라져서 my-ico/truffle.js에 아래와 같이 설정을 변경하여 줍니다.

이더 접속환경 설정인 networks > development 설정을 localhost:9545로 하겠다는 의미입니다.

my-ico/truffle.js

module.exports = {
  // See <http://truffleframework.com/docs/advanced/configuration>
  // to customize your Truffle configuration!
  networks: {
   development: {
   host: "localhost",
   port: 9545,
   network_id: "*" // Match any network id
    }
  }
};

Compile

자 이제 다왔습니다. 컴파일 하고 실행해 보겠습니다.

$ truffle compile

정말 컴파일이 되는군요 ㅋㅋ
몇 개 경고가 떴지만, 가볍게 무시하겠습니다.

콘솔의 결과 화면을 보니 제가 만든 JHPCoin과 CrowdSale,
truffle에서 기본적으로 제공하는 Migration.sol,
그리고 zepplin의 ERC20 관련 토큰 코드들이 컴파일 됩니다.

truffle_compile.png

개발넷 실행

별도의 콘솔을 실행하고, 가상의 이더리움 네트워크를 구동합니다.

$truffle develop

localhost:9545로 개발넷이 실행되고, 몇 개의 account가 생성이 되었음을 알 수 있습니다.

truffle_develope.png

테스트 환경에 배포

막상 작성하고 보니 길군요... 이제 마지막입니다.
이번주 토요일 반나절은 소비한 것 같군요. 끝이 보입니다.

truffle migrate 를 실행합니다. 배포되어랏! 이얏!

$truffle migrate --reset

migrate 명령어는 컴파일된 contract를 목표한 이더리움 네트워크에 배포하는 역할을 합니다.
원문에서는 testrpc 에 하였으나, truffle 4.0.x로 넘어오면서 자체 develop network를 제공하여 여기에 배포하였습니다.

저는 네트워크를 인지하지 못하는 오류가 발생하였으나, reset 옵션을 붙여주니 정상적으로 됩니다. 오류 원인은 좀 더 찾아봐야 될것 같군요

truffle_migrate_reset.png

계약 생성 확인 및 ICO 확인

그럼 development 네트워크에 계약이 잘 올라갔는지 확인해 보겠습니다.
truffle console 로 network에 접속이 가능합니다.

$truffle console

첫번째 구매자를 1번 계정으로 설정합니다.

참고로 web3는 이더리움 네트워크에 접속하기 위한 인터페이스 입니다.

truffle(development)> first_buyer = web3.eth.accounts[1]
'0xf17f52151ebef6c7334fad080c5704d77216b732'

CrowdSale 코드가 배포된지 확인하고, 배포된 계약의 주소를 받아 옵니다.

truffle(development)> JHPCoinCrowdsale.deployed().then(inst => { crowdsale = inst } )
undefined

CrowdSale 계약이 생성되면, JHPCoin 계약도 같이 생성이 됩니다.
CrowdSale의 계약주소를 읽어서, 토큰계약의 주소를 받아옵니다.

truffle(development)> crowdsale.token().then(addr => { tokenAddress = addr } )
undefined

아래는 토큰 계약 주소입니다.
모든 계약은 지갑과 동일하게 주소 하나가 할당이 됩니다.

truffle(development)> tokenAddress
'0x6b5f2b72ed649a5018701eb2b71c4fd8f472595c'

우리의 첫번째 토큰 구매자인 first_buyer의 현재 balance를 확인합니다.
아직 아무것도 구매하지 않았으므로, balance가 '0' 임을 확인할 수 있습니다.

truffle(development)> JHPCoin.at(tokenAddress).balanceOf(first_buyer).then( balance => balance.toString(10) )
'0'

crowdsale에서 transaction 하나를 발생시킵니다.
first_buyer로 부터 1 이더를 crowdsale 계약으로 전송하는 transaction 입니다.

truffle(development)> crowdsale.sendTransaction({ from: first_buyer, value: web3.toWei(1, "ether")})
{ tx: '0xca48615349f295b9b61d5c02651f0801e083bdbf205bda5ee8925543cf877988',
  receipt:
  { transactionHash: '0xca48615349f295b9b61d5c02651f0801e083bdbf205bda5ee8925543cf877988',
  transactionIndex: 0,
  blockHash: '0x5309fdd94e2b4cf7a73efd3ef1431977bf677d5abb79ac26fd8ffa7b7adb1bf4',
  blockNumber: 10,
  gasUsed: 99279,
  cumulativeGasUsed: 99279,
  contractAddress: null,
  logs: [ [Object], [Object], [Object] ],
  status: 1 },
  logs:
  [ { logIndex: 2,
  transactionIndex: 0,
  transactionHash: '0xca48615349f295b9b61d5c02651f0801e083bdbf205bda5ee8925543cf877988',
  blockHash: '0x5309fdd94e2b4cf7a73efd3ef1431977bf677d5abb79ac26fd8ffa7b7adb1bf4',
  blockNumber: 10,
  address: '0x30753e4a8aad7f8597332e813735def5dd395028',
  type: 'mined',
  event: 'TokenPurchase',
  args: [Object] } ] }

transaction 이후에 우리의 첫번째 구매자의 balance가 증가했는지 확인해 보겠습니다.
1eth * 1000 rate 만큼의 토큰이 발행이 되었네요!!
참고로 JHPToken 토큰 설정 시 decimal을 18로 설정하여서, 10^18 * 1000 으로 표시됩니다.

truffle(development)> JHPCoin.at(tokenAddress).balanceOf(first_buyer).then( balance => balance.toString(10) )
'1000000000000000000000'

휴~ 생각보다 오래걸렸네요.
다음 번에는 표준 토큰의 특성에 대해서 좀 더 파보고, 실제 거래되는 ICO 코드를 분석해 보겠습니다.
코인 로고를 만들고, 잡 거래소라도 한 번 등록을 해봐야 되겠네요.

순서

나만의 코인을 만들어 봅시다. #1 - 개발환경 세팅 및 ERC20 코인 생성
나만의 코인을 만들어 봅시다. #2 - ERCxx 표준 토큰 특성 분석 및 실제 ICO 코드 분석
나만의 코인을 만들어 봅시다. #3 - 로고와 ICO 페이지 만들어 보기
나만의 코인을 만들어 봅시다. #4 - 리얼넷에 붙여서 잡거래소에 상장해보기

Sort:  

다음 편도 기대됩니다!

즐거운 스티밋!
힘내세요 빠샤!

즐거운 스티밋! 방문 감사합니다.

거래소상장까지해봐야겠네요

Congratulations @dimens! You received a personal award!

1 Year on Steemit

Click here to view your Board

Support SteemitBoard's project! Vote for its witness and get one more award!

Congratulations @dimens! You received a personal award!

Happy Birthday! - You are on the Steem blockchain for 2 years!

You can view your badges on your Steem Board and compare to others on the Steem Ranking

Vote for @Steemitboard as a witness to get one more award and increased upvotes!