Socket
Book a DemoInstallSign in
Socket

@samouraiwallet/bip47

Package Overview
Dependencies
Maintainers
1
Versions
8
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@samouraiwallet/bip47

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

1.1.0
latest
Source
npmnpm
Version published
Maintainers
1
Created
Source

@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
  • API documentation
  • Usage

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://github.com/Dojo-Open-Source-Project/bip47/archive/refs/heads/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 PaymentCodePrivate 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 PaymentCodePublic 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;
}

Keywords

bitcoin

FAQs

Package last updated on 01 Jun 2025

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

About

Packages

Stay in touch

Get open source security insights delivered straight into your inbox.

  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc

U.S. Patent No. 12,346,443 & 12,314,394. Other pending.