Truffle: Contract.call()が返すのはPromiseなのでハマった

# はじめに

Truffleを使い始めたばかりでコントラクトをつくってる最中にハマりましたのでメモ。

## 結論

`Contract.call()`が返すのは`<object Promise>`です。truffle console上では文字列が返ってきてるように見えてるけど、Promiseです。

```
truffle version
Truffle v4.0.4 (core: 4.0.4)
Solidity v0.4.18 (solc-js)
```

```
json_string = JSON.stringify({"greet": "Hello World!", "value": 999})
'{"greet":"Hello World!","value":999}'
contract = SimpleJsonStorage.at(SimpleJsonStorage.address)
contract.setJsonString.sendTransaction(json_string, {from: web3.eth.accounts[0]})

正しい
contract.json.call().then(v=>{ const json = JSON.parse(v); console.log(json.greet); })
Hello World!
undefined

間違い
v = contract.json.call()
'{"greet":"Hello World!","value":999}'
JSON.parse(v)
SyntaxError: Unexpected token o in JSON at position 1
    at JSON.parse (<anonymous>)
    at evalmachine.<anonymous>:1:6
    at ContextifyScript.Script.runInContext (vm.js:53:29)
    at Object.runInContext (vm.js:108:6)
    at Console.interpret (/Users/user/.nodebrew/node/v8.0.0/lib/node_modules/truffle/build/cli.bundled.js:202629:17)
    at ReplManager.interpret (/Users/user/.nodebrew/node/v8.0.0/lib/node_modules/truffle/build/cli.bundled.js:203345:18)
    at bound (domain.js:301:14)
    at REPLServer.runBound [as eval] (domain.js:314:12)
    at REPLServer.onLine (repl.js:433:10)
    at emitOne (events.js:115:13)
```

# はまった顛末

[Introduction to Smart Contracts A Simple Smart Contract](http://solidity.readthedocs.io/en/develop/introduction-to-smart-contracts.html#a-simple-smart-contract) を参考に以下のようなコントラクトを作ってみた。

```SimpleJsonStorage.sol
pragma solidity ^0.4.18;

contract SimpleJsonStorage {
  string public json;

  function sendJsonString(string _json) {
    bytes memory temp = bytes(_json);
    require(temp.length > 0);
    json = _json;
  }

}
```

コンパイルしてデプロイして、

```
json_string = JSON.stringify({"greet": "Hello World!", "value": 999})
contract = SimpleJsonStorage.at(SimpleJsonStorage.address)
contract.sendJsonString.sendTransaction(json_string, {from: web3.eth.accounts[0]})
'0x4923c16608454e4bc58c87d26cb9646e1ec9dd7dff561cf9a256ebdfd17c0388'

v = contract.json.call()
'{"greet":"Hello World!","value":999}'
JSON.parse(v)
SyntaxError: Unexpected token o in JSON at position 1
    at JSON.parse (<anonymous>)
    at evalmachine.<anonymous>:1:6
    at ContextifyScript.Script.runInContext (vm.js:53:29)
    at Object.runInContext (vm.js:108:6)
    at Console.interpret (/Users/user/.nodebrew/node/v8.0.0/lib/node_modules/truffle/build/cli.bundled.js:202629:17)
    at ReplManager.interpret (/Users/user/.nodebrew/node/v8.0.0/lib/node_modules/truffle/build/cli.bundled.js:203345:18)
    at bound (domain.js:301:14)
    at REPLServer.runBound [as eval] (domain.js:314:12)
    at REPLServer.onLine (repl.js:433:10)
    at emitOne (events.js:115:13)
```

...え？ってなった。

# 調べたこと

そもそも

```
v = contract.json.call()
'{"greet":"Hello World!","value":999}'
```

って感じであたかも文字列が返ってきてるかのようにtruffle consoleが出すので紛らわしい。
資料あさってもそれっぽいのヒットしないし、以下のようにして突き止めた。

```
typeof v
'object'
```

ん？ object？ Stringじゃねえの？
なんのObjectかわからない場合は、`toString()`でなんかわかることもある。

```
v.toString()
'[object Promise]'
```

Promiseかよ！

```
contract.json.call().then(v=>{ const json = JSON.parse(v); console.log(json.greet); })
Hello World!
undefined
```

できたよ。。

# まとめ

詳しく見てないんだけど、たぶんTruffleは[web3js](https://github.com/ethereum/web3.js/)をラップしてるんじゃないかと思うので[このあたり](https://web3js.readthedocs.io/en/1.0/web3-eth-contract.html#contract-call)がヒントになったのかもしれない。あとで考えてみれば。

コンソールは親切にコールバックの結果を表示してくれるんだろう。親切なんだけど覚えておかないとまたハマりそうｗ