@usebutr/bitcoin 1.1.0 → 2.0.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/CHANGELOG.md +255 -0
- package/LICENSE +21 -0
- package/README.md +91 -0
- package/dist/index.d.ts +50 -76
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +216 -271
- package/dist/index.js.map +1 -1
- package/package.json +24 -6
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../src/capabilities.ts","../src/wallet-standard-adapter.ts","../src/chains.ts","../src/injected/icon.ts","../src/injected/sats-connect.ts","../src/injected/unisat.ts","../src/injected/index.ts","../src/discoverer.ts"],"sourcesContent":["import type { WalletCapabilities } from \"@usebutr/core\";\nimport { buildWalletCapabilities } from \"@usebutr/wallet-standard-shared\";\n\ntype BitcoinCapabilityInput = {\n chainCount: number;\n features: {\n events: boolean;\n sendTransfer: boolean;\n signMessage: boolean;\n signPsbt: boolean;\n };\n};\n\n/**\n * `signIn` is false: there is no Sign-In-With-Bitcoin standard, and BIP-322\n * is message-signing oriented rather than auth. `sendTransfer` leaves UTXO\n * selection, fees and broadcast to the wallet; `signPsbt` is sign-only.\n */\nconst resolveBitcoinCapabilities = (input: BitcoinCapabilityInput): WalletCapabilities =>\n buildWalletCapabilities({\n chainCount: input.chainCount,\n events: input.features.events,\n sendTransaction: input.features.sendTransfer,\n signIn: false,\n signMessage: input.features.signMessage,\n signTransaction: input.features.signPsbt,\n });\n\nexport type { BitcoinCapabilityInput };\nexport { resolveBitcoinCapabilities };\n","import type { WalletAdapter } from \"@usebutr/core\";\nimport {\n createWalletStandardCore,\n discoverWalletStandard,\n getFeature,\n slugify,\n} from \"@usebutr/wallet-standard-shared\";\nimport type { WalletStandardWallet } from \"@usebutr/wallet-standard-shared\";\n\nimport { resolveBitcoinCapabilities } from \"./capabilities\";\nimport type {\n BitcoinSendTransferFeature,\n BitcoinSignMessageFeature,\n BitcoinSignPsbtFeature,\n} from \"./wallet-standard-types\";\n\nconst BITCOIN_PREFIX = \"bip122:\";\nconst BITCOIN_DECIMALS = 8;\nconst BITCOIN_MAINNET_ID = \"bip122:000000000019d6689c085ae165831e93\";\n\n/**\n * `sendTx` takes `{ amount, recipient }` for `bitcoin:sendTransfer` and\n * `signTransaction` takes raw PSBT bytes for `bitcoin:signPsbt`. Balance\n * and receipt reads would need an Esplora/Electrum client butr doesn't ship.\n */\nconst buildBitcoinAdapter = (\n wallet: WalletStandardWallet,\n /** Optional. Called with a function that pushes a synthetic\n * `disconnected` event to all current subscribers. The discovery\n * layer invokes it on Wallet Standard `unregister`. */\n registerDisconnector?: (emit: () => void) => void,\n): WalletAdapter | null => {\n const core = createWalletStandardCore({\n chainPrefix: BITCOIN_PREFIX,\n id: slugify(\"btc\", wallet.name),\n label: \"Bitcoin\",\n namespace: \"bip122\",\n platform: \"Bitcoin\",\n preferredChainIds: [BITCOIN_MAINNET_ID],\n registerDisconnector,\n trackChainChanges: true,\n wallet,\n });\n if (core === null) {\n return null;\n }\n\n const signMessage = getFeature<BitcoinSignMessageFeature>(wallet, \"bitcoin:signMessage\");\n const signPsbt = getFeature<BitcoinSignPsbtFeature>(wallet, \"bitcoin:signPsbt\");\n const sendTransfer = getFeature<BitcoinSendTransferFeature>(wallet, \"bitcoin:sendTransfer\");\n\n /** Resolve a caller-supplied target into a chain the wallet advertises,\n * accepting either a full CAIP-2 id or a bare genesis-hash reference. */\n const resolveTargetChain = (targetChainId: string): string => {\n const candidate = targetChainId.startsWith(BITCOIN_PREFIX)\n ? targetChainId\n : `${BITCOIN_PREFIX}${targetChainId}`;\n if (!wallet.chains.includes(candidate)) {\n throw new Error(\n `Wallet ${wallet.name} does not advertise chain \"${candidate}\". Available: ${wallet.chains.join(\", \")}`,\n );\n }\n return candidate;\n };\n\n const sendTransferTx = async (\n tx: unknown,\n account?: { walletAddress: string },\n chain?: string,\n ): Promise<string> => {\n if (sendTransfer === undefined) {\n throw new Error(`Wallet ${wallet.name} does not advertise bitcoin:sendTransfer`);\n }\n if (\n typeof tx !== \"object\" ||\n tx === null ||\n !(\"amount\" in tx) ||\n typeof tx.amount !== \"bigint\" ||\n !(\"recipient\" in tx) ||\n typeof tx.recipient !== \"string\"\n ) {\n throw new TypeError(\n \"Bitcoin sendTx expects { amount: bigint, recipient: string }: pass the recipient address and an amount in satoshis\",\n );\n }\n const { amount, recipient } = tx;\n const output = await sendTransfer.sendTransfer({\n account: core.resolveAccount(account),\n amount,\n chain: chain ?? core.currentChainId(),\n recipient,\n });\n return output.txid;\n };\n\n return {\n ...core,\n capabilities: resolveBitcoinCapabilities({\n chainCount: core.chainCount,\n features: {\n events: core.hasEvents,\n sendTransfer: Boolean(sendTransfer),\n signMessage: Boolean(signMessage),\n signPsbt: Boolean(signPsbt),\n },\n }),\n chainPlatform: \"bitcoin\",\n\n getBalance: () =>\n Promise.resolve({\n decimals: BITCOIN_DECIMALS,\n formatted: \"0\",\n symbol: \"BTC\",\n value: 0n,\n }),\n\n getTransactionReceipt: () => Promise.resolve({ status: \"Pending\" as const }),\n\n async requestAccounts() {\n await core.connect();\n },\n\n sendTx: (tx, account) => sendTransferTx(tx, account),\n\n // Async so an unadvertised chain surfaces as a rejection rather than a\n // synchronous throw; the declared return type is a promise either way.\n async sendTxToChain(tx, targetChainId, account, cb) {\n const target = resolveTargetChain(targetChainId);\n if (target !== core.currentChainId()) {\n cb?.();\n }\n const txid = await sendTransferTx(tx, account, target);\n return txid;\n },\n\n async signMessage(msg, account) {\n if (signMessage === undefined) {\n throw new Error(`Wallet ${wallet.name} does not advertise bitcoin:signMessage`);\n }\n const output = await signMessage.signMessage({\n account: core.resolveAccount(account),\n message: msg,\n });\n return { signature: output.signature, signedMessage: output.signedMessage };\n },\n\n ...(signPsbt === undefined\n ? {}\n : {\n async signTransaction(tx, account) {\n const wsAccount = core.resolveAccount(account);\n if (!(tx instanceof Uint8Array)) {\n throw new TypeError(\n \"Bitcoin signTransaction expects a PSBT as Uint8Array (e.g. psbt.toBuffer())\",\n );\n }\n const output = await signPsbt.signPsbt({\n account: wsAccount,\n chain: core.currentChainId(),\n psbt: tx,\n });\n return output.signedPsbt;\n },\n }),\n };\n};\n\n/** Requires the optional `@wallet-standard/app` peer dep. */\nconst discoverBitcoinAdapters = (onAdapter: (adapter: WalletAdapter) => void): (() => void) =>\n discoverWalletStandard(onAdapter, (wallet, registerDisconnector) =>\n buildBitcoinAdapter(wallet, registerDisconnector),\n );\n\nexport { buildBitcoinAdapter, discoverBitcoinAdapters };\n","import type { ChainBase } from \"@usebutr/core\";\n\n/**\n * CAIP-2 Bitcoin references are the first 8 bytes of each network's\n * genesis block hash, which is what wallets advertise in `wallet.chains`.\n * No major wallet exposes a switch-chain RPC, so chain stays local state.\n */\nconst BITCOIN_CHAINS = {\n mainnet: {\n id: \"bip122:000000000019d6689c085ae165831e93\",\n name: \"Bitcoin\",\n namespace: \"bip122\",\n reference: \"000000000019d6689c085ae165831e93\",\n },\n signet: {\n id: \"bip122:00000008819873e925422c1ff0f99f7c\",\n name: \"Bitcoin Signet\",\n namespace: \"bip122\",\n reference: \"00000008819873e925422c1ff0f99f7c\",\n },\n testnet: {\n id: \"bip122:000000000933ea01ad0ee984209779ba\",\n name: \"Bitcoin Testnet\",\n namespace: \"bip122\",\n reference: \"000000000933ea01ad0ee984209779ba\",\n },\n} as const satisfies Record<string, ChainBase>;\n\nconst BITCOIN_CHAINS_LIST: ReadonlyArray<ChainBase> = Object.values(BITCOIN_CHAINS);\n\nexport { BITCOIN_CHAINS, BITCOIN_CHAINS_LIST };\n","/**\n * Inlined as a data URI so the picker doesn't flash, and shared by both\n * injected adapters as the fallback when a wallet advertises no icon.\n */\nconst GENERIC_BITCOIN_ICON =\n \"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0iI2Y3OTMxYSIgc3Ryb2tlPSJub25lIj48Y2lyY2xlIGN4PSIxMiIgY3k9IjEyIiByPSIxMCIvPjx0ZXh0IHg9IjEyIiB5PSIxNyIgZm9udC1mYW1pbHk9InNlcmlmIiBmb250LXNpemU9IjE0IiBmb250LXdlaWdodD0iYm9sZCIgZmlsbD0iI2ZmZiIgdGV4dC1hbmNob3I9Im1pZGRsZSI+QjwvdGV4dD48L3N2Zz4=\";\n\nexport { GENERIC_BITCOIN_ICON };\n","import type { Account, ChainBase, WalletAdapter, WalletCapabilities } from \"@usebutr/core\";\nimport { base64ToBytes, bytesToBase64 } from \"@usebutr/core\";\nimport { buildAccount } from \"@usebutr/wallet-standard-shared\";\n\nimport { BITCOIN_CHAINS } from \"../chains\";\n\nimport { GENERIC_BITCOIN_ICON } from \"./icon\";\n\n/** sats-connect (Xverse) shape; a JSON-RPC-ish `request(method, params)`. */\ntype SatsConnectProvider = {\n request: (\n method: string,\n params?: Record<string, unknown>,\n ) => Promise<{ error?: { message: string }; result?: unknown }>;\n};\n\n/** One address entry of a sats-connect account result. `purpose` tags the\n * role: `\"payment\"` is the spendable address, `\"ordinals\"` is a taproot\n * address that `sendTransfer` never debits. */\ntype SatsAddress = {\n address: string;\n publicKey?: string;\n purpose?: string;\n};\n\ntype ConnectedSession = {\n addresses: ReadonlyArray<SatsAddress>;\n payment: string;\n status: \"connected\";\n};\n\ntype Session = ConnectedSession | { status: \"disconnected\" };\n\nconst CAPS_SATS_CONNECT: WalletCapabilities = {\n getBalance: false,\n getTransactionReceipt: false,\n requestAccounts: true,\n sendTransaction: true,\n signIn: false,\n signMessage: true,\n signTransaction: true,\n subscribe: false,\n switchAccount: false,\n switchChain: false,\n};\n\nconst ACCOUNT_PURPOSES = [\"payment\", \"ordinals\"];\nconst CONNECT_MESSAGE = \"Connect to butr\";\n\nconst pickPaymentAddress = (addresses: ReadonlyArray<SatsAddress>): SatsAddress | undefined =>\n addresses.find((a) => a.purpose === \"payment\") ?? addresses[0];\n\n/**\n * Only the payment address is exposed as an Account: sats-connect's\n * `sendTransfer` takes no sender and always debits it. The taproot ordinals\n * address stays reachable through `getSigner()` and `signMessage`'s account.\n */\nconst buildSatsConnectAdapter = (\n id: string,\n name: string,\n provider: SatsConnectProvider,\n): WalletAdapter => {\n let chain: ChainBase = BITCOIN_CHAINS.mainnet;\n let session: Session = { status: \"disconnected\" };\n\n // oxlint-disable-next-line typescript/no-unnecessary-type-parameters -- caller-supplied result shape for an untyped RPC bridge\n const callRequest = async <T>(method: string, params?: Record<string, unknown>): Promise<T> => {\n const response = await provider.request(method, params);\n if (response.error) {\n throw new Error(`[butr/bitcoin] sats-connect ${method} failed: ${response.error.message}`);\n }\n // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- untyped sats-connect RPC result; caller declares the shape\n return response.result as T;\n };\n\n const startSession = async (method: string, params: Record<string, unknown>): Promise<void> => {\n const result = await callRequest<{\n addresses?: ReadonlyArray<SatsAddress>;\n } | null>(method, params);\n const addresses = result?.addresses ?? [];\n const payment = pickPaymentAddress(addresses);\n if (payment === undefined) {\n throw new Error(`Wallet ${name} returned no addresses from ${method}`);\n }\n session = { addresses, payment: payment.address, status: \"connected\" };\n };\n\n const requestSession = () =>\n startSession(\"getAccounts\", { message: CONNECT_MESSAGE, purposes: ACCOUNT_PURPOSES });\n\n const requireSession = (): ConnectedSession => {\n if (session.status !== \"connected\") {\n throw new Error(\"No connected account\");\n }\n return session;\n };\n\n const resolveAddress = (account?: Account): string => {\n const active = requireSession();\n if (account === undefined) {\n return active.payment;\n }\n const match = active.addresses.find((a) => a.address === account.walletAddress);\n if (match === undefined) {\n throw new Error(`Account ${account.walletAddress} is not exposed by ${name}`);\n }\n return match.address;\n };\n\n const sendTransferTx = async (tx: unknown, account?: Account): Promise<string> => {\n const sender = resolveAddress(account);\n if (sender !== requireSession().payment) {\n throw new Error(\n `Wallet ${name} always debits its payment address; ${sender} cannot be used as the sender.`,\n );\n }\n if (\n typeof tx !== \"object\" ||\n tx === null ||\n !(\"recipient\" in tx) ||\n typeof tx.recipient !== \"string\" ||\n !(\"amount\" in tx) ||\n typeof tx.amount !== \"bigint\"\n ) {\n throw new TypeError(\n \"Bitcoin sendTx expects { amount: bigint, recipient: string }: amount in satoshis\",\n );\n }\n const { amount, recipient } = tx;\n const result = await callRequest<{ txid: string }>(\"sendTransfer\", {\n recipients: [{ address: recipient, amount: amount.toString() }],\n });\n return result.txid;\n };\n\n return {\n capabilities: CAPS_SATS_CONNECT,\n chainPlatform: \"bitcoin\",\n\n async connect(opts) {\n if (opts?.silent === true) {\n // `wallet_getAccount` reads already-granted permissions without\n // showing wallet UI; `getAccounts` IS Xverse's approval prompt.\n // Builds predating `wallet_getAccount` reject here, which butr's\n // hydration treats as a clean restore failure.\n await startSession(\"wallet_getAccount\", { addresses: ACCOUNT_PURPOSES });\n return;\n }\n await requestSession();\n },\n\n disconnect: () => {\n session = { status: \"disconnected\" };\n return Promise.resolve();\n },\n\n getAccount: () =>\n Promise.resolve(session.status === \"connected\" ? buildAccount(session.payment, chain) : null),\n\n getAccounts: () =>\n Promise.resolve(session.status === \"connected\" ? [buildAccount(session.payment, chain)] : []),\n\n getBalance: () =>\n Promise.resolve({\n decimals: 8,\n formatted: \"0\",\n symbol: \"BTC\",\n value: 0n,\n }),\n\n getSigner: () => Promise.resolve(provider),\n\n getTransactionReceipt: () => Promise.resolve({ status: \"Pending\" as const }),\n\n icon: GENERIC_BITCOIN_ICON,\n id,\n name,\n\n requestAccounts: () => requestSession(),\n\n sendTx: (tx, account) => sendTransferTx(tx, account),\n\n sendTxToChain: (tx, _targetChainId, account, cb) => {\n cb?.();\n return sendTransferTx(tx, account);\n },\n\n async signMessage(msg, account) {\n const address = resolveAddress(account);\n const result = await callRequest<{ messageHash?: string; signature: string }>(\"signMessage\", {\n address,\n message: new TextDecoder().decode(msg),\n });\n return { signature: base64ToBytes(result.signature), signedMessage: msg };\n },\n\n async signTransaction(tx) {\n if (!(tx instanceof Uint8Array)) {\n throw new TypeError(\n \"Bitcoin signTransaction expects a PSBT as Uint8Array (e.g. psbt.toBuffer())\",\n );\n }\n const result = await callRequest<{ psbt: string }>(\"signPsbt\", {\n psbt: bytesToBase64(tx),\n });\n return base64ToBytes(result.psbt);\n },\n\n switchChain: (target) => {\n if (target.namespace !== \"bip122\") {\n throw new Error(\n `Bitcoin adapter received non-Bitcoin chain \"${target.id}\". Pass a chain with namespace \"bip122\".`,\n );\n }\n chain = target;\n return Promise.resolve();\n },\n };\n};\n\nexport type { SatsConnectProvider };\nexport { buildSatsConnectAdapter };\n","import type { ChainBase, WalletAdapter, WalletCapabilities } from \"@usebutr/core\";\nimport { base64ToBytes, bytesToHex, hexToBytes } from \"@usebutr/core\";\nimport { buildAccount } from \"@usebutr/wallet-standard-shared\";\n\nimport { BITCOIN_CHAINS } from \"../chains\";\n\nimport { GENERIC_BITCOIN_ICON } from \"./icon\";\n\n/** UniSat-style provider: a single object on `window.unisat` with the\n * same four methods every UniSat-derivative wallet exposes (UniSat\n * itself, OKX Wallet's Bitcoin path at `window.okxwallet.bitcoin`). */\ntype UnisatProvider = {\n getAccounts: () => Promise<ReadonlyArray<string>>;\n getNetwork?: () => Promise<\"livenet\" | \"mainnet\" | \"testnet\" | \"signet\">;\n on?: (\n event: \"accountsChanged\" | \"networkChanged\",\n listener: (...args: Array<unknown>) => void,\n ) => void;\n pushPsbt?: (psbtHex: string) => Promise<string>;\n removeListener?: (\n event: \"accountsChanged\" | \"networkChanged\",\n listener: (...args: Array<unknown>) => void,\n ) => void;\n requestAccounts: () => Promise<ReadonlyArray<string>>;\n sendBitcoin?: (recipient: string, amount: number) => Promise<string>;\n signMessage: (message: string, type?: \"ecdsa\" | \"bip322-simple\") => Promise<string>;\n signPsbt: (psbtHex: string, options?: Record<string, unknown>) => Promise<string>;\n};\n\nconst CAPS_UNISAT: WalletCapabilities = {\n getBalance: false,\n getTransactionReceipt: false,\n requestAccounts: true,\n sendTransaction: true,\n signIn: false,\n signMessage: true,\n signTransaction: true,\n subscribe: true,\n switchAccount: false,\n switchChain: false,\n};\n\nconst toStringArray = (value: unknown): Array<string> =>\n Array.isArray(value) ? value.filter((item): item is string => typeof item === \"string\") : [];\n\n/**\n * The UniSat shape is consistent enough across `window.unisat`,\n * `window.okxwallet.bitcoin` and `window.btc` that one adapter covers all\n * three; the differences (network names, `sendBitcoin`) are probed per call.\n */\nconst buildUnisatAdapter = (id: string, name: string, provider: UnisatProvider): WalletAdapter => {\n let chain: ChainBase = BITCOIN_CHAINS.mainnet;\n\n const sendBitcoinTx = async (tx: unknown): Promise<string> => {\n if (typeof provider.sendBitcoin !== \"function\") {\n throw new TypeError(`Wallet ${name} does not expose sendBitcoin`);\n }\n if (\n typeof tx !== \"object\" ||\n tx === null ||\n !(\"recipient\" in tx) ||\n typeof tx.recipient !== \"string\" ||\n !(\"amount\" in tx) ||\n typeof tx.amount !== \"bigint\"\n ) {\n throw new TypeError(\n \"Bitcoin sendTx expects { amount: bigint, recipient: string }: amount in satoshis\",\n );\n }\n const { amount, recipient } = tx;\n const txid = await provider.sendBitcoin(recipient, Number(amount));\n return txid;\n };\n\n const refreshChain = async () => {\n if (typeof provider.getNetwork !== \"function\") {\n return;\n }\n try {\n const network = await provider.getNetwork();\n if (network === \"testnet\") {\n chain = BITCOIN_CHAINS.testnet;\n } else if (network === \"signet\") {\n chain = BITCOIN_CHAINS.signet;\n } else {\n chain = BITCOIN_CHAINS.mainnet;\n }\n } catch {\n void 0;\n }\n };\n\n return {\n capabilities: CAPS_UNISAT,\n chainPlatform: \"bitcoin\",\n\n async connect(opts) {\n if (opts?.silent === true) {\n const accounts = await provider.getAccounts();\n if (accounts.length === 0) {\n throw new Error(\"No authorized accounts for silent reconnect\");\n }\n await refreshChain();\n return;\n }\n await provider.requestAccounts();\n await refreshChain();\n },\n\n disconnect: () => Promise.resolve(),\n\n async getAccount() {\n const accounts = await provider.getAccounts();\n const first = accounts[0];\n if (first === undefined) {\n return null;\n }\n await refreshChain();\n return buildAccount(first, chain);\n },\n\n async getAccounts() {\n const accounts = await provider.getAccounts();\n if (accounts.length === 0) {\n return [];\n }\n await refreshChain();\n return accounts.map((a) => buildAccount(a, chain));\n },\n\n getBalance: () =>\n Promise.resolve({\n decimals: 8,\n formatted: \"0\",\n symbol: \"BTC\",\n value: 0n,\n }),\n\n getSigner: () => Promise.resolve(provider),\n\n getTransactionReceipt: () => Promise.resolve({ status: \"Pending\" as const }),\n\n icon: GENERIC_BITCOIN_ICON,\n id,\n name,\n\n async requestAccounts() {\n await provider.requestAccounts();\n await refreshChain();\n },\n\n sendTx: (tx) => sendBitcoinTx(tx),\n\n sendTxToChain: (tx, _targetChainIdDecimal, _account, cb) => {\n cb?.();\n return sendBitcoinTx(tx);\n },\n\n async signMessage(msg) {\n const text = new TextDecoder().decode(msg);\n const signatureB64 = await provider.signMessage(text);\n return { signature: base64ToBytes(signatureB64), signedMessage: msg };\n },\n\n async signTransaction(tx) {\n if (!(tx instanceof Uint8Array)) {\n throw new TypeError(\n \"Bitcoin signTransaction expects a PSBT as Uint8Array (e.g. psbt.toBuffer())\",\n );\n }\n const signedHex = await provider.signPsbt(bytesToHex(tx));\n return hexToBytes(signedHex);\n },\n\n subscribe(listener) {\n const onAccountsChanged = (...args: ReadonlyArray<unknown>) => {\n const accounts = toStringArray(args[0]);\n if (accounts.length === 0) {\n listener({ type: \"disconnected\" });\n return;\n }\n const built = accounts.map((a) => buildAccount(a, chain));\n const first = built[0];\n if (first === undefined) {\n return;\n }\n listener({ account: first, accounts: built, type: \"accountChanged\" });\n };\n const onNetworkChanged = () => {\n void refreshChain();\n };\n provider.on?.(\"accountsChanged\", onAccountsChanged);\n provider.on?.(\"networkChanged\", onNetworkChanged);\n return () => {\n provider.removeListener?.(\"accountsChanged\", onAccountsChanged);\n provider.removeListener?.(\"networkChanged\", onNetworkChanged);\n };\n },\n\n // `capabilities.switchChain` is false: UniSat exposes no way to ask the\n // wallet to change network, so the wallet's own setting is authoritative\n // and every account read re-reads it. This validates the request and then\n // reports what the wallet actually says, rather than assigning the target\n // locally and having the next read silently contradict it.\n async switchChain(target) {\n if (target.namespace !== \"bip122\") {\n throw new Error(\n `Bitcoin adapter received non-Bitcoin chain \"${target.id}\". Pass a chain with namespace \"bip122\".`,\n );\n }\n chain = target;\n await refreshChain();\n },\n };\n};\n\nexport type { UnisatProvider };\nexport { buildUnisatAdapter };\n","import type { WalletAdapter } from \"@usebutr/core\";\n\nimport type { SatsConnectProvider } from \"./sats-connect\";\nimport { buildSatsConnectAdapter } from \"./sats-connect\";\nimport type { UnisatProvider } from \"./unisat\";\nimport { buildUnisatAdapter } from \"./unisat\";\n\nconst DEFAULT_SETTLE_MS = 150;\n\ntype InjectedHost = {\n btc?: UnisatProvider;\n okxwallet?: { bitcoin?: UnisatProvider };\n unisat?: UnisatProvider;\n XverseProviders?: { BitcoinProvider?: SatsConnectProvider };\n};\n\ntype InjectedBitcoinDiscoveryOptions = {\n /** Suppresses emission when Wallet Standard discovery has already\n * registered a Bitcoin adapter for the same browser session. */\n hasAnyWalletStandardAdapter?: () => boolean;\n /** Settle deadline in ms before the fallback fires. Same default and\n * intent as the EVM injected fallback. */\n settleMs?: number;\n /** Override the global host (tests, iframes). */\n target?: InjectedHost | null;\n};\n\nconst readHost = (target: InjectedBitcoinDiscoveryOptions[\"target\"]): InjectedHost | null => {\n if (target !== undefined) {\n return target;\n }\n if (typeof window === \"undefined\") {\n return null;\n }\n // `window` carries the injected wallet globals (`unisat`, `okxwallet`,\n // etc.) as an untyped host object; `InjectedHost` names the four keys\n // butr probes, all optional and read defensively in `probeProviders`.\n // oxlint-disable-next-line typescript/no-unsafe-type-assertion, anti-slop/no-chained-type-assertions -- untyped injected-wallet window globals\n return window as unknown as InjectedHost;\n};\n\nconst probeProviders = (host: InjectedHost): Array<WalletAdapter> => {\n const adapters: Array<WalletAdapter> = [];\n const seen = new Set<UnisatProvider | SatsConnectProvider>();\n\n if (host.unisat && !seen.has(host.unisat)) {\n seen.add(host.unisat);\n adapters.push(buildUnisatAdapter(\"injected:bitcoin:unisat\", \"Unisat\", host.unisat));\n }\n\n const okxBitcoin = host.okxwallet?.bitcoin;\n if (okxBitcoin && !seen.has(okxBitcoin)) {\n seen.add(okxBitcoin);\n adapters.push(buildUnisatAdapter(\"injected:bitcoin:okx\", \"OKX Wallet (Bitcoin)\", okxBitcoin));\n }\n\n const xverse = host.XverseProviders?.BitcoinProvider;\n if (xverse && !seen.has(xverse)) {\n seen.add(xverse);\n adapters.push(buildSatsConnectAdapter(\"injected:bitcoin:xverse\", \"Xverse\", xverse));\n }\n\n if (host.btc && !seen.has(host.btc)) {\n seen.add(host.btc);\n adapters.push(\n buildUnisatAdapter(\"injected:bitcoin:legacy\", \"Browser Bitcoin wallet\", host.btc),\n );\n }\n\n return adapters;\n};\n\n/**\n * Last-resort path for wallets that don't announce via Wallet Standard:\n * `window.unisat`, OKX, Xverse, `window.btc`. The `settleMs` wait lets\n * Wallet Standard announce first, else a wallet on both channels lists twice.\n */\nconst discoverInjectedBitcoinAdapter = (\n onAdapter: (adapter: WalletAdapter) => void,\n options: InjectedBitcoinDiscoveryOptions = {},\n): (() => void) => {\n const settleMs = options.settleMs ?? DEFAULT_SETTLE_MS;\n let cancelled = false;\n const timer = setTimeout(() => {\n if (cancelled) {\n return;\n }\n if (options.hasAnyWalletStandardAdapter?.() === true) {\n return;\n }\n const host = readHost(options.target);\n if (host === null) {\n return;\n }\n const adapters = probeProviders(host);\n for (const adapter of adapters) {\n onAdapter(adapter);\n }\n }, settleMs);\n\n return () => {\n cancelled = true;\n clearTimeout(timer);\n };\n};\n\nexport type { InjectedBitcoinDiscoveryOptions };\nexport { GENERIC_BITCOIN_ICON } from \"./icon\";\nexport { discoverInjectedBitcoinAdapter };\n","import type { PlatformDiscoverer } from \"@usebutr/core\";\n\nimport { discoverInjectedBitcoinAdapter } from \"./injected\";\nimport { discoverBitcoinAdapters } from \"./wallet-standard-adapter\";\n\n/**\n * Wallet Standard is primary; the legacy fallback covers sats-connect\n * (Xverse), `window.unisat`, OKX legacy and `window.btc`, and defers to\n * the primary channel via `hasAnyPrimaryAdapter`.\n */\nconst bitcoinDiscoverer: PlatformDiscoverer = {\n fallback: {\n subscribe: (onAdapter, opts) =>\n discoverInjectedBitcoinAdapter(onAdapter, {\n hasAnyWalletStandardAdapter: opts.hasAnyPrimaryAdapter,\n }),\n },\n subscribe: discoverBitcoinAdapters,\n};\n\nexport { bitcoinDiscoverer };\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/wallet-standard-adapter.ts","../src/injected/chain.ts","../src/injected/icon.ts","../src/injected/sats-connect.ts","../src/injected/unisat.ts","../src/injected/index.ts","../src/discoverer.ts"],"sourcesContent":["import type {\n AccountOptions,\n BitcoinAdapter,\n BitcoinTransfer,\n TransactionOptions,\n WalletAdapter,\n} from \"@usebutr/core\";\nimport { BITCOIN_CHAINS, BITCOIN_CHAINS_LIST } from \"@usebutr/core\";\nimport {\n createWalletStandardCore,\n discoverWalletStandard,\n getFeature,\n slugify,\n} from \"@usebutr/wallet-standard-shared\";\nimport type { WalletStandardWallet } from \"@usebutr/wallet-standard-shared\";\n\nimport type {\n BitcoinSendTransferFeature,\n BitcoinSignMessageFeature,\n BitcoinSignPsbtFeature,\n} from \"./wallet-standard-types\";\n\n/**\n * `bitcoin:sendTransfer` backs `sendTx` and `bitcoin:signPsbt` backs\n * `signTransaction`, both routing `options.chain` per call. Balance and\n * receipt reads would need an Esplora/Electrum client butr doesn't ship.\n */\nconst buildBitcoinAdapter = (\n wallet: WalletStandardWallet,\n /** Optional. Called with a function that pushes a synthetic\n * `disconnected` event to all current subscribers. The discovery\n * layer invokes it on Wallet Standard `unregister`. */\n registerDisconnector?: (emit: () => void) => void,\n): BitcoinAdapter | null => {\n const core = createWalletStandardCore({\n chains: BITCOIN_CHAINS_LIST,\n id: slugify(\"btc\", wallet.name),\n label: \"Bitcoin\",\n namespace: \"bip122\",\n preferredChainIds: [BITCOIN_CHAINS.mainnet.id],\n registerDisconnector,\n trackChainChanges: true,\n wallet,\n });\n if (core === null) {\n return null;\n }\n\n const sendTransfer = getFeature<BitcoinSendTransferFeature>(\n wallet,\n \"bitcoin:sendTransfer\",\n \"sendTransfer\",\n );\n const signMessage = getFeature<BitcoinSignMessageFeature>(\n wallet,\n \"bitcoin:signMessage\",\n \"signMessage\",\n );\n const signPsbt = getFeature<BitcoinSignPsbtFeature>(wallet, \"bitcoin:signPsbt\", \"signPsbt\");\n\n return {\n ...core.base,\n chainPlatform: \"bitcoin\",\n ...(sendTransfer !== undefined && {\n async sendTx({ amount, recipient }: BitcoinTransfer, options?: TransactionOptions) {\n const output = await sendTransfer.sendTransfer({\n account: core.resolveAccount(options?.account),\n amount,\n chain: core.resolveChainId(options?.chain),\n recipient,\n });\n return output.txid;\n },\n }),\n ...(signMessage !== undefined && {\n async signMessage(message: Uint8Array, options?: AccountOptions) {\n const output = await signMessage.signMessage({\n account: core.resolveAccount(options?.account),\n message,\n });\n return { signature: output.signature, signedMessage: output.signedMessage };\n },\n }),\n ...(signPsbt !== undefined && {\n async signTransaction(psbt: Uint8Array, options?: TransactionOptions) {\n const output = await signPsbt.signPsbt({\n account: core.resolveAccount(options?.account),\n chain: core.resolveChainId(options?.chain),\n psbt,\n });\n return output.signedPsbt;\n },\n }),\n };\n};\n\n/** Requires the optional `@wallet-standard/app` peer dep. */\nconst discoverBitcoinAdapters = (onAdapter: (adapter: WalletAdapter) => void): (() => void) =>\n discoverWalletStandard(onAdapter, buildBitcoinAdapter);\n\nexport { buildBitcoinAdapter, discoverBitcoinAdapters };\n","import type { ChainBase } from \"@usebutr/core\";\nimport { ConnectionError } from \"@usebutr/core\";\n\nconst assertBitcoinChain = (chain: ChainBase): void => {\n if (chain.namespace !== \"bip122\") {\n throw new Error(\n `Bitcoin adapter received non-Bitcoin chain \"${chain.id}\". Pass a chain with namespace \"bip122\".`,\n );\n }\n};\n\n/** An injected wallet has one network for every call, so a target it cannot\n * move to is refused rather than sent on the network it happens to be on. */\nconst chainMismatch = (wallet: string, current: ChainBase, target: ChainBase): ConnectionError =>\n new ConnectionError(\n \"ChainMismatch\",\n `Wallet ${wallet} is on ${current.name} and cannot switch to ${target.name}`,\n );\n\nexport { assertBitcoinChain, chainMismatch };\n","/**\n * Inlined as a data URI so the picker doesn't flash, and shared by both\n * injected adapters as the fallback when a wallet advertises no icon.\n */\nconst GENERIC_BITCOIN_ICON =\n \"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0iI2Y3OTMxYSIgc3Ryb2tlPSJub25lIj48Y2lyY2xlIGN4PSIxMiIgY3k9IjEyIiByPSIxMCIvPjx0ZXh0IHg9IjEyIiB5PSIxNyIgZm9udC1mYW1pbHk9InNlcmlmIiBmb250LXNpemU9IjE0IiBmb250LXdlaWdodD0iYm9sZCIgZmlsbD0iI2ZmZiIgdGV4dC1hbmNob3I9Im1pZGRsZSI+QjwvdGV4dD48L3N2Zz4=\";\n\nexport { GENERIC_BITCOIN_ICON };\n","import type {\n Account,\n BitcoinAdapter,\n BitcoinTransfer,\n ChainBase,\n ConnectorEvent,\n TransactionOptions,\n} from \"@usebutr/core\";\nimport {\n BITCOIN_CHAINS,\n BITCOIN_CHAINS_LIST,\n base64ToBytes,\n buildAccount,\n bytesToBase64,\n resolveChain,\n} from \"@usebutr/core\";\nimport { z } from \"zod\";\n\nimport { assertBitcoinChain, chainMismatch } from \"./chain\";\nimport { GENERIC_BITCOIN_ICON } from \"./icon\";\n\n/** sats-connect (Xverse) shape; a JSON-RPC-ish `request(method, params)`. */\ntype RpcValue =\n | boolean\n | number\n | string\n | null\n | ReadonlyArray<RpcValue>\n | { readonly [key: string]: RpcValue | undefined };\n\ntype SatsConnectProvider = {\n request: (\n method: string,\n params?: Readonly<Record<string, RpcValue>>,\n ) => Promise<{ error?: { message: string }; result?: RpcValue }>;\n};\n\n/** One address entry of a sats-connect account result. `purpose` tags the\n * role: `\"payment\"` is the spendable address, `\"ordinals\"` is a taproot\n * address that `sendTransfer` never debits. */\ntype SatsAddress = {\n address: string;\n publicKey?: string;\n purpose?: string;\n};\n\ntype ConnectedSession = {\n addresses: ReadonlyArray<SatsAddress>;\n payment: string;\n status: \"connected\";\n};\n\ntype Session = ConnectedSession | { status: \"disconnected\" };\n\nconst ACCOUNT_PURPOSES = [\"payment\", \"ordinals\"];\nconst CONNECT_MESSAGE = \"Connect to butr\";\n\nconst networkNameSchema = z.enum([\"Mainnet\", \"Regtest\", \"Signet\", \"Testnet\", \"Testnet4\"]);\n\n/** sats-connect names networks, not chains. Regtest sits outside butr's\n * registry, so `resolveChain` names it by its CAIP-2 id. */\nconst NETWORK_CHAIN_IDS: Readonly<Record<z.output<typeof networkNameSchema>, string>> = {\n Mainnet: BITCOIN_CHAINS.mainnet.id,\n Regtest: \"bip122:0f9188f13cb7b2c71f2a335e3a4fc328\",\n Signet: BITCOIN_CHAINS.signet.id,\n Testnet: BITCOIN_CHAINS.testnet.id,\n Testnet4: BITCOIN_CHAINS.testnet4.id,\n};\n\nconst satsAddressSchema = z.object({\n address: z.string(),\n publicKey: z.string().optional(),\n purpose: z.string().optional(),\n});\n\n// Legacy `getAccounts` resolves the address list itself; `wallet_getAccount`\n// wraps it alongside the wallet id and network.\nconst accountResultSchema = z.union([\n z.array(satsAddressSchema),\n z.object({ addresses: z.array(satsAddressSchema) }).transform((result) => result.addresses),\n]);\nconst networkResultSchema = z.object({ bitcoin: z.object({ name: networkNameSchema }) });\nconst sendTransferResultSchema = z.object({ txid: z.string() });\nconst signMessageResultSchema = z.object({\n messageHash: z.string().optional(),\n signature: z.string(),\n});\nconst signPsbtResultSchema = z.object({ psbt: z.string() });\n// Module-level like the rest: a schema built per call gets hoisted by apps\n// compiling with zod-compiler, which then needs zod in the app itself.\nconst changeNetworkResultSchema = z.unknown();\n\nconst pickPaymentAddress = (addresses: ReadonlyArray<SatsAddress>): SatsAddress | undefined =>\n addresses.find((a) => a.purpose === \"payment\") ?? addresses[0];\n\nconst networkFor = (chain: ChainBase): string | undefined =>\n Object.entries(NETWORK_CHAIN_IDS).find(([, chainId]) => chainId === chain.id)?.[0];\n\n/**\n * Only the payment address is an Account (`sendTransfer` always debits it); `signMessage` also\n * takes the ordinals address. The network is wallet-wide, so a call targeting another chain\n * moves it with `wallet_changeNetwork` first.\n */\nconst buildSatsConnectAdapter = (\n id: string,\n name: string,\n provider: SatsConnectProvider,\n): BitcoinAdapter => {\n let chain: ChainBase = BITCOIN_CHAINS.mainnet;\n let session: Session = { status: \"disconnected\" };\n const listeners = new Set<(event: ConnectorEvent) => void>();\n\n const callRequest = async <Schema extends z.ZodType>(\n method: string,\n schema: Schema,\n params?: Readonly<Record<string, RpcValue>>,\n ): Promise<z.output<Schema>> => {\n const response = await provider.request(method, params);\n if (response.error) {\n throw new Error(`[butr/bitcoin] sats-connect ${method} failed: ${response.error.message}`);\n }\n return schema.parse(response.result);\n };\n\n const startSession = async (\n method: string,\n params: Readonly<Record<string, RpcValue>>,\n ): Promise<void> => {\n const addresses = await callRequest(method, accountResultSchema, params);\n const payment = pickPaymentAddress(addresses);\n if (payment === undefined) {\n throw new Error(`Wallet ${name} returned no addresses from ${method}`);\n }\n session = { addresses, payment: payment.address, status: \"connected\" };\n };\n\n // `wallet_getAccount` reads already-granted permissions without showing\n // wallet UI; `getAccounts` IS Xverse's approval prompt.\n const readSession = () => startSession(\"wallet_getAccount\", { addresses: ACCOUNT_PURPOSES });\n\n const readChain = async (): Promise<ChainBase> => {\n const result = await callRequest(\"wallet_getNetwork\", networkResultSchema);\n return resolveChain(NETWORK_CHAIN_IDS[result.bitcoin.name], BITCOIN_CHAINS_LIST);\n };\n\n const exposedAccounts = (): ReadonlyArray<Account> =>\n session.status === \"connected\" ? [buildAccount(session.payment, chain)] : [];\n\n const requireSession = (): ConnectedSession => {\n if (session.status !== \"connected\") {\n throw new Error(\"No connected account\");\n }\n return session;\n };\n\n const resolveAddress = (account?: Account): string => {\n const active = requireSession();\n if (account === undefined) {\n return active.payment;\n }\n const match = active.addresses.find((a) => a.address === account.walletAddress);\n if (match === undefined) {\n throw new Error(`Account ${account.walletAddress} is not exposed by ${name}`);\n }\n return match.address;\n };\n\n const moveTo = async (target: ChainBase): Promise<void> => {\n assertBitcoinChain(target);\n const current = await readChain();\n if (current.id !== target.id) {\n const network = networkFor(target);\n if (network === undefined) {\n throw chainMismatch(name, current, target);\n }\n await callRequest(\"wallet_changeNetwork\", changeNetworkResultSchema, { name: network });\n }\n if (chain.id === target.id) {\n return;\n }\n // A Bitcoin address encodes its network, so the session is re-read on\n // the new one before anything is labelled with it.\n await readSession();\n chain = resolveChain(target.id, BITCOIN_CHAINS_LIST);\n const accounts = exposedAccounts();\n for (const listener of listeners) {\n listener({ accounts, type: \"accountsChanged\" });\n }\n };\n\n // The account is matched after the move: its address only exists on the\n // network it was built for.\n const prepare = async (options?: TransactionOptions): Promise<string> => {\n if (options?.chain !== undefined) {\n await moveTo(options.chain);\n }\n return resolveAddress(options?.account);\n };\n\n return {\n chainPlatform: \"bitcoin\",\n\n async connect(options) {\n // Builds predating `wallet_getAccount` reject a silent connect, which\n // butr's hydration treats as a clean restore failure.\n await (options?.silent === true\n ? readSession()\n : startSession(\"getAccounts\", { message: CONNECT_MESSAGE, purposes: ACCOUNT_PURPOSES }));\n try {\n chain = await readChain();\n } catch {\n // Builds predating `wallet_getNetwork` keep the last known label;\n // a transaction naming a chain still reads the network strictly.\n }\n },\n\n disconnect: () => {\n session = { status: \"disconnected\" };\n return Promise.resolve();\n },\n\n getAccounts: () => Promise.resolve(exposedAccounts()),\n\n getSigner: () => Promise.resolve({ kind: \"sats-connect\", provider }),\n\n icon: GENERIC_BITCOIN_ICON,\n id,\n name,\n\n async sendTx({ amount, recipient }: BitcoinTransfer, options?: TransactionOptions) {\n const sender = await prepare(options);\n if (sender !== requireSession().payment) {\n throw new Error(\n `Wallet ${name} always debits its payment address; ${sender} cannot be used as the sender.`,\n );\n }\n const result = await callRequest(\"sendTransfer\", sendTransferResultSchema, {\n recipients: [{ address: recipient, amount: Number(amount) }],\n });\n return result.txid;\n },\n\n async signMessage(message, options) {\n const address = resolveAddress(options?.account);\n const result = await callRequest(\"signMessage\", signMessageResultSchema, {\n address,\n message: new TextDecoder().decode(message),\n });\n return { signature: base64ToBytes(result.signature), signedMessage: message };\n },\n\n async signTransaction(psbt, options) {\n await prepare(options);\n const result = await callRequest(\"signPsbt\", signPsbtResultSchema, {\n psbt: bytesToBase64(psbt),\n });\n return base64ToBytes(result.psbt);\n },\n\n // Xverse's own wallet events are not bridged: this reports the network\n // moves butr makes, which re-address the payment account.\n subscribe: (listener) => {\n listeners.add(listener);\n return () => {\n listeners.delete(listener);\n };\n },\n\n switchChain: moveTo,\n };\n};\n\nexport type { RpcValue, SatsConnectProvider };\nexport { buildSatsConnectAdapter };\n","import type {\n Account,\n BitcoinAdapter,\n BitcoinTransfer,\n ChainBase,\n ConnectorEvent,\n TransactionOptions,\n} from \"@usebutr/core\";\nimport {\n BITCOIN_CHAINS,\n BITCOIN_CHAINS_LIST,\n base64ToBytes,\n buildAccount,\n bytesToHex,\n hexToBytes,\n logWarn,\n resolveChain,\n} from \"@usebutr/core\";\n\nimport { assertBitcoinChain, chainMismatch } from \"./chain\";\nimport { GENERIC_BITCOIN_ICON } from \"./icon\";\n\ntype UnisatNetwork = \"livenet\" | \"mainnet\" | \"signet\" | \"testnet\";\n\n/** The only networks UniSat's `switchNetwork` accepts. */\ntype SwitchableNetwork = \"livenet\" | \"testnet\";\n\n/** UniSat-style provider: a single object on `window.unisat` with the\n * same four methods every UniSat-derivative wallet exposes (UniSat\n * itself, OKX Wallet's Bitcoin path at `window.okxwallet.bitcoin`). */\ntype UnisatProvider = {\n getAccounts: () => Promise<ReadonlyArray<string>>;\n getNetwork?: () => Promise<UnisatNetwork>;\n on?: (\n event: \"accountsChanged\" | \"networkChanged\",\n listener: (...args: Array<UnisatEventValue>) => void,\n ) => void;\n pushPsbt?: (psbtHex: string) => Promise<string>;\n removeListener?: (\n event: \"accountsChanged\" | \"networkChanged\",\n listener: (...args: Array<UnisatEventValue>) => void,\n ) => void;\n requestAccounts: () => Promise<ReadonlyArray<string>>;\n sendBitcoin?: (recipient: string, amount: number) => Promise<string>;\n signMessage: (message: string, type?: \"ecdsa\" | \"bip322-simple\") => Promise<string>;\n signPsbt: (psbtHex: string, options?: UnisatSignPsbtOptions) => Promise<string>;\n /** UniSat has it; OKX's `window.okxwallet.bitcoin` is pinned to mainnet. */\n switchNetwork?: (network: SwitchableNetwork) => Promise<void>;\n};\n\ntype UnisatEventItem = number | string | null;\ntype UnisatEventValue = ReadonlyArray<UnisatEventItem> | string | undefined;\n\ntype UnisatSignPsbtOptions = {\n autoFinalized?: boolean;\n};\n\nconst NETWORK_CHAINS: ReadonlyMap<string, ChainBase> = new Map<UnisatNetwork, ChainBase>([\n [\"livenet\", BITCOIN_CHAINS.mainnet],\n [\"mainnet\", BITCOIN_CHAINS.mainnet],\n [\"signet\", BITCOIN_CHAINS.signet],\n [\"testnet\", BITCOIN_CHAINS.testnet],\n]);\n\nconst SWITCH_NETWORKS: ReadonlyMap<string, SwitchableNetwork> = new Map([\n [BITCOIN_CHAINS.mainnet.id, \"livenet\"],\n [BITCOIN_CHAINS.testnet.id, \"testnet\"],\n]);\n\nconst toStringArray = (value: UnisatEventValue | undefined): Array<string> =>\n Array.isArray(value) ? value.filter((item): item is string => typeof item === \"string\") : [];\n\n/**\n * One adapter covers `window.unisat`, `window.okxwallet.bitcoin` and `window.btc`.\n * The network is wallet-wide, so a call targeting another chain switches it\n * first, or rejects when the provider cannot switch.\n */\nconst buildUnisatAdapter = (id: string, name: string, provider: UnisatProvider): BitcoinAdapter => {\n // Bound so they keep `this`: they are methods on the wallet's own object.\n const getNetwork = provider.getNetwork?.bind(provider);\n const on = provider.on?.bind(provider);\n const sendBitcoin = provider.sendBitcoin?.bind(provider);\n const switchNetwork = provider.switchNetwork?.bind(provider);\n\n // Providers without `getNetwork` (legacy `window.btc`) are mainnet wallets.\n let chain: ChainBase = BITCOIN_CHAINS.mainnet;\n\n const readChain = async (): Promise<ChainBase> => {\n if (getNetwork === undefined) {\n return chain;\n }\n const network = await getNetwork();\n const match = NETWORK_CHAINS.get(network);\n if (match === undefined) {\n throw new Error(`Wallet ${name} reported an unknown network \"${network}\"`);\n }\n return match;\n };\n\n const readAccounts = async (): Promise<ReadonlyArray<Account>> => {\n const addresses = await provider.getAccounts();\n if (addresses.length === 0) {\n return [];\n }\n try {\n chain = await readChain();\n } catch {\n // Labels only: a locked wallet may refuse `getNetwork` while still\n // listing its accounts, which keep the last known chain.\n }\n return addresses.map((address) => buildAccount(address, chain));\n };\n\n // UniSat takes no sender: it always signs with its active account.\n const assertActive = async (account?: Account): Promise<void> => {\n if (account === undefined) {\n return;\n }\n const [active] = await provider.getAccounts();\n if (account.walletAddress !== active) {\n throw new Error(\n `Wallet ${name} signs only with its active account, and ${account.walletAddress} is not it`,\n );\n }\n };\n\n const moveTo = async (target: ChainBase): Promise<void> => {\n assertBitcoinChain(target);\n chain = await readChain();\n if (chain.id === target.id) {\n return;\n }\n const network = SWITCH_NETWORKS.get(target.id);\n if (switchNetwork === undefined || network === undefined) {\n throw chainMismatch(name, chain, target);\n }\n await switchNetwork(network);\n chain = resolveChain(target.id, BITCOIN_CHAINS_LIST);\n };\n\n // A Bitcoin address encodes its network, so the wallet moves first and\n // the account is matched on the network it will sign on.\n const prepare = async (options?: TransactionOptions): Promise<void> => {\n if (options?.chain !== undefined) {\n await moveTo(options.chain);\n }\n await assertActive(options?.account);\n };\n\n return {\n chainPlatform: \"bitcoin\",\n\n async connect(options) {\n if (options?.silent !== true) {\n await provider.requestAccounts();\n return;\n }\n const accounts = await provider.getAccounts();\n if (accounts.length === 0) {\n throw new Error(\"No authorized accounts for silent reconnect\");\n }\n },\n\n getAccounts: readAccounts,\n\n getSigner: () => Promise.resolve({ kind: \"unisat\", provider }),\n\n icon: GENERIC_BITCOIN_ICON,\n id,\n name,\n\n async signMessage(message, options) {\n await assertActive(options?.account);\n const signature = await provider.signMessage(new TextDecoder().decode(message));\n return { signature: base64ToBytes(signature), signedMessage: message };\n },\n\n async signTransaction(psbt, options) {\n await prepare(options);\n return hexToBytes(await provider.signPsbt(bytesToHex(psbt)));\n },\n\n ...(sendBitcoin !== undefined && {\n async sendTx({ amount, recipient }: BitcoinTransfer, options?: TransactionOptions) {\n await prepare(options);\n return sendBitcoin(recipient, Number(amount));\n },\n }),\n\n ...(on !== undefined && {\n subscribe: (listener: (event: ConnectorEvent) => void) => {\n const emit = (accounts: ReadonlyArray<Account>) => {\n listener(\n accounts.length === 0\n ? { type: \"disconnected\" }\n : { accounts, type: \"accountsChanged\" },\n );\n };\n const onAccountsChanged = (...args: ReadonlyArray<UnisatEventValue>) => {\n emit(toStringArray(args[0]).map((address) => buildAccount(address, chain)));\n };\n // The network is wallet-wide, so a change moves every account with it.\n const reemitAccounts = async () => {\n try {\n emit(await readAccounts());\n } catch (error) {\n logWarn(`[butr] ${name} accounts could not be re-read after a network change:`, error);\n }\n };\n const onNetworkChanged = () => {\n void reemitAccounts();\n };\n on(\"accountsChanged\", onAccountsChanged);\n on(\"networkChanged\", onNetworkChanged);\n return () => {\n provider.removeListener?.(\"accountsChanged\", onAccountsChanged);\n provider.removeListener?.(\"networkChanged\", onNetworkChanged);\n };\n },\n }),\n\n ...(switchNetwork !== undefined && { switchChain: moveTo }),\n };\n};\n\nexport type { UnisatProvider };\nexport { buildUnisatAdapter };\n","import type { BitcoinAdapter, WalletAdapter } from \"@usebutr/core\";\n\nimport type { SatsConnectProvider } from \"./sats-connect\";\nimport { buildSatsConnectAdapter } from \"./sats-connect\";\nimport type { UnisatProvider } from \"./unisat\";\nimport { buildUnisatAdapter } from \"./unisat\";\n\nconst DEFAULT_SETTLE_MS = 150;\n\ntype InjectedHost = {\n btc?: UnisatProvider;\n okxwallet?: { bitcoin?: UnisatProvider };\n unisat?: UnisatProvider;\n XverseProviders?: { BitcoinProvider?: SatsConnectProvider };\n};\n\ndeclare global {\n // oxlint-disable-next-line typescript/consistent-type-definitions -- DOM globals require interface merging.\n interface Window {\n btc?: UnisatProvider;\n okxwallet?: { bitcoin?: UnisatProvider };\n unisat?: UnisatProvider;\n XverseProviders?: { BitcoinProvider?: SatsConnectProvider };\n }\n}\n\ntype InjectedBitcoinDiscoveryOptions = {\n /** Suppresses emission when Wallet Standard discovery has already\n * registered a Bitcoin adapter for the same browser session. */\n hasAnyWalletStandardAdapter?: () => boolean;\n /** Settle deadline in ms before the fallback fires. Same default and\n * intent as the EVM injected fallback. */\n settleMs?: number;\n /** Override the global host (tests, iframes). */\n target?: InjectedHost | null;\n};\n\nconst readHost = (target: InjectedBitcoinDiscoveryOptions[\"target\"]): InjectedHost | null => {\n if (target !== undefined) {\n return target;\n }\n if (typeof window === \"undefined\") {\n return null;\n }\n return window;\n};\n\nconst probeProviders = (host: InjectedHost): Array<BitcoinAdapter> => {\n const adapters: Array<BitcoinAdapter> = [];\n const seen = new Set<UnisatProvider | SatsConnectProvider>();\n\n if (host.unisat && !seen.has(host.unisat)) {\n seen.add(host.unisat);\n adapters.push(buildUnisatAdapter(\"injected:bitcoin:unisat\", \"Unisat\", host.unisat));\n }\n\n const okxBitcoin = host.okxwallet?.bitcoin;\n if (okxBitcoin && !seen.has(okxBitcoin)) {\n seen.add(okxBitcoin);\n adapters.push(buildUnisatAdapter(\"injected:bitcoin:okx\", \"OKX Wallet (Bitcoin)\", okxBitcoin));\n }\n\n const xverse = host.XverseProviders?.BitcoinProvider;\n if (xverse && !seen.has(xverse)) {\n seen.add(xverse);\n adapters.push(buildSatsConnectAdapter(\"injected:bitcoin:xverse\", \"Xverse\", xverse));\n }\n\n if (host.btc && !seen.has(host.btc)) {\n seen.add(host.btc);\n adapters.push(\n buildUnisatAdapter(\"injected:bitcoin:legacy\", \"Browser Bitcoin wallet\", host.btc),\n );\n }\n\n return adapters;\n};\n\n/**\n * Last-resort path for wallets that don't announce via Wallet Standard:\n * `window.unisat`, OKX, Xverse, `window.btc`. The `settleMs` wait lets\n * Wallet Standard announce first, else a wallet on both channels lists twice.\n */\nconst discoverInjectedBitcoinAdapter = (\n onAdapter: (adapter: WalletAdapter) => void,\n options: InjectedBitcoinDiscoveryOptions = {},\n): (() => void) => {\n const settleMs = options.settleMs ?? DEFAULT_SETTLE_MS;\n let cancelled = false;\n const timer = setTimeout(() => {\n if (cancelled) {\n return;\n }\n if (options.hasAnyWalletStandardAdapter?.() === true) {\n return;\n }\n const host = readHost(options.target);\n if (host === null) {\n return;\n }\n const adapters = probeProviders(host);\n for (const adapter of adapters) {\n onAdapter(adapter);\n }\n }, settleMs);\n\n return () => {\n cancelled = true;\n clearTimeout(timer);\n };\n};\n\nexport type { InjectedBitcoinDiscoveryOptions };\nexport { GENERIC_BITCOIN_ICON } from \"./icon\";\nexport { discoverInjectedBitcoinAdapter };\n","import type { PlatformDiscoverer } from \"@usebutr/core\";\n\nimport { discoverInjectedBitcoinAdapter } from \"./injected\";\nimport { discoverBitcoinAdapters } from \"./wallet-standard-adapter\";\n\n/**\n * Wallet Standard is primary; the legacy fallback covers sats-connect\n * (Xverse), `window.unisat`, OKX legacy and `window.btc`, and defers to\n * the primary channel via `hasAnyPrimaryAdapter`.\n */\nconst bitcoinDiscoverer: PlatformDiscoverer = {\n fallback: {\n subscribe: (onAdapter, opts) =>\n discoverInjectedBitcoinAdapter(onAdapter, {\n hasAnyWalletStandardAdapter: opts.hasAnyPrimaryAdapter,\n }),\n },\n subscribe: discoverBitcoinAdapters,\n};\n\nexport { bitcoinDiscoverer };\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,23 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@usebutr/bitcoin",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"description": "Wallet Standard + injected (sats-connect / Unisat / OKX) wallet discovery and adapters for butr (Bitcoin).",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"bitcoin",
|
|
7
|
+
"butr",
|
|
8
|
+
"dapp",
|
|
9
|
+
"psbt",
|
|
10
|
+
"react",
|
|
11
|
+
"typescript",
|
|
12
|
+
"unisat",
|
|
13
|
+
"wallet",
|
|
14
|
+
"web3",
|
|
15
|
+
"xverse"
|
|
16
|
+
],
|
|
17
|
+
"homepage": "https://docs.usebutr.com/api/bitcoin",
|
|
18
|
+
"bugs": {
|
|
19
|
+
"url": "https://github.com/pedroapfilho/usebutr/issues"
|
|
20
|
+
},
|
|
5
21
|
"license": "MIT",
|
|
6
22
|
"author": "Pedro Filho <pedro@filho.me>",
|
|
7
23
|
"repository": {
|
|
@@ -10,7 +26,8 @@
|
|
|
10
26
|
"directory": "packages/bitcoin"
|
|
11
27
|
},
|
|
12
28
|
"files": [
|
|
13
|
-
"dist"
|
|
29
|
+
"dist",
|
|
30
|
+
"CHANGELOG.md"
|
|
14
31
|
],
|
|
15
32
|
"type": "module",
|
|
16
33
|
"sideEffects": false,
|
|
@@ -25,13 +42,14 @@
|
|
|
25
42
|
"access": "public"
|
|
26
43
|
},
|
|
27
44
|
"dependencies": {
|
|
28
|
-
"
|
|
29
|
-
"@usebutr/
|
|
45
|
+
"zod": "^4.6.1",
|
|
46
|
+
"@usebutr/core": "3.0.0",
|
|
47
|
+
"@usebutr/wallet-standard-shared": "2.0.0"
|
|
30
48
|
},
|
|
31
49
|
"devDependencies": {
|
|
32
50
|
"@wallet-standard/app": "^1.1.1",
|
|
33
|
-
"typescript": "^
|
|
34
|
-
"vitest": "^
|
|
51
|
+
"typescript": "^7.0.2",
|
|
52
|
+
"vitest": "^5.0.0",
|
|
35
53
|
"@repo/config-vitest": "0.0.0",
|
|
36
54
|
"@repo/typescript-config": "0.0.0"
|
|
37
55
|
},
|