4th Street Bar Hive-Bar

Hive-Bar Powered by Hive beta-fdb5b5b

Community post

[dApp] 진짜 쉬운 이더리움 은행 만들기 2편 with Truffle

Ethereum_Truffle

할 것


  1. Contract 생성 및 작성

  2. MigrationDeploy

  3. 실행하기

이 프로젝트는 github에 등록되어 있습니다.


컨트랙트 생성


```console > truffle create contract Bank ```
잘 생성되었나 확인합시다:
> tree
.
├── contracts
│   ├── Bank.sol
│   └── Migrations.sol
├── migrations
│   └── 1_initial_migration.js
├── test
├── truffle-config.js
└── truffle.js

3 directories, 5 files

`/contracts` 에 `Bank.sol` 이 보입니다.

생성자 및 멤버 변수


``` pragma solidity ^0.4.20;

contract Bank {
function Bank() {
// 생성자
}
}

<br/>
`Bank.sol` 컨트랙트와 함께 생성자(`Constructor`)가 자동으로 생성되었습니다.

첫번째 라인은 `0.4.2` ~ `0.5.0` 버전 사이의 `Solidity Compiler` 를 사용함을 의미합니다. `truffle version` 을 입력하여 확인해볼까요?

```console
> truffle version
Truffle v4.1.8 (core: 4.1.8)
Solidity v0.4.23 (solc-js)

멤버 변수를 선언합니다:
contract Bank {
  // 계좌의 소유주
  address public owner;
  ...

* `address`: `20byte` 사이즈의 이더리움 주소를 담는 특별한 타입입니다.

멤버 변수를 선언하고 Visibility 를 정의합니다. Solidity 는 객체 지향 프로그래밍 언어에서 흔히 사용하는 접근지정자(Access Modifier)를 Visibility 로 부릅니다. public 으로 설정하면 다른 Contract 와 클라이언트가 이 변수를 들여다 볼 수 있습니다. 자세한 내용은 여기에서 확인해주세요.

이제 생성자(Constructor)를 수정합시다:

function Bank(address _owner) public {
        owner = _owner;
}

이 생성자는 `address` 타입의 `_owner` 매개 변수를 받아 계좌 소유주를 의미하는 `owner` 멤버 변수에 대입합니다.

입금 함수


``` function deposit() public payable { require(msg.value > 0); } ```
* `payable` _은 매우 중요합니다._ 이 키워드가 없다면 이더리움 트랜젝션(*`Transaction`*)이 불가능합니다. `deposit()` 함수는 직접적으로 이더리움을 전송하므로 만약 `payable` 키워드 없이 함수를 정의하면 트랜잭션(`Transaction`)은 거절(`reject`)됩니다.
  • deposit() 함수는 payable function 이기 때문에 내부에 송금 로직을 작성하지 않고도 이더리움을 전송 할 수 있습니다.

  • require 은 괄호 안의 값을 평가합니다. 만약 이라면 계속해서 함수를 실행 시키지만 거짓 일땐 함수 실행을 중지시키며 Transaction 을 취소(Revert)합니다. msg.value > 0 은 입금(deposit) 금액이 0 ETH 이상인지 검사합니다.

  • msg.value 는 전송하는 이더리움의 양입니다. Bank.sol 어디에서 정의되어 있지 않지만 사용 가능한 이유는 우리가 payable 함수를 실행(call)시킬때 인자로 msg 객체를 전달합니다.

출금 함수


``` function withdraw() public { require(msg.sender == owner); owner.transfer(address(this).balance); } ```
* `require` 를 이용해 `withdraw()` 함수를 실행(`call`)하는 클라이언트(`msg.sender`)가 계좌 소유주(`owner`)와 동일한지 확인합니다. `msg.sender` 는 함수를 실행하는 주체(`address`)입니다. 값은 함수 실행시 자동 할당됩니다.
  • transfer(amount) 함수는 amount 만큼 이더리움을 송금합니다. 이는 payable function call 과 달리 transaction 이 아닙니다. 이에 대한 자세한 내용은 여기를 참고하세요.

  • address(this).balance 는 컨트랙트의 이더 잔액(balance)입니다. address(this)Contract 인스턴스의 주소를 의미합니다. 즉 thisContract 자기 자신입니다.

정리하자면 withdraw() 는 함수를 실행시키는 클라이언트가 계좌의 소유주임을 확인하고 현재 Contract 의 잔액(balance) 만큼 owner 에세 송금합니다.

마지막으로 Bank.sol 의 전체 코드를 확인하세요.

pragma solidity ^0.4.4;

contract Bank {
    address public owner;

    function Bank(address _owner) public {
        owner = _owner;
    }

    function deposit() public payable {
        require(msg.value > 0);
    }

    function withdraw() public {
        require(msg.sender == owner);
        owner.transfer(address(this).balance);
    }
}

축하합니다! 이제 `Contract` 모두 작성했습니다. 앞으로
  • compile

  • migrate

작업이 남았습니다!


Compile & Migrate


컴파일을 합니다:
> truffle compile
Compiling ./contracts/Bank.sol...
Compilation warnings encountered:
Writing artifacts to ./build/contracts

/build 폴더에 여러분이 작성한 Bank.sol 코드가 Bank.json 으로 아름답게 변환되어 있을겁니다.

Truffle 은 여러분이 작성한 Contract 를 어떻게 Deploy 할 지 아직 모릅니다. 이를 알려주기 위해서 우리는 Migration Script 를 작성합니다.

> truffle create migration bank

`/migrations` 폴더에 `1525834979_bank.js` 처럼 타임스탬프(`timestamp`) 형식으로 파일이 자동 생성되었습니다.

아래 코드로 채워주세요:

var Bank = artifacts.require("Bank");

module.exports = function(deployer) {
  let ownerAddress = web3.eth.accounts[0];
  deployer.deploy(Bank, ownerAddress);
};

우리가 `Compile` 한 `Bank.json` 를 불러오기 위해 `artifacts.require` 라는 조금 특수한 구문을 사용합니다. 이는 `Truffle` 이 `Contract` 를 성공적으로 `Deploy` 하도록 고안 방법입니다.
  • ownerAddress0 번 계정을 대입했습니다.

  • web3.eth.accounts 는 클라이언트의 정보를 담고 있는 배열(Array)입니다. 즉 web3.eth.accounts[0]Ganache 상의 첫번째 계정과 동일하며 ownerAddress 는 이를 담고 있습니다.

  • deplyer.deployContractDeploy 합니다. 첫 번째 매개 변수는 Contract 를 전달하고 두 번째 매개 변수는 생성자(Constructor)에 전달할 매개 변수입니다. 우리가 앞서 작성한 생성자 함수에는 address 타입의 매개 변수를 요구하므로 ownerAddress 를 전달합니다. 이는 우리가 작성한 은행의 소유주는 Ganache 의 첫 번째 계정, 다시 말해 web3.eth.accounts[0] 이라는걸 뜻합니다.

Migration 하기 전에 마지막으로 설치한 Ganache 를 실행시켜주세요. Ganache 인스턴스가 가동중이 아니라면 Migration 이 불가능합니다.

Ganache 실행 화면:

Ganache

이제 터미널에 truffle migrate 를 입력해주세요:

> truffle migrate
Using network 'development'.

Running migration: 1_initial_migration.js
  Replacing Migrations...
  ... 0x189d93748c4f08398e841a303017514df868b7fcb54eba73bb4a631aad8c2bb9
  Migrations: 0x695ebfa99c04c3bcf934c65dd84cafa8d7e955f9
Saving successful migration to network...
  ... 0x0b1a2c70362deeb97322306c1680e865bd7759b54aba69ae57d8f51985d9e493
Saving artifacts...
Running migration: 1525834979_bank.js
  Replacing Bank...
  ... 0x9f702f9405c93be4c08b8dded6e3ce9f682228d9d54456fc331766270671132d
  Bank: 0xc18d5daf5afab9bc329d81700b269d4aac25a528
Saving successful migration to network...
  ... 0x84af0d76df1ecc280f6624f8a91691ebde7c646d3fa45d903a00569a1afb1454
Saving artifacts...

만약 에러가 발생하면 truffle migrate --reset 를 입력해주세요. 이전에 작업하시던 dApp 프로젝트와 충돌이 날 때가 있습니다.


실습


우리는 프론트엔드 없이 콘솔 환경 실습합니다.
> truffle console
truffle(development)>

이제 `Deploy` 한 `Contract` 의 인스턴스를 변수에 저장합니다:
truffle(development)> Bank.deployed().then(instance => bank = instance)

`Bank.deployed()` 는 `Contract` 의 인스턴스 평가하는 프로미스(`Promise`)를 반환합니다. `then` 을 이용하여 우리는 이를 `bank` 에 `bind` 합니다.

owner 멤버 변수를 확인해봅시다:

truffle(development)> bank.owner()
'0xdaf72fcee99c3ed561b5f91a83b69c6f3d6b02e8'

`Ganache` 의 첫 번째 계정과 `address` 가 동일합니다!

이제 은행에 10 ETH 만큼 입금을 해봅시다:

truffle(development)> bank.deposit({value: web3.toWei(10, 'ether')})

`deposit` 은 `payable` 함수입니다. 때문에 저희는 `value` 를 매개 변수로 담을 수 있습니다. `value` 는 `ETH` 의 최소 단위인 `Wei` 를 가집니다. 따라서 `web3.toWei` 를 통해 `10 ETH` 를 `Wei` 로 변환해야합니다.

이제 Ganache 의 첫 번째 계정의 잔액(balance)을 확인합니다:

Ganache_First_Account

89.94 ETH 가 남았습니다. 왜 90.00 ETH 가 아닐까요? 이는 Contract 의 함수를 실행시키는 수수료(Gas) 때문입니다. Gas 에 대한 자세한 내용은 여기를 참고하세요.

이제 출금할 차례입니다:

truffle(development)> bank.withdraw()

![Ganache_First_Account](https://dangen-effy.github.io/assets/ganache_2nd_account.png)

첫 번째 계정에 10 ETH 가 다시 들어왔습니다!

마치며


축하합니다! 드디어 이더리움 은행 `dApp` 을 완성했습니다. 여기까지 따라오신 분들 모두 수고하셨습니다. 감사합니다.
4 upvotes $0.00

Replies (3)

Review before signing

Posting as . Signing with . Keychain permission: Posting. Hive Keychain will ask you to approve this action next.


  
Technical details

Operation fingerprint: