A lightweight JavaScript/TypeScript SDK for integrating dApps with the BitMask browser extension, a Bitcoin-only wallet supporting Layer 1, Lightning Network, and RGB smart contracts. Facilitating wallet operations like authentication, asset management, and swaps for RGB20, RGB21, and BTC. Running RGB 0.11.1
bitmask-connect enables decentralized applications (dApps) to communicate with the BitMask browser extension. It provides a Promise-based API for wallet operations like authentication, asset management, UDA(RGB21) issuing, and swaps. Designed for simplicity, it supports TypeScript, handles extension quirks (e.g., dual id/dateId, transfer call), and includes a LaserEyes adapter for multi-wallet integration.
- Website: BitMask Wallet
- Topics: bitcoin, wallet, sdk, browser-extension, typescript, rgb-protocol, lightning-network, dapp-integration
- License: MIT
- 1:1 API mapping to BitMask extension’s content-script calls.
- Promise-based responses with configurable timeouts (default 30s).
- ID routing via
returnidfor reliable request-response matching. - TypeScript support with optional
bitmask-coretype imports. - Compatibility with extension quirks (e.g.,
transfer, dualid/dateId). - LaserEyes integration for multi-wallet dApp support.
###🔑 API Overview
| Method | Description |
|---|---|
get_vault |
Triggers auth/connect; returns wallet_id. |
get_pubkeyhash |
Returns { pubkeyHash, network }. |
get_address |
Returns current address if logged in. |
is_funded |
Checks funding status (requires pubkeyHash). |
get_username |
Resolves wallet username. |
issue_uda |
Issues a user-defined asset. |
issue_asset |
Issues an asset (same response shape as UDA). |
bulk_issue_uda |
Issue multiple UDAs at once. |
get_invoice |
Returns invoice for a UDA. |
swap_offer |
Creates a swap offer. |
cancel_swap_offer |
Cancels an active offer. |
swap_bid |
Places a bid (requires bidData, contract). |
cancel_swap_bid |
Cancels a bid. |
pass_asset |
Adds an asset locally (expects UDA JSON). |
transfer |
Transfers an asset (expects UDA JSON). |
get_assets |
Fetches all wallet assets. |
send_notification |
Fire-and-forget page notification. |
yarn add bitmask-connect
# or
npm i bitmask-connectimport { BitmaskConnect } from "bitmask-connect";
const bm = new BitmaskConnect();
// Optional: check the bridge quickly
const available = await bm.detect();
if (!available) {
console.warn("Bitmask extension not detected");
}
// Get pubkeyHash / network
const pub = await bm.getPubKeyHash();
// Fetch assets
const assets = await bm.getAssets();
// Issue UDA
await bm.issueUDA({
pubkeyHash: (pub as any).pubkeyHash,
uda: { name: "My Asset" } as any,
});All methods return a Promise<...> that resolves to the raw payload posted by the content-script for the matching returnid.
Most methods accept optional { title?, description?, pubkeyHash?, uid? } metadata where applicable.
const bm = new BitmaskConnect({ timeoutMs?: number, targetOrigin?: string });
// Session / identity
bm.getVault(params?) => Promise<{ wallet_id: string, returnid: string, errorTitle?, errorMessage? }>
bm.getPubKeyHash({ timeoutMs? }?) => Promise<{ pubkeyHash: string | "0" | "-1", returnid: string, network? }>
bm.getUsername(params?) => Promise<{ txid: string, username?, returnid: string }>
// Assets
bm.getAssets() => Promise<{ assets?: any[], error?: string, returnid: string | null }>
bm.getInvoice({ uda, ... }) => Promise<{ txid: string, invoiceResponse?, returnid: string }>
bm.passAsset({ pubkeyHash, udaData }) => Promise<{ txid: string, vout: number, returnid: string }>
bm.transfer({ pubkeyHash, udaData }) => Promise<{ txid: string, vout: number, consignment: string, returnid: string }>
// UDA issuing
bm.issueUDA({ uda, ... }) => Promise<{ txid: string, issueResponse?, swapResponse?, network?, errorTitle?, errorMessage?, returnid: string }>
bm.issueAsset({ uda?, asset?, ... }) => Promise<{ txid: string, issueResponse?, swapResponse?, network?, errorTitle?, errorMessage?, returnid: string }>
bm.bulkIssueUDA({ uda: UDA[], ... }) => Promise<same as issueUDA>
// Swaps
bm.swapOffer({ offerData, ... }) => Promise<{ txid: string, swapOfferResponse?, checkSwapResponse?, returnid: string }>
bm.cancelSwapOffer({ offerCancelData, ... }) => Promise<{ txid: string, cancelSwapResponse?, returnid: string }>
bm.swapBid({ bidData, contract, ... }) => Promise<{ transaction?, swapResponse?, checkSwapResponse?, network?, errorTitle?, errorMessage?, returnid: string }>
bm.cancelSwapBid({ bidData, ... }) => Promise<{ txid: string, cancelSwapResponse?, returnid: string }>
// Wallet state
bm.isFunded({ pubkeyHash }) => Promise<{ isLogged: false, returnid } | { isLogged: true, isFunded: boolean, returnid }>
bm.getAddress({ pubkeyHash }) => Promise<{ isLogged: false, returnid } | { isLogged: true, address?: string, returnid }>
// UX
bm.sendNotification({ title?, message }) => Promise<void>
// Lifecycle
bm.detect(timeoutMs = 800) => Promise<boolean>
bm.dispose(): void- The SDK posts messages on
windowand listens for replies that include a matchingreturnid. - Every request includes both
idanddateId(same value) to be compatible with the current content-script. getAssetsinternally uses the extension's port bridge; the SDK just sends the request with anidand resolves on the first matching reply.- The
transfercall name is literally`transfer`to match the current content-script condition. passAssetandtransferstringifyudaDataas expected by the content-script.sendNotificationis fire-and-forget (no response expected).- Default timeout is 30s. You can override per instance or per call (only for
getPubKeyHashat the moment).
If you have bitmask-core in your project, the SDK uses type-only imports to annotate inputs like UDA. Otherwise, you can treat those as any or add your own ambient types.
import type { UDA } from "bitmask-core";
await bm.issueUDA({
uda: {
/* your UDA fields */
} as UDA,
});The current content-script accepts messages from any page origin. Consider tightening checks in the extension in future versions. DApps should also validate response shapes and handle errors/timeouts gracefully.
yarn
yarn buildThis builds ESM, CJS, and type declarations in dist/.
Use the adapter in bitmask-connect/lasereyes to add Bitmask as a wallet in LaserEyes. See LaserEyes docs.
- Import the adapter:
import { BITMASK, createBitmaskWallet } from "bitmask-connect/lasereyes";- With React (lasereyes-react):
import { LaserEyesProvider } from "@omnisat/lasereyes-react";
import { BITMASK } from "bitmask-connect/lasereyes";
export function App() {
return (
<LaserEyesProvider
config={{
network: "mainnet",
wallets: [BITMASK],
}}
>
{/* your UI */}
</LaserEyesProvider>
);
}- Combine with other wallets, or show only Bitmask:
import { LaserEyesProvider } from "@omnisat/lasereyes-react";
import { BITMASK, createBitmaskWallet } from "bitmask-connect/lasereyes";
const customBitmask = createBitmaskWallet({
timeoutMs: 2000,
onConnect: (s) => console.log("Bitmask connected", s),
});
<LaserEyesProvider
config={{
network: "mainnet",
wallets: [customBitmask],
}}
>
{/* render only Bitmask button in your UI */}
</LaserEyesProvider>;- Render a default Bitmask button (no React dependency):
import { getBitmaskButton } from "bitmask-connect/lasereyes";
const btn = getBitmaskButton();
document.getElementById("bitmask-btn")!.onclick = () => btn.onClick();Adapter API:
BITMASKready-made adaptercreateBitmaskWallet(options?)returns a new adaptergetBitmaskButton(adapter?)returns{ id, label, icon, onClick }
The adapter exposes:
Basic LaserEyes wallet interface:
connect()→ resolves{ connected, address, pubkeyHash, network }disconnect()connected(),address(),getState()
Advanced Bitmask operations via adapter.bitmask:
Access all Bitmask operations through the bitmask property:
import { createBitmaskWallet } from "bitmask-connect/lasereyes";
const adapter = createBitmaskWallet();
await adapter.connect();
// Basic operations (LaserEyes interface)
const state = adapter.getState();
const address = adapter.address();
// Advanced operations (full Bitmask SDK)
await adapter.bitmask.issueUDA({ pubkeyHash: state.pubkeyHash!, uda: {...} });
await adapter.bitmask.sendSats({ pubkeyHash: state.pubkeyHash!, recipientAddress: "...", amount: 1000 });
await adapter.bitmask.getAssets();
await adapter.bitmask.swapOffer({ pubkeyHash: state.pubkeyHash!, offerData: {...} });
// ... all other Bitmask methods availableAll methods from BitmaskConnect are accessible via adapter.bitmask.*:
getVault(),getUsername(),getUserData()issueUDA(),issueAsset(),bulkIssueUDA()getInvoice(),passAsset(),transfer()sendSats(),mintPerSats()swapOffer(),cancelSwapOffer(),swapBid(),cancelSwapBid()getAssets(),isFunded(),getAddress(),getPubKeyHash()sendNotification(),detect(),dispose(),on(),off()
MIT