Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@samouraiwallet/bip47

Package Overview
Dependencies
Maintainers
1
Versions
7
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.0.0
  • latest
  • npm
  • Socket score

Version published
Weekly downloads
49
increased by44.12%
Maintainers
1
Weekly downloads
 
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://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;
}

Keywords

FAQs

Package last updated on 20 Apr 2024

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

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc