@utxopia/sdk 0.1.0-alpha.1

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 (94) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +171 -0
  3. package/package.json +108 -0
  4. package/packages/btc-client/src/esplora-client.ts +153 -0
  5. package/packages/btc-client/src/index.ts +3 -0
  6. package/packages/btc-client/src/op-return.ts +93 -0
  7. package/packages/btc-client/src/types.ts +112 -0
  8. package/packages/sdk/README.md +277 -0
  9. package/packages/sdk/dist/announcement-client.d.ts +64 -0
  10. package/packages/sdk/dist/announcement-client.js +337 -0
  11. package/packages/sdk/dist/auditor-ciphertext.d.ts +72 -0
  12. package/packages/sdk/dist/auditor-ciphertext.js +135 -0
  13. package/packages/sdk/dist/auditor.d.ts +115 -0
  14. package/packages/sdk/dist/auditor.js +292 -0
  15. package/packages/sdk/dist/bitcoin/ika.d.ts +47 -0
  16. package/packages/sdk/dist/bitcoin/ika.js +74 -0
  17. package/packages/sdk/dist/bitcoin/index.d.ts +2 -0
  18. package/packages/sdk/dist/bitcoin/index.js +1 -0
  19. package/packages/sdk/dist/bound-params.d.ts +96 -0
  20. package/packages/sdk/dist/bound-params.js +249 -0
  21. package/packages/sdk/dist/chadbuffer.d.ts +124 -0
  22. package/packages/sdk/dist/chadbuffer.js +405 -0
  23. package/packages/sdk/dist/claim-link.d.ts +30 -0
  24. package/packages/sdk/dist/claim-link.js +50 -0
  25. package/packages/sdk/dist/client.d.ts +233 -0
  26. package/packages/sdk/dist/client.js +416 -0
  27. package/packages/sdk/dist/commitment-tree.d.ts +268 -0
  28. package/packages/sdk/dist/commitment-tree.js +564 -0
  29. package/packages/sdk/dist/config.d.ts +177 -0
  30. package/packages/sdk/dist/config.js +426 -0
  31. package/packages/sdk/dist/core/esplora.d.ts +110 -0
  32. package/packages/sdk/dist/core/esplora.js +187 -0
  33. package/packages/sdk/dist/core/mempool.d.ts +60 -0
  34. package/packages/sdk/dist/core/mempool.js +107 -0
  35. package/packages/sdk/dist/crypto-babyjub.d.ts +105 -0
  36. package/packages/sdk/dist/crypto-babyjub.js +312 -0
  37. package/packages/sdk/dist/crypto-ed25519.d.ts +116 -0
  38. package/packages/sdk/dist/crypto-ed25519.js +235 -0
  39. package/packages/sdk/dist/crypto.d.ts +59 -0
  40. package/packages/sdk/dist/crypto.js +140 -0
  41. package/packages/sdk/dist/event-client.d.ts +64 -0
  42. package/packages/sdk/dist/event-client.js +165 -0
  43. package/packages/sdk/dist/events.d.ts +127 -0
  44. package/packages/sdk/dist/events.js +305 -0
  45. package/packages/sdk/dist/explorer.d.ts +86 -0
  46. package/packages/sdk/dist/explorer.js +197 -0
  47. package/packages/sdk/dist/index.d.ts +61 -0
  48. package/packages/sdk/dist/index.js +216 -0
  49. package/packages/sdk/dist/instructions.d.ts +1125 -0
  50. package/packages/sdk/dist/instructions.js +1760 -0
  51. package/packages/sdk/dist/keys.d.ts +467 -0
  52. package/packages/sdk/dist/keys.js +799 -0
  53. package/packages/sdk/dist/logger.d.ts +10 -0
  54. package/packages/sdk/dist/logger.js +40 -0
  55. package/packages/sdk/dist/magicblock.d.ts +90 -0
  56. package/packages/sdk/dist/magicblock.js +164 -0
  57. package/packages/sdk/dist/merkle.d.ts +82 -0
  58. package/packages/sdk/dist/merkle.js +141 -0
  59. package/packages/sdk/dist/note.d.ts +348 -0
  60. package/packages/sdk/dist/note.js +483 -0
  61. package/packages/sdk/dist/pda.d.ts +160 -0
  62. package/packages/sdk/dist/pda.js +384 -0
  63. package/packages/sdk/dist/pool-state.d.ts +100 -0
  64. package/packages/sdk/dist/pool-state.js +126 -0
  65. package/packages/sdk/dist/poseidon.d.ts +53 -0
  66. package/packages/sdk/dist/poseidon.js +136 -0
  67. package/packages/sdk/dist/prover/index.d.ts +10 -0
  68. package/packages/sdk/dist/prover/index.js +10 -0
  69. package/packages/sdk/dist/prover/mobile.d.ts +45 -0
  70. package/packages/sdk/dist/prover/mobile.js +227 -0
  71. package/packages/sdk/dist/prover/web.d.ts +136 -0
  72. package/packages/sdk/dist/prover/web.js +597 -0
  73. package/packages/sdk/dist/psbt.d.ts +73 -0
  74. package/packages/sdk/dist/psbt.js +202 -0
  75. package/packages/sdk/dist/selective-disclosure.d.ts +181 -0
  76. package/packages/sdk/dist/selective-disclosure.js +172 -0
  77. package/packages/sdk/dist/sender-memo.d.ts +149 -0
  78. package/packages/sdk/dist/sender-memo.js +250 -0
  79. package/packages/sdk/dist/sns-resolver.d.ts +121 -0
  80. package/packages/sdk/dist/sns-resolver.js +229 -0
  81. package/packages/sdk/dist/solana/connection.d.ts +77 -0
  82. package/packages/sdk/dist/solana/connection.js +133 -0
  83. package/packages/sdk/dist/solana/priority-fee.d.ts +78 -0
  84. package/packages/sdk/dist/solana/priority-fee.js +137 -0
  85. package/packages/sdk/dist/stealth.d.ts +429 -0
  86. package/packages/sdk/dist/stealth.js +703 -0
  87. package/packages/sdk/dist/taproot.d.ts +172 -0
  88. package/packages/sdk/dist/taproot.js +494 -0
  89. package/packages/sdk/dist/token-registry.d.ts +96 -0
  90. package/packages/sdk/dist/token-registry.js +122 -0
  91. package/packages/sdk/dist/utils/encoding.d.ts +19 -0
  92. package/packages/sdk/dist/utils/encoding.js +29 -0
  93. package/packages/sdk/dist/vk-registry.d.ts +100 -0
  94. package/packages/sdk/dist/vk-registry.js +212 -0
@@ -0,0 +1,429 @@
1
+ /**
2
+ * Stealth address utilities for UTXOPIA
3
+ *
4
+ * Dual-curve stealth flow (Railgun-style):
5
+ *
6
+ * Stealth Deposit Flow:
7
+ * ```
8
+ * Sender:
9
+ * 1. ephemeral = random Ed25519 keypair
10
+ * 2. sharedSecret = X25519(ephemeral.priv, recipientViewingPub)
11
+ * 3. stealthScalar = SHA256(sharedSecret || domain) mod BJJ_ORDER
12
+ * 4. stealthPub = spendingPub + stealthScalar × BASE8 (Baby Jubjub)
13
+ * 5. commitment = Poseidon(stealthPub.x, amount)
14
+ * 6. encryptedAmount = amount XOR sha256(sharedSecret)[0..8]
15
+ *
16
+ * Recipient (viewing key only - can detect and see amount):
17
+ * 1. sharedSecret = X25519(viewingPriv, ephemeralPub)
18
+ * 2. amount = encryptedAmount XOR sha256(sharedSecret)[0..8]
19
+ * 3. stealthPub = spendingPub + stealthScalar × BASE8
20
+ * 4. Verify: commitment == Poseidon(stealthPub.x, amount)
21
+ *
22
+ * Recipient (spending key - can claim):
23
+ * 1. stealthPriv = spendingPriv + stealthScalar (mod BJJ_ORDER)
24
+ * 2. nullifier = Poseidon(stealthPriv, leafIndex)
25
+ * ```
26
+ *
27
+ * Format (90 bytes on-chain):
28
+ * - ephemeral_pub (32 bytes) - Ed25519 public key
29
+ * - encrypted_amount (8 bytes) - XOR encrypted with shared secret
30
+ * - commitment (32 bytes) - Poseidon hash for Merkle tree
31
+ * - leaf_index (8 bytes) - Position in Merkle tree
32
+ * - created_at (8 bytes) - Timestamp
33
+ */
34
+ /** Announcement type: deposit (plaintext amount) */
35
+ export declare const ANNOUNCEMENT_TYPE_DEPOSIT = 0;
36
+ /** Announcement type: transfer (XOR-encrypted amount) */
37
+ export declare const ANNOUNCEMENT_TYPE_TRANSFER = 1;
38
+ import { type BabyJubPoint } from "./crypto";
39
+ import type { StealthMetaAddress, UTXOpiaKeys, WalletSignerAdapter } from "./keys";
40
+ import type { DepositOpReturnContext } from "./taproot";
41
+ /**
42
+ * Encrypt amount using XOR with shared secret
43
+ */
44
+ export declare function encryptAmount(amount: bigint, sharedSecret: Uint8Array): Uint8Array;
45
+ /**
46
+ * Decrypt amount using XOR with shared secret
47
+ */
48
+ export declare function decryptAmount(encryptedAmount: Uint8Array, sharedSecret: Uint8Array): bigint;
49
+ export { encryptNoteData, decryptNoteData } from "./crypto-ed25519";
50
+ /**
51
+ * Type guard to distinguish between WalletSignerAdapter and UTXOpiaKeys
52
+ */
53
+ export declare function isWalletAdapter(source: unknown): source is WalletSignerAdapter;
54
+ /**
55
+ * Stealth Deposit with single Ed25519 ephemeral key
56
+ */
57
+ export interface StealthDeposit {
58
+ /** Ed25519 ephemeral public key (32 bytes) */
59
+ ephemeralPub: Uint8Array;
60
+ /** Encrypted amount (8 bytes) */
61
+ encryptedAmount: Uint8Array;
62
+ /** Commitment for Merkle tree (32 bytes) - Poseidon(stealthPub.x, amount) */
63
+ commitment: Uint8Array;
64
+ /** Unix timestamp when created */
65
+ createdAt: number;
66
+ }
67
+ /**
68
+ * Scanned note from announcement (viewing key can detect)
69
+ */
70
+ export interface ScannedNote {
71
+ /** Amount in satoshis */
72
+ amount: bigint;
73
+ /** Ed25519 ephemeral public key (needed for shared secret) */
74
+ ephemeralPub: Uint8Array;
75
+ /** Computed stealth public key (Baby Jubjub) */
76
+ stealthPub: BabyJubPoint;
77
+ /** Leaf index in Merkle tree */
78
+ leafIndex: number;
79
+ /** Original announcement commitment */
80
+ commitment: Uint8Array;
81
+ /** Unix timestamp (seconds) from on-chain block_time, 0 if unavailable */
82
+ blockTime?: number;
83
+ }
84
+ /**
85
+ * Prepared claim inputs for JoinSplit ZK proof (requires spending key)
86
+ */
87
+ export interface ClaimInputs {
88
+ stealthPrivKey: bigint;
89
+ nullifyingKey: bigint;
90
+ amount: bigint;
91
+ leafIndex: number;
92
+ merklePath: bigint[];
93
+ merkleIndices: number[];
94
+ merkleRoot: bigint;
95
+ nullifier: bigint;
96
+ npk: bigint;
97
+ random: bigint;
98
+ }
99
+ /**
100
+ * Parsed stealth announcement from on-chain data
101
+ */
102
+ export interface OnChainStealthAnnouncement {
103
+ /** 0 = deposit (plaintext amount), 1 = transfer (encrypted amount) */
104
+ announcementType: number;
105
+ ephemeralPub: Uint8Array;
106
+ /** Raw amount bytes: plaintext if type=0, encrypted if type=1 */
107
+ encryptedAmount: Uint8Array;
108
+ /** Commitment = Poseidon(npk, token, amount) stored on-chain */
109
+ commitment: Uint8Array;
110
+ leafIndex: number;
111
+ /** Unix timestamp (seconds) from on-chain block_time, 0 if unavailable */
112
+ blockTime?: number;
113
+ /** Solana slot the announcement was emitted in. Needed for auditor slot-range scoping. */
114
+ slot?: number;
115
+ /** Token id hex from the backend indexer, when available. */
116
+ tokenIdHex?: string;
117
+ }
118
+ /**
119
+ * Create a stealth deposit (JoinSplit-compatible)
120
+ *
121
+ * 1. Generate Ed25519 ephemeral keypair
122
+ * 2. sharedSecret = X25519(ephemeral.priv, viewingPub)
123
+ * 3. stealthPub = spendingPub + hash(sharedSecret) × BASE8
124
+ * 4. stealthMPK = Poseidon(stealthPub.x, stealthPub.y, nullifyingKey)
125
+ * (sender uses recipientMPK from meta-address for stealth deposits)
126
+ * 5. npk = Poseidon(recipientMPK, random)
127
+ * 6. commitment = Poseidon(npk, tokenId, amount)
128
+ * 7. encryptedAmount = amount XOR sha256(sharedSecret)[0..8]
129
+ */
130
+ export declare function createStealthDeposit(recipientMeta: StealthMetaAddress, amountSats: bigint, tokenId: bigint): Promise<StealthDeposit>;
131
+ /**
132
+ * Extended stealth output data including the derived stealth pub key
133
+ */
134
+ export interface StealthOutputWithKeys extends StealthOutputData {
135
+ stealthPubKeyX: bigint;
136
+ /** npk as 32-byte LE Uint8Array — ready for on-chain instruction data */
137
+ npkBytes: Uint8Array;
138
+ }
139
+ /**
140
+ * Create stealth deposit with npk for JoinSplit circuit input
141
+ */
142
+ export declare function createStealthDepositWithKeys(recipientMeta: StealthMetaAddress, amountSats: bigint, tokenId: bigint): Promise<StealthOutputWithKeys>;
143
+ /**
144
+ * Result of a non-interactive deposit preparation.
145
+ * Contains everything needed to build a PSBT with an OP_RETURN output.
146
+ *
147
+ * npk-based flow: user can send any amount of BTC. The commitment is
148
+ * computed on-chain from npk + actual amount.
149
+ */
150
+ export interface NonInteractiveDepositResult {
151
+ /** Taproot address to send BTC to */
152
+ btcAddress: string;
153
+ /** 32-byte x-only output key for the deposit P2TR output */
154
+ depositOutputKey: Uint8Array;
155
+ /** 73-byte OP_RETURN payload: header || poolTag || ephemeralPub || npk */
156
+ opReturnPayload: Uint8Array;
157
+ /** 32-byte note public key (for tracking) */
158
+ npk: Uint8Array;
159
+ /** 32-byte Ed25519 ephemeral public key */
160
+ ephemeralPub: Uint8Array;
161
+ }
162
+ /**
163
+ * Extended result when a user refund pubkey is provided.
164
+ * Includes Taproot script-path data for the refund spending path.
165
+ */
166
+ export interface NonInteractiveDepositWithRefundResult extends NonInteractiveDepositResult {
167
+ /** 32-byte Merkle root (TapLeaf hash of the refund script) */
168
+ merkleRoot: Uint8Array;
169
+ /** 33-byte control block for script-path spend (leaf_version|parity + internal_key) */
170
+ controlBlock: Uint8Array;
171
+ /** 73-byte refund script */
172
+ refundScript: Uint8Array;
173
+ }
174
+ /**
175
+ * Create a non-interactive stealth deposit (npk-based).
176
+ *
177
+ * This is the client-side-only deposit flow: no backend API call needed.
178
+ * The ephemeral key and npk are embedded in the BTC transaction's OP_RETURN
179
+ * output so the backend can passively detect them.
180
+ *
181
+ * The user can send ANY amount of BTC — the commitment is computed on-chain
182
+ * from the npk + actual BTC amount received.
183
+ *
184
+ * When `userRefundPubkey` is provided, the Taproot address includes a
185
+ * script-path with a time-locked refund spending condition (144 blocks).
186
+ *
187
+ * @param recipientMeta - Recipient's stealth meta-address
188
+ * @param custodyInternalKey - Pool custody x-only pubkey (32 bytes), used as the Taproot internal key
189
+ * @param network - Bitcoin network for address encoding
190
+ * @param userRefundPubkey - Optional 32-byte x-only pubkey for refund script path
191
+ */
192
+ export declare function createNonInteractiveDeposit(recipientMeta: StealthMetaAddress, custodyInternalKey: Uint8Array, network?: "mainnet" | "testnet" | "regtest", userRefundPubkey?: undefined, opReturnContext?: DepositOpReturnContext): Promise<NonInteractiveDepositResult>;
193
+ export declare function createNonInteractiveDeposit(recipientMeta: StealthMetaAddress, custodyInternalKey: Uint8Array, network: "mainnet" | "testnet" | "regtest", userRefundPubkey: Uint8Array, opReturnContext: DepositOpReturnContext): Promise<NonInteractiveDepositWithRefundResult>;
194
+ /**
195
+ * Create a non-interactive deposit directly to an Ika-controlled vault.
196
+ *
197
+ * The BTC address is the raw Ika x-only Taproot witness program, so Ika can
198
+ * later sign and spend the UTXO. Privacy/ownership metadata stays per-deposit
199
+ * in OP_RETURN(header || poolTag || ephemeralPub || npk), and the destination chain
200
+ * credits the note from that transaction.
201
+ */
202
+ export declare function createDirectVaultDeposit(recipientMeta: StealthMetaAddress, vaultXOnlyPubkey: Uint8Array, network?: "mainnet" | "testnet" | "regtest", opReturnContext?: DepositOpReturnContext): Promise<NonInteractiveDepositResult>;
203
+ /**
204
+ * Create a non-interactive deposit using the current SDK config.
205
+ *
206
+ * Direct-vault/Ika deposit helper.
207
+ *
208
+ * Deposits go to the raw Ika x-only P2TR vault address. Recipient binding
209
+ * stays per-deposit in OP_RETURN(header || poolTag || ephemeralPub || npk), and the destination chain
210
+ * credits the note by SPV-verifying that deposit transaction directly. Legacy sweep-mode
211
+ * address derivation is intentionally not selected from config anymore.
212
+ */
213
+ export declare function createDepositFromConfig(recipientMeta: StealthMetaAddress, network?: "mainnet" | "testnet" | "regtest", opReturnContext?: DepositOpReturnContext): Promise<NonInteractiveDepositResult>;
214
+ export declare function isDirectVaultDepositMode(mode?: string): boolean;
215
+ /**
216
+ * Choose the Taproot internal key for deposit-address derivation.
217
+ * The Ika dWallet x-only pubkey is the sole custody key; throws if unset.
218
+ * Exported for unit tests; non-test callers should use `createDepositFromConfig`.
219
+ */
220
+ export declare function pickCustodyInternalKey(config: {
221
+ ikaDwalletXOnlyPubkey?: string;
222
+ }): Uint8Array;
223
+ export declare function pickIkaCustodyKey(config: {
224
+ ikaDwalletXOnlyPubkey?: string;
225
+ }): Uint8Array | null;
226
+ /**
227
+ * Scan announcements using viewing key only
228
+ */
229
+ export declare function scanAnnouncements(source: WalletSignerAdapter | UTXOpiaKeys, announcements: {
230
+ ephemeralPub: Uint8Array;
231
+ encryptedAmount: Uint8Array;
232
+ commitment: Uint8Array;
233
+ leafIndex: number;
234
+ }[], tokenId: bigint): Promise<ScannedNote[]>;
235
+ /**
236
+ * View-only keys for scanning without spending capability
237
+ */
238
+ export interface ViewOnlyKeys {
239
+ /** Ed25519 viewing private key (32 bytes) */
240
+ viewingPrivKey: Uint8Array;
241
+ /** Baby Jubjub spending public key */
242
+ spendingPubKey: BabyJubPoint;
243
+ /** Nullifying key (needed for MPK computation in JoinSplit scanning) */
244
+ nullifyingKey: bigint;
245
+ }
246
+ /**
247
+ * Scanned note from view-only scanning
248
+ */
249
+ export interface ViewOnlyScannedNote {
250
+ amount: bigint;
251
+ leafIndex: number;
252
+ commitment: Uint8Array;
253
+ ephemeralPub: Uint8Array;
254
+ /** Unix timestamp (seconds) from on-chain block_time, 0 if unavailable */
255
+ blockTime?: number;
256
+ }
257
+ /**
258
+ * Scan announcements with VIEW-ONLY keys against SEVERAL token ids in one pass.
259
+ * Same one-ECDH-per-announcement economics as {@link scanUnifiedNotesMulti}.
260
+ */
261
+ export declare function scanAnnouncementsViewOnlyMulti(viewOnlyKeys: ViewOnlyKeys, announcements: {
262
+ announcementType: number;
263
+ ephemeralPub: Uint8Array;
264
+ encryptedAmount: Uint8Array;
265
+ commitment: Uint8Array;
266
+ leafIndex: number;
267
+ blockTime?: number;
268
+ }[], tokenIds: bigint[]): Promise<Array<ViewOnlyScannedNote & {
269
+ tokenId: bigint;
270
+ }>>;
271
+ /**
272
+ * Scan announcements with VIEW-ONLY keys.
273
+ * Latest announcement rows must carry an explicit type.
274
+ */
275
+ export declare function scanAnnouncementsViewOnly(viewOnlyKeys: ViewOnlyKeys, announcements: {
276
+ announcementType: number;
277
+ ephemeralPub: Uint8Array;
278
+ encryptedAmount: Uint8Array;
279
+ commitment: Uint8Array;
280
+ leafIndex: number;
281
+ blockTime?: number;
282
+ }[], tokenId: bigint): Promise<ViewOnlyScannedNote[]>;
283
+ /**
284
+ * Export view-only keys from full UTXOpiaKeys
285
+ */
286
+ export declare function exportViewOnlyKeys(keys: UTXOpiaKeys): ViewOnlyKeys;
287
+ /**
288
+ * Encode view-only keys as a hex string for sharing
289
+ * Format: viewingPrivKey(32) + compressedSpendingPub(32) + nullifyingKey(32) = 96 bytes
290
+ */
291
+ export declare function encodeViewOnlyKeys(keys: ViewOnlyKeys): string;
292
+ /**
293
+ * Decode view-only keys from a hex string
294
+ */
295
+ export declare function decodeViewOnlyKeys(encoded: string): ViewOnlyKeys;
296
+ /**
297
+ * Prepare claim inputs for ZK proof generation
298
+ */
299
+ export declare function prepareClaimInputs(source: WalletSignerAdapter | UTXOpiaKeys, note: ScannedNote, merkleProof: {
300
+ root: bigint;
301
+ pathElements: bigint[];
302
+ pathIndices: number[];
303
+ }): Promise<ClaimInputs>;
304
+ /** A note found by a multi-token scan, tagged with the token id it matched. */
305
+ export type MultiScannedNote = ScannedNote & {
306
+ tokenId: bigint;
307
+ };
308
+ /**
309
+ * Scan unified StealthAnnouncement notes (both deposits and transfers) against
310
+ * SEVERAL token ids in one pass.
311
+ *
312
+ * Prefer this over calling {@link scanUnifiedNotes} once per token: the cost is
313
+ * one ECDH per announcement either way, plus one Poseidon per token id tried.
314
+ */
315
+ export declare function scanUnifiedNotesMulti(source: WalletSignerAdapter | UTXOpiaKeys, announcements: OnChainStealthAnnouncement[], tokenIds: bigint[]): Promise<MultiScannedNote[]>;
316
+ /**
317
+ * Scan unified StealthAnnouncement notes (both deposits and transfers).
318
+ *
319
+ * For each announcement:
320
+ * - type=0 (deposit): amount is plaintext u64 LE in amount_bytes
321
+ * - type=1 (transfer): amount is XOR-encrypted in amount_bytes
322
+ *
323
+ * Commitment is computed locally: Poseidon(npk, tokenId, amount) and compared
324
+ * against the on-chain one, which is what proves the note is ours.
325
+ */
326
+ export declare function scanUnifiedNotes(source: WalletSignerAdapter | UTXOpiaKeys, announcements: OnChainStealthAnnouncement[], tokenId: bigint): Promise<ScannedNote[]>;
327
+ import type { Address } from "@solana/kit";
328
+ export interface ConnectionAdapter {
329
+ getAccountInfo: (pubkey: Address) => Promise<{
330
+ data: Uint8Array;
331
+ } | null>;
332
+ }
333
+ export interface StealthOutputData {
334
+ /** Ed25519 ephemeral public key (32 bytes) */
335
+ ephemeralPub: Uint8Array;
336
+ /** XOR encrypted amount (8 bytes) */
337
+ encryptedAmount: Uint8Array;
338
+ /** Commitment = Poseidon(stealthPub.x, amount) */
339
+ commitment: Uint8Array;
340
+ }
341
+ /**
342
+ * Circuit-ready stealth output data
343
+ */
344
+ export interface CircuitStealthOutput {
345
+ /** Ephemeral pubkey (32 bytes as bigint) */
346
+ ephemeralPubX: bigint;
347
+ /** Packed: bits 0-63 = encrypted amount, bit 64 = reserved (0 for Ed25519) */
348
+ encryptedAmountWithSign: bigint;
349
+ }
350
+ /**
351
+ * Pack encrypted amount (no y_sign needed for Ed25519 — 32-byte keys, no prefix)
352
+ *
353
+ * Layout: bits 0-63 = encrypted amount (little-endian), bit 64 = 0 (reserved)
354
+ */
355
+ export declare function packEncryptedAmountWithSign(encryptedAmount: Uint8Array, _ySign?: boolean): bigint;
356
+ /**
357
+ * Convert StealthOutputData to circuit-ready format
358
+ */
359
+ export declare function packStealthOutputForCircuit(output: StealthOutputData): CircuitStealthOutput;
360
+ /**
361
+ * Unpack encrypted amount from packed Field element
362
+ */
363
+ export declare function unpackEncryptedAmountWithSign(packed: bigint): {
364
+ encryptedAmount: Uint8Array;
365
+ ySign: boolean;
366
+ };
367
+ /**
368
+ * Create stealth output data for a self-send (change output)
369
+ */
370
+ export declare function createStealthOutput(keys: UTXOpiaKeys, amountSats: bigint, tokenId: bigint): Promise<StealthOutputData>;
371
+ /**
372
+ * Create stealth output with npk for JoinSplit circuit input
373
+ */
374
+ export declare function createStealthOutputWithKeys(keys: UTXOpiaKeys, amountSats: bigint, tokenId: bigint): Promise<StealthOutputWithKeys>;
375
+ /**
376
+ * Create stealth output data with pre-computed commitment
377
+ */
378
+ export declare function createStealthOutputForCommitment(keys: UTXOpiaKeys, amountSats: bigint, existingCommitment: Uint8Array): Promise<StealthOutputData>;
379
+ /**
380
+ * Compute nullifier hash for a scanned note
381
+ */
382
+ export declare function computeNullifierHashForNote(keys: UTXOpiaKeys, note: ScannedNote): Uint8Array;
383
+ /**
384
+ * Compute nullifier hash for a note and return as raw bytes.
385
+ * Convenience wrapper — avoids importing computeJoinSplitNullifierSync + bigintToBytes in consumers.
386
+ */
387
+ export declare function computeNullifierBytes(nullifyingKey: bigint, leafIndex: number): Uint8Array;
388
+ /**
389
+ * Parse backend announcement rows (hex strings) into the format scanUnifiedNotes expects.
390
+ */
391
+ export declare function parseAnnouncementsFromHex(rows: Array<{
392
+ announcement_type: number;
393
+ ephemeral_pub: string;
394
+ encrypted_amount: string;
395
+ commitment: string;
396
+ leaf_index: number;
397
+ token_id?: string | null;
398
+ }>): Array<{
399
+ announcementType: number;
400
+ ephemeralPub: Uint8Array;
401
+ encryptedAmount: Uint8Array;
402
+ commitment: Uint8Array;
403
+ leafIndex: number;
404
+ tokenIdHex?: string;
405
+ }>;
406
+ /**
407
+ * Check if a deposit (identified by its OP_RETURN ephemeralPub + npk) belongs
408
+ * to the given viewing key holder.
409
+ *
410
+ * Performs X25519 ECDH between the viewer's private key and the deposit's
411
+ * ephemeral public key, derives the expected NPK, and compares it with the
412
+ * deposit's actual NPK.
413
+ */
414
+ export declare function isDepositForViewer(viewingPrivKey: Uint8Array, spendingPubKey: {
415
+ x: bigint;
416
+ y: bigint;
417
+ }, nullifyingKey: bigint, ephemeralPub: Uint8Array, depositNpk: bigint): boolean;
418
+ /**
419
+ * Check if a deposit belongs to this viewer — accepts hex string inputs.
420
+ * Convenience wrapper around isDepositForViewer for frontend use.
421
+ */
422
+ export declare function isDepositForViewerHex(keys: {
423
+ viewingPrivKey: Uint8Array;
424
+ spendingPubKey: {
425
+ x: bigint;
426
+ y: bigint;
427
+ };
428
+ nullifyingKey: bigint;
429
+ }, ephemeralPubHex: string, npkHex: string): boolean;