Crear una cuenta de multisig de varios niveles

Esta guía te mostrará cómo conectar múltiples cuentas de multisig para lograr una lógica de autorización avanzada en la cadena.

Caso de uso

Las cuentas de multisig pueden tener como cosignatarios otras cuentas de multisig y agregar lógica “Y/O�?a transacciones de firma múltiple.

En esta guía, vamos a crear una cuenta de multisig de 3 niveles compleja.

../../_images/mlma-complex-1.png

Ejemplo de cuenta de multisig de 3 niveles

Por ejemplo, si la cuenta #5 inicia una AggregateBondedTransaction que involucra a la cuenta #1, las cuentas #7 o #8 y #4 deben cosignar la transacción para que sea incluida en un bloque.

../../_images/mlma-complex-2.png

Enviando una AggregateBondedTransaction desde un MLMA

Prerrequisitos

Método #1: Usando el SDK

  1. Define la cuenta de multisig #2.

// replace with network type
const networkType = NetworkType.TEST_NET;
// replace with private key
const multisig2PrivateKey =
  'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF';
const multisigAccount2 = Account.createFromPrivateKey(
  multisig2PrivateKey,
  networkType,
);
// replace with public key
const cosignatoryAccount5PublicKey =
  '17E42BDF5B7FF5001DC96A262A1141FFBE3F09A3A45DE7C095AAEA14F45C0DA0';
const cosignatory5 = PublicAccount.createFromPublicKey(
  cosignatoryAccount5PublicKey,
  networkType,
);
// replace with public key
const cosignatoryAccount6PublicKey =
  'D04AB232742BB4AB3A1368BD4615E4E6D0224AB71A016BAF8520A332C9778737';
const cosignatory6 = PublicAccount.createFromPublicKey(
  cosignatoryAccount6PublicKey,
  networkType,
);

const convertMultisigAccount2Transaction = MultisigAccountModificationTransaction.create(
  Deadline.create(epochAdjustment),
  1,
  1,
  [cosignatory5.address, cosignatory6.address],
  [],
  networkType,
);
// replace with network type
const networkType = bitxor_sdk_1.NetworkType.TEST_NET;
// replace with private key
const multisig2PrivateKey =
    'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF';
const multisigAccount2 = bitxor_sdk_1.Account.createFromPrivateKey(
    multisig2PrivateKey,
    networkType,
);
// replace with public key
const cosignatoryAccount5PublicKey =
    '17E42BDF5B7FF5001DC96A262A1141FFBE3F09A3A45DE7C095AAEA14F45C0DA0';
const cosignatory5 = bitxor_sdk_1.PublicAccount.createFromPublicKey(
    cosignatoryAccount5PublicKey,
    networkType,
);
// replace with public key
const cosignatoryAccount6PublicKey =
    'D04AB232742BB4AB3A1368BD4615E4E6D0224AB71A016BAF8520A332C9778737';
const cosignatory6 = bitxor_sdk_1.PublicAccount.createFromPublicKey(
    cosignatoryAccount6PublicKey,
    networkType,
);
const convertMultisigAccount2Transaction = bitxor_sdk_1.MultisigAccountModificationTransaction.create(
    bitxor_sdk_1.Deadline.create(epochAdjustment),
    1,
    1, [cosignatory5.address, cosignatory6.address], [],
    networkType,
);
  1. Define la cuenta de multisig #3.

// replace with private key
const multisig3PrivateKey =
  '1111111111111111111111111111111111111111111111111111111111111111';
const multisigAccount3 = Account.createFromPrivateKey(
  multisig3PrivateKey,
  networkType,
);
// replace with public key
const cosignatoryAccount7PublicKey =
  '38C22255DE39952C5D18803EC305A888D5DDE2C59BF3D4EFFAE6FC5FFCBF4F5D';
const cosignatory7 = PublicAccount.createFromPublicKey(
  cosignatoryAccount7PublicKey,
  networkType,
);
// replace with public key
const cosignatoryAccount8PublicKey =
  '9F784BF20318AE3CA6246C0EC2207FE095FFF7A84B6787E7E3C2CE4C3B92A2EA';
const cosignatory8 = PublicAccount.createFromPublicKey(
  cosignatoryAccount8PublicKey,
  networkType,
);
// replace with public key
const cosignatoryAccount4PublicKey =
  'EB2B065D27C6A6FB322F2E568E1AAD9CD6C0F155675E2837058D4811F5C0247D';
const cosignatory4 = PublicAccount.createFromPublicKey(
  cosignatoryAccount4PublicKey,
  networkType,
);

const convertMultisigAccount3Transaction = MultisigAccountModificationTransaction.create(
  Deadline.create(epochAdjustment),
  2,
  1,
  [cosignatory7.address, cosignatory8.address, cosignatory4.address],
  [],
  networkType,
);
// replace with private key
const multisig3PrivateKey =
    '1111111111111111111111111111111111111111111111111111111111111111';
const multisigAccount3 = bitxor_sdk_1.Account.createFromPrivateKey(
    multisig3PrivateKey,
    networkType,
);
// replace with public key
const cosignatoryAccount7PublicKey =
    '38C22255DE39952C5D18803EC305A888D5DDE2C59BF3D4EFFAE6FC5FFCBF4F5D';
const cosignatory7 = bitxor_sdk_1.PublicAccount.createFromPublicKey(
    cosignatoryAccount7PublicKey,
    networkType,
);
// replace with public key
const cosignatoryAccount8PublicKey =
    '9F784BF20318AE3CA6246C0EC2207FE095FFF7A84B6787E7E3C2CE4C3B92A2EA';
const cosignatory8 = bitxor_sdk_1.PublicAccount.createFromPublicKey(
    cosignatoryAccount8PublicKey,
    networkType,
);
// replace with public key
const cosignatoryAccount4PublicKey =
    'EB2B065D27C6A6FB322F2E568E1AAD9CD6C0F155675E2837058D4811F5C0247D';
const cosignatory4 = bitxor_sdk_1.PublicAccount.createFromPublicKey(
    cosignatoryAccount4PublicKey,
    networkType,
);
const convertMultisigAccount3Transaction = bitxor_sdk_1.MultisigAccountModificationTransaction.create(
    bitxor_sdk_1.Deadline.create(epochAdjustment),
    2,
    1, [cosignatory7.address, cosignatory8.address, cosignatory4.address], [],
    networkType,
);
  1. Define la cuenta de multisig #1.

// replace with private key
const multisig1PrivateKey =
  '0000000000000000000000000000000000000000000000000000000000000000';
const multisigAccount1 = Account.createFromPrivateKey(
  multisig1PrivateKey,
  networkType,
);

const convertMultisigAccount1Transaction = MultisigAccountModificationTransaction.create(
  Deadline.create(epochAdjustment),
  3,
  1,
  [
    multisigAccount2.publicAccount.address,
    multisigAccount3.publicAccount.address,
    cosignatory4.address,
  ],
  [],
  networkType,
);
// replace with private key
const multisig1PrivateKey =
    '0000000000000000000000000000000000000000000000000000000000000000';
const multisigAccount1 = bitxor_sdk_1.Account.createFromPrivateKey(
    multisig1PrivateKey,
    networkType,
);
const convertMultisigAccount1Transaction = bitxor_sdk_1.MultisigAccountModificationTransaction.create(
    bitxor_sdk_1.Deadline.create(epochAdjustment),
    3,
    1, [
        multisigAccount2.publicAccount.address,
        multisigAccount3.publicAccount.address,
        cosignatory4.address,
    ], [],
    networkType,
);

4. Anuncia las transacciones juntas usando una AggregateBondedTransaction. La cuenta #1 debe bloquear 10 bitxor para anunciar la transacción.

const aggregateTransaction = AggregateTransaction.createBonded(
  Deadline.create(epochAdjustment),
  [
    convertMultisigAccount2Transaction.toAggregate(
      multisigAccount2.publicAccount,
    ),
    convertMultisigAccount3Transaction.toAggregate(
      multisigAccount3.publicAccount,
    ),
    convertMultisigAccount1Transaction.toAggregate(
      multisigAccount1.publicAccount,
    ),
  ],
  networkType,
  [],
  UInt64.fromUint(2000000),
);

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

// replace with bitxor id
const networkCurrencyTokenId = new TokenId('5E62990DCAC5BE8A');
// replace with network currency divisibility
const networkCurrencyDivisibility = 6;

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

const signedHashLockTransaction = multisigAccount1.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(),
    );
});
const aggregateTransaction = bitxor_sdk_1.AggregateTransaction.createBonded(
    bitxor_sdk_1.Deadline.create(epochAdjustment), [
        convertMultisigAccount2Transaction.toAggregate(
            multisigAccount2.publicAccount,
        ),
        convertMultisigAccount3Transaction.toAggregate(
            multisigAccount3.publicAccount,
        ),
        convertMultisigAccount1Transaction.toAggregate(
            multisigAccount1.publicAccount,
        ),
    ],
    networkType, [],
    bitxor_sdk_1.UInt64.fromUint(2000000),
);
// replace with meta.networkGenerationHash (nodeUrl + '/node/info')
const networkGenerationHash =
    '1DFB2FAA9E7F054168B0C5FCB84F4DEB62CC2B4D317D861F3168D161F54EA78B';
const signedTransaction = multisigAccount1.sign(
    aggregateTransaction,
    networkGenerationHash,
);
console.log(signedTransaction.hash);
// replace with bitxor id
const networkCurrencyTokenId = new bitxor_sdk_1.TokenId('5E62990DCAC5BE8A');
// replace with network currency divisibility
const networkCurrencyDivisibility = 6;
const hashLockTransaction = bitxor_sdk_1.HashLockTransaction.create(
    bitxor_sdk_1.Deadline.create(epochAdjustment),
    new bitxor_sdk_1.Token(
        networkCurrencyTokenId,
        bitxor_sdk_1.UInt64.fromUint(
            10 * Math.pow(10, networkCurrencyDivisibility),
        ),
    ),
    bitxor_sdk_1.UInt64.fromUint(480),
    signedTransaction,
    networkType,
    bitxor_sdk_1.UInt64.fromUint(2000000),
);
const signedHashLockTransaction = multisigAccount1.sign(
    hashLockTransaction,
    networkGenerationHash,
);
// replace with node endpoint
const nodeUrl = 'NODE_URL';
const repositoryFactory = new bitxor_sdk_1.RepositoryFactoryHttp(nodeUrl);
const listener = repositoryFactory.createListener();
const receiptHttp = repositoryFactory.createReceiptRepository();
const transactionHttp = repositoryFactory.createTransactionRepository();
const transactionService = new bitxor_sdk_1.TransactionService(
    transactionHttp,
    receiptHttp,
);
listener.open().then(() => {
    transactionService
        .announceHashLockAggregateBonded(
            signedHashLockTransaction,
            signedTransaction,
            listener,
        )
        .subscribe(
            (x) => console.log(x),
            (err) => console.log(err),
            () => listener.close(),
        );
});

5. Los posibles cosignatarios deben optar por ser cosignatarios. Firma la AggregateTransaction anunciada con las cuentas #5, #6, #7, #8 y #4.

bitxor-cli transaction cosign --hash A6A374E66B32A3D5133018EFA9CD6E3169C8EEA339F7CCBE29C47D07086E068C --profile <cuenta>