I am trying to create a multisig wallet from two externally generated xpubs. The process I am taking is to create two multisig wallets with the two xpubs, add each others keys as shared keys and generating the multisigscript using keyrings. However, when I send testnet coins to the base58addr that I generate in the end, I do not see it coming to either of my wallets. Could someone kindly help me figure out where I am doing wrong? This is my code:

const wallet1_accountKey = "tpubDCe8iQEHFMvcm9WZsYZEd8h9dNvoDidS3y9EVkDzZZr59NcNF2n8ecfZWQkttDp6PWujaCUcXrptSoTKUuYjXp8fMKsz3wJvYpnpxsMQUbD"
const wallet2_accountKey = "tpubDDQHqrK6Xj7A9tfW2zkiZiBPs475QJ8EQ5obViboBxgA1BG5Ai1BnPqBWKTVf6ecEi8XoKK9WQP7GK5jYgdjaoegqBH1EvhVCx2PLc3Zgru"
const type='multisig'

const options_wallet1 = {

const options_wallet2 = {

const result1 = await walletClient.createWallet('wallet1', options_wallet1);
const result2 = await walletClient.createWallet('wallet2', options_wallet2);

const wallet1 = walletClient.wallet('wallet1');
const wallet2 = walletClient.wallet('wallet2');

const wallet1_account = await wallet1.getAccount('default');
const result3 = await wallet2.addSharedKey('default', wallet1_account.accountKey);

const wallet2_account = await wallet6.getAccount('default');
const result4 = await wallet1.addSharedKey('default', wallet2_account.accountKey);

const wallet1_address = await wallet1.createAddress('default');
const wallet2_address = await wallet2.createAddress('default');
const ring1 = KeyRing.fromJSON(wallet1_address);
const ring2 = KeyRing.fromJSON(wallet2_address);
const pubKeys = [ring1.publicKey, ring2.publicKey];

const multiSigScript = Script.fromMultisig(m, n, pubKeys);
const base58addr = multiSigScript.getAddress().toBase58('testnet');

1 Answer 1


There may be a few misunderstandings around BIP32/BIP44 key derivation and bcoin wallet usage in particular. I re-wrote your script below to demonstrate how to use bcoin multisig wallets and manually derive multisig P2SH addresses from keys. If you run it, you should see all three output addresses are identical.

Here are a few things you need to know for this script to work:

  1. To create a bcoin wallet from an xpub you must initialize the wallet as watch-only. Otherwise the account-key option is ignored, and a fresh master private key is generated for the wallet.
  2. The public keys used in multisig scripts must be derived from the xpub (see BIP32 and BIP44). In this case, you need to derive the branch key (0=receive, 1=change) and then from there derive the index key (0 in this case, incremented every time you need a new receive address)

Let me know if you have any other questions about bcoin!

'use strict';

const {WalletDB, HDPublicKey, Script} = require('bcoin');

const wdb = new WalletDB({
  network: 'testnet'

const key1 = 'tpubDCe8iQEHFMvcm9WZsYZEd8h9dNvoDidS3y9EVkDzZZr59NcNF2n8ec' +

const key2 = 'tpubDDQHqrK6Xj7A9tfW2zkiZiBPs475QJ8EQ5obViboBxgA1BG5Ai1BnP' +

(async() => {
  await wdb.open();

  // Create two watch-only multisig wallets
  const wallet1 = await wdb.create({
    m: 2,
    n: 2,
    watchOnly: true,
    accountKey: key1

  const wallet2 = await wdb.create({
    m: 2,
    n: 2,
    watchOnly: true,
    accountKey: key2

  // Add xpubs to each other's wallet's default account
  await wallet1.addSharedKey('default', key2);
  await wallet2.addSharedKey('default', key1);

  // Get receive address index=0 from each wallet
  const addr1 = await wallet1.receiveAddress();
  const addr2 = await wallet2.receiveAddress();

  // They will be the same

  // Now do it all manually...

  // Create HDPublicKey objects from xpubs
  const xpub1 = HDPublicKey.fromBase58(key1);
  const xpub2 = HDPublicKey.fromBase58(key2);

  // Derive public keys for each xpub (branch=0, index=0)
  const pubKey1 = xpub1.derive(0).derive(0);
  const pubKey2 = xpub2.derive(0).derive(0);

  // Construct multisig script with 2 pubkeys
  const script = Script.fromMultisig(
    [pubKey1.publicKey, pubKey2.publicKey]);

  // Create P2SH address from script
  const addr3 = script.getAddress().toString('testnet');

  // Will match the first two results

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.