Pythonで複数アドレスにSymbol(xym)を一斉送金

こんにちは、keiと申します。Pythonを利用して仮想通貨Symbolを一括送金する方法をみーちさんが紹介してくれています。

https://nemlog.nem.social/blog/62080

みーちさんのコード、とても便利ですがそれぞれのアドレスに別々の金額を設定できなくて使いたくても使えない方がいるかもしれません。そこで、ヘボプログラマーの私ですが、最終的にはグーグルスプレッドシートからデータを読み込んで、各アドレスに送金出来るようにしてみたいと思います。

まずはみーちさんコードを確実に動かしましょう

上記リンクのみーちさんのコードが動いているのが大前提です。もしも、そこにたどり着けていない方は、先ずはみーちさんのコードを動かすまでやることが重要です。早くやりたい気持ちはあるかもしれませんが、一つ一つやる方が問題があった時に切り分けが出来て解決し易いと思います。

私がつまづいた所

みーちさんのページで私がつまづいた所が幾つかありましたので、紹介しておきます。記録していないで、記憶を頼りに書くので正確じゃなくてスミマセン。

・Pythonのバージョン
⇒私の環境が未だにWindows7 32bitを利用している為、最新のPythonがインストール出来ませんでした。Pythonのサイトの中のWindowsのダウンロードページを見てみるとそれぞれのバージョンに「Note that Python 3.9.5 cannot be used on Windows 7 or earlier.」等と書かれています。
そこで、私はWindow 7が対応しているギリギリの「Python 3.8.8 - Feb. 19, 2021」を利用しました。

・pipの実行方法
⇒何とかPython自体はインストール出来ましたが、次につまづいたのはpip installでした。まず、そもそもどうやって実行するのか分からない。初めはコマンドプロンプトでPythonを実行してから、やるのかと思っていましたが、何度やってもエラーが出てしまう。調べてみたらPython実行せずに、直接pipを実行して良いことが分かりました。
しかし、それでも上手く行かない、、、。結局、管理者権限が必要だと言う事が分かりました。そこで、コマンドプロンプトを右クリックして「管理者として実行」で無事にpipが実行されるようになりました。

・pipのバージョン
⇒次につまづいたのがpipのバージョンでした。pipにてSymbol-sdkをインストールしようとしたところ、「バージョンが古いのでアップグレードしなさい」みたいなアラートが出て来ました。そこで「pip install --upgrade pip」を実行したところ、ここでも最後にエラーのアラートが出ました。「何かが足りません」みたいな警告だったと思いますが、結局大丈夫だったようでエラーが出てもアップグレードは出来ていたようでした。

・Microsoft C++ Build Toolsのインストール
⇒みーちさんの記事にもありますが、Microsoft C++ Build Toolsのエラーが出ました。これがなかなか苦労しました。
私の場合は以前からVisualStudio2019が入っていたのですが、その場合にMicrosoft C++ Build Toolsをどうやって追加すれば良いのか?よく分かりませんでした。

色々と調べてみて、最終的にこちらのページの中にあった、「MSVC v142 - VS 2019 C++ x64/x86ビルドツール」「Windows 10 SDK(最新のもの)」「Windows 用 C++ CMakeツール」を追加し、これでやっとpipが動きSymbol-sdkをインストールすることが出来ました。

いよいよ本題

いよいよ本題なのですが、何度も書きますが必ずみーちさんのスクリプトが動くのを確認してください。そうすればエラーが発生した時に、どこが問題なのか見つけやすくなると思います。
みーちさんのを元にして、私が直したコードは以下の通りとなります。

import sha3
import datetime
import json
import http.client
from binascii import unhexlify
from binascii import hexlify
from symbolchain.core.CryptoTypes import PrivateKey
from symbolchain.core.sym.KeyPair import KeyPair
from symbolchain.core.facade.SymFacade import SymFacade
from symbolchain.core.sym.MerkleHashBuilder import MerkleHashBuilder
from symbolchain.core.CryptoTypes import Hash256


### 設定 #############################################################################

# テストネット=0 メインネット=1
current_net = 1


# 送信元ウォレットの秘密鍵
private_key = "~~~64桁の秘密鍵~~~"


# トランザクション送信に使う手数料
fee_size    = 0.1


# メインネットのノードアドレス(折角なので自分のノードがある方はそのアドレスをどうぞ)
my_node_adr = "ngl-dual-001.symbolblockchain.io"


# 宛先リスト[アドレス,送金したいxym数,送信メッセージ] ※最後の行のみカンマ[,]なし
addressList = [
   ["送信先アドレス1",送金額1,"コメント1"],
   ["送信先アドレス2",送金額2,"コメント2"]
   ]
#####################################################################################

# 接続するネットワークの設定
if current_net == 0:
	facade = SymFacade('public_test')
	start_time = 1616694977
	mosaics_id = 0x091F837E059AE13C
	node_adr = "sym-test-01.opening-line.jp"

elif current_net == 1:
	facade = SymFacade('public')
	start_time = 1615853185
	mosaics_id = 0x6BED913FA20223F8
	node_adr = my_node_adr


# 送信元の設定
alicePrikey     = PrivateKey(unhexlify(private_key))
aliceKeypair    = KeyPair(alicePrikey)
alicePubkey     = aliceKeypair.public_key
aliceAddress    = facade.network.public_key_to_address(alicePubkey)
print("send from :", aliceAddress)

# 受信先の設定
addressTx = []
for address in addressList:
   msg = address[2]
   tx  = facade.transaction_factory.create_embedded({
       'type': 'transfer',
       'signer_public_key': alicePubkey,
       'recipient_address' : SymFacade.Address(address[0].replace('-','')),
       'mosaics': [(mosaics_id, int(address[1] * 1000000))],
       'message': bytes(1) + msg.encode('utf8')
   })
   addressTx.append(tx)
   print(address[0],address[1],address[2])


# マークルハッシュの作成
hash_builder = MerkleHashBuilder()
for tx in addressTx:
   hash_builder.update(Hash256(sha3.sha3_256(tx.serialize()).digest()))
merkle_hash = hash_builder.final()

# アグリゲートトランザクションの作成
deadline = (int((datetime.datetime.today() + datetime.timedelta(hours=2)).timestamp()) - start_time) * 1000
aggregate = facade.transaction_factory.create({
   'type': 'aggregateComplete',
   'signer_public_key': alicePubkey,
   'fee': int(fee_size * 1000000),
   'deadline': deadline,
   'transactions_hash': merkle_hash,
   'transactions': addressTx
})
signature = facade.sign_transaction(aliceKeypair, aggregate)
aggregate.signature = signature.bytes

# ネットワークへアナウンス
payload = {"payload": hexlify(aggregate.serialize()).decode('utf8').upper()}
jsonPayload = json.dumps(payload)
headers = {'Content-type': 'application/json'}
conn = http.client.HTTPConnection(node_adr, 3000)
conn.request("PUT", "/transactions", jsonPayload, headers)
response = conn.getresponse()
print(response.status, response.reason)

# 確認
hash = facade.hash_transaction(aggregate)
print('http://' + node_adr + ':3000/transactionStatus/' + str(hash))

みーちさんのものからの変更点

変更点は以下の通りです。
・テストネットとメインネットを切替えられるようにした
・メインネットの場合はアドレスを指定するようにした。このスクリプトを使う方はノード管理者の方が多いと思いますので、是非ご自分のノードに接続してください。
・送信するアドレス、送金額、メッセージを個別に設定できるようにした。

大まかには、上記の通りとなります。特にそれぞれのアドレスに違う金額を送金したい場合があると思いますので、ご利用ください。

設定方法

・テストネット or メインネットを決めるには以下の部分を設定してください。0の場合がテストネット、1の場合がメインネットです。

# テストネット=0 メインネット=1
current_net = 1

・メインネットの場合、下記の部分でノードのアドレスを入力してください。とりあえずはnglのアドレスが入っていますが、混んでいる場合もあるようなので、分散という意味でも変更しておいた方が良いと思います。

# メインネットのノードアドレス(折角なので自分のノードがある方はそのアドレスをどうぞ)
my_node_adr = "ngl-dual-001.symbolblockchain.io"

・送信内容の設定。次にメインの送信先アドレス等の設定です。下記の部分を編集してください。みーちさんの記事にもあった通り、最後の行はカンマ「 , 」が付きませんので、ご注意ください。

# 宛先リスト[アドレス,送金したいxym数,送信メッセージ] ※最後の行のみカンマ[,]なし
addressList = [
   ["送信先アドレス1",送金額1,"コメント1"],
   ["送信先アドレス2",送金額2,"コメント2"]
   ]

設定例

# 宛先リスト[アドレス,送金したいxym数,送信メッセージ] ※最後の行のみカンマ[,]なし
addressList = [
   ["NLF~~~送信先アドレス1~~~P9N",10000,"1万xymおめでとうございます"],
   ["NLK~~~送信先アドレス2~~~5QQ",20,"いつもお世話になっているので20xymお送りします"],
   ["NCM~~~送信先アドレスN~~~GJA",0.039,"いつもありがとうございます。"]
   ]

上記の通り、送金額にはダブルクォーテーション「 " 」を付けずに、そのまま入力してください。なお、メッセージの長さは確認取れていないので、現状は短めにお願いします。改行は出来ません。
また、送信先アドレスにハイフン「 - 」はあっても無くても大丈夫だと思います。

とりあえず、ここまでやっておくと次に繋げやすい

最終的にはグーグルスプレッドシートやエクセルからのデータを元に送信出来るようにするのが目標です。
しかし、とりあえずはここまでをキッチリ動かせることが大切だと思いますので、今回はこの辺にしておきます。

Special Thanks

この記事を書くに当って、みーちさんXEMBookさんの記事を参考にさせていただきました。お二人の記事が無ければ全く分かりませんでした。ありがとうございました。

https://nemlog.nem.social/blog/62080

https://qiita.com/nem_takanobu/items/f3c02caa17ad385b6155

https://qiita.com/nem_takanobu/items/d148dee444a74737769b

次回は、頑張ってグーグルスプレッドシートの内容を元に、送信を出来るようにする予定です。最後までお読みいただきましてありがとうございました。

この記事が気に入ったらサポートをしてみませんか?