UNPKG

@bigmi/client

Version:

Reactive primitives for Bitcoin apps.

130 lines (129 loc) 5.76 kB
import { createConnector } from "../factories/createConnector.js"; import { debounce } from "../utils/debounce.js"; import { ChainId, MethodNotSupportedRpcError, ProviderNotFoundError, UserRejectedRequestError, base64ToHex, hexToBase64 } from "@bigmi/core"; //#region src/connectors/xverse.ts function xverse(parameters = {}) { const XverseBitcoinChainIdMap = { Mainnet: ChainId.BITCOIN_MAINNET, Testnet: ChainId.BITCOIN_TESTNET, Testnet4: ChainId.BITCOIN_TESTNET4, Signet: ChainId.BITCOIN_SIGNET }; const { shimDisconnect = true } = parameters; let accountChange; let chainChange; 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; if ("XverseProviders" in window) return window.XverseProviders.BitcoinProvider; }, async getProvider() { const internalProvider = await this.getInternalProvider(); if (!internalProvider) return; return { request: this.request.bind(internalProvider) }; }, 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, 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); } if (!chainChange) { chainChange = debounce((event) => this.onChainChanged(XverseBitcoinChainIdMap[event.bitcoin.name]), 300); provider.addListener("networkChange", chainChange); } 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 = void 0; } if (chainChange) { provider.removeListener?.("networkChange", chainChange); chainChange.cancel?.(); chainChange = void 0; } 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; }, async getChainId() { const provider = await this.getInternalProvider(); if (!provider) throw new ProviderNotFoundError(); const network = await provider.request("wallet_getNetwork"); if (!network.result) throw new UserRejectedRequestError(network.error?.message ?? "Unknown error"); return XverseBitcoinChainIdMap[network.result.bitcoin.name]; }, async isAuthorized() { try { return shimDisconnect && Boolean(await config.storage?.getItem(`${this.id}.connected`)); } catch { return false; } }, async onAccountsChanged() { const { accounts } = await this.connect(); config.emitter.emit("change", { accounts }); }, async onChainChanged() { const { accounts, chainId } = await this.connect(); config.emitter.emit("change", { chainId, accounts }); }, async onDisconnect(_error) { config.emitter.emit("disconnect"); } })); } xverse.type = "UTXO"; //#endregion export { xverse }; //# sourceMappingURL=xverse.js.map