@sip-protocol/sdk 0.7.3 → 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 (264) 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 +47556 -19603
  7. package/dist/browser.mjs +628 -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-3M3HNQCW.mjs → chunk-YWGJ77A2.mjs} +28656 -13103
  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-DIBZHOOQ.d.ts → index-DXh2IGkz.d.ts} +21239 -10304
  24. package/dist/{index-8MQz13eJ.d.mts → index-DeE1ZzA4.d.mts} +21239 -10304
  25. package/dist/index.d.mts +9 -3
  26. package/dist/index.d.ts +9 -3
  27. package/dist/index.js +48396 -19623
  28. package/dist/index.mjs +537 -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 +252 -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 +47 -6
  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 +186 -33
  98. package/src/chains/solana/providers/index.ts +31 -0
  99. package/src/chains/solana/providers/interface.ts +61 -18
  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 +338 -67
  103. package/src/chains/solana/rpc-client.ts +1150 -0
  104. package/src/chains/solana/scan.ts +83 -66
  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 +57 -6
  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 +23 -0
  116. package/src/compliance/range-sas.ts +398 -33
  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 +686 -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 +254 -4
  143. package/src/privacy-backends/interface.ts +649 -6
  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.ts +13 -17
  148. package/src/privacy-backends/private-swap.ts +570 -0
  149. package/src/privacy-backends/rate-limiter.ts +683 -0
  150. package/src/privacy-backends/registry.ts +414 -2
  151. package/src/privacy-backends/router.ts +283 -3
  152. package/src/privacy-backends/shadowwire.ts +449 -0
  153. package/src/privacy-backends/sip-native.ts +3 -0
  154. package/src/privacy-logger.ts +191 -0
  155. package/src/production-safety.ts +373 -0
  156. package/src/proofs/aggregator.ts +1029 -0
  157. package/src/proofs/browser-composer.ts +1150 -0
  158. package/src/proofs/browser.ts +113 -25
  159. package/src/proofs/cache/index.ts +127 -0
  160. package/src/proofs/cache/interface.ts +545 -0
  161. package/src/proofs/cache/key-generator.ts +188 -0
  162. package/src/proofs/cache/lru-cache.ts +481 -0
  163. package/src/proofs/cache/multi-tier-cache.ts +575 -0
  164. package/src/proofs/cache/persistent-cache.ts +788 -0
  165. package/src/proofs/compliance-proof.ts +872 -0
  166. package/src/proofs/composer/base.ts +923 -0
  167. package/src/proofs/composer/index.ts +25 -0
  168. package/src/proofs/composer/interface.ts +518 -0
  169. package/src/proofs/composer/types.ts +383 -0
  170. package/src/proofs/converters/halo2.ts +452 -0
  171. package/src/proofs/converters/index.ts +208 -0
  172. package/src/proofs/converters/interface.ts +363 -0
  173. package/src/proofs/converters/kimchi.ts +462 -0
  174. package/src/proofs/converters/noir.ts +451 -0
  175. package/src/proofs/fallback.ts +888 -0
  176. package/src/proofs/halo2.ts +42 -0
  177. package/src/proofs/index.ts +471 -0
  178. package/src/proofs/interface.ts +13 -0
  179. package/src/proofs/kimchi.ts +42 -0
  180. package/src/proofs/lazy.ts +1004 -0
  181. package/src/proofs/mock.ts +25 -1
  182. package/src/proofs/noir.ts +110 -29
  183. package/src/proofs/orchestrator.ts +960 -0
  184. package/src/proofs/parallel/concurrency.ts +297 -0
  185. package/src/proofs/parallel/dependency-graph.ts +602 -0
  186. package/src/proofs/parallel/executor.ts +420 -0
  187. package/src/proofs/parallel/index.ts +131 -0
  188. package/src/proofs/parallel/interface.ts +685 -0
  189. package/src/proofs/parallel/worker-pool.ts +644 -0
  190. package/src/proofs/providers/halo2.ts +560 -0
  191. package/src/proofs/providers/index.ts +34 -0
  192. package/src/proofs/providers/kimchi.ts +641 -0
  193. package/src/proofs/validator.ts +881 -0
  194. package/src/proofs/verifier.ts +867 -0
  195. package/src/quantum/index.ts +112 -0
  196. package/src/quantum/winternitz-vault.ts +639 -0
  197. package/src/quantum/wots.ts +611 -0
  198. package/src/settlement/backends/direct-chain.ts +1 -0
  199. package/src/settlement/index.ts +9 -0
  200. package/src/settlement/router.ts +732 -46
  201. package/src/solana/index.ts +72 -0
  202. package/src/solana/jito-relayer.ts +687 -0
  203. package/src/solana/noir-verifier-types.ts +430 -0
  204. package/src/solana/noir-verifier.ts +816 -0
  205. package/src/stealth/address-derivation.ts +193 -0
  206. package/src/stealth/ed25519.ts +431 -0
  207. package/src/stealth/index.ts +233 -0
  208. package/src/stealth/meta-address.ts +221 -0
  209. package/src/stealth/secp256k1.ts +368 -0
  210. package/src/stealth/utils.ts +194 -0
  211. package/src/stealth.ts +50 -1504
  212. package/src/sync/index.ts +106 -0
  213. package/src/sync/manager.ts +504 -0
  214. package/src/sync/mock-provider.ts +318 -0
  215. package/src/sync/oblivious.ts +625 -0
  216. package/src/tokens/index.ts +15 -0
  217. package/src/tokens/registry.ts +301 -0
  218. package/src/utils/deprecation.ts +94 -0
  219. package/src/utils/index.ts +9 -0
  220. package/src/wallet/ethereum/index.ts +68 -0
  221. package/src/wallet/ethereum/metamask-privacy.ts +420 -0
  222. package/src/wallet/ethereum/multi-wallet.ts +646 -0
  223. package/src/wallet/ethereum/privacy-adapter.ts +700 -0
  224. package/src/wallet/ethereum/types.ts +3 -1
  225. package/src/wallet/ethereum/walletconnect-adapter.ts +675 -0
  226. package/src/wallet/hardware/index.ts +10 -0
  227. package/src/wallet/hardware/ledger-privacy.ts +414 -0
  228. package/src/wallet/index.ts +71 -0
  229. package/src/wallet/near/adapter.ts +626 -0
  230. package/src/wallet/near/index.ts +86 -0
  231. package/src/wallet/near/meteor-wallet.ts +1153 -0
  232. package/src/wallet/near/my-near-wallet.ts +790 -0
  233. package/src/wallet/near/wallet-selector.ts +702 -0
  234. package/src/wallet/solana/adapter.ts +6 -4
  235. package/src/wallet/solana/index.ts +13 -0
  236. package/src/wallet/solana/privacy-adapter.ts +567 -0
  237. package/src/wallet/sui/types.ts +6 -4
  238. package/src/zcash/rpc-client.ts +13 -6
  239. package/dist/chunk-2XIVXWHA.mjs +0 -1930
  240. package/dist/chunk-3INS3PR5.mjs +0 -884
  241. package/dist/chunk-3OVABDRH.mjs +0 -17096
  242. package/dist/chunk-7RFRWDCW.mjs +0 -1504
  243. package/dist/chunk-DLDWZFYC.mjs +0 -1495
  244. package/dist/chunk-E6SZWREQ.mjs +0 -57
  245. package/dist/chunk-F6F73W35.mjs +0 -16166
  246. package/dist/chunk-G33LB27A.mjs +0 -16166
  247. package/dist/chunk-HGU6HZRC.mjs +0 -231
  248. package/dist/chunk-L2K34JCU.mjs +0 -1496
  249. package/dist/chunk-OFDBEIEK.mjs +0 -16166
  250. package/dist/chunk-SF7YSLF5.mjs +0 -1515
  251. package/dist/chunk-SN4ZDTVW.mjs +0 -16166
  252. package/dist/chunk-WWUSGOXE.mjs +0 -17129
  253. package/dist/constants-VOI7BSLK.mjs +0 -27
  254. package/dist/index-B71aXVzk.d.ts +0 -13264
  255. package/dist/index-BYZbDjal.d.ts +0 -11390
  256. package/dist/index-CHB3KuOB.d.mts +0 -11859
  257. package/dist/index-CzWPI6Le.d.ts +0 -11859
  258. package/dist/index-pOIIuwfV.d.mts +0 -13264
  259. package/dist/index-xbWjohNq.d.mts +0 -11390
  260. package/dist/solana-4O4K45VU.mjs +0 -46
  261. package/dist/solana-5EMCTPTS.mjs +0 -46
  262. package/dist/solana-NDABAZ6P.mjs +0 -56
  263. package/dist/solana-Q4NAVBTS.mjs +0 -46
  264. package/dist/solana-ZYO63LY5.mjs +0 -46
@@ -0,0 +1,675 @@
1
+ /**
2
+ * WalletConnect v2 Privacy Adapter
3
+ *
4
+ * Extends privacy wallet adapter for WalletConnect v2 protocol,
5
+ * enabling mobile wallet privacy operations.
6
+ *
7
+ * @module wallet/ethereum/walletconnect-adapter
8
+ */
9
+
10
+ import type { HexString } from '@sip-protocol/types'
11
+ import { WalletErrorCode } from '@sip-protocol/types'
12
+ import { WalletError } from '../errors'
13
+ import {
14
+ PrivacyEthereumWalletAdapter,
15
+ type PrivacyEthereumAdapterConfig,
16
+ type PrivacyContext,
17
+ } from './privacy-adapter'
18
+ import type { EIP1193Provider, EIP712TypedData } from './types'
19
+ import { EthereumChainId } from './types'
20
+
21
+ // ─── Types ──────────────────────────────────────────────────────────────────
22
+
23
+ /**
24
+ * WalletConnect session info
25
+ */
26
+ export interface WalletConnectSession {
27
+ /** Session topic */
28
+ topic: string
29
+ /** Peer metadata */
30
+ peer: {
31
+ name: string
32
+ description: string
33
+ url: string
34
+ icons: string[]
35
+ }
36
+ /** Namespaces with accounts and methods */
37
+ namespaces: {
38
+ eip155?: {
39
+ accounts: string[]
40
+ methods: string[]
41
+ events: string[]
42
+ chains?: string[]
43
+ }
44
+ }
45
+ /** Session expiry timestamp */
46
+ expiry: number
47
+ /** Acknowledged flag */
48
+ acknowledged: boolean
49
+ }
50
+
51
+ /**
52
+ * WalletConnect adapter configuration
53
+ */
54
+ export interface WalletConnectAdapterConfig extends Omit<PrivacyEthereumAdapterConfig, 'provider' | 'wallet'> {
55
+ /**
56
+ * WalletConnect project ID from cloud.walletconnect.com
57
+ */
58
+ projectId: string
59
+ /**
60
+ * Relay URL (defaults to wss://relay.walletconnect.com)
61
+ */
62
+ relayUrl?: string
63
+ /**
64
+ * App metadata for pairing proposal
65
+ */
66
+ metadata?: {
67
+ name: string
68
+ description: string
69
+ url: string
70
+ icons: string[]
71
+ }
72
+ /**
73
+ * Required chain IDs for session
74
+ */
75
+ requiredChains?: number[]
76
+ /**
77
+ * Optional chain IDs
78
+ */
79
+ optionalChains?: number[]
80
+ /**
81
+ * Session storage key
82
+ */
83
+ storageKey?: string
84
+ /**
85
+ * Connection timeout in ms
86
+ */
87
+ connectionTimeout?: number
88
+ /**
89
+ * Auto-reconnect to previous session
90
+ */
91
+ autoReconnect?: boolean
92
+ }
93
+
94
+ /**
95
+ * Connection result
96
+ */
97
+ export interface WalletConnectResult {
98
+ /** Connected address */
99
+ address: string
100
+ /** Chain ID */
101
+ chainId: number
102
+ /** Session info */
103
+ session: WalletConnectSession
104
+ }
105
+
106
+ /**
107
+ * Pairing URI for QR code
108
+ */
109
+ export interface PairingUri {
110
+ /** Full URI for QR code */
111
+ uri: string
112
+ /** Topic for tracking */
113
+ topic: string
114
+ }
115
+
116
+ // ─── WalletConnect Adapter ──────────────────────────────────────────────────
117
+
118
+ /**
119
+ * WalletConnect v2 Privacy Adapter
120
+ *
121
+ * Enables privacy operations through WalletConnect for mobile wallets.
122
+ * Handles session management, reconnection, and multi-chain support.
123
+ *
124
+ * @example Basic usage
125
+ * ```typescript
126
+ * const adapter = new WalletConnectPrivacyAdapter({
127
+ * projectId: 'your-project-id',
128
+ * chainId: 1,
129
+ * })
130
+ *
131
+ * // Generate pairing URI for QR code
132
+ * const { uri } = await adapter.createPairing()
133
+ * displayQRCode(uri)
134
+ *
135
+ * // Wait for connection
136
+ * await adapter.connect()
137
+ * await adapter.initializePrivacy()
138
+ *
139
+ * // Use privacy features
140
+ * const metaAddress = adapter.getMetaAddress()
141
+ * ```
142
+ *
143
+ * @example With auto-reconnect
144
+ * ```typescript
145
+ * const adapter = new WalletConnectPrivacyAdapter({
146
+ * projectId: 'your-project-id',
147
+ * autoReconnect: true,
148
+ * storageKey: 'my-app-wc-session',
149
+ * })
150
+ *
151
+ * // Attempt to reconnect to previous session
152
+ * const reconnected = await adapter.tryReconnect()
153
+ * if (!reconnected) {
154
+ * // Create new pairing
155
+ * const { uri } = await adapter.createPairing()
156
+ * displayQRCode(uri)
157
+ * }
158
+ * ```
159
+ */
160
+ export class WalletConnectPrivacyAdapter extends PrivacyEthereumWalletAdapter {
161
+ private projectId: string
162
+ private relayUrl: string
163
+ private wcMetadata: Required<WalletConnectAdapterConfig>['metadata']
164
+ private requiredChains: number[]
165
+ private optionalChains: number[]
166
+ private storageKey: string
167
+ private connectionTimeout: number
168
+ private autoReconnect: boolean
169
+ private currentSession: WalletConnectSession | undefined
170
+ private pairingUri: PairingUri | undefined
171
+ private signClient: unknown // WalletConnect SignClient instance
172
+ private wcProvider: EIP1193Provider | undefined
173
+
174
+ constructor(config: WalletConnectAdapterConfig) {
175
+ // Create with a placeholder provider - will be set during connect
176
+ super({
177
+ ...config,
178
+ wallet: 'walletconnect',
179
+ provider: undefined,
180
+ })
181
+
182
+ this.projectId = config.projectId
183
+ this.relayUrl = config.relayUrl ?? 'wss://relay.walletconnect.com'
184
+ this.wcMetadata = config.metadata ?? {
185
+ name: 'SIP Protocol',
186
+ description: 'Privacy-preserving transactions',
187
+ url: 'https://sip-protocol.org',
188
+ icons: ['https://sip-protocol.org/icon.png'],
189
+ }
190
+ this.requiredChains = config.requiredChains ?? [config.chainId ?? EthereumChainId.MAINNET]
191
+ this.optionalChains = config.optionalChains ?? [
192
+ EthereumChainId.MAINNET,
193
+ EthereumChainId.SEPOLIA,
194
+ EthereumChainId.ARBITRUM,
195
+ EthereumChainId.OPTIMISM,
196
+ EthereumChainId.BASE,
197
+ EthereumChainId.POLYGON,
198
+ ]
199
+ this.storageKey = config.storageKey ?? 'sip-wc-session'
200
+ this.connectionTimeout = config.connectionTimeout ?? 30000
201
+ this.autoReconnect = config.autoReconnect ?? true
202
+ }
203
+
204
+ // ─── Session Management ─────────────────────────────────────────────────────
205
+
206
+ /**
207
+ * Create a pairing URI for QR code display
208
+ *
209
+ * Call this before connect() to get the pairing URI.
210
+ *
211
+ * @returns Pairing URI and topic
212
+ */
213
+ async createPairing(): Promise<PairingUri> {
214
+ await this.ensureSignClient()
215
+
216
+ // Create pairing proposal
217
+ const { uri, approval } = await this.createConnectProposal()
218
+
219
+ this.pairingUri = { uri, topic: '' }
220
+
221
+ // Store approval promise for connect()
222
+ ;(this as unknown as { _approval: Promise<WalletConnectSession> })._approval = approval
223
+
224
+ return this.pairingUri
225
+ }
226
+
227
+ /**
228
+ * Connect to WalletConnect
229
+ *
230
+ * If createPairing() was called, waits for user to scan QR.
231
+ * Otherwise, attempts to reconnect to existing session.
232
+ */
233
+ async connect(): Promise<void> {
234
+ try {
235
+ this._connectionState = 'connecting'
236
+
237
+ // Try auto-reconnect if enabled
238
+ if (this.autoReconnect && !this.pairingUri) {
239
+ const reconnected = await this.tryReconnect()
240
+ if (reconnected) {
241
+ return
242
+ }
243
+ }
244
+
245
+ // Wait for approval from pairing
246
+ const approval = (this as unknown as { _approval: Promise<WalletConnectSession> })._approval
247
+ if (!approval) {
248
+ throw new WalletError(
249
+ 'Call createPairing() first to get pairing URI',
250
+ WalletErrorCode.NOT_CONNECTED
251
+ )
252
+ }
253
+
254
+ // Wait for session with timeout
255
+ const session = await Promise.race([
256
+ approval,
257
+ new Promise<never>((_, reject) =>
258
+ setTimeout(
259
+ () => reject(new Error('Connection timeout')),
260
+ this.connectionTimeout
261
+ )
262
+ ),
263
+ ])
264
+
265
+ this.currentSession = session
266
+ await this.setupFromSession(session)
267
+
268
+ // Store session for reconnection
269
+ this.storeSession(session)
270
+
271
+ } catch (error) {
272
+ this._connectionState = 'error'
273
+
274
+ if (error instanceof WalletError) {
275
+ throw error
276
+ }
277
+
278
+ throw new WalletError(
279
+ `WalletConnect connection failed: ${String(error)}`,
280
+ WalletErrorCode.CONNECTION_FAILED
281
+ )
282
+ }
283
+ }
284
+
285
+ /**
286
+ * Try to reconnect to a previous session
287
+ *
288
+ * @returns True if successfully reconnected
289
+ */
290
+ async tryReconnect(): Promise<boolean> {
291
+ const storedSession = this.loadSession()
292
+ if (!storedSession) {
293
+ return false
294
+ }
295
+
296
+ try {
297
+ await this.ensureSignClient()
298
+
299
+ // Check if session is still valid
300
+ const now = Math.floor(Date.now() / 1000)
301
+ if (storedSession.expiry < now) {
302
+ this.clearStoredSession()
303
+ return false
304
+ }
305
+
306
+ // Try to restore session
307
+ this.currentSession = storedSession
308
+ await this.setupFromSession(storedSession)
309
+
310
+ return true
311
+ } catch {
312
+ this.clearStoredSession()
313
+ return false
314
+ }
315
+ }
316
+
317
+ /**
318
+ * Disconnect from WalletConnect
319
+ */
320
+ async disconnect(): Promise<void> {
321
+ if (this.currentSession && this.signClient) {
322
+ try {
323
+ // Disconnect WalletConnect session
324
+ await (this.signClient as { disconnect: (params: { topic: string; reason: { code: number; message: string } }) => Promise<void> }).disconnect({
325
+ topic: this.currentSession.topic,
326
+ reason: { code: 6000, message: 'User disconnected' },
327
+ })
328
+ } catch {
329
+ // Ignore disconnect errors
330
+ }
331
+ }
332
+
333
+ this.currentSession = undefined
334
+ this.wcProvider = undefined
335
+ this.pairingUri = undefined
336
+ this.clearStoredSession()
337
+ this.clearPrivacy()
338
+
339
+ await super.disconnect()
340
+ }
341
+
342
+ // ─── Session Info ───────────────────────────────────────────────────────────
343
+
344
+ /**
345
+ * Get current session info
346
+ */
347
+ getSession(): WalletConnectSession | undefined {
348
+ return this.currentSession
349
+ }
350
+
351
+ /**
352
+ * Check if session is active
353
+ */
354
+ isSessionActive(): boolean {
355
+ if (!this.currentSession) return false
356
+ const now = Math.floor(Date.now() / 1000)
357
+ return this.currentSession.expiry > now
358
+ }
359
+
360
+ /**
361
+ * Get connected peer metadata
362
+ */
363
+ getPeerMetadata(): WalletConnectSession['peer'] | undefined {
364
+ return this.currentSession?.peer
365
+ }
366
+
367
+ /**
368
+ * Get pairing URI for QR code
369
+ */
370
+ getPairingUri(): string | undefined {
371
+ return this.pairingUri?.uri
372
+ }
373
+
374
+ // ─── Privacy Context Persistence ────────────────────────────────────────────
375
+
376
+ /**
377
+ * Save privacy context to storage
378
+ *
379
+ * Allows preserving privacy keys across page reloads.
380
+ */
381
+ savePrivacyContext(): void {
382
+ const context = this.getPrivacyContext()
383
+ if (context && typeof localStorage !== 'undefined') {
384
+ localStorage.setItem(
385
+ `${this.storageKey}-privacy`,
386
+ JSON.stringify(context)
387
+ )
388
+ }
389
+ }
390
+
391
+ /**
392
+ * Load and restore privacy context from storage
393
+ *
394
+ * @returns True if context was restored
395
+ */
396
+ loadPrivacyContext(): boolean {
397
+ if (typeof localStorage === 'undefined') return false
398
+
399
+ const stored = localStorage.getItem(`${this.storageKey}-privacy`)
400
+ if (!stored) return false
401
+
402
+ try {
403
+ const context = JSON.parse(stored) as PrivacyContext
404
+ this.setPrivacyContext(context)
405
+ return true
406
+ } catch {
407
+ return false
408
+ }
409
+ }
410
+
411
+ /**
412
+ * Clear stored privacy context
413
+ */
414
+ clearPrivacyContext(): void {
415
+ if (typeof localStorage !== 'undefined') {
416
+ localStorage.removeItem(`${this.storageKey}-privacy`)
417
+ }
418
+ }
419
+
420
+ // ─── Signing with Mobile Wallet Handling ────────────────────────────────────
421
+
422
+ /**
423
+ * Sign typed data with extended timeout for mobile
424
+ *
425
+ * Mobile wallets may take longer to respond due to user interaction.
426
+ */
427
+ async signTypedDataWithTimeout(
428
+ typedData: EIP712TypedData,
429
+ timeout: number = 60000
430
+ ): Promise<HexString> {
431
+ if (!this.wcProvider) {
432
+ throw new WalletError(
433
+ 'WalletConnect not connected',
434
+ WalletErrorCode.NOT_CONNECTED
435
+ )
436
+ }
437
+
438
+ const signature = await Promise.race([
439
+ this.signTypedData(typedData),
440
+ new Promise<never>((_, reject) =>
441
+ setTimeout(
442
+ () => reject(new WalletError('Signing timeout', WalletErrorCode.SIGNING_FAILED)),
443
+ timeout
444
+ )
445
+ ),
446
+ ])
447
+
448
+ return signature.signature
449
+ }
450
+
451
+ // ─── Private Methods ────────────────────────────────────────────────────────
452
+
453
+ /**
454
+ * Ensure SignClient is initialized
455
+ */
456
+ private async ensureSignClient(): Promise<void> {
457
+ if (this.signClient) return
458
+
459
+ // Dynamic import of WalletConnect
460
+ // This allows the package to be optional
461
+ try {
462
+ // @ts-expect-error - Optional peer dependency, users must install separately
463
+ const { SignClient } = await import('@walletconnect/sign-client')
464
+
465
+ this.signClient = await SignClient.init({
466
+ projectId: this.projectId,
467
+ relayUrl: this.relayUrl,
468
+ metadata: this.wcMetadata,
469
+ })
470
+
471
+ // Set up event handlers
472
+ this.setupEventHandlers()
473
+ } catch (error) {
474
+ throw new WalletError(
475
+ 'Failed to initialize WalletConnect. Make sure @walletconnect/sign-client is installed.',
476
+ WalletErrorCode.CONNECTION_FAILED
477
+ )
478
+ }
479
+ }
480
+
481
+ /**
482
+ * Create connection proposal
483
+ */
484
+ private async createConnectProposal(): Promise<{
485
+ uri: string
486
+ approval: Promise<WalletConnectSession>
487
+ }> {
488
+ const client = this.signClient as {
489
+ connect: (params: {
490
+ requiredNamespaces: Record<string, { chains: string[]; methods: string[]; events: string[] }>
491
+ optionalNamespaces?: Record<string, { chains: string[]; methods: string[]; events: string[] }>
492
+ }) => Promise<{ uri: string; approval: () => Promise<{ topic: string; peer: { metadata: WalletConnectSession['peer'] }; namespaces: WalletConnectSession['namespaces']; expiry: number; acknowledged: boolean }> }>
493
+ }
494
+
495
+ const { uri, approval } = await client.connect({
496
+ requiredNamespaces: {
497
+ eip155: {
498
+ chains: this.requiredChains.map(id => `eip155:${id}`),
499
+ methods: [
500
+ 'eth_sendTransaction',
501
+ 'eth_signTransaction',
502
+ 'eth_sign',
503
+ 'personal_sign',
504
+ 'eth_signTypedData',
505
+ 'eth_signTypedData_v4',
506
+ ],
507
+ events: ['chainChanged', 'accountsChanged'],
508
+ },
509
+ },
510
+ optionalNamespaces: {
511
+ eip155: {
512
+ chains: this.optionalChains.map(id => `eip155:${id}`),
513
+ methods: [
514
+ 'eth_sendTransaction',
515
+ 'personal_sign',
516
+ 'eth_signTypedData_v4',
517
+ ],
518
+ events: ['chainChanged', 'accountsChanged'],
519
+ },
520
+ },
521
+ })
522
+
523
+ return {
524
+ uri: uri ?? '',
525
+ approval: approval().then(session => ({
526
+ topic: session.topic,
527
+ peer: session.peer.metadata,
528
+ namespaces: session.namespaces,
529
+ expiry: session.expiry,
530
+ acknowledged: session.acknowledged,
531
+ })),
532
+ }
533
+ }
534
+
535
+ /**
536
+ * Set up adapter from session
537
+ */
538
+ private async setupFromSession(session: WalletConnectSession): Promise<void> {
539
+ // Get first account from session
540
+ const account = session.namespaces.eip155?.accounts[0]
541
+ if (!account) {
542
+ throw new WalletError(
543
+ 'No accounts in WalletConnect session',
544
+ WalletErrorCode.CONNECTION_FAILED
545
+ )
546
+ }
547
+
548
+ // Parse account format: eip155:chainId:address
549
+ const [, _chainIdStr, address] = account.split(':')
550
+
551
+ // Create EIP-1193 provider from SignClient
552
+ this.wcProvider = this.createProviderFromSession(session)
553
+
554
+ // Set connected state
555
+ this.setConnected(address, address as HexString)
556
+ }
557
+
558
+ /**
559
+ * Create EIP-1193 provider from session
560
+ */
561
+ private createProviderFromSession(session: WalletConnectSession): EIP1193Provider {
562
+ const client = this.signClient as {
563
+ request: <T>(params: { topic: string; chainId: string; request: { method: string; params: unknown[] } }) => Promise<T>
564
+ }
565
+ const topic = session.topic
566
+ const chainId = this.getChainId()
567
+
568
+ return {
569
+ request: async <T>({ method, params }: { method: string; params?: unknown[] }): Promise<T> => {
570
+ return client.request<T>({
571
+ topic,
572
+ chainId: `eip155:${chainId}`,
573
+ request: { method, params: params ?? [] },
574
+ })
575
+ },
576
+ on: () => {},
577
+ removeListener: () => {},
578
+ }
579
+ }
580
+
581
+ /**
582
+ * Set up WalletConnect event handlers
583
+ */
584
+ private setupEventHandlers(): void {
585
+ const client = this.signClient as {
586
+ on: (event: string, callback: (data: { topic: string; params?: { message?: string } }) => void) => void
587
+ }
588
+
589
+ client.on('session_delete', ({ topic }) => {
590
+ if (this.currentSession?.topic === topic) {
591
+ this.onWalletConnectDisconnect()
592
+ }
593
+ })
594
+
595
+ client.on('session_expire', ({ topic }) => {
596
+ if (this.currentSession?.topic === topic) {
597
+ this.onWalletConnectDisconnect()
598
+ }
599
+ })
600
+
601
+ client.on('session_event', () => {
602
+ // Handle session events (chainChanged, accountsChanged)
603
+ })
604
+ }
605
+
606
+ /**
607
+ * Handle WalletConnect disconnect event
608
+ */
609
+ private onWalletConnectDisconnect(): void {
610
+ this.currentSession = undefined
611
+ this.wcProvider = undefined
612
+ this.setDisconnected('WalletConnect session ended')
613
+ }
614
+
615
+ // ─── Session Storage ────────────────────────────────────────────────────────
616
+
617
+ /**
618
+ * Store session to localStorage
619
+ */
620
+ private storeSession(session: WalletConnectSession): void {
621
+ if (typeof localStorage !== 'undefined') {
622
+ localStorage.setItem(this.storageKey, JSON.stringify(session))
623
+ }
624
+ }
625
+
626
+ /**
627
+ * Load session from localStorage
628
+ */
629
+ private loadSession(): WalletConnectSession | undefined {
630
+ if (typeof localStorage === 'undefined') return undefined
631
+
632
+ const stored = localStorage.getItem(this.storageKey)
633
+ if (!stored) return undefined
634
+
635
+ try {
636
+ return JSON.parse(stored) as WalletConnectSession
637
+ } catch {
638
+ return undefined
639
+ }
640
+ }
641
+
642
+ /**
643
+ * Clear stored session
644
+ */
645
+ private clearStoredSession(): void {
646
+ if (typeof localStorage !== 'undefined') {
647
+ localStorage.removeItem(this.storageKey)
648
+ }
649
+ }
650
+ }
651
+
652
+ // ─── Factory Function ───────────────────────────────────────────────────────
653
+
654
+ /**
655
+ * Create a WalletConnect privacy adapter
656
+ *
657
+ * @example
658
+ * ```typescript
659
+ * const adapter = createWalletConnectPrivacyAdapter({
660
+ * projectId: 'your-walletconnect-project-id',
661
+ * chainId: 1,
662
+ * })
663
+ *
664
+ * const { uri } = await adapter.createPairing()
665
+ * // Display QR code with uri
666
+ *
667
+ * await adapter.connect()
668
+ * await adapter.initializePrivacy()
669
+ * ```
670
+ */
671
+ export function createWalletConnectPrivacyAdapter(
672
+ config: WalletConnectAdapterConfig
673
+ ): WalletConnectPrivacyAdapter {
674
+ return new WalletConnectPrivacyAdapter(config)
675
+ }
@@ -74,6 +74,16 @@ export {
74
74
  // Ledger adapter
75
75
  export { LedgerWalletAdapter, createLedgerAdapter } from './ledger'
76
76
 
77
+ // Ledger privacy adapter (Ethereum stealth addresses)
78
+ export {
79
+ LedgerPrivacyAdapter,
80
+ createLedgerPrivacyAdapter,
81
+ type LedgerPrivacyConfig,
82
+ type LedgerStealthKeyMaterial,
83
+ type LedgerScannedPayment,
84
+ type LedgerClaimResult,
85
+ } from './ledger-privacy'
86
+
77
87
  // Trezor adapter
78
88
  export { TrezorWalletAdapter, createTrezorAdapter } from './trezor'
79
89