@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
@@ -30,15 +30,17 @@ import {
30
30
  getSolanaProvider,
31
31
  solanaPublicKeyToHex,
32
32
  } from './types'
33
+ import { SOLANA_RPC_ENDPOINTS as SOLANA_RPC_CONFIG } from '../../config/endpoints'
33
34
 
34
35
  /**
35
36
  * Default RPC endpoints for Solana clusters
37
+ * Localnet is configurable via SOLANA_LOCALNET_RPC environment variable
36
38
  */
37
39
  const DEFAULT_RPC_ENDPOINTS: Record<SolanaCluster, string> = {
38
- 'mainnet-beta': 'https://api.mainnet-beta.solana.com',
39
- 'testnet': 'https://api.testnet.solana.com',
40
- 'devnet': 'https://api.devnet.solana.com',
41
- 'localnet': 'http://localhost:8899',
40
+ 'mainnet-beta': SOLANA_RPC_CONFIG.mainnet,
41
+ 'testnet': SOLANA_RPC_CONFIG.testnet,
42
+ 'devnet': SOLANA_RPC_CONFIG.devnet,
43
+ 'localnet': SOLANA_RPC_CONFIG.localnet,
42
44
  }
43
45
 
44
46
  /**
@@ -17,6 +17,19 @@ export {
17
17
 
18
18
  export type { MockSolanaAdapterConfig } from './mock'
19
19
 
20
+ // Privacy-enabled adapter (Issue #304)
21
+ export {
22
+ PrivacySolanaWalletAdapter,
23
+ createPrivacySolanaAdapter,
24
+ } from './privacy-adapter'
25
+
26
+ export type {
27
+ PrivacySolanaAdapterConfig,
28
+ StealthKeyMaterial,
29
+ ScannedPayment,
30
+ ClaimResult,
31
+ } from './privacy-adapter'
32
+
20
33
  // Types
21
34
  export {
22
35
  getSolanaProvider,
@@ -0,0 +1,567 @@
1
+ /**
2
+ * Privacy-Extended Solana Wallet Adapter
3
+ *
4
+ * Extends SolanaWalletAdapter with stealth address capabilities for
5
+ * same-chain privacy operations.
6
+ *
7
+ * @module wallet/solana/privacy-adapter
8
+ */
9
+
10
+ import type {
11
+ HexString,
12
+ StealthMetaAddress,
13
+ StealthAddress,
14
+ } from '@sip-protocol/types'
15
+ import { sha256 } from '@noble/hashes/sha2'
16
+ import { ed25519 } from '@noble/curves/ed25519'
17
+ import { SolanaWalletAdapter } from './adapter'
18
+ import type { SolanaAdapterConfig } from './types'
19
+ import {
20
+ generateEd25519StealthMetaAddress,
21
+ generateEd25519StealthAddress,
22
+ deriveEd25519StealthPrivateKey,
23
+ checkEd25519StealthAddress,
24
+ ed25519PublicKeyToSolanaAddress,
25
+ } from '../../stealth'
26
+
27
+ // ─── Types ──────────────────────────────────────────────────────────────────
28
+
29
+ /**
30
+ * Configuration for privacy adapter
31
+ */
32
+ export interface PrivacySolanaAdapterConfig extends SolanaAdapterConfig {
33
+ /**
34
+ * Pre-existing stealth meta-address to use
35
+ * If not provided, one will be generated on first use
36
+ */
37
+ metaAddress?: StealthMetaAddress
38
+ /**
39
+ * Pre-existing spending private key
40
+ * Required if metaAddress is provided
41
+ */
42
+ spendingPrivateKey?: HexString
43
+ /**
44
+ * Pre-existing viewing private key
45
+ * Required if metaAddress is provided
46
+ */
47
+ viewingPrivateKey?: HexString
48
+ /**
49
+ * Derive stealth keys from wallet signature
50
+ * If true, keys are derived deterministically from wallet
51
+ * If false (default), random keys are generated
52
+ */
53
+ deriveFromWallet?: boolean
54
+ /**
55
+ * Domain separation string for key derivation
56
+ * Used when deriveFromWallet is true
57
+ */
58
+ derivationDomain?: string
59
+ }
60
+
61
+ /**
62
+ * Stealth key material
63
+ */
64
+ export interface StealthKeyMaterial {
65
+ metaAddress: StealthMetaAddress
66
+ spendingPrivateKey: HexString
67
+ viewingPrivateKey: HexString
68
+ }
69
+
70
+ /**
71
+ * Scanned stealth payment
72
+ */
73
+ export interface ScannedPayment {
74
+ /** Stealth address that received the payment */
75
+ stealthAddress: string
76
+ /** Ephemeral public key from sender */
77
+ ephemeralPublicKey: HexString
78
+ /** View tag for fast scanning */
79
+ viewTag: number
80
+ /** Whether this payment belongs to us */
81
+ isOwned: boolean
82
+ /** Solana address format of stealth address */
83
+ solanaAddress: string
84
+ }
85
+
86
+ /**
87
+ * Result of claiming a stealth payment
88
+ */
89
+ export interface ClaimResult {
90
+ /** Derived private key for spending */
91
+ privateKey: HexString
92
+ /** Public key (stealth address) */
93
+ publicKey: HexString
94
+ /** Solana address format */
95
+ solanaAddress: string
96
+ }
97
+
98
+ // ─── Privacy Adapter ────────────────────────────────────────────────────────
99
+
100
+ /**
101
+ * Privacy-enabled Solana wallet adapter
102
+ *
103
+ * Extends the base SolanaWalletAdapter with:
104
+ * - Stealth meta-address generation and management
105
+ * - Stealth address derivation for receiving
106
+ * - Private key derivation for spending
107
+ * - Payment scanning with view tags
108
+ *
109
+ * @example Generate stealth address for receiving
110
+ * ```typescript
111
+ * const wallet = new PrivacySolanaWalletAdapter({ wallet: 'phantom' })
112
+ * await wallet.connect()
113
+ * await wallet.initializePrivacy()
114
+ *
115
+ * // Share meta-address with senders
116
+ * const metaAddress = wallet.getMetaAddress()
117
+ * console.log('Send to:', metaAddress)
118
+ * ```
119
+ *
120
+ * @example Derive from wallet (deterministic)
121
+ * ```typescript
122
+ * const wallet = new PrivacySolanaWalletAdapter({
123
+ * wallet: 'phantom',
124
+ * deriveFromWallet: true,
125
+ * derivationDomain: 'my-app.com',
126
+ * })
127
+ * await wallet.connect()
128
+ * await wallet.initializePrivacy()
129
+ * // Keys derived deterministically from wallet signature
130
+ * ```
131
+ *
132
+ * @example Scan and claim payments
133
+ * ```typescript
134
+ * const payments = wallet.scanPayments([announcement1, announcement2])
135
+ * for (const payment of payments.filter(p => p.isOwned)) {
136
+ * const claim = wallet.deriveClaimKey(payment.ephemeralPublicKey, payment.viewTag)
137
+ * // Use claim.privateKey to sign transactions
138
+ * }
139
+ * ```
140
+ */
141
+ export class PrivacySolanaWalletAdapter extends SolanaWalletAdapter {
142
+ private stealthKeys: StealthKeyMaterial | undefined
143
+ private deriveFromWallet: boolean
144
+ private derivationDomain: string
145
+
146
+ constructor(config: PrivacySolanaAdapterConfig = {}) {
147
+ super(config)
148
+
149
+ this.deriveFromWallet = config.deriveFromWallet ?? false
150
+ this.derivationDomain = config.derivationDomain ?? 'sip-protocol.org'
151
+
152
+ // If pre-existing keys provided, validate and store
153
+ if (config.metaAddress) {
154
+ if (!config.spendingPrivateKey || !config.viewingPrivateKey) {
155
+ throw new Error('spendingPrivateKey and viewingPrivateKey required when metaAddress provided')
156
+ }
157
+ this.stealthKeys = {
158
+ metaAddress: config.metaAddress,
159
+ spendingPrivateKey: config.spendingPrivateKey,
160
+ viewingPrivateKey: config.viewingPrivateKey,
161
+ }
162
+ }
163
+ }
164
+
165
+ /**
166
+ * Initialize privacy features
167
+ *
168
+ * Generates or derives stealth keys. Must be called after connect().
169
+ * If deriveFromWallet is true, will prompt for a signature.
170
+ */
171
+ async initializePrivacy(): Promise<void> {
172
+ this.requireConnected()
173
+
174
+ if (this.stealthKeys) {
175
+ return // Already initialized
176
+ }
177
+
178
+ if (this.deriveFromWallet) {
179
+ await this.deriveStealthKeysFromWallet()
180
+ } else {
181
+ this.generateRandomStealthKeys()
182
+ }
183
+ }
184
+
185
+ /**
186
+ * Check if privacy is initialized
187
+ */
188
+ isPrivacyInitialized(): boolean {
189
+ return !!this.stealthKeys
190
+ }
191
+
192
+ /**
193
+ * Get the stealth meta-address
194
+ *
195
+ * Share this with senders to receive private payments.
196
+ *
197
+ * @throws If privacy not initialized
198
+ */
199
+ getMetaAddress(): StealthMetaAddress {
200
+ if (!this.stealthKeys) {
201
+ throw new Error('Privacy not initialized. Call initializePrivacy() first.')
202
+ }
203
+ return this.stealthKeys.metaAddress
204
+ }
205
+
206
+ /**
207
+ * Get the viewing private key
208
+ *
209
+ * Used for scanning incoming payments.
210
+ * Can be shared with auditors for compliance.
211
+ *
212
+ * @throws If privacy not initialized
213
+ */
214
+ getViewingPrivateKey(): HexString {
215
+ if (!this.stealthKeys) {
216
+ throw new Error('Privacy not initialized. Call initializePrivacy() first.')
217
+ }
218
+ return this.stealthKeys.viewingPrivateKey
219
+ }
220
+
221
+ /**
222
+ * Get the spending private key
223
+ *
224
+ * SENSITIVE: Required for deriving stealth private keys.
225
+ * Keep secure and never share.
226
+ *
227
+ * @throws If privacy not initialized
228
+ */
229
+ getSpendingPrivateKey(): HexString {
230
+ if (!this.stealthKeys) {
231
+ throw new Error('Privacy not initialized. Call initializePrivacy() first.')
232
+ }
233
+ return this.stealthKeys.spendingPrivateKey
234
+ }
235
+
236
+ /**
237
+ * Generate a one-time stealth address for a sender
238
+ *
239
+ * Typically used by the sender side. Recipients share their meta-address,
240
+ * and senders generate unique stealth addresses for each payment.
241
+ *
242
+ * @param recipientMetaAddress - Recipient's stealth meta-address
243
+ * @returns Stealth address details for the transaction
244
+ */
245
+ generateStealthAddressFor(recipientMetaAddress: StealthMetaAddress): {
246
+ stealthAddress: StealthAddress
247
+ solanaAddress: string
248
+ sharedSecret: HexString
249
+ } {
250
+ const { stealthAddress, sharedSecret } = generateEd25519StealthAddress(recipientMetaAddress)
251
+ const solanaAddress = ed25519PublicKeyToSolanaAddress(stealthAddress.address)
252
+
253
+ return {
254
+ stealthAddress,
255
+ solanaAddress,
256
+ sharedSecret,
257
+ }
258
+ }
259
+
260
+ /**
261
+ * Scan announcements to find payments belonging to us
262
+ *
263
+ * Uses the viewing key to check if stealth addresses belong to this wallet.
264
+ * First checks view tags for fast filtering, then verifies ownership.
265
+ *
266
+ * @param announcements - Array of stealth address announcements to scan
267
+ * @returns Array of payments with ownership status
268
+ */
269
+ scanPayments(announcements: StealthAddress[]): ScannedPayment[] {
270
+ if (!this.stealthKeys) {
271
+ throw new Error('Privacy not initialized. Call initializePrivacy() first.')
272
+ }
273
+
274
+ const results: ScannedPayment[] = []
275
+
276
+ for (const announcement of announcements) {
277
+ try {
278
+ const isOwned = checkEd25519StealthAddress(
279
+ announcement,
280
+ this.stealthKeys.metaAddress.spendingKey,
281
+ this.stealthKeys.viewingPrivateKey,
282
+ )
283
+
284
+ results.push({
285
+ stealthAddress: announcement.address,
286
+ ephemeralPublicKey: announcement.ephemeralPublicKey,
287
+ viewTag: announcement.viewTag,
288
+ isOwned,
289
+ solanaAddress: ed25519PublicKeyToSolanaAddress(announcement.address),
290
+ })
291
+ } catch {
292
+ // Invalid announcement, skip
293
+ results.push({
294
+ stealthAddress: announcement.address,
295
+ ephemeralPublicKey: announcement.ephemeralPublicKey,
296
+ viewTag: announcement.viewTag,
297
+ isOwned: false,
298
+ solanaAddress: '',
299
+ })
300
+ }
301
+ }
302
+
303
+ return results
304
+ }
305
+
306
+ /**
307
+ * Fast scan using view tags only
308
+ *
309
+ * Pre-filters announcements by view tag before full verification.
310
+ * Much faster for large announcement sets.
311
+ *
312
+ * @param announcements - Announcements with view tags
313
+ * @returns Potentially matching announcements
314
+ */
315
+ fastScanByViewTag(announcements: StealthAddress[]): StealthAddress[] {
316
+ if (!this.stealthKeys) {
317
+ throw new Error('Privacy not initialized. Call initializePrivacy() first.')
318
+ }
319
+
320
+ // Compute expected view tag from our viewing key
321
+ // View tags are derived from hash(viewing_key || ephemeral_key)[0]
322
+ const viewingKeyBytes = hexToBytes(this.stealthKeys.metaAddress.viewingKey.slice(2))
323
+
324
+ return announcements.filter(ann => {
325
+ try {
326
+ const ephemeralBytes = hexToBytes(ann.ephemeralPublicKey.slice(2))
327
+
328
+ // Compute expected view tag
329
+ const combined = new Uint8Array(viewingKeyBytes.length + ephemeralBytes.length)
330
+ combined.set(viewingKeyBytes)
331
+ combined.set(ephemeralBytes, viewingKeyBytes.length)
332
+
333
+ const hash = sha256(combined)
334
+ const expectedViewTag = hash[0]
335
+
336
+ return ann.viewTag === expectedViewTag
337
+ } catch {
338
+ return false
339
+ }
340
+ })
341
+ }
342
+
343
+ /**
344
+ * Derive the private key for spending from a stealth address
345
+ *
346
+ * @param ephemeralPublicKey - Ephemeral public key from the announcement
347
+ * @param viewTag - View tag from the announcement
348
+ * @returns Claim key material for spending
349
+ */
350
+ deriveClaimKey(
351
+ ephemeralPublicKey: HexString,
352
+ viewTag: number
353
+ ): ClaimResult {
354
+ if (!this.stealthKeys) {
355
+ throw new Error('Privacy not initialized. Call initializePrivacy() first.')
356
+ }
357
+
358
+ // Compute stealth address from ephemeral key
359
+ const ephemeralPubBytes = hexToBytes(ephemeralPublicKey.slice(2))
360
+
361
+ // Compute shared secret: S = spending_scalar * R
362
+ const spendingScalar = getEd25519ScalarFromPrivate(
363
+ hexToBytes(this.stealthKeys.spendingPrivateKey.slice(2))
364
+ )
365
+
366
+ const ephemeralPoint = ed25519.ExtendedPoint.fromHex(ephemeralPubBytes)
367
+ const sharedSecretPoint = ephemeralPoint.multiply(spendingScalar)
368
+ const sharedSecretHash = sha256(sharedSecretPoint.toRawBytes())
369
+
370
+ // Derive stealth public key: P_stealth = P_view + hash(S)*G
371
+ const hashScalar = bytesToBigInt(sharedSecretHash) % ED25519_ORDER
372
+ const hashTimesG = ed25519.ExtendedPoint.BASE.multiply(hashScalar)
373
+
374
+ const viewingPoint = ed25519.ExtendedPoint.fromHex(
375
+ hexToBytes(this.stealthKeys.metaAddress.viewingKey.slice(2))
376
+ )
377
+ const stealthPoint = viewingPoint.add(hashTimesG)
378
+ const stealthAddressHex = `0x${bytesToHex(stealthPoint.toRawBytes())}` as HexString
379
+
380
+ // Create StealthAddress for derivation
381
+ const stealthAddr: StealthAddress = {
382
+ address: stealthAddressHex,
383
+ ephemeralPublicKey,
384
+ viewTag,
385
+ }
386
+
387
+ // Derive the private key
388
+ const recovery = deriveEd25519StealthPrivateKey(
389
+ stealthAddr,
390
+ this.stealthKeys.spendingPrivateKey,
391
+ this.stealthKeys.viewingPrivateKey,
392
+ )
393
+
394
+ return {
395
+ privateKey: recovery.privateKey,
396
+ publicKey: stealthAddressHex,
397
+ solanaAddress: ed25519PublicKeyToSolanaAddress(stealthAddressHex),
398
+ }
399
+ }
400
+
401
+ /**
402
+ * Export stealth keys for backup
403
+ *
404
+ * Returns all key material needed to restore privacy functionality.
405
+ * SENSITIVE: Store securely and never expose.
406
+ */
407
+ exportStealthKeys(): StealthKeyMaterial | undefined {
408
+ return this.stealthKeys ? { ...this.stealthKeys } : undefined
409
+ }
410
+
411
+ /**
412
+ * Import stealth keys from backup
413
+ *
414
+ * @param keys - Previously exported stealth keys
415
+ */
416
+ importStealthKeys(keys: StealthKeyMaterial): void {
417
+ this.stealthKeys = { ...keys }
418
+ }
419
+
420
+ /**
421
+ * Generate random stealth keys
422
+ */
423
+ private generateRandomStealthKeys(): void {
424
+ const { metaAddress, spendingPrivateKey, viewingPrivateKey } =
425
+ generateEd25519StealthMetaAddress('solana')
426
+
427
+ this.stealthKeys = {
428
+ metaAddress,
429
+ spendingPrivateKey,
430
+ viewingPrivateKey,
431
+ }
432
+ }
433
+
434
+ /**
435
+ * Derive stealth keys deterministically from wallet signature
436
+ *
437
+ * Uses wallet signature over a domain-specific message to derive
438
+ * deterministic stealth keys. Same wallet + domain = same keys.
439
+ */
440
+ private async deriveStealthKeysFromWallet(): Promise<void> {
441
+ const message = `SIP Protocol Stealth Key Derivation\n` +
442
+ `Domain: ${this.derivationDomain}\n` +
443
+ `Address: ${this.address}\n` +
444
+ `Version: 1`
445
+
446
+ // Sign the derivation message
447
+ const messageBytes = new TextEncoder().encode(message)
448
+ const signature = await this.signMessage(messageBytes)
449
+
450
+ // Use signature as seed for key derivation
451
+ const signatureBytes = hexToBytes(signature.signature.slice(2))
452
+
453
+ // Derive spending key: hash(sig || "spending")
454
+ const spendingInput = new Uint8Array(signatureBytes.length + 8)
455
+ spendingInput.set(signatureBytes)
456
+ spendingInput.set(new TextEncoder().encode('spending'), signatureBytes.length)
457
+ const spendingPrivateKey = sha256(spendingInput)
458
+
459
+ // Derive viewing key: hash(sig || "viewing")
460
+ const viewingInput = new Uint8Array(signatureBytes.length + 7)
461
+ viewingInput.set(signatureBytes)
462
+ viewingInput.set(new TextEncoder().encode('viewing'), signatureBytes.length)
463
+ const viewingPrivateKey = sha256(viewingInput)
464
+
465
+ // Compute public keys
466
+ const spendingKey = ed25519.getPublicKey(spendingPrivateKey)
467
+ const viewingKey = ed25519.getPublicKey(viewingPrivateKey)
468
+
469
+ this.stealthKeys = {
470
+ metaAddress: {
471
+ chain: 'solana',
472
+ spendingKey: `0x${bytesToHex(spendingKey)}` as HexString,
473
+ viewingKey: `0x${bytesToHex(viewingKey)}` as HexString,
474
+ },
475
+ spendingPrivateKey: `0x${bytesToHex(spendingPrivateKey)}` as HexString,
476
+ viewingPrivateKey: `0x${bytesToHex(viewingPrivateKey)}` as HexString,
477
+ }
478
+ }
479
+ }
480
+
481
+ // ─── Utilities ──────────────────────────────────────────────────────────────
482
+
483
+ /** ed25519 curve order */
484
+ const ED25519_ORDER = BigInt('0x1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3ed')
485
+
486
+ /**
487
+ * Convert bytes to BigInt (little-endian)
488
+ */
489
+ function bytesToBigInt(bytes: Uint8Array): bigint {
490
+ let result = 0n
491
+ for (let i = bytes.length - 1; i >= 0; i--) {
492
+ result = (result << 8n) | BigInt(bytes[i])
493
+ }
494
+ return result
495
+ }
496
+
497
+ /**
498
+ * Convert hex string to bytes
499
+ */
500
+ function hexToBytes(hex: string): Uint8Array {
501
+ const bytes = new Uint8Array(hex.length / 2)
502
+ for (let i = 0; i < hex.length; i += 2) {
503
+ bytes[i / 2] = parseInt(hex.substring(i, i + 2), 16)
504
+ }
505
+ return bytes
506
+ }
507
+
508
+ /**
509
+ * Convert bytes to hex string
510
+ */
511
+ function bytesToHex(bytes: Uint8Array): string {
512
+ return Array.from(bytes)
513
+ .map(b => b.toString(16).padStart(2, '0'))
514
+ .join('')
515
+ }
516
+
517
+ /**
518
+ * Get ed25519 scalar from private key seed
519
+ *
520
+ * ed25519 derives the actual scalar by hashing the seed and taking
521
+ * the lower 32 bytes with specific bit manipulations.
522
+ */
523
+ function getEd25519ScalarFromPrivate(seed: Uint8Array): bigint {
524
+ // Hash the seed to get 64 bytes
525
+ const h = sha256(seed)
526
+
527
+ // Take lower 32 bytes and apply ed25519 clamping
528
+ const scalar = new Uint8Array(32)
529
+ for (let i = 0; i < 32; i++) {
530
+ scalar[i] = h[i]
531
+ }
532
+
533
+ // Clamp: clear low 3 bits, clear high bit, set second-high bit
534
+ scalar[0] &= 248
535
+ scalar[31] &= 127
536
+ scalar[31] |= 64
537
+
538
+ return bytesToBigInt(scalar)
539
+ }
540
+
541
+ // ─── Factory ────────────────────────────────────────────────────────────────
542
+
543
+ /**
544
+ * Create a privacy-enabled Solana wallet adapter
545
+ *
546
+ * @example Random keys
547
+ * ```typescript
548
+ * const wallet = createPrivacySolanaAdapter({ wallet: 'phantom' })
549
+ * await wallet.connect()
550
+ * await wallet.initializePrivacy()
551
+ * ```
552
+ *
553
+ * @example Deterministic keys from wallet
554
+ * ```typescript
555
+ * const wallet = createPrivacySolanaAdapter({
556
+ * wallet: 'phantom',
557
+ * deriveFromWallet: true,
558
+ * })
559
+ * await wallet.connect()
560
+ * await wallet.initializePrivacy() // Will prompt for signature
561
+ * ```
562
+ */
563
+ export function createPrivacySolanaAdapter(
564
+ config: PrivacySolanaAdapterConfig = {}
565
+ ): PrivacySolanaWalletAdapter {
566
+ return new PrivacySolanaWalletAdapter(config)
567
+ }
@@ -6,6 +6,7 @@
6
6
  */
7
7
 
8
8
  import type { HexString } from '@sip-protocol/types'
9
+ import { SUI_RPC_ENDPOINTS as SUI_RPC_CONFIG } from '../../config/endpoints'
9
10
 
10
11
  /**
11
12
  * Supported Sui wallet names
@@ -229,12 +230,13 @@ export function suiPublicKeyToHex(publicKey: string | Uint8Array): HexString {
229
230
 
230
231
  /**
231
232
  * Default RPC endpoints for Sui networks
233
+ * Localnet is configurable via SUI_LOCALNET_RPC environment variable
232
234
  */
233
235
  export const DEFAULT_SUI_RPC_ENDPOINTS: Record<string, string> = {
234
- mainnet: 'https://fullnode.mainnet.sui.io:443',
235
- testnet: 'https://fullnode.testnet.sui.io:443',
236
- devnet: 'https://fullnode.devnet.sui.io:443',
237
- localnet: 'http://localhost:9000',
236
+ mainnet: SUI_RPC_CONFIG.mainnet,
237
+ testnet: SUI_RPC_CONFIG.testnet,
238
+ devnet: SUI_RPC_CONFIG.devnet,
239
+ localnet: SUI_RPC_CONFIG.localnet,
238
240
  }
239
241
 
240
242
  /**
@@ -47,12 +47,18 @@ import {
47
47
  ZcashErrorCode,
48
48
  } from '@sip-protocol/types'
49
49
  import { NetworkError, ErrorCode } from '../errors'
50
+ import { warnOnce, deprecationMessage } from '../utils'
51
+ import { ZCASH_RPC_CONFIG } from '../config/endpoints'
50
52
 
51
53
  // ─── Default Configuration ─────────────────────────────────────────────────────
52
54
 
55
+ /**
56
+ * Default configuration for Zcash RPC client
57
+ * Host and port are configurable via ZCASH_RPC_HOST and ZCASH_RPC_PORT environment variables
58
+ */
53
59
  const DEFAULT_CONFIG: Required<Omit<ZcashConfig, 'username' | 'password'>> = {
54
- host: '127.0.0.1',
55
- port: 8232,
60
+ host: ZCASH_RPC_CONFIG.host,
61
+ port: ZCASH_RPC_CONFIG.port,
56
62
  testnet: false,
57
63
  timeout: 30000,
58
64
  retries: 3,
@@ -190,10 +196,11 @@ export class ZcashRPCClient {
190
196
  * @returns New shielded address
191
197
  */
192
198
  async generateShieldedAddress(type: 'sapling' | 'sprout' = 'sapling'): Promise<string> {
193
- console.warn(
194
- 'generateShieldedAddress() is deprecated and will be removed in v0.2.0. ' +
195
- 'Use createAccount() and getAddressForAccount() instead.'
196
- )
199
+ warnOnce('generateShieldedAddress', deprecationMessage(
200
+ 'generateShieldedAddress()',
201
+ 'createAccount() and getAddressForAccount()',
202
+ '2026-06-01'
203
+ ))
197
204
  return this.call<string>('z_getnewaddress', [type])
198
205
  }
199
206