bnrp-resolver
v1.0.0
Published
Bitcoin Name Resolution Protocol (BNRP) resolver. Resolves .btc, .sats, .unisat, .x, .xbt, .sat names to on-chain identity records.
Maintainers
Readme
bnrp-resolver
Bitcoin Name Resolution Protocol (BNRP) — JavaScript/TypeScript SDK.
Resolves .btc, .sats, .unisat, .x, .xbt, .sat names to on-chain identity records. Zero dependencies. Works in Node.js, browsers, and edge runtimes.
Spec: github.com/nlgal/bnrp-spec
Demo: bnrp.name
Install
npm install bnrp-resolverUsage
Resolve a name
import { resolve } from 'bnrp-resolver';
const result = await resolve('trump.btc');
if (result.found) {
console.log(result.record.name); // "trump.btc"
console.log(result.record.btc_taproot); // "bc1p..."
console.log(result.record.avatar); // "ord:ac975..."
console.log(result.record.twitter); // "ordinalpunk72"
console.log(result.record.url); // "https://bnrp.name"
console.log(result.via); // "unisat" | "btcname" | "sns"
}Just get the BTC address (send flow)
import { resolveAddress } from 'bnrp-resolver';
const address = await resolveAddress('trump.btc');
// "bc1pkdqs4ksyha8n2ugxtyywku35pwmv7t60yrru0f860aaf3u5faujq9a6hmc"
// Returns null if not foundJust get the avatar inscription ID
import { resolveAvatar } from 'bnrp-resolver';
const inscriptionId = await resolveAvatar('trump.btc');
// "ac975126b9a6138238bb3a42b1a9c5b9b4da91bca6bacb6539bc34dbed2cf329i0"
// Returns null if not found or no avatar setCheck if a string is a BTC name
import { isBtcName } from 'bnrp-resolver';
isBtcName('trump.btc'); // true
isBtcName('vitalik.eth'); // false
isBtcName('bc1p...'); // falseResolveResult shape
{
found: boolean; // Whether a valid record was found
name: string; // Original input
normalized: string | null; // Normalized per BNRP-IP-01
record: BnrpRecord | null;
error: string | null;
via: 'unisat' | 'btcname' | 'sns' | null;
}BnrpRecord shape
{
// Source
inscriptionId: string;
ownerAddress: string;
blockHeight: number;
protocol: 'bnrp' | 'btcname';
// Identity
name: string;
display: string | null;
description: string | null;
avatar: string | null; // "ord:{inscriptionId}" format
// Bitcoin (taproot preferred)
btc_taproot: string | null;
btc_segwit: string | null;
btc_p2sh: string | null;
btc_legacy: string | null;
// Other chains
eth: string | null;
sol: string | null;
ltc: string | null;
// Social / web
twitter: string | null;
github: string | null;
url: string | null;
nostr: string | null;
}Options
All resolve functions accept an optional options object:
await resolve('trump.btc', {
unisatApiBase: 'https://wallet-api.unisat.io/v5', // override UniSat API
btcnameApiBase: 'https://api.btcname.id/v1', // override BtcName API
snsApiBase: 'https://api.sats.id', // override SNS API
debug: true, // log resolution steps
timeoutMs: 8000, // request timeout
});Resolution Strategy
The resolver runs three strategies in parallel and picks the winning record:
| Strategy | Covers | API | |----------|--------|-----| | UniSat | All TLDs | wallet-api.unisat.io | | BtcName | .btc only | api.btcname.id | | SNS | .sats .unisat .x .xbt .sat | api.sats.id |
Latest-wins rule: if multiple valid records exist for the same name, the one with the highest block height wins. Same block: lower tx index wins. This is per BNRP-IP-02 §10.
BtcName Compatibility
Records inscribed with "p":"btcname" resolve natively without re-inscription. Field mapping per BNRP-IP-07:
| BtcName field | BNRP field | |---------------|----------------| | eth_address | eth | | ord_index | avatar | | btc_p2phk | btc_legacy |
Supported TLDs
.btc .sats .unisat .x .xbt .sat .ord .gm .fb
Wallet Integration
Drop-in resolution for any send flow:
import { resolveAddress, isBtcName } from 'bnrp-resolver';
async function resolveRecipient(input) {
if (isBtcName(input)) {
const address = await resolveAddress(input);
if (address) return { address, resolvedFrom: input };
}
return { address: input, resolvedFrom: null };
}