@utxopia/sdk 0.1.0-alpha.2 → 0.1.0-alpha.3

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 (142) hide show
  1. package/README.md +214 -108
  2. package/{packages/sdk/dist → dist}/client.d.ts +25 -1
  3. package/{packages/sdk/dist → dist}/client.js +36 -1
  4. package/{packages/sdk/dist → dist}/crypto-ed25519.d.ts +14 -0
  5. package/{packages/sdk/dist → dist}/crypto-ed25519.js +14 -0
  6. package/{packages/sdk/dist → dist}/index.d.ts +3 -3
  7. package/{packages/sdk/dist → dist}/index.js +3 -3
  8. package/{packages/sdk/dist → dist}/instructions.d.ts +28 -11
  9. package/{packages/sdk/dist → dist}/instructions.js +45 -15
  10. package/{packages/sdk/dist → dist}/stealth.d.ts +104 -9
  11. package/{packages/sdk/dist → dist}/stealth.js +146 -14
  12. package/{packages/sdk/dist → dist}/taproot.d.ts +39 -2
  13. package/{packages/sdk/dist → dist}/taproot.js +54 -2
  14. package/package.json +86 -63
  15. package/src/announcement-client.ts +457 -0
  16. package/src/auditor-ciphertext.ts +181 -0
  17. package/src/auditor.ts +409 -0
  18. package/src/bitcoin/ika.ts +103 -0
  19. package/src/bitcoin/index.ts +5 -0
  20. package/src/bound-params.ts +322 -0
  21. package/src/chadbuffer.ts +603 -0
  22. package/src/circomlibjs.d.ts +51 -0
  23. package/src/claim-link.ts +53 -0
  24. package/src/client.ts +638 -0
  25. package/src/commitment-tree.ts +736 -0
  26. package/src/config.ts +772 -0
  27. package/src/core/esplora.ts +332 -0
  28. package/src/core/mempool.ts +159 -0
  29. package/src/crypto-babyjub.ts +385 -0
  30. package/src/crypto-ed25519.ts +297 -0
  31. package/src/crypto.ts +199 -0
  32. package/src/event-client.ts +231 -0
  33. package/src/events.ts +384 -0
  34. package/src/explorer.ts +300 -0
  35. package/src/index.ts +902 -0
  36. package/src/instructions.ts +2820 -0
  37. package/src/keys.ts +1228 -0
  38. package/src/logger.ts +41 -0
  39. package/src/magicblock.ts +278 -0
  40. package/src/merkle.ts +197 -0
  41. package/src/note.ts +754 -0
  42. package/src/pda.ts +516 -0
  43. package/src/pool-state.ts +176 -0
  44. package/src/poseidon.ts +175 -0
  45. package/src/prover/index.ts +19 -0
  46. package/src/prover/mobile.ts +303 -0
  47. package/src/prover/web.ts +771 -0
  48. package/src/psbt.ts +333 -0
  49. package/src/selective-disclosure.ts +284 -0
  50. package/src/sender-memo.ts +343 -0
  51. package/src/snarkjs.d.ts +19 -0
  52. package/src/sns-resolver.ts +333 -0
  53. package/src/solana/connection.ts +189 -0
  54. package/src/solana/priority-fee.ts +201 -0
  55. package/src/spend-doc.ts +163 -0
  56. package/src/stealth.ts +1477 -0
  57. package/src/taproot.ts +707 -0
  58. package/src/token-registry.ts +207 -0
  59. package/src/utils/encoding.ts +33 -0
  60. package/src/vk-registry.ts +295 -0
  61. package/LICENSE +0 -21
  62. package/packages/btc-client/src/esplora-client.ts +0 -153
  63. package/packages/btc-client/src/index.ts +0 -3
  64. package/packages/btc-client/src/op-return.ts +0 -93
  65. package/packages/btc-client/src/types.ts +0 -112
  66. package/packages/sdk/README.md +0 -277
  67. /package/{packages/sdk/dist → dist}/announcement-client.d.ts +0 -0
  68. /package/{packages/sdk/dist → dist}/announcement-client.js +0 -0
  69. /package/{packages/sdk/dist → dist}/auditor-ciphertext.d.ts +0 -0
  70. /package/{packages/sdk/dist → dist}/auditor-ciphertext.js +0 -0
  71. /package/{packages/sdk/dist → dist}/auditor.d.ts +0 -0
  72. /package/{packages/sdk/dist → dist}/auditor.js +0 -0
  73. /package/{packages/sdk/dist → dist}/bitcoin/ika.d.ts +0 -0
  74. /package/{packages/sdk/dist → dist}/bitcoin/ika.js +0 -0
  75. /package/{packages/sdk/dist → dist}/bitcoin/index.d.ts +0 -0
  76. /package/{packages/sdk/dist → dist}/bitcoin/index.js +0 -0
  77. /package/{packages/sdk/dist → dist}/bound-params.d.ts +0 -0
  78. /package/{packages/sdk/dist → dist}/bound-params.js +0 -0
  79. /package/{packages/sdk/dist → dist}/chadbuffer.d.ts +0 -0
  80. /package/{packages/sdk/dist → dist}/chadbuffer.js +0 -0
  81. /package/{packages/sdk/dist → dist}/claim-link.d.ts +0 -0
  82. /package/{packages/sdk/dist → dist}/claim-link.js +0 -0
  83. /package/{packages/sdk/dist → dist}/commitment-tree.d.ts +0 -0
  84. /package/{packages/sdk/dist → dist}/commitment-tree.js +0 -0
  85. /package/{packages/sdk/dist → dist}/config.d.ts +0 -0
  86. /package/{packages/sdk/dist → dist}/config.js +0 -0
  87. /package/{packages/sdk/dist → dist}/core/esplora.d.ts +0 -0
  88. /package/{packages/sdk/dist → dist}/core/esplora.js +0 -0
  89. /package/{packages/sdk/dist → dist}/core/mempool.d.ts +0 -0
  90. /package/{packages/sdk/dist → dist}/core/mempool.js +0 -0
  91. /package/{packages/sdk/dist → dist}/crypto-babyjub.d.ts +0 -0
  92. /package/{packages/sdk/dist → dist}/crypto-babyjub.js +0 -0
  93. /package/{packages/sdk/dist → dist}/crypto.d.ts +0 -0
  94. /package/{packages/sdk/dist → dist}/crypto.js +0 -0
  95. /package/{packages/sdk/dist → dist}/event-client.d.ts +0 -0
  96. /package/{packages/sdk/dist → dist}/event-client.js +0 -0
  97. /package/{packages/sdk/dist → dist}/events.d.ts +0 -0
  98. /package/{packages/sdk/dist → dist}/events.js +0 -0
  99. /package/{packages/sdk/dist → dist}/explorer.d.ts +0 -0
  100. /package/{packages/sdk/dist → dist}/explorer.js +0 -0
  101. /package/{packages/sdk/dist → dist}/keys.d.ts +0 -0
  102. /package/{packages/sdk/dist → dist}/keys.js +0 -0
  103. /package/{packages/sdk/dist → dist}/logger.d.ts +0 -0
  104. /package/{packages/sdk/dist → dist}/logger.js +0 -0
  105. /package/{packages/sdk/dist → dist}/magicblock.d.ts +0 -0
  106. /package/{packages/sdk/dist → dist}/magicblock.js +0 -0
  107. /package/{packages/sdk/dist → dist}/merkle.d.ts +0 -0
  108. /package/{packages/sdk/dist → dist}/merkle.js +0 -0
  109. /package/{packages/sdk/dist → dist}/note.d.ts +0 -0
  110. /package/{packages/sdk/dist → dist}/note.js +0 -0
  111. /package/{packages/sdk/dist → dist}/pda.d.ts +0 -0
  112. /package/{packages/sdk/dist → dist}/pda.js +0 -0
  113. /package/{packages/sdk/dist → dist}/pool-state.d.ts +0 -0
  114. /package/{packages/sdk/dist → dist}/pool-state.js +0 -0
  115. /package/{packages/sdk/dist → dist}/poseidon.d.ts +0 -0
  116. /package/{packages/sdk/dist → dist}/poseidon.js +0 -0
  117. /package/{packages/sdk/dist → dist}/prover/index.d.ts +0 -0
  118. /package/{packages/sdk/dist → dist}/prover/index.js +0 -0
  119. /package/{packages/sdk/dist → dist}/prover/mobile.d.ts +0 -0
  120. /package/{packages/sdk/dist → dist}/prover/mobile.js +0 -0
  121. /package/{packages/sdk/dist → dist}/prover/web.d.ts +0 -0
  122. /package/{packages/sdk/dist → dist}/prover/web.js +0 -0
  123. /package/{packages/sdk/dist → dist}/psbt.d.ts +0 -0
  124. /package/{packages/sdk/dist → dist}/psbt.js +0 -0
  125. /package/{packages/sdk/dist → dist}/selective-disclosure.d.ts +0 -0
  126. /package/{packages/sdk/dist → dist}/selective-disclosure.js +0 -0
  127. /package/{packages/sdk/dist → dist}/sender-memo.d.ts +0 -0
  128. /package/{packages/sdk/dist → dist}/sender-memo.js +0 -0
  129. /package/{packages/sdk/dist → dist}/sns-resolver.d.ts +0 -0
  130. /package/{packages/sdk/dist → dist}/sns-resolver.js +0 -0
  131. /package/{packages/sdk/dist → dist}/solana/connection.d.ts +0 -0
  132. /package/{packages/sdk/dist → dist}/solana/connection.js +0 -0
  133. /package/{packages/sdk/dist → dist}/solana/priority-fee.d.ts +0 -0
  134. /package/{packages/sdk/dist → dist}/solana/priority-fee.js +0 -0
  135. /package/{packages/sdk/dist → dist}/spend-doc.d.ts +0 -0
  136. /package/{packages/sdk/dist → dist}/spend-doc.js +0 -0
  137. /package/{packages/sdk/dist → dist}/token-registry.d.ts +0 -0
  138. /package/{packages/sdk/dist → dist}/token-registry.js +0 -0
  139. /package/{packages/sdk/dist → dist}/utils/encoding.d.ts +0 -0
  140. /package/{packages/sdk/dist → dist}/utils/encoding.js +0 -0
  141. /package/{packages/sdk/dist → dist}/vk-registry.d.ts +0 -0
  142. /package/{packages/sdk/dist → dist}/vk-registry.js +0 -0
package/src/config.ts ADDED
@@ -0,0 +1,772 @@
1
+ /**
2
+ * UTXOPIA SDK Configuration
3
+ *
4
+ * Centralized configuration for all network-specific addresses, endpoints, and settings.
5
+ * This is the SINGLE SOURCE OF TRUTH for all on-chain addresses and configuration.
6
+ *
7
+ * When deploying to a new network or updating addresses:
8
+ * 1. Update the relevant network config below
9
+ * 2. Bump SDK version
10
+ * 3. Publish to npm
11
+ *
12
+ * @module config
13
+ */
14
+
15
+ import { address as _address, getAddressEncoder, getAddressDecoder, getProgramDerivedAddress, type Address } from "@solana/kit";
16
+
17
+ /**
18
+ * Safe address wrapper — catches codec validation errors that occur during
19
+ * Vercel's build phase when @solana/kit validates byte lengths at module load.
20
+ * Returns the input string cast as Address on failure (safe for config objects
21
+ * that are only used at runtime, not build time).
22
+ */
23
+ export function address(input: string): Address {
24
+ try {
25
+ return _address(input);
26
+ } catch {
27
+ console.warn(`[utxopia-sdk] address() failed for "${input.slice(0, 12)}..." — returning raw string (build-time fallback)`);
28
+ return input as Address;
29
+ }
30
+ }
31
+
32
+ // =============================================================================
33
+ // Network Types
34
+ // =============================================================================
35
+
36
+ export type NetworkType = "devnet" | "mainnet" | "localnet";
37
+ export type AppNetworkId =
38
+ | NetworkType
39
+ | "devnet-regtest"
40
+ | "devnet-testnet4";
41
+
42
+ export interface NetworkConfig {
43
+ /** Network identifier */
44
+ network: NetworkType;
45
+
46
+ // -------------------------------------------------------------------------
47
+ // Program IDs
48
+ // -------------------------------------------------------------------------
49
+
50
+ /** UTXOpia main program ID */
51
+ utxopiaProgramId: Address;
52
+
53
+ /** Minimal PER PolicyApproval coprocessor. Falls back to the asset program on older networks. */
54
+ policyProgramId?: Address;
55
+
56
+ /** BTC Light Client program ID (manages light client + block headers for SPV) */
57
+ btcLightClientProgramId: Address;
58
+
59
+ /** ChadBuffer program ID (for SPV verification) */
60
+ chadbufferProgramId: Address;
61
+
62
+ /** Token-2022 program ID */
63
+ token2022ProgramId: Address;
64
+
65
+ /** Associated Token Account program ID */
66
+ ataProgramId: Address;
67
+
68
+ // -------------------------------------------------------------------------
69
+ // Deployed Accounts (PDAs and Mints)
70
+ // -------------------------------------------------------------------------
71
+
72
+ /** Pool State PDA address */
73
+ poolStatePda: Address;
74
+
75
+ /** Commitment Tree PDA address */
76
+ commitmentTreePda: Address;
77
+
78
+ /** zkBTC Mint address (Token-2022) */
79
+ zkbtcMint: Address;
80
+
81
+ /** Pool Vault (ATA for pool holding zkBTC) */
82
+ poolVault: Address;
83
+
84
+ // -------------------------------------------------------------------------
85
+ // RPC Endpoints
86
+ // -------------------------------------------------------------------------
87
+
88
+ /** Solana RPC endpoint */
89
+ solanaRpcUrl: string;
90
+
91
+ /** Solana WebSocket endpoint */
92
+ solanaWsUrl: string;
93
+
94
+ // -------------------------------------------------------------------------
95
+ // Bitcoin Network
96
+ // -------------------------------------------------------------------------
97
+
98
+ /** Bitcoin network */
99
+ bitcoinNetwork: "mainnet" | "testnet" | "testnet4" | "signet" | "regtest";
100
+
101
+ /** Esplora API endpoint */
102
+ esploraUrl: string;
103
+
104
+ // -------------------------------------------------------------------------
105
+ // Circuit CDN
106
+ // -------------------------------------------------------------------------
107
+
108
+ /** Base URL for circuit artifacts */
109
+ circuitCdnUrl: string;
110
+
111
+ // -------------------------------------------------------------------------
112
+ // Groth16 Verifier (Client-side ZK)
113
+ // -------------------------------------------------------------------------
114
+
115
+ /** Groth16 verifier program ID (browser proof generation via snarkjs) */
116
+ groth16VerifierProgramId: Address;
117
+
118
+ // -------------------------------------------------------------------------
119
+ // VK Hashes (for CPI verification)
120
+ // -------------------------------------------------------------------------
121
+
122
+ /** VK hashes for each circuit type (32 bytes each, hex-encoded) */
123
+ vkHashes: {
124
+ claim: string;
125
+ split: string;
126
+ spendPartialPublic: string;
127
+ };
128
+
129
+ /** VK hashes for JoinSplit variants, keyed by "NxM" (e.g., "1x2" -> "abc...") */
130
+ joinSplitVkHashes: Record<string, string>;
131
+
132
+ // -------------------------------------------------------------------------
133
+ // Pool Keys
134
+ // -------------------------------------------------------------------------
135
+
136
+ /** Ika dWallet x-only secp256k1 pubkey (hex, 64 chars = 32 bytes).
137
+ * The sole Taproot internal key for deposit-address derivation. Read from
138
+ * `pool_config.ika_dwallet_xonly_pubkey` (offset 68..100) on chain. All-zero
139
+ * indicates the pool's PoolConfig has not been initialized yet. */
140
+ ikaDwalletXOnlyPubkey: string;
141
+
142
+ /** BTC deposit custody mode.
143
+ * "sweep" keeps legacy per-deposit tweaked Taproot addresses.
144
+ * "direct" sends deposits directly to the Ika raw x-only vault address. */
145
+ depositMode?: "sweep" | "direct" | "direct_vault" | "ika_direct";
146
+
147
+ // -------------------------------------------------------------------------
148
+ // SNS Subdomain Resolution (stealth address via .sol names)
149
+ // -------------------------------------------------------------------------
150
+
151
+ /** SPL Name Service program ID (stores name records / PDAs) */
152
+ snsNameServiceProgramId: string;
153
+
154
+ /** SNS Registrar program ID (for domain registration) */
155
+ snsRegistrarProgramId: string;
156
+
157
+ /** SNS Sub-Registrar program ID (for subdomain registration) */
158
+ snsSubRegistrarProgramId: string;
159
+
160
+ /** SNS root domain account (.sol TLD — differs per network) */
161
+ snsRootDomain: string;
162
+
163
+ /** Parent domain for stealth address subdomains (e.g., "utxopia" for *.utxopia.sol) */
164
+ snsParentDomain: string;
165
+
166
+ /** SNS reverse lookup class key (used for reverse name resolution) */
167
+ snsReverseLookupClass: string;
168
+
169
+ /** Stealth data version expected in SNS records */
170
+ snsStealthDataVersion: number;
171
+ }
172
+
173
+ // =============================================================================
174
+ // Program IDs (Constants)
175
+ // =============================================================================
176
+
177
+ /** Legacy Token Program ID */
178
+ export const TOKEN_PROGRAM_ID: Address = address(
179
+ "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"
180
+ );
181
+
182
+ /** Token-2022 Program ID */
183
+ export const TOKEN_2022_PROGRAM_ID: Address = address(
184
+ "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb"
185
+ );
186
+
187
+ /** Associated Token Account Program ID */
188
+ export const ATA_PROGRAM_ID: Address = address(
189
+ "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL"
190
+ );
191
+
192
+ /** ChadBuffer Program ID (deployed to devnet 2025-01-30) */
193
+ export const CHADBUFFER_PROGRAM_ID: Address = address(
194
+ "C5RpjtTMFXKVZCtXSzKXD4CDNTaWBg3dVeMfYvjZYHDF"
195
+ );
196
+
197
+ /** ChadBuffer Program ID for localnet testing */
198
+ export const LOCALNET_CHADBUFFER_PROGRAM_ID: Address = address(
199
+ "EgWyMVFZewHmjJ9GGvVBTyaC376Xp7qu7CAFjWYPYYDv"
200
+ );
201
+
202
+ // =============================================================================
203
+ // Network Configurations
204
+ // =============================================================================
205
+
206
+ /**
207
+ * Greenfield devnet + Bitcoin testnet4 deployment (2026-08-26).
208
+ *
209
+ * The previous deployment's programs were closed on chain, so this is not a redeploy and none
210
+ * of the old addresses resolve any more — anything still pinned to CvfSyACR… is talking to a
211
+ * program that no longer exists.
212
+ *
213
+ * Two pools were deployed, each with its own Ika DKG and therefore its own dWallet. The default
214
+ * below is the OPEN pool. Select the verified pool by overriding `zkbtcMint` and
215
+ * `ikaDwalletXOnlyPubkey` — `getConfig` re-derives poolStatePda, commitmentTreePda and poolVault
216
+ * from the mint, so those two values are all a caller needs:
217
+ *
218
+ * verified mint G78CTddWGDaNaSKQayAt7m3pzcMyaUNxgR8y3R34YvEv
219
+ * state Eqn9SmFYtacrdfPE9Shbi8bDXLjCNNz3WhHfqtJnwbKY
220
+ * xonly 16c563baa11bfc8fe93acafe8fe169b954b3ead3ecda7754c615dec9e840b5a5
221
+ *
222
+ * Read off chain, not from the deploy notes: Eqn9SmFY… is the pool whose PoolState flags carry
223
+ * the permissioned bit (0b10 at offset 2). The deployment also contains a THIRD pool —
224
+ * 3chHiDqM… / 7wDtDd1u… — which the deploy notes name as the verified one but which is not
225
+ * permissioned and whose mint has zero supply. Treat it as abandoned; do not wire it up.
226
+ */
227
+ export const DEVNET_CONFIG: NetworkConfig = {
228
+ network: "devnet",
229
+
230
+ utxopiaProgramId: address("28z2AtKA6aFGrGCh4ns1rmp7vGpWuh6x3H7gXKBcfxur"),
231
+ policyProgramId: address("9asWYKVriWGpExW5xM44ChHjZtispkLCiWKkM8SQi8Rs"),
232
+ // testnet4 light client, deployed 2026-08-26. Must match the `devnet` arm of
233
+ // BTC_LIGHT_CLIENT_PROGRAM_ID in programs/utxopia/src/constants.rs.
234
+ btcLightClientProgramId: address("4LZbktiNsiVAe2bwPCTPNgqiWWgZNUj4T3bDx8GZmehv"),
235
+ chadbufferProgramId: CHADBUFFER_PROGRAM_ID,
236
+ token2022ProgramId: TOKEN_2022_PROGRAM_ID,
237
+ ataProgramId: ATA_PROGRAM_ID,
238
+
239
+ // Open pool. Derived and then confirmed on chain: pool_state and commitment_tree are owned by
240
+ // the program (332 / 8816 bytes), the vault by Token-2022 (170 bytes).
241
+ poolStatePda: address("FezM7ksBwftqrd4TtabMa9uXt51eCT5M946YnpSEQZHm"),
242
+ commitmentTreePda: address("CHwJZqNAUag6ARDfmntvmbS4WeAsGX67f2vALxXbB6PP"),
243
+ zkbtcMint: address("87zWstDnNgMig2vk8q8jTrK6YTcyugeRTanfT3LfyU3T"),
244
+ poolVault: address("8VMfH4mDizU6nHybQumxeauyiEL2QTqrGQLXmAr9wpC3"),
245
+
246
+ // RPC Endpoints
247
+ solanaRpcUrl: "https://api.devnet.solana.com",
248
+ solanaWsUrl: "wss://api.devnet.solana.com",
249
+
250
+ // Bitcoin Network
251
+ bitcoinNetwork: "testnet4",
252
+ esploraUrl: "https://mempool.space/testnet4/api",
253
+
254
+ // Circuit CDN (Groth16 artifacts: .wasm, .zkey files)
255
+ circuitCdnUrl: "https://circuit.utxopia.com/circuits/v2/groth16",
256
+
257
+ // Groth16 verification is inline in the UTXOpia program, so this is the same address.
258
+ // It used to hold a stale third id, which `getConfig` silently overwrote with the program id
259
+ // whenever a programId override was supplied — meaning the constant was only ever read on the
260
+ // no-override path, where it was wrong.
261
+ groth16VerifierProgramId: address("28z2AtKA6aFGrGCh4ns1rmp7vGpWuh6x3H7gXKBcfxur"),
262
+
263
+ // VK Hashes (SHA256 of serialized VK bytes, generated from circom trusted setup)
264
+ vkHashes: {
265
+ claim: "7af0e702e7b595fbdb62fd268e6c529481003e07957e0f60e4fb23cd9fe6a77f",
266
+ split: "00fb9e4c3fcc7b99fec5191370b516537f74831ad868a18c4ab2d519f332cc4f",
267
+ spendPartialPublic: "732126aaec8355efdfb1b96aee1c9014506c99815a81057edbefd775b1b10663",
268
+ },
269
+
270
+ // JoinSplit VK hashes (populated after trusted setup for new circuits)
271
+ joinSplitVkHashes: {
272
+ "1x1": "745d536fb3a86424ee9560cb7b630bb0eb3d3c3af06c85bcda1eb7bcc5b1a07a",
273
+ "1x2": "f782d4bc2f696417688cdec3cb4f822d6961892192e13e8842505bd8d119fa6d",
274
+ "2x1": "3af6cdad3c1f4de9e088975a1ac5b20e0445d7f3fea0a5038f300102cf98fd98",
275
+ "2x2": "6fffc4962028d0ac69f4d7877badc9f5adea4b83e6224ebb8db22657e847e7b8",
276
+ "1x3": "ca396f36bbd1b07255b7a2f5585cedb4a51f925149747dd6ab4f695d19aa6ff8",
277
+ "3x1": "4e0c5cbea0ccf80302d2589e41a2f22e19287f5acc5d0577451680fd909e1942",
278
+ "2x3": "bf398583f064de96560cb9092b1357b0d742991a88f18a351e5b8793fed4b7a7",
279
+ "3x2": "9da8d33d57896e76aadf3f5c66295774bd3273511af6e733ca7f9446ab58d42e",
280
+ "1x4": "01728b82e810a8ba604cc66aa6a563444d18f4598c402d11767d0a7e5049a9be",
281
+ "4x1": "0362b306b17dae916d836d9448a26c97e51b1b0a1a0ed052ebfbd4800e5000cf",
282
+ },
283
+
284
+ // Ika dWallet x-only pubkey for the OPEN pool, read from its PoolConfig PDA
285
+ // (GQ5ZfD4tJmgcquHLAHSbmAm72Foi9hf3VduPrroysM1b, offset 68..100) on 2026-08-26.
286
+ // All-zero here used to mean "deposit addresses cannot be derived until sync-env.sh runs";
287
+ // the two pools have distinct dWallets, so a single synced value could only ever be right
288
+ // for one of them. See the verified pool's key in the header comment above.
289
+ ikaDwalletXOnlyPubkey:
290
+ "3a6ab80ba14bc050f048ee3e0b77d8935adf4fc5e2f5947311f26cc2cb5bd194",
291
+
292
+ // SNS Subdomain Resolution (devnet)
293
+ snsNameServiceProgramId: "namesLPneVptA9Z5rqUDD9tMTWEJwofgaYwp8cawRkX", // SPL Name Service (devnet)
294
+ snsRegistrarProgramId: "snshBoEQ9jx4QoHBpZDQPYdNCtw7RMxJvYrKFEhwaPJ", // SNS Registrar (devnet)
295
+ snsSubRegistrarProgramId: "31tT5CmpphAtRL3mstu962zeYH7C6TEkJWLB5nYxciBB", // Sub-Registrar (devnet)
296
+ snsRootDomain: "5eoDkP6vCQBXqDV9YN2NdUs3nmML3dMRNmEYpiyVNBm2", // .sol TLD (devnet)
297
+ snsParentDomain: "utxopia",
298
+ snsReverseLookupClass: "7NbD1vprif6apthEZAqhRfYuhrqnuderB8qpnfXGCc8H", // Reverse lookup class (devnet)
299
+ snsStealthDataVersion: 1,
300
+ };
301
+
302
+ /**
303
+ * Solana devnet + Bitcoin **regtest** deployment — the environment app.utxopia.com serves.
304
+ *
305
+ * This is a different deployment from DEVNET_CONFIG above, not a Bitcoin-side variation of it:
306
+ * a different program (CvfSyACR…), a different pool, a different Ika dWallet. It used to share
307
+ * DEVNET_CONFIG and differ only by bitcoinNetwork, which worked while one program hosted both.
308
+ * It no longer does — after 2026-08-26 there are two programs — so `devnet-regtest` resolving
309
+ * to DEVNET_CONFIG would silently point this environment at testnet4's program and pool.
310
+ *
311
+ * Pool addresses derived from the mint with the same seeds getConfig uses, then confirmed on
312
+ * devnet: pool_state and commitment_tree owned by CvfSyACR… at 332 and 8816 bytes, the vault by
313
+ * Token-2022 at 170.
314
+ */
315
+ export const DEVNET_REGTEST_CONFIG: NetworkConfig = {
316
+ ...DEVNET_CONFIG,
317
+
318
+ utxopiaProgramId: address("CvfSyACR8xemPdeJsB3D8Xh15rKUQ3b5c1PvnmABCBJp"),
319
+ groth16VerifierProgramId: address("CvfSyACR8xemPdeJsB3D8Xh15rKUQ3b5c1PvnmABCBJp"),
320
+ btcLightClientProgramId: address("8hCSNKf8ByqZdet2D4SDiZHDrB1u9ohkhqKKzr9i7vfQ"),
321
+
322
+ poolStatePda: address("CeEEmE9MvFPZtqcgv1rsXmzNmfvchbs8VEZJGFKZ2Cyj"),
323
+ commitmentTreePda: address("45bCw97GssorJM9b1ZWZLMGy1NJUczcaNVaKASmCRohL"),
324
+ zkbtcMint: address("BJ5SXA33qK8r8BxJD4nQPf72ae9bactiA2Zqo33EcvPu"),
325
+ poolVault: address("JsZ1ipHZWiZYE8kRDXmEkKuiK6KKVxCVJKv1tGnCkM6"),
326
+
327
+ ikaDwalletXOnlyPubkey:
328
+ "243a6c47504f82d168754da9392a9dbcbab9b9f9c515a609227fac4642b2a26f",
329
+
330
+ bitcoinNetwork: "regtest",
331
+ esploraUrl: "http://localhost:2140",
332
+ };
333
+
334
+ /**
335
+ * Mainnet Configuration (placeholder - not yet deployed)
336
+ */
337
+ export const MAINNET_CONFIG: NetworkConfig = {
338
+ network: "mainnet",
339
+
340
+ // Program IDs (placeholder - update when deployed)
341
+ utxopiaProgramId: address("11111111111111111111111111111111"),
342
+ btcLightClientProgramId: address("11111111111111111111111111111111"),
343
+ chadbufferProgramId: CHADBUFFER_PROGRAM_ID,
344
+ token2022ProgramId: TOKEN_2022_PROGRAM_ID,
345
+ ataProgramId: ATA_PROGRAM_ID,
346
+
347
+ // Deployed Accounts (placeholder - update when deployed)
348
+ poolStatePda: address("11111111111111111111111111111111"),
349
+ commitmentTreePda: address("11111111111111111111111111111111"),
350
+ zkbtcMint: address("11111111111111111111111111111111"),
351
+ poolVault: address("11111111111111111111111111111111"),
352
+
353
+ // RPC Endpoints
354
+ solanaRpcUrl: "https://api.mainnet-beta.solana.com",
355
+ solanaWsUrl: "wss://api.mainnet-beta.solana.com",
356
+
357
+ // Bitcoin Network
358
+ bitcoinNetwork: "mainnet",
359
+ esploraUrl: "https://mempool.space/api",
360
+
361
+ // Circuit CDN
362
+ circuitCdnUrl: "https://circuit.utxopia.com",
363
+
364
+ // Groth16 Verifier (placeholder)
365
+ groth16VerifierProgramId: address("11111111111111111111111111111111"),
366
+
367
+ // VK Hashes (placeholder - update when deployed)
368
+ vkHashes: {
369
+ claim: "0000000000000000000000000000000000000000000000000000000000000000",
370
+ split: "0000000000000000000000000000000000000000000000000000000000000000",
371
+ spendPartialPublic: "171daac7e5ff45e2d0e736ac0d28f5fe8e0cc8fc9961efa4dd9ee18e4413f755",
372
+ },
373
+
374
+ joinSplitVkHashes: {},
375
+
376
+ ikaDwalletXOnlyPubkey:
377
+ "0000000000000000000000000000000000000000000000000000000000000000",
378
+
379
+ // SNS Subdomain Resolution (mainnet)
380
+ snsNameServiceProgramId: "namesLPneVptA9Z5rqUDD9tMTWEJwofgaYwp8cawRkX", // SPL Name Service (mainnet)
381
+ snsRegistrarProgramId: "jCebN34bUfdeUYJT13J1yG16XWQpt5PDx6Mse9GUqhR", // SNS Registrar (mainnet)
382
+ snsSubRegistrarProgramId: "2KkyPzjaAYaz2ojQZ9P3xYakLd96B5UH6a2isLaZ4Cgs", // Sub-Registrar (mainnet)
383
+ snsRootDomain: "58PwtjSDuFHuUkYjH9BYod9SZaELfsvdrNMryy9iYNvo", // .sol TLD (mainnet)
384
+ snsParentDomain: "utxopia",
385
+ snsReverseLookupClass: "33m47vH6Eav6jr5Ry86XjhRft2jRBLDnDgPSHoquXi2Z", // Reverse lookup class (mainnet)
386
+ snsStealthDataVersion: 1,
387
+ };
388
+
389
+ /**
390
+ * Localnet Configuration (for local development)
391
+ * Synced with .localnet-config.json (2026-02-22)
392
+ */
393
+ export const LOCALNET_CONFIG: NetworkConfig = {
394
+ network: "localnet",
395
+
396
+ // Program IDs
397
+ utxopiaProgramId: address("2dBmKyfLibkqdxgyEWUhHos3g56oU2wXLVrucY2dCpGV"),
398
+ btcLightClientProgramId: address("Ho6UTeF8yFnRdCK15tSZtcJozvkDABJZWYxkgGyWAfyq"),
399
+ chadbufferProgramId: LOCALNET_CHADBUFFER_PROGRAM_ID,
400
+ token2022ProgramId: TOKEN_2022_PROGRAM_ID,
401
+ ataProgramId: ATA_PROGRAM_ID,
402
+
403
+ // Deployed Accounts (synced with .localnet-config.json 2026-02-23)
404
+ poolStatePda: address("E6DVestxC5dn5ixvLa3FcYodcVtwUAyanpVPbs4y3p16"),
405
+ commitmentTreePda: address("JCiGqC1a1rjfqk2dqcybU2e3FQjAQ19x8ts9fQCtTFCq"),
406
+ zkbtcMint: address("CHg1f85uxw4HrVkj3ianLezVAJTv29VcCWiBxjZ4YFdF"),
407
+ poolVault: address("7vpuYKngG75Km1bbZ5TZJZzRn2BBtkh9BaqPS814tPLg"),
408
+
409
+ // RPC Endpoints
410
+ solanaRpcUrl: "http://127.0.0.1:8899",
411
+ solanaWsUrl: "ws://127.0.0.1:8900",
412
+
413
+ // Bitcoin Network (regtest for local dev)
414
+ bitcoinNetwork: "regtest",
415
+ esploraUrl: "http://localhost:2140",
416
+
417
+ // Circuit CDN (use local files for development)
418
+ circuitCdnUrl: "/circuits",
419
+
420
+ // Groth16 Verifier: verification is inline in the UTXOpia program
421
+ groth16VerifierProgramId: address("RoqAPQgZ5ztdhV3jHBKgTmeLBAfyYcaBsjKiXHNwXf3"),
422
+
423
+ // VK Hashes (same as devnet - generated from same trusted setup)
424
+ vkHashes: {
425
+ claim: "7af0e702e7b595fbdb62fd268e6c529481003e07957e0f60e4fb23cd9fe6a77f",
426
+ split: "00fb9e4c3fcc7b99fec5191370b516537f74831ad868a18c4ab2d519f332cc4f",
427
+ spendPartialPublic: "732126aaec8355efdfb1b96aee1c9014506c99815a81057edbefd775b1b10663",
428
+ },
429
+
430
+ joinSplitVkHashes: {
431
+ "1x1": "745d536fb3a86424ee9560cb7b630bb0eb3d3c3af06c85bcda1eb7bcc5b1a07a",
432
+ "1x2": "f782d4bc2f696417688cdec3cb4f822d6961892192e13e8842505bd8d119fa6d",
433
+ "2x1": "3af6cdad3c1f4de9e088975a1ac5b20e0445d7f3fea0a5038f300102cf98fd98",
434
+ "2x2": "6fffc4962028d0ac69f4d7877badc9f5adea4b83e6224ebb8db22657e847e7b8",
435
+ },
436
+
437
+ // Ika dWallet x-only pubkey — populated by ./scripts/sync-env.sh from localnet-state.json.
438
+ ikaDwalletXOnlyPubkey:
439
+ "0000000000000000000000000000000000000000000000000000000000000000",
440
+
441
+ // SNS Subdomain Resolution (not available on localnet)
442
+ snsNameServiceProgramId: "",
443
+ snsRegistrarProgramId: "",
444
+ snsSubRegistrarProgramId: "",
445
+ snsRootDomain: "",
446
+ snsParentDomain: "",
447
+ snsReverseLookupClass: "",
448
+ snsStealthDataVersion: 1,
449
+ };
450
+
451
+ // =============================================================================
452
+ // Default Configuration
453
+ // =============================================================================
454
+
455
+ /** Current active configuration (defaults to devnet, overridden by env vars) */
456
+ let currentConfig: NetworkConfig = DEVNET_CONFIG;
457
+
458
+ // Eagerly apply env var overrides synchronously (program ID + mint only).
459
+ // PDA derivation happens async in initConfig(), but at least getConfig()
460
+ // returns the correct program ID immediately.
461
+ if (typeof process !== "undefined") {
462
+ const _pid = process.env?.NEXT_PUBLIC_UTXOPIA_PROGRAM_ID || process.env?.UTXOPIA_PROGRAM_ID;
463
+ const _mint = process.env?.NEXT_PUBLIC_ZKBTC_MINT || process.env?.UTXOPIA_ZKBTC_MINT;
464
+ if (_pid) {
465
+ currentConfig = { ...currentConfig, utxopiaProgramId: address(_pid), groth16VerifierProgramId: address(_pid) };
466
+ }
467
+ if (_mint) {
468
+ currentConfig = { ...currentConfig, zkbtcMint: address(_mint) };
469
+ }
470
+ }
471
+
472
+ /** Esplora URL for a given Bitcoin network */
473
+ function esploraUrlForNetwork(net: string): string {
474
+ switch (net) {
475
+ case "mainnet": return "https://mempool.space/api";
476
+ case "testnet": return "https://mempool.space/testnet/api";
477
+ case "testnet4": return "https://mempool.space/testnet4/api";
478
+ case "signet": return "https://mempool.space/signet/api";
479
+ case "regtest": return "http://localhost:2140";
480
+ default: return `https://mempool.space/${net}/api`;
481
+ }
482
+ }
483
+
484
+ /**
485
+ * Base config for an app network id. Two devnet deployments now exist, so this cannot be
486
+ * derived from NetworkType alone — that is what normalizeAppNetwork collapses away.
487
+ */
488
+ function baseConfigForAppNetwork(network?: string): NetworkConfig {
489
+ switch (network) {
490
+ case "localnet":
491
+ return LOCALNET_CONFIG;
492
+ case "mainnet":
493
+ return MAINNET_CONFIG;
494
+ case "devnet-regtest":
495
+ return DEVNET_REGTEST_CONFIG;
496
+ case "devnet-testnet4":
497
+ case "devnet":
498
+ default:
499
+ return DEVNET_CONFIG;
500
+ }
501
+ }
502
+
503
+ function normalizeAppNetwork(network?: string): NetworkType {
504
+ switch (network) {
505
+ case "mainnet":
506
+ return "mainnet";
507
+ case "localnet":
508
+ return "localnet";
509
+ case "devnet":
510
+ case "devnet-regtest":
511
+ case "devnet-testnet4":
512
+ default:
513
+ return "devnet";
514
+ }
515
+ }
516
+
517
+ function bitcoinNetworkForAppNetwork(network?: string): NetworkConfig["bitcoinNetwork"] | undefined {
518
+ switch (network) {
519
+ case "localnet":
520
+ case "devnet-regtest":
521
+ return "regtest";
522
+ case "devnet":
523
+ case "devnet-testnet4":
524
+ return "testnet4";
525
+ case "mainnet":
526
+ return "mainnet";
527
+ default:
528
+ return undefined;
529
+ }
530
+ }
531
+
532
+ /**
533
+ * Get the current network configuration.
534
+ * Respects NEXT_PUBLIC_BTC_NETWORK env var to override Bitcoin network
535
+ * (e.g., "testnet" for testnet3, "testnet4" for testnet4).
536
+ */
537
+ export function getConfig(): NetworkConfig {
538
+ const btcNetOverride =
539
+ typeof process !== "undefined" && process.env?.NEXT_PUBLIC_BTC_NETWORK;
540
+ if (btcNetOverride && btcNetOverride !== currentConfig.bitcoinNetwork) {
541
+ return {
542
+ ...currentConfig,
543
+ bitcoinNetwork: btcNetOverride as NetworkConfig["bitcoinNetwork"],
544
+ esploraUrl: esploraUrlForNetwork(btcNetOverride),
545
+ };
546
+ }
547
+ return currentConfig;
548
+ }
549
+
550
+ /**
551
+ * Set the network configuration
552
+ *
553
+ * @param network - Network type or custom config
554
+ * @throws Error if mainnet is selected (not yet deployed)
555
+ */
556
+ export function setConfig(network: AppNetworkId | NetworkConfig): void {
557
+ if (typeof network === "string") {
558
+ const baseNetwork = normalizeAppNetwork(network);
559
+ switch (baseNetwork) {
560
+ case "devnet":
561
+ currentConfig = baseConfigForAppNetwork(network);
562
+ break;
563
+ case "mainnet":
564
+ throw new Error(
565
+ "Mainnet is not yet deployed. " +
566
+ "UTXOpia is currently available on devnet only. " +
567
+ "Use setConfig('devnet') or wait for mainnet deployment announcement."
568
+ );
569
+ case "localnet":
570
+ currentConfig = LOCALNET_CONFIG;
571
+ break;
572
+ default:
573
+ throw new Error(`Unknown network: ${network}`);
574
+ }
575
+ const bitcoinNetwork = bitcoinNetworkForAppNetwork(network);
576
+ if (bitcoinNetwork) {
577
+ currentConfig = {
578
+ ...currentConfig,
579
+ bitcoinNetwork,
580
+ esploraUrl: esploraUrlForNetwork(bitcoinNetwork),
581
+ };
582
+ }
583
+ } else {
584
+ // Check if custom config is using placeholder mainnet addresses
585
+ if (network.network === "mainnet" && network.utxopiaProgramId === MAINNET_CONFIG.utxopiaProgramId) {
586
+ throw new Error(
587
+ "Cannot use placeholder mainnet configuration. " +
588
+ "Mainnet is not yet deployed."
589
+ );
590
+ }
591
+ currentConfig = network;
592
+ }
593
+ }
594
+
595
+ /**
596
+ * Create a custom configuration by overriding specific values
597
+ *
598
+ * @param base - Base configuration to extend
599
+ * @param overrides - Values to override
600
+ */
601
+ export function createConfig(
602
+ base: NetworkConfig,
603
+ overrides: Partial<NetworkConfig>
604
+ ): NetworkConfig {
605
+ return { ...base, ...overrides };
606
+ }
607
+
608
+ // =============================================================================
609
+ // Environment-based Initialization
610
+ // =============================================================================
611
+
612
+ /**
613
+ * Initialize SDK configuration with optional overrides.
614
+ *
615
+ * Reads `utxopiaProgramId` and `zkbtcMint` from params, then env vars, then
616
+ * falls back to DEVNET_CONFIG defaults. All PDAs are auto-derived from these
617
+ * two values.
618
+ *
619
+ * Env vars checked (in order):
620
+ * - NEXT_PUBLIC_UTXOPIA_PROGRAM_ID / UTXOPIA_PROGRAM_ID
621
+ * - NEXT_PUBLIC_ZKBTC_MINT / UTXOPIA_ZKBTC_MINT
622
+ *
623
+ * @example
624
+ * // Use env vars (set NEXT_PUBLIC_UTXOPIA_PROGRAM_ID + NEXT_PUBLIC_ZKBTC_MINT)
625
+ * await initConfig();
626
+ *
627
+ * // Or pass explicitly
628
+ * await initConfig({ utxopiaProgramId: "...", zkbtcMint: "..." });
629
+ */
630
+ export type NetworkId = AppNetworkId;
631
+
632
+ export async function initConfig(overrides?: {
633
+ network?: NetworkId;
634
+ utxopiaProgramId?: string;
635
+ policyProgramId?: string;
636
+ zkbtcMint?: string;
637
+ solanaRpcUrl?: string;
638
+ ikaDwalletXOnlyPubkey?: string;
639
+ depositMode?: "sweep" | "direct" | "direct_vault" | "ika_direct";
640
+ }): Promise<NetworkConfig> {
641
+ // Pick base config from network: param > env > devnet
642
+ const appNetworkId: NetworkId =
643
+ overrides?.network ||
644
+ (typeof process !== "undefined" && (process.env?.NEXT_PUBLIC_NETWORK || process.env?.UTXOPIA_NETWORK) as NetworkId) ||
645
+ "devnet";
646
+ const networkId = normalizeAppNetwork(appNetworkId);
647
+
648
+ const baseConfig = baseConfigForAppNetwork(appNetworkId);
649
+
650
+ const config = { ...baseConfig };
651
+ const appBitcoinNetwork = bitcoinNetworkForAppNetwork(appNetworkId);
652
+ const btcNetOverride =
653
+ typeof process !== "undefined" && process.env?.NEXT_PUBLIC_BTC_NETWORK;
654
+ const bitcoinNetwork = btcNetOverride || appBitcoinNetwork;
655
+ if (bitcoinNetwork) {
656
+ config.bitcoinNetwork = bitcoinNetwork as NetworkConfig["bitcoinNetwork"];
657
+ config.esploraUrl = esploraUrlForNetwork(bitcoinNetwork);
658
+ }
659
+
660
+ // Resolve program ID: param > env > base config default
661
+ const programId =
662
+ overrides?.utxopiaProgramId ||
663
+ (typeof process !== "undefined" && (process.env?.NEXT_PUBLIC_UTXOPIA_PROGRAM_ID || process.env?.UTXOPIA_PROGRAM_ID)) ||
664
+ undefined;
665
+ const policyProgramId =
666
+ overrides?.policyProgramId ||
667
+ (typeof process !== "undefined" &&
668
+ (process.env?.NEXT_PUBLIC_UTXOPIA_POLICY_PROGRAM_ID ||
669
+ process.env?.UTXOPIA_POLICY_PROGRAM_ID)) ||
670
+ undefined;
671
+ if (policyProgramId) {
672
+ config.policyProgramId = address(policyProgramId);
673
+ }
674
+
675
+ // Resolve mint: param > env > default
676
+ const mint =
677
+ overrides?.zkbtcMint ||
678
+ (typeof process !== "undefined" && (process.env?.NEXT_PUBLIC_ZKBTC_MINT || process.env?.UTXOPIA_ZKBTC_MINT)) ||
679
+ config.zkbtcMint;
680
+
681
+ // Resolve RPC URL for on-chain fetching
682
+ const rpcUrl =
683
+ overrides?.solanaRpcUrl ||
684
+ (typeof process !== "undefined" && (process.env?.NEXT_PUBLIC_SOLANA_RPC_URL || process.env?.UTXOPIA_SOLANA_RPC)) ||
685
+ undefined;
686
+
687
+ if (programId) {
688
+ config.utxopiaProgramId = address(programId);
689
+ config.groth16VerifierProgramId = address(programId); // same program
690
+
691
+ // Fresh multi-pool deployments use zkBTC mint as the pool namespace.
692
+ const encoder = getAddressEncoder();
693
+ config.zkbtcMint = address(mint);
694
+ const [poolStatePda] = await getProgramDerivedAddress({
695
+ programAddress: config.utxopiaProgramId,
696
+ seeds: [
697
+ new TextEncoder().encode("pool_state"),
698
+ encoder.encode(config.zkbtcMint),
699
+ ],
700
+ });
701
+ const treeIndex = new Uint8Array(4);
702
+ const [commitmentTreePda] = await getProgramDerivedAddress({
703
+ programAddress: config.utxopiaProgramId,
704
+ seeds: [
705
+ new TextEncoder().encode("commitment_tree"),
706
+ encoder.encode(poolStatePda),
707
+ treeIndex,
708
+ ],
709
+ });
710
+ config.poolStatePda = poolStatePda;
711
+ config.commitmentTreePda = commitmentTreePda;
712
+ }
713
+
714
+ if (mint) {
715
+ config.zkbtcMint = address(mint);
716
+
717
+ // Derive pool vault (ATA: seeds = [owner, TOKEN_2022, mint] under ATA program)
718
+ const encoder = getAddressEncoder();
719
+ const [poolVault] = await getProgramDerivedAddress({
720
+ programAddress: config.ataProgramId,
721
+ seeds: [
722
+ encoder.encode(config.poolStatePda),
723
+ encoder.encode(config.token2022ProgramId),
724
+ encoder.encode(config.zkbtcMint),
725
+ ],
726
+ });
727
+ config.poolVault = poolVault;
728
+ }
729
+
730
+ // Apply Ika dWallet x-only pubkey override (sole Taproot custody key)
731
+ if (overrides?.ikaDwalletXOnlyPubkey) {
732
+ config.ikaDwalletXOnlyPubkey = overrides.ikaDwalletXOnlyPubkey;
733
+ }
734
+ if (overrides?.depositMode) {
735
+ config.depositMode = overrides.depositMode;
736
+ }
737
+
738
+ currentConfig = config;
739
+ return config;
740
+ }
741
+
742
+ // =============================================================================
743
+ // Convenience Exports
744
+ // =============================================================================
745
+
746
+ /** Default UTXOpia program ID (from current config) */
747
+ export const UTXOPIA_PROGRAM_ID: Address = DEVNET_CONFIG.utxopiaProgramId;
748
+ export const UTXOPIA_POLICY_PROGRAM_ID: Address =
749
+ DEVNET_CONFIG.policyProgramId ?? DEVNET_CONFIG.utxopiaProgramId;
750
+
751
+ /** BTC Light Client program ID (manages light client + block headers) */
752
+ export const BTC_LIGHT_CLIENT_PROGRAM_ID: Address = DEVNET_CONFIG.btcLightClientProgramId;
753
+
754
+ // =============================================================================
755
+ // Version Info
756
+ // =============================================================================
757
+
758
+ export const SDK_VERSION = "3.3.0";
759
+
760
+ /** JoinSplit Merkle tree depth */
761
+ export const JOINSPLIT_TREE_DEPTH = 16;
762
+
763
+ export const DEPLOYMENT_INFO = {
764
+ version: SDK_VERSION,
765
+ deployedAt: "2026-03-03",
766
+ network: "devnet" as NetworkType,
767
+ features: [
768
+ "stealth-addresses",
769
+ "groth16-browser-proving",
770
+ ],
771
+ notes: "Client-side Groth16 proof generation via snarkjs",
772
+ };