Posts in "Node JS"

Understanding and Generating Bitcoin Addresses in Node.js (2023)

In this piece, I’m sharing what I learned while making a multi-chain Cryptocurrency wallet from scratch recently. Since the world of cryptocurrency was new to me, I faced some challenges. I hope my experience makes things easier for you.

Generating a Bitcoin address can be confusing, especially with the variety of address types and the sometimes outdated or contradictory information available. In this guide, I’ll clarify the different types of Bitcoin addresses, which one you should follow, and demonstrate how to create a BTC address using Node.js.

We will concentrate on generating a BTC address offline, instead of utilizing Bitcoin Core. This is needed for creating a self-managed Bitcoin wallet, where you retain complete control over your private keys.

Different address types

First of all, let me explain the different kinds of Bitcoin addresses and their significance before we get into generating them. I am going to list the few main types of BTC addresses, not including the obsolete ones, ones with low adoption or being phased out, along with a sample of each on different networks.

Bitcoin addresses have different starting letters depending on if they’re for “mainnet”, “testnet”, or “regtest” networks due to the use of different network identifiers as a safety measure. This helps prevent mistakes, like using real Bitcoin addresses for testing, or vice versa, which could result in losing money.

P2PKH (Pay-to-Public-Key-Hash) Addresses:

This is the original Bitcoin address format, also called the legacy addresses. They start with the number ‘1’ on mainnet and with ‘m’ or ‘n’ on testnet or regtest network. P2PKH addresses do not support SegWit (what is Segwit?), which means slightly higher transaction fees as compared to the newer address types. While these addresses hold the most amount of BTC today, their adoption is decreasing.

Address Examples:
mainnet: 1FfmbHfnpaZjKFvyi1okTjJJusN455paPH
regtest: msiGFK1PjCk8E6FXeoGkQPTscmcpyBdkgS
testnet: mucFNhKMYoBQYUAEsrFVscQ1YaFQPekBpg

P2SH (Pay-to-Script-Hash) Addresses:

Introduced to simplify the use of complex scripts and to provide a layer of abstraction. They start with the number ‘3’ on mainnet and ‘2’ on testnet/regtest networks. P2SH addresses are commonly used for multisig wallets and were the first step toward the adoption of SegWit. Their adoption is also decreasing as they are replaced by newer types.

Address Examples:
mainnet: 3J98t1WpEZ73CNmQviecrnyiWrnqRhWNLy
regtest: 2NEb8N5B9jhPUCBchz16BB7bkJk8VCZQjf3
testnet: 2NFUBBRcTJbYc1D4HSCbJhKZp6YCV4PQFpQ

P2TR address (Taproot):

A pay-to-taproot (P2TR), also known as a Taproot or Bech32m address, is the most recent and advanced Bitcoin address format. Taproot introduces more advanced security, privacy, flexibility, and scaling to bitcoin. Like SegWit, Taproot addresses are opt-in currently but have very low adoption compared to SegWit. Taproot adoption can be tracked here.

Taproot addresses start with bc1p on mainnet, ‘bcrt’ on regtest and tb1 on testnet and are case-sensitive.

Address Examples:
mainnet: bc1p5d7rjq7g6rdk2yhzks9smlaqtedr4dekq08ge8ztwac72sfr9rusxg3297
regtest: bcrt1pema6mzjsr3849rg5e5ls9lfck46zc3muph65rmskt28ravzzzxwsz99c2q
testnet: tb1pzpelffrdh9ptpaqnurwx30dlewqv57rcxfeetp86hsssk30p4cws38tr9y

P2WPKH – Bech32 Addresses (SegWit):

This is considered the go-to format as of writing this article with their adoption increasing, introduced with Segregated Witness (SegWit) to address some deficiencies in the earlier address formats. They start with bc1q for mainnet, tb1 for testnet and ‘bcrt’ for regtest.

Bech32 addresses are lower-case only, which helps avoid errors caused by case insensitivity. They also allow for more efficient block space usage, leading to lower transaction fees.

You will see this address format in most wallets in the market today, including Trust Wallet and Exodus. The official Bitcoin core client has it as the default address type as well.

Address Examples:
mainnet: bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq
regtest: bcrt1q39c0vrwpgfjkhasu5mfke9wnym45nydfwaeems
testnet: tb1qxhkl607frtvjsy9nlyeg03lf6fsq947pl2pe82

There are a few more types of addresses not mentioned above as they are either phased out, being phased out, or, have a low adoption rate. For this article, I will focus on generating the P2WPKH Bech32 Addresses (SegWit) address as that’s the most popular standard today with an increasing adoption rate. You can learn more about each type of address here, including the adoption rate for each.

Generating the addresses

So with that out of the way, let’s generate our address, we will be generating a random address.

Start by installing the following NPM packages:

npm install bitcoinjs-lib tiny-secp256k1 ecpair

Next up, in your JS file, import these libraries and initialize ECPair:

const bitcoin = require("bitcoinjs-lib");
const ecc = require("tiny-secp256k1");
const { ECPairFactory } = require("ecpair");

const ECPair = ECPairFactory(ecc);

next, you have to define the network you want to generate the address for:

// for mainnet  
const network = bitcoin.networks.bitcoin;
// for testnet
const network = bitcoin.networks.testnet;
// for regtest
const network = bitcoin.networks.regtest;

next, we generate a random key pair, this is a very important part, you can read more about the importance of randomness here

const keyPair = ECPair.makeRandom();

The next part is the actual address generation, here’s how to generate a Bech32 (SegWit) address:

const p2wpkh = bitcoin.payments.p2wpkh({
    pubkey: keyPair.publicKey,
    network,
});
console.log("Address: ", p2wpkh.address);

Here’s how to get your private key (handle with utmost care):

const privateKey = keyPair.toWIF();

Security Consideration

It’s crucial to emphasize the security risks associated with handling private keys. Always ensure they are stored and used in a secure environment to prevent unauthorized access.

That’s it, you have got your address. For those interested in delving deeper into Bitcoin development, consider exploring the official Bitcoin documentation and community forums for advanced discussions and tutorials.

I am hoping this article helps someone out there just starting with Bitcoin development. Watch this space for more articles like this one. I am also going to be writing an article on how to generate a Hierarchical Deterministic seed phrase (aka BIP39 seed phrase) and use it to generate addresses for different blockchains using that seed phrase as most multi-currency wallets in the market do, such as Trust Wallet and Exodus.