otx-btc-wallet-react 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +726 -0
- package/dist/index.d.mts +436 -0
- package/dist/index.d.ts +436 -0
- package/dist/index.js +586 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +573 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +45 -0
- package/src/context.tsx +24 -0
- package/src/hooks/useAccount.ts +74 -0
- package/src/hooks/useConnect.ts +136 -0
- package/src/hooks/useDisconnect.ts +95 -0
- package/src/hooks/useMultiAddress.ts +135 -0
- package/src/hooks/useNetwork.ts +33 -0
- package/src/hooks/useSendTransaction.ts +137 -0
- package/src/hooks/useSignMessage.ts +136 -0
- package/src/hooks/useSignPsbt.ts +144 -0
- package/src/hooks/useSignPsbts.ts +164 -0
- package/src/index.ts +31 -0
- package/src/provider.tsx +70 -0
package/README.md
ADDED
|
@@ -0,0 +1,726 @@
|
|
|
1
|
+
# otx-btc-wallet-react
|
|
2
|
+
|
|
3
|
+
React provider and hooks for the `otx-btc-wallet` library. Provides a complete set of hooks for connecting wallets, signing messages, signing PSBTs, and sending Bitcoin.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pnpm add otx-btc-wallet-react otx-btc-wallet-core otx-btc-wallet-connectors
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
### 1. Setup Provider
|
|
14
|
+
|
|
15
|
+
Wrap your app with `BtcWalletProvider` and pass a config created with `createConfig()`:
|
|
16
|
+
|
|
17
|
+
```tsx
|
|
18
|
+
import { createConfig } from 'otx-btc-wallet-core';
|
|
19
|
+
import { BtcWalletProvider } from 'otx-btc-wallet-react';
|
|
20
|
+
import { UnisatConnector, XverseConnector } from 'otx-btc-wallet-connectors';
|
|
21
|
+
|
|
22
|
+
const config = createConfig({
|
|
23
|
+
connectors: [
|
|
24
|
+
new UnisatConnector(),
|
|
25
|
+
new XverseConnector(),
|
|
26
|
+
],
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
function App() {
|
|
30
|
+
return (
|
|
31
|
+
<BtcWalletProvider config={config}>
|
|
32
|
+
<YourApp />
|
|
33
|
+
</BtcWalletProvider>
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### 2. Use Hooks
|
|
39
|
+
|
|
40
|
+
```tsx
|
|
41
|
+
import { useAccount, useConnect, useDisconnect } from 'otx-btc-wallet-react';
|
|
42
|
+
|
|
43
|
+
function WalletButton() {
|
|
44
|
+
const { address, isConnected } = useAccount();
|
|
45
|
+
const { connect, connectors, isLoading } = useConnect();
|
|
46
|
+
const { disconnect } = useDisconnect();
|
|
47
|
+
|
|
48
|
+
if (isConnected) {
|
|
49
|
+
return (
|
|
50
|
+
<div>
|
|
51
|
+
<p>{address}</p>
|
|
52
|
+
<button onClick={() => disconnect()}>Disconnect</button>
|
|
53
|
+
</div>
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return (
|
|
58
|
+
<div>
|
|
59
|
+
{connectors.map((connector) => (
|
|
60
|
+
<button
|
|
61
|
+
key={connector.id}
|
|
62
|
+
onClick={() => connect({ connector })}
|
|
63
|
+
disabled={!connector.ready || isLoading}
|
|
64
|
+
>
|
|
65
|
+
{connector.name}
|
|
66
|
+
{!connector.ready && ' (not installed)'}
|
|
67
|
+
</button>
|
|
68
|
+
))}
|
|
69
|
+
</div>
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Provider
|
|
75
|
+
|
|
76
|
+
### `BtcWalletProvider`
|
|
77
|
+
|
|
78
|
+
Required wrapper component. Must be placed above any component that uses hooks.
|
|
79
|
+
|
|
80
|
+
```tsx
|
|
81
|
+
import { BtcWalletProvider } from 'otx-btc-wallet-react';
|
|
82
|
+
|
|
83
|
+
<BtcWalletProvider config={config}>
|
|
84
|
+
{children}
|
|
85
|
+
</BtcWalletProvider>
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
**Props:**
|
|
89
|
+
|
|
90
|
+
| Prop | Type | Description |
|
|
91
|
+
|------|------|-------------|
|
|
92
|
+
| `config` | `ResolvedConfig` | Config object from `createConfig()` |
|
|
93
|
+
| `children` | `ReactNode` | Child components |
|
|
94
|
+
|
|
95
|
+
**Behavior:**
|
|
96
|
+
- Provides the config context to all child hooks
|
|
97
|
+
- Handles auto-reconnect on mount if `autoConnect` is enabled and a previous wallet session exists
|
|
98
|
+
|
|
99
|
+
## Hooks
|
|
100
|
+
|
|
101
|
+
### `useConfig`
|
|
102
|
+
|
|
103
|
+
Access the config object directly. Useful for advanced store operations.
|
|
104
|
+
|
|
105
|
+
```tsx
|
|
106
|
+
import { useConfig } from 'otx-btc-wallet-react';
|
|
107
|
+
|
|
108
|
+
function Debug() {
|
|
109
|
+
const config = useConfig();
|
|
110
|
+
const state = config.store.getState();
|
|
111
|
+
|
|
112
|
+
return <pre>{JSON.stringify(state, null, 2)}</pre>;
|
|
113
|
+
}
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
**Returns:** `ResolvedConfig` - The full config object including the Zustand store.
|
|
117
|
+
|
|
118
|
+
---
|
|
119
|
+
|
|
120
|
+
### `useAccount`
|
|
121
|
+
|
|
122
|
+
Get the connected account information. Reactively updates when the account changes.
|
|
123
|
+
|
|
124
|
+
```tsx
|
|
125
|
+
import { useAccount } from 'otx-btc-wallet-react';
|
|
126
|
+
|
|
127
|
+
function Account() {
|
|
128
|
+
const {
|
|
129
|
+
address, // string | undefined
|
|
130
|
+
publicKey, // string | undefined
|
|
131
|
+
addressType, // AddressType | undefined ('legacy' | 'nested-segwit' | 'segwit' | 'taproot')
|
|
132
|
+
account, // WalletAccount | undefined
|
|
133
|
+
connector, // BitcoinConnector | undefined
|
|
134
|
+
status, // ConnectionStatus
|
|
135
|
+
isConnected, // boolean
|
|
136
|
+
isConnecting, // boolean
|
|
137
|
+
isDisconnected, // boolean
|
|
138
|
+
isReconnecting, // boolean
|
|
139
|
+
} = useAccount();
|
|
140
|
+
|
|
141
|
+
if (!isConnected) return <p>Not connected</p>;
|
|
142
|
+
|
|
143
|
+
return (
|
|
144
|
+
<div>
|
|
145
|
+
<p>Address: {address}</p>
|
|
146
|
+
<p>Type: {addressType}</p>
|
|
147
|
+
<p>Public Key: {publicKey}</p>
|
|
148
|
+
</div>
|
|
149
|
+
);
|
|
150
|
+
}
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
**Return Type: `UseAccountReturn`**
|
|
154
|
+
|
|
155
|
+
| Field | Type | Description |
|
|
156
|
+
|-------|------|-------------|
|
|
157
|
+
| `address` | `string \| undefined` | Connected Bitcoin address |
|
|
158
|
+
| `publicKey` | `string \| undefined` | Hex-encoded public key |
|
|
159
|
+
| `addressType` | `AddressType \| undefined` | Address type |
|
|
160
|
+
| `account` | `WalletAccount \| undefined` | Full account object |
|
|
161
|
+
| `connector` | `BitcoinConnector \| undefined` | Active connector instance |
|
|
162
|
+
| `status` | `ConnectionStatus` | `'connected'` \| `'connecting'` \| `'disconnected'` \| `'reconnecting'` |
|
|
163
|
+
| `isConnected` | `boolean` | `true` when status is `'connected'` |
|
|
164
|
+
| `isConnecting` | `boolean` | `true` when status is `'connecting'` |
|
|
165
|
+
| `isDisconnected` | `boolean` | `true` when status is `'disconnected'` |
|
|
166
|
+
| `isReconnecting` | `boolean` | `true` when status is `'reconnecting'` |
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
170
|
+
### `useConnect`
|
|
171
|
+
|
|
172
|
+
Connect to a wallet connector.
|
|
173
|
+
|
|
174
|
+
```tsx
|
|
175
|
+
import { useConnect } from 'otx-btc-wallet-react';
|
|
176
|
+
|
|
177
|
+
function ConnectWallet() {
|
|
178
|
+
const {
|
|
179
|
+
connect, // (args: ConnectArgs) => void
|
|
180
|
+
connectAsync, // (args: ConnectArgs) => Promise<WalletAccount>
|
|
181
|
+
connectors, // BitcoinConnector[]
|
|
182
|
+
isLoading, // boolean
|
|
183
|
+
isSuccess, // boolean
|
|
184
|
+
isError, // boolean
|
|
185
|
+
error, // Error | null
|
|
186
|
+
reset, // () => void
|
|
187
|
+
} = useConnect();
|
|
188
|
+
|
|
189
|
+
return (
|
|
190
|
+
<div>
|
|
191
|
+
{connectors.map((connector) => (
|
|
192
|
+
<button
|
|
193
|
+
key={connector.id}
|
|
194
|
+
onClick={() => connect({ connector })}
|
|
195
|
+
disabled={!connector.ready || isLoading}
|
|
196
|
+
>
|
|
197
|
+
{connector.name}
|
|
198
|
+
{!connector.ready && ' (not installed)'}
|
|
199
|
+
</button>
|
|
200
|
+
))}
|
|
201
|
+
{isError && <p>Error: {error?.message}</p>}
|
|
202
|
+
</div>
|
|
203
|
+
);
|
|
204
|
+
}
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
**Connect Args:**
|
|
208
|
+
|
|
209
|
+
```typescript
|
|
210
|
+
type ConnectArgs = {
|
|
211
|
+
connector: BitcoinConnector; // The connector to use
|
|
212
|
+
network?: BitcoinNetwork; // Optional network override
|
|
213
|
+
};
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
**Return Type: `UseConnectReturn`**
|
|
217
|
+
|
|
218
|
+
| Field | Type | Description |
|
|
219
|
+
|-------|------|-------------|
|
|
220
|
+
| `connect` | `(args: ConnectArgs) => void` | Fire-and-forget connect |
|
|
221
|
+
| `connectAsync` | `(args: ConnectArgs) => Promise<WalletAccount>` | Connect and await result |
|
|
222
|
+
| `connectors` | `BitcoinConnector[]` | All registered connectors |
|
|
223
|
+
| `isLoading` | `boolean` | Connection in progress |
|
|
224
|
+
| `isSuccess` | `boolean` | Connection succeeded |
|
|
225
|
+
| `isError` | `boolean` | Connection failed |
|
|
226
|
+
| `error` | `Error \| null` | Error details |
|
|
227
|
+
| `reset` | `() => void` | Reset loading/error/success state |
|
|
228
|
+
|
|
229
|
+
**Async Usage:**
|
|
230
|
+
|
|
231
|
+
```tsx
|
|
232
|
+
const handleConnect = async () => {
|
|
233
|
+
try {
|
|
234
|
+
const account = await connectAsync({ connector, network: 'testnet' });
|
|
235
|
+
console.log('Connected:', account.address);
|
|
236
|
+
} catch (err) {
|
|
237
|
+
console.error('Connection failed:', err);
|
|
238
|
+
}
|
|
239
|
+
};
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
---
|
|
243
|
+
|
|
244
|
+
### `useDisconnect`
|
|
245
|
+
|
|
246
|
+
Disconnect the current wallet.
|
|
247
|
+
|
|
248
|
+
```tsx
|
|
249
|
+
import { useDisconnect } from 'otx-btc-wallet-react';
|
|
250
|
+
|
|
251
|
+
function DisconnectButton() {
|
|
252
|
+
const {
|
|
253
|
+
disconnect, // () => void
|
|
254
|
+
disconnectAsync, // () => Promise<void>
|
|
255
|
+
isLoading, // boolean
|
|
256
|
+
isSuccess, // boolean
|
|
257
|
+
isError, // boolean
|
|
258
|
+
error, // Error | null
|
|
259
|
+
} = useDisconnect();
|
|
260
|
+
|
|
261
|
+
return (
|
|
262
|
+
<button onClick={() => disconnect()} disabled={isLoading}>
|
|
263
|
+
Disconnect
|
|
264
|
+
</button>
|
|
265
|
+
);
|
|
266
|
+
}
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
**Return Type: `UseDisconnectReturn`**
|
|
270
|
+
|
|
271
|
+
| Field | Type | Description |
|
|
272
|
+
|-------|------|-------------|
|
|
273
|
+
| `disconnect` | `() => void` | Fire-and-forget disconnect |
|
|
274
|
+
| `disconnectAsync` | `() => Promise<void>` | Disconnect and await completion |
|
|
275
|
+
| `isLoading` | `boolean` | Disconnect in progress |
|
|
276
|
+
| `isSuccess` | `boolean` | Disconnect succeeded |
|
|
277
|
+
| `isError` | `boolean` | Disconnect failed |
|
|
278
|
+
| `error` | `Error \| null` | Error details |
|
|
279
|
+
|
|
280
|
+
---
|
|
281
|
+
|
|
282
|
+
### `useNetwork`
|
|
283
|
+
|
|
284
|
+
Get the current Bitcoin network.
|
|
285
|
+
|
|
286
|
+
```tsx
|
|
287
|
+
import { useNetwork } from 'otx-btc-wallet-react';
|
|
288
|
+
|
|
289
|
+
function NetworkInfo() {
|
|
290
|
+
const { network } = useNetwork();
|
|
291
|
+
// 'mainnet' | 'testnet' | 'testnet4' | 'signet'
|
|
292
|
+
|
|
293
|
+
return <p>Network: {network}</p>;
|
|
294
|
+
}
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
**Return Type: `UseNetworkReturn`**
|
|
298
|
+
|
|
299
|
+
| Field | Type | Description |
|
|
300
|
+
|-------|------|-------------|
|
|
301
|
+
| `network` | `BitcoinNetwork` | Current Bitcoin network |
|
|
302
|
+
|
|
303
|
+
---
|
|
304
|
+
|
|
305
|
+
### `useSignMessage`
|
|
306
|
+
|
|
307
|
+
Sign a text message with the connected wallet.
|
|
308
|
+
|
|
309
|
+
```tsx
|
|
310
|
+
import { useSignMessage } from 'otx-btc-wallet-react';
|
|
311
|
+
|
|
312
|
+
function SignMessage() {
|
|
313
|
+
const {
|
|
314
|
+
signMessage, // (args: { message: string }) => void
|
|
315
|
+
signMessageAsync, // (args: { message: string }) => Promise<string>
|
|
316
|
+
data, // string | undefined (signature)
|
|
317
|
+
isLoading, // boolean
|
|
318
|
+
isSuccess, // boolean
|
|
319
|
+
isError, // boolean
|
|
320
|
+
error, // Error | null
|
|
321
|
+
reset, // () => void
|
|
322
|
+
} = useSignMessage();
|
|
323
|
+
|
|
324
|
+
return (
|
|
325
|
+
<div>
|
|
326
|
+
<button
|
|
327
|
+
onClick={() => signMessage({ message: 'Hello Bitcoin!' })}
|
|
328
|
+
disabled={isLoading}
|
|
329
|
+
>
|
|
330
|
+
Sign Message
|
|
331
|
+
</button>
|
|
332
|
+
{data && <p>Signature: {data}</p>}
|
|
333
|
+
{isError && <p>Error: {error?.message}</p>}
|
|
334
|
+
</div>
|
|
335
|
+
);
|
|
336
|
+
}
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
**Return Type: `UseSignMessageReturn`**
|
|
340
|
+
|
|
341
|
+
| Field | Type | Description |
|
|
342
|
+
|-------|------|-------------|
|
|
343
|
+
| `signMessage` | `(args: { message: string }) => void` | Fire-and-forget sign |
|
|
344
|
+
| `signMessageAsync` | `(args: { message: string }) => Promise<string>` | Sign and await signature |
|
|
345
|
+
| `data` | `string \| undefined` | The resulting signature |
|
|
346
|
+
| `isLoading` | `boolean` | Signing in progress |
|
|
347
|
+
| `isSuccess` | `boolean` | Signing succeeded |
|
|
348
|
+
| `isError` | `boolean` | Signing failed |
|
|
349
|
+
| `error` | `Error \| null` | Error details |
|
|
350
|
+
| `reset` | `() => void` | Reset state |
|
|
351
|
+
|
|
352
|
+
---
|
|
353
|
+
|
|
354
|
+
### `useSignPsbt`
|
|
355
|
+
|
|
356
|
+
Sign a single PSBT (Partially Signed Bitcoin Transaction).
|
|
357
|
+
|
|
358
|
+
```tsx
|
|
359
|
+
import { useSignPsbt } from 'otx-btc-wallet-react';
|
|
360
|
+
|
|
361
|
+
function SignTransaction() {
|
|
362
|
+
const {
|
|
363
|
+
signPsbt, // (args) => void
|
|
364
|
+
signPsbtAsync, // (args) => Promise<string>
|
|
365
|
+
data, // string | undefined (signed PSBT hex)
|
|
366
|
+
isLoading,
|
|
367
|
+
isSuccess,
|
|
368
|
+
isError,
|
|
369
|
+
error,
|
|
370
|
+
reset,
|
|
371
|
+
} = useSignPsbt();
|
|
372
|
+
|
|
373
|
+
const handleSign = () => {
|
|
374
|
+
signPsbt({
|
|
375
|
+
psbt: '70736274ff01...', // PSBT hex string
|
|
376
|
+
options: {
|
|
377
|
+
autoFinalize: true,
|
|
378
|
+
broadcast: false,
|
|
379
|
+
toSignInputs: [
|
|
380
|
+
{ index: 0, address: 'bc1q...' },
|
|
381
|
+
],
|
|
382
|
+
},
|
|
383
|
+
});
|
|
384
|
+
};
|
|
385
|
+
|
|
386
|
+
return (
|
|
387
|
+
<div>
|
|
388
|
+
<button onClick={handleSign} disabled={isLoading}>
|
|
389
|
+
Sign PSBT
|
|
390
|
+
</button>
|
|
391
|
+
{data && <p>Signed: {data}</p>}
|
|
392
|
+
</div>
|
|
393
|
+
);
|
|
394
|
+
}
|
|
395
|
+
```
|
|
396
|
+
|
|
397
|
+
**Return Type: `UseSignPsbtReturn`**
|
|
398
|
+
|
|
399
|
+
| Field | Type | Description |
|
|
400
|
+
|-------|------|-------------|
|
|
401
|
+
| `signPsbt` | `(args: { psbt: string; options?: SignPsbtOptions }) => void` | Fire-and-forget sign |
|
|
402
|
+
| `signPsbtAsync` | `(args: { psbt: string; options?: SignPsbtOptions }) => Promise<string>` | Sign and await result |
|
|
403
|
+
| `data` | `string \| undefined` | Signed PSBT hex |
|
|
404
|
+
| `isLoading` | `boolean` | Signing in progress |
|
|
405
|
+
| `isSuccess` | `boolean` | Signing succeeded |
|
|
406
|
+
| `isError` | `boolean` | Signing failed |
|
|
407
|
+
| `error` | `Error \| null` | Error details |
|
|
408
|
+
| `reset` | `() => void` | Reset state |
|
|
409
|
+
|
|
410
|
+
---
|
|
411
|
+
|
|
412
|
+
### `useSignPsbts`
|
|
413
|
+
|
|
414
|
+
Sign multiple PSBTs in a batch. Not all wallets support this (check `isSupported`).
|
|
415
|
+
|
|
416
|
+
```tsx
|
|
417
|
+
import { useSignPsbts } from 'otx-btc-wallet-react';
|
|
418
|
+
|
|
419
|
+
function BatchSign() {
|
|
420
|
+
const {
|
|
421
|
+
signPsbts, // (args) => void
|
|
422
|
+
signPsbtsAsync, // (args) => Promise<string[]>
|
|
423
|
+
data, // string[] | undefined (signed PSBT hex array)
|
|
424
|
+
isLoading,
|
|
425
|
+
isSuccess,
|
|
426
|
+
isError,
|
|
427
|
+
error,
|
|
428
|
+
isSupported, // boolean - does the wallet support batch signing?
|
|
429
|
+
reset,
|
|
430
|
+
} = useSignPsbts();
|
|
431
|
+
|
|
432
|
+
if (!isSupported) {
|
|
433
|
+
return <p>This wallet does not support batch signing.</p>;
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
return (
|
|
437
|
+
<button
|
|
438
|
+
onClick={() => signPsbts({
|
|
439
|
+
psbts: [psbt1Hex, psbt2Hex],
|
|
440
|
+
options: { autoFinalize: true },
|
|
441
|
+
})}
|
|
442
|
+
disabled={isLoading}
|
|
443
|
+
>
|
|
444
|
+
Sign {2} PSBTs
|
|
445
|
+
</button>
|
|
446
|
+
);
|
|
447
|
+
}
|
|
448
|
+
```
|
|
449
|
+
|
|
450
|
+
**Return Type: `UseSignPsbtsReturn`**
|
|
451
|
+
|
|
452
|
+
| Field | Type | Description |
|
|
453
|
+
|-------|------|-------------|
|
|
454
|
+
| `signPsbts` | `(args: { psbts: string[]; options?: SignPsbtOptions }) => void` | Fire-and-forget batch sign |
|
|
455
|
+
| `signPsbtsAsync` | `(args: { psbts: string[]; options?: SignPsbtOptions }) => Promise<string[]>` | Sign and await results |
|
|
456
|
+
| `data` | `string[] \| undefined` | Array of signed PSBT hex strings |
|
|
457
|
+
| `isLoading` | `boolean` | Signing in progress |
|
|
458
|
+
| `isSuccess` | `boolean` | Signing succeeded |
|
|
459
|
+
| `isError` | `boolean` | Signing failed |
|
|
460
|
+
| `error` | `Error \| null` | Error details |
|
|
461
|
+
| `isSupported` | `boolean` | `true` if the connected wallet has `signPsbts` method |
|
|
462
|
+
| `reset` | `() => void` | Reset state |
|
|
463
|
+
|
|
464
|
+
**Supported wallets:** Currently only Unisat supports batch PSBT signing.
|
|
465
|
+
|
|
466
|
+
---
|
|
467
|
+
|
|
468
|
+
### `useSendTransaction`
|
|
469
|
+
|
|
470
|
+
Send Bitcoin to an address. Amount is specified in satoshis.
|
|
471
|
+
|
|
472
|
+
```tsx
|
|
473
|
+
import { useSendTransaction } from 'otx-btc-wallet-react';
|
|
474
|
+
|
|
475
|
+
function SendBitcoin() {
|
|
476
|
+
const {
|
|
477
|
+
sendTransaction, // (args: { to: string; amount: number }) => void
|
|
478
|
+
sendTransactionAsync, // (args: { to: string; amount: number }) => Promise<string>
|
|
479
|
+
data, // string | undefined (transaction ID)
|
|
480
|
+
isLoading,
|
|
481
|
+
isSuccess,
|
|
482
|
+
isError,
|
|
483
|
+
error,
|
|
484
|
+
reset,
|
|
485
|
+
} = useSendTransaction();
|
|
486
|
+
|
|
487
|
+
return (
|
|
488
|
+
<div>
|
|
489
|
+
<button
|
|
490
|
+
onClick={() => sendTransaction({
|
|
491
|
+
to: 'bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh',
|
|
492
|
+
amount: 10000, // 10,000 satoshis
|
|
493
|
+
})}
|
|
494
|
+
disabled={isLoading}
|
|
495
|
+
>
|
|
496
|
+
Send 10,000 sats
|
|
497
|
+
</button>
|
|
498
|
+
{data && <p>TX ID: {data}</p>}
|
|
499
|
+
{isError && <p>Error: {error?.message}</p>}
|
|
500
|
+
</div>
|
|
501
|
+
);
|
|
502
|
+
}
|
|
503
|
+
```
|
|
504
|
+
|
|
505
|
+
**Return Type: `UseSendTransactionReturn`**
|
|
506
|
+
|
|
507
|
+
| Field | Type | Description |
|
|
508
|
+
|-------|------|-------------|
|
|
509
|
+
| `sendTransaction` | `(args: { to: string; amount: number }) => void` | Fire-and-forget send |
|
|
510
|
+
| `sendTransactionAsync` | `(args: { to: string; amount: number }) => Promise<string>` | Send and await txid |
|
|
511
|
+
| `data` | `string \| undefined` | Transaction ID |
|
|
512
|
+
| `isLoading` | `boolean` | Transaction in progress |
|
|
513
|
+
| `isSuccess` | `boolean` | Transaction succeeded |
|
|
514
|
+
| `isError` | `boolean` | Transaction failed |
|
|
515
|
+
| `error` | `Error \| null` | Error details |
|
|
516
|
+
| `reset` | `() => void` | Reset state |
|
|
517
|
+
|
|
518
|
+
---
|
|
519
|
+
|
|
520
|
+
### `useMultiAddress`
|
|
521
|
+
|
|
522
|
+
Manage multiple addresses from a single wallet. Useful for wallets like Xverse that provide separate payment and ordinals addresses.
|
|
523
|
+
|
|
524
|
+
```tsx
|
|
525
|
+
import { useMultiAddress } from 'otx-btc-wallet-react';
|
|
526
|
+
|
|
527
|
+
function MultiAddress() {
|
|
528
|
+
const {
|
|
529
|
+
addresses, // WalletAccount[] - all addresses
|
|
530
|
+
paymentAddress, // WalletAccount | null - segwit/nested-segwit address
|
|
531
|
+
ordinalsAddress, // WalletAccount | null - taproot address
|
|
532
|
+
primaryAddress, // WalletAccount | null - currently selected
|
|
533
|
+
setPrimaryAddress, // (address: WalletAccount) => void
|
|
534
|
+
isLoading, // boolean
|
|
535
|
+
refresh, // () => Promise<void> - refetch from wallet
|
|
536
|
+
} = useMultiAddress();
|
|
537
|
+
|
|
538
|
+
return (
|
|
539
|
+
<div>
|
|
540
|
+
{paymentAddress && (
|
|
541
|
+
<p>Payment: {paymentAddress.address} ({paymentAddress.type})</p>
|
|
542
|
+
)}
|
|
543
|
+
{ordinalsAddress && (
|
|
544
|
+
<p>Ordinals: {ordinalsAddress.address} ({ordinalsAddress.type})</p>
|
|
545
|
+
)}
|
|
546
|
+
|
|
547
|
+
<h3>All Addresses:</h3>
|
|
548
|
+
{addresses.map((addr) => (
|
|
549
|
+
<button
|
|
550
|
+
key={addr.address}
|
|
551
|
+
onClick={() => setPrimaryAddress(addr)}
|
|
552
|
+
style={{ fontWeight: addr === primaryAddress ? 'bold' : 'normal' }}
|
|
553
|
+
>
|
|
554
|
+
{addr.address} ({addr.type})
|
|
555
|
+
</button>
|
|
556
|
+
))}
|
|
557
|
+
|
|
558
|
+
<button onClick={refresh}>Refresh</button>
|
|
559
|
+
</div>
|
|
560
|
+
);
|
|
561
|
+
}
|
|
562
|
+
```
|
|
563
|
+
|
|
564
|
+
**Return Type: `UseMultiAddressReturn`**
|
|
565
|
+
|
|
566
|
+
| Field | Type | Description |
|
|
567
|
+
|-------|------|-------------|
|
|
568
|
+
| `addresses` | `WalletAccount[]` | All wallet addresses |
|
|
569
|
+
| `paymentAddress` | `WalletAccount \| null` | First segwit or nested-segwit address (for payments) |
|
|
570
|
+
| `ordinalsAddress` | `WalletAccount \| null` | First taproot address (for ordinals/inscriptions) |
|
|
571
|
+
| `primaryAddress` | `WalletAccount \| null` | Currently selected address |
|
|
572
|
+
| `setPrimaryAddress` | `(address: WalletAccount) => void` | Change the primary address |
|
|
573
|
+
| `isLoading` | `boolean` | Fetching addresses |
|
|
574
|
+
| `refresh` | `() => Promise<void>` | Re-fetch addresses from the wallet |
|
|
575
|
+
|
|
576
|
+
**Address Selection Logic:**
|
|
577
|
+
- `paymentAddress`: First address with type `'segwit'` or `'nested-segwit'`, falls back to the first address
|
|
578
|
+
- `ordinalsAddress`: First address with type `'taproot'`
|
|
579
|
+
|
|
580
|
+
## Hook Patterns
|
|
581
|
+
|
|
582
|
+
All action hooks follow a consistent pattern:
|
|
583
|
+
|
|
584
|
+
### Fire-and-Forget vs Async
|
|
585
|
+
|
|
586
|
+
Every action hook provides two versions:
|
|
587
|
+
- **`action()`** - Fire-and-forget. Updates internal state (`isLoading`, `isSuccess`, `isError`, `data`).
|
|
588
|
+
- **`actionAsync()`** - Returns a Promise. Use with `try/catch` for more control.
|
|
589
|
+
|
|
590
|
+
```tsx
|
|
591
|
+
// Fire-and-forget (state updates automatically)
|
|
592
|
+
signMessage({ message: 'Hello' });
|
|
593
|
+
|
|
594
|
+
// Async (handle result directly)
|
|
595
|
+
try {
|
|
596
|
+
const signature = await signMessageAsync({ message: 'Hello' });
|
|
597
|
+
doSomethingWith(signature);
|
|
598
|
+
} catch (err) {
|
|
599
|
+
handleError(err);
|
|
600
|
+
}
|
|
601
|
+
```
|
|
602
|
+
|
|
603
|
+
### Reset State
|
|
604
|
+
|
|
605
|
+
All action hooks provide a `reset()` method to clear `data`, `error`, `isSuccess`, and `isError` back to their initial values.
|
|
606
|
+
|
|
607
|
+
```tsx
|
|
608
|
+
const { signMessage, data, reset } = useSignMessage();
|
|
609
|
+
|
|
610
|
+
// After showing result, clear it
|
|
611
|
+
<button onClick={reset}>Clear</button>
|
|
612
|
+
```
|
|
613
|
+
|
|
614
|
+
## Complete Example
|
|
615
|
+
|
|
616
|
+
```tsx
|
|
617
|
+
import { createConfig } from 'otx-btc-wallet-core';
|
|
618
|
+
import {
|
|
619
|
+
BtcWalletProvider,
|
|
620
|
+
useAccount,
|
|
621
|
+
useConnect,
|
|
622
|
+
useDisconnect,
|
|
623
|
+
useSignMessage,
|
|
624
|
+
useSendTransaction,
|
|
625
|
+
useNetwork,
|
|
626
|
+
} from 'otx-btc-wallet-react';
|
|
627
|
+
import { UnisatConnector, OKXConnector } from 'otx-btc-wallet-connectors';
|
|
628
|
+
|
|
629
|
+
const config = createConfig({
|
|
630
|
+
connectors: [new UnisatConnector(), new OKXConnector()],
|
|
631
|
+
});
|
|
632
|
+
|
|
633
|
+
function Wallet() {
|
|
634
|
+
const { address, isConnected, addressType } = useAccount();
|
|
635
|
+
const { connect, connectors, isLoading: connecting } = useConnect();
|
|
636
|
+
const { disconnect } = useDisconnect();
|
|
637
|
+
const { signMessage, data: signature } = useSignMessage();
|
|
638
|
+
const { sendTransaction, data: txid } = useSendTransaction();
|
|
639
|
+
const { network } = useNetwork();
|
|
640
|
+
|
|
641
|
+
if (!isConnected) {
|
|
642
|
+
return (
|
|
643
|
+
<div>
|
|
644
|
+
<h2>Connect Wallet</h2>
|
|
645
|
+
{connectors.map((c) => (
|
|
646
|
+
<button
|
|
647
|
+
key={c.id}
|
|
648
|
+
onClick={() => connect({ connector: c })}
|
|
649
|
+
disabled={!c.ready || connecting}
|
|
650
|
+
>
|
|
651
|
+
{c.name} {!c.ready ? '(not installed)' : ''}
|
|
652
|
+
</button>
|
|
653
|
+
))}
|
|
654
|
+
</div>
|
|
655
|
+
);
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
return (
|
|
659
|
+
<div>
|
|
660
|
+
<p>Address: {address}</p>
|
|
661
|
+
<p>Type: {addressType}</p>
|
|
662
|
+
<p>Network: {network}</p>
|
|
663
|
+
|
|
664
|
+
<button onClick={() => signMessage({ message: 'Hello!' })}>
|
|
665
|
+
Sign Message
|
|
666
|
+
</button>
|
|
667
|
+
{signature && <p>Signature: {signature}</p>}
|
|
668
|
+
|
|
669
|
+
<button onClick={() => sendTransaction({ to: 'bc1q...', amount: 10000 })}>
|
|
670
|
+
Send 10,000 sats
|
|
671
|
+
</button>
|
|
672
|
+
{txid && <p>TX: {txid}</p>}
|
|
673
|
+
|
|
674
|
+
<button onClick={() => disconnect()}>Disconnect</button>
|
|
675
|
+
</div>
|
|
676
|
+
);
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
function App() {
|
|
680
|
+
return (
|
|
681
|
+
<BtcWalletProvider config={config}>
|
|
682
|
+
<Wallet />
|
|
683
|
+
</BtcWalletProvider>
|
|
684
|
+
);
|
|
685
|
+
}
|
|
686
|
+
```
|
|
687
|
+
|
|
688
|
+
## Full Exports
|
|
689
|
+
|
|
690
|
+
```typescript
|
|
691
|
+
// Provider
|
|
692
|
+
export { BtcWalletProvider } from './provider';
|
|
693
|
+
export type { BtcWalletProviderProps } from './provider';
|
|
694
|
+
|
|
695
|
+
// Context
|
|
696
|
+
export { useConfig, BtcWalletContext } from './context';
|
|
697
|
+
|
|
698
|
+
// Hooks
|
|
699
|
+
export { useAccount } from './hooks/useAccount';
|
|
700
|
+
export { useConnect } from './hooks/useConnect';
|
|
701
|
+
export { useDisconnect } from './hooks/useDisconnect';
|
|
702
|
+
export { useNetwork } from './hooks/useNetwork';
|
|
703
|
+
export { useSignMessage } from './hooks/useSignMessage';
|
|
704
|
+
export { useSignPsbt } from './hooks/useSignPsbt';
|
|
705
|
+
export { useSignPsbts } from './hooks/useSignPsbts';
|
|
706
|
+
export { useSendTransaction } from './hooks/useSendTransaction';
|
|
707
|
+
export { useMultiAddress } from './hooks/useMultiAddress';
|
|
708
|
+
|
|
709
|
+
// Return types
|
|
710
|
+
export type {
|
|
711
|
+
UseAccountReturn,
|
|
712
|
+
UseConnectReturn,
|
|
713
|
+
ConnectArgs,
|
|
714
|
+
UseDisconnectReturn,
|
|
715
|
+
UseNetworkReturn,
|
|
716
|
+
UseSignMessageReturn,
|
|
717
|
+
UseSignPsbtReturn,
|
|
718
|
+
UseSignPsbtsReturn,
|
|
719
|
+
UseSendTransactionReturn,
|
|
720
|
+
UseMultiAddressReturn,
|
|
721
|
+
} from './hooks';
|
|
722
|
+
```
|
|
723
|
+
|
|
724
|
+
## License
|
|
725
|
+
|
|
726
|
+
MIT
|