@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,386 @@
1
+ /**
2
+ * Solana Anchor-based Shielded Transfer
3
+ *
4
+ * Uses the SIP Privacy Anchor program for on-chain privacy with:
5
+ * - Pedersen commitments for hidden amounts
6
+ * - Stealth addresses for hidden recipients
7
+ * - Viewing keys for compliance
8
+ */
9
+
10
+ import {
11
+ PublicKey,
12
+ Transaction,
13
+ TransactionInstruction,
14
+ SystemProgram,
15
+ Connection,
16
+ } from '@solana/web3.js'
17
+ import { sha256 } from '@noble/hashes/sha2'
18
+ import { bytesToHex, hexToBytes } from '@noble/hashes/utils'
19
+ import { ValidationError } from '../../errors'
20
+ import { commit } from '../../commitment'
21
+ import {
22
+ generateEd25519StealthAddress,
23
+ ed25519PublicKeyToSolanaAddress,
24
+ decodeStealthMetaAddress,
25
+ } from '../../stealth'
26
+ import type { StealthMetaAddress, HexString, StealthAddress } from '@sip-protocol/types'
27
+
28
+ // Program ID - deployed on devnet
29
+ export const SIP_PRIVACY_PROGRAM_ID = new PublicKey(
30
+ 'S1PMFspo4W6BYKHWkHNF7kZ3fnqibEXg3LQjxepS9at'
31
+ )
32
+
33
+ // Config PDA - initialized on devnet
34
+ export const CONFIG_PDA = new PublicKey(
35
+ 'BVawZkppFewygA5nxdrLma4ThKx8Th7bW4KTCkcWTZwZ'
36
+ )
37
+
38
+ // Treasury/fee collector (using authority for now)
39
+ export const FEE_COLLECTOR = new PublicKey(
40
+ 'S1P6j1yeTm6zkewQVeihrTZvmfoHABRkHDhabWTuWMd'
41
+ )
42
+
43
+ // Seeds
44
+ const TRANSFER_RECORD_SEED = Buffer.from('transfer_record')
45
+
46
+ // Instruction discriminators (first 8 bytes of sha256("global:<instruction_name>"))
47
+ const SHIELDED_TRANSFER_DISCRIMINATOR = Buffer.from([
48
+ 0x9d, 0x2a, 0x42, 0x93, 0xee, 0x75, 0x61, 0x5c
49
+ ])
50
+
51
+ export interface AnchorShieldedTransferParams {
52
+ /** Solana connection */
53
+ connection: Connection
54
+ /** Sender's public key */
55
+ sender: PublicKey
56
+ /** Recipient's SIP address (sip:solana:spending:viewing) or StealthMetaAddress */
57
+ recipient: string | StealthMetaAddress
58
+ /** Amount in lamports */
59
+ amount: bigint
60
+ /** Transaction signer */
61
+ signTransaction: <T extends Transaction>(tx: T) => Promise<T>
62
+ }
63
+
64
+ export interface AnchorShieldedTransferResult {
65
+ /** Transaction signature */
66
+ signature: string
67
+ /** Transfer record PDA (noteId) */
68
+ noteId: string
69
+ /** Stealth address funds were sent to */
70
+ stealthAddress: string
71
+ /** Ephemeral public key for recipient scanning */
72
+ ephemeralPublicKey: HexString
73
+ /** Amount commitment */
74
+ commitment: HexString
75
+ /** View tag for quick filtering */
76
+ viewTag: string
77
+ /** Viewing key hash for compliance */
78
+ viewingKeyHash: HexString
79
+ /** Explorer URL */
80
+ explorerUrl: string
81
+ }
82
+
83
+ /**
84
+ * Execute a shielded SOL transfer using the Anchor program
85
+ *
86
+ * @example
87
+ * ```typescript
88
+ * const result = await shieldedTransfer({
89
+ * connection,
90
+ * sender: wallet.publicKey,
91
+ * recipient: 'sip:solana:0x02abc...:0x03def...',
92
+ * amount: 1_000_000_000n, // 1 SOL
93
+ * signTransaction: wallet.signTransaction,
94
+ * })
95
+ *
96
+ * console.log('Tx:', result.signature)
97
+ * console.log('Note ID:', result.noteId)
98
+ * ```
99
+ */
100
+ export async function shieldedTransfer(
101
+ params: AnchorShieldedTransferParams
102
+ ): Promise<AnchorShieldedTransferResult> {
103
+ const { connection, sender, recipient, amount, signTransaction } = params
104
+
105
+ // Validate inputs
106
+ if (!connection) {
107
+ throw new ValidationError('connection is required', 'connection')
108
+ }
109
+ if (!sender) {
110
+ throw new ValidationError('sender is required', 'sender')
111
+ }
112
+ if (!recipient) {
113
+ throw new ValidationError('recipient is required', 'recipient')
114
+ }
115
+ if (amount <= 0n) {
116
+ throw new ValidationError('amount must be positive', 'amount')
117
+ }
118
+
119
+ // Parse recipient address
120
+ const recipientMeta: StealthMetaAddress = typeof recipient === 'string'
121
+ ? decodeStealthMetaAddress(recipient)
122
+ : recipient
123
+
124
+ if (recipientMeta.chain !== 'solana') {
125
+ throw new ValidationError(
126
+ `Expected solana chain, got ${recipientMeta.chain}`,
127
+ 'recipient'
128
+ )
129
+ }
130
+
131
+ // 1. Generate stealth address
132
+ const stealthResult = generateEd25519StealthAddress(recipientMeta)
133
+ const stealthAddr: StealthAddress = stealthResult.stealthAddress
134
+ const stealthPubkey = ed25519PublicKeyToSolanaAddress(stealthAddr.address)
135
+ const stealthAccountPubkey = new PublicKey(stealthPubkey)
136
+
137
+ // 2. Generate Pedersen commitment
138
+ const { commitment, blinding } = commit(amount)
139
+ const commitmentBytes = hexToBytes(commitment.slice(2))
140
+
141
+ // Ensure commitment is 33 bytes (compressed point)
142
+ if (commitmentBytes.length !== 33) {
143
+ throw new ValidationError(
144
+ `Invalid commitment size: ${commitmentBytes.length}, expected 33`,
145
+ 'commitment'
146
+ )
147
+ }
148
+
149
+ // 3. Prepare ephemeral public key (33 bytes compressed)
150
+ const ephemeralPubkeyHex = stealthAddr.ephemeralPublicKey
151
+ const ephemeralPubkeyBytes = hexToBytes(ephemeralPubkeyHex.slice(2))
152
+
153
+ // Pad or truncate to 33 bytes if needed
154
+ const ephemeralPubkey33 = new Uint8Array(33)
155
+ ephemeralPubkey33[0] = 0x02 // compressed prefix
156
+ ephemeralPubkey33.set(ephemeralPubkeyBytes.slice(0, 32), 1)
157
+
158
+ // 4. Compute viewing key hash
159
+ const viewingKeyBytes = hexToBytes(recipientMeta.viewingKey.slice(2))
160
+ const viewingKeyHash = sha256(viewingKeyBytes)
161
+
162
+ // 5. Encrypt amount with viewing key
163
+ const encryptedAmount = encryptAmount(amount, recipientMeta.viewingKey)
164
+ const encryptedAmountBytes = hexToBytes(encryptedAmount.slice(2))
165
+
166
+ // 6. Create mock proof (real ZK proof integration in future)
167
+ const mockProof = createMockProof(commitment, amount, blinding)
168
+
169
+ // 7. Get current transfer count to derive PDA
170
+ const configAccount = await connection.getAccountInfo(CONFIG_PDA)
171
+ if (!configAccount) {
172
+ throw new ValidationError('SIP Privacy program not initialized', 'config')
173
+ }
174
+
175
+ // Parse total_transfers from config (offset: 8 + 32 + 2 + 1 = 43, size: 8)
176
+ const totalTransfers = configAccount.data.readBigUInt64LE(43)
177
+
178
+ // 8. Derive transfer record PDA
179
+ const [transferRecordPda] = PublicKey.findProgramAddressSync(
180
+ [
181
+ TRANSFER_RECORD_SEED,
182
+ sender.toBuffer(),
183
+ Buffer.from(bigintToLeBytes(totalTransfers)),
184
+ ],
185
+ SIP_PRIVACY_PROGRAM_ID
186
+ )
187
+
188
+ // 9. Build instruction data
189
+ const instructionData = buildShieldedTransferData({
190
+ commitment: commitmentBytes,
191
+ stealthPubkey: stealthAccountPubkey,
192
+ ephemeralPubkey: ephemeralPubkey33,
193
+ viewingKeyHash,
194
+ encryptedAmount: encryptedAmountBytes,
195
+ proof: mockProof,
196
+ actualAmount: amount,
197
+ })
198
+
199
+ // 10. Create instruction
200
+ const instruction = new TransactionInstruction({
201
+ keys: [
202
+ { pubkey: CONFIG_PDA, isSigner: false, isWritable: true },
203
+ { pubkey: transferRecordPda, isSigner: false, isWritable: true },
204
+ { pubkey: sender, isSigner: true, isWritable: true },
205
+ { pubkey: stealthAccountPubkey, isSigner: false, isWritable: true },
206
+ { pubkey: FEE_COLLECTOR, isSigner: false, isWritable: true },
207
+ { pubkey: SystemProgram.programId, isSigner: false, isWritable: false },
208
+ ],
209
+ programId: SIP_PRIVACY_PROGRAM_ID,
210
+ data: instructionData,
211
+ })
212
+
213
+ // 11. Build transaction
214
+ const transaction = new Transaction()
215
+ transaction.add(instruction)
216
+
217
+ const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash()
218
+ transaction.recentBlockhash = blockhash
219
+ transaction.feePayer = sender
220
+
221
+ // 12. Sign and send
222
+ const signedTx = await signTransaction(transaction)
223
+ const signature = await connection.sendRawTransaction(signedTx.serialize())
224
+
225
+ // Wait for confirmation
226
+ await connection.confirmTransaction({
227
+ signature,
228
+ blockhash,
229
+ lastValidBlockHeight,
230
+ })
231
+
232
+ // 13. Return result
233
+ const cluster = await getCluster(connection)
234
+
235
+ return {
236
+ signature,
237
+ noteId: transferRecordPda.toBase58(),
238
+ stealthAddress: stealthAccountPubkey.toBase58(),
239
+ ephemeralPublicKey: ephemeralPubkeyHex,
240
+ commitment,
241
+ viewTag: `0x${stealthAddr.viewTag.toString(16).padStart(2, '0')}`,
242
+ viewingKeyHash: `0x${bytesToHex(viewingKeyHash)}`,
243
+ explorerUrl: `https://solscan.io/tx/${signature}?cluster=${cluster}`,
244
+ }
245
+ }
246
+
247
+ /**
248
+ * Build the instruction data for shielded_transfer
249
+ */
250
+ function buildShieldedTransferData(params: {
251
+ commitment: Uint8Array
252
+ stealthPubkey: PublicKey
253
+ ephemeralPubkey: Uint8Array
254
+ viewingKeyHash: Uint8Array
255
+ encryptedAmount: Uint8Array
256
+ proof: Uint8Array
257
+ actualAmount: bigint
258
+ }): Buffer {
259
+ const {
260
+ commitment,
261
+ stealthPubkey,
262
+ ephemeralPubkey,
263
+ viewingKeyHash,
264
+ encryptedAmount,
265
+ proof,
266
+ actualAmount,
267
+ } = params
268
+
269
+ // Calculate total size
270
+ const size =
271
+ 8 + // discriminator
272
+ 33 + // commitment
273
+ 32 + // stealth_pubkey
274
+ 33 + // ephemeral_pubkey
275
+ 32 + // viewing_key_hash
276
+ 4 + encryptedAmount.length + // encrypted_amount (Vec<u8>)
277
+ 4 + proof.length + // proof (Vec<u8>)
278
+ 8 // actual_amount
279
+
280
+ const buffer = Buffer.alloc(size)
281
+ let offset = 0
282
+
283
+ // Discriminator
284
+ SHIELDED_TRANSFER_DISCRIMINATOR.copy(buffer, offset)
285
+ offset += 8
286
+
287
+ // Commitment [u8; 33]
288
+ buffer.set(commitment, offset)
289
+ offset += 33
290
+
291
+ // Stealth pubkey (Pubkey = 32 bytes)
292
+ buffer.set(stealthPubkey.toBuffer(), offset)
293
+ offset += 32
294
+
295
+ // Ephemeral pubkey [u8; 33]
296
+ buffer.set(ephemeralPubkey, offset)
297
+ offset += 33
298
+
299
+ // Viewing key hash [u8; 32]
300
+ buffer.set(viewingKeyHash, offset)
301
+ offset += 32
302
+
303
+ // Encrypted amount Vec<u8> (4-byte length prefix + data)
304
+ buffer.writeUInt32LE(encryptedAmount.length, offset)
305
+ offset += 4
306
+ buffer.set(encryptedAmount, offset)
307
+ offset += encryptedAmount.length
308
+
309
+ // Proof Vec<u8>
310
+ buffer.writeUInt32LE(proof.length, offset)
311
+ offset += 4
312
+ buffer.set(proof, offset)
313
+ offset += proof.length
314
+
315
+ // Actual amount u64
316
+ buffer.writeBigUInt64LE(actualAmount, offset)
317
+
318
+ return buffer
319
+ }
320
+
321
+ /**
322
+ * Create a mock proof for development (real ZK proof in future)
323
+ */
324
+ function createMockProof(
325
+ commitment: HexString,
326
+ amount: bigint,
327
+ blinding: HexString
328
+ ): Uint8Array {
329
+ // Mock proof: 128 bytes of deterministic data
330
+ const proof = new Uint8Array(128)
331
+ const commitmentBytes = hexToBytes(commitment.slice(2))
332
+
333
+ // Fill with hash of inputs for reproducibility
334
+ const inputHash = sha256(
335
+ new Uint8Array([
336
+ ...commitmentBytes,
337
+ ...bigintToLeBytes(amount),
338
+ ...hexToBytes(blinding.slice(2)),
339
+ ])
340
+ )
341
+
342
+ proof.set(inputHash, 0)
343
+ proof.set(inputHash, 32)
344
+ proof.set(inputHash, 64)
345
+ proof.set(inputHash, 96)
346
+
347
+ return proof
348
+ }
349
+
350
+ /**
351
+ * Convert bigint to little-endian bytes (8 bytes)
352
+ */
353
+ function bigintToLeBytes(value: bigint): Uint8Array {
354
+ const buffer = new ArrayBuffer(8)
355
+ const view = new DataView(buffer)
356
+ view.setBigUint64(0, value, true)
357
+ return new Uint8Array(buffer)
358
+ }
359
+
360
+ /**
361
+ * Detect cluster from connection
362
+ */
363
+ async function getCluster(connection: Connection): Promise<string> {
364
+ const endpoint = connection.rpcEndpoint
365
+ if (endpoint.includes('devnet')) return 'devnet'
366
+ if (endpoint.includes('testnet')) return 'testnet'
367
+ if (endpoint.includes('mainnet') || endpoint.includes('api.mainnet-beta')) return 'mainnet'
368
+ return 'devnet'
369
+ }
370
+
371
+ /**
372
+ * Encrypt amount using viewing key (XChaCha20-Poly1305)
373
+ */
374
+ function encryptAmount(amount: bigint, viewingKey: HexString): HexString {
375
+ // Simple encryption: amount XOR'd with viewing key hash
376
+ // TODO: Use proper XChaCha20-Poly1305 from @noble/ciphers
377
+ const amountBytes = bigintToLeBytes(amount)
378
+ const keyHash = sha256(hexToBytes(viewingKey.slice(2)))
379
+
380
+ const encrypted = new Uint8Array(amountBytes.length)
381
+ for (let i = 0; i < amountBytes.length; i++) {
382
+ encrypted[i] = amountBytes[i] ^ keyHash[i]
383
+ }
384
+
385
+ return `0x${bytesToHex(encrypted)}`
386
+ }