@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,584 @@
1
+ /**
2
+ * Ethereum Stealth Meta-Address Registry Client
3
+ *
4
+ * ERC-6538 compliant registry for publishing and discovering
5
+ * stealth meta-addresses on Ethereum.
6
+ *
7
+ * @module chains/ethereum/registry
8
+ */
9
+
10
+ import type { HexString } from '@sip-protocol/types'
11
+ import {
12
+ type EthereumNetwork,
13
+ EIP5564_REGISTRY_ADDRESS,
14
+ SECP256K1_SCHEME_ID,
15
+ isValidEthAddress,
16
+ } from './constants'
17
+ import {
18
+ parseEthereumStealthMetaAddress,
19
+ encodeEthereumStealthMetaAddress,
20
+ type EthereumStealthMetaAddress,
21
+ } from './stealth'
22
+
23
+ // ─── Types ────────────────────────────────────────────────────────────────────
24
+
25
+ /**
26
+ * Registry entry for a stealth meta-address
27
+ */
28
+ export interface StealthRegistryEntry {
29
+ /**
30
+ * Owner's Ethereum address
31
+ */
32
+ owner: HexString
33
+
34
+ /**
35
+ * Scheme ID (1 = secp256k1)
36
+ */
37
+ schemeId: number
38
+
39
+ /**
40
+ * Stealth meta-address
41
+ */
42
+ metaAddress: EthereumStealthMetaAddress
43
+
44
+ /**
45
+ * Encoded meta-address string
46
+ */
47
+ encoded: string
48
+
49
+ /**
50
+ * Block number when registered
51
+ */
52
+ blockNumber?: number
53
+
54
+ /**
55
+ * Timestamp when registered
56
+ */
57
+ timestamp?: number
58
+ }
59
+
60
+ /**
61
+ * Options for registry lookup
62
+ */
63
+ export interface RegistryLookupOptions {
64
+ /**
65
+ * Scheme ID to filter by (default: SECP256K1_SCHEME_ID)
66
+ */
67
+ schemeId?: number
68
+
69
+ /**
70
+ * Block number to query at (latest if not specified)
71
+ */
72
+ blockNumber?: number | 'latest'
73
+ }
74
+
75
+ /**
76
+ * Options for registry registration
77
+ */
78
+ export interface RegistryRegisterOptions {
79
+ /**
80
+ * Scheme ID (default: SECP256K1_SCHEME_ID)
81
+ */
82
+ schemeId?: number
83
+
84
+ /**
85
+ * Gas limit override
86
+ */
87
+ gasLimit?: bigint
88
+ }
89
+
90
+ /**
91
+ * Result of registry query
92
+ */
93
+ export interface RegistryQueryResult {
94
+ /**
95
+ * Whether an entry was found
96
+ */
97
+ found: boolean
98
+
99
+ /**
100
+ * The registry entry (if found)
101
+ */
102
+ entry?: StealthRegistryEntry
103
+
104
+ /**
105
+ * Raw bytes from registry (for debugging)
106
+ */
107
+ rawData?: HexString
108
+ }
109
+
110
+ /**
111
+ * Built transaction for registry operations
112
+ */
113
+ export interface RegistryTransaction {
114
+ /**
115
+ * Target contract address
116
+ */
117
+ to: HexString
118
+
119
+ /**
120
+ * Transaction data
121
+ */
122
+ data: HexString
123
+
124
+ /**
125
+ * Value (should be 0 for registry operations)
126
+ */
127
+ value: bigint
128
+
129
+ /**
130
+ * Suggested gas limit
131
+ */
132
+ gasLimit: bigint
133
+ }
134
+
135
+ /**
136
+ * Registry cache entry
137
+ */
138
+ interface CacheEntry {
139
+ entry: StealthRegistryEntry | null
140
+ timestamp: number
141
+ }
142
+
143
+ // ─── Constants ────────────────────────────────────────────────────────────────
144
+
145
+ /**
146
+ * Registry contract ABI selectors
147
+ */
148
+ const REGISTRY_SELECTORS = {
149
+ /**
150
+ * registerKeys(uint256 schemeId, bytes stealthMetaAddress)
151
+ */
152
+ registerKeys: '0x4a8c1fb4',
153
+
154
+ /**
155
+ * registerKeysOnBehalf(address registrant, uint256 schemeId, bytes signature, bytes stealthMetaAddress)
156
+ */
157
+ registerKeysOnBehalf: '0x6ea7b7ef',
158
+
159
+ /**
160
+ * stealthMetaAddressOf(address registrant, uint256 schemeId) returns (bytes)
161
+ */
162
+ stealthMetaAddressOf: '0x3c154045',
163
+
164
+ /**
165
+ * incrementNonce() - for signature replay protection
166
+ */
167
+ incrementNonce: '0xd09de08a',
168
+
169
+ /**
170
+ * nonceOf(address registrant) returns (uint256)
171
+ */
172
+ nonceOf: '0x70ae92d2',
173
+ } as const
174
+
175
+ /**
176
+ * Cache duration (5 minutes)
177
+ */
178
+ const CACHE_DURATION = 5 * 60 * 1000
179
+
180
+ /**
181
+ * Network-specific registry addresses
182
+ * Falls back to default EIP5564_REGISTRY_ADDRESS
183
+ */
184
+ const REGISTRY_ADDRESSES: Partial<Record<EthereumNetwork, HexString>> = {
185
+ mainnet: EIP5564_REGISTRY_ADDRESS as HexString,
186
+ sepolia: EIP5564_REGISTRY_ADDRESS as HexString,
187
+ // Other networks may have different addresses
188
+ }
189
+
190
+ // ─── Registry Client Class ──────────────────────────────────────────────────
191
+
192
+ /**
193
+ * ERC-6538 Stealth Meta-Address Registry Client
194
+ *
195
+ * Provides methods to lookup and register stealth meta-addresses on-chain.
196
+ *
197
+ * @example Basic usage
198
+ * ```typescript
199
+ * const registry = new RegistryClient('mainnet')
200
+ *
201
+ * // Lookup meta-address
202
+ * const result = await registry.lookup('0x...')
203
+ * if (result.found) {
204
+ * console.log(result.entry?.encoded)
205
+ * }
206
+ *
207
+ * // Build registration transaction
208
+ * const tx = registry.buildRegisterTransaction(metaAddress)
209
+ * // Sign and submit tx externally
210
+ * ```
211
+ */
212
+ export class RegistryClient {
213
+ private network: EthereumNetwork
214
+ private registryAddress: HexString
215
+ private cache: Map<string, CacheEntry> = new Map()
216
+ private cacheEnabled: boolean
217
+
218
+ constructor(
219
+ network: EthereumNetwork = 'mainnet',
220
+ options?: {
221
+ registryAddress?: HexString
222
+ enableCache?: boolean
223
+ }
224
+ ) {
225
+ this.network = network
226
+ this.registryAddress = options?.registryAddress ??
227
+ (REGISTRY_ADDRESSES[network] ?? EIP5564_REGISTRY_ADDRESS) as HexString
228
+ this.cacheEnabled = options?.enableCache ?? true
229
+ }
230
+
231
+ // ─── Query Methods ───────────────────────────────────────────────────────────
232
+
233
+ /**
234
+ * Build call data for looking up a meta-address
235
+ *
236
+ * Use this to make an eth_call to the registry.
237
+ *
238
+ * @param address - Ethereum address to lookup
239
+ * @param options - Lookup options
240
+ * @returns Call data for eth_call
241
+ */
242
+ buildLookupCallData(
243
+ address: HexString,
244
+ options: RegistryLookupOptions = {}
245
+ ): { to: HexString; data: HexString } {
246
+ if (!isValidEthAddress(address)) {
247
+ throw new Error(`Invalid Ethereum address: ${address}`)
248
+ }
249
+
250
+ const schemeId = options.schemeId ?? SECP256K1_SCHEME_ID
251
+
252
+ // Encode: stealthMetaAddressOf(address,uint256)
253
+ const addressParam = address.slice(2).padStart(64, '0')
254
+ const schemeIdParam = schemeId.toString(16).padStart(64, '0')
255
+ const data = `${REGISTRY_SELECTORS.stealthMetaAddressOf}${addressParam}${schemeIdParam}` as HexString
256
+
257
+ return {
258
+ to: this.registryAddress,
259
+ data,
260
+ }
261
+ }
262
+
263
+ /**
264
+ * Parse the response from a lookup call
265
+ *
266
+ * @param response - Raw response from eth_call
267
+ * @param owner - The address that was looked up
268
+ * @returns Parsed registry entry or null
269
+ */
270
+ parseLookupResponse(
271
+ response: HexString,
272
+ owner: HexString
273
+ ): StealthRegistryEntry | null {
274
+ // Remove 0x prefix
275
+ const data = response.slice(2)
276
+
277
+ // Empty response or zero response means not registered
278
+ if (!data || data === '0' || data === '' || /^0+$/.test(data)) {
279
+ return null
280
+ }
281
+
282
+ try {
283
+ // Response is ABI-encoded bytes
284
+ // Format: offset (32 bytes) + length (32 bytes) + data
285
+ if (data.length < 128) {
286
+ return null
287
+ }
288
+
289
+ // Skip offset (first 32 bytes)
290
+ // Get length (next 32 bytes)
291
+ const lengthHex = data.slice(64, 128)
292
+ const length = parseInt(lengthHex, 16)
293
+
294
+ if (length === 0) {
295
+ return null
296
+ }
297
+
298
+ // Get actual data
299
+ const metaAddressBytes = data.slice(128, 128 + length * 2)
300
+
301
+ // Meta-address format: spendingKey (33 bytes) + viewingKey (33 bytes)
302
+ if (metaAddressBytes.length !== 132) {
303
+ // 66 * 2 = 132 hex chars
304
+ return null
305
+ }
306
+
307
+ const spendingKey = `0x${metaAddressBytes.slice(0, 66)}` as HexString
308
+ const viewingKey = `0x${metaAddressBytes.slice(66)}` as HexString
309
+
310
+ const metaAddress: EthereumStealthMetaAddress = {
311
+ chain: 'ethereum',
312
+ schemeId: SECP256K1_SCHEME_ID,
313
+ spendingKey,
314
+ viewingKey,
315
+ }
316
+
317
+ const encoded = encodeEthereumStealthMetaAddress(metaAddress)
318
+
319
+ return {
320
+ owner,
321
+ schemeId: SECP256K1_SCHEME_ID,
322
+ metaAddress,
323
+ encoded,
324
+ }
325
+ } catch {
326
+ return null
327
+ }
328
+ }
329
+
330
+ /**
331
+ * Get a cached lookup result
332
+ *
333
+ * @param address - Address to check cache for
334
+ * @returns Cached entry or undefined
335
+ */
336
+ getCached(address: HexString): StealthRegistryEntry | null | undefined {
337
+ if (!this.cacheEnabled) return undefined
338
+
339
+ const key = this.getCacheKey(address)
340
+ const cached = this.cache.get(key)
341
+
342
+ if (!cached) return undefined
343
+ if (Date.now() - cached.timestamp > CACHE_DURATION) {
344
+ this.cache.delete(key)
345
+ return undefined
346
+ }
347
+
348
+ return cached.entry
349
+ }
350
+
351
+ /**
352
+ * Cache a lookup result
353
+ *
354
+ * @param address - Address that was looked up
355
+ * @param entry - Result to cache (null if not found)
356
+ */
357
+ setCached(address: HexString, entry: StealthRegistryEntry | null): void {
358
+ if (!this.cacheEnabled) return
359
+
360
+ const key = this.getCacheKey(address)
361
+ this.cache.set(key, {
362
+ entry,
363
+ timestamp: Date.now(),
364
+ })
365
+ }
366
+
367
+ /**
368
+ * Clear the cache
369
+ */
370
+ clearCache(): void {
371
+ this.cache.clear()
372
+ }
373
+
374
+ // ─── Registration Methods ────────────────────────────────────────────────────
375
+
376
+ /**
377
+ * Build a transaction to register a stealth meta-address
378
+ *
379
+ * @param metaAddress - Meta-address to register
380
+ * @param options - Registration options
381
+ * @returns Transaction to sign and submit
382
+ */
383
+ buildRegisterTransaction(
384
+ metaAddress: EthereumStealthMetaAddress | string,
385
+ options: RegistryRegisterOptions = {}
386
+ ): RegistryTransaction {
387
+ const parsed = typeof metaAddress === 'string'
388
+ ? parseEthereumStealthMetaAddress(metaAddress)
389
+ : metaAddress
390
+
391
+ const schemeId = options.schemeId ?? SECP256K1_SCHEME_ID
392
+
393
+ // Encode the meta-address bytes
394
+ const metaAddressBytes = this.encodeMetaAddressBytes(parsed)
395
+
396
+ // Encode: registerKeys(uint256 schemeId, bytes stealthMetaAddress)
397
+ const schemeIdParam = schemeId.toString(16).padStart(64, '0')
398
+
399
+ // ABI encode bytes: offset + length + data
400
+ const offset = (64).toString(16).padStart(64, '0') // 0x40 = 64
401
+ const length = (66).toString(16).padStart(64, '0') // 66 bytes
402
+ const paddedBytes = metaAddressBytes.padEnd(128, '0') // Pad to 64 bytes (2 words)
403
+
404
+ const data = `${REGISTRY_SELECTORS.registerKeys}${schemeIdParam}${offset}${length}${paddedBytes}` as HexString
405
+
406
+ return {
407
+ to: this.registryAddress,
408
+ data,
409
+ value: 0n,
410
+ gasLimit: options.gasLimit ?? 150000n,
411
+ }
412
+ }
413
+
414
+ /**
415
+ * Build a transaction to update an existing registration
416
+ *
417
+ * (Same as register - the contract handles updates)
418
+ *
419
+ * @param metaAddress - New meta-address
420
+ * @param options - Registration options
421
+ * @returns Transaction to sign and submit
422
+ */
423
+ buildUpdateTransaction(
424
+ metaAddress: EthereumStealthMetaAddress | string,
425
+ options: RegistryRegisterOptions = {}
426
+ ): RegistryTransaction {
427
+ return this.buildRegisterTransaction(metaAddress, {
428
+ ...options,
429
+ gasLimit: options.gasLimit ?? 100000n, // Lower gas for updates
430
+ })
431
+ }
432
+
433
+ // ─── Nonce Methods ───────────────────────────────────────────────────────────
434
+
435
+ /**
436
+ * Build call data for getting the nonce of an address
437
+ *
438
+ * Used for signature-based registration on behalf of others.
439
+ *
440
+ * @param address - Address to get nonce for
441
+ * @returns Call data for eth_call
442
+ */
443
+ buildNonceCallData(address: HexString): { to: HexString; data: HexString } {
444
+ if (!isValidEthAddress(address)) {
445
+ throw new Error(`Invalid Ethereum address: ${address}`)
446
+ }
447
+
448
+ const addressParam = address.slice(2).padStart(64, '0')
449
+ const data = `${REGISTRY_SELECTORS.nonceOf}${addressParam}` as HexString
450
+
451
+ return {
452
+ to: this.registryAddress,
453
+ data,
454
+ }
455
+ }
456
+
457
+ /**
458
+ * Parse nonce response
459
+ *
460
+ * @param response - Raw response from eth_call
461
+ * @returns Nonce value
462
+ */
463
+ parseNonceResponse(response: HexString): bigint {
464
+ return BigInt(response)
465
+ }
466
+
467
+ // ─── Utility Methods ─────────────────────────────────────────────────────────
468
+
469
+ /**
470
+ * Get the registry contract address
471
+ */
472
+ getRegistryAddress(): HexString {
473
+ return this.registryAddress
474
+ }
475
+
476
+ /**
477
+ * Get the network
478
+ */
479
+ getNetwork(): EthereumNetwork {
480
+ return this.network
481
+ }
482
+
483
+ /**
484
+ * Check if caching is enabled
485
+ */
486
+ isCacheEnabled(): boolean {
487
+ return this.cacheEnabled
488
+ }
489
+
490
+ /**
491
+ * Enable or disable caching
492
+ */
493
+ setCacheEnabled(enabled: boolean): void {
494
+ this.cacheEnabled = enabled
495
+ if (!enabled) {
496
+ this.clearCache()
497
+ }
498
+ }
499
+
500
+ /**
501
+ * Get cache key for an address
502
+ */
503
+ private getCacheKey(address: HexString): string {
504
+ return `${this.network}:${address.toLowerCase()}`
505
+ }
506
+
507
+ /**
508
+ * Encode meta-address to bytes (spending + viewing keys)
509
+ */
510
+ private encodeMetaAddressBytes(metaAddress: EthereumStealthMetaAddress): string {
511
+ // Remove 0x prefixes and concatenate
512
+ const spending = metaAddress.spendingKey.slice(2)
513
+ const viewing = metaAddress.viewingKey.slice(2)
514
+ return `${spending}${viewing}`
515
+ }
516
+ }
517
+
518
+ // ─── Factory Functions ────────────────────────────────────────────────────────
519
+
520
+ /**
521
+ * Create a registry client for a specific network
522
+ *
523
+ * @param network - Target network
524
+ * @param options - Client options
525
+ * @returns Registry client
526
+ */
527
+ export function createRegistryClient(
528
+ network: EthereumNetwork = 'mainnet',
529
+ options?: {
530
+ registryAddress?: HexString
531
+ enableCache?: boolean
532
+ }
533
+ ): RegistryClient {
534
+ return new RegistryClient(network, options)
535
+ }
536
+
537
+ /**
538
+ * Create a mainnet registry client
539
+ */
540
+ export function createMainnetRegistryClient(): RegistryClient {
541
+ return new RegistryClient('mainnet')
542
+ }
543
+
544
+ /**
545
+ * Create a Sepolia testnet registry client
546
+ */
547
+ export function createSepoliaRegistryClient(): RegistryClient {
548
+ return new RegistryClient('sepolia')
549
+ }
550
+
551
+ // ─── Helper Functions ────────────────────────────────────────────────────────
552
+
553
+ /**
554
+ * Check if an address has a registered meta-address
555
+ *
556
+ * Helper that takes raw eth_call response.
557
+ *
558
+ * @param response - eth_call response
559
+ * @returns True if registered
560
+ */
561
+ export function isRegistered(response: HexString): boolean {
562
+ const data = response.slice(2)
563
+ if (!data || data === '0' || /^0+$/.test(data)) {
564
+ return false
565
+ }
566
+ // Check if length is non-zero
567
+ if (data.length >= 128) {
568
+ const lengthHex = data.slice(64, 128)
569
+ const length = parseInt(lengthHex, 16)
570
+ return length > 0
571
+ }
572
+ return false
573
+ }
574
+
575
+ /**
576
+ * Extract scheme ID from meta-address prefix
577
+ *
578
+ * @param _metaAddress - Meta-address bytes or encoded string (unused, for future expansion)
579
+ * @returns Scheme ID
580
+ */
581
+ export function extractSchemeId(_metaAddress: HexString | string): number {
582
+ // For now, we only support secp256k1
583
+ return SECP256K1_SCHEME_ID
584
+ }