npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@samouraiwallet/bip47

v1.0.0

Published

A set of utilities for working with BIP47 and bitcoinjs-lib

Downloads

328

Readme

@samouraiwallet/bip47

A set of utilities for working with BIP47 and bitcoinjs-lib.

This library uses ES Modules. Node.js v16 or later is required. This library does not use any Node.js built-ins and thus is browser compatible.

Source code was written in Typescript. Type definitions are included in the published bundle.

Contents

Installation

npm install @samouraiwallet/bip47

or

pnpm add @samouraiwallet/bip47

or

yarn add @samouraiwallet/bip47

API documentation

Generated API documentation is available in the git repository. To view latest API docs locally, you can run these commands.

# create a temp folder
mkdir bip47-docs
cd bip47-docs

# download and extract docs directory
curl -fsSL https://code.samourai.io/dojo/bip47-js/-/archive/master/bip47-js-master.tar.gz\?path\=docs | tar -xzv --strip-components=2

# run simple HTTP file server
npx serve .

Usage

ECC library

You need to provide an implementation of secp256k1 elliptic curve.

Supported libraries:

  • tiny-secp256k1 - Rust implementation compiled to Webassembly, work in Node.js and browsers but might require reconfiguring your bundler
  • @bitcoinerlab/secp256k1 - Javascript implementation which works everywhere but has a lower performance

Examples

Create an instance of bip47

import BIP47Factory from "@samouraiwallet/bip47";
import * as ecc from "tiny-secp256k1";

const bip47 = BIP47Factory(ecc);

Create a PaymetCodePrivate instance from wallet master seed

on mainnet

import type {PaymentCodePrivate} from "@samouraiwallet/bip47";

let walletSeed: Uint8Array;

const alice: PaymentCodePrivate = bip47.fromSeed(walletSeed);

// with segwit support
const alice2: PaymentCodePrivate = bip47.fromSeed(walletSeed, true);

on testnet

import type {PaymentCodePrivate} from "@samouraiwallet/bip47";
import {networks} from "@samouraiwallet/bip47/utils";

let walletSeed: Uint8Array;

// pass in a desired network object (bitcoin | testnet | regtest) from utils or directly from bitcoinjs-lib
const alice: PaymentCodePrivate = bip47.fromSeed(walletSeed, false, networks['testnet']);
// with segwit support
const alice2: PaymentCodePrivate = bip47.fromSeed(walletSeed, true, networks['testnet']);

Create a PaymetCodePublic instance from payment code string

on mainnet

import type {PaymentCodePublic} from "@samouraiwallet/bip47";

const pcode = "PM8TJS2JxQ5ztXUpBBRnpTbcUXbUHy2T1abfrb3KkAAtMEGNbey4oumH7Hc578WgQJhPjBxteQ5GHHToTYHE3A1w6p7tU6KSoFmWBVbFGjKPisZDbP97";

const bob: PaymentCodePublic = bip47.fromBase58(pcode);

on testnet

import type {PaymentCodePublic} from "@samouraiwallet/bip47";
import {networks} from "@samouraiwallet/bip47/utils";

const pcode = "PM8TJS2JxQ5ztXUpBBRnpTbcUXbUHy2T1abfrb3KkAAtMEGNbey4oumH7Hc578WgQJhPjBxteQ5GHHToTYHE3A1w6p7tU6KSoFmWBVbFGjKPisZDbP97";

// pass in a desired network object (bitcoin | testnet | regtest) from utils or directly from bitcoinjs-lib
const bob: PaymentCodePublic = bip47.fromBase58(pcode, networks['testnet']);

Generate a base58 encoded payment code

const alicePcode: string = alice.toBase58(); // PM8TJTLJbPRGxSbc8EJi42Wrr6QbNSaSSVJ5Y3E4pbCYiTHUskHg13935Ubb7q8tx9GVbh2UuRnBc3WSyJHhUrw8KhprKnn9eDznYGieTzFcwQRya4GA

Get notification address

const aliceNotificationAddress: string = alice.getNotificationAddress(); // 1JDdmqFLhpzcUwPeinhJbUPw4Co3aWLyzW

Get notification address public key

const aliceNotifPubKey: Uint8Array = alice.getNotificationPublicKey(); // 0353883a146a23f988e0f381a9507cbdb3e3130cd81b3ce26daf2af088724ce683 

Get notification address private key

const aliceNotifPrivKey: Uint8Array = alice.getNotificationPrivateKey(); // 8d6a8ecd8ee5e0042ad0cb56e3a971c760b5145c3917a8e7beaf0ed92d7a520c 

Derive addresses from Alice to Bob

Alice's side

// Bob's P2PKH address at index 0
const bobAddress: string = bob.getPaymentAddress(alice, 0, 'p2pkh'); // 141fi7TY3h936vRUKh1qfUZr8rSBuYbVBK

// check if Bob's payment code supports receiving to segwit addresses
if (bob.segwit) {
    // Bob's P2WPKH address at index 1
    const bobSegwitAddress = bob.getPaymentAddress(alice, 1, 'p2wpkh'); // bc1qzn8a8drxv6ln7rztjsw660gzf3hnrfwupzmsfh
}

Bob's side

import type {PaymentCodePrivate, PaymentCodePublic} from "@samouraiwallet/bip47";

let bobSeed: Uint8Array;
let alicePcode: string; // base58 encoded payment code

const bob: PaymentCodePrivate = bip47.fromSeed(bobSeed);
const alice: PaymentCodePublic = bip47.fromBase58(alicePcode);

const bobAddress: string = bob.getPaymentAddress(alice, 0, 'p2pkh'); // 141fi7TY3h936vRUKh1qfUZr8rSBuYbVBK

Derive payment keys from Alice to Bob

Alice's side

// Bob's payment pubkey at index 0
const bobPubKey: Uint8Array = bob.derivePaymentPublicKey(alice, 0); // 0344b4795e48df097bd87e6cf87a70e4f0c30b2d847b6e34cddde64af10296952d

Bob's side

import type {PaymentCodePrivate, PaymentCodePublic} from "@samouraiwallet/bip47";

let bobSeed: Uint8Array;
let alicePcode: string; // base58 encoded payment code

const bob: PaymentCodePrivate = bip47.fromSeed(bobSeed);
const alice: PaymentCodePublic = bip47.fromBase58(alicePcode);

// Bob's payment keys at index 0
const bobPubKey: Uint8Array = bob.derivePaymentPublicKey(alice, 0);
const bobPrivKey: Uint8Array = bob.derivePaymentPrivateKey(alice, 0);

Extract payment code from notification transaction

import type {PaymentCodePrivate, PaymentCodePublic} from "@samouraiwallet/bip47";

let bobSeed: Uint8Array;
const bob: PaymentCodePrivate = bip47.fromSeed(bob.seed);

let scriptPubKey: Uint8Array; // scriptPubKey of notification transaction OP_RETURN output
let outpoint: Uint8Array; // outpoint of first input of notification transaction
let pubKey: Uint8Array; // public key of first input of notification transaction

const alice: PaymentCodePublic = bob.getPaymentCodeFromNotificationTransactionData(scriptPubKey, outpoint, pubKey);
const alicePcode: string = alice.toBase58(); // PM8TJTLJbPRGxSbc8EJi42Wrr6QbNSaSSVJ5Y3E4pbCYiTHUskHg13935Ubb7q8tx9GVbh2UuRnBc3WSyJHhUrw8KhprKnn9eDznYGieTzFcwQRya4GA

In order to extract payment code from a notification transaction, the scriptPubKey, outpoint and pubKey must be provided. You can use bitcoinjs-lib to extract these values from a transaction.

import * as bitcoin from 'bitcoinjs-lib';

let notificationTxHex: string;
    
const tx: bitcoin.Transaction = bitcoin.Transaction.fromHex(notificationTxHex);

const opReturnOutput = tx.outs.find((o) =>
    o.script[0] === 0x6a && o.script[1] === 0x4c && o.script[2] === 0x50
);

if (!opReturnOutput) throw new error("Transaction doesn't contain OP_RETURN output");

const scriptPubKey: Uint8Array = opReturnOutput.script;

const input = tx.ins[0];
const outpoint: Uint8Array = new Uint8Array(input.hash.length + 4);
outpoint.set(input.hash);
outpoint.set(new Uint32Array([input.index]), input.hash.length)

let pubKey: Uint8Array;

if (input.witness.length) {
    pubKey = input.witness[1];
} else if (bitcoin.script.toASM(input.script).split(' ').length === 2) {
    pubKey = Buffer.from(bitcoin.script.toASM(input.script).split(' ')[1], 'hex',);
} else throw new Error('Unknown Transaction type');

Get blinded payment code for notification transaction

let outpoint: Uint8Array; // outpoint of the first input of the notification transaction
let privKey: Uint8Array; // private key of a first input of the notification transaction

const blindedAlicePcode: string = alicePcode.getBlindedPaymentCode(bob, outpoint, privKey);

Interfaces

export declare const BIP47Factory: (ecc: TinySecp256k1Interface) => {
    fromSeed: (bSeed: Uint8Array, segwit?: boolean, network?: Network) => PaymentCodePrivate;
    fromBase58: (inString: string, network?: Network) => PaymentCodePublic;
    fromBuffer: (buf: Uint8Array, network?: Network) => PaymentCodePublic;
};

export declare class PaymentCodePublic {
    protected readonly ecc: TinySecp256k1Interface;
    protected readonly bip32: BIP32API;
    protected readonly buf: Uint8Array;
    protected readonly network: Network;
    root: BIP32Interface;
    hasPrivKeys: boolean;
    segwit: boolean;

    constructor(ecc: TinySecp256k1Interface, bip32: BIP32API, buf: Uint8Array, network?: Network);

    get features(): Uint8Array;

    get pubKey(): Uint8Array;

    get chainCode(): Uint8Array;

    get paymentCode(): Uint8Array;

    clone(): PaymentCodePublic;

    toBase58(): string;

    derive(index: number): BIP32Interface;

    getNotificationPublicKey(): Uint8Array;

    getNotificationAddress(): string;

    protected derivePublicKeyFromSharedSecret(B: Uint8Array, S: Uint8Array | null): Uint8Array;

    derivePaymentPublicKey(paymentCode: PaymentCodePrivate, idx: number): Uint8Array;

    protected getAddressFromPubkey(pubKey: Uint8Array, type: AddressType): string;

    getPaymentAddress(paymentCode: PaymentCodePrivate, idx: number, type?: AddressType): string;

    getBlindedPaymentCode(destinationPaymentCode: PaymentCodePublic, outpoint: Uint8Array, privateKey: Uint8Array): string;
}

export declare class PaymentCodePrivate extends PaymentCodePublic {
    constructor(root: BIP32Interface, ecc: TinySecp256k1Interface, bip32: BIP32API, buf: Uint8Array, network?: Network);

    toPaymentCodePublic(): PaymentCodePublic;

    clone(): PaymentCodePrivate;

    deriveHardened(index: number): BIP32Interface;

    derivePaymentPublicKey(paymentCode: PaymentCodePublic, idx: number): Uint8Array;

    getPaymentAddress(paymentCode: PaymentCodePublic, idx: number, type?: AddressType): string;

    derivePaymentPrivateKey(paymentCodePublic: PaymentCodePublic, idx: number): Uint8Array;

    getNotificationPrivateKey(): Uint8Array;

    getPaymentCodeFromNotificationTransactionData(scriptPubKey: Uint8Array, outpoint: Uint8Array, pubKey: Uint8Array): PaymentCodePublic;
}