@utxopia/sdk 0.1.0-alpha.1 → 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}/config.d.ts +34 -3
  5. package/{packages/sdk/dist → dist}/config.js +88 -18
  6. package/{packages/sdk/dist → dist}/crypto-ed25519.d.ts +14 -0
  7. package/{packages/sdk/dist → dist}/crypto-ed25519.js +14 -0
  8. package/{packages/sdk/dist → dist}/index.d.ts +5 -4
  9. package/{packages/sdk/dist → dist}/index.js +5 -4
  10. package/{packages/sdk/dist → dist}/instructions.d.ts +88 -1
  11. package/{packages/sdk/dist → dist}/instructions.js +104 -3
  12. package/dist/spend-doc.d.ts +63 -0
  13. package/dist/spend-doc.js +100 -0
  14. package/{packages/sdk/dist → dist}/stealth.d.ts +124 -1
  15. package/{packages/sdk/dist → dist}/stealth.js +172 -4
  16. package/{packages/sdk/dist → dist}/taproot.d.ts +48 -0
  17. package/{packages/sdk/dist → dist}/taproot.js +71 -0
  18. package/package.json +86 -63
  19. package/src/announcement-client.ts +457 -0
  20. package/src/auditor-ciphertext.ts +181 -0
  21. package/src/auditor.ts +409 -0
  22. package/src/bitcoin/ika.ts +103 -0
  23. package/src/bitcoin/index.ts +5 -0
  24. package/src/bound-params.ts +322 -0
  25. package/src/chadbuffer.ts +603 -0
  26. package/src/circomlibjs.d.ts +51 -0
  27. package/src/claim-link.ts +53 -0
  28. package/src/client.ts +638 -0
  29. package/src/commitment-tree.ts +736 -0
  30. package/src/config.ts +772 -0
  31. package/src/core/esplora.ts +332 -0
  32. package/src/core/mempool.ts +159 -0
  33. package/src/crypto-babyjub.ts +385 -0
  34. package/src/crypto-ed25519.ts +297 -0
  35. package/src/crypto.ts +199 -0
  36. package/src/event-client.ts +231 -0
  37. package/src/events.ts +384 -0
  38. package/src/explorer.ts +300 -0
  39. package/src/index.ts +902 -0
  40. package/src/instructions.ts +2820 -0
  41. package/src/keys.ts +1228 -0
  42. package/src/logger.ts +41 -0
  43. package/src/magicblock.ts +278 -0
  44. package/src/merkle.ts +197 -0
  45. package/src/note.ts +754 -0
  46. package/src/pda.ts +516 -0
  47. package/src/pool-state.ts +176 -0
  48. package/src/poseidon.ts +175 -0
  49. package/src/prover/index.ts +19 -0
  50. package/src/prover/mobile.ts +303 -0
  51. package/src/prover/web.ts +771 -0
  52. package/src/psbt.ts +333 -0
  53. package/src/selective-disclosure.ts +284 -0
  54. package/src/sender-memo.ts +343 -0
  55. package/src/snarkjs.d.ts +19 -0
  56. package/src/sns-resolver.ts +333 -0
  57. package/src/solana/connection.ts +189 -0
  58. package/src/solana/priority-fee.ts +201 -0
  59. package/src/spend-doc.ts +163 -0
  60. package/src/stealth.ts +1477 -0
  61. package/src/taproot.ts +707 -0
  62. package/src/token-registry.ts +207 -0
  63. package/src/utils/encoding.ts +33 -0
  64. package/src/vk-registry.ts +295 -0
  65. package/LICENSE +0 -21
  66. package/packages/btc-client/src/esplora-client.ts +0 -153
  67. package/packages/btc-client/src/index.ts +0 -3
  68. package/packages/btc-client/src/op-return.ts +0 -93
  69. package/packages/btc-client/src/types.ts +0 -112
  70. package/packages/sdk/README.md +0 -277
  71. /package/{packages/sdk/dist → dist}/announcement-client.d.ts +0 -0
  72. /package/{packages/sdk/dist → dist}/announcement-client.js +0 -0
  73. /package/{packages/sdk/dist → dist}/auditor-ciphertext.d.ts +0 -0
  74. /package/{packages/sdk/dist → dist}/auditor-ciphertext.js +0 -0
  75. /package/{packages/sdk/dist → dist}/auditor.d.ts +0 -0
  76. /package/{packages/sdk/dist → dist}/auditor.js +0 -0
  77. /package/{packages/sdk/dist → dist}/bitcoin/ika.d.ts +0 -0
  78. /package/{packages/sdk/dist → dist}/bitcoin/ika.js +0 -0
  79. /package/{packages/sdk/dist → dist}/bitcoin/index.d.ts +0 -0
  80. /package/{packages/sdk/dist → dist}/bitcoin/index.js +0 -0
  81. /package/{packages/sdk/dist → dist}/bound-params.d.ts +0 -0
  82. /package/{packages/sdk/dist → dist}/bound-params.js +0 -0
  83. /package/{packages/sdk/dist → dist}/chadbuffer.d.ts +0 -0
  84. /package/{packages/sdk/dist → dist}/chadbuffer.js +0 -0
  85. /package/{packages/sdk/dist → dist}/claim-link.d.ts +0 -0
  86. /package/{packages/sdk/dist → dist}/claim-link.js +0 -0
  87. /package/{packages/sdk/dist → dist}/commitment-tree.d.ts +0 -0
  88. /package/{packages/sdk/dist → dist}/commitment-tree.js +0 -0
  89. /package/{packages/sdk/dist → dist}/core/esplora.d.ts +0 -0
  90. /package/{packages/sdk/dist → dist}/core/esplora.js +0 -0
  91. /package/{packages/sdk/dist → dist}/core/mempool.d.ts +0 -0
  92. /package/{packages/sdk/dist → dist}/core/mempool.js +0 -0
  93. /package/{packages/sdk/dist → dist}/crypto-babyjub.d.ts +0 -0
  94. /package/{packages/sdk/dist → dist}/crypto-babyjub.js +0 -0
  95. /package/{packages/sdk/dist → dist}/crypto.d.ts +0 -0
  96. /package/{packages/sdk/dist → dist}/crypto.js +0 -0
  97. /package/{packages/sdk/dist → dist}/event-client.d.ts +0 -0
  98. /package/{packages/sdk/dist → dist}/event-client.js +0 -0
  99. /package/{packages/sdk/dist → dist}/events.d.ts +0 -0
  100. /package/{packages/sdk/dist → dist}/events.js +0 -0
  101. /package/{packages/sdk/dist → dist}/explorer.d.ts +0 -0
  102. /package/{packages/sdk/dist → dist}/explorer.js +0 -0
  103. /package/{packages/sdk/dist → dist}/keys.d.ts +0 -0
  104. /package/{packages/sdk/dist → dist}/keys.js +0 -0
  105. /package/{packages/sdk/dist → dist}/logger.d.ts +0 -0
  106. /package/{packages/sdk/dist → dist}/logger.js +0 -0
  107. /package/{packages/sdk/dist → dist}/magicblock.d.ts +0 -0
  108. /package/{packages/sdk/dist → dist}/magicblock.js +0 -0
  109. /package/{packages/sdk/dist → dist}/merkle.d.ts +0 -0
  110. /package/{packages/sdk/dist → dist}/merkle.js +0 -0
  111. /package/{packages/sdk/dist → dist}/note.d.ts +0 -0
  112. /package/{packages/sdk/dist → dist}/note.js +0 -0
  113. /package/{packages/sdk/dist → dist}/pda.d.ts +0 -0
  114. /package/{packages/sdk/dist → dist}/pda.js +0 -0
  115. /package/{packages/sdk/dist → dist}/pool-state.d.ts +0 -0
  116. /package/{packages/sdk/dist → dist}/pool-state.js +0 -0
  117. /package/{packages/sdk/dist → dist}/poseidon.d.ts +0 -0
  118. /package/{packages/sdk/dist → dist}/poseidon.js +0 -0
  119. /package/{packages/sdk/dist → dist}/prover/index.d.ts +0 -0
  120. /package/{packages/sdk/dist → dist}/prover/index.js +0 -0
  121. /package/{packages/sdk/dist → dist}/prover/mobile.d.ts +0 -0
  122. /package/{packages/sdk/dist → dist}/prover/mobile.js +0 -0
  123. /package/{packages/sdk/dist → dist}/prover/web.d.ts +0 -0
  124. /package/{packages/sdk/dist → dist}/prover/web.js +0 -0
  125. /package/{packages/sdk/dist → dist}/psbt.d.ts +0 -0
  126. /package/{packages/sdk/dist → dist}/psbt.js +0 -0
  127. /package/{packages/sdk/dist → dist}/selective-disclosure.d.ts +0 -0
  128. /package/{packages/sdk/dist → dist}/selective-disclosure.js +0 -0
  129. /package/{packages/sdk/dist → dist}/sender-memo.d.ts +0 -0
  130. /package/{packages/sdk/dist → dist}/sender-memo.js +0 -0
  131. /package/{packages/sdk/dist → dist}/sns-resolver.d.ts +0 -0
  132. /package/{packages/sdk/dist → dist}/sns-resolver.js +0 -0
  133. /package/{packages/sdk/dist → dist}/solana/connection.d.ts +0 -0
  134. /package/{packages/sdk/dist → dist}/solana/connection.js +0 -0
  135. /package/{packages/sdk/dist → dist}/solana/priority-fee.d.ts +0 -0
  136. /package/{packages/sdk/dist → dist}/solana/priority-fee.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
@@ -44,21 +44,42 @@ export const LOCALNET_CHADBUFFER_PROGRAM_ID = address("EgWyMVFZewHmjJ9GGvVBTyaC3
44
44
  // Network Configurations
45
45
  // =============================================================================
46
46
  /**
47
- * Fresh multi-pool devnet deployment (2026-07-26).
48
- * The default domain is public; institution pools are selected explicitly.
47
+ * Greenfield devnet + Bitcoin testnet4 deployment (2026-08-26).
48
+ *
49
+ * The previous deployment's programs were closed on chain, so this is not a redeploy and none
50
+ * of the old addresses resolve any more — anything still pinned to CvfSyACR… is talking to a
51
+ * program that no longer exists.
52
+ *
53
+ * Two pools were deployed, each with its own Ika DKG and therefore its own dWallet. The default
54
+ * below is the OPEN pool. Select the verified pool by overriding `zkbtcMint` and
55
+ * `ikaDwalletXOnlyPubkey` — `getConfig` re-derives poolStatePda, commitmentTreePda and poolVault
56
+ * from the mint, so those two values are all a caller needs:
57
+ *
58
+ * verified mint G78CTddWGDaNaSKQayAt7m3pzcMyaUNxgR8y3R34YvEv
59
+ * state Eqn9SmFYtacrdfPE9Shbi8bDXLjCNNz3WhHfqtJnwbKY
60
+ * xonly 16c563baa11bfc8fe93acafe8fe169b954b3ead3ecda7754c615dec9e840b5a5
61
+ *
62
+ * Read off chain, not from the deploy notes: Eqn9SmFY… is the pool whose PoolState flags carry
63
+ * the permissioned bit (0b10 at offset 2). The deployment also contains a THIRD pool —
64
+ * 3chHiDqM… / 7wDtDd1u… — which the deploy notes name as the verified one but which is not
65
+ * permissioned and whose mint has zero supply. Treat it as abandoned; do not wire it up.
49
66
  */
50
67
  export const DEVNET_CONFIG = {
51
68
  network: "devnet",
52
- utxopiaProgramId: address("CvfSyACR8xemPdeJsB3D8Xh15rKUQ3b5c1PvnmABCBJp"),
69
+ utxopiaProgramId: address("28z2AtKA6aFGrGCh4ns1rmp7vGpWuh6x3H7gXKBcfxur"),
53
70
  policyProgramId: address("9asWYKVriWGpExW5xM44ChHjZtispkLCiWKkM8SQi8Rs"),
54
- btcLightClientProgramId: address("859B7kw1xDyY8rzSXY6pAPNxaAsPWrsaAPJk3iivd43g"),
71
+ // testnet4 light client, deployed 2026-08-26. Must match the `devnet` arm of
72
+ // BTC_LIGHT_CLIENT_PROGRAM_ID in programs/utxopia/src/constants.rs.
73
+ btcLightClientProgramId: address("4LZbktiNsiVAe2bwPCTPNgqiWWgZNUj4T3bDx8GZmehv"),
55
74
  chadbufferProgramId: CHADBUFFER_PROGRAM_ID,
56
75
  token2022ProgramId: TOKEN_2022_PROGRAM_ID,
57
76
  ataProgramId: ATA_PROGRAM_ID,
58
- poolStatePda: address("9xeWc39r3Z176MUpMpaqCGJGneHMj4pfMRv9u6dp2Qgd"),
59
- commitmentTreePda: address("4FvM9dCzDvr39Xu5xRUQc6EEm3UjSikyWUY5Hzpc5C4A"),
60
- zkbtcMint: address("GuruxfN5irYcCyDiKFMeDRTNbP2WeHF1oWjQ8q8Esc16"),
61
- poolVault: address("3GffHxesFsGj4QmgQ8ozs17dZFNTv4AAhdwyR2XZPzkm"),
77
+ // Open pool. Derived and then confirmed on chain: pool_state and commitment_tree are owned by
78
+ // the program (332 / 8816 bytes), the vault by Token-2022 (170 bytes).
79
+ poolStatePda: address("FezM7ksBwftqrd4TtabMa9uXt51eCT5M946YnpSEQZHm"),
80
+ commitmentTreePda: address("CHwJZqNAUag6ARDfmntvmbS4WeAsGX67f2vALxXbB6PP"),
81
+ zkbtcMint: address("87zWstDnNgMig2vk8q8jTrK6YTcyugeRTanfT3LfyU3T"),
82
+ poolVault: address("8VMfH4mDizU6nHybQumxeauyiEL2QTqrGQLXmAr9wpC3"),
62
83
  // RPC Endpoints
63
84
  solanaRpcUrl: "https://api.devnet.solana.com",
64
85
  solanaWsUrl: "wss://api.devnet.solana.com",
@@ -67,8 +88,11 @@ export const DEVNET_CONFIG = {
67
88
  esploraUrl: "https://mempool.space/testnet4/api",
68
89
  // Circuit CDN (Groth16 artifacts: .wasm, .zkey files)
69
90
  circuitCdnUrl: "https://circuit.utxopia.com/circuits/v2/groth16",
70
- // Groth16 Verifier: verification is inline in the UTXOpia program (no separate verifier program)
71
- groth16VerifierProgramId: address("AjbX243s2JMFG2uhfTjKkadjPvQEPgcuyV3vfLJv36MT"), // inline in utxopia program
91
+ // Groth16 verification is inline in the UTXOpia program, so this is the same address.
92
+ // It used to hold a stale third id, which `getConfig` silently overwrote with the program id
93
+ // whenever a programId override was supplied — meaning the constant was only ever read on the
94
+ // no-override path, where it was wrong.
95
+ groth16VerifierProgramId: address("28z2AtKA6aFGrGCh4ns1rmp7vGpWuh6x3H7gXKBcfxur"),
72
96
  // VK Hashes (SHA256 of serialized VK bytes, generated from circom trusted setup)
73
97
  vkHashes: {
74
98
  claim: "7af0e702e7b595fbdb62fd268e6c529481003e07957e0f60e4fb23cd9fe6a77f",
@@ -88,8 +112,12 @@ export const DEVNET_CONFIG = {
88
112
  "1x4": "01728b82e810a8ba604cc66aa6a563444d18f4598c402d11767d0a7e5049a9be",
89
113
  "4x1": "0362b306b17dae916d836d9448a26c97e51b1b0a1a0ed052ebfbd4800e5000cf",
90
114
  },
91
- // Ika dWallet x-only pubkey populated by ./scripts/sync-env.sh from devnet-state.json.
92
- ikaDwalletXOnlyPubkey: "0000000000000000000000000000000000000000000000000000000000000000",
115
+ // Ika dWallet x-only pubkey for the OPEN pool, read from its PoolConfig PDA
116
+ // (GQ5ZfD4tJmgcquHLAHSbmAm72Foi9hf3VduPrroysM1b, offset 68..100) on 2026-08-26.
117
+ // All-zero here used to mean "deposit addresses cannot be derived until sync-env.sh runs";
118
+ // the two pools have distinct dWallets, so a single synced value could only ever be right
119
+ // for one of them. See the verified pool's key in the header comment above.
120
+ ikaDwalletXOnlyPubkey: "3a6ab80ba14bc050f048ee3e0b77d8935adf4fc5e2f5947311f26cc2cb5bd194",
93
121
  // SNS Subdomain Resolution (devnet)
94
122
  snsNameServiceProgramId: "namesLPneVptA9Z5rqUDD9tMTWEJwofgaYwp8cawRkX", // SPL Name Service (devnet)
95
123
  snsRegistrarProgramId: "snshBoEQ9jx4QoHBpZDQPYdNCtw7RMxJvYrKFEhwaPJ", // SNS Registrar (devnet)
@@ -99,6 +127,32 @@ export const DEVNET_CONFIG = {
99
127
  snsReverseLookupClass: "7NbD1vprif6apthEZAqhRfYuhrqnuderB8qpnfXGCc8H", // Reverse lookup class (devnet)
100
128
  snsStealthDataVersion: 1,
101
129
  };
130
+ /**
131
+ * Solana devnet + Bitcoin **regtest** deployment — the environment app.utxopia.com serves.
132
+ *
133
+ * This is a different deployment from DEVNET_CONFIG above, not a Bitcoin-side variation of it:
134
+ * a different program (CvfSyACR…), a different pool, a different Ika dWallet. It used to share
135
+ * DEVNET_CONFIG and differ only by bitcoinNetwork, which worked while one program hosted both.
136
+ * It no longer does — after 2026-08-26 there are two programs — so `devnet-regtest` resolving
137
+ * to DEVNET_CONFIG would silently point this environment at testnet4's program and pool.
138
+ *
139
+ * Pool addresses derived from the mint with the same seeds getConfig uses, then confirmed on
140
+ * devnet: pool_state and commitment_tree owned by CvfSyACR… at 332 and 8816 bytes, the vault by
141
+ * Token-2022 at 170.
142
+ */
143
+ export const DEVNET_REGTEST_CONFIG = {
144
+ ...DEVNET_CONFIG,
145
+ utxopiaProgramId: address("CvfSyACR8xemPdeJsB3D8Xh15rKUQ3b5c1PvnmABCBJp"),
146
+ groth16VerifierProgramId: address("CvfSyACR8xemPdeJsB3D8Xh15rKUQ3b5c1PvnmABCBJp"),
147
+ btcLightClientProgramId: address("8hCSNKf8ByqZdet2D4SDiZHDrB1u9ohkhqKKzr9i7vfQ"),
148
+ poolStatePda: address("CeEEmE9MvFPZtqcgv1rsXmzNmfvchbs8VEZJGFKZ2Cyj"),
149
+ commitmentTreePda: address("45bCw97GssorJM9b1ZWZLMGy1NJUczcaNVaKASmCRohL"),
150
+ zkbtcMint: address("BJ5SXA33qK8r8BxJD4nQPf72ae9bactiA2Zqo33EcvPu"),
151
+ poolVault: address("JsZ1ipHZWiZYE8kRDXmEkKuiK6KKVxCVJKv1tGnCkM6"),
152
+ ikaDwalletXOnlyPubkey: "243a6c47504f82d168754da9392a9dbcbab9b9f9c515a609227fac4642b2a26f",
153
+ bitcoinNetwork: "regtest",
154
+ esploraUrl: "http://localhost:2140",
155
+ };
102
156
  /**
103
157
  * Mainnet Configuration (placeholder - not yet deployed)
104
158
  */
@@ -221,6 +275,24 @@ function esploraUrlForNetwork(net) {
221
275
  default: return `https://mempool.space/${net}/api`;
222
276
  }
223
277
  }
278
+ /**
279
+ * Base config for an app network id. Two devnet deployments now exist, so this cannot be
280
+ * derived from NetworkType alone — that is what normalizeAppNetwork collapses away.
281
+ */
282
+ function baseConfigForAppNetwork(network) {
283
+ switch (network) {
284
+ case "localnet":
285
+ return LOCALNET_CONFIG;
286
+ case "mainnet":
287
+ return MAINNET_CONFIG;
288
+ case "devnet-regtest":
289
+ return DEVNET_REGTEST_CONFIG;
290
+ case "devnet-testnet4":
291
+ case "devnet":
292
+ default:
293
+ return DEVNET_CONFIG;
294
+ }
295
+ }
224
296
  function normalizeAppNetwork(network) {
225
297
  switch (network) {
226
298
  case "mainnet":
@@ -229,6 +301,7 @@ function normalizeAppNetwork(network) {
229
301
  return "localnet";
230
302
  case "devnet":
231
303
  case "devnet-regtest":
304
+ case "devnet-testnet4":
232
305
  default:
233
306
  return "devnet";
234
307
  }
@@ -239,6 +312,7 @@ function bitcoinNetworkForAppNetwork(network) {
239
312
  case "devnet-regtest":
240
313
  return "regtest";
241
314
  case "devnet":
315
+ case "devnet-testnet4":
242
316
  return "testnet4";
243
317
  case "mainnet":
244
318
  return "mainnet";
@@ -273,7 +347,7 @@ export function setConfig(network) {
273
347
  const baseNetwork = normalizeAppNetwork(network);
274
348
  switch (baseNetwork) {
275
349
  case "devnet":
276
- currentConfig = DEVNET_CONFIG;
350
+ currentConfig = baseConfigForAppNetwork(network);
277
351
  break;
278
352
  case "mainnet":
279
353
  throw new Error("Mainnet is not yet deployed. " +
@@ -318,11 +392,7 @@ export async function initConfig(overrides) {
318
392
  (typeof process !== "undefined" && (process.env?.NEXT_PUBLIC_NETWORK || process.env?.UTXOPIA_NETWORK)) ||
319
393
  "devnet";
320
394
  const networkId = normalizeAppNetwork(appNetworkId);
321
- const baseConfig = networkId === "localnet"
322
- ? LOCALNET_CONFIG
323
- : networkId === "mainnet"
324
- ? MAINNET_CONFIG
325
- : DEVNET_CONFIG;
395
+ const baseConfig = baseConfigForAppNetwork(appNetworkId);
326
396
  const config = { ...baseConfig };
327
397
  const appBitcoinNetwork = bitcoinNetworkForAppNetwork(appNetworkId);
328
398
  const btcNetOverride = typeof process !== "undefined" && process.env?.NEXT_PUBLIC_BTC_NETWORK;
@@ -20,6 +20,20 @@ export declare function ed25519GenerateKeyPair(): {
20
20
  privKey: Uint8Array;
21
21
  pubKey: Uint8Array;
22
22
  };
23
+ /**
24
+ * Derive an Ed25519 keypair deterministically from secret material.
25
+ *
26
+ * Used for deposit ephemeral keys, where a random keypair is a liability: the
27
+ * deposit address commits to the ephemeral pubkey, so losing it makes the coins
28
+ * unspendable by anyone, forever. Deriving it from the owner's seed means the
29
+ * seed alone can rebuild every address they were ever handed.
30
+ *
31
+ * @param material - secret bytes; hashed, so it need not be uniform
32
+ */
33
+ export declare function ed25519KeyPairFromMaterial(material: Uint8Array): {
34
+ privKey: Uint8Array;
35
+ pubKey: Uint8Array;
36
+ };
23
37
  /**
24
38
  * Derive an Ed25519 public key from a private key
25
39
  *
@@ -27,6 +27,20 @@ export function ed25519GenerateKeyPair() {
27
27
  const pubKey = ed25519.getPublicKey(privKey);
28
28
  return { privKey, pubKey };
29
29
  }
30
+ /**
31
+ * Derive an Ed25519 keypair deterministically from secret material.
32
+ *
33
+ * Used for deposit ephemeral keys, where a random keypair is a liability: the
34
+ * deposit address commits to the ephemeral pubkey, so losing it makes the coins
35
+ * unspendable by anyone, forever. Deriving it from the owner's seed means the
36
+ * seed alone can rebuild every address they were ever handed.
37
+ *
38
+ * @param material - secret bytes; hashed, so it need not be uniform
39
+ */
40
+ export function ed25519KeyPairFromMaterial(material) {
41
+ const privKey = sha256(material);
42
+ return { privKey, pubKey: ed25519.getPublicKey(privKey) };
43
+ }
30
44
  /**
31
45
  * Derive an Ed25519 public key from a private key
32
46
  *
@@ -34,16 +34,17 @@ export { fetchTokenConfig, getTokenId, fetchSupportedTokens, fetchEnabledTokens,
34
34
  export { MAGICBLOCK_DELEGATION_PROGRAM_ID, MAGICBLOCK_DEVNET_ROUTER_URL, MAGICBLOCK_DEVNET_ROUTER_WS_URL, MAGICBLOCK_EPHEMERAL_VAULT_ID, MAGICBLOCK_MAGIC_CONTEXT_ID, MAGICBLOCK_MAGIC_PROGRAM_ID, MAGICBLOCK_MAX_PER_MEMBERS, MAGICBLOCK_PERMISSION_PROGRAM_ID, MAGICBLOCK_PER_MEMBER_FLAGS, MAGICBLOCK_VALIDATOR_IDENTITIES, buildDefaultPrivacyDomain, buildMagicBlockPerMemberFlags, deriveMagicBlockCommitRecordPDA, deriveMagicBlockCommitStatePDA, deriveMagicBlockDelegateBufferPDA, deriveMagicBlockDelegationMetadataPDA, deriveMagicBlockDelegationRecordPDA, deriveMagicBlockPermissionPDA, deriveMagicBlockUndelegateBufferPDA, requiresMagicBlockEndpoint, getMagicBlockEndpoint, getMagicBlockValidatorIdentity, createMagicBlockRouterConnection, type BuildPrivacyDomainOptions, type MagicBlockEndpointConfig, type MagicBlockExecutionMode, type MagicBlockPolicyMode, type MagicBlockPerMemberFlagName, type MagicBlockValidatorRegion, type PrivacyDomainConfig, type PrivacyDomainKind, } from "./magicblock";
35
35
  export { generateNote, createNoteFromSecrets, serializeNote, deserializeNote, noteHasComputedHashes, getNotePublicKeyX, computeNoteCommitment, computeNoteNullifier, formatBtc, parseBtc, deriveNote, deriveNotes, deriveMasterKey, deriveNoteFromMaster, estimateSeedStrength, createNote, prepareWithdrawal, createStealthNote, serializeStealthNote, deserializeStealthNote, type Note, type SerializedNote, type NoteData, type StealthNote, type SerializedStealthNote, createJoinSplitNote, computeJoinSplitNoteNullifier, serializeJoinSplitNote, deserializeJoinSplitNote, type JoinSplitNote, type SerializedJoinSplitNote, } from "./note";
36
36
  export { createMerkleProof, createMerkleProofFromBigints, proofToCircomFormat, proofToOnChainFormat, createEmptyMerkleProof, leafIndexToPathIndices, pathIndicesToLeafIndex, validateMerkleProofStructure, parseMerkleProofResponse, TREE_DEPTH, ROOT_HISTORY_SIZE, MAX_LEAVES, ZERO_VALUE, type MerkleProof, } from "./merkle";
37
- export { deriveTaprootAddress, deriveTaprootAddressWithRefund, buildRefundScript, computeTapLeafHash, verifyTaprootAddress, createP2TRScriptPubkey, parseP2TRScriptPubkey, isValidBitcoinAddress, getInternalKey, createCustomInternalKey, createOpReturnScriptFromPayload, buildDepositOpReturn, parseDepositOpReturn, encodeDepositOpReturnHeader, decodeDepositOpReturnHeader, validateDepositOpReturnContext, computeDepositPoolTag, DEPOSIT_DESTINATION_CHAIN, DEPOSIT_BITCOIN_NETWORK, DEPOSIT_OP_RETURN_VERSION, DEPOSIT_POOL_TAG_SIZE, DEPOSIT_OP_RETURN_SIZE, type DepositDestinationChain, type DepositBitcoinNetwork, type DepositOpReturnContext, type ParsedDepositOpReturn, } from "./taproot";
37
+ export { deriveTaprootAddress, deriveTaprootAddressWithRefund, depositTweakCommitment, deriveDepositAddress, depositLeafScript, DEPOSIT_NUMS_INTERNAL_KEY, buildRefundScript, computeTapLeafHash, verifyTaprootAddress, createP2TRScriptPubkey, parseP2TRScriptPubkey, isValidBitcoinAddress, getInternalKey, createCustomInternalKey, createOpReturnScriptFromPayload, buildDepositOpReturn, parseDepositOpReturn, encodeDepositOpReturnHeader, decodeDepositOpReturnHeader, validateDepositOpReturnContext, computeDepositPoolTag, DEPOSIT_DESTINATION_CHAIN, DEPOSIT_BITCOIN_NETWORK, DEPOSIT_OP_RETURN_VERSION, DEPOSIT_POOL_TAG_SIZE, DEPOSIT_OP_RETURN_SIZE, type DepositDestinationChain, type DepositBitcoinNetwork, type DepositOpReturnContext, type ParsedDepositOpReturn, } from "./taproot";
38
38
  export { encodeClaimLink, decodeClaimLink, parseClaimUrl, } from "./claim-link";
39
39
  export type { ProofData, MerkleProofInput, CircuitType, JoinSplitProofInputs, } from "./prover/web";
40
40
  export { uploadTransactionToBuffer, uploadProofToBuffer, closeBuffer, readBufferData, fetchRawTransaction, fetchMerkleProof, prepareVerifyDeposit, buildMerkleProof, needsBuffer as bufferNeedsBuffer, getProofSource, calculateUploadTransactions, CHADBUFFER_PROGRAM_ID, AUTHORITY_SIZE, MAX_DATA_PER_WRITE, SOLANA_TX_SIZE_LIMIT, type ProofUploadResult, } from "./chadbuffer";
41
41
  export { computeBoundParamsHash, computeSolanaDomainBoundParamsHash, computeSolanaDomainSeparator, computeStealthDataHash, createTransferBoundParams, createUnshieldBoundParams, createRedeemBoundParams, SOLANA_BOUND_CHAIN_ID, SOLANA_DEVNET_BOUND_CHAIN_ID, SOLANA_MAINNET_BOUND_CHAIN_ID, DEFAULT_BOUND_PARAMS, type BoundParams, type BoundParamsMode, type SolanaPrivacyDomainContext, type SolanaPrivacyDomainKind, } from "./bound-params";
42
- export { getConfig, setConfig, createConfig, initConfig, DEVNET_CONFIG, MAINNET_CONFIG, LOCALNET_CONFIG, TOKEN_PROGRAM_ID, TOKEN_2022_PROGRAM_ID, ATA_PROGRAM_ID, UTXOPIA_POLICY_PROGRAM_ID, SDK_VERSION, DEPLOYMENT_INFO, JOINSPLIT_TREE_DEPTH, type NetworkConfig, type NetworkType, } from "./config";
42
+ export { formatSpendDoc, renderSpendDoc, SpendDocMismatch, type SpendDoc, type SpendSignals, } from "./spend-doc";
43
+ export { getConfig, setConfig, createConfig, initConfig, DEVNET_CONFIG, DEVNET_REGTEST_CONFIG, MAINNET_CONFIG, LOCALNET_CONFIG, TOKEN_PROGRAM_ID, TOKEN_2022_PROGRAM_ID, ATA_PROGRAM_ID, UTXOPIA_POLICY_PROGRAM_ID, SDK_VERSION, DEPLOYMENT_INFO, JOINSPLIT_TREE_DEPTH, type NetworkConfig, type NetworkType, } from "./config";
43
44
  export { POOL_STATE_DISCRIMINATOR, POOL_STATE_LEN, POOL_STATE_OFFSETS, POOL_FLAG, parsePoolState, parsePoolFees, BPS_DENOMINATOR, computeBpsFee, feeShareBps, } from "./pool-state";
44
45
  export type { PoolState, PoolFees } from "./pool-state";
45
46
  export { PDA_SEEDS, poolStateSeeds, commitmentTreeSeeds, tokenConfigSeeds, poolConfigSeeds, nullifierRecordSeeds, redemptionRequestSeeds, vkRegistrySeeds, depositReceiptSeeds, policyApprovalSeeds, exitDestinationSeeds, lightClientSeeds, blockHeaderSeeds, heightIndexSeeds, verifiedTransactionSeeds, derivePoolStatePDA, deriveCommitmentTreePDA, deriveNullifierRecordPDA, derivePolicyApprovalPDA, deriveExitDestinationPDA, EXIT_KIND_SOLANA_OWNER, EXIT_KIND_BTC_SCRIPT, deriveLightClientPDA, deriveBlockHeaderPDA, deriveHeightIndexPDA, deriveVkRegistryPDA, deriveRedemptionRequestPDA, deriveTokenConfigPDA, derivePoolConfigPDA, deriveDepositReceiptPDA, commitmentToBytes, } from "./pda";
46
- export { createStealthDeposit, createStealthDepositWithKeys, createStealthOutput, createStealthOutputWithKeys, createStealthOutputForCommitment, packStealthOutputForCircuit, scanAnnouncements, scanAnnouncementsViewOnly, scanAnnouncementsViewOnlyMulti, exportViewOnlyKeys, encodeViewOnlyKeys, decodeViewOnlyKeys, prepareClaimInputs, scanUnifiedNotes, scanUnifiedNotesMulti, encryptAmount, decryptAmount, computeNullifierHashForNote, computeNullifierBytes, parseAnnouncementsFromHex, createDepositFromConfig, createDirectVaultDeposit, isDepositForViewer, isDepositForViewerHex, ANNOUNCEMENT_TYPE_DEPOSIT, ANNOUNCEMENT_TYPE_TRANSFER, type StealthDeposit, type StealthOutputData, type StealthOutputWithKeys, type CircuitStealthOutput, type ScannedNote, type ClaimInputs as StealthClaimInputs, type OnChainStealthAnnouncement, type ConnectionAdapter, type ViewOnlyKeys, type ViewOnlyScannedNote, createNonInteractiveDeposit, pickIkaCustodyKey, type NonInteractiveDepositResult, type NonInteractiveDepositWithRefundResult, } from "./stealth";
47
+ export { createStealthDeposit, createStealthDepositWithKeys, createStealthOutput, createStealthOutputWithKeys, createStealthOutputForCommitment, packStealthOutputForCircuit, scanAnnouncements, scanAnnouncementsViewOnly, scanAnnouncementsViewOnlyMulti, exportViewOnlyKeys, encodeViewOnlyKeys, decodeViewOnlyKeys, prepareClaimInputs, scanUnifiedNotes, scanUnifiedNotesMulti, encryptAmount, decryptAmount, computeNullifierHashForNote, computeNullifierBytes, parseAnnouncementsFromHex, createDepositFromConfig, createDirectVaultDeposit, createTweakDeposit, depositEphemeralKeyPair, depositViewingNode, outgoingViewingNode, outgoingEphemeralKeyPair, findNextSendIndex, isDepositForViewer, isDepositForViewerHex, ANNOUNCEMENT_TYPE_DEPOSIT, ANNOUNCEMENT_TYPE_TRANSFER, type StealthDeposit, type StealthOutputData, type StealthOutputWithKeys, type CircuitStealthOutput, type ScannedNote, type ClaimInputs as StealthClaimInputs, type OnChainStealthAnnouncement, type ConnectionAdapter, type ViewOnlyKeys, type ViewOnlyScannedNote, createNonInteractiveDeposit, pickIkaCustodyKey, type NonInteractiveDepositResult, type TweakDepositResult, type DepositRecoveryMaterial, type OutgoingRecoveryMaterial, type NonInteractiveDepositWithRefundResult, } from "./stealth";
47
48
  export { buildDepositPsbt, estimateDepositFee, fetchUtxos, selectUtxos, type BuildDepositPsbtParams, type BuildDepositPsbtResult, type UtxoDescriptor, } from "./psbt";
48
49
  export { EsploraClient, esploraTestnet, esploraMainnet, type EsploraTransaction, type EsploraVin, type EsploraVout, type EsploraStatus, type EsploraAddressInfo, type EsploraUtxo, type EsploraMerkleProof, type EsploraNetwork, } from "./core/esplora";
49
50
  export { MempoolClient, mempoolTestnet, mempoolMainnet, reverseBytes, type BlockHeader, type TransactionInfo, type SPVProofData, } from "./core/mempool";
@@ -52,7 +53,7 @@ export { setDebug } from "./logger";
52
53
  export { createFetchConnectionAdapter, createConnectionAdapterFromWeb3, createConnectionAdapterFromKit, getConnectionAdapter, clearConnectionAdapterCache, type RpcConfig, type Web3Connection, type KitRpc, } from "./solana/connection";
53
54
  export { resolveSnsName, resolveStealthName, parseSnsStealthData, isSnsStealthAddress, isAuditorDisclosable, SnsComplianceFlags, SNS_COMPLIANCE_AUDITOR_OFFSET, SNS_COMPLIANCE_AUDITOR_BYTES, deriveParentDomainKey, SNS_STEALTH_DATA_SIZE, type SnsStealthAddress, } from "./sns-resolver";
54
55
  export { COMMITMENT_TREE_DISCRIMINATOR, parseCommitmentTreeData, isValidRoot, fetchCommitmentTree, getCommitmentIndex, saveCommitmentIndex, CommitmentTreeIndex, buildCommitmentTreeFromChain, fetchLeafIndexForCommitment, fetchMerkleProofForCommitment, getMerkleProofFromTree, type CommitmentTreeState, type RpcClient, type OnChainMerkleProof, } from "./commitment-tree";
55
- export { INSTRUCTION_DISCRIMINATORS, buildShieldInstructionData, buildShieldInstruction, type ShieldInstructionOptions, buildApproveRedemptionSigningInstructionData, buildApproveRedemptionSigningInstruction, buildCancelRedemptionInstructionData, buildCancelRedemptionInstruction, type CancelRedemptionInstructionOptions, bigintTo32Bytes, bytes32ToBigint, buildTransactInstructionData, buildTransactInstruction, buildRedeemInstructionData, buildUnshieldInstructionData, buildUnshieldInstruction, buildProposePoolUpdateInstructionData, buildProposePoolUpdateInstruction, buildExecutePoolUpdateInstructionData, buildExecutePoolUpdateInstruction, buildCancelPoolUpdateInstructionData, buildCancelPoolUpdateInstruction, buildRotateTreeInstructionData, buildRotateTreeInstruction, type RotateTreeOptions, buildMagicBlockDelegateInstructionData, buildMagicBlockDelegateInstruction, buildMagicBlockCommitInstructionData, buildMagicBlockCommitInstruction, buildMagicBlockPerPermissionInstructionData, buildMagicBlockPerPermissionInstruction, buildPolicyRequestHash, buildPolicyIntentParts, buildRegisterExitDestinationInstruction, buildRegisterExitDestinationInstructionData, MAX_POLICY_INTENT_PARTS, buildInitializePolicyApprovalInstructionData, buildInitializePolicyApprovalInstruction, buildPolicyApprovalDecisionInstruction, buildPolicyApprovalCommitInstruction, buildCompleteDepositPermissionedInstructionData, buildCompleteDepositPermissionedInstruction, buildShieldPermissionedInstructionData, buildShieldPermissionedInstruction, buildRotateAuditorInstructionData, buildRotateAuditorInstruction, type MagicBlockDelegateTarget, type MagicBlockDelegateInstructionOptions, type MagicBlockCommitInstructionOptions, type MagicBlockPerPermissionOperation, type MagicBlockPerPermissionMember, type MagicBlockPerPermissionInstructionOptions, type PolicyApprovalDecision, type InitializePolicyApprovalOptions, type CompleteDepositPermissionedOptions, type ShieldPermissionedInstructionOptions, type RotateAuditorOptions, buildVerifyTransactionInstructionData, buildCompleteDepositInstructionData, buildSetPoolConfigInstructionData, parsePoolConfig, type ParsedPoolConfig, POOL_CONFIG_DISCRIMINATOR, POOL_CONFIG_LEN, POOL_SCRIPT_MAX_LEN, type Instruction, type ApproveRedemptionSigningInstructionOptions, type TransactInstructionOptions, type UnshieldInstructionOptions, type ProposePoolUpdateOptions, type ExecutePoolUpdateOptions, type CancelPoolUpdateOptions, } from "./instructions";
56
+ export { INSTRUCTION_DISCRIMINATORS, buildShieldInstructionData, buildShieldInstruction, type ShieldInstructionOptions, buildApproveRedemptionSigningInstructionData, buildApproveRedemptionSigningInstruction, buildCancelRedemptionInstructionData, buildCancelRedemptionInstruction, type CancelRedemptionInstructionOptions, bigintTo32Bytes, bytes32ToBigint, buildTransactInstructionData, buildTransactInstruction, buildRedeemInstructionData, buildUnshieldInstructionData, buildUnshieldInstruction, buildProposePoolUpdateInstructionData, buildProposePoolUpdateInstruction, buildExecutePoolUpdateInstructionData, buildExecutePoolUpdateInstruction, buildCancelPoolUpdateInstructionData, buildCancelPoolUpdateInstruction, buildRotateTreeInstructionData, buildRotateTreeInstruction, type RotateTreeOptions, buildMagicBlockDelegateInstructionData, buildMagicBlockDelegateInstruction, buildMagicBlockCommitInstructionData, buildMagicBlockCommitInstruction, buildMagicBlockPerPermissionInstructionData, buildMagicBlockPerPermissionInstruction, buildPolicyRequestHash, buildPolicyIntentParts, buildRegisterExitDestinationInstruction, buildRegisterExitDestinationInstructionData, MAX_POLICY_INTENT_PARTS, buildInitializePolicyApprovalInstructionData, buildInitializePolicyApprovalInstruction, buildPolicyApprovalDecisionInstruction, buildPolicyApprovalCommitInstruction, buildCompleteDepositPermissionedInstructionData, buildCompleteDepositPermissionedInstruction, buildShieldPermissionedInstructionData, buildShieldPermissionedInstruction, buildRotateAuditorInstructionData, buildRotateAuditorInstruction, type MagicBlockDelegateTarget, type MagicBlockDelegateInstructionOptions, type MagicBlockCommitInstructionOptions, type MagicBlockPerPermissionOperation, type MagicBlockPerPermissionMember, type MagicBlockPerPermissionInstructionOptions, type PolicyApprovalDecision, type InitializePolicyApprovalOptions, type CompleteDepositPermissionedOptions, type ShieldPermissionedInstructionOptions, type RotateAuditorOptions, buildVerifyTransactionInstructionData, buildCompleteDepositInstructionData, buildVerifyDepositInstructionData, buildVerifyDepositPermissionedInstructionData, buildSetPoolConfigInstructionData, parsePoolConfig, type ParsedPoolConfig, POOL_CONFIG_DISCRIMINATOR, POOL_CONFIG_LEN, POOL_SCRIPT_MAX_LEN, type Instruction, type ApproveRedemptionSigningInstructionOptions, type TransactInstructionOptions, type UnshieldInstructionOptions, type ProposePoolUpdateOptions, type ExecutePoolUpdateOptions, type CancelPoolUpdateOptions, } from "./instructions";
56
57
  export { VK_REGISTRY_DISCRIMINATOR, VK_REGISTRY_LEN, MAX_IC_POINTS, MAX_SAFE_JOINSPLIT_SIZE, INIT_VK_REGISTRY_DISCRIMINATOR, UPDATE_VK_REGISTRY_DISCRIMINATOR, joinSplitNumPublicInputs, computeVkHash, vkeyJsonToVkMaterial, buildVkRegistryData, parseVkRegistry, assertVkRegistryForShape, isVkRegistryReady, type JoinSplitVkMaterial, type SnarkjsVkeyJson, type ParsedVkRegistry, } from "./vk-registry";
57
58
  export { fetchExplorerDeposits, fetchExplorerTransfers, fetchExplorerRedemptions, parseNullifierRecord, parseRedemptionRequest, NULLIFIER_RECORD_SIZE, REDEMPTION_REQUEST_SIZE, NULLIFIER_RECORD_DISCRIMINATOR, REDEMPTION_REQUEST_DISCRIMINATOR, OPERATION_TYPE_LABELS, type ExplorerDeposit, type ExplorerTransferEvent, type ExplorerRedemption, type IndexerLeaf, } from "./explorer";
58
59
  export { parseProgramEvents, parseNullifierSpentEvent, parseStealthAnnouncementEvent, parseSenderMemoEvent, parseBtcOriginAttestationEvent, parseAuditorCiphertextEvent, EVENT_NULLIFIER_SPENT, EVENT_STEALTH_ANNOUNCEMENT, EVENT_NULLIFIERS_BATCH, EVENT_ANNOUNCEMENTS_BATCH, EVENT_SENDER_MEMO, EVENT_BTC_ORIGIN_ATTESTATION, EVENT_AUDITOR_CIPHERTEXT, type NullifierSpentEvent, type StealthAnnouncementEvent, type SenderMemoEvent, type BtcOriginAttestationEvent, type AuditorCiphertextEvent, type ProgramEvent, } from "./events";
@@ -94,7 +94,7 @@ export { createMerkleProof, createMerkleProofFromBigints, proofToCircomFormat, p
94
94
  // ==========================================================================
95
95
  // Taproot address utilities
96
96
  // ==========================================================================
97
- export { deriveTaprootAddress, deriveTaprootAddressWithRefund, buildRefundScript, computeTapLeafHash, verifyTaprootAddress, createP2TRScriptPubkey, parseP2TRScriptPubkey, isValidBitcoinAddress, getInternalKey, createCustomInternalKey, createOpReturnScriptFromPayload, buildDepositOpReturn, parseDepositOpReturn, encodeDepositOpReturnHeader, decodeDepositOpReturnHeader, validateDepositOpReturnContext, computeDepositPoolTag, DEPOSIT_DESTINATION_CHAIN, DEPOSIT_BITCOIN_NETWORK, DEPOSIT_OP_RETURN_VERSION, DEPOSIT_POOL_TAG_SIZE, DEPOSIT_OP_RETURN_SIZE, } from "./taproot";
97
+ export { deriveTaprootAddress, deriveTaprootAddressWithRefund, depositTweakCommitment, deriveDepositAddress, depositLeafScript, DEPOSIT_NUMS_INTERNAL_KEY, buildRefundScript, computeTapLeafHash, verifyTaprootAddress, createP2TRScriptPubkey, parseP2TRScriptPubkey, isValidBitcoinAddress, getInternalKey, createCustomInternalKey, createOpReturnScriptFromPayload, buildDepositOpReturn, parseDepositOpReturn, encodeDepositOpReturnHeader, decodeDepositOpReturnHeader, validateDepositOpReturnContext, computeDepositPoolTag, DEPOSIT_DESTINATION_CHAIN, DEPOSIT_BITCOIN_NETWORK, DEPOSIT_OP_RETURN_VERSION, DEPOSIT_POOL_TAG_SIZE, DEPOSIT_OP_RETURN_SIZE, } from "./taproot";
98
98
  // ==========================================================================
99
99
  // Claim link utilities
100
100
  // ==========================================================================
@@ -107,10 +107,11 @@ export { uploadTransactionToBuffer, uploadProofToBuffer, closeBuffer, readBuffer
107
107
  // Bound Parameters (JoinSplit transaction binding)
108
108
  // ==========================================================================
109
109
  export { computeBoundParamsHash, computeSolanaDomainBoundParamsHash, computeSolanaDomainSeparator, computeStealthDataHash, createTransferBoundParams, createUnshieldBoundParams, createRedeemBoundParams, SOLANA_BOUND_CHAIN_ID, SOLANA_DEVNET_BOUND_CHAIN_ID, SOLANA_MAINNET_BOUND_CHAIN_ID, DEFAULT_BOUND_PARAMS, } from "./bound-params";
110
+ export { formatSpendDoc, renderSpendDoc, SpendDocMismatch, } from "./spend-doc";
110
111
  // ==========================================================================
111
112
  // Configuration
112
113
  // ==========================================================================
113
- export { getConfig, setConfig, createConfig, initConfig, DEVNET_CONFIG, MAINNET_CONFIG, LOCALNET_CONFIG, TOKEN_PROGRAM_ID, TOKEN_2022_PROGRAM_ID, ATA_PROGRAM_ID, UTXOPIA_POLICY_PROGRAM_ID, SDK_VERSION, DEPLOYMENT_INFO, JOINSPLIT_TREE_DEPTH, } from "./config";
114
+ export { getConfig, setConfig, createConfig, initConfig, DEVNET_CONFIG, DEVNET_REGTEST_CONFIG, MAINNET_CONFIG, LOCALNET_CONFIG, TOKEN_PROGRAM_ID, TOKEN_2022_PROGRAM_ID, ATA_PROGRAM_ID, UTXOPIA_POLICY_PROGRAM_ID, SDK_VERSION, DEPLOYMENT_INFO, JOINSPLIT_TREE_DEPTH, } from "./config";
114
115
  // ==========================================================================
115
116
  // PoolState account layout + fee arithmetic
116
117
  // ==========================================================================
@@ -126,7 +127,7 @@ poolStateSeeds, commitmentTreeSeeds, tokenConfigSeeds, poolConfigSeeds, nullifie
126
127
  // ==========================================================================
127
128
  // Stealth address utilities
128
129
  // ==========================================================================
129
- export { createStealthDeposit, createStealthDepositWithKeys, createStealthOutput, createStealthOutputWithKeys, createStealthOutputForCommitment, packStealthOutputForCircuit, scanAnnouncements, scanAnnouncementsViewOnly, scanAnnouncementsViewOnlyMulti, exportViewOnlyKeys, encodeViewOnlyKeys, decodeViewOnlyKeys, prepareClaimInputs, scanUnifiedNotes, scanUnifiedNotesMulti, encryptAmount, decryptAmount, computeNullifierHashForNote, computeNullifierBytes, parseAnnouncementsFromHex, createDepositFromConfig, createDirectVaultDeposit, isDepositForViewer, isDepositForViewerHex, ANNOUNCEMENT_TYPE_DEPOSIT, ANNOUNCEMENT_TYPE_TRANSFER, createNonInteractiveDeposit, pickIkaCustodyKey, } from "./stealth";
130
+ export { createStealthDeposit, createStealthDepositWithKeys, createStealthOutput, createStealthOutputWithKeys, createStealthOutputForCommitment, packStealthOutputForCircuit, scanAnnouncements, scanAnnouncementsViewOnly, scanAnnouncementsViewOnlyMulti, exportViewOnlyKeys, encodeViewOnlyKeys, decodeViewOnlyKeys, prepareClaimInputs, scanUnifiedNotes, scanUnifiedNotesMulti, encryptAmount, decryptAmount, computeNullifierHashForNote, computeNullifierBytes, parseAnnouncementsFromHex, createDepositFromConfig, createDirectVaultDeposit, createTweakDeposit, depositEphemeralKeyPair, depositViewingNode, outgoingViewingNode, outgoingEphemeralKeyPair, findNextSendIndex, isDepositForViewer, isDepositForViewerHex, ANNOUNCEMENT_TYPE_DEPOSIT, ANNOUNCEMENT_TYPE_TRANSFER, createNonInteractiveDeposit, pickIkaCustodyKey, } from "./stealth";
130
131
  // ==========================================================================
131
132
  // PSBT builder for wallet-integrated deposits
132
133
  // ==========================================================================
@@ -180,7 +181,7 @@ buildRotateTreeInstructionData, buildRotateTreeInstruction,
180
181
  // MagicBlock lifecycle
181
182
  buildMagicBlockDelegateInstructionData, buildMagicBlockDelegateInstruction, buildMagicBlockCommitInstructionData, buildMagicBlockCommitInstruction, buildMagicBlockPerPermissionInstructionData, buildMagicBlockPerPermissionInstruction, buildPolicyRequestHash, buildPolicyIntentParts, buildRegisterExitDestinationInstruction, buildRegisterExitDestinationInstructionData, MAX_POLICY_INTENT_PARTS, buildInitializePolicyApprovalInstructionData, buildInitializePolicyApprovalInstruction, buildPolicyApprovalDecisionInstruction, buildPolicyApprovalCommitInstruction, buildCompleteDepositPermissionedInstructionData, buildCompleteDepositPermissionedInstruction, buildShieldPermissionedInstructionData, buildShieldPermissionedInstruction, buildRotateAuditorInstructionData, buildRotateAuditorInstruction,
182
183
  // Verify instruction data builders
183
- buildVerifyTransactionInstructionData, buildCompleteDepositInstructionData,
184
+ buildVerifyTransactionInstructionData, buildCompleteDepositInstructionData, buildVerifyDepositInstructionData, buildVerifyDepositPermissionedInstructionData,
184
185
  // Pool config (disc 2) builder + parser
185
186
  buildSetPoolConfigInstructionData, parsePoolConfig, POOL_CONFIG_DISCRIMINATOR, POOL_CONFIG_LEN, POOL_SCRIPT_MAX_LEN, } from "./instructions";
186
187
  // ==========================================================================
@@ -32,10 +32,13 @@ export declare const INSTRUCTION_DISCRIMINATORS: {
32
32
  readonly CLAIM_FEES: 10;
33
33
  readonly COMPLETE_DEPOSIT: 11;
34
34
  readonly SHIELD: 12;
35
+ /** OP_RETURN-free deposit: note keys ride in instruction data, proven by the
36
+ * deposit address's tapleaf. */
37
+ readonly VERIFY_DEPOSIT: 25;
35
38
  readonly TRANSACT: 13;
36
39
  readonly UNSHIELD: 14;
37
40
  readonly REDEEM: 15;
38
- readonly RESERVED_REQUEST_REDEMPTION: 16;
41
+ readonly FREEZE_VK_REGISTRY: 16;
39
42
  readonly COMPLETE_REDEMPTION: 17;
40
43
  readonly MARK_PROCESSING: 18;
41
44
  readonly CANCEL_REDEMPTION: 19;
@@ -113,6 +116,17 @@ export interface CompleteRedemptionInstructionOptions {
113
116
  poolVault: Address;
114
117
  completionReceipt: Address;
115
118
  poolConfig: Address;
119
+ /** HeightIndex PDA for the VerifiedTransaction's block —
120
+ * `deriveHeightIndexPDA(blockHeight, config.btcLightClientProgramId)`.
121
+ *
122
+ * REQUIRED. The program re-checks that the proof's block is still the canonical one at
123
+ * that height before it settles (audit_1 F-BTC-04): a VerifiedTransaction records a merkle
124
+ * proof that was valid once and is never invalidated, and the confirmation count is taken
125
+ * against a tip that only grows, so neither notices a reorg. Omitting this fails with
126
+ * InvalidSpvProof — the program locates the account by address, so its position in the
127
+ * list does not matter, but its absence is an error rather than a skipped check.
128
+ */
129
+ heightIndex: Address;
116
130
  /** Change UTXO PDA. Required when poolScript is non-empty. */
117
131
  changeUtxo?: Address;
118
132
  /** zkBTC TokenConfig PDA (credits protocol revenue) */
@@ -135,6 +149,17 @@ export interface ApproveRedemptionSigningInstructionOptions {
135
149
  redemptionRequest: Address;
136
150
  authority: Address;
137
151
  poolConfig: Address;
152
+ /** HeightIndex PDA for the VerifiedTransaction's block —
153
+ * `deriveHeightIndexPDA(blockHeight, config.btcLightClientProgramId)`.
154
+ *
155
+ * REQUIRED. The program re-checks that the proof's block is still the canonical one at
156
+ * that height before it settles (audit_1 F-BTC-04): a VerifiedTransaction records a merkle
157
+ * proof that was valid once and is never invalidated, and the confirmation count is taken
158
+ * against a tip that only grows, so neither notices a reorg. Omitting this fails with
159
+ * InvalidSpvProof — the program locates the account by address, so its position in the
160
+ * list does not matter, but its absence is an error rather than a skipped check.
161
+ */
162
+ heightIndex: Address;
138
163
  ikaProgram: Address;
139
164
  ikaCoordinator: Address;
140
165
  ikaMessageApproval: Address;
@@ -732,6 +757,55 @@ export declare function buildCompleteDepositInstructionData(params: {
732
757
  depositTxSize: number;
733
758
  depositTxid: Uint8Array;
734
759
  }): Uint8Array;
760
+ /**
761
+ * Build utxopia verify_deposit instruction data (disc=25).
762
+ *
763
+ * The OP_RETURN-free deposit path. `notePublicKey` + `ephemeralPubkey` travel in
764
+ * instruction data instead of in the Bitcoin transaction, and the program proves
765
+ * them against the deposit output's tapleaf — a different key pair derives a
766
+ * different leaf, and so a different address, which the funding transaction did
767
+ * not pay. Nothing marks the deposit as a UTXOpia transaction on chain, so any
768
+ * wallet or exchange that can send to a P2TR address can fund it.
769
+ *
770
+ * Derive the address with `deriveDepositAddress(depositTweakCommitment(npk, eph),
771
+ * ikaXOnlyPubkey)`. Both keys are hashed into the leaf, so a caller cannot swap
772
+ * in an ephemeral key that leaves the note undiscoverable.
773
+ *
774
+ * No sweep: the deposit output's tapleaf names the pool's own dWallet key, so it
775
+ * is already under pool custody and is recorded as a pool UTXO directly. The
776
+ * SPV-verified transaction must therefore BE the deposit — `depositTxSize` is 0
777
+ * and `depositTxid` defaults to `sweepTxid`. The receipt PDA is seeded
778
+ * `["deposit_receipt", txid, vout]`, so pass `depositVout` to
779
+ * `deriveDepositReceiptPDA` for this flow.
780
+ *
781
+ * Layout: disc(1) + sweep_txid(32) + block_height(u64 LE) + sweep_tx_size(u32 LE)
782
+ * + deposit_tx_size(u32 LE) + deposit_txid(32) + ephemeral_pubkey(32)
783
+ * + note_public_key(32) + deposit_vout(u32 LE) = 149 bytes
784
+ */
785
+ export declare function buildVerifyDepositInstructionData(params: {
786
+ sweepTxid: Uint8Array;
787
+ blockHeight: number;
788
+ sweepTxSize: number;
789
+ depositTxSize?: number;
790
+ depositTxid?: Uint8Array;
791
+ ephemeralPubkey: Uint8Array;
792
+ notePublicKey: Uint8Array;
793
+ depositVout: number;
794
+ }): Uint8Array;
795
+ /**
796
+ * Build utxopia verify_deposit_permissioned instruction data (disc=26).
797
+ *
798
+ * `buildVerifyDepositInstructionData`'s payload with a different discriminator
799
+ * and an auditor ciphertext appended. The tapleaf already tells the pools apart —
800
+ * each carries its own Ika custody key — but that is not the same as clearing the
801
+ * pool's policy, which is what a permissioned pool exists for.
802
+ *
803
+ * The one-time PolicyApproval is bound to the WHOLE payload, ciphertext included,
804
+ * so these exact bytes must be the ones approved.
805
+ */
806
+ export declare function buildVerifyDepositPermissionedInstructionData(params: Parameters<typeof buildVerifyDepositInstructionData>[0] & {
807
+ auditorCiphertext?: Uint8Array;
808
+ }): Uint8Array;
735
809
  /** PoolConfig account discriminator (0x0a) */
736
810
  export declare const POOL_CONFIG_DISCRIMINATOR = 10;
737
811
  /** Serialized PoolConfig account length (bytes) */
@@ -901,6 +975,17 @@ export interface CompleteDepositPermissionedOptions {
901
975
  tokenConfig: Address;
902
976
  /** 14. pool_config PDA (readonly) */
903
977
  poolConfig: Address;
978
+ /** HeightIndex PDA for the VerifiedTransaction's block —
979
+ * `deriveHeightIndexPDA(blockHeight, config.btcLightClientProgramId)`.
980
+ *
981
+ * REQUIRED. The program re-checks that the proof's block is still the canonical one at
982
+ * that height before it settles (audit_1 F-BTC-04): a VerifiedTransaction records a merkle
983
+ * proof that was valid once and is never invalidated, and the confirmation count is taken
984
+ * against a tip that only grows, so neither notices a reorg. Omitting this fails with
985
+ * InvalidSpvProof — the program locates the account by address, so its position in the
986
+ * list does not matter, but its absence is an error rather than a skipped check.
987
+ */
988
+ heightIndex: Address;
904
989
  /** 15. one-time PolicyApproval (writable) */
905
990
  policyApproval: Address;
906
991
  };
@@ -944,6 +1029,8 @@ export declare function buildCompleteDepositPermissionedInstructionData(options:
944
1029
  * 13. token_config (writable)
945
1030
  * 14. pool_config (readonly)
946
1031
  * 15. policy_approval (writable)
1032
+ * 16. policy_program (readonly)
1033
+ * 17. height_index (readonly) — canonicality re-check, located by address
947
1034
  */
948
1035
  export declare function buildCompleteDepositPermissionedInstruction(options: CompleteDepositPermissionedOptions): Instruction;
949
1036
  /** shieldPermissioned instruction options */
@@ -8,6 +8,7 @@
8
8
  */
9
9
  import { AccountRole, } from "@solana/kit";
10
10
  import { sha256 } from "@noble/hashes/sha2.js";
11
+ import { bytesToHex as toHex } from "./crypto";
11
12
  import { address, getConfig, TOKEN_2022_PROGRAM_ID } from "./config";
12
13
  import { resolveAuditorCiphertext } from "./auditor-ciphertext";
13
14
  import { MAGICBLOCK_EPHEMERAL_VAULT_ID, MAGICBLOCK_DELEGATION_PROGRAM_ID, MAGICBLOCK_MAGIC_CONTEXT_ID, MAGICBLOCK_MAGIC_PROGRAM_ID, MAGICBLOCK_MAX_PER_MEMBERS, MAGICBLOCK_PERMISSION_PROGRAM_ID, MAGICBLOCK_PER_MEMBER_FLAGS, } from "./magicblock";
@@ -33,15 +34,19 @@ const INSTRUCTION = {
33
34
  REGISTER_TOKEN: 8,
34
35
  UPDATE_TOKEN_CONFIG: 9,
35
36
  CLAIM_FEES: 10,
36
- // Deposit (11-12)
37
+ // Deposit (11-12, 25)
37
38
  COMPLETE_DEPOSIT: 11,
38
39
  SHIELD: 12,
40
+ /** OP_RETURN-free deposit: note keys ride in instruction data, proven by the
41
+ * deposit address's tapleaf. */
42
+ VERIFY_DEPOSIT: 25,
39
43
  // JoinSplit (13-15) — all share n_in + n_out + n_pub + proof_source header
40
44
  TRANSACT: 13,
41
45
  UNSHIELD: 14,
42
46
  REDEEM: 15,
43
- // Redemption lifecycle (16-19)
44
- RESERVED_REQUEST_REDEMPTION: 16,
47
+ // VK registry freeze (16) — NOT part of the redemption range below
48
+ FREEZE_VK_REGISTRY: 16,
49
+ // Redemption lifecycle (17-19)
45
50
  COMPLETE_REDEMPTION: 17,
46
51
  MARK_PROCESSING: 18,
47
52
  CANCEL_REDEMPTION: 19,
@@ -68,6 +73,8 @@ const INSTRUCTION = {
68
73
  const PERMISSIONED_DISC = {
69
74
  INITIALIZE_PERMISSIONED: 21,
70
75
  COMPLETE_DEPOSIT_PERMISSIONED: 22,
76
+ /** Same binding as VERIFY_DEPOSIT, plus the permissioned pool's policy gate. */
77
+ VERIFY_DEPOSIT_PERMISSIONED: 26,
71
78
  SHIELD_PERMISSIONED: 23,
72
79
  REGISTER_EXIT_DESTINATION: 39,
73
80
  };
@@ -308,6 +315,9 @@ export function buildCompleteRedemptionInstruction(options) {
308
315
  }
309
316
  }
310
317
  accounts.push({ address: options.accounts.tokenConfig, role: AccountRole.WRITABLE });
318
+ // Located by address, so the trailing position is free — this instruction already has a
319
+ // variable tail (change UTXO, consumed UTXOs) and the program scans rather than indexing.
320
+ accounts.push({ address: options.accounts.heightIndex, role: AccountRole.READONLY });
311
321
  return {
312
322
  programAddress: config.utxopiaProgramId,
313
323
  accounts,
@@ -1297,6 +1307,94 @@ export function buildCompleteDepositInstructionData(params) {
1297
1307
  return data;
1298
1308
  }
1299
1309
  // =============================================================================
1310
+ // UTXOpia Verify Deposit (disc=25) — OP_RETURN-free
1311
+ // =============================================================================
1312
+ /**
1313
+ * Build utxopia verify_deposit instruction data (disc=25).
1314
+ *
1315
+ * The OP_RETURN-free deposit path. `notePublicKey` + `ephemeralPubkey` travel in
1316
+ * instruction data instead of in the Bitcoin transaction, and the program proves
1317
+ * them against the deposit output's tapleaf — a different key pair derives a
1318
+ * different leaf, and so a different address, which the funding transaction did
1319
+ * not pay. Nothing marks the deposit as a UTXOpia transaction on chain, so any
1320
+ * wallet or exchange that can send to a P2TR address can fund it.
1321
+ *
1322
+ * Derive the address with `deriveDepositAddress(depositTweakCommitment(npk, eph),
1323
+ * ikaXOnlyPubkey)`. Both keys are hashed into the leaf, so a caller cannot swap
1324
+ * in an ephemeral key that leaves the note undiscoverable.
1325
+ *
1326
+ * No sweep: the deposit output's tapleaf names the pool's own dWallet key, so it
1327
+ * is already under pool custody and is recorded as a pool UTXO directly. The
1328
+ * SPV-verified transaction must therefore BE the deposit — `depositTxSize` is 0
1329
+ * and `depositTxid` defaults to `sweepTxid`. The receipt PDA is seeded
1330
+ * `["deposit_receipt", txid, vout]`, so pass `depositVout` to
1331
+ * `deriveDepositReceiptPDA` for this flow.
1332
+ *
1333
+ * Layout: disc(1) + sweep_txid(32) + block_height(u64 LE) + sweep_tx_size(u32 LE)
1334
+ * + deposit_tx_size(u32 LE) + deposit_txid(32) + ephemeral_pubkey(32)
1335
+ * + note_public_key(32) + deposit_vout(u32 LE) = 149 bytes
1336
+ */
1337
+ export function buildVerifyDepositInstructionData(params) {
1338
+ const depositTxid = params.depositTxid ?? params.sweepTxid;
1339
+ for (const [name, value] of [
1340
+ ["sweepTxid", params.sweepTxid],
1341
+ ["depositTxid", depositTxid],
1342
+ ["ephemeralPubkey", params.ephemeralPubkey],
1343
+ ["notePublicKey", params.notePublicKey],
1344
+ ]) {
1345
+ if (value.length !== 32) {
1346
+ throw new Error(`${name} must be 32 bytes, got ${value.length}`);
1347
+ }
1348
+ }
1349
+ if (params.depositTxSize) {
1350
+ throw new Error("verify_deposit takes no second transaction: depositTxSize must be 0");
1351
+ }
1352
+ if (toHex(depositTxid) !== toHex(params.sweepTxid)) {
1353
+ throw new Error("verify_deposit proves the deposit itself: depositTxid must equal sweepTxid");
1354
+ }
1355
+ const data = new Uint8Array(149);
1356
+ const view = new DataView(data.buffer);
1357
+ let offset = 0;
1358
+ data[offset++] = INSTRUCTION.VERIFY_DEPOSIT;
1359
+ data.set(params.sweepTxid, offset);
1360
+ offset += 32;
1361
+ view.setBigUint64(offset, BigInt(params.blockHeight), true);
1362
+ offset += 8;
1363
+ view.setUint32(offset, params.sweepTxSize, true);
1364
+ offset += 4;
1365
+ view.setUint32(offset, 0, true);
1366
+ offset += 4; // no second transaction
1367
+ data.set(depositTxid, offset);
1368
+ offset += 32;
1369
+ data.set(params.ephemeralPubkey, offset);
1370
+ offset += 32;
1371
+ data.set(params.notePublicKey, offset);
1372
+ offset += 32;
1373
+ view.setUint32(offset, params.depositVout, true);
1374
+ offset += 4;
1375
+ return data;
1376
+ }
1377
+ /**
1378
+ * Build utxopia verify_deposit_permissioned instruction data (disc=26).
1379
+ *
1380
+ * `buildVerifyDepositInstructionData`'s payload with a different discriminator
1381
+ * and an auditor ciphertext appended. The tapleaf already tells the pools apart —
1382
+ * each carries its own Ika custody key — but that is not the same as clearing the
1383
+ * pool's policy, which is what a permissioned pool exists for.
1384
+ *
1385
+ * The one-time PolicyApproval is bound to the WHOLE payload, ciphertext included,
1386
+ * so these exact bytes must be the ones approved.
1387
+ */
1388
+ export function buildVerifyDepositPermissionedInstructionData(params) {
1389
+ const base = buildVerifyDepositInstructionData(params);
1390
+ const ciphertext = params.auditorCiphertext ?? new Uint8Array(0);
1391
+ const data = new Uint8Array(base.length + ciphertext.length);
1392
+ data.set(base, 0);
1393
+ data.set(ciphertext, base.length);
1394
+ data[0] = PERMISSIONED_DISC.VERIFY_DEPOSIT_PERMISSIONED;
1395
+ return data;
1396
+ }
1397
+ // =============================================================================
1300
1398
  // UTXOpia Set Pool Config (disc=2)
1301
1399
  // =============================================================================
1302
1400
  /** PoolConfig account discriminator (0x0a) */
@@ -1523,6 +1621,8 @@ export function buildCompleteDepositPermissionedInstructionData(options) {
1523
1621
  * 13. token_config (writable)
1524
1622
  * 14. pool_config (readonly)
1525
1623
  * 15. policy_approval (writable)
1624
+ * 16. policy_program (readonly)
1625
+ * 17. height_index (readonly) — canonicality re-check, located by address
1526
1626
  */
1527
1627
  export function buildCompleteDepositPermissionedInstruction(options) {
1528
1628
  const config = getConfig();
@@ -1554,6 +1654,7 @@ export function buildCompleteDepositPermissionedInstruction(options) {
1554
1654
  { address: options.accounts.poolConfig, role: AccountRole.READONLY },
1555
1655
  { address: options.accounts.policyApproval, role: AccountRole.WRITABLE },
1556
1656
  { address: config.policyProgramId ?? config.utxopiaProgramId, role: AccountRole.READONLY },
1657
+ { address: options.accounts.heightIndex, role: AccountRole.READONLY },
1557
1658
  ],
1558
1659
  data,
1559
1660
  };