Sample Contracts

이 장에서는 truffle을 이용하여 스마트 컨트랙트를 작성하고 배포하는 방법에 대하여 설명합니다.

스마트 컨트랙트 작성

Truffle을 사용하여 스마트 컨트랙트의 작성과 배포를 하는 방법에 대해서 설명합니다.

Truffle 사용 방법

1. 설치

Node package manager인 npm 사용하여 truffle을 설치할 수 있습니다. npm 설치 방법은 다음 링크를 참조하세요. https://www.npmjs.com/

$ npm install --g truffle

2. 초기화

$ truffle init

truffle init을 수행하면 Truffle project가 생성됩니다. 생성된 truffle project는 build/contracts, contracts, migrations, test, truffle-config.js 로 구성되어 있습니다.

  • build/contracts : solidity로 작성한 contract가 compile된 결과(abi, bytecode)가 저장

  • contract : smart contract solidity files

  • migrations : deploy code(js format)

  • test : test code(js format)

  • truffle-config.js : solidity compiler version 설정, network 설정 등의 configuration

truffle init을 수행하면 contract 폴더 안에 Migrations.sol 이라는 예제 solidity 코드가 아래와 같이 생성되어 있는 것을 확인 할 수 있습니다. 작성된 스마트 컨트랙트를 배포하기 위해 사용자는 작성한 스마트 컨트랙트를 먼저 컴파일 해야합니다.

pragma solidity >=0.4.22 <0.9.0;

contract Migrations {
  address public owner = msg.sender;
  uint public last_completed_migration;

  modifier restricted() {
    require(
      msg.sender == owner,
      "This function is restricted to the contract's owner"
    );
    _;
  }

  function setCompleted(uint completed) public restricted {
    last_completed_migration = completed;
  }
}

3. 설정

컴파일 및 배포를 위하여 truffle-config.js 파일을 수정하여야 합니다.

3.1 계정 설정

배포를 위해 사용할 계정에 대한 설정을 위해 truffle-config.js 파일의 HDWalletProvider와 privKeys를 추가합니다. Private key는 Web Wallet (https://wallet.test.wemix.com)을 통해 계정을 생성한 후 가져올 수 있습니다.

const HDWalletProvider = require('@truffle/hdwallet-provider');
const privKeys = ["privatekey from Web Wallet"];

3.2 네트워크 설정

WEMIX3.0 테스트넷을 사용하기 위해서는 아래와 같이 네트워크 설정을 추가합니다.

networks: {
  wemix_testnet: {
    provider: ()=> new HDWalletProvider(privKeys, "https://api.test.wemix.com"),
    network_id: 1112,
    maxFeePerGas: 100000000010,
    maxPriorityFeePerGas: 100000000000
  }
},

3.3 컴파일러 설정

마지막으로 사용하고자 하는 Solidity 컴파일러 버전을 설정합니다. 현재 최신 버전은 0.8.x 이며 예제는 0.8.11 버전을 사용합니다. 컴파일러를 사용하는 운영체제에 바로 설치되어 있으면 초기 설정과 동일하게 docker 설정을 주석처리하면 되며, docker를 사용하여 설치하기 위해서는 아래와 같이 "docker: true"로 설정하고 docker가 설치되어 있어야 합니다. optimizer를 사용한다면 주석을 해제하고 적절한 설정을 해주면 됩니다.

compilers: {
    solc: {
      version: "0.8.11",    // Fetch exact version from solc-bin (default: truffle's version)
      docker: true,         // Use "0.5.1" you've installed locally with docker (default: false)
      // settings: {          // See the solidity docs for advice about optimization and evmVersion
      //  optimizer: {
      //    enabled: false,
      //    runs: 200
      //  },
      //  evmVersion: "byzantium"
      }
    }

4. Solidity 코드 작성

다음은 count 변수를 증가 또는 감소시키고 값을 조회하는 간단한 스마트 컨트랙트 예제입니다. Counter.sol로 저장합니다.

pragma solidity ^0.8.0;

contract Counter {
    uint256 count;
    
    constructor(uint256 _count) {
        count = _count;
    }
    
    function get() public view returns (uint256) {
        return count;
    }
    
    function inc() public {
        count += 1;
    }
    
    function dec() public {
        count -= 1;
    }
}

5. Solidity 코드 컴파일

truffle compile <file name>을 truffle project 폴더에서 수행하면 대상으로 지정한 solidity 파일을 컴파일하게 됩니다. 컴파일된 solidity contract는 build/contracts 폴더에 <contract name>.json 포맷으로 저장됩니다.

truffle compile <file name>
ex) truffle compile Counter.sol

6. 스마트 컨트랙트 배포

컴파일된 contract file을 블록체인에 배포하기 위해 다음과 같이 스크립트를 작성하고 2_deploy_contracts.js로 저장합니다.

var Counter = artifacts.require("./Counter.sol");

module.exports = function(deployer) {
  deployer.deploy(Counter, 10)
    .then(() => Counter.deployed());
};

배포할 스마트 컨트랙트를 artifacts.require(<build/contracts에 저장된 artifacts file 명>)로 로드하고, deployer.deploy(contract_artifacts,{constructor arguments})를 수행하면 개별적으로 스마트 컨트랙트를 배포할 수 있습니다.

truffle migrate <file name>
ex) truffle migrate 1_initial_migration.js

배포 스크립트는 위의 truffle migrate <file name>으로 수행할 수 있습니다. <file name>을 사용하지 않으면 스크립트 명에 사용된 숫자 순서대로 수행됩니다.

WEMIX3.0 테스트넷에 배포한 결과는 다음과 같습니다. 배포를 위해서는 배포에 사용할 계정에 WEMIX가 있어야 합니다. https://wallet.test.wemix.com의 WEMIX-Faucet에서 필요한 WEMIX를 받을 수 있습니다.

❯ truffle migrate --reset --network wemix_testnet

Compiling your contracts...
===========================
> Everything is up to date, there is nothing to compile.


Starting migrations...
======================
> Network name:    'wemix_testnet'
> Network id:      1112
> Block gas limit: 105000000 (0x6422c40)


1_initial_migration.js
======================

   Replacing 'Migrations'
   ----------------------
   > transaction hash:    0x8f57dc573afbf1e33b75b2f05282aac9152be70cee292c31c94877397cf27d82
   > Blocks: 0            Seconds: 0
   > contract address:    0x09C38aaf3AF7Dba9Cc2B755d75Acccf4A5b7bECC
   > block number:        428504
   > block timestamp:     1658480854
   > account:             0x435AaB89A2878102fDf894dA3e5F3b4454FF9772
   > balance:             9.926666599999266666
   > gas used:            250142 (0x3d11e)
   > gas price:           100.000000001 gwei
   > value sent:          0 ETH
   > total cost:          0.025014200000250142 ETH

   > Saving migration to chain.
   > Saving artifacts
   -------------------------------------
   > Total cost:     0.025014200000250142 ETH


2_deploy_contracts.js
=====================

   Deploying 'Counter'
   -------------------
   > transaction hash:    0x893fcc06e298b95ff145c90311c5d36a3f8c511470e73a753d13195ea9dae051
   > Blocks: 0            Seconds: 0
   > contract address:    0x76F3A4DFD8741E765Bf27Cd0BaaE26f64c192765
   > block number:        428508
   > block timestamp:     1658480857
   > account:             0x435AaB89A2878102fDf894dA3e5F3b4454FF9772
   > balance:             9.904089499999040895
   > gas used:            179858 (0x2be92)
   > gas price:           100.000000001 gwei
   > value sent:          0 ETH
   > total cost:          0.017985800000179858 ETH

   > Saving migration to chain.
   > Saving artifacts
   -------------------------------------
   > Total cost:     0.017985800000179858 ETH

Summary
=======
> Total deployments:   2
> Final cost:          0.04300000000043 ETH

7. 스마트 컨트랙트 테스트

배포한 스마트 컨트랙트를 다음과 같이 javascript 파일을 이용하여 테스트를 수행할 수 있습니다.

const migration = artifacts.require("Migrations");

contract("Migration", async () => {
    describe("Migration test", async () => {
        it("setCompleted", async () => {
            const migrations = await migration.deployed();
            await migrations.setCompleted(0);
        });
    });
});
  • contract : test 대상 contract

  • describe : test case 집합

  • it : 개별 test case

truffle test <test file name>

test code 작성이 완료되면 test file을 test 폴더에 <testName.test.js> format으로 저장하고, truffle test <testName.test.js> 를 수행하면 테스트가 수행됩니다.

Last updated