How to Generate Multisig Bitcoin Addresses with the list of xpubs in PHP

By | May 18, 2020

Another script, that I had to create by myself, since I haven’t found a solution for such a simple task.

Let’s say you create a multisig Bitcoin wallet in Electrum. Let’s start with a basic version where you have 2 signatures out of 2 possible, so you need to have both to send funds. You follow this guide and make a new wallet. When you’re done, you should have a multisig wallet, that has some addresses inside.

If you want to generate your receive addressed without opening Electrum, you’ll have to get all xpubs of the wallet. Go to Wallet->Information in Electrum – you should see something like this:

You need to copy and paste all xpubs of all cosigners in order to be able to generate receive addresses. Now it’s time for my script. Note, that only xpub keys are supported (for legacy addresses, ypub and zpub will throw an exception).


<?php

use BitWasp\BitcoinLib\BIP32;
use BitWasp\BitcoinLib\RawTransaction;

require_once(__DIR__. '/vendor/autoload.php');

// Defining an array with extended public keys that will be used to make addresses
$xpubs[]="xpubnumber1";
$xpubs[]="xpubnumber2";

// Setting up the number of required signatures (M)
$required_sigs="2";

// And the number of all possible signatures (N)
$total_sigs="2";

// Defining how many addresses we want to make
$howmanyaddresses=20;

// Checking the number of xpubs - it must match the number in M / N scheme
if (count($xpubs)!=$total_sigs) die ("Wrong number of XPUBs");

// Verifying M is less than N (dumb check)
if ($required_sigs>$total_sigs) die ("Wrong M / N scheme");

// Converting XPUB array for use with BIP32
for($i=0; $i<count($xpubs); $i++)
{
$pub[$i][0]=$xpubs[$i];
$pub[$i][1]="";
}


// Main loop for the total number of addresses needed
for($i = 0; $i < $howmanyaddresses; $i++) {

	for ($j=0; $j<count($xpubs); $j++)
	{
	$bip32key[$j] = BIP32::build_key($pub[$j], "0/{$i}");
	// Getting Public Key from XPUB and deviation path
	$pubkey[$j] = BIP32::extract_public_key($bip32key[$j]);
	// Noticing the address that was used to create the multisig address
	$sourceaddress[$i][]=BIP32::key_to_address($bip32key[$j][0]);
	}

	// Sorting keys in right order
	$pubkey=RawTransaction::sort_multisig_keys($pubkey);

	// Making multisig address
	echo $i." ".RawTransaction::create_multisig($required_sigs, $pubkey)['address']." (made from public keys of ".implode(", ", $sourceaddress[$i]).")\r\n";

}

?>

I have included some more information in the output (addresses, which were used as public key donors) – you can remove it if you don’t need them. You will have to verify it the output of the script matches the output of your Electrum. If it does, you are welcome to use it to generate receive addresses outside Electrum.

Same solution is for other M / N schemes – you just need to paste all xpubs and define the number of signatures that are enough to sign a transaction.

Leave a Reply