Removing a signer from a multisig account

This guide will show you how to remove a cosignatory from a multisig account.

Prerequisites

Method #01: Using the Desktop Wallet

  1. Log in to one of the cosignatory accounts of the multisig account.

  2. Click on “Multisig” on the left-side menu.

  3. Select the multisig account in the dropdown menu.

  4. Find the cosignatory address that you want to remove in the cosignatories listed. Click the trash icon - this should highlight the account you want to remove. Then click “Send”. Review the information in the popup and enter your wallet password. Finally, click “Confirm”.

../../_images/remove-signer-1.gif
  1. If the multisig account has the “minimum approval” set to a number greater than 1, log in to another cosignatory account and cosign the transaction. Repeat this step until the minimum approval number is satisfied.

../../_images/add-signer-2.gif
  1. You can check that the signer has been removed by going back to the “multisig” page.

../../_images/remove-signer-screenshot.png

Method #02: Using the SDK

The following code shows how to remove a cosignatory from a 2-of-3 multisig account with minRemoval set to 1.

// 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 cosignatory public key
const cosignatoryToRemovePublicKey =
  '17E42BDF5B7FF5001DC96A262A1141FFBE3F09A3A45DE7C095AAEA14F45C0DA0';
const cosignatoryToRemove = PublicAccount.createFromPublicKey(
  cosignatoryToRemovePublicKey,
  networkType,
);
// replace with cosignatory private key
const cosignatoryPrivateKey =
  '1111111111111111111111111111111111111111111111111111111111111111';
const cosignatoryAccount = Account.createFromPrivateKey(
  cosignatoryPrivateKey,
  networkType,
);

const multisigAccountModificationTransaction = MultisigAccountModificationTransaction.create(
  Deadline.create(epochAdjustment),
  0,
  0,
  [],
  [cosignatoryToRemove.address],
  networkType,
);

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

// replace with meta.networkGenerationHash (nodeUrl + '/node/info')
const networkGenerationHash =
  '1DFB2FAA9E7F054168B0C5FCB84F4DEB62CC2B4D317D861F3168D161F54EA78B';
const signedTransaction = cosignatoryAccount.sign(
  aggregateTransaction,
  networkGenerationHash,
);
// replace with node endpoint
const nodeUrl = 'NODE_URL';
const repositoryFactory = new RepositoryFactoryHttp(nodeUrl);
const transactionHttp = repositoryFactory.createTransactionRepository();

transactionHttp.announce(signedTransaction).subscribe(
  (x) => console.log(x),
  (err) => console.error(err),
);
// replace with network type
const networkType = symbol_sdk_1.NetworkType.TEST_NET;
// replace with multisig public key
const multisigAccountPublicKey =
  '3A537D5A1AF51158C42F80A199BB58351DBF3253C4A6A1B7BD1014682FB595EA';
const multisigAccount = symbol_sdk_1.PublicAccount.createFromPublicKey(
  multisigAccountPublicKey,
  networkType,
);
// replace with cosignatory public key
const cosignatoryToRemovePublicKey =
  '17E42BDF5B7FF5001DC96A262A1141FFBE3F09A3A45DE7C095AAEA14F45C0DA0';
const cosignatoryToRemove = symbol_sdk_1.PublicAccount.createFromPublicKey(
  cosignatoryToRemovePublicKey,
  networkType,
);
// replace with cosignatory private key
const cosignatoryPrivateKey =
  '1111111111111111111111111111111111111111111111111111111111111111';
const cosignatoryAccount = symbol_sdk_1.Account.createFromPrivateKey(
  cosignatoryPrivateKey,
  networkType,
);
const multisigAccountModificationTransaction = symbol_sdk_1.MultisigAccountModificationTransaction.create(
  symbol_sdk_1.Deadline.create(epochAdjustment),
  0,
  0,
  [],
  [cosignatoryToRemove.address],
  networkType,
);
const aggregateTransaction = symbol_sdk_1.AggregateTransaction.createComplete(
  symbol_sdk_1.Deadline.create(epochAdjustment),
  [multisigAccountModificationTransaction.toAggregate(multisigAccount)],
  networkType,
  [],
  symbol_sdk_1.UInt64.fromUint(2000000),
);
// replace with meta.networkGenerationHash (nodeUrl + '/node/info')
const networkGenerationHash =
  '1DFB2FAA9E7F054168B0C5FCB84F4DEB62CC2B4D317D861F3168D161F54EA78B';
const signedTransaction = cosignatoryAccount.sign(
  aggregateTransaction,
  networkGenerationHash,
);
// replace with node endpoint
const nodeUrl = 'NODE_URL';
const repositoryFactory = new symbol_sdk_1.RepositoryFactoryHttp(nodeUrl);
const transactionHttp = repositoryFactory.createTransactionRepository();
transactionHttp.announce(signedTransaction).subscribe(
  (x) => console.log(x),
  (err) => console.error(err),
);

The minRemoval property indicates the number of required signatures to delete an account from the multisig. This value can be increased or decreased in the same way as the minApproval property is modified.

This time, the MultisigModificationTransaction is wrapped in an AggregateCompleteTransaction because just one account is required to delete others from the multisig.

Note

If more than one cosignature is required to announce the transaction (e.g., minRemoval is set to 2), the transaction must be defined as aggregate bonded, and all other required multisig participants should cosign it in order to be confirmed. Follow the next guide to announce aggregate bonded transactions involving a multisig account.

Follow the next guide to create a multi-level multisig account.