Reissuable Tokenとはなんなのだ?

再発行可能なんだな〜〜のゆるい認識をしていたが実際に触るとよく分からんくなってきたのでメモ。

Reissuable Token

Tapyrusで発行可能なトークンのうち、COLOR識別子の先頭1バイトが 0xC1 であるトークン。再発行可能なFungible Tokenである。

実際にtapyrus-cliで操作してみる。

発行

発行にはscriptPubkeyを引数に渡す必要がある。token_type1amount は 10 として発行してみる。

# UTXO $ tapyrus-cli listunspent [ { "txid": "15d60147aa843d5ceada27af42b7a972dd1248a9a8e5fa02bd6f47114f56aea9", "vout": 0, "address": "1sE4kAd7uxyNREk4saD47jbzQ54pAwXiM", "token": "TPC", "amount": 0.01990000, "scriptPubKey": "76a914097fb42e4cdab55b1961629172997998433d092188ac", "confirmations": 6, "spendable": true, "solvable": true, "safe": true }, ... ] $ tapyrus-cli issuetoken 1 10 76a914097fb42e4cdab55b1961629172997998433d092188ac { "color": "c157d6abaf844ddc12ae4f5a1276c75ca651247f0f2fac781db52e5b08e94b4833", "txids": [ "b01e02f86bda5f0012536e413d105e53cb197e84fc7ccb6ecb043b5813ac8649", "77646f85a986c755d224560cf251c7073e94a4169e4aad982ccc6730a9af5e04" ] }

二つのトランザクションが発行される。両者順番に getrawtransaction → decoderawtransaction して中身を確認する。

# ひとつ目 { "txid": "b01e02f86bda5f0012536e413d105e53cb197e84fc7ccb6ecb043b5813ac8649", "hash": "312aec8a0b9b76c21be652f8d008735c0c5e81c3ed95291d7de1b2214eac9608", "features": 1, "size": 225, "locktime": 188132, "vin": [ { "txid": "15d60147aa843d5ceada27af42b7a972dd1248a9a8e5fa02bd6f47114f56aea9", "vout": 0, "scriptSig": { "asm": "30440220340f5b9ecd00406f63111e4956e42d5892e07c17552d5e5a5780d26dd0f8867502201b438b58c3aab221db09421d4d819d7f9baaf2261d59b876d6f6b793ca9a20ae[ALL] 0369fea4b568e330c741ff208b0fdaf2d5cab24bfbffc9cd5a762ca3a4cdb45934", "hex": "4730440220340f5b9ecd00406f63111e4956e42d5892e07c17552d5e5a5780d26dd0f8867502201b438b58c3aab221db09421d4d819d7f9baaf2261d59b876d6f6b793ca9a20ae01210369fea4b568e330c741ff208b0fdaf2d5cab24bfbffc9cd5a762ca3a4cdb45934" }, "sequence": 4294967294 } ], "vout": [ { "token": "TPC", "value": 0.00020000, "n": 0, "scriptPubKey": { "asm": "OP_DUP OP_HASH160 097fb42e4cdab55b1961629172997998433d0921 OP_EQUALVERIFY OP_CHECKSIG", "hex": "76a914097fb42e4cdab55b1961629172997998433d092188ac", "reqSigs": 1, "type": "pubkeyhash", "addresses": [ "1sE4kAd7uxyNREk4saD47jbzQ54pAwXiM" ] } }, { "token": "TPC", "value": 0.01965500, "n": 1, "scriptPubKey": { "asm": "OP_DUP OP_HASH160 87e9b4f98261f9244cde481224b5434afaa40a7a OP_EQUALVERIFY OP_CHECKSIG", "hex": "76a91487e9b4f98261f9244cde481224b5434afaa40a7a88ac", "reqSigs": 1, "type": "pubkeyhash", "addresses": [ "1DPeC963srfSCejW89EG4Gap8j2nSdDphb" ] } } ] } # ふたつ目 { "txid": "77646f85a986c755d224560cf251c7073e94a4169e4aad982ccc6730a9af5e04", "hash": "2955c2fa3726a016c330a3d4783339829ab9e222d271dd2fd61269e5b0c1ab17", "features": 1, "size": 258, "locktime": 188136, "vin": [ { "txid": "b01e02f86bda5f0012536e413d105e53cb197e84fc7ccb6ecb043b5813ac8649", "vout": 0, "scriptSig": { "asm": "304402205480da6bf37570c83a8722c737bc4bac9e203b5be4984ef2fa31995bc18b72280220376b5a72d02b5edcf90cff5ac84acafb82162839f2755c216c13a6c44fd5d3e5[ALL] 0369fea4b568e330c741ff208b0fdaf2d5cab24bfbffc9cd5a762ca3a4cdb45934", "hex": "47304402205480da6bf37570c83a8722c737bc4bac9e203b5be4984ef2fa31995bc18b72280220376b5a72d02b5edcf90cff5ac84acafb82162839f2755c216c13a6c44fd5d3e501210369fea4b568e330c741ff208b0fdaf2d5cab24bfbffc9cd5a762ca3a4cdb45934" }, "sequence": 4294967294 } ], "vout": [ { "token": "c157d6abaf844ddc12ae4f5a1276c75ca651247f0f2fac781db52e5b08e94b4833", "value": 10, "n": 0, "scriptPubKey": { "asm": "c157d6abaf844ddc12ae4f5a1276c75ca651247f0f2fac781db52e5b08e94b4833 OP_COLOR OP_HASH160 877826eb145d8929cdb926a734720d8cc8bcc4a6 OP_EQUAL", "hex": "21c157d6abaf844ddc12ae4f5a1276c75ca651247f0f2fac781db52e5b08e94b4833bca914877826eb145d8929cdb926a734720d8cc8bcc4a687", "reqSigs": 1, "type": "coloredscripthash", "addresses": [ "4ZiF2DEMLKFBKtuW8uV7u9b1GCY3YKSAJ9zJWRuCuxY31crT4moVssjKmgFoBYqzQtEmojv9EJpQBNu" ] } }, { "token": "TPC", "value": 0.00014840, "n": 1, "scriptPubKey": { "asm": "OP_DUP OP_HASH160 cc5dbf074b34b8fe0e6911c29168cf25be2b50aa OP_EQUALVERIFY OP_CHECKSIG", "hex": "76a914cc5dbf074b34b8fe0e6911c29168cf25be2b50aa88ac", "reqSigs": 1, "type": "pubkeyhash", "addresses": [ "1Kdb9jZvDWm4LQNJHLkGHHstTHRQSYjCVB" ] } } ] }

ひとつ目のトランザクションは

Input最初に指定したscriptPubkeyを持つUTXO
Output0.0002 だけ切り出されたアウトプット
お釣りアウトプット

ふたつ目のトランザクションは

Inputひとつ目のトランザクションの vout[0]、つまり0.0002 だけ切り出されたアウトプット(UTXO)
Output発行されたトークンのアウトプット
お釣りアウトプット
再発行

試しに発行枚の半数、5枚をReissueしてみ...ようとしたがタイプミスして50枚発行。

$ tapyrus-cli -conf=/etc/tapyrus/tapyrus.conf reissuetoken c157d6abaf844ddc12ae4f5a1276c75ca651247f0f2fac781db52e5b08e94b4833 50 { "color": "c157d6abaf844ddc12ae4f5a1276c75ca651247f0f2fac781db52e5b08e94b4833", "txids": [ "68ab524ff0c124e80bcbc119f15cc94bbc999cf278fb14267877f4bec9103231", "9c3efae4a91b34bd36a45358f5fb43e8a5e1a82f5ae4073fd923bb2e6aa03ba2" ] }

発行時と同様にふたつのトランザクションが発行される。両者の構造は発行時と全く同じ。

トークンの発行アウトプットのみ切り出すと

{ "token": "c157d6abaf844ddc12ae4f5a1276c75ca651247f0f2fac781db52e5b08e94b4833", "value": 50, "n": 0, "scriptPubKey": { "asm": "c157d6abaf844ddc12ae4f5a1276c75ca651247f0f2fac781db52e5b08e94b4833 OP_COLOR OP_HASH160 f02d1487212d8789431e177b322d552f3b4181e9 OP_EQUAL", "hex": "21c157d6abaf844ddc12ae4f5a1276c75ca651247f0f2fac781db52e5b08e94b4833bca914f02d1487212d8789431e177b322d552f3b4181e987", "reqSigs": 1, "type": "coloredscripthash", "addresses": [ "4ZiF2DEMLKFBKtuW8uV7u9b1GCY3YKSAJ9zJWRuCuxY31d1zhnrwwfrEfYyTmJ2WkjByKabYz5XnmjM" ] } },

つまりどうなったのか。

$ tapyrus-cli listunspent [ { "txid": "77646f85a986c755d224560cf251c7073e94a4169e4aad982ccc6730a9af5e04", "vout": 0, "address": "4ZiF2DEMLKFBKtuW8uV7u9b1GCY3YKSAJ9zJWRuCuxY31crT4moVssjKmgFoBYqzQtEmojv9EJpQBNu", "token": "c157d6abaf844ddc12ae4f5a1276c75ca651247f0f2fac781db52e5b08e94b4833", "amount": 10, "label": "", "scriptPubKey": "21c157d6abaf844ddc12ae4f5a1276c75ca651247f0f2fac781db52e5b08e94b4833bca914877826eb145d8929cdb926a734720d8cc8bcc4a687", "confirmations": 3, "spendable": true, "solvable": true, "safe": true }, { "txid": "9c3efae4a91b34bd36a45358f5fb43e8a5e1a82f5ae4073fd923bb2e6aa03ba2", "vout": 0, "address": "4ZiF2DEMLKFBKtuW8uV7u9b1GCY3YKSAJ9zJWRuCuxY31d1zhnrwwfrEfYyTmJ2WkjByKabYz5XnmjM", "token": "c157d6abaf844ddc12ae4f5a1276c75ca651247f0f2fac781db52e5b08e94b4833", "amount": 50, "label": "", "scriptPubKey": "21c157d6abaf844ddc12ae4f5a1276c75ca651247f0f2fac781db52e5b08e94b4833bca914f02d1487212d8789431e177b322d552f3b4181e987", "confirmations": 1, "spendable": true, "solvable": true, "safe": true }, ... ]

同じCOLOR識別子をもったトークンを、再度50枚発行することができた。

勝手に「トークンの再生成(=既存をburn, 再度issue)」だと思っていたが、どちらかというと「トークンの追加」に近いものらしい。

ふたつのトランザクションの意味

Reissuable TokenのCOLOR識別子はscriptPubkeyをペイロードとして決定される。発行時にひとつ目のトランザクションで 0.0002 を切り出した際のscriptPubkeyに注目すると、InputのscriptPubkeyと同じであることがわかる。これにより、ふたつ目のトランザクションでInputに 0.0002 アウトプットを指定するとコマンド実行で利用したUTXOのscriptPubkeyを使ったCOLOR識別子が生成される。

# 発行に利用したUTXO ... "scriptPubKey": "76a914097fb42e4cdab55b1961629172997998433d092188ac", ... # 切り出された 0.0002 アウトプット ... "scriptPubKey": { "hex": "76a914097fb42e4cdab55b1961629172997998433d092188ac", ...

再発行時に際しては、指定トークンからscriptPubkeyを導出して切り出した 0.0002 アウトプットに渡し、そのアウトプットを使うことで「同じscriptPubkeyを持つ」=「同じCOLOR識別子を持つ」トークンを発行することができる。

再発行時のトランザクションを表に表すと

Tx1In指定したトークン持つUTXO
Tx1Out0.0002 だけ切り出され、Tx1Inと同じscriptPubkeyを持つアウトプット
お釣りアウトプット
Tx2In0.0002 だけ切り出され、Tx1Inと同じscriptPubkeyを持つアウトプット
Tx2OutTx2InのscriptPubkeyを参照し発行されたトークンのアウトプット
お釣りアウトプット

つまり「0.0002 を切り出した理由」は「トークン発行トランザクション(ふたつ目のトランザクション)のインプットに任意の scriptPubkey を渡すため」であることがわかる。例えば上記表の場合、Tx1InのscriptPubkeyはトークンとは関係のないものであり、それを用いて発行してしまうと全く別のトークンが発行されてしまう。そのためトークンのscriptPubkeyを「切り出しアウトプット」で橋渡しすることで、同一のscriptPubkeyによるトークン発行を実現している。

おまけ

チェーン上のトークンは gettxoutsetinfo コマンドで total_amount が確認できる。

tapyrus-cli -conf=/etc/tapyrus/tapyrus.conf gettxoutsetinfo { ... "total_amount": { "TPC": 9407100.00000000, "c157d6abaf844ddc12ae4f5a1276c75ca651247f0f2fac781db52e5b08e94b4833": 60, ... } }

10枚発行 → 50枚再発行したので合計は60枚。

追記

発行者以外でreissueすると

$ tapyrus-cli reissuetoken c157d6abaf844ddc12ae4f5a1276c75ca651247f0f2fac781db52e5b08e94b4833 10 error code: -8 error message: Script corresponding to color c157d6abaf844ddc12ae4f5a1276c75ca651247f0f2fac781db52e5b08e94b4833 could not be found in the wallet

怒られる。

トークンの発行に利用したscriptPubkeyのアンロックスクリプトを持っていないと再発行はできなさそう。なるほどそれでscriptPubkey。切り出す理由はCOLOR識別子の辻馬合わせよりこっちな気もする。