symbol-sdk@3.0.7で作るマルチシグ化のトランザクション

# はじめに

こんにちは。

symbol-sdkの3系、トランザクションシリーズ第五弾です。

今回はマルチシグをやっていきます。

https://www.npmjs.com/package/symbol-sdk/v/3.0.7

## 注意事項

書いてあるコードについて、正確性や完全性を保証するものではありません。あくまで参考程度として頂き、最新情報は公式ドキュメンテーションをご確認ください。

# 共通

まずは共通となる個所について。デッドラインと鍵ペアです。

```jsx
import symbolSdk from 'symbol-sdk';

const network = symbolSdk.symbol.Network.TESTNET;
const deadline = network.fromDatetime(new Date(Date.now() + 7200000)).timestamp;

const facade = new symbolSdk.facade.SymbolFacade(network.name);

const privateKey = new symbolSdk.PrivateKey(PRIVATE_KEY);
const keyPair = new facade.constructor.KeyPair(privateKey);
```

XEMのモザイクIDも書いておきます。

```jsx
const currencyMosaicId = 0x72C0212E67A08BCEn;
```

マルチシグアカウントを作成するにあたって、登場人物を３人用意します。

Alice, Bob, Carol です。それぞれ、ランダムな秘密鍵を生成します。

```jsx
import crypto from 'crypto';

const alicePrivateKey = new symbolSdk.PrivateKey(crypto.randomBytes(32).toString('hex').toUpperCase());
const aliceKeyPair = new facade.constructor.KeyPair(alicePrivateKey);
const aliceAddress = network.publicKeyToAddress(aliceKeyPair.publicKey);

const bobPrivateKey = new symbolSdk.PrivateKey(crypto.randomBytes(32).toString('hex').toUpperCase());
const bobKeyPair = new facade.constructor.KeyPair(bobPrivateKey);
const bobAddress = network.publicKeyToAddress(bobKeyPair.publicKey);

const carolPrivateKey = new symbolSdk.PrivateKey(crypto.randomBytes(32).toString('hex').toUpperCase());
const carolKeyPair = new facade.constructor.KeyPair(carolPrivateKey);
const carolAddress = network.publicKeyToAddress(carolKeyPair.publicKey);
```

# マルチシグ構成

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172833/028a0a71-613e-dc9e-3a03-36b60cba717c.png)


# 事前準備

今回は、Alice がトランザクションの送信者（署名者）にする予定です。

そのためにはXEM残高が必要ですが、ランダム生成したアカウントなので残高ゼロです。

そこでXEMを少し送っておきます。

```jsx
const fundTransaction = facade.transactionFactory.create({
  type: 'transfer_transaction_v1',
  signerPublicKey: keyPair.publicKey.toString(),
  fee: 1000000n,
  deadline,
  recipientAddress: aliceAddress,
  mosaics: [
    { mosaicId: currencyMosaicId, amount: 1000000n },
  ],
});
const fundSignature = facade.signTransaction(keyPair, fundTransaction);
const fundJsonPayload = facade.transactionFactory.constructor.attachSignature(fundTransaction, fundSignature);
const fundHash = facade.hashTransaction(fundTransaction).toString();
const fundSendRes = await axios.put(`${NODE_INFO}/transactions`, fundJsonPayload).then((res) => res.data);
```

# マルチシグ化

今回は、 Alice をマルチシグアカウントとし、Bob と Carol の 2 of 2 マルチシグを組みます。

そのためには、３人全員の署名が必要になります（確か）。

なのでまずは、マルチシグモディフィケーショントランザクションを作成し、

次に、アグリゲートコンプリートトランザクションでラップして全員の署名を付けていきます。

## マルチシグモディフィケーショントランザクション

`createEmbedded` を使うところに注意。

```jsx
const innerTransaction1 = facade.transactionFactory.createEmbedded({
  type: 'multisig_account_modification_transaction_v1',
  signerPublicKey: aliceKeyPair.publicKey,
  minRemovalDelta: 2,
  minApprovalDelta: 2,
  addressAdditions: [ bobAddress, carolAddress ],
  addressDeletions: [],
});
```

## アグリゲートコンプリートトランザクション

```jsx
const innerTransactions = [ innerTransaction1 ];
const transactionsHash = symbolSdk.facade.SymbolFacade.hashEmbeddedTransactions(innerTransactions);

const transaction = facade.transactionFactory.create({
  type: 'aggregate_complete_transaction_v2',
  signerPublicKey: aliceKeyPair.publicKey,
  fee: 1000000n,
  deadline,
  transactions: innerTransactions,
  transactionsHash,
});
```

## 署名とハッシュ計算

先に Alice の署名を行い、トランザクションハッシュを計算します。ここで、 `attachSignature` の戻り値は破棄します。

```jsx
const signature = facade.signTransaction(aliceKeyPair, transaction);
facade.transactionFactory.constructor.attachSignature(transaction, signature);
const hash = facade.hashTransaction(transaction).toString();
```

Bob と Carol の連署を作成し、トランザクションに取り込みます。

```jsx
const bobCosignature = facade.cosignTransaction(bobKeyPair, transaction);
const carolCosignature = facade.cosignTransaction(carolKeyPair, transaction);

transaction.cosignatures.push(bobCosignature);
transaction.cosignatures.push(carolCosignature);
```

ここで、もう一度 `attachSignature` を行い、トランザクションのペイロードを入手します。

```jsx
const jsonPayload = facade.transactionFactory.constructor.attachSignature(transaction, signature);
```

## 送信

あとは、トランザクションを送信すれば、マルチシグ化が完了します。

```jsx
const sendRes = await axios.put(`${NODE_URL}/transactions`, jsonPayload).then((res) => res.data);
console.log(sendRes);
```

# おわりに

今回はマルチシグのトランザクションを作りました。

# シリーズ

https://qiita.com/planethouki/items/860d9f1095c087ccd98f

https://qiita.com/planethouki/items/25f104ef4930b019ddfb

https://qiita.com/planethouki/items/525b5a582f78be57217b

https://qiita.com/planethouki/items/c0336b479f6c11918183