@usebutr/bitcoin 1.1.0 → 1.1.2

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 ADDED
@@ -0,0 +1,222 @@
1
+ # @usebutr/bitcoin
2
+
3
+ ## 1.1.2
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies [[`bc5b58c`](https://github.com/pedroapfilho/usebutr/commit/bc5b58cd87601be38dbb77a14e16eaaa36e8f012), [`bc5b58c`](https://github.com/pedroapfilho/usebutr/commit/bc5b58cd87601be38dbb77a14e16eaaa36e8f012)]:
8
+ - @usebutr/wallet-standard-shared@1.0.0
9
+ - @usebutr/core@2.0.1
10
+
11
+ ## 1.1.1
12
+
13
+ ### Patch Changes
14
+
15
+ - Updated dependencies [302ae4a]
16
+ - @usebutr/wallet-standard-shared@0.5.1
17
+
18
+ ## 1.1.0
19
+
20
+ ### Minor Changes
21
+
22
+ - 9b1caa2: Correctness pass across the storage, hydration and connector layers. Several of
23
+ these change observable behaviour; the ones worth knowing about before upgrading:
24
+
25
+ **Breaking**
26
+
27
+ - `SuiWallet.signTransaction` now returns `{ bytes, signature }` instead of
28
+ `Uint8Array`. Sui's `executeTransactionBlock` needs both, and each connector
29
+ previously returned a different half, so the old value could not be broadcast
30
+ and a consumer could not tell which half they held. SVM and Bitcoin keep their
31
+ single-`Uint8Array` shape.
32
+ - `@usebutr/svm`'s `sendTx` returns the signature base58-encoded, matching the
33
+ WalletConnect namespace, the Ledger app, Solana explorers and
34
+ `getSignatureStatuses`. It previously returned base64.
35
+ - `@usebutr/sui`'s feature input types drop the `string` arm from
36
+ `transaction`; wallets only ever accepted the `toJSON()` form. Strings and BCS
37
+ bytes are now wrapped for you, so `sendTx` accepts strictly more than before.
38
+
39
+ **Behaviour fixes**
40
+
41
+ - `WalletStorage.setPool` and `removePoolEntry` could self-deadlock on a corrupt
42
+ pool payload, leaving `connectWallet` unresolved and every later pool write
43
+ jammed for the page's life. Both are fixed, and `readWalletSnapshot` now shares
44
+ one codec with `WalletStorage` so the server and client decodes cannot drift.
45
+ - A seeded (SSR) entry whose silent reconnect failed used to stay in the pool
46
+ backed by a placeholder connector forever, so `useSigner`/`useBalance`
47
+ reported an error and `useConnectionStatus` reported `"reconnecting"`
48
+ permanently. Those entries are now dropped.
49
+ - `useSigner` and `useBalance` stay `idle` for a wallet that is still
50
+ reconnecting instead of surfacing a placeholder rejection as `status: "error"`.
51
+ - `useConnectionStatus` lets a live `"connecting"`/`"error"` take precedence over
52
+ the derived `"reconnecting"`, so an in-flight attempt and a connection error
53
+ are no longer hidden. New `useIsReconnecting(connectorId?)` answers the
54
+ per-wallet question directly.
55
+ - A background restore no longer writes the connect-attempt status or steals
56
+ `activeConnectorId`, and a superseded `CONNECT_FAILED` no longer overwrites the
57
+ current attempt.
58
+ - An externally-disconnected connector is now torn down, not just dropped from
59
+ the pool, so a cached adapter is not reused while still holding a session.
60
+ - EVM: a malformed provider response is treated as absent rather than `""`, which
61
+ previously produced chain `eip155:0`, zero-length signatures, empty transaction
62
+ hashes and a confident `0 ETH`. `switchChain` gained the same-chain
63
+ short-circuit `sendTxToChain` already had.
64
+ - WalletConnect: accounts carry their own chain instead of all being stamped with
65
+ the active one, so a multi-chain session no longer returns a wrong-chain
66
+ address. One pairing now covers every configured namespace, the pairing URI
67
+ survives a reconnect, and concurrent connects share one pairing.
68
+ - Bitcoin: the sats-connect (Xverse) adapter honours `silent`, so a reload no
69
+ longer triggers an unsolicited approval prompt, and exposes the payment address
70
+ as its single account instead of also presenting the ordinals address as
71
+ spendable.
72
+ - Polkadot: the injected adapter actually delivers events to subscribers,
73
+ `switchChain` notifies like its Wallet Standard sibling, and chain resolution
74
+ prefers the mainnets rather than whatever the wallet listed first.
75
+ - Ledger: the device session is committed atomically, so a locked device no
76
+ longer leaves an open transport that reports itself connected, and concurrent
77
+ connects open one transport.
78
+ - SVM: `sendTxToChain` submits to the chain you asked for instead of the
79
+ adapter's current one, and rejects a chain the wallet does not advertise.
80
+ - `@usebutr/svm`'s `switchChain` capability now counts only `solana:` chains, so
81
+ a multi-namespace wallet no longer advertises a method that always throws.
82
+
83
+ **Testing**
84
+
85
+ - `createFakePersistence` is now the real `WalletStorage` over memory drivers
86
+ rather than a parallel implementation, so it inherits upsert semantics,
87
+ validation and JSON round-tripping. Two divergences are fixed as a result:
88
+ `setPool` upserts rather than replaces, and `clearAll` leaves the
89
+ user-disconnected flag alone.
90
+ - `createFakeConnectedWallet` rejects being given both an `adapter` and explicit
91
+ `addresses`/`accounts`, a combination whose halves could disagree.
92
+
93
+ ### Patch Changes
94
+
95
+ - Updated dependencies [9b1caa2]
96
+ - @usebutr/wallet-standard-shared@0.5.0
97
+ - @usebutr/core@2.0.0
98
+
99
+ ## 1.0.1
100
+
101
+ ### Patch Changes
102
+
103
+ - Updated dependencies [8ecaf89]
104
+ - @usebutr/core@1.1.0
105
+ - @usebutr/wallet-standard-shared@0.4.1
106
+
107
+ ## 1.0.0
108
+
109
+ ### Major Changes
110
+
111
+ - f0a5116: **Breaking:** the `platform` field is gone from the `PlatformDiscoverer` type in `@usebutr/core`, and from the `evmDiscoverer`, `svmDiscoverer`, `suiDiscoverer`, `bitcoinDiscoverer` and `polkadotDiscoverer` objects that implement it. Nothing read it: the aggregator keys discoverers by `ChainPlatform` in its own registry, so the field only restated the key.
112
+
113
+ Migration: read the platform from the `KNOWN_DISCOVERERS` key in `@usebutr/wallets` (`Object.entries(KNOWN_DISCOVERERS)`), or from `adapter.chainPlatform` on a discovered adapter. Custom `PlatformDiscoverer` implementations must drop the `platform` property; keeping it is now an excess-property error.
114
+
115
+ - f0a5116: **Breaking:** `slugify` is no longer exported from `@usebutr/svm`, `@usebutr/sui` or `@usebutr/bitcoin`. Each package exported a one-argument wrapper that only bound a platform prefix onto the canonical two-argument helper, so three names shadowed one implementation.
116
+
117
+ Migration: import `slugify` from `@usebutr/wallet-standard-shared` and pass the platform prefix as the first argument. `slugify(name)` from `@usebutr/svm` becomes `slugify("svm", name)`; the `@usebutr/sui` prefix is `"sui"` and the `@usebutr/bitcoin` prefix is `"btc"`. Adapter ids are byte-for-byte the same.
118
+
119
+ ### Patch Changes
120
+
121
+ - 7887cf0: Resolve capabilities through `buildWalletCapabilities` from `@usebutr/wallet-standard-shared` instead of a per-package copy of the same object literal. Resolver names, input types and returned flags are unchanged. The injected Polkadot profile now derives its chain count from `POLKADOT_CHAINS_LIST` rather than asserting `switchChain: true` directly; the result is the same.
122
+ - 7887cf0: Move each package's `discover*Adapters` function next to the adapter builder it wraps and drop the single-function `wallet-standard.ts` module. The functions are still exported from the package root under the same names; only an internal file boundary went away.
123
+ - Updated dependencies [7887cf0]
124
+ - Updated dependencies [7887cf0]
125
+ - Updated dependencies [f0a5116]
126
+ - Updated dependencies [f0a5116]
127
+ - Updated dependencies [7887cf0]
128
+ - @usebutr/core@1.0.0
129
+ - @usebutr/wallet-standard-shared@0.4.0
130
+
131
+ ## 0.2.7
132
+
133
+ ### Patch Changes
134
+
135
+ - efe4550: Share the session plumbing behind the Wallet Standard and WalletConnect CAIP adapters. `@usebutr/wallet-standard-shared` now exports `createWalletStandardCore`, which the Bitcoin, Polkadot, Sui and SVM adapters build on; the WalletConnect Bitcoin, Sui and SVM namespaces share an equivalent CAIP core. Every package's public API is unchanged. The one visible difference is a dev-console warning: a failed SVM disconnect now logs `[butr] SVM Wallet Standard disconnect threw:` instead of `[butr] Wallet Standard disconnect threw:`.
136
+ - Updated dependencies [efe4550]
137
+ - Updated dependencies [4467a5e]
138
+ - @usebutr/wallet-standard-shared@0.3.0
139
+ - @usebutr/core@0.5.0
140
+
141
+ ## 0.2.6
142
+
143
+ ### Patch Changes
144
+
145
+ - 99eaef0: Restore guards that the type-aware lint pass narrowed away.
146
+
147
+ - `@usebutr/bitcoin`: the sats-connect `getAccounts` reader dropped its optional
148
+ chain on the RPC payload. The declared shape is an assertion over an untyped
149
+ bridge, so a wallet answering without a `result` threw a `TypeError` instead
150
+ of reporting no accounts.
151
+ - `@usebutr/walletconnect`: the Sui and Solana signing paths treated an
152
+ empty-string `transaction` / `transactionBytes` / `bytes` field as a real
153
+ value and decoded it to zero bytes. They now fall through to the signature
154
+ path (Sui `signPersonalMessage`) or the original message, matching the
155
+ previous truthiness checks.
156
+ - `@usebutr/ledger`: the unknown-platform rejection lost the platform name from
157
+ its message, which is the only detail that made the error actionable.
158
+
159
+ - Updated dependencies [c1309ee]
160
+ - @usebutr/core@0.4.2
161
+ - @usebutr/wallet-standard-shared@0.2.6
162
+
163
+ ## 0.2.5
164
+
165
+ ### Patch Changes
166
+
167
+ - 937dfae: Bump runtime dependency floors (`@wallet-standard/app` 1.1.1, `@ledgerhq/*` latest minors, `@walletconnect/universal-provider` 2.23.10) and modernize public type declarations from method signatures to property function types (oxlint `method-signature-style`). Type-level only — no runtime behavior change.
168
+ - Updated dependencies [937dfae]
169
+ - @usebutr/core@0.4.1
170
+ - @usebutr/wallet-standard-shared@0.2.5
171
+
172
+ ## 0.2.4
173
+
174
+ ### Patch Changes
175
+
176
+ - a46eecd: Ship unminified ESM so downstream bundlers (Vite/esbuild dep pre-bundling) process the package correctly; fixes a ReferenceError in consumer dev servers. The consuming app minifies once at its own build.
177
+ - Updated dependencies [b5322ae]
178
+ - Updated dependencies [d5f32c7]
179
+ - Updated dependencies [a46eecd]
180
+ - Updated dependencies [3f26776]
181
+ - @usebutr/core@0.4.0
182
+ - @usebutr/wallet-standard-shared@0.2.4
183
+
184
+ ## 0.2.3
185
+
186
+ ### Patch Changes
187
+
188
+ - Updated dependencies [886ee1d]
189
+ - @usebutr/core@0.3.0
190
+ - @usebutr/wallet-standard-shared@0.2.3
191
+
192
+ ## 0.2.2
193
+
194
+ ### Patch Changes
195
+
196
+ - Updated dependencies [db5d7e9]
197
+ - @usebutr/core@0.2.2
198
+ - @usebutr/wallet-standard-shared@0.2.2
199
+
200
+ ## 0.2.1
201
+
202
+ ### Patch Changes
203
+
204
+ - f846e77: Wallet-announced icons are trimmed of surrounding whitespace on ingestion. Some wallets ship data-URI icons with a leading newline, which strict consumers reject — Next.js's `<Image>` throws because `src` must not start with a control character. `@usebutr/core` exports a `sanitizeIcon` helper; the EIP-6963 and Wallet Standard adapters apply it, and an all-whitespace icon now resolves to `undefined` rather than a blank string.
205
+ - Updated dependencies [f846e77]
206
+ - @usebutr/core@0.2.1
207
+ - @usebutr/wallet-standard-shared@0.2.1
208
+
209
+ ## 0.2.0
210
+
211
+ ### Minor Changes
212
+
213
+ - b77a477: Shared Wallet Standard protocol types (`WalletStandardWallet`, `WalletStandardWalletAccount`, `WalletStandardAppModule`, `WalletsApp`, `StandardConnectFeature`, `StandardDisconnectFeature`, `StandardEventsFeature`, `StandardEventsListener`) are imported from `@usebutr/wallet-standard-shared` directly — they are no longer re-exported from `@usebutr/svm`, `@usebutr/sui`, or `@usebutr/bitcoin`. Platform-specific feature shapes still ship from their own packages.
214
+
215
+ `@usebutr/svm` adapter ids are now platform-prefixed (`wallet-standard:svm-<slug>`), consistent with the `sui-` and `btc-` prefixes. `slugify` in `@usebutr/wallet-standard-shared` requires a non-empty platform prefix.
216
+
217
+ ### Patch Changes
218
+
219
+ - Updated dependencies [b77a477]
220
+ - Updated dependencies [b77a477]
221
+ - @usebutr/core@0.2.0
222
+ - @usebutr/wallet-standard-shared@0.2.0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Pedro Filho
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,39 @@
1
+ # @usebutr/bitcoin
2
+
3
+ Wallet Standard + injected (sats-connect / Unisat / OKX) wallet discovery and adapters for butr (Bitcoin).
4
+
5
+ Part of [butr](https://www.usebutr.com), a multi-chain wallet discovery and
6
+ connection-state library. Your application owns the picker UI and chain client.
7
+
8
+ ## Install
9
+
10
+ ```bash
11
+ npm install @usebutr/react @usebutr/core @usebutr/bitcoin zustand @wallet-standard/app
12
+ ```
13
+
14
+ React 18+ is a peer dependency of the provider. Discovery does not render a connect modal; add your picker as the provider child. `@wallet-standard/app` is required for Wallet Standard discovery.
15
+
16
+ ## Usage
17
+
18
+ ```tsx
19
+ import type { ReactNode } from "react";
20
+ import { createWalletSource } from "@usebutr/core";
21
+ import { discoverBitcoinAdapters } from "@usebutr/bitcoin";
22
+ import { WalletManagerProvider } from "@usebutr/react";
23
+
24
+ const discovery = createWalletSource(discoverBitcoinAdapters);
25
+ export const WalletProvider = ({ children }: { children: ReactNode }) => (
26
+ <WalletManagerProvider discovery={discovery}>{children}</WalletManagerProvider>
27
+ );
28
+ ```
29
+
30
+ ## Documentation
31
+
32
+ - [Package reference](https://docs.usebutr.com/api/bitcoin)
33
+ - [Getting started](https://docs.usebutr.com/getting-started/quickstart)
34
+ - [Examples and source](https://github.com/pedroapfilho/usebutr)
35
+ - [Report an issue](https://github.com/pedroapfilho/usebutr/issues)
36
+
37
+ ## License
38
+
39
+ [MIT](./LICENSE), copyright 2026 Pedro Filho.
package/dist/index.d.ts CHANGED
@@ -11,6 +11,7 @@ type BitcoinSignMessageOutput = {
11
11
  };
12
12
  type BitcoinSignMessageFeature = {
13
13
  signMessage: (input: BitcoinSignMessageInput) => Promise<BitcoinSignMessageOutput>;
14
+ version?: string;
14
15
  };
15
16
  type BitcoinSignPsbtInput = {
16
17
  account: WalletStandardWalletAccount;
@@ -29,6 +30,7 @@ type BitcoinSignPsbtOutput = {
29
30
  };
30
31
  type BitcoinSignPsbtFeature = {
31
32
  signPsbt: (input: BitcoinSignPsbtInput) => Promise<BitcoinSignPsbtOutput>;
33
+ version?: string;
32
34
  };
33
35
  type BitcoinSendTransferInput = {
34
36
  account: WalletStandardWalletAccount;
@@ -42,6 +44,7 @@ type BitcoinSendTransferOutput = {
42
44
  };
43
45
  type BitcoinSendTransferFeature = {
44
46
  sendTransfer: (input: BitcoinSendTransferInput) => Promise<BitcoinSendTransferOutput>;
47
+ version?: string;
45
48
  };
46
49
  //#endregion
47
50
  //#region src/wallet-standard-adapter.d.ts
@@ -105,12 +108,15 @@ declare const resolveBitcoinCapabilities: (input: BitcoinCapabilityInput) => Wal
105
108
  //#endregion
106
109
  //#region src/injected/sats-connect.d.ts
107
110
  /** sats-connect (Xverse) shape; a JSON-RPC-ish `request(method, params)`. */
111
+ type RpcValue = boolean | number | string | null | ReadonlyArray<RpcValue> | {
112
+ readonly [key: string]: RpcValue | undefined;
113
+ };
108
114
  type SatsConnectProvider = {
109
- request: (method: string, params?: Record<string, unknown>) => Promise<{
115
+ request: (method: string, params?: Readonly<Record<string, RpcValue>>) => Promise<{
110
116
  error?: {
111
117
  message: string;
112
118
  };
113
- result?: unknown;
119
+ result?: RpcValue;
114
120
  }>;
115
121
  };
116
122
  //#endregion
@@ -121,13 +127,18 @@ type SatsConnectProvider = {
121
127
  type UnisatProvider = {
122
128
  getAccounts: () => Promise<ReadonlyArray<string>>;
123
129
  getNetwork?: () => Promise<"livenet" | "mainnet" | "testnet" | "signet">;
124
- on?: (event: "accountsChanged" | "networkChanged", listener: (...args: Array<unknown>) => void) => void;
130
+ on?: (event: "accountsChanged" | "networkChanged", listener: (...args: Array<UnisatEventValue>) => void) => void;
125
131
  pushPsbt?: (psbtHex: string) => Promise<string>;
126
- removeListener?: (event: "accountsChanged" | "networkChanged", listener: (...args: Array<unknown>) => void) => void;
132
+ removeListener?: (event: "accountsChanged" | "networkChanged", listener: (...args: Array<UnisatEventValue>) => void) => void;
127
133
  requestAccounts: () => Promise<ReadonlyArray<string>>;
128
134
  sendBitcoin?: (recipient: string, amount: number) => Promise<string>;
129
135
  signMessage: (message: string, type?: "ecdsa" | "bip322-simple") => Promise<string>;
130
- signPsbt: (psbtHex: string, options?: Record<string, unknown>) => Promise<string>;
136
+ signPsbt: (psbtHex: string, options?: UnisatSignPsbtOptions) => Promise<string>;
137
+ };
138
+ type UnisatEventItem = number | string | null;
139
+ type UnisatEventValue = ReadonlyArray<UnisatEventItem> | string | undefined;
140
+ type UnisatSignPsbtOptions = {
141
+ autoFinalized?: boolean;
131
142
  };
132
143
  //#endregion
133
144
  //#region src/injected/icon.d.ts
@@ -148,6 +159,18 @@ type InjectedHost = {
148
159
  BitcoinProvider?: SatsConnectProvider;
149
160
  };
150
161
  };
162
+ declare global {
163
+ interface Window {
164
+ btc?: UnisatProvider;
165
+ okxwallet?: {
166
+ bitcoin?: UnisatProvider;
167
+ };
168
+ unisat?: UnisatProvider;
169
+ XverseProviders?: {
170
+ BitcoinProvider?: SatsConnectProvider;
171
+ };
172
+ }
173
+ }
151
174
  type InjectedBitcoinDiscoveryOptions = {
152
175
  /** Suppresses emission when Wallet Standard discovery has already
153
176
  * registered a Bitcoin adapter for the same browser session. */
@@ -179,23 +202,9 @@ declare const bitcoinDiscoverer: PlatformDiscoverer;
179
202
  * `WalletStandardWallet`, a UniSat-shaped provider, or a sats-connect
180
203
  * `BitcoinProvider` depending on which adapter discovered the wallet.
181
204
  */
182
- type UnisatLike = {
183
- getAccounts: () => Promise<ReadonlyArray<string>>;
184
- requestAccounts: () => Promise<ReadonlyArray<string>>;
185
- signMessage: (message: string, type?: string) => Promise<string>;
186
- signPsbt: (psbtHex: string, options?: Record<string, unknown>) => Promise<string>;
187
- };
188
- type SatsConnectLike = {
189
- request: (method: string, params?: Record<string, unknown>) => Promise<{
190
- error?: {
191
- message: string;
192
- };
193
- result?: unknown;
194
- }>;
195
- };
196
205
  declare module "@usebutr/core" {
197
206
  interface SignerForPlatform {
198
- bitcoin: SatsConnectLike | UnisatLike | WalletStandardWallet;
207
+ bitcoin: SatsConnectProvider | UnisatProvider | WalletStandardWallet;
199
208
  }
200
209
  }
201
210
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../src/wallet-standard-types.ts","../src/wallet-standard-adapter.ts","../src/chains.ts","../src/capabilities.ts","../src/injected/sats-connect.ts","../src/injected/unisat.ts","../src/injected/icon.ts","../src/injected/index.ts","../src/discoverer.ts","../src/signer-augmentation.ts"],"mappings":";;;KAQK;EACH,SAAS;EACT,SAAS;;KAGN;EACH,WAAW;EACX,eAAe;;KAGZ;EACH,cAAc,OAAO,4BAA4B,QAAQ;;KAGtD;EACH,SAAS;;EAET;;EAEA,MAAM;;;EAGN,aAAa;;KAGV;;;EAGH,YAAY;;KAGT;EACH,WAAW,OAAO,yBAAyB,QAAQ;;KAGhD;EACH,SAAS;EACT;EACA;EACA;;KAGG;;EAEH;;KAGG;EACH,eAAe,OAAO,6BAA6B,QAAQ;;;;;;;;;cC/BvD,sBACJ,QAAQ,sBAIR;;;;AAAA,wBAAwB,8BACvB;;cAyIG,0BAA2B,YAAY,SAAS;;;;;;;;cCjKhD;;;;;;;;;;;;;;;;;;;;cAqBA,qBAAqB,cAAc;;;KCzBpC;EACH;EACA;IACE;IACA;IACA;IACA;;;;;;;;cASE,6BAA8B,OAAO,2BAAyB;;;;KCT/D;EACH,UACE,gBACA,SAAS,4BACN;IAAU;MAAU;;IAAmB;;;;;;;;KCFzC;EACH,mBAAmB,QAAQ;EAC3B,mBAAmB;EACnB,MACE,6CACA,cAAc,MAAM;EAEtB,YAAY,oBAAoB;EAChC,kBACE,6CACA,cAAc,MAAM;EAEtB,uBAAuB,QAAQ;EAC/B,eAAe,mBAAmB,mBAAmB;EACrD,cAAc,iBAAiB,qCAAqC;EACpE,WAAW,iBAAiB,UAAU,4BAA4B;;;;;;;;cCtB9D;;;KCKD;EACH,MAAM;EACN;IAAc,UAAU;;EACxB,SAAS;EACT;IAAoB,kBAAkB;;;KAGnC;;;EAGH;;;EAGA;;EAEA,SAAS;;;;;;;cAqDL,iCACJ,YAAY,SAAS,wBACrB,UAAS;;;;;;;;cCrEL,mBAAmB;;;;;;;;KCHpB;EACH,mBAAmB,QAAQ;EAC3B,uBAAuB,QAAQ;EAC/B,cAAc,iBAAiB,kBAAkB;EACjD,WAAW,iBAAiB,UAAU,4BAA4B;;KAG/D;EACH,UACE,gBACA,SAAS,4BACN;IAAU;MAAU;;IAAmB;;;;YAKlC;IACR,SAAS,kBAAkB,aAAa"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../src/wallet-standard-types.ts","../src/wallet-standard-adapter.ts","../src/chains.ts","../src/capabilities.ts","../src/injected/sats-connect.ts","../src/injected/unisat.ts","../src/injected/icon.ts","../src/injected/index.ts","../src/discoverer.ts","../src/signer-augmentation.ts"],"mappings":";;;KAQK;EACH,SAAS;EACT,SAAS;;KAGN;EACH,WAAW;EACX,eAAe;;KAGZ;EACH,cAAc,OAAO,4BAA4B,QAAQ;EACzD;;KAGG;EACH,SAAS;;EAET;;EAEA,MAAM;;;EAGN,aAAa;;KAGV;;;EAGH,YAAY;;KAGT;EACH,WAAW,OAAO,yBAAyB,QAAQ;EACnD;;KAGG;EACH,SAAS;EACT;EACA;EACA;;KAGG;;EAEH;;KAGG;EACH,eAAe,OAAO,6BAA6B,QAAQ;EAC3D;;;;;;;;;cCnBI,sBAAmB,QACf,sBAIe;;;;AAAA,wBAAC,8BACvB;;cAuIG,0BAAuB,YAAgB,SAAS;;;;;;;;cC9KhD;;aAEF;aACA;aACA;aACA;;;aAGA;aACA;aACA;aACA;;;aAGA;aACA;aACA;aACA;;;cAIE,qBAAqB,cAAc;;;KCzBpC;EACH;EACA;IACE;IACA;IACA;IACA;;;;;;;;cASE,6BAA0B,OAAW,2BAAyB;;;;KCF/D,8CAKD,cAAc;YACF,cAAc;;KAEzB;EACH,UACE,gBACA,SAAS,SAAS,eAAe,eAC9B;IAAU;MAAU;;IAAmB,SAAS;;;;;;;;KCjBlD;EACH,mBAAmB,QAAQ;EAC3B,mBAAmB;EACnB,MACE,6CACA,cAAc,MAAM,MAAM;EAE5B,YAAY,oBAAoB;EAChC,kBACE,6CACA,cAAc,MAAM,MAAM;EAE5B,uBAAuB,QAAQ;EAC/B,eAAe,mBAAmB,mBAAmB;EACrD,cAAc,iBAAiB,qCAAqC;EACpE,WAAW,iBAAiB,UAAU,0BAA0B;;KAG7D;KACA,mBAAmB,cAAc;KAEjC;EACH;;;;;;;;cC7BI;;;KCKD;EACH,MAAM;EACN;IAAc,UAAU;;EACxB,SAAS;EACT;IAAoB,kBAAkB;;;QAGhC;YAEI;IACR,MAAM;IACN;MAAc,UAAU;;IACxB,SAAS;IACT;MAAoB,kBAAkB;;;;KAIrC;;;EAGH;;;EAGA;;EAEA,SAAS;;;;;;;cAiDL,iCAA8B,YACtB,SAAS,wBAAsB,UAClC;;;;;;;;cC3EL,mBAAmB;;;;;;;;;YCEb;IACR,SAAS,sBAAsB,iBAAiB"}
package/dist/index.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import { buildAccount, buildWalletCapabilities, createWalletStandardCore, discoverWalletStandard, getFeature, slugify } from "@usebutr/wallet-standard-shared";
2
2
  import { base64ToBytes, bytesToBase64, bytesToHex, hexToBytes } from "@usebutr/core";
3
+ import { z } from "zod";
3
4
 
4
5
  //#region src/capabilities.ts
5
6
  /**
@@ -21,6 +22,9 @@ const resolveBitcoinCapabilities = (input) => buildWalletCapabilities({
21
22
  const BITCOIN_PREFIX = "bip122:";
22
23
  const BITCOIN_DECIMALS = 8;
23
24
  const BITCOIN_MAINNET_ID = "bip122:000000000019d6689c085ae165831e93";
25
+ const isBitcoinSignMessageFeature = (feature) => "signMessage" in feature && typeof feature.signMessage === "function";
26
+ const isBitcoinSignPsbtFeature = (feature) => "signPsbt" in feature && typeof feature.signPsbt === "function";
27
+ const isBitcoinSendTransferFeature = (feature) => "sendTransfer" in feature && typeof feature.sendTransfer === "function";
24
28
  /**
25
29
  * `sendTx` takes `{ amount, recipient }` for `bitcoin:sendTransfer` and
26
30
  * `signTransaction` takes raw PSBT bytes for `bitcoin:signPsbt`. Balance
@@ -39,9 +43,9 @@ const buildBitcoinAdapter = (wallet, registerDisconnector) => {
39
43
  wallet
40
44
  });
41
45
  if (core === null) return null;
42
- const signMessage = getFeature(wallet, "bitcoin:signMessage");
43
- const signPsbt = getFeature(wallet, "bitcoin:signPsbt");
44
- const sendTransfer = getFeature(wallet, "bitcoin:sendTransfer");
46
+ const signMessage = getFeature(wallet, "bitcoin:signMessage", isBitcoinSignMessageFeature);
47
+ const signPsbt = getFeature(wallet, "bitcoin:signPsbt", isBitcoinSignPsbtFeature);
48
+ const sendTransfer = getFeature(wallet, "bitcoin:sendTransfer", isBitcoinSendTransferFeature);
45
49
  /** Resolve a caller-supplied target into a chain the wallet advertises,
46
50
  * accepting either a full CAIP-2 id or a bare genesis-hash reference. */
47
51
  const resolveTargetChain = (targetChainId) => {
@@ -60,7 +64,7 @@ const buildBitcoinAdapter = (wallet, registerDisconnector) => {
60
64
  recipient
61
65
  })).txid;
62
66
  };
63
- return {
67
+ const adapter = {
64
68
  ...core,
65
69
  capabilities: resolveBitcoinCapabilities({
66
70
  chainCount: core.chainCount,
@@ -98,17 +102,18 @@ const buildBitcoinAdapter = (wallet, registerDisconnector) => {
98
102
  signature: output.signature,
99
103
  signedMessage: output.signedMessage
100
104
  };
101
- },
102
- ...signPsbt === void 0 ? {} : { async signTransaction(tx, account) {
103
- const wsAccount = core.resolveAccount(account);
104
- if (!(tx instanceof Uint8Array)) throw new TypeError("Bitcoin signTransaction expects a PSBT as Uint8Array (e.g. psbt.toBuffer())");
105
- return (await signPsbt.signPsbt({
106
- account: wsAccount,
107
- chain: core.currentChainId(),
108
- psbt: tx
109
- })).signedPsbt;
110
- } }
105
+ }
111
106
  };
107
+ if (signPsbt !== void 0) adapter.signTransaction = async (tx, account) => {
108
+ const wsAccount = core.resolveAccount(account);
109
+ if (!(tx instanceof Uint8Array)) throw new TypeError("Bitcoin signTransaction expects a PSBT as Uint8Array (e.g. psbt.toBuffer())");
110
+ return (await signPsbt.signPsbt({
111
+ account: wsAccount,
112
+ chain: core.currentChainId(),
113
+ psbt: tx
114
+ })).signedPsbt;
115
+ };
116
+ return adapter;
112
117
  };
113
118
  /** Requires the optional `@wallet-standard/app` peer dep. */
114
119
  const discoverBitcoinAdapters = (onAdapter) => discoverWalletStandard(onAdapter, (wallet, registerDisconnector) => buildBitcoinAdapter(wallet, registerDisconnector));
@@ -166,6 +171,18 @@ const CAPS_SATS_CONNECT = {
166
171
  };
167
172
  const ACCOUNT_PURPOSES = ["payment", "ordinals"];
168
173
  const CONNECT_MESSAGE = "Connect to butr";
174
+ const satsAddressSchema = z.object({
175
+ address: z.string(),
176
+ publicKey: z.string().optional(),
177
+ purpose: z.string().optional()
178
+ });
179
+ const accountResultSchema = z.object({ addresses: z.array(satsAddressSchema).optional() }).nullable();
180
+ const sendTransferResultSchema = z.object({ txid: z.string() });
181
+ const signMessageResultSchema = z.object({
182
+ messageHash: z.string().optional(),
183
+ signature: z.string()
184
+ });
185
+ const signPsbtResultSchema = z.object({ psbt: z.string() });
169
186
  const pickPaymentAddress = (addresses) => addresses.find((a) => a.purpose === "payment") ?? addresses[0];
170
187
  /**
171
188
  * Only the payment address is exposed as an Account: sats-connect's
@@ -175,13 +192,13 @@ const pickPaymentAddress = (addresses) => addresses.find((a) => a.purpose === "p
175
192
  const buildSatsConnectAdapter = (id, name, provider) => {
176
193
  let chain = BITCOIN_CHAINS.mainnet;
177
194
  let session = { status: "disconnected" };
178
- const callRequest = async (method, params) => {
195
+ const callRequest = async (method, schema, params) => {
179
196
  const response = await provider.request(method, params);
180
197
  if (response.error) throw new Error(`[butr/bitcoin] sats-connect ${method} failed: ${response.error.message}`);
181
- return response.result;
198
+ return schema.parse(response.result);
182
199
  };
183
200
  const startSession = async (method, params) => {
184
- const addresses = (await callRequest(method, params))?.addresses ?? [];
201
+ const addresses = (await callRequest(method, accountResultSchema, params))?.addresses ?? [];
185
202
  const payment = pickPaymentAddress(addresses);
186
203
  if (payment === void 0) throw new Error(`Wallet ${name} returned no addresses from ${method}`);
187
204
  session = {
@@ -210,7 +227,7 @@ const buildSatsConnectAdapter = (id, name, provider) => {
210
227
  if (sender !== requireSession().payment) throw new Error(`Wallet ${name} always debits its payment address; ${sender} cannot be used as the sender.`);
211
228
  if (typeof tx !== "object" || tx === null || !("recipient" in tx) || typeof tx.recipient !== "string" || !("amount" in tx) || typeof tx.amount !== "bigint") throw new TypeError("Bitcoin sendTx expects { amount: bigint, recipient: string }: amount in satoshis");
212
229
  const { amount, recipient } = tx;
213
- return (await callRequest("sendTransfer", { recipients: [{
230
+ return (await callRequest("sendTransfer", sendTransferResultSchema, { recipients: [{
214
231
  address: recipient,
215
232
  amount: amount.toString()
216
233
  }] })).txid;
@@ -250,7 +267,7 @@ const buildSatsConnectAdapter = (id, name, provider) => {
250
267
  },
251
268
  async signMessage(msg, account) {
252
269
  const address = resolveAddress(account);
253
- const result = await callRequest("signMessage", {
270
+ const result = await callRequest("signMessage", signMessageResultSchema, {
254
271
  address,
255
272
  message: new TextDecoder().decode(msg)
256
273
  });
@@ -261,7 +278,7 @@ const buildSatsConnectAdapter = (id, name, provider) => {
261
278
  },
262
279
  async signTransaction(tx) {
263
280
  if (!(tx instanceof Uint8Array)) throw new TypeError("Bitcoin signTransaction expects a PSBT as Uint8Array (e.g. psbt.toBuffer())");
264
- const result = await callRequest("signPsbt", { psbt: bytesToBase64(tx) });
281
+ const result = await callRequest("signPsbt", signPsbtResultSchema, { psbt: bytesToBase64(tx) });
265
282
  return base64ToBytes(result.psbt);
266
283
  },
267
284
  switchChain: (target) => {
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/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 { TransactionInput, WalletAdapter } from \"@usebutr/core\";\nimport {\n createWalletStandardCore,\n discoverWalletStandard,\n getFeature,\n slugify,\n} from \"@usebutr/wallet-standard-shared\";\nimport type { WalletStandardFeature, 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\nconst isBitcoinSignMessageFeature = (\n feature: WalletStandardFeature,\n): feature is WalletStandardFeature & BitcoinSignMessageFeature =>\n \"signMessage\" in feature && typeof feature.signMessage === \"function\";\n\nconst isBitcoinSignPsbtFeature = (\n feature: WalletStandardFeature,\n): feature is WalletStandardFeature & BitcoinSignPsbtFeature =>\n \"signPsbt\" in feature && typeof feature.signPsbt === \"function\";\n\nconst isBitcoinSendTransferFeature = (\n feature: WalletStandardFeature,\n): feature is WalletStandardFeature & BitcoinSendTransferFeature =>\n \"sendTransfer\" in feature && typeof feature.sendTransfer === \"function\";\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(wallet, \"bitcoin:signMessage\", isBitcoinSignMessageFeature);\n const signPsbt = getFeature(wallet, \"bitcoin:signPsbt\", isBitcoinSignPsbtFeature);\n const sendTransfer = getFeature(wallet, \"bitcoin:sendTransfer\", isBitcoinSendTransferFeature);\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: TransactionInput,\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 const adapter: WalletAdapter = {\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 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\n if (signPsbt !== undefined) {\n adapter.signTransaction = async (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 return adapter;\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 {\n Account,\n ChainBase,\n TransactionInput,\n WalletAdapter,\n WalletCapabilities,\n} from \"@usebutr/core\";\nimport { base64ToBytes, bytesToBase64 } from \"@usebutr/core\";\nimport { buildAccount } from \"@usebutr/wallet-standard-shared\";\nimport { z } from \"zod\";\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 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 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 satsAddressSchema = z.object({\n address: z.string(),\n publicKey: z.string().optional(),\n purpose: z.string().optional(),\n});\n\nconst accountResultSchema = z\n .object({ addresses: z.array(satsAddressSchema).optional() })\n .nullable();\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\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 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 result = await callRequest(method, accountResultSchema, 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: TransactionInput, 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(\"sendTransfer\", sendTransferResultSchema, {\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(\"signMessage\", signMessageResultSchema, {\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(\"signPsbt\", signPsbtResultSchema, {\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 { RpcValue, SatsConnectProvider };\nexport { buildSatsConnectAdapter };\n","import type { ChainBase, TransactionInput, 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<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};\n\ntype UnisatEventItem = number | string | null;\ntype UnisatEventValue = ReadonlyArray<UnisatEventItem> | string | undefined;\n\ntype UnisatSignPsbtOptions = {\n autoFinalized?: boolean;\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: UnisatEventValue | undefined): 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: TransactionInput): 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<UnisatEventValue>) => {\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\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<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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"}
package/package.json CHANGED
@@ -1,7 +1,23 @@
1
1
  {
2
2
  "name": "@usebutr/bitcoin",
3
- "version": "1.1.0",
3
+ "version": "1.1.2",
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,12 +42,13 @@
25
42
  "access": "public"
26
43
  },
27
44
  "dependencies": {
28
- "@usebutr/core": "2.0.0",
29
- "@usebutr/wallet-standard-shared": "0.5.0"
45
+ "zod": "^4.4.3",
46
+ "@usebutr/core": "2.0.1",
47
+ "@usebutr/wallet-standard-shared": "1.0.0"
30
48
  },
31
49
  "devDependencies": {
32
50
  "@wallet-standard/app": "^1.1.1",
33
- "typescript": "^6.0.3",
51
+ "typescript": "^7.0.2",
34
52
  "vitest": "^4.1.10",
35
53
  "@repo/config-vitest": "0.0.0",
36
54
  "@repo/typescript-config": "0.0.0"