bitcoin-wallet-connector 0.1.0 → 0.2.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.
Files changed (140) hide show
  1. package/README.md +24 -21
  2. package/lib/BitcoinConnectionProvider.d.ts +3 -3
  3. package/lib/BitcoinWalletConnector-BC92ulXx.js +2 -0
  4. package/lib/BitcoinWalletConnector-BC92ulXx.js.map +1 -0
  5. package/lib/{BitcoinWalletAdapterConnector-Bq835yj0.mjs → BitcoinWalletConnector-CS0BshOl.mjs} +11 -19
  6. package/lib/BitcoinWalletConnector-CS0BshOl.mjs.map +1 -0
  7. package/lib/{BitcoinWalletAdapterConnector.d.ts → BitcoinWalletConnector.d.ts} +4 -5
  8. package/lib/BitgetWalletAdapter.impl-D8kqiYDi.mjs +11 -0
  9. package/lib/BitgetWalletAdapter.impl-D8kqiYDi.mjs.map +1 -0
  10. package/lib/BitgetWalletAdapter.impl-DiyzNQ9d.js +2 -0
  11. package/lib/BitgetWalletAdapter.impl-DiyzNQ9d.js.map +1 -0
  12. package/lib/{LeatherWalletAdapter.impl-RUYx555r.mjs → LeatherWalletAdapter.impl-B1PoZS7z.mjs} +48 -37
  13. package/lib/LeatherWalletAdapter.impl-B1PoZS7z.mjs.map +1 -0
  14. package/lib/LeatherWalletAdapter.impl-BIWirus3.js +2 -0
  15. package/lib/LeatherWalletAdapter.impl-BIWirus3.js.map +1 -0
  16. package/lib/{MagicEdenWalletAdapter.impl-CrA6SGvG.mjs → MagicEdenWalletAdapter.impl-B3d5lbkD.mjs} +31 -20
  17. package/lib/MagicEdenWalletAdapter.impl-B3d5lbkD.mjs.map +1 -0
  18. package/lib/MagicEdenWalletAdapter.impl-DLBP3p4o.js +2 -0
  19. package/lib/MagicEdenWalletAdapter.impl-DLBP3p4o.js.map +1 -0
  20. package/lib/OkxWalletAdapter.impl-7cj96tmr.js +2 -0
  21. package/lib/OkxWalletAdapter.impl-7cj96tmr.js.map +1 -0
  22. package/lib/{OkxWalletAdapter.impl-BepoUL1B.mjs → OkxWalletAdapter.impl-nRgHsPTn.mjs} +13 -9
  23. package/lib/OkxWalletAdapter.impl-nRgHsPTn.mjs.map +1 -0
  24. package/lib/{UnisatCompatibleWalletAdapterImpl-M38FqkZI.mjs → UnisatCompatibleWalletAdapterImpl-8lRRF7Zj.mjs} +18 -10
  25. package/lib/UnisatCompatibleWalletAdapterImpl-8lRRF7Zj.mjs.map +1 -0
  26. package/lib/{UnisatCompatibleWalletAdapterImpl-Cq2Oqk1b.js → UnisatCompatibleWalletAdapterImpl-C-JWrc9s.js} +2 -2
  27. package/lib/UnisatCompatibleWalletAdapterImpl-C-JWrc9s.js.map +1 -0
  28. package/lib/UnisatWalletAdapter.impl-DXDfnHz_.js +2 -0
  29. package/lib/UnisatWalletAdapter.impl-DXDfnHz_.js.map +1 -0
  30. package/lib/UnisatWalletAdapter.impl-DvA33Ikj.mjs +19 -0
  31. package/lib/UnisatWalletAdapter.impl-DvA33Ikj.mjs.map +1 -0
  32. package/lib/WalletAdapters.types-CExaiK0o.js +2 -0
  33. package/lib/WalletAdapters.types-CExaiK0o.js.map +1 -0
  34. package/lib/WalletAdapters.types-DBvhI1hu.mjs +20 -0
  35. package/lib/WalletAdapters.types-DBvhI1hu.mjs.map +1 -0
  36. package/lib/WalletAdapters.types.d.ts +7 -12
  37. package/lib/{XverseCompatibleWalletAdapterImpl-Bf-BK5VK.js → XverseCompatibleWalletAdapterImpl-Dp_GUxQM.js} +2 -2
  38. package/lib/XverseCompatibleWalletAdapterImpl-Dp_GUxQM.js.map +1 -0
  39. package/lib/{XverseCompatibleWalletAdapterImpl-DXKnO_-V.mjs → XverseCompatibleWalletAdapterImpl-bgp9xDYH.mjs} +12 -8
  40. package/lib/XverseCompatibleWalletAdapterImpl-bgp9xDYH.mjs.map +1 -0
  41. package/lib/{XverseWalletAdapter.impl-CZO0RQva.mjs → XverseWalletAdapter.impl-BOpY4Vf8.mjs} +15 -15
  42. package/lib/XverseWalletAdapter.impl-BOpY4Vf8.mjs.map +1 -0
  43. package/lib/XverseWalletAdapter.impl-D0eOtEOa.js +2 -0
  44. package/lib/XverseWalletAdapter.impl-D0eOtEOa.js.map +1 -0
  45. package/lib/adapters/BitgetWalletAdapter.d.ts +6 -2
  46. package/lib/adapters/LeatherWalletAdapter.d.ts +4 -2
  47. package/lib/adapters/LeatherWalletAdapter.impl.d.ts +8 -1
  48. package/lib/adapters/MagicEdenWalletAdapter.d.ts +5 -2
  49. package/lib/adapters/MagicEdenWalletAdapter.impl.d.ts +1 -1
  50. package/lib/adapters/MockAddressWalletAdapter.d.ts +8 -32
  51. package/lib/adapters/OkxWalletAdapter.d.ts +3 -2
  52. package/lib/adapters/OkxWalletAdapter.impl.d.ts +5 -1
  53. package/lib/adapters/UnisatWalletAdapter.d.ts +3 -2
  54. package/lib/adapters/UnisatWalletAdapter.impl.d.ts +4 -0
  55. package/lib/adapters/XverseWalletAdapter.d.ts +3 -2
  56. package/lib/adapters/XverseWalletAdapter.impl.d.ts +1 -1
  57. package/lib/adapters/index.d.ts +6 -6
  58. package/lib/adapters.js +1 -1
  59. package/lib/adapters.mjs +8 -8
  60. package/lib/constants-B7qVf97f.mjs +5 -0
  61. package/lib/constants-B7qVf97f.mjs.map +1 -0
  62. package/lib/constants-Dr0_Mix2.js +2 -0
  63. package/lib/constants-Dr0_Mix2.js.map +1 -0
  64. package/lib/constants.d.ts +1 -0
  65. package/lib/{index-D7YwhNAG.mjs → index-DM4G-LJz.mjs} +639 -590
  66. package/lib/index-DM4G-LJz.mjs.map +1 -0
  67. package/lib/index-jRY8YhyK.js +2 -0
  68. package/lib/index-jRY8YhyK.js.map +1 -0
  69. package/lib/index.d.ts +1 -1
  70. package/lib/index.js +1 -1
  71. package/lib/index.mjs +13 -13
  72. package/lib/react.js +1 -1
  73. package/lib/react.js.map +1 -1
  74. package/lib/react.mjs +7 -7
  75. package/lib/react.mjs.map +1 -1
  76. package/lib/{transaction-CiLOYSE_.mjs → transaction-4ShhFCwN.mjs} +2 -2
  77. package/lib/{transaction-CiLOYSE_.mjs.map → transaction-4ShhFCwN.mjs.map} +1 -1
  78. package/lib/{transaction-CzdnbXSo.js → transaction-B6SlpRzN.js} +2 -2
  79. package/lib/{transaction-CzdnbXSo.js.map → transaction-B6SlpRzN.js.map} +1 -1
  80. package/lib/utils/UnisatCompatibleWalletAdapterImpl.d.ts +11 -3
  81. package/lib/utils/XverseCompatibleWalletAdapterImpl.d.ts +4 -0
  82. package/lib/utils/XverseCompatibleWalletAdapterImpl_legacy.d.ts +7 -2
  83. package/package.json +9 -10
  84. package/src/BitcoinConnectionProvider.stories.tsx +111 -43
  85. package/src/BitcoinConnectionProvider.tsx +5 -5
  86. package/src/{BitcoinWalletAdapterConnector.ts → BitcoinWalletConnector.ts} +18 -26
  87. package/src/WalletAdapters.types.ts +13 -22
  88. package/src/adapters/BitgetWalletAdapter.impl.ts +2 -1
  89. package/src/adapters/BitgetWalletAdapter.ts +9 -7
  90. package/src/adapters/LeatherWalletAdapter.impl.ts +23 -13
  91. package/src/adapters/LeatherWalletAdapter.ts +11 -8
  92. package/src/adapters/MagicEdenWalletAdapter.impl.ts +9 -8
  93. package/src/adapters/MagicEdenWalletAdapter.ts +17 -14
  94. package/src/adapters/MockAddressWalletAdapter.ts +61 -35
  95. package/src/adapters/OkxWalletAdapter.impl.ts +12 -7
  96. package/src/adapters/OkxWalletAdapter.ts +10 -7
  97. package/src/adapters/UnisatWalletAdapter.impl.ts +8 -2
  98. package/src/adapters/UnisatWalletAdapter.ts +9 -7
  99. package/src/adapters/XverseWalletAdapter.impl.ts +6 -6
  100. package/src/adapters/XverseWalletAdapter.ts +10 -7
  101. package/src/adapters/index.ts +6 -6
  102. package/src/constants.ts +1 -0
  103. package/src/index.ts +1 -1
  104. package/src/utils/UnisatCompatibleWalletAdapterImpl.ts +11 -2
  105. package/src/utils/XverseCompatibleWalletAdapterImpl.ts +4 -0
  106. package/src/utils/XverseCompatibleWalletAdapterImpl_legacy.ts +19 -7
  107. package/lib/BitcoinWalletAdapterConnector-Bq835yj0.mjs.map +0 -1
  108. package/lib/BitcoinWalletAdapterConnector-DMef0iHV.js +0 -2
  109. package/lib/BitcoinWalletAdapterConnector-DMef0iHV.js.map +0 -1
  110. package/lib/BitgetWalletAdapter.impl-C_HLO7Oi.mjs +0 -10
  111. package/lib/BitgetWalletAdapter.impl-C_HLO7Oi.mjs.map +0 -1
  112. package/lib/BitgetWalletAdapter.impl-CxnKMf7U.js +0 -2
  113. package/lib/BitgetWalletAdapter.impl-CxnKMf7U.js.map +0 -1
  114. package/lib/LeatherWalletAdapter.impl-B2QgX_tO.js +0 -2
  115. package/lib/LeatherWalletAdapter.impl-B2QgX_tO.js.map +0 -1
  116. package/lib/LeatherWalletAdapter.impl-RUYx555r.mjs.map +0 -1
  117. package/lib/MagicEdenWalletAdapter.impl-CrA6SGvG.mjs.map +0 -1
  118. package/lib/MagicEdenWalletAdapter.impl-Di3Nu2S5.js +0 -2
  119. package/lib/MagicEdenWalletAdapter.impl-Di3Nu2S5.js.map +0 -1
  120. package/lib/OkxWalletAdapter.impl-BepoUL1B.mjs.map +0 -1
  121. package/lib/OkxWalletAdapter.impl-C8kesjGu.js +0 -2
  122. package/lib/OkxWalletAdapter.impl-C8kesjGu.js.map +0 -1
  123. package/lib/UnisatCompatibleWalletAdapterImpl-Cq2Oqk1b.js.map +0 -1
  124. package/lib/UnisatCompatibleWalletAdapterImpl-M38FqkZI.mjs.map +0 -1
  125. package/lib/UnisatWalletAdapter.impl-CJB22se8.mjs +0 -14
  126. package/lib/UnisatWalletAdapter.impl-CJB22se8.mjs.map +0 -1
  127. package/lib/UnisatWalletAdapter.impl-EISvxdpc.js +0 -2
  128. package/lib/UnisatWalletAdapter.impl-EISvxdpc.js.map +0 -1
  129. package/lib/WalletAdapters.types-CnvOqHFH.mjs +0 -32
  130. package/lib/WalletAdapters.types-CnvOqHFH.mjs.map +0 -1
  131. package/lib/WalletAdapters.types-De_x1lzr.js +0 -2
  132. package/lib/WalletAdapters.types-De_x1lzr.js.map +0 -1
  133. package/lib/XverseCompatibleWalletAdapterImpl-Bf-BK5VK.js.map +0 -1
  134. package/lib/XverseCompatibleWalletAdapterImpl-DXKnO_-V.mjs.map +0 -1
  135. package/lib/XverseWalletAdapter.impl-CZO0RQva.mjs.map +0 -1
  136. package/lib/XverseWalletAdapter.impl-lJwMi-Iv.js +0 -2
  137. package/lib/XverseWalletAdapter.impl-lJwMi-Iv.js.map +0 -1
  138. package/lib/index-D7YwhNAG.mjs.map +0 -1
  139. package/lib/index-Zx0KcpYx.js +0 -2
  140. package/lib/index-Zx0KcpYx.js.map +0 -1
@@ -1,4 +1,4 @@
1
- import { SignMessageResult, WalletAdapter, WalletAdapter_onAddressesChanged_callback, WalletAdapterAddress } from '../WalletAdapters.types';
1
+ import { SignMessageResult, WalletAdapter, WalletAdapter_onAddressesChanged_callback, WalletAdapterAddress, WalletAdapterSendBitcoinCapability } from '../WalletAdapters.types';
2
2
  /**
3
3
  * https://docs.unisat.io/dev-center/open-api-documentation/unisat-wallet#events
4
4
  */
@@ -69,13 +69,21 @@ export declare class UnisatCompatibleWalletAdapterImpl implements WalletAdapter
69
69
  disconnect(): Promise<void>;
70
70
  getAddresses(): Promise<UnisatCompatibleWalletAdapterAddresses>;
71
71
  signMessage(address: string, message: string): Promise<SignMessageResult>;
72
- sendBitcoinFeeRateCapability: WalletAdapter["sendBitcoinFeeRateCapability"];
72
+ sendBitcoinFeeRateCapability: WalletAdapterSendBitcoinCapability;
73
73
  sendBitcoin(fromAddress: string, receiverAddress: string, satoshiAmount: bigint, options?: {
74
74
  feeRate?: number;
75
75
  }): Promise<{
76
76
  txid: string;
77
77
  }>;
78
- sendInscriptionFeeRateCapability: WalletAdapter["sendInscriptionFeeRateCapability"];
78
+ /**
79
+ * @internal
80
+ * @experimental
81
+ */
82
+ sendInscriptionFeeRateCapability: "unavailable" | "available" | "required";
83
+ /**
84
+ * @internal
85
+ * @experimental
86
+ */
79
87
  sendInscription(fromAddress: string, receiverAddress: string, inscriptionId: string, options?: {
80
88
  feeRate?: number;
81
89
  }): Promise<{
@@ -26,6 +26,10 @@ export declare class XverseCompatibleWalletAdapterImpl implements WalletAdapter
26
26
  sendBitcoin(fromAddress: string, receiverAddress: string, satoshiAmount: bigint): Promise<{
27
27
  txid: string;
28
28
  }>;
29
+ /**
30
+ * @internal
31
+ * @experimental
32
+ */
29
33
  sendInscriptionFeeRateCapability: "unavailable";
30
34
  signAndFinalizePsbt(psbtHex: string, signIndices: [address: string, signIndex: number][]): Promise<{
31
35
  signedPsbtHex: string;
@@ -10,18 +10,19 @@ export type XverseCompatibleWalletAdapterImplAddress = WalletAdapterAddress & {
10
10
  };
11
11
  export declare class XverseCompatibleWalletAdapterImpl_legacy implements WalletAdapter {
12
12
  protected readonly network: WalletAdapterBitcoinNetwork;
13
- protected readonly localStorageKey: string;
13
+ protected readonly localStorageKeyPrefix: string;
14
14
  protected readonly walletDisplayName: string;
15
15
  protected readonly getProvider: XverseCompatibleWalletAdapterGetProviderFn;
16
16
  protected readonly parseAddresses: XverseCompatibleWalletAdapterParsedAddressesFn;
17
17
  constructor(info: {
18
18
  network: WalletAdapterBitcoinNetwork;
19
- localStorageKey: string;
19
+ localStorageKeyPrefix: string;
20
20
  walletDisplayName: string;
21
21
  getProvider: XverseCompatibleWalletAdapterGetProviderFn;
22
22
  parseAddresses: XverseCompatibleWalletAdapterParsedAddressesFn;
23
23
  });
24
24
  private getSdk;
25
+ protected get connectAddresses_localStorageKey(): string;
25
26
  protected retrieveConnectedAddress(): GetAddressResponse | undefined;
26
27
  protected updateConnectedAddress(addresses: GetAddressResponse["addresses"]): Promise<void>;
27
28
  connect(): Promise<void>;
@@ -33,6 +34,10 @@ export declare class XverseCompatibleWalletAdapterImpl_legacy implements WalletA
33
34
  sendBitcoin(fromAddress: string, receiverAddress: string, satoshiAmount: bigint): Promise<{
34
35
  txid: string;
35
36
  }>;
37
+ /**
38
+ * @internal
39
+ * @experimental
40
+ */
36
41
  sendInscriptionFeeRateCapability: "unavailable";
37
42
  signAndFinalizePsbt(psbtHex: string, signIndices: [address: string, signIndex: number][]): Promise<{
38
43
  signedPsbtHex: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bitcoin-wallet-connector",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "A Bitcoin wallet connector with various adapters.",
5
5
  "main": "lib/index.js",
6
6
  "module": "lib/index.mjs",
@@ -26,14 +26,6 @@
26
26
  "lib",
27
27
  "src"
28
28
  ],
29
- "scripts": {
30
- "prepare": "pnpm run build",
31
- "postinstall": "git-hook-pure install",
32
- "build": "vite build",
33
- "test": "vitest",
34
- "storybook": "storybook dev -p 6006",
35
- "build-storybook": "storybook build"
36
- },
37
29
  "devDependencies": {
38
30
  "@commitlint/cli": "^20.3.0",
39
31
  "@commitlint/config-conventional": "^20.3.0",
@@ -82,5 +74,12 @@
82
74
  "sats-connect": {
83
75
  "optional": true
84
76
  }
77
+ },
78
+ "scripts": {
79
+ "postinstall": "git-hook-pure install",
80
+ "build": "vite build",
81
+ "test": "vitest",
82
+ "storybook": "storybook dev -p 6006",
83
+ "build-storybook": "storybook build"
85
84
  }
86
- }
85
+ }
@@ -1,30 +1,34 @@
1
1
  import { Meta, StoryFn } from "@storybook/react-vite"
2
- import React, { useState } from "react"
2
+ import React, { FC, useEffect, useState } from "react"
3
3
  import {
4
4
  BitcoinConnectionProvider,
5
5
  useBitcoinConnectionContext,
6
6
  WalletSession,
7
7
  } from "./BitcoinConnectionProvider"
8
8
  import {
9
+ WalletAdapter,
9
10
  WalletAdapterAddress,
10
11
  WalletAdapterBitcoinNetwork,
12
+ WalletAdapterFactory,
11
13
  } from "./WalletAdapters.types"
12
14
  import {
13
- UnisatWalletAdapter,
14
- XverseWalletAdapter,
15
- OkxWalletAdapter,
16
- LeatherWalletAdapter,
17
- BitgetWalletAdapter,
15
+ UnisatWalletAdapterFactory,
16
+ XverseWalletAdapterFactory,
17
+ OkxWalletAdapterFactory,
18
+ LeatherWalletAdapterFactory,
19
+ BitgetWalletAdapterFactory,
18
20
  MagicEdenWalletAdapterFactory,
19
21
  } from "./adapters"
20
22
 
21
- const adapterFactories = [
22
- UnisatWalletAdapter,
23
- XverseWalletAdapter,
24
- OkxWalletAdapter,
25
- LeatherWalletAdapter,
26
- BitgetWalletAdapter,
27
- MagicEdenWalletAdapterFactory(WalletAdapterBitcoinNetwork.MAINNET),
23
+ const adapterFactories: WalletAdapterFactory<WalletAdapter>[] = [
24
+ UnisatWalletAdapterFactory(),
25
+ XverseWalletAdapterFactory(),
26
+ OkxWalletAdapterFactory(),
27
+ LeatherWalletAdapterFactory(),
28
+ BitgetWalletAdapterFactory(),
29
+ MagicEdenWalletAdapterFactory({
30
+ network: WalletAdapterBitcoinNetwork.MAINNET,
31
+ }),
28
32
  ]
29
33
 
30
34
  export default {
@@ -104,34 +108,49 @@ const WalletConnectionContent = (): React.ReactElement => {
104
108
  <div style={{ marginBottom: "16px" }}>
105
109
  <h3>Available Wallets ({ctx.availableAdapters.length})</h3>
106
110
  <div style={{ display: "flex", flexWrap: "wrap", gap: "8px" }}>
107
- {ctx.availableAdapters.map(([adapterId, adapter]) => (
108
- <button
109
- key={adapterId}
110
- onClick={() => {
111
- addDebugInfo(`Connecting to ${adapterId}...`)
112
- ctx
113
- .connect(adapterId, adapter)
114
- .then(() => {
115
- addDebugInfo(`Connected to ${adapterId}`)
116
- })
117
- .catch(err => {
118
- addDebugInfo(`Failed to connect: ${err.message}`)
119
- })
120
- }}
121
- disabled={ctx.isConnectionInitializing}
122
- style={{
123
- padding: "8px 16px",
124
- cursor: ctx.isConnectionInitializing
125
- ? "not-allowed"
126
- : "pointer",
127
- border: "1px solid #ccc",
128
- borderRadius: "4px",
129
- background: "#fff",
130
- }}
131
- >
132
- {adapterId}
133
- </button>
134
- ))}
111
+ {ctx.availableAdapters.map(([adapterId, adapter]) => {
112
+ const factory = adapterFactories.find(
113
+ factory => factory.adapterId === adapterId,
114
+ )!
115
+
116
+ return (
117
+ <div
118
+ key={adapterId}
119
+ onClick={() => {
120
+ addDebugInfo(`Connecting to ${adapterId}...`)
121
+ ctx
122
+ .connect(adapterId, adapter)
123
+ .then(() => {
124
+ addDebugInfo(`Connected to ${adapterId}`)
125
+ })
126
+ .catch(err => {
127
+ addDebugInfo(`Failed to connect: ${err.message}`)
128
+ })
129
+ }}
130
+ style={{
131
+ display: "flex",
132
+ alignItems: "center",
133
+ justifyContent: "center",
134
+ padding: "8px 16px",
135
+ cursor: ctx.isConnectionInitializing
136
+ ? "not-allowed"
137
+ : "pointer",
138
+ border: "1px solid #ccc",
139
+ borderRadius: "4px",
140
+ background: "#fff",
141
+ }}
142
+ >
143
+ {ctx.isConnectionInitializing ? (
144
+ "Connecting..."
145
+ ) : (
146
+ <>
147
+ <WalletIcon adapterFactory={factory} />
148
+ <span>{factory.metadata.name}</span>
149
+ </>
150
+ )}
151
+ </div>
152
+ )
153
+ })}
135
154
  </div>
136
155
  </div>
137
156
 
@@ -248,7 +267,7 @@ const WalletConnectionContent = (): React.ReactElement => {
248
267
  <h3>Registered Adapter Factories ({ctx.adapterFactories.length})</h3>
249
268
  <ul>
250
269
  {ctx.adapterFactories.map((factory, i) => (
251
- <li key={i}>{factory.adapterId}</li>
270
+ <li key={i}>{factory.metadata.name}</li>
252
271
  ))}
253
272
  </ul>
254
273
  </div>
@@ -303,7 +322,6 @@ export const Default: StoryFn<typeof BitcoinConnectionProvider> = () => {
303
322
  addEvent(`Addresses changed: ${addresses.length} addresses`)
304
323
  }}
305
324
  onWalletDisconnected={() => {
306
- debugger
307
325
  addEvent("Wallet disconnected")
308
326
  }}
309
327
  >
@@ -327,3 +345,53 @@ export const Default: StoryFn<typeof BitcoinConnectionProvider> = () => {
327
345
  </BitcoinConnectionProvider>
328
346
  )
329
347
  }
348
+
349
+ const WalletIcon: FC<{
350
+ adapterFactory: WalletAdapterFactory<WalletAdapter>
351
+ }> = ({ adapterFactory }) => {
352
+ const [iconUrl, setIconUrl] = useState<null | string>(null)
353
+
354
+ useEffect(() => {
355
+ const abortController = new AbortController()
356
+
357
+ void adapterFactory.metadata
358
+ .iconUrl()
359
+ .then(url => {
360
+ if (abortController.signal.aborted) return
361
+ setIconUrl(url)
362
+ })
363
+ .catch(err => {
364
+ console.error(
365
+ "Failed to load icon for ",
366
+ adapterFactory.metadata.name,
367
+ err,
368
+ )
369
+ })
370
+
371
+ return () => {
372
+ abortController.abort()
373
+ }
374
+ }, [adapterFactory.metadata])
375
+
376
+ if (!iconUrl) {
377
+ return (
378
+ <div
379
+ style={{
380
+ width: "24px",
381
+ height: "24px",
382
+ marginRight: "8px",
383
+ borderRadius: "4px",
384
+ background: "#eaeaea",
385
+ }}
386
+ ></div>
387
+ )
388
+ }
389
+
390
+ return (
391
+ <img
392
+ src={iconUrl}
393
+ alt={adapterFactory.metadata.name}
394
+ style={{ width: "24px", height: "24px", marginRight: "8px" }}
395
+ />
396
+ )
397
+ }
@@ -9,11 +9,11 @@ import {
9
9
  useRef,
10
10
  useState,
11
11
  } from "react"
12
- import { BitcoinWalletAdapterConnector } from "./BitcoinWalletAdapterConnector"
12
+ import { BitcoinWalletConnector } from "./BitcoinWalletConnector"
13
13
  import {
14
14
  WalletAdapter,
15
15
  WalletAdapterAddress,
16
- WalletAdapterStatic,
16
+ WalletAdapterFactory,
17
17
  } from "./WalletAdapters.types"
18
18
 
19
19
  export interface WalletSession {
@@ -30,7 +30,7 @@ export interface BitcoinConnectionContextValue {
30
30
  disconnect: () => Promise<void>
31
31
 
32
32
  // Wallet management (for UI)
33
- adapterFactories: WalletAdapterStatic<WalletAdapter>[]
33
+ adapterFactories: WalletAdapterFactory<WalletAdapter>[]
34
34
  availableAdapters: (readonly [adapterId: string, adapter: WalletAdapter])[]
35
35
  }
36
36
 
@@ -55,7 +55,7 @@ function useConnectorState<T>(
55
55
 
56
56
  export const BitcoinConnectionProvider: FC<{
57
57
  children: ReactNode
58
- adapterFactories: WalletAdapterStatic<WalletAdapter>[]
58
+ adapterFactories: WalletAdapterFactory<WalletAdapter>[]
59
59
  onWalletConnected?: (session: WalletSession) => void
60
60
  onWalletAddressesChanged?: (addresses: WalletAdapterAddress[]) => void
61
61
  onWalletDisconnected?: () => void
@@ -71,7 +71,7 @@ export const BitcoinConnectionProvider: FC<{
71
71
  const onWalletDisconnected = usePersistFn(props.onWalletDisconnected ?? noop)
72
72
 
73
73
  const connector = useMemo(
74
- () => new BitcoinWalletAdapterConnector(props.adapterFactories),
74
+ () => new BitcoinWalletConnector(props.adapterFactories),
75
75
  [props.adapterFactories],
76
76
  )
77
77
 
@@ -1,14 +1,14 @@
1
+ import { LOCAL_STORAGE_KEY_PREFIX } from "./constants"
1
2
  import { AvailabilitySubscription } from "./utils/createAdapterAvailability"
2
- import { BitcoinWalletAdapterError } from "./utils/error"
3
3
  import { StateChannel, StateChannelListener } from "./utils/StateChannel"
4
4
  import {
5
5
  WalletAdapter,
6
+ WalletAdapterFactory,
6
7
  WalletAdapterNotConnectedError,
7
- WalletAdapterStatic,
8
8
  } from "./WalletAdapters.types"
9
9
 
10
- const previousConnectWalletAdapterIdLocalStorageKey =
11
- "app:BitcoinWalletAdapterConnector:previousConnectWallet"
10
+ const localStorageKeyPrefix = `${LOCAL_STORAGE_KEY_PREFIX}:BitcoinWalletConnector`
11
+ const previousConnectWalletAdapterId_localStorageKey = `${localStorageKeyPrefix}:previousConnectWallet`
12
12
 
13
13
  export interface ConnectInfo {
14
14
  adapterId: string
@@ -17,16 +17,16 @@ export interface ConnectInfo {
17
17
 
18
18
  export type AdapterEntry = readonly [string, WalletAdapter]
19
19
 
20
- export class BitcoinWalletAdapterConnector {
20
+ export class BitcoinWalletConnector {
21
21
  private availableAdaptersState = new StateChannel<AdapterEntry[]>([])
22
22
  private connectedInfoState = new StateChannel<null | ConnectInfo>(null)
23
23
  private autoConnectRunning = false
24
24
  private availabilitySubscriptions: AvailabilitySubscription[] = []
25
25
  private adapterOrder = new Map<string, number>()
26
26
 
27
- constructor(private Adapters: WalletAdapterStatic<WalletAdapter>[]) {
27
+ constructor(private factories: WalletAdapterFactory<WalletAdapter>[]) {
28
28
  this.adapterOrder = new Map(
29
- Adapters.map((adapter, index) => [adapter.adapterId, index]),
29
+ factories.map((factory, index) => [factory.adapterId, index]),
30
30
  )
31
31
  this.initializeAdapterAvailability()
32
32
  }
@@ -57,9 +57,9 @@ export class BitcoinWalletAdapterConnector {
57
57
  }
58
58
 
59
59
  private initializeAdapterAvailability(): void {
60
- this.availabilitySubscriptions = this.Adapters.map(Adapter => {
61
- return Adapter.getAdapter().subscribe(adapter => {
62
- this.addOrUpdateAvailableAdapter(Adapter.adapterId, adapter)
60
+ this.availabilitySubscriptions = this.factories.map(factory => {
61
+ return factory.getAdapter().subscribe(adapter => {
62
+ this.addOrUpdateAvailableAdapter(factory.adapterId, adapter)
63
63
  })
64
64
  })
65
65
  }
@@ -91,16 +91,9 @@ export class BitcoinWalletAdapterConnector {
91
91
  async connect(adapterId: string, adapter: WalletAdapter): Promise<void> {
92
92
  const finalAdapter = adapter
93
93
 
94
- await finalAdapter.connect().catch(err => {
95
- if (err instanceof BitcoinWalletAdapterError) {
96
- alert(err.message)
97
- return
98
- }
99
- throw err
100
- })
101
-
94
+ await finalAdapter.connect()
102
95
  localStorage.setItem(
103
- previousConnectWalletAdapterIdLocalStorageKey,
96
+ previousConnectWalletAdapterId_localStorageKey,
104
97
  adapterId,
105
98
  )
106
99
 
@@ -110,13 +103,12 @@ export class BitcoinWalletAdapterConnector {
110
103
  async disconnect(): Promise<void> {
111
104
  const info = this.connectedInfoState.getValue()
112
105
  if (info == null) return
113
- await this.disconnectAdapter(info.adapter)
106
+
107
+ await info.adapter.disconnect()
108
+ localStorage.removeItem(previousConnectWalletAdapterId_localStorageKey)
109
+
114
110
  this.connectedInfoState.setValue(null)
115
111
  }
116
- private async disconnectAdapter(adapter: WalletAdapter): Promise<void> {
117
- await adapter.disconnect()
118
- localStorage.removeItem(previousConnectWalletAdapterIdLocalStorageKey)
119
- }
120
112
 
121
113
  private async autoConnect(): Promise<void> {
122
114
  if (this.isConnected || this.autoConnectRunning) return
@@ -151,10 +143,10 @@ export class BitcoinWalletAdapterConnector {
151
143
 
152
144
  private get previousConnectedWallet(): string | undefined {
153
145
  const adapterId =
154
- localStorage.getItem(previousConnectWalletAdapterIdLocalStorageKey) ||
146
+ localStorage.getItem(previousConnectWalletAdapterId_localStorageKey) ||
155
147
  undefined
156
148
 
157
- if (this.Adapters.some(adapter => adapter.adapterId === adapterId)) {
149
+ if (this.factories.some(factory => factory.adapterId === adapterId)) {
158
150
  return adapterId
159
151
  }
160
152
  return undefined
@@ -84,12 +84,12 @@ export interface WalletAdapterAddress extends Partial<
84
84
 
85
85
  export interface WalletAdapterMetadata {
86
86
  name: string
87
- iconUrl: Promise<string>
87
+ iconUrl: () => Promise<string>
88
88
  websiteUrl: string
89
89
  downloadUrl: string
90
90
  }
91
91
 
92
- export interface WalletAdapterStatic<T extends WalletAdapter> {
92
+ export interface WalletAdapterFactory<T extends WalletAdapter> {
93
93
  adapterId: string
94
94
  metadata: WalletAdapterMetadata
95
95
  getAdapter(): Availability<T>
@@ -111,34 +111,25 @@ export interface WalletAdapter {
111
111
 
112
112
  signMessage(address: string, message: string): Promise<SignMessageResult>
113
113
 
114
- readonly sendBitcoinFeeRateCapability:
115
- | "unavailable"
116
- | "available"
117
- | "required"
114
+ signAndFinalizePsbt(
115
+ psbtHex: string,
116
+ signIndices: [address: string, signIndex: number][],
117
+ ): Promise<{ signedPsbtHex: string }>
118
+
119
+ sendBitcoinFeeRateCapability: WalletAdapterSendBitcoinCapability
118
120
  sendBitcoin(
119
121
  fromAddress: string,
120
122
  receiverAddress: string,
121
123
  satoshiAmount: bigint,
122
124
  options?: { feeRate?: number },
123
125
  ): Promise<{ txid: string }>
124
-
125
- readonly sendInscriptionFeeRateCapability:
126
- | "unavailable"
127
- | "available"
128
- | "required"
129
- sendInscription?(
130
- fromAddress: string,
131
- receiverAddress: string,
132
- inscriptionId: string,
133
- options?: { feeRate?: number },
134
- ): Promise<{ txid: string }>
135
-
136
- signAndFinalizePsbt(
137
- psbtHex: string,
138
- signIndices: [address: string, signIndex: number][],
139
- ): Promise<{ signedPsbtHex: string }>
140
126
  }
141
127
 
128
+ export type WalletAdapterSendBitcoinCapability =
129
+ | "unavailable"
130
+ | "available"
131
+ | "required"
132
+
142
133
  export class WalletAdapterErrorBase extends Error {
143
134
  constructor(message: string) {
144
135
  super(message)
@@ -3,6 +3,7 @@ import {
3
3
  UnisatCompatibleWalletAdapterImpl,
4
4
  } from "../utils/UnisatCompatibleWalletAdapterImpl"
5
5
  import { WalletAdapter } from "../WalletAdapters.types"
6
+ import { metadata } from "./BitgetWalletAdapter"
6
7
 
7
8
  /**
8
9
  * Derivation path (BIP-44): m/44'/0'/0'/0/ address_index
@@ -17,6 +18,6 @@ export class BitgetWalletAdapterImpl
17
18
  *
18
19
  * https://web3.bitget.com/zh-CN/docs/provider-api/btc.html
19
20
  */
20
- super(provider, "Bitget")
21
+ super(provider, metadata.name)
21
22
  }
22
23
  }
@@ -3,7 +3,7 @@ import type { UnisatCompatibleProviderAPI } from "../utils/UnisatCompatibleWalle
3
3
  import type {
4
4
  WalletAdapter,
5
5
  WalletAdapterMetadata,
6
- WalletAdapterStatic,
6
+ WalletAdapterFactory,
7
7
  } from "../WalletAdapters.types"
8
8
 
9
9
  /**
@@ -15,9 +15,9 @@ const adapterId = "bitget.bitcoin"
15
15
  /**
16
16
  * https://web3.bitget.com/en/docs/wallet/brand-assets.html
17
17
  */
18
- const metadata: WalletAdapterMetadata = {
18
+ export const metadata: WalletAdapterMetadata = {
19
19
  name: "Bitget",
20
- iconUrl: import("../_/bitget.png").then(m => m.default),
20
+ iconUrl: () => import("../_/bitget.png").then(m => m.default),
21
21
  websiteUrl: "https://web3.bitget.com/",
22
22
  downloadUrl: "https://web3.bitget.com/en/wallet-download",
23
23
  }
@@ -37,8 +37,10 @@ const availability = createAvailability<
37
37
  },
38
38
  })
39
39
 
40
- export const BitgetWalletAdapter: WalletAdapterStatic<WalletAdapter> = {
41
- adapterId,
42
- metadata,
43
- getAdapter: () => availability,
40
+ export function BitgetWalletAdapterFactory(): WalletAdapterFactory<WalletAdapter> {
41
+ return {
42
+ adapterId,
43
+ metadata,
44
+ getAdapter: () => availability,
45
+ }
44
46
  }
@@ -1,11 +1,12 @@
1
1
  import type { RequestFn, RpcErrorBody, RpcErrorResponse } from "@leather.io/rpc"
2
2
  import { hex } from "@scure/base"
3
+ import { LOCAL_STORAGE_KEY_PREFIX } from "../constants"
3
4
  import {
4
5
  addressToScriptPubKey,
5
6
  getTapInternalKeyOf_P2TR_publicKey,
6
7
  } from "../utils/bitcoinAddressHelpers"
7
8
  import { getBitcoinNetwork } from "../utils/bitcoinNetworkHelpers"
8
- import { UserRejectError, BitcoinWalletAdapterError } from "../utils/error"
9
+ import { BitcoinWalletAdapterError, UserRejectError } from "../utils/error"
9
10
  import {
10
11
  SignMessageAlgorithm,
11
12
  SignMessageResult,
@@ -17,6 +18,7 @@ import {
17
18
  WalletAdapterBitcoinNetwork,
18
19
  WalletAdapterNotConnectedError,
19
20
  } from "../WalletAdapters.types"
21
+ import { adapterId, metadata } from "./LeatherWalletAdapter"
20
22
 
21
23
  type GetAddressesResponseData = any
22
24
 
@@ -41,9 +43,8 @@ enum RpcErrorCode {
41
43
 
42
44
  type Addresses = (WalletAdapterAddress & { publicKey: string })[]
43
45
 
44
- const LEATHER_PROVIDER_ID = "LeatherProvider.BitcoinProvider"
45
-
46
- const localStorageKey = `app:${LEATHER_PROVIDER_ID}:`
46
+ const localStorageKeyPrefix = `${LOCAL_STORAGE_KEY_PREFIX}:${adapterId}`
47
+ const connectedAddress_localStorageKey = `${localStorageKeyPrefix}:connectedAddress`
47
48
 
48
49
  /**
49
50
  * Derivation path (BIP-84): m/84'/0'/ account_index '/0/0
@@ -51,11 +52,10 @@ const localStorageKey = `app:${LEATHER_PROVIDER_ID}:`
51
52
  export class LeatherWalletAdapterImpl implements WalletAdapter {
52
53
  constructor(private request: RequestFn) {}
53
54
 
54
- private readonly walletDisplayName = "Leather"
55
-
56
55
  private retrieveConnectedAddress(): GetAddressesResponseData | undefined {
57
56
  let resp: GetAddressesResponseData | undefined
58
- const stored = localStorage.getItem(localStorageKey) || undefined
57
+ const stored =
58
+ localStorage.getItem(connectedAddress_localStorageKey) || undefined
59
59
  if (stored != null) {
60
60
  try {
61
61
  resp = JSON.parse(stored)
@@ -67,7 +67,7 @@ export class LeatherWalletAdapterImpl implements WalletAdapter {
67
67
  throw new Error("Invalid stored addresses")
68
68
  }
69
69
  } catch {
70
- localStorage.removeItem(localStorageKey)
70
+ localStorage.removeItem(connectedAddress_localStorageKey)
71
71
  }
72
72
  }
73
73
  return resp
@@ -81,12 +81,15 @@ export class LeatherWalletAdapterImpl implements WalletAdapter {
81
81
  */
82
82
  this.request("getAddresses"),
83
83
  )
84
- localStorage.setItem(localStorageKey, JSON.stringify(resp))
84
+ localStorage.setItem(
85
+ connectedAddress_localStorageKey,
86
+ JSON.stringify(resp),
87
+ )
85
88
  }
86
89
  }
87
90
 
88
91
  async disconnect(): Promise<void> {
89
- localStorage.removeItem(localStorageKey)
92
+ localStorage.removeItem(connectedAddress_localStorageKey)
90
93
  return Promise.resolve()
91
94
  }
92
95
 
@@ -94,7 +97,7 @@ export class LeatherWalletAdapterImpl implements WalletAdapter {
94
97
  const resp = this.retrieveConnectedAddress()
95
98
 
96
99
  if (resp == null) {
97
- throw new WalletAdapterNotConnectedError(this.walletDisplayName)
100
+ throw new WalletAdapterNotConnectedError(metadata.name)
98
101
  }
99
102
 
100
103
  const addresses = resp.addresses.filter(
@@ -200,8 +203,15 @@ export class LeatherWalletAdapterImpl implements WalletAdapter {
200
203
  return { txid: resp.txid }
201
204
  }
202
205
 
206
+ /**
207
+ * @internal
208
+ * @experimental
209
+ */
203
210
  sendInscriptionFeeRateCapability = "available" as const
204
-
211
+ /**
212
+ * @internal
213
+ * @experimental
214
+ */
205
215
  async sendInscription(
206
216
  fromAddress: string,
207
217
  receiverAddress: string,
@@ -238,7 +248,7 @@ export class LeatherWalletAdapterImpl implements WalletAdapter {
238
248
  account => account.address === signIndices[0]?.[0],
239
249
  )
240
250
  if (signingAccount == null) {
241
- throw new WalletAdapterNotConnectedError(this.walletDisplayName)
251
+ throw new WalletAdapterNotConnectedError(metadata.name)
242
252
  }
243
253
 
244
254
  const resp: any = await handleRpcError(