@hula-privacy/mixer 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +933 -0
- package/dist/index.d.ts +933 -0
- package/dist/index.js +2587 -0
- package/dist/index.mjs +2480 -0
- package/package.json +1 -8
- package/src/api.ts +5 -1
- package/src/crypto.ts +32 -12
- package/src/idl.ts +838 -0
- package/src/merkle.ts +3 -1
- package/src/transaction.ts +3 -4
- package/src/types.ts +2 -0
- package/src/utxo.ts +26 -11
- package/src/wallet.ts +238 -36
package/package.json
CHANGED
|
@@ -1,17 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hula-privacy/mixer",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Hula Privacy Protocol SDK - Complete toolkit for private transactions on Solana",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|
|
7
7
|
"types": "dist/index.d.ts",
|
|
8
|
-
"exports": {
|
|
9
|
-
".": {
|
|
10
|
-
"import": "./dist/index.mjs",
|
|
11
|
-
"require": "./dist/index.js",
|
|
12
|
-
"types": "./dist/index.d.ts"
|
|
13
|
-
}
|
|
14
|
-
},
|
|
15
8
|
"scripts": {
|
|
16
9
|
"build": "tsup src/index.ts --format cjs,esm --dts",
|
|
17
10
|
"dev": "tsup src/index.ts --format cjs,esm --dts --watch",
|
package/src/api.ts
CHANGED
|
@@ -155,7 +155,11 @@ export class RelayerClient {
|
|
|
155
155
|
const leaves = await this.getAllLeavesForTree(treeIndex);
|
|
156
156
|
// Sort by leafIndex to ensure correct order
|
|
157
157
|
leaves.sort((a, b) => a.leafIndex - b.leafIndex);
|
|
158
|
-
|
|
158
|
+
// Handle hex strings with or without 0x prefix
|
|
159
|
+
return leaves.map(l => {
|
|
160
|
+
const commitment = l.commitment.startsWith("0x") ? l.commitment : `0x${l.commitment}`;
|
|
161
|
+
return BigInt(commitment);
|
|
162
|
+
});
|
|
159
163
|
}
|
|
160
164
|
|
|
161
165
|
// ============================================================================
|
package/src/crypto.ts
CHANGED
|
@@ -179,21 +179,28 @@ export function deriveSpendingKeyFromSignature(signature: Uint8Array): bigint {
|
|
|
179
179
|
* Encrypt a note for a recipient
|
|
180
180
|
*
|
|
181
181
|
* The note contains the UTXO data needed for the recipient to claim it.
|
|
182
|
+
* Optimized for size:
|
|
183
|
+
* - mintTokenAddress: only first 8 bytes (can match on-chain by prefix)
|
|
184
|
+
* - leafIndex: omitted (recipient can query relayer with commitment)
|
|
182
185
|
*/
|
|
183
186
|
export function encryptNote(
|
|
184
187
|
noteData: {
|
|
185
188
|
value: bigint;
|
|
186
189
|
mintTokenAddress: bigint;
|
|
187
190
|
secret: bigint;
|
|
188
|
-
leafIndex
|
|
191
|
+
leafIndex?: number; // Optional, omitted to save space
|
|
189
192
|
},
|
|
190
193
|
recipientEncryptionPubKey: Uint8Array
|
|
191
194
|
): EncryptedNote {
|
|
195
|
+
// Use only first 8 bytes of mintTokenAddress to save space
|
|
196
|
+
// Recipient can match this prefix against known mints
|
|
197
|
+
const mintPrefix = noteData.mintTokenAddress.toString(16).padStart(64, "0").slice(0, 16);
|
|
198
|
+
|
|
192
199
|
const payload = {
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
leafIndex
|
|
200
|
+
v: noteData.value.toString(), // value
|
|
201
|
+
m: mintPrefix, // mint (first 8 bytes as hex)
|
|
202
|
+
s: noteData.secret.toString(), // secret
|
|
203
|
+
// leafIndex omitted - recipient queries relayer with computed commitment
|
|
197
204
|
};
|
|
198
205
|
|
|
199
206
|
const message = new TextEncoder().encode(JSON.stringify(payload));
|
|
@@ -218,11 +225,13 @@ export function encryptNote(
|
|
|
218
225
|
* Decrypt an encrypted note
|
|
219
226
|
*
|
|
220
227
|
* Returns null if decryption fails (not intended for this recipient)
|
|
228
|
+
* Note: leafIndex is not included in encrypted notes to save space.
|
|
229
|
+
* The recipient should query the relayer with the computed commitment.
|
|
221
230
|
*/
|
|
222
231
|
export function decryptNote(
|
|
223
232
|
encryptedNote: EncryptedNote,
|
|
224
233
|
encryptionSecretKey: Uint8Array
|
|
225
|
-
): { value: bigint;
|
|
234
|
+
): { value: bigint; mintPrefix: string; secret: bigint } | null {
|
|
226
235
|
try {
|
|
227
236
|
const decrypted = nacl.box.open(
|
|
228
237
|
encryptedNote.ciphertext,
|
|
@@ -234,12 +243,23 @@ export function decryptNote(
|
|
|
234
243
|
if (!decrypted) return null;
|
|
235
244
|
|
|
236
245
|
const noteData = JSON.parse(new TextDecoder().decode(decrypted));
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
246
|
+
|
|
247
|
+
// Handle both old format (full data) and new format (compact)
|
|
248
|
+
if (noteData.v !== undefined) {
|
|
249
|
+
// New compact format
|
|
250
|
+
return {
|
|
251
|
+
value: BigInt(noteData.v),
|
|
252
|
+
mintPrefix: noteData.m, // First 8 bytes as hex string
|
|
253
|
+
secret: BigInt(noteData.s),
|
|
254
|
+
};
|
|
255
|
+
} else {
|
|
256
|
+
// Legacy format (full mintTokenAddress)
|
|
257
|
+
return {
|
|
258
|
+
value: BigInt(noteData.value),
|
|
259
|
+
mintPrefix: BigInt(noteData.mintTokenAddress).toString(16).padStart(64, "0").slice(0, 16),
|
|
260
|
+
secret: BigInt(noteData.secret),
|
|
261
|
+
};
|
|
262
|
+
}
|
|
243
263
|
} catch {
|
|
244
264
|
return null;
|
|
245
265
|
}
|