@sip-protocol/sdk 0.7.3 → 0.8.0

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 (263) hide show
  1. package/README.md +267 -0
  2. package/dist/{TransportWebUSB-TQ7WZ4LE.mjs → TransportWebUSB-YQMAGJAJ.mjs} +12 -9
  3. package/dist/browser.d.mts +10 -4
  4. package/dist/browser.d.ts +10 -4
  5. package/dist/browser.js +47556 -19603
  6. package/dist/browser.mjs +628 -48
  7. package/dist/chunk-4GRJ5MAW.mjs +152 -0
  8. package/dist/chunk-5D7A3L3W.mjs +717 -0
  9. package/dist/chunk-64AYA5F5.mjs +7834 -0
  10. package/dist/chunk-GMDGB22A.mjs +379 -0
  11. package/dist/chunk-I534WKN7.mjs +328 -0
  12. package/dist/chunk-IBZVA5Y7.mjs +1003 -0
  13. package/dist/chunk-PRRZAWJE.mjs +223 -0
  14. package/dist/{chunk-UJCSKKID.mjs → chunk-XGB3TDIC.mjs} +13 -1
  15. package/dist/{chunk-3M3HNQCW.mjs → chunk-YWGJ77A2.mjs} +28656 -13103
  16. package/dist/{chunk-6WGN57S2.mjs → chunk-Z3K7W5S3.mjs} +48 -0
  17. package/dist/constants-LHAAUC2T.mjs +51 -0
  18. package/dist/dist-2OGQ7FED.mjs +3957 -0
  19. package/dist/dist-IFHPYLDX.mjs +254 -0
  20. package/dist/fulfillment_proof-ANHVPKTB.mjs +21 -0
  21. package/dist/funding_proof-ICFZ5LHY.mjs +21 -0
  22. package/dist/{index-DIBZHOOQ.d.ts → index-DXh2IGkz.d.ts} +21239 -10304
  23. package/dist/{index-8MQz13eJ.d.mts → index-DeE1ZzA4.d.mts} +21239 -10304
  24. package/dist/index.d.mts +9 -3
  25. package/dist/index.d.ts +9 -3
  26. package/dist/index.js +48396 -19623
  27. package/dist/index.mjs +537 -19
  28. package/dist/interface-Bf7w1PLW.d.mts +679 -0
  29. package/dist/interface-Bf7w1PLW.d.ts +679 -0
  30. package/dist/{noir-DKfEzWy9.d.mts → noir-kzbLVTei.d.mts} +31 -21
  31. package/dist/{noir-DKfEzWy9.d.ts → noir-kzbLVTei.d.ts} +31 -21
  32. package/dist/proofs/halo2.d.mts +151 -0
  33. package/dist/proofs/halo2.d.ts +151 -0
  34. package/dist/proofs/halo2.js +350 -0
  35. package/dist/proofs/halo2.mjs +11 -0
  36. package/dist/proofs/kimchi.d.mts +160 -0
  37. package/dist/proofs/kimchi.d.ts +160 -0
  38. package/dist/proofs/kimchi.js +431 -0
  39. package/dist/proofs/kimchi.mjs +13 -0
  40. package/dist/proofs/noir.d.mts +1 -1
  41. package/dist/proofs/noir.d.ts +1 -1
  42. package/dist/proofs/noir.js +74 -18
  43. package/dist/proofs/noir.mjs +84 -24
  44. package/dist/solana-U3MEGU7W.mjs +280 -0
  45. package/dist/validity_proof-3POXLPNY.mjs +21 -0
  46. package/package.json +44 -11
  47. package/src/adapters/index.ts +41 -0
  48. package/src/adapters/jupiter.ts +571 -0
  49. package/src/adapters/near-intents.ts +135 -0
  50. package/src/advisor/advisor.ts +653 -0
  51. package/src/advisor/index.ts +54 -0
  52. package/src/advisor/tools.ts +303 -0
  53. package/src/advisor/types.ts +164 -0
  54. package/src/chains/ethereum/announcement.ts +536 -0
  55. package/src/chains/ethereum/bnb-optimizations.ts +474 -0
  56. package/src/chains/ethereum/commitment.ts +522 -0
  57. package/src/chains/ethereum/constants.ts +462 -0
  58. package/src/chains/ethereum/deployment.ts +596 -0
  59. package/src/chains/ethereum/gas-estimation.ts +538 -0
  60. package/src/chains/ethereum/index.ts +268 -0
  61. package/src/chains/ethereum/optimizations.ts +614 -0
  62. package/src/chains/ethereum/privacy-adapter.ts +855 -0
  63. package/src/chains/ethereum/registry.ts +584 -0
  64. package/src/chains/ethereum/rpc.ts +905 -0
  65. package/src/chains/ethereum/stealth.ts +491 -0
  66. package/src/chains/ethereum/token.ts +790 -0
  67. package/src/chains/ethereum/transfer.ts +637 -0
  68. package/src/chains/ethereum/types.ts +456 -0
  69. package/src/chains/ethereum/viewing-key.ts +455 -0
  70. package/src/chains/near/commitment.ts +608 -0
  71. package/src/chains/near/constants.ts +284 -0
  72. package/src/chains/near/function-call.ts +871 -0
  73. package/src/chains/near/history.ts +654 -0
  74. package/src/chains/near/implicit-account.ts +840 -0
  75. package/src/chains/near/index.ts +393 -0
  76. package/src/chains/near/native-transfer.ts +658 -0
  77. package/src/chains/near/nep141.ts +775 -0
  78. package/src/chains/near/privacy-adapter.ts +889 -0
  79. package/src/chains/near/resolver.ts +971 -0
  80. package/src/chains/near/rpc.ts +1016 -0
  81. package/src/chains/near/stealth.ts +419 -0
  82. package/src/chains/near/types.ts +317 -0
  83. package/src/chains/near/viewing-key.ts +876 -0
  84. package/src/chains/solana/anchor-transfer.ts +386 -0
  85. package/src/chains/solana/commitment.ts +577 -0
  86. package/src/chains/solana/constants.ts +126 -12
  87. package/src/chains/solana/ephemeral-keys.ts +543 -0
  88. package/src/chains/solana/index.ts +252 -1
  89. package/src/chains/solana/key-derivation.ts +418 -0
  90. package/src/chains/solana/kit-compat.ts +334 -0
  91. package/src/chains/solana/optimizations.ts +560 -0
  92. package/src/chains/solana/privacy-adapter.ts +605 -0
  93. package/src/chains/solana/providers/generic.ts +47 -6
  94. package/src/chains/solana/providers/helius-enhanced-types.ts +336 -0
  95. package/src/chains/solana/providers/helius-enhanced.ts +623 -0
  96. package/src/chains/solana/providers/helius.ts +186 -33
  97. package/src/chains/solana/providers/index.ts +31 -0
  98. package/src/chains/solana/providers/interface.ts +61 -18
  99. package/src/chains/solana/providers/quicknode.ts +409 -0
  100. package/src/chains/solana/providers/triton.ts +426 -0
  101. package/src/chains/solana/providers/webhook.ts +338 -67
  102. package/src/chains/solana/rpc-client.ts +1150 -0
  103. package/src/chains/solana/scan.ts +83 -66
  104. package/src/chains/solana/sol-transfer.ts +732 -0
  105. package/src/chains/solana/spl-transfer.ts +886 -0
  106. package/src/chains/solana/stealth-scanner.ts +703 -0
  107. package/src/chains/solana/sunspot-verifier.ts +453 -0
  108. package/src/chains/solana/transaction-builder.ts +755 -0
  109. package/src/chains/solana/transfer.ts +74 -5
  110. package/src/chains/solana/types.ts +57 -6
  111. package/src/chains/solana/utils.ts +110 -0
  112. package/src/chains/solana/viewing-key.ts +807 -0
  113. package/src/compliance/fireblocks.ts +921 -0
  114. package/src/compliance/index.ts +23 -0
  115. package/src/compliance/range-sas.ts +398 -33
  116. package/src/config/endpoints.ts +100 -0
  117. package/src/crypto.ts +11 -8
  118. package/src/errors.ts +82 -0
  119. package/src/evm/erc4337-relayer.ts +830 -0
  120. package/src/evm/index.ts +47 -0
  121. package/src/fees/calculator.ts +396 -0
  122. package/src/fees/index.ts +87 -0
  123. package/src/fees/near-contract.ts +429 -0
  124. package/src/fees/types.ts +268 -0
  125. package/src/index.ts +686 -1
  126. package/src/intent.ts +6 -3
  127. package/src/logger.ts +324 -0
  128. package/src/network/index.ts +80 -0
  129. package/src/network/proxy.ts +691 -0
  130. package/src/optimizations/index.ts +541 -0
  131. package/src/oracle/types.ts +1 -0
  132. package/src/privacy-backends/arcium-types.ts +727 -0
  133. package/src/privacy-backends/arcium.ts +719 -0
  134. package/src/privacy-backends/combined-privacy.ts +866 -0
  135. package/src/privacy-backends/cspl-token.ts +595 -0
  136. package/src/privacy-backends/cspl-types.ts +512 -0
  137. package/src/privacy-backends/cspl.ts +907 -0
  138. package/src/privacy-backends/health.ts +488 -0
  139. package/src/privacy-backends/inco-types.ts +323 -0
  140. package/src/privacy-backends/inco.ts +616 -0
  141. package/src/privacy-backends/index.ts +254 -4
  142. package/src/privacy-backends/interface.ts +649 -6
  143. package/src/privacy-backends/lru-cache.ts +343 -0
  144. package/src/privacy-backends/magicblock.ts +458 -0
  145. package/src/privacy-backends/mock.ts +258 -0
  146. package/src/privacy-backends/privacycash.ts +13 -17
  147. package/src/privacy-backends/private-swap.ts +570 -0
  148. package/src/privacy-backends/rate-limiter.ts +683 -0
  149. package/src/privacy-backends/registry.ts +414 -2
  150. package/src/privacy-backends/router.ts +283 -3
  151. package/src/privacy-backends/shadowwire.ts +449 -0
  152. package/src/privacy-backends/sip-native.ts +3 -0
  153. package/src/privacy-logger.ts +191 -0
  154. package/src/production-safety.ts +373 -0
  155. package/src/proofs/aggregator.ts +1029 -0
  156. package/src/proofs/browser-composer.ts +1150 -0
  157. package/src/proofs/browser.ts +113 -25
  158. package/src/proofs/cache/index.ts +127 -0
  159. package/src/proofs/cache/interface.ts +545 -0
  160. package/src/proofs/cache/key-generator.ts +188 -0
  161. package/src/proofs/cache/lru-cache.ts +481 -0
  162. package/src/proofs/cache/multi-tier-cache.ts +575 -0
  163. package/src/proofs/cache/persistent-cache.ts +788 -0
  164. package/src/proofs/compliance-proof.ts +872 -0
  165. package/src/proofs/composer/base.ts +923 -0
  166. package/src/proofs/composer/index.ts +25 -0
  167. package/src/proofs/composer/interface.ts +518 -0
  168. package/src/proofs/composer/types.ts +383 -0
  169. package/src/proofs/converters/halo2.ts +452 -0
  170. package/src/proofs/converters/index.ts +208 -0
  171. package/src/proofs/converters/interface.ts +363 -0
  172. package/src/proofs/converters/kimchi.ts +462 -0
  173. package/src/proofs/converters/noir.ts +451 -0
  174. package/src/proofs/fallback.ts +888 -0
  175. package/src/proofs/halo2.ts +42 -0
  176. package/src/proofs/index.ts +471 -0
  177. package/src/proofs/interface.ts +13 -0
  178. package/src/proofs/kimchi.ts +42 -0
  179. package/src/proofs/lazy.ts +1004 -0
  180. package/src/proofs/mock.ts +25 -1
  181. package/src/proofs/noir.ts +110 -29
  182. package/src/proofs/orchestrator.ts +960 -0
  183. package/src/proofs/parallel/concurrency.ts +297 -0
  184. package/src/proofs/parallel/dependency-graph.ts +602 -0
  185. package/src/proofs/parallel/executor.ts +420 -0
  186. package/src/proofs/parallel/index.ts +131 -0
  187. package/src/proofs/parallel/interface.ts +685 -0
  188. package/src/proofs/parallel/worker-pool.ts +644 -0
  189. package/src/proofs/providers/halo2.ts +560 -0
  190. package/src/proofs/providers/index.ts +34 -0
  191. package/src/proofs/providers/kimchi.ts +641 -0
  192. package/src/proofs/validator.ts +881 -0
  193. package/src/proofs/verifier.ts +867 -0
  194. package/src/quantum/index.ts +112 -0
  195. package/src/quantum/winternitz-vault.ts +639 -0
  196. package/src/quantum/wots.ts +611 -0
  197. package/src/settlement/backends/direct-chain.ts +1 -0
  198. package/src/settlement/index.ts +9 -0
  199. package/src/settlement/router.ts +732 -46
  200. package/src/solana/index.ts +72 -0
  201. package/src/solana/jito-relayer.ts +687 -0
  202. package/src/solana/noir-verifier-types.ts +430 -0
  203. package/src/solana/noir-verifier.ts +816 -0
  204. package/src/stealth/address-derivation.ts +193 -0
  205. package/src/stealth/ed25519.ts +431 -0
  206. package/src/stealth/index.ts +233 -0
  207. package/src/stealth/meta-address.ts +221 -0
  208. package/src/stealth/secp256k1.ts +368 -0
  209. package/src/stealth/utils.ts +194 -0
  210. package/src/stealth.ts +50 -1504
  211. package/src/sync/index.ts +106 -0
  212. package/src/sync/manager.ts +504 -0
  213. package/src/sync/mock-provider.ts +318 -0
  214. package/src/sync/oblivious.ts +625 -0
  215. package/src/tokens/index.ts +15 -0
  216. package/src/tokens/registry.ts +301 -0
  217. package/src/utils/deprecation.ts +94 -0
  218. package/src/utils/index.ts +9 -0
  219. package/src/wallet/ethereum/index.ts +68 -0
  220. package/src/wallet/ethereum/metamask-privacy.ts +420 -0
  221. package/src/wallet/ethereum/multi-wallet.ts +646 -0
  222. package/src/wallet/ethereum/privacy-adapter.ts +700 -0
  223. package/src/wallet/ethereum/types.ts +3 -1
  224. package/src/wallet/ethereum/walletconnect-adapter.ts +675 -0
  225. package/src/wallet/hardware/index.ts +10 -0
  226. package/src/wallet/hardware/ledger-privacy.ts +414 -0
  227. package/src/wallet/index.ts +71 -0
  228. package/src/wallet/near/adapter.ts +626 -0
  229. package/src/wallet/near/index.ts +86 -0
  230. package/src/wallet/near/meteor-wallet.ts +1153 -0
  231. package/src/wallet/near/my-near-wallet.ts +790 -0
  232. package/src/wallet/near/wallet-selector.ts +702 -0
  233. package/src/wallet/solana/adapter.ts +6 -4
  234. package/src/wallet/solana/index.ts +13 -0
  235. package/src/wallet/solana/privacy-adapter.ts +567 -0
  236. package/src/wallet/sui/types.ts +6 -4
  237. package/src/zcash/rpc-client.ts +13 -6
  238. package/dist/chunk-2XIVXWHA.mjs +0 -1930
  239. package/dist/chunk-3INS3PR5.mjs +0 -884
  240. package/dist/chunk-3OVABDRH.mjs +0 -17096
  241. package/dist/chunk-7RFRWDCW.mjs +0 -1504
  242. package/dist/chunk-DLDWZFYC.mjs +0 -1495
  243. package/dist/chunk-E6SZWREQ.mjs +0 -57
  244. package/dist/chunk-F6F73W35.mjs +0 -16166
  245. package/dist/chunk-G33LB27A.mjs +0 -16166
  246. package/dist/chunk-HGU6HZRC.mjs +0 -231
  247. package/dist/chunk-L2K34JCU.mjs +0 -1496
  248. package/dist/chunk-OFDBEIEK.mjs +0 -16166
  249. package/dist/chunk-SF7YSLF5.mjs +0 -1515
  250. package/dist/chunk-SN4ZDTVW.mjs +0 -16166
  251. package/dist/chunk-WWUSGOXE.mjs +0 -17129
  252. package/dist/constants-VOI7BSLK.mjs +0 -27
  253. package/dist/index-B71aXVzk.d.ts +0 -13264
  254. package/dist/index-BYZbDjal.d.ts +0 -11390
  255. package/dist/index-CHB3KuOB.d.mts +0 -11859
  256. package/dist/index-CzWPI6Le.d.ts +0 -11859
  257. package/dist/index-pOIIuwfV.d.mts +0 -13264
  258. package/dist/index-xbWjohNq.d.mts +0 -11390
  259. package/dist/solana-4O4K45VU.mjs +0 -46
  260. package/dist/solana-5EMCTPTS.mjs +0 -46
  261. package/dist/solana-NDABAZ6P.mjs +0 -56
  262. package/dist/solana-Q4NAVBTS.mjs +0 -46
  263. package/dist/solana-ZYO63LY5.mjs +0 -46
@@ -0,0 +1,755 @@
1
+ /**
2
+ * Shielded Transaction Builder
3
+ *
4
+ * Builds properly structured Solana transactions for privacy operations.
5
+ * Handles instruction ordering, compute budget, and versioned transactions.
6
+ *
7
+ * @module chains/solana/transaction-builder
8
+ */
9
+
10
+ import {
11
+ Connection,
12
+ PublicKey,
13
+ Transaction,
14
+ TransactionInstruction,
15
+ TransactionMessage,
16
+ VersionedTransaction,
17
+ ComputeBudgetProgram,
18
+ SystemProgram,
19
+ AddressLookupTableAccount,
20
+ type Commitment,
21
+ type Blockhash,
22
+ } from '@solana/web3.js'
23
+ import {
24
+ getAssociatedTokenAddress,
25
+ createAssociatedTokenAccountInstruction,
26
+ createTransferInstruction,
27
+ TOKEN_PROGRAM_ID,
28
+ ASSOCIATED_TOKEN_PROGRAM_ID,
29
+ } from '@solana/spl-token'
30
+ import {
31
+ generateEd25519StealthAddress,
32
+ ed25519PublicKeyToSolanaAddress,
33
+ } from '../../stealth'
34
+ import type { StealthMetaAddress } from '@sip-protocol/types'
35
+ import { createAnnouncementMemo } from './types'
36
+ import { MEMO_PROGRAM_ID } from './constants'
37
+
38
+ // ─── Constants ────────────────────────────────────────────────────────────────
39
+
40
+ /**
41
+ * Default compute unit limit for shielded transactions
42
+ * Higher than standard to accommodate memo + potential ATA creation
43
+ */
44
+ export const DEFAULT_COMPUTE_UNITS = 200_000
45
+
46
+ /**
47
+ * Default priority fee in micro-lamports per compute unit
48
+ */
49
+ export const DEFAULT_PRIORITY_FEE = 1_000
50
+
51
+ /**
52
+ * Minimum compute units for a simple transfer
53
+ */
54
+ export const MIN_COMPUTE_UNITS = 50_000
55
+
56
+ /**
57
+ * Maximum compute units allowed
58
+ */
59
+ export const MAX_COMPUTE_UNITS = 1_400_000
60
+
61
+ // ─── Types ────────────────────────────────────────────────────────────────────
62
+
63
+ /**
64
+ * Transaction type enumeration
65
+ */
66
+ export enum ShieldedTransactionType {
67
+ /** SPL token transfer to stealth address */
68
+ SPL_TRANSFER = 'spl_transfer',
69
+ /** Native SOL transfer to stealth address */
70
+ SOL_TRANSFER = 'sol_transfer',
71
+ /** Claim from stealth address */
72
+ CLAIM = 'claim',
73
+ /** Batch transfer to multiple stealth addresses */
74
+ BATCH_TRANSFER = 'batch_transfer',
75
+ }
76
+
77
+ /**
78
+ * Compute budget configuration
79
+ */
80
+ export interface ComputeBudgetConfig {
81
+ /** Compute unit limit (default: 200,000) */
82
+ units?: number
83
+ /** Priority fee in micro-lamports per compute unit (default: 1,000) */
84
+ priorityFee?: number
85
+ }
86
+
87
+ /**
88
+ * Transaction builder configuration
89
+ */
90
+ export interface TransactionBuilderConfig {
91
+ /** Solana RPC connection */
92
+ connection: Connection
93
+ /** Fee payer public key */
94
+ feePayer: PublicKey
95
+ /** Use versioned transactions (default: false for legacy) */
96
+ useVersionedTransaction?: boolean
97
+ /** Compute budget configuration */
98
+ computeBudget?: ComputeBudgetConfig
99
+ /** Address lookup tables for account compression */
100
+ lookupTables?: AddressLookupTableAccount[]
101
+ /** Transaction commitment level */
102
+ commitment?: Commitment
103
+ }
104
+
105
+ /**
106
+ * SPL transfer instruction parameters
107
+ */
108
+ export interface SPLTransferInstruction {
109
+ /** Token mint address */
110
+ mint: PublicKey
111
+ /** Source token account */
112
+ sourceAccount: PublicKey
113
+ /** Source account owner */
114
+ owner: PublicKey
115
+ /** Recipient's stealth meta-address */
116
+ recipientMetaAddress: StealthMetaAddress
117
+ /** Amount to transfer */
118
+ amount: bigint
119
+ }
120
+
121
+ /**
122
+ * SOL transfer instruction parameters
123
+ */
124
+ export interface SOLTransferInstruction {
125
+ /** Source account (sender) */
126
+ sender: PublicKey
127
+ /** Recipient's stealth meta-address */
128
+ recipientMetaAddress: StealthMetaAddress
129
+ /** Amount in lamports */
130
+ amount: bigint
131
+ }
132
+
133
+ /**
134
+ * Built transaction result
135
+ */
136
+ export interface BuiltTransaction {
137
+ /** Transaction type */
138
+ type: ShieldedTransactionType
139
+ /** Legacy transaction (if useVersionedTransaction is false) */
140
+ transaction?: Transaction
141
+ /** Versioned transaction (if useVersionedTransaction is true) */
142
+ versionedTransaction?: VersionedTransaction
143
+ /** Stealth address details */
144
+ stealthDetails: Array<{
145
+ stealthAddress: string
146
+ ephemeralPublicKey: string
147
+ viewTag: string
148
+ mint?: string
149
+ amount: bigint
150
+ }>
151
+ /** Recent blockhash used */
152
+ blockhash: Blockhash
153
+ /** Last valid block height */
154
+ lastValidBlockHeight: number
155
+ /** Estimated compute units */
156
+ estimatedComputeUnits: number
157
+ /** Estimated fee in lamports */
158
+ estimatedFee: bigint
159
+ }
160
+
161
+ /**
162
+ * Serialized transaction for external signing
163
+ */
164
+ export interface SerializedTransaction {
165
+ /** Base64 encoded transaction */
166
+ serialized: string
167
+ /** Transaction type */
168
+ type: ShieldedTransactionType
169
+ /** Stealth details for reference */
170
+ stealthDetails: BuiltTransaction['stealthDetails']
171
+ /** Blockhash */
172
+ blockhash: string
173
+ /** Is versioned transaction */
174
+ isVersioned: boolean
175
+ }
176
+
177
+ // ─── Transaction Builder Class ────────────────────────────────────────────────
178
+
179
+ /**
180
+ * Shielded Transaction Builder
181
+ *
182
+ * Builds properly structured Solana transactions for privacy operations.
183
+ *
184
+ * @example Legacy transaction
185
+ * ```typescript
186
+ * const builder = new ShieldedTransactionBuilder({
187
+ * connection,
188
+ * feePayer: wallet.publicKey,
189
+ * })
190
+ *
191
+ * const built = await builder.buildSPLTransfer({
192
+ * mint: USDC_MINT,
193
+ * sourceAccount: senderATA,
194
+ * owner: wallet.publicKey,
195
+ * recipientMetaAddress: recipientMeta,
196
+ * amount: 5_000_000n,
197
+ * })
198
+ *
199
+ * const signedTx = await wallet.signTransaction(built.transaction!)
200
+ * ```
201
+ *
202
+ * @example Versioned transaction with priority fees
203
+ * ```typescript
204
+ * const builder = new ShieldedTransactionBuilder({
205
+ * connection,
206
+ * feePayer: wallet.publicKey,
207
+ * useVersionedTransaction: true,
208
+ * computeBudget: { units: 300_000, priorityFee: 5_000 },
209
+ * })
210
+ *
211
+ * const built = await builder.buildSOLTransfer({
212
+ * sender: wallet.publicKey,
213
+ * recipientMetaAddress: recipientMeta,
214
+ * amount: 1_000_000_000n,
215
+ * })
216
+ *
217
+ * const signedTx = await wallet.signTransaction(built.versionedTransaction!)
218
+ * ```
219
+ */
220
+ export class ShieldedTransactionBuilder {
221
+ private connection: Connection
222
+ private feePayer: PublicKey
223
+ private useVersioned: boolean
224
+ private computeUnits: number
225
+ private priorityFee: number
226
+ private lookupTables: AddressLookupTableAccount[]
227
+ private commitment: Commitment
228
+
229
+ constructor(config: TransactionBuilderConfig) {
230
+ this.connection = config.connection
231
+ this.feePayer = config.feePayer
232
+ this.useVersioned = config.useVersionedTransaction ?? false
233
+ this.computeUnits = config.computeBudget?.units ?? DEFAULT_COMPUTE_UNITS
234
+ this.priorityFee = config.computeBudget?.priorityFee ?? DEFAULT_PRIORITY_FEE
235
+ this.lookupTables = config.lookupTables ?? []
236
+ this.commitment = config.commitment ?? 'confirmed'
237
+
238
+ // Validate compute units
239
+ if (this.computeUnits < MIN_COMPUTE_UNITS || this.computeUnits > MAX_COMPUTE_UNITS) {
240
+ throw new Error(
241
+ `Compute units must be between ${MIN_COMPUTE_UNITS} and ${MAX_COMPUTE_UNITS}`
242
+ )
243
+ }
244
+ }
245
+
246
+ // ─── SPL Transfer ─────────────────────────────────────────────────────────────
247
+
248
+ /**
249
+ * Build SPL token transfer to stealth address
250
+ *
251
+ * Creates a transaction with:
252
+ * 1. Compute budget instructions (if priority fee > 0)
253
+ * 2. ATA creation instruction (if needed)
254
+ * 3. SPL transfer instruction
255
+ * 4. Memo with ephemeral key announcement
256
+ */
257
+ async buildSPLTransfer(params: SPLTransferInstruction): Promise<BuiltTransaction> {
258
+ const { mint, sourceAccount, owner, recipientMetaAddress, amount } = params
259
+
260
+ // Validate chain
261
+ if (recipientMetaAddress.chain !== 'solana') {
262
+ throw new Error(`Invalid chain: expected 'solana', got '${recipientMetaAddress.chain}'`)
263
+ }
264
+
265
+ // Generate stealth address
266
+ const { stealthAddress } = generateEd25519StealthAddress(recipientMetaAddress)
267
+ const stealthAddressBase58 = ed25519PublicKeyToSolanaAddress(stealthAddress.address)
268
+ const stealthPubkey = new PublicKey(stealthAddressBase58)
269
+ const ephemeralPubkeyBase58 = ed25519PublicKeyToSolanaAddress(stealthAddress.ephemeralPublicKey)
270
+
271
+ // Get stealth ATA
272
+ const stealthATA = await getAssociatedTokenAddress(mint, stealthPubkey, true)
273
+
274
+ // Build instructions
275
+ const instructions: TransactionInstruction[] = []
276
+
277
+ // 1. Compute budget (priority fee)
278
+ if (this.priorityFee > 0) {
279
+ instructions.push(
280
+ ComputeBudgetProgram.setComputeUnitLimit({ units: this.computeUnits }),
281
+ ComputeBudgetProgram.setComputeUnitPrice({ microLamports: this.priorityFee })
282
+ )
283
+ }
284
+
285
+ // 2. ATA creation (if needed)
286
+ let needsAtaCreation = false
287
+ try {
288
+ const accountInfo = await this.connection.getAccountInfo(stealthATA)
289
+ needsAtaCreation = accountInfo === null
290
+ } catch {
291
+ needsAtaCreation = true
292
+ }
293
+
294
+ if (needsAtaCreation) {
295
+ instructions.push(
296
+ createAssociatedTokenAccountInstruction(
297
+ this.feePayer,
298
+ stealthATA,
299
+ stealthPubkey,
300
+ mint,
301
+ TOKEN_PROGRAM_ID,
302
+ ASSOCIATED_TOKEN_PROGRAM_ID
303
+ )
304
+ )
305
+ }
306
+
307
+ // 3. SPL transfer
308
+ instructions.push(
309
+ createTransferInstruction(sourceAccount, stealthATA, owner, amount)
310
+ )
311
+
312
+ // 4. Announcement memo
313
+ const viewTagHex = stealthAddress.viewTag.toString(16).padStart(2, '0')
314
+ const memoContent = createAnnouncementMemo(
315
+ ephemeralPubkeyBase58,
316
+ viewTagHex,
317
+ stealthAddressBase58
318
+ )
319
+
320
+ instructions.push(
321
+ new TransactionInstruction({
322
+ keys: [],
323
+ programId: new PublicKey(MEMO_PROGRAM_ID),
324
+ data: Buffer.from(memoContent, 'utf-8'),
325
+ })
326
+ )
327
+
328
+ return this.buildTransaction(
329
+ instructions,
330
+ ShieldedTransactionType.SPL_TRANSFER,
331
+ [{
332
+ stealthAddress: stealthAddressBase58,
333
+ ephemeralPublicKey: ephemeralPubkeyBase58,
334
+ viewTag: viewTagHex,
335
+ mint: mint.toBase58(),
336
+ amount,
337
+ }]
338
+ )
339
+ }
340
+
341
+ // ─── SOL Transfer ─────────────────────────────────────────────────────────────
342
+
343
+ /**
344
+ * Build native SOL transfer to stealth address
345
+ *
346
+ * Creates a transaction with:
347
+ * 1. Compute budget instructions (if priority fee > 0)
348
+ * 2. System program transfer
349
+ * 3. Memo with ephemeral key announcement
350
+ */
351
+ async buildSOLTransfer(params: SOLTransferInstruction): Promise<BuiltTransaction> {
352
+ const { sender, recipientMetaAddress, amount } = params
353
+
354
+ // Validate chain
355
+ if (recipientMetaAddress.chain !== 'solana') {
356
+ throw new Error(`Invalid chain: expected 'solana', got '${recipientMetaAddress.chain}'`)
357
+ }
358
+
359
+ // Generate stealth address
360
+ const { stealthAddress } = generateEd25519StealthAddress(recipientMetaAddress)
361
+ const stealthAddressBase58 = ed25519PublicKeyToSolanaAddress(stealthAddress.address)
362
+ const stealthPubkey = new PublicKey(stealthAddressBase58)
363
+ const ephemeralPubkeyBase58 = ed25519PublicKeyToSolanaAddress(stealthAddress.ephemeralPublicKey)
364
+
365
+ // Build instructions
366
+ const instructions: TransactionInstruction[] = []
367
+
368
+ // 1. Compute budget (priority fee)
369
+ if (this.priorityFee > 0) {
370
+ instructions.push(
371
+ ComputeBudgetProgram.setComputeUnitLimit({ units: this.computeUnits }),
372
+ ComputeBudgetProgram.setComputeUnitPrice({ microLamports: this.priorityFee })
373
+ )
374
+ }
375
+
376
+ // 2. System transfer
377
+ instructions.push(
378
+ SystemProgram.transfer({
379
+ fromPubkey: sender,
380
+ toPubkey: stealthPubkey,
381
+ lamports: amount,
382
+ })
383
+ )
384
+
385
+ // 3. Announcement memo
386
+ const viewTagHex = stealthAddress.viewTag.toString(16).padStart(2, '0')
387
+ const memoContent = createAnnouncementMemo(
388
+ ephemeralPubkeyBase58,
389
+ viewTagHex,
390
+ stealthAddressBase58
391
+ )
392
+
393
+ instructions.push(
394
+ new TransactionInstruction({
395
+ keys: [],
396
+ programId: new PublicKey(MEMO_PROGRAM_ID),
397
+ data: Buffer.from(memoContent, 'utf-8'),
398
+ })
399
+ )
400
+
401
+ return this.buildTransaction(
402
+ instructions,
403
+ ShieldedTransactionType.SOL_TRANSFER,
404
+ [{
405
+ stealthAddress: stealthAddressBase58,
406
+ ephemeralPublicKey: ephemeralPubkeyBase58,
407
+ viewTag: viewTagHex,
408
+ amount,
409
+ }]
410
+ )
411
+ }
412
+
413
+ // ─── Batch Transfer ───────────────────────────────────────────────────────────
414
+
415
+ /**
416
+ * Build batch SPL transfer to multiple stealth addresses
417
+ *
418
+ * @param mint - Token mint
419
+ * @param sourceAccount - Source token account
420
+ * @param owner - Source account owner
421
+ * @param transfers - Array of recipient + amount pairs
422
+ */
423
+ async buildBatchSPLTransfer(
424
+ mint: PublicKey,
425
+ sourceAccount: PublicKey,
426
+ owner: PublicKey,
427
+ transfers: Array<{ recipientMetaAddress: StealthMetaAddress; amount: bigint }>
428
+ ): Promise<BuiltTransaction> {
429
+ const instructions: TransactionInstruction[] = []
430
+ const stealthDetails: BuiltTransaction['stealthDetails'] = []
431
+
432
+ // 1. Compute budget (higher for batch)
433
+ const batchComputeUnits = Math.min(
434
+ this.computeUnits * Math.ceil(transfers.length / 2),
435
+ MAX_COMPUTE_UNITS
436
+ )
437
+
438
+ if (this.priorityFee > 0) {
439
+ instructions.push(
440
+ ComputeBudgetProgram.setComputeUnitLimit({ units: batchComputeUnits }),
441
+ ComputeBudgetProgram.setComputeUnitPrice({ microLamports: this.priorityFee })
442
+ )
443
+ }
444
+
445
+ // 2. Process each transfer
446
+ for (const transfer of transfers) {
447
+ if (transfer.recipientMetaAddress.chain !== 'solana') {
448
+ throw new Error(`Invalid chain: expected 'solana'`)
449
+ }
450
+
451
+ // Generate stealth address
452
+ const { stealthAddress } = generateEd25519StealthAddress(transfer.recipientMetaAddress)
453
+ const stealthAddressBase58 = ed25519PublicKeyToSolanaAddress(stealthAddress.address)
454
+ const stealthPubkey = new PublicKey(stealthAddressBase58)
455
+ const ephemeralPubkeyBase58 = ed25519PublicKeyToSolanaAddress(stealthAddress.ephemeralPublicKey)
456
+
457
+ // Get/create ATA
458
+ const stealthATA = await getAssociatedTokenAddress(mint, stealthPubkey, true)
459
+
460
+ try {
461
+ const accountInfo = await this.connection.getAccountInfo(stealthATA)
462
+ if (accountInfo === null) {
463
+ instructions.push(
464
+ createAssociatedTokenAccountInstruction(
465
+ this.feePayer,
466
+ stealthATA,
467
+ stealthPubkey,
468
+ mint,
469
+ TOKEN_PROGRAM_ID,
470
+ ASSOCIATED_TOKEN_PROGRAM_ID
471
+ )
472
+ )
473
+ }
474
+ } catch {
475
+ instructions.push(
476
+ createAssociatedTokenAccountInstruction(
477
+ this.feePayer,
478
+ stealthATA,
479
+ stealthPubkey,
480
+ mint,
481
+ TOKEN_PROGRAM_ID,
482
+ ASSOCIATED_TOKEN_PROGRAM_ID
483
+ )
484
+ )
485
+ }
486
+
487
+ // Transfer
488
+ instructions.push(
489
+ createTransferInstruction(sourceAccount, stealthATA, owner, transfer.amount)
490
+ )
491
+
492
+ // Announcement
493
+ const viewTagHex = stealthAddress.viewTag.toString(16).padStart(2, '0')
494
+ const memoContent = createAnnouncementMemo(
495
+ ephemeralPubkeyBase58,
496
+ viewTagHex,
497
+ stealthAddressBase58
498
+ )
499
+
500
+ instructions.push(
501
+ new TransactionInstruction({
502
+ keys: [],
503
+ programId: new PublicKey(MEMO_PROGRAM_ID),
504
+ data: Buffer.from(memoContent, 'utf-8'),
505
+ })
506
+ )
507
+
508
+ stealthDetails.push({
509
+ stealthAddress: stealthAddressBase58,
510
+ ephemeralPublicKey: ephemeralPubkeyBase58,
511
+ viewTag: viewTagHex,
512
+ mint: mint.toBase58(),
513
+ amount: transfer.amount,
514
+ })
515
+ }
516
+
517
+ return this.buildTransaction(
518
+ instructions,
519
+ ShieldedTransactionType.BATCH_TRANSFER,
520
+ stealthDetails,
521
+ batchComputeUnits
522
+ )
523
+ }
524
+
525
+ // ─── Core Builder ─────────────────────────────────────────────────────────────
526
+
527
+ /**
528
+ * Build transaction from instructions
529
+ */
530
+ private async buildTransaction(
531
+ instructions: TransactionInstruction[],
532
+ type: ShieldedTransactionType,
533
+ stealthDetails: BuiltTransaction['stealthDetails'],
534
+ computeUnits?: number
535
+ ): Promise<BuiltTransaction> {
536
+ const { blockhash, lastValidBlockHeight } = await this.connection.getLatestBlockhash(
537
+ this.commitment
538
+ )
539
+
540
+ const effectiveComputeUnits = computeUnits ?? this.computeUnits
541
+
542
+ // Calculate estimated fee
543
+ const baseFee = 5000n // Base transaction fee
544
+ const priorityFee = BigInt(Math.ceil((effectiveComputeUnits * this.priorityFee) / 1_000_000))
545
+ const estimatedFee = baseFee + priorityFee
546
+
547
+ if (this.useVersioned) {
548
+ // Build versioned transaction
549
+ const messageV0 = new TransactionMessage({
550
+ payerKey: this.feePayer,
551
+ recentBlockhash: blockhash,
552
+ instructions,
553
+ }).compileToV0Message(this.lookupTables.length > 0 ? this.lookupTables : undefined)
554
+
555
+ const versionedTransaction = new VersionedTransaction(messageV0)
556
+
557
+ return {
558
+ type,
559
+ versionedTransaction,
560
+ stealthDetails,
561
+ blockhash,
562
+ lastValidBlockHeight,
563
+ estimatedComputeUnits: effectiveComputeUnits,
564
+ estimatedFee,
565
+ }
566
+ } else {
567
+ // Build legacy transaction
568
+ const transaction = new Transaction()
569
+ transaction.recentBlockhash = blockhash
570
+ transaction.lastValidBlockHeight = lastValidBlockHeight
571
+ transaction.feePayer = this.feePayer
572
+ instructions.forEach((ix) => transaction.add(ix))
573
+
574
+ return {
575
+ type,
576
+ transaction,
577
+ stealthDetails,
578
+ blockhash,
579
+ lastValidBlockHeight,
580
+ estimatedComputeUnits: effectiveComputeUnits,
581
+ estimatedFee,
582
+ }
583
+ }
584
+ }
585
+
586
+ // ─── Serialization ────────────────────────────────────────────────────────────
587
+
588
+ /**
589
+ * Serialize transaction for external signing
590
+ *
591
+ * Useful for wallets that require base64 serialized transactions.
592
+ */
593
+ serializeForSigning(built: BuiltTransaction): SerializedTransaction {
594
+ let serialized: string
595
+
596
+ if (built.versionedTransaction) {
597
+ serialized = Buffer.from(built.versionedTransaction.serialize()).toString('base64')
598
+ } else if (built.transaction) {
599
+ serialized = built.transaction
600
+ .serialize({ requireAllSignatures: false, verifySignatures: false })
601
+ .toString('base64')
602
+ } else {
603
+ throw new Error('No transaction to serialize')
604
+ }
605
+
606
+ return {
607
+ serialized,
608
+ type: built.type,
609
+ stealthDetails: built.stealthDetails,
610
+ blockhash: built.blockhash,
611
+ isVersioned: !!built.versionedTransaction,
612
+ }
613
+ }
614
+
615
+ /**
616
+ * Deserialize a signed transaction
617
+ */
618
+ deserializeSignedTransaction(
619
+ serialized: string,
620
+ isVersioned: boolean
621
+ ): Transaction | VersionedTransaction {
622
+ const buffer = Buffer.from(serialized, 'base64')
623
+
624
+ if (isVersioned) {
625
+ return VersionedTransaction.deserialize(buffer)
626
+ } else {
627
+ return Transaction.from(buffer)
628
+ }
629
+ }
630
+
631
+ // ─── Configuration ────────────────────────────────────────────────────────────
632
+
633
+ /**
634
+ * Update compute budget configuration
635
+ */
636
+ setComputeBudget(config: ComputeBudgetConfig): void {
637
+ if (config.units !== undefined) {
638
+ if (config.units < MIN_COMPUTE_UNITS || config.units > MAX_COMPUTE_UNITS) {
639
+ throw new Error(
640
+ `Compute units must be between ${MIN_COMPUTE_UNITS} and ${MAX_COMPUTE_UNITS}`
641
+ )
642
+ }
643
+ this.computeUnits = config.units
644
+ }
645
+ if (config.priorityFee !== undefined) {
646
+ this.priorityFee = config.priorityFee
647
+ }
648
+ }
649
+
650
+ /**
651
+ * Set lookup tables for account compression
652
+ */
653
+ setLookupTables(tables: AddressLookupTableAccount[]): void {
654
+ this.lookupTables = tables
655
+ }
656
+
657
+ /**
658
+ * Enable or disable versioned transactions
659
+ */
660
+ setVersionedTransactions(enabled: boolean): void {
661
+ this.useVersioned = enabled
662
+ }
663
+
664
+ /**
665
+ * Get current configuration
666
+ */
667
+ getConfig(): {
668
+ computeUnits: number
669
+ priorityFee: number
670
+ useVersioned: boolean
671
+ lookupTablesCount: number
672
+ } {
673
+ return {
674
+ computeUnits: this.computeUnits,
675
+ priorityFee: this.priorityFee,
676
+ useVersioned: this.useVersioned,
677
+ lookupTablesCount: this.lookupTables.length,
678
+ }
679
+ }
680
+ }
681
+
682
+ // ─── Factory Function ─────────────────────────────────────────────────────────
683
+
684
+ /**
685
+ * Create a shielded transaction builder
686
+ *
687
+ * @example
688
+ * ```typescript
689
+ * const builder = createTransactionBuilder({
690
+ * connection,
691
+ * feePayer: wallet.publicKey,
692
+ * computeBudget: { priorityFee: 5000 },
693
+ * })
694
+ * ```
695
+ */
696
+ export function createTransactionBuilder(
697
+ config: TransactionBuilderConfig
698
+ ): ShieldedTransactionBuilder {
699
+ return new ShieldedTransactionBuilder(config)
700
+ }
701
+
702
+ // ─── Utilities ────────────────────────────────────────────────────────────────
703
+
704
+ /**
705
+ * Estimate compute units for a transaction
706
+ *
707
+ * @param instructions - Transaction instructions
708
+ * @returns Estimated compute units
709
+ */
710
+ export function estimateComputeUnits(instructions: TransactionInstruction[]): number {
711
+ // Base compute per instruction
712
+ let units = 5000 * instructions.length
713
+
714
+ // Additional compute for specific programs
715
+ for (const ix of instructions) {
716
+ const programId = ix.programId.toBase58()
717
+
718
+ if (programId === TOKEN_PROGRAM_ID.toBase58()) {
719
+ units += 10000 // Token transfer
720
+ } else if (programId === ASSOCIATED_TOKEN_PROGRAM_ID.toBase58()) {
721
+ units += 30000 // ATA creation
722
+ } else if (programId === MEMO_PROGRAM_ID) {
723
+ units += 2000 // Memo
724
+ } else if (programId === SystemProgram.programId.toBase58()) {
725
+ units += 3000 // System transfer
726
+ } else if (programId === ComputeBudgetProgram.programId.toBase58()) {
727
+ units += 500 // Compute budget
728
+ }
729
+ }
730
+
731
+ return Math.min(units, MAX_COMPUTE_UNITS)
732
+ }
733
+
734
+ /**
735
+ * Calculate priority fee from desired priority
736
+ *
737
+ * @param priority - Priority level (low, medium, high, urgent)
738
+ * @returns Priority fee in micro-lamports
739
+ */
740
+ export function calculatePriorityFee(
741
+ priority: 'low' | 'medium' | 'high' | 'urgent'
742
+ ): number {
743
+ switch (priority) {
744
+ case 'low':
745
+ return 100
746
+ case 'medium':
747
+ return 1_000
748
+ case 'high':
749
+ return 10_000
750
+ case 'urgent':
751
+ return 100_000
752
+ default:
753
+ return 1_000
754
+ }
755
+ }