@sip-protocol/sdk 0.7.2 → 0.7.4

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 (262) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +267 -0
  3. package/dist/{TransportWebUSB-TQ7WZ4LE.mjs → TransportWebUSB-YQMAGJAJ.mjs} +12 -9
  4. package/dist/browser.d.mts +10 -4
  5. package/dist/browser.d.ts +10 -4
  6. package/dist/browser.js +48874 -18336
  7. package/dist/browser.mjs +674 -48
  8. package/dist/chunk-4GRJ5MAW.mjs +152 -0
  9. package/dist/chunk-5D7A3L3W.mjs +717 -0
  10. package/dist/chunk-64AYA5F5.mjs +7834 -0
  11. package/dist/chunk-GMDGB22A.mjs +379 -0
  12. package/dist/chunk-I534WKN7.mjs +328 -0
  13. package/dist/chunk-IBZVA5Y7.mjs +1003 -0
  14. package/dist/chunk-PRRZAWJE.mjs +223 -0
  15. package/dist/{chunk-UJCSKKID.mjs → chunk-XGB3TDIC.mjs} +13 -1
  16. package/dist/chunk-YWGJ77A2.mjs +33806 -0
  17. package/dist/{chunk-6WGN57S2.mjs → chunk-Z3K7W5S3.mjs} +48 -0
  18. package/dist/constants-LHAAUC2T.mjs +51 -0
  19. package/dist/dist-2OGQ7FED.mjs +3957 -0
  20. package/dist/dist-IFHPYLDX.mjs +254 -0
  21. package/dist/fulfillment_proof-ANHVPKTB.mjs +21 -0
  22. package/dist/funding_proof-ICFZ5LHY.mjs +21 -0
  23. package/dist/index-DXh2IGkz.d.ts +24681 -0
  24. package/dist/index-DeE1ZzA4.d.mts +24681 -0
  25. package/dist/index.d.mts +9 -3
  26. package/dist/index.d.ts +9 -3
  27. package/dist/index.js +48676 -17318
  28. package/dist/index.mjs +583 -19
  29. package/dist/interface-Bf7w1PLW.d.mts +679 -0
  30. package/dist/interface-Bf7w1PLW.d.ts +679 -0
  31. package/dist/{noir-DKfEzWy9.d.mts → noir-kzbLVTei.d.mts} +31 -21
  32. package/dist/{noir-DKfEzWy9.d.ts → noir-kzbLVTei.d.ts} +31 -21
  33. package/dist/proofs/halo2.d.mts +151 -0
  34. package/dist/proofs/halo2.d.ts +151 -0
  35. package/dist/proofs/halo2.js +350 -0
  36. package/dist/proofs/halo2.mjs +11 -0
  37. package/dist/proofs/kimchi.d.mts +160 -0
  38. package/dist/proofs/kimchi.d.ts +160 -0
  39. package/dist/proofs/kimchi.js +431 -0
  40. package/dist/proofs/kimchi.mjs +13 -0
  41. package/dist/proofs/noir.d.mts +1 -1
  42. package/dist/proofs/noir.d.ts +1 -1
  43. package/dist/proofs/noir.js +74 -18
  44. package/dist/proofs/noir.mjs +84 -24
  45. package/dist/solana-U3MEGU7W.mjs +280 -0
  46. package/dist/validity_proof-3POXLPNY.mjs +21 -0
  47. package/package.json +54 -21
  48. package/src/adapters/index.ts +41 -0
  49. package/src/adapters/jupiter.ts +571 -0
  50. package/src/adapters/near-intents.ts +135 -0
  51. package/src/advisor/advisor.ts +653 -0
  52. package/src/advisor/index.ts +54 -0
  53. package/src/advisor/tools.ts +303 -0
  54. package/src/advisor/types.ts +164 -0
  55. package/src/chains/ethereum/announcement.ts +536 -0
  56. package/src/chains/ethereum/bnb-optimizations.ts +474 -0
  57. package/src/chains/ethereum/commitment.ts +522 -0
  58. package/src/chains/ethereum/constants.ts +462 -0
  59. package/src/chains/ethereum/deployment.ts +596 -0
  60. package/src/chains/ethereum/gas-estimation.ts +538 -0
  61. package/src/chains/ethereum/index.ts +268 -0
  62. package/src/chains/ethereum/optimizations.ts +614 -0
  63. package/src/chains/ethereum/privacy-adapter.ts +855 -0
  64. package/src/chains/ethereum/registry.ts +584 -0
  65. package/src/chains/ethereum/rpc.ts +905 -0
  66. package/src/chains/ethereum/stealth.ts +491 -0
  67. package/src/chains/ethereum/token.ts +790 -0
  68. package/src/chains/ethereum/transfer.ts +637 -0
  69. package/src/chains/ethereum/types.ts +456 -0
  70. package/src/chains/ethereum/viewing-key.ts +455 -0
  71. package/src/chains/near/commitment.ts +608 -0
  72. package/src/chains/near/constants.ts +284 -0
  73. package/src/chains/near/function-call.ts +871 -0
  74. package/src/chains/near/history.ts +654 -0
  75. package/src/chains/near/implicit-account.ts +840 -0
  76. package/src/chains/near/index.ts +393 -0
  77. package/src/chains/near/native-transfer.ts +658 -0
  78. package/src/chains/near/nep141.ts +775 -0
  79. package/src/chains/near/privacy-adapter.ts +889 -0
  80. package/src/chains/near/resolver.ts +971 -0
  81. package/src/chains/near/rpc.ts +1016 -0
  82. package/src/chains/near/stealth.ts +419 -0
  83. package/src/chains/near/types.ts +317 -0
  84. package/src/chains/near/viewing-key.ts +876 -0
  85. package/src/chains/solana/anchor-transfer.ts +386 -0
  86. package/src/chains/solana/commitment.ts +577 -0
  87. package/src/chains/solana/constants.ts +126 -12
  88. package/src/chains/solana/ephemeral-keys.ts +543 -0
  89. package/src/chains/solana/index.ts +276 -1
  90. package/src/chains/solana/key-derivation.ts +418 -0
  91. package/src/chains/solana/kit-compat.ts +334 -0
  92. package/src/chains/solana/optimizations.ts +560 -0
  93. package/src/chains/solana/privacy-adapter.ts +605 -0
  94. package/src/chains/solana/providers/generic.ts +201 -0
  95. package/src/chains/solana/providers/helius-enhanced-types.ts +336 -0
  96. package/src/chains/solana/providers/helius-enhanced.ts +623 -0
  97. package/src/chains/solana/providers/helius.ts +402 -0
  98. package/src/chains/solana/providers/index.ts +85 -0
  99. package/src/chains/solana/providers/interface.ts +221 -0
  100. package/src/chains/solana/providers/quicknode.ts +409 -0
  101. package/src/chains/solana/providers/triton.ts +426 -0
  102. package/src/chains/solana/providers/webhook.ts +790 -0
  103. package/src/chains/solana/rpc-client.ts +1150 -0
  104. package/src/chains/solana/scan.ts +170 -73
  105. package/src/chains/solana/sol-transfer.ts +732 -0
  106. package/src/chains/solana/spl-transfer.ts +886 -0
  107. package/src/chains/solana/stealth-scanner.ts +703 -0
  108. package/src/chains/solana/sunspot-verifier.ts +453 -0
  109. package/src/chains/solana/transaction-builder.ts +755 -0
  110. package/src/chains/solana/transfer.ts +74 -5
  111. package/src/chains/solana/types.ts +77 -7
  112. package/src/chains/solana/utils.ts +110 -0
  113. package/src/chains/solana/viewing-key.ts +807 -0
  114. package/src/compliance/fireblocks.ts +921 -0
  115. package/src/compliance/index.ts +37 -0
  116. package/src/compliance/range-sas.ts +956 -0
  117. package/src/config/endpoints.ts +100 -0
  118. package/src/crypto.ts +11 -8
  119. package/src/errors.ts +82 -0
  120. package/src/evm/erc4337-relayer.ts +830 -0
  121. package/src/evm/index.ts +47 -0
  122. package/src/fees/calculator.ts +396 -0
  123. package/src/fees/index.ts +87 -0
  124. package/src/fees/near-contract.ts +429 -0
  125. package/src/fees/types.ts +268 -0
  126. package/src/index.ts +785 -1
  127. package/src/intent.ts +6 -3
  128. package/src/logger.ts +324 -0
  129. package/src/network/index.ts +80 -0
  130. package/src/network/proxy.ts +691 -0
  131. package/src/optimizations/index.ts +541 -0
  132. package/src/oracle/types.ts +1 -0
  133. package/src/privacy-backends/arcium-types.ts +727 -0
  134. package/src/privacy-backends/arcium.ts +719 -0
  135. package/src/privacy-backends/combined-privacy.ts +866 -0
  136. package/src/privacy-backends/cspl-token.ts +595 -0
  137. package/src/privacy-backends/cspl-types.ts +512 -0
  138. package/src/privacy-backends/cspl.ts +907 -0
  139. package/src/privacy-backends/health.ts +488 -0
  140. package/src/privacy-backends/inco-types.ts +323 -0
  141. package/src/privacy-backends/inco.ts +616 -0
  142. package/src/privacy-backends/index.ts +336 -0
  143. package/src/privacy-backends/interface.ts +906 -0
  144. package/src/privacy-backends/lru-cache.ts +343 -0
  145. package/src/privacy-backends/magicblock.ts +458 -0
  146. package/src/privacy-backends/mock.ts +258 -0
  147. package/src/privacy-backends/privacycash-types.ts +278 -0
  148. package/src/privacy-backends/privacycash.ts +456 -0
  149. package/src/privacy-backends/private-swap.ts +570 -0
  150. package/src/privacy-backends/rate-limiter.ts +683 -0
  151. package/src/privacy-backends/registry.ts +690 -0
  152. package/src/privacy-backends/router.ts +626 -0
  153. package/src/privacy-backends/shadowwire.ts +449 -0
  154. package/src/privacy-backends/sip-native.ts +256 -0
  155. package/src/privacy-logger.ts +191 -0
  156. package/src/production-safety.ts +373 -0
  157. package/src/proofs/aggregator.ts +1029 -0
  158. package/src/proofs/browser-composer.ts +1150 -0
  159. package/src/proofs/browser.ts +113 -25
  160. package/src/proofs/cache/index.ts +127 -0
  161. package/src/proofs/cache/interface.ts +545 -0
  162. package/src/proofs/cache/key-generator.ts +188 -0
  163. package/src/proofs/cache/lru-cache.ts +481 -0
  164. package/src/proofs/cache/multi-tier-cache.ts +575 -0
  165. package/src/proofs/cache/persistent-cache.ts +788 -0
  166. package/src/proofs/compliance-proof.ts +872 -0
  167. package/src/proofs/composer/base.ts +923 -0
  168. package/src/proofs/composer/index.ts +25 -0
  169. package/src/proofs/composer/interface.ts +518 -0
  170. package/src/proofs/composer/types.ts +383 -0
  171. package/src/proofs/converters/halo2.ts +452 -0
  172. package/src/proofs/converters/index.ts +208 -0
  173. package/src/proofs/converters/interface.ts +363 -0
  174. package/src/proofs/converters/kimchi.ts +462 -0
  175. package/src/proofs/converters/noir.ts +451 -0
  176. package/src/proofs/fallback.ts +888 -0
  177. package/src/proofs/halo2.ts +42 -0
  178. package/src/proofs/index.ts +471 -0
  179. package/src/proofs/interface.ts +13 -0
  180. package/src/proofs/kimchi.ts +42 -0
  181. package/src/proofs/lazy.ts +1004 -0
  182. package/src/proofs/mock.ts +25 -1
  183. package/src/proofs/noir.ts +111 -30
  184. package/src/proofs/orchestrator.ts +960 -0
  185. package/src/proofs/parallel/concurrency.ts +297 -0
  186. package/src/proofs/parallel/dependency-graph.ts +602 -0
  187. package/src/proofs/parallel/executor.ts +420 -0
  188. package/src/proofs/parallel/index.ts +131 -0
  189. package/src/proofs/parallel/interface.ts +685 -0
  190. package/src/proofs/parallel/worker-pool.ts +644 -0
  191. package/src/proofs/providers/halo2.ts +560 -0
  192. package/src/proofs/providers/index.ts +34 -0
  193. package/src/proofs/providers/kimchi.ts +641 -0
  194. package/src/proofs/validator.ts +881 -0
  195. package/src/proofs/verifier.ts +867 -0
  196. package/src/quantum/index.ts +112 -0
  197. package/src/quantum/winternitz-vault.ts +639 -0
  198. package/src/quantum/wots.ts +611 -0
  199. package/src/settlement/backends/direct-chain.ts +1 -0
  200. package/src/settlement/index.ts +9 -0
  201. package/src/settlement/router.ts +732 -46
  202. package/src/solana/index.ts +72 -0
  203. package/src/solana/jito-relayer.ts +687 -0
  204. package/src/solana/noir-verifier-types.ts +430 -0
  205. package/src/solana/noir-verifier.ts +816 -0
  206. package/src/stealth/address-derivation.ts +193 -0
  207. package/src/stealth/ed25519.ts +431 -0
  208. package/src/stealth/index.ts +233 -0
  209. package/src/stealth/meta-address.ts +221 -0
  210. package/src/stealth/secp256k1.ts +368 -0
  211. package/src/stealth/utils.ts +194 -0
  212. package/src/stealth.ts +50 -1504
  213. package/src/surveillance/algorithms/address-reuse.ts +143 -0
  214. package/src/surveillance/algorithms/cluster.ts +247 -0
  215. package/src/surveillance/algorithms/exchange.ts +295 -0
  216. package/src/surveillance/algorithms/temporal.ts +337 -0
  217. package/src/surveillance/analyzer.ts +442 -0
  218. package/src/surveillance/index.ts +64 -0
  219. package/src/surveillance/scoring.ts +372 -0
  220. package/src/surveillance/types.ts +264 -0
  221. package/src/sync/index.ts +106 -0
  222. package/src/sync/manager.ts +504 -0
  223. package/src/sync/mock-provider.ts +318 -0
  224. package/src/sync/oblivious.ts +625 -0
  225. package/src/tokens/index.ts +15 -0
  226. package/src/tokens/registry.ts +301 -0
  227. package/src/utils/deprecation.ts +94 -0
  228. package/src/utils/index.ts +9 -0
  229. package/src/wallet/ethereum/index.ts +68 -0
  230. package/src/wallet/ethereum/metamask-privacy.ts +420 -0
  231. package/src/wallet/ethereum/multi-wallet.ts +646 -0
  232. package/src/wallet/ethereum/privacy-adapter.ts +700 -0
  233. package/src/wallet/ethereum/types.ts +3 -1
  234. package/src/wallet/ethereum/walletconnect-adapter.ts +675 -0
  235. package/src/wallet/hardware/index.ts +10 -0
  236. package/src/wallet/hardware/ledger-privacy.ts +414 -0
  237. package/src/wallet/index.ts +71 -0
  238. package/src/wallet/near/adapter.ts +626 -0
  239. package/src/wallet/near/index.ts +86 -0
  240. package/src/wallet/near/meteor-wallet.ts +1153 -0
  241. package/src/wallet/near/my-near-wallet.ts +790 -0
  242. package/src/wallet/near/wallet-selector.ts +702 -0
  243. package/src/wallet/solana/adapter.ts +6 -4
  244. package/src/wallet/solana/index.ts +13 -0
  245. package/src/wallet/solana/privacy-adapter.ts +567 -0
  246. package/src/wallet/sui/types.ts +6 -4
  247. package/src/zcash/rpc-client.ts +13 -6
  248. package/dist/chunk-3INS3PR5.mjs +0 -884
  249. package/dist/chunk-3OVABDRH.mjs +0 -17096
  250. package/dist/chunk-DLDWZFYC.mjs +0 -1495
  251. package/dist/chunk-E6SZWREQ.mjs +0 -57
  252. package/dist/chunk-G33LB27A.mjs +0 -16166
  253. package/dist/chunk-HGU6HZRC.mjs +0 -231
  254. package/dist/chunk-L2K34JCU.mjs +0 -1496
  255. package/dist/chunk-SN4ZDTVW.mjs +0 -16166
  256. package/dist/constants-VOI7BSLK.mjs +0 -27
  257. package/dist/index-BYZbDjal.d.ts +0 -11390
  258. package/dist/index-CHB3KuOB.d.mts +0 -11859
  259. package/dist/index-CzWPI6Le.d.ts +0 -11859
  260. package/dist/index-xbWjohNq.d.mts +0 -11390
  261. package/dist/solana-5EMCTPTS.mjs +0 -46
  262. package/dist/solana-Q4NAVBTS.mjs +0 -46
@@ -0,0 +1,646 @@
1
+ /**
2
+ * Multi-Wallet Privacy Adapter
3
+ *
4
+ * Unified privacy adapter supporting multiple Ethereum wallets including
5
+ * Rabby, Rainbow, MetaMask, and any EIP-1193 compatible wallet.
6
+ *
7
+ * @module wallet/ethereum/multi-wallet
8
+ */
9
+
10
+ import { PrivacyEthereumWalletAdapter } from './privacy-adapter'
11
+ import type { HexString } from '@sip-protocol/types'
12
+
13
+ // ─── Types ────────────────────────────────────────────────────────────────────
14
+
15
+ /**
16
+ * Supported wallet types
17
+ */
18
+ export type WalletType =
19
+ | 'metamask'
20
+ | 'rabby'
21
+ | 'rainbow'
22
+ | 'coinbase'
23
+ | 'trust'
24
+ | 'brave'
25
+ | 'frame'
26
+ | 'phantom'
27
+ | 'okx'
28
+ | 'unknown'
29
+
30
+ /**
31
+ * Wallet detection result
32
+ */
33
+ export interface DetectedWallet {
34
+ /** Wallet type identifier */
35
+ type: WalletType
36
+ /** Display name */
37
+ name: string
38
+ /** Wallet icon URL (if available) */
39
+ icon?: string
40
+ /** EIP-1193 provider */
41
+ provider: EIP1193Provider
42
+ /** Whether this wallet is the default (window.ethereum) */
43
+ isDefault: boolean
44
+ /** Wallet version (if available) */
45
+ version?: string
46
+ /** Chain ID if already connected */
47
+ chainId?: number
48
+ }
49
+
50
+ /**
51
+ * EIP-1193 provider interface
52
+ */
53
+ export interface EIP1193Provider {
54
+ request: (args: { method: string; params?: unknown[] }) => Promise<unknown>
55
+ on?: (event: string, handler: (...args: unknown[]) => void) => void
56
+ removeListener?: (event: string, handler: (...args: unknown[]) => void) => void
57
+ isMetaMask?: boolean
58
+ isRabby?: boolean
59
+ isRainbow?: boolean
60
+ isCoinbaseWallet?: boolean
61
+ isTrust?: boolean
62
+ isBraveWallet?: boolean
63
+ isFrame?: boolean
64
+ isPhantom?: boolean
65
+ isOKExWallet?: boolean
66
+ providers?: EIP1193Provider[]
67
+ }
68
+
69
+ /**
70
+ * Multi-wallet configuration options
71
+ */
72
+ export interface MultiWalletConfig {
73
+ /** Preferred wallet type (if multiple detected) */
74
+ preferredWallet?: WalletType
75
+ /** Auto-connect to last used wallet */
76
+ autoConnect?: boolean
77
+ /** Chain ID to request */
78
+ chainId?: number
79
+ /** Storage key for persisting wallet preference */
80
+ storageKey?: string
81
+ }
82
+
83
+ /**
84
+ * Wallet connection options
85
+ */
86
+ export interface WalletConnectionOptions {
87
+ /** Target chain ID */
88
+ chainId?: number
89
+ /** Request specific permissions */
90
+ permissions?: string[]
91
+ /** Silent connection (no popup if already connected) */
92
+ silent?: boolean
93
+ }
94
+
95
+ // ─── Wallet Detection ─────────────────────────────────────────────────────────
96
+
97
+ /**
98
+ * Wallet metadata for display
99
+ */
100
+ const WALLET_METADATA: Record<WalletType, { name: string; icon?: string }> = {
101
+ metamask: {
102
+ name: 'MetaMask',
103
+ icon: 'https://raw.githubusercontent.com/MetaMask/brand-resources/master/SVG/metamask-fox.svg',
104
+ },
105
+ rabby: {
106
+ name: 'Rabby',
107
+ icon: 'https://rabby.io/assets/images/logo-rabby.svg',
108
+ },
109
+ rainbow: {
110
+ name: 'Rainbow',
111
+ icon: 'https://rainbow.me/favicon.ico',
112
+ },
113
+ coinbase: {
114
+ name: 'Coinbase Wallet',
115
+ icon: 'https://www.coinbase.com/favicon.ico',
116
+ },
117
+ trust: {
118
+ name: 'Trust Wallet',
119
+ icon: 'https://trustwallet.com/favicon.ico',
120
+ },
121
+ brave: {
122
+ name: 'Brave Wallet',
123
+ icon: 'https://brave.com/static-assets/images/brave-favicon.png',
124
+ },
125
+ frame: {
126
+ name: 'Frame',
127
+ icon: 'https://frame.sh/favicon.ico',
128
+ },
129
+ phantom: {
130
+ name: 'Phantom',
131
+ icon: 'https://phantom.app/favicon.ico',
132
+ },
133
+ okx: {
134
+ name: 'OKX Wallet',
135
+ icon: 'https://www.okx.com/favicon.ico',
136
+ },
137
+ unknown: {
138
+ name: 'Unknown Wallet',
139
+ },
140
+ }
141
+
142
+ /**
143
+ * Detect wallet type from provider
144
+ */
145
+ function detectWalletType(provider: EIP1193Provider): WalletType {
146
+ // Check specific wallet flags (order matters - some wallets set multiple flags)
147
+ if (provider.isRabby) return 'rabby'
148
+ if (provider.isRainbow) return 'rainbow'
149
+ if (provider.isCoinbaseWallet) return 'coinbase'
150
+ if (provider.isTrust) return 'trust'
151
+ if (provider.isBraveWallet) return 'brave'
152
+ if (provider.isFrame) return 'frame'
153
+ if (provider.isPhantom) return 'phantom'
154
+ if (provider.isOKExWallet) return 'okx'
155
+ if (provider.isMetaMask) return 'metamask'
156
+
157
+ return 'unknown'
158
+ }
159
+
160
+ /**
161
+ * Get global window.ethereum provider
162
+ */
163
+ function getWindowEthereum(): EIP1193Provider | undefined {
164
+ if (typeof window !== 'undefined' && 'ethereum' in window) {
165
+ return window.ethereum as EIP1193Provider
166
+ }
167
+ return undefined
168
+ }
169
+
170
+ /**
171
+ * Detect all available wallets
172
+ *
173
+ * @returns Array of detected wallets
174
+ *
175
+ * @example
176
+ * ```typescript
177
+ * const wallets = detectWallets()
178
+ * console.log(wallets.map(w => w.name)) // ['MetaMask', 'Rabby']
179
+ * ```
180
+ */
181
+ export function detectWallets(): DetectedWallet[] {
182
+ const wallets: DetectedWallet[] = []
183
+ const ethereum = getWindowEthereum()
184
+
185
+ if (!ethereum) {
186
+ return wallets
187
+ }
188
+
189
+ // Check for multiple providers (some wallets expose array)
190
+ if (ethereum.providers && Array.isArray(ethereum.providers)) {
191
+ for (const provider of ethereum.providers) {
192
+ const type = detectWalletType(provider)
193
+ const metadata = WALLET_METADATA[type]
194
+
195
+ wallets.push({
196
+ type,
197
+ name: metadata.name,
198
+ icon: metadata.icon,
199
+ provider,
200
+ isDefault: false,
201
+ })
202
+ }
203
+
204
+ // Mark the default provider
205
+ const defaultType = detectWalletType(ethereum)
206
+ const defaultWallet = wallets.find(w => w.type === defaultType)
207
+ if (defaultWallet) {
208
+ defaultWallet.isDefault = true
209
+ }
210
+ } else {
211
+ // Single provider
212
+ const type = detectWalletType(ethereum)
213
+ const metadata = WALLET_METADATA[type]
214
+
215
+ wallets.push({
216
+ type,
217
+ name: metadata.name,
218
+ icon: metadata.icon,
219
+ provider: ethereum,
220
+ isDefault: true,
221
+ })
222
+ }
223
+
224
+ return wallets
225
+ }
226
+
227
+ /**
228
+ * Check if a specific wallet is installed
229
+ *
230
+ * @param walletType - Wallet type to check
231
+ * @returns Whether the wallet is available
232
+ */
233
+ export function isWalletInstalled(walletType: WalletType): boolean {
234
+ const wallets = detectWallets()
235
+ return wallets.some(w => w.type === walletType)
236
+ }
237
+
238
+ /**
239
+ * Get a specific wallet provider
240
+ *
241
+ * @param walletType - Wallet type to get
242
+ * @returns Wallet provider or undefined
243
+ */
244
+ export function getWalletProvider(walletType: WalletType): EIP1193Provider | undefined {
245
+ const wallets = detectWallets()
246
+ const wallet = wallets.find(w => w.type === walletType)
247
+ return wallet?.provider
248
+ }
249
+
250
+ // ─── Multi-Wallet Adapter ─────────────────────────────────────────────────────
251
+
252
+ /**
253
+ * MultiWalletPrivacyAdapter - Unified privacy adapter for multiple wallets
254
+ *
255
+ * Extends PrivacyEthereumWalletAdapter with multi-wallet detection and
256
+ * connection management.
257
+ *
258
+ * @example
259
+ * ```typescript
260
+ * // Create adapter
261
+ * const adapter = new MultiWalletPrivacyAdapter()
262
+ *
263
+ * // Detect available wallets
264
+ * const wallets = adapter.getAvailableWallets()
265
+ * console.log(wallets.map(w => w.name)) // ['MetaMask', 'Rabby']
266
+ *
267
+ * // Connect to specific wallet
268
+ * await adapter.connectWallet('rabby')
269
+ *
270
+ * // Use privacy features
271
+ * const meta = await adapter.generateStealthMetaAddress()
272
+ * ```
273
+ */
274
+ export class MultiWalletPrivacyAdapter extends PrivacyEthereumWalletAdapter {
275
+ private currentWallet: DetectedWallet | null = null
276
+ private config: MultiWalletConfig
277
+ private walletListeners: Map<string, (...args: unknown[]) => void> = new Map()
278
+
279
+ /**
280
+ * Create a new multi-wallet privacy adapter
281
+ *
282
+ * @param config - Configuration options
283
+ */
284
+ constructor(config: MultiWalletConfig = {}) {
285
+ // Initialize with default/preferred provider
286
+ const wallets = detectWallets()
287
+ const preferred = config.preferredWallet
288
+ ? wallets.find(w => w.type === config.preferredWallet)
289
+ : wallets.find(w => w.isDefault)
290
+
291
+ super({
292
+ chainId: config.chainId ?? 1,
293
+ })
294
+
295
+ this.config = {
296
+ storageKey: 'sip-preferred-wallet',
297
+ ...config,
298
+ }
299
+
300
+ if (preferred) {
301
+ this.currentWallet = preferred
302
+ }
303
+
304
+ // Auto-connect if configured
305
+ if (config.autoConnect && preferred) {
306
+ this.connectWallet(preferred.type, { silent: true }).catch(() => {
307
+ // Silent connection failed, user will need to explicitly connect
308
+ })
309
+ }
310
+ }
311
+
312
+ /**
313
+ * Get all available wallets
314
+ *
315
+ * @returns Array of detected wallets
316
+ */
317
+ getAvailableWallets(): DetectedWallet[] {
318
+ return detectWallets()
319
+ }
320
+
321
+ /**
322
+ * Get currently connected wallet
323
+ *
324
+ * @returns Current wallet or null
325
+ */
326
+ getCurrentWallet(): DetectedWallet | null {
327
+ return this.currentWallet
328
+ }
329
+
330
+ /**
331
+ * Check if a specific wallet is available
332
+ *
333
+ * @param walletType - Wallet type to check
334
+ * @returns Whether wallet is installed
335
+ */
336
+ isWalletAvailable(walletType: WalletType): boolean {
337
+ return isWalletInstalled(walletType)
338
+ }
339
+
340
+ /**
341
+ * Connect to a specific wallet
342
+ *
343
+ * @param walletType - Wallet type to connect
344
+ * @param options - Connection options
345
+ * @returns Connected address
346
+ *
347
+ * @example
348
+ * ```typescript
349
+ * // Connect to Rabby
350
+ * const address = await adapter.connectWallet('rabby')
351
+ *
352
+ * // Connect to Rainbow with specific chain
353
+ * const address = await adapter.connectWallet('rainbow', { chainId: 42161 })
354
+ * ```
355
+ */
356
+ async connectWallet(
357
+ walletType: WalletType,
358
+ options: WalletConnectionOptions = {}
359
+ ): Promise<HexString> {
360
+ const wallets = detectWallets()
361
+ const wallet = wallets.find(w => w.type === walletType)
362
+
363
+ if (!wallet) {
364
+ throw new Error(`Wallet ${walletType} is not installed`)
365
+ }
366
+
367
+ const provider = wallet.provider
368
+
369
+ try {
370
+ // Request accounts
371
+ const accounts = options.silent
372
+ ? await provider.request({ method: 'eth_accounts' })
373
+ : await provider.request({ method: 'eth_requestAccounts' })
374
+
375
+ const accountList = accounts as string[]
376
+ if (!accountList || accountList.length === 0) {
377
+ throw new Error('No accounts available')
378
+ }
379
+
380
+ // Switch chain if needed
381
+ if (options.chainId) {
382
+ await this.switchChainForProvider(provider, options.chainId)
383
+ }
384
+
385
+ // Update current wallet
386
+ this.currentWallet = {
387
+ ...wallet,
388
+ chainId: options.chainId ?? this.config.chainId,
389
+ }
390
+
391
+ // Set up event listeners
392
+ this.setupWalletListeners(provider)
393
+
394
+ // Persist preference
395
+ this.persistWalletPreference(walletType)
396
+
397
+ return accountList[0] as HexString
398
+ } catch (error) {
399
+ // Handle user rejection
400
+ if ((error as { code?: number }).code === 4001) {
401
+ throw new Error('User rejected connection request')
402
+ }
403
+ throw error
404
+ }
405
+ }
406
+
407
+ /**
408
+ * Disconnect from current wallet
409
+ */
410
+ async disconnectWallet(): Promise<void> {
411
+ if (this.currentWallet?.provider) {
412
+ // Remove listeners
413
+ this.removeWalletListeners(this.currentWallet.provider)
414
+ }
415
+
416
+ this.currentWallet = null
417
+ this.clearWalletPreference()
418
+ }
419
+
420
+ /**
421
+ * Switch chain for a specific provider
422
+ *
423
+ * Unlike the base class switchChain(), this works with any EIP-1193 provider.
424
+ * Useful when working with multiple wallets or dynamically detected providers.
425
+ *
426
+ * @param provider - EIP-1193 provider to switch chain on
427
+ * @param chainId - Target chain ID
428
+ */
429
+ async switchChainForProvider(provider: EIP1193Provider, chainId: number): Promise<void> {
430
+ const chainIdHex = `0x${chainId.toString(16)}`
431
+
432
+ try {
433
+ await provider.request({
434
+ method: 'wallet_switchEthereumChain',
435
+ params: [{ chainId: chainIdHex }],
436
+ })
437
+ } catch (error) {
438
+ // Chain not added, try to add it
439
+ if ((error as { code?: number }).code === 4902) {
440
+ await this.addChain(provider, chainId)
441
+ } else {
442
+ throw error
443
+ }
444
+ }
445
+ }
446
+
447
+ /**
448
+ * Add a chain to the wallet
449
+ */
450
+ private async addChain(provider: EIP1193Provider, chainId: number): Promise<void> {
451
+ const chainConfigs: Record<number, { name: string; rpcUrl: string; symbol: string; explorer: string }> = {
452
+ 1: { name: 'Ethereum', rpcUrl: 'https://eth.llamarpc.com', symbol: 'ETH', explorer: 'https://etherscan.io' },
453
+ 42161: { name: 'Arbitrum One', rpcUrl: 'https://arb1.arbitrum.io/rpc', symbol: 'ETH', explorer: 'https://arbiscan.io' },
454
+ 10: { name: 'Optimism', rpcUrl: 'https://mainnet.optimism.io', symbol: 'ETH', explorer: 'https://optimistic.etherscan.io' },
455
+ 8453: { name: 'Base', rpcUrl: 'https://mainnet.base.org', symbol: 'ETH', explorer: 'https://basescan.org' },
456
+ 137: { name: 'Polygon', rpcUrl: 'https://polygon-rpc.com', symbol: 'MATIC', explorer: 'https://polygonscan.com' },
457
+ }
458
+
459
+ const config = chainConfigs[chainId]
460
+ if (!config) {
461
+ throw new Error(`Unknown chain ID: ${chainId}`)
462
+ }
463
+
464
+ await provider.request({
465
+ method: 'wallet_addEthereumChain',
466
+ params: [{
467
+ chainId: `0x${chainId.toString(16)}`,
468
+ chainName: config.name,
469
+ nativeCurrency: { name: config.symbol, symbol: config.symbol, decimals: 18 },
470
+ rpcUrls: [config.rpcUrl],
471
+ blockExplorerUrls: [config.explorer],
472
+ }],
473
+ })
474
+ }
475
+
476
+ /**
477
+ * Sign a personal message with the connected wallet
478
+ *
479
+ * Convenience method that accepts a string message directly.
480
+ * For Uint8Array messages, use the inherited signMessage() method.
481
+ *
482
+ * @param message - Message string to sign
483
+ * @returns Signature as hex string
484
+ */
485
+ async signPersonalMessage(message: string): Promise<HexString> {
486
+ if (!this.currentWallet) {
487
+ throw new Error('No wallet connected')
488
+ }
489
+
490
+ const accounts = await this.currentWallet.provider.request({
491
+ method: 'eth_accounts',
492
+ }) as string[]
493
+
494
+ if (!accounts || accounts.length === 0) {
495
+ throw new Error('No accounts available')
496
+ }
497
+
498
+ const signature = await this.currentWallet.provider.request({
499
+ method: 'personal_sign',
500
+ params: [message, accounts[0]],
501
+ })
502
+
503
+ return signature as HexString
504
+ }
505
+
506
+ /**
507
+ * Sign typed data (EIP-712 v4) with the connected wallet
508
+ *
509
+ * Convenience method that accepts a generic typed data object.
510
+ * For strict EIP712TypedData, use the inherited signTypedData() method.
511
+ *
512
+ * @param typedData - Typed data object to sign
513
+ * @returns Signature as hex string
514
+ */
515
+ async signTypedDataV4(typedData: Record<string, unknown>): Promise<HexString> {
516
+ if (!this.currentWallet) {
517
+ throw new Error('No wallet connected')
518
+ }
519
+
520
+ const accounts = await this.currentWallet.provider.request({
521
+ method: 'eth_accounts',
522
+ }) as string[]
523
+
524
+ if (!accounts || accounts.length === 0) {
525
+ throw new Error('No accounts available')
526
+ }
527
+
528
+ const signature = await this.currentWallet.provider.request({
529
+ method: 'eth_signTypedData_v4',
530
+ params: [accounts[0], JSON.stringify(typedData)],
531
+ })
532
+
533
+ return signature as HexString
534
+ }
535
+
536
+ /**
537
+ * Set up wallet event listeners
538
+ */
539
+ private setupWalletListeners(provider: EIP1193Provider): void {
540
+ if (!provider.on) return
541
+
542
+ const accountsHandler = (accounts: unknown) => {
543
+ const accountList = accounts as string[]
544
+ if (accountList.length === 0) {
545
+ // Disconnected
546
+ this.disconnectWallet()
547
+ }
548
+ }
549
+
550
+ const chainHandler = (chainId: unknown) => {
551
+ if (this.currentWallet) {
552
+ this.currentWallet.chainId = parseInt(chainId as string, 16)
553
+ }
554
+ }
555
+
556
+ provider.on('accountsChanged', accountsHandler)
557
+ provider.on('chainChanged', chainHandler)
558
+
559
+ this.walletListeners.set('accountsChanged', accountsHandler)
560
+ this.walletListeners.set('chainChanged', chainHandler)
561
+ }
562
+
563
+ /**
564
+ * Remove wallet event listeners
565
+ */
566
+ private removeWalletListeners(provider: EIP1193Provider): void {
567
+ if (!provider.removeListener) return
568
+
569
+ for (const [event, handler] of this.walletListeners) {
570
+ provider.removeListener(event, handler)
571
+ }
572
+
573
+ this.walletListeners.clear()
574
+ }
575
+
576
+ /**
577
+ * Persist wallet preference to storage
578
+ */
579
+ private persistWalletPreference(walletType: WalletType): void {
580
+ if (typeof localStorage !== 'undefined' && this.config.storageKey) {
581
+ localStorage.setItem(this.config.storageKey, walletType)
582
+ }
583
+ }
584
+
585
+ /**
586
+ * Clear wallet preference from storage
587
+ */
588
+ private clearWalletPreference(): void {
589
+ if (typeof localStorage !== 'undefined' && this.config.storageKey) {
590
+ localStorage.removeItem(this.config.storageKey)
591
+ }
592
+ }
593
+
594
+ /**
595
+ * Load persisted wallet preference
596
+ *
597
+ * @returns Preferred wallet type or undefined
598
+ */
599
+ getPersistedWalletPreference(): WalletType | undefined {
600
+ if (typeof localStorage !== 'undefined' && this.config.storageKey) {
601
+ const stored = localStorage.getItem(this.config.storageKey)
602
+ return stored as WalletType | undefined
603
+ }
604
+ return undefined
605
+ }
606
+ }
607
+
608
+ /**
609
+ * Create a multi-wallet privacy adapter
610
+ *
611
+ * @param config - Configuration options
612
+ * @returns MultiWalletPrivacyAdapter instance
613
+ *
614
+ * @example
615
+ * ```typescript
616
+ * // Basic usage
617
+ * const adapter = createMultiWalletAdapter()
618
+ *
619
+ * // With preferred wallet
620
+ * const adapter = createMultiWalletAdapter({
621
+ * preferredWallet: 'rabby',
622
+ * autoConnect: true,
623
+ * })
624
+ * ```
625
+ */
626
+ export function createMultiWalletAdapter(
627
+ config: MultiWalletConfig = {}
628
+ ): MultiWalletPrivacyAdapter {
629
+ return new MultiWalletPrivacyAdapter(config)
630
+ }
631
+
632
+ /**
633
+ * Create adapter for Rabby wallet
634
+ */
635
+ export function createRabbyPrivacyAdapter(): MultiWalletPrivacyAdapter {
636
+ return new MultiWalletPrivacyAdapter({ preferredWallet: 'rabby' })
637
+ }
638
+
639
+ /**
640
+ * Create adapter for Rainbow wallet
641
+ */
642
+ export function createRainbowPrivacyAdapter(): MultiWalletPrivacyAdapter {
643
+ return new MultiWalletPrivacyAdapter({ preferredWallet: 'rainbow' })
644
+ }
645
+
646
+ export default MultiWalletPrivacyAdapter