symbol-sdk-pythonと使用してsymbolブロックチェーン上でトークン（モザイク）を発行し、名前を付ける。(23年2月)

## 1. 概要
symbolブロックチェーンには誰でもモザイクという独自のトークン(以下モザイクと表記）を発行できる機能がある。通常はウォレットから作成可能だが、今回はPythonでその機能を再現する。新しく発行したモザイク供給量は作成者が設定できる。さらにネームスペースという機能を使って名前を付けることが出来る。方法は4種類のトランザクションをノードにアナウンスして作成する。今回はそれについて試してみる。
※デスクトップウォレットを使用します。まだダウンロードしていない方は[こちらから](https://github.com/symbol/desktop-wallet/releases)。

## 2. 環境・前提条件

windows10
Python 3.10.9
symbol-sdk-python v3.0.3
symbol-desktop-wallet 1.0.13

## 3.新しいモザイクを作成する

ナンスは時間を使って生成。pythonのflag管理を使用します。
duration()に何も入れないとモザイクの期間を無限にできます。
今回はduration(50)とし約25分間存在するモザイクを作成します。
以下の4種類のプロパティを設定します。

転送可否：transferable  = True
供給量変更：supply_mutable = False
制限設定：restrictable = False
回収可能：revokable = False

以下、Definition_mosaic_testnet.py
```
from binascii import unhexlify
from symbolchain.CryptoTypes import PrivateKey
from symbolchain.symbol.KeyPair import KeyPair
from symbolchain.facade.SymbolFacade import SymbolFacade
from symbolchain.sc import BlockDuration, MosaicNonce, MosaicFlags
import http.client
import datetime
import requests
import json
import time

#Mosaicの作成に必要な項目を入力
node = "sym-test-04.opening-line.jp"
private_key = "Yourtestnet privatekey"
fee = 0.1
mosaic_nonce = int(time.mktime(datetime.datetime.now().timetuple()))

#ノードからプロパティを取得
def get_node_properties():
        """
        network type, epock ajustment, currency mosaic id, generation hashを取得する
        """
        node_url = "https://" + node+ ":3001"
        node_url_properties = node_url + "/network/properties"
        response = requests.get(node_url_properties)
        if response.status_code != 200:
            raise Exception("status code is {}".format(response.status_code))
        contents = json.loads(response.text)
        network = str(contents["network"]["identifier"].replace("'", ""))
        epoch_adjustment = int(contents["network"]["epochAdjustment"].replace("s", ""))
        currency_mosaic_id = int(contents["chain"]["currencyMosaicId"].replace("'", ""), 16)
        generation_hash_seed = str(contents["network"]["generationHashSeed"].replace("'", ""))
        return network, epoch_adjustment,currency_mosaic_id, generation_hash_seed, node_url

#nodeをmainnetノードに変えればにプロパティも変わる
NETWORK_TYPE = get_node_properties()[0]
EPOCH_ADJUSTMENT = get_node_properties()[1]
MOSAICID = get_node_properties()[2]
NODE_URL = get_node_properties()[4]


#GENARATION_HASHは送金に利用しないが、確認用。
GENERATOIN_HASH = get_node_properties()[3]

#各プロパティ確認用
print("Network type => " + str(NETWORK_TYPE))
print("Epoch ajustment => " + str(EPOCH_ADJUSTMENT))
print("Mosaic ID => " + str(hex(MOSAICID)).upper())
print("Generation hash => " + str(GENERATOIN_HASH))
print("Using node url => " + str(NODE_URL))

#秘密鍵から公開鍵を導出
unhex_privatekey = unhexlify(private_key)
privatekey = PrivateKey(unhex_privatekey)
keypair = KeyPair(privatekey)
publickey = keypair.public_key
#print(str(publickey))

#testnet or mainnet
facade = SymbolFacade(NETWORK_TYPE)

#アドレスを導出
address = facade.network.public_key_to_address(publickey)
print("Your address => " + str(address))

deadline = (int((datetime.datetime.today() + datetime.timedelta(hours=2)).timestamp()) - EPOCH_ADJUSTMENT) * 1000

#Mosaicのプロパティを設定
transferable  = True
supply_mutable = False
restrictable = False
revokable = False

#プロパティをflagsで管理する。
flags = MosaicFlags.NONE
flags = flags | MosaicFlags.TRANSFERABLE if transferable else flags
flags = flags | MosaicFlags.SUPPLY_MUTABLE if supply_mutable else flags
flags = flags | MosaicFlags.RESTRICTABLE if restrictable else flags
flags = flags | MosaicFlags.REVOKABLE if revokable else flags


#Mosaic定義用のトランザクションを生成
#duration()内にブロック数を入れないとunlimited durationになる。
#divisibilityは例えば3にすると0.001が最小単位

mosaic_definition_tx = facade.transaction_factory.create({
    'type': 'mosaic_definition_transaction',
    'signer_public_key': publickey,
    'fee': int(fee * 1000000),
    'deadline': deadline,
    'duration': BlockDuration(50),
    'nonce': MosaicNonce(mosaic_nonce),
    'flags': flags,
    'divisibility': 0
})

#署名＆ペイロード生成(v3.0.3から書き方変更)
signature = facade.sign_transaction(keypair, mosaic_definition_tx)
json_payload = facade.transaction_factory.attach_signature(mosaic_definition_tx, signature)

#ネットワークへアナウンス
headers = {'Content-type': 'application/json'}
conn = http.client.HTTPConnection(node, 3000)
conn.request("PUT", "/transactions", json_payload, headers)
responce = conn.getresponse()
print(responce.status, responce.reason)

#確認
hash = facade.hash_transaction(mosaic_definition_tx)
print(get_node_properties()[4] + "/transactionStatus/" + str(hash))
```
新しいモザイクが作成されました。
![スクリーンショット (218).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1794143/032c740a-a74b-904b-1da3-76edd04a50cd.png)

## 4.作成したモザイクの供給量を設定する
新しく作成したモザイク供給量の供給量を変更します。
mosaic_idはウォレット上で確認します。
以下、Mosaic_supply_change_testnet.py

```
from binascii import unhexlify
from symbolchain.CryptoTypes import PrivateKey
from symbolchain.symbol.KeyPair import KeyPair
from symbolchain.facade.SymbolFacade import SymbolFacade
from symbolchain.sc import Amount, MosaicSupplyChangeAction
import http.client
import datetime
import requests
import json

#XYM送信に必要な項目を入力
node = "sym-test-04.opening-line.jp"
private_key = "Your testnet privatekey"
fee = 0.1

#ノードからプロパティを取得
def get_node_properties():
        """
        network type, epock ajustment, currency mosaic id, generation hashを取得する
        """
        node_url = "https://" + node+ ":3001"
        node_url_properties = node_url + "/network/properties"
        response = requests.get(node_url_properties)
        if response.status_code != 200:
            raise Exception("status code is {}".format(response.status_code))
        contents = json.loads(response.text)
        network = str(contents["network"]["identifier"].replace("'", ""))
        epoch_adjustment = int(contents["network"]["epochAdjustment"].replace("s", ""))
        currency_mosaic_id = int(contents["chain"]["currencyMosaicId"].replace("'", ""), 16)
        generation_hash_seed = str(contents["network"]["generationHashSeed"].replace("'", ""))
        return network, epoch_adjustment,currency_mosaic_id, generation_hash_seed, node_url

#nodeをmainnetノードに変えればにプロパティも変わる
NETWORK_TYPE = get_node_properties()[0]
EPOCH_ADJUSTMENT = get_node_properties()[1]
#MOSAICID = get_node_properties()[2]
NODE_URL = get_node_properties()[4]


#GENARATION_HASHは送金に利用しないが、確認用。
GENERATOIN_HASH = get_node_properties()[3]

#各プロパティ確認用
print("Network type => " + str(NETWORK_TYPE))
print("Epoch ajustment => " + str(EPOCH_ADJUSTMENT))
#print("Mosaic ID => " + str(hex(mosaic_id)).upper())
print("Generation hash => " + str(GENERATOIN_HASH))
print("Using node url => " + str(NODE_URL))

#秘密鍵から公開鍵を導出
unhex_privatekey = unhexlify(private_key)
privatekey = PrivateKey(unhex_privatekey)
keypair = KeyPair(privatekey)
publickey = keypair.public_key
#print(str(publickey))

#testnet or mainnet
facade = SymbolFacade(NETWORK_TYPE)

#アドレスを導出
address = facade.network.public_key_to_address(publickey)
print("Your address => " + str(address))

deadline = (int((datetime.datetime.today() + datetime.timedelta(hours=2)).timestamp()) - EPOCH_ADJUSTMENT) * 1000

#作成したMosaicの供給量を変更するトランザクションを生成
#"mosaic_id"には新しく作成したmosaic idを入力する。

mosaic_supply_change_tx = facade.transaction_factory.create({
    "type": "mosaic_supply_change_transaction",
    "signer_public_key": publickey,
    "deadline": deadline,
    "fee": int(fee * 1000000),
    "mosaic_id": your new mosaic id(example: 0X********),
    "delta": Amount(123456789),
    "action": MosaicSupplyChangeAction.INCREASE
})

#署名＆ペイロード生成(v3.0.3から書き方変更)
signature = facade.sign_transaction(keypair, mosaic_supply_change_tx)
json_payload = facade.transaction_factory.attach_signature(mosaic_supply_change_tx, signature)

#ネットワークへアナウンス
headers = {'Content-type': 'application/json'}
conn = http.client.HTTPConnection(node, 3000)
conn.request("PUT", "/transactions", json_payload, headers)
responce = conn.getresponse()
print(responce.status, responce.reason)

#確認
hash = facade.hash_transaction(mosaic_supply_change_tx)
print(get_node_properties()[4] + "/transactionStatus/" + str(hash))

```

供給量が変更されました
![スクリーンショット (213).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1794143/80609672-2b19-54b4-bea0-f6f64c9406d9.png)

## 5.新しいネームスペースを作成する
続いてモザイクにつける名前をネームスペースの機能を使用して作成します。
Durationは86400以上で設定します。
name_txtは登録されていて使えないワードやもともと使えないワードがあるようです。

以下、Namespace_registration.py

```
from binascii import unhexlify
from symbolchain.CryptoTypes import PrivateKey
from symbolchain.symbol.KeyPair import KeyPair
from symbolchain.facade.SymbolFacade import SymbolFacade
from symbolchain.sc import BlockDuration
import http.client
import datetime
import requests
import json

#ネームスペース登録にに必要な項目を入力
node = "sym-test-04.opening-line.jp"
private_key = "Your testnet privatekey"
fee = 0.1
name_txt = "your new name of namespace"

#ノードからプロパティを取得
def get_node_properties():
        """
        network type, epock ajustment, currency mosaic id, generation hashを取得する
        """
        node_url = "https://" + node+ ":3001"
        node_url_properties = node_url + "/network/properties"
        response = requests.get(node_url_properties)
        if response.status_code != 200:
            raise Exception("status code is {}".format(response.status_code))
        contents = json.loads(response.text)
        network = str(contents["network"]["identifier"].replace("'", ""))
        epoch_adjustment = int(contents["network"]["epochAdjustment"].replace("s", ""))
        currency_mosaic_id = int(contents["chain"]["currencyMosaicId"].replace("'", ""), 16)
        generation_hash_seed = str(contents["network"]["generationHashSeed"].replace("'", ""))
        return network, epoch_adjustment,currency_mosaic_id, generation_hash_seed, node_url

#nodeをmainnetノードに変えればにプロパティも変わる
NETWORK_TYPE = get_node_properties()[0]
EPOCH_ADJUSTMENT = get_node_properties()[1]
#MOSAICID = get_node_properties()[2]
NODE_URL = get_node_properties()[4]

#GENARATION_HASHは送金に利用しないが、確認用。
GENERATOIN_HASH = get_node_properties()[3]

#各プロパティ確認用
print("Network type => " + str(NETWORK_TYPE))
print("Epoch ajustment => " + str(EPOCH_ADJUSTMENT))
#print("Mosaic ID => " + str(hex(MOSAICID)).upper())
print("Generation hash => " + str(GENERATOIN_HASH))
print("Using node url => " + str(NODE_URL))

#秘密鍵から公開鍵を導出
unhex_privatekey = unhexlify(private_key)
privatekey = PrivateKey(unhex_privatekey)
keypair = KeyPair(privatekey)
publickey = keypair.public_key

#testnet or mainnet
facade = SymbolFacade(NETWORK_TYPE)

#アドレスを導出
address = facade.network.public_key_to_address(publickey)
print("Your address => " + str(address))

deadline = (int((datetime.datetime.today() + datetime.timedelta(hours=2)).timestamp()) - EPOCH_ADJUSTMENT) * 1000

#ネームスペース登録用のトランザクションを生成
#durationは86400以上で入力
#registration_typeは　0:ROOT  1:CHILD
#nameは登録されていて使えないワードやもともと使えないワードあり。

namespace_regiatration_tx = facade.transaction_factory.create({
    'type': 'namespace_registration_transaction',
    'signer_public_key': publickey,
    'fee': int(fee * 1000000),
    'deadline': deadline,
    'duration': BlockDuration(86400),
    'registration_type': 0,
	'name': name_txt.encode('utf8')
})


#署名＆ペイロード生成(v3.0.3から書き方変更)
signature = facade.sign_transaction(keypair, namespace_regiatration_tx)
json_payload = facade.transaction_factory.attach_signature(namespace_regiatration_tx, signature)

#ネットワークへアナウンス
headers = {'Content-type': 'application/json'}
conn = http.client.HTTPConnection(node, 3000)
conn.request("PUT", "/transactions", json_payload, headers)
responce = conn.getresponse()
print(responce.status, responce.reason)

#確認
hash = facade.hash_transaction(namespace_regiatration_tx)
print(get_node_properties()[4] + "/transactionStatus/" + str(hash))


```
新しいネームスペースが作成されました。

![スクリーンショット (215).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1794143/0522077e-d7cc-88e7-be5d-5630124b762c.png)


## 6.モザイクにネームスぺースをリンク
最後に作成したモザイクとネームスペースをリンクさせ、モザイクに名前を付けます。
ウォレットのネームスペースとモザイクのIDをトランザクションに記載します。
alias_actionは　1:namespaceとmosaicをlink　 0:namespaceとmosaicをunlinkとのことです。

Mosaic_alias_testnet.py

```
from binascii import unhexlify
from symbolchain.CryptoTypes import PrivateKey
from symbolchain.symbol.KeyPair import KeyPair
from symbolchain.facade.SymbolFacade import SymbolFacade
import http.client
import datetime
import requests
import json

#XYM送信に必要な項目を入力
node = "sym-test-04.opening-line.jp"
private_key = "Yourtestnet privatekey"
fee = 0.1

#ノードからプロパティを取得
def get_node_properties():
        """
        network type, epock ajustment, currency mosaic id, generation hashを取得する
        """
        node_url = "https://" + node+ ":3001"
        node_url_properties = node_url + "/network/properties"
        response = requests.get(node_url_properties)
        if response.status_code != 200:
            raise Exception("status code is {}".format(response.status_code))
        contents = json.loads(response.text)
        network = str(contents["network"]["identifier"].replace("'", ""))
        epoch_adjustment = int(contents["network"]["epochAdjustment"].replace("s", ""))
        currency_mosaic_id = int(contents["chain"]["currencyMosaicId"].replace("'", ""), 16)
        generation_hash_seed = str(contents["network"]["generationHashSeed"].replace("'", ""))
        return network, epoch_adjustment,currency_mosaic_id, generation_hash_seed, node_url

#nodeをmainnetノードに変えればにプロパティも変わる
NETWORK_TYPE = get_node_properties()[0]
EPOCH_ADJUSTMENT = get_node_properties()[1]
#MOSAICID = get_node_properties()[2]
NODE_URL = get_node_properties()[4]

#GENARATION_HASHは送金に利用しないが、確認用。
GENERATOIN_HASH = get_node_properties()[3]

#各プロパティ確認用
print("Network type => " + str(NETWORK_TYPE))
print("Epoch ajustment => " + str(EPOCH_ADJUSTMENT))
#print("Mosaic ID => " + str(hex(MOSAICID)).upper())
print("Generation hash => " + str(GENERATOIN_HASH))
print("Using node url => " + str(NODE_URL))

#秘密鍵から公開鍵を導出
unhex_privatekey = unhexlify(private_key)
privatekey = PrivateKey(unhex_privatekey)
keypair = KeyPair(privatekey)
publickey = keypair.public_key

#testnet or mainnet
facade = SymbolFacade(NETWORK_TYPE)

#アドレスを導出
address = facade.network.public_key_to_address(publickey)
print("Your address => " + str(address))

deadline = (int((datetime.datetime.today() + datetime.timedelta(hours=2)).timestamp()) - EPOCH_ADJUSTMENT) * 1000

#モザイクにネームスペースの情報を登録するトランザクションを生成
#alias_actionは　1:namespaceとmosaicをlink　 0:namespaceとmosaicをunlink
mosaic_alias_tx = facade.transaction_factory.create({
    'type': 'mosaic_alias_transaction',
    'signer_public_key': publickey,
    'fee': int(fee * 1000000),
    'deadline': deadline,
    'namespace_id': your new namespaceid(example: 0X********),
    'mosaic_id': your new mosaic id(example: 0X********),
	'alias_action': 1
})

#署名＆ペイロード生成(v3.0.3から書き方変更)
signature = facade.sign_transaction(keypair, mosaic_alias_tx)
json_payload = facade.transaction_factory.attach_signature(mosaic_alias_tx, signature)

#ネットワークへアナウンス
headers = {'Content-type': 'application/json'}
conn = http.client.HTTPConnection(node, 3000)
conn.request("PUT", "/transactions", json_payload, headers)
responce = conn.getresponse()
print(responce.status, responce.reason)

#確認
hash = facade.hash_transaction(mosaic_alias_tx)
print(get_node_properties()[4] + "/transactionStatus/" + str(hash))

```
ネームスペースをモザイクに反映できました。

![スクリーンショット (217).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1794143/8c5c6bf5-0697-c384-93bb-78953f827c5f.png)

## 7.あとがき
以上、４種類のトランザクションを使って、モザイク、ネームスペースを作成してみました。
課題があるとすれば、モザイクIDとネームスペースIDをウォレットで確認しているので、
pythonで両IDを拾い出して、各トランザクションに当て込めば、モザイク作成から
ネームスペースリンクまで一気にできるかもしれません。

## 8.引用
[Github参考記事](https://github.com/curio184/symbol_sdk_python_example/blob/main/example.py "Github参考記事")
[symobol-sdk-python init.py](https://github.com/symbol/symbol/blob/main/sdk/python/symbolchain/sc/__init__.py "symobol-sdk-python __init__.py")