@sip-protocol/sdk 0.7.3 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (263) hide show
  1. package/README.md +267 -0
  2. package/dist/{TransportWebUSB-TQ7WZ4LE.mjs → TransportWebUSB-YQMAGJAJ.mjs} +12 -9
  3. package/dist/browser.d.mts +10 -4
  4. package/dist/browser.d.ts +10 -4
  5. package/dist/browser.js +47556 -19603
  6. package/dist/browser.mjs +628 -48
  7. package/dist/chunk-4GRJ5MAW.mjs +152 -0
  8. package/dist/chunk-5D7A3L3W.mjs +717 -0
  9. package/dist/chunk-64AYA5F5.mjs +7834 -0
  10. package/dist/chunk-GMDGB22A.mjs +379 -0
  11. package/dist/chunk-I534WKN7.mjs +328 -0
  12. package/dist/chunk-IBZVA5Y7.mjs +1003 -0
  13. package/dist/chunk-PRRZAWJE.mjs +223 -0
  14. package/dist/{chunk-UJCSKKID.mjs → chunk-XGB3TDIC.mjs} +13 -1
  15. package/dist/{chunk-3M3HNQCW.mjs → chunk-YWGJ77A2.mjs} +28656 -13103
  16. package/dist/{chunk-6WGN57S2.mjs → chunk-Z3K7W5S3.mjs} +48 -0
  17. package/dist/constants-LHAAUC2T.mjs +51 -0
  18. package/dist/dist-2OGQ7FED.mjs +3957 -0
  19. package/dist/dist-IFHPYLDX.mjs +254 -0
  20. package/dist/fulfillment_proof-ANHVPKTB.mjs +21 -0
  21. package/dist/funding_proof-ICFZ5LHY.mjs +21 -0
  22. package/dist/{index-DIBZHOOQ.d.ts → index-DXh2IGkz.d.ts} +21239 -10304
  23. package/dist/{index-8MQz13eJ.d.mts → index-DeE1ZzA4.d.mts} +21239 -10304
  24. package/dist/index.d.mts +9 -3
  25. package/dist/index.d.ts +9 -3
  26. package/dist/index.js +48396 -19623
  27. package/dist/index.mjs +537 -19
  28. package/dist/interface-Bf7w1PLW.d.mts +679 -0
  29. package/dist/interface-Bf7w1PLW.d.ts +679 -0
  30. package/dist/{noir-DKfEzWy9.d.mts → noir-kzbLVTei.d.mts} +31 -21
  31. package/dist/{noir-DKfEzWy9.d.ts → noir-kzbLVTei.d.ts} +31 -21
  32. package/dist/proofs/halo2.d.mts +151 -0
  33. package/dist/proofs/halo2.d.ts +151 -0
  34. package/dist/proofs/halo2.js +350 -0
  35. package/dist/proofs/halo2.mjs +11 -0
  36. package/dist/proofs/kimchi.d.mts +160 -0
  37. package/dist/proofs/kimchi.d.ts +160 -0
  38. package/dist/proofs/kimchi.js +431 -0
  39. package/dist/proofs/kimchi.mjs +13 -0
  40. package/dist/proofs/noir.d.mts +1 -1
  41. package/dist/proofs/noir.d.ts +1 -1
  42. package/dist/proofs/noir.js +74 -18
  43. package/dist/proofs/noir.mjs +84 -24
  44. package/dist/solana-U3MEGU7W.mjs +280 -0
  45. package/dist/validity_proof-3POXLPNY.mjs +21 -0
  46. package/package.json +44 -11
  47. package/src/adapters/index.ts +41 -0
  48. package/src/adapters/jupiter.ts +571 -0
  49. package/src/adapters/near-intents.ts +135 -0
  50. package/src/advisor/advisor.ts +653 -0
  51. package/src/advisor/index.ts +54 -0
  52. package/src/advisor/tools.ts +303 -0
  53. package/src/advisor/types.ts +164 -0
  54. package/src/chains/ethereum/announcement.ts +536 -0
  55. package/src/chains/ethereum/bnb-optimizations.ts +474 -0
  56. package/src/chains/ethereum/commitment.ts +522 -0
  57. package/src/chains/ethereum/constants.ts +462 -0
  58. package/src/chains/ethereum/deployment.ts +596 -0
  59. package/src/chains/ethereum/gas-estimation.ts +538 -0
  60. package/src/chains/ethereum/index.ts +268 -0
  61. package/src/chains/ethereum/optimizations.ts +614 -0
  62. package/src/chains/ethereum/privacy-adapter.ts +855 -0
  63. package/src/chains/ethereum/registry.ts +584 -0
  64. package/src/chains/ethereum/rpc.ts +905 -0
  65. package/src/chains/ethereum/stealth.ts +491 -0
  66. package/src/chains/ethereum/token.ts +790 -0
  67. package/src/chains/ethereum/transfer.ts +637 -0
  68. package/src/chains/ethereum/types.ts +456 -0
  69. package/src/chains/ethereum/viewing-key.ts +455 -0
  70. package/src/chains/near/commitment.ts +608 -0
  71. package/src/chains/near/constants.ts +284 -0
  72. package/src/chains/near/function-call.ts +871 -0
  73. package/src/chains/near/history.ts +654 -0
  74. package/src/chains/near/implicit-account.ts +840 -0
  75. package/src/chains/near/index.ts +393 -0
  76. package/src/chains/near/native-transfer.ts +658 -0
  77. package/src/chains/near/nep141.ts +775 -0
  78. package/src/chains/near/privacy-adapter.ts +889 -0
  79. package/src/chains/near/resolver.ts +971 -0
  80. package/src/chains/near/rpc.ts +1016 -0
  81. package/src/chains/near/stealth.ts +419 -0
  82. package/src/chains/near/types.ts +317 -0
  83. package/src/chains/near/viewing-key.ts +876 -0
  84. package/src/chains/solana/anchor-transfer.ts +386 -0
  85. package/src/chains/solana/commitment.ts +577 -0
  86. package/src/chains/solana/constants.ts +126 -12
  87. package/src/chains/solana/ephemeral-keys.ts +543 -0
  88. package/src/chains/solana/index.ts +252 -1
  89. package/src/chains/solana/key-derivation.ts +418 -0
  90. package/src/chains/solana/kit-compat.ts +334 -0
  91. package/src/chains/solana/optimizations.ts +560 -0
  92. package/src/chains/solana/privacy-adapter.ts +605 -0
  93. package/src/chains/solana/providers/generic.ts +47 -6
  94. package/src/chains/solana/providers/helius-enhanced-types.ts +336 -0
  95. package/src/chains/solana/providers/helius-enhanced.ts +623 -0
  96. package/src/chains/solana/providers/helius.ts +186 -33
  97. package/src/chains/solana/providers/index.ts +31 -0
  98. package/src/chains/solana/providers/interface.ts +61 -18
  99. package/src/chains/solana/providers/quicknode.ts +409 -0
  100. package/src/chains/solana/providers/triton.ts +426 -0
  101. package/src/chains/solana/providers/webhook.ts +338 -67
  102. package/src/chains/solana/rpc-client.ts +1150 -0
  103. package/src/chains/solana/scan.ts +83 -66
  104. package/src/chains/solana/sol-transfer.ts +732 -0
  105. package/src/chains/solana/spl-transfer.ts +886 -0
  106. package/src/chains/solana/stealth-scanner.ts +703 -0
  107. package/src/chains/solana/sunspot-verifier.ts +453 -0
  108. package/src/chains/solana/transaction-builder.ts +755 -0
  109. package/src/chains/solana/transfer.ts +74 -5
  110. package/src/chains/solana/types.ts +57 -6
  111. package/src/chains/solana/utils.ts +110 -0
  112. package/src/chains/solana/viewing-key.ts +807 -0
  113. package/src/compliance/fireblocks.ts +921 -0
  114. package/src/compliance/index.ts +23 -0
  115. package/src/compliance/range-sas.ts +398 -33
  116. package/src/config/endpoints.ts +100 -0
  117. package/src/crypto.ts +11 -8
  118. package/src/errors.ts +82 -0
  119. package/src/evm/erc4337-relayer.ts +830 -0
  120. package/src/evm/index.ts +47 -0
  121. package/src/fees/calculator.ts +396 -0
  122. package/src/fees/index.ts +87 -0
  123. package/src/fees/near-contract.ts +429 -0
  124. package/src/fees/types.ts +268 -0
  125. package/src/index.ts +686 -1
  126. package/src/intent.ts +6 -3
  127. package/src/logger.ts +324 -0
  128. package/src/network/index.ts +80 -0
  129. package/src/network/proxy.ts +691 -0
  130. package/src/optimizations/index.ts +541 -0
  131. package/src/oracle/types.ts +1 -0
  132. package/src/privacy-backends/arcium-types.ts +727 -0
  133. package/src/privacy-backends/arcium.ts +719 -0
  134. package/src/privacy-backends/combined-privacy.ts +866 -0
  135. package/src/privacy-backends/cspl-token.ts +595 -0
  136. package/src/privacy-backends/cspl-types.ts +512 -0
  137. package/src/privacy-backends/cspl.ts +907 -0
  138. package/src/privacy-backends/health.ts +488 -0
  139. package/src/privacy-backends/inco-types.ts +323 -0
  140. package/src/privacy-backends/inco.ts +616 -0
  141. package/src/privacy-backends/index.ts +254 -4
  142. package/src/privacy-backends/interface.ts +649 -6
  143. package/src/privacy-backends/lru-cache.ts +343 -0
  144. package/src/privacy-backends/magicblock.ts +458 -0
  145. package/src/privacy-backends/mock.ts +258 -0
  146. package/src/privacy-backends/privacycash.ts +13 -17
  147. package/src/privacy-backends/private-swap.ts +570 -0
  148. package/src/privacy-backends/rate-limiter.ts +683 -0
  149. package/src/privacy-backends/registry.ts +414 -2
  150. package/src/privacy-backends/router.ts +283 -3
  151. package/src/privacy-backends/shadowwire.ts +449 -0
  152. package/src/privacy-backends/sip-native.ts +3 -0
  153. package/src/privacy-logger.ts +191 -0
  154. package/src/production-safety.ts +373 -0
  155. package/src/proofs/aggregator.ts +1029 -0
  156. package/src/proofs/browser-composer.ts +1150 -0
  157. package/src/proofs/browser.ts +113 -25
  158. package/src/proofs/cache/index.ts +127 -0
  159. package/src/proofs/cache/interface.ts +545 -0
  160. package/src/proofs/cache/key-generator.ts +188 -0
  161. package/src/proofs/cache/lru-cache.ts +481 -0
  162. package/src/proofs/cache/multi-tier-cache.ts +575 -0
  163. package/src/proofs/cache/persistent-cache.ts +788 -0
  164. package/src/proofs/compliance-proof.ts +872 -0
  165. package/src/proofs/composer/base.ts +923 -0
  166. package/src/proofs/composer/index.ts +25 -0
  167. package/src/proofs/composer/interface.ts +518 -0
  168. package/src/proofs/composer/types.ts +383 -0
  169. package/src/proofs/converters/halo2.ts +452 -0
  170. package/src/proofs/converters/index.ts +208 -0
  171. package/src/proofs/converters/interface.ts +363 -0
  172. package/src/proofs/converters/kimchi.ts +462 -0
  173. package/src/proofs/converters/noir.ts +451 -0
  174. package/src/proofs/fallback.ts +888 -0
  175. package/src/proofs/halo2.ts +42 -0
  176. package/src/proofs/index.ts +471 -0
  177. package/src/proofs/interface.ts +13 -0
  178. package/src/proofs/kimchi.ts +42 -0
  179. package/src/proofs/lazy.ts +1004 -0
  180. package/src/proofs/mock.ts +25 -1
  181. package/src/proofs/noir.ts +110 -29
  182. package/src/proofs/orchestrator.ts +960 -0
  183. package/src/proofs/parallel/concurrency.ts +297 -0
  184. package/src/proofs/parallel/dependency-graph.ts +602 -0
  185. package/src/proofs/parallel/executor.ts +420 -0
  186. package/src/proofs/parallel/index.ts +131 -0
  187. package/src/proofs/parallel/interface.ts +685 -0
  188. package/src/proofs/parallel/worker-pool.ts +644 -0
  189. package/src/proofs/providers/halo2.ts +560 -0
  190. package/src/proofs/providers/index.ts +34 -0
  191. package/src/proofs/providers/kimchi.ts +641 -0
  192. package/src/proofs/validator.ts +881 -0
  193. package/src/proofs/verifier.ts +867 -0
  194. package/src/quantum/index.ts +112 -0
  195. package/src/quantum/winternitz-vault.ts +639 -0
  196. package/src/quantum/wots.ts +611 -0
  197. package/src/settlement/backends/direct-chain.ts +1 -0
  198. package/src/settlement/index.ts +9 -0
  199. package/src/settlement/router.ts +732 -46
  200. package/src/solana/index.ts +72 -0
  201. package/src/solana/jito-relayer.ts +687 -0
  202. package/src/solana/noir-verifier-types.ts +430 -0
  203. package/src/solana/noir-verifier.ts +816 -0
  204. package/src/stealth/address-derivation.ts +193 -0
  205. package/src/stealth/ed25519.ts +431 -0
  206. package/src/stealth/index.ts +233 -0
  207. package/src/stealth/meta-address.ts +221 -0
  208. package/src/stealth/secp256k1.ts +368 -0
  209. package/src/stealth/utils.ts +194 -0
  210. package/src/stealth.ts +50 -1504
  211. package/src/sync/index.ts +106 -0
  212. package/src/sync/manager.ts +504 -0
  213. package/src/sync/mock-provider.ts +318 -0
  214. package/src/sync/oblivious.ts +625 -0
  215. package/src/tokens/index.ts +15 -0
  216. package/src/tokens/registry.ts +301 -0
  217. package/src/utils/deprecation.ts +94 -0
  218. package/src/utils/index.ts +9 -0
  219. package/src/wallet/ethereum/index.ts +68 -0
  220. package/src/wallet/ethereum/metamask-privacy.ts +420 -0
  221. package/src/wallet/ethereum/multi-wallet.ts +646 -0
  222. package/src/wallet/ethereum/privacy-adapter.ts +700 -0
  223. package/src/wallet/ethereum/types.ts +3 -1
  224. package/src/wallet/ethereum/walletconnect-adapter.ts +675 -0
  225. package/src/wallet/hardware/index.ts +10 -0
  226. package/src/wallet/hardware/ledger-privacy.ts +414 -0
  227. package/src/wallet/index.ts +71 -0
  228. package/src/wallet/near/adapter.ts +626 -0
  229. package/src/wallet/near/index.ts +86 -0
  230. package/src/wallet/near/meteor-wallet.ts +1153 -0
  231. package/src/wallet/near/my-near-wallet.ts +790 -0
  232. package/src/wallet/near/wallet-selector.ts +702 -0
  233. package/src/wallet/solana/adapter.ts +6 -4
  234. package/src/wallet/solana/index.ts +13 -0
  235. package/src/wallet/solana/privacy-adapter.ts +567 -0
  236. package/src/wallet/sui/types.ts +6 -4
  237. package/src/zcash/rpc-client.ts +13 -6
  238. package/dist/chunk-2XIVXWHA.mjs +0 -1930
  239. package/dist/chunk-3INS3PR5.mjs +0 -884
  240. package/dist/chunk-3OVABDRH.mjs +0 -17096
  241. package/dist/chunk-7RFRWDCW.mjs +0 -1504
  242. package/dist/chunk-DLDWZFYC.mjs +0 -1495
  243. package/dist/chunk-E6SZWREQ.mjs +0 -57
  244. package/dist/chunk-F6F73W35.mjs +0 -16166
  245. package/dist/chunk-G33LB27A.mjs +0 -16166
  246. package/dist/chunk-HGU6HZRC.mjs +0 -231
  247. package/dist/chunk-L2K34JCU.mjs +0 -1496
  248. package/dist/chunk-OFDBEIEK.mjs +0 -16166
  249. package/dist/chunk-SF7YSLF5.mjs +0 -1515
  250. package/dist/chunk-SN4ZDTVW.mjs +0 -16166
  251. package/dist/chunk-WWUSGOXE.mjs +0 -17129
  252. package/dist/constants-VOI7BSLK.mjs +0 -27
  253. package/dist/index-B71aXVzk.d.ts +0 -13264
  254. package/dist/index-BYZbDjal.d.ts +0 -11390
  255. package/dist/index-CHB3KuOB.d.mts +0 -11859
  256. package/dist/index-CzWPI6Le.d.ts +0 -11859
  257. package/dist/index-pOIIuwfV.d.mts +0 -13264
  258. package/dist/index-xbWjohNq.d.mts +0 -11390
  259. package/dist/solana-4O4K45VU.mjs +0 -46
  260. package/dist/solana-5EMCTPTS.mjs +0 -46
  261. package/dist/solana-NDABAZ6P.mjs +0 -56
  262. package/dist/solana-Q4NAVBTS.mjs +0 -46
  263. package/dist/solana-ZYO63LY5.mjs +0 -46
@@ -0,0 +1,491 @@
1
+ /**
2
+ * Ethereum Stealth Address Implementation (EIP-5564)
3
+ *
4
+ * Ethereum-specific wrapper around secp256k1 stealth addresses.
5
+ * Implements EIP-5564 compliant stealth address generation and resolution.
6
+ *
7
+ * ## EIP-5564 Overview
8
+ *
9
+ * EIP-5564 defines a standard for stealth addresses on Ethereum:
10
+ * - Meta-address format: `st:eth:0x<spendingKey><viewingKey>`
11
+ * - Scheme ID 1: secp256k1 curve
12
+ * - Uses keccak256 for address derivation
13
+ *
14
+ * @see https://eips.ethereum.org/EIPS/eip-5564
15
+ * @packageDocumentation
16
+ */
17
+
18
+ import type {
19
+ StealthMetaAddress,
20
+ StealthAddress,
21
+ StealthAddressRecovery,
22
+ HexString,
23
+ } from '@sip-protocol/types'
24
+ import {
25
+ generateSecp256k1StealthMetaAddress,
26
+ generateSecp256k1StealthAddress,
27
+ deriveSecp256k1StealthPrivateKey,
28
+ checkSecp256k1StealthAddress,
29
+ publicKeyToEthAddress,
30
+ } from '../../stealth/secp256k1'
31
+ import { ValidationError } from '../../errors'
32
+ import { SECP256K1_SCHEME_ID } from './constants'
33
+
34
+ // ─── Types ────────────────────────────────────────────────────────────────────
35
+
36
+ /**
37
+ * Ethereum stealth meta-address with additional context
38
+ */
39
+ export interface EthereumStealthMetaAddress extends StealthMetaAddress {
40
+ /** Always 'ethereum' for this chain */
41
+ chain: 'ethereum'
42
+ /** EIP-5564 scheme ID (1 for secp256k1) */
43
+ schemeId: typeof SECP256K1_SCHEME_ID
44
+ }
45
+
46
+ /**
47
+ * Ethereum stealth address with derived ETH address
48
+ */
49
+ export interface EthereumStealthAddress extends StealthAddress {
50
+ /** Ethereum address derived from the stealth public key */
51
+ ethAddress: HexString
52
+ }
53
+
54
+ /**
55
+ * Result of generating an Ethereum stealth meta-address
56
+ */
57
+ export interface EthereumStealthMetaAddressResult {
58
+ /** The stealth meta-address */
59
+ metaAddress: EthereumStealthMetaAddress
60
+ /** EIP-5564 encoded string */
61
+ encoded: string
62
+ /** Spending private key (keep secret!) */
63
+ spendingPrivateKey: HexString
64
+ /** Viewing private key (share with auditors) */
65
+ viewingPrivateKey: HexString
66
+ }
67
+
68
+ /**
69
+ * Result of resolving a stealth address for a recipient
70
+ */
71
+ export interface EthereumStealthAddressResult {
72
+ /** The stealth address */
73
+ stealthAddress: EthereumStealthAddress
74
+ /** Shared secret (for debugging, should be discarded) */
75
+ sharedSecret: HexString
76
+ }
77
+
78
+ // ─── Constants ────────────────────────────────────────────────────────────────
79
+
80
+ /**
81
+ * EIP-5564 meta-address prefix for Ethereum
82
+ */
83
+ export const EIP5564_PREFIX = 'st:eth:0x'
84
+
85
+ /**
86
+ * Scheme ID for secp256k1 (EIP-5564)
87
+ */
88
+ export const SCHEME_ID = SECP256K1_SCHEME_ID
89
+
90
+ // ─── Meta-Address Generation ────────────────────────────────────────────────
91
+
92
+ /**
93
+ * Generate a new Ethereum stealth meta-address
94
+ *
95
+ * Creates a new keypair suitable for receiving stealth payments on Ethereum.
96
+ *
97
+ * @param label - Optional label for the meta-address
98
+ * @returns Generated meta-address and private keys
99
+ *
100
+ * @example
101
+ * ```typescript
102
+ * const result = generateEthereumStealthMetaAddress('My Wallet')
103
+ *
104
+ * // Share the encoded meta-address with senders
105
+ * console.log(result.encoded)
106
+ * // => 'st:eth:0x02abc...123def...456'
107
+ *
108
+ * // Store private keys securely
109
+ * console.log(result.spendingPrivateKey) // For claiming funds
110
+ * console.log(result.viewingPrivateKey) // For scanning & auditors
111
+ * ```
112
+ */
113
+ export function generateEthereumStealthMetaAddress(
114
+ label?: string
115
+ ): EthereumStealthMetaAddressResult {
116
+ const { metaAddress, spendingPrivateKey, viewingPrivateKey } =
117
+ generateSecp256k1StealthMetaAddress('ethereum', label)
118
+
119
+ const ethereumMetaAddress: EthereumStealthMetaAddress = {
120
+ ...metaAddress,
121
+ chain: 'ethereum',
122
+ schemeId: SCHEME_ID,
123
+ }
124
+
125
+ return {
126
+ metaAddress: ethereumMetaAddress,
127
+ encoded: encodeEthereumStealthMetaAddress(ethereumMetaAddress),
128
+ spendingPrivateKey,
129
+ viewingPrivateKey,
130
+ }
131
+ }
132
+
133
+ // ─── Meta-Address Encoding ──────────────────────────────────────────────────
134
+
135
+ /**
136
+ * Encode an Ethereum stealth meta-address to EIP-5564 string format
137
+ *
138
+ * Format: `st:eth:0x<spendingKey><viewingKey>`
139
+ * - spendingKey: 33 bytes compressed secp256k1 (66 hex chars)
140
+ * - viewingKey: 33 bytes compressed secp256k1 (66 hex chars)
141
+ *
142
+ * @param metaAddress - The meta-address to encode
143
+ * @returns EIP-5564 encoded string
144
+ *
145
+ * @example
146
+ * ```typescript
147
+ * const encoded = encodeEthereumStealthMetaAddress(metaAddress)
148
+ * // => 'st:eth:0x02abc...123def...456'
149
+ * ```
150
+ */
151
+ export function encodeEthereumStealthMetaAddress(
152
+ metaAddress: StealthMetaAddress
153
+ ): string {
154
+ // Remove 0x prefixes
155
+ const spendingKey = metaAddress.spendingKey.slice(2)
156
+ const viewingKey = metaAddress.viewingKey.slice(2)
157
+
158
+ // Validate lengths (33 bytes = 66 hex chars)
159
+ if (spendingKey.length !== 66) {
160
+ throw new ValidationError(
161
+ `spendingKey must be 33 bytes (66 hex chars), got ${spendingKey.length / 2} bytes`,
162
+ 'metaAddress.spendingKey'
163
+ )
164
+ }
165
+
166
+ if (viewingKey.length !== 66) {
167
+ throw new ValidationError(
168
+ `viewingKey must be 33 bytes (66 hex chars), got ${viewingKey.length / 2} bytes`,
169
+ 'metaAddress.viewingKey'
170
+ )
171
+ }
172
+
173
+ return `${EIP5564_PREFIX}${spendingKey}${viewingKey}`
174
+ }
175
+
176
+ /**
177
+ * Parse an EIP-5564 encoded meta-address string
178
+ *
179
+ * @param encoded - The encoded meta-address string
180
+ * @returns Parsed meta-address
181
+ *
182
+ * @example
183
+ * ```typescript
184
+ * const metaAddress = parseEthereumStealthMetaAddress('st:eth:0x02abc...123def...456')
185
+ * console.log(metaAddress.spendingKey) // '0x02abc...123'
186
+ * console.log(metaAddress.viewingKey) // '0x03def...456'
187
+ * ```
188
+ */
189
+ export function parseEthereumStealthMetaAddress(
190
+ encoded: string
191
+ ): EthereumStealthMetaAddress {
192
+ if (!encoded || typeof encoded !== 'string') {
193
+ throw new ValidationError('must be a non-empty string', 'encoded')
194
+ }
195
+
196
+ // Check prefix
197
+ if (!encoded.startsWith(EIP5564_PREFIX)) {
198
+ throw new ValidationError(
199
+ `must start with '${EIP5564_PREFIX}', got '${encoded.slice(0, 10)}...'`,
200
+ 'encoded'
201
+ )
202
+ }
203
+
204
+ // Extract keys (after 'st:eth:0x')
205
+ const keysHex = encoded.slice(EIP5564_PREFIX.length)
206
+
207
+ // Should be 132 hex chars (66 + 66 for two 33-byte keys)
208
+ if (keysHex.length !== 132) {
209
+ throw new ValidationError(
210
+ `expected 132 hex characters for keys, got ${keysHex.length}`,
211
+ 'encoded'
212
+ )
213
+ }
214
+
215
+ // Validate hex
216
+ if (!/^[0-9a-fA-F]+$/.test(keysHex)) {
217
+ throw new ValidationError('contains invalid hex characters', 'encoded')
218
+ }
219
+
220
+ const spendingKey = `0x${keysHex.slice(0, 66)}` as HexString
221
+ const viewingKey = `0x${keysHex.slice(66)}` as HexString
222
+
223
+ return {
224
+ spendingKey,
225
+ viewingKey,
226
+ chain: 'ethereum',
227
+ schemeId: SCHEME_ID,
228
+ }
229
+ }
230
+
231
+ /**
232
+ * Validate an EIP-5564 encoded meta-address string
233
+ *
234
+ * @param encoded - The string to validate
235
+ * @returns True if valid
236
+ */
237
+ export function isValidEthereumStealthMetaAddress(encoded: string): boolean {
238
+ try {
239
+ parseEthereumStealthMetaAddress(encoded)
240
+ return true
241
+ } catch {
242
+ return false
243
+ }
244
+ }
245
+
246
+ // ─── Stealth Address Generation ─────────────────────────────────────────────
247
+
248
+ /**
249
+ * Generate a one-time stealth address for an Ethereum recipient
250
+ *
251
+ * Creates a stealth address that only the recipient can derive the private key for.
252
+ *
253
+ * @param recipientMetaAddress - Recipient's meta-address (object or encoded string)
254
+ * @returns Stealth address with Ethereum address
255
+ *
256
+ * @example
257
+ * ```typescript
258
+ * // Generate stealth address for recipient
259
+ * const result = generateEthereumStealthAddress(recipientMetaAddress)
260
+ *
261
+ * // Send ETH to this address
262
+ * console.log(result.stealthAddress.ethAddress)
263
+ * // => '0x1234...abcd'
264
+ *
265
+ * // Include ephemeral key in announcement
266
+ * console.log(result.stealthAddress.ephemeralPublicKey)
267
+ * ```
268
+ */
269
+ export function generateEthereumStealthAddress(
270
+ recipientMetaAddress: StealthMetaAddress | string
271
+ ): EthereumStealthAddressResult {
272
+ // Parse if string
273
+ const metaAddress =
274
+ typeof recipientMetaAddress === 'string'
275
+ ? parseEthereumStealthMetaAddress(recipientMetaAddress)
276
+ : recipientMetaAddress
277
+
278
+ // Generate stealth address
279
+ const { stealthAddress, sharedSecret } =
280
+ generateSecp256k1StealthAddress(metaAddress)
281
+
282
+ // Derive Ethereum address from stealth public key
283
+ const ethAddress = publicKeyToEthAddress(stealthAddress.address)
284
+
285
+ const ethereumStealthAddress: EthereumStealthAddress = {
286
+ ...stealthAddress,
287
+ ethAddress,
288
+ }
289
+
290
+ return {
291
+ stealthAddress: ethereumStealthAddress,
292
+ sharedSecret,
293
+ }
294
+ }
295
+
296
+ // ─── Private Key Derivation ─────────────────────────────────────────────────
297
+
298
+ /**
299
+ * Derive the private key for an Ethereum stealth address
300
+ *
301
+ * Used by the recipient to claim funds sent to a stealth address.
302
+ *
303
+ * @param stealthAddress - The stealth address to derive key for
304
+ * @param spendingPrivateKey - Recipient's spending private key
305
+ * @param viewingPrivateKey - Recipient's viewing private key
306
+ * @returns Recovery information including private key
307
+ *
308
+ * @example
309
+ * ```typescript
310
+ * // Recipient derives private key to claim funds
311
+ * const recovery = deriveEthereumStealthPrivateKey(
312
+ * announcement.stealthAddress,
313
+ * mySpendingPrivateKey,
314
+ * myViewingPrivateKey
315
+ * )
316
+ *
317
+ * // Use private key to sign claim transaction
318
+ * console.log(recovery.privateKey)
319
+ * ```
320
+ */
321
+ export function deriveEthereumStealthPrivateKey(
322
+ stealthAddress: StealthAddress,
323
+ spendingPrivateKey: HexString,
324
+ viewingPrivateKey: HexString
325
+ ): StealthAddressRecovery & { ethAddress: HexString } {
326
+ const recovery = deriveSecp256k1StealthPrivateKey(
327
+ stealthAddress,
328
+ spendingPrivateKey,
329
+ viewingPrivateKey
330
+ )
331
+
332
+ // Derive Ethereum address
333
+ const ethAddress = publicKeyToEthAddress(stealthAddress.address)
334
+
335
+ return {
336
+ ...recovery,
337
+ ethAddress,
338
+ }
339
+ }
340
+
341
+ // ─── Address Checking ───────────────────────────────────────────────────────
342
+
343
+ /**
344
+ * Check if an Ethereum stealth address belongs to this recipient
345
+ *
346
+ * Used during scanning to quickly filter announcements.
347
+ *
348
+ * @param stealthAddress - The stealth address to check
349
+ * @param spendingPrivateKey - Recipient's spending private key
350
+ * @param viewingPrivateKey - Recipient's viewing private key
351
+ * @returns True if the address belongs to this recipient
352
+ *
353
+ * @example
354
+ * ```typescript
355
+ * // During scanning, check each announcement
356
+ * for (const announcement of announcements) {
357
+ * const isMine = checkEthereumStealthAddress(
358
+ * announcement.stealthAddress,
359
+ * mySpendingPrivateKey,
360
+ * myViewingPrivateKey
361
+ * )
362
+ * if (isMine) {
363
+ * console.log('Found incoming payment!')
364
+ * }
365
+ * }
366
+ * ```
367
+ */
368
+ export function checkEthereumStealthAddress(
369
+ stealthAddress: StealthAddress,
370
+ spendingPrivateKey: HexString,
371
+ viewingPrivateKey: HexString
372
+ ): boolean {
373
+ return checkSecp256k1StealthAddress(
374
+ stealthAddress,
375
+ spendingPrivateKey,
376
+ viewingPrivateKey
377
+ )
378
+ }
379
+
380
+ /**
381
+ * Quick view tag check for efficient scanning
382
+ *
383
+ * Before doing the full elliptic curve check, verify the view tag matches.
384
+ * This is ~256x faster for non-matching addresses.
385
+ *
386
+ * @param _announcement - The announcement to check (unused, for API compatibility)
387
+ * @param _viewingPrivateKey - Recipient's viewing private key (unused)
388
+ * @param _spendingPublicKey - Sender's spending public key (unused)
389
+ * @returns True if view tag matches (address *might* be ours)
390
+ *
391
+ * @deprecated Use checkEthereumStealthAddress instead which handles everything
392
+ */
393
+ export function checkViewTag(
394
+ _announcement: { ephemeralPublicKey: HexString; viewTag: number },
395
+ _viewingPrivateKey: HexString,
396
+ _spendingPublicKey: HexString
397
+ ): boolean {
398
+ // This is a simplified check - the full implementation would compute
399
+ // the shared secret and compare the first byte with the view tag.
400
+ // For efficiency, the secp256k1.checkSecp256k1StealthAddress already
401
+ // does the view tag check first, so we delegate to it with a minimal
402
+ // StealthAddress object.
403
+
404
+ // Note: This function is provided for API completeness but in practice,
405
+ // users should call checkEthereumStealthAddress which handles everything.
406
+ return true // Placeholder - actual implementation in checkEthereumStealthAddress
407
+ }
408
+
409
+ // ─── Address Conversion ─────────────────────────────────────────────────────
410
+
411
+ /**
412
+ * Convert a secp256k1 public key to an Ethereum address
413
+ *
414
+ * @param publicKey - Compressed or uncompressed public key
415
+ * @returns Checksummed Ethereum address
416
+ */
417
+ export function stealthPublicKeyToEthAddress(publicKey: HexString): HexString {
418
+ return publicKeyToEthAddress(publicKey)
419
+ }
420
+
421
+ // ─── Utility Functions ──────────────────────────────────────────────────────
422
+
423
+ /**
424
+ * Extract public keys from a meta-address for sharing
425
+ *
426
+ * @param metaAddress - The meta-address
427
+ * @returns Object with spending and viewing public keys
428
+ */
429
+ export function extractPublicKeys(metaAddress: StealthMetaAddress): {
430
+ spendingPublicKey: HexString
431
+ viewingPublicKey: HexString
432
+ } {
433
+ return {
434
+ spendingPublicKey: metaAddress.spendingKey,
435
+ viewingPublicKey: metaAddress.viewingKey,
436
+ }
437
+ }
438
+
439
+ /**
440
+ * Create a meta-address from public keys
441
+ *
442
+ * @param spendingPublicKey - Spending public key (33 bytes compressed)
443
+ * @param viewingPublicKey - Viewing public key (33 bytes compressed)
444
+ * @param label - Optional label
445
+ * @returns Ethereum stealth meta-address
446
+ */
447
+ export function createMetaAddressFromPublicKeys(
448
+ spendingPublicKey: HexString,
449
+ viewingPublicKey: HexString,
450
+ label?: string
451
+ ): EthereumStealthMetaAddress {
452
+ // Validate public keys
453
+ const spendingHex = spendingPublicKey.startsWith('0x')
454
+ ? spendingPublicKey.slice(2)
455
+ : spendingPublicKey
456
+
457
+ const viewingHex = viewingPublicKey.startsWith('0x')
458
+ ? viewingPublicKey.slice(2)
459
+ : viewingPublicKey
460
+
461
+ if (spendingHex.length !== 66) {
462
+ throw new ValidationError(
463
+ 'spendingPublicKey must be 33 bytes (66 hex chars)',
464
+ 'spendingPublicKey'
465
+ )
466
+ }
467
+
468
+ if (viewingHex.length !== 66) {
469
+ throw new ValidationError(
470
+ 'viewingPublicKey must be 33 bytes (66 hex chars)',
471
+ 'viewingPublicKey'
472
+ )
473
+ }
474
+
475
+ return {
476
+ spendingKey: `0x${spendingHex}` as HexString,
477
+ viewingKey: `0x${viewingHex}` as HexString,
478
+ chain: 'ethereum',
479
+ schemeId: SCHEME_ID,
480
+ label,
481
+ }
482
+ }
483
+
484
+ /**
485
+ * Get the scheme ID for Ethereum stealth addresses
486
+ *
487
+ * @returns EIP-5564 scheme ID (1 for secp256k1)
488
+ */
489
+ export function getSchemeId(): number {
490
+ return SCHEME_ID
491
+ }