@sip-protocol/sdk 0.7.2 → 0.7.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (262) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +267 -0
  3. package/dist/{TransportWebUSB-TQ7WZ4LE.mjs → TransportWebUSB-YQMAGJAJ.mjs} +12 -9
  4. package/dist/browser.d.mts +10 -4
  5. package/dist/browser.d.ts +10 -4
  6. package/dist/browser.js +48874 -18336
  7. package/dist/browser.mjs +674 -48
  8. package/dist/chunk-4GRJ5MAW.mjs +152 -0
  9. package/dist/chunk-5D7A3L3W.mjs +717 -0
  10. package/dist/chunk-64AYA5F5.mjs +7834 -0
  11. package/dist/chunk-GMDGB22A.mjs +379 -0
  12. package/dist/chunk-I534WKN7.mjs +328 -0
  13. package/dist/chunk-IBZVA5Y7.mjs +1003 -0
  14. package/dist/chunk-PRRZAWJE.mjs +223 -0
  15. package/dist/{chunk-UJCSKKID.mjs → chunk-XGB3TDIC.mjs} +13 -1
  16. package/dist/chunk-YWGJ77A2.mjs +33806 -0
  17. package/dist/{chunk-6WGN57S2.mjs → chunk-Z3K7W5S3.mjs} +48 -0
  18. package/dist/constants-LHAAUC2T.mjs +51 -0
  19. package/dist/dist-2OGQ7FED.mjs +3957 -0
  20. package/dist/dist-IFHPYLDX.mjs +254 -0
  21. package/dist/fulfillment_proof-ANHVPKTB.mjs +21 -0
  22. package/dist/funding_proof-ICFZ5LHY.mjs +21 -0
  23. package/dist/index-DXh2IGkz.d.ts +24681 -0
  24. package/dist/index-DeE1ZzA4.d.mts +24681 -0
  25. package/dist/index.d.mts +9 -3
  26. package/dist/index.d.ts +9 -3
  27. package/dist/index.js +48676 -17318
  28. package/dist/index.mjs +583 -19
  29. package/dist/interface-Bf7w1PLW.d.mts +679 -0
  30. package/dist/interface-Bf7w1PLW.d.ts +679 -0
  31. package/dist/{noir-DKfEzWy9.d.mts → noir-kzbLVTei.d.mts} +31 -21
  32. package/dist/{noir-DKfEzWy9.d.ts → noir-kzbLVTei.d.ts} +31 -21
  33. package/dist/proofs/halo2.d.mts +151 -0
  34. package/dist/proofs/halo2.d.ts +151 -0
  35. package/dist/proofs/halo2.js +350 -0
  36. package/dist/proofs/halo2.mjs +11 -0
  37. package/dist/proofs/kimchi.d.mts +160 -0
  38. package/dist/proofs/kimchi.d.ts +160 -0
  39. package/dist/proofs/kimchi.js +431 -0
  40. package/dist/proofs/kimchi.mjs +13 -0
  41. package/dist/proofs/noir.d.mts +1 -1
  42. package/dist/proofs/noir.d.ts +1 -1
  43. package/dist/proofs/noir.js +74 -18
  44. package/dist/proofs/noir.mjs +84 -24
  45. package/dist/solana-U3MEGU7W.mjs +280 -0
  46. package/dist/validity_proof-3POXLPNY.mjs +21 -0
  47. package/package.json +54 -21
  48. package/src/adapters/index.ts +41 -0
  49. package/src/adapters/jupiter.ts +571 -0
  50. package/src/adapters/near-intents.ts +135 -0
  51. package/src/advisor/advisor.ts +653 -0
  52. package/src/advisor/index.ts +54 -0
  53. package/src/advisor/tools.ts +303 -0
  54. package/src/advisor/types.ts +164 -0
  55. package/src/chains/ethereum/announcement.ts +536 -0
  56. package/src/chains/ethereum/bnb-optimizations.ts +474 -0
  57. package/src/chains/ethereum/commitment.ts +522 -0
  58. package/src/chains/ethereum/constants.ts +462 -0
  59. package/src/chains/ethereum/deployment.ts +596 -0
  60. package/src/chains/ethereum/gas-estimation.ts +538 -0
  61. package/src/chains/ethereum/index.ts +268 -0
  62. package/src/chains/ethereum/optimizations.ts +614 -0
  63. package/src/chains/ethereum/privacy-adapter.ts +855 -0
  64. package/src/chains/ethereum/registry.ts +584 -0
  65. package/src/chains/ethereum/rpc.ts +905 -0
  66. package/src/chains/ethereum/stealth.ts +491 -0
  67. package/src/chains/ethereum/token.ts +790 -0
  68. package/src/chains/ethereum/transfer.ts +637 -0
  69. package/src/chains/ethereum/types.ts +456 -0
  70. package/src/chains/ethereum/viewing-key.ts +455 -0
  71. package/src/chains/near/commitment.ts +608 -0
  72. package/src/chains/near/constants.ts +284 -0
  73. package/src/chains/near/function-call.ts +871 -0
  74. package/src/chains/near/history.ts +654 -0
  75. package/src/chains/near/implicit-account.ts +840 -0
  76. package/src/chains/near/index.ts +393 -0
  77. package/src/chains/near/native-transfer.ts +658 -0
  78. package/src/chains/near/nep141.ts +775 -0
  79. package/src/chains/near/privacy-adapter.ts +889 -0
  80. package/src/chains/near/resolver.ts +971 -0
  81. package/src/chains/near/rpc.ts +1016 -0
  82. package/src/chains/near/stealth.ts +419 -0
  83. package/src/chains/near/types.ts +317 -0
  84. package/src/chains/near/viewing-key.ts +876 -0
  85. package/src/chains/solana/anchor-transfer.ts +386 -0
  86. package/src/chains/solana/commitment.ts +577 -0
  87. package/src/chains/solana/constants.ts +126 -12
  88. package/src/chains/solana/ephemeral-keys.ts +543 -0
  89. package/src/chains/solana/index.ts +276 -1
  90. package/src/chains/solana/key-derivation.ts +418 -0
  91. package/src/chains/solana/kit-compat.ts +334 -0
  92. package/src/chains/solana/optimizations.ts +560 -0
  93. package/src/chains/solana/privacy-adapter.ts +605 -0
  94. package/src/chains/solana/providers/generic.ts +201 -0
  95. package/src/chains/solana/providers/helius-enhanced-types.ts +336 -0
  96. package/src/chains/solana/providers/helius-enhanced.ts +623 -0
  97. package/src/chains/solana/providers/helius.ts +402 -0
  98. package/src/chains/solana/providers/index.ts +85 -0
  99. package/src/chains/solana/providers/interface.ts +221 -0
  100. package/src/chains/solana/providers/quicknode.ts +409 -0
  101. package/src/chains/solana/providers/triton.ts +426 -0
  102. package/src/chains/solana/providers/webhook.ts +790 -0
  103. package/src/chains/solana/rpc-client.ts +1150 -0
  104. package/src/chains/solana/scan.ts +170 -73
  105. package/src/chains/solana/sol-transfer.ts +732 -0
  106. package/src/chains/solana/spl-transfer.ts +886 -0
  107. package/src/chains/solana/stealth-scanner.ts +703 -0
  108. package/src/chains/solana/sunspot-verifier.ts +453 -0
  109. package/src/chains/solana/transaction-builder.ts +755 -0
  110. package/src/chains/solana/transfer.ts +74 -5
  111. package/src/chains/solana/types.ts +77 -7
  112. package/src/chains/solana/utils.ts +110 -0
  113. package/src/chains/solana/viewing-key.ts +807 -0
  114. package/src/compliance/fireblocks.ts +921 -0
  115. package/src/compliance/index.ts +37 -0
  116. package/src/compliance/range-sas.ts +956 -0
  117. package/src/config/endpoints.ts +100 -0
  118. package/src/crypto.ts +11 -8
  119. package/src/errors.ts +82 -0
  120. package/src/evm/erc4337-relayer.ts +830 -0
  121. package/src/evm/index.ts +47 -0
  122. package/src/fees/calculator.ts +396 -0
  123. package/src/fees/index.ts +87 -0
  124. package/src/fees/near-contract.ts +429 -0
  125. package/src/fees/types.ts +268 -0
  126. package/src/index.ts +785 -1
  127. package/src/intent.ts +6 -3
  128. package/src/logger.ts +324 -0
  129. package/src/network/index.ts +80 -0
  130. package/src/network/proxy.ts +691 -0
  131. package/src/optimizations/index.ts +541 -0
  132. package/src/oracle/types.ts +1 -0
  133. package/src/privacy-backends/arcium-types.ts +727 -0
  134. package/src/privacy-backends/arcium.ts +719 -0
  135. package/src/privacy-backends/combined-privacy.ts +866 -0
  136. package/src/privacy-backends/cspl-token.ts +595 -0
  137. package/src/privacy-backends/cspl-types.ts +512 -0
  138. package/src/privacy-backends/cspl.ts +907 -0
  139. package/src/privacy-backends/health.ts +488 -0
  140. package/src/privacy-backends/inco-types.ts +323 -0
  141. package/src/privacy-backends/inco.ts +616 -0
  142. package/src/privacy-backends/index.ts +336 -0
  143. package/src/privacy-backends/interface.ts +906 -0
  144. package/src/privacy-backends/lru-cache.ts +343 -0
  145. package/src/privacy-backends/magicblock.ts +458 -0
  146. package/src/privacy-backends/mock.ts +258 -0
  147. package/src/privacy-backends/privacycash-types.ts +278 -0
  148. package/src/privacy-backends/privacycash.ts +456 -0
  149. package/src/privacy-backends/private-swap.ts +570 -0
  150. package/src/privacy-backends/rate-limiter.ts +683 -0
  151. package/src/privacy-backends/registry.ts +690 -0
  152. package/src/privacy-backends/router.ts +626 -0
  153. package/src/privacy-backends/shadowwire.ts +449 -0
  154. package/src/privacy-backends/sip-native.ts +256 -0
  155. package/src/privacy-logger.ts +191 -0
  156. package/src/production-safety.ts +373 -0
  157. package/src/proofs/aggregator.ts +1029 -0
  158. package/src/proofs/browser-composer.ts +1150 -0
  159. package/src/proofs/browser.ts +113 -25
  160. package/src/proofs/cache/index.ts +127 -0
  161. package/src/proofs/cache/interface.ts +545 -0
  162. package/src/proofs/cache/key-generator.ts +188 -0
  163. package/src/proofs/cache/lru-cache.ts +481 -0
  164. package/src/proofs/cache/multi-tier-cache.ts +575 -0
  165. package/src/proofs/cache/persistent-cache.ts +788 -0
  166. package/src/proofs/compliance-proof.ts +872 -0
  167. package/src/proofs/composer/base.ts +923 -0
  168. package/src/proofs/composer/index.ts +25 -0
  169. package/src/proofs/composer/interface.ts +518 -0
  170. package/src/proofs/composer/types.ts +383 -0
  171. package/src/proofs/converters/halo2.ts +452 -0
  172. package/src/proofs/converters/index.ts +208 -0
  173. package/src/proofs/converters/interface.ts +363 -0
  174. package/src/proofs/converters/kimchi.ts +462 -0
  175. package/src/proofs/converters/noir.ts +451 -0
  176. package/src/proofs/fallback.ts +888 -0
  177. package/src/proofs/halo2.ts +42 -0
  178. package/src/proofs/index.ts +471 -0
  179. package/src/proofs/interface.ts +13 -0
  180. package/src/proofs/kimchi.ts +42 -0
  181. package/src/proofs/lazy.ts +1004 -0
  182. package/src/proofs/mock.ts +25 -1
  183. package/src/proofs/noir.ts +111 -30
  184. package/src/proofs/orchestrator.ts +960 -0
  185. package/src/proofs/parallel/concurrency.ts +297 -0
  186. package/src/proofs/parallel/dependency-graph.ts +602 -0
  187. package/src/proofs/parallel/executor.ts +420 -0
  188. package/src/proofs/parallel/index.ts +131 -0
  189. package/src/proofs/parallel/interface.ts +685 -0
  190. package/src/proofs/parallel/worker-pool.ts +644 -0
  191. package/src/proofs/providers/halo2.ts +560 -0
  192. package/src/proofs/providers/index.ts +34 -0
  193. package/src/proofs/providers/kimchi.ts +641 -0
  194. package/src/proofs/validator.ts +881 -0
  195. package/src/proofs/verifier.ts +867 -0
  196. package/src/quantum/index.ts +112 -0
  197. package/src/quantum/winternitz-vault.ts +639 -0
  198. package/src/quantum/wots.ts +611 -0
  199. package/src/settlement/backends/direct-chain.ts +1 -0
  200. package/src/settlement/index.ts +9 -0
  201. package/src/settlement/router.ts +732 -46
  202. package/src/solana/index.ts +72 -0
  203. package/src/solana/jito-relayer.ts +687 -0
  204. package/src/solana/noir-verifier-types.ts +430 -0
  205. package/src/solana/noir-verifier.ts +816 -0
  206. package/src/stealth/address-derivation.ts +193 -0
  207. package/src/stealth/ed25519.ts +431 -0
  208. package/src/stealth/index.ts +233 -0
  209. package/src/stealth/meta-address.ts +221 -0
  210. package/src/stealth/secp256k1.ts +368 -0
  211. package/src/stealth/utils.ts +194 -0
  212. package/src/stealth.ts +50 -1504
  213. package/src/surveillance/algorithms/address-reuse.ts +143 -0
  214. package/src/surveillance/algorithms/cluster.ts +247 -0
  215. package/src/surveillance/algorithms/exchange.ts +295 -0
  216. package/src/surveillance/algorithms/temporal.ts +337 -0
  217. package/src/surveillance/analyzer.ts +442 -0
  218. package/src/surveillance/index.ts +64 -0
  219. package/src/surveillance/scoring.ts +372 -0
  220. package/src/surveillance/types.ts +264 -0
  221. package/src/sync/index.ts +106 -0
  222. package/src/sync/manager.ts +504 -0
  223. package/src/sync/mock-provider.ts +318 -0
  224. package/src/sync/oblivious.ts +625 -0
  225. package/src/tokens/index.ts +15 -0
  226. package/src/tokens/registry.ts +301 -0
  227. package/src/utils/deprecation.ts +94 -0
  228. package/src/utils/index.ts +9 -0
  229. package/src/wallet/ethereum/index.ts +68 -0
  230. package/src/wallet/ethereum/metamask-privacy.ts +420 -0
  231. package/src/wallet/ethereum/multi-wallet.ts +646 -0
  232. package/src/wallet/ethereum/privacy-adapter.ts +700 -0
  233. package/src/wallet/ethereum/types.ts +3 -1
  234. package/src/wallet/ethereum/walletconnect-adapter.ts +675 -0
  235. package/src/wallet/hardware/index.ts +10 -0
  236. package/src/wallet/hardware/ledger-privacy.ts +414 -0
  237. package/src/wallet/index.ts +71 -0
  238. package/src/wallet/near/adapter.ts +626 -0
  239. package/src/wallet/near/index.ts +86 -0
  240. package/src/wallet/near/meteor-wallet.ts +1153 -0
  241. package/src/wallet/near/my-near-wallet.ts +790 -0
  242. package/src/wallet/near/wallet-selector.ts +702 -0
  243. package/src/wallet/solana/adapter.ts +6 -4
  244. package/src/wallet/solana/index.ts +13 -0
  245. package/src/wallet/solana/privacy-adapter.ts +567 -0
  246. package/src/wallet/sui/types.ts +6 -4
  247. package/src/zcash/rpc-client.ts +13 -6
  248. package/dist/chunk-3INS3PR5.mjs +0 -884
  249. package/dist/chunk-3OVABDRH.mjs +0 -17096
  250. package/dist/chunk-DLDWZFYC.mjs +0 -1495
  251. package/dist/chunk-E6SZWREQ.mjs +0 -57
  252. package/dist/chunk-G33LB27A.mjs +0 -16166
  253. package/dist/chunk-HGU6HZRC.mjs +0 -231
  254. package/dist/chunk-L2K34JCU.mjs +0 -1496
  255. package/dist/chunk-SN4ZDTVW.mjs +0 -16166
  256. package/dist/constants-VOI7BSLK.mjs +0 -27
  257. package/dist/index-BYZbDjal.d.ts +0 -11390
  258. package/dist/index-CHB3KuOB.d.mts +0 -11859
  259. package/dist/index-CzWPI6Le.d.ts +0 -11859
  260. package/dist/index-xbWjohNq.d.mts +0 -11390
  261. package/dist/solana-5EMCTPTS.mjs +0 -46
  262. package/dist/solana-Q4NAVBTS.mjs +0 -46
@@ -9,9 +9,8 @@ import {
9
9
  PublicKey,
10
10
  Transaction,
11
11
  TransactionInstruction,
12
- SystemProgram,
13
- LAMPORTS_PER_SOL,
14
12
  } from '@solana/web3.js'
13
+ import { ValidationError } from '../../errors'
15
14
  import {
16
15
  getAssociatedTokenAddress,
17
16
  createAssociatedTokenAccountInstruction,
@@ -75,6 +74,11 @@ import { bytesToHex } from '@noble/hashes/utils'
75
74
  export async function sendPrivateSPLTransfer(
76
75
  params: SolanaPrivateTransferParams
77
76
  ): Promise<SolanaPrivateTransferResult> {
77
+ // H-6 FIX: Comprehensive input validation
78
+ if (!params) {
79
+ throw new ValidationError('params is required', 'params')
80
+ }
81
+
78
82
  const {
79
83
  connection,
80
84
  sender,
@@ -85,10 +89,75 @@ export async function sendPrivateSPLTransfer(
85
89
  signTransaction,
86
90
  } = params
87
91
 
88
- // Validate recipient meta-address is for Solana
92
+ // Validate connection
93
+ if (!connection) {
94
+ throw new ValidationError('connection is required', 'connection')
95
+ }
96
+
97
+ // Validate sender
98
+ if (!sender) {
99
+ throw new ValidationError('sender is required', 'sender')
100
+ }
101
+
102
+ // Validate senderTokenAccount
103
+ if (!senderTokenAccount) {
104
+ throw new ValidationError('senderTokenAccount is required', 'senderTokenAccount')
105
+ }
106
+
107
+ // Validate mint
108
+ if (!mint) {
109
+ throw new ValidationError('mint is required', 'mint')
110
+ }
111
+
112
+ // Validate signTransaction callback
113
+ if (typeof signTransaction !== 'function') {
114
+ throw new ValidationError('signTransaction must be a function', 'signTransaction')
115
+ }
116
+
117
+ // Validate amount
118
+ if (amount === undefined || amount === null) {
119
+ throw new ValidationError('amount is required', 'amount')
120
+ }
121
+ if (typeof amount !== 'bigint') {
122
+ throw new ValidationError('amount must be a bigint', 'amount')
123
+ }
124
+ if (amount <= 0n) {
125
+ throw new ValidationError('amount must be greater than 0', 'amount')
126
+ }
127
+ // Prevent unreasonably large amounts (> 2^64, which is the max for SPL tokens)
128
+ const MAX_SPL_AMOUNT = 2n ** 64n - 1n
129
+ if (amount > MAX_SPL_AMOUNT) {
130
+ throw new ValidationError(`amount exceeds maximum SPL token amount`, 'amount')
131
+ }
132
+
133
+ // Validate recipient meta-address
134
+ if (!recipientMetaAddress) {
135
+ throw new ValidationError('recipientMetaAddress is required', 'recipientMetaAddress')
136
+ }
89
137
  if (recipientMetaAddress.chain !== 'solana') {
90
- throw new Error(
91
- `Invalid chain: expected 'solana', got '${recipientMetaAddress.chain}'`
138
+ throw new ValidationError(
139
+ `Invalid chain: expected 'solana', got '${recipientMetaAddress.chain}'`,
140
+ 'recipientMetaAddress.chain'
141
+ )
142
+ }
143
+ // Validate meta-address keys are present
144
+ if (!recipientMetaAddress.spendingKey) {
145
+ throw new ValidationError('recipientMetaAddress.spendingKey is required', 'recipientMetaAddress.spendingKey')
146
+ }
147
+ if (!recipientMetaAddress.viewingKey) {
148
+ throw new ValidationError('recipientMetaAddress.viewingKey is required', 'recipientMetaAddress.viewingKey')
149
+ }
150
+ // Validate key format (should be hex strings starting with 0x)
151
+ if (!recipientMetaAddress.spendingKey.startsWith('0x') || recipientMetaAddress.spendingKey.length !== 66) {
152
+ throw new ValidationError(
153
+ 'recipientMetaAddress.spendingKey must be a 32-byte hex string (0x + 64 chars)',
154
+ 'recipientMetaAddress.spendingKey'
155
+ )
156
+ }
157
+ if (!recipientMetaAddress.viewingKey.startsWith('0x') || recipientMetaAddress.viewingKey.length !== 66) {
158
+ throw new ValidationError(
159
+ 'recipientMetaAddress.viewingKey must be a 32-byte hex string (0x + 64 chars)',
160
+ 'recipientMetaAddress.viewingKey'
92
161
  )
93
162
  }
94
163
 
@@ -5,8 +5,9 @@
5
5
  */
6
6
 
7
7
  import type { PublicKey, Connection, Transaction, VersionedTransaction } from '@solana/web3.js'
8
- import type { StealthMetaAddress, StealthAddress, HexString } from '@sip-protocol/types'
8
+ import type { StealthMetaAddress, HexString } from '@sip-protocol/types'
9
9
  import type { SolanaCluster } from './constants'
10
+ import type { SolanaRPCProvider } from './providers/interface'
10
11
 
11
12
  /**
12
13
  * Parameters for sending a private SPL token transfer
@@ -48,11 +49,19 @@ export interface SolanaPrivateTransferResult {
48
49
 
49
50
  /**
50
51
  * Parameters for scanning for incoming stealth payments
52
+ *
53
+ * @security This interface requires sensitive cryptographic keys.
54
+ * Never log, store in plain text, or transmit these keys insecurely.
51
55
  */
52
56
  export interface SolanaScanParams {
53
57
  /** Solana RPC connection */
54
58
  connection: Connection
55
- /** Recipient's viewing private key (hex) */
59
+ /**
60
+ * Recipient's viewing private key (hex)
61
+ *
62
+ * @security SENSITIVE - This key enables scanning for incoming payments.
63
+ * Store securely (encrypted). Never log or expose in error messages.
64
+ */
56
65
  viewingPrivateKey: HexString
57
66
  /** Recipient's spending public key (hex) */
58
67
  spendingPublicKey: HexString
@@ -62,6 +71,24 @@ export interface SolanaScanParams {
62
71
  toSlot?: number
63
72
  /** Optional: Limit number of results */
64
73
  limit?: number
74
+ /**
75
+ * Optional: RPC provider for efficient asset queries
76
+ *
77
+ * When provided, uses provider.getAssetsByOwner() for token detection
78
+ * instead of parsing transaction logs. Recommended for production.
79
+ *
80
+ * @example
81
+ * ```typescript
82
+ * const helius = createProvider('helius', { apiKey: '...' })
83
+ * const payments = await scanForPayments({
84
+ * connection,
85
+ * provider: helius,
86
+ * viewingPrivateKey,
87
+ * spendingPublicKey,
88
+ * })
89
+ * ```
90
+ */
91
+ provider?: SolanaRPCProvider
65
92
  }
66
93
 
67
94
  /**
@@ -88,6 +115,10 @@ export interface SolanaScanResult {
88
115
 
89
116
  /**
90
117
  * Parameters for claiming a stealth payment
118
+ *
119
+ * @security This interface requires highly sensitive cryptographic keys.
120
+ * The spending private key can authorize fund transfers.
121
+ * Never log, store in plain text, or transmit these keys insecurely.
91
122
  */
92
123
  export interface SolanaClaimParams {
93
124
  /** Solana RPC connection */
@@ -96,9 +127,21 @@ export interface SolanaClaimParams {
96
127
  stealthAddress: string
97
128
  /** Ephemeral public key from the payment (base58) */
98
129
  ephemeralPublicKey: string
99
- /** Recipient's viewing private key (hex) */
130
+ /**
131
+ * Recipient's viewing private key (hex)
132
+ *
133
+ * @security SENSITIVE - Required for stealth key derivation.
134
+ * Store securely (encrypted). Never log or expose in error messages.
135
+ */
100
136
  viewingPrivateKey: HexString
101
- /** Recipient's spending private key (hex) */
137
+ /**
138
+ * Recipient's spending private key (hex)
139
+ *
140
+ * @security CRITICAL - This key can authorize fund transfers.
141
+ * Store with maximum security (hardware wallet, secure enclave, or encrypted storage).
142
+ * Never log, expose in errors, or transmit over network.
143
+ * Clear from memory after use when possible.
144
+ */
102
145
  spendingPrivateKey: HexString
103
146
  /** Destination address to send claimed funds (base58) */
104
147
  destinationAddress: string
@@ -135,6 +178,8 @@ export interface SolanaAnnouncement {
135
178
  /**
136
179
  * Parse announcement from memo string
137
180
  * Format: SIP:1:<ephemeral_pubkey_base58>:<view_tag_hex>
181
+ *
182
+ * M4 FIX: Validates view tag is exactly 1-2 hex characters (1 byte)
138
183
  */
139
184
  export function parseAnnouncement(memo: string): SolanaAnnouncement | null {
140
185
  if (!memo.startsWith('SIP:1:')) {
@@ -146,10 +191,35 @@ export function parseAnnouncement(memo: string): SolanaAnnouncement | null {
146
191
  return null
147
192
  }
148
193
 
194
+ const ephemeralPublicKey = parts[0]
195
+ const viewTag = parts[1]
196
+ const stealthAddress = parts[2]
197
+
198
+ // M4 FIX: Validate ephemeral public key (base58, 32-44 chars for Solana)
199
+ if (!ephemeralPublicKey || ephemeralPublicKey.length < 32 || ephemeralPublicKey.length > 44) {
200
+ return null
201
+ }
202
+
203
+ // M4 FIX: Validate view tag is 1-2 hex characters (represents 1 byte: 0-255)
204
+ if (!viewTag || viewTag.length > 2 || !/^[0-9a-fA-F]+$/.test(viewTag)) {
205
+ return null
206
+ }
207
+
208
+ // M4 FIX: Validate view tag numeric range (0-255)
209
+ const viewTagNum = parseInt(viewTag, 16)
210
+ if (viewTagNum < 0 || viewTagNum > 255) {
211
+ return null
212
+ }
213
+
214
+ // M4 FIX: Validate stealth address if provided
215
+ if (stealthAddress && (stealthAddress.length < 32 || stealthAddress.length > 44)) {
216
+ return null
217
+ }
218
+
149
219
  return {
150
- ephemeralPublicKey: parts[0],
151
- viewTag: parts[1],
152
- stealthAddress: parts[2],
220
+ ephemeralPublicKey,
221
+ viewTag,
222
+ stealthAddress,
153
223
  }
154
224
  }
155
225
 
@@ -0,0 +1,110 @@
1
+ /**
2
+ * Solana Shared Utilities
3
+ *
4
+ * Common utility functions used across scan.ts and webhook.ts.
5
+ * Extracted to reduce code duplication (L3 audit fix).
6
+ */
7
+
8
+ import { SOLANA_TOKEN_MINTS } from './constants'
9
+
10
+ /**
11
+ * Token balance entry from Solana transaction metadata
12
+ *
13
+ * Common interface for pre/post token balances used in both
14
+ * standard RPC and webhook transaction parsing.
15
+ */
16
+ export interface TokenBalanceEntry {
17
+ accountIndex: number
18
+ mint: string
19
+ uiTokenAmount: {
20
+ amount: string
21
+ decimals: number
22
+ }
23
+ }
24
+
25
+ /**
26
+ * Result of parsing a token transfer from transaction balances
27
+ */
28
+ export interface TokenTransferInfo {
29
+ /** Token mint address (base58) */
30
+ mint: string
31
+ /** Transfer amount in smallest unit */
32
+ amount: bigint
33
+ }
34
+
35
+ /**
36
+ * Get token symbol from mint address
37
+ *
38
+ * Looks up the token symbol for a known mint address in our registry.
39
+ * Returns undefined for unknown tokens.
40
+ *
41
+ * @param mint - SPL token mint address (base58)
42
+ * @returns Token symbol (e.g., 'USDC') or undefined if not found
43
+ *
44
+ * @example
45
+ * ```typescript
46
+ * getTokenSymbol('EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v')
47
+ * // => 'USDC'
48
+ *
49
+ * getTokenSymbol('unknown-mint-address')
50
+ * // => undefined
51
+ * ```
52
+ */
53
+ export function getTokenSymbol(mint: string): string | undefined {
54
+ for (const [symbol, address] of Object.entries(SOLANA_TOKEN_MINTS)) {
55
+ if (address === mint) {
56
+ return symbol
57
+ }
58
+ }
59
+ return undefined
60
+ }
61
+
62
+ /**
63
+ * Parse token transfer info from pre/post balance changes
64
+ *
65
+ * Analyzes pre and post token balances to determine the transferred
66
+ * token and amount. Finds the first account with an increased balance.
67
+ *
68
+ * @param preBalances - Pre-transaction token balances
69
+ * @param postBalances - Post-transaction token balances
70
+ * @returns Token mint and amount transferred, or null if no transfer found
71
+ *
72
+ * @example
73
+ * ```typescript
74
+ * const transfer = parseTokenTransferFromBalances(
75
+ * tx.meta.preTokenBalances,
76
+ * tx.meta.postTokenBalances
77
+ * )
78
+ *
79
+ * if (transfer) {
80
+ * console.log(`Received ${transfer.amount} of ${transfer.mint}`)
81
+ * }
82
+ * ```
83
+ */
84
+ export function parseTokenTransferFromBalances(
85
+ preBalances: TokenBalanceEntry[] | undefined | null,
86
+ postBalances: TokenBalanceEntry[] | undefined | null
87
+ ): TokenTransferInfo | null {
88
+ if (!postBalances || !preBalances) {
89
+ return null
90
+ }
91
+
92
+ // Find token balance changes (account with increased balance)
93
+ for (const post of postBalances) {
94
+ const pre = preBalances.find(
95
+ (p) => p.accountIndex === post.accountIndex
96
+ )
97
+
98
+ const postAmount = BigInt(post.uiTokenAmount.amount)
99
+ const preAmount = pre ? BigInt(pre.uiTokenAmount.amount) : 0n
100
+
101
+ if (postAmount > preAmount) {
102
+ return {
103
+ mint: post.mint,
104
+ amount: postAmount - preAmount,
105
+ }
106
+ }
107
+ }
108
+
109
+ return null
110
+ }