署名済みトランザクションによるサブスクリプションサービスを考える

この記事は [nem Advent Calendar 2019](https://qiita.com/advent-calendar/2019/nem) 19日目の記事です。

## はじめに

⭕️[高崎](https://twitter.com/tkskysk)と申します。NEM を使って過去に下記のようなものを作りました。

- [NEM でピクセルアートを NFT 化した「閉鎖国家ピユピル」] (https://crypto.watch.impress.co.jp/docs/column/akiohoshi/1171564.html)
- [NEM に自分の所在地を記録する装置「ブロックチェーン上に天国を作る（プロトタイプ）」](https://www.youtube.com/watch?v=dau3o5unPNA)
- [書くと消せないスレッド式掲示板「SNEMS」](https://snems.com)

総じて「スマートコントラクトがなくても色々できるよ」という感じの事をやっています。[^1]

[^1]: 過去のアドベントカレンダー用ポストはこちら。2017=>[NEM-sdk を使ってサーバーレスな無記名掲示板を作る](https://qiita.com/tkskysk/items/1072ca26d41d8b09928c) / 2018=>[NEM で NFT を作ってみた。ついでにモザイクに画像を保存してみた。](https://qiita.com/tkskysk/items/adfb779bd64202a5d546)

2019年12月現在は NEM から Catapult への移行期間でもあり、正直なところ Catapult で色々できるほどちゃんと触っていません。そこで最近ずっと考えている**「署名済みトランザクションの多目的利用」**について考えつつ**「サブスクリプション」**が作れるかどうか検討します。

## 結論
定期購読サービスの事業者が、**ユーザーから「未来の日時の署名済みトランザクション」を事前に預かる**事で NEM でサブスクリプションを実現する。

## 署名済みトランザクションって何？
送金処理等の情報を秘密鍵で署名をしたトランザクションです。署名済みのトランザクションをネットワークにリリースして承認されるとブロックに取り込まれ、処理が完了します。

トランザクションは必ずしも署名してすぐにネットワークにリリースする必要はありません。それを利用して多目的利用します。

## 多目的利用って？
送金やメッセージの送信など、本来想定されているトランザクションの用途ではない使い方をする試みです。
一人で格好つけて **GPSTX** - **G**eneral **P**urpose **S**igned **T**ransa **X** ion　と呼んでます。誰か一緒に呼んでください。**GPSTX!**

## DeadLine に注目する
NEM のトランザクションには DeadLine というパラメーターがあります。トランザクションの寿命とも言える値で、使用期限の日時を指定します。DeadLine を過ぎていたり「DeadLine の24時間前」を過ぎる前にトランザクションをリリースしようとしても受け付けてくれません。なので自分のPCの時計が進んでいると[まだそのトランザクション使えねえぞ！というエラー](https://nemlog.nem.social/blog/16000)が出たりします。[^timestamp]

[^timestamp]: このリンク先のエラーは正しくは FAILURE_TIMESTAMP_TOO_FAR_IN_FUTURE なので、トランザクションの Timestamp が未来の時間だよ、というエラーです。NEM1 では Timestamp から DeadLine までの時間は最大で24時間まで認められます。Timestamp は Catapult では廃止されるため本文中では Timestamp には言及していません。

つまり、NEM の署名済みトランザクションは最大で「DeadLine の24時間前」から「DeadLine」までの24時間に限り使用できることになります。

<img width="726" alt="スクリーンショット 2019-12-17 18.00.42.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/215722/191f5f12-53c5-9447-1254-e80115983b62.png">

## DeadLine を LockTime として考えてみる
DeadLine という名称だと「使用期限」だと思い込みがちですが、これを LockTime として考える事はできないでしょうか。

LockTime とは Bictoin のトランザクションに於いて、ある指定した時刻（=LockTime）までトランザクションが承認されないようにするためのパラメーターです。LockTime が指定されているトランザクションは、指定の時間が過ぎるまで使用することができません。

前述の通り NEM のトランザクションは DeadLine の24時間前を過ぎるまで使用することができません。これは実質的に LockTime であり、その時間から24時間のみ使用可能な署名済みトランザクションだと見なすことができます。

そこで DeadLine に未来の時間を設定して署名すると、ある日時が過ぎるまで使用できない（=LockTimeの設定された）署名済みトランザクションが出来上がります。この署名済みトランザクションは[先日付小切手](https://kotobank.jp/word/先日付小切手-68640)のように使用することができます。

## LockTime 付きの署名済みトランザクションを複数用意する
ではその LockTime を設定した署名済みトランザクションを複数用意して、サブスクリプションの仕組みができるかどうか考えてみましょう。

### 12ヶ月の定期購読（毎月1日に引き落とし）の場合


#### 前提
* :bear: 事業者は 12ヶ月の間、毎月1日に指定の額の XEM をユーザーから受け取り、定期購読サービスを提供したい。
* :wolf: ユーザーは事業者から定期購読サービスを受けるため毎月1日に支払いをしたい。しかし資産の保全のため秘密鍵を事業者に渡したくない。かといって毎月手動で送金するのは面倒なので避けたい。また途中でサービスを解約する可能性がある。

#### 手順
1. ユーザーは定期購読用のアドレス（以下 A ）を作成し、A に対して引き落とし用の XEM を送金する。
2. ユーザーは A の秘密鍵を使い、毎月１日に使用できる LockTime 付きの署名済みトランザクションを、連続した12ヶ月分作成する。
3. 事業者はユーザーから12ヶ月分の LockTime 付きの署名済みトランザクションを受け取り、保存する。
4. 事業者は毎月１日に署名済みトランザクションをネットワークにリリースし、引き落としを行う。

![General purpose signed transaction](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/215722/87d7f7d2-9dcd-4608-af44-ad0bbea84ab8.png)



この時、ユーザーが事業者に渡すのは署名済みトランザクションのみであり、秘密鍵を渡す必要はありません。また、署名済みトランザクションを預かった事業者は LockTime よりも前に引き落としすることはできないため、ユーザーの資産は保全されます。

ユーザーが定期購読の解約をする場合、事業者は預かっている残りの署名済みトランザクションを破棄します。トラストレスな運用にしたい場合はユーザーが定期購読用のアドレスから資金を引き上げればOKです。

これで、サブスクリプションの仕組みができました。

## 想定されるトラブルと対処
考えられるトラブルとしては

1. ユーザーの定期購読用アドレスの残額不足により引き落としができない
2. なんらかの障害で DeadLine までにトランザクションをリリースできず、トランザクションが失効する

などがあります。この時

1 の場合はサブスクリプションの解約と見なせばOK。
2 の場合はユーザーに手動でお支払いいただくか、障害に対するお詫びとして当月無料、などの対応が必要でしょうか。

## まとめ
以上、事業者がユーザーの秘密鍵を保持する事なく、**未来の署名済みトランザクションをまとめて預かる事で**サブスクリプション機能が実現しました（**頭の中で。**実装してなくてごめんなさい:bow::bow::bow:）

この仕組みであれば、万が一署名済みトランザクションが漏洩してしまっても送信元と受信先のアドレスを変更することはできないので、事業者以外にユーザーの資金が送金されることはありません。

このサブスクリプションの仕組みを発展させると「予約の無断キャンセル問題」[^cancel]を防いだり DAICO[^daico]を再現できたりしそうです。

もちろん実際に実装する段階で、見落としていた問題が噴出することもあるかもしれません。（絶対あるよね）

[^cancel]: たとえば…客は予約時に予約日当日までの1日ごとの署名済みトランザクションを発行し、店は毎日少しずつ支払いを受ける。客がキャンセルした場合、店からの返金は無し。客が予約当日に来店して店を利用した場合、利用額と事前支払い分との差額を支払う。予約日が近づくにつれて実質的にキャンセル料が上がるが、来店すればキャンセル料は相殺される仕組み。この場合、客が秘密鍵を持っていると逃げられちゃうので工夫が必要。2of2のマルチシグとかですかね。

[^daico]: DAICO とはプロジェクトの進捗に応じて資金が支払われる ICO。2018年に Ethereum の考案者・ヴィタリック・ブテリンが提案した、ICO で資金を集めた事業者が逃げるのを防ぐ仕組みです。DAICO では支払いを受ける際、プロジェクトの進捗をステークホルダーが評価し、支払いの可否を投票で決める事ができます。支払い元のアドレスをマルチシグ化すれば投票によって支払いの可否をチェック可能？


## 最後にお知らせ

NEM 関連のイベントが２つほど。ご都合が合えば是非。

### 『出ピユピル記』 sponsored by スタヂオポートマン
2019年12月20日（fri） 〜 22日（sun）。名古屋は栄の #1010 にて。
2019年2月に開催した[閉鎖国家ピユピル](https://nemlog.nem.social/blog/12813)展のその後のストーリーを展開しています。

「閉鎖国家ピユピル」ではピクセルアート×ブロックチェーンをテーマに、ピクセルアーティストの[ヘルミッペ](https://twitter.com/komiya_ma)氏の作品を NEM のオンチェーンに保存し、さらにそのピクセルアートを NFT 化して「デジタル作品のオリジナルデータ」を作りました。ブロックチェーンを使うことで作品は製作者の手を離れて制御できなくなる…というはずだったのですが Catapult への移行にあたって「モザイクは移行されない」ためその根底が揺らいでいるという現状を受けての展示となっています。

詳細については[『出ピユピル記』sponsored by スタヂオポートマン](https://www.1010-sakae.com/single-post/2019/12/04/【展示】20191220fri-1222sun-『出ピユピル記』presented-by-スタヂオポートマン) をご覧ください。[nemicon](https://twitter.com/_nemicon_) さんのご協力により、各方面からサポートいただくことになりました。この場を借りて御礼申し上げます。

最終日にはアフターパーティー『MEET TECH NIGHT』開催します。東京での展示の時にも大好評だった[B級フード研究家・野島慎一郎氏](https://twitter.com/aochins8)による「バカレシピ」フードの提供も！なにそれ！

### 『nemセミナー2020（仮）』
2020年1月19日開催予定。イベントの企画初期にノリと勢いで登壇して喋ることにしたら、その後どんどん規模が大きくなっててだいぶビビってますが頑張ります。追って詳細は [主催者ちゃんかま](https://twitter.com/kamatsukachan) さんからの続報をお待ちください。