@fiber-pay/sdk 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -0
- package/dist/index.d.ts +227 -1
- package/dist/index.js +395 -0
- package/dist/index.js.map +1 -1
- package/package.json +13 -1
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/address.ts","../src/types/policy.ts","../src/types/rpc.ts","../src/utils.ts","../src/funds/liquidity-analyzer.ts","../src/rpc/client.ts","../src/security/biscuit-policy.ts","../src/security/crypto.ts","../src/security/policy-engine.ts","../src/verification/invoice-verifier.ts"],"sourcesContent":["/**\n * CKB Address Encoding (Bech32m)\n * Encode CKB lock scripts to human-readable addresses\n */\n\n// Bech32m charset\nconst BECH32_CHARSET = 'qpzry9x8gf2tvdw0s3jn54khce6mua7l';\n\nfunction bech32mPolymod(values: number[]): number {\n const GEN = [0x3b6a57b2, 0x26508e6d, 0x1ea119fa, 0x3d4233dd, 0x2a1462b3];\n let chk = 1;\n for (const v of values) {\n const top = chk >> 25;\n chk = ((chk & 0x1ffffff) << 5) ^ v;\n for (let i = 0; i < 5; i++) {\n if ((top >> i) & 1) {\n chk ^= GEN[i];\n }\n }\n }\n return chk;\n}\n\nfunction bech32mHrpExpand(hrp: string): number[] {\n const ret: number[] = [];\n for (let i = 0; i < hrp.length; i++) {\n ret.push(hrp.charCodeAt(i) >> 5);\n }\n ret.push(0);\n for (let i = 0; i < hrp.length; i++) {\n ret.push(hrp.charCodeAt(i) & 31);\n }\n return ret;\n}\n\nfunction bech32mCreateChecksum(hrp: string, data: number[]): number[] {\n const values = bech32mHrpExpand(hrp).concat(data).concat([0, 0, 0, 0, 0, 0]);\n const polymod = bech32mPolymod(values) ^ 0x2bc830a3; // Bech32m constant\n const ret: number[] = [];\n for (let i = 0; i < 6; i++) {\n ret.push((polymod >> (5 * (5 - i))) & 31);\n }\n return ret;\n}\n\nfunction convertBits(data: Uint8Array, fromBits: number, toBits: number, pad: boolean): number[] {\n let acc = 0;\n let bits = 0;\n const ret: number[] = [];\n const maxv = (1 << toBits) - 1;\n\n for (const value of data) {\n acc = (acc << fromBits) | value;\n bits += fromBits;\n while (bits >= toBits) {\n bits -= toBits;\n ret.push((acc >> bits) & maxv);\n }\n }\n\n if (pad && bits > 0) {\n ret.push((acc << (toBits - bits)) & maxv);\n }\n\n return ret;\n}\n\nfunction bech32mEncode(hrp: string, data: number[]): string {\n const checksum = bech32mCreateChecksum(hrp, data);\n const combined = data.concat(checksum);\n let result = `${hrp}1`;\n for (const d of combined) {\n result += BECH32_CHARSET[d];\n }\n return result;\n}\n\nexport interface Script {\n code_hash: string;\n hash_type: 'type' | 'data' | 'data1' | 'data2';\n args: string;\n}\n\n/**\n * Convert a CKB lock script to a bech32m-encoded address\n * @param script - The lock script to encode\n * @param network - The CKB network ('testnet' or 'mainnet')\n * @returns Bech32m-encoded CKB address\n */\nexport function scriptToAddress(script: Script, network: 'testnet' | 'mainnet'): string {\n const hrp = network === 'mainnet' ? 'ckb' : 'ckt';\n\n // CKB full address format (2021)\n // Format: 0x00 | code_hash | hash_type | args\n const hashTypeByte =\n script.hash_type === 'type'\n ? 0x01\n : script.hash_type === 'data'\n ? 0x00\n : script.hash_type === 'data1'\n ? 0x02\n : 0x04; // data2\n\n const codeHash = script.code_hash.startsWith('0x') ? script.code_hash.slice(2) : script.code_hash;\n const args = script.args.startsWith('0x') ? script.args.slice(2) : script.args;\n\n // Construct the payload: format_type(0x00) + code_hash(32) + hash_type(1) + args\n const payload = new Uint8Array(1 + 32 + 1 + args.length / 2);\n payload[0] = 0x00; // Full format type\n\n // code_hash\n for (let i = 0; i < 32; i++) {\n payload[1 + i] = parseInt(codeHash.slice(i * 2, i * 2 + 2), 16);\n }\n\n // hash_type\n payload[33] = hashTypeByte;\n\n // args\n for (let i = 0; i < args.length / 2; i++) {\n payload[34 + i] = parseInt(args.slice(i * 2, i * 2 + 2), 16);\n }\n\n // Convert to 5-bit groups and encode with bech32m\n const data = convertBits(payload, 8, 5, true);\n return bech32mEncode(hrp, data);\n}\n","/**\n * Security Policy Types\n * Configuration for AI agent spending limits and guardrails\n */\n\nimport { z } from 'zod';\nimport type { HexString } from './rpc.js';\n\n// =============================================================================\n// Policy Configuration Schema\n// =============================================================================\n\nexport const SpendingLimitSchema = z.object({\n /** Maximum amount per single transaction (in shannons for CKB, or base units for UDT) */\n maxPerTransaction: z.string().regex(/^0x[0-9a-fA-F]+$/),\n /** Maximum total amount per time window */\n maxPerWindow: z.string().regex(/^0x[0-9a-fA-F]+$/),\n /** Time window in seconds */\n windowSeconds: z.number().positive(),\n /** Current spent amount in window (runtime state) */\n currentSpent: z\n .string()\n .regex(/^0x[0-9a-fA-F]+$/)\n .optional(),\n /** Window start timestamp (runtime state) */\n windowStart: z.number().optional(),\n});\n\nexport type SpendingLimit = z.infer<typeof SpendingLimitSchema>;\n\nexport const RecipientPolicySchema = z.object({\n /** Allowlist mode: only allow payments to these recipients */\n allowlist: z.array(z.string()).optional(),\n /** Blocklist mode: block payments to these recipients */\n blocklist: z.array(z.string()).optional(),\n /** Allow payments to unknown recipients (not in allowlist) */\n allowUnknown: z.boolean().default(true),\n});\n\nexport type RecipientPolicy = z.infer<typeof RecipientPolicySchema>;\n\nexport const RateLimitSchema = z.object({\n /** Maximum number of transactions per window */\n maxTransactions: z.number().positive(),\n /** Time window in seconds */\n windowSeconds: z.number().positive(),\n /** Cooldown between transactions in seconds */\n cooldownSeconds: z.number().nonnegative().default(0),\n /** Current transaction count in window (runtime state) */\n currentCount: z.number().optional(),\n /** Window start timestamp (runtime state) */\n windowStart: z.number().optional(),\n /** Last transaction timestamp (runtime state) */\n lastTransaction: z.number().optional(),\n});\n\nexport type RateLimit = z.infer<typeof RateLimitSchema>;\n\nexport const ChannelPolicySchema = z.object({\n /** Allow opening new channels */\n allowOpen: z.boolean().default(true),\n /** Allow closing channels */\n allowClose: z.boolean().default(true),\n /** Allow force close */\n allowForceClose: z.boolean().default(false),\n /** Maximum funding amount for new channels */\n maxFundingAmount: z\n .string()\n .regex(/^0x[0-9a-fA-F]+$/)\n .optional(),\n /** Minimum funding amount for new channels */\n minFundingAmount: z\n .string()\n .regex(/^0x[0-9a-fA-F]+$/)\n .optional(),\n /** Maximum number of channels */\n maxChannels: z.number().positive().optional(),\n});\n\nexport type ChannelPolicy = z.infer<typeof ChannelPolicySchema>;\n\nexport const SecurityPolicySchema = z.object({\n /** Policy name for identification */\n name: z.string(),\n /** Policy version */\n version: z.string().default('1.0.0'),\n /** Whether this policy is active */\n enabled: z.boolean().default(true),\n /** Spending limits configuration */\n spending: SpendingLimitSchema.optional(),\n /** Recipient restrictions */\n recipients: RecipientPolicySchema.optional(),\n /** Rate limiting configuration */\n rateLimit: RateLimitSchema.optional(),\n /** Channel operation policy */\n channels: ChannelPolicySchema.optional(),\n /** Require confirmation for amounts above this threshold */\n confirmationThreshold: z\n .string()\n .regex(/^0x[0-9a-fA-F]+$/)\n .optional(),\n /** Log all transactions to audit log */\n auditLogging: z.boolean().default(true),\n /** Custom metadata */\n metadata: z.record(z.string(), z.unknown()).optional(),\n});\n\nexport type SecurityPolicy = z.infer<typeof SecurityPolicySchema>;\n\n// =============================================================================\n// Policy Violation Types\n// =============================================================================\n\nexport type ViolationType =\n | 'SPENDING_LIMIT_PER_TX'\n | 'SPENDING_LIMIT_PER_WINDOW'\n | 'RATE_LIMIT_EXCEEDED'\n | 'RATE_LIMIT_COOLDOWN'\n | 'RECIPIENT_NOT_ALLOWED'\n | 'RECIPIENT_BLOCKED'\n | 'CHANNEL_OPEN_NOT_ALLOWED'\n | 'CHANNEL_CLOSE_NOT_ALLOWED'\n | 'CHANNEL_FORCE_CLOSE_NOT_ALLOWED'\n | 'CHANNEL_FUNDING_EXCEEDS_MAX'\n | 'CHANNEL_FUNDING_BELOW_MIN'\n | 'MAX_CHANNELS_REACHED'\n | 'REQUIRES_CONFIRMATION';\n\nexport interface PolicyViolation {\n type: ViolationType;\n message: string;\n details: {\n requested?: string;\n limit?: string;\n recipient?: string;\n remaining?: string;\n cooldownRemaining?: number;\n };\n}\n\nexport interface PolicyCheckResult {\n allowed: boolean;\n violations: PolicyViolation[];\n requiresConfirmation: boolean;\n}\n\n// =============================================================================\n// Audit Log Types\n// =============================================================================\n\nexport type AuditAction =\n | 'PAYMENT_SENT'\n | 'PAYMENT_RECEIVED'\n | 'INVOICE_CREATED'\n | 'INVOICE_VALIDATED'\n | 'HOLD_INVOICE_CREATED'\n | 'HOLD_INVOICE_SETTLED'\n | 'CHANNEL_OPENED'\n | 'CHANNEL_CLOSED'\n | 'POLICY_VIOLATION'\n | 'POLICY_UPDATED'\n | 'NODE_STARTED'\n | 'NODE_STOPPED';\n\nexport interface AuditLogEntry {\n timestamp: number;\n action: AuditAction;\n success: boolean;\n details: Record<string, unknown>;\n policyViolations?: PolicyViolation[];\n sessionId?: string;\n agentId?: string;\n}\n\n// =============================================================================\n// Key Management Types\n// =============================================================================\n\nexport interface KeyConfig {\n /** Base directory for key storage */\n baseDir: string;\n /** Password for key encryption (should come from secure source) */\n encryptionPassword?: string;\n /** Whether to generate keys if they don't exist */\n autoGenerate: boolean;\n}\n\nexport interface KeyInfo {\n /** Public key (hex) */\n publicKey: HexString;\n /** Whether the key is encrypted */\n encrypted: boolean;\n /** Key file path */\n path: string;\n /** Key creation timestamp */\n createdAt?: number;\n}\n\n// =============================================================================\n// Session Types (for multi-agent scenarios)\n// =============================================================================\n\nexport interface AgentSession {\n /** Unique session ID */\n sessionId: string;\n /** Agent identifier */\n agentId: string;\n /** Session start time */\n startedAt: number;\n /** Session expiry time */\n expiresAt?: number;\n /** Session-specific policy overrides */\n policyOverrides?: Partial<SecurityPolicy>;\n /** Session metadata */\n metadata?: Record<string, unknown>;\n}\n\n// =============================================================================\n// Default Policy\n// =============================================================================\n\nexport const DEFAULT_SECURITY_POLICY: SecurityPolicy = {\n name: 'default',\n version: '1.0.0',\n enabled: true,\n spending: {\n // 100 CKB per transaction\n maxPerTransaction: '0x2540be400',\n // 1000 CKB per hour\n maxPerWindow: '0x174876e800',\n windowSeconds: 3600,\n },\n rateLimit: {\n maxTransactions: 100,\n windowSeconds: 3600,\n cooldownSeconds: 1,\n },\n recipients: {\n allowUnknown: true,\n },\n channels: {\n allowOpen: true,\n allowClose: true,\n allowForceClose: false,\n maxChannels: 10,\n },\n auditLogging: true,\n};\n","/**\n * Fiber Network Node RPC Types (Fiber v0.7.1)\n *\n * The types in this file are intended to align with the upstream RPC spec:\n * https://github.com/nervosnetwork/fiber/blob/v0.7.1/crates/fiber-lib/src/rpc/README.md\n */\n\n// =============================================================================\n// Common Types\n// =============================================================================\n\n/** Hex-encoded string (prefixed with 0x). The RPC serializes most numeric values as hex strings. */\nexport type HexString = `0x${string}`;\n\n/** A 256-bit hash digest (Hash256 in the RPC spec). */\nexport type Hash256 = HexString;\n\n/** Public key for a node (Pubkey in the RPC spec). */\nexport type Pubkey = HexString;\n\n/** Private key (Privkey in the RPC spec). */\nexport type Privkey = HexString;\n\n/** Peer ID in libp2p format. */\nexport type PeerId = string;\n\n/** Multiaddr format for network addresses. */\nexport type Multiaddr = string;\n\n/** Channel ID (Hash256). */\nexport type ChannelId = Hash256;\n\n/** Payment hash (Hash256). */\nexport type PaymentHash = Hash256;\n\n/** Script structure for CKB. */\nexport interface Script {\n code_hash: HexString;\n hash_type: 'type' | 'data' | 'data1' | 'data2';\n args: HexString;\n}\n\n/** Transaction out point. */\nexport interface OutPoint {\n tx_hash: Hash256;\n index: HexString;\n}\n\n/** UDT (User Defined Token) script (UdtScript in the RPC spec). */\nexport type UdtScript = Script;\n\n// =============================================================================\n// Invoice Types\n// =============================================================================\n\nexport type Currency = 'Fibb' | 'Fibt' | 'Fibd';\n\nexport type HashAlgorithm = 'CkbHash' | 'Sha256';\n\n/** Recoverable signature (InvoiceSignature in the RPC spec). */\nexport type InvoiceSignature = HexString;\n\n/**\n * Invoice attribute types as returned by the RPC.\n * Each attribute is an object with a single key indicating the attribute type.\n */\nexport type Attribute =\n /** Deprecated since v0.6.0, preserved for compatibility. */\n | { FinalHtlcTimeout: HexString }\n /** Final TLC minimum expiry delta in milliseconds. */\n | { FinalHtlcMinimumExpiryDelta: HexString }\n /** Invoice expiry time in seconds. */\n | { ExpiryTime: HexString }\n /** Human-readable invoice description. */\n | { Description: string }\n /** Fallback address for on-chain settlement. */\n | { FallbackAddr: string }\n /** UDT script for token invoices. */\n | { UdtScript: UdtScript }\n /** Payee public key. */\n | { PayeePublicKey: Pubkey }\n /** Hash algorithm used in the payment hash lock. */\n | { HashAlgorithm: HashAlgorithm }\n /** Feature flags list. */\n | { Feature: string[] }\n /** Payment secret. */\n | { PaymentSecret: Hash256 };\n\nexport interface InvoiceData {\n timestamp: HexString;\n payment_hash: PaymentHash;\n attrs: Attribute[];\n}\n\nexport interface CkbInvoice {\n currency: Currency;\n amount?: HexString;\n signature?: InvoiceSignature;\n data: InvoiceData;\n}\n\nexport type CkbInvoiceStatus = 'Open' | 'Cancelled' | 'Expired' | 'Received' | 'Paid';\n\n// =============================================================================\n// Channel Types\n// =============================================================================\n\nexport enum ChannelState {\n NegotiatingFunding = 'NEGOTIATING_FUNDING',\n CollaboratingFundingTx = 'COLLABORATING_FUNDING_TX',\n SigningCommitment = 'SIGNING_COMMITMENT',\n AwaitingTxSignatures = 'AWAITING_TX_SIGNATURES',\n AwaitingChannelReady = 'AWAITING_CHANNEL_READY',\n ChannelReady = 'CHANNEL_READY',\n ShuttingDown = 'SHUTTING_DOWN',\n Closed = 'CLOSED',\n}\n\n/** Channel state flags are serialized as flag names by upstream RPC and may evolve. */\nexport type ChannelStateFlags = string[];\n\n/** TLC status. The upstream spec defines OutboundTlcStatus / InboundTlcStatus, which may evolve. */\nexport type TlcStatus = { Outbound: unknown } | { Inbound: unknown };\n\nexport interface Htlc {\n id: HexString;\n amount: HexString;\n payment_hash: PaymentHash;\n expiry: HexString;\n forwarding_channel_id?: Hash256;\n forwarding_tlc_id?: HexString;\n status: TlcStatus;\n}\n\nexport interface Channel {\n channel_id: ChannelId;\n is_public: boolean;\n is_acceptor: boolean;\n is_one_way: boolean;\n channel_outpoint: OutPoint | null;\n peer_id: PeerId;\n funding_udt_type_script: Script | null;\n state: {\n state_name: ChannelState;\n state_flags?: ChannelStateFlags;\n };\n local_balance: HexString;\n offered_tlc_balance: HexString;\n remote_balance: HexString;\n received_tlc_balance: HexString;\n pending_tlcs: Htlc[];\n latest_commitment_transaction_hash: Hash256 | null;\n created_at: HexString;\n enabled: boolean;\n tlc_expiry_delta: HexString;\n tlc_fee_proportional_millionths: HexString;\n shutdown_transaction_hash: Hash256 | null;\n failure_detail?: string;\n}\n\n// =============================================================================\n// Peer Types\n// =============================================================================\n\nexport interface PeerInfo {\n pubkey: Pubkey;\n peer_id: PeerId;\n address: Multiaddr;\n}\n\n// =============================================================================\n// Payment Types\n// =============================================================================\n\nexport type PaymentStatus = 'Created' | 'Inflight' | 'Success' | 'Failed';\n\n/**\n * Custom records for payments.\n *\n * Keys are hex-encoded u32 values (e.g. `0x1`, range 0..=65535),\n * values are hex-encoded byte arrays (0x-prefixed).\n */\nexport type PaymentCustomRecords = Record<string, HexString>;\n\nexport interface SessionRouteNode {\n pubkey: Pubkey;\n amount: HexString;\n channel_outpoint: OutPoint;\n}\n\nexport interface SessionRoute {\n nodes: SessionRouteNode[];\n}\n\nexport interface PaymentInfo {\n payment_hash: PaymentHash;\n status: PaymentStatus;\n created_at: HexString;\n last_updated_at: HexString;\n failed_error?: string;\n fee: HexString;\n custom_records?: PaymentCustomRecords;\n routers?: SessionRoute[];\n}\n\nexport interface HopHint {\n pubkey: Pubkey;\n channel_outpoint: OutPoint;\n fee_rate: HexString;\n tlc_expiry_delta: HexString;\n}\n\n// =============================================================================\n// Node / UDT Types\n// =============================================================================\n\nexport interface UdtCellDep {\n out_point: OutPoint;\n dep_type: 'code' | 'dep_group';\n}\n\nexport interface UdtDep {\n cell_dep?: UdtCellDep | null;\n type_id?: Script | null;\n}\n\nexport interface UdtArgInfo {\n name: string;\n script: UdtScript;\n auto_accept_amount?: HexString;\n cell_deps: UdtDep[];\n}\n\nexport type UdtCfgInfos = UdtArgInfo[];\n\nexport interface NodeInfo {\n version: string;\n commit_hash: string;\n node_id: Pubkey;\n features: string[];\n node_name: string | null;\n addresses: Multiaddr[];\n chain_hash: Hash256;\n open_channel_auto_accept_min_ckb_funding_amount: HexString;\n auto_accept_channel_ckb_funding_amount: HexString;\n default_funding_lock_script: Script;\n tlc_expiry_delta: HexString;\n tlc_min_value: HexString;\n tlc_fee_proportional_millionths: HexString;\n channel_count: HexString;\n pending_channel_count: HexString;\n peers_count: HexString;\n udt_cfg_infos: UdtCfgInfos;\n}\n\n// =============================================================================\n// Graph Types\n// =============================================================================\n\nexport interface ChannelUpdateInfo {\n timestamp: HexString;\n enabled: boolean;\n outbound_liquidity?: HexString;\n tlc_expiry_delta: HexString;\n tlc_minimum_value: HexString;\n fee_rate: HexString;\n}\n\nexport interface GraphNodeInfo {\n node_name: string;\n version: string;\n addresses: Multiaddr[];\n features: string[];\n node_id: Pubkey;\n timestamp: HexString;\n chain_hash: Hash256;\n auto_accept_min_ckb_funding_amount: HexString;\n udt_cfg_infos: UdtCfgInfos;\n}\n\nexport interface GraphChannelInfo {\n channel_outpoint: OutPoint;\n node1: Pubkey;\n node2: Pubkey;\n created_timestamp: HexString;\n update_info_of_node1?: ChannelUpdateInfo | null;\n update_info_of_node2?: ChannelUpdateInfo | null;\n capacity: HexString;\n chain_hash: Hash256;\n udt_type_script?: Script | null;\n}\n\n// =============================================================================\n// RPC Request/Response Types\n// =============================================================================\n\n// --- Peer Module ---\n\nexport interface ConnectPeerParams {\n address: Multiaddr;\n save?: boolean;\n}\n\n/** connect_peer returns null. */\nexport type ConnectPeerResult = null;\n\nexport interface DisconnectPeerParams {\n peer_id: PeerId;\n}\n\nexport interface ListPeersResult {\n peers: PeerInfo[];\n}\n\n// --- Channel Module ---\n\nexport interface OpenChannelParams {\n peer_id: PeerId;\n funding_amount: HexString;\n public?: boolean;\n one_way?: boolean;\n funding_udt_type_script?: Script;\n shutdown_script?: Script;\n commitment_delay_epoch?: HexString;\n commitment_fee_rate?: HexString;\n funding_fee_rate?: HexString;\n tlc_expiry_delta?: HexString;\n tlc_min_value?: HexString;\n tlc_fee_proportional_millionths?: HexString;\n max_tlc_value_in_flight?: HexString;\n max_tlc_number_in_flight?: HexString;\n}\n\nexport interface OpenChannelResult {\n temporary_channel_id: ChannelId;\n}\n\nexport interface AcceptChannelParams {\n temporary_channel_id: ChannelId;\n funding_amount: HexString;\n shutdown_script?: Script;\n max_tlc_value_in_flight?: HexString;\n max_tlc_number_in_flight?: HexString;\n tlc_min_value?: HexString;\n tlc_fee_proportional_millionths?: HexString;\n tlc_expiry_delta?: HexString;\n}\n\nexport interface AcceptChannelResult {\n channel_id: ChannelId;\n}\n\nexport interface ListChannelsParams {\n peer_id?: PeerId;\n include_closed?: boolean;\n only_pending?: boolean;\n}\n\nexport interface ListChannelsResult {\n channels: Channel[];\n}\n\nexport interface ShutdownChannelParams {\n channel_id: ChannelId;\n close_script?: Script;\n fee_rate?: HexString;\n force?: boolean;\n}\n\nexport interface AbandonChannelParams {\n channel_id: ChannelId;\n}\n\nexport interface UpdateChannelParams {\n channel_id: ChannelId;\n enabled?: boolean;\n tlc_expiry_delta?: HexString;\n tlc_minimum_value?: HexString;\n tlc_fee_proportional_millionths?: HexString;\n}\n\n// --- Payment Module ---\n\nexport interface SendPaymentParams {\n target_pubkey?: Pubkey;\n amount?: HexString;\n payment_hash?: PaymentHash;\n final_tlc_expiry_delta?: HexString;\n tlc_expiry_limit?: HexString;\n invoice?: string;\n timeout?: HexString;\n max_fee_amount?: HexString;\n max_fee_rate?: HexString;\n max_parts?: HexString;\n trampoline_hops?: Pubkey[];\n keysend?: boolean;\n udt_type_script?: Script;\n allow_self_payment?: boolean;\n custom_records?: PaymentCustomRecords;\n hop_hints?: HopHint[];\n dry_run?: boolean;\n}\n\nexport interface SendPaymentResult extends PaymentInfo {}\n\nexport interface GetPaymentParams {\n payment_hash: PaymentHash;\n}\n\nexport interface GetPaymentResult extends PaymentInfo {}\n\n// --- Invoice Module ---\n\nexport interface NewInvoiceParams {\n amount: HexString;\n description?: string;\n currency: Currency;\n payment_preimage?: Hash256;\n payment_hash?: PaymentHash;\n expiry?: HexString;\n fallback_address?: string;\n final_expiry_delta?: HexString;\n udt_type_script?: Script;\n hash_algorithm?: HashAlgorithm;\n allow_mpp?: boolean;\n allow_trampoline_routing?: boolean;\n}\n\nexport interface NewInvoiceResult {\n invoice_address: string;\n invoice: CkbInvoice;\n}\n\nexport interface ParseInvoiceParams {\n invoice: string;\n}\n\nexport interface ParseInvoiceResult {\n invoice: CkbInvoice;\n}\n\nexport interface GetInvoiceParams {\n payment_hash: PaymentHash;\n}\n\nexport interface GetInvoiceResult {\n invoice_address: string;\n invoice: CkbInvoice;\n status: CkbInvoiceStatus;\n}\n\nexport interface CancelInvoiceParams {\n payment_hash: PaymentHash;\n}\n\nexport interface CancelInvoiceResult {\n invoice_address: string;\n invoice: CkbInvoice;\n status: CkbInvoiceStatus;\n}\n\nexport interface SettleInvoiceParams {\n payment_hash: PaymentHash;\n payment_preimage: Hash256;\n}\n\n// --- Router Module ---\n\nexport interface HopRequire {\n pubkey: Pubkey;\n channel_outpoint?: OutPoint | null;\n}\n\nexport interface BuildRouterParams {\n amount?: HexString;\n udt_type_script?: Script;\n hops_info: HopRequire[];\n final_tlc_expiry_delta?: HexString;\n}\n\nexport interface RouterHop {\n target: Pubkey;\n channel_outpoint: OutPoint;\n amount_received: HexString;\n incoming_tlc_expiry: HexString;\n}\n\nexport interface BuildRouterResult {\n router_hops: RouterHop[];\n}\n\nexport interface SendPaymentWithRouterParams {\n payment_hash?: PaymentHash;\n router: RouterHop[];\n invoice?: string;\n custom_records?: PaymentCustomRecords;\n keysend?: boolean;\n allow_self_payment?: boolean;\n udt_type_script?: Script;\n dry_run?: boolean;\n}\n\n// --- Graph Module ---\n\nexport interface GraphNodesParams {\n limit?: HexString;\n after?: HexString;\n}\n\nexport interface GraphNodesResult {\n nodes: GraphNodeInfo[];\n last_cursor: HexString;\n}\n\nexport interface GraphChannelsParams {\n limit?: HexString;\n after?: HexString;\n}\n\nexport interface GraphChannelsResult {\n channels: GraphChannelInfo[];\n last_cursor: HexString;\n}\n\n// =============================================================================\n// Additional Upstream RPC Types (for advanced custom call usage)\n// =============================================================================\n\n/** Cross-chain hub invoice variant. */\nexport type CchInvoice = { Fiber: string } | { Lightning: string };\n\n/** Cross-chain hub order status. */\nexport type CchOrderStatus =\n | 'Pending'\n | 'IncomingAccepted'\n | 'OutgoingInFlight'\n | 'OutgoingSucceeded'\n | 'Succeeded'\n | 'Failed';\n\n/** Reason for removing a TLC in Dev module APIs. */\nexport type RemoveTlcReason = { RemoveTlcFulfill: Hash256 } | { RemoveTlcFail: HexString };\n\n/** TLC id wrapper in watchtower-related types. */\nexport type TLCId = { Offered: HexString } | { Received: HexString };\n\n/** Minimal CKB cell output representation used by watchtower revocation data. */\nexport interface CellOutput {\n capacity: HexString;\n lock: Script;\n type?: Script | null;\n}\n\n/** Settlement TLC data used by watchtower operations. */\nexport interface SettlementTlc {\n tlc_id: TLCId;\n hash_algorithm: HashAlgorithm;\n payment_amount: HexString;\n payment_hash: Hash256;\n expiry: HexString;\n local_key: Privkey;\n remote_key: Pubkey;\n}\n\n/** Settlement data used by watchtower operations. */\nexport interface SettlementData {\n local_amount: HexString;\n remote_amount: HexString;\n tlcs: SettlementTlc[];\n}\n\n/** Revocation data used by watchtower operations. */\nexport interface RevocationData {\n commitment_number: HexString;\n aggregated_signature: HexString;\n output: CellOutput;\n output_data: HexString;\n}\n\n// --- Info Module ---\n\nexport interface NodeInfoResult extends NodeInfo {}\n\n// =============================================================================\n// JSON-RPC Types\n// =============================================================================\n\nexport interface JsonRpcRequest<T = unknown> {\n jsonrpc: '2.0';\n id: number | string;\n method: string;\n params: T[];\n}\n\nexport interface JsonRpcResponse<T = unknown> {\n jsonrpc: '2.0';\n id: number | string;\n result?: T;\n error?: JsonRpcError;\n}\n\nexport interface JsonRpcError {\n code: number;\n message: string;\n data?: unknown;\n}\n","/**\n * Utility Functions\n * Common utilities for hex conversion, CKB amount calculation, and random generation\n */\n\nimport type { HexString } from './types/index.js';\n\nconst BASE58_ALPHABET = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';\n\n/**\n * Convert number to hex string\n */\nexport function toHex(value: number | bigint): HexString {\n return `0x${value.toString(16)}`;\n}\n\n/**\n * Convert hex string to bigint\n */\nexport function fromHex(hex: HexString): bigint {\n return BigInt(hex);\n}\n\n/**\n * Convert CKB amount (in CKB units) to shannons (hex)\n */\nexport function ckbToShannons(ckb: number | string): HexString {\n const amount = typeof ckb === 'string' ? parseFloat(ckb) : ckb;\n const shannons = BigInt(Math.floor(amount * 1e8));\n return toHex(shannons);\n}\n\n/**\n * Convert shannons (hex) to CKB amount\n */\nexport function shannonsToCkb(shannons: HexString): number {\n return Number(fromHex(shannons)) / 1e8;\n}\n\n/**\n * Generate a random 32-byte hex string (for payment preimage)\n */\nexport function randomBytes32(): HexString {\n const bytes = new Uint8Array(32);\n crypto.getRandomValues(bytes);\n return `0x${Array.from(bytes)\n .map((b) => b.toString(16).padStart(2, '0'))\n .join('')}`;\n}\n\nfunction base58btcEncode(bytes: Uint8Array): string {\n if (bytes.length === 0) return '';\n\n let number = 0n;\n for (const byte of bytes) {\n number = (number << 8n) + BigInt(byte);\n }\n\n let encoded = '';\n while (number > 0n) {\n const remainder = Number(number % 58n);\n encoded = BASE58_ALPHABET[remainder] + encoded;\n number /= 58n;\n }\n\n for (let i = 0; i < bytes.length && bytes[i] === 0; i++) {\n encoded = `1${encoded}`;\n }\n\n return encoded || '1';\n}\n\n/**\n * Convert a Fiber node id (hex-encoded compressed secp256k1 pubkey, 33 bytes)\n * to a libp2p peer id (base58btc encoded sha2-256 multihash).\n */\nexport async function nodeIdToPeerId(nodeId: string): Promise<string> {\n const normalized = nodeId.trim().replace(/^0x/i, '');\n\n if (!/^[0-9a-fA-F]+$/.test(normalized)) {\n throw new Error('Invalid node id: expected hex string');\n }\n if (normalized.length !== 66) {\n throw new Error(\n `Invalid node id: expected 33-byte compressed pubkey, got ${normalized.length / 2} bytes`,\n );\n }\n\n const raw = Uint8Array.from(\n normalized.match(/.{1,2}/g)?.map((byte) => Number.parseInt(byte, 16)) ?? [],\n );\n\n if (raw.length !== 33) {\n throw new Error(`Invalid node id: expected 33-byte compressed pubkey, got ${raw.length} bytes`);\n }\n\n const digestBuffer = await crypto.subtle.digest('SHA-256', raw);\n const digest = new Uint8Array(digestBuffer);\n const multihash = new Uint8Array(2 + digest.length);\n multihash[0] = 0x12;\n multihash[1] = 0x20;\n multihash.set(digest, 2);\n\n return base58btcEncode(multihash);\n}\n\n/**\n * Build a canonical multiaddr by appending/replacing /p2p/<peerId>.\n */\nexport function buildMultiaddr(address: string, peerId: string): string {\n const normalizedAddress = address.trim();\n const normalizedPeerId = peerId.trim();\n\n if (!normalizedAddress.startsWith('/')) {\n throw new Error('Invalid multiaddr: expected address starting with \"/\"');\n }\n if (!normalizedPeerId) {\n throw new Error('Invalid peer id: empty value');\n }\n\n const withoutPeerSuffix = normalizedAddress.replace(/\\/p2p\\/[^/]+$/, '');\n return `${withoutPeerSuffix}/p2p/${normalizedPeerId}`;\n}\n\n/**\n * Build a canonical multiaddr from a node id and base address.\n */\nexport async function buildMultiaddrFromNodeId(address: string, nodeId: string): Promise<string> {\n const peerId = await nodeIdToPeerId(nodeId);\n return buildMultiaddr(address, peerId);\n}\n\n/**\n * Build a best-effort local multiaddr from an RPC URL and peer id.\n * Uses rpcPort + 1 as inferred P2P port when advertised addresses are unavailable.\n */\nexport function buildMultiaddrFromRpcUrl(rpcUrl: string, peerId: string): string {\n let parsed: URL;\n try {\n parsed = new URL(rpcUrl);\n } catch {\n throw new Error(`Invalid RPC URL: ${rpcUrl}`);\n }\n\n if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {\n throw new Error(`Unsupported RPC protocol: ${parsed.protocol}`);\n }\n\n const port = parsed.port\n ? Number.parseInt(parsed.port, 10)\n : parsed.protocol === 'https:'\n ? 443\n : 80;\n if (!Number.isFinite(port) || port <= 0 || port > 65535) {\n throw new Error(`Invalid RPC port in URL: ${rpcUrl}`);\n }\n\n const p2pPort = port + 1;\n if (p2pPort > 65535) {\n throw new Error(`Cannot infer P2P port from RPC port ${port}`);\n }\n\n const host = parsed.hostname;\n const isIpv4 = /^\\d{1,3}(?:\\.\\d{1,3}){3}$/.test(host);\n const isIpv6 = host.includes(':');\n const base = isIpv4\n ? `/ip4/${host}/tcp/${p2pPort}`\n : isIpv6\n ? `/ip6/${host}/tcp/${p2pPort}`\n : `/dns/${host}/tcp/${p2pPort}`;\n\n return buildMultiaddr(base, peerId);\n}\n","/**\n * Fund Management & Liquidity Analyzer\n * Analyzes channel health, identifies liquidity gaps, and provides funding recommendations\n */\n\nimport type { FiberRpcClient } from '../rpc/client.js';\nimport type { Channel } from '../types/index.js';\nimport { ChannelState } from '../types/index.js';\nimport { shannonsToCkb } from '../utils.js';\n\n// =============================================================================\n// Types\n// =============================================================================\n\n/**\n * Channel health score breakdown\n */\nexport interface ChannelHealthMetrics {\n channelId: string;\n peerId: string;\n localBalanceCkb: number;\n remoteBalanceCkb: number;\n totalCapacityCkb: number;\n utilizationPercent: number; // How much of capacity is used\n balanceRatioPercent: number; // % of capacity on local side (50% = perfectly balanced)\n isBalanced: boolean; // Within 40-60% = balanced\n pendingLocalCkb: number; // Pending offered payments\n pendingRemoteCkb: number; // Pending received payments\n availableToSendCkb: number; // Can actually send right now\n availableToReceiveCkb: number; // Can actually receive right now\n healthScore: number; // 0-100\n state: ChannelState;\n}\n\nexport interface LiquidityGap {\n amount: number; // How much liquidity is missing\n reason: string; // Why it's needed\n severity: 'low' | 'medium' | 'high'; // Impact on operations\n affectedChannels: string[];\n}\n\nexport interface RebalanceRecommendation {\n from: string; // Source channel ID\n to: string; // Destination channel ID\n amountCkb: number;\n reason: string;\n benefit: string; // What this achieves\n estimatedRoutingFeeCkb: number;\n priority: number; // 1 (low) to 10 (critical)\n}\n\nexport interface FundingNeed {\n amount: number; // How much funding needed\n reason: string;\n optimalChannelPeerId?: string; // Recommended peer ID to fund\n urgency: 'low' | 'normal' | 'high';\n estimatedTimeToDepletion?: number; // Days until liquidity runs out\n}\n\nexport interface LiquidityReport {\n timestamp: number;\n balance: {\n totalCkb: number;\n availableToSendCkb: number;\n availableToReceiveCkb: number;\n lockedInChannelsCkb: number;\n };\n channels: {\n count: number;\n health: ChannelHealthMetrics[];\n averageHealthScore: number;\n balancedCount: number;\n imbalancedCount: number;\n };\n liquidity: {\n gaps: LiquidityGap[];\n hasCriticalGaps: boolean;\n runway: {\n daysAtCurrentRate?: number;\n estimatedDailySpendCkb?: number;\n };\n };\n recommendations: {\n rebalances: RebalanceRecommendation[];\n funding: FundingNeed[];\n };\n summary: string; // Human-readable summary\n}\n\n// =============================================================================\n// Liquidity Analyzer\n// =============================================================================\n\nexport class LiquidityAnalyzer {\n constructor(private rpc: FiberRpcClient) {}\n\n /**\n * Comprehensive liquidity analysis\n */\n async analyzeLiquidity(): Promise<LiquidityReport> {\n const timestamp = Date.now();\n\n // Fetch data\n const channels = await this.rpc.listChannels({});\n\n // Analyze each channel\n const channelMetrics: ChannelHealthMetrics[] = channels.channels.map((ch) =>\n this.analyzeChannelHealth(ch),\n );\n\n // Calculate totals\n const totalCkb = channelMetrics.reduce(\n (sum, ch) => sum + ch.localBalanceCkb + ch.remoteBalanceCkb,\n 0,\n );\n const availableToSendCkb = channelMetrics.reduce((sum, ch) => sum + ch.availableToSendCkb, 0);\n const availableToReceiveCkb = channelMetrics.reduce(\n (sum, ch) => sum + ch.availableToReceiveCkb,\n 0,\n );\n\n // Identify gaps and issues\n const gaps = this.identifyLiquidityGaps(channelMetrics, availableToSendCkb);\n\n // Generate rebalance recommendations\n const rebalances = this.generateRebalanceRecommendations(channelMetrics);\n\n // Estimate funding needs\n const fundingNeeds = this.estimateFundingNeeds(channelMetrics, gaps);\n\n // Calculate runway\n const runway = this.estimateRunway(availableToSendCkb, channelMetrics);\n\n // Summary\n const summary = this.generateSummary(channelMetrics, gaps, fundingNeeds, runway);\n\n return {\n timestamp,\n balance: {\n totalCkb,\n availableToSendCkb,\n availableToReceiveCkb,\n lockedInChannelsCkb: totalCkb - availableToSendCkb - availableToReceiveCkb,\n },\n channels: {\n count: channels.channels.length,\n health: channelMetrics,\n averageHealthScore:\n channelMetrics.length > 0\n ? channelMetrics.reduce((sum, ch) => sum + ch.healthScore, 0) / channelMetrics.length\n : 0,\n balancedCount: channelMetrics.filter((ch) => ch.isBalanced).length,\n imbalancedCount: channelMetrics.filter((ch) => !ch.isBalanced).length,\n },\n liquidity: {\n gaps,\n hasCriticalGaps: gaps.some((g) => g.severity === 'high'),\n runway,\n },\n recommendations: {\n rebalances,\n funding: fundingNeeds,\n },\n summary,\n };\n }\n\n /**\n * Analyze individual channel health\n */\n private analyzeChannelHealth(channel: Channel): ChannelHealthMetrics {\n const localBalance = shannonsToCkb(channel.local_balance);\n const remoteBalance = shannonsToCkb(channel.remote_balance);\n const totalCapacity = localBalance + remoteBalance;\n\n const pendingLocal = shannonsToCkb(channel.offered_tlc_balance);\n const pendingRemote = shannonsToCkb(channel.received_tlc_balance);\n\n const availableToSend = Math.max(0, localBalance - pendingLocal);\n const availableToReceive = Math.max(0, remoteBalance - pendingRemote);\n\n const utilizationPercent =\n totalCapacity > 0 ? ((pendingLocal + pendingRemote) / totalCapacity) * 100 : 0;\n const balanceRatioPercent = totalCapacity > 0 ? (localBalance / totalCapacity) * 100 : 50;\n\n // Channel is balanced if local balance is 40-60% of total\n const isBalanced = balanceRatioPercent >= 40 && balanceRatioPercent <= 60;\n\n // Health score (0-100)\n let healthScore = 100;\n\n // Deduct for high utilization (pending payments)\n if (utilizationPercent > 80) healthScore -= 20;\n else if (utilizationPercent > 50) healthScore -= 10;\n\n // Deduct for imbalance\n const imbalance = Math.abs(50 - balanceRatioPercent);\n healthScore -= (imbalance / 50) * 20; // Up to 20 points for extreme imbalance\n\n // Bonus for healthy balance\n if (isBalanced && utilizationPercent < 50) healthScore += 10;\n\n healthScore = Math.max(0, Math.min(100, healthScore));\n\n return {\n channelId: channel.channel_id,\n peerId: channel.peer_id,\n localBalanceCkb: localBalance,\n remoteBalanceCkb: remoteBalance,\n totalCapacityCkb: totalCapacity,\n utilizationPercent,\n balanceRatioPercent,\n isBalanced,\n pendingLocalCkb: pendingLocal,\n pendingRemoteCkb: pendingRemote,\n availableToSendCkb: availableToSend,\n availableToReceiveCkb: availableToReceive,\n healthScore,\n state: channel.state.state_name,\n };\n }\n\n /**\n * Identify liquidity shortfalls and gaps\n */\n private identifyLiquidityGaps(\n metrics: ChannelHealthMetrics[],\n _totalSendable: number,\n ): LiquidityGap[] {\n const gaps: LiquidityGap[] = [];\n\n // Gap 1: No send-capable channels\n const sendCapableCount = metrics.filter((ch) => ch.availableToSendCkb > 0).length;\n if (sendCapableCount === 0 && metrics.length > 0) {\n gaps.push({\n amount: 100, // Arbitrary amount - need to rebalance\n reason: 'No channels currently capable of sending. All liquidity on remote side.',\n severity: 'high',\n affectedChannels: metrics.map((ch) => ch.channelId),\n });\n }\n\n // Gap 2: All channels imbalanced (all local-heavy or all remote-heavy)\n const allLocalHeavy = metrics.every((ch) => ch.balanceRatioPercent > 70);\n const allRemoteHeavy = metrics.every((ch) => ch.balanceRatioPercent < 30);\n\n if (allLocalHeavy) {\n gaps.push({\n amount: 0, // Rebalance doesn't require funding\n reason: 'All channels are local-heavy. Cannot receive payments. Need inbound liquidity.',\n severity: 'high',\n affectedChannels: metrics.map((ch) => ch.channelId),\n });\n }\n\n if (allRemoteHeavy) {\n gaps.push({\n amount: 0, // Need to open new channels or rebalance\n reason: 'All channels are remote-heavy. Cannot send without rebalancing or new channels.',\n severity: 'high',\n affectedChannels: metrics.map((ch) => ch.channelId),\n });\n }\n\n // Gap 3: High utilization in all channels\n const allHighUtilization = metrics.every((ch) => ch.utilizationPercent > 70);\n if (allHighUtilization) {\n gaps.push({\n amount: 0,\n reason:\n 'High utilization in all channels. Many pending payments. Risk of payment failures.',\n severity: 'medium',\n affectedChannels: metrics.map((ch) => ch.channelId),\n });\n }\n\n return gaps;\n }\n\n /**\n * Generate rebalance recommendations between channels\n */\n private generateRebalanceRecommendations(\n metrics: ChannelHealthMetrics[],\n ): RebalanceRecommendation[] {\n const recommendations: RebalanceRecommendation[] = [];\n\n // Look for pairs: one local-heavy, one remote-heavy\n const localHeavy = metrics.filter((ch) => ch.balanceRatioPercent > 65);\n const remoteHeavy = metrics.filter((ch) => ch.balanceRatioPercent < 35);\n\n // Sort by how imbalanced they are\n localHeavy.sort((a, b) => b.balanceRatioPercent - a.balanceRatioPercent);\n remoteHeavy.sort((a, b) => a.balanceRatioPercent - b.balanceRatioPercent);\n\n // Pair them up\n for (let i = 0; i < Math.min(localHeavy.length, remoteHeavy.length); i++) {\n const source = localHeavy[i];\n const dest = remoteHeavy[i];\n\n // Calculate how much to move to balance both closer to 50%\n const sourceExcess = source.localBalanceCkb - source.totalCapacityCkb * 0.5;\n const destDeficit = dest.totalCapacityCkb * 0.5 - dest.localBalanceCkb;\n\n const amountToMove = Math.min(sourceExcess, destDeficit) * 0.8; // Move 80% to be conservative\n\n if (amountToMove > 0.1) {\n // Only if meaningful amount\n recommendations.push({\n from: source.channelId,\n to: dest.channelId,\n amountCkb: amountToMove,\n reason: `Rebalance liquidity: source is ${source.balanceRatioPercent.toFixed(0)}% local, destination is ${dest.balanceRatioPercent.toFixed(0)}% local`,\n benefit: `Improves payment success rate by balancing channel liquidity`,\n estimatedRoutingFeeCkb: amountToMove * 0.001, // 0.1% estimated fee\n priority: Math.round(\n (Math.abs(50 - source.balanceRatioPercent) + Math.abs(50 - dest.balanceRatioPercent)) /\n 20,\n ), // 1-10\n });\n }\n }\n\n return recommendations.sort((a, b) => b.priority - a.priority);\n }\n\n /**\n * Estimate funding needs for future operations\n */\n private estimateFundingNeeds(\n metrics: ChannelHealthMetrics[],\n gaps: LiquidityGap[],\n ): FundingNeed[] {\n const needs: FundingNeed[] = [];\n\n // If there are critical gaps, funding is needed\n const criticalGaps = gaps.filter((g) => g.severity === 'high');\n if (criticalGaps.length > 0) {\n // Find the best channel to fund (most balanced, highest capacity)\n const bestChannel = [...metrics]\n .filter((ch) => ch.state === ChannelState.ChannelReady)\n .sort((a, b) => {\n const scoreA = a.healthScore + a.totalCapacityCkb / 1000; // Higher score + capacity = better\n const scoreB = b.healthScore + b.totalCapacityCkb / 1000;\n return scoreB - scoreA;\n })[0];\n\n const fundingAmount = Math.ceil(bestChannel?.totalCapacityCkb || 100);\n\n needs.push({\n amount: fundingAmount,\n reason: 'Critical liquidity gaps detected in current channels',\n optimalChannelPeerId: bestChannel?.peerId,\n urgency: 'high',\n });\n }\n\n // If all channels are small, recommend growth\n const avgCapacity =\n metrics.length > 0\n ? metrics.reduce((sum, ch) => sum + ch.totalCapacityCkb, 0) / metrics.length\n : 0;\n\n if (avgCapacity < 100) {\n needs.push({\n amount: 500, // Reasonable growth target\n reason: 'Average channel capacity is small. Consider larger channels for reliability.',\n urgency: 'low',\n });\n }\n\n return needs;\n }\n\n /**\n * Estimate runway (days until liquidity depleted at current spending rate)\n */\n private estimateRunway(\n availableToSend: number,\n _metrics: ChannelHealthMetrics[],\n ): {\n daysAtCurrentRate?: number;\n estimatedDailySpendCkb?: number;\n } {\n // This is a simplified estimate\n // In real implementation, would track historical spending\n const estimatedDailySpend = 0.1; // Default: assume 0.1 CKB per day\n\n if (availableToSend > 0 && estimatedDailySpend > 0) {\n const days = availableToSend / estimatedDailySpend;\n return {\n daysAtCurrentRate: Math.floor(days),\n estimatedDailySpendCkb: estimatedDailySpend,\n };\n }\n\n return {};\n }\n\n /**\n * Generate human-readable summary\n */\n private generateSummary(\n metrics: ChannelHealthMetrics[],\n gaps: LiquidityGap[],\n fundingNeeds: FundingNeed[],\n runway: {\n daysAtCurrentRate?: number;\n estimatedDailySpendCkb?: number;\n },\n ): string {\n const parts: string[] = [];\n\n if (metrics.length === 0) {\n return 'No channels available. Open a channel to start making payments.';\n }\n\n parts.push(\n `Channel Health: ${metrics.filter((ch) => ch.healthScore >= 70).length}/${metrics.length} channels healthy`,\n );\n\n const avgScore = metrics.reduce((sum, ch) => sum + ch.healthScore, 0) / metrics.length;\n if (avgScore >= 80) {\n parts.push('Overall liquidity is good ✓');\n } else if (avgScore >= 60) {\n parts.push('Overall liquidity is fair. Some rebalancing recommended.');\n } else {\n parts.push('Overall liquidity is poor. Rebalancing needed urgently.');\n }\n\n if (gaps.length > 0) {\n parts.push(`${gaps.length} liquidity gap(s) detected.`);\n }\n\n if (fundingNeeds.length > 0) {\n parts.push(\n `Need to fund ${fundingNeeds.map((n) => n.amount).join(', ')} CKB to resolve issues.`,\n );\n }\n\n if (runway.daysAtCurrentRate) {\n parts.push(`Estimated runway: ${runway.daysAtCurrentRate} days at current spending rate.`);\n }\n\n return parts.join(' ');\n }\n\n /**\n * Get missing liquidity for a specific amount\n */\n async getMissingLiquidityForAmount(targetCkb: number): Promise<{\n canSend: boolean;\n shortfallCkb: number;\n recommendation: string;\n }> {\n const report = await this.analyzeLiquidity();\n\n const shortfallCkb = Math.max(0, targetCkb - report.balance.availableToSendCkb);\n const canSend = shortfallCkb === 0;\n\n let recommendation = '';\n if (canSend) {\n recommendation = `You have enough liquidity to send ${targetCkb} CKB.`;\n } else {\n recommendation = `You need ${shortfallCkb.toFixed(4)} more CKB in send capacity. Consider rebalancing or opening larger channels.`;\n }\n\n return { canSend, shortfallCkb, recommendation };\n }\n}\n","/**\n * Fiber RPC Client\n * Type-safe JSON-RPC client for Fiber Network Node\n */\n\nimport type {\n AbandonChannelParams,\n AcceptChannelParams,\n AcceptChannelResult,\n // Router methods\n BuildRouterParams,\n BuildRouterResult,\n CancelInvoiceParams,\n CancelInvoiceResult,\n Channel,\n ChannelId,\n CkbInvoiceStatus,\n // Peer methods\n ConnectPeerParams,\n ConnectPeerResult,\n DisconnectPeerParams,\n GetInvoiceParams,\n GetInvoiceResult,\n GetPaymentParams,\n GetPaymentResult,\n GraphChannelsParams,\n GraphChannelsResult,\n // Graph methods\n GraphNodesParams,\n GraphNodesResult,\n JsonRpcError,\n JsonRpcRequest,\n JsonRpcResponse,\n ListChannelsParams,\n ListChannelsResult,\n ListPeersResult,\n // Invoice methods\n NewInvoiceParams,\n NewInvoiceResult,\n // Info methods\n NodeInfoResult,\n // Channel methods\n OpenChannelParams,\n OpenChannelResult,\n ParseInvoiceParams,\n ParseInvoiceResult,\n PaymentHash,\n // Payment methods\n SendPaymentParams,\n SendPaymentResult,\n SendPaymentWithRouterParams,\n SettleInvoiceParams,\n ShutdownChannelParams,\n UpdateChannelParams,\n} from '../types/index.js';\nimport { ChannelState, type HashAlgorithm } from '../types/index.js';\n\n// =============================================================================\n// Constants\n// =============================================================================\n\n/**\n * Mapping from SDK PascalCase HashAlgorithm to FNN RPC snake_case values.\n *\n * Upstream issue: https://github.com/RetricSu/fiber-pay/issues/66\n *\n * The SDK's HashAlgorithm type uses PascalCase ('CkbHash' | 'Sha256')\n * but FNN v0.7.1 RPC expects snake_case ('ckb_hash' | 'sha256').\n */\nconst HASH_ALGORITHM_MAP: Record<HashAlgorithm, string> = {\n CkbHash: 'ckb_hash',\n Sha256: 'sha256',\n};\n\n// =============================================================================\n// RPC Client Configuration\n// =============================================================================\n\nexport interface RpcClientConfig {\n /** RPC endpoint URL */\n url: string;\n /** Request timeout in milliseconds */\n timeout?: number;\n /** Custom headers */\n headers?: Record<string, string>;\n /**\n * Biscuit token for authentication.\n *\n * Prefer server-side usage. In browser apps, avoid embedding long-lived\n * privileged tokens and use a trusted backend/proxy where possible.\n */\n biscuitToken?: string;\n}\n\n// =============================================================================\n// RPC Error\n// =============================================================================\n\nexport class FiberRpcError extends Error {\n constructor(\n public code: number,\n message: string,\n public data?: unknown,\n ) {\n super(message);\n this.name = 'FiberRpcError';\n }\n\n static fromJsonRpcError(error: JsonRpcError): FiberRpcError {\n return new FiberRpcError(error.code, error.message, error.data);\n }\n}\n\n// =============================================================================\n// RPC Client\n// =============================================================================\n\nexport class FiberRpcClient {\n private requestId = 0;\n private config: Required<Pick<RpcClientConfig, 'url' | 'timeout'>> & RpcClientConfig;\n\n private readonly channelStateAliases: Record<string, ChannelState> = {\n NEGOTIATING_FUNDING: ChannelState.NegotiatingFunding,\n COLLABORATING_FUNDING_TX: ChannelState.CollaboratingFundingTx,\n SIGNING_COMMITMENT: ChannelState.SigningCommitment,\n AWAITING_TX_SIGNATURES: ChannelState.AwaitingTxSignatures,\n AWAITING_CHANNEL_READY: ChannelState.AwaitingChannelReady,\n CHANNEL_READY: ChannelState.ChannelReady,\n SHUTTING_DOWN: ChannelState.ShuttingDown,\n CLOSED: ChannelState.Closed,\n };\n\n constructor(config: RpcClientConfig) {\n this.config = {\n timeout: 30000,\n ...config,\n };\n }\n\n /**\n * Make a raw JSON-RPC call\n *\n * Useful for advanced/experimental RPCs not wrapped by convenience methods.\n *\n * @example\n * ```ts\n * const result = await client.call<MyResult>('some_method', [{ foo: 'bar' }]);\n * ```\n */\n async call<TResult>(method: string, params: unknown[] = []): Promise<TResult> {\n const request: JsonRpcRequest = {\n jsonrpc: '2.0',\n id: ++this.requestId,\n method,\n params,\n };\n\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n ...this.config.headers,\n };\n\n if (this.config.biscuitToken) {\n headers.Authorization = `Bearer ${this.config.biscuitToken}`;\n }\n\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.config.timeout);\n\n try {\n const response = await fetch(this.config.url, {\n method: 'POST',\n headers,\n body: JSON.stringify(request),\n signal: controller.signal,\n });\n\n if (!response.ok) {\n throw new FiberRpcError(-32000, `HTTP error: ${response.status} ${response.statusText}`);\n }\n\n const json = (await response.json()) as JsonRpcResponse<TResult>;\n\n if (json.error) {\n throw FiberRpcError.fromJsonRpcError(json.error);\n }\n\n if (json.result === undefined) {\n throw new FiberRpcError(-32000, 'Invalid JSON-RPC response: missing result and error');\n }\n\n return json.result as TResult;\n } catch (error) {\n if (error instanceof FiberRpcError) {\n throw error;\n }\n if (error instanceof Error) {\n if (error.name === 'AbortError') {\n throw new FiberRpcError(-32000, 'Request timeout');\n }\n throw new FiberRpcError(-32000, error.message);\n }\n throw new FiberRpcError(-32000, 'Unknown error');\n } finally {\n clearTimeout(timeoutId);\n }\n }\n\n // ===========================================================================\n // Peer Module\n // ===========================================================================\n\n /**\n * Connect to a peer\n */\n async connectPeer(params: ConnectPeerParams): Promise<ConnectPeerResult> {\n return this.call<ConnectPeerResult>('connect_peer', [params]);\n }\n\n /**\n * Disconnect from a peer\n */\n async disconnectPeer(params: DisconnectPeerParams): Promise<null> {\n return this.call<null>('disconnect_peer', [params]);\n }\n\n /**\n * List all connected peers\n */\n async listPeers(): Promise<ListPeersResult> {\n return this.call<ListPeersResult>('list_peers', []);\n }\n\n // ===========================================================================\n // Channel Module\n // ===========================================================================\n\n /**\n * Open a new channel with a peer\n */\n async openChannel(params: OpenChannelParams): Promise<OpenChannelResult> {\n return this.call<OpenChannelResult>('open_channel', [params]);\n }\n\n /**\n * Accept a channel opening request\n */\n async acceptChannel(params: AcceptChannelParams): Promise<AcceptChannelResult> {\n return this.call<AcceptChannelResult>('accept_channel', [params]);\n }\n\n /**\n * List all channels\n */\n async listChannels(params?: ListChannelsParams): Promise<ListChannelsResult> {\n const result = await this.call<ListChannelsResult>('list_channels', params ? [params] : [{}]);\n return {\n ...result,\n channels: result.channels.map((channel) => this.normalizeChannel(channel)),\n };\n }\n\n private normalizeChannelStateName(stateName: string): ChannelState {\n const alias = this.channelStateAliases[stateName];\n if (alias) return alias;\n\n const normalizedInput = stateName.replace(/[^a-zA-Z0-9]/g, '').toLowerCase();\n for (const value of Object.values(ChannelState)) {\n const normalizedValue = value.replace(/[^a-zA-Z0-9]/g, '').toLowerCase();\n if (normalizedValue === normalizedInput) {\n return value;\n }\n }\n\n return stateName as ChannelState;\n }\n\n private normalizeChannel(channel: Channel): Channel {\n return {\n ...channel,\n state: {\n ...channel.state,\n state_name: this.normalizeChannelStateName(channel.state.state_name),\n },\n };\n }\n\n /**\n * Shutdown (close) a channel\n */\n async shutdownChannel(params: ShutdownChannelParams): Promise<null> {\n return this.call<null>('shutdown_channel', [params]);\n }\n\n /**\n * Abandon a pending channel\n */\n async abandonChannel(params: AbandonChannelParams): Promise<null> {\n return this.call<null>('abandon_channel', [params]);\n }\n\n /**\n * Update channel parameters\n */\n async updateChannel(params: UpdateChannelParams): Promise<null> {\n return this.call<null>('update_channel', [params]);\n }\n\n // ===========================================================================\n // Payment Module\n // ===========================================================================\n\n /**\n * Send a payment\n */\n async sendPayment(params: SendPaymentParams): Promise<SendPaymentResult> {\n return this.call<SendPaymentResult>('send_payment', [params]);\n }\n\n /**\n * Get payment status\n */\n async getPayment(params: GetPaymentParams): Promise<GetPaymentResult> {\n return this.call<GetPaymentResult>('get_payment', [params]);\n }\n\n // ===========================================================================\n // Invoice Module\n // ===========================================================================\n\n /**\n * Create a new invoice\n *\n * NOTE: HashAlgorithm value mapping\n *\n * Upstream issue: https://github.com/RetricSu/fiber-pay/issues/66\n *\n * The SDK's HashAlgorithm type uses PascalCase ('CkbHash' | 'Sha256')\n * but FNN v0.7.1 RPC expects snake_case ('ckb_hash' | 'sha256').\n *\n * This mapping ensures compatibility while maintaining backward-compatible\n * SDK types. When upstream fixes this inconsistency, this mapping can\n * be removed.\n */\n async newInvoice(params: NewInvoiceParams): Promise<NewInvoiceResult> {\n const { hash_algorithm, ...rest } = params;\n const rpcParams: Record<string, unknown> = { ...rest };\n\n if (hash_algorithm) {\n // Map PascalCase HashAlgorithm values to snake_case for RPC\n rpcParams.hash_algorithm = HASH_ALGORITHM_MAP[hash_algorithm];\n }\n\n return this.call<NewInvoiceResult>('new_invoice', [rpcParams]);\n }\n\n /**\n * Parse an invoice string\n */\n async parseInvoice(params: ParseInvoiceParams): Promise<ParseInvoiceResult> {\n return this.call<ParseInvoiceResult>('parse_invoice', [params]);\n }\n\n /**\n * Get invoice by payment hash\n */\n async getInvoice(params: GetInvoiceParams): Promise<GetInvoiceResult> {\n return this.call<GetInvoiceResult>('get_invoice', [params]);\n }\n\n /**\n * Cancel an open invoice\n */\n async cancelInvoice(params: CancelInvoiceParams): Promise<CancelInvoiceResult> {\n return this.call<CancelInvoiceResult>('cancel_invoice', [params]);\n }\n\n /**\n * Settle a hold invoice with the preimage\n * Used for conditional/escrow payments where the invoice was created\n * with a payment_hash (no preimage provided upfront)\n */\n async settleInvoice(params: SettleInvoiceParams): Promise<null> {\n return this.call<null>('settle_invoice', [params]);\n }\n\n // ===========================================================================\n // Router Module\n // ===========================================================================\n\n /**\n * Build a custom route for payment\n * Useful for channel rebalancing (circular payments) and advanced routing\n */\n async buildRouter(params: BuildRouterParams): Promise<BuildRouterResult> {\n return this.call<BuildRouterResult>('build_router', [params]);\n }\n\n /**\n * Send a payment using a pre-built route from buildRouter()\n * Use with allow_self_payment for channel rebalancing\n */\n async sendPaymentWithRouter(params: SendPaymentWithRouterParams): Promise<SendPaymentResult> {\n return this.call<SendPaymentResult>('send_payment_with_router', [params]);\n }\n\n // ===========================================================================\n // Graph Module\n // ===========================================================================\n\n /**\n * List nodes in the network graph\n */\n async graphNodes(params?: GraphNodesParams): Promise<GraphNodesResult> {\n return this.call<GraphNodesResult>('graph_nodes', params ? [params] : [{}]);\n }\n\n /**\n * List channels in the network graph\n */\n async graphChannels(params?: GraphChannelsParams): Promise<GraphChannelsResult> {\n return this.call<GraphChannelsResult>('graph_channels', params ? [params] : [{}]);\n }\n\n // ===========================================================================\n // Info Module\n // ===========================================================================\n\n /**\n * Get local node information\n */\n async nodeInfo(): Promise<NodeInfoResult> {\n return this.call<NodeInfoResult>('node_info', []);\n }\n\n // ===========================================================================\n // Utility Methods\n // ===========================================================================\n\n /**\n * Check if the node is reachable\n */\n async ping(): Promise<boolean> {\n try {\n await this.nodeInfo();\n return true;\n } catch {\n return false;\n }\n }\n\n /**\n * Wait for the node to be ready\n */\n async waitForReady(options: { timeout?: number; interval?: number } = {}): Promise<void> {\n const { timeout = 60000, interval = 1000 } = options;\n const start = Date.now();\n\n while (Date.now() - start < timeout) {\n if (await this.ping()) {\n return;\n }\n await new Promise((resolve) => setTimeout(resolve, interval));\n }\n\n throw new FiberRpcError(-32000, 'Node not ready within timeout');\n }\n\n // ===========================================================================\n // Polling / Watching Helpers\n // ===========================================================================\n\n /**\n * Wait for a payment to reach a terminal state (Success or Failed)\n * Polls get_payment at the specified interval.\n *\n * @returns The final payment result\n * @throws FiberRpcError on timeout\n */\n async waitForPayment(\n paymentHash: PaymentHash,\n options: { timeout?: number; interval?: number } = {},\n ): Promise<GetPaymentResult> {\n const { timeout = 120000, interval = 2000 } = options;\n const start = Date.now();\n\n while (Date.now() - start < timeout) {\n const result = await this.getPayment({ payment_hash: paymentHash });\n if (result.status === 'Success' || result.status === 'Failed') {\n return result;\n }\n await new Promise((resolve) => setTimeout(resolve, interval));\n }\n\n throw new FiberRpcError(-32000, `Payment ${paymentHash} did not complete within ${timeout}ms`);\n }\n\n /**\n * Wait for a channel to reach ChannelReady state.\n * Polls list_channels at the specified interval.\n *\n * @returns The channel info once ready\n * @throws FiberRpcError on timeout or if channel disappears\n */\n async waitForChannelReady(\n channelId: ChannelId,\n options: { timeout?: number; interval?: number } = {},\n ): Promise<Channel> {\n const { timeout = 300000, interval = 5000 } = options;\n const start = Date.now();\n\n while (Date.now() - start < timeout) {\n const result = await this.listChannels({});\n const channel = result.channels.find((ch) => ch.channel_id === channelId);\n\n if (!channel) {\n // Channel may use temporary_channel_id initially, check all\n const allChannels = result.channels;\n const found = allChannels.find((ch) => ch.channel_id === channelId);\n if (!found) {\n // Channel not yet visible or was abandoned - keep waiting\n await new Promise((resolve) => setTimeout(resolve, interval));\n continue;\n }\n }\n\n if (channel && channel.state.state_name === ChannelState.ChannelReady) {\n return channel;\n }\n\n if (channel && channel.state.state_name === ChannelState.Closed) {\n throw new FiberRpcError(-32000, `Channel ${channelId} was closed before becoming ready`);\n }\n\n await new Promise((resolve) => setTimeout(resolve, interval));\n }\n\n throw new FiberRpcError(\n -32000,\n `Channel ${channelId} did not become ready within ${timeout}ms`,\n );\n }\n\n /**\n * Wait for an invoice to reach a specific status.\n * Useful for hold invoice workflows: wait for 'Received' before settling.\n *\n * @returns The invoice info once the target status is reached\n * @throws FiberRpcError on timeout\n */\n async waitForInvoiceStatus(\n paymentHash: PaymentHash,\n targetStatus: CkbInvoiceStatus | CkbInvoiceStatus[],\n options: { timeout?: number; interval?: number } = {},\n ): Promise<GetInvoiceResult> {\n const { timeout = 120000, interval = 2000 } = options;\n const statuses = Array.isArray(targetStatus) ? targetStatus : [targetStatus];\n const start = Date.now();\n\n while (Date.now() - start < timeout) {\n const result = await this.getInvoice({ payment_hash: paymentHash });\n if (statuses.includes(result.status)) {\n return result;\n }\n // If cancelled, stop waiting\n if (result.status === 'Cancelled') {\n throw new FiberRpcError(-32000, `Invoice ${paymentHash} was cancelled`);\n }\n await new Promise((resolve) => setTimeout(resolve, interval));\n }\n\n throw new FiberRpcError(\n -32000,\n `Invoice ${paymentHash} did not reach status [${statuses.join(', ')}] within ${timeout}ms`,\n );\n }\n\n /**\n * Watch for incoming payments on specified invoices.\n * Polls invoice statuses and calls the callback when a status changes.\n * Use an AbortSignal to stop watching.\n *\n * @example\n * ```typescript\n * const controller = new AbortController();\n * client.watchIncomingPayments({\n * paymentHashes: [hash1, hash2],\n * onPayment: (invoice) => console.log('Payment received!', invoice),\n * signal: controller.signal,\n * });\n * // Later: controller.abort(); to stop watching\n * ```\n */\n async watchIncomingPayments(options: {\n /** Payment hashes of invoices to watch */\n paymentHashes: PaymentHash[];\n /** Callback when an invoice status changes to Received or Paid */\n onPayment: (invoice: GetInvoiceResult) => void;\n /** Polling interval in ms (default: 3000) */\n interval?: number;\n /** AbortSignal to stop watching */\n signal?: AbortSignal;\n }): Promise<void> {\n const { paymentHashes, onPayment, interval = 3000, signal } = options;\n const knownStatuses = new Map<string, CkbInvoiceStatus>();\n\n // Initialize known statuses\n for (const hash of paymentHashes) {\n try {\n const invoice = await this.getInvoice({ payment_hash: hash });\n knownStatuses.set(hash, invoice.status);\n } catch {\n knownStatuses.set(hash, 'Open');\n }\n }\n\n while (!signal?.aborted) {\n for (const hash of paymentHashes) {\n if (signal?.aborted) return;\n\n try {\n const invoice = await this.getInvoice({ payment_hash: hash });\n const previousStatus = knownStatuses.get(hash);\n\n if (\n invoice.status !== previousStatus &&\n (invoice.status === 'Received' || invoice.status === 'Paid')\n ) {\n knownStatuses.set(hash, invoice.status);\n onPayment(invoice);\n } else if (invoice.status !== previousStatus) {\n knownStatuses.set(hash, invoice.status);\n }\n } catch {\n // Invoice may not exist yet or node unreachable — skip this round\n }\n }\n\n await new Promise<void>((resolve) => {\n if (signal?.aborted) {\n resolve();\n return;\n }\n const timer = setTimeout(resolve, interval);\n signal?.addEventListener(\n 'abort',\n () => {\n clearTimeout(timer);\n resolve();\n },\n { once: true },\n );\n });\n }\n }\n}\n\n// =============================================================================\n// Re-export utility functions\n// =============================================================================\n\nexport { ckbToShannons, fromHex, randomBytes32, shannonsToCkb, toHex } from '../utils.js';\n","/**\n * Biscuit policy helpers for Fiber RPC.\n *\n * These helpers model the upstream RPC authorization rules and generate\n * token-side permission facts like `read(\"peers\");` and `write(\"payments\");`.\n */\n\nexport type BiscuitAction = 'read' | 'write';\n\nexport interface BiscuitPermission {\n action: BiscuitAction;\n resource: string;\n}\n\nexport interface BiscuitMethodRule {\n permissions: BiscuitPermission[];\n requiresChannelRight: boolean;\n}\n\nconst RULES: Record<string, BiscuitMethodRule> = {\n // Cch\n send_btc: {\n permissions: [{ action: 'write', resource: 'cch' }],\n requiresChannelRight: false,\n },\n receive_btc: {\n permissions: [{ action: 'read', resource: 'cch' }],\n requiresChannelRight: false,\n },\n get_cch_order: {\n permissions: [{ action: 'read', resource: 'cch' }],\n requiresChannelRight: false,\n },\n\n // Channel\n open_channel: {\n permissions: [{ action: 'write', resource: 'channels' }],\n requiresChannelRight: false,\n },\n accept_channel: {\n permissions: [{ action: 'write', resource: 'channels' }],\n requiresChannelRight: false,\n },\n abandon_channel: {\n permissions: [{ action: 'write', resource: 'channels' }],\n requiresChannelRight: false,\n },\n list_channels: {\n permissions: [{ action: 'read', resource: 'channels' }],\n requiresChannelRight: false,\n },\n shutdown_channel: {\n permissions: [{ action: 'write', resource: 'channels' }],\n requiresChannelRight: false,\n },\n update_channel: {\n permissions: [{ action: 'write', resource: 'channels' }],\n requiresChannelRight: false,\n },\n\n // Dev\n commitment_signed: {\n permissions: [{ action: 'write', resource: 'messages' }],\n requiresChannelRight: false,\n },\n add_tlc: {\n permissions: [{ action: 'write', resource: 'channels' }],\n requiresChannelRight: false,\n },\n remove_tlc: {\n permissions: [{ action: 'write', resource: 'channels' }],\n requiresChannelRight: false,\n },\n check_channel_shutdown: {\n permissions: [{ action: 'write', resource: 'channels' }],\n requiresChannelRight: false,\n },\n submit_commitment_transaction: {\n permissions: [{ action: 'write', resource: 'chain' }],\n requiresChannelRight: false,\n },\n\n // Graph\n graph_nodes: {\n permissions: [{ action: 'read', resource: 'graph' }],\n requiresChannelRight: false,\n },\n graph_channels: {\n permissions: [{ action: 'read', resource: 'graph' }],\n requiresChannelRight: false,\n },\n\n // Info\n node_info: {\n permissions: [{ action: 'read', resource: 'node' }],\n requiresChannelRight: false,\n },\n\n // Invoice\n new_invoice: {\n permissions: [{ action: 'write', resource: 'invoices' }],\n requiresChannelRight: false,\n },\n parse_invoice: {\n permissions: [{ action: 'read', resource: 'invoices' }],\n requiresChannelRight: false,\n },\n get_invoice: {\n permissions: [{ action: 'read', resource: 'invoices' }],\n requiresChannelRight: false,\n },\n cancel_invoice: {\n permissions: [{ action: 'write', resource: 'invoices' }],\n requiresChannelRight: false,\n },\n settle_invoice: {\n permissions: [{ action: 'write', resource: 'invoices' }],\n requiresChannelRight: false,\n },\n\n // Payment\n send_payment: {\n permissions: [{ action: 'write', resource: 'payments' }],\n requiresChannelRight: false,\n },\n get_payment: {\n permissions: [{ action: 'read', resource: 'payments' }],\n requiresChannelRight: false,\n },\n build_router: {\n permissions: [{ action: 'read', resource: 'payments' }],\n requiresChannelRight: false,\n },\n send_payment_with_router: {\n permissions: [{ action: 'write', resource: 'payments' }],\n requiresChannelRight: false,\n },\n\n // Peer\n connect_peer: {\n permissions: [{ action: 'write', resource: 'peers' }],\n requiresChannelRight: false,\n },\n disconnect_peer: {\n permissions: [{ action: 'write', resource: 'peers' }],\n requiresChannelRight: false,\n },\n list_peers: {\n permissions: [{ action: 'read', resource: 'peers' }],\n requiresChannelRight: false,\n },\n\n // Watchtower\n create_watch_channel: {\n permissions: [{ action: 'write', resource: 'watchtower' }],\n requiresChannelRight: true,\n },\n remove_watch_channel: {\n permissions: [{ action: 'write', resource: 'watchtower' }],\n requiresChannelRight: true,\n },\n update_revocation: {\n permissions: [{ action: 'write', resource: 'watchtower' }],\n requiresChannelRight: true,\n },\n update_local_settlement: {\n permissions: [{ action: 'write', resource: 'watchtower' }],\n requiresChannelRight: true,\n },\n update_pending_remote_settlement: {\n permissions: [{ action: 'write', resource: 'watchtower' }],\n requiresChannelRight: true,\n },\n create_preimage: {\n permissions: [{ action: 'write', resource: 'watchtower' }],\n requiresChannelRight: false,\n },\n remove_preimage: {\n permissions: [{ action: 'write', resource: 'watchtower' }],\n requiresChannelRight: false,\n },\n};\n\nfunction escapeDatalogString(value: string): string {\n return value.replace(/\\\\/g, '\\\\\\\\').replace(/\"/g, '\\\\\"');\n}\n\nexport function getBiscuitRuleForMethod(method: string): BiscuitMethodRule | undefined {\n return RULES[method];\n}\n\nexport function collectBiscuitPermissions(methods: string[]): BiscuitPermission[] {\n const dedup = new Map<string, BiscuitPermission>();\n\n for (const method of methods) {\n const rule = RULES[method];\n if (!rule) continue;\n\n for (const permission of rule.permissions) {\n const key = `${permission.action}:${permission.resource}`;\n if (!dedup.has(key)) {\n dedup.set(key, permission);\n }\n }\n }\n\n return [...dedup.values()].sort((a, b) => {\n if (a.action === b.action) {\n return a.resource.localeCompare(b.resource);\n }\n return a.action.localeCompare(b.action);\n });\n}\n\nexport function renderBiscuitPermissionFacts(permissions: BiscuitPermission[]): string {\n return permissions.map((p) => `${p.action}(\"${escapeDatalogString(p.resource)}\");`).join('\\n');\n}\n\nexport function renderBiscuitFactsForMethods(methods: string[]): string {\n return renderBiscuitPermissionFacts(collectBiscuitPermissions(methods));\n}\n\nexport function listSupportedBiscuitMethods(): string[] {\n return Object.keys(RULES).sort();\n}\n","/**\n * Crypto Utilities\n * Pure cryptographic functions for key operations.\n * Browser-compatible — uses Web Crypto API and @noble/hashes.\n */\n\nimport { blake2b } from '@noble/hashes/blake2.js';\nimport { scrypt } from '@noble/hashes/scrypt.js';\nimport { sha256 } from '@noble/hashes/sha2.js';\nimport type { Hash256, HashAlgorithm, HexString } from '../types/index.js';\n\n// =============================================================================\n// Constants\n// =============================================================================\n\nexport const SCRYPT_N = 2 ** 14;\nexport const SCRYPT_R = 8;\nexport const SCRYPT_P = 1;\nexport const KEY_LENGTH = 32;\nexport const SALT_LENGTH = 32;\nexport const IV_LENGTH = 16;\nexport const AUTH_TAG_LENGTH = 16;\n\n/** Magic bytes: ASCII 'FIBERENC' */\nexport const ENCRYPTED_MAGIC = new Uint8Array([0x46, 0x49, 0x42, 0x45, 0x52, 0x45, 0x4e, 0x43]);\n\n// =============================================================================\n// Helpers\n// =============================================================================\n\nfunction bytesToHex(bytes: Uint8Array): string {\n return Array.from(bytes)\n .map((b) => b.toString(16).padStart(2, '0'))\n .join('');\n}\n\n/**\n * Copy a Uint8Array into a new one backed by its own ArrayBuffer.\n * Needed because subarray() shares the parent buffer, which breaks\n * Web Crypto APIs that expect an owned ArrayBuffer.\n */\nfunction ownedCopy(src: Uint8Array): Uint8Array<ArrayBuffer> {\n const dst = new Uint8Array(src.length);\n dst.set(src);\n return dst;\n}\n\n// =============================================================================\n// Functions\n// =============================================================================\n\n/**\n * Check if key data is encrypted (starts with FIBERENC magic bytes)\n */\nexport function isEncryptedKey(data: Uint8Array): boolean {\n if (data.length < ENCRYPTED_MAGIC.length) return false;\n for (let i = 0; i < ENCRYPTED_MAGIC.length; i++) {\n if (data[i] !== ENCRYPTED_MAGIC[i]) return false;\n }\n return true;\n}\n\n/**\n * Decrypt an encrypted key using scrypt + AES-256-GCM\n */\nexport async function decryptKey(data: Uint8Array, password: string): Promise<Uint8Array> {\n let offset = ENCRYPTED_MAGIC.length;\n const salt = data.subarray(offset, offset + SALT_LENGTH);\n offset += SALT_LENGTH;\n const iv = ownedCopy(data.subarray(offset, offset + IV_LENGTH));\n offset += IV_LENGTH;\n const authTag = data.subarray(offset, offset + AUTH_TAG_LENGTH);\n offset += AUTH_TAG_LENGTH;\n const encrypted = data.subarray(offset);\n\n const derivedKey = ownedCopy(\n scrypt(new TextEncoder().encode(password), salt, {\n N: SCRYPT_N,\n r: SCRYPT_R,\n p: SCRYPT_P,\n dkLen: KEY_LENGTH,\n }),\n );\n\n const cryptoKey = await crypto.subtle.importKey('raw', derivedKey, { name: 'AES-GCM' }, false, [\n 'decrypt',\n ]);\n\n // Web Crypto expects ciphertext + authTag concatenated\n const ciphertext = new Uint8Array(encrypted.length + authTag.length);\n ciphertext.set(encrypted);\n ciphertext.set(authTag, encrypted.length);\n\n const decrypted = await crypto.subtle.decrypt(\n { name: 'AES-GCM', iv, tagLength: AUTH_TAG_LENGTH * 8 },\n cryptoKey,\n ciphertext,\n );\n\n return new Uint8Array(decrypted);\n}\n\n/**\n * Derive a public key hash from a private key (SHA-256)\n */\nexport async function derivePublicKey(privateKey: Uint8Array): Promise<HexString> {\n const hashBuffer = await crypto.subtle.digest('SHA-256', ownedCopy(privateKey));\n return `0x${bytesToHex(new Uint8Array(hashBuffer))}` as HexString;\n}\n\n/**\n * Generate a random 32-byte private key\n */\nexport function generatePrivateKey(): Uint8Array {\n const bytes = new Uint8Array(32);\n crypto.getRandomValues(bytes);\n return bytes;\n}\n\n/**\n * Generate a random preimage for hold invoice\n * @returns Hex-encoded random 32-byte preimage\n */\nexport function generatePreimage(): HexString {\n const bytes = new Uint8Array(32);\n crypto.getRandomValues(bytes);\n return `0x${bytesToHex(bytes)}` as HexString;\n}\n\n// =============================================================================\n// Payment Hash Utilities\n// =============================================================================\n\n/** CKB blake2b-256 personalization string */\nconst CKB_HASH_PERSONALIZATION = new Uint8Array([\n 99, 107, 98, 45, 100, 101, 102, 97, 117, 108, 116, 45, 104, 97, 115, 104,\n]);\n\n/**\n * Compute CKB hash (blake2b-256 with \"ckb-default-hash\" personalization)\n */\nexport function ckbHash(data: Uint8Array): Uint8Array {\n return blake2b(data, { dkLen: 32, personalization: CKB_HASH_PERSONALIZATION });\n}\n\n/**\n * Compute SHA-256 hash\n */\nexport function sha256Hash(data: Uint8Array): Uint8Array {\n return sha256(data);\n}\n\n/**\n * Decode a hex string to Uint8Array (browser-compatible)\n * @param hex - Hex string (with or without 0x prefix)\n */\nfunction hexToBytes(hex: string): Uint8Array {\n const cleanHex = hex.replace(/^0x/i, '');\n\n if (cleanHex.length === 0) {\n return new Uint8Array(0);\n }\n\n if (!/^[0-9a-fA-F]*$/.test(cleanHex)) {\n throw new Error('Invalid hex string: contains non-hex characters');\n }\n\n if (cleanHex.length % 2 !== 0) {\n throw new Error('Invalid hex string: odd length');\n }\n\n const bytes = new Uint8Array(cleanHex.length / 2);\n for (let i = 0; i < bytes.length; i++) {\n bytes[i] = parseInt(cleanHex.slice(i * 2, i * 2 + 2), 16);\n }\n return bytes;\n}\n\n/**\n * Assert that a value is never (exhaustiveness check for switch statements)\n */\nfunction assertNever(x: never): never {\n throw new Error(`Unexpected value: ${String(x)}`);\n}\n\n/**\n * Compute payment hash from preimage using specified algorithm\n * @param preimageHex - Hex-encoded preimage (0x-prefixed)\n * @param algorithm - Hash algorithm: 'CkbHash' or 'Sha256'\n * @returns Hex-encoded payment hash (0x-prefixed, 64 hex chars)\n */\nexport function hashPreimage(preimageHex: HexString, algorithm: HashAlgorithm): Hash256 {\n const data = hexToBytes(preimageHex);\n\n let hashBytes: Uint8Array;\n switch (algorithm) {\n case 'Sha256':\n hashBytes = sha256Hash(data);\n break;\n case 'CkbHash':\n hashBytes = ckbHash(data);\n break;\n default:\n return assertNever(algorithm);\n }\n\n return `0x${bytesToHex(hashBytes)}` as Hash256;\n}\n\n/**\n * Verify that a preimage matches the given payment hash\n * @param preimageHex - Hex-encoded preimage\n * @param paymentHash - Expected payment hash\n * @param algorithm - Hash algorithm used\n * @returns true if preimage hashes to paymentHash\n */\nexport function verifyPreimageHash(\n preimageHex: HexString,\n paymentHash: Hash256,\n algorithm: HashAlgorithm,\n): boolean {\n try {\n const computedHash = hashPreimage(preimageHex, algorithm);\n\n // Compare all bytes to reduce timing side channels for equal-length hashes.\n const computed = hexToBytes(computedHash);\n const expected = hexToBytes(paymentHash);\n\n if (computed.length !== expected.length) {\n return false;\n }\n\n let result = 0;\n for (let i = 0; i < computed.length; i++) {\n result |= computed[i] ^ expected[i];\n }\n return result === 0;\n } catch {\n // Treat malformed inputs as non-matching in this boolean helper.\n return false;\n }\n}\n","/**\n * Policy Engine\n * Enforces spending limits, rate limits, and other security policies\n * This operates at the SDK level and cannot be bypassed via prompts\n */\n\nimport type {\n AuditAction,\n AuditLogEntry,\n PolicyCheckResult,\n PolicyViolation,\n RateLimit,\n SecurityPolicy,\n SpendingLimit,\n} from '../types/index.js';\nimport { fromHex, toHex } from '../utils.js';\n\n// =============================================================================\n// Policy Engine\n// =============================================================================\n\nexport class PolicyEngine {\n private policy: SecurityPolicy;\n private auditLog: AuditLogEntry[] = [];\n private spendingState: SpendingLimit;\n private rateLimitState: RateLimit;\n\n constructor(policy: SecurityPolicy) {\n this.policy = policy;\n\n // Initialize spending state\n this.spendingState = {\n ...(policy.spending ?? {\n maxPerTransaction: '0x0',\n maxPerWindow: '0x0',\n windowSeconds: 3600,\n }),\n currentSpent: '0x0',\n windowStart: Date.now(),\n };\n\n // Initialize rate limit state\n this.rateLimitState = {\n ...(policy.rateLimit ?? {\n maxTransactions: 0,\n windowSeconds: 3600,\n cooldownSeconds: 0,\n }),\n currentCount: 0,\n windowStart: Date.now(),\n lastTransaction: 0,\n };\n }\n\n /**\n * Check if a payment is allowed by the policy\n */\n checkPayment(params: {\n amount: string; // hex\n recipient?: string;\n }): PolicyCheckResult {\n const violations: PolicyViolation[] = [];\n let requiresConfirmation = false;\n\n if (!this.policy.enabled) {\n return { allowed: true, violations: [], requiresConfirmation: false };\n }\n\n const amount = fromHex(params.amount as `0x${string}`);\n\n // Check spending limit per transaction\n if (this.policy.spending) {\n const maxPerTx = fromHex(this.policy.spending.maxPerTransaction as `0x${string}`);\n if (amount > maxPerTx) {\n violations.push({\n type: 'SPENDING_LIMIT_PER_TX',\n message: `Amount ${amount} exceeds per-transaction limit of ${maxPerTx}`,\n details: {\n requested: params.amount,\n limit: this.policy.spending.maxPerTransaction,\n },\n });\n }\n\n // Check spending limit per window\n this.refreshSpendingWindow();\n const currentSpent = fromHex(this.spendingState.currentSpent as `0x${string}`);\n const maxPerWindow = fromHex(this.policy.spending.maxPerWindow as `0x${string}`);\n\n if (currentSpent + amount > maxPerWindow) {\n const remaining = maxPerWindow - currentSpent;\n violations.push({\n type: 'SPENDING_LIMIT_PER_WINDOW',\n message: `Amount ${amount} would exceed window limit. Remaining: ${remaining}`,\n details: {\n requested: params.amount,\n limit: this.policy.spending.maxPerWindow,\n remaining: toHex(remaining > 0n ? remaining : 0n),\n },\n });\n }\n }\n\n // Check rate limit\n if (this.policy.rateLimit) {\n this.refreshRateLimitWindow();\n\n if ((this.rateLimitState.currentCount ?? 0) >= this.policy.rateLimit.maxTransactions) {\n violations.push({\n type: 'RATE_LIMIT_EXCEEDED',\n message: `Rate limit of ${this.policy.rateLimit.maxTransactions} transactions per ${this.policy.rateLimit.windowSeconds}s exceeded`,\n details: {},\n });\n }\n\n // Check cooldown\n const now = Date.now();\n const cooldownMs = this.policy.rateLimit.cooldownSeconds * 1000;\n const timeSinceLast = now - (this.rateLimitState.lastTransaction || 0);\n\n if (timeSinceLast < cooldownMs) {\n violations.push({\n type: 'RATE_LIMIT_COOLDOWN',\n message: `Cooldown period not elapsed. Wait ${Math.ceil((cooldownMs - timeSinceLast) / 1000)}s`,\n details: {\n cooldownRemaining: Math.ceil((cooldownMs - timeSinceLast) / 1000),\n },\n });\n }\n }\n\n // Check recipient policy\n if (this.policy.recipients && params.recipient) {\n if (this.policy.recipients.blocklist?.includes(params.recipient)) {\n violations.push({\n type: 'RECIPIENT_BLOCKED',\n message: `Recipient ${params.recipient} is blocklisted`,\n details: { recipient: params.recipient },\n });\n }\n\n if (\n this.policy.recipients.allowlist &&\n this.policy.recipients.allowlist.length > 0 &&\n !this.policy.recipients.allowlist.includes(params.recipient) &&\n !this.policy.recipients.allowUnknown\n ) {\n violations.push({\n type: 'RECIPIENT_NOT_ALLOWED',\n message: `Recipient ${params.recipient} is not in allowlist`,\n details: { recipient: params.recipient },\n });\n }\n }\n\n // Check confirmation threshold\n if (this.policy.confirmationThreshold) {\n const threshold = fromHex(this.policy.confirmationThreshold as `0x${string}`);\n if (amount > threshold) {\n requiresConfirmation = true;\n violations.push({\n type: 'REQUIRES_CONFIRMATION',\n message: `Amount ${amount} exceeds confirmation threshold of ${threshold}`,\n details: {\n requested: params.amount,\n limit: this.policy.confirmationThreshold,\n },\n });\n }\n }\n\n return {\n allowed: violations.filter((v) => v.type !== 'REQUIRES_CONFIRMATION').length === 0,\n violations,\n requiresConfirmation,\n };\n }\n\n /**\n * Check if a channel operation is allowed\n */\n checkChannelOperation(params: {\n operation: 'open' | 'close' | 'force_close';\n fundingAmount?: string; // hex\n currentChannelCount?: number;\n }): PolicyCheckResult {\n const violations: PolicyViolation[] = [];\n\n if (!this.policy.enabled || !this.policy.channels) {\n return { allowed: true, violations: [], requiresConfirmation: false };\n }\n\n const { channels } = this.policy;\n\n if (params.operation === 'open') {\n if (!channels.allowOpen) {\n violations.push({\n type: 'CHANNEL_OPEN_NOT_ALLOWED',\n message: 'Channel opening is not allowed by policy',\n details: {},\n });\n }\n\n if (params.fundingAmount && channels.maxFundingAmount) {\n const funding = fromHex(params.fundingAmount as `0x${string}`);\n const max = fromHex(channels.maxFundingAmount as `0x${string}`);\n if (funding > max) {\n violations.push({\n type: 'CHANNEL_FUNDING_EXCEEDS_MAX',\n message: `Funding amount ${funding} exceeds maximum ${max}`,\n details: {\n requested: params.fundingAmount,\n limit: channels.maxFundingAmount,\n },\n });\n }\n }\n\n if (params.fundingAmount && channels.minFundingAmount) {\n const funding = fromHex(params.fundingAmount as `0x${string}`);\n const min = fromHex(channels.minFundingAmount as `0x${string}`);\n if (funding < min) {\n violations.push({\n type: 'CHANNEL_FUNDING_BELOW_MIN',\n message: `Funding amount ${funding} below minimum ${min}`,\n details: {\n requested: params.fundingAmount,\n limit: channels.minFundingAmount,\n },\n });\n }\n }\n\n if (\n channels.maxChannels &&\n params.currentChannelCount !== undefined &&\n params.currentChannelCount >= channels.maxChannels\n ) {\n violations.push({\n type: 'MAX_CHANNELS_REACHED',\n message: `Maximum channel count of ${channels.maxChannels} reached`,\n details: {},\n });\n }\n }\n\n if (params.operation === 'close' && !channels.allowClose) {\n violations.push({\n type: 'CHANNEL_CLOSE_NOT_ALLOWED',\n message: 'Channel closing is not allowed by policy',\n details: {},\n });\n }\n\n if (params.operation === 'force_close' && !channels.allowForceClose) {\n violations.push({\n type: 'CHANNEL_FORCE_CLOSE_NOT_ALLOWED',\n message: 'Force channel closing is not allowed by policy',\n details: {},\n });\n }\n\n return {\n allowed: violations.length === 0,\n violations,\n requiresConfirmation: false,\n };\n }\n\n /**\n * Record a successful payment (updates spending and rate limit state)\n */\n recordPayment(amount: string): void {\n this.refreshSpendingWindow();\n this.refreshRateLimitWindow();\n\n // Update spending\n const currentSpent = fromHex(this.spendingState.currentSpent as `0x${string}`);\n const paymentAmount = fromHex(amount as `0x${string}`);\n this.spendingState.currentSpent = toHex(currentSpent + paymentAmount);\n\n // Update rate limit\n this.rateLimitState.currentCount = (this.rateLimitState.currentCount ?? 0) + 1;\n this.rateLimitState.lastTransaction = Date.now();\n }\n\n /**\n * Add an entry to the audit log\n */\n addAuditEntry(\n action: AuditAction,\n success: boolean,\n details: Record<string, unknown>,\n violations?: PolicyViolation[],\n ): void {\n if (!this.policy.auditLogging) return;\n\n this.auditLog.push({\n timestamp: Date.now(),\n action,\n success,\n details,\n policyViolations: violations,\n });\n\n // Keep audit log bounded (last 1000 entries)\n if (this.auditLog.length > 1000) {\n this.auditLog = this.auditLog.slice(-1000);\n }\n }\n\n /**\n * Get the audit log\n */\n getAuditLog(options?: { limit?: number; since?: number }): AuditLogEntry[] {\n let log = this.auditLog;\n\n const since = options?.since;\n if (since !== undefined) {\n log = log.filter((entry) => entry.timestamp >= since);\n }\n\n if (options?.limit) {\n log = log.slice(-options.limit);\n }\n\n return log;\n }\n\n /**\n * Get remaining spending allowance\n */\n getRemainingAllowance(): { perTransaction: bigint; perWindow: bigint } {\n this.refreshSpendingWindow();\n\n const maxPerTx = this.policy.spending\n ? fromHex(this.policy.spending.maxPerTransaction as `0x${string}`)\n : BigInt(Number.MAX_SAFE_INTEGER);\n\n const maxPerWindow = this.policy.spending\n ? fromHex(this.policy.spending.maxPerWindow as `0x${string}`)\n : BigInt(Number.MAX_SAFE_INTEGER);\n\n const currentSpent = fromHex(this.spendingState.currentSpent as `0x${string}`);\n const remainingWindow = maxPerWindow - currentSpent;\n\n return {\n perTransaction: maxPerTx,\n perWindow: remainingWindow > 0n ? remainingWindow : 0n,\n };\n }\n\n /**\n * Update the policy\n */\n updatePolicy(newPolicy: Partial<SecurityPolicy>): void {\n this.policy = { ...this.policy, ...newPolicy };\n this.addAuditEntry('POLICY_UPDATED', true, { newPolicy });\n }\n\n /**\n * Get the current policy\n */\n getPolicy(): SecurityPolicy {\n return { ...this.policy };\n }\n\n // ===========================================================================\n // Private Methods\n // ===========================================================================\n\n private refreshSpendingWindow(): void {\n if (!this.policy.spending) return;\n\n const now = Date.now();\n const windowMs = this.policy.spending.windowSeconds * 1000;\n const windowStart = this.spendingState.windowStart || now;\n\n if (now - windowStart >= windowMs) {\n // Reset window\n this.spendingState.currentSpent = '0x0';\n this.spendingState.windowStart = now;\n }\n }\n\n private refreshRateLimitWindow(): void {\n if (!this.policy.rateLimit) return;\n\n const now = Date.now();\n const windowMs = this.policy.rateLimit.windowSeconds * 1000;\n const windowStart = this.rateLimitState.windowStart || now;\n\n if (now - windowStart >= windowMs) {\n // Reset window\n this.rateLimitState.currentCount = 0;\n this.rateLimitState.windowStart = now;\n }\n }\n}\n","/**\n * Invoice Verification Engine\n * Validates invoice legitimacy, format, cryptographic correctness, and peer connectivity\n * This ensures the agent only pays valid invoices\n */\n\nimport type { FiberRpcClient } from '../rpc/client.js';\nimport type { Attribute, CkbInvoice, HexString } from '../types/index.js';\nimport { fromHex, shannonsToCkb } from '../utils.js';\n\n// =============================================================================\n// Types\n// =============================================================================\n\n/**\n * Invoice verification result\n */\nexport interface InvoiceVerificationResult {\n /** Overall validity (true = safe to pay) */\n valid: boolean;\n /** Invoice parsed details */\n details: {\n paymentHash: string;\n amountCkb: number;\n expiresAt: number; // Unix timestamp\n description?: string;\n isExpired: boolean;\n };\n /** Peer information */\n peer: {\n nodeId?: string;\n isConnected: boolean;\n trustScore: number; // 0-100\n };\n /** Validation checks performed */\n checks: {\n validFormat: boolean;\n notExpired: boolean;\n validAmount: boolean;\n peerConnected: boolean;\n };\n /** Issues found */\n issues: VerificationIssue[];\n /** Recommendation for agent */\n recommendation: 'proceed' | 'warn' | 'reject';\n /** Human-readable reason for recommendation */\n reason: string;\n}\n\nexport interface VerificationIssue {\n type: 'warning' | 'critical';\n code: string;\n message: string;\n}\n\n// =============================================================================\n// Invoice Verifier\n// =============================================================================\n\nexport class InvoiceVerifier {\n constructor(private rpc: FiberRpcClient) {}\n\n /**\n * Fully validate an invoice before payment\n */\n async verifyInvoice(invoiceString: string): Promise<InvoiceVerificationResult> {\n const issues: VerificationIssue[] = [];\n const checks = {\n validFormat: false,\n notExpired: false,\n validAmount: false,\n peerConnected: false,\n };\n\n // 1. Validate format\n const formatCheck = this.validateInvoiceFormat(invoiceString);\n checks.validFormat = formatCheck.valid;\n if (!formatCheck.valid) {\n issues.push({\n type: 'critical',\n code: 'INVALID_INVOICE_FORMAT',\n message: formatCheck.error || 'Invoice format is invalid',\n });\n }\n\n let invoice: CkbInvoice | null = null;\n\n // 2. Parse invoice\n if (checks.validFormat) {\n try {\n const result = await this.rpc.parseInvoice({ invoice: invoiceString });\n invoice = result.invoice;\n } catch (error) {\n issues.push({\n type: 'critical',\n code: 'PARSE_INVOICE_FAILED',\n message: `Failed to parse invoice: ${error instanceof Error ? error.message : 'Unknown error'}`,\n });\n }\n }\n\n // Default details if parsing failed\n const details = {\n paymentHash: invoice?.data.payment_hash || 'unknown',\n amountCkb: invoice?.amount ? shannonsToCkb(invoice.amount) : 0,\n expiresAt: this.getExpiryTimestamp(invoice),\n description: this.getDescription(invoice),\n isExpired: invoice ? this.isInvoiceExpired(invoice) : true,\n };\n\n // 3. Validate not expired\n if (invoice) {\n if (!details.isExpired) {\n checks.notExpired = true;\n } else {\n issues.push({\n type: 'critical',\n code: 'INVOICE_EXPIRED',\n message: `Invoice expired at ${new Date(details.expiresAt).toISOString()}`,\n });\n }\n }\n\n // 4. Validate amount\n if (invoice?.amount) {\n const validAmount = this.validateAmount(invoice.amount);\n checks.validAmount = validAmount.valid;\n if (!validAmount.valid) {\n issues.push({\n type: 'critical',\n code: validAmount.code || 'INVALID_AMOUNT',\n message: validAmount.message || 'Amount validation failed',\n });\n }\n }\n\n // 5. Check peer connectivity - verify payee is reachable\n const payeePublicKey = this.extractNodeIdFromInvoice(invoice);\n try {\n const peers = await this.rpc.listPeers();\n if (payeePublicKey) {\n // We have the payee's public key - check if they're connected or reachable\n // Note: peer_id in Fiber is derived from public key, but format may differ\n // For now, we check if we have any path to peers (routing will find the payee)\n if (peers.peers && peers.peers.length > 0) {\n checks.peerConnected = true;\n } else {\n issues.push({\n type: 'warning',\n code: 'NO_PEERS_CONNECTED',\n message: `No peers connected. Cannot route payment to payee ${payeePublicKey.slice(0, 16)}...`,\n });\n }\n } else {\n // No payee public key in invoice - just check basic connectivity\n if (peers.peers && peers.peers.length > 0) {\n checks.peerConnected = true;\n } else {\n issues.push({\n type: 'warning',\n code: 'NO_PEERS_CONNECTED',\n message: 'No peers currently connected. Payment may fail.',\n });\n }\n }\n } catch {\n issues.push({\n type: 'warning',\n code: 'PEER_CHECK_FAILED',\n message: 'Could not verify peer connectivity',\n });\n }\n\n // Determine overall validity and recommendation\n const criticalIssues = issues.filter((i) => i.type === 'critical');\n const valid = criticalIssues.length === 0;\n\n let recommendation: 'proceed' | 'warn' | 'reject';\n let reason: string;\n\n if (!valid) {\n recommendation = 'reject';\n reason = `Invoice has ${criticalIssues.length} critical issue(s): ${criticalIssues.map((i) => i.code).join(', ')}`;\n } else if (issues.length > 0) {\n recommendation = 'warn';\n reason = `Invoice is valid but has warnings: ${issues.map((i) => i.code).join(', ')}`;\n } else {\n recommendation = 'proceed';\n reason = 'Invoice is valid and safe to pay';\n }\n\n return {\n valid,\n details,\n peer: {\n nodeId: payeePublicKey, // Use the already-extracted payee public key\n isConnected:\n checks.peerConnected ||\n issues.filter((i) => i.code === 'NO_PEERS_CONNECTED').length === 0,\n trustScore: this.calculateTrustScore(checks, issues),\n },\n checks: {\n ...checks,\n },\n issues,\n recommendation,\n reason,\n };\n }\n\n /**\n * Quick format validation (regex-based, before RPC call)\n */\n private validateInvoiceFormat(invoice: string): { valid: boolean; error?: string } {\n // Invoice should be bech32-encoded and start with fibt (testnet) or fibb (mainnet)\n const invoiceRegex = /^fib[tb]{1}[a-z0-9]{50,}$/i;\n\n if (!invoiceRegex.test(invoice)) {\n return {\n valid: false,\n error: 'Invoice must be bech32-encoded (fibt... for testnet or fibb... for mainnet)',\n };\n }\n\n return { valid: true };\n }\n\n /**\n * Validate amount is positive and reasonable\n */\n private validateAmount(amountHex: HexString): {\n valid: boolean;\n code?: string;\n message?: string;\n } {\n try {\n const amount = fromHex(amountHex);\n\n if (amount <= 0n) {\n return {\n valid: false,\n code: 'ZERO_AMOUNT',\n message: 'Invoice amount must be greater than zero',\n };\n }\n\n // Sanity check: prevent obviously spoofed invoices\n // Max 1 million CKB (would be ~$XXX at current rates)\n const maxShannons = BigInt(1000000) * BigInt(100000000); // 1M CKB in shannons\n if (amount > maxShannons) {\n const amountCkb = Number(amount) / 1e8;\n return {\n valid: false,\n code: 'AMOUNT_TOO_LARGE',\n message: `Invoice amount (${amountCkb.toFixed(2)} CKB) exceeds reasonable maximum`,\n };\n }\n\n return { valid: true };\n } catch {\n return {\n valid: false,\n code: 'INVALID_AMOUNT_FORMAT',\n message: 'Could not parse invoice amount',\n };\n }\n }\n\n /**\n * Check if invoice has expired\n */\n private isInvoiceExpired(invoice: CkbInvoice): boolean {\n const expiryTimestamp = this.getExpiryTimestamp(invoice);\n return Date.now() > expiryTimestamp;\n }\n\n /**\n * Get expiry timestamp in milliseconds\n */\n private getExpiryTimestamp(invoice: CkbInvoice | null): number {\n if (!invoice) return 0;\n\n // Expiry is a duration in seconds, stored as an attribute (ExpiryTime).\n // Invoice timestamp is in seconds since UNIX epoch.\n try {\n const createdSeconds = fromHex(invoice.data.timestamp as HexString);\n const expiryDeltaSeconds =\n this.getAttributeU64(invoice.data.attrs, 'ExpiryTime') ?? BigInt(60 * 60);\n return Number(createdSeconds + expiryDeltaSeconds) * 1000;\n } catch {\n // Fall through to default\n }\n\n // Default: assume 1 hour from now\n return Date.now() + 60 * 60 * 1000;\n }\n\n private getAttributeU64(\n attrs: Attribute[],\n key: 'ExpiryTime' | 'FinalHtlcTimeout' | 'FinalHtlcMinimumExpiryDelta',\n ): bigint | undefined {\n for (const attr of attrs) {\n if (key in attr) {\n return fromHex((attr as Record<string, HexString>)[key] as HexString);\n }\n }\n return undefined;\n }\n\n private getDescription(invoice: CkbInvoice | null): string | undefined {\n if (!invoice) return undefined;\n for (const attr of invoice.data.attrs) {\n if ('Description' in attr) {\n return attr.Description;\n }\n }\n return undefined;\n }\n\n /**\n * Try to extract payee node public key from invoice attributes\n * The payee public key is embedded in the invoice as a PayeePublicKey attribute\n */\n private extractNodeIdFromInvoice(invoice: CkbInvoice | null): string | undefined {\n if (!invoice) {\n return undefined;\n }\n\n // Search for PayeePublicKey attribute in the invoice data\n for (const attr of invoice.data.attrs) {\n if ('PayeePublicKey' in attr) {\n return attr.PayeePublicKey;\n }\n }\n\n return undefined;\n }\n\n /**\n * Calculate trust score (0-100) based on various factors\n */\n private calculateTrustScore(\n checks: {\n validFormat: boolean;\n notExpired: boolean;\n validAmount: boolean;\n peerConnected: boolean;\n },\n issues: VerificationIssue[],\n ): number {\n let score = 100;\n\n // Deduct for failed checks\n if (!checks.validFormat) score -= 25;\n if (!checks.notExpired) score -= 20;\n if (!checks.validAmount) score -= 15;\n if (!checks.peerConnected) score -= 10;\n\n // Deduct for warnings\n const warnings = issues.filter((i) => i.type === 'warning').length;\n score -= warnings * 5;\n\n return Math.max(0, score);\n }\n}\n"],"mappings":"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","names":["ChannelState"]}
|
|
1
|
+
{"version":3,"sources":["../src/address.ts","../src/types/policy.ts","../src/types/rpc.ts","../src/utils.ts","../src/funds/liquidity-analyzer.ts","../src/l402/macaroon.ts","../src/rpc/client.ts","../src/l402/middleware.ts","../src/l402/resources.ts","../src/security/biscuit-policy.ts","../src/security/crypto.ts","../src/security/policy-engine.ts","../src/verification/invoice-verifier.ts"],"sourcesContent":["/**\n * CKB Address Encoding (Bech32m)\n * Encode CKB lock scripts to human-readable addresses\n */\n\n// Bech32m charset\nconst BECH32_CHARSET = 'qpzry9x8gf2tvdw0s3jn54khce6mua7l';\n\nfunction bech32mPolymod(values: number[]): number {\n const GEN = [0x3b6a57b2, 0x26508e6d, 0x1ea119fa, 0x3d4233dd, 0x2a1462b3];\n let chk = 1;\n for (const v of values) {\n const top = chk >> 25;\n chk = ((chk & 0x1ffffff) << 5) ^ v;\n for (let i = 0; i < 5; i++) {\n if ((top >> i) & 1) {\n chk ^= GEN[i];\n }\n }\n }\n return chk;\n}\n\nfunction bech32mHrpExpand(hrp: string): number[] {\n const ret: number[] = [];\n for (let i = 0; i < hrp.length; i++) {\n ret.push(hrp.charCodeAt(i) >> 5);\n }\n ret.push(0);\n for (let i = 0; i < hrp.length; i++) {\n ret.push(hrp.charCodeAt(i) & 31);\n }\n return ret;\n}\n\nfunction bech32mCreateChecksum(hrp: string, data: number[]): number[] {\n const values = bech32mHrpExpand(hrp).concat(data).concat([0, 0, 0, 0, 0, 0]);\n const polymod = bech32mPolymod(values) ^ 0x2bc830a3; // Bech32m constant\n const ret: number[] = [];\n for (let i = 0; i < 6; i++) {\n ret.push((polymod >> (5 * (5 - i))) & 31);\n }\n return ret;\n}\n\nfunction convertBits(data: Uint8Array, fromBits: number, toBits: number, pad: boolean): number[] {\n let acc = 0;\n let bits = 0;\n const ret: number[] = [];\n const maxv = (1 << toBits) - 1;\n\n for (const value of data) {\n acc = (acc << fromBits) | value;\n bits += fromBits;\n while (bits >= toBits) {\n bits -= toBits;\n ret.push((acc >> bits) & maxv);\n }\n }\n\n if (pad && bits > 0) {\n ret.push((acc << (toBits - bits)) & maxv);\n }\n\n return ret;\n}\n\nfunction bech32mEncode(hrp: string, data: number[]): string {\n const checksum = bech32mCreateChecksum(hrp, data);\n const combined = data.concat(checksum);\n let result = `${hrp}1`;\n for (const d of combined) {\n result += BECH32_CHARSET[d];\n }\n return result;\n}\n\nexport interface Script {\n code_hash: string;\n hash_type: 'type' | 'data' | 'data1' | 'data2';\n args: string;\n}\n\n/**\n * Convert a CKB lock script to a bech32m-encoded address\n * @param script - The lock script to encode\n * @param network - The CKB network ('testnet' or 'mainnet')\n * @returns Bech32m-encoded CKB address\n */\nexport function scriptToAddress(script: Script, network: 'testnet' | 'mainnet'): string {\n const hrp = network === 'mainnet' ? 'ckb' : 'ckt';\n\n // CKB full address format (2021)\n // Format: 0x00 | code_hash | hash_type | args\n const hashTypeByte =\n script.hash_type === 'type'\n ? 0x01\n : script.hash_type === 'data'\n ? 0x00\n : script.hash_type === 'data1'\n ? 0x02\n : 0x04; // data2\n\n const codeHash = script.code_hash.startsWith('0x') ? script.code_hash.slice(2) : script.code_hash;\n const args = script.args.startsWith('0x') ? script.args.slice(2) : script.args;\n\n // Construct the payload: format_type(0x00) + code_hash(32) + hash_type(1) + args\n const payload = new Uint8Array(1 + 32 + 1 + args.length / 2);\n payload[0] = 0x00; // Full format type\n\n // code_hash\n for (let i = 0; i < 32; i++) {\n payload[1 + i] = parseInt(codeHash.slice(i * 2, i * 2 + 2), 16);\n }\n\n // hash_type\n payload[33] = hashTypeByte;\n\n // args\n for (let i = 0; i < args.length / 2; i++) {\n payload[34 + i] = parseInt(args.slice(i * 2, i * 2 + 2), 16);\n }\n\n // Convert to 5-bit groups and encode with bech32m\n const data = convertBits(payload, 8, 5, true);\n return bech32mEncode(hrp, data);\n}\n","/**\n * Security Policy Types\n * Configuration for AI agent spending limits and guardrails\n */\n\nimport { z } from 'zod';\nimport type { HexString } from './rpc.js';\n\n// =============================================================================\n// Policy Configuration Schema\n// =============================================================================\n\nexport const SpendingLimitSchema = z.object({\n /** Maximum amount per single transaction (in shannons for CKB, or base units for UDT) */\n maxPerTransaction: z.string().regex(/^0x[0-9a-fA-F]+$/),\n /** Maximum total amount per time window */\n maxPerWindow: z.string().regex(/^0x[0-9a-fA-F]+$/),\n /** Time window in seconds */\n windowSeconds: z.number().positive(),\n /** Current spent amount in window (runtime state) */\n currentSpent: z\n .string()\n .regex(/^0x[0-9a-fA-F]+$/)\n .optional(),\n /** Window start timestamp (runtime state) */\n windowStart: z.number().optional(),\n});\n\nexport type SpendingLimit = z.infer<typeof SpendingLimitSchema>;\n\nexport const RecipientPolicySchema = z.object({\n /** Allowlist mode: only allow payments to these recipients */\n allowlist: z.array(z.string()).optional(),\n /** Blocklist mode: block payments to these recipients */\n blocklist: z.array(z.string()).optional(),\n /** Allow payments to unknown recipients (not in allowlist) */\n allowUnknown: z.boolean().default(true),\n});\n\nexport type RecipientPolicy = z.infer<typeof RecipientPolicySchema>;\n\nexport const RateLimitSchema = z.object({\n /** Maximum number of transactions per window */\n maxTransactions: z.number().positive(),\n /** Time window in seconds */\n windowSeconds: z.number().positive(),\n /** Cooldown between transactions in seconds */\n cooldownSeconds: z.number().nonnegative().default(0),\n /** Current transaction count in window (runtime state) */\n currentCount: z.number().optional(),\n /** Window start timestamp (runtime state) */\n windowStart: z.number().optional(),\n /** Last transaction timestamp (runtime state) */\n lastTransaction: z.number().optional(),\n});\n\nexport type RateLimit = z.infer<typeof RateLimitSchema>;\n\nexport const ChannelPolicySchema = z.object({\n /** Allow opening new channels */\n allowOpen: z.boolean().default(true),\n /** Allow closing channels */\n allowClose: z.boolean().default(true),\n /** Allow force close */\n allowForceClose: z.boolean().default(false),\n /** Maximum funding amount for new channels */\n maxFundingAmount: z\n .string()\n .regex(/^0x[0-9a-fA-F]+$/)\n .optional(),\n /** Minimum funding amount for new channels */\n minFundingAmount: z\n .string()\n .regex(/^0x[0-9a-fA-F]+$/)\n .optional(),\n /** Maximum number of channels */\n maxChannels: z.number().positive().optional(),\n});\n\nexport type ChannelPolicy = z.infer<typeof ChannelPolicySchema>;\n\nexport const SecurityPolicySchema = z.object({\n /** Policy name for identification */\n name: z.string(),\n /** Policy version */\n version: z.string().default('1.0.0'),\n /** Whether this policy is active */\n enabled: z.boolean().default(true),\n /** Spending limits configuration */\n spending: SpendingLimitSchema.optional(),\n /** Recipient restrictions */\n recipients: RecipientPolicySchema.optional(),\n /** Rate limiting configuration */\n rateLimit: RateLimitSchema.optional(),\n /** Channel operation policy */\n channels: ChannelPolicySchema.optional(),\n /** Require confirmation for amounts above this threshold */\n confirmationThreshold: z\n .string()\n .regex(/^0x[0-9a-fA-F]+$/)\n .optional(),\n /** Log all transactions to audit log */\n auditLogging: z.boolean().default(true),\n /** Custom metadata */\n metadata: z.record(z.string(), z.unknown()).optional(),\n});\n\nexport type SecurityPolicy = z.infer<typeof SecurityPolicySchema>;\n\n// =============================================================================\n// Policy Violation Types\n// =============================================================================\n\nexport type ViolationType =\n | 'SPENDING_LIMIT_PER_TX'\n | 'SPENDING_LIMIT_PER_WINDOW'\n | 'RATE_LIMIT_EXCEEDED'\n | 'RATE_LIMIT_COOLDOWN'\n | 'RECIPIENT_NOT_ALLOWED'\n | 'RECIPIENT_BLOCKED'\n | 'CHANNEL_OPEN_NOT_ALLOWED'\n | 'CHANNEL_CLOSE_NOT_ALLOWED'\n | 'CHANNEL_FORCE_CLOSE_NOT_ALLOWED'\n | 'CHANNEL_FUNDING_EXCEEDS_MAX'\n | 'CHANNEL_FUNDING_BELOW_MIN'\n | 'MAX_CHANNELS_REACHED'\n | 'REQUIRES_CONFIRMATION';\n\nexport interface PolicyViolation {\n type: ViolationType;\n message: string;\n details: {\n requested?: string;\n limit?: string;\n recipient?: string;\n remaining?: string;\n cooldownRemaining?: number;\n };\n}\n\nexport interface PolicyCheckResult {\n allowed: boolean;\n violations: PolicyViolation[];\n requiresConfirmation: boolean;\n}\n\n// =============================================================================\n// Audit Log Types\n// =============================================================================\n\nexport type AuditAction =\n | 'PAYMENT_SENT'\n | 'PAYMENT_RECEIVED'\n | 'INVOICE_CREATED'\n | 'INVOICE_VALIDATED'\n | 'HOLD_INVOICE_CREATED'\n | 'HOLD_INVOICE_SETTLED'\n | 'CHANNEL_OPENED'\n | 'CHANNEL_CLOSED'\n | 'POLICY_VIOLATION'\n | 'POLICY_UPDATED'\n | 'NODE_STARTED'\n | 'NODE_STOPPED';\n\nexport interface AuditLogEntry {\n timestamp: number;\n action: AuditAction;\n success: boolean;\n details: Record<string, unknown>;\n policyViolations?: PolicyViolation[];\n sessionId?: string;\n agentId?: string;\n}\n\n// =============================================================================\n// Key Management Types\n// =============================================================================\n\nexport interface KeyConfig {\n /** Base directory for key storage */\n baseDir: string;\n /** Password for key encryption (should come from secure source) */\n encryptionPassword?: string;\n /** Whether to generate keys if they don't exist */\n autoGenerate: boolean;\n}\n\nexport interface KeyInfo {\n /** Public key (hex) */\n publicKey: HexString;\n /** Whether the key is encrypted */\n encrypted: boolean;\n /** Key file path */\n path: string;\n /** Key creation timestamp */\n createdAt?: number;\n}\n\n// =============================================================================\n// Session Types (for multi-agent scenarios)\n// =============================================================================\n\nexport interface AgentSession {\n /** Unique session ID */\n sessionId: string;\n /** Agent identifier */\n agentId: string;\n /** Session start time */\n startedAt: number;\n /** Session expiry time */\n expiresAt?: number;\n /** Session-specific policy overrides */\n policyOverrides?: Partial<SecurityPolicy>;\n /** Session metadata */\n metadata?: Record<string, unknown>;\n}\n\n// =============================================================================\n// Default Policy\n// =============================================================================\n\nexport const DEFAULT_SECURITY_POLICY: SecurityPolicy = {\n name: 'default',\n version: '1.0.0',\n enabled: true,\n spending: {\n // 100 CKB per transaction\n maxPerTransaction: '0x2540be400',\n // 1000 CKB per hour\n maxPerWindow: '0x174876e800',\n windowSeconds: 3600,\n },\n rateLimit: {\n maxTransactions: 100,\n windowSeconds: 3600,\n cooldownSeconds: 1,\n },\n recipients: {\n allowUnknown: true,\n },\n channels: {\n allowOpen: true,\n allowClose: true,\n allowForceClose: false,\n maxChannels: 10,\n },\n auditLogging: true,\n};\n","/**\n * Fiber Network Node RPC Types (Fiber v0.7.1)\n *\n * The types in this file are intended to align with the upstream RPC spec:\n * https://github.com/nervosnetwork/fiber/blob/v0.7.1/crates/fiber-lib/src/rpc/README.md\n */\n\n// =============================================================================\n// Common Types\n// =============================================================================\n\n/** Hex-encoded string (prefixed with 0x). The RPC serializes most numeric values as hex strings. */\nexport type HexString = `0x${string}`;\n\n/** A 256-bit hash digest (Hash256 in the RPC spec). */\nexport type Hash256 = HexString;\n\n/** Public key for a node (Pubkey in the RPC spec). */\nexport type Pubkey = HexString;\n\n/** Private key (Privkey in the RPC spec). */\nexport type Privkey = HexString;\n\n/** Peer ID in libp2p format. */\nexport type PeerId = string;\n\n/** Multiaddr format for network addresses. */\nexport type Multiaddr = string;\n\n/** Channel ID (Hash256). */\nexport type ChannelId = Hash256;\n\n/** Payment hash (Hash256). */\nexport type PaymentHash = Hash256;\n\n/** Script structure for CKB. */\nexport interface Script {\n code_hash: HexString;\n hash_type: 'type' | 'data' | 'data1' | 'data2';\n args: HexString;\n}\n\n/** Transaction out point. */\nexport interface OutPoint {\n tx_hash: Hash256;\n index: HexString;\n}\n\n/** UDT (User Defined Token) script (UdtScript in the RPC spec). */\nexport type UdtScript = Script;\n\n// =============================================================================\n// Invoice Types\n// =============================================================================\n\nexport type Currency = 'Fibb' | 'Fibt' | 'Fibd';\n\nexport type HashAlgorithm = 'CkbHash' | 'Sha256';\n\n/** Recoverable signature (InvoiceSignature in the RPC spec). */\nexport type InvoiceSignature = HexString;\n\n/**\n * Invoice attribute types as returned by the RPC.\n * Each attribute is an object with a single key indicating the attribute type.\n */\nexport type Attribute =\n /** Deprecated since v0.6.0, preserved for compatibility. */\n | { FinalHtlcTimeout: HexString }\n /** Final TLC minimum expiry delta in milliseconds. */\n | { FinalHtlcMinimumExpiryDelta: HexString }\n /** Invoice expiry time in seconds. */\n | { ExpiryTime: HexString }\n /** Human-readable invoice description. */\n | { Description: string }\n /** Fallback address for on-chain settlement. */\n | { FallbackAddr: string }\n /** UDT script for token invoices. */\n | { UdtScript: UdtScript }\n /** Payee public key. */\n | { PayeePublicKey: Pubkey }\n /** Hash algorithm used in the payment hash lock. */\n | { HashAlgorithm: HashAlgorithm }\n /** Feature flags list. */\n | { Feature: string[] }\n /** Payment secret. */\n | { PaymentSecret: Hash256 };\n\nexport interface InvoiceData {\n timestamp: HexString;\n payment_hash: PaymentHash;\n attrs: Attribute[];\n}\n\nexport interface CkbInvoice {\n currency: Currency;\n amount?: HexString;\n signature?: InvoiceSignature;\n data: InvoiceData;\n}\n\nexport type CkbInvoiceStatus = 'Open' | 'Cancelled' | 'Expired' | 'Received' | 'Paid';\n\n// =============================================================================\n// Channel Types\n// =============================================================================\n\nexport enum ChannelState {\n NegotiatingFunding = 'NEGOTIATING_FUNDING',\n CollaboratingFundingTx = 'COLLABORATING_FUNDING_TX',\n SigningCommitment = 'SIGNING_COMMITMENT',\n AwaitingTxSignatures = 'AWAITING_TX_SIGNATURES',\n AwaitingChannelReady = 'AWAITING_CHANNEL_READY',\n ChannelReady = 'CHANNEL_READY',\n ShuttingDown = 'SHUTTING_DOWN',\n Closed = 'CLOSED',\n}\n\n/** Channel state flags are serialized as flag names by upstream RPC and may evolve. */\nexport type ChannelStateFlags = string[];\n\n/** TLC status. The upstream spec defines OutboundTlcStatus / InboundTlcStatus, which may evolve. */\nexport type TlcStatus = { Outbound: unknown } | { Inbound: unknown };\n\nexport interface Htlc {\n id: HexString;\n amount: HexString;\n payment_hash: PaymentHash;\n expiry: HexString;\n forwarding_channel_id?: Hash256;\n forwarding_tlc_id?: HexString;\n status: TlcStatus;\n}\n\nexport interface Channel {\n channel_id: ChannelId;\n is_public: boolean;\n is_acceptor: boolean;\n is_one_way: boolean;\n channel_outpoint: OutPoint | null;\n peer_id: PeerId;\n funding_udt_type_script: Script | null;\n state: {\n state_name: ChannelState;\n state_flags?: ChannelStateFlags;\n };\n local_balance: HexString;\n offered_tlc_balance: HexString;\n remote_balance: HexString;\n received_tlc_balance: HexString;\n pending_tlcs: Htlc[];\n latest_commitment_transaction_hash: Hash256 | null;\n created_at: HexString;\n enabled: boolean;\n tlc_expiry_delta: HexString;\n tlc_fee_proportional_millionths: HexString;\n shutdown_transaction_hash: Hash256 | null;\n failure_detail?: string;\n}\n\n// =============================================================================\n// Peer Types\n// =============================================================================\n\nexport interface PeerInfo {\n pubkey: Pubkey;\n peer_id: PeerId;\n address: Multiaddr;\n}\n\n// =============================================================================\n// Payment Types\n// =============================================================================\n\nexport type PaymentStatus = 'Created' | 'Inflight' | 'Success' | 'Failed';\n\n/**\n * Custom records for payments.\n *\n * Keys are hex-encoded u32 values (e.g. `0x1`, range 0..=65535),\n * values are hex-encoded byte arrays (0x-prefixed).\n */\nexport type PaymentCustomRecords = Record<string, HexString>;\n\nexport interface SessionRouteNode {\n pubkey: Pubkey;\n amount: HexString;\n channel_outpoint: OutPoint;\n}\n\nexport interface SessionRoute {\n nodes: SessionRouteNode[];\n}\n\nexport interface PaymentInfo {\n payment_hash: PaymentHash;\n status: PaymentStatus;\n created_at: HexString;\n last_updated_at: HexString;\n failed_error?: string;\n fee: HexString;\n custom_records?: PaymentCustomRecords;\n routers?: SessionRoute[];\n}\n\nexport interface HopHint {\n pubkey: Pubkey;\n channel_outpoint: OutPoint;\n fee_rate: HexString;\n tlc_expiry_delta: HexString;\n}\n\n// =============================================================================\n// Node / UDT Types\n// =============================================================================\n\nexport interface UdtCellDep {\n out_point: OutPoint;\n dep_type: 'code' | 'dep_group';\n}\n\nexport interface UdtDep {\n cell_dep?: UdtCellDep | null;\n type_id?: Script | null;\n}\n\nexport interface UdtArgInfo {\n name: string;\n script: UdtScript;\n auto_accept_amount?: HexString;\n cell_deps: UdtDep[];\n}\n\nexport type UdtCfgInfos = UdtArgInfo[];\n\nexport interface NodeInfo {\n version: string;\n commit_hash: string;\n node_id: Pubkey;\n features: string[];\n node_name: string | null;\n addresses: Multiaddr[];\n chain_hash: Hash256;\n open_channel_auto_accept_min_ckb_funding_amount: HexString;\n auto_accept_channel_ckb_funding_amount: HexString;\n default_funding_lock_script: Script;\n tlc_expiry_delta: HexString;\n tlc_min_value: HexString;\n tlc_fee_proportional_millionths: HexString;\n channel_count: HexString;\n pending_channel_count: HexString;\n peers_count: HexString;\n udt_cfg_infos: UdtCfgInfos;\n}\n\n// =============================================================================\n// Graph Types\n// =============================================================================\n\nexport interface ChannelUpdateInfo {\n timestamp: HexString;\n enabled: boolean;\n outbound_liquidity?: HexString;\n tlc_expiry_delta: HexString;\n tlc_minimum_value: HexString;\n fee_rate: HexString;\n}\n\nexport interface GraphNodeInfo {\n node_name: string;\n version: string;\n addresses: Multiaddr[];\n features: string[];\n node_id: Pubkey;\n timestamp: HexString;\n chain_hash: Hash256;\n auto_accept_min_ckb_funding_amount: HexString;\n udt_cfg_infos: UdtCfgInfos;\n}\n\nexport interface GraphChannelInfo {\n channel_outpoint: OutPoint;\n node1: Pubkey;\n node2: Pubkey;\n created_timestamp: HexString;\n update_info_of_node1?: ChannelUpdateInfo | null;\n update_info_of_node2?: ChannelUpdateInfo | null;\n capacity: HexString;\n chain_hash: Hash256;\n udt_type_script?: Script | null;\n}\n\n// =============================================================================\n// RPC Request/Response Types\n// =============================================================================\n\n// --- Peer Module ---\n\nexport interface ConnectPeerParams {\n address: Multiaddr;\n save?: boolean;\n}\n\n/** connect_peer returns null. */\nexport type ConnectPeerResult = null;\n\nexport interface DisconnectPeerParams {\n peer_id: PeerId;\n}\n\nexport interface ListPeersResult {\n peers: PeerInfo[];\n}\n\n// --- Channel Module ---\n\nexport interface OpenChannelParams {\n peer_id: PeerId;\n funding_amount: HexString;\n public?: boolean;\n one_way?: boolean;\n funding_udt_type_script?: Script;\n shutdown_script?: Script;\n commitment_delay_epoch?: HexString;\n commitment_fee_rate?: HexString;\n funding_fee_rate?: HexString;\n tlc_expiry_delta?: HexString;\n tlc_min_value?: HexString;\n tlc_fee_proportional_millionths?: HexString;\n max_tlc_value_in_flight?: HexString;\n max_tlc_number_in_flight?: HexString;\n}\n\nexport interface OpenChannelResult {\n temporary_channel_id: ChannelId;\n}\n\nexport interface AcceptChannelParams {\n temporary_channel_id: ChannelId;\n funding_amount: HexString;\n shutdown_script?: Script;\n max_tlc_value_in_flight?: HexString;\n max_tlc_number_in_flight?: HexString;\n tlc_min_value?: HexString;\n tlc_fee_proportional_millionths?: HexString;\n tlc_expiry_delta?: HexString;\n}\n\nexport interface AcceptChannelResult {\n channel_id: ChannelId;\n}\n\nexport interface ListChannelsParams {\n peer_id?: PeerId;\n include_closed?: boolean;\n only_pending?: boolean;\n}\n\nexport interface ListChannelsResult {\n channels: Channel[];\n}\n\nexport interface ShutdownChannelParams {\n channel_id: ChannelId;\n close_script?: Script;\n fee_rate?: HexString;\n force?: boolean;\n}\n\nexport interface AbandonChannelParams {\n channel_id: ChannelId;\n}\n\nexport interface UpdateChannelParams {\n channel_id: ChannelId;\n enabled?: boolean;\n tlc_expiry_delta?: HexString;\n tlc_minimum_value?: HexString;\n tlc_fee_proportional_millionths?: HexString;\n}\n\n// --- Payment Module ---\n\nexport interface SendPaymentParams {\n target_pubkey?: Pubkey;\n amount?: HexString;\n payment_hash?: PaymentHash;\n final_tlc_expiry_delta?: HexString;\n tlc_expiry_limit?: HexString;\n invoice?: string;\n timeout?: HexString;\n max_fee_amount?: HexString;\n max_fee_rate?: HexString;\n max_parts?: HexString;\n trampoline_hops?: Pubkey[];\n keysend?: boolean;\n udt_type_script?: Script;\n allow_self_payment?: boolean;\n custom_records?: PaymentCustomRecords;\n hop_hints?: HopHint[];\n dry_run?: boolean;\n}\n\nexport interface SendPaymentResult extends PaymentInfo {}\n\nexport interface GetPaymentParams {\n payment_hash: PaymentHash;\n}\n\nexport interface GetPaymentResult extends PaymentInfo {}\n\n// --- Invoice Module ---\n\nexport interface NewInvoiceParams {\n amount: HexString;\n description?: string;\n currency: Currency;\n payment_preimage?: Hash256;\n payment_hash?: PaymentHash;\n expiry?: HexString;\n fallback_address?: string;\n final_expiry_delta?: HexString;\n udt_type_script?: Script;\n hash_algorithm?: HashAlgorithm;\n allow_mpp?: boolean;\n allow_trampoline_routing?: boolean;\n}\n\nexport interface NewInvoiceResult {\n invoice_address: string;\n invoice: CkbInvoice;\n}\n\nexport interface ParseInvoiceParams {\n invoice: string;\n}\n\nexport interface ParseInvoiceResult {\n invoice: CkbInvoice;\n}\n\nexport interface GetInvoiceParams {\n payment_hash: PaymentHash;\n}\n\nexport interface GetInvoiceResult {\n invoice_address: string;\n invoice: CkbInvoice;\n status: CkbInvoiceStatus;\n}\n\nexport interface CancelInvoiceParams {\n payment_hash: PaymentHash;\n}\n\nexport interface CancelInvoiceResult {\n invoice_address: string;\n invoice: CkbInvoice;\n status: CkbInvoiceStatus;\n}\n\nexport interface SettleInvoiceParams {\n payment_hash: PaymentHash;\n payment_preimage: Hash256;\n}\n\n// --- Router Module ---\n\nexport interface HopRequire {\n pubkey: Pubkey;\n channel_outpoint?: OutPoint | null;\n}\n\nexport interface BuildRouterParams {\n amount?: HexString;\n udt_type_script?: Script;\n hops_info: HopRequire[];\n final_tlc_expiry_delta?: HexString;\n}\n\nexport interface RouterHop {\n target: Pubkey;\n channel_outpoint: OutPoint;\n amount_received: HexString;\n incoming_tlc_expiry: HexString;\n}\n\nexport interface BuildRouterResult {\n router_hops: RouterHop[];\n}\n\nexport interface SendPaymentWithRouterParams {\n payment_hash?: PaymentHash;\n router: RouterHop[];\n invoice?: string;\n custom_records?: PaymentCustomRecords;\n keysend?: boolean;\n allow_self_payment?: boolean;\n udt_type_script?: Script;\n dry_run?: boolean;\n}\n\n// --- Graph Module ---\n\nexport interface GraphNodesParams {\n limit?: HexString;\n after?: HexString;\n}\n\nexport interface GraphNodesResult {\n nodes: GraphNodeInfo[];\n last_cursor: HexString;\n}\n\nexport interface GraphChannelsParams {\n limit?: HexString;\n after?: HexString;\n}\n\nexport interface GraphChannelsResult {\n channels: GraphChannelInfo[];\n last_cursor: HexString;\n}\n\n// =============================================================================\n// Additional Upstream RPC Types (for advanced custom call usage)\n// =============================================================================\n\n/** Cross-chain hub invoice variant. */\nexport type CchInvoice = { Fiber: string } | { Lightning: string };\n\n/** Cross-chain hub order status. */\nexport type CchOrderStatus =\n | 'Pending'\n | 'IncomingAccepted'\n | 'OutgoingInFlight'\n | 'OutgoingSucceeded'\n | 'Succeeded'\n | 'Failed';\n\n/** Reason for removing a TLC in Dev module APIs. */\nexport type RemoveTlcReason = { RemoveTlcFulfill: Hash256 } | { RemoveTlcFail: HexString };\n\n/** TLC id wrapper in watchtower-related types. */\nexport type TLCId = { Offered: HexString } | { Received: HexString };\n\n/** Minimal CKB cell output representation used by watchtower revocation data. */\nexport interface CellOutput {\n capacity: HexString;\n lock: Script;\n type?: Script | null;\n}\n\n/** Settlement TLC data used by watchtower operations. */\nexport interface SettlementTlc {\n tlc_id: TLCId;\n hash_algorithm: HashAlgorithm;\n payment_amount: HexString;\n payment_hash: Hash256;\n expiry: HexString;\n local_key: Privkey;\n remote_key: Pubkey;\n}\n\n/** Settlement data used by watchtower operations. */\nexport interface SettlementData {\n local_amount: HexString;\n remote_amount: HexString;\n tlcs: SettlementTlc[];\n}\n\n/** Revocation data used by watchtower operations. */\nexport interface RevocationData {\n commitment_number: HexString;\n aggregated_signature: HexString;\n output: CellOutput;\n output_data: HexString;\n}\n\n// --- Info Module ---\n\nexport interface NodeInfoResult extends NodeInfo {}\n\n// =============================================================================\n// JSON-RPC Types\n// =============================================================================\n\nexport interface JsonRpcRequest<T = unknown> {\n jsonrpc: '2.0';\n id: number | string;\n method: string;\n params: T[];\n}\n\nexport interface JsonRpcResponse<T = unknown> {\n jsonrpc: '2.0';\n id: number | string;\n result?: T;\n error?: JsonRpcError;\n}\n\nexport interface JsonRpcError {\n code: number;\n message: string;\n data?: unknown;\n}\n","/**\n * Utility Functions\n * Common utilities for hex conversion, CKB amount calculation, and random generation\n */\n\nimport type { HexString } from './types/index.js';\n\nconst BASE58_ALPHABET = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';\n\n/**\n * Convert number to hex string\n */\nexport function toHex(value: number | bigint): HexString {\n return `0x${value.toString(16)}`;\n}\n\n/**\n * Convert hex string to bigint\n */\nexport function fromHex(hex: HexString): bigint {\n return BigInt(hex);\n}\n\n/**\n * Convert CKB amount (in CKB units) to shannons (hex)\n */\nexport function ckbToShannons(ckb: number | string): HexString {\n const amount = typeof ckb === 'string' ? parseFloat(ckb) : ckb;\n const shannons = BigInt(Math.floor(amount * 1e8));\n return toHex(shannons);\n}\n\n/**\n * Convert shannons (hex) to CKB amount\n */\nexport function shannonsToCkb(shannons: HexString): number {\n return Number(fromHex(shannons)) / 1e8;\n}\n\n/**\n * Generate a random 32-byte hex string (for payment preimage)\n */\nexport function randomBytes32(): HexString {\n const bytes = new Uint8Array(32);\n crypto.getRandomValues(bytes);\n return `0x${Array.from(bytes)\n .map((b) => b.toString(16).padStart(2, '0'))\n .join('')}`;\n}\n\nfunction base58btcEncode(bytes: Uint8Array): string {\n if (bytes.length === 0) return '';\n\n let number = 0n;\n for (const byte of bytes) {\n number = (number << 8n) + BigInt(byte);\n }\n\n let encoded = '';\n while (number > 0n) {\n const remainder = Number(number % 58n);\n encoded = BASE58_ALPHABET[remainder] + encoded;\n number /= 58n;\n }\n\n for (let i = 0; i < bytes.length && bytes[i] === 0; i++) {\n encoded = `1${encoded}`;\n }\n\n return encoded || '1';\n}\n\n/**\n * Convert a Fiber node id (hex-encoded compressed secp256k1 pubkey, 33 bytes)\n * to a libp2p peer id (base58btc encoded sha2-256 multihash).\n */\nexport async function nodeIdToPeerId(nodeId: string): Promise<string> {\n const normalized = nodeId.trim().replace(/^0x/i, '');\n\n if (!/^[0-9a-fA-F]+$/.test(normalized)) {\n throw new Error('Invalid node id: expected hex string');\n }\n if (normalized.length !== 66) {\n throw new Error(\n `Invalid node id: expected 33-byte compressed pubkey, got ${normalized.length / 2} bytes`,\n );\n }\n\n const raw = Uint8Array.from(\n normalized.match(/.{1,2}/g)?.map((byte) => Number.parseInt(byte, 16)) ?? [],\n );\n\n if (raw.length !== 33) {\n throw new Error(`Invalid node id: expected 33-byte compressed pubkey, got ${raw.length} bytes`);\n }\n\n const digestBuffer = await crypto.subtle.digest('SHA-256', raw);\n const digest = new Uint8Array(digestBuffer);\n const multihash = new Uint8Array(2 + digest.length);\n multihash[0] = 0x12;\n multihash[1] = 0x20;\n multihash.set(digest, 2);\n\n return base58btcEncode(multihash);\n}\n\n/**\n * Build a canonical multiaddr by appending/replacing /p2p/<peerId>.\n */\nexport function buildMultiaddr(address: string, peerId: string): string {\n const normalizedAddress = address.trim();\n const normalizedPeerId = peerId.trim();\n\n if (!normalizedAddress.startsWith('/')) {\n throw new Error('Invalid multiaddr: expected address starting with \"/\"');\n }\n if (!normalizedPeerId) {\n throw new Error('Invalid peer id: empty value');\n }\n\n const withoutPeerSuffix = normalizedAddress.replace(/\\/p2p\\/[^/]+$/, '');\n return `${withoutPeerSuffix}/p2p/${normalizedPeerId}`;\n}\n\n/**\n * Build a canonical multiaddr from a node id and base address.\n */\nexport async function buildMultiaddrFromNodeId(address: string, nodeId: string): Promise<string> {\n const peerId = await nodeIdToPeerId(nodeId);\n return buildMultiaddr(address, peerId);\n}\n\n/**\n * Build a best-effort local multiaddr from an RPC URL and peer id.\n * Uses rpcPort + 1 as inferred P2P port when advertised addresses are unavailable.\n */\nexport function buildMultiaddrFromRpcUrl(rpcUrl: string, peerId: string): string {\n let parsed: URL;\n try {\n parsed = new URL(rpcUrl);\n } catch {\n throw new Error(`Invalid RPC URL: ${rpcUrl}`);\n }\n\n if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {\n throw new Error(`Unsupported RPC protocol: ${parsed.protocol}`);\n }\n\n const port = parsed.port\n ? Number.parseInt(parsed.port, 10)\n : parsed.protocol === 'https:'\n ? 443\n : 80;\n if (!Number.isFinite(port) || port <= 0 || port > 65535) {\n throw new Error(`Invalid RPC port in URL: ${rpcUrl}`);\n }\n\n const p2pPort = port + 1;\n if (p2pPort > 65535) {\n throw new Error(`Cannot infer P2P port from RPC port ${port}`);\n }\n\n const host = parsed.hostname;\n const isIpv4 = /^\\d{1,3}(?:\\.\\d{1,3}){3}$/.test(host);\n const isIpv6 = host.includes(':');\n const base = isIpv4\n ? `/ip4/${host}/tcp/${p2pPort}`\n : isIpv6\n ? `/ip6/${host}/tcp/${p2pPort}`\n : `/dns/${host}/tcp/${p2pPort}`;\n\n return buildMultiaddr(base, peerId);\n}\n","/**\n * Fund Management & Liquidity Analyzer\n * Analyzes channel health, identifies liquidity gaps, and provides funding recommendations\n */\n\nimport type { FiberRpcClient } from '../rpc/client.js';\nimport type { Channel } from '../types/index.js';\nimport { ChannelState } from '../types/index.js';\nimport { shannonsToCkb } from '../utils.js';\n\n// =============================================================================\n// Types\n// =============================================================================\n\n/**\n * Channel health score breakdown\n */\nexport interface ChannelHealthMetrics {\n channelId: string;\n peerId: string;\n localBalanceCkb: number;\n remoteBalanceCkb: number;\n totalCapacityCkb: number;\n utilizationPercent: number; // How much of capacity is used\n balanceRatioPercent: number; // % of capacity on local side (50% = perfectly balanced)\n isBalanced: boolean; // Within 40-60% = balanced\n pendingLocalCkb: number; // Pending offered payments\n pendingRemoteCkb: number; // Pending received payments\n availableToSendCkb: number; // Can actually send right now\n availableToReceiveCkb: number; // Can actually receive right now\n healthScore: number; // 0-100\n state: ChannelState;\n}\n\nexport interface LiquidityGap {\n amount: number; // How much liquidity is missing\n reason: string; // Why it's needed\n severity: 'low' | 'medium' | 'high'; // Impact on operations\n affectedChannels: string[];\n}\n\nexport interface RebalanceRecommendation {\n from: string; // Source channel ID\n to: string; // Destination channel ID\n amountCkb: number;\n reason: string;\n benefit: string; // What this achieves\n estimatedRoutingFeeCkb: number;\n priority: number; // 1 (low) to 10 (critical)\n}\n\nexport interface FundingNeed {\n amount: number; // How much funding needed\n reason: string;\n optimalChannelPeerId?: string; // Recommended peer ID to fund\n urgency: 'low' | 'normal' | 'high';\n estimatedTimeToDepletion?: number; // Days until liquidity runs out\n}\n\nexport interface LiquidityReport {\n timestamp: number;\n balance: {\n totalCkb: number;\n availableToSendCkb: number;\n availableToReceiveCkb: number;\n lockedInChannelsCkb: number;\n };\n channels: {\n count: number;\n health: ChannelHealthMetrics[];\n averageHealthScore: number;\n balancedCount: number;\n imbalancedCount: number;\n };\n liquidity: {\n gaps: LiquidityGap[];\n hasCriticalGaps: boolean;\n runway: {\n daysAtCurrentRate?: number;\n estimatedDailySpendCkb?: number;\n };\n };\n recommendations: {\n rebalances: RebalanceRecommendation[];\n funding: FundingNeed[];\n };\n summary: string; // Human-readable summary\n}\n\n// =============================================================================\n// Liquidity Analyzer\n// =============================================================================\n\nexport class LiquidityAnalyzer {\n constructor(private rpc: FiberRpcClient) {}\n\n /**\n * Comprehensive liquidity analysis\n */\n async analyzeLiquidity(): Promise<LiquidityReport> {\n const timestamp = Date.now();\n\n // Fetch data\n const channels = await this.rpc.listChannels({});\n\n // Analyze each channel\n const channelMetrics: ChannelHealthMetrics[] = channels.channels.map((ch) =>\n this.analyzeChannelHealth(ch),\n );\n\n // Calculate totals\n const totalCkb = channelMetrics.reduce(\n (sum, ch) => sum + ch.localBalanceCkb + ch.remoteBalanceCkb,\n 0,\n );\n const availableToSendCkb = channelMetrics.reduce((sum, ch) => sum + ch.availableToSendCkb, 0);\n const availableToReceiveCkb = channelMetrics.reduce(\n (sum, ch) => sum + ch.availableToReceiveCkb,\n 0,\n );\n\n // Identify gaps and issues\n const gaps = this.identifyLiquidityGaps(channelMetrics, availableToSendCkb);\n\n // Generate rebalance recommendations\n const rebalances = this.generateRebalanceRecommendations(channelMetrics);\n\n // Estimate funding needs\n const fundingNeeds = this.estimateFundingNeeds(channelMetrics, gaps);\n\n // Calculate runway\n const runway = this.estimateRunway(availableToSendCkb, channelMetrics);\n\n // Summary\n const summary = this.generateSummary(channelMetrics, gaps, fundingNeeds, runway);\n\n return {\n timestamp,\n balance: {\n totalCkb,\n availableToSendCkb,\n availableToReceiveCkb,\n lockedInChannelsCkb: totalCkb - availableToSendCkb - availableToReceiveCkb,\n },\n channels: {\n count: channels.channels.length,\n health: channelMetrics,\n averageHealthScore:\n channelMetrics.length > 0\n ? channelMetrics.reduce((sum, ch) => sum + ch.healthScore, 0) / channelMetrics.length\n : 0,\n balancedCount: channelMetrics.filter((ch) => ch.isBalanced).length,\n imbalancedCount: channelMetrics.filter((ch) => !ch.isBalanced).length,\n },\n liquidity: {\n gaps,\n hasCriticalGaps: gaps.some((g) => g.severity === 'high'),\n runway,\n },\n recommendations: {\n rebalances,\n funding: fundingNeeds,\n },\n summary,\n };\n }\n\n /**\n * Analyze individual channel health\n */\n private analyzeChannelHealth(channel: Channel): ChannelHealthMetrics {\n const localBalance = shannonsToCkb(channel.local_balance);\n const remoteBalance = shannonsToCkb(channel.remote_balance);\n const totalCapacity = localBalance + remoteBalance;\n\n const pendingLocal = shannonsToCkb(channel.offered_tlc_balance);\n const pendingRemote = shannonsToCkb(channel.received_tlc_balance);\n\n const availableToSend = Math.max(0, localBalance - pendingLocal);\n const availableToReceive = Math.max(0, remoteBalance - pendingRemote);\n\n const utilizationPercent =\n totalCapacity > 0 ? ((pendingLocal + pendingRemote) / totalCapacity) * 100 : 0;\n const balanceRatioPercent = totalCapacity > 0 ? (localBalance / totalCapacity) * 100 : 50;\n\n // Channel is balanced if local balance is 40-60% of total\n const isBalanced = balanceRatioPercent >= 40 && balanceRatioPercent <= 60;\n\n // Health score (0-100)\n let healthScore = 100;\n\n // Deduct for high utilization (pending payments)\n if (utilizationPercent > 80) healthScore -= 20;\n else if (utilizationPercent > 50) healthScore -= 10;\n\n // Deduct for imbalance\n const imbalance = Math.abs(50 - balanceRatioPercent);\n healthScore -= (imbalance / 50) * 20; // Up to 20 points for extreme imbalance\n\n // Bonus for healthy balance\n if (isBalanced && utilizationPercent < 50) healthScore += 10;\n\n healthScore = Math.max(0, Math.min(100, healthScore));\n\n return {\n channelId: channel.channel_id,\n peerId: channel.peer_id,\n localBalanceCkb: localBalance,\n remoteBalanceCkb: remoteBalance,\n totalCapacityCkb: totalCapacity,\n utilizationPercent,\n balanceRatioPercent,\n isBalanced,\n pendingLocalCkb: pendingLocal,\n pendingRemoteCkb: pendingRemote,\n availableToSendCkb: availableToSend,\n availableToReceiveCkb: availableToReceive,\n healthScore,\n state: channel.state.state_name,\n };\n }\n\n /**\n * Identify liquidity shortfalls and gaps\n */\n private identifyLiquidityGaps(\n metrics: ChannelHealthMetrics[],\n _totalSendable: number,\n ): LiquidityGap[] {\n const gaps: LiquidityGap[] = [];\n\n // Gap 1: No send-capable channels\n const sendCapableCount = metrics.filter((ch) => ch.availableToSendCkb > 0).length;\n if (sendCapableCount === 0 && metrics.length > 0) {\n gaps.push({\n amount: 100, // Arbitrary amount - need to rebalance\n reason: 'No channels currently capable of sending. All liquidity on remote side.',\n severity: 'high',\n affectedChannels: metrics.map((ch) => ch.channelId),\n });\n }\n\n // Gap 2: All channels imbalanced (all local-heavy or all remote-heavy)\n const allLocalHeavy = metrics.every((ch) => ch.balanceRatioPercent > 70);\n const allRemoteHeavy = metrics.every((ch) => ch.balanceRatioPercent < 30);\n\n if (allLocalHeavy) {\n gaps.push({\n amount: 0, // Rebalance doesn't require funding\n reason: 'All channels are local-heavy. Cannot receive payments. Need inbound liquidity.',\n severity: 'high',\n affectedChannels: metrics.map((ch) => ch.channelId),\n });\n }\n\n if (allRemoteHeavy) {\n gaps.push({\n amount: 0, // Need to open new channels or rebalance\n reason: 'All channels are remote-heavy. Cannot send without rebalancing or new channels.',\n severity: 'high',\n affectedChannels: metrics.map((ch) => ch.channelId),\n });\n }\n\n // Gap 3: High utilization in all channels\n const allHighUtilization = metrics.every((ch) => ch.utilizationPercent > 70);\n if (allHighUtilization) {\n gaps.push({\n amount: 0,\n reason:\n 'High utilization in all channels. Many pending payments. Risk of payment failures.',\n severity: 'medium',\n affectedChannels: metrics.map((ch) => ch.channelId),\n });\n }\n\n return gaps;\n }\n\n /**\n * Generate rebalance recommendations between channels\n */\n private generateRebalanceRecommendations(\n metrics: ChannelHealthMetrics[],\n ): RebalanceRecommendation[] {\n const recommendations: RebalanceRecommendation[] = [];\n\n // Look for pairs: one local-heavy, one remote-heavy\n const localHeavy = metrics.filter((ch) => ch.balanceRatioPercent > 65);\n const remoteHeavy = metrics.filter((ch) => ch.balanceRatioPercent < 35);\n\n // Sort by how imbalanced they are\n localHeavy.sort((a, b) => b.balanceRatioPercent - a.balanceRatioPercent);\n remoteHeavy.sort((a, b) => a.balanceRatioPercent - b.balanceRatioPercent);\n\n // Pair them up\n for (let i = 0; i < Math.min(localHeavy.length, remoteHeavy.length); i++) {\n const source = localHeavy[i];\n const dest = remoteHeavy[i];\n\n // Calculate how much to move to balance both closer to 50%\n const sourceExcess = source.localBalanceCkb - source.totalCapacityCkb * 0.5;\n const destDeficit = dest.totalCapacityCkb * 0.5 - dest.localBalanceCkb;\n\n const amountToMove = Math.min(sourceExcess, destDeficit) * 0.8; // Move 80% to be conservative\n\n if (amountToMove > 0.1) {\n // Only if meaningful amount\n recommendations.push({\n from: source.channelId,\n to: dest.channelId,\n amountCkb: amountToMove,\n reason: `Rebalance liquidity: source is ${source.balanceRatioPercent.toFixed(0)}% local, destination is ${dest.balanceRatioPercent.toFixed(0)}% local`,\n benefit: `Improves payment success rate by balancing channel liquidity`,\n estimatedRoutingFeeCkb: amountToMove * 0.001, // 0.1% estimated fee\n priority: Math.round(\n (Math.abs(50 - source.balanceRatioPercent) + Math.abs(50 - dest.balanceRatioPercent)) /\n 20,\n ), // 1-10\n });\n }\n }\n\n return recommendations.sort((a, b) => b.priority - a.priority);\n }\n\n /**\n * Estimate funding needs for future operations\n */\n private estimateFundingNeeds(\n metrics: ChannelHealthMetrics[],\n gaps: LiquidityGap[],\n ): FundingNeed[] {\n const needs: FundingNeed[] = [];\n\n // If there are critical gaps, funding is needed\n const criticalGaps = gaps.filter((g) => g.severity === 'high');\n if (criticalGaps.length > 0) {\n // Find the best channel to fund (most balanced, highest capacity)\n const bestChannel = [...metrics]\n .filter((ch) => ch.state === ChannelState.ChannelReady)\n .sort((a, b) => {\n const scoreA = a.healthScore + a.totalCapacityCkb / 1000; // Higher score + capacity = better\n const scoreB = b.healthScore + b.totalCapacityCkb / 1000;\n return scoreB - scoreA;\n })[0];\n\n const fundingAmount = Math.ceil(bestChannel?.totalCapacityCkb || 100);\n\n needs.push({\n amount: fundingAmount,\n reason: 'Critical liquidity gaps detected in current channels',\n optimalChannelPeerId: bestChannel?.peerId,\n urgency: 'high',\n });\n }\n\n // If all channels are small, recommend growth\n const avgCapacity =\n metrics.length > 0\n ? metrics.reduce((sum, ch) => sum + ch.totalCapacityCkb, 0) / metrics.length\n : 0;\n\n if (avgCapacity < 100) {\n needs.push({\n amount: 500, // Reasonable growth target\n reason: 'Average channel capacity is small. Consider larger channels for reliability.',\n urgency: 'low',\n });\n }\n\n return needs;\n }\n\n /**\n * Estimate runway (days until liquidity depleted at current spending rate)\n */\n private estimateRunway(\n availableToSend: number,\n _metrics: ChannelHealthMetrics[],\n ): {\n daysAtCurrentRate?: number;\n estimatedDailySpendCkb?: number;\n } {\n // This is a simplified estimate\n // In real implementation, would track historical spending\n const estimatedDailySpend = 0.1; // Default: assume 0.1 CKB per day\n\n if (availableToSend > 0 && estimatedDailySpend > 0) {\n const days = availableToSend / estimatedDailySpend;\n return {\n daysAtCurrentRate: Math.floor(days),\n estimatedDailySpendCkb: estimatedDailySpend,\n };\n }\n\n return {};\n }\n\n /**\n * Generate human-readable summary\n */\n private generateSummary(\n metrics: ChannelHealthMetrics[],\n gaps: LiquidityGap[],\n fundingNeeds: FundingNeed[],\n runway: {\n daysAtCurrentRate?: number;\n estimatedDailySpendCkb?: number;\n },\n ): string {\n const parts: string[] = [];\n\n if (metrics.length === 0) {\n return 'No channels available. Open a channel to start making payments.';\n }\n\n parts.push(\n `Channel Health: ${metrics.filter((ch) => ch.healthScore >= 70).length}/${metrics.length} channels healthy`,\n );\n\n const avgScore = metrics.reduce((sum, ch) => sum + ch.healthScore, 0) / metrics.length;\n if (avgScore >= 80) {\n parts.push('Overall liquidity is good ✓');\n } else if (avgScore >= 60) {\n parts.push('Overall liquidity is fair. Some rebalancing recommended.');\n } else {\n parts.push('Overall liquidity is poor. Rebalancing needed urgently.');\n }\n\n if (gaps.length > 0) {\n parts.push(`${gaps.length} liquidity gap(s) detected.`);\n }\n\n if (fundingNeeds.length > 0) {\n parts.push(\n `Need to fund ${fundingNeeds.map((n) => n.amount).join(', ')} CKB to resolve issues.`,\n );\n }\n\n if (runway.daysAtCurrentRate) {\n parts.push(`Estimated runway: ${runway.daysAtCurrentRate} days at current spending rate.`);\n }\n\n return parts.join(' ');\n }\n\n /**\n * Get missing liquidity for a specific amount\n */\n async getMissingLiquidityForAmount(targetCkb: number): Promise<{\n canSend: boolean;\n shortfallCkb: number;\n recommendation: string;\n }> {\n const report = await this.analyzeLiquidity();\n\n const shortfallCkb = Math.max(0, targetCkb - report.balance.availableToSendCkb);\n const canSend = shortfallCkb === 0;\n\n let recommendation = '';\n if (canSend) {\n recommendation = `You have enough liquidity to send ${targetCkb} CKB.`;\n } else {\n recommendation = `You need ${shortfallCkb.toFixed(4)} more CKB in send capacity. Consider rebalancing or opening larger channels.`;\n }\n\n return { canSend, shortfallCkb, recommendation };\n }\n}\n","/**\n * MacaroonService\n *\n * Handles L402 macaroon minting, verification, and caveat management.\n * Uses the `macaroon` npm package for cryptographic operations and\n * Node.js built-in `crypto` for SHA-256 hashing.\n */\n\nimport { createHash } from 'node:crypto';\nimport * as macaroon from 'macaroon';\n\n// ─── Types ─────────────────────────────────────────────────\n\nexport interface MacaroonCaveat {\n condition: string;\n value: string;\n}\n\nexport interface MintParams {\n identifier: string;\n paymentHash: string;\n resourceId?: string;\n resourceType?: string;\n expirySeconds?: number;\n location?: string;\n}\n\nexport interface VerifyResult {\n valid: boolean;\n error?: string;\n caveats?: Record<string, string>;\n}\n\n// ─── Service ───────────────────────────────────────────────\n\nexport class MacaroonService {\n private rootKey: Buffer;\n\n constructor(rootKey?: string) {\n const keyHex = rootKey || process.env.L402_ROOT_KEY || this.generateRootKey();\n this.rootKey = Buffer.from(keyHex.replace(/^0x/, ''), 'hex');\n\n if (this.rootKey.length !== 32) {\n throw new Error('Root key must be 32 bytes (64 hex characters)');\n }\n }\n\n /**\n * Mint a new macaroon with embedded caveats.\n *\n * The macaroon identifier encodes the payment hash, resource info, and\n * version. First-party caveats are added for payment_hash, expiry, and\n * optionally resource_id / resource_type.\n */\n mint(params: MintParams): { macaroon: string; caveats: MacaroonCaveat[] } {\n const expiryTimestamp = Math.floor(Date.now() / 1000) + (params.expirySeconds || 3600);\n\n const caveats: MacaroonCaveat[] = [\n { condition: 'payment_hash', value: params.paymentHash },\n { condition: 'expiry', value: expiryTimestamp.toString() },\n ];\n\n if (params.resourceId) {\n caveats.push({ condition: 'resource_id', value: params.resourceId });\n }\n if (params.resourceType) {\n caveats.push({ condition: 'resource_type', value: params.resourceType });\n }\n\n const identifier = JSON.stringify({\n v: 0,\n pid: params.paymentHash,\n rid: params.resourceId,\n rtype: params.resourceType,\n loc: params.location || 'fiber-l402',\n });\n\n const m = macaroon.newMacaroon({\n rootKey: this.rootKey,\n identifier,\n location: params.location || 'fiber-l402',\n });\n\n for (const caveat of caveats) {\n m.addFirstPartyCaveat(`${caveat.condition}=${caveat.value}`);\n }\n\n const exported = m.exportJSON();\n const macaroonB64 = Buffer.from(JSON.stringify(exported)).toString('base64');\n\n return { macaroon: macaroonB64, caveats };\n }\n\n /**\n * Verify a macaroon with a payment preimage.\n *\n * Validates:\n * 1. SHA-256(preimage) === payment_hash in the macaroon identifier\n * 2. Macaroon signature against root key\n * 3. Expiry caveat is not past\n */\n verify(macaroonB64: string, preimage: string): VerifyResult {\n try {\n const exported = JSON.parse(Buffer.from(macaroonB64, 'base64').toString());\n const m = macaroon.importMacaroon(exported);\n\n const identifierBytes = m.identifier;\n const identifier = Buffer.from(identifierBytes).toString('utf-8');\n const idData = JSON.parse(identifier);\n const paymentHash = idData.pid;\n\n const preimageHash = createHash('sha256')\n .update(Buffer.from(preimage.replace(/^0x/, ''), 'hex'))\n .digest('hex');\n\n if (preimageHash !== paymentHash.replace(/^0x/, '')) {\n return { valid: false, error: 'Invalid preimage: hash mismatch' };\n }\n\n const caveatCheck = (caveat: string): string | null => {\n if (caveat.startsWith('expiry=')) {\n const expiry = parseInt(caveat.split('=')[1], 10);\n if (expiry < Math.floor(Date.now() / 1000)) {\n return 'Macaroon expired';\n }\n }\n return null;\n };\n\n m.verify(this.rootKey, caveatCheck, []);\n\n const caveats: Record<string, string> = {};\n for (const caveat of m.caveats) {\n const caveatStr = Buffer.from(caveat.identifier).toString('utf-8');\n const [key, value] = caveatStr.split('=');\n if (key && value) {\n caveats[key] = value;\n }\n }\n\n return { valid: true, caveats };\n } catch (error) {\n return {\n valid: false,\n error: error instanceof Error ? error.message : 'Verification failed',\n };\n }\n }\n\n /**\n * Verify macaroon signature and caveats without requiring a preimage.\n *\n * Used in the \"connected-node\" flow where the middleware verifies\n * invoice settlement via Fiber RPC instead of requiring the client\n * to provide the preimage directly.\n */\n verifyWithoutPreimage(macaroonB64: string): VerifyResult {\n try {\n const exported = JSON.parse(Buffer.from(macaroonB64, 'base64').toString());\n const m = macaroon.importMacaroon(exported);\n\n const caveatCheck = (caveat: string): string | null => {\n if (caveat.startsWith('expiry=')) {\n const expiry = parseInt(caveat.split('=')[1], 10);\n if (expiry < Math.floor(Date.now() / 1000)) {\n return 'Macaroon expired';\n }\n }\n return null;\n };\n\n m.verify(this.rootKey, caveatCheck, []);\n\n const caveats: Record<string, string> = {};\n for (const caveat of m.caveats) {\n const caveatStr = Buffer.from(caveat.identifier).toString('utf-8');\n const [key, value] = caveatStr.split('=');\n if (key && value) {\n caveats[key] = value;\n }\n }\n\n return { valid: true, caveats };\n } catch (error) {\n return {\n valid: false,\n error: error instanceof Error ? error.message : 'Verification failed',\n };\n }\n }\n\n /** Extract caveats from a macaroon without full verification. */\n extractCaveats(macaroonB64: string): Record<string, string> {\n try {\n const exported = JSON.parse(Buffer.from(macaroonB64, 'base64').toString());\n const m = macaroon.importMacaroon(exported);\n const caveats: Record<string, string> = {};\n\n for (const caveat of m.caveats) {\n const caveatStr = Buffer.from(caveat.identifier).toString('utf-8');\n const parts = caveatStr.split('=');\n if (parts.length === 2) {\n caveats[parts[0]] = parts[1];\n }\n }\n\n return caveats;\n } catch {\n return {};\n }\n }\n\n private generateRootKey(): string {\n const bytes = new Uint8Array(32);\n for (let i = 0; i < 32; i++) {\n bytes[i] = Math.floor(Math.random() * 256);\n }\n return Buffer.from(bytes).toString('hex');\n }\n}\n","/**\n * Fiber RPC Client\n * Type-safe JSON-RPC client for Fiber Network Node\n */\n\nimport type {\n AbandonChannelParams,\n AcceptChannelParams,\n AcceptChannelResult,\n // Router methods\n BuildRouterParams,\n BuildRouterResult,\n CancelInvoiceParams,\n CancelInvoiceResult,\n Channel,\n ChannelId,\n CkbInvoiceStatus,\n // Peer methods\n ConnectPeerParams,\n ConnectPeerResult,\n DisconnectPeerParams,\n GetInvoiceParams,\n GetInvoiceResult,\n GetPaymentParams,\n GetPaymentResult,\n GraphChannelsParams,\n GraphChannelsResult,\n // Graph methods\n GraphNodesParams,\n GraphNodesResult,\n JsonRpcError,\n JsonRpcRequest,\n JsonRpcResponse,\n ListChannelsParams,\n ListChannelsResult,\n ListPeersResult,\n // Invoice methods\n NewInvoiceParams,\n NewInvoiceResult,\n // Info methods\n NodeInfoResult,\n // Channel methods\n OpenChannelParams,\n OpenChannelResult,\n ParseInvoiceParams,\n ParseInvoiceResult,\n PaymentHash,\n // Payment methods\n SendPaymentParams,\n SendPaymentResult,\n SendPaymentWithRouterParams,\n SettleInvoiceParams,\n ShutdownChannelParams,\n UpdateChannelParams,\n} from '../types/index.js';\nimport { ChannelState, type HashAlgorithm } from '../types/index.js';\n\n// =============================================================================\n// Constants\n// =============================================================================\n\n/**\n * Mapping from SDK PascalCase HashAlgorithm to FNN RPC snake_case values.\n *\n * Upstream issue: https://github.com/RetricSu/fiber-pay/issues/66\n *\n * The SDK's HashAlgorithm type uses PascalCase ('CkbHash' | 'Sha256')\n * but FNN v0.7.1 RPC expects snake_case ('ckb_hash' | 'sha256').\n */\nconst HASH_ALGORITHM_MAP: Record<HashAlgorithm, string> = {\n CkbHash: 'ckb_hash',\n Sha256: 'sha256',\n};\n\n// =============================================================================\n// RPC Client Configuration\n// =============================================================================\n\nexport interface RpcClientConfig {\n /** RPC endpoint URL */\n url: string;\n /** Request timeout in milliseconds */\n timeout?: number;\n /** Custom headers */\n headers?: Record<string, string>;\n /**\n * Biscuit token for authentication.\n *\n * Prefer server-side usage. In browser apps, avoid embedding long-lived\n * privileged tokens and use a trusted backend/proxy where possible.\n */\n biscuitToken?: string;\n}\n\n// =============================================================================\n// RPC Error\n// =============================================================================\n\nexport class FiberRpcError extends Error {\n constructor(\n public code: number,\n message: string,\n public data?: unknown,\n ) {\n super(message);\n this.name = 'FiberRpcError';\n }\n\n static fromJsonRpcError(error: JsonRpcError): FiberRpcError {\n return new FiberRpcError(error.code, error.message, error.data);\n }\n}\n\n// =============================================================================\n// RPC Client\n// =============================================================================\n\nexport class FiberRpcClient {\n private requestId = 0;\n private config: Required<Pick<RpcClientConfig, 'url' | 'timeout'>> & RpcClientConfig;\n\n private readonly channelStateAliases: Record<string, ChannelState> = {\n NEGOTIATING_FUNDING: ChannelState.NegotiatingFunding,\n COLLABORATING_FUNDING_TX: ChannelState.CollaboratingFundingTx,\n SIGNING_COMMITMENT: ChannelState.SigningCommitment,\n AWAITING_TX_SIGNATURES: ChannelState.AwaitingTxSignatures,\n AWAITING_CHANNEL_READY: ChannelState.AwaitingChannelReady,\n CHANNEL_READY: ChannelState.ChannelReady,\n SHUTTING_DOWN: ChannelState.ShuttingDown,\n CLOSED: ChannelState.Closed,\n };\n\n constructor(config: RpcClientConfig) {\n this.config = {\n timeout: 30000,\n ...config,\n };\n }\n\n /**\n * Make a raw JSON-RPC call\n *\n * Useful for advanced/experimental RPCs not wrapped by convenience methods.\n *\n * @example\n * ```ts\n * const result = await client.call<MyResult>('some_method', [{ foo: 'bar' }]);\n * ```\n */\n async call<TResult>(method: string, params: unknown[] = []): Promise<TResult> {\n const request: JsonRpcRequest = {\n jsonrpc: '2.0',\n id: ++this.requestId,\n method,\n params,\n };\n\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n ...this.config.headers,\n };\n\n if (this.config.biscuitToken) {\n headers.Authorization = `Bearer ${this.config.biscuitToken}`;\n }\n\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.config.timeout);\n\n try {\n const response = await fetch(this.config.url, {\n method: 'POST',\n headers,\n body: JSON.stringify(request),\n signal: controller.signal,\n });\n\n if (!response.ok) {\n throw new FiberRpcError(-32000, `HTTP error: ${response.status} ${response.statusText}`);\n }\n\n const json = (await response.json()) as JsonRpcResponse<TResult>;\n\n if (json.error) {\n throw FiberRpcError.fromJsonRpcError(json.error);\n }\n\n if (json.result === undefined) {\n throw new FiberRpcError(-32000, 'Invalid JSON-RPC response: missing result and error');\n }\n\n return json.result as TResult;\n } catch (error) {\n if (error instanceof FiberRpcError) {\n throw error;\n }\n if (error instanceof Error) {\n if (error.name === 'AbortError') {\n throw new FiberRpcError(-32000, 'Request timeout');\n }\n throw new FiberRpcError(-32000, error.message);\n }\n throw new FiberRpcError(-32000, 'Unknown error');\n } finally {\n clearTimeout(timeoutId);\n }\n }\n\n // ===========================================================================\n // Peer Module\n // ===========================================================================\n\n /**\n * Connect to a peer\n */\n async connectPeer(params: ConnectPeerParams): Promise<ConnectPeerResult> {\n return this.call<ConnectPeerResult>('connect_peer', [params]);\n }\n\n /**\n * Disconnect from a peer\n */\n async disconnectPeer(params: DisconnectPeerParams): Promise<null> {\n return this.call<null>('disconnect_peer', [params]);\n }\n\n /**\n * List all connected peers\n */\n async listPeers(): Promise<ListPeersResult> {\n return this.call<ListPeersResult>('list_peers', []);\n }\n\n // ===========================================================================\n // Channel Module\n // ===========================================================================\n\n /**\n * Open a new channel with a peer\n */\n async openChannel(params: OpenChannelParams): Promise<OpenChannelResult> {\n return this.call<OpenChannelResult>('open_channel', [params]);\n }\n\n /**\n * Accept a channel opening request\n */\n async acceptChannel(params: AcceptChannelParams): Promise<AcceptChannelResult> {\n return this.call<AcceptChannelResult>('accept_channel', [params]);\n }\n\n /**\n * List all channels\n */\n async listChannels(params?: ListChannelsParams): Promise<ListChannelsResult> {\n const result = await this.call<ListChannelsResult>('list_channels', params ? [params] : [{}]);\n return {\n ...result,\n channels: result.channels.map((channel) => this.normalizeChannel(channel)),\n };\n }\n\n private normalizeChannelStateName(stateName: string): ChannelState {\n const alias = this.channelStateAliases[stateName];\n if (alias) return alias;\n\n const normalizedInput = stateName.replace(/[^a-zA-Z0-9]/g, '').toLowerCase();\n for (const value of Object.values(ChannelState)) {\n const normalizedValue = value.replace(/[^a-zA-Z0-9]/g, '').toLowerCase();\n if (normalizedValue === normalizedInput) {\n return value;\n }\n }\n\n return stateName as ChannelState;\n }\n\n private normalizeChannel(channel: Channel): Channel {\n return {\n ...channel,\n state: {\n ...channel.state,\n state_name: this.normalizeChannelStateName(channel.state.state_name),\n },\n };\n }\n\n /**\n * Shutdown (close) a channel\n */\n async shutdownChannel(params: ShutdownChannelParams): Promise<null> {\n return this.call<null>('shutdown_channel', [params]);\n }\n\n /**\n * Abandon a pending channel\n */\n async abandonChannel(params: AbandonChannelParams): Promise<null> {\n return this.call<null>('abandon_channel', [params]);\n }\n\n /**\n * Update channel parameters\n */\n async updateChannel(params: UpdateChannelParams): Promise<null> {\n return this.call<null>('update_channel', [params]);\n }\n\n // ===========================================================================\n // Payment Module\n // ===========================================================================\n\n /**\n * Send a payment\n */\n async sendPayment(params: SendPaymentParams): Promise<SendPaymentResult> {\n return this.call<SendPaymentResult>('send_payment', [params]);\n }\n\n /**\n * Get payment status\n */\n async getPayment(params: GetPaymentParams): Promise<GetPaymentResult> {\n return this.call<GetPaymentResult>('get_payment', [params]);\n }\n\n // ===========================================================================\n // Invoice Module\n // ===========================================================================\n\n /**\n * Create a new invoice\n *\n * NOTE: HashAlgorithm value mapping\n *\n * Upstream issue: https://github.com/RetricSu/fiber-pay/issues/66\n *\n * The SDK's HashAlgorithm type uses PascalCase ('CkbHash' | 'Sha256')\n * but FNN v0.7.1 RPC expects snake_case ('ckb_hash' | 'sha256').\n *\n * This mapping ensures compatibility while maintaining backward-compatible\n * SDK types. When upstream fixes this inconsistency, this mapping can\n * be removed.\n */\n async newInvoice(params: NewInvoiceParams): Promise<NewInvoiceResult> {\n const { hash_algorithm, ...rest } = params;\n const rpcParams: Record<string, unknown> = { ...rest };\n\n if (hash_algorithm) {\n // Map PascalCase HashAlgorithm values to snake_case for RPC\n rpcParams.hash_algorithm = HASH_ALGORITHM_MAP[hash_algorithm];\n }\n\n return this.call<NewInvoiceResult>('new_invoice', [rpcParams]);\n }\n\n /**\n * Parse an invoice string\n */\n async parseInvoice(params: ParseInvoiceParams): Promise<ParseInvoiceResult> {\n return this.call<ParseInvoiceResult>('parse_invoice', [params]);\n }\n\n /**\n * Get invoice by payment hash\n */\n async getInvoice(params: GetInvoiceParams): Promise<GetInvoiceResult> {\n return this.call<GetInvoiceResult>('get_invoice', [params]);\n }\n\n /**\n * Cancel an open invoice\n */\n async cancelInvoice(params: CancelInvoiceParams): Promise<CancelInvoiceResult> {\n return this.call<CancelInvoiceResult>('cancel_invoice', [params]);\n }\n\n /**\n * Settle a hold invoice with the preimage\n * Used for conditional/escrow payments where the invoice was created\n * with a payment_hash (no preimage provided upfront)\n */\n async settleInvoice(params: SettleInvoiceParams): Promise<null> {\n return this.call<null>('settle_invoice', [params]);\n }\n\n // ===========================================================================\n // Router Module\n // ===========================================================================\n\n /**\n * Build a custom route for payment\n * Useful for channel rebalancing (circular payments) and advanced routing\n */\n async buildRouter(params: BuildRouterParams): Promise<BuildRouterResult> {\n return this.call<BuildRouterResult>('build_router', [params]);\n }\n\n /**\n * Send a payment using a pre-built route from buildRouter()\n * Use with allow_self_payment for channel rebalancing\n */\n async sendPaymentWithRouter(params: SendPaymentWithRouterParams): Promise<SendPaymentResult> {\n return this.call<SendPaymentResult>('send_payment_with_router', [params]);\n }\n\n // ===========================================================================\n // Graph Module\n // ===========================================================================\n\n /**\n * List nodes in the network graph\n */\n async graphNodes(params?: GraphNodesParams): Promise<GraphNodesResult> {\n return this.call<GraphNodesResult>('graph_nodes', params ? [params] : [{}]);\n }\n\n /**\n * List channels in the network graph\n */\n async graphChannels(params?: GraphChannelsParams): Promise<GraphChannelsResult> {\n return this.call<GraphChannelsResult>('graph_channels', params ? [params] : [{}]);\n }\n\n // ===========================================================================\n // Info Module\n // ===========================================================================\n\n /**\n * Get local node information\n */\n async nodeInfo(): Promise<NodeInfoResult> {\n return this.call<NodeInfoResult>('node_info', []);\n }\n\n // ===========================================================================\n // Utility Methods\n // ===========================================================================\n\n /**\n * Check if the node is reachable\n */\n async ping(): Promise<boolean> {\n try {\n await this.nodeInfo();\n return true;\n } catch {\n return false;\n }\n }\n\n /**\n * Wait for the node to be ready\n */\n async waitForReady(options: { timeout?: number; interval?: number } = {}): Promise<void> {\n const { timeout = 60000, interval = 1000 } = options;\n const start = Date.now();\n\n while (Date.now() - start < timeout) {\n if (await this.ping()) {\n return;\n }\n await new Promise((resolve) => setTimeout(resolve, interval));\n }\n\n throw new FiberRpcError(-32000, 'Node not ready within timeout');\n }\n\n // ===========================================================================\n // Polling / Watching Helpers\n // ===========================================================================\n\n /**\n * Wait for a payment to reach a terminal state (Success or Failed)\n * Polls get_payment at the specified interval.\n *\n * @returns The final payment result\n * @throws FiberRpcError on timeout\n */\n async waitForPayment(\n paymentHash: PaymentHash,\n options: { timeout?: number; interval?: number } = {},\n ): Promise<GetPaymentResult> {\n const { timeout = 120000, interval = 2000 } = options;\n const start = Date.now();\n\n while (Date.now() - start < timeout) {\n const result = await this.getPayment({ payment_hash: paymentHash });\n if (result.status === 'Success' || result.status === 'Failed') {\n return result;\n }\n await new Promise((resolve) => setTimeout(resolve, interval));\n }\n\n throw new FiberRpcError(-32000, `Payment ${paymentHash} did not complete within ${timeout}ms`);\n }\n\n /**\n * Wait for a channel to reach ChannelReady state.\n * Polls list_channels at the specified interval.\n *\n * @returns The channel info once ready\n * @throws FiberRpcError on timeout or if channel disappears\n */\n async waitForChannelReady(\n channelId: ChannelId,\n options: { timeout?: number; interval?: number } = {},\n ): Promise<Channel> {\n const { timeout = 300000, interval = 5000 } = options;\n const start = Date.now();\n\n while (Date.now() - start < timeout) {\n const result = await this.listChannels({});\n const channel = result.channels.find((ch) => ch.channel_id === channelId);\n\n if (!channel) {\n // Channel may use temporary_channel_id initially, check all\n const allChannels = result.channels;\n const found = allChannels.find((ch) => ch.channel_id === channelId);\n if (!found) {\n // Channel not yet visible or was abandoned - keep waiting\n await new Promise((resolve) => setTimeout(resolve, interval));\n continue;\n }\n }\n\n if (channel && channel.state.state_name === ChannelState.ChannelReady) {\n return channel;\n }\n\n if (channel && channel.state.state_name === ChannelState.Closed) {\n throw new FiberRpcError(-32000, `Channel ${channelId} was closed before becoming ready`);\n }\n\n await new Promise((resolve) => setTimeout(resolve, interval));\n }\n\n throw new FiberRpcError(\n -32000,\n `Channel ${channelId} did not become ready within ${timeout}ms`,\n );\n }\n\n /**\n * Wait for an invoice to reach a specific status.\n * Useful for hold invoice workflows: wait for 'Received' before settling.\n *\n * @returns The invoice info once the target status is reached\n * @throws FiberRpcError on timeout\n */\n async waitForInvoiceStatus(\n paymentHash: PaymentHash,\n targetStatus: CkbInvoiceStatus | CkbInvoiceStatus[],\n options: { timeout?: number; interval?: number } = {},\n ): Promise<GetInvoiceResult> {\n const { timeout = 120000, interval = 2000 } = options;\n const statuses = Array.isArray(targetStatus) ? targetStatus : [targetStatus];\n const start = Date.now();\n\n while (Date.now() - start < timeout) {\n const result = await this.getInvoice({ payment_hash: paymentHash });\n if (statuses.includes(result.status)) {\n return result;\n }\n // If cancelled, stop waiting\n if (result.status === 'Cancelled') {\n throw new FiberRpcError(-32000, `Invoice ${paymentHash} was cancelled`);\n }\n await new Promise((resolve) => setTimeout(resolve, interval));\n }\n\n throw new FiberRpcError(\n -32000,\n `Invoice ${paymentHash} did not reach status [${statuses.join(', ')}] within ${timeout}ms`,\n );\n }\n\n /**\n * Watch for incoming payments on specified invoices.\n * Polls invoice statuses and calls the callback when a status changes.\n * Use an AbortSignal to stop watching.\n *\n * @example\n * ```typescript\n * const controller = new AbortController();\n * client.watchIncomingPayments({\n * paymentHashes: [hash1, hash2],\n * onPayment: (invoice) => console.log('Payment received!', invoice),\n * signal: controller.signal,\n * });\n * // Later: controller.abort(); to stop watching\n * ```\n */\n async watchIncomingPayments(options: {\n /** Payment hashes of invoices to watch */\n paymentHashes: PaymentHash[];\n /** Callback when an invoice status changes to Received or Paid */\n onPayment: (invoice: GetInvoiceResult) => void;\n /** Polling interval in ms (default: 3000) */\n interval?: number;\n /** AbortSignal to stop watching */\n signal?: AbortSignal;\n }): Promise<void> {\n const { paymentHashes, onPayment, interval = 3000, signal } = options;\n const knownStatuses = new Map<string, CkbInvoiceStatus>();\n\n // Initialize known statuses\n for (const hash of paymentHashes) {\n try {\n const invoice = await this.getInvoice({ payment_hash: hash });\n knownStatuses.set(hash, invoice.status);\n } catch {\n knownStatuses.set(hash, 'Open');\n }\n }\n\n while (!signal?.aborted) {\n for (const hash of paymentHashes) {\n if (signal?.aborted) return;\n\n try {\n const invoice = await this.getInvoice({ payment_hash: hash });\n const previousStatus = knownStatuses.get(hash);\n\n if (\n invoice.status !== previousStatus &&\n (invoice.status === 'Received' || invoice.status === 'Paid')\n ) {\n knownStatuses.set(hash, invoice.status);\n onPayment(invoice);\n } else if (invoice.status !== previousStatus) {\n knownStatuses.set(hash, invoice.status);\n }\n } catch {\n // Invoice may not exist yet or node unreachable — skip this round\n }\n }\n\n await new Promise<void>((resolve) => {\n if (signal?.aborted) {\n resolve();\n return;\n }\n const timer = setTimeout(resolve, interval);\n signal?.addEventListener(\n 'abort',\n () => {\n clearTimeout(timer);\n resolve();\n },\n { once: true },\n );\n });\n }\n }\n}\n\n// =============================================================================\n// Re-export utility functions\n// =============================================================================\n\nexport { ckbToShannons, fromHex, randomBytes32, shannonsToCkb, toHex } from '../utils.js';\n","/**\n * L402 Middleware for Express\n *\n * Protects routes with the L402 payment protocol. On unauthenticated\n * requests it issues a 402 challenge (macaroon + Fiber invoice); on\n * subsequent requests it verifies the L402 token.\n *\n * Two verification paths are supported:\n * Path A — client provides macaroon:preimage (legacy / manual flow)\n * Path B — client provides macaroon only; middleware checks invoice\n * settlement via Fiber RPC (connected-node flow)\n *\n * Uses `FiberRpcClient` from `@fiber-pay/sdk` directly for invoice\n * creation and settlement checks, eliminating the intermediate\n * InvoiceService abstraction from the upstream fiber-l402 SDK.\n */\n\nimport type { NextFunction, Request, Response } from 'express';\nimport { FiberRpcClient } from '../rpc/index.js';\nimport type { Currency, HashAlgorithm } from '../types/index.js';\nimport { MacaroonService } from './macaroon.js';\nimport type { L402MiddlewareConfig, L402Request, ProtectedResourceInfo } from './types.js';\n\n// ─── Internal Types ────────────────────────────────────────\n\ninterface L402ResourceResolver {\n resolve(req: Request): Promise<ProtectedResourceInfo | undefined>;\n}\n\ntype LegacyResourceProvider = (\n req: Request,\n) => Promise<ProtectedResourceInfo | undefined> | ProtectedResourceInfo | undefined;\n\n// ─── Middleware Class ──────────────────────────────────────\n\nexport class L402Middleware {\n private config: L402MiddlewareConfig;\n private rateLimitStore: Map<string, { count: number; resetTime: number }>;\n private macaroonService: MacaroonService;\n private rpcClient: FiberRpcClient;\n private resourceResolver?: L402ResourceResolver;\n private currency: Currency;\n\n constructor(\n config: Partial<L402MiddlewareConfig> & {\n /** Pre-configured RPC client. Takes precedence over rpcUrl. */\n rpcClient?: FiberRpcClient;\n /** Fiber node RPC URL. Used when rpcClient is not provided. */\n rpcUrl?: string;\n /** Biscuit token for Fiber RPC authentication. */\n biscuitToken?: string;\n /** Invoice currency. Default: 'Fibt' (testnet). */\n currency?: Currency;\n /** Resource resolver registry for dynamic pricing. */\n resourceResolver?: L402ResourceResolver;\n /** @deprecated Use resourceResolver instead. */\n resourceProvider?: LegacyResourceProvider;\n } = {},\n ) {\n this.config = {\n rootKey: config.rootKey || process.env.L402_ROOT_KEY,\n expirySeconds: config.expirySeconds || 3600,\n priceCkb: config.priceCkb || 0.1,\n rateLimitWindowMs: config.rateLimitWindowMs || 60000,\n rateLimitMaxRequests: config.rateLimitMaxRequests || 100,\n };\n\n this.rateLimitStore = new Map();\n this.macaroonService = new MacaroonService(this.config.rootKey);\n this.currency = config.currency || 'Fibt';\n\n this.rpcClient =\n config.rpcClient ||\n new FiberRpcClient({\n url: config.rpcUrl || process.env.FIBER_RPC_URL || 'http://127.0.0.1:8227',\n biscuitToken: config.biscuitToken || process.env.FIBER_BISCUIT_TOKEN,\n });\n\n if (config.resourceResolver) {\n this.resourceResolver = config.resourceResolver;\n } else if (config.resourceProvider) {\n this.resourceResolver = {\n resolve: async (req: Request) => config.resourceProvider?.(req),\n };\n }\n }\n\n async handle(req: L402Request, res: Response, next: NextFunction): Promise<void> {\n const clientIp = req.ip || req.socket.remoteAddress || 'unknown';\n if (!this.checkRateLimit(clientIp)) {\n res.status(429).json({\n error: 'Rate limit exceeded',\n retryAfter: Math.ceil(this.config.rateLimitWindowMs / 1000),\n });\n return;\n }\n\n const resource = this.resourceResolver ? await this.resourceResolver.resolve(req) : undefined;\n\n const authHeader = req.headers.authorization;\n if (!authHeader?.startsWith('L402 ')) {\n return this.issueChallenge(req, res, 402, undefined, resource);\n }\n\n const [, token] = authHeader.split(' ');\n if (!token) {\n return this.issueChallenge(req, res);\n }\n\n const splitIndex = token.indexOf(':');\n const macaroonToken = splitIndex >= 0 ? token.slice(0, splitIndex) : token;\n const preimage = splitIndex >= 0 ? token.slice(splitIndex + 1) : undefined;\n\n if (!macaroonToken) {\n return this.issueChallenge(req, res);\n }\n\n // Path A: legacy flow with explicit preimage (manual entry).\n if (preimage) {\n const result = this.macaroonService.verify(macaroonToken, preimage);\n if (!result.valid) {\n return this.issueChallenge(req, res, 401, result.error, resource);\n }\n\n const headerError = this.validatePaymentHashHeader(req, result.caveats || {});\n if (headerError) {\n return this.issueChallenge(req, res, 401, headerError, resource);\n }\n\n const validateError = this.validateResourceCaveats(result.caveats || {}, resource);\n if (validateError) {\n return this.issueChallenge(req, res, 401, validateError, resource);\n }\n\n req.l402 = { valid: true, preimage };\n next();\n return;\n }\n\n // Path B: connected-node flow without preimage.\n // Verify macaroon signature + caveats, then check invoice settlement via RPC.\n const verifyResult = this.macaroonService.verifyWithoutPreimage(macaroonToken);\n if (!verifyResult.valid) {\n return this.issueChallenge(req, res, 401, verifyResult.error, resource);\n }\n\n const caveats = verifyResult.caveats || {};\n const paymentHash = caveats.payment_hash;\n if (!paymentHash) {\n return this.issueChallenge(req, res, 401, 'Missing payment hash caveat', resource);\n }\n\n const headerError = this.validatePaymentHashHeader(req, caveats);\n if (headerError) {\n return this.issueChallenge(req, res, 401, headerError, resource);\n }\n\n const validateError = this.validateResourceCaveats(caveats, resource);\n if (validateError) {\n return this.issueChallenge(req, res, 401, validateError, resource);\n }\n\n try {\n const invoiceResult = await this.rpcClient.getInvoice({\n payment_hash: paymentHash as `0x${string}`,\n });\n if (invoiceResult.status !== 'Paid') {\n return this.issueChallenge(\n req,\n res,\n 401,\n `Invoice not settled (status: ${invoiceResult.status})`,\n resource,\n );\n }\n } catch {\n return this.issueChallenge(req, res, 401, 'Failed to verify invoice status', resource);\n }\n\n req.l402 = { valid: true, paymentHash };\n next();\n }\n\n // ─── Private Helpers ───────────────────────────────────────\n\n private validateResourceCaveats(\n caveats: Record<string, string>,\n resource?: ProtectedResourceInfo,\n ): string | undefined {\n if (!resource) {\n return undefined;\n }\n\n if (resource.id && caveats.resource_id && caveats.resource_id !== resource.id) {\n return 'Resource id mismatch';\n }\n\n if (resource.type && caveats.resource_type && caveats.resource_type !== resource.type) {\n return 'Resource type mismatch';\n }\n\n if (resource.id && !caveats.resource_id) {\n return 'Missing resource_id in macaroon';\n }\n\n if (resource.type && !caveats.resource_type) {\n return 'Missing resource_type in macaroon';\n }\n\n return undefined;\n }\n\n private validatePaymentHashHeader(\n req: Request,\n caveats: Record<string, string>,\n ): string | undefined {\n const rawHeader = req.headers['x-l402-payment-hash'];\n const headerPaymentHash = Array.isArray(rawHeader) ? rawHeader[0] : rawHeader;\n if (!headerPaymentHash) {\n return undefined;\n }\n\n const caveatPaymentHash = caveats.payment_hash;\n if (!caveatPaymentHash) {\n return 'Missing payment hash caveat';\n }\n\n if (headerPaymentHash !== caveatPaymentHash) {\n return 'Payment hash header mismatch';\n }\n\n return undefined;\n }\n\n private checkRateLimit(ip: string): boolean {\n const now = Date.now();\n const record = this.rateLimitStore.get(ip);\n\n if (!record) {\n this.rateLimitStore.set(ip, {\n count: 1,\n resetTime: now + this.config.rateLimitWindowMs,\n });\n return true;\n }\n\n if (now > record.resetTime) {\n this.rateLimitStore.set(ip, {\n count: 1,\n resetTime: now + this.config.rateLimitWindowMs,\n });\n return true;\n }\n\n if (record.count >= this.config.rateLimitMaxRequests) {\n return false;\n }\n\n record.count++;\n return true;\n }\n\n private async issueChallenge(\n req: Request,\n res: Response,\n statusCode: number = 402,\n errorMessage?: string,\n resource?: ProtectedResourceInfo,\n ): Promise<void> {\n try {\n const { macaroon, invoice } = await this.createChallenge(req, resource);\n const wwwAuthenticate = `L402 macaroon=\"${macaroon}\", invoice=\"${invoice}\"`;\n\n res\n .status(statusCode)\n .set('WWW-Authenticate', wwwAuthenticate)\n .json({\n error: errorMessage || 'Payment Required',\n macaroon,\n invoice,\n });\n } catch (error) {\n res.status(500).json({\n error: 'Failed to create payment challenge',\n message: error instanceof Error ? error.message : 'Unknown error',\n });\n }\n }\n\n private async createChallenge(\n req: Request,\n resource?: ProtectedResourceInfo,\n ): Promise<{ macaroon: string; invoice: string }> {\n const priceCkb = resource?.priceCkb ?? this.config.priceCkb;\n const amountShannons = `0x${(priceCkb * 100000000).toString(16)}` as `0x${string}`;\n\n const invoiceResult = await this.rpcClient.newInvoice({\n amount: amountShannons,\n description: `L402 Payment ${resource?.type ?? 'resource'}`,\n currency: this.currency,\n expiry: `0x${this.config.expirySeconds.toString(16)}`,\n hash_algorithm: 'Sha256' as HashAlgorithm,\n });\n\n const paymentHash = invoiceResult.invoice.data.payment_hash;\n\n const { macaroon } = this.macaroonService.mint({\n identifier: `l402-${Date.now()}-${Math.random().toString(36).slice(2)}`,\n paymentHash,\n expirySeconds: this.config.expirySeconds,\n resourceId: resource?.id,\n resourceType: resource?.type,\n location: req.headers.host || 'fiber-l402',\n });\n\n return { macaroon, invoice: invoiceResult.invoice_address };\n }\n}\n\n// ─── Factory ───────────────────────────────────────────────\n\n/**\n * Create an L402 middleware function for Express.\n *\n * @example\n * ```ts\n * import express from 'express';\n * import { createL402Middleware } from '@fiber-pay/sdk';\n *\n * const app = express();\n *\n * app.get('/api/premium/*', createL402Middleware({\n * rootKey: process.env.L402_ROOT_KEY,\n * priceCkb: 0.1,\n * expirySeconds: 3600,\n * }));\n * ```\n */\nexport function createL402Middleware(\n config: Partial<L402MiddlewareConfig> & {\n rpcClient?: FiberRpcClient;\n rpcUrl?: string;\n biscuitToken?: string;\n currency?: Currency;\n resourceResolver?: L402ResourceResolver;\n resourceProvider?: LegacyResourceProvider;\n } = {},\n) {\n const middleware = new L402Middleware(config);\n return middleware.handle.bind(middleware);\n}\n","/**\n * Default Resource Resolver Registry\n *\n * Iterates registered resolvers to match incoming requests to protected\n * resource metadata (id, type, price). Used by L402Middleware for\n * dynamic per-resource pricing.\n */\n\nimport type { Request } from 'express';\nimport type { ProtectedResourceInfo, ResourceResolver, ResourceResolverRegistry } from './types.js';\n\nexport class DefaultResourceResolverRegistry implements ResourceResolverRegistry {\n private resolvers: ResourceResolver[];\n\n constructor(resolvers: ResourceResolver[] = []) {\n this.resolvers = [...resolvers];\n }\n\n register(resolver: ResourceResolver): void {\n this.resolvers.push(resolver);\n }\n\n async resolve(req: Request): Promise<ProtectedResourceInfo | undefined> {\n for (const resolver of this.resolvers) {\n if (!resolver.matches(req)) {\n continue;\n }\n\n const resource = await resolver.resolve(req);\n if (resource) {\n return resource;\n }\n }\n\n return undefined;\n }\n}\n","/**\n * Biscuit policy helpers for Fiber RPC.\n *\n * These helpers model the upstream RPC authorization rules and generate\n * token-side permission facts like `read(\"peers\");` and `write(\"payments\");`.\n */\n\nexport type BiscuitAction = 'read' | 'write';\n\nexport interface BiscuitPermission {\n action: BiscuitAction;\n resource: string;\n}\n\nexport interface BiscuitMethodRule {\n permissions: BiscuitPermission[];\n requiresChannelRight: boolean;\n}\n\nconst RULES: Record<string, BiscuitMethodRule> = {\n // Cch\n send_btc: {\n permissions: [{ action: 'write', resource: 'cch' }],\n requiresChannelRight: false,\n },\n receive_btc: {\n permissions: [{ action: 'read', resource: 'cch' }],\n requiresChannelRight: false,\n },\n get_cch_order: {\n permissions: [{ action: 'read', resource: 'cch' }],\n requiresChannelRight: false,\n },\n\n // Channel\n open_channel: {\n permissions: [{ action: 'write', resource: 'channels' }],\n requiresChannelRight: false,\n },\n accept_channel: {\n permissions: [{ action: 'write', resource: 'channels' }],\n requiresChannelRight: false,\n },\n abandon_channel: {\n permissions: [{ action: 'write', resource: 'channels' }],\n requiresChannelRight: false,\n },\n list_channels: {\n permissions: [{ action: 'read', resource: 'channels' }],\n requiresChannelRight: false,\n },\n shutdown_channel: {\n permissions: [{ action: 'write', resource: 'channels' }],\n requiresChannelRight: false,\n },\n update_channel: {\n permissions: [{ action: 'write', resource: 'channels' }],\n requiresChannelRight: false,\n },\n\n // Dev\n commitment_signed: {\n permissions: [{ action: 'write', resource: 'messages' }],\n requiresChannelRight: false,\n },\n add_tlc: {\n permissions: [{ action: 'write', resource: 'channels' }],\n requiresChannelRight: false,\n },\n remove_tlc: {\n permissions: [{ action: 'write', resource: 'channels' }],\n requiresChannelRight: false,\n },\n check_channel_shutdown: {\n permissions: [{ action: 'write', resource: 'channels' }],\n requiresChannelRight: false,\n },\n submit_commitment_transaction: {\n permissions: [{ action: 'write', resource: 'chain' }],\n requiresChannelRight: false,\n },\n\n // Graph\n graph_nodes: {\n permissions: [{ action: 'read', resource: 'graph' }],\n requiresChannelRight: false,\n },\n graph_channels: {\n permissions: [{ action: 'read', resource: 'graph' }],\n requiresChannelRight: false,\n },\n\n // Info\n node_info: {\n permissions: [{ action: 'read', resource: 'node' }],\n requiresChannelRight: false,\n },\n\n // Invoice\n new_invoice: {\n permissions: [{ action: 'write', resource: 'invoices' }],\n requiresChannelRight: false,\n },\n parse_invoice: {\n permissions: [{ action: 'read', resource: 'invoices' }],\n requiresChannelRight: false,\n },\n get_invoice: {\n permissions: [{ action: 'read', resource: 'invoices' }],\n requiresChannelRight: false,\n },\n cancel_invoice: {\n permissions: [{ action: 'write', resource: 'invoices' }],\n requiresChannelRight: false,\n },\n settle_invoice: {\n permissions: [{ action: 'write', resource: 'invoices' }],\n requiresChannelRight: false,\n },\n\n // Payment\n send_payment: {\n permissions: [{ action: 'write', resource: 'payments' }],\n requiresChannelRight: false,\n },\n get_payment: {\n permissions: [{ action: 'read', resource: 'payments' }],\n requiresChannelRight: false,\n },\n build_router: {\n permissions: [{ action: 'read', resource: 'payments' }],\n requiresChannelRight: false,\n },\n send_payment_with_router: {\n permissions: [{ action: 'write', resource: 'payments' }],\n requiresChannelRight: false,\n },\n\n // Peer\n connect_peer: {\n permissions: [{ action: 'write', resource: 'peers' }],\n requiresChannelRight: false,\n },\n disconnect_peer: {\n permissions: [{ action: 'write', resource: 'peers' }],\n requiresChannelRight: false,\n },\n list_peers: {\n permissions: [{ action: 'read', resource: 'peers' }],\n requiresChannelRight: false,\n },\n\n // Watchtower\n create_watch_channel: {\n permissions: [{ action: 'write', resource: 'watchtower' }],\n requiresChannelRight: true,\n },\n remove_watch_channel: {\n permissions: [{ action: 'write', resource: 'watchtower' }],\n requiresChannelRight: true,\n },\n update_revocation: {\n permissions: [{ action: 'write', resource: 'watchtower' }],\n requiresChannelRight: true,\n },\n update_local_settlement: {\n permissions: [{ action: 'write', resource: 'watchtower' }],\n requiresChannelRight: true,\n },\n update_pending_remote_settlement: {\n permissions: [{ action: 'write', resource: 'watchtower' }],\n requiresChannelRight: true,\n },\n create_preimage: {\n permissions: [{ action: 'write', resource: 'watchtower' }],\n requiresChannelRight: false,\n },\n remove_preimage: {\n permissions: [{ action: 'write', resource: 'watchtower' }],\n requiresChannelRight: false,\n },\n};\n\nfunction escapeDatalogString(value: string): string {\n return value.replace(/\\\\/g, '\\\\\\\\').replace(/\"/g, '\\\\\"');\n}\n\nexport function getBiscuitRuleForMethod(method: string): BiscuitMethodRule | undefined {\n return RULES[method];\n}\n\nexport function collectBiscuitPermissions(methods: string[]): BiscuitPermission[] {\n const dedup = new Map<string, BiscuitPermission>();\n\n for (const method of methods) {\n const rule = RULES[method];\n if (!rule) continue;\n\n for (const permission of rule.permissions) {\n const key = `${permission.action}:${permission.resource}`;\n if (!dedup.has(key)) {\n dedup.set(key, permission);\n }\n }\n }\n\n return [...dedup.values()].sort((a, b) => {\n if (a.action === b.action) {\n return a.resource.localeCompare(b.resource);\n }\n return a.action.localeCompare(b.action);\n });\n}\n\nexport function renderBiscuitPermissionFacts(permissions: BiscuitPermission[]): string {\n return permissions.map((p) => `${p.action}(\"${escapeDatalogString(p.resource)}\");`).join('\\n');\n}\n\nexport function renderBiscuitFactsForMethods(methods: string[]): string {\n return renderBiscuitPermissionFacts(collectBiscuitPermissions(methods));\n}\n\nexport function listSupportedBiscuitMethods(): string[] {\n return Object.keys(RULES).sort();\n}\n","/**\n * Crypto Utilities\n * Pure cryptographic functions for key operations.\n * Browser-compatible — uses Web Crypto API and @noble/hashes.\n */\n\nimport { blake2b } from '@noble/hashes/blake2.js';\nimport { scrypt } from '@noble/hashes/scrypt.js';\nimport { sha256 } from '@noble/hashes/sha2.js';\nimport type { Hash256, HashAlgorithm, HexString } from '../types/index.js';\n\n// =============================================================================\n// Constants\n// =============================================================================\n\nexport const SCRYPT_N = 2 ** 14;\nexport const SCRYPT_R = 8;\nexport const SCRYPT_P = 1;\nexport const KEY_LENGTH = 32;\nexport const SALT_LENGTH = 32;\nexport const IV_LENGTH = 16;\nexport const AUTH_TAG_LENGTH = 16;\n\n/** Magic bytes: ASCII 'FIBERENC' */\nexport const ENCRYPTED_MAGIC = new Uint8Array([0x46, 0x49, 0x42, 0x45, 0x52, 0x45, 0x4e, 0x43]);\n\n// =============================================================================\n// Helpers\n// =============================================================================\n\nfunction bytesToHex(bytes: Uint8Array): string {\n return Array.from(bytes)\n .map((b) => b.toString(16).padStart(2, '0'))\n .join('');\n}\n\n/**\n * Copy a Uint8Array into a new one backed by its own ArrayBuffer.\n * Needed because subarray() shares the parent buffer, which breaks\n * Web Crypto APIs that expect an owned ArrayBuffer.\n */\nfunction ownedCopy(src: Uint8Array): Uint8Array<ArrayBuffer> {\n const dst = new Uint8Array(src.length);\n dst.set(src);\n return dst;\n}\n\n// =============================================================================\n// Functions\n// =============================================================================\n\n/**\n * Check if key data is encrypted (starts with FIBERENC magic bytes)\n */\nexport function isEncryptedKey(data: Uint8Array): boolean {\n if (data.length < ENCRYPTED_MAGIC.length) return false;\n for (let i = 0; i < ENCRYPTED_MAGIC.length; i++) {\n if (data[i] !== ENCRYPTED_MAGIC[i]) return false;\n }\n return true;\n}\n\n/**\n * Decrypt an encrypted key using scrypt + AES-256-GCM\n */\nexport async function decryptKey(data: Uint8Array, password: string): Promise<Uint8Array> {\n let offset = ENCRYPTED_MAGIC.length;\n const salt = data.subarray(offset, offset + SALT_LENGTH);\n offset += SALT_LENGTH;\n const iv = ownedCopy(data.subarray(offset, offset + IV_LENGTH));\n offset += IV_LENGTH;\n const authTag = data.subarray(offset, offset + AUTH_TAG_LENGTH);\n offset += AUTH_TAG_LENGTH;\n const encrypted = data.subarray(offset);\n\n const derivedKey = ownedCopy(\n scrypt(new TextEncoder().encode(password), salt, {\n N: SCRYPT_N,\n r: SCRYPT_R,\n p: SCRYPT_P,\n dkLen: KEY_LENGTH,\n }),\n );\n\n const cryptoKey = await crypto.subtle.importKey('raw', derivedKey, { name: 'AES-GCM' }, false, [\n 'decrypt',\n ]);\n\n // Web Crypto expects ciphertext + authTag concatenated\n const ciphertext = new Uint8Array(encrypted.length + authTag.length);\n ciphertext.set(encrypted);\n ciphertext.set(authTag, encrypted.length);\n\n const decrypted = await crypto.subtle.decrypt(\n { name: 'AES-GCM', iv, tagLength: AUTH_TAG_LENGTH * 8 },\n cryptoKey,\n ciphertext,\n );\n\n return new Uint8Array(decrypted);\n}\n\n/**\n * Derive a public key hash from a private key (SHA-256)\n */\nexport async function derivePublicKey(privateKey: Uint8Array): Promise<HexString> {\n const hashBuffer = await crypto.subtle.digest('SHA-256', ownedCopy(privateKey));\n return `0x${bytesToHex(new Uint8Array(hashBuffer))}` as HexString;\n}\n\n/**\n * Generate a random 32-byte private key\n */\nexport function generatePrivateKey(): Uint8Array {\n const bytes = new Uint8Array(32);\n crypto.getRandomValues(bytes);\n return bytes;\n}\n\n/**\n * Generate a random preimage for hold invoice\n * @returns Hex-encoded random 32-byte preimage\n */\nexport function generatePreimage(): HexString {\n const bytes = new Uint8Array(32);\n crypto.getRandomValues(bytes);\n return `0x${bytesToHex(bytes)}` as HexString;\n}\n\n// =============================================================================\n// Payment Hash Utilities\n// =============================================================================\n\n/** CKB blake2b-256 personalization string */\nconst CKB_HASH_PERSONALIZATION = new Uint8Array([\n 99, 107, 98, 45, 100, 101, 102, 97, 117, 108, 116, 45, 104, 97, 115, 104,\n]);\n\n/**\n * Compute CKB hash (blake2b-256 with \"ckb-default-hash\" personalization)\n */\nexport function ckbHash(data: Uint8Array): Uint8Array {\n return blake2b(data, { dkLen: 32, personalization: CKB_HASH_PERSONALIZATION });\n}\n\n/**\n * Compute SHA-256 hash\n */\nexport function sha256Hash(data: Uint8Array): Uint8Array {\n return sha256(data);\n}\n\n/**\n * Decode a hex string to Uint8Array (browser-compatible)\n * @param hex - Hex string (with or without 0x prefix)\n */\nfunction hexToBytes(hex: string): Uint8Array {\n const cleanHex = hex.replace(/^0x/i, '');\n\n if (cleanHex.length === 0) {\n return new Uint8Array(0);\n }\n\n if (!/^[0-9a-fA-F]*$/.test(cleanHex)) {\n throw new Error('Invalid hex string: contains non-hex characters');\n }\n\n if (cleanHex.length % 2 !== 0) {\n throw new Error('Invalid hex string: odd length');\n }\n\n const bytes = new Uint8Array(cleanHex.length / 2);\n for (let i = 0; i < bytes.length; i++) {\n bytes[i] = parseInt(cleanHex.slice(i * 2, i * 2 + 2), 16);\n }\n return bytes;\n}\n\n/**\n * Assert that a value is never (exhaustiveness check for switch statements)\n */\nfunction assertNever(x: never): never {\n throw new Error(`Unexpected value: ${String(x)}`);\n}\n\n/**\n * Compute payment hash from preimage using specified algorithm\n * @param preimageHex - Hex-encoded preimage (0x-prefixed)\n * @param algorithm - Hash algorithm: 'CkbHash' or 'Sha256'\n * @returns Hex-encoded payment hash (0x-prefixed, 64 hex chars)\n */\nexport function hashPreimage(preimageHex: HexString, algorithm: HashAlgorithm): Hash256 {\n const data = hexToBytes(preimageHex);\n\n let hashBytes: Uint8Array;\n switch (algorithm) {\n case 'Sha256':\n hashBytes = sha256Hash(data);\n break;\n case 'CkbHash':\n hashBytes = ckbHash(data);\n break;\n default:\n return assertNever(algorithm);\n }\n\n return `0x${bytesToHex(hashBytes)}` as Hash256;\n}\n\n/**\n * Verify that a preimage matches the given payment hash\n * @param preimageHex - Hex-encoded preimage\n * @param paymentHash - Expected payment hash\n * @param algorithm - Hash algorithm used\n * @returns true if preimage hashes to paymentHash\n */\nexport function verifyPreimageHash(\n preimageHex: HexString,\n paymentHash: Hash256,\n algorithm: HashAlgorithm,\n): boolean {\n try {\n const computedHash = hashPreimage(preimageHex, algorithm);\n\n // Compare all bytes to reduce timing side channels for equal-length hashes.\n const computed = hexToBytes(computedHash);\n const expected = hexToBytes(paymentHash);\n\n if (computed.length !== expected.length) {\n return false;\n }\n\n let result = 0;\n for (let i = 0; i < computed.length; i++) {\n result |= computed[i] ^ expected[i];\n }\n return result === 0;\n } catch {\n // Treat malformed inputs as non-matching in this boolean helper.\n return false;\n }\n}\n","/**\n * Policy Engine\n * Enforces spending limits, rate limits, and other security policies\n * This operates at the SDK level and cannot be bypassed via prompts\n */\n\nimport type {\n AuditAction,\n AuditLogEntry,\n PolicyCheckResult,\n PolicyViolation,\n RateLimit,\n SecurityPolicy,\n SpendingLimit,\n} from '../types/index.js';\nimport { fromHex, toHex } from '../utils.js';\n\n// =============================================================================\n// Policy Engine\n// =============================================================================\n\nexport class PolicyEngine {\n private policy: SecurityPolicy;\n private auditLog: AuditLogEntry[] = [];\n private spendingState: SpendingLimit;\n private rateLimitState: RateLimit;\n\n constructor(policy: SecurityPolicy) {\n this.policy = policy;\n\n // Initialize spending state\n this.spendingState = {\n ...(policy.spending ?? {\n maxPerTransaction: '0x0',\n maxPerWindow: '0x0',\n windowSeconds: 3600,\n }),\n currentSpent: '0x0',\n windowStart: Date.now(),\n };\n\n // Initialize rate limit state\n this.rateLimitState = {\n ...(policy.rateLimit ?? {\n maxTransactions: 0,\n windowSeconds: 3600,\n cooldownSeconds: 0,\n }),\n currentCount: 0,\n windowStart: Date.now(),\n lastTransaction: 0,\n };\n }\n\n /**\n * Check if a payment is allowed by the policy\n */\n checkPayment(params: {\n amount: string; // hex\n recipient?: string;\n }): PolicyCheckResult {\n const violations: PolicyViolation[] = [];\n let requiresConfirmation = false;\n\n if (!this.policy.enabled) {\n return { allowed: true, violations: [], requiresConfirmation: false };\n }\n\n const amount = fromHex(params.amount as `0x${string}`);\n\n // Check spending limit per transaction\n if (this.policy.spending) {\n const maxPerTx = fromHex(this.policy.spending.maxPerTransaction as `0x${string}`);\n if (amount > maxPerTx) {\n violations.push({\n type: 'SPENDING_LIMIT_PER_TX',\n message: `Amount ${amount} exceeds per-transaction limit of ${maxPerTx}`,\n details: {\n requested: params.amount,\n limit: this.policy.spending.maxPerTransaction,\n },\n });\n }\n\n // Check spending limit per window\n this.refreshSpendingWindow();\n const currentSpent = fromHex(this.spendingState.currentSpent as `0x${string}`);\n const maxPerWindow = fromHex(this.policy.spending.maxPerWindow as `0x${string}`);\n\n if (currentSpent + amount > maxPerWindow) {\n const remaining = maxPerWindow - currentSpent;\n violations.push({\n type: 'SPENDING_LIMIT_PER_WINDOW',\n message: `Amount ${amount} would exceed window limit. Remaining: ${remaining}`,\n details: {\n requested: params.amount,\n limit: this.policy.spending.maxPerWindow,\n remaining: toHex(remaining > 0n ? remaining : 0n),\n },\n });\n }\n }\n\n // Check rate limit\n if (this.policy.rateLimit) {\n this.refreshRateLimitWindow();\n\n if ((this.rateLimitState.currentCount ?? 0) >= this.policy.rateLimit.maxTransactions) {\n violations.push({\n type: 'RATE_LIMIT_EXCEEDED',\n message: `Rate limit of ${this.policy.rateLimit.maxTransactions} transactions per ${this.policy.rateLimit.windowSeconds}s exceeded`,\n details: {},\n });\n }\n\n // Check cooldown\n const now = Date.now();\n const cooldownMs = this.policy.rateLimit.cooldownSeconds * 1000;\n const timeSinceLast = now - (this.rateLimitState.lastTransaction || 0);\n\n if (timeSinceLast < cooldownMs) {\n violations.push({\n type: 'RATE_LIMIT_COOLDOWN',\n message: `Cooldown period not elapsed. Wait ${Math.ceil((cooldownMs - timeSinceLast) / 1000)}s`,\n details: {\n cooldownRemaining: Math.ceil((cooldownMs - timeSinceLast) / 1000),\n },\n });\n }\n }\n\n // Check recipient policy\n if (this.policy.recipients && params.recipient) {\n if (this.policy.recipients.blocklist?.includes(params.recipient)) {\n violations.push({\n type: 'RECIPIENT_BLOCKED',\n message: `Recipient ${params.recipient} is blocklisted`,\n details: { recipient: params.recipient },\n });\n }\n\n if (\n this.policy.recipients.allowlist &&\n this.policy.recipients.allowlist.length > 0 &&\n !this.policy.recipients.allowlist.includes(params.recipient) &&\n !this.policy.recipients.allowUnknown\n ) {\n violations.push({\n type: 'RECIPIENT_NOT_ALLOWED',\n message: `Recipient ${params.recipient} is not in allowlist`,\n details: { recipient: params.recipient },\n });\n }\n }\n\n // Check confirmation threshold\n if (this.policy.confirmationThreshold) {\n const threshold = fromHex(this.policy.confirmationThreshold as `0x${string}`);\n if (amount > threshold) {\n requiresConfirmation = true;\n violations.push({\n type: 'REQUIRES_CONFIRMATION',\n message: `Amount ${amount} exceeds confirmation threshold of ${threshold}`,\n details: {\n requested: params.amount,\n limit: this.policy.confirmationThreshold,\n },\n });\n }\n }\n\n return {\n allowed: violations.filter((v) => v.type !== 'REQUIRES_CONFIRMATION').length === 0,\n violations,\n requiresConfirmation,\n };\n }\n\n /**\n * Check if a channel operation is allowed\n */\n checkChannelOperation(params: {\n operation: 'open' | 'close' | 'force_close';\n fundingAmount?: string; // hex\n currentChannelCount?: number;\n }): PolicyCheckResult {\n const violations: PolicyViolation[] = [];\n\n if (!this.policy.enabled || !this.policy.channels) {\n return { allowed: true, violations: [], requiresConfirmation: false };\n }\n\n const { channels } = this.policy;\n\n if (params.operation === 'open') {\n if (!channels.allowOpen) {\n violations.push({\n type: 'CHANNEL_OPEN_NOT_ALLOWED',\n message: 'Channel opening is not allowed by policy',\n details: {},\n });\n }\n\n if (params.fundingAmount && channels.maxFundingAmount) {\n const funding = fromHex(params.fundingAmount as `0x${string}`);\n const max = fromHex(channels.maxFundingAmount as `0x${string}`);\n if (funding > max) {\n violations.push({\n type: 'CHANNEL_FUNDING_EXCEEDS_MAX',\n message: `Funding amount ${funding} exceeds maximum ${max}`,\n details: {\n requested: params.fundingAmount,\n limit: channels.maxFundingAmount,\n },\n });\n }\n }\n\n if (params.fundingAmount && channels.minFundingAmount) {\n const funding = fromHex(params.fundingAmount as `0x${string}`);\n const min = fromHex(channels.minFundingAmount as `0x${string}`);\n if (funding < min) {\n violations.push({\n type: 'CHANNEL_FUNDING_BELOW_MIN',\n message: `Funding amount ${funding} below minimum ${min}`,\n details: {\n requested: params.fundingAmount,\n limit: channels.minFundingAmount,\n },\n });\n }\n }\n\n if (\n channels.maxChannels &&\n params.currentChannelCount !== undefined &&\n params.currentChannelCount >= channels.maxChannels\n ) {\n violations.push({\n type: 'MAX_CHANNELS_REACHED',\n message: `Maximum channel count of ${channels.maxChannels} reached`,\n details: {},\n });\n }\n }\n\n if (params.operation === 'close' && !channels.allowClose) {\n violations.push({\n type: 'CHANNEL_CLOSE_NOT_ALLOWED',\n message: 'Channel closing is not allowed by policy',\n details: {},\n });\n }\n\n if (params.operation === 'force_close' && !channels.allowForceClose) {\n violations.push({\n type: 'CHANNEL_FORCE_CLOSE_NOT_ALLOWED',\n message: 'Force channel closing is not allowed by policy',\n details: {},\n });\n }\n\n return {\n allowed: violations.length === 0,\n violations,\n requiresConfirmation: false,\n };\n }\n\n /**\n * Record a successful payment (updates spending and rate limit state)\n */\n recordPayment(amount: string): void {\n this.refreshSpendingWindow();\n this.refreshRateLimitWindow();\n\n // Update spending\n const currentSpent = fromHex(this.spendingState.currentSpent as `0x${string}`);\n const paymentAmount = fromHex(amount as `0x${string}`);\n this.spendingState.currentSpent = toHex(currentSpent + paymentAmount);\n\n // Update rate limit\n this.rateLimitState.currentCount = (this.rateLimitState.currentCount ?? 0) + 1;\n this.rateLimitState.lastTransaction = Date.now();\n }\n\n /**\n * Add an entry to the audit log\n */\n addAuditEntry(\n action: AuditAction,\n success: boolean,\n details: Record<string, unknown>,\n violations?: PolicyViolation[],\n ): void {\n if (!this.policy.auditLogging) return;\n\n this.auditLog.push({\n timestamp: Date.now(),\n action,\n success,\n details,\n policyViolations: violations,\n });\n\n // Keep audit log bounded (last 1000 entries)\n if (this.auditLog.length > 1000) {\n this.auditLog = this.auditLog.slice(-1000);\n }\n }\n\n /**\n * Get the audit log\n */\n getAuditLog(options?: { limit?: number; since?: number }): AuditLogEntry[] {\n let log = this.auditLog;\n\n const since = options?.since;\n if (since !== undefined) {\n log = log.filter((entry) => entry.timestamp >= since);\n }\n\n if (options?.limit) {\n log = log.slice(-options.limit);\n }\n\n return log;\n }\n\n /**\n * Get remaining spending allowance\n */\n getRemainingAllowance(): { perTransaction: bigint; perWindow: bigint } {\n this.refreshSpendingWindow();\n\n const maxPerTx = this.policy.spending\n ? fromHex(this.policy.spending.maxPerTransaction as `0x${string}`)\n : BigInt(Number.MAX_SAFE_INTEGER);\n\n const maxPerWindow = this.policy.spending\n ? fromHex(this.policy.spending.maxPerWindow as `0x${string}`)\n : BigInt(Number.MAX_SAFE_INTEGER);\n\n const currentSpent = fromHex(this.spendingState.currentSpent as `0x${string}`);\n const remainingWindow = maxPerWindow - currentSpent;\n\n return {\n perTransaction: maxPerTx,\n perWindow: remainingWindow > 0n ? remainingWindow : 0n,\n };\n }\n\n /**\n * Update the policy\n */\n updatePolicy(newPolicy: Partial<SecurityPolicy>): void {\n this.policy = { ...this.policy, ...newPolicy };\n this.addAuditEntry('POLICY_UPDATED', true, { newPolicy });\n }\n\n /**\n * Get the current policy\n */\n getPolicy(): SecurityPolicy {\n return { ...this.policy };\n }\n\n // ===========================================================================\n // Private Methods\n // ===========================================================================\n\n private refreshSpendingWindow(): void {\n if (!this.policy.spending) return;\n\n const now = Date.now();\n const windowMs = this.policy.spending.windowSeconds * 1000;\n const windowStart = this.spendingState.windowStart || now;\n\n if (now - windowStart >= windowMs) {\n // Reset window\n this.spendingState.currentSpent = '0x0';\n this.spendingState.windowStart = now;\n }\n }\n\n private refreshRateLimitWindow(): void {\n if (!this.policy.rateLimit) return;\n\n const now = Date.now();\n const windowMs = this.policy.rateLimit.windowSeconds * 1000;\n const windowStart = this.rateLimitState.windowStart || now;\n\n if (now - windowStart >= windowMs) {\n // Reset window\n this.rateLimitState.currentCount = 0;\n this.rateLimitState.windowStart = now;\n }\n }\n}\n","/**\n * Invoice Verification Engine\n * Validates invoice legitimacy, format, cryptographic correctness, and peer connectivity\n * This ensures the agent only pays valid invoices\n */\n\nimport type { FiberRpcClient } from '../rpc/client.js';\nimport type { Attribute, CkbInvoice, HexString } from '../types/index.js';\nimport { fromHex, shannonsToCkb } from '../utils.js';\n\n// =============================================================================\n// Types\n// =============================================================================\n\n/**\n * Invoice verification result\n */\nexport interface InvoiceVerificationResult {\n /** Overall validity (true = safe to pay) */\n valid: boolean;\n /** Invoice parsed details */\n details: {\n paymentHash: string;\n amountCkb: number;\n expiresAt: number; // Unix timestamp\n description?: string;\n isExpired: boolean;\n };\n /** Peer information */\n peer: {\n nodeId?: string;\n isConnected: boolean;\n trustScore: number; // 0-100\n };\n /** Validation checks performed */\n checks: {\n validFormat: boolean;\n notExpired: boolean;\n validAmount: boolean;\n peerConnected: boolean;\n };\n /** Issues found */\n issues: VerificationIssue[];\n /** Recommendation for agent */\n recommendation: 'proceed' | 'warn' | 'reject';\n /** Human-readable reason for recommendation */\n reason: string;\n}\n\nexport interface VerificationIssue {\n type: 'warning' | 'critical';\n code: string;\n message: string;\n}\n\n// =============================================================================\n// Invoice Verifier\n// =============================================================================\n\nexport class InvoiceVerifier {\n constructor(private rpc: FiberRpcClient) {}\n\n /**\n * Fully validate an invoice before payment\n */\n async verifyInvoice(invoiceString: string): Promise<InvoiceVerificationResult> {\n const issues: VerificationIssue[] = [];\n const checks = {\n validFormat: false,\n notExpired: false,\n validAmount: false,\n peerConnected: false,\n };\n\n // 1. Validate format\n const formatCheck = this.validateInvoiceFormat(invoiceString);\n checks.validFormat = formatCheck.valid;\n if (!formatCheck.valid) {\n issues.push({\n type: 'critical',\n code: 'INVALID_INVOICE_FORMAT',\n message: formatCheck.error || 'Invoice format is invalid',\n });\n }\n\n let invoice: CkbInvoice | null = null;\n\n // 2. Parse invoice\n if (checks.validFormat) {\n try {\n const result = await this.rpc.parseInvoice({ invoice: invoiceString });\n invoice = result.invoice;\n } catch (error) {\n issues.push({\n type: 'critical',\n code: 'PARSE_INVOICE_FAILED',\n message: `Failed to parse invoice: ${error instanceof Error ? error.message : 'Unknown error'}`,\n });\n }\n }\n\n // Default details if parsing failed\n const details = {\n paymentHash: invoice?.data.payment_hash || 'unknown',\n amountCkb: invoice?.amount ? shannonsToCkb(invoice.amount) : 0,\n expiresAt: this.getExpiryTimestamp(invoice),\n description: this.getDescription(invoice),\n isExpired: invoice ? this.isInvoiceExpired(invoice) : true,\n };\n\n // 3. Validate not expired\n if (invoice) {\n if (!details.isExpired) {\n checks.notExpired = true;\n } else {\n issues.push({\n type: 'critical',\n code: 'INVOICE_EXPIRED',\n message: `Invoice expired at ${new Date(details.expiresAt).toISOString()}`,\n });\n }\n }\n\n // 4. Validate amount\n if (invoice?.amount) {\n const validAmount = this.validateAmount(invoice.amount);\n checks.validAmount = validAmount.valid;\n if (!validAmount.valid) {\n issues.push({\n type: 'critical',\n code: validAmount.code || 'INVALID_AMOUNT',\n message: validAmount.message || 'Amount validation failed',\n });\n }\n }\n\n // 5. Check peer connectivity - verify payee is reachable\n const payeePublicKey = this.extractNodeIdFromInvoice(invoice);\n try {\n const peers = await this.rpc.listPeers();\n if (payeePublicKey) {\n // We have the payee's public key - check if they're connected or reachable\n // Note: peer_id in Fiber is derived from public key, but format may differ\n // For now, we check if we have any path to peers (routing will find the payee)\n if (peers.peers && peers.peers.length > 0) {\n checks.peerConnected = true;\n } else {\n issues.push({\n type: 'warning',\n code: 'NO_PEERS_CONNECTED',\n message: `No peers connected. Cannot route payment to payee ${payeePublicKey.slice(0, 16)}...`,\n });\n }\n } else {\n // No payee public key in invoice - just check basic connectivity\n if (peers.peers && peers.peers.length > 0) {\n checks.peerConnected = true;\n } else {\n issues.push({\n type: 'warning',\n code: 'NO_PEERS_CONNECTED',\n message: 'No peers currently connected. Payment may fail.',\n });\n }\n }\n } catch {\n issues.push({\n type: 'warning',\n code: 'PEER_CHECK_FAILED',\n message: 'Could not verify peer connectivity',\n });\n }\n\n // Determine overall validity and recommendation\n const criticalIssues = issues.filter((i) => i.type === 'critical');\n const valid = criticalIssues.length === 0;\n\n let recommendation: 'proceed' | 'warn' | 'reject';\n let reason: string;\n\n if (!valid) {\n recommendation = 'reject';\n reason = `Invoice has ${criticalIssues.length} critical issue(s): ${criticalIssues.map((i) => i.code).join(', ')}`;\n } else if (issues.length > 0) {\n recommendation = 'warn';\n reason = `Invoice is valid but has warnings: ${issues.map((i) => i.code).join(', ')}`;\n } else {\n recommendation = 'proceed';\n reason = 'Invoice is valid and safe to pay';\n }\n\n return {\n valid,\n details,\n peer: {\n nodeId: payeePublicKey, // Use the already-extracted payee public key\n isConnected:\n checks.peerConnected ||\n issues.filter((i) => i.code === 'NO_PEERS_CONNECTED').length === 0,\n trustScore: this.calculateTrustScore(checks, issues),\n },\n checks: {\n ...checks,\n },\n issues,\n recommendation,\n reason,\n };\n }\n\n /**\n * Quick format validation (regex-based, before RPC call)\n */\n private validateInvoiceFormat(invoice: string): { valid: boolean; error?: string } {\n // Invoice should be bech32-encoded and start with fibt (testnet) or fibb (mainnet)\n const invoiceRegex = /^fib[tb]{1}[a-z0-9]{50,}$/i;\n\n if (!invoiceRegex.test(invoice)) {\n return {\n valid: false,\n error: 'Invoice must be bech32-encoded (fibt... for testnet or fibb... for mainnet)',\n };\n }\n\n return { valid: true };\n }\n\n /**\n * Validate amount is positive and reasonable\n */\n private validateAmount(amountHex: HexString): {\n valid: boolean;\n code?: string;\n message?: string;\n } {\n try {\n const amount = fromHex(amountHex);\n\n if (amount <= 0n) {\n return {\n valid: false,\n code: 'ZERO_AMOUNT',\n message: 'Invoice amount must be greater than zero',\n };\n }\n\n // Sanity check: prevent obviously spoofed invoices\n // Max 1 million CKB (would be ~$XXX at current rates)\n const maxShannons = BigInt(1000000) * BigInt(100000000); // 1M CKB in shannons\n if (amount > maxShannons) {\n const amountCkb = Number(amount) / 1e8;\n return {\n valid: false,\n code: 'AMOUNT_TOO_LARGE',\n message: `Invoice amount (${amountCkb.toFixed(2)} CKB) exceeds reasonable maximum`,\n };\n }\n\n return { valid: true };\n } catch {\n return {\n valid: false,\n code: 'INVALID_AMOUNT_FORMAT',\n message: 'Could not parse invoice amount',\n };\n }\n }\n\n /**\n * Check if invoice has expired\n */\n private isInvoiceExpired(invoice: CkbInvoice): boolean {\n const expiryTimestamp = this.getExpiryTimestamp(invoice);\n return Date.now() > expiryTimestamp;\n }\n\n /**\n * Get expiry timestamp in milliseconds\n */\n private getExpiryTimestamp(invoice: CkbInvoice | null): number {\n if (!invoice) return 0;\n\n // Expiry is a duration in seconds, stored as an attribute (ExpiryTime).\n // Invoice timestamp is in seconds since UNIX epoch.\n try {\n const createdSeconds = fromHex(invoice.data.timestamp as HexString);\n const expiryDeltaSeconds =\n this.getAttributeU64(invoice.data.attrs, 'ExpiryTime') ?? BigInt(60 * 60);\n return Number(createdSeconds + expiryDeltaSeconds) * 1000;\n } catch {\n // Fall through to default\n }\n\n // Default: assume 1 hour from now\n return Date.now() + 60 * 60 * 1000;\n }\n\n private getAttributeU64(\n attrs: Attribute[],\n key: 'ExpiryTime' | 'FinalHtlcTimeout' | 'FinalHtlcMinimumExpiryDelta',\n ): bigint | undefined {\n for (const attr of attrs) {\n if (key in attr) {\n return fromHex((attr as Record<string, HexString>)[key] as HexString);\n }\n }\n return undefined;\n }\n\n private getDescription(invoice: CkbInvoice | null): string | undefined {\n if (!invoice) return undefined;\n for (const attr of invoice.data.attrs) {\n if ('Description' in attr) {\n return attr.Description;\n }\n }\n return undefined;\n }\n\n /**\n * Try to extract payee node public key from invoice attributes\n * The payee public key is embedded in the invoice as a PayeePublicKey attribute\n */\n private extractNodeIdFromInvoice(invoice: CkbInvoice | null): string | undefined {\n if (!invoice) {\n return undefined;\n }\n\n // Search for PayeePublicKey attribute in the invoice data\n for (const attr of invoice.data.attrs) {\n if ('PayeePublicKey' in attr) {\n return attr.PayeePublicKey;\n }\n }\n\n return undefined;\n }\n\n /**\n * Calculate trust score (0-100) based on various factors\n */\n private calculateTrustScore(\n checks: {\n validFormat: boolean;\n notExpired: boolean;\n validAmount: boolean;\n peerConnected: boolean;\n },\n issues: VerificationIssue[],\n ): number {\n let score = 100;\n\n // Deduct for failed checks\n if (!checks.validFormat) score -= 25;\n if (!checks.notExpired) score -= 20;\n if (!checks.validAmount) score -= 15;\n if (!checks.peerConnected) score -= 10;\n\n // Deduct for warnings\n const warnings = issues.filter((i) => i.type === 'warning').length;\n score -= warnings * 5;\n\n return Math.max(0, score);\n }\n}\n"],"mappings":"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","names":["ChannelState","headerError","validateError","macaroon"]}
|