ZCash プールマイニングで得られた報酬履歴を zchain でスキャンし課税計算に使う(進捗 95%)

漢なら ZCash プールマイニングで得られた報酬の統計処理し, 確定申告用の税計算に活用したいですね!

やりましょう!

## 前提条件

* なんからのプールマイニングをしており, 自動払い出しを有効にしていて, ブロックチェーンに記録が残っているとする. (払い出し可能であるのに払い出していないプール内の残高は考慮しない)
* 使っている zcash アドレスはひとつとする
* マイニングで得られたコインはガチホし, 売っていないとする

## 各払い出しトランザクションの取得額と取得時間を得る

ZChain API を使います.

https://explorer.zcha.in/api

一度に取得できるトランザクション数は 20 個までになります(`limit` パラメータ)

したがって, 全部欲しい場合は `offset` を変えて GET で叩いて全体を取得することになります.

総トランザクション数(受け取り回数)は `https://api.zcha.in/v2/mainnet/accounts/YOUR_ADDRESS` の `recvCounts` でわかります.

offset を変えて取得するスクリプトを作りました. 20 個ごとに連番で JSON でファイルに保存します. python requests を pip あたりでインストールしてください.

```
#!/usr/bin/env python
# 
import json
import os
import sys
import datetime
import time

import requests

# Set your ZCash address.
MY_ADDR = 'XXXXXX'
max_items = 20 # zchain API limits 20 items for each API call.

def main():
    r = requests.get("https://api.zcha.in/v2/mainnet/accounts/" + MY_ADDR)
    j = r.json()
    recvCount = int(j["recvCount"])
    print(recvCount)

    n = int(recvCount / max_items) + 1
    for i in range(n):
        offset = i * max_items
        if offset >= recvCount:
            continue

        limit = max_items 

        print("requesting from {0} to {1} ...".format(offset, offset + limit))
        payload = {'limit': limit, 'offset': offset}
        rcv = requests.get("https://api.zcha.in/v2/mainnet/accounts/" + MY_ADDR + "/recv", params = payload )
        filename = "%03d.json" % i
        with open(filename, 'w') as f:
            f.write(rcv.text)

        # Wait for a while to avoid API calling limit
        time.sleep(5)

main()
```

JSON のレイアウトは以下のようになります.

<img width="757" alt="Screen Shot 2018-01-28 at 19.38.52.png" src="https://qiita-image-store.s3.amazonaws.com/0/36275/c317f172-d147-c788-3987-045e4f495d3d.png">

timestamp はブロック全体のところに, 受け取り(送信先)アドレスは `vout[].scriptPubKey.addresses[]` に, その額は `vout.value` にあることがわかります.

上記を踏まえて python で集計するスクリプトを書きます.

```
import json
import os
import sys
import datetime

# Set your ZCash address.
MY_ADDR = 'XXXXXXXXXX'

def findReceivedAmount(b, addr):
    amount = 0

    for vout in b['vout']:
        if MY_ADDR in vout['scriptPubKey']['addresses']:
            amount += vout['value']

    return amount

def main():
    if len(sys.argv) < 3:
        print("Requires basename count")
        sys.exit(-1)

    print("timestamp, date, amount")

    i = int(sys.argv[1])
    n = int(sys.argv[2])

    while i < n:
        filename = "%03d.json" % i
        i = i + 1

        j = json.loads(open(filename).read())
        # for each block
        for b in j:
            timestamp = b['timestamp']
            # print(b['timestamp'])

            # find received amount for my account
            amount = findReceivedAmount(b, MY_ADDR)
            textualdate = datetime.datetime.fromtimestamp(timestamp)
            print("{0}, {1}, {2}".format(timestamp, textualdate, amount))  
```

000.json, 001.json, ... とファイルを連番で読んでいき, 以下のように取引履歴を出力します.

```
timestamp, date, amount
1516959786, 2018-01-26 18:43:06, 0.0102
1516889217, 2018-01-25 23:06:57, 0.0107
1516805807, 2018-01-24 23:56:47, 0.0105
1516740818, 2018-01-24 05:53:38, 0.011
1516658566, 2018-01-23 07:02:46, 0.0105
...
```

あとはこれで timestamp 時の ZEC/JPY 価格, もしくはなんらかの一貫した価格決め(各日の open 価格など)で取得価格を計算すれば完了です!

## TODO

* unixtime で古い日付からの順番にソートする.
* 送金時点で時価を計算しほうがよいか, 着金時点で計算したほうがよいか.
* ウォレットのヒストリあたりと照合して齟齬がないか検証する
* timestamp の ZEC/JPY 価格で取得価格を計算する.
* 手数料を考慮する?