@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.
- package/LICENSE +21 -0
- package/README.md +171 -0
- package/package.json +108 -0
- package/packages/btc-client/src/esplora-client.ts +153 -0
- package/packages/btc-client/src/index.ts +3 -0
- package/packages/btc-client/src/op-return.ts +93 -0
- package/packages/btc-client/src/types.ts +112 -0
- package/packages/sdk/README.md +277 -0
- package/packages/sdk/dist/announcement-client.d.ts +64 -0
- package/packages/sdk/dist/announcement-client.js +337 -0
- package/packages/sdk/dist/auditor-ciphertext.d.ts +72 -0
- package/packages/sdk/dist/auditor-ciphertext.js +135 -0
- package/packages/sdk/dist/auditor.d.ts +115 -0
- package/packages/sdk/dist/auditor.js +292 -0
- package/packages/sdk/dist/bitcoin/ika.d.ts +47 -0
- package/packages/sdk/dist/bitcoin/ika.js +74 -0
- package/packages/sdk/dist/bitcoin/index.d.ts +2 -0
- package/packages/sdk/dist/bitcoin/index.js +1 -0
- package/packages/sdk/dist/bound-params.d.ts +96 -0
- package/packages/sdk/dist/bound-params.js +249 -0
- package/packages/sdk/dist/chadbuffer.d.ts +124 -0
- package/packages/sdk/dist/chadbuffer.js +405 -0
- package/packages/sdk/dist/claim-link.d.ts +30 -0
- package/packages/sdk/dist/claim-link.js +50 -0
- package/packages/sdk/dist/client.d.ts +233 -0
- package/packages/sdk/dist/client.js +416 -0
- package/packages/sdk/dist/commitment-tree.d.ts +268 -0
- package/packages/sdk/dist/commitment-tree.js +564 -0
- package/packages/sdk/dist/config.d.ts +177 -0
- package/packages/sdk/dist/config.js +426 -0
- package/packages/sdk/dist/core/esplora.d.ts +110 -0
- package/packages/sdk/dist/core/esplora.js +187 -0
- package/packages/sdk/dist/core/mempool.d.ts +60 -0
- package/packages/sdk/dist/core/mempool.js +107 -0
- package/packages/sdk/dist/crypto-babyjub.d.ts +105 -0
- package/packages/sdk/dist/crypto-babyjub.js +312 -0
- package/packages/sdk/dist/crypto-ed25519.d.ts +116 -0
- package/packages/sdk/dist/crypto-ed25519.js +235 -0
- package/packages/sdk/dist/crypto.d.ts +59 -0
- package/packages/sdk/dist/crypto.js +140 -0
- package/packages/sdk/dist/event-client.d.ts +64 -0
- package/packages/sdk/dist/event-client.js +165 -0
- package/packages/sdk/dist/events.d.ts +127 -0
- package/packages/sdk/dist/events.js +305 -0
- package/packages/sdk/dist/explorer.d.ts +86 -0
- package/packages/sdk/dist/explorer.js +197 -0
- package/packages/sdk/dist/index.d.ts +61 -0
- package/packages/sdk/dist/index.js +216 -0
- package/packages/sdk/dist/instructions.d.ts +1125 -0
- package/packages/sdk/dist/instructions.js +1760 -0
- package/packages/sdk/dist/keys.d.ts +467 -0
- package/packages/sdk/dist/keys.js +799 -0
- package/packages/sdk/dist/logger.d.ts +10 -0
- package/packages/sdk/dist/logger.js +40 -0
- package/packages/sdk/dist/magicblock.d.ts +90 -0
- package/packages/sdk/dist/magicblock.js +164 -0
- package/packages/sdk/dist/merkle.d.ts +82 -0
- package/packages/sdk/dist/merkle.js +141 -0
- package/packages/sdk/dist/note.d.ts +348 -0
- package/packages/sdk/dist/note.js +483 -0
- package/packages/sdk/dist/pda.d.ts +160 -0
- package/packages/sdk/dist/pda.js +384 -0
- package/packages/sdk/dist/pool-state.d.ts +100 -0
- package/packages/sdk/dist/pool-state.js +126 -0
- package/packages/sdk/dist/poseidon.d.ts +53 -0
- package/packages/sdk/dist/poseidon.js +136 -0
- package/packages/sdk/dist/prover/index.d.ts +10 -0
- package/packages/sdk/dist/prover/index.js +10 -0
- package/packages/sdk/dist/prover/mobile.d.ts +45 -0
- package/packages/sdk/dist/prover/mobile.js +227 -0
- package/packages/sdk/dist/prover/web.d.ts +136 -0
- package/packages/sdk/dist/prover/web.js +597 -0
- package/packages/sdk/dist/psbt.d.ts +73 -0
- package/packages/sdk/dist/psbt.js +202 -0
- package/packages/sdk/dist/selective-disclosure.d.ts +181 -0
- package/packages/sdk/dist/selective-disclosure.js +172 -0
- package/packages/sdk/dist/sender-memo.d.ts +149 -0
- package/packages/sdk/dist/sender-memo.js +250 -0
- package/packages/sdk/dist/sns-resolver.d.ts +121 -0
- package/packages/sdk/dist/sns-resolver.js +229 -0
- package/packages/sdk/dist/solana/connection.d.ts +77 -0
- package/packages/sdk/dist/solana/connection.js +133 -0
- package/packages/sdk/dist/solana/priority-fee.d.ts +78 -0
- package/packages/sdk/dist/solana/priority-fee.js +137 -0
- package/packages/sdk/dist/stealth.d.ts +429 -0
- package/packages/sdk/dist/stealth.js +703 -0
- package/packages/sdk/dist/taproot.d.ts +172 -0
- package/packages/sdk/dist/taproot.js +494 -0
- package/packages/sdk/dist/token-registry.d.ts +96 -0
- package/packages/sdk/dist/token-registry.js +122 -0
- package/packages/sdk/dist/utils/encoding.d.ts +19 -0
- package/packages/sdk/dist/utils/encoding.js +29 -0
- package/packages/sdk/dist/vk-registry.d.ts +100 -0
- 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;
|