UNPKG

@shocknet/clink-sdk

Version:

sdk client for clink

164 lines 5.97 kB
import { bytesToHex, concatBytes, hexToBytes } from '@noble/hashes/utils'; import { bech32 } from '@scure/base'; export const utf8Decoder = new TextDecoder('utf-8'); export const utf8Encoder = new TextEncoder(); /* const NostrTypeGuard = { isNoffer: (value?: string | null): value is Noffer => /^noffer1[a-z\d]+$/.test(value || ''), isNdebit: (value?: string | null): value is Ndebit => /^ndebit1[a-z\d]+$/.test(value || ''), } */ export const Bech32MaxSize = 5000; /** * Bech32 regex. * @see https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki#bech32 */ export const BECH32_REGEX = /[\x21-\x7E]{1,83}1[023456789acdefghjklmnpqrstuvwxyz]{6,}/; function integerToUint8Array(number) { // Create a Uint8Array with enough space to hold a 32-bit integer (4 bytes). const uint8Array = new Uint8Array(4); // Use bitwise operations to extract the bytes. uint8Array[0] = (number >> 24) & 0xff; // Most significant byte (MSB) uint8Array[1] = (number >> 16) & 0xff; uint8Array[2] = (number >> 8) & 0xff; uint8Array[3] = number & 0xff; // Least significant byte (LSB) return uint8Array; } export var OfferPriceType; (function (OfferPriceType) { OfferPriceType[OfferPriceType["Fixed"] = 0] = "Fixed"; OfferPriceType[OfferPriceType["Variable"] = 1] = "Variable"; OfferPriceType[OfferPriceType["Spontaneous"] = 2] = "Spontaneous"; })(OfferPriceType || (OfferPriceType = {})); export function decodeBech32(nip19) { let { prefix, words } = bech32.decode(nip19, Bech32MaxSize); let data = new Uint8Array(bech32.fromWords(words)); switch (prefix) { case 'noffer': { const tlv = parseTLV(data); if (!tlv[0]?.[0]) throw new Error('missing TLV 0 for noffer'); if (tlv[0][0].length !== 32) throw new Error('TLV 0 should be 32 bytes'); if (!tlv[1]?.[0]) throw new Error('missing TLV 1 for noffer'); if (!tlv[2]?.[0]) throw new Error('missing TLV 2 for noffer'); if (!tlv[3]?.[0]) throw new Error('missing TLV 3 for noffer'); return { type: 'noffer', data: { pubkey: bytesToHex(tlv[0][0]), relay: utf8Decoder.decode(tlv[1][0]), offer: utf8Decoder.decode(tlv[2][0]), priceType: tlv[3][0][0], price: tlv[4] ? parseInt(bytesToHex(tlv[4][0]), 16) : undefined } }; } case 'ndebit': { const tlv = parseTLV(data); if (!tlv[0]?.[0]) throw new Error('missing TLV 0 for ndebit'); if (tlv[0][0].length !== 32) throw new Error('TLV 0 should be 32 bytes'); if (!tlv[1]?.[0]) throw new Error('missing TLV 1 for ndebit'); return { type: 'ndebit', data: { pubkey: bytesToHex(tlv[0][0]), relay: utf8Decoder.decode(tlv[1][0]), pointer: tlv[2] ? utf8Decoder.decode(tlv[2][0]) : undefined } }; } case 'nmanage': { const tlv = parseTLV(data); if (!tlv[0]?.[0]) throw new Error('missing TLV 0 for nmanage'); if (tlv[0][0].length !== 32) throw new Error('TLV 0 should be 32 bytes'); if (!tlv[1]?.[0]) throw new Error('missing TLV 1 for nmanage'); return { type: 'nmanage', data: { pubkey: bytesToHex(tlv[0][0]), relay: utf8Decoder.decode(tlv[1][0]), pointer: tlv[2] ? utf8Decoder.decode(tlv[2][0]) : undefined } }; } default: throw new Error(`unknown prefix ${prefix}`); } } function parseTLV(data) { let result = {}; let rest = data; while (rest.length > 0) { let t = rest[0]; let l = rest[1]; let v = rest.slice(2, 2 + l); rest = rest.slice(2 + l); if (v.length < l) throw new Error(`not enough data to read on TLV ${t}`); result[t] = result[t] || []; result[t].push(v); } return result; } export const nofferEncode = (offer) => { const o = { 0: [hexToBytes(offer.pubkey)], 1: [utf8Encoder.encode(offer.relay)], 2: [utf8Encoder.encode(offer.offer)], 3: [new Uint8Array([Number(offer.priceType)])], }; if (offer.price) { o[4] = [integerToUint8Array(offer.price)]; } const data = encodeTLV(o); const words = bech32.toWords(data); return bech32.encode('noffer', words, 5000); }; export const ndebitEncode = (debit) => { const o = { 0: [hexToBytes(debit.pubkey)], 1: [utf8Encoder.encode(debit.relay)], }; if (debit.pointer) { o[2] = [utf8Encoder.encode(debit.pointer)]; } const data = encodeTLV(o); const words = bech32.toWords(data); return bech32.encode('ndebit', words, 5000); }; export const nmanageEncode = (manage) => { const o = { 0: [hexToBytes(manage.pubkey)], 1: [utf8Encoder.encode(manage.relay)], }; if (manage.pointer) { o[2] = [utf8Encoder.encode(manage.pointer)]; } const data = encodeTLV(o); const words = bech32.toWords(data); return bech32.encode('nmanage', words, 5000); }; function encodeTLV(tlv) { let entries = []; Object.entries(tlv) .reverse() .forEach(([t, vs]) => { vs.forEach(v => { let entry = new Uint8Array(v.length + 2); entry.set([parseInt(t)], 0); entry.set([v.length], 1); entry.set(v, 2); entries.push(entry); }); }); return concatBytes(...entries); } //# sourceMappingURL=nip19Extension.js.map