Bitcoinjs-lib Generate Address

2 views
Skip to first unread message

William Dupere

unread,
Aug 5, 2024, 4:20:21 AM8/5/24
to wenregitan
Usersand developers in Bitcoin may find themselves needing more than one keypair address to develop and test code. In this guide, we'll talk about the different Bitcoin addresses available today, show you how to create a Bitcoin address using bitcoinjs-lib, and demonstrate the process of fetching a Bitcoin address's balance using QuickNode.

bitcoinjs-lib is a JavaScript library for interacting with the Bitcoin blockchain via Node.js and your browser. The library provides a wide variety of features like creating Bitcoin wallets (i.e., addresses) and multisigs, as well as creating, fetching, and broadcasting transactions.


If you came across the bitcoinjs-lib docs, you'll notice a list of different address types like SegWit address, SegWit P2SH address, SegWit P2PKH, SegWit 3-of-4 multisig address, and more. These are all custodial wallets (i.e., the user custodies the asset with a private key, not a 3rd party like a centralized exchange), which you can create with this library. Now, let's cover each:


You're welcome to use public nodes or deploy and manage your own infrastructure; however, if you'd like 8x faster response times, you can leave the heavy lifting to us. Sign up for a free account here. Once logged in, click the Create endpoint button, then select the blockchain and network you want to deploy on. For the purpose of this guide, we'll choose the Bitcoin Testnet blockchain. After creating your endpoint, keep the HTTP Provider URL handy, as we'll need it in the programming portion of this guide.


First off, we start by importing the required libraries, bitcoinjs-lib for configuring networks and ecpair + tiny-secp256k1 to assist with keypair creation. We also import fs to access to our file system with read/write privledges. Next, we declare an instance of ECPair to help assist with keypair creation and define a network constant to toggle which network we'll configure our address for. Later, we define a createP2PKHwallet async function, which will try to do the following:


You should see your newly created address printed in the terminal window as well as saved in a wallet.json file. Remember that these keys should not be shared and are recommended to be used during testing (not production). In the next section, we'll use our QuickNode Bitcoin node endpoint to fetch the balance of our newly created address.


Now that we have a newly created Bitcoin address, we can read from the Bitcoin blockchain to fetch details like our balance. Currently, the Bitcoin JSON-RPC client does not make it easy to fetch data like balances so we'll use a handy tool like the Blockbook add-on from the QuickNode Marketplace. The Blockbook add-on provides access to balances, transactions, and UTXOs for addresses or xpubs via JSON-RPC. You can check out the full list of support methods and pricing here.


To learn how to use the add-on, check out the full guide here: How to Build a Real-Time Bitcoin Wallet Analytics App. If you followed along with the guide, you should be able to see the balance and transaction history for an address as well as chart visualizations.


In fact every derived address is possibly also a new chain (derive() returns a new HDNode). Also your hdNode is intended to be used only for address derivation yet it has own address too (the one you have sent your funds too), just because there are no separate datatypes for addresses and for chains. To access that funds just generate private key without derivation:


On the other hand if you use Electrum instead of Core you may just extract the main key of one of address chains of an Electrum wallet (it does not work the opposite way as Electrum uses checksum for wallet seed and you cannot just import non-electrum chain). This way you will be able to independently generate new addresses (also just new addresses without privKeys, for security reasons) which would be recognized by the wallet without importing them explicitly.


Taproot introduces Taptrees, a feature that reduces the size of transaction data and ensures only necessary information is revealed on the blockchain, thereby preserving privacy. With Taproot, multisig transactions are also more private as unused spending conditions are hidden.


We'll go over two examples. In our first example, we will create a pay-to-taproot(p2tr) address that will lock funds to a key and create a spend transaction for it. In our second example, we will jump straight into taproot script-spend transactions, we will create a Taptree consisting of two script-spend paths, a hash-lock script spend path and a pay-to-pubkey script spend path. We will create transactions that spend from both paths.


To spend on any of the leaf scripts, you must present the leafVersion, script and controlBlock for that leaf script. The control block is data required to prove that the leaf script exists in the script tree(merkle proof).


To spend using the hash-lock leaf script, we have to create a custom finalizer function. In our custom finalizer, we will create our witness stack of signature, preimage, original hash-lock script and our control block




By reading this article, you should now have a better understanding of how to use bitcoinjs-lib to create and spend P2TR (Pay to Taproot) payments. With this knowledge, you are one step closer to leveraging the benefits of Taproot in your Bitcoin transactions, such as improved privacy, scalability, and the ability to create more complex smart contracts.

You can find more examples in bitcoinjs-lib's repo. The full code for this article can be found on github at taproot-with-bitcoinjs.

If you need some help understanding taproot, you can check this out More on Taproot.


Hi, i'm trying to use the examples below to replicate an ordinals transfer, paid for by another wallet. May i ask how we would extend these examples for taproot transfer from one wallet to another but payment transfer done from one P2SH wallet to another?


I can now do a transfer but i feel that my base understanding of taproot is not quite there. Are you planning to write more articles on deep diving into taproot or have suggestions on reading sources?


If you're not familiar with Bitcoin, Bitcoin is essentially a P2P currency that has increased an order of magnitude in value within the last year. This video does a good job of explaining it. There are a number of libraries to work with Bitcoin in some of the most popular languages: C, Java, C#, Ruby, Python, Go, and JavaScript. This article will focus exclusively on the JavaScript library.


I'd be remiss if I didn't mention anything about random number generation. Random number generation is the basis of most cryptography and Bitcoin. Your Bitcoin addresses are only as secure as your random number generator. A random number generator that is said to be cryptographically secure if it is good enough to use for cryptography in that there is enough entropy for a person to predict the number generator. Math.random() is not cryptographically secure. This is because Math.random() is predictable. If it's predictable, an attacker could figure out your private key from your public key. The implications of someone else knowing your private key means that they can also spend your Bitcoins.


At the time of this writing, the predominant JavaScript Bitcoin library uses CryptoJS which surprisingly uses Math.random(). This article shows how you can use the up and coming window.crytpo standard or the Stanford JavaScript Crypto Library


You're going to want to use the latest BitcoinJS client lib. It's pretty outdated though. There are some more recent forks: 1, 2, and the one that I will eventually maintain. For now, use the outdated one, from BitcoinJS.


Bitcoin derives its security from the public-key crypto scheme Elliptic Curve Cryptography (ECC). So why did the designer of Bitcoin, Satoshi Nakamoto, decide to use ECC over the prevalent RSA crypto scheme? The primary benefit is the key size. According to the Wikipedia article on ECC, "a 256-bit ECC public key should provide comparable security to a 3072-bit RSA public key".


You'll notice that we generate 32 random values. And n does not have a maximum of $ 2^256 - 1 $, so it's theoretically possible to generate a key larger than the standard dictates. However, in practice, you really don't have to worry about it.


simple enough, huh? But wait, this doesn't look like the private keys that you see in your Bitcoin clients. So, what's going on? Private keys typically use a format called the Wallet Import Format (WIF).


A compressed key is just a way of storing a public key in fewer bytes (33 instead of 65). There are no compatibility or security issues because they are precisely the same keys, just stored in a different way. The original Bitcoin software didn't use compressed keys only because their use was poorly documented in OpenSSL. They have no disadvantages other than that a little bit of additional computation is needed before they can be used to validate a signature.


If you think of a public key as a point somewhere along a giant U, an uncompressed key is the X and Y coordinates of the point. A compressed key is how high up on the U the point is along with a single bit indicating whether it's on the left or right side. As you can visualize, they both encode precisely the same thing, but the compressed form requires half as much space plus one bit. (Of course, they're really points on elliptic curve secp256k1, but the concept is the same.)


You may have noticed that when you toggle back and forth between Compressed and Uncompressed on that the Private Key changes as well. So, if you import a private key into your wallet, which public key will it use? Another good answer on Bitcoin Stack Exchange on how to deal with this:


...Thus, in order to support both, we must remember for each public/private keypair whether the normal or compressed encoding is to be used. As you point out, we also need this information when importing a private key. To do so, the "Wallet Import Format" for private keys (the base58 form, typically starting with a '5'), was extended. If the public key/address for a particular private key are to be derived from the compressed encoding of the public key, the private key gets an extra 0x01 byte at the end, resulting in a base58 form that starts with 'K' or 'L'.

3a8082e126
Reply all
Reply to author
Forward
0 new messages