UNPKG

@gorbchain-xyz/chaindecode

Version:

GorbchainSDK V1.3+ - Complete Solana development toolkit with advanced cryptography, messaging, and collaboration features. Build secure applications with blockchain, DeFi, and end-to-end encryption.

606 lines (605 loc) 25.7 kB
/** * Wallet Integration Utilities - Universal wallet connection and management * * This module provides comprehensive wallet integration for: * - Solana web3 providers (Phantom, Solflare, etc.) * - Deep link wallet providers * - Custom injected scripts * - WalletConnect protocol * - Hardware wallets */ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; /** * Universal wallet manager for comprehensive wallet integration * * @example * ```typescript * const sdk = new GorbchainSDK({ rpcEndpoint: 'https://rpc.gorbchain.xyz' }); * const walletManager = new UniversalWalletManager(sdk); * * // Discover available wallets * const discovery = await walletManager.discoverWallets(); * console.log(`Found ${discovery.available.length} wallets`); * * // Connect to a specific wallet * const wallet = await walletManager.connectWallet('phantom'); * console.log(`Connected to ${wallet.name}: ${wallet.address}`); * console.log(`Portfolio value: $${wallet.portfolio.totalValueUsd}`); * * // Auto-connect to best available wallet * const autoWallet = await walletManager.autoConnect({ * preferredWallets: ['phantom', 'solflare'], * includePortfolio: true * }); * ``` */ export class UniversalWalletManager { constructor(sdk) { this.connectedWallet = null; this.providers = new Map(); this.eventListeners = new Map(); // Cache for localStorage operations to avoid repeated parsing this.connectionCache = null; this.STORAGE_KEY = 'gorbchain_wallet_connections'; this.sdk = sdk; this.initializeProviders(); } /** * Discover all available wallets on the device/browser * * @param options - Discovery options * @returns Promise resolving to wallet discovery results */ discoverWallets() { return __awaiter(this, arguments, void 0, function* (options = {}) { const { includeDeepLinks = true, includeMobile = true, includeHardware = true } = options; const available = []; const recommended = []; const previouslyConnected = []; // Check for browser extension wallets const browserWallets = [ { type: 'trashpack', name: 'TrashPack', key: 'trashpack', icon: 'https://trashpack.tech/icon.png', downloadUrl: 'https://trashpack.tech/' }, { type: 'phantom', name: 'Phantom', key: 'phantom', icon: 'https://phantom.app/img/logo.png', downloadUrl: 'https://phantom.app/' }, { type: 'solflare', name: 'Solflare', key: 'solflare', icon: 'https://solflare.com/assets/logo.svg', downloadUrl: 'https://solflare.com/' }, { type: 'backpack', name: 'Backpack', key: 'backpack', downloadUrl: 'https://backpack.app/' }, { type: 'glow', name: 'Glow', key: 'glow', downloadUrl: 'https://glow.app/' }, { type: 'slope', name: 'Slope', key: 'slope', downloadUrl: 'https://slope.finance/' }, { type: 'sollet', name: 'Sollet', key: 'sollet', downloadUrl: 'https://www.sollet.io/' } ]; for (const wallet of browserWallets) { const isInstalled = yield this.checkWalletInstalled(wallet.type); available.push({ type: wallet.type, name: wallet.name, icon: wallet.icon, installed: isInstalled, downloadUrl: wallet.downloadUrl }); if (isInstalled) { recommended.push(wallet.type); } // Check if previously connected if (this.wasWalletPreviouslyConnected(wallet.type)) { previouslyConnected.push(wallet.type); } } // Add WalletConnect for mobile support if (includeMobile) { available.push({ type: 'walletconnect', name: 'WalletConnect', installed: true, // Always available deepLink: 'wc:' }); } // Add hardware wallet support if (includeHardware) { available.push({ type: 'ledger', name: 'Ledger', installed: yield this.checkLedgerSupport() }); } return { available, recommended, previouslyConnected }; }); } /** * Connect to a specific wallet and get rich wallet information * * @param walletType - Type of wallet to connect to * @param options - Connection options * @returns Promise resolving to rich wallet information */ connectWallet(walletType_1) { return __awaiter(this, arguments, void 0, function* (walletType, options = {}) { const { includePortfolio = true, rememberConnection = true, connectionParams = {} } = options; try { // Get wallet provider const provider = yield this.getWalletProvider(walletType, connectionParams); if (!provider) { throw new Error(`Wallet provider not available: ${walletType}`); } // Connect to wallet yield provider.connect(); if (!provider.publicKey) { throw new Error('Failed to get wallet public key'); } // Create rich wallet object const richWallet = { address: provider.publicKey, type: walletType, name: this.getWalletName(walletType), status: 'connected', provider, portfolio: { solBalance: 0, solBalanceFormatted: '0 SOL', totalTokens: 0, totalNFTs: 0, recentTransactions: 0, topTokens: [] }, metadata: { icon: this.getWalletIcon(walletType), website: this.getWalletWebsite(walletType), features: provider.features || [], lastConnected: Date.now(), connectionCount: this.getConnectionCount(walletType) + 1 }, network: { current: 'gorbchain', supported: ['gorbchain', 'solana-mainnet', 'solana-devnet'], customRPC: [this.sdk.config.rpcEndpoint] } }; // Load portfolio if requested if (includePortfolio) { richWallet.portfolio = yield this.loadWalletPortfolio(provider.publicKey); } // Remember connection if requested if (rememberConnection) { this.rememberWalletConnection(walletType); } // Store connected wallet this.connectedWallet = richWallet; this.providers.set(walletType, provider); // Emit connection event this.emit('wallet:connected', richWallet); return richWallet; } catch (error) { const errorMessage = error instanceof Error ? error.message : 'Unknown error'; // Emit error event this.emit('wallet:error', { type: walletType, error: errorMessage }); throw new Error(`Failed to connect to ${walletType}: ${errorMessage}`); } }); } /** * Auto-connect to the best available wallet * * @param options - Auto-connection options * @returns Promise resolving to connected wallet or null */ autoConnect() { return __awaiter(this, arguments, void 0, function* (options = {}) { const { preferredWallets = ['trashpack', 'phantom', 'solflare', 'backpack'], includePortfolio = true, onlyPrevious = false } = options; try { const discovery = yield this.discoverWallets(); // Build priority list let priorityList = []; if (onlyPrevious) { priorityList = discovery.previouslyConnected; } else { // Start with preferred wallets that are available priorityList = preferredWallets.filter(type => discovery.available.some(w => w.type === type && w.installed)); // Add other recommended wallets const otherRecommended = discovery.recommended.filter(type => !preferredWallets.includes(type)); priorityList.push(...otherRecommended); } // Try to connect to wallets in priority order for (const walletType of priorityList) { try { const wallet = yield this.connectWallet(walletType, { includePortfolio, rememberConnection: true }); return wallet; } catch (error) { console.warn(`Failed to auto-connect to ${walletType}:`, error); continue; } } return null; } catch (error) { console.error('Auto-connect failed:', error); return null; } }); } /** * Disconnect from current wallet */ disconnect() { return __awaiter(this, void 0, void 0, function* () { var _a; if (!this.connectedWallet) { return; } try { if ((_a = this.connectedWallet.provider) === null || _a === void 0 ? void 0 : _a.disconnect) { yield this.connectedWallet.provider.disconnect(); } const disconnectedWallet = this.connectedWallet; this.connectedWallet = null; // Emit disconnection event this.emit('wallet:disconnected', disconnectedWallet); } catch (error) { console.error('Failed to disconnect wallet:', error); } }); } /** * Get current connected wallet */ getConnectedWallet() { return this.connectedWallet; } /** * Sign transaction with connected wallet */ signTransaction(transaction) { return __awaiter(this, void 0, void 0, function* () { var _a; if (!((_a = this.connectedWallet) === null || _a === void 0 ? void 0 : _a.provider)) { throw new Error('No wallet connected'); } return this.connectedWallet.provider.signTransaction(transaction); }); } /** * Sign message with connected wallet */ signMessage(message) { return __awaiter(this, void 0, void 0, function* () { var _a; if (!((_a = this.connectedWallet) === null || _a === void 0 ? void 0 : _a.provider)) { throw new Error('No wallet connected'); } const messageBytes = typeof message === 'string' ? new TextEncoder().encode(message) : message; return this.connectedWallet.provider.signMessage(messageBytes); }); } /** * Add event listener */ on(event, listener) { if (!this.eventListeners.has(event)) { this.eventListeners.set(event, []); } this.eventListeners.get(event).push(listener); } /** * Remove event listener */ off(event, listener) { const listeners = this.eventListeners.get(event); if (listeners) { const index = listeners.indexOf(listener); if (index > -1) { listeners.splice(index, 1); } } } // Private methods initializeProviders() { return __awaiter(this, void 0, void 0, function* () { // Initialize wallet providers // This would be expanded to include actual wallet provider initialization }); } checkWalletInstalled(walletType) { return __awaiter(this, void 0, void 0, function* () { var _a, _b, _c, _d, _e, _f, _g; if (typeof window === 'undefined') return false; // Optimized wallet detection with standardized checks const globalWindow = window; switch (walletType) { case 'trashpack': return !!((_a = globalWindow.trashpack) === null || _a === void 0 ? void 0 : _a.isTrashPack); case 'phantom': return !!((_c = (_b = globalWindow.phantom) === null || _b === void 0 ? void 0 : _b.solana) === null || _c === void 0 ? void 0 : _c.isPhantom); case 'solflare': return !!((_d = globalWindow.solflare) === null || _d === void 0 ? void 0 : _d.isSolflare); case 'backpack': return !!((_e = globalWindow.backpack) === null || _e === void 0 ? void 0 : _e.isBackpack); case 'glow': return !!((_f = globalWindow.glow) === null || _f === void 0 ? void 0 : _f.isGlow); case 'slope': return !!((_g = globalWindow.slope) === null || _g === void 0 ? void 0 : _g.isSlope); case 'sollet': return !!(globalWindow.sollet); case 'walletconnect': return true; // Always available as a protocol case 'ledger': return yield this.checkLedgerSupport(); case 'custom': case 'injected': return false; default: return false; } }); } checkLedgerSupport() { return __awaiter(this, void 0, void 0, function* () { // Check for WebUSB/WebHID support return !!(navigator === null || navigator === void 0 ? void 0 : navigator.usb) || !!(navigator === null || navigator === void 0 ? void 0 : navigator.hid); }); } wasWalletPreviouslyConnected(walletType) { const connections = this.getCachedConnections(); return connections.has(walletType); } rememberWalletConnection(walletType) { if (typeof localStorage === 'undefined') return; const connections = this.getCachedConnections(); if (!connections.has(walletType)) { connections.add(walletType); this.saveConnections(connections); } } getCachedConnections() { if (this.connectionCache === null) { this.connectionCache = this.loadConnectionsFromStorage(); } return this.connectionCache; } loadConnectionsFromStorage() { if (typeof localStorage === 'undefined') return new Set(); try { const stored = localStorage.getItem(this.STORAGE_KEY); if (!stored) return new Set(); const parsed = JSON.parse(stored); return new Set(Array.isArray(parsed) ? parsed : []); } catch (_a) { return new Set(); } } saveConnections(connections) { if (typeof localStorage === 'undefined') return; try { const array = Array.from(connections); localStorage.setItem(this.STORAGE_KEY, JSON.stringify(array)); this.connectionCache = connections; // Update cache } catch (_a) { // Silently fail if localStorage is not available } } getPreviousConnections() { return Array.from(this.getCachedConnections()); } getConnectionCount(walletType) { if (typeof localStorage === 'undefined') return 0; const key = `gorbchain_wallet_count_${walletType}`; const count = localStorage.getItem(key); return count ? parseInt(count, 10) : 0; } getWalletProvider(walletType, params) { return __awaiter(this, void 0, void 0, function* () { var _a, _b; if (typeof window === 'undefined') return null; try { // Get the actual wallet provider based on type let provider = null; const globalWindow = window; switch (walletType) { case 'trashpack': provider = globalWindow.trashpack; break; case 'phantom': provider = (_a = globalWindow.phantom) === null || _a === void 0 ? void 0 : _a.solana; break; case 'solflare': provider = globalWindow.solflare; break; case 'backpack': provider = globalWindow.backpack; break; case 'glow': provider = globalWindow.glow; break; case 'slope': provider = globalWindow.slope; break; case 'sollet': provider = globalWindow.sollet; break; default: return null; } if (!provider) return null; // Create standardized wallet provider interface return { isConnected: provider.isConnected || false, publicKey: ((_b = provider.publicKey) === null || _b === void 0 ? void 0 : _b.toString()) || null, signTransaction: (tx) => __awaiter(this, void 0, void 0, function* () { if (!provider.signTransaction) { throw new Error(`${walletType} does not support transaction signing`); } return yield provider.signTransaction(tx); }), signMessage: (msg) => __awaiter(this, void 0, void 0, function* () { if (!provider.signMessage) { throw new Error(`${walletType} does not support message signing`); } return yield provider.signMessage(msg); }), connect: () => __awaiter(this, void 0, void 0, function* () { if (!provider.connect) { throw new Error(`${walletType} does not support connection`); } const response = yield provider.connect(); return response; }), disconnect: () => __awaiter(this, void 0, void 0, function* () { if (provider.disconnect) { yield provider.disconnect(); } }), features: provider.features || this.getWalletFeatures(walletType) }; } catch (error) { console.warn(`Failed to get wallet provider for ${walletType}:`, error); return null; } }); } getWalletFeatures(walletType) { const features = { trashpack: ['signTransaction', 'signMessage', 'signAllTransactions', 'signAndSendTransaction', 'connect', 'disconnect'], phantom: ['signTransaction', 'signMessage', 'connect', 'disconnect'], solflare: ['signTransaction', 'signMessage', 'connect', 'disconnect'], backpack: ['signTransaction', 'signMessage', 'connect', 'disconnect'], glow: ['signTransaction', 'signMessage', 'connect', 'disconnect'], slope: ['signTransaction', 'signMessage', 'connect', 'disconnect'], sollet: ['signTransaction', 'connect', 'disconnect'], walletconnect: ['signTransaction', 'signMessage', 'connect', 'disconnect'], ledger: ['signTransaction', 'connect', 'disconnect'], custom: [], injected: [] }; return features[walletType] || []; } loadWalletPortfolio(address) { return __awaiter(this, void 0, void 0, function* () { try { // Get SOL balance const accountInfo = yield this.sdk.rpc.getAccountInfo(address); const solBalance = (accountInfo === null || accountInfo === void 0 ? void 0 : accountInfo.lamports) || 0; // Get token holdings const holdings = yield this.sdk.getAllTokenHoldings(address); // Get recent transactions count const signatures = yield this.sdk.rpc.request('getSignaturesForAddress', [address, { limit: 50 }]); return { solBalance: solBalance / 1e9, solBalanceFormatted: `${(solBalance / 1e9).toFixed(4)} SOL`, totalTokens: holdings.holdings.filter(h => !h.isNFT).length, totalNFTs: holdings.holdings.filter(h => h.isNFT).length, recentTransactions: Array.isArray(signatures) ? signatures.length : 0, topTokens: holdings.holdings .filter(h => !h.isNFT) .slice(0, 5) .map(h => { var _a, _b, _c; return ({ symbol: ((_a = h.metadata) === null || _a === void 0 ? void 0 : _a.symbol) || 'UNKNOWN', balance: ((_b = h.balance) === null || _b === void 0 ? void 0 : _b.formatted) || ((_c = h.balance) === null || _c === void 0 ? void 0 : _c.toString()) || '0' }); }) }; } catch (error) { console.warn('Failed to load wallet portfolio:', error); return { solBalance: 0, solBalanceFormatted: '0 SOL', totalTokens: 0, totalNFTs: 0, recentTransactions: 0, topTokens: [] }; } }); } getWalletName(walletType) { const names = { trashpack: 'TrashPack', phantom: 'Phantom', solflare: 'Solflare', backpack: 'Backpack', glow: 'Glow', slope: 'Slope', sollet: 'Sollet', walletconnect: 'WalletConnect', ledger: 'Ledger', custom: 'Custom Wallet', injected: 'Injected Wallet' }; return names[walletType] || walletType; } getWalletIcon(walletType) { const icons = { trashpack: '/trashpack.png', // As defined in injected.js phantom: 'https://phantom.app/img/logo.png', solflare: 'https://solflare.com/assets/logo.svg', backpack: 'https://backpack.app/icon.png', glow: 'https://glow.app/icon.png', slope: 'https://slope.finance/icon.png', sollet: 'https://www.sollet.io/icon.png', walletconnect: 'https://walletconnect.org/walletconnect-logo.svg', ledger: 'https://ledger.com/icon.png', custom: undefined, injected: undefined }; return icons[walletType]; } getWalletWebsite(walletType) { const websites = { trashpack: 'https://trashpack.tech', phantom: 'https://phantom.app/', solflare: 'https://solflare.com/', backpack: 'https://backpack.app/', glow: 'https://glow.app/', slope: 'https://slope.finance/', sollet: 'https://www.sollet.io/', walletconnect: 'https://walletconnect.org/', ledger: 'https://ledger.com/', custom: undefined, injected: undefined }; return websites[walletType]; } emit(event, data) { const listeners = this.eventListeners.get(event); if (listeners) { listeners.forEach(listener => { try { listener(data); } catch (error) { console.error('Error in event listener:', error); } }); } } }