Agregar un nuevo firmante a una cuenta multisig

Esta guía te mostrará cómo agregar un nuevo cosignatario a una cuenta multisig.

Casos de uso

Imagine que Alice y Bob quieren agregar a Carol, un tercer participante, como cosignatario de una cuenta multisig 2-de-2. Sin embargo, no desean aumentar el número de firmas necesarias para aceptar transacciones, por lo que la nueva cuenta requerirá solo 2-de-3 firmas para transacciones.

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

Ejemplo de cuenta multisig 2-de-3

Prerrequisitos

Método #01: Usando la Billetera de Escritorio

  1. Inicia sesión en una cuenta que sea cosignatario de la cuenta multisig. Esto podría ser la cuenta de Alice o Bob.

  2. Haz clic en “Multisig” en el menú de la izquierda.

  3. Selecciona la billetera multisig que deseas modificar en el menú desplegable del campo superior. Esto convertirá el “Tipo de operación” a “Modificación de propiedades de cuenta multisig”.

  4. Haz clic en “Agregar un cosignatario” y proporciona la dirección o la clave pública de la cuenta que deseas agregar como nuevo firmante de la multisig. Haz clic en “Enviar”. Revisa la información en el cuadro emergente. Ingresa la contraseña de tu billetera y haz clic en “Confirmar”.

resources/images/screenshots/add-signer-1.gif
  1. Si la cuenta multisig tiene un “aprobación mínima” establecida en un número mayor que 1, inicia sesión en otra cuenta de cosignatario y firma la transacción. Repite este paso hasta que se cumpla el número mínimo de aprobaciones.

resources/images/screenshots/add-signer-2.gif
  1. Puedes verificar que el nuevo firmante se haya agregado navegando a la página “Multisig”. El nuevo firmante debería aparecer en la lista de “Cosignatarios”.

resources/images/screenshots/add-signer-3.png

Método #02: Usando el SDK

  1. Abre un archivo nuevo. Define las claves públicas de la cuenta multisig y la nueva cuenta que se agregará en nuevas variables.

// replace with network type
const networkType = NetworkType.TEST_NET;
// replace with multisig public key
const multisigAccountPublicKey =
  '3A537D5A1AF51158C42F80A199BB58351DBF3253C4A6A1B7BD1014682FB595EA';
const multisigAccount = PublicAccount.createFromPublicKey(
  multisigAccountPublicKey,
  networkType,
);
// replace with new cosignatory public key
const newCosignatoryPublicKey =
  '17E42BDF5B7FF5001DC96A262A1141FFBE3F09A3A45DE7C095AAEA14F45C0DA0';
const newCosignatoryAccount = PublicAccount.createFromPublicKey(
  newCosignatoryPublicKey,
  networkType,
);
// replace with network type
const networkType = bitxor_sdk_1.NetworkType.TEST_NET;
// replace with multisig public key
const multisigAccountPublicKey =
    '3A537D5A1AF51158C42F80A199BB58351DBF3253C4A6A1B7BD1014682FB595EA';
const multisigAccount = bitxor_sdk_1.PublicAccount.createFromPublicKey(
    multisigAccountPublicKey,
    networkType,
);
// replace with new cosignatory public key
const newCosignatoryPublicKey =
    '17E42BDF5B7FF5001DC96A262A1141FFBE3F09A3A45DE7C095AAEA14F45C0DA0';
const newCosignatoryAccount = bitxor_sdk_1.PublicAccount.createFromPublicKey(
    newCosignatoryPublicKey,
    networkType,
);
  1. Crea una Transacción de Modificación de Cuenta Multisig, agregando al nuevo participante como cosignatario.

Note

Siguiendo el ejemplo anterior, la cuenta multisig se convertirá en una 2-de-3, ya que estamos agregando un nuevo cosignatario pero no aumentando el valor de minApprovalDelta.

const multisigAccountModificationTransaction = MultisigAccountModificationTransaction.create(
  Deadline.create(epochAdjustment),
  0,
  0,
  [newCosignatoryAccount.address],
  [],
  networkType,
);
const multisigAccountModificationTransaction = bitxor_sdk_1.MultisigAccountModificationTransaction.create(
    bitxor_sdk_1.Deadline.create(epochAdjustment),
    0,
    0, [newCosignatoryAccount.address], [],
    networkType,
);
  1. Envuelve la Transacción de Modificación de Cuenta Multisig en una transacción agregada. Fírmala con un cosignatario de la cuenta multisig original.

const aggregateTransaction = AggregateTransaction.createBonded(
  Deadline.create(epochAdjustment),
  [multisigAccountModificationTransaction.toAggregate(multisigAccount)],
  networkType,
  [],
  UInt64.fromUint(2000000),
);

// replace with cosignatory private key
const cosignatoryPrivateKey =
  '1111111111111111111111111111111111111111111111111111111111111111';
const cosignatoryAccount = Account.createFromPrivateKey(
  cosignatoryPrivateKey,
  networkType,
);
// replace with meta.networkGenerationHash (nodeUrl + '/node/info')
const networkGenerationHash =
  '1DFB2FAA9E7F054168B0C5FCB84F4DEB62CC2B4D317D861F3168D161F54EA78B';
const signedTransaction = cosignatoryAccount.sign(
  aggregateTransaction,
  networkGenerationHash,
);
console.log(signedTransaction.hash);
const aggregateTransaction = bitxor_sdk_1.AggregateTransaction.createBonded(
    bitxor_sdk_1.Deadline.create(epochAdjustment), [multisigAccountModificationTransaction.toAggregate(multisigAccount)],
    networkType, [],
    bitxor_sdk_1.UInt64.fromUint(2000000),
);
// replace with cosignatory private key
const cosignatoryPrivateKey =
    '1111111111111111111111111111111111111111111111111111111111111111';
const cosignatoryAccount = bitxor_sdk_1.Account.createFromPrivateKey(
    cosignatoryPrivateKey,
    networkType,
);
// replace with meta.networkGenerationHash (nodeUrl + '/node/info')
const networkGenerationHash =
    '1DFB2FAA9E7F054168B0C5FCB84F4DEB62CC2B4D317D861F3168D161F54EA78B';
const signedTransaction = cosignatoryAccount.sign(
    aggregateTransaction,
    networkGenerationHash,
);
console.log(signedTransaction.hash);

4. Antes de enviar una Transacción Agregada con Vinculación de Hash (AggregateBondedTransaction), una cuenta debe bloquear al menos 10 bitxor. Esta transacción es necesaria para evitar el envío masivo de transacciones a la red. Después de que la Transacción de Bloqueo de Hash (HashLockTransaction) haya sido confirmada, anuncia la Transacción Agregada (AggregateTransaction).

// 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 = cosignatoryAccount.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 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 = cosignatoryAccount.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. La nueva cuenta debe optar primero para convertirse en cosignatario de la cuenta multisig. Firma el hash de la Transacción Agregada con la cuenta que se agregará a la multisig.

bitxor-cli transaction cosign --hash A6A374E66B32A3D5133018EFA9CD6E3169C8EEA339F7CCBE29C47D07086E068C --profile carol

6. Firma la Transacción Agregada con todos los demás participantes de la cuenta multisig necesarios para alcanzar el quórum. La cantidad de bitxor bloqueada vuelve a estar disponible en la cuenta que envió la Transacción de Bloqueo de Hash (HashLockTransaction), y el nuevo participante se agrega a la multisig.

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

Sigue la siguiente guía para eliminar un cosignatario de una cuenta multisig.