/** * Copyright 2025-2026 The Lotusia Stewardship * Github: https://github.com/LotusiaStewardship * License: MIT */ import type { Buffer } from 'buffer/'; import { Chunk } from './bitcore'; /** LOKAD protocol identifiers as UTF-8 strings */ export type ScriptChunkLokadUTF8 = 'RANK' | 'RNKC' | 'RNKE'; /** RANK/RNKC platform identifiers as UTF-8 strings */ export type ScriptChunkPlatformUTF8 = 'lotusia' | 'twitter'; /** RANK sentiment values as UTF-8 strings */ export type ScriptChunkSentimentUTF8 = 'positive' | 'negative' | 'neutral'; /** Map of LOKAD integer values to UTF-8 protocol identifiers */ export type ScriptChunkLokadMap = Map; /** Map of platform integer values to UTF-8 platform identifiers */ export type ScriptChunkPlatformMap = Map; /** Map of sentiment integer values to UTF-8 sentiment identifiers */ export type ScriptChunkSentimentMap = Map; export type ScriptChunkField = 'sentiment' | 'platform' | 'profileId' | 'postId' | 'comment' | 'postHash' | 'instanceId'; export type ScriptChunk = { /** Byte offset of the chunk in the output script */ offset: number | null; /** Byte length of the chunk in the output script */ len: number | null; /** Map of supported RANK script chunks */ map?: ScriptChunkLokadMap | ScriptChunkPlatformMap | ScriptChunkSentimentMap; }; /** Required RNKC script chunks */ export type ScriptChunksRNKC = { [name in Exclude]: ScriptChunk; }; /** Required RANK script chunks */ export type ScriptChunksRANK = { [name in Exclude]: ScriptChunk; }; /** Optional RANK script chunks */ export type ScriptChunksOptionalRANK = { [name in Extract]: ScriptChunk; }; /** OP_RETURN \ \ \ [\ \ [\]] */ export type TransactionOutputRANK = { /** positive or negative sentiment (can support more) */ sentiment: ScriptChunkSentimentUTF8; /** e.g. Twitter/X.com, etc. */ platform: ScriptChunkPlatformUTF8; /** who the ranking is for */ profileId: string; /** optional post ID if ranking specific content */ postId?: string; }; /** OP_RETURN \ \ \ \ */ export type TransactionOutputRNKC = { /** outIdx 1 and 2 concatenated as comment data in UTF-8 encoding */ data: Uint8Array; /** Minimum fee rate for accepting RNKC transaction, in satoshis per byte */ feeRate: number; /** e.g. Twitter/X.com, etc. */ inReplyToPlatform: ScriptChunkPlatformUTF8; /** who the comment is replying to */ inReplyToProfileId?: string; /** ID of the post being replied to */ inReplyToPostId?: string; }; /** Transaction data for the backend indexer */ export type Transaction = { txid: string; outIdx: number; sats: bigint; firstSeen: bigint; scriptPayload: string; instanceId?: string; height?: number; timestamp?: bigint; }; /** RANK transaction data for the backend indexer */ export type TransactionRANK = TransactionOutputRANK & Transaction; /** RNKC transaction data for the backend indexer */ export type TransactionRNKC = TransactionOutputRNKC & Transaction; /** * Target entity being ranked by a RANK transaction, commented on by an * RNKC transaction, etc. (e.g. Profile, Post, etc.) */ export type TargetEntity = { id: string; platform: string; ranking: bigint; ranks: Omit[]; comments: Omit[]; satsPositive: bigint; satsNegative: bigint; votesPositive: number; votesNegative: number; }; /** * `IndexedTransactionRANK` objects are converted to a `ProfileMap` for database ops * * `string` is `profileId` */ export type ProfileMap = Map; export type PostMap = Map; /** * Profile entity that can be ranked and contains associated posts * @extends TargetEntity */ export interface Profile extends TargetEntity { /** Map of posts associated with this profile, keyed by post ID */ posts?: PostMap; } /** * Post entity that can be ranked and commented on * @extends TargetEntity */ export interface Post extends TargetEntity { /** The profile ID that owns this post */ profileId: string; /** If this post is a RNKC transaction, this contains the comment data for establishing relation to `RankComment` */ data?: Uint8Array; } /** * Platform parameters for configuring profile and post ID validation * @property profileId - Configuration for profile ID validation * @property profileId.len - Maximum length of the profile ID in bytes * @property profileId.regex - Regular expression for validating profile ID format * @property postId - Configuration for post ID validation * @property postId.len - Maximum length of the post ID in bytes * @property postId.regex - Regular expression for validating post ID format * @property postId.type - The type used to represent the post ID value */ export interface PlatformParameters { profileId: { len: number; regex: RegExp; }; postId: { len: number; regex: RegExp; type: 'BigInt' | 'Number' | 'String'; }; } /** Map of LOKAD protocol byte values to their UTF-8 string identifiers */ export declare const LOKAD_PREFIX_RANK = 1380011595; export declare const LOKAD_PREFIX_RNKC = 1380862787; export declare const LOKAD_PREFIX_RNKE = 1380862789; /** LOKAD chunk map */ export declare const SCRIPT_CHUNK_LOKAD: ScriptChunkLokadMap; /** Sentiment value for neutral ranking (OP_16) */ export declare const RANK_SENTIMENT_NEUTRAL = 96; /** Sentiment value for positive ranking (OP_1) */ export declare const RANK_SENTIMENT_POSITIVE = 81; /** Sentiment value for negative ranking (OP_0) */ export declare const RANK_SENTIMENT_NEGATIVE = 0; /** Sentiment chunk map */ export declare const SCRIPT_CHUNK_SENTIMENT: ScriptChunkSentimentMap; /** Sentiment op code map */ export declare const RANK_SENTIMENT_OP_CODES: Map; /** Platform chunk map */ export declare const SCRIPT_CHUNK_PLATFORM: ScriptChunkPlatformMap; /** Required RANK Comment script chunks */ export declare const ScriptChunksRNKCMap: Map; /** Length of the required RANK script chunks in bytes */ export declare const RANK_SCRIPT_REQUIRED_LENGTH = 10; /** Required RANK script chunks */ export declare const ScriptChunksRANKMap: Map; /** * Optional RANK script chunks for extended functionality * These chunks are not required for basic RANK transactions but enable * additional features like ranking specific posts or tracking extension instances */ export declare const ScriptChunksOptionalRANKMap: Map; /** * Platform configuration map for RANK protocol * * Maps platform identifiers to their validation parameters for profile IDs and post IDs. * Each platform has specific requirements for ID formats, lengths, and types. * * @example * ```typescript * const lotusiaConfig = PlatformConfiguration.get('lotusia') * // { profileId: { len: 33, regex: /^[0-9a-fA-F]{40,66}$/ }, postId: { len: 32, regex: /^[0-9a-f]{64}$/, type: 'String' } } * ``` * * @see {@link PlatformParameters} for the structure of platform configuration * @see {@link ScriptChunkPlatformUTF8} for supported platform identifiers */ export declare const PlatformConfiguration: Map; /** * Check provided script for OP_RETURN op code * @param script - The script to check, as a `Buffer` or hex `string` * @returns true if the output is an OP_RETURN, false otherwise */ export declare function isOpReturn(script: Buffer | string): boolean; /** * Convert the profile ID to a buffer * @param platform - The platform to convert the profile ID for * @param profileId - The profile ID to convert * @returns The profile ID buffer */ export declare function toProfileIdBuf(platform: ScriptChunkPlatformUTF8, profileId: string): Buffer | null; /** * Convert the `OP_RETURN` profile name back to UTF-8 with null bytes removed * @param profileIdBuf - The profile ID buffer to convert, padded with null bytes * @returns The UTF-8 profile ID */ export declare function toProfileIdUTF8(profileIdBuf: Buffer): string; /** * Convert the post ID to a buffer * @param platform - The platform to convert the post ID for * @param postId - The post ID to convert * @returns The post ID buffer */ export declare function toPostIdBuf(platform: ScriptChunkPlatformUTF8, postId: string): Buffer | undefined; /** * Convert the UTF-8 platform name to the defined 1-byte platform hex code * @param platform * @returns */ export declare function toPlatformBuf(platform: ScriptChunkPlatformUTF8): Buffer | undefined; /** * Convert the defined 1-byte platform hex code to the UTF-8 platform name * @param platformBuf */ export declare function toPlatformUTF8(platformBuf: Buffer): ScriptChunkPlatformUTF8 | undefined; /** * Convert the UTF-8 sentiment name to the defined 1-byte OP code * @param sentiment * @returns */ export declare function toSentimentOpCode(sentiment: ScriptChunkSentimentUTF8): string | undefined; /** * Convert the defined 1-byte sentiment OP code to the UTF-8 sentiment name * @param sentimentBuf */ export declare function toSentimentUTF8(sentimentBuf: Buffer): ScriptChunkSentimentUTF8 | undefined; /** * Convert the comment buffer to a UTF-8 string * @param commentBuf - The comment buffer to convert * @returns The UTF-8 string */ export declare function toCommentUTF8(commentBuf: Buffer | Uint8Array): string | undefined; /** * Check if a script chunk contains a valid LOKAD identifier * @param scriptChunk - The script chunk to validate * @param lokadType - Optional specific LOKAD type to validate against * @returns `true` if the chunk contains a valid 4-byte LOKAD identifier, `false` otherwise */ export declare function isValidLokad(scriptChunk: Chunk, lokadType?: ScriptChunkLokadUTF8): boolean; /** * Parse a RANK script buffer into a structured TransactionOutputRANK object * * Decodes the RANK protocol script format: * OP_RETURN [] * * @param scriptBuf - The script buffer or hex string to parse * @returns The parsed RANK transaction output data * @throws Error if the script is not a valid OP_RETURN * @throws Error if the LOKAD identifier is invalid or not RANK * @throws Error if sentiment, platform, or profileId chunks are invalid * @throws Error if profileId doesn't match the platform's regex pattern * @throws Error if postId is present but invalid for the platform * * @example * ```typescript * const rankData = fromScriptRANK(scriptBuffer) * console.log(rankData.sentiment) // 'positive' * console.log(rankData.platform) // 'lotusia' * console.log(rankData.profileId) // '0x...' * console.log(rankData.postId) // optional * ``` */ export declare function fromScriptRANK(scriptBuf: Buffer | string): TransactionOutputRANK; /** * Create a hex-encoded RANK script from the given parameters * * The RANK script follows the format: * OP_RETURN [] * * @param sentiment - The sentiment to express: 'positive', 'negative', or 'neutral' * @param platform - The platform identifier: 'lotusia' or 'twitter' * @param profileId - The profile ID to rank (script payload for lotusia, username for twitter) * @param postId - Optional post ID to rank a specific post instead of the profile * @returns The hex-encoded RANK script as a `Buffer` * @throws Error if sentiment, platform, or profileId is not specified * @throws Error if the platform specification is not defined * @throws Error if postId is provided but the platform doesn't support post ranking */ export declare function toScriptRANK(sentiment: ScriptChunkSentimentUTF8, platform: ScriptChunkPlatformUTF8, profileId: string, postId?: string): Buffer; /** * Parse a RNKC script buffer into a structured TransactionOutputRNKC object * * Decodes the RNKC protocol script format: * OP_RETURN [] * OP_RETURN * [OP_RETURN ] * * @param scriptBuf - The main RNKC script buffer or hex string (output index 0) * @param supplementalScriptBufs - Additional OP_RETURN scripts containing comment data * @param burnedSats - The amount of satoshis burned for this transaction * @param options - Optional validation parameters * @param options.minDataLength - Minimum required comment data length (default: RNKC_MIN_DATA_LENGTH) * @param options.minFeeRate - Minimum required fee rate per byte (default: RNKC_MIN_FEE_RATE) * @returns The parsed RNKC transaction output data * @throws Error if the script is not a valid OP_RETURN * @throws Error if the LOKAD chunk is invalid or unsupported * @throws Error if the platform is invalid or unsupported * @throws Error if the profileId format is invalid for the platform * @throws Error if the postId format is invalid for the platform * @throws Error if no comment data is found in supplemental scripts * @throws Error if comment data length is below minimum * @throws Error if fee rate is too low */ export declare function fromScriptRNKC(scriptBuf: Buffer | string, supplementalScriptBufs: (Buffer | string)[], burnedSats: number | bigint, options?: { minDataLength: number; minFeeRate: number; }): TransactionOutputRNKC; /** * Create hex-encoded RANK Comment (RNKC) scripts from the given parameters * * RNKC is used to post comments on ranked content. The protocol requires * multiple output scripts: the first contains the RNKC header with platform, * profile, and optional post identifiers, while subsequent outputs contain * the comment data (split across 1-2 outputs if needed). * * The RNKC script format is: * Output 0: OP_RETURN [] * Output 1: OP_RETURN * Output 2 (optional): OP_RETURN * * @param platform - The platform identifier: 'lotusia' or 'twitter' * @param profileId - The profile ID to comment on (script payload for lotusia, username for twitter) * @param postId - Optional post ID to comment on a specific post * @param comment - The comment text (UTF-8 encoded, max 2x MAX_OP_RETURN_DATA bytes) * @returns Array of hex-encoded RNKC scripts as `Buffer` objects * @throws Error if platform or profileId is not specified * @throws Error if the platform specification is not defined * @throws Error if profileId doesn't match the platform's regex pattern * @throws Error if postId is provided but doesn't match the platform's regex pattern * @throws Error if comment length is outside valid range (1 to MAX_OP_RETURN_DATA * 2 bytes) * * @example * ```typescript * const scripts = toScriptRNKC({ * platform: 'twitter', * profileId: 'username', * postId: '1234567890', * comment: 'Great post!' * }) * // Returns array of Buffer objects for each output script * ``` * * @see {@link toScriptRANK} for ranking without comments * @see {@link ScriptProcessor.processScriptRNKC} for parsing RNKC scripts */ export declare function toScriptRNKC({ platform, profileId, postId, comment, }: { platform: ScriptChunkPlatformUTF8; profileId: string; postId?: string; comment: string; }): Buffer[]; /** * Processor for defined LOKAD protocols (RANK, RNKC, etc.) * @param script - The script to process, as a `Buffer` * @deprecated Use the individual LOKAD `from` functions instead (e.g. `fromScriptRANK`, `fromScriptRNKC`, etc.) */ export declare class ScriptProcessor { private chunks; /** The script to process, as a `Buffer` */ private script; /** Supplemental scripts, e.g. outIdx 1 and/or 2 for RNKC */ private supplementalScripts; constructor(script: Buffer); /** * Add a supplemental OP_RETURN script to the processor * @param script - The script to add, as a `Buffer` * @returns true if the script was added, false otherwise */ addScript(script: string | Buffer): boolean; /** * Get the LOKAD type from the script * @returns The LOKAD type or undefined if invalid */ get lokadType(): ScriptChunkLokadUTF8 | undefined; /** * Process the LOKAD chunk * @returns The LOKAD value or undefined if invalid */ private processLokad; /** * Process the sentiment chunk (RANK) * @returns The sentiment value or undefined if invalid */ private processSentiment; /** * Process the platform chunk * @returns The platform value or undefined if invalid */ private processPlatform; /** * Process the profileId chunk * @returns The profileId value or undefined if invalid */ private processProfileId; /** * Process the postId chunk * @returns The postId value or undefined if invalid */ private processPostId; /** * Process the RNKC comment chunks (outIdx 1 and 2) * @param scripts - outIdx 1 and 2 scripts, if outIdx 0 is RNKC * @returns The comment value or null if invalid */ private processComment; /** * Validate the required RANK chunks and store the processed output * @returns true if all required chunks are valid, false otherwise */ processScriptRANK(): TransactionOutputRANK | null; /** * Validate the required RNKC chunks and store the processed output * @returns true if all required chunks are valid, false otherwise */ processScriptRNKC(burnedSats: number | bigint, options?: { minDataLength: number; minFeeRate: number; }): TransactionOutputRNKC | null; } //# sourceMappingURL=lokad.d.ts.map