@mdip/inscription
v1.4.1
Published
MDIP Inscription
Readme
@mdip/inscription
High‑level TypeScript/JavaScript library for creating and fee‑bumping Taproot inscription transactions using bitcoinjs-lib. It builds the standard two‑transaction flow (commit + reveal) and supports both P2TR and P2WPKH funding inputs. The library signs entirely in‑process using account‑level BIP32 extended private keys (xprv/tprv), no external signers or PSBT hand‑offs required.
Installation
npm install @mdip/inscriptionimport Inscription from '@mdip/inscription';
const inscription = new Inscription({
feeMax: 0.002, // maximum total BTC fee you are willing to pay
network: 'bitcoin', // 'bitcoin' | 'testnet' | 'regtest'
});Security Model
Pass only account‑level xprvs, not your root seed. The lib never needs the master seed and never persists keys.
Required keys:
- BIP86 account xprv (Taproot):
m/86'/{coin}'/{account}'mandatory - BIP84 account xprv (bech32):
m/84'/{coin}'/{account}'optional, only if funding with P2WPKH UTXOs
- BIP86 account xprv (Taproot):
coinis0for mainnet and1for testnets/regtest.
Types
export type NetworkName = 'bitcoin' | 'testnet' | 'regtest';
export type SupportedTypes = 'p2wpkh' | 'p2tr';
export interface FundInput {
type: SupportedTypes; // 'p2wpkh' or 'p2tr'
txid: string; // funding txid
vout: number; // output index
amount: number; // amount in satoshis
hdkeypath: string; // full path, e.g. m/86/1/0/0/123
}
export interface AccountKeys {
bip86: string; // account xprv/tprv for BIP86 (Taproot)
bip84?: string; // account xprv/tprv for BIP84 (bech32), if using P2WPKH inputs
}
export interface InscriptionOptions {
feeMax: number; // maximum total fee in BTC (e.g., 0.002)
network: NetworkName; // 'bitcoin' | 'testnet' | 'regtest'
}Note:
FundInput.amountis satoshis (number).hdkeypathmust be a concrete child path under the relevant account.
API
new Inscription(options: InscriptionOptions)
Creates an instance configured for your network and fee cap.
createTransactions(queue, hdkeypath, utxos, estSatPerVByte, keys)
Builds and signs the commit and reveal transactions for a batch of operations.
Parameters
queue: Operation[]— The operations to inscribe (e.g., fromgatekeeper.getQueue(...)). The library will pack as many as fit under its internal size limits.hdkeypath: string— Full BIP86 derivation path for the Taproot address that:- receives the commit change, and
- is used to create the Taproot outputs that will later be spent in the reveal.
If used a package with a single Taproot key define its hdkeypath here.
utxos: FundInput[]— Funding UTXOs from either this Taproot branch or other addresses under the same BIP84/BIP86 account keys.estSatPerVByte: number— Target fee rate in sat/vB used to estimate and set fees.keys: AccountKeys— Account‑level extended private keys used for signing.
Returns
{
commitHex: string; // raw hex of the commit transaction
revealHex: string; // raw hex of the reveal transaction
batch: Operation[]; // the subset of queue that was actually inscribed
}Broadcasting
Send both commitHex and revealHex immediately, in order (commit first). The reveal can sit in the mempool while the commit is unconfirmed.
Example
import Inscription from '@mdip/inscription';
const inscription = new Inscription({ feeMax: 0.002, network: 'bitcoin' });
const queue = await gatekeeper.getQueue(REGISTRY);
const { commitHex, revealHex, batch } = await inscription.createTransactions(
queue, // Operation[]
"m/86/0/0/0/0", // Taproot address path for outputs/change
utxos, // FundInput[] (P2TR/P2WPKH) under the same accounts
35, // estSatPerVByte (sat/vB)
{
bip86: 'xprv…', // BIP86 account xprv (required)
bip84: 'xprv…', // BIP84 account xprv (optional if using P2WPKH)
}
);
await gatekeeper.clearQueue(REGISTRY, batch);
// broadcast commitHex then revealHexbumpTransactionFee(hdkeypath, utxos, curSatPerVb, estSatPerVByte, keys, commitHex, revealHex)
Creates a replacement reveal transaction at a higher fee rate. This is a CPFP/RBF‑style bump that can add new inputs (P2TR and/or P2WPKH) and sends change back to the provided Taproot path.
Parameters
hdkeypath: string— Full BIP86 path for the Taproot change and reveal spending key (same as increateTransactions).utxos: FundInput[]— Additional funding UTXOs (P2TR/P2WPKH) under the same account keys.curSatPerVb: number— Current fee rate (sat/vB) you’re paying on the existing reveal in the mempool.estSatPerVByte: number— Target fee rate (sat/vB). The new reveal will aim for this or the minimum possible above the current fee, whichever is higher.keys: AccountKeys— Account‑level xprvs used to sign any added inputs and the taproot spend.commitHex: string— Raw hex of the original commit transaction.revealHex: string— Raw hex of the original or most revently bumped reveal transaction to bump.
Returns
string— Raw hex of the new reveal transaction (broadcast this to bump the fee).
Example
const newRevealHex = await inscription.bumpTransactionFee(
"m/86/0/0/0/0",
utxos, // new UTXOs to fund the bump
25, // curSatPerVb currently paid by reveal
40, // estSatPerVByte target
{
bip86: 'xprv…', // BIP86 account xprv (required)
bip84: 'xprv…', // BIP84 account xprv (optional if using P2WPKH)
},
commitHex,
revealHex
);
// broadcast newRevealHexAddress derivation helpers
The library exposes convenience methods to derive addresses directly from account‑level xprv keys and a full BIP32 path.
⚠️ These helpers expect account xprvs (e.g., BIP86:
m/86'/{coin}'/{acct}'and BIP84:m/84'/{coin}'/{acct}').
deriveP2TRAddress(bip86Xprv: string, hdkeypath: string): string
Derives a Taproot (BIP86) bech32m address from an account‑level BIP86 xprv and an address path.
Parameters
bip86Xprv– Account‑level extended private key for BIP86 (e.g.,tprv...on testnet,xprv...on mainnet).hdkeypath– Full BIP32 path to the desired address under that account (e.g.,m/86/1/0'/0/0).
Returns: A Taproot bech32m address string (e.g.,
tb1p...on testnet orbc1p...on mainnet).
Example
import Inscription from '@mdip/inscription';
import { logger } from '@mdip/common/logger';
const ins = new Inscription({ feeMax: 0.002, network: 'testnet' });
const addr = ins.deriveP2TRAddress(process.env.BIP86_XPRV, "m/86/1/0/0/0");
logger.info(`Taproot address: ${addr}`);deriveP2WPKHAddress(bip84Xprv: string, hdkeypath: string): string
Derives a Native SegWit (BIP84) bech32 P2WPKH address from an account‑level BIP84 xprv and an address path.
Parameters
bip84Xprv– Account‑level extended private key for BIP84 (e.g.,tprv...on testnet,xprv...on mainnet).hdkeypath– Full BIP32 path under that account (e.g.,m/84/1/0/0/0).
Returns: A bech32 P2WPKH address string (e.g.,
tb1q...on testnet orbc1q...on mainnet).
Example
import Inscription from '@mdip/inscription';
import { logger } from '@mdip/common/logger';
const ins = new Inscription({ feeMax: 0.002, network: 'testnet' });
const addr = ins.deriveP2WPKHAddress(process.env.BIP84_XPRV, "m/84/1/0/0/0");
logger.info(`P2WPKH address: ${addr}`);Notes & Best Practices
- Account keys vs seed: Always pass account‑level xprvs (BIP86/BIP84). Do not pass your root seed.
- UTXO amounts: Provide
amountin satoshis. - Mixed inputs: You may fund with a mixture of P2TR and P2WPKH UTXOs. If you include P2WPKH, you must provide
keys.bip84. - Change: Commit and fee‑bumped reveal change will return to the Taproot address derived from
hdkeypath. - Broadcast order: Broadcast
commitHexfirst, thenrevealHex. Both may remain unconfirmed together. - Limits: The library enforces an inscription payload limit to keep reveals standard.
