概要
Symbolブロックチェーンのネームスペース宛にXYMを送金する処理
SDKのドキュメント等を見ても少し分かりづらかったので備忘も兼ねてメモ
環境・前提条件
Python 3.7.3
symbol-sdk-python 3.0.3
経緯など
ラズパイ+Bluetoothボタンを組み合わせて、ボタンを押すとトランザクションを飛ばす仕組みを過去に構築。
それらのプログラムを拡張する中で、ネームスペース宛にも送信したくなったのでトライしたものです。
サンプルコード
方法1:Namespace -> NamespaceIDの形に変換して宛先にセット
from symbolchain.symbol.IdGenerator import generate_namespace_id
# Symbol-sdkの中にあるNamespaceIdへの変換処理を呼び出し
def get_namespaceid(self, namespace):
return generate_namespace_id(namespace)
# ネームスペースからNamespaceID(24byte)への変換
def aliasToRecipient(namespaceId: np.ndarray, networkType: int) -> np.ndarray:
# 0x91 | namespaceId on 8 bytes | 15 bytes 0-pad = 24 bytes
padded = np.zeros(24, dtype=np.uint8)
padded[0] = networkType | 0x01
padded[1:9] = namespaceId[::-1]
padded[9:24] = np.tile(np.array([0x00], dtype=np.uint8), 15)
return padded
# ネームスペース名からNamespaceIdのバイト列を生成する処理の例
def namespace_to_idbytes(namespace, network_type):
# namespaceをバイト配列に変換
byte_array = get_namespaceid(namespace).to_bytes(8, 'big')
narray = np.frombuffer(byte_array, dtype=np.uint8)
# namespaceIdの形に変換
# (networkType | 0x01) | namespaceId on 8 bytes | 15 bytes 0-pad = 24 bytes
# network_type = メインネットは104 テストネットは152
namespaceid = aliasToRecipient(narray, network_type)
return namespaceid.tobytes()
namespace='kuri_dev_test'
network_type=152
namespaceid = namespace_to_idbytes(namespace, network_type)
print(namespaceid)
# 出力例
"""
b'\x99\xcdF1sN1\xed\x95\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
"""
上記の方法で算出したバイト列を、トランザクションの送信先アドレスに直接指定することでXYMを送ることができます。
namespaceid = namespace_to_idbytes(namespace, network_type)
# b'\x99\xcdF1sN1\xed\x95\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
# トランザクションの宛先セットの例
tx = SymbolFacade.transaction_factory.create({
'type': 'transfer_transaction',
'signer_public_key': pubkey,
'fee': fee,
'deadline': deadline,
'recipient_address': namespaceid, #ここにバイト列を直接指定
'mosaics': mosaics,
'message': msg_txt
})
方法2:NamespaceIDからアドレスの形に変換する方法(ノードに問い合わせ)
ネームスペース情報をノードに問い合わせることで、ネームスペースが紐づくアドレス情報を取得する方法もあります。
実際に使う際は、対象ネームスペースがモザイクではなくアドレスに紐づいているか?そのアドレスの受信制限などはかかっていないか?などの送付前チェックが必要になるケースが多いので、こちらの方法が使いやすいかもしれません。
from symbolchain.symbol.IdGenerator import generate_namespace_id
# ネームスペースをNamespaceIdの形に変換
namespace = 'kuri_dev_test'
namespaceid = hex(generate_namespace_id(namespace))[2:]
print(namespaceid) # 95ed314e733146cd
# ノードに対象ネームスペース情報を問い合わせ
def send_namespace_req(node_url, namespaceid):
headers = {'Content-type': 'application/json'}
conn = http.client.HTTPConnection(node_url,3000)
conn.request("GET", f"/namespaces/{namespaceid}")
response = conn.getresponse()
data = response.read()
return data.decode()
namespace_info = json.loads(send_namespace_req(namespaceid))
print(namespace_info)
{'meta': {'index': 0, 'active': True}, 'namespace': {'version': 1, 'registrationType': 0, 'depth': 1, 'level0': '95ED314E733146CD', 'alias': {'type': 2, 'address': '986E56E8D544EEF241F15B9371CB3117CDBB87AFF064D739'}, 'parentId': '0000000000000000', 'ownerAddress': '986E56E8D544EEF241F15B9371CB3117CDBB87AFF064D739', 'startHeight': '244746', 'endHeight': '654102'}, 'id': '63F7188E92758138390A3013'}
ネームスペースの情報が取得出来たら、aliasの判定や紐づくアドレス情報の取得を行います。
# ネームスペースは有効か?
if namespace_info['meta']['active'] == False:
print('無効なネームスペース')
return
# ネームスペースのaliasはアドレスに紐づいているか?
alias = namespace_info['namespace']['alias']
address = ''
if alias['type'] == 2: # アドレスに紐づくネームスペース
# アドレス形式を変換(Hex to base32)
raw_address = alias['address']
address = base64.b32encode(binascii.unhexlify(raw_address)).decode('utf-8')[:-1]
ネームスペースがアドレスに紐づいている場合、紐づくアドレスが16進数形式になっているので、扱いやすいようにbase32エンコード形式に変換します。これで、ネームスペースが紐づく宛先のアドレスを取得することができます。
Special Thanks
親身に相談に乗ってくださった @nem_takanobu さん、@Toshi_ma さんに感謝します。
Symbolブロックチェーンの開発者コミュニティは国内外問わず皆さん非常に技術力が高く、そして親身にアドバイスをくれる人が多くて本当に素晴らしいと思います。
コード全文
記事内のサンプルコードは要点を抜粋したものなので、そのままでは動かない場合もあります。
コード全文は以下のリポジトリにあります。
https://github.com/kurikou02/XymSendButton