マルチシグアカウントの作成

このガイドでは、共同アカウントを設定する方法について説明します。

ユースケース

例えば Alice と Bob はそれぞれのアカウントを持っているとします。彼らは食料雑貨の購入に共有アカウントを使用したいと思っています。どちらかが買い物に出かけたとき、他方からの明示的な承認を必要とせずに、共有アカウントを使って取引ができます。

この共有アカウントは Symbol では 1-of-2 マルチシグ として表されます。 マルチシグアカウント を作ることは Alice と Bob が別々のアカウントで資産を共有することを可能にします。アカウントは 1-of-2 として設定されているので、トランザクションには彼らどちらかの署名を必要とします。

../../_images/multisig-1-of-2.png

1-of-2 マルチシグアカウントの例

前提条件

  • 入門セクション を完了している

  • マルチシグへ変換する新しい アカウント を作成します。

  • アカウントに手数料を支払うために十分な symbol.xym を入金してください。

  • Alice と Bob のアカウントを作成します。

注釈

このガイド に従って新しいアカウントを作成します。

方法 #01: デスクトップウォレットを使用する

  1. マルチシグアカウントに変換するアカウントにログインします。

  2. 左側のメニューの "マルチシグ" タブをクリックします。

  3. "署名者を追加" をクリックし、マルチシグ連署者として追加するアカウントのアドレスまたは公開鍵を入力します。 "+" ボタンをクリックします。

../../_images/create-multisig-2.gif
  1. マルチシグ連署者として追加するアカウントごとに、手順 3 を繰り返します。この例では、連署者として追加する 2 つのアカウントの Alice と Bob があります。

  2. マルチシグの “最小承認数” と “最小削除数” を選択します。

  3. "送信" をクリックします。ポップアップの情報を確認します。ウォレットパスワードを入力して "確認" をクリックします。

../../_images/create-multisig-3.gif
  1. マルチシグ連署者として選択したアカウントにログインします。 "ホーム" ページで "パーシャル"トランザクションをクリックします。保留中のアグリゲートボンデッドトランザクションをクリックします。ウォレットパスワードを入力して "確認" をクリックします。

../../_images/create-multisig-4.gif
  1. マルチシグ連署者候補として追加するアカウントごとに、手順 7 を繰り返します。

  2. マルチシグに変換されるアカウントにログインします。 アグリゲートボンデッドトランザクションが完了 (承認済み) したら、"マルチシグ" ページに戻って、変換されたことを確認できます。

../../_images/create-multisig-5.png

方法 #02: SDK を使用する

1. First, define the accounts that will become cosignatories of the multisig account. Following our example, these are Alice and Bob addresses. Then, open the account that will be converted into multisig using its private key.

// replace with network type
const networkType = NetworkType.TEST_NET;
// replace with candidate multisig private key
const privateKey =
  'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF';
const account = Account.createFromPrivateKey(privateKey, networkType);
// replace with cosignatory 1 public key
const cosignatory1PublicKey =
  'D04AB232742BB4AB3A1368BD4615E4E6D0224AB71A016BAF8520A332C9778737';
const cosignatory1 = PublicAccount.createFromPublicKey(
  cosignatory1PublicKey,
  networkType,
);
// replace with cosignatory 2 public key
const cosignatory2PublicKey =
  '462EE976890916E54FA825D26BDD0235F5EB5B6A143C199AB0AE5EE9328E08CE';
const cosignatory2 = PublicAccount.createFromPublicKey(
  cosignatory2PublicKey,
  networkType,
);
// replace with network type
const networkType = symbol_sdk_1.NetworkType.TEST_NET;
// replace with candidate multisig private key
const privateKey =
  'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF';
const account = symbol_sdk_1.Account.createFromPrivateKey(
  privateKey,
  networkType,
);
// replace with cosignatory 1 public key
const cosignatory1PublicKey =
  'D04AB232742BB4AB3A1368BD4615E4E6D0224AB71A016BAF8520A332C9778737';
const cosignatory1 = symbol_sdk_1.PublicAccount.createFromPublicKey(
  cosignatory1PublicKey,
  networkType,
);
// replace with cosignatory 2 public key
const cosignatory2PublicKey =
  '462EE976890916E54FA825D26BDD0235F5EB5B6A143C199AB0AE5EE9328E08CE';
const cosignatory2 = symbol_sdk_1.PublicAccount.createFromPublicKey(
  cosignatory2PublicKey,
  networkType,
);

2. Create a MultisigAccountModificationTransaction to convert the shared account into a multisig account. Since we want to create a 1-of-2 multisig account, let's set the minimum required signatures to 1.

const multisigAccountModificationTransaction = MultisigAccountModificationTransaction.create(
  Deadline.create(epochAdjustment),
  1,
  1,
  [cosignatory1.address, cosignatory2.address],
  [],
  networkType,
);
const multisigAccountModificationTransaction = symbol_sdk_1.MultisigAccountModificationTransaction.create(
  symbol_sdk_1.Deadline.create(epochAdjustment),
  1,
  1,
  [cosignatory1.address, cosignatory2.address],
  [],
  networkType,
);

3. Create an AggregateBondedTransaction, wrapping the MultisigAccountModificationTransaction defined in the previous step. This action is necessary because Alice and Bob must opt-in to become cosignatories of the new multisig account.

const aggregateTransaction = AggregateTransaction.createBonded(
  Deadline.create(epochAdjustment),
  [multisigAccountModificationTransaction.toAggregate(account.publicAccount)],
  networkType,
  [],
  UInt64.fromUint(2000000),
);
const aggregateTransaction = symbol_sdk_1.AggregateTransaction.createBonded(
  symbol_sdk_1.Deadline.create(epochAdjustment),
  [multisigAccountModificationTransaction.toAggregate(account.publicAccount)],
  networkType,
  [],
  symbol_sdk_1.UInt64.fromUint(2000000),
);
  1. 後のマルチシグアカウントの秘密鍵を使って AggregateTransaction に署名します。

注釈

自分のネットワークでのみ有効なトランザクションを作るには、ネットワークジェネレーションハッシュを含めます。新しいブラウザタブで NODE_URL /node/info を開いて meta.networkGenerationHash の値をコピーします。

// replace with meta.networkGenerationHash (nodeUrl + '/node/info')
const networkGenerationHash =
  '1DFB2FAA9E7F054168B0C5FCB84F4DEB62CC2B4D317D861F3168D161F54EA78B';
const signedTransaction = account.sign(
  aggregateTransaction,
  networkGenerationHash,
);
console.log(signedTransaction.hash);
// replace with meta.networkGenerationHash (nodeUrl + '/node/info')
const networkGenerationHash =
  '1DFB2FAA9E7F054168B0C5FCB84F4DEB62CC2B4D317D861F3168D161F54EA78B';
const signedTransaction = account.sign(
  aggregateTransaction,
  networkGenerationHash,
);
console.log(signedTransaction.hash);

5. Before sending an AggregateBondedTransaction, the future multisig account needs to lock at least 10 symbol.xym. This transaction is required to prevent spamming the network. After the HashLockTransaction has been confirmed, announce the AggregateTransaction signed in (4).

// replace with symbol.xym id
const networkCurrencyMosaicId = new MosaicId('5E62990DCAC5BE8A');
// replace with network currency divisibility
const networkCurrencyDivisibility = 6;

const hashLockTransaction = HashLockTransaction.create(
  Deadline.create(epochAdjustment),
  new Mosaic(
    networkCurrencyMosaicId,
    UInt64.fromUint(10 * Math.pow(10, networkCurrencyDivisibility)),
  ),
  UInt64.fromUint(480),
  signedTransaction,
  networkType,
  UInt64.fromUint(2000000),
);

const signedHashLockTransaction = account.sign(
  hashLockTransaction,
  networkGenerationHash,
);

// replace with node endpoint
const nodeUrl = 'NODE_URL';
const repositoryFactory = new RepositoryFactoryHttp(nodeUrl);
const listener = repositoryFactory.createListener();
const receiptHttp = repositoryFactory.createReceiptRepository();
const transactionHttp = repositoryFactory.createTransactionRepository();
const transactionService = new TransactionService(transactionHttp, receiptHttp);

listener.open().then(() => {
  transactionService
    .announceHashLockAggregateBonded(
      signedHashLockTransaction,
      signedTransaction,
      listener,
    )
    .subscribe(
      (x) => console.log(x),
      (err) => console.log(err),
      () => listener.close(),
    );
});
// replace with symbol.xym id
const networkCurrencyMosaicId = new symbol_sdk_1.MosaicId('5E62990DCAC5BE8A');
// replace with network currency divisibility
const networkCurrencyDivisibility = 6;
const hashLockTransaction = symbol_sdk_1.HashLockTransaction.create(
  symbol_sdk_1.Deadline.create(epochAdjustment),
  new symbol_sdk_1.Mosaic(
    networkCurrencyMosaicId,
    symbol_sdk_1.UInt64.fromUint(
      10 * Math.pow(10, networkCurrencyDivisibility),
    ),
  ),
  symbol_sdk_1.UInt64.fromUint(480),
  signedTransaction,
  networkType,
  symbol_sdk_1.UInt64.fromUint(2000000),
);
const signedHashLockTransaction = account.sign(
  hashLockTransaction,
  networkGenerationHash,
);
// replace with node endpoint
const nodeUrl = 'NODE_URL';
const repositoryFactory = new symbol_sdk_1.RepositoryFactoryHttp(nodeUrl);
const listener = repositoryFactory.createListener();
const receiptHttp = repositoryFactory.createReceiptRepository();
const transactionHttp = repositoryFactory.createTransactionRepository();
const transactionService = new symbol_sdk_1.TransactionService(
  transactionHttp,
  receiptHttp,
);
listener.open().then(() => {
  transactionService
    .announceHashLockAggregateBonded(
      signedHashLockTransaction,
      signedTransaction,
      listener,
    )
    .subscribe(
      (x) => console.log(x),
      (err) => console.log(err),
      () => listener.close(),
    );
});

6. Cosign the AggregateTransaction with the CLI using Alice's account. Replace the hash A6A374E66B32A3D5133018EFA9CD6E3169C8EEA339F7CCBE29C47D07086E068C with the AggregateTransaction hash signed in (4).

symbol-cli transaction cosign --hash A6A374E66B32A3D5133018EFA9CD6E3169C8EEA339F7CCBE29C47D07086E068C --profile alice
  1. Bob のアカウントで AggregateTransaction に署名 します。

symbol-cli transaction cosign --hash A6A374E66B32A3D5133018EFA9CD6E3169C8EEA339F7CCBE29C47D07086E068C --profile bob

8. If everything goes well, the account is now set as multisig, being Alice and Bob accounts their cosignatories. You can get the list of the multisig accounts where Alice or Bob are cosignatories with the function MultisigHttp.getMultisigAccountInfo().

// replace with multisig address
const rawAddress = 'TAEG6L-KWXRA7-PSWUEE-ILQPG4-3V5CYZ-S5652T-JTUU';
const address = Address.createFromRawAddress(rawAddress);

// replace with node endpoint
const nodeUrl = 'NODE_URL';
const repositoryFactory = new RepositoryFactoryHttp(nodeUrl);
const multisigHttp = repositoryFactory.createMultisigRepository();

multisigHttp.getMultisigAccountInfo(address).subscribe(
  (multisigInfo) => console.log(multisigInfo),
  (err) => console.error(err),
);
// replace with multisig address
const rawAddress = 'TAEG6L-KWXRA7-PSWUEE-ILQPG4-3V5CYZ-S5652T-JTUU';
const address = symbol_sdk_1.Address.createFromRawAddress(rawAddress);
// replace with node endpoint
const nodeUrl = 'NODE_URL';
const repositoryFactory = new symbol_sdk_1.RepositoryFactoryHttp(nodeUrl);
const multisigHttp = repositoryFactory.createMultisigRepository();
multisigHttp.getMultisigAccountInfo(address).subscribe(
  (multisigInfo) => console.log(multisigInfo),
  (err) => console.error(err),
);
        // replace with node endpoint
        try (final RepositoryFactory repositoryFactory = new RepositoryFactoryVertxImpl(
            "NODE_URL")) {

            final MultisigRepository multisigRepository = repositoryFactory
                .createMultisigRepository();

            // replace with multisig address
            final String rawAddress = "TAEG6L-KWXRA7-PSWUEE-ILQPG4-3V5CYZ-S5652T-JTUU";
            final Address address = Address.createFromRawAddress(rawAddress);

            final MultisigAccountInfo multisigAccountInfo = multisigRepository
                .getMultisigAccountInfo(address).toFuture().get();

            final JsonHelper helper = new JsonHelperJackson2();
            System.out.println(helper.prettyPrint(multisigAccountInfo));

次のガイド に従って、要求される署名数を変更します。