@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
@@ -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
 
@@ -49,11 +49,19 @@ export interface SolanaPrivateTransferResult {
49
49
 
50
50
  /**
51
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.
52
55
  */
53
56
  export interface SolanaScanParams {
54
57
  /** Solana RPC connection */
55
58
  connection: Connection
56
- /** 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
+ */
57
65
  viewingPrivateKey: HexString
58
66
  /** Recipient's spending public key (hex) */
59
67
  spendingPublicKey: HexString
@@ -107,6 +115,10 @@ export interface SolanaScanResult {
107
115
 
108
116
  /**
109
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.
110
122
  */
111
123
  export interface SolanaClaimParams {
112
124
  /** Solana RPC connection */
@@ -115,9 +127,21 @@ export interface SolanaClaimParams {
115
127
  stealthAddress: string
116
128
  /** Ephemeral public key from the payment (base58) */
117
129
  ephemeralPublicKey: string
118
- /** 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
+ */
119
136
  viewingPrivateKey: HexString
120
- /** 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
+ */
121
145
  spendingPrivateKey: HexString
122
146
  /** Destination address to send claimed funds (base58) */
123
147
  destinationAddress: string
@@ -154,6 +178,8 @@ export interface SolanaAnnouncement {
154
178
  /**
155
179
  * Parse announcement from memo string
156
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)
157
183
  */
158
184
  export function parseAnnouncement(memo: string): SolanaAnnouncement | null {
159
185
  if (!memo.startsWith('SIP:1:')) {
@@ -165,10 +191,35 @@ export function parseAnnouncement(memo: string): SolanaAnnouncement | null {
165
191
  return null
166
192
  }
167
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
+
168
219
  return {
169
- ephemeralPublicKey: parts[0],
170
- viewTag: parts[1],
171
- stealthAddress: parts[2],
220
+ ephemeralPublicKey,
221
+ viewTag,
222
+ stealthAddress,
172
223
  }
173
224
  }
174
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
+ }