UNPKG

@bigmi/client

Version:

Reactive primitives for Bitcoin apps.

148 lines 6.87 kB
import { MethodNotSupportedRpcError, ProviderNotFoundError, UserRejectedRequestError, base64ToHex, hexToBase64, } from '@bigmi/core'; import { createConnector } from '../factories/createConnector.js'; xverse.type = 'UTXO'; export function xverse(parameters = {}) { const { chainId, shimDisconnect = true } = parameters; let accountChange; return createConnector((config) => ({ id: 'XverseProviders.BitcoinProvider', name: 'Xverse Wallet', type: xverse.type, icon: 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI2MDAiIGhlaWdodD0iNjAwIj48ZyBmaWxsPSJub25lIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiPjxwYXRoIGZpbGw9IiMxNzE3MTciIGQ9Ik0wIDBoNjAwdjYwMEgweiIvPjxwYXRoIGZpbGw9IiNGRkYiIGZpbGwtcnVsZT0ibm9uemVybyIgZD0iTTQ0MCA0MzUuNHYtNTFjMC0yLS44LTMuOS0yLjItNS4zTDIyMCAxNjIuMmE3LjYgNy42IDAgMCAwLTUuNC0yLjJoLTUxLjFjLTIuNSAwLTQuNiAyLTQuNiA0LjZ2NDcuM2MwIDIgLjggNCAyLjIgNS40bDc4LjIgNzcuOGE0LjYgNC42IDAgMCAxIDAgNi41bC03OSA3OC43Yy0xIC45LTEuNCAyLTEuNCAzLjJ2NTJjMCAyLjQgMiA0LjUgNC42IDQuNUgyNDljMi42IDAgNC42LTIgNC42LTQuNlY0MDVjMC0xLjIuNS0yLjQgMS40LTMuM2w0Mi40LTQyLjJhNC42IDQuNiAwIDAgMSA2LjQgMGw3OC43IDc4LjRhNy42IDcuNiAwIDAgMCA1LjQgMi4yaDQ3LjVjMi41IDAgNC42LTIgNC42LTQuNloiLz48cGF0aCBmaWxsPSIjRUU3QTMwIiBmaWxsLXJ1bGU9Im5vbnplcm8iIGQ9Ik0zMjUuNiAyMjcuMmg0Mi44YzIuNiAwIDQuNiAyLjEgNC42IDQuNnY0Mi42YzAgNCA1IDYuMSA4IDMuMmw1OC43LTU4LjVjLjgtLjggMS4zLTIgMS4zLTMuMnYtNTEuMmMwLTIuNi0yLTQuNi00LjYtNC42TDM4NCAxNjBjLTEuMiAwLTIuNC41LTMuMyAxLjNsLTU4LjQgNTguMWE0LjYgNC42IDAgMCAwIDMuMiA3LjhaIi8+PC9nPjwvc3ZnPg==', async setup() { // }, async getInternalProvider() { if (typeof window === 'undefined') { return undefined; } if ('XverseProviders' in window) { const anyWindow = window; const provider = anyWindow.XverseProviders.BitcoinProvider; return provider; } }, async getProvider() { const internalProvider = await this.getInternalProvider(); if (!internalProvider) { return; } const provider = { request: this.request.bind(internalProvider), }; return provider; }, async request({ method, params }) { switch (method) { case 'signPsbt': { const { psbt, ...options } = params; const psbtBase64 = hexToBase64(psbt); const signInputs = options.inputsToSign.reduce((signInputs, input) => { if (!signInputs[input.address]) { signInputs[input.address] = []; } signInputs[input.address].push(...input.signingIndexes); return signInputs; }, {}); const signedPsbt = await this.request('signPsbt', { psbt: psbtBase64, allowedSignHash: 1, // Default to Transaction.SIGHASH_ALL - 1 signInputs: signInputs, broadcast: options.finalize, }); if (signedPsbt?.error) { throw signedPsbt?.error; } return base64ToHex(signedPsbt?.result?.psbt); } default: throw new MethodNotSupportedRpcError(method); } }, async connect({ isReconnecting } = {}) { const provider = await this.getInternalProvider(); if (!provider) { throw new ProviderNotFoundError(); } if (!isReconnecting) { const connected = await provider.request('wallet_requestPermissions'); if (connected.error) { throw new UserRejectedRequestError(connected.error.message); } } const accounts = await this.getAccounts(); const chainId = await this.getChainId(); if (!accountChange) { accountChange = this.onAccountsChanged.bind(this); provider.addListener('accountChange', accountChange); } // Remove disconnected shim if it exists if (shimDisconnect) { await Promise.all([ config.storage?.setItem(`${this.id}.connected`, true), config.storage?.removeItem(`${this.id}.disconnected`), ]); } return { accounts, chainId }; }, async disconnect() { const provider = await this.getInternalProvider(); if (!provider) { throw new ProviderNotFoundError(); } if (accountChange) { provider.removeListener?.('accountChange', accountChange); accountChange = undefined; } // await provider.request('wallet_renouncePermissions').catch(); // Add shim signalling connector is disconnected if (shimDisconnect) { await Promise.all([ config.storage?.setItem(`${this.id}.disconnected`, true), config.storage?.removeItem(`${this.id}.connected`), ]); } }, async getAccounts() { const provider = await this.getInternalProvider(); if (!provider) { throw new ProviderNotFoundError(); } const accounts = await provider.request('getAddresses', { purposes: ['payment'], }); if (!accounts.result) { throw new UserRejectedRequestError(accounts.error?.message); } return accounts.result.addresses.map((account) => account.address); }, async getChainId() { return chainId; }, async isAuthorized() { try { const isConnected = shimDisconnect && // If shim exists in storage, connector is disconnected Boolean(await config.storage?.getItem(`${this.id}.connected`)); return isConnected; } catch { return false; } }, async onAccountsChanged() { const { accounts } = await this.connect(); config.emitter.emit('change', { accounts, }); }, onChainChanged(chain) { const chainId = Number(chain); config.emitter.emit('change', { chainId }); }, async onDisconnect(_error) { config.emitter.emit('disconnect'); }, })); } //# sourceMappingURL=xverse.js.map