バックエンドからのモナカードの送付

バックエンドからのモナカードの送付

Monacard(モナカード)1 Advent Calendar 2023 14日目です。

https://adventar.org/calendars/8922

モナカードとは

Monapartyアセット(トークン)にイラストや画像を紐付ける、いわゆるアート系(N)FTです。
Monapartyは、モナコインブロックチェーン上で、アセット発行、送付等をできるようにする仕組みで、Bitcoin ↔ Counterparty, Monacoin ↔ Monaparty のような関係です。

https://card.mona.jp/

法律

金融庁の「事務ガイドライン(第三分冊:金融会社関係)」の一部改正(案)【ドキュメントA】、および、左記に対するパブリックコメントに対する金融庁の考え方【ドキュメントB】によると、以下のようなものは暗号資産に該当しない可能性が高いと考えられます。

【A】Ⅰ-1-1①(注)ロ.

当該財産的価値の価格や数量、技術的特性・仕様等を 総合考慮し、不特定の者に対して物品等の代価の弁済に 使用し得る要素が限定的であること。例えば、以下のいずれかの性質を有すること
・ 最小取引単位当たりの価格が通常の決済手段として 用いるものとしては高額であること
・ 発行数量を最小取引単位で除した数量(分割可能性を踏まえた発行数量)が限定的であること

【B】20

 一般的に発行数量を最小取引単位で除した数 量(分割可能性を踏まえた発行数量)が少ないほ ど通常の決済手段として用いられる蓋然性が小 さいと考えられ、例えば 100 万個以下である場合 には、「限定的」といえると考えられます。

「事務ガイドライン(第三分冊:金融会社関係)」の一部改正(案)の公表に対するパブリックコメントの結果等について
https://www.fsa.go.jp/news/r4/sonota/20230324-2/20230324-2.html

【Aの新旧対照表】
https://www.fsa.go.jp/news/r4/sonota/20221216-2/01.pdf
【B】
https://www.fsa.go.jp/news/r4/sonota/20230324-2/1.pdf

というわけで、発行枚数が100万個以下であれば、暗号資産ではない、すなわち、人様のモナカードを預かっても大丈夫そうです。

ちなみに、

・ 最小取引単位当たりの価格が通常の決済手段として 用いるものとしては高額であること

に対する金融庁の考え方は、

【B】16

一般的に最小取引単位当たりの価格が高額で あるほど通常の決済手段として用いられる蓋然 性が小さいと考えられ、例えば 1000 円以上のも のについては「最小取引単位当たりの価格が通常 の決済手段として用いるものとしては高額」なも のであると考えられます。

なので、低価格で取引されているモナカードの場合、この条件は使えなさそうです。

動機

人様のモナカードを預かれるとなると、「モナパちゃん」(サービス停止中)や「もなこっと」(https://monacotto.monatoka.com/)のようなサービスを提供できるということになります。
そうすると、人様から預かったモナカードを、人様に送り返す(あるいは購入した別の人様にお送りする)という作業が必要になりますね。そうでないと、預かりっぱなしになってしまいます。

流れ

0. 準備
1.トランザクション作成
2.署名
3.ブロードキャスト

有志の方々が建ててくださっているモナコイン・Monaparty関連サーバー

Blockbook

counterparty-server(counterblock)

■ドキュメント

BlockbookAPI

https://github.com/trezor/blockbook/blob/master/docs/api.md

Counterparty公式

https://counterparty.io/

counterparty-server API

https://github.com/CounterpartyXCP/Documentation/blob/master/Developers/API.md

counterblock API

https://github.com/CounterpartyXCP/Documentation/blob/master/Developers/counterblock_API.md

※ 人様が運営するノードです。大きな負荷をかけることは避け、お行儀よく使わせていただきましょう。

準備

node.js でやります。

import bitcoin from 'bitcoinjs-lib';
import coininfo from 'coininfo';

bitcoinjs-libは署名に使います。
Monapartyサーバが作る未署名トランザクションがPSBTのフォーマットでないので、version6のPSBTではなく、version5のTransactionBuilderを使います。

npm install bitcoinjs-lib@5

bitcoinjs-lib

https://github.com/bitcoinjs/bitcoinjs-lib

bitcoinjs-libはその名の通り、ビットコインためのライブラリなので、モナコインで使う場合は、モナコインのネットワーク情報が必要です。そのために、coininfoを使います。

coininfo

https://github.com/cryptocoinjs/coininfo

トランザクション作成

Counterpartyサーバ群は、counterparty-serverとcounterblockで構成されています。APIも、counterparty-serverに投げるものとcounterblockに投げるものがありますが、counterblockがcounterparty-serverのプロキシを担ってくれています。よって、counterparty-serverに投げたいリクエストは、counterblockに対して「これをcounterparty-serverに投げてね」と言えば大丈夫です。

それをふまえて、

const requestToMonapartyBody = JSON.stringify({
  "jsonrpc": "2.0",
  "id": 0,
  "method": "proxy_to_counterpartyd",
  "params": {
    "method": "create_send",
    "params": {
      "source": source,
      "destination": destinations.length >= 2 ? destinations : destinations[0],
      "asset": assets.length >= 2 ? assets : assets[0],
      "quantity": quantitys.length >= 2 ? quantitys : quantitys[0],
    }
  }
});

をcounterblockに対してリクエストします。

1つ目の"method"である"proxy_to_counterpartyd"、これが「これをcounterparty-serverに投げてね」ですね。

2つ目の"method"である"create_send"は、「モナパアセットを送信する未署名トランザクションを作ってください」というものです。

"source":  送信元のアドレスです。
"destination": 送信先のアドレスなのですが、単数のときと複数のときで型を変えなければいけない!!!からこんなことをしています。
"asset": 送信対象のアセットです。
"quantity": 送信する数量です。

送信先が複数、あるいは、送信対象アセットが複数種の場合は、配列で指定しますが、"destination", "asset", "quantity"の同一のインデックスのものが組み合わされます。

署名

const networkMona = coininfo('MONA').toBitcoinJS();
const keyPair = bitcoin.ECPair.fromWIF(wif, networkMona);
const tx = bitcoin.Transaction.fromHex(txHex);
const txb = bitcoin.TransactionBuilder.fromTransaction(tx, networkMona);

for (let i = 0; i < tx.ins.length; i++) {
  txb.sign(i, keyPair);
}

const signedTxHex = txb.build().toHex();

wifは、送信元の秘密鍵のWIFです。

txHexは、さっきcounterblockにリクエストして返ってきた未署名トランザクションです。

未署名トランザクションをTransactionBuilderオブジェクトにして、各インプットを秘密鍵で署名しています。

最後に、署名済みトランザクションをHEXで出力しています。

ブロードキャスト

自前でモナコインサーバを建てている場合

const requestToMonacoindUrl = `http://localhost:8332/wallet/${wallet}`;
const requestToMonacoindMethod = 'POST';

const requestToMonacoindHeaders = {
  'Content-Type': 'text/plain',
};

const requestToMonacoindBody = JSON.stringify({
  jsonrpc: "1.0",
  id: 0,
  method: "sendrawtransaction",
  params: [
    signedTxHex,
  ],
});

const authorization = Buffer.from(rpcUser + ':' + rpcPassword, 'utf-8').toString('base64');
requestToMonacoind.headers.Authorization = 'Basic ' + authorization;

これを投げてください。成功すれば、TXIDが返ってきます。

walletはウォレット名です。(マルチウォレットの前提。)
ホスト、ポート番号は人によって違うかもしれません。

人様のサーバを利用させていただく場合

Blockbook

GET /api/v2/sendtx/<hex tx data>
POST /api/v2/sendtx/ (hex tx data in request body)

だそうです。

counterblock

broadcast_tx(signed_tx_hex)

というmethodがあるようです。

Blockbook、counterblockのいずれも、私は使ったことがないので、ドキュメントを参照ください。

おわりに

バックエンドでモナカードが扱えると、だいぶサービスの幅が広がりますよね。
楽しいモナカードサービス、作ってみてください!

Remaining : 0 characters / 0 images
100

Sign up / Continue after login

Related stories

Writer

ビットコインとかモナコインが好きなので、自分で会社を作りました。 株式会社モナトカの代表取締役。 モナコインを中心に、暗号資産の普及を推進するのがミッションです。 【提供サービス】 ・JPYCをモナコインで買える・売れる「もなちぇん」 ・モナカードマーケットプレイス「もなこっと」

Share

Popular stories

モナカードゲーム始めます! (前編)

431

Knights of Monadom あそびかた

410

monablessの使い方

353