[Truffle, React.js] 과일 가게 dApp 만들기 (1/2)

in ethereum •  7 years ago  (edited)

할 것


  1. 이더리움을 이용해 과일을 구매하고 판매하는 dApp 을 만듭니다.

  2. React.js 로 프론트엔드를 구성합니다.

완성물 미리보기 (Youtube)


Project_Preview

클릭하면 유뷰트로 이동합니다.

실제 완성물은 조금 더 못생겼습니다. css 를 다루기 귀찮아서...



준비물


Node.js

홈페이지에 접속해 LTS 버전을 설치해주세요. Truffle 을 설치하는데 사용합니다. (Node.js 5.0 상위 버전을 추천합니다.)

Truffle

npm install -g truffle



Truffle 은 이더리움 dApp 개발 프레임워크입니다. 스마트 컨트랙트 작성, 빌드 및 배포를 제공하며 유닛 테스트에 용이합니다.

Ganache

홈페이지에 접속하면 쉽게 다운로드 및 설치 할 수 있습니다.

Ganache 는 가상의 이더리움 클라이언트를 만들어줍니다. 마음껏 테스트 가능한 지갑, 계정, 화폐를 제공합니다. 이번 예제에서 Ganache 에 있는 이더리움을 사용합니다.

MetaMask

MetaMask 는 크롬 익스텐션입니다. 웹브라우저에 이더리움 트랜잭션 기능을 추가합니다. 꼭 설치해주세요.



프로젝트 생성



Truffle_React

Truffle 은 dApp 을 손쉽게 개발 할 수 있도록 미리 세팅해둔 프로젝트(보일러플레이트)를 제공합니다. 이를 Truffle Boxes 라고 부릅니다.

우리는 그 안에 기능만 추가하면 됩니다.

Truffle Boxes 중 react 박스를 사용합니다.

react 박스는 Truffle 이 제공하는 Official Box 이며 292 개 이상의 Star 를 보유하고 있습니다.

디렉토리를 생성하고 reactunbox 합니다:

> mkdir fruitshop
> cd fruitshop
> truffle unbox react



프로젝트를 생성하는데 몇 분 걸립니다.

프로젝트 구조



디렉토리를 조사합니다:

> tree -L 1
.
├── box-img-lg.png
├── box-img-sm.png
├── config
├── contracts
├── migrations
├── node_modules
├── package-lock.json
├── package.json
├── public
├── scripts
├── src
├── test
├── truffle-config.js
└── truffle.js



다양한 폴더가 존재하지만 우리는 일부만 사용합니다:

  • /contracts: 스마트 컨트랙트를 작성합니다.

  • /migrations: Truffle 마이그레이션 파일을 작성합니다.

  • /scripts: build, start, test 환경을 설정합니다.

  • /src: React.js 폴더입니다.

  • truffle.js: Truffle 환경 설정 파일입니다.



불필요 코드 제거하기


  1. react box 가 미리 작성해 놓은 /contracts/SimpleStorage.sol, /build/contracts/SimpleStorage.json 를 삭제합니다.

  2. 이에 해당하는 /migrations/2_deploy_contracts.js 마이그레이션도 함께 지워줍니다. 추후에 우리가 작성한 컨트랙트에 해당하는 마이그레이션 파일을 생성합니다.

Truffle 콘픽 설정하기



truffle.js 를 열어서 다음과 같이 입력합니다:

module.exports = {
  networks: {
    development: {
      host: "127.0.0.1",
      port: 7545,
      network_id: "*" // Match any network id
    }
  }
};



우리는 로컬 환경에서 실습하기 때문에 host127.0.0.1 로 설정합니다. portGanache 의 포트를 적어줍니다:

Ganache_Port

컨트랙트 생성하기



과일 가게를 운영할 Shop.sol 컨트랙트가 필요합니다.

컨트랙트를 생성하는 방법은 두 가지가 있습니다:

> truffle create contract Shop



이렇게 커맨드를 입력하거나 직접 Shop.sol 파일을 /contracts 폴더에 생성합니다.

이제 /contracts 폴더는 다음과 같습니다:

> tree .
.
├── Migrations.sol
└── Shop.sol


  • Migrations.sol 은 프로젝트 생성시 포함되는 컨트랙트입니다. 이는 여러분이 Deploy, Migrate 한 모든 컨트랙트의 상태 및 변화를 추적합니다. 자세한 내용은 여기를 참고해주세요.

컨트랙트 작성하기



우리는 과일을 구매하고 판매 할 수 있는 하나의 시장을 구축해야 합니다.

앞서 보여드린 동영상에서 사과, 바나나 그리고 키위를 판매했지만 포스팅에선 사과만 다루겠습니다. 바나나와 키위는 단순히 기능 추가만 하면 되므로 생략하겠습니다.

첫째로, 계정의 사과 보유량을 기록하는 mapping 을 선언합니다:

pragma solidity ^0.4.18;

contract Shop {
  mapping (address=>uint16) myApple;
}


  • myApple 은 계정에 몇 개의 사과가 남았는지 addressuint16 을 맵핑합니다.

예를 들어 특정한 두 계정이 사과를 4개, 3개 씩 구매 했다면 myApple 은 다음과 같습니다:

0xdaF72FcEE99c3ED561b5F91a83B69c6F3D6B02e8 => 4
0x5De494B59aa0a1c3B7a4f2E45929Bcd341599613 => 3


만약 0xdaF72FcEE99c3ED561b5F91a83B69c6F3D6B02e8 가 사과를 한 개 더 구매한다면 myApple 은 이렇게 변하겠죠?:

0xdaF72FcEE99c3ED561b5F91a83B69c6F3D6B02e8 => 5
0x5De494B59aa0a1c3B7a4f2E45929Bcd341599613 => 3


다음으로 사과 구매 함수를 작성합니다:

function buyApple() payable  external {
        myApple[msg.sender]++;
}


  • buyApple 은 외부에서 트랜잭션을 실행하기 위해 payable external 입니다.

  • 함수가 실행되면 msg.sendermyApple 을 증가시킵니다.

보유한 사과 개수를 반환하는 함수를 작성합니다:

function getMyApples() view external returns(uint16) {
        return myApple[msg.sender];
}


  • getMyApples 는 컨트랙트의 상태를 변경하지 않고 값을 반환하므로 view 함수입니다. 또한 외부에서 호출 가능하도록 external 로 선언했습니다.

  • msg.sender 의 사과 개수를 uint16 형으로 반환합니다.

보유한 모든 사과를 시장에 다시 판매하는 함수를 작성합니다:

function sellMyApple(uint _applePrice) payable external {
        uint refund = (myApple[msg.sender] * _applePrice);
        myApple[msg.sender] = 0;
        msg.sender.transfer(refund);
}


  • sellMyApple 은 트랜잭션 가능하고 외부에서 호출해야하므로 payable external 함수입니다.

  • 사과의 시세(_applePrice)를 서버에서 받아와 현재 계정이 보유한 개수과 곱해 총 가격을 산출합니다.

  • msg.sendermyApple0 으로 초기화합니다.

  • 계산한 총 가격만큼 msg.senderETH 를 전송합니다.

이제 컨트랙트를 완성했습니다. Shop.sol 을 다시 한 번 확인하세요:

pragma solidity ^0.4.18;

contract Shop {

  mapping (address=>uint16) myApple;

  function buyApple() payable  external {
          myApple[msg.sender]++;
  }

  function getMyApples() view external returns(uint16) {
          return myApple[msg.sender];
  }

  function sellMyApple(uint _applePrice) payable external {
        uint refund = (myApple[msg.sender] * _applePrice);
        myApple[msg.sender] = 0;
        msg.sender.transfer(refund);
  }

}




컨트랙트 배포 준비



Truffle 에서 컨트랙트를 배포(Deploy)하려면 migration 을 작성해야합니다.

/migrations 폴더에 2_deploy_contracts.js 를 직접 생성해주세요.

혹은 truffle console 을 사용합니다.

> truffle create migration shop


커맨드로 생성한 migration 은 파일 이름이 1526449185_shop.js 처럼 생성됩니다. 이를 2_deploy_contracts.js 로 변경해주세요. 파일 이름이 직접적으로 영향을 끼치지 않지만 x_script_name.js 를 사용하는게 관습입니다.

2_deploy_contracts.js 에 Truffle 이 우리가 작성한 컨트랙트를 어떻게 배포할지 지시합니다.

이제 코드를 작성합시다:

// 2_deploy_contracts.js
var Shop = artifacts.require("./Shop.sol");

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


  • 우리가 작성한 Shop.sol 을 불러오고 이를 배포합니다. 현재는 별다른 기능이 없지만 여러개의 컨트랙트를 작성한 경우 순서를 설정하거나 관계를 정의 할 수 있습니다.

컨트랙트 배포



Shop.sol 컨트랙트를 자바스크립트에서 접근 가능하도록 json 파일로 변환 작업이 필요합니다:

> truffle compile
Compiling ./contracts/Shop.sol...
Writing artifacts to ./build/contracts



/build/contracts/ 폴더에 Shop.json 파일이 생성되었습니다. 컨트랙트를 다루는데 필요한 정보가 들어있습니다.

Ganache 가 실행된 상태에서 migration 을 진행합니다:

> truffle migrate --reset
Using network 'development'.

Running migration: 1_initial_migration.js
  Replacing Migrations...
  ... 0xcea701639e031a7211bbe43038b4fb3fb710a539161e6f36249efb1520c8c653
  Migrations: 0x302c323f97a9d01fabeb57d7746865afd9a94ec4
Saving successful migration to network...
  ... 0x5225d65039b9f92eed19d76abb52c7ebd1173dd9001d5a6181868f09db3d4ae0
Saving artifacts...
Running migration: 2_deploy_contracts.js
  Deploying Shop...
  ... 0x720118601d7250e764a4da707489abfefe8c1a98ab8259b24a860102fe234c05
  Shop: 0x5648e270176f70be090d07ccfaaada2e5d4e1da2
Saving successful migration to network...
  ... 0x3106e54ca62502c0eb0eca0aaf804b969b12f04f6561796b33c28b13ba082fe6
Saving artifacts...


--reset 옵션을 사용하면 이전에 로컬에서 작업한 내용들을 지우고 다시 migrate 합니다. 만약 Ganache 를 처음 설치하셨다면 해당 옵션 없이 진행하셔도 괜찮습니다.

방금 입력한 커맨드로 여러분이 작성한 스마트 컨트랙트를 로컬 이더리움 네트워크에 배포했습니다. 축하합니다!!

이어서...



다음 포스팅은 React.js 와 Web3.js 를 통해 컨트랙트와 통신합니다.

감사합니다.

Authors get paid when people like you upvote their post.
If you enjoyed what you read here, create your account today and start earning FREE STEEM!
Sort Order:  

짱짱맨 호출에 출동했습니다!!

안녕하세요. 리액트와 dapp에 대해서 둘다 공부 중이였는데 마침 좋은 예제 만들어주셔서 잘보고갑니다. 자주들를게요😊

감사합니다. 저도 처음 시도해보는거라 많이 허접하지만 잘 부탁드립니다 😃😃

좋은 글 감사합니다.