UNPKG

@snowballmoney/chain-agnostic-utils

Version:

Chain agnostic utilities for cross-chain applications

165 lines (145 loc) 4.56 kB
import { NAMESPACES } from "./constants/namespaces"; import { NETWORK_METADATA } from "./constants/metadata"; import { NETWORKS } from "./constants/networks"; import { CAIP2, NetworkMetadata } from "./types"; export interface CAIP2ManagerOptions { networks?: Record<string, NetworkMetadata>; defaultNetworks?: boolean; // if false, only custom networks will be used } export class CAIP2Manager { private static instance: CAIP2Manager | null = null; private networks: Map<string, NetworkMetadata>; private initialized: boolean = false; private constructor() { this.networks = new Map(); } public static getInstance(): CAIP2Manager { if (!CAIP2Manager.instance) { CAIP2Manager.instance = new CAIP2Manager(); } return CAIP2Manager.instance; } /** * Initialize the manager with options * This should be called before using the manager */ public init(options: CAIP2ManagerOptions = {}): void { if (this.initialized) { throw new Error('CAIP2Manager is already initialized'); } // Load default networks if not explicitly disabled if (options.defaultNetworks !== false) { Object.entries(NETWORK_METADATA).forEach(([key, value]) => { this.networks.set(key, value); }); } // Add custom networks if (options.networks) { Object.entries(options.networks).forEach(([key, value]) => { if (this.isValid(key)) { this.networks.set(key, value); } else { console.warn(`Invalid CAIP-2 identifier skipped: ${key}`); } }); } this.initialized = true; } /** * Get built-in networks object */ public static get NETWORKS() { return NETWORKS; } /** * Get built-in namespaces */ public static get NAMESPACES() { return NAMESPACES; } /** * Parse CAIP2 identifier into namespace and reference */ public parse(chainId: string): CAIP2 { const [namespace, reference] = chainId.split(':'); if (!namespace || !reference) { throw new Error('Invalid CAIP-2 identifier'); } return { namespace, reference }; } /** * Format namespace and reference into CAIP2 identifier */ public format(namespace: string, reference: string): string { return `${namespace}:${reference}`; } /** * Validate CAIP2 identifier */ public isValid(chainId: string): boolean { try { const { namespace } = this.parse(chainId); return Object.values(NAMESPACES).includes(namespace as any); } catch { return false; } } /** * Get network metadata */ public getNetwork(caip2Id: string): NetworkMetadata { this.checkInitialized(); const metadata = this.networks.get(caip2Id); if (!metadata) { throw new Error(`No metadata found for network: ${caip2Id}`); } return metadata; } /** * Add or update network */ public addNetwork(caip2Id: string, metadata: NetworkMetadata, merge = true): void { this.checkInitialized(); if (!this.isValid(caip2Id)) { throw new Error(`Invalid CAIP-2 identifier: ${caip2Id}`); } let metadataToSet = metadata if (merge && this.networks.has(caip2Id)) { metadataToSet = { ...this.networks.get(caip2Id), ...metadata } } this.networks.set(caip2Id, metadataToSet); } /** * Remove custom network */ public removeNetwork(caip2Id: string): boolean { this.checkInitialized(); return this.networks.delete(caip2Id); } /** * Get all registered networks */ public getAllNetworks(): Map<string, NetworkMetadata> { this.checkInitialized(); return new Map(this.networks); } /** * Check if network exists */ public hasNetwork(caip2Id: string): boolean { this.checkInitialized(); return this.networks.has(caip2Id); } /** * Reset to initial state */ public reset(): void { this.networks.clear(); this.initialized = false; } private checkInitialized(): void { if (!this.initialized) { throw new Error('CAIP2Manager is not initialized. Call init() first.'); } } }