본문 바로가기
블록체인 및 경제/솔리디티

3. 스마트컨트랙트 작성 후 배포하기

by Danny_Kim 2020. 11. 3.

1. 스마트 계약의 시작, 리믹스 도구 사용해보기

2. 솔리디티 개발환경 구성

3. 스마트컨트랙트 작성 후 배포하기

4. openzeppelin 사용하여 ERC20 토큰 만들기

5. Ropsten 테스트넷에 ERC20토큰 배포하기

6. web3.js 와 자바스크립트를 활용한 간단한 예제

7. 솔리디티 기초, 리믹스로 컨트랙트 작성하기

8. 솔리디티 기본문법 (변수, 데이터타입, 구조체)

9. 솔리디티 배열, 맵핑

10. 솔리디티 조건문, 반복문(if, else, for)

11. 솔리디티 암호화폐 지불(호텔룸 예약하기 프로그램)

12. 솔리디티 상속

13. 리믹스 솔리디티 6.0 버전 ERC20토큰 만들기

14. web3.js 와 자바스크립트를 활용하여 (이더잔액조회) 지갑 만들기

15. 솔리디티 컨트랙트 Web.js 활용하여 웹으로 보여주기

 

1. openzeppelin 라이브러리 설치하기

 openzeppelin라이브러리는 기본적이고 많이 사용되는 smartcontract코드를 모아놓은 라이브러리입니다.

 이미 잘 짜여진 코드가 있는데 힘겹게 다시 코딩할 필요는 없습니다. 항상 최신의 문제 없는 라이브러리를 잘 찾아서 사용하는 방법을 아는게 중요합니다.

 

  1) smartcontract 폴더 생성 

  2) truffle init

    3) npm init -y

     4) npm install -E openzeppelin-solidity

 

네, 이제 openzeppelin-solidity 라이브러리가 설치되었습니다.

이제 ATOM 에디터로 해당 폴더를 열어봅니다. 아래와 같은 폴더구조를 보실 수 있습니다.

간략하게 설명을 하면,

 - contracts : 실제 우리가 solidity언어로 스마트컨트랙트를 작성하는 공간입니다.

 - mgrations : contracts 폴더에서 작업한 코드를 블록체인에 deploy하기 위한 코드

 - node_modules : 스마트컨트랙트 개발에 필요한 라이브러리

 - test : 테스트를 위한 폴더

 - truffle-config.js 통신을 위한 설정부분.

 

통신을 위해서 truffle-config.js 부분의 소스를 아래와 같이 수정해줍니다.

     development: {
      host: "127.0.0.1",     // Localhost (default: none)
      port: 8545,            // Standard Ethereum port (default: none)
      network_id: "*",       // Any network (default: none)
     },

그리고 아래에 컴파일 버전도 아래와 같이 수정해줍니다.

 

 

 

2. 스마트컨트랙트 작성해보기

 

이제 본격적인 준비작업은 끝났으니, 간단한 스마트컨트랙트를 직접작성해봅시다.

 

1. Test.sol 파일 작성

contract 폴더 안에 Test.sol 파일을 작성합니다.

그리고 아래와 같은 코드를 입력해주세요!!

pragma solidity ^0.5.2; // solidity 0.5.2 버전을 사용

contract TEST {  // contract 이름을 TEST로 지정
  string public constant name = "TEST token"; // 토큰의 이름은 TEST token
  string public constant symbol = "TEST"; // TEST라는 이름을 사용
  uint public constant decimals = 18; // 소수점 18자리까지 사용하겠음
  uint public constant INITIAL_SUPPLY = 1000 * 10 ** decimals; // 초기 발행량은 1000.000000000000000000 (소수점 18자리까지사용)
  string constant test = "You can not see this"; // public 표시가 없는 경우 해당 문구 볼 수 없음.
}

- 변수 선언시 public를 하지 않으면 외부에서 해당 변수를 찾을 수 없음.

- constant : 변하지 않는 변수 선언.

- public : 누구나 확인 할 수 있는 변수 선언.

- string : 문자열

- uint : unsigned integer (부호(+,-) 없는 정수- 양수 범위를 2배로 늘리게 됨, 즉 이진수와 같은 십진수가 됨)

 

 

2. 배포 코드 작성하기

 

migration폴더에 아래와 같이 2_Test_Migration.js 파일을 생성합니다.

위에 작성한 Test.sol 코드를 블록체인에 올리기 위해서 해당 파일을 작성하는겁니다.

아래와 같이 코딩해줍니다.

const TestToken = artifacts.require("./Test");

module.exports = function(deployer){
  deployer.deploy(TestToken);
};

 

3. 컨트랙트 배포하기

 

먼저 ganache-cli 를 실행합니다.

이후 truffle migrate 명령어를 실행합니다.

제일 아래에 우리가 작성한 2_Test_Migration.js 스마트컨트랙트 파일이 블록체인에 업로드 된걸 확인할 수 있습니다.

 

위에 보면 contract address가 나오는데, 이 주소를 기반으로 TEST라는 스마트컨트랙트와 통신이 가능합니다.

그리고 아톰에디터를 보면, build폴더에 TETS.json 파일이 생성된걸 확인할 수 있습니다.

이 코드파일에서 "abi": 라고 되어 있는 부분이 있습니다.

ABI는 애플리케이션 바이너리 인터페이스(Application Binary Interface)라고 부릅니다.

모든 외부, 공개 함수의 선언 및 파라미터, 반환유형으로 구성된 인터페이스인데요.

ABI에서 계약을 정의하고, 계약함수를 호출하고자 하는 호출자는 ABI를 사용할 수 있습니다.

 

그리고 소스 조금 아래로 내려와보면, "deployedBytecode" 부분이 있는데요. 계약을 배포하기 위해서 이 바이트코드가 필요합니다. 

정리하면,

 계약의 배포를 위해서 바이트코드가 필요하고,

 계약의 함수를 호출하기 위해서 ABI가 필요합니다.

 계약을 배포하는 것 자체가 블록체인에서는 거래이기 때문에 계약을 배포했다는 건 거래가 생성된걸로 간주합니다. 즉 바이트코드와 ABI는 계약을 배포하기 위해서 가장 중요한 2가지 요소입니다.

 

 

 

4. 스마트컨트랙트와 통신하기

 

이번에는 ABI를 통해서 스마트컨트랙트와 통신하는 방법을 알아보겠습니다.

기존에 설치했던  myetherwallet을 엽니다.

왼쪽 메뉴에 보면, Contract - Interact with Contract 메뉴가 있습니다.

 

Contract Address에는 truffle migrate를 통해서 얻은 컨트랙트주소를 입력합니다.

저의 경우에는 아래에 contract address에 해당하는  x5af58f7b22dd98238a2e27725903d6db96190a07ab5f90cb28d47c7ca258da50를 사용합니다.

 

아래 ABI/JSON Interface에는 abi를 입력해줍니다.

ATOM 에디터 TEST.json 파일에서 "abi": 오른쪽 [ 부터~ ] 까지 복사, 붙여넣기 합니다.

제가 복사&붙여넣기 한 ABI 소스는 아래와 같습니다.

[
    {
      "constant": true,
      "inputs": [],
      "name": "INITIAL_SUPPLY",
      "outputs": [
        {
          "internalType": "uint256",
          "name": "",
          "type": "uint256"
        }
      ],
      "payable": false,
      "stateMutability": "view",
      "type": "function"
    },
    {
      "constant": true,
      "inputs": [],
      "name": "decimals",
      "outputs": [
        {
          "internalType": "uint256",
          "name": "",
          "type": "uint256"
        }
      ],
      "payable": false,
      "stateMutability": "view",
      "type": "function"
    },
    {
      "constant": true,
      "inputs": [],
      "name": "name",
      "outputs": [
        {
          "internalType": "string",
          "name": "",
          "type": "string"
        }
      ],
      "payable": false,
      "stateMutability": "view",
      "type": "function"
    },
    {
      "constant": true,
      "inputs": [],
      "name": "symbol",
      "outputs": [
        {
          "internalType": "string",
          "name": "",
          "type": "string"
        }
      ],
      "payable": false,
      "stateMutability": "view",
      "type": "function"
    }
  ]

 

이걸 myetherwalle 아래의 그림과 같이 붙여넣기 해줍니다.

Continue를 클릭하면, 우리가 작성한 스마트컨트랙트 기능을 확인할 수 있습니다.

 

오른쪽에 작성된 아이템을 하나씩 클릭해보면,

초기공급량, Deciminals, 토큰 이름, 토큰 심볼까지 모두 아래와 같이 나오는걸 확인할 수 있습니다.

 

 

처음에 작성된 코드가 아래 코딩임을 다시 한번 상기해보신다면,

마지막에 public을 사용하지 않은 string 배열 test인 "you can not see this"는 표시되지 않은걸 확인 할 수 있습니다.

나머지는 모두 위와 같이 스마트컨트랙트에 정상적으로 배포가 되었네요.

 

 

 

 

반응형

댓글8

  • 정호영 2021.02.01 00:06

    pragma solidity ^0.5.2; // solidity 0.5.2 버전을 사용 contract TEST { // contract 이름을 TEST로 지정 string public constant name = "TEST token"; // 토큰의 이름은 TEST token string public constant symbol = "TEST"; // TEST라는 이름을 사용 uint public constant decimals = 18; // 소수점 18자리까지 사용하겠음 uint public constant INITIAL_SUPPLY = 1000 * 10 ** decimals; // 초기 발행량은 1000.000000000000000000 (소수점 18자리까지사용) string constant test = "You can not see this"; // public 표시가 없는 경우 해당 문구 볼 수 없음. }

    여기서 ^0.5.2 부분부터 인식을 못하네요 이유를 알 수 있을까요?
    2번째 글에서 알려주신 linter-solidity 그리고 그 밑에것이 인스톨이 안돼서 인스톨을 못받았는게 그게 이유인가요?
    답글

    • Danny_Kim 2021.02.01 11:08 신고

      truffle-config.js 에서 버전을 똑같이 적었는지 확인해보세요~

  • 진명수 2021.02.06 11:05

    C:\Users\brosn\smartcontract>

    C:\Users\brosn\smartcontract>truffle migrat

    Compiling your contracts...
    ===========================
    > Compiling .\contracts\Test.sol
    > Artifacts written to C:\Users\brosn\smartcontract\build\contracts
    > Compiled successfully using:
    - solc: 0.5.16+commit.9c3226ce.Emscripten.clang

    > Something went wrong while attempting to connect to the network. Check your network configuration.
    ProviderError:
    Could not connect to your Ethereum client with the following parameters:
    - host > 127.0.0.1
    - port > 7545
    - network_id > 5777
    Please check that your Ethereum client:
    - is running
    - is accepting RPC connections (i.e., "--rpc" option is used in geth)
    - is accessible over the network
    - is properly configured in your Truffle configuration file (truffle-config.js)

    at C:\Users\brosn\AppData\Roaming\npm\node_modules\truffle\build\webpack:\packages\provider\wrapper.js:73:1
    at C:\Users\brosn\AppData\Roaming\npm\node_modules\truffle\build\webpack:\packages\provider\wrapper.js:102:1
    at XMLHttpRequest.request.onreadystatechange (C:\Users\brosn\AppData\Roaming\npm\node_modules\truffle\build\webpack:\node_modules\web3\node_modules\web3-providers-http\src\index.js:111:1)
    at XMLHttpRequestEventTarget.dispatchEvent (C:\Users\brosn\AppData\Roaming\npm\node_modules\truffle\build\webpack:\node_modules\xhr2-cookies\dist\xml-http-request-event-target.js:34:1)
    at XMLHttpRequest._setReadyState (C:\Users\brosn\AppData\Roaming\npm\node_modules\truffle\build\webpack:\node_modules\xhr2-cookies\dist\xml-http-request.js:208:1)
    at XMLHttpRequest._onHttpRequestError (C:\Users\brosn\AppData\Roaming\npm\node_modules\truffle\build\webpack:\node_modules\xhr2-cookies\dist\xml-http-request.js:349:1)
    at ClientRequest.<anonymous> (C:\Users\brosn\AppData\Roaming\npm\node_modules\truffle\build\webpack:\node_modules\xhr2-cookies\dist\xml-http-request.js:252:47)
    at ClientRequest.emit (node:events:378:20)
    at Socket.socketErrorListener (node:_http_client:462:9)
    at Socket.emit (node:events:378:20)
    at emitErrorNT (node:internal/streams/destroy:188:8)
    at emitErrorCloseNT (node:internal/streams/destroy:153:3)
    at processTicksAndRejections (node:internal/process/task_queues:81:21)
    Truffle v5.1.65 (core: 5.1.65)
    Node v15.8.0

    네트워크 접속이 안되는거같은데 포트 번호가 8545로 변경했는데 ~ 이유가뭘가요>>
    답글

    • Danny_Kim 2021.02.06 15:32 신고

      저기 에러에는 포트번호 7545가 접속이 안되네요? ganache 한번 확인해보세요 7545 또는 8545로 되어 있을것 같은데요?

  • 루다 2021.02.08 09:09

    감사합니다 해결했습니다!!!
    답글

  • happyzoomy 2021.03.23 18:53

    좋은 글 감사합니다. ABI 소스를 그대로 복사하고 붙여넣기 했는데 SOMETHING IS WRONG 이라며 토큰 내용이 뜨지 않네요. 테스트 토큰 코드는 잘 받았는데 무엇이 문제일까요?
    답글

    • happyzoomy 2021.03.23 18:55

      에러 디테일은 이러합니다

      {
      "exception": {
      "values": [
      {
      "type": "TypeError",
      "value": "Cannot read property '0' of null",
      "stacktrace": {
      "frames": [
      {
      "colno": 12156,
      "filename": "https://www.myetherwallet.com/js/vendors.c7913402.js",
      "function": "ut",
      "in_app": true,
      "lineno": 109
      },
      {
      "colno": 12761,
      "filename": "https://www.myetherwallet.com/js/vendors.c7913402.js",
      "function": "Array.<anonymous>",
      "in_app": true,
      "lineno": 109
      },
      {
      "colno": 29624,
      "filename": "https://www.myetherwallet.com/js/vendors.c7913402.js",
      "function": "Vr",
      "in_app": true,
      "lineno": 109
      },
      {
      "colno": 31417,
      "filename": "https://www.myetherwallet.com/js/vendors.c7913402.js",
      "function": "tn.run",
      "in_app": true,
      "lineno": 109
      },
      {
      "colno": 30684,
      "filename": "https://www.myetherwallet.com/js/vendors.c7913402.js",
      "function": "tn.get",
      "in_app": true,
      "lineno": 109
      },
      {
      "colno": 27824,
      "filename": "https://www.myetherwallet.com/js/vendors.c7913402.js",
      "function": "a.n",
      "in_app": true,
      "lineno": 109
      },
      {
      "colno": 23733,
      "filename": "https://www.myetherwallet.com/js/vendors.c7913402.js",
      "function": "a.Ar.e._render",
      "in_app": true,
      "lineno": 109
      },
      {
      "colno": 5331,
      "filename": "https://www.myetherwallet.com/js/chunk-ffbc0c08.8e938f2f.js?__WB_REVISION__=364be4085668060ec2b6",
      "function": "a.s",
      "in_app": true,
      "lineno": 1
      },
      {
      "colno": 16912,
      "filename": "https://www.myetherwallet.com/js/vendors.c7913402.js",
      "function": "a.Ft [as _l]",
      "in_app": true,
      "lineno": 109
      },
      {
      "colno": 5715,
      "filename": "https://www.myetherwallet.com/js/chunk-ffbc0c08.8e938f2f.js?__WB_REVISION__=364be4085668060ec2b6",
      "function": "?",
      "in_app": true,
      "lineno": 1
      }
      ]
      },
      "mechanism": {
      "handled": true,
      "type": "generic"
      }
      }
      ]
      },
      "level": "error",
      "event_id": "f3a1d6d3f1b94af89af5b43cbefcd4da",
      "platform": "javascript",
      "timestamp": 1616493275.062,
      "environment": "web",
      "release": "5.7.24",
      "contexts": {
      "vue": {
      "componentName": "anonymous component",
      "propsData": "[undefined]",
      "lifecycleHook": "render"
      }
      },
      "request": {
      "url": "https://www.myetherwallet.com/interface/interact-with-contract",
      "headers": {
      "Referer": "https://kimsfamily.kr/327?category=903691",
      "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36"
      }
      },
      "tags": {
      "network": "ETH",
      "service": "myetherwallet.com",
      "walletType": "web3_wallet"
      }
      }

    • happyzoomy 2021.03.23 19:29

      ABI 소스는 이러합니다

      [
      {
      "constant": true,
      "inputs": [],
      "name": "name",
      "outputs": [
      {
      "name": "",
      "type": "string"
      }
      ],
      "payable": false,
      "stateMutability": "view",
      "type": "function"
      },
      {
      "constant": true,
      "inputs": [],
      "name": "INITIAL_SUPPLY",
      "outputs": [
      {
      "name": "",
      "type": "uint256"
      }
      ],
      "payable": false,
      "stateMutability": "view",
      "type": "function"
      },
      {
      "constant": true,
      "inputs": [],
      "name": "decimals",
      "outputs": [
      {
      "name": "",
      "type": "uint256"
      }
      ],
      "payable": false,
      "stateMutability": "view",
      "type": "function"
      },
      {
      "constant": true,
      "inputs": [],
      "name": "symbol",
      "outputs": [
      {
      "name": "",
      "type": "string"
      }
      ],
      "payable": false,
      "stateMutability": "view",
      "type": "function"
      }
      ]