 ## 할 것 ## <br/> 1. `Contract` 생성 및 작성 2. `Migration` 및 `Deploy` 3. 실행하기 이 프로젝트는 [github](https://github.com/dangen-effy/ethereum-bank)에 등록되어 있습니다. - - - ## 컨트랙트 생성 ## <br/> ```console > truffle create contract Bank ``` <br/> 잘 생성되었나 확인합시다: ```console > tree . ├── contracts │ ├── Bank.sol │ └── Migrations.sol ├── migrations │ └── 1_initial_migration.js ├── test ├── truffle-config.js └── truffle.js 3 directories, 5 files ``` <br/> `/contracts` 에 `Bank.sol` 이 보입니다. ## 생성자 및 멤버 변수 ## <br/> ``` 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) ``` <br/> 멤버 변수를 선언합니다: ``` contract Bank { // 계좌의 소유주 address public owner; ... ``` <br/> * `address`: `20byte` 사이즈의 이더리움 주소를 담는 특별한 타입입니다. 멤버 변수를 선언하고 `Visibility` 를 정의합니다. `Solidity` 는 객체 지향 프로그래밍 언어에서 흔히 사용하는 접근지정자(`Access Modifier`)를 `Visibility` 로 부릅니다. `public` 으로 설정하면 다른 `Contract` 와 클라이언트가 이 변수를 들여다 볼 수 있습니다. 자세한 내용은 [여기](http://solidity.readthedocs.io/en/v0.4.21/contracts.html#visibility-and-getters)에서 확인해주세요. 이제 생성자(`Constructor`)를 수정합시다: ``` function Bank(address _owner) public { owner = _owner; } ``` <br/> 이 생성자는 `address` 타입의 `_owner` 매개 변수를 받아 계좌 소유주를 의미하는 `owner` 멤버 변수에 대입합니다. ## 입금 함수 ## <br/> ``` function deposit() public payable { require(msg.value > 0); } ``` <br/> * `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` 객체를 전달합니다. ## 출금 함수 ## <br/> ``` function withdraw() public { require(msg.sender == owner); owner.transfer(address(this).balance); } ``` <br/> * `require` 를 이용해 `withdraw()` 함수를 실행(`call`)하는 클라이언트(`msg.sender`)가 계좌 소유주(`owner`)와 동일한지 확인합니다. `msg.sender` 는 함수를 실행하는 주체(`address`)입니다. 값은 함수 실행시 자동 할당됩니다. * `transfer(amount)` 함수는 `amount` 만큼 이더리움을 송금합니다. 이는 `payable function call` 과 달리 `transaction` 이 아닙니다. 이에 대한 자세한 내용은 [여기](https://ethereum.stackexchange.com/questions/38387/contract-address-transfer-method-gas-cost?rq=1&utm_medium=organic&utm_source=google_rich_qa&utm_campaign=google_rich_qa)를 참고하세요. * `address(this).balance` 는 컨트랙트의 이더 잔액(`balance`)입니다. `address(this)` 는 `Contract` 인스턴스의 주소를 의미합니다. 즉 `this` 는 `Contract` 자기 자신입니다. 정리하자면 `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); } } ``` <br/> 축하합니다! 이제 `Contract` 모두 작성했습니다. 앞으로 * `compile` * `migrate` 작업이 남았습니다! - - - ## Compile & Migrate ## <br/> 컴파일을 합니다: ```console > truffle compile Compiling ./contracts/Bank.sol... Compilation warnings encountered: Writing artifacts to ./build/contracts ``` `/build` 폴더에 여러분이 작성한 `Bank.sol` 코드가 `Bank.json` 으로 _아름답게_ 변환되어 있을겁니다. `Truffle` 은 여러분이 작성한 `Contract` 를 어떻게 `Deploy` 할 지 아직 모릅니다. 이를 알려주기 위해서 우리는 `Migration Script` 를 작성합니다. ```console > truffle create migration bank ``` <br/> `/migrations` 폴더에 `1525834979_bank.js` 처럼 타임스탬프(`timestamp`) 형식으로 파일이 자동 생성되었습니다. 아래 코드로 채워주세요: ```js var Bank = artifacts.require("Bank"); module.exports = function(deployer) { let ownerAddress = web3.eth.accounts[0]; deployer.deploy(Bank, ownerAddress); }; ``` <br/> 우리가 `Compile` 한 `Bank.json` 를 불러오기 위해 `artifacts.require` 라는 조금 특수한 구문을 사용합니다. 이는 `Truffle` 이 `Contract` 를 성공적으로 `Deploy` 하도록 고안 방법입니다. * `ownerAddress` 에 `0` 번 계정을 대입했습니다. * `web3.eth.accounts` 는 클라이언트의 정보를 담고 있는 배열(`Array`)입니다. 즉 `web3.eth.accounts[0]` 은 `Ganache` 상의 첫번째 계정과 동일하며 `ownerAddress` 는 이를 담고 있습니다. * `deplyer.deploy` 는 `Contract` 를 `Deploy` 합니다. 첫 번째 매개 변수는 `Contract` 를 전달하고 두 번째 매개 변수는 생성자(`Constructor`)에 전달할 매개 변수입니다. 우리가 앞서 작성한 생성자 함수에는 `address` 타입의 매개 변수를 요구하므로 `ownerAddress` 를 전달합니다. **이는 우리가 작성한 은행의 소유주는 `Ganache` 의 첫 번째 계정, 다시 말해 `web3.eth.accounts[0]` 이라는걸 뜻합니다.** `Migration` 하기 전에 마지막으로 설치한 `Ganache` 를 실행시켜주세요. `Ganache` 인스턴스가 가동중이 아니라면 `Migration` 이 불가능합니다. `Ganache` 실행 화면:  이제 터미널에 `truffle migrate` 를 입력해주세요: ```console > 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` 프로젝트와 충돌이 날 때가 있습니다. - - - ## 실습 ## <br/> 우리는 프론트엔드 없이 콘솔 환경 실습합니다. ```console > truffle console truffle(development)> ``` <br/> 이제 `Deploy` 한 `Contract` 의 인스턴스를 변수에 저장합니다: ```console truffle(development)> Bank.deployed().then(instance => bank = instance) ``` <br/> `Bank.deployed()` 는 `Contract` 의 인스턴스 평가하는 프로미스(`Promise`)를 반환합니다. `then` 을 이용하여 우리는 이를 `bank` 에 `bind` 합니다. `owner` 멤버 변수를 확인해봅시다: ```console truffle(development)> bank.owner() '0xdaf72fcee99c3ed561b5f91a83b69c6f3d6b02e8' ``` <br/> `Ganache` 의 첫 번째 계정과 `address` 가 동일합니다! 이제 은행에 `10 ETH` 만큼 입금을 해봅시다: ```console truffle(development)> bank.deposit({value: web3.toWei(10, 'ether')}) ``` <br/> `deposit` 은 `payable` 함수입니다. 때문에 저희는 `value` 를 매개 변수로 담을 수 있습니다. `value` 는 `ETH` 의 최소 단위인 `Wei` 를 가집니다. 따라서 `web3.toWei` 를 통해 `10 ETH` 를 `Wei` 로 변환해야합니다. 이제 `Ganache` 의 첫 번째 계정의 잔액(`balance`)을 확인합니다:  `89.94 ETH` 가 남았습니다. 왜 `90.00 ETH` 가 아닐까요? 이는 `Contract` 의 함수를 실행시키는 수수료(`Gas`) 때문입니다. `Gas` 에 대한 자세한 내용은 [여기](http://ethdocs.org/en/latest/contracts-and-transactions/account-types-gas-and-transactions.html)를 참고하세요. 이제 출금할 차례입니다: ```console truffle(development)> bank.withdraw() ``` <br/>  첫 번째 계정에 `10 ETH` 가 다시 들어왔습니다! ## 마치며 ## <br/> 축하합니다! 드디어 이더리움 은행 `dApp` 을 완성했습니다. 여기까지 따라오신 분들 모두 수고하셨습니다. 감사합니다.
author | dangen |
---|---|
permlink | dapp-2-with-truffle |
category | ethereum |
json_metadata | {"tags":["ethereum","blockchain","truffle","dapp","nodejs"],"image":["https://dangen-effy.github.io/assets/ethereum_truffle.png","https://dangen-effy.github.io/assets/ganache_preview.png","https://dangen-effy.github.io/assets/ganache_1st_account.png","https://dangen-effy.github.io/assets/ganache_2nd_account.png"],"links":["https://github.com/dangen-effy/ethereum-bank","http://solidity.readthedocs.io/en/v0.4.21/contracts.html#visibility-and-getters","https://ethereum.stackexchange.com/questions/38387/contract-address-transfer-method-gas-cost?rq=1&utm_medium=organic&utm_source=google_rich_qa&utm_campaign=google_rich_qa","http://ethdocs.org/en/latest/contracts-and-transactions/account-types-gas-and-transactions.html"],"app":"steemit/0.1","format":"markdown"} |
created | 2018-05-10 02:20:27 |
last_update | 2018-05-15 06:22:27 |
depth | 0 |
children | 3 |
last_payout | 2018-05-17 02:20:27 |
cashout_time | 1969-12-31 23:59:59 |
total_payout_value | 0.000 HBD |
curator_payout_value | 0.000 HBD |
pending_payout_value | 0.000 HBD |
promoted | 0.000 HBD |
body_length | 7,263 |
author_reputation | 14,971,045,596 |
root_title | "[dApp] 진짜 쉬운 이더리움 은행 만들기 2편 with Truffle" |
beneficiaries | [] |
max_accepted_payout | 1,000,000.000 HBD |
percent_hbd | 10,000 |
post_id | 54,864,929 |
net_rshares | 577,079,951 |
author_curate_reward | "" |
voter | weight | wgt% | rshares | pct | time |
---|---|---|---|---|---|
kilnamkim | 0 | 0 | 100% | ||
modolee | 0 | 0 | 100% | ||
dangen | 0 | 577,079,951 | 100% | ||
sclear | 0 | 0 | 100% |
좋은 글 감사합니다.
author | kilnamkim |
---|---|
permlink | re-dangen-dapp-2-with-truffle-20180617t072723055z |
category | ethereum |
json_metadata | {"tags":["ethereum"],"app":"steemit/0.1"} |
created | 2018-06-17 07:27:18 |
last_update | 2018-06-17 07:27:18 |
depth | 1 |
children | 0 |
last_payout | 2018-06-24 07:27:18 |
cashout_time | 1969-12-31 23:59:59 |
total_payout_value | 0.000 HBD |
curator_payout_value | 0.000 HBD |
pending_payout_value | 0.000 HBD |
promoted | 0.000 HBD |
body_length | 11 |
author_reputation | 0 |
root_title | "[dApp] 진짜 쉬운 이더리움 은행 만들기 2편 with Truffle" |
beneficiaries | [] |
max_accepted_payout | 1,000,000.000 HBD |
percent_hbd | 10,000 |
post_id | 61,064,109 |
net_rshares | 0 |
자세하고 쉬운 설명 감사합니다~ 잘 보았어요~
author | kovexcoin |
---|---|
permlink | re-dangen-dapp-2-with-truffle-20190227t065125278z |
category | ethereum |
json_metadata | {"tags":["ethereum"],"app":"steemit/0.1"} |
created | 2019-02-27 06:51:27 |
last_update | 2019-02-27 06:51:27 |
depth | 1 |
children | 0 |
last_payout | 2019-03-06 06:51:27 |
cashout_time | 1969-12-31 23:59:59 |
total_payout_value | 0.000 HBD |
curator_payout_value | 0.000 HBD |
pending_payout_value | 0.000 HBD |
promoted | 0.000 HBD |
body_length | 25 |
author_reputation | 0 |
root_title | "[dApp] 진짜 쉬운 이더리움 은행 만들기 2편 with Truffle" |
beneficiaries | [] |
max_accepted_payout | 1,000,000.000 HBD |
percent_hbd | 10,000 |
post_id | 80,476,790 |
net_rshares | 0 |
안녕하세요. 손당근님 저는 이제 막 dapp 개발 공부를 시작한 모도리라고 합니다. 최신 자료가 많이 없었는데, 이렇게 포스팅 해주셔서 감사합니다. 따라하면서 한 가지 궁금한 점이 있었는데요. msg.sender는 무조건 account[0]로 고정되어 있는건가요? 혹시나 해서 bank.deposit({from: account[1]의 주소, value: web3.toWei(10, 'ether')}) 이런식으로 실행을 해보려니 invalid address 에러나 나오네요. ganache를 이용해서 테스트해 볼때에는 컨트랙트 owner만 msg를 보낼 수 있는지 궁금합니다.
author | modolee |
---|---|
permlink | re-dangen-dapp-2-with-truffle-20180519t134819294z |
category | ethereum |
json_metadata | {"tags":["ethereum"],"app":"steemit/0.1"} |
created | 2018-05-19 13:48:24 |
last_update | 2018-05-19 13:48:24 |
depth | 1 |
children | 0 |
last_payout | 2018-05-26 13:48:24 |
cashout_time | 1969-12-31 23:59:59 |
total_payout_value | 0.000 HBD |
curator_payout_value | 0.000 HBD |
pending_payout_value | 0.000 HBD |
promoted | 0.000 HBD |
body_length | 321 |
author_reputation | 285,192,678,959 |
root_title | "[dApp] 진짜 쉬운 이더리움 은행 만들기 2편 with Truffle" |
beneficiaries | [] |
max_accepted_payout | 1,000,000.000 HBD |
percent_hbd | 10,000 |
post_id | 56,547,723 |
net_rshares | 540,439,954 |
author_curate_reward | "" |
voter | weight | wgt% | rshares | pct | time |
---|---|---|---|---|---|
dangen | 0 | 540,439,954 | 100% |