@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
JavaScript
/**
* 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);
}
});
}
}
}