otx-btc-wallet-connectors 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +554 -0
- package/dist/base-IAFq7sd8.d.mts +53 -0
- package/dist/base-IAFq7sd8.d.ts +53 -0
- package/dist/binance/index.d.mts +81 -0
- package/dist/binance/index.d.ts +81 -0
- package/dist/binance/index.js +13 -0
- package/dist/binance/index.js.map +1 -0
- package/dist/binance/index.mjs +4 -0
- package/dist/binance/index.mjs.map +1 -0
- package/dist/bitget/index.d.mts +84 -0
- package/dist/bitget/index.d.ts +84 -0
- package/dist/bitget/index.js +13 -0
- package/dist/bitget/index.js.map +1 -0
- package/dist/bitget/index.mjs +4 -0
- package/dist/bitget/index.mjs.map +1 -0
- package/dist/chunk-5Z5Q2Y75.mjs +91 -0
- package/dist/chunk-5Z5Q2Y75.mjs.map +1 -0
- package/dist/chunk-7KK2LZLZ.mjs +208 -0
- package/dist/chunk-7KK2LZLZ.mjs.map +1 -0
- package/dist/chunk-AW2JZIHR.mjs +753 -0
- package/dist/chunk-AW2JZIHR.mjs.map +1 -0
- package/dist/chunk-EIJOSZXZ.js +331 -0
- package/dist/chunk-EIJOSZXZ.js.map +1 -0
- package/dist/chunk-EQHR7P7G.js +541 -0
- package/dist/chunk-EQHR7P7G.js.map +1 -0
- package/dist/chunk-EWRXLZO4.mjs +539 -0
- package/dist/chunk-EWRXLZO4.mjs.map +1 -0
- package/dist/chunk-FISNQZZ7.js +802 -0
- package/dist/chunk-FISNQZZ7.js.map +1 -0
- package/dist/chunk-HL4WDMGS.js +200 -0
- package/dist/chunk-HL4WDMGS.js.map +1 -0
- package/dist/chunk-IPYWR76I.js +314 -0
- package/dist/chunk-IPYWR76I.js.map +1 -0
- package/dist/chunk-JYYNWR5G.js +142 -0
- package/dist/chunk-JYYNWR5G.js.map +1 -0
- package/dist/chunk-LNKTYZJM.js +701 -0
- package/dist/chunk-LNKTYZJM.js.map +1 -0
- package/dist/chunk-LVZMONQL.mjs +699 -0
- package/dist/chunk-LVZMONQL.mjs.map +1 -0
- package/dist/chunk-MFXLQWOE.js +93 -0
- package/dist/chunk-MFXLQWOE.js.map +1 -0
- package/dist/chunk-NBIA4TTE.mjs +204 -0
- package/dist/chunk-NBIA4TTE.mjs.map +1 -0
- package/dist/chunk-O4DD2XJ2.js +206 -0
- package/dist/chunk-O4DD2XJ2.js.map +1 -0
- package/dist/chunk-P7HVBU2B.mjs +140 -0
- package/dist/chunk-P7HVBU2B.mjs.map +1 -0
- package/dist/chunk-Q7QVQYEB.js +210 -0
- package/dist/chunk-Q7QVQYEB.js.map +1 -0
- package/dist/chunk-RLZEG6KL.mjs +329 -0
- package/dist/chunk-RLZEG6KL.mjs.map +1 -0
- package/dist/chunk-SYLDBJ75.mjs +246 -0
- package/dist/chunk-SYLDBJ75.mjs.map +1 -0
- package/dist/chunk-TTEUU3CI.mjs +198 -0
- package/dist/chunk-TTEUU3CI.mjs.map +1 -0
- package/dist/chunk-V66BXDTR.mjs +292 -0
- package/dist/chunk-V66BXDTR.mjs.map +1 -0
- package/dist/chunk-X77ZT4OI.js +268 -0
- package/dist/chunk-X77ZT4OI.js.map +1 -0
- package/dist/imtoken/index.d.mts +116 -0
- package/dist/imtoken/index.d.ts +116 -0
- package/dist/imtoken/index.js +14 -0
- package/dist/imtoken/index.js.map +1 -0
- package/dist/imtoken/index.mjs +5 -0
- package/dist/imtoken/index.mjs.map +1 -0
- package/dist/index.d.mts +14 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.js +170 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +13 -0
- package/dist/index.mjs.map +1 -0
- package/dist/ledger/index.d.mts +290 -0
- package/dist/ledger/index.d.ts +290 -0
- package/dist/ledger/index.js +14 -0
- package/dist/ledger/index.js.map +1 -0
- package/dist/ledger/index.mjs +5 -0
- package/dist/ledger/index.mjs.map +1 -0
- package/dist/okx/index.d.mts +88 -0
- package/dist/okx/index.d.ts +88 -0
- package/dist/okx/index.js +13 -0
- package/dist/okx/index.js.map +1 -0
- package/dist/okx/index.mjs +4 -0
- package/dist/okx/index.mjs.map +1 -0
- package/dist/phantom/index.d.mts +96 -0
- package/dist/phantom/index.d.ts +96 -0
- package/dist/phantom/index.js +14 -0
- package/dist/phantom/index.js.map +1 -0
- package/dist/phantom/index.mjs +5 -0
- package/dist/phantom/index.mjs.map +1 -0
- package/dist/psbt-builder-CFOs69Z5.d.mts +131 -0
- package/dist/psbt-builder-CFOs69Z5.d.ts +131 -0
- package/dist/trezor/index.d.mts +155 -0
- package/dist/trezor/index.d.ts +155 -0
- package/dist/trezor/index.js +14 -0
- package/dist/trezor/index.js.map +1 -0
- package/dist/trezor/index.mjs +5 -0
- package/dist/trezor/index.mjs.map +1 -0
- package/dist/unisat/index.d.mts +75 -0
- package/dist/unisat/index.d.ts +75 -0
- package/dist/unisat/index.js +13 -0
- package/dist/unisat/index.js.map +1 -0
- package/dist/unisat/index.mjs +4 -0
- package/dist/unisat/index.mjs.map +1 -0
- package/dist/utils/index.d.mts +398 -0
- package/dist/utils/index.d.ts +398 -0
- package/dist/utils/index.js +120 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/index.mjs +3 -0
- package/dist/utils/index.mjs.map +1 -0
- package/dist/xverse/index.d.mts +79 -0
- package/dist/xverse/index.d.ts +79 -0
- package/dist/xverse/index.js +13 -0
- package/dist/xverse/index.js.map +1 -0
- package/dist/xverse/index.mjs +4 -0
- package/dist/xverse/index.mjs.map +1 -0
- package/package.json +108 -0
- package/src/base.ts +132 -0
- package/src/binance/BinanceConnector.ts +307 -0
- package/src/binance/index.ts +1 -0
- package/src/bitget/BitgetConnector.ts +301 -0
- package/src/bitget/index.ts +1 -0
- package/src/imtoken/ImTokenConnector.ts +420 -0
- package/src/imtoken/index.ts +2 -0
- package/src/index.ts +78 -0
- package/src/ledger/LedgerConnector.ts +1019 -0
- package/src/ledger/index.ts +8 -0
- package/src/okx/OKXConnector.ts +230 -0
- package/src/okx/index.ts +1 -0
- package/src/phantom/PhantomConnector.ts +381 -0
- package/src/phantom/index.ts +2 -0
- package/src/trezor/TrezorConnector.ts +824 -0
- package/src/trezor/index.ts +6 -0
- package/src/unisat/UnisatConnector.ts +312 -0
- package/src/unisat/index.ts +1 -0
- package/src/utils/blockstream.ts +230 -0
- package/src/utils/btc-service.ts +364 -0
- package/src/utils/index.ts +56 -0
- package/src/utils/mempool.ts +232 -0
- package/src/utils/psbt-builder.ts +492 -0
- package/src/utils/types.ts +183 -0
- package/src/xverse/XverseConnector.ts +479 -0
- package/src/xverse/index.ts +1 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/utils/mempool.ts","../src/utils/blockstream.ts","../src/utils/btc-service.ts","../src/utils/psbt-builder.ts"],"names":["address","fetchWithTimeout","estimatedVBytes","estimatedFee"],"mappings":"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","sourcesContent":["import type { BitcoinNetwork } from 'otx-btc-wallet-core';\nimport type {\n IBtcService,\n Utxo,\n UtxoWithTx,\n FeeRates,\n Transaction,\n FullTransaction,\n AddressBalance,\n NetworkEndpoints,\n} from './types';\n\n/**\n * Default API endpoints for mempool.space\n */\nconst DEFAULT_MEMPOOL_ENDPOINTS: Record<BitcoinNetwork, string> = {\n mainnet: 'https://mempool.space/api',\n testnet: 'https://mempool.space/testnet/api',\n testnet4: 'https://mempool.space/testnet4/api',\n signet: 'https://mempool.space/signet/api',\n};\n\n/**\n * Fetch with timeout helper\n */\nasync function fetchWithTimeout(\n url: string,\n options?: RequestInit,\n timeout: number = 10000\n): Promise<Response> {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), timeout);\n\n try {\n const response = await fetch(url, {\n ...options,\n signal: controller.signal,\n });\n clearTimeout(timeoutId);\n return response;\n } catch (error) {\n clearTimeout(timeoutId);\n throw error;\n }\n}\n\n/**\n * Mempool.space Bitcoin Service\n *\n * @see https://mempool.space/docs/api\n *\n * @example\n * ```typescript\n * // Default usage\n * const service = new MempoolService('mainnet');\n *\n * // With custom endpoints\n * const service = new MempoolService('mainnet', {\n * mainnet: 'https://my-mempool-proxy.com/api',\n * testnet: 'https://my-mempool-proxy.com/testnet/api',\n * });\n * ```\n */\nexport class MempoolService implements IBtcService {\n readonly name = 'mempool';\n private _network: BitcoinNetwork;\n private _customEndpoints: NetworkEndpoints;\n\n constructor(network: BitcoinNetwork = 'mainnet', customEndpoints?: NetworkEndpoints) {\n this._network = network;\n this._customEndpoints = customEndpoints ?? {};\n }\n\n get network(): BitcoinNetwork {\n return this._network;\n }\n\n private get baseUrl(): string {\n // Use custom endpoint if provided, otherwise use default\n return this._customEndpoints[this._network] ?? DEFAULT_MEMPOOL_ENDPOINTS[this._network];\n }\n\n setNetwork(network: BitcoinNetwork): void {\n this._network = network;\n }\n\n /**\n * Set custom endpoints for this service\n */\n setCustomEndpoints(endpoints: NetworkEndpoints): void {\n this._customEndpoints = { ...this._customEndpoints, ...endpoints };\n }\n\n /**\n * Get current endpoints configuration\n */\n getEndpoints(): Record<BitcoinNetwork, string> {\n return {\n mainnet: this._customEndpoints.mainnet ?? DEFAULT_MEMPOOL_ENDPOINTS.mainnet,\n testnet: this._customEndpoints.testnet ?? DEFAULT_MEMPOOL_ENDPOINTS.testnet,\n testnet4: this._customEndpoints.testnet4 ?? DEFAULT_MEMPOOL_ENDPOINTS.testnet4,\n signet: this._customEndpoints.signet ?? DEFAULT_MEMPOOL_ENDPOINTS.signet,\n };\n }\n\n // ============ UTXO Methods ============\n\n async getUtxos(address: string): Promise<Utxo[]> {\n const response = await fetchWithTimeout(`${this.baseUrl}/address/${address}/utxo`);\n\n if (!response.ok) {\n throw new Error(`Mempool API error: ${response.status} ${response.statusText}`);\n }\n\n return response.json() as Promise<Utxo[]>;\n }\n\n async getUtxosWithTxHex(address: string): Promise<UtxoWithTx[]> {\n const utxos = await this.getUtxos(address);\n\n const utxosWithTx = await Promise.all(\n utxos.map(async (utxo): Promise<UtxoWithTx> => {\n const txHex = await this.getTxHex(utxo.txid);\n return { ...utxo, txHex };\n })\n );\n\n return utxosWithTx;\n }\n\n // ============ Transaction Methods ============\n\n async getTxHex(txid: string): Promise<string> {\n const response = await fetchWithTimeout(`${this.baseUrl}/tx/${txid}/hex`);\n\n if (!response.ok) {\n throw new Error(`Mempool API error: ${response.status} ${response.statusText}`);\n }\n\n return response.text();\n }\n\n async getTransaction(txid: string): Promise<Transaction> {\n const response = await fetchWithTimeout(`${this.baseUrl}/tx/${txid}`);\n\n if (!response.ok) {\n throw new Error(`Mempool API error: ${response.status} ${response.statusText}`);\n }\n\n return response.json() as Promise<Transaction>;\n }\n\n async getFullTransaction(txid: string): Promise<FullTransaction> {\n const response = await fetchWithTimeout(`${this.baseUrl}/tx/${txid}`);\n\n if (!response.ok) {\n throw new Error(`Mempool API error: ${response.status} ${response.statusText}`);\n }\n\n return response.json() as Promise<FullTransaction>;\n }\n\n async broadcastTransaction(txHex: string): Promise<string> {\n const response = await fetchWithTimeout(\n `${this.baseUrl}/tx`,\n {\n method: 'POST',\n body: txHex,\n headers: { 'Content-Type': 'text/plain' },\n },\n 30000\n );\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`Mempool broadcast error: ${error}`);\n }\n\n return response.text();\n }\n\n // ============ Address Methods ============\n\n async getAddressInfo(address: string): Promise<AddressBalance> {\n const response = await fetchWithTimeout(`${this.baseUrl}/address/${address}`);\n\n if (!response.ok) {\n throw new Error(`Mempool API error: ${response.status} ${response.statusText}`);\n }\n\n return response.json() as Promise<AddressBalance>;\n }\n\n async getBalance(address: string): Promise<number> {\n const info = await this.getAddressInfo(address);\n const confirmedBalance =\n info.chain_stats.funded_txo_sum - info.chain_stats.spent_txo_sum;\n const unconfirmedBalance =\n info.mempool_stats.funded_txo_sum - info.mempool_stats.spent_txo_sum;\n return confirmedBalance + unconfirmedBalance;\n }\n\n async getConfirmedBalance(address: string): Promise<number> {\n const info = await this.getAddressInfo(address);\n return info.chain_stats.funded_txo_sum - info.chain_stats.spent_txo_sum;\n }\n\n // ============ Fee Methods ============\n\n async getFeeRates(): Promise<FeeRates> {\n const response = await fetchWithTimeout(`${this.baseUrl}/v1/fees/recommended`);\n\n if (!response.ok) {\n throw new Error(`Mempool API error: ${response.status} ${response.statusText}`);\n }\n\n const fees = (await response.json()) as {\n fastestFee: number;\n halfHourFee: number;\n hourFee: number;\n economyFee: number;\n minimumFee: number;\n };\n return {\n fastest: fees.fastestFee,\n halfHour: fees.halfHourFee,\n hour: fees.hourFee,\n economy: fees.economyFee,\n minimum: fees.minimumFee,\n };\n }\n}\n","import type { BitcoinNetwork } from 'otx-btc-wallet-core';\nimport type {\n IBtcService,\n Utxo,\n UtxoWithTx,\n FeeRates,\n Transaction,\n FullTransaction,\n AddressBalance,\n NetworkEndpoints,\n} from './types';\n\n/**\n * Default API endpoints for blockstream.info\n * Note: Blockstream doesn't support testnet4 and signet, fallback to mempool for those\n */\nconst DEFAULT_BLOCKSTREAM_ENDPOINTS: Record<BitcoinNetwork, string> = {\n mainnet: 'https://blockstream.info/api',\n testnet: 'https://blockstream.info/testnet/api',\n testnet4: 'https://mempool.space/testnet4/api', // Fallback to mempool\n signet: 'https://mempool.space/signet/api', // Fallback to mempool\n};\n\n/**\n * Fetch with timeout helper\n */\nasync function fetchWithTimeout(\n url: string,\n options?: RequestInit,\n timeout: number = 10000\n): Promise<Response> {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), timeout);\n\n try {\n const response = await fetch(url, {\n ...options,\n signal: controller.signal,\n });\n clearTimeout(timeoutId);\n return response;\n } catch (error) {\n clearTimeout(timeoutId);\n throw error;\n }\n}\n\n/**\n * Blockstream.info Bitcoin Service\n *\n * @see https://github.com/Blockstream/esplora/blob/master/API.md\n *\n * @example\n * ```typescript\n * // Default usage\n * const service = new BlockstreamService('mainnet');\n *\n * // With custom endpoints\n * const service = new BlockstreamService('mainnet', {\n * mainnet: 'https://my-esplora-proxy.com/api',\n * testnet: 'https://my-esplora-proxy.com/testnet/api',\n * });\n * ```\n */\nexport class BlockstreamService implements IBtcService {\n readonly name = 'blockstream';\n private _network: BitcoinNetwork;\n private _customEndpoints: NetworkEndpoints;\n\n constructor(network: BitcoinNetwork = 'mainnet', customEndpoints?: NetworkEndpoints) {\n this._network = network;\n this._customEndpoints = customEndpoints ?? {};\n }\n\n get network(): BitcoinNetwork {\n return this._network;\n }\n\n private get baseUrl(): string {\n // Use custom endpoint if provided, otherwise use default\n return this._customEndpoints[this._network] ?? DEFAULT_BLOCKSTREAM_ENDPOINTS[this._network];\n }\n\n setNetwork(network: BitcoinNetwork): void {\n this._network = network;\n }\n\n /**\n * Set custom endpoints for this service\n */\n setCustomEndpoints(endpoints: NetworkEndpoints): void {\n this._customEndpoints = { ...this._customEndpoints, ...endpoints };\n }\n\n /**\n * Get current endpoints configuration\n */\n getEndpoints(): Record<BitcoinNetwork, string> {\n return {\n mainnet: this._customEndpoints.mainnet ?? DEFAULT_BLOCKSTREAM_ENDPOINTS.mainnet,\n testnet: this._customEndpoints.testnet ?? DEFAULT_BLOCKSTREAM_ENDPOINTS.testnet,\n testnet4: this._customEndpoints.testnet4 ?? DEFAULT_BLOCKSTREAM_ENDPOINTS.testnet4,\n signet: this._customEndpoints.signet ?? DEFAULT_BLOCKSTREAM_ENDPOINTS.signet,\n };\n }\n\n // ============ UTXO Methods ============\n\n async getUtxos(address: string): Promise<Utxo[]> {\n const response = await fetchWithTimeout(`${this.baseUrl}/address/${address}/utxo`);\n\n if (!response.ok) {\n throw new Error(`Blockstream API error: ${response.status} ${response.statusText}`);\n }\n\n return response.json() as Promise<Utxo[]>;\n }\n\n async getUtxosWithTxHex(address: string): Promise<UtxoWithTx[]> {\n const utxos = await this.getUtxos(address);\n\n const utxosWithTx = await Promise.all(\n utxos.map(async (utxo): Promise<UtxoWithTx> => {\n const txHex = await this.getTxHex(utxo.txid);\n return { ...utxo, txHex };\n })\n );\n\n return utxosWithTx;\n }\n\n // ============ Transaction Methods ============\n\n async getTxHex(txid: string): Promise<string> {\n const response = await fetchWithTimeout(`${this.baseUrl}/tx/${txid}/hex`);\n\n if (!response.ok) {\n throw new Error(`Blockstream API error: ${response.status} ${response.statusText}`);\n }\n\n return response.text();\n }\n\n async getTransaction(txid: string): Promise<Transaction> {\n const response = await fetchWithTimeout(`${this.baseUrl}/tx/${txid}`);\n\n if (!response.ok) {\n throw new Error(`Blockstream API error: ${response.status} ${response.statusText}`);\n }\n\n return response.json() as Promise<Transaction>;\n }\n\n async getFullTransaction(txid: string): Promise<FullTransaction> {\n const response = await fetchWithTimeout(`${this.baseUrl}/tx/${txid}`);\n\n if (!response.ok) {\n throw new Error(`Blockstream API error: ${response.status} ${response.statusText}`);\n }\n\n return response.json() as Promise<FullTransaction>;\n }\n\n async broadcastTransaction(txHex: string): Promise<string> {\n const response = await fetchWithTimeout(\n `${this.baseUrl}/tx`,\n {\n method: 'POST',\n body: txHex,\n headers: { 'Content-Type': 'text/plain' },\n },\n 30000\n );\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`Blockstream broadcast error: ${error}`);\n }\n\n return response.text();\n }\n\n // ============ Address Methods ============\n\n async getAddressInfo(address: string): Promise<AddressBalance> {\n const response = await fetchWithTimeout(`${this.baseUrl}/address/${address}`);\n\n if (!response.ok) {\n throw new Error(`Blockstream API error: ${response.status} ${response.statusText}`);\n }\n\n return response.json() as Promise<AddressBalance>;\n }\n\n async getBalance(address: string): Promise<number> {\n const info = await this.getAddressInfo(address);\n const confirmedBalance =\n info.chain_stats.funded_txo_sum - info.chain_stats.spent_txo_sum;\n const unconfirmedBalance =\n info.mempool_stats.funded_txo_sum - info.mempool_stats.spent_txo_sum;\n return confirmedBalance + unconfirmedBalance;\n }\n\n async getConfirmedBalance(address: string): Promise<number> {\n const info = await this.getAddressInfo(address);\n return info.chain_stats.funded_txo_sum - info.chain_stats.spent_txo_sum;\n }\n\n // ============ Fee Methods ============\n\n async getFeeRates(): Promise<FeeRates> {\n // Blockstream uses mempool.space fee API format\n const response = await fetchWithTimeout(`${this.baseUrl}/fee-estimates`);\n\n if (!response.ok) {\n throw new Error(`Blockstream API error: ${response.status} ${response.statusText}`);\n }\n\n const fees = (await response.json()) as Record<string, number>;\n // Blockstream returns fee estimates keyed by confirmation target\n // e.g., { \"1\": 25.5, \"2\": 20.1, \"3\": 15.2, ... }\n return {\n fastest: Math.ceil(fees['1'] || fees['2'] || 10),\n halfHour: Math.ceil(fees['3'] || fees['4'] || 8),\n hour: Math.ceil(fees['6'] || fees['12'] || 5),\n economy: Math.ceil(fees['144'] || fees['504'] || 2),\n minimum: Math.ceil(fees['1008'] || 1),\n };\n }\n}\n","import type { BitcoinNetwork } from 'otx-btc-wallet-core';\nimport type {\n IBtcService,\n Utxo,\n UtxoWithTx,\n FeeRates,\n Transaction,\n FullTransaction,\n AddressBalance,\n BtcServiceConfig,\n} from './types';\nimport { MempoolService } from './mempool';\nimport { BlockstreamService } from './blockstream';\n\n/**\n * Global configuration for BtcService\n * This is applied to all new BtcService instances and standalone functions\n */\nlet globalConfig: BtcServiceConfig = {};\n\n/**\n * Configure global BtcService settings\n *\n * @example\n * ```typescript\n * import { configureBtcService } from 'otx-btc-wallet-connectors';\n *\n * // Use custom mempool instance\n * configureBtcService({\n * mempool: {\n * mainnet: 'https://my-mempool.com/api',\n * testnet: 'https://my-mempool.com/testnet/api',\n * }\n * });\n *\n * // Use only mempool provider (no race)\n * configureBtcService({\n * preferredProvider: 'mempool',\n * mempool: {\n * mainnet: 'https://custom-api.example.com/api',\n * }\n * });\n *\n * // Reset to defaults\n * configureBtcService({});\n * ```\n */\nexport function configureBtcService(config: BtcServiceConfig): void {\n globalConfig = config;\n // Reset default service so it picks up new config\n defaultService = null;\n}\n\n/**\n * Get current global BtcService configuration\n */\nexport function getBtcServiceConfig(): BtcServiceConfig {\n return { ...globalConfig };\n}\n\n/**\n * Race promises and return first result\n */\nfunction race<T>(promises: Promise<T>[]): Promise<T> {\n return Promise.race(promises);\n}\n\n/**\n * Bitcoin Service that combines Mempool and Blockstream APIs\n * Uses Promise.race for reliability and speed\n *\n * @example\n * ```typescript\n * // Default usage\n * const btcService = new BtcService('mainnet');\n *\n * // With custom configuration\n * const btcService = new BtcService('mainnet', {\n * mempool: {\n * mainnet: 'https://my-mempool-proxy.com/api',\n * },\n * preferredProvider: 'mempool', // Only use mempool\n * });\n *\n * // Get balance (uses fastest responding API if preferredProvider is 'race')\n * const balance = await btcService.getBalance('bc1q...');\n *\n * // Get UTXOs with tx hex (for Ledger signing)\n * const utxos = await btcService.getUtxosWithTxHex('bc1q...');\n *\n * // Broadcast transaction\n * const txid = await btcService.broadcastTransaction(signedTxHex);\n * ```\n */\nexport class BtcService implements IBtcService {\n readonly name = 'btc-service';\n private _network: BitcoinNetwork;\n private _mempool: MempoolService;\n private _blockstream: BlockstreamService;\n private _config: BtcServiceConfig;\n\n constructor(network: BitcoinNetwork = 'mainnet', config?: BtcServiceConfig) {\n this._network = network;\n // Merge with global config, instance config takes precedence\n this._config = { ...globalConfig, ...config };\n this._mempool = new MempoolService(network, this._config.mempool);\n this._blockstream = new BlockstreamService(network, this._config.blockstream);\n }\n\n get network(): BitcoinNetwork {\n return this._network;\n }\n\n /**\n * Get the underlying Mempool service for direct access\n */\n get mempool(): MempoolService {\n return this._mempool;\n }\n\n /**\n * Get the underlying Blockstream service for direct access\n */\n get blockstream(): BlockstreamService {\n return this._blockstream;\n }\n\n /**\n * Get current configuration\n */\n get config(): BtcServiceConfig {\n return { ...this._config };\n }\n\n setNetwork(network: BitcoinNetwork): void {\n this._network = network;\n this._mempool.setNetwork(network);\n this._blockstream.setNetwork(network);\n }\n\n /**\n * Update configuration\n */\n setConfig(config: BtcServiceConfig): void {\n this._config = { ...this._config, ...config };\n if (config.mempool) {\n this._mempool.setCustomEndpoints(config.mempool);\n }\n if (config.blockstream) {\n this._blockstream.setCustomEndpoints(config.blockstream);\n }\n }\n\n /**\n * Execute method based on preferred provider setting\n */\n private async executeWithProvider<T>(\n mempoolFn: () => Promise<T>,\n blockstreamFn: () => Promise<T>\n ): Promise<T> {\n const provider = this._config.preferredProvider ?? 'race';\n\n switch (provider) {\n case 'mempool':\n return mempoolFn();\n case 'blockstream':\n return blockstreamFn();\n case 'race':\n default:\n return race([mempoolFn(), blockstreamFn()]);\n }\n }\n\n // ============ UTXO Methods ============\n\n async getUtxos(address: string): Promise<Utxo[]> {\n return this.executeWithProvider(\n () => this._mempool.getUtxos(address),\n () => this._blockstream.getUtxos(address)\n );\n }\n\n async getUtxosWithTxHex(address: string): Promise<UtxoWithTx[]> {\n return this.executeWithProvider(\n () => this._mempool.getUtxosWithTxHex(address),\n () => this._blockstream.getUtxosWithTxHex(address)\n );\n }\n\n // ============ Transaction Methods ============\n\n async getTxHex(txid: string): Promise<string> {\n return this.executeWithProvider(\n () => this._mempool.getTxHex(txid),\n () => this._blockstream.getTxHex(txid)\n );\n }\n\n async getTransaction(txid: string): Promise<Transaction> {\n return this.executeWithProvider(\n () => this._mempool.getTransaction(txid),\n () => this._blockstream.getTransaction(txid)\n );\n }\n\n async getFullTransaction(txid: string): Promise<FullTransaction> {\n return this.executeWithProvider(\n () => this._mempool.getFullTransaction(txid),\n () => this._blockstream.getFullTransaction(txid)\n );\n }\n\n async broadcastTransaction(txHex: string): Promise<string> {\n return this.executeWithProvider(\n () => this._mempool.broadcastTransaction(txHex),\n () => this._blockstream.broadcastTransaction(txHex)\n );\n }\n\n // ============ Address Methods ============\n\n async getAddressInfo(address: string): Promise<AddressBalance> {\n return this.executeWithProvider(\n () => this._mempool.getAddressInfo(address),\n () => this._blockstream.getAddressInfo(address)\n );\n }\n\n async getBalance(address: string): Promise<number> {\n return this.executeWithProvider(\n () => this._mempool.getBalance(address),\n () => this._blockstream.getBalance(address)\n );\n }\n\n async getConfirmedBalance(address: string): Promise<number> {\n return this.executeWithProvider(\n () => this._mempool.getConfirmedBalance(address),\n () => this._blockstream.getConfirmedBalance(address)\n );\n }\n\n // ============ Fee Methods ============\n\n async getFeeRates(): Promise<FeeRates> {\n return this.executeWithProvider(\n () => this._mempool.getFeeRates(),\n () => this._blockstream.getFeeRates()\n );\n }\n}\n\n// ============ Standalone Functions ============\n\n/**\n * Default service instance (mainnet)\n */\nlet defaultService: BtcService | null = null;\n\nfunction getDefaultService(network: BitcoinNetwork = 'mainnet'): BtcService {\n if (!defaultService || defaultService.network !== network) {\n defaultService = new BtcService(network);\n }\n return defaultService;\n}\n\n/**\n * Get UTXOs for an address\n */\nexport async function getUtxos(\n address: string,\n network: BitcoinNetwork = 'mainnet'\n): Promise<Utxo[]> {\n return getDefaultService(network).getUtxos(address);\n}\n\n/**\n * Get UTXOs with raw transaction hex\n */\nexport async function getUtxosWithTxHex(\n address: string,\n network: BitcoinNetwork = 'mainnet'\n): Promise<UtxoWithTx[]> {\n return getDefaultService(network).getUtxosWithTxHex(address);\n}\n\n/**\n * Get raw transaction hex\n */\nexport async function getTxHex(\n txid: string,\n network: BitcoinNetwork = 'mainnet'\n): Promise<string> {\n return getDefaultService(network).getTxHex(txid);\n}\n\n/**\n * Get transaction details\n */\nexport async function getTransaction(\n txid: string,\n network: BitcoinNetwork = 'mainnet'\n): Promise<Transaction> {\n return getDefaultService(network).getTransaction(txid);\n}\n\n/**\n * Get full transaction with inputs and outputs (for Trezor refTxs)\n */\nexport async function getFullTransaction(\n txid: string,\n network: BitcoinNetwork = 'mainnet'\n): Promise<FullTransaction> {\n return getDefaultService(network).getFullTransaction(txid);\n}\n\n/**\n * Broadcast a signed transaction\n */\nexport async function broadcastTransaction(\n txHex: string,\n network: BitcoinNetwork = 'mainnet'\n): Promise<string> {\n return getDefaultService(network).broadcastTransaction(txHex);\n}\n\n/**\n * Get address info\n */\nexport async function getAddressInfo(\n address: string,\n network: BitcoinNetwork = 'mainnet'\n): Promise<AddressBalance> {\n return getDefaultService(network).getAddressInfo(address);\n}\n\n/**\n * Get balance for an address\n */\nexport async function getBalance(\n address: string,\n network: BitcoinNetwork = 'mainnet'\n): Promise<number> {\n return getDefaultService(network).getBalance(address);\n}\n\n/**\n * Get confirmed balance for an address\n */\nexport async function getConfirmedBalance(\n address: string,\n network: BitcoinNetwork = 'mainnet'\n): Promise<number> {\n return getDefaultService(network).getConfirmedBalance(address);\n}\n\n/**\n * Get current fee rates\n */\nexport async function getFeeRates(\n network: BitcoinNetwork = 'mainnet'\n): Promise<FeeRates> {\n return getDefaultService(network).getFeeRates();\n}\n","/**\n * PSBT Builder Utility\n * Reusable functions for building PSBTs across different wallet connectors\n */\n\nimport type { BitcoinNetwork, AddressType } from 'otx-btc-wallet-core';\nimport * as bitcoin from 'bitcoinjs-lib';\nimport { BtcService } from './btc-service';\n\n/**\n * UTXO type\n */\nexport interface Utxo {\n txid: string;\n vout: number;\n value: number;\n status?: {\n confirmed: boolean;\n block_height?: number;\n };\n}\n\n/**\n * Options for generating a send PSBT\n */\nexport interface GeneratePsbtOptions {\n /** Fee rate in sat/vB */\n feeRate?: number;\n /** Fee rate multiplier */\n feeRateMultiplier?: number;\n}\n\n/**\n * Result from generating a send PSBT\n */\nexport interface GeneratePsbtResult {\n /** The constructed PSBT */\n psbt: bitcoin.Psbt;\n /** PSBT as hex string */\n psbtHex: string;\n /** PSBT as base64 string */\n psbtBase64: string;\n /** Bitcoin network used */\n btcNetwork: bitcoin.Network;\n /** Selected UTXOs used in the transaction */\n selectedUtxos: Utxo[];\n /** Total input value in satoshis */\n totalInputValue: number;\n /** Estimated fee in satoshis */\n estimatedFee: number;\n /** Change amount in satoshis (0 if no change output) */\n changeAmount: number;\n /** Inputs to sign (for wallet APIs that require this) */\n inputsToSign: Array<{ address: string; index: number }>;\n}\n\n/**\n * Helper to convert hex string to Uint8Array\n */\nexport function hexToBytes(hex: string): Uint8Array {\n const cleanHex = hex.replace(/^0x/, '');\n const bytes = new Uint8Array(cleanHex.length / 2);\n for (let i = 0; i < bytes.length; i++) {\n bytes[i] = parseInt(cleanHex.substring(i * 2, i * 2 + 2), 16);\n }\n return bytes;\n}\n\n/**\n * Helper to convert Uint8Array to hex string\n */\nexport function bytesToHex(bytes: Uint8Array): string {\n return Array.from(bytes)\n .map((b) => b.toString(16).padStart(2, '0'))\n .join('');\n}\n\n/**\n * Helper to convert public key to x-only (for Taproot)\n */\nexport function toXOnly(pubKey: Uint8Array): Uint8Array {\n return pubKey.subarray(1, 33);\n}\n\n/**\n * Get address type from address string\n */\nexport function getAddressType(address: string): AddressType {\n if (address.startsWith('bc1q') || address.startsWith('tb1q')) {\n return 'segwit';\n }\n if (address.startsWith('bc1p') || address.startsWith('tb1p')) {\n return 'taproot';\n }\n if (address.startsWith('3') || address.startsWith('2')) {\n return 'nested-segwit';\n }\n return 'legacy';\n}\n\n/**\n * Get bitcoinjs-lib network object from BitcoinNetwork\n */\nexport function getBitcoinJsNetwork(network: BitcoinNetwork): bitcoin.Network {\n switch (network) {\n case 'mainnet':\n return bitcoin.networks.bitcoin;\n case 'testnet':\n case 'testnet4':\n case 'signet':\n return bitcoin.networks.testnet;\n default:\n return bitcoin.networks.bitcoin;\n }\n}\n\n/**\n * Estimate vBytes per input based on address type\n */\nexport function getInputVBytes(addressType: AddressType): number {\n switch (addressType) {\n case 'taproot':\n return 58; // P2TR input\n case 'segwit':\n return 68; // P2WPKH input\n case 'nested-segwit':\n return 91; // P2SH-P2WPKH input\n default:\n return 148; // P2PKH input\n }\n}\n\n/**\n * Estimate vBytes per output based on address type\n */\nexport function getOutputVBytes(addressType: AddressType): number {\n switch (addressType) {\n case 'taproot':\n return 43; // P2TR output\n case 'segwit':\n return 31; // P2WPKH output\n case 'nested-segwit':\n return 32; // P2SH output\n default:\n return 34; // P2PKH output\n }\n}\n\n/**\n * Get dust threshold for address type\n */\nexport function getDustThreshold(addressType: AddressType): number {\n return addressType === 'legacy' ? 546 : 294;\n}\n\n/**\n * Select UTXOs for transaction using a simple greedy algorithm\n */\nexport function selectUtxos(\n utxos: Utxo[],\n fromAddressType: AddressType,\n toAddressType: AddressType,\n amount: number,\n feeRate: number\n): { selectedUtxos: Utxo[]; totalValue: number; estimatedFee: number } {\n const inputVBytes = getInputVBytes(fromAddressType);\n const outputVBytes = getOutputVBytes(toAddressType);\n const baseVBytes = 10.5; // Base transaction overhead\n\n // Sort UTXOs by value (descending) for better selection\n const sortedUtxos = [...utxos].sort((a, b) => b.value - a.value);\n\n const selectedUtxos: Utxo[] = [];\n let totalValue = 0;\n\n for (const utxo of sortedUtxos) {\n selectedUtxos.push(utxo);\n totalValue += utxo.value;\n\n // Calculate fee with current selection (2 outputs: recipient + change)\n const estimatedVBytes =\n baseVBytes + selectedUtxos.length * inputVBytes + 2 * outputVBytes;\n const estimatedFee = Math.ceil(estimatedVBytes * feeRate);\n\n if (totalValue >= amount + estimatedFee) {\n return { selectedUtxos, totalValue, estimatedFee };\n }\n }\n\n // If we get here, we don't have enough funds\n // Return what we have and let the caller handle the error\n const estimatedVBytes =\n baseVBytes + selectedUtxos.length * inputVBytes + 2 * outputVBytes;\n const estimatedFee = Math.ceil(estimatedVBytes * feeRate);\n\n return { selectedUtxos, totalValue, estimatedFee };\n}\n\n/**\n * Generate a PSBT for sending Bitcoin\n *\n * @param toAddress - Recipient address\n * @param amount - Amount to send in satoshis\n * @param fromAddress - Sender address\n * @param publicKey - Sender's public key (hex string)\n * @param network - Bitcoin network\n * @param options - Additional options (feeRate, feeRateMultiplier)\n * @returns GeneratePsbtResult containing the PSBT and related info\n */\nexport async function generatePsbtForSend(\n toAddress: string,\n amount: number,\n fromAddress: string,\n publicKey: string,\n network: BitcoinNetwork,\n options?: GeneratePsbtOptions\n): Promise<GeneratePsbtResult> {\n const btcService = new BtcService(network);\n const btcNetwork = getBitcoinJsNetwork(network);\n\n // 1. Get UTXOs (only confirmed)\n const allUtxos = await btcService.getUtxos(fromAddress);\n const confirmedUtxos = allUtxos.filter(\n (utxo) => utxo.status?.confirmed !== false\n );\n\n if (confirmedUtxos.length === 0) {\n throw new Error('No confirmed UTXOs available for spending');\n }\n\n // 2. Get fee rate\n let feeRate = options?.feeRate;\n if (!feeRate) {\n const feeRates = await btcService.getFeeRates();\n feeRate = feeRates.hour;\n }\n if (options?.feeRateMultiplier) {\n feeRate = Math.ceil(feeRate * options.feeRateMultiplier);\n }\n\n // 3. Get address types\n const fromAddressType = getAddressType(fromAddress);\n const toAddressType = getAddressType(toAddress);\n\n // 4. Select UTXOs\n const { selectedUtxos, totalValue, estimatedFee } = selectUtxos(\n confirmedUtxos,\n fromAddressType,\n toAddressType,\n amount,\n feeRate\n );\n\n if (totalValue < amount + estimatedFee) {\n throw new Error(\n `Insufficient funds. Available: ${totalValue} sats, Required: ${amount + estimatedFee} sats (including fee)`\n );\n }\n\n // 5. Calculate change\n const dustThreshold = getDustThreshold(fromAddressType);\n let changeAmount = totalValue - amount - estimatedFee;\n\n // If change is below dust threshold, add it to fee\n if (changeAmount > 0 && changeAmount <= dustThreshold) {\n changeAmount = 0;\n }\n\n // 6. Build PSBT\n const psbt = new bitcoin.Psbt({ network: btcNetwork });\n const publicKeyBytes = hexToBytes(publicKey);\n const inputsToSign: Array<{ address: string; index: number }> = [];\n\n // Add inputs\n for (let i = 0; i < selectedUtxos.length; i++) {\n const utxo = selectedUtxos[i]!;\n const script = bitcoin.address.toOutputScript(fromAddress, btcNetwork);\n\n if (fromAddressType === 'taproot') {\n // P2TR - Taproot\n psbt.addInput({\n hash: utxo.txid,\n index: utxo.vout,\n witnessUtxo: {\n script,\n value: BigInt(utxo.value),\n },\n tapInternalKey: toXOnly(publicKeyBytes),\n });\n } else if (fromAddressType === 'segwit') {\n // P2WPKH - Native SegWit\n psbt.addInput({\n hash: utxo.txid,\n index: utxo.vout,\n witnessUtxo: {\n script,\n value: BigInt(utxo.value),\n },\n });\n } else if (fromAddressType === 'nested-segwit') {\n // P2SH-P2WPKH - Nested SegWit\n const p2wpkh = bitcoin.payments.p2wpkh({\n pubkey: publicKeyBytes,\n network: btcNetwork,\n });\n if (!p2wpkh.output) {\n throw new Error('Failed to generate P2WPKH redeem script');\n }\n psbt.addInput({\n hash: utxo.txid,\n index: utxo.vout,\n witnessUtxo: {\n script,\n value: BigInt(utxo.value),\n },\n redeemScript: p2wpkh.output,\n });\n } else {\n // Legacy P2PKH\n psbt.addInput({\n hash: utxo.txid,\n index: utxo.vout,\n witnessUtxo: {\n script,\n value: BigInt(utxo.value),\n },\n });\n }\n\n inputsToSign.push({ address: fromAddress, index: i });\n }\n\n // Add recipient output\n psbt.addOutput({\n address: toAddress,\n value: BigInt(amount),\n });\n\n // Add change output if needed\n if (changeAmount > 0) {\n psbt.addOutput({\n address: fromAddress,\n value: BigInt(Math.floor(changeAmount)),\n });\n }\n\n return {\n psbt,\n psbtHex: psbt.toHex(),\n psbtBase64: psbt.toBase64(),\n btcNetwork,\n selectedUtxos,\n totalInputValue: totalValue,\n estimatedFee,\n changeAmount,\n inputsToSign,\n };\n}\n\n/**\n * Finalize all inputs in a signed PSBT\n */\nexport function finalizeAllInputs(\n signedPsbt: bitcoin.Psbt,\n inputCount: number\n): void {\n for (let i = 0; i < inputCount; i++) {\n try {\n signedPsbt.finalizeInput(i);\n } catch (finalizeError) {\n console.warn(\n `Failed to finalize input ${i}, attempting alternative finalization:`,\n finalizeError\n );\n // For complex input types, try finalization with empty witness\n try {\n signedPsbt.finalizeInput(i, () => ({\n finalScriptSig: undefined,\n finalScriptWitness: undefined,\n }));\n } catch {\n // If that also fails, just skip - the transaction might still work\n console.warn(`Could not finalize input ${i}`);\n }\n }\n }\n}\n\n/**\n * Extract and broadcast a signed PSBT\n *\n * @param signedPsbtHex - Signed PSBT hex string\n * @param network - Bitcoin network\n * @param inputCount - Number of inputs to finalize\n * @returns Transaction ID\n */\nexport async function finalizeAndBroadcast(\n signedPsbtHex: string,\n network: BitcoinNetwork,\n inputCount: number\n): Promise<string> {\n const btcNetwork = getBitcoinJsNetwork(network);\n const btcService = new BtcService(network);\n\n // Parse signed PSBT\n const signedPsbt = bitcoin.Psbt.fromHex(signedPsbtHex, { network: btcNetwork });\n\n // Finalize all inputs\n finalizeAllInputs(signedPsbt, inputCount);\n\n // Extract transaction\n const tx = signedPsbt.extractTransaction();\n const txHex = tx.toHex();\n\n // Broadcast\n return await btcService.broadcastTransaction(txHex);\n}\n\n/**\n * Derive Bitcoin address from public key based on address type\n *\n * @param publicKeyHex - Public key in hex format (33 bytes compressed)\n * @param addressType - Type of address to derive (legacy, nested-segwit, segwit, taproot)\n * @param network - Bitcoin network\n * @returns Derived Bitcoin address\n */\nexport function deriveAddressFromPublicKey(\n publicKeyHex: string,\n addressType: AddressType,\n network: BitcoinNetwork\n): string {\n const btcNetwork = getBitcoinJsNetwork(network);\n const publicKeyBytes = hexToBytes(publicKeyHex);\n\n switch (addressType) {\n case 'legacy': {\n // P2PKH - Legacy address (starts with 1 or m/n)\n const p2pkh = bitcoin.payments.p2pkh({\n pubkey: publicKeyBytes,\n network: btcNetwork,\n });\n if (!p2pkh.address) {\n throw new Error('Failed to derive legacy address from public key');\n }\n return p2pkh.address;\n }\n\n case 'nested-segwit': {\n // P2SH-P2WPKH - Nested SegWit (starts with 3 or 2)\n const p2wpkh = bitcoin.payments.p2wpkh({\n pubkey: publicKeyBytes,\n network: btcNetwork,\n });\n const p2sh = bitcoin.payments.p2sh({\n redeem: p2wpkh,\n network: btcNetwork,\n });\n if (!p2sh.address) {\n throw new Error('Failed to derive nested-segwit address from public key');\n }\n return p2sh.address;\n }\n\n case 'segwit': {\n // P2WPKH - Native SegWit (starts with bc1q or tb1q)\n const p2wpkh = bitcoin.payments.p2wpkh({\n pubkey: publicKeyBytes,\n network: btcNetwork,\n });\n if (!p2wpkh.address) {\n throw new Error('Failed to derive segwit address from public key');\n }\n return p2wpkh.address;\n }\n\n case 'taproot': {\n // P2TR - Taproot (starts with bc1p or tb1p)\n const xOnlyPubKey = toXOnly(publicKeyBytes);\n const p2tr = bitcoin.payments.p2tr({\n internalPubkey: xOnlyPubKey,\n network: btcNetwork,\n });\n if (!p2tr.address) {\n throw new Error('Failed to derive taproot address from public key');\n }\n return p2tr.address;\n }\n\n default:\n throw new Error(`Unsupported address type: ${addressType}`);\n }\n}\n"]}
|
|
@@ -0,0 +1,331 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var chunkMFXLQWOE_js = require('./chunk-MFXLQWOE.js');
|
|
4
|
+
|
|
5
|
+
// src/xverse/XverseConnector.ts
|
|
6
|
+
var XVERSE_ICON = "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjAwIiBoZWlnaHQ9IjIwMCIgdmlld0JveD0iMCAwIDIwMCAyMDAiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMF83MDM3XzEwMykiPgo8cGF0aCBkPSJNMjAwIDBIMFYyMDBIMjAwVjBaIiBmaWxsPSJ1cmwoI3BhaW50MF9saW5lYXJfNzAzN18xMDMpIi8+CjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMV83MDM3XzEwMykiPgo8cGF0aCBkPSJNMTU5LjM2NyAxNTcuNDQ1VjEzNS43MThDMTU5LjM2NyAxMzQuODU2IDE1OS4wMjUgMTM0LjAzNCAxNTguNDE0IDEzMy40MjRMNjUuOTY2NCA0MC45NzU2QzY1LjM1NTkgNDAuMzY1MSA2NC41MzQyIDQwLjAyMjggNjMuNjcyNiA0MC4wMjI4SDQxLjk0NTZDNDAuODczIDQwLjAyMjggNDAgNDAuODk1NyA0MCA0MS45Njg0VjYyLjE1NDlDNDAgNjMuMDE2NSA0MC4zNDIzIDYzLjgzOCA0MC45NTI4IDY0LjQ0ODZMNzQuMTM2OCA5Ny42MzI0Qzc0Ljg5NTYgOTguMzkxNiA3NC44OTU2IDk5LjYyNCA3NC4xMzY4IDEwMC4zODNMNDAuNTcwNiAxMzMuOTQ5QzQwLjIwNTQgMTM0LjMxNCA0MCAxMzQuODEgNDAgMTM1LjMyNFYxNTcuNDQ1QzQwIDE1OC41MTcgNDAuODczIDE1OS4zOTEgNDEuOTQ1NiAxNTkuMzkxSDc4LjI1MDVDNzkuMzIzMiAxNTkuMzkxIDgwLjE5NiAxNTguNTE3IDgwLjE5NiAxNTcuNDQ1VjE0NC40MTNDODAuMTk2IDE0My45IDgwLjQwMTYgMTQzLjQwMyA4MC43NjY4IDE0My4wMzhMOTguNzczNiAxMjUuMDMxQzk5LjUzMjQgMTI0LjI3MiAxMDAuNzY1IDEyNC4yNzIgMTAxLjUyNCAxMjUuMDMxTDEzNC45MzYgMTU4LjQ0NEMxMzUuNTQ2IDE1OS4wNTQgMTM2LjM2OCAxNTkuMzk2IDEzNy4yMyAxNTkuMzk2SDE1Ny40MTZDMTU4LjQ4OSAxNTkuMzk2IDE1OS4zNjIgMTU4LjUyMyAxNTkuMzYyIDE1Ny40NTFMMTU5LjM2NyAxNTcuNDQ1WiIgZmlsbD0id2hpdGUiLz4KPHBhdGggZD0iTTExMC45MzggNjguNzk2SDEyOS4xMjJDMTMwLjIgNjguNzk2IDEzMS4wNzkgNjkuNjc0NyAxMzEuMDc5IDcwLjc1MzFWODguOTM2OEMxMzEuMDc5IDkwLjY4MjggMTMzLjE5IDkxLjU1NiAxMzQuNDIyIDkwLjMxNzZMMTU5LjM2NyA2NS4zMzI4QzE1OS43MzIgNjQuOTY3NiAxNTkuOTM4IDY0LjQ3MTMgMTU5LjkzOCA2My45NTJWNDIuMDcwOUMxNTkuOTM4IDQwLjk5MjUgMTU5LjA2NCA0MC4xMTM5IDE1Ny45ODEgNDAuMTEzOUwxMzUuNzc0IDQwLjA4NTRDMTM1LjI1NiA0MC4wODU0IDEzNC43NTkgNDAuMjkwOCAxMzQuMzg4IDQwLjY1NTlMMTA5LjU1MiA2NS40NTI2QzEwOC4zMTkgNjYuNjg1IDEwOS4xOTIgNjguNzk2IDExMC45MzIgNjguNzk2SDExMC45MzhaIiBmaWxsPSIjRUU3QTMwIi8+CjwvZz4KPC9nPgo8ZGVmcz4KPGxpbmVhckdyYWRpZW50IGlkPSJwYWludDBfbGluZWFyXzcwMzdfMTAzIiB4MT0iMTAwIiB5MT0iMCIgeDI9IjEwMCIgeTI9IjIwMCIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiPgo8c3RvcCBzdG9wLWNvbG9yPSIjMEYwRjBGIi8+CjxzdG9wIG9mZnNldD0iMSIgc3RvcC1jb2xvcj0iIzE4MTgxOCIvPgo8L2xpbmVhckdyYWRpZW50Pgo8Y2xpcFBhdGggaWQ9ImNsaXAwXzcwMzdfMTAzIj4KPHJlY3Qgd2lkdGg9IjIwMCIgaGVpZ2h0PSIyMDAiIHJ4PSIzNS41NTU2IiBmaWxsPSJ3aGl0ZSIvPgo8L2NsaXBQYXRoPgo8Y2xpcFBhdGggaWQ9ImNsaXAxXzcwMzdfMTAzIj4KPHJlY3Qgd2lkdGg9IjEyMCIgaGVpZ2h0PSIxMjAiIGZpbGw9IndoaXRlIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSg0MCA0MCkiLz4KPC9jbGlwUGF0aD4KPC9kZWZzPgo8L3N2Zz4K";
|
|
7
|
+
var XverseConnector = class extends chunkMFXLQWOE_js.BaseConnector {
|
|
8
|
+
constructor() {
|
|
9
|
+
super(...arguments);
|
|
10
|
+
this.id = "xverse";
|
|
11
|
+
this.name = "Xverse Wallet";
|
|
12
|
+
this.icon = XVERSE_ICON;
|
|
13
|
+
this._paymentAddress = null;
|
|
14
|
+
this._ordinalsAddress = null;
|
|
15
|
+
this._network = "mainnet";
|
|
16
|
+
this._accounts = [];
|
|
17
|
+
this._removeAccountChangeListener = null;
|
|
18
|
+
this._removeNetworkChangeListener = null;
|
|
19
|
+
this._removeDisconnectedListener = null;
|
|
20
|
+
}
|
|
21
|
+
getProvider() {
|
|
22
|
+
if (typeof window === "undefined")
|
|
23
|
+
return void 0;
|
|
24
|
+
return window.XverseProviders?.BitcoinProvider;
|
|
25
|
+
}
|
|
26
|
+
async connect(network = "mainnet") {
|
|
27
|
+
const provider = this.getProvider();
|
|
28
|
+
if (!provider) {
|
|
29
|
+
this.handleError(new Error("Xverse Wallet is not installed"));
|
|
30
|
+
}
|
|
31
|
+
try {
|
|
32
|
+
this._network = network;
|
|
33
|
+
const permissionResponse = await provider.request("wallet_requestPermissions", void 0);
|
|
34
|
+
if (permissionResponse.error) {
|
|
35
|
+
throw new Error(permissionResponse.error.message);
|
|
36
|
+
}
|
|
37
|
+
const response = await provider.request("getAddresses", {
|
|
38
|
+
purposes: ["payment" /* Payment */, "ordinals" /* Ordinals */],
|
|
39
|
+
message: "Connect to application"
|
|
40
|
+
});
|
|
41
|
+
if (response.error) {
|
|
42
|
+
throw response.error;
|
|
43
|
+
}
|
|
44
|
+
const addresses = response.result.addresses;
|
|
45
|
+
this._accounts = addresses;
|
|
46
|
+
const paymentAddr = addresses.find((a) => a.purpose === "payment" /* Payment */);
|
|
47
|
+
const ordinalsAddr = addresses.find((a) => a.purpose === "ordinals" /* Ordinals */);
|
|
48
|
+
if (paymentAddr) {
|
|
49
|
+
this._paymentAddress = {
|
|
50
|
+
address: paymentAddr.address,
|
|
51
|
+
publicKey: paymentAddr.publicKey,
|
|
52
|
+
type: this.inferAddressType(paymentAddr.address)
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
if (ordinalsAddr) {
|
|
56
|
+
this._ordinalsAddress = {
|
|
57
|
+
address: ordinalsAddr.address,
|
|
58
|
+
publicKey: ordinalsAddr.publicKey,
|
|
59
|
+
type: this.inferAddressType(ordinalsAddr.address)
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
await this.checkAndSwitchNetwork(network);
|
|
63
|
+
this.setupEventListeners();
|
|
64
|
+
if (!this._paymentAddress) {
|
|
65
|
+
throw new Error("No payment address found");
|
|
66
|
+
}
|
|
67
|
+
return this._paymentAddress;
|
|
68
|
+
} catch (error) {
|
|
69
|
+
this.handleError(error);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
async checkAndSwitchNetwork(network) {
|
|
73
|
+
const provider = this.getProvider();
|
|
74
|
+
if (!provider)
|
|
75
|
+
return;
|
|
76
|
+
if (network === "testnet4") {
|
|
77
|
+
try {
|
|
78
|
+
const currentNetwork = await provider.request("wallet_getNetwork", null);
|
|
79
|
+
if (currentNetwork?.result?.bitcoin?.name !== "Testnet4") {
|
|
80
|
+
await provider.request("wallet_changeNetwork", { name: "Testnet4" });
|
|
81
|
+
}
|
|
82
|
+
} catch {
|
|
83
|
+
}
|
|
84
|
+
} else if (network === "testnet") {
|
|
85
|
+
try {
|
|
86
|
+
const currentNetwork = await provider.request("wallet_getNetwork", null);
|
|
87
|
+
if (currentNetwork?.result?.bitcoin?.name !== "Testnet") {
|
|
88
|
+
await provider.request("wallet_changeNetwork", { name: "Testnet" });
|
|
89
|
+
}
|
|
90
|
+
} catch {
|
|
91
|
+
}
|
|
92
|
+
} else if (network === "mainnet") {
|
|
93
|
+
try {
|
|
94
|
+
const currentNetwork = await provider.request("wallet_getNetwork", null);
|
|
95
|
+
if (currentNetwork?.result?.bitcoin?.name !== "Mainnet") {
|
|
96
|
+
await provider.request("wallet_changeNetwork", { name: "Mainnet" });
|
|
97
|
+
}
|
|
98
|
+
} catch {
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
setupEventListeners() {
|
|
103
|
+
const provider = this.getProvider();
|
|
104
|
+
if (!provider || typeof provider.addListener !== "function")
|
|
105
|
+
return;
|
|
106
|
+
this.removeEventListeners();
|
|
107
|
+
this._removeAccountChangeListener = provider.addListener("accountChange", async () => {
|
|
108
|
+
await this.handleAccountChange();
|
|
109
|
+
});
|
|
110
|
+
this._removeNetworkChangeListener = provider.addListener("networkChange", async (event) => {
|
|
111
|
+
await this.handleNetworkChange(event);
|
|
112
|
+
});
|
|
113
|
+
this._removeDisconnectedListener = provider.addListener("accountDisconnected", () => {
|
|
114
|
+
this.emitAccountsChanged([]);
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
async handleAccountChange() {
|
|
118
|
+
const provider = this.getProvider();
|
|
119
|
+
if (!provider)
|
|
120
|
+
return;
|
|
121
|
+
try {
|
|
122
|
+
const response = await provider.request("getAddresses", {
|
|
123
|
+
purposes: ["payment" /* Payment */, "ordinals" /* Ordinals */]
|
|
124
|
+
});
|
|
125
|
+
if (!response.error && response.result?.addresses?.length) {
|
|
126
|
+
this._accounts = response.result.addresses;
|
|
127
|
+
const paymentAddr = response.result.addresses.find((a) => a.purpose === "payment" /* Payment */);
|
|
128
|
+
if (paymentAddr) {
|
|
129
|
+
this._paymentAddress = {
|
|
130
|
+
address: paymentAddr.address,
|
|
131
|
+
publicKey: paymentAddr.publicKey,
|
|
132
|
+
type: this.inferAddressType(paymentAddr.address)
|
|
133
|
+
};
|
|
134
|
+
const accounts = response.result.addresses.map((addr) => ({
|
|
135
|
+
address: addr.address,
|
|
136
|
+
publicKey: addr.publicKey,
|
|
137
|
+
type: this.inferAddressType(addr.address)
|
|
138
|
+
}));
|
|
139
|
+
this.emitAccountsChanged(accounts);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
} catch (error) {
|
|
143
|
+
console.error("Error handling account change:", error);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
async handleNetworkChange(event) {
|
|
147
|
+
if (!event.network)
|
|
148
|
+
return;
|
|
149
|
+
const networkMap = {
|
|
150
|
+
"Mainnet": "mainnet",
|
|
151
|
+
"Testnet": "testnet",
|
|
152
|
+
"Testnet4": "testnet4",
|
|
153
|
+
"Signet": "signet"
|
|
154
|
+
};
|
|
155
|
+
const mappedNetwork = networkMap[event.network] || "mainnet";
|
|
156
|
+
if (mappedNetwork !== this._network) {
|
|
157
|
+
this._network = mappedNetwork;
|
|
158
|
+
this.emitNetworkChanged(mappedNetwork);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
removeEventListeners() {
|
|
162
|
+
this._removeAccountChangeListener?.();
|
|
163
|
+
this._removeAccountChangeListener = null;
|
|
164
|
+
this._removeNetworkChangeListener?.();
|
|
165
|
+
this._removeNetworkChangeListener = null;
|
|
166
|
+
this._removeDisconnectedListener?.();
|
|
167
|
+
this._removeDisconnectedListener = null;
|
|
168
|
+
}
|
|
169
|
+
async disconnect() {
|
|
170
|
+
const provider = this.getProvider();
|
|
171
|
+
try {
|
|
172
|
+
if (provider) {
|
|
173
|
+
await provider.request("wallet_renouncePermissions", void 0);
|
|
174
|
+
}
|
|
175
|
+
} catch {
|
|
176
|
+
} finally {
|
|
177
|
+
this.removeEventListeners();
|
|
178
|
+
this._paymentAddress = null;
|
|
179
|
+
this._ordinalsAddress = null;
|
|
180
|
+
this._accounts = [];
|
|
181
|
+
this.cleanup();
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
async getAccounts() {
|
|
185
|
+
const accounts = [];
|
|
186
|
+
if (this._paymentAddress)
|
|
187
|
+
accounts.push(this._paymentAddress);
|
|
188
|
+
if (this._ordinalsAddress)
|
|
189
|
+
accounts.push(this._ordinalsAddress);
|
|
190
|
+
return accounts;
|
|
191
|
+
}
|
|
192
|
+
async signMessage(message) {
|
|
193
|
+
const provider = this.getProvider();
|
|
194
|
+
if (!provider) {
|
|
195
|
+
throw new Error("Xverse Wallet is not installed");
|
|
196
|
+
}
|
|
197
|
+
if (!this._paymentAddress) {
|
|
198
|
+
throw new Error("Not connected");
|
|
199
|
+
}
|
|
200
|
+
try {
|
|
201
|
+
const response = await provider.request("signMessage", {
|
|
202
|
+
address: this._paymentAddress.address,
|
|
203
|
+
message
|
|
204
|
+
});
|
|
205
|
+
if (response.error) {
|
|
206
|
+
throw response.error;
|
|
207
|
+
}
|
|
208
|
+
return response.result.signature;
|
|
209
|
+
} catch (error) {
|
|
210
|
+
this.handleError(error);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
async signPsbt(psbtHex, options) {
|
|
214
|
+
const provider = this.getProvider();
|
|
215
|
+
if (!provider) {
|
|
216
|
+
throw new Error("Xverse Wallet is not installed");
|
|
217
|
+
}
|
|
218
|
+
if (!this._paymentAddress) {
|
|
219
|
+
throw new Error("Not connected");
|
|
220
|
+
}
|
|
221
|
+
try {
|
|
222
|
+
const psbtBase64 = Buffer.from(psbtHex, "hex").toString("base64");
|
|
223
|
+
const signInputs = {};
|
|
224
|
+
const allAddresses = this._accounts.map((a) => a.address);
|
|
225
|
+
if (options?.toSignInputs && options.toSignInputs.length > 0) {
|
|
226
|
+
for (const input of options.toSignInputs) {
|
|
227
|
+
const addr = input.address && allAddresses.includes(input.address) ? input.address : this._paymentAddress.address;
|
|
228
|
+
if (!signInputs[addr]) {
|
|
229
|
+
signInputs[addr] = [];
|
|
230
|
+
}
|
|
231
|
+
signInputs[addr].push(input.index);
|
|
232
|
+
}
|
|
233
|
+
if (Object.keys(signInputs).length === 0) {
|
|
234
|
+
signInputs[this._paymentAddress.address] = options.toSignInputs.map((i) => i.index);
|
|
235
|
+
}
|
|
236
|
+
} else {
|
|
237
|
+
signInputs[this._paymentAddress.address] = [0];
|
|
238
|
+
}
|
|
239
|
+
const response = await provider.request("signPsbt", {
|
|
240
|
+
psbt: psbtBase64,
|
|
241
|
+
signInputs,
|
|
242
|
+
broadcast: options?.broadcast ?? false,
|
|
243
|
+
allowedSignHash: options?.toSignInputs?.[0]?.sighashTypes?.[0]
|
|
244
|
+
});
|
|
245
|
+
if (response.error) {
|
|
246
|
+
throw response.error;
|
|
247
|
+
}
|
|
248
|
+
if (response.result.txid) {
|
|
249
|
+
return response.result.txid;
|
|
250
|
+
}
|
|
251
|
+
return Buffer.from(response.result.psbt, "base64").toString("hex");
|
|
252
|
+
} catch (error) {
|
|
253
|
+
this.handleError(error);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
async sendTransaction(to, satoshis) {
|
|
257
|
+
const provider = this.getProvider();
|
|
258
|
+
if (!provider) {
|
|
259
|
+
throw new Error("Xverse Wallet is not installed");
|
|
260
|
+
}
|
|
261
|
+
if (!this._paymentAddress) {
|
|
262
|
+
throw new Error("Not connected");
|
|
263
|
+
}
|
|
264
|
+
try {
|
|
265
|
+
const response = await provider.request("sendTransfer", {
|
|
266
|
+
recipients: [
|
|
267
|
+
{
|
|
268
|
+
address: to,
|
|
269
|
+
amount: satoshis
|
|
270
|
+
}
|
|
271
|
+
]
|
|
272
|
+
});
|
|
273
|
+
if (response.error) {
|
|
274
|
+
throw response.error;
|
|
275
|
+
}
|
|
276
|
+
if (!response.result.txid) {
|
|
277
|
+
throw new Error("No transaction ID received");
|
|
278
|
+
}
|
|
279
|
+
return response.result.txid;
|
|
280
|
+
} catch (error) {
|
|
281
|
+
this.handleError(error);
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
async getNetwork() {
|
|
285
|
+
return this._network;
|
|
286
|
+
}
|
|
287
|
+
async switchNetwork(network) {
|
|
288
|
+
await this.checkAndSwitchNetwork(network);
|
|
289
|
+
this._network = network;
|
|
290
|
+
this.emitNetworkChanged(network);
|
|
291
|
+
}
|
|
292
|
+
/**
|
|
293
|
+
* Get the ordinals address (if available)
|
|
294
|
+
*/
|
|
295
|
+
getOrdinalsAddress() {
|
|
296
|
+
return this._ordinalsAddress;
|
|
297
|
+
}
|
|
298
|
+
/**
|
|
299
|
+
* Get the payment address
|
|
300
|
+
*/
|
|
301
|
+
getPaymentAddress() {
|
|
302
|
+
return this._paymentAddress;
|
|
303
|
+
}
|
|
304
|
+
/**
|
|
305
|
+
* Get all connected addresses (for multi-address support)
|
|
306
|
+
*/
|
|
307
|
+
getAllAddresses() {
|
|
308
|
+
return this._accounts.map((acc) => acc.address);
|
|
309
|
+
}
|
|
310
|
+
/**
|
|
311
|
+
* Switch to a specific address within the connected accounts
|
|
312
|
+
*/
|
|
313
|
+
switchWalletAddress(address) {
|
|
314
|
+
const account = this._accounts.find((a) => a.address === address);
|
|
315
|
+
if (account) {
|
|
316
|
+
if (account.purpose === "payment" /* Payment */) {
|
|
317
|
+
this._paymentAddress = {
|
|
318
|
+
address: account.address,
|
|
319
|
+
publicKey: account.publicKey,
|
|
320
|
+
type: this.inferAddressType(account.address)
|
|
321
|
+
};
|
|
322
|
+
}
|
|
323
|
+
return true;
|
|
324
|
+
}
|
|
325
|
+
return false;
|
|
326
|
+
}
|
|
327
|
+
};
|
|
328
|
+
|
|
329
|
+
exports.XverseConnector = XverseConnector;
|
|
330
|
+
//# sourceMappingURL=out.js.map
|
|
331
|
+
//# sourceMappingURL=chunk-EIJOSZXZ.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/xverse/XverseConnector.ts"],"names":[],"mappings":";;;;;AA2EA,IAAM,cACJ;AAQK,IAAM,kBAAN,cAA8B,cAAc;AAAA,EAA5C;AAAA;AACL,SAAS,KAAK;AACd,SAAS,OAAO;AAChB,SAAS,OAAO;AAEhB,SAAQ,kBAAwC;AAChD,SAAQ,mBAAyC;AACjD,SAAQ,WAA2B;AACnC,SAAQ,YAA+B,CAAC;AACxC,SAAQ,+BAAoD;AAC5D,SAAQ,+BAAoD;AAC5D,SAAQ,8BAAmD;AAAA;AAAA,EAEjD,cAAiD;AACzD,QAAI,OAAO,WAAW;AAAa,aAAO;AAC1C,WAAO,OAAO,iBAAiB;AAAA,EACjC;AAAA,EAEA,MAAM,QAAQ,UAA0B,WAAmC;AACzE,UAAM,WAAW,KAAK,YAAY;AAClC,QAAI,CAAC,UAAU;AACb,WAAK,YAAY,IAAI,MAAM,gCAAgC,CAAC;AAAA,IAC9D;AAEA,QAAI;AACF,WAAK,WAAW;AAGhB,YAAM,qBAAqB,MAAM,SAAU,QAAiB,6BAA6B,MAAS;AAClG,UAAI,mBAAmB,OAAO;AAC5B,cAAM,IAAI,MAAM,mBAAmB,MAAM,OAAO;AAAA,MAClD;AAGA,YAAM,WAAW,MAAM,SAAU,QAA4B,gBAAgB;AAAA,QAC3E,UAAU,CAAC,yBAAwB,yBAAuB;AAAA,QAC1D,SAAS;AAAA,MACX,CAAC;AAED,UAAI,SAAS,OAAO;AAClB,cAAM,SAAS;AAAA,MACjB;AAEA,YAAM,YAAY,SAAS,OAAO;AAClC,WAAK,YAAY;AAEjB,YAAM,cAAc,UAAU,KAAK,CAAC,MAAM,EAAE,YAAY,uBAAsB;AAC9E,YAAM,eAAe,UAAU,KAAK,CAAC,MAAM,EAAE,YAAY,yBAAuB;AAEhF,UAAI,aAAa;AACf,aAAK,kBAAkB;AAAA,UACrB,SAAS,YAAY;AAAA,UACrB,WAAW,YAAY;AAAA,UACvB,MAAM,KAAK,iBAAiB,YAAY,OAAO;AAAA,QACjD;AAAA,MACF;AAEA,UAAI,cAAc;AAChB,aAAK,mBAAmB;AAAA,UACtB,SAAS,aAAa;AAAA,UACtB,WAAW,aAAa;AAAA,UACxB,MAAM,KAAK,iBAAiB,aAAa,OAAO;AAAA,QAClD;AAAA,MACF;AAGA,YAAM,KAAK,sBAAsB,OAAO;AAGxC,WAAK,oBAAoB;AAEzB,UAAI,CAAC,KAAK,iBAAiB;AACzB,cAAM,IAAI,MAAM,0BAA0B;AAAA,MAC5C;AAEA,aAAO,KAAK;AAAA,IACd,SAAS,OAAO;AACd,WAAK,YAAY,KAAK;AAAA,IACxB;AAAA,EACF;AAAA,EAEA,MAAc,sBAAsB,SAAwC;AAC1E,UAAM,WAAW,KAAK,YAAY;AAClC,QAAI,CAAC;AAAU;AAGf,QAAI,YAAY,YAAY;AAC1B,UAAI;AACF,cAAM,iBAAiB,MAAM,SAAS,QAAuB,qBAAqB,IAAI;AACtF,YAAI,gBAAgB,QAAQ,SAAS,SAAS,YAAY;AACxD,gBAAM,SAAS,QAAiB,wBAAwB,EAAE,MAAM,WAAW,CAAC;AAAA,QAC9E;AAAA,MACF,QAAQ;AAAA,MAER;AAAA,IACF,WAAW,YAAY,WAAW;AAChC,UAAI;AACF,cAAM,iBAAiB,MAAM,SAAS,QAAuB,qBAAqB,IAAI;AACtF,YAAI,gBAAgB,QAAQ,SAAS,SAAS,WAAW;AACvD,gBAAM,SAAS,QAAiB,wBAAwB,EAAE,MAAM,UAAU,CAAC;AAAA,QAC7E;AAAA,MACF,QAAQ;AAAA,MAER;AAAA,IACF,WAAW,YAAY,WAAW;AAChC,UAAI;AACF,cAAM,iBAAiB,MAAM,SAAS,QAAuB,qBAAqB,IAAI;AACtF,YAAI,gBAAgB,QAAQ,SAAS,SAAS,WAAW;AACvD,gBAAM,SAAS,QAAiB,wBAAwB,EAAE,MAAM,UAAU,CAAC;AAAA,QAC7E;AAAA,MACF,QAAQ;AAAA,MAER;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,sBAA4B;AAClC,UAAM,WAAW,KAAK,YAAY;AAClC,QAAI,CAAC,YAAY,OAAO,SAAS,gBAAgB;AAAY;AAG7D,SAAK,qBAAqB;AAG1B,SAAK,+BAA+B,SAAS,YAAY,iBAAiB,YAAY;AACpF,YAAM,KAAK,oBAAoB;AAAA,IACjC,CAAC;AAGD,SAAK,+BAA+B,SAAS,YAAY,iBAAiB,OAAO,UAAU;AACzF,YAAM,KAAK,oBAAoB,KAAK;AAAA,IACtC,CAAC;AAGD,SAAK,8BAA8B,SAAS,YAAY,uBAAuB,MAAM;AACnF,WAAK,oBAAoB,CAAC,CAAC;AAAA,IAC7B,CAAC;AAAA,EACH;AAAA,EAEA,MAAc,sBAAqC;AACjD,UAAM,WAAW,KAAK,YAAY;AAClC,QAAI,CAAC;AAAU;AAEf,QAAI;AACF,YAAM,WAAW,MAAM,SAAS,QAA4B,gBAAgB;AAAA,QAC1E,UAAU,CAAC,yBAAwB,yBAAuB;AAAA,MAC5D,CAAC;AAED,UAAI,CAAC,SAAS,SAAS,SAAS,QAAQ,WAAW,QAAQ;AACzD,aAAK,YAAY,SAAS,OAAO;AACjC,cAAM,cAAc,SAAS,OAAO,UAAU,KAAK,CAAC,MAAM,EAAE,YAAY,uBAAsB;AAE9F,YAAI,aAAa;AACf,eAAK,kBAAkB;AAAA,YACrB,SAAS,YAAY;AAAA,YACrB,WAAW,YAAY;AAAA,YACvB,MAAM,KAAK,iBAAiB,YAAY,OAAO;AAAA,UACjD;AAEA,gBAAM,WAA4B,SAAS,OAAO,UAAU,IAAI,CAAC,UAAU;AAAA,YACzE,SAAS,KAAK;AAAA,YACd,WAAW,KAAK;AAAA,YAChB,MAAM,KAAK,iBAAiB,KAAK,OAAO;AAAA,UAC1C,EAAE;AAEF,eAAK,oBAAoB,QAAQ;AAAA,QACnC;AAAA,MACF;AAAA,IACF,SAAS,OAAO;AACd,cAAQ,MAAM,kCAAkC,KAAK;AAAA,IACvD;AAAA,EACF;AAAA,EAEA,MAAc,oBAAoB,OAAuC;AACvE,QAAI,CAAC,MAAM;AAAS;AAEpB,UAAM,aAA6C;AAAA,MACjD,WAAW;AAAA,MACX,WAAW;AAAA,MACX,YAAY;AAAA,MACZ,UAAU;AAAA,IACZ;AAEA,UAAM,gBAAgB,WAAW,MAAM,OAAO,KAAK;AACnD,QAAI,kBAAkB,KAAK,UAAU;AACnC,WAAK,WAAW;AAChB,WAAK,mBAAmB,aAAa;AAAA,IACvC;AAAA,EACF;AAAA,EAEQ,uBAA6B;AACnC,SAAK,+BAA+B;AACpC,SAAK,+BAA+B;AAEpC,SAAK,+BAA+B;AACpC,SAAK,+BAA+B;AAEpC,SAAK,8BAA8B;AACnC,SAAK,8BAA8B;AAAA,EACrC;AAAA,EAEA,MAAM,aAA4B;AAChC,UAAM,WAAW,KAAK,YAAY;AAElC,QAAI;AACF,UAAI,UAAU;AACZ,cAAM,SAAS,QAAiB,8BAA8B,MAAS;AAAA,MACzE;AAAA,IACF,QAAQ;AAAA,IAER,UAAE;AACA,WAAK,qBAAqB;AAC1B,WAAK,kBAAkB;AACvB,WAAK,mBAAmB;AACxB,WAAK,YAAY,CAAC;AAClB,WAAK,QAAQ;AAAA,IACf;AAAA,EACF;AAAA,EAEA,MAAM,cAAwC;AAC5C,UAAM,WAA4B,CAAC;AACnC,QAAI,KAAK;AAAiB,eAAS,KAAK,KAAK,eAAe;AAC5D,QAAI,KAAK;AAAkB,eAAS,KAAK,KAAK,gBAAgB;AAC9D,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,YAAY,SAAkC;AAClD,UAAM,WAAW,KAAK,YAAY;AAClC,QAAI,CAAC,UAAU;AACb,YAAM,IAAI,MAAM,gCAAgC;AAAA,IAClD;AACA,QAAI,CAAC,KAAK,iBAAiB;AACzB,YAAM,IAAI,MAAM,eAAe;AAAA,IACjC;AAEA,QAAI;AACF,YAAM,WAAW,MAAM,SAAS,QAA2B,eAAe;AAAA,QACxE,SAAS,KAAK,gBAAgB;AAAA,QAC9B;AAAA,MACF,CAAC;AAED,UAAI,SAAS,OAAO;AAClB,cAAM,SAAS;AAAA,MACjB;AAEA,aAAO,SAAS,OAAO;AAAA,IACzB,SAAS,OAAO;AACd,WAAK,YAAY,KAAK;AAAA,IACxB;AAAA,EACF;AAAA,EAEA,MAAM,SAAS,SAAiB,SAA4C;AAC1E,UAAM,WAAW,KAAK,YAAY;AAClC,QAAI,CAAC,UAAU;AACb,YAAM,IAAI,MAAM,gCAAgC;AAAA,IAClD;AAEA,QAAI,CAAC,KAAK,iBAAiB;AACzB,YAAM,IAAI,MAAM,eAAe;AAAA,IACjC;AAEA,QAAI;AAEF,YAAM,aAAa,OAAO,KAAK,SAAS,KAAK,EAAE,SAAS,QAAQ;AAGhE,YAAM,aAAuC,CAAC;AAC9C,YAAM,eAAe,KAAK,UAAU,IAAI,CAAC,MAAM,EAAE,OAAO;AAExD,UAAI,SAAS,gBAAgB,QAAQ,aAAa,SAAS,GAAG;AAC5D,mBAAW,SAAS,QAAQ,cAAc;AACxC,gBAAM,OAAO,MAAM,WAAW,aAAa,SAAS,MAAM,OAAO,IAC7D,MAAM,UACN,KAAK,gBAAgB;AAEzB,cAAI,CAAC,WAAW,IAAI,GAAG;AACrB,uBAAW,IAAI,IAAI,CAAC;AAAA,UACtB;AACA,qBAAW,IAAI,EAAG,KAAK,MAAM,KAAK;AAAA,QACpC;AAGA,YAAI,OAAO,KAAK,UAAU,EAAE,WAAW,GAAG;AACxC,qBAAW,KAAK,gBAAgB,OAAO,IAAI,QAAQ,aAAa,IAAI,CAAC,MAAM,EAAE,KAAK;AAAA,QACpF;AAAA,MACF,OAAO;AAEL,mBAAW,KAAK,gBAAgB,OAAO,IAAI,CAAC,CAAC;AAAA,MAC/C;AAEA,YAAM,WAAW,MAAM,SAAS,QAAwB,YAAY;AAAA,QAClE,MAAM;AAAA,QACN;AAAA,QACA,WAAW,SAAS,aAAa;AAAA,QACjC,iBAAiB,SAAS,eAAe,CAAC,GAAG,eAAe,CAAC;AAAA,MAC/D,CAAC;AACD,UAAI,SAAS,OAAO;AAClB,cAAM,SAAS;AAAA,MACjB;AAGA,UAAI,SAAS,OAAO,MAAM;AACxB,eAAO,SAAS,OAAO;AAAA,MACzB;AAGA,aAAO,OAAO,KAAK,SAAS,OAAO,MAAM,QAAQ,EAAE,SAAS,KAAK;AAAA,IACnE,SAAS,OAAO;AACd,WAAK,YAAY,KAAK;AAAA,IACxB;AAAA,EACF;AAAA,EAEA,MAAM,gBAAgB,IAAY,UAAmC;AACnE,UAAM,WAAW,KAAK,YAAY;AAClC,QAAI,CAAC,UAAU;AACb,YAAM,IAAI,MAAM,gCAAgC;AAAA,IAClD;AAEA,QAAI,CAAC,KAAK,iBAAiB;AACzB,YAAM,IAAI,MAAM,eAAe;AAAA,IACjC;AAEA,QAAI;AACF,YAAM,WAAW,MAAM,SAAS,QAA4B,gBAAgB;AAAA,QAC1E,YAAY;AAAA,UACV;AAAA,YACE,SAAS;AAAA,YACT,QAAQ;AAAA,UACV;AAAA,QACF;AAAA,MACF,CAAC;AAED,UAAI,SAAS,OAAO;AAClB,cAAM,SAAS;AAAA,MACjB;AAEA,UAAI,CAAC,SAAS,OAAO,MAAM;AACzB,cAAM,IAAI,MAAM,4BAA4B;AAAA,MAC9C;AAEA,aAAO,SAAS,OAAO;AAAA,IACzB,SAAS,OAAO;AACd,WAAK,YAAY,KAAK;AAAA,IACxB;AAAA,EACF;AAAA,EAEA,MAAM,aAAsC;AAC1C,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,MAAM,cAAc,SAAwC;AAC1D,UAAM,KAAK,sBAAsB,OAAO;AACxC,SAAK,WAAW;AAChB,SAAK,mBAAmB,OAAO;AAAA,EACjC;AAAA;AAAA;AAAA;AAAA,EAKA,qBAA2C;AACzC,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA,EAKA,oBAA0C;AACxC,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA,EAKA,kBAA4B;AAC1B,WAAO,KAAK,UAAU,IAAI,CAAC,QAAQ,IAAI,OAAO;AAAA,EAChD;AAAA;AAAA;AAAA;AAAA,EAKA,oBAAoB,SAA0B;AAC5C,UAAM,UAAU,KAAK,UAAU,KAAK,CAAC,MAAM,EAAE,YAAY,OAAO;AAChE,QAAI,SAAS;AACX,UAAI,QAAQ,YAAY,yBAAwB;AAC9C,aAAK,kBAAkB;AAAA,UACrB,SAAS,QAAQ;AAAA,UACjB,WAAW,QAAQ;AAAA,UACnB,MAAM,KAAK,iBAAiB,QAAQ,OAAO;AAAA,QAC7C;AAAA,MACF;AACA,aAAO;AAAA,IACT;AACA,WAAO;AAAA,EACT;AACF","sourcesContent":["import type {\n WalletAccount,\n BitcoinNetwork,\n SignPsbtOptions,\n} from 'otx-btc-wallet-core';\nimport { BaseConnector } from '../base';\n\n/**\n * Address purpose enum for Xverse\n */\nenum AddressPurpose {\n Payment = 'payment',\n Ordinals = 'ordinals',\n}\n\n/**\n * Xverse address response\n */\ninterface AddressResponse {\n address: string;\n publicKey: string;\n purpose: AddressPurpose;\n}\n\n/**\n * Xverse Provider request/response types\n */\ninterface XverseRequestResponse<T> {\n result: T;\n error?: { message: string };\n}\n\ninterface GetAddressesResult {\n addresses: AddressResponse[];\n}\n\ninterface SignMessageResult {\n signature: string;\n}\n\ninterface SignPsbtResult {\n psbt: string;\n txid?: string;\n}\n\ninterface SendTransferResult {\n txid: string;\n}\n\ninterface NetworkResult {\n bitcoin?: { name: string };\n}\n\ninterface XverseEventData {\n network?: string;\n}\n\n/**\n * Xverse Bitcoin Provider interface\n */\ninterface XverseBitcoinProvider {\n request<T>(method: string, params: unknown): Promise<XverseRequestResponse<T>>;\n addListener(event: string, callback: (data: XverseEventData) => void): () => void;\n}\n\n// Extend window type\ndeclare global {\n interface Window {\n XverseProviders?: {\n BitcoinProvider?: XverseBitcoinProvider;\n };\n }\n}\n\n// Xverse wallet icon\nconst XVERSE_ICON =\n 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjAwIiBoZWlnaHQ9IjIwMCIgdmlld0JveD0iMCAwIDIwMCAyMDAiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMF83MDM3XzEwMykiPgo8cGF0aCBkPSJNMjAwIDBIMFYyMDBIMjAwVjBaIiBmaWxsPSJ1cmwoI3BhaW50MF9saW5lYXJfNzAzN18xMDMpIi8+CjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMV83MDM3XzEwMykiPgo8cGF0aCBkPSJNMTU5LjM2NyAxNTcuNDQ1VjEzNS43MThDMTU5LjM2NyAxMzQuODU2IDE1OS4wMjUgMTM0LjAzNCAxNTguNDE0IDEzMy40MjRMNjUuOTY2NCA0MC45NzU2QzY1LjM1NTkgNDAuMzY1MSA2NC41MzQyIDQwLjAyMjggNjMuNjcyNiA0MC4wMjI4SDQxLjk0NTZDNDAuODczIDQwLjAyMjggNDAgNDAuODk1NyA0MCA0MS45Njg0VjYyLjE1NDlDNDAgNjMuMDE2NSA0MC4zNDIzIDYzLjgzOCA0MC45NTI4IDY0LjQ0ODZMNzQuMTM2OCA5Ny42MzI0Qzc0Ljg5NTYgOTguMzkxNiA3NC44OTU2IDk5LjYyNCA3NC4xMzY4IDEwMC4zODNMNDAuNTcwNiAxMzMuOTQ5QzQwLjIwNTQgMTM0LjMxNCA0MCAxMzQuODEgNDAgMTM1LjMyNFYxNTcuNDQ1QzQwIDE1OC41MTcgNDAuODczIDE1OS4zOTEgNDEuOTQ1NiAxNTkuMzkxSDc4LjI1MDVDNzkuMzIzMiAxNTkuMzkxIDgwLjE5NiAxNTguNTE3IDgwLjE5NiAxNTcuNDQ1VjE0NC40MTNDODAuMTk2IDE0My45IDgwLjQwMTYgMTQzLjQwMyA4MC43NjY4IDE0My4wMzhMOTguNzczNiAxMjUuMDMxQzk5LjUzMjQgMTI0LjI3MiAxMDAuNzY1IDEyNC4yNzIgMTAxLjUyNCAxMjUuMDMxTDEzNC45MzYgMTU4LjQ0NEMxMzUuNTQ2IDE1OS4wNTQgMTM2LjM2OCAxNTkuMzk2IDEzNy4yMyAxNTkuMzk2SDE1Ny40MTZDMTU4LjQ4OSAxNTkuMzk2IDE1OS4zNjIgMTU4LjUyMyAxNTkuMzYyIDE1Ny40NTFMMTU5LjM2NyAxNTcuNDQ1WiIgZmlsbD0id2hpdGUiLz4KPHBhdGggZD0iTTExMC45MzggNjguNzk2SDEyOS4xMjJDMTMwLjIgNjguNzk2IDEzMS4wNzkgNjkuNjc0NyAxMzEuMDc5IDcwLjc1MzFWODguOTM2OEMxMzEuMDc5IDkwLjY4MjggMTMzLjE5IDkxLjU1NiAxMzQuNDIyIDkwLjMxNzZMMTU5LjM2NyA2NS4zMzI4QzE1OS43MzIgNjQuOTY3NiAxNTkuOTM4IDY0LjQ3MTMgMTU5LjkzOCA2My45NTJWNDIuMDcwOUMxNTkuOTM4IDQwLjk5MjUgMTU5LjA2NCA0MC4xMTM5IDE1Ny45ODEgNDAuMTEzOUwxMzUuNzc0IDQwLjA4NTRDMTM1LjI1NiA0MC4wODU0IDEzNC43NTkgNDAuMjkwOCAxMzQuMzg4IDQwLjY1NTlMMTA5LjU1MiA2NS40NTI2QzEwOC4zMTkgNjYuNjg1IDEwOS4xOTIgNjguNzk2IDExMC45MzIgNjguNzk2SDExMC45MzhaIiBmaWxsPSIjRUU3QTMwIi8+CjwvZz4KPC9nPgo8ZGVmcz4KPGxpbmVhckdyYWRpZW50IGlkPSJwYWludDBfbGluZWFyXzcwMzdfMTAzIiB4MT0iMTAwIiB5MT0iMCIgeDI9IjEwMCIgeTI9IjIwMCIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiPgo8c3RvcCBzdG9wLWNvbG9yPSIjMEYwRjBGIi8+CjxzdG9wIG9mZnNldD0iMSIgc3RvcC1jb2xvcj0iIzE4MTgxOCIvPgo8L2xpbmVhckdyYWRpZW50Pgo8Y2xpcFBhdGggaWQ9ImNsaXAwXzcwMzdfMTAzIj4KPHJlY3Qgd2lkdGg9IjIwMCIgaGVpZ2h0PSIyMDAiIHJ4PSIzNS41NTU2IiBmaWxsPSJ3aGl0ZSIvPgo8L2NsaXBQYXRoPgo8Y2xpcFBhdGggaWQ9ImNsaXAxXzcwMzdfMTAzIj4KPHJlY3Qgd2lkdGg9IjEyMCIgaGVpZ2h0PSIxMjAiIGZpbGw9IndoaXRlIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSg0MCA0MCkiLz4KPC9jbGlwUGF0aD4KPC9kZWZzPgo8L3N2Zz4K';\n\n/**\n * Xverse Wallet Connector\n * Uses the native Xverse Provider API\n *\n * @see https://docs.xverse.app/\n */\nexport class XverseConnector extends BaseConnector {\n readonly id = 'xverse';\n readonly name = 'Xverse Wallet';\n readonly icon = XVERSE_ICON;\n\n private _paymentAddress: WalletAccount | null = null;\n private _ordinalsAddress: WalletAccount | null = null;\n private _network: BitcoinNetwork = 'mainnet';\n private _accounts: AddressResponse[] = [];\n private _removeAccountChangeListener: (() => void) | null = null;\n private _removeNetworkChangeListener: (() => void) | null = null;\n private _removeDisconnectedListener: (() => void) | null = null;\n\n protected getProvider(): XverseBitcoinProvider | undefined {\n if (typeof window === 'undefined') return undefined;\n return window.XverseProviders?.BitcoinProvider;\n }\n\n async connect(network: BitcoinNetwork = 'mainnet'): Promise<WalletAccount> {\n const provider = this.getProvider();\n if (!provider) {\n this.handleError(new Error('Xverse Wallet is not installed'));\n }\n\n try {\n this._network = network;\n\n // Request permissions first\n const permissionResponse = await provider!.request<unknown>('wallet_requestPermissions', undefined);\n if (permissionResponse.error) {\n throw new Error(permissionResponse.error.message);\n }\n\n // Get addresses\n const response = await provider!.request<GetAddressesResult>('getAddresses', {\n purposes: [AddressPurpose.Payment, AddressPurpose.Ordinals],\n message: 'Connect to application',\n });\n\n if (response.error) {\n throw response.error;\n }\n\n const addresses = response.result.addresses;\n this._accounts = addresses;\n\n const paymentAddr = addresses.find((a) => a.purpose === AddressPurpose.Payment);\n const ordinalsAddr = addresses.find((a) => a.purpose === AddressPurpose.Ordinals);\n\n if (paymentAddr) {\n this._paymentAddress = {\n address: paymentAddr.address,\n publicKey: paymentAddr.publicKey,\n type: this.inferAddressType(paymentAddr.address),\n };\n }\n\n if (ordinalsAddr) {\n this._ordinalsAddress = {\n address: ordinalsAddr.address,\n publicKey: ordinalsAddr.publicKey,\n type: this.inferAddressType(ordinalsAddr.address),\n };\n }\n\n // Check and switch network if needed\n await this.checkAndSwitchNetwork(network);\n\n // Setup event listeners\n this.setupEventListeners();\n\n if (!this._paymentAddress) {\n throw new Error('No payment address found');\n }\n\n return this._paymentAddress;\n } catch (error) {\n this.handleError(error);\n }\n }\n\n private async checkAndSwitchNetwork(network: BitcoinNetwork): Promise<void> {\n const provider = this.getProvider();\n if (!provider) return;\n\n // For testnet4, we need to switch to Testnet4 network in Xverse\n if (network === 'testnet4') {\n try {\n const currentNetwork = await provider.request<NetworkResult>('wallet_getNetwork', null);\n if (currentNetwork?.result?.bitcoin?.name !== 'Testnet4') {\n await provider.request<unknown>('wallet_changeNetwork', { name: 'Testnet4' });\n }\n } catch {\n // Network switch may not be supported, continue anyway\n }\n } else if (network === 'testnet') {\n try {\n const currentNetwork = await provider.request<NetworkResult>('wallet_getNetwork', null);\n if (currentNetwork?.result?.bitcoin?.name !== 'Testnet') {\n await provider.request<unknown>('wallet_changeNetwork', { name: 'Testnet' });\n }\n } catch {\n // Network switch may not be supported\n }\n } else if (network === 'mainnet') {\n try {\n const currentNetwork = await provider.request<NetworkResult>('wallet_getNetwork', null);\n if (currentNetwork?.result?.bitcoin?.name !== 'Mainnet') {\n await provider.request<unknown>('wallet_changeNetwork', { name: 'Mainnet' });\n }\n } catch {\n // Network switch may not be supported\n }\n }\n }\n\n private setupEventListeners(): void {\n const provider = this.getProvider();\n if (!provider || typeof provider.addListener !== 'function') return;\n\n // Remove existing listeners\n this.removeEventListeners();\n\n // Account change listener\n this._removeAccountChangeListener = provider.addListener('accountChange', async () => {\n await this.handleAccountChange();\n });\n\n // Network change listener\n this._removeNetworkChangeListener = provider.addListener('networkChange', async (event) => {\n await this.handleNetworkChange(event);\n });\n\n // Disconnected listener\n this._removeDisconnectedListener = provider.addListener('accountDisconnected', () => {\n this.emitAccountsChanged([]);\n });\n }\n\n private async handleAccountChange(): Promise<void> {\n const provider = this.getProvider();\n if (!provider) return;\n\n try {\n const response = await provider.request<GetAddressesResult>('getAddresses', {\n purposes: [AddressPurpose.Payment, AddressPurpose.Ordinals],\n });\n\n if (!response.error && response.result?.addresses?.length) {\n this._accounts = response.result.addresses;\n const paymentAddr = response.result.addresses.find((a) => a.purpose === AddressPurpose.Payment);\n\n if (paymentAddr) {\n this._paymentAddress = {\n address: paymentAddr.address,\n publicKey: paymentAddr.publicKey,\n type: this.inferAddressType(paymentAddr.address),\n };\n\n const accounts: WalletAccount[] = response.result.addresses.map((addr) => ({\n address: addr.address,\n publicKey: addr.publicKey,\n type: this.inferAddressType(addr.address),\n }));\n\n this.emitAccountsChanged(accounts);\n }\n }\n } catch (error) {\n console.error('Error handling account change:', error);\n }\n }\n\n private async handleNetworkChange(event: XverseEventData): Promise<void> {\n if (!event.network) return;\n\n const networkMap: Record<string, BitcoinNetwork> = {\n 'Mainnet': 'mainnet',\n 'Testnet': 'testnet',\n 'Testnet4': 'testnet4',\n 'Signet': 'signet',\n };\n\n const mappedNetwork = networkMap[event.network] || 'mainnet';\n if (mappedNetwork !== this._network) {\n this._network = mappedNetwork;\n this.emitNetworkChanged(mappedNetwork);\n }\n }\n\n private removeEventListeners(): void {\n this._removeAccountChangeListener?.();\n this._removeAccountChangeListener = null;\n\n this._removeNetworkChangeListener?.();\n this._removeNetworkChangeListener = null;\n\n this._removeDisconnectedListener?.();\n this._removeDisconnectedListener = null;\n }\n\n async disconnect(): Promise<void> {\n const provider = this.getProvider();\n\n try {\n if (provider) {\n await provider.request<unknown>('wallet_renouncePermissions', undefined);\n }\n } catch {\n // Ignore disconnect errors\n } finally {\n this.removeEventListeners();\n this._paymentAddress = null;\n this._ordinalsAddress = null;\n this._accounts = [];\n this.cleanup();\n }\n }\n\n async getAccounts(): Promise<WalletAccount[]> {\n const accounts: WalletAccount[] = [];\n if (this._paymentAddress) accounts.push(this._paymentAddress);\n if (this._ordinalsAddress) accounts.push(this._ordinalsAddress);\n return accounts;\n }\n\n async signMessage(message: string): Promise<string> {\n const provider = this.getProvider();\n if (!provider) {\n throw new Error('Xverse Wallet is not installed');\n }\n if (!this._paymentAddress) {\n throw new Error('Not connected');\n }\n\n try {\n const response = await provider.request<SignMessageResult>('signMessage', {\n address: this._paymentAddress.address,\n message,\n });\n\n if (response.error) {\n throw response.error;\n }\n\n return response.result.signature;\n } catch (error) {\n this.handleError(error);\n }\n }\n\n async signPsbt(psbtHex: string, options?: SignPsbtOptions): Promise<string> {\n const provider = this.getProvider();\n if (!provider) {\n throw new Error('Xverse Wallet is not installed');\n }\n\n if (!this._paymentAddress) {\n throw new Error('Not connected');\n }\n\n try {\n // Convert hex to base64 for Xverse\n const psbtBase64 = Buffer.from(psbtHex, 'hex').toString('base64');\n\n // Build signInputs map\n const signInputs: Record<string, number[]> = {};\n const allAddresses = this._accounts.map((a) => a.address);\n\n if (options?.toSignInputs && options.toSignInputs.length > 0) {\n for (const input of options.toSignInputs) {\n const addr = input.address && allAddresses.includes(input.address)\n ? input.address\n : this._paymentAddress.address;\n\n if (!signInputs[addr]) {\n signInputs[addr] = [];\n }\n signInputs[addr]!.push(input.index);\n }\n\n // If no matching addresses found, use payment address\n if (Object.keys(signInputs).length === 0) {\n signInputs[this._paymentAddress.address] = options.toSignInputs.map((i) => i.index);\n }\n } else {\n // Default: sign all inputs with payment address\n signInputs[this._paymentAddress.address] = [0];\n }\n\n const response = await provider.request<SignPsbtResult>('signPsbt', {\n psbt: psbtBase64,\n signInputs,\n broadcast: options?.broadcast ?? false,\n allowedSignHash: options?.toSignInputs?.[0]?.sighashTypes?.[0],\n });\n if (response.error) {\n throw response.error;\n }\n\n // Return txid if broadcast, otherwise return signed psbt as hex\n if (response.result.txid) {\n return response.result.txid;\n }\n\n // Convert base64 back to hex\n return Buffer.from(response.result.psbt, 'base64').toString('hex');\n } catch (error) {\n this.handleError(error);\n }\n }\n\n async sendTransaction(to: string, satoshis: number): Promise<string> {\n const provider = this.getProvider();\n if (!provider) {\n throw new Error('Xverse Wallet is not installed');\n }\n\n if (!this._paymentAddress) {\n throw new Error('Not connected');\n }\n\n try {\n const response = await provider.request<SendTransferResult>('sendTransfer', {\n recipients: [\n {\n address: to,\n amount: satoshis,\n },\n ],\n });\n\n if (response.error) {\n throw response.error;\n }\n\n if (!response.result.txid) {\n throw new Error('No transaction ID received');\n }\n\n return response.result.txid;\n } catch (error) {\n this.handleError(error);\n }\n }\n\n async getNetwork(): Promise<BitcoinNetwork> {\n return this._network;\n }\n\n async switchNetwork(network: BitcoinNetwork): Promise<void> {\n await this.checkAndSwitchNetwork(network);\n this._network = network;\n this.emitNetworkChanged(network);\n }\n\n /**\n * Get the ordinals address (if available)\n */\n getOrdinalsAddress(): WalletAccount | null {\n return this._ordinalsAddress;\n }\n\n /**\n * Get the payment address\n */\n getPaymentAddress(): WalletAccount | null {\n return this._paymentAddress;\n }\n\n /**\n * Get all connected addresses (for multi-address support)\n */\n getAllAddresses(): string[] {\n return this._accounts.map((acc) => acc.address);\n }\n\n /**\n * Switch to a specific address within the connected accounts\n */\n switchWalletAddress(address: string): boolean {\n const account = this._accounts.find((a) => a.address === address);\n if (account) {\n if (account.purpose === AddressPurpose.Payment) {\n this._paymentAddress = {\n address: account.address,\n publicKey: account.publicKey,\n type: this.inferAddressType(account.address),\n };\n }\n return true;\n }\n return false;\n }\n}\n"]}
|