import localforage from 'localforage'; import { WalletNotConnectedError, WalletNotReadyError, WalletReadyState } from '@solana/wallet-adapter-base'; export const SolanaWalletHandler = class { constructor() { this.name = null; this.publicKey = null; this.isConnected = false; this.isConnecting = false; this.isDisconnecting = false; this.ready = 'Unsupported'; this.localStorageKey = 'walletAdapter' this.adapter = null; this.wallets = []; this.signTransaction = undefined; this.signAllTransactions = undefined; this.signMessage = undefined; /** @type {LocalForage} */ this.store = localforage.createInstance({ name: "tp-solana-connect" }); } async connect() { if (this.isConnected || this.isConnecting || this.isDisconnecting) return; if (!adapter) throw new WalletNotReadyError(); if (!(this.ready === WalletReadyState.Installed || this.ready === WalletReadyState.Loadable)) { this.resetWallet(); if (typeof window !== 'undefined') { window.open(adapter.url, '_blank'); } throw new WalletNotReadyError(); } try { this.isConnecting = true; await adapter.connect(); } catch (error) { walletStore.resetWallet(); throw error; } finally { this.isConnecting = false; } } async autoConnect() { try { this.isConnecting = true; await this.adapter.connect(); } catch (error) { this.resetWallet(); } finally { this.isConnecting = false; } } async disconnect() { if (this.disconnecting) return; if (!this.adapter) return this.resetWallet(); try { this.isDisconnecting = true; await this.adapter.disconnect(); } finally { this.resetWallet(); this.isDisconnecting = false; } } updateAdapter(adapter) { removeAdapterEventListeners(); if (adapter) { this.addAdapterEventListeners(adapter); this.adapter = adapter; } } resetWallet() { this.isConnected = false; this.isConnecting = false; this.isDisconnecting = false; this.ready = 'Unsupported'; this.adapter = null; this.store.setItem('wallet', null); } addAdapterEventListeners(adapter) { this.wallets.forEach(({ adapter }) => { adapter.on('readyStateChange', this.onReadyStateChange, adapter); }); adapter.on('connect', onConnect); adapter.on('disconnect', onDisconnect); adapter.on('error', onError); } removeAdapterEventListeners() { if (!this.adapter) return; this.wallets.forEach(({ adapter }) => { adapter.off('readyStateChange', this.onReadyStateChange, adapter); }); this.adapter.off('connect', onConnect); this.adapter.off('disconnect', onDisconnect); this.adapter.off('error', onError); } onReadyStateChange(readyState) { if (!this.adapter) return; this.ready = adapter.readyState; // When the wallets change, start to listen for changes to their `readyState` const walletIndex = this.wallets.findIndex(({ adapter }) => adapter.name === this.name); if (walletIndex === -1) { return; } this.wallets = [ ...this.wallets.slice(0, walletIndex), { ...this.wallets[walletIndex], readyState }, ...this.wallets.slice(walletIndex + 1), ]; } async select(walletName) { if (this.name === walletName) return; if (this.adapter) { await disconnect(); } walletStore.updateWallet(walletName); } updateWalletName(name) { var _a; const adapter = (_a = this.walletsByName === null || this.walletsByName === undefined ? undefined : walletsByName[name]) !== null && _a !== void 0 ? _a : null; this.store.setItem(this.localStorageKey, name); updateWalletState(adapter); } updateWalletState(adapter) { this.updateAdapter(adapter); this.name = adapter?.name || null; this.ready = adapter?.readyState || 'Unsupported'; this.publicKey = adapter?.publicKey || null; this.connected = adapter?.connected || false; } onConnect() { if (!this.adapter) return; walletStore.updateFeatures(adapter); walletStore.updateStatus({ publicKey: adapter.publicKey, connected: adapter.connected, }); } updateFeatures() { if (!this.adapter) return; this.signTransaction = undefined; this.signAllTransactions = undefined; this.signMessage = undefined; // Sign a transaction if the wallet supports it if ('signTransaction' in this.adapter) { this.signTransaction = async function (transaction) { if (!this.connected) throw new WalletNotConnectedError(); return await this.adapter.signTransaction(transaction); }; } // Sign multiple transactions if the wallet supports it if ('signAllTransactions' in this.adapter) { this.signAllTransactions = async function (transactions) { if (!this.connected) throw newError(new WalletNotConnectedError()); return await this.adapter.signAllTransactions(transactions); }; } // Sign an arbitrary message if the wallet supports it if ('signMessage' in this.adapter) { this.signMessage = async function (message) { if (!this.connected) throw newError(new WalletNotConnectedError()); return await this.adapter.signMessage(message); }; } } removeAdapterEventListeners() { if (!this.adapter) return; this.wallets.forEach(({ adapter }) => { adapter.off('readyStateChange', this.onReadyStateChange, adapter); }); this.adapter.off('connect', this.onConnect); this.adapter.off('disconnect', this.onDisconnect); this.adapter.off('error', this.onError); } shouldAutoConnect() { const { adapter, ready, connected, connecting } = this; const _autoConnect = (adapter && typeof autoConnect === 'function') ? this.autoConnect(adapter) : autoConnect; return !(!_autoConnect || !adapter || !(ready === WalletReadyState.Installed || ready === WalletReadyState.Loadable) || connected || connecting); } } export const walletMixin = function(superClass) { return class extends superClass { constructor() { super(); if (this.walletStore === undefined) { this.walletStore = new SolanaWalletHandler(); } } } }