Web3.jsを使ってJavaScriptからEthereumのスマートコントラクトを制御する

#はじめに

以前CounterPartyを使って、独自コインを発行してみましたが、今回はEthereumを使った方法で独自コインを発行して、JavaScriptから制御する方法の覚書です。

##先ずはプライベートネットの構築

http://qiita.com/oggata/items/eea4d5e37f38785f6079
を参考にGethで環境を作成して起動しておく。

```
geth --mine --unlock 0,1 --ipcpath="/tmp/geth.ipc" --minerthreads 2 --identity "sampleNode" --rpc --rpcport 8545 --rpcapi "web3,eth,net,personal" --rpccorsdomain "*" --rpcaddr "0.0.0.0" --datadir "/Users/hoge/eth_private" --nodiscover --networkid 10 console 2>> /Users/hoge/eth_private/geth.log
```

##スマートコントラクトの用意
https://www.ethereum.org/token
を参考にするとトークンの作成方法が紹介されています。
今回は説明のために、もっとも基本的なexampleである
「MINIMUM VIABLE TOKEN」
を使ってみます。

<img width="944" alt="スクリーンショット 2017-08-14 13.20.16.png" src="https://qiita-image-store.s3.amazonaws.com/0/43766/8e467515-4710-f17c-f9f5-f3f25111f17d.png">

上記のようにコードを貼り付けて1000コインをcreateしてみます。
その後、transferを押下して作成したアドレスを見ると残高1000になっています。

##node環境の構築とセットアップ

```
npm install web3@^0.20.0
```

##サンプルスクリプトを用意する

http://web3js.readthedocs.io/en/1.0/index.html

```js:create_account.js
var Web3 = require('web3');
var web3 = new Web3();
web3.setProvider(new web3.providers.HttpProvider('http://localhost:8545'));
var _account = web3.personal.newAccount("test");
console.log(_account)
```

```js:balance.js
#!/usr/bin/env node

var Web3 = require('web3');
var web3 = new Web3();
web3.setProvider(new web3.providers.HttpProvider('http://localhost:8545'));
web3.eth.defaultAccount=web3.eth.accounts[0]

//Contract details (bytecode, interface etc.)のInterfaceをabiとして貼り付ける
var abi = [{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"balanceOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transfer","outputs":[],"payable":false,"type":"function"},{"inputs":[{"name":"initialSupply","type":"uint256"}],"payable":false,"type":"constructor"}];

var _balance = web3.eth.contract(abi).at("コントラクトのaddress").balanceOf("残高をみるアドレス");
console.log(_balance);
```

```js:transfer.js
#!/usr/bin/env node
var Web3 = require('web3');
var web3 = new Web3();
web3.setProvider(new web3.providers.HttpProvider('http://localhost:8545'));
web3.eth.defaultAccount=web3.eth.accounts[0]

var abi = [{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"balanceOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transfer","outputs":[],"payable":false,"type":"function"},{"inputs":[{"name":"initialSupply","type":"uint256"}],"payable":false,"type":"constructor"}];

var _transfer = web3.eth.contract(abi).at("コントラクトのaddress").transfer.sendTransaction("送信先のアドレス",10);
console.log(_transfer);
```


#コインを送ってみる

##1.残高
```
node balance.js
{ [String: '1000'] s: 1, e: 3, c: [ 1000 ] }
```

##2.送る
```
node transfer.js
```

##3.pendingTransactionsをみて処理されるのを待つ
```
> eth.pendingTransactions
[{
    blockHash: null,
    blockNumber: null,
    from: "0xe176db0944a2119eed8a74f667e4298e1325987f",
    gas: 90000,
    gasPrice: 20000000000,
    hash: "0xd38936a7927a811a0c2c51d538da8af498f57af36d95077914c6b07587dda289",
    input: "0xa9059cbb0000000000000000000000009c7e20e44bec6085165c27183605245f22c00f23000000000000000000000000000000000000000000000000000000000000000a",
    nonce: 64,
    r: "0x881600ba0fac1885c081f0311f45b0e0abcbc16d377bbe9eefa6a138f8b1f0ab",
    s: "0x541c7d8ce387d8c23e2145d7eb22f3e98d76435e3f4c371bd1a5ad5bb3e797c9",
    to: "0x231cc3c04af5c5b64fb34ecb322e264981ec6af7",
    transactionIndex: null,
    v: "0x1b",
    value: 0
```

##4.完了後
コインが移動している

```
node balance.js
{ [String: '990'] s: 1, e: 2, c: [ 990 ] }
```


#コインの売買など、機能を足したい場合はこちらを参考

https://www.ethereum.org/token
(AUTOMATIC SELLING AND BUYINGなど)

#Promise.allで非同期な値をまとめて取得



```
const abi = require('./abi.json');
const config = require('./config.json');
const Web3 = require('web3');
const web3 = new Web3(new Web3.providers.HttpProvider(config.httpProvider));

const tokenInfo = (contractAddress)=>{
    const contract = new web3.eth.Contract(abi,contractAddress);

    let workers = [
        contract.methods.name().call(),
        contract.methods.symbol().call(),
        contract.methods.totalSupply().call(),
        contract.methods.decimals().call()
    ];
    return Promise.all(workers).then(res=>{
        let decimals = res[3];
        let divisor = Math.pow(10,decimals);
        let totalSupply = res[2];
        totalSupply = Number(totalSupply)/divisor;
        return Promise.resolve({
            'name':res[0],
            'symbol':res[1],
            'totalSupply':totalSupply,
            'decimals':decimals,
        })
    }).catch(err=>{
        return Promise.reject(err);
    });
}
```

#参考
web3js
https://github.com/ethereum/wiki/wiki/JavaScript-API
https://github.com/ethereum/web3.js/

web3-ethの使い方
http://web3js.readthedocs.io/en/1.0/web3-eth.html