@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,855 @@
1
+ /**
2
+ * Ethereum Privacy Adapter
3
+ *
4
+ * Orchestrates privacy operations for Ethereum same-chain transactions.
5
+ * Provides a unified interface for stealth transfers, scanning, and claiming.
6
+ *
7
+ * @module chains/ethereum/privacy-adapter
8
+ */
9
+
10
+ import type { StealthMetaAddress, HexString, StealthAddress } from '@sip-protocol/types'
11
+ import {
12
+ generateEthereumStealthMetaAddress,
13
+ generateEthereumStealthAddress,
14
+ parseEthereumStealthMetaAddress,
15
+ encodeEthereumStealthMetaAddress,
16
+ deriveEthereumStealthPrivateKey,
17
+ checkEthereumStealthAddress,
18
+ type EthereumStealthMetaAddress,
19
+ type EthereumStealthAddress,
20
+ } from './stealth'
21
+ import {
22
+ commitETH,
23
+ commitERC20Token,
24
+ fromWei,
25
+ } from './commitment'
26
+ import {
27
+ exportViewingKey,
28
+ importViewingKey,
29
+ createSharedViewingKey,
30
+ type ViewingKeyPermissions,
31
+ } from './viewing-key'
32
+ import {
33
+ createAnnouncementMetadata,
34
+ encodeAnnouncementCallData,
35
+ announcementToStealthAddress,
36
+ buildAnnouncementTopics,
37
+ } from './announcement'
38
+ import {
39
+ type EthereumNetwork,
40
+ ETHEREUM_RPC_ENDPOINTS,
41
+ EIP5564_ANNOUNCER_ADDRESS,
42
+ DEFAULT_GAS_LIMITS,
43
+ ONE_GWEI,
44
+ getExplorerUrl,
45
+ getChainId,
46
+ isValidEthAddress,
47
+ } from './constants'
48
+ import type {
49
+ EthereumPrivacyLevel,
50
+ EthereumAnnouncement,
51
+ EthereumShieldedTransferBuild,
52
+ EthereumClaimParams,
53
+ EthereumClaimBuild,
54
+ EthereumGasEstimate,
55
+ EthereumPrivacyAdapterState,
56
+ EthereumScanRecipient,
57
+ EthereumDetectedPaymentResult,
58
+ EthereumViewingKeyExport,
59
+ EthereumViewingKeyPair,
60
+ EthereumPedersenCommitment,
61
+ } from './types'
62
+
63
+ // ─── Types ────────────────────────────────────────────────────────────────────
64
+
65
+ /**
66
+ * Configuration for EthereumPrivacyAdapter
67
+ */
68
+ export interface EthereumPrivacyAdapterConfig {
69
+ /**
70
+ * Ethereum RPC URL
71
+ */
72
+ rpcUrl?: string
73
+
74
+ /**
75
+ * Network type
76
+ * @default 'mainnet'
77
+ */
78
+ network?: EthereumNetwork
79
+
80
+ /**
81
+ * Default privacy level
82
+ * @default 'shielded'
83
+ */
84
+ defaultPrivacyLevel?: EthereumPrivacyLevel
85
+
86
+ /**
87
+ * Custom announcer contract address
88
+ */
89
+ announcerAddress?: HexString
90
+
91
+ /**
92
+ * Enable amount hiding with Pedersen commitments
93
+ * @default true
94
+ */
95
+ hideAmounts?: boolean
96
+ }
97
+
98
+ /**
99
+ * Parameters for shielded ETH transfer
100
+ */
101
+ export interface EthereumShieldedTransferParams {
102
+ /**
103
+ * Recipient's stealth meta-address
104
+ */
105
+ recipient: StealthMetaAddress | string
106
+
107
+ /**
108
+ * Amount in wei
109
+ */
110
+ amount: bigint
111
+
112
+ /**
113
+ * Privacy level for this transaction
114
+ */
115
+ privacyLevel?: EthereumPrivacyLevel
116
+
117
+ /**
118
+ * Optional memo/reference
119
+ */
120
+ memo?: string
121
+ }
122
+
123
+ /**
124
+ * Parameters for shielded ERC-20 transfer
125
+ */
126
+ export interface EthereumShieldedTokenTransferParams extends EthereumShieldedTransferParams {
127
+ /**
128
+ * ERC-20 token contract address
129
+ */
130
+ tokenContract: HexString
131
+
132
+ /**
133
+ * Token decimals (for display purposes)
134
+ */
135
+ decimals?: number
136
+ }
137
+
138
+ /**
139
+ * Built transaction for signing
140
+ */
141
+ export interface EthereumBuiltTransaction {
142
+ /**
143
+ * Target address
144
+ */
145
+ to: HexString
146
+
147
+ /**
148
+ * ETH value in wei
149
+ */
150
+ value: bigint
151
+
152
+ /**
153
+ * Transaction data (for contract calls)
154
+ */
155
+ data?: HexString
156
+
157
+ /**
158
+ * Suggested gas limit
159
+ */
160
+ gasLimit: bigint
161
+
162
+ /**
163
+ * Chain ID
164
+ */
165
+ chainId: number
166
+ }
167
+
168
+ // ─── EthereumPrivacyAdapter Class ─────────────────────────────────────────────
169
+
170
+ /**
171
+ * Ethereum Privacy Adapter
172
+ *
173
+ * Provides a unified interface for privacy operations on Ethereum:
174
+ * - Shielded transfers to stealth addresses
175
+ * - Payment scanning and detection
176
+ * - Claiming detected payments
177
+ * - Meta-address and keypair generation
178
+ *
179
+ * @example Basic usage
180
+ * ```typescript
181
+ * const adapter = new EthereumPrivacyAdapter({
182
+ * rpcUrl: 'https://eth.llamarpc.com',
183
+ * network: 'mainnet',
184
+ * })
185
+ *
186
+ * // Generate meta-address for recipient
187
+ * const { metaAddress, viewingPrivateKey, spendingPrivateKey } =
188
+ * adapter.generateMetaAddress('Primary Wallet')
189
+ *
190
+ * // Build shielded transfer
191
+ * const build = adapter.buildShieldedTransfer({
192
+ * recipient: recipientMetaAddress,
193
+ * amount: toWei(1), // 1 ETH
194
+ * })
195
+ *
196
+ * // Sign and submit transactions externally
197
+ * // 1. Send ETH to stealth address
198
+ * // 2. Announce the payment
199
+ * ```
200
+ *
201
+ * @example Scanning and claiming
202
+ * ```typescript
203
+ * // Add recipient for scanning
204
+ * adapter.addScanRecipient({
205
+ * viewingPrivateKey,
206
+ * spendingPublicKey: metaAddress.spendingKey,
207
+ * label: 'Main Wallet',
208
+ * })
209
+ *
210
+ * // Scan announcements
211
+ * const payments = await adapter.scanAnnouncements(announcements)
212
+ *
213
+ * // Claim a payment
214
+ * const claimBuild = adapter.buildClaimTransaction({
215
+ * payment: payments[0],
216
+ * viewingPrivateKey,
217
+ * spendingPrivateKey,
218
+ * destinationAddress: '0x...',
219
+ * })
220
+ * ```
221
+ */
222
+ export class EthereumPrivacyAdapter {
223
+ private rpcUrl: string
224
+ private network: EthereumNetwork
225
+ private chainId: number
226
+ private defaultPrivacyLevel: EthereumPrivacyLevel
227
+ private announcerAddress: HexString
228
+ private hideAmounts: boolean
229
+ private scanRecipients: Map<string, EthereumScanRecipient> = new Map()
230
+ private lastScannedBlock?: number
231
+
232
+ constructor(config: EthereumPrivacyAdapterConfig = {}) {
233
+ this.network = config.network ?? 'mainnet'
234
+ this.rpcUrl = config.rpcUrl ?? ETHEREUM_RPC_ENDPOINTS[this.network]
235
+ this.chainId = getChainId(this.network)
236
+ this.defaultPrivacyLevel = config.defaultPrivacyLevel ?? 'shielded'
237
+ this.announcerAddress = config.announcerAddress ?? (EIP5564_ANNOUNCER_ADDRESS as HexString)
238
+ this.hideAmounts = config.hideAmounts ?? true
239
+ }
240
+
241
+ // ─── Meta-Address Generation ────────────────────────────────────────────────
242
+
243
+ /**
244
+ * Generate a new stealth meta-address
245
+ *
246
+ * Creates a new keypair for receiving private payments.
247
+ * The meta-address can be shared publicly; only the private keys
248
+ * enable scanning and claiming.
249
+ *
250
+ * @param label - Optional label for the address
251
+ * @returns Meta-address and private keys
252
+ */
253
+ generateMetaAddress(label?: string): {
254
+ metaAddress: EthereumStealthMetaAddress
255
+ encoded: string
256
+ viewingPrivateKey: HexString
257
+ spendingPrivateKey: HexString
258
+ } {
259
+ const result = generateEthereumStealthMetaAddress(label)
260
+ return {
261
+ metaAddress: result.metaAddress,
262
+ encoded: result.encoded,
263
+ viewingPrivateKey: result.viewingPrivateKey,
264
+ spendingPrivateKey: result.spendingPrivateKey,
265
+ }
266
+ }
267
+
268
+ /**
269
+ * Parse an encoded meta-address string
270
+ *
271
+ * @param encoded - Encoded meta-address (st:eth:0x...)
272
+ * @returns Decoded meta-address
273
+ */
274
+ parseMetaAddress(encoded: string): EthereumStealthMetaAddress {
275
+ return parseEthereumStealthMetaAddress(encoded)
276
+ }
277
+
278
+ /**
279
+ * Encode a meta-address to string format
280
+ *
281
+ * @param metaAddress - Meta-address to encode
282
+ * @returns Encoded string (st:eth:0x...)
283
+ */
284
+ encodeMetaAddress(metaAddress: StealthMetaAddress): string {
285
+ return encodeEthereumStealthMetaAddress(metaAddress)
286
+ }
287
+
288
+ // ─── Viewing Key Management ─────────────────────────────────────────────────
289
+
290
+ /**
291
+ * Export a viewing key for sharing (compliance)
292
+ *
293
+ * @param viewingKeyPair - Viewing keypair to export
294
+ * @param expiresAt - Optional expiration date
295
+ * @returns Exportable viewing key data
296
+ */
297
+ exportViewingKey(
298
+ viewingKeyPair: EthereumViewingKeyPair,
299
+ expiresAt?: Date
300
+ ): EthereumViewingKeyExport {
301
+ return exportViewingKey(viewingKeyPair, this.network, expiresAt)
302
+ }
303
+
304
+ /**
305
+ * Import a viewing key from export format
306
+ *
307
+ * @param exported - Exported viewing key data (JSON string or object)
308
+ * @returns Parsed viewing key export
309
+ */
310
+ importViewingKey(exported: string | EthereumViewingKeyExport): EthereumViewingKeyExport {
311
+ return importViewingKey(exported)
312
+ }
313
+
314
+ /**
315
+ * Create a shared viewing key with specific permissions
316
+ *
317
+ * @param viewingKeyPair - The full viewing keypair
318
+ * @param permissions - Permissions to grant
319
+ * @param expiresAt - Optional expiration
320
+ * @returns Shared viewing key for auditor
321
+ */
322
+ createSharedViewingKey(
323
+ viewingKeyPair: EthereumViewingKeyPair,
324
+ permissions: ViewingKeyPermissions,
325
+ expiresAt?: Date
326
+ ) {
327
+ return createSharedViewingKey(viewingKeyPair, permissions, expiresAt)
328
+ }
329
+
330
+ // ─── Stealth Address Resolution ─────────────────────────────────────────────
331
+
332
+ /**
333
+ * Resolve a meta-address to a one-time stealth address
334
+ *
335
+ * Generates a fresh stealth address for the recipient.
336
+ * Each call produces a different, unlinkable address.
337
+ *
338
+ * @param recipient - Recipient's meta-address
339
+ * @returns Stealth address details
340
+ */
341
+ resolveStealthAddress(recipient: StealthMetaAddress | string): {
342
+ stealthAddress: EthereumStealthAddress
343
+ ethAddress: HexString
344
+ sharedSecret: HexString
345
+ } {
346
+ const metaAddress = typeof recipient === 'string'
347
+ ? parseEthereumStealthMetaAddress(recipient)
348
+ : recipient
349
+
350
+ const { stealthAddress, sharedSecret } = generateEthereumStealthAddress(metaAddress)
351
+
352
+ return {
353
+ stealthAddress,
354
+ ethAddress: stealthAddress.ethAddress,
355
+ sharedSecret,
356
+ }
357
+ }
358
+
359
+ /**
360
+ * Check if a stealth address belongs to a recipient
361
+ *
362
+ * @param stealthAddress - Stealth address object
363
+ * @param spendingPrivateKey - Spending private key (hex)
364
+ * @param viewingPrivateKey - Viewing private key (hex)
365
+ * @returns True if the address belongs to the recipient
366
+ */
367
+ checkStealthAddress(
368
+ stealthAddress: StealthAddress,
369
+ spendingPrivateKey: HexString,
370
+ viewingPrivateKey: HexString
371
+ ): boolean {
372
+ return checkEthereumStealthAddress(
373
+ stealthAddress,
374
+ spendingPrivateKey,
375
+ viewingPrivateKey
376
+ )
377
+ }
378
+
379
+ // ─── Shielded Transfers ─────────────────────────────────────────────────────
380
+
381
+ /**
382
+ * Build a shielded ETH transfer
383
+ *
384
+ * Creates transaction data for a private ETH transfer.
385
+ * Returns two transactions:
386
+ * 1. ETH transfer to stealth address
387
+ * 2. Announcement to EIP-5564 contract
388
+ *
389
+ * @param params - Transfer parameters
390
+ * @returns Built transfer ready for signing
391
+ */
392
+ buildShieldedTransfer(params: EthereumShieldedTransferParams): EthereumShieldedTransferBuild {
393
+ const privacyLevel = params.privacyLevel ?? this.defaultPrivacyLevel
394
+
395
+ // For transparent level, throw - use regular transfer instead
396
+ if (privacyLevel === 'transparent') {
397
+ throw new Error('Use regular ETH transfer for transparent privacy level')
398
+ }
399
+
400
+ const metaAddress = typeof params.recipient === 'string'
401
+ ? parseEthereumStealthMetaAddress(params.recipient)
402
+ : params.recipient
403
+
404
+ // Generate stealth address
405
+ const { stealthAddress, sharedSecret } = generateEthereumStealthAddress(metaAddress)
406
+
407
+ // Create amount commitment if hiding amounts
408
+ // Note: privacyLevel is guaranteed to be 'shielded' or 'compliant' here (transparent throws above)
409
+ let amountCommitment: EthereumPedersenCommitment | undefined
410
+ if (this.hideAmounts) {
411
+ amountCommitment = commitETH(params.amount)
412
+ }
413
+
414
+ // Create metadata for announcement
415
+ const metadata = this.hideAmounts && amountCommitment
416
+ ? createAnnouncementMetadata({
417
+ amountCommitment: amountCommitment.commitment,
418
+ })
419
+ : undefined
420
+
421
+ // Build announcement call data
422
+ const announcementData = encodeAnnouncementCallData(
423
+ 1, // schemeId for secp256k1
424
+ stealthAddress.ethAddress,
425
+ stealthAddress.ephemeralPublicKey,
426
+ metadata
427
+ )
428
+
429
+ // Estimate gas
430
+ const transferGas = DEFAULT_GAS_LIMITS.ethTransfer
431
+ const announcementGas = DEFAULT_GAS_LIMITS.announcement
432
+ const totalGas = transferGas + announcementGas
433
+
434
+ return {
435
+ stealthAddress,
436
+ stealthEthAddress: stealthAddress.ethAddress,
437
+ ephemeralPublicKey: stealthAddress.ephemeralPublicKey,
438
+ viewTag: stealthAddress.viewTag,
439
+ sharedSecret,
440
+ amountCommitment: amountCommitment?.commitment,
441
+ blindingFactor: amountCommitment?.blinding,
442
+ transferTx: {
443
+ to: stealthAddress.ethAddress,
444
+ value: params.amount,
445
+ },
446
+ announcementTx: {
447
+ to: this.announcerAddress,
448
+ value: 0n,
449
+ data: announcementData,
450
+ },
451
+ estimatedGas: totalGas,
452
+ }
453
+ }
454
+
455
+ /**
456
+ * Build a shielded ERC-20 token transfer
457
+ *
458
+ * Creates transaction data for a private token transfer.
459
+ * Returns multiple transactions:
460
+ * 1. Token transfer to stealth address
461
+ * 2. Announcement to EIP-5564 contract
462
+ *
463
+ * @param params - Transfer parameters
464
+ * @returns Built transfer ready for signing
465
+ */
466
+ buildShieldedTokenTransfer(
467
+ params: EthereumShieldedTokenTransferParams
468
+ ): EthereumShieldedTransferBuild & { tokenTransferData: HexString } {
469
+ const privacyLevel = params.privacyLevel ?? this.defaultPrivacyLevel
470
+
471
+ if (privacyLevel === 'transparent') {
472
+ throw new Error('Use regular ERC-20 transfer for transparent privacy level')
473
+ }
474
+
475
+ if (!isValidEthAddress(params.tokenContract)) {
476
+ throw new Error(`Invalid token contract: ${params.tokenContract}`)
477
+ }
478
+
479
+ const metaAddress = typeof params.recipient === 'string'
480
+ ? parseEthereumStealthMetaAddress(params.recipient)
481
+ : params.recipient
482
+
483
+ // Generate stealth address
484
+ const { stealthAddress, sharedSecret } = generateEthereumStealthAddress(metaAddress)
485
+
486
+ // Create amount commitment
487
+ const decimals = params.decimals ?? 18
488
+ const amountCommitment = this.hideAmounts
489
+ ? commitERC20Token(params.amount, params.tokenContract, decimals)
490
+ : undefined
491
+
492
+ // Create metadata for announcement
493
+ const metadata = createAnnouncementMetadata({
494
+ tokenAddress: params.tokenContract,
495
+ amountCommitment: amountCommitment?.commitment,
496
+ })
497
+
498
+ // Build ERC-20 transfer data
499
+ // transfer(address,uint256) selector: 0xa9059cbb
500
+ const tokenTransferData = this.encodeERC20Transfer(
501
+ stealthAddress.ethAddress,
502
+ params.amount
503
+ )
504
+
505
+ // Build announcement call data
506
+ const announcementData = encodeAnnouncementCallData(
507
+ 1,
508
+ stealthAddress.ethAddress,
509
+ stealthAddress.ephemeralPublicKey,
510
+ metadata
511
+ )
512
+
513
+ // Estimate gas
514
+ const transferGas = DEFAULT_GAS_LIMITS.erc20Transfer
515
+ const announcementGas = DEFAULT_GAS_LIMITS.announcement
516
+ const totalGas = transferGas + announcementGas
517
+
518
+ return {
519
+ stealthAddress,
520
+ stealthEthAddress: stealthAddress.ethAddress,
521
+ ephemeralPublicKey: stealthAddress.ephemeralPublicKey,
522
+ viewTag: stealthAddress.viewTag,
523
+ sharedSecret,
524
+ amountCommitment: amountCommitment?.commitment,
525
+ blindingFactor: amountCommitment?.blinding,
526
+ transferTx: {
527
+ to: params.tokenContract,
528
+ value: 0n,
529
+ data: tokenTransferData,
530
+ },
531
+ announcementTx: {
532
+ to: this.announcerAddress,
533
+ value: 0n,
534
+ data: announcementData,
535
+ },
536
+ estimatedGas: totalGas,
537
+ tokenTransferData,
538
+ }
539
+ }
540
+
541
+ // ─── Payment Scanning ───────────────────────────────────────────────────────
542
+
543
+ /**
544
+ * Add a recipient for payment scanning
545
+ *
546
+ * @param recipient - Scan recipient with viewing key
547
+ */
548
+ addScanRecipient(recipient: EthereumScanRecipient): void {
549
+ const key = recipient.viewingPrivateKey.toLowerCase()
550
+ this.scanRecipients.set(key, recipient)
551
+ }
552
+
553
+ /**
554
+ * Remove a scan recipient
555
+ *
556
+ * @param viewingPrivateKey - The viewing key to remove
557
+ */
558
+ removeScanRecipient(viewingPrivateKey: HexString): void {
559
+ this.scanRecipients.delete(viewingPrivateKey.toLowerCase())
560
+ }
561
+
562
+ /**
563
+ * Get all scan recipients
564
+ */
565
+ getScanRecipients(): EthereumScanRecipient[] {
566
+ return Array.from(this.scanRecipients.values())
567
+ }
568
+
569
+ /**
570
+ * Scan announcements for incoming payments
571
+ *
572
+ * @param announcements - Announcements to scan
573
+ * @returns Detected payments with recipient info
574
+ */
575
+ scanAnnouncements(
576
+ announcements: EthereumAnnouncement[]
577
+ ): EthereumDetectedPaymentResult[] {
578
+ const results: EthereumDetectedPaymentResult[] = []
579
+
580
+ for (const announcement of announcements) {
581
+ const stealthAddress = announcementToStealthAddress(announcement)
582
+
583
+ // Check each recipient
584
+ for (const recipient of this.scanRecipients.values()) {
585
+ const isOwner = checkEthereumStealthAddress(
586
+ stealthAddress,
587
+ recipient.spendingPublicKey, // Note: need spending PRIVATE key for full check
588
+ recipient.viewingPrivateKey
589
+ )
590
+
591
+ if (isOwner) {
592
+ // Derive stealth private key for claiming
593
+ const recovery = deriveEthereumStealthPrivateKey(
594
+ stealthAddress,
595
+ recipient.spendingPublicKey, // This should be spending PRIVATE key
596
+ recipient.viewingPrivateKey
597
+ )
598
+
599
+ results.push({
600
+ payment: {
601
+ stealthAddress,
602
+ stealthEthAddress: announcement.stealthAddress,
603
+ txHash: announcement.txHash!,
604
+ blockNumber: announcement.blockNumber!,
605
+ logIndex: announcement.logIndex,
606
+ timestamp: announcement.timestamp,
607
+ },
608
+ recipient,
609
+ stealthPrivateKey: recovery.privateKey,
610
+ })
611
+ break // Found owner, no need to check other recipients
612
+ }
613
+ }
614
+ }
615
+
616
+ return results
617
+ }
618
+
619
+ /**
620
+ * Get topics for filtering announcement logs
621
+ *
622
+ * @param options - Optional filters
623
+ * @returns Topics array for eth_getLogs
624
+ */
625
+ getAnnouncementTopics(options?: {
626
+ schemeId?: number
627
+ stealthAddress?: HexString
628
+ caller?: HexString
629
+ }): (HexString | null)[] {
630
+ return buildAnnouncementTopics(options)
631
+ }
632
+
633
+ // ─── Claiming ───────────────────────────────────────────────────────────────
634
+
635
+ /**
636
+ * Build a claim transaction
637
+ *
638
+ * Creates transaction data to claim funds from a stealth address.
639
+ *
640
+ * @param params - Claim parameters
641
+ * @returns Built claim transaction
642
+ */
643
+ buildClaimTransaction(params: EthereumClaimParams): EthereumClaimBuild {
644
+ // Derive stealth private key
645
+ const recovery = deriveEthereumStealthPrivateKey(
646
+ params.stealthAddress,
647
+ params.spendingPrivateKey,
648
+ params.viewingPrivateKey
649
+ )
650
+
651
+ // Build transaction
652
+ const amount = params.amount ?? 0n // Full balance if not specified
653
+
654
+ let tx: { to: HexString; value: bigint; data?: HexString }
655
+
656
+ if (params.tokenContract) {
657
+ // ERC-20 claim
658
+ const transferData = this.encodeERC20Transfer(
659
+ params.destinationAddress,
660
+ amount
661
+ )
662
+ tx = {
663
+ to: params.tokenContract,
664
+ value: 0n,
665
+ data: transferData,
666
+ }
667
+ } else {
668
+ // Native ETH claim
669
+ tx = {
670
+ to: params.destinationAddress,
671
+ value: amount,
672
+ }
673
+ }
674
+
675
+ return {
676
+ stealthEthAddress: recovery.ethAddress,
677
+ stealthPrivateKey: recovery.privateKey,
678
+ destinationAddress: params.destinationAddress,
679
+ amount,
680
+ tx,
681
+ estimatedGas: params.tokenContract
682
+ ? DEFAULT_GAS_LIMITS.erc20Transfer
683
+ : DEFAULT_GAS_LIMITS.ethTransfer,
684
+ }
685
+ }
686
+
687
+ // ─── Gas Estimation ─────────────────────────────────────────────────────────
688
+
689
+ /**
690
+ * Estimate gas for a shielded transfer
691
+ *
692
+ * @param isTokenTransfer - Whether this is a token transfer
693
+ * @returns Gas estimate
694
+ */
695
+ estimateTransferGas(isTokenTransfer: boolean = false): EthereumGasEstimate {
696
+ const transferGas = isTokenTransfer
697
+ ? DEFAULT_GAS_LIMITS.erc20Transfer
698
+ : DEFAULT_GAS_LIMITS.ethTransfer
699
+ const announcementGas = DEFAULT_GAS_LIMITS.announcement
700
+
701
+ const totalGas = transferGas + announcementGas
702
+ const gasPrice = 30n * ONE_GWEI // Assume 30 gwei
703
+
704
+ const estimatedCost = totalGas * gasPrice
705
+
706
+ return {
707
+ gasLimit: totalGas,
708
+ gasPrice,
709
+ estimatedCost,
710
+ estimatedCostEth: fromWei(estimatedCost),
711
+ }
712
+ }
713
+
714
+ /**
715
+ * Estimate gas for claiming a payment
716
+ *
717
+ * @param isTokenClaim - Whether claiming tokens
718
+ * @returns Gas estimate
719
+ */
720
+ estimateClaimGas(isTokenClaim: boolean = false): EthereumGasEstimate {
721
+ const claimGas = isTokenClaim
722
+ ? DEFAULT_GAS_LIMITS.erc20Transfer
723
+ : DEFAULT_GAS_LIMITS.ethTransfer
724
+
725
+ const gasPrice = 30n * ONE_GWEI
726
+
727
+ return {
728
+ gasLimit: claimGas,
729
+ gasPrice,
730
+ estimatedCost: claimGas * gasPrice,
731
+ estimatedCostEth: fromWei(claimGas * gasPrice),
732
+ }
733
+ }
734
+
735
+ // ─── Utility Methods ────────────────────────────────────────────────────────
736
+
737
+ /**
738
+ * Get adapter state
739
+ */
740
+ getState(): EthereumPrivacyAdapterState {
741
+ return {
742
+ network: this.network,
743
+ rpcUrl: this.rpcUrl,
744
+ chainId: this.chainId,
745
+ defaultPrivacyLevel: this.defaultPrivacyLevel,
746
+ scanRecipientCount: this.scanRecipients.size,
747
+ lastScannedBlock: this.lastScannedBlock,
748
+ isConnected: true,
749
+ }
750
+ }
751
+
752
+ /**
753
+ * Get RPC URL
754
+ */
755
+ getRpcUrl(): string {
756
+ return this.rpcUrl
757
+ }
758
+
759
+ /**
760
+ * Get network
761
+ */
762
+ getNetwork(): EthereumNetwork {
763
+ return this.network
764
+ }
765
+
766
+ /**
767
+ * Get chain ID
768
+ */
769
+ getChainId(): number {
770
+ return this.chainId
771
+ }
772
+
773
+ /**
774
+ * Get transaction explorer URL
775
+ *
776
+ * @param txHash - Transaction hash
777
+ * @returns Explorer URL
778
+ */
779
+ getTransactionExplorerUrl(txHash: HexString): string {
780
+ return getExplorerUrl(txHash, this.network)
781
+ }
782
+
783
+ /**
784
+ * Encode ERC-20 transfer data
785
+ *
786
+ * @param to - Recipient address
787
+ * @param amount - Amount in token units
788
+ * @returns Encoded call data
789
+ */
790
+ private encodeERC20Transfer(to: HexString, amount: bigint): HexString {
791
+ // transfer(address,uint256) selector
792
+ const selector = '0xa9059cbb'
793
+ const toParam = to.slice(2).padStart(64, '0')
794
+ const amountParam = amount.toString(16).padStart(64, '0')
795
+
796
+ return `${selector}${toParam}${amountParam}` as HexString
797
+ }
798
+
799
+ /**
800
+ * Clean up adapter resources
801
+ */
802
+ dispose(): void {
803
+ this.scanRecipients.clear()
804
+ this.lastScannedBlock = undefined
805
+ }
806
+ }
807
+
808
+ // ─── Factory Functions ────────────────────────────────────────────────────────
809
+
810
+ /**
811
+ * Create an Ethereum privacy adapter
812
+ *
813
+ * @param config - Adapter configuration
814
+ * @returns Configured adapter
815
+ */
816
+ export function createEthereumPrivacyAdapter(
817
+ config?: EthereumPrivacyAdapterConfig
818
+ ): EthereumPrivacyAdapter {
819
+ return new EthereumPrivacyAdapter(config)
820
+ }
821
+
822
+ /**
823
+ * Create a mainnet Ethereum privacy adapter
824
+ */
825
+ export function createMainnetEthereumPrivacyAdapter(): EthereumPrivacyAdapter {
826
+ return new EthereumPrivacyAdapter({ network: 'mainnet' })
827
+ }
828
+
829
+ /**
830
+ * Create a Sepolia testnet privacy adapter
831
+ */
832
+ export function createSepoliaEthereumPrivacyAdapter(): EthereumPrivacyAdapter {
833
+ return new EthereumPrivacyAdapter({ network: 'sepolia' })
834
+ }
835
+
836
+ /**
837
+ * Create an Arbitrum privacy adapter
838
+ */
839
+ export function createArbitrumPrivacyAdapter(): EthereumPrivacyAdapter {
840
+ return new EthereumPrivacyAdapter({ network: 'arbitrum' })
841
+ }
842
+
843
+ /**
844
+ * Create an Optimism privacy adapter
845
+ */
846
+ export function createOptimismPrivacyAdapter(): EthereumPrivacyAdapter {
847
+ return new EthereumPrivacyAdapter({ network: 'optimism' })
848
+ }
849
+
850
+ /**
851
+ * Create a Base privacy adapter
852
+ */
853
+ export function createBasePrivacyAdapter(): EthereumPrivacyAdapter {
854
+ return new EthereumPrivacyAdapter({ network: 'base' })
855
+ }