UNPKG

@ckb-ccc/core

Version:

Core of CCC - CKBer's Codebase

183 lines (166 loc) 4.88 kB
import { bech32, bech32m } from "bech32"; import { Script, hashTypeFromBytes } from "../ckb/index.js"; import { Client, KnownScript } from "../client/index.js"; import { hexFrom } from "../hex/index.js"; import { type AddressLike } from "./index.js"; /** * Parses an address string into an address information object. * * @param address - The address string to parse. * @returns An object containing the address prefix, address format, and payload array. * * @throws Will throw an error if the address format is unknown. * * @example * ```typescript * const addressInfo = addressPayloadFromString("ckt1112139193129"); * console.log(addressInfo.prefix); // Outputs the address prefix * console.log(addressInfo.format); // Outputs the address format * console.log(addressInfo.payload); // Outputs the payload array * ``` */ export function addressPayloadFromString(address: string): { prefix: string; format: AddressFormat; payload: number[]; } { // Try parse full format address try { const { words, prefix } = bech32m.decode(address, ADDRESS_BECH32_LIMIT); const decoded = bech32m.fromWords(words); const formatType = decoded[0]; const payload = decoded.slice(1); if (formatType === (AddressFormat.Full as number)) { return { prefix, format: AddressFormat.Full, payload }; } } catch (_) {} // Try parse legacy 2019 format address try { const { prefix, words } = bech32.decode(address, ADDRESS_BECH32_LIMIT); const decoded = bech32.fromWords(words); const formatType = decoded[0]; const payload = decoded.slice(1); if ( [ AddressFormat.FullData, AddressFormat.FullType, AddressFormat.Short, ].includes(formatType) ) { return { prefix, format: formatType, payload }; } } catch (_) {} throw Error(`Unknown address format ${address}`); } /** * Converts an address payload into an address-like object. * * @param prefix - The address prefix. * @param format - The format of the address, as defined by the AddressFormat enum. * @param payload - The payload array containing the address data. * @param client - The client instance used to fetch known scripts. * @returns A promise that resolves to an AddressLike object. * * @throws Will throw an error if the payload length is insufficient or if the script type is unknown. * * @example * ```typescript * const address = await addressFromPayload("ckt", AddressFormat.Full, [/* payload data *\/], client); * console.log(address.script); // Outputs the script object * console.log(address.prefix); // Outputs the address prefix * ``` */ export async function addressFromPayload( prefix: string, format: AddressFormat, payload: number[], client: Client, ): Promise<AddressLike> { if (format === AddressFormat.Full) { if (payload.length < 32 + 1) { throw new Error( `Invalid full address without enough payload ${hexFrom(payload)}`, ); } return { script: { codeHash: payload.slice(0, 32), hashType: hashTypeFromBytes(payload.slice(32, 33)), args: payload.slice(33), }, prefix, }; } if (format === AddressFormat.FullData) { if (payload.length < 32) { throw new Error( `Invalid full data address without enough payload ${hexFrom(payload)}`, ); } return { script: { codeHash: payload.slice(0, 32), hashType: "data", args: payload.slice(32), }, prefix, }; } if (format === AddressFormat.FullType) { if (payload.length < 32) { throw new Error( `Invalid full type address without enough payload ${hexFrom(payload)}`, ); } return { script: { codeHash: payload.slice(0, 32), hashType: "type", args: payload.slice(32), }, prefix, }; } // format === AddressFormat.Short if (payload.length !== 21) { throw new Error( `Invalid short address without enough payload ${hexFrom(payload)}`, ); } const script = [ KnownScript.Secp256k1Blake160, KnownScript.Secp256k1Multisig, KnownScript.AnyoneCanPay, ][payload[0]]; if (script === undefined) { throw new Error( `Invalid short address with unknown script ${hexFrom(payload)}`, ); } return { script: await Script.fromKnownScript(client, script, payload.slice(1)), prefix, }; } export enum AddressFormat { /** * full version identifies the hashType */ Full = 0x00, /** * @deprecated * short version for locks with Known codeHash, deprecated */ Short = 0x01, /** * @deprecated * full version with hashType = "Data", deprecated */ FullData = 0x02, /** * @deprecated * full version with hashType = "Type", deprecated */ FullType = 0x04, } export const ADDRESS_BECH32_LIMIT = 1023;