SubstrateでMultisig(マルチシグ)を試してみる

# はじめに

[Substrate](https://substrate.io/)ではMultisig(マルチシグ)の機能があり[Multisigのpallet](https://docs.rs/pallet-multisig/latest/pallet_multisig/)(pallet = ライブラリのようなもの)を使う事で簡単に導入できます。
[Substrateのチュートリアル](https://docs.substrate.io/tutorials/v3/)にはMultisigの紹介がないため、今回の記事ではSubstrateでどのようにMultisigを使うかを簡単にですが紹介します。

# 導入手順

手順は基本的に下に記載のページのものと同じです。
[Adding MultiSig to Substrate](https://shirshak55.github.io/articles/adding-multisig-to-substrate/)

### Clone

まずベースとなる substrate-node-template を clone します。

```bash
% git clone https://github.com/substrate-developer-hub/substrate-node-template
% cd substrate-node-template
```

### runtime/Cargo.tomlの修正

runtime/Cargo.tomlをエディタで開いて、[dependencies]の下に以下multisigの部分を追加します。

```rust:runtime/Cargo.toml
[dependencies]
pallet-multisig = { version = "4.0.0-dev", default-features= false, git = "https://github.com/paritytech/substrate.git", tag = "devhub/latest" }
```

次に同ファイルの[features]のセクションで 'pallet-multisig/std' を追記します。

```rust:runtime/Cargo.toml
[features]
default = ["std"]
std = [
    'pallet-multisig/std',
```

その後、修正がうまくいったか以下コマンドで依存パッケージのチェックをおこないます。

```bash
% cargo check -p node-template-runtime
```

### runtime/src/lib.rsの修正

#### Config trait

MultisigのConfig traitを実装します。
runtime/src/lib.rsの一番下に以下を追記します。

```rust:runtime/src/lib.rs
pub const MILLICENTS: Balance = 1_000_000_000;
pub const CENTS: Balance = 1_000 * MILLICENTS;
pub const DOLLARS: Balance = 100 * CENTS;

parameter_types! {
	pub const DepositBase: Balance = 5 * CENTS;
	pub const DepositFactor: Balance = 10 * CENTS;
	pub const MaxSignatories: u16 = 20;
}

impl pallet_multisig::Config for Runtime {
	type Event = Event;
	type Call = Call;
	type Currency = Balances;
	type DepositBase = DepositBase;
	type DepositFactor = DepositFactor;
	type MaxSignatories = MaxSignatories;
	type WeightInfo = pallet_multisig::weights::SubstrateWeight<Runtime>;
}
```

Config traitの詳しい情報は[Add the Nicks Pallet to your Runtime](https://docs.substrate.io/tutorials/v3/add-a-pallet/)を参考にしてください。

#### construct_runtimeへの追加

construct_runtimeにMultisigの記述を追加します。
記事の記載(古いバージョンの書き方)と違います。また"MultiSig"ではなく"Multisig"です。(Sが小さい)。
この修正が正しくできていないと後のMultisig確認できなくなってしまいます。

```rust:runtime/src/lib.rs
construct_runtime!(
	pub enum Runtime where
		Block = Block,
		NodeBlock = opaque::Block,
		UncheckedExtrinsic = UncheckedExtrinsic
	{
: 
: 
		Multisig: pallet_multisig,   // これを追加！！！！！！！
```

### Compile

一通りファイルを修正したらCompileします。

```bash
% cargo build --release
```

# Multisigの動作確認

### Node起動

まずはSubstrateのNodeをターミナルで起動しておきます。

```bash
% ./target/release/node-template --dev --tmp
2022-03-02 14:37:35 Running in --dev mode, RPC CORS has been disabled.
2022-03-02 14:37:35 Substrate Node
2022-03-02 14:37:35 ✌️  version 4.0.0-dev-2ea642a-x86_64-macos
2022-03-02 14:37:35 ❤️  by Substrate DevHub <https://github.com/substrate-developer-hub>, 2017-2022
2022-03-02 14:37:35 📋 Chain specification: Development
2022-03-02 14:37:35 🏷 Node name: imaginary-cactus-3064
2022-03-02 14:37:35 👤 Role: AUTHORITY
2022-03-02 14:37:35 💾 Database: RocksDb at /var/folders/nh/fsz2n5z16753v95_x9ly7s_m0000gn/T/substrateEbNeEw/chains/dev/db/full
2022-03-02 14:37:35 ⛓  Native runtime: node-template-100 (node-template-1.tx1.au1)
2022-03-02 14:37:35 🔨 Initializing Genesis block/state (state: 0xacd5…b687, header-hash: 0xf000…053f)
2022-03-02 14:37:35 👴 Loading GRANDPA authority set from genesis on what appears to be first startup.
2022-03-02 14:37:35 ⏱  Loaded block-time = 6s from block 0xf0005367ba586015204a5448a7f27796846a749351a8e41c4bf19037d774053f
2022-03-02 14:37:35 Using default protocol ID "sup" because none is configured in the chain specs
2022-03-02 14:37:35 🏷 Local node identity is: 12D3KooWJQ9RuxMsvMB814hYkYJwLCz54tso623w2iHTMTn4v2Sh
2022-03-02 14:37:35 📦 Highest known block at #0
2022-03-02 14:37:35 〽️ Prometheus exporter started at 127.0.0.1:9615
2022-03-02 14:37:35 Listening for new connections on 127.0.0.1:9944.
^C2022-03-02 14:37:36 🙌 Starting consensus session on top of parent 0xf0005367ba586015204a5448a7f27796846a749351a8e41c4bf19037d774053f
```

### Multisigアカウントの作成

NodeのコンソールでBlockが順調に増え続けている状態で、ブラウザから以下(Polkadot-JS application)にアクセスします。

"https://polkadot.js.org/apps/?rpc=ws%3A%2F%2F127.0.0.1%3A9944#/accounts"

すると以下のような画面が表示されて、マルチシグ のボタン部分が活性化されている事を確認します。うまく Multisigの導入ができていないと、ここが非活性化されてしまいMultisigの確認ができません。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2560317/069b0e4e-66ba-fed1-19df-eb82ba6c0a18.png)

例として2of3のMultisigを作成する時は以下のように作ります。
利用可能な署名の欄から、Multisigを構成するアカウントを３つ選びます。これが2of3の3の部分です。
2of3の2の部分は[出発点]の数値を変更します。画面上は2になっています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2560317/3e26c8e1-0e50-6a40-88a0-d4a81a51fb88.png)

[作成]ボタンをおして、以下のようにmultisigのアカウントを作成する事ができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2560317/277bbdb8-e8f2-5435-ef9d-dfd046f0e728.png)

### Multisigアカウントへの送金

Multisigアカウントへの送金自体は、他のアカウントへ送金する手順と変わりはありません。
画面上で残高があるアカウント行の[送信]ボタンを押します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2560317/46b26e4b-da0c-0930-7993-b9e45bba99e1.png)

[アカウントに送信する]で2of3アカウントを指定して送金するだけです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2560317/4e36ed9c-f559-d64f-c37e-57edaa16a8bf.png)

### Multisigアカウントからの送金

Multisigアカウントからの送金は、Multisigアカウントに参加しているアカウントの署名が一定以上([出発点]で決めた数値)の署名が必要になります。

2of3アカウントの[送信]ボタンを押して、適当なアカウントに送金します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2560317/709b71da-fa08-beae-a2c7-724e6655dca8.png)

以下画面の[multisig signatory]でMultisigアカウントに参加しているアカウント(このアカウントはtx手数料以上の残高が必要です)のいずれかを選びます。
また、[multisig call data]を後で使うためコピーしておきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2560317/ab6f2e65-9311-e501-378b-8f184fa09c72.png)

[Sign and Submit]ボタンを押すと1つのアカウントに署名された送金用のデータができます。

送金用データができた結果としてアカウント一覧画面の2of3アカウント行で署名された数が行の左に表示され3点リーダーを押すと[マルチシグの承認]ができるようになってるので、これを押します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2560317/54591ddc-d9c0-1f8c-5465-0072ed9f89bb.png)

ペンディングコールハッシュといいう画面が表示されますが、ここで[call data for final approval]の部分に先ほどコピーしておいた[multisig call data]を入れます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2560317/346725ac-bd0f-38d4-f8f9-56e63dcf2e52.png)

すると以下のように何のtxに対しての署名かを明確にする事ができ[Approve]ボタンが活性化されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2560317/f0d50bce-6060-28f1-0006-2acc251b471b.png)

[Approve]ボタンを押して、ブロックが進むと以下のように送信先に残高が移動した事が確認できました。ここでは2of3なので2アカウントの署名ができたので送金できました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2560317/0c6aabc7-ef9e-aaed-4359-18f77a026f18.png)

# 最後に

簡単にですがブラウザからアクセスできる[Polkadot-JS application](https://polkadot.js.org/apps/?rpc=ws%3A%2F%2F127.0.0.1%3A9944#/accounts)を使って Multisigでのトークンの送受信を試してみました。

実際に自分のWEBサイトに組み込む際は[substrate-front-end-template](https://github.com/substrate-developer-hub/substrate-front-end-template)を参考にMultisigのqueryやらtxにアクセスしてみると良いかもしれません。

Polkadot-JS applicationはGithub上に[ソース](https://github.com/polkadot-js/apps#development)が公開されてますので、こちらからコードは確認できます。

## 余談

[construct_runtimeへの追加]で"MultiSig"ではなくて"Multisig"でないと動かない、という記載をしましたが

```rust
		// MultiSig: pallet_multisig,   // これだと動かない
		Multisig: pallet_multisig,   // こちらは動く
```
Polkadot-JS applicationの[マルチシグ]ボタンの活性化するどうかの条件文で"api.tx.multisig"という変数を参照しているんですよね。
```ts
          <Button
            icon='plus'
            isDisabled={!(api.tx.multisig || api.tx.utility) || !hasAccounts}
            label={t<string>('Multisig')}
            onClick={toggleMultisig}
          />
```
もし"S"が大文字で記載してしまっている"MultiSig: pallet_multisig"という記述ですと"api.tx.multisig"ではなく"api.tx.multiSig"にしないと動かないんですよね。。。みなさんも、camel caseには気をつけましょう〜。

# 参考

[Adding MultiSig to Substrate](https://shirshak55.github.io/articles/adding-multisig-to-substrate/)