BMAPjs is a transaction parser for Bitcoin data protocols like B, MAP, BAP, 1Sat Ordinals, METANET and AIP/HAIP. Supports multiple outputs, signature verification, and multiple instances in a single OP_RETURN. It also has support for some Script based protocols like 21e8.
It processes BOB formatted transactions for B | MAP
OP_RETURN protocols. It processes transaction outputs and transforms them into self-descriptive TypeScript objects based on the OP_RETURN protocols it discovers in the data.
It supports B, MAP, AIP, METANET and a list of other popular protocols. It ingests structured JSON objects in BOB format.
It is written in TypeScript and can be used both as an ESM module or in the browser as CommonJS via script tag. See the dist
folder for compiled outputs.
BOB format is a great way to express Bitcoin transaction outputs, especially those containing data protocols, but there are some problems. For example, each field has multiple options to choose from, be it a base64 encoded binary representation in the b field, a string value in the s field, or a hex value in the h field. Depending on the protocol and the specific field you might choose one or another. This means you have to have a full understanding of the protocol you're trying to use. That's where bmapjs comes in. It can recognize many protocols, structure the data according to their individual protocols, and provide an easy to use BMAP transaction object with no mysteries about the data.
- A BOB formatted transaction. If you only have a raw transaction you can convert to BOB using BPU. More information here
- Bun (for development)
bun add bmapjs
or
npm install bmapjs
# Install dependencies
bun install
# Run tests
bun test
# Build
bun run build
# Lint
bun run lint
# Format
bun run format
You can import bmap using require:
const { BMAP } = require('bmapjs')
or using ESM module import:
import { BMAP, TransformTx } from 'bmapjs'
You can use bmapjs in the browser by pointing to the .cjs file in the dist folder:
<script src="dist/bmap.cjs"></script>
The CJS is by far the largest package since it includes dependencies. It is also possible to import in the browser using the module syntax:
<script src="dist/bmap.es.js" type="module">
import { TransformTx } from 'bmapjs'
// more code here
</script>
Turn a BOB formatted transaction into a BMAP tx. It will throw an error if the transaction is malformed.
In Node.js/Bun:
import { TransformTx } from 'bmapjs'
try {
const bmapTx = await TransformTx(bob_tx_object)
} catch (e) {
console.error(e)
}
or in the browser:
<script src="dist/bmap.cjs"></script>
bmap
will be available on the window object:
const bmapTx = await bmap.TransformTx(bob_tx_object)
After transforming the object will contain a key for each protocol found within the transaction. Each value will be an array. Most of the time the array will have only one value indicating the protocol was detected only once. However, in some cases where protocols will be used multiple times in the same transaction, the array will contain one object for each protocol instance detected.
interface BmapTx {
tx: {
h: string; // Transaction hash
r: string; // Raw transaction
};
blk?: {
i: number; // Block index
h: string; // Block hash
t: number; // Block time
};
in: Input[]; // Transaction inputs
out: Output[]; // Transaction outputs
// Protocol data
AIP?: AIP[]; // Identity protocol
B?: B[]; // Data protocol
BAP?: BAP[]; // Bitcoin Attestation Protocol
MAP?: MAP[]; // Magic Attribute Protocol
ORD?: ORD[]; // 1Sat Ordinals
"21E8"?: _21E8[]; // Proof of work protocol
BITCOM?: BITCOM[];
BITKEY?: BITKEY[];
BITPIC?: BITPIC[];
METANET?: METANET[];
RON?: RON[];
SYMRE?: SYMRE[];
HAIP?: HAIP[];
}
Not all protocols available in bmap.js
are active by default. These are less used or older protocols, but they can be easily added at runtime.
import { BMAP, RON } from 'bmapjs'
const bmap = new BMAP()
bmap.addProtocolHandler(RON)
The protocols that are available but not active by default are BITCOM
, BITKEY
, BITPIC
, RON
and SYMRE
.
You can also easily add new handlers for processing any type of bitcom output.
import { BMAP } from 'bmapjs'
import type { Protocol, SchemaField } from 'bmapjs'
const bmap = new BMAP()
const opReturnSchema: SchemaField[] = [{}] // optional
const handler: Protocol['handler'] = ({ dataObj, cell, tape, tx }) => {
// dataObj is the object that all data is added to
// cell is the current cell being processed
// tape is the tape the cell is in
// tx is the total transaction
}
bmap.addProtocolHandler({
name: 'TEST',
address: '1FJrobAYoQ6qSVJH7yiawfaUmZ3G13q9iJ',
opReturnSchema,
handler,
})
await bmap.transformTx(bob_tx)
You can also use the default protocol handler with a well-defined schema to make it even easier:
import { BMAP } from 'bmapjs'
import { bmapOpReturnSchemaHandler } from './utils'
import type { SchemaField } from 'bmapjs'
const opReturnSchema: SchemaField[] = [
{ type: 'string' },
{ hash: 'string' },
{ sequence: 'string' },
]
const handler = ({ dataObj, cell, tape, tx }) => {
bmapOpReturnSchemaHandler('TEST', opReturnSchema, dataObj, cell, tx)
}
bmap.addProtocolHandler({
name: 'TEST',
address: '1FJrobAYoQ6qSVJH7yiawfaUmZ3G13q9iJ',
opReturnSchema,
handler,
})
Open BSV