privacycash 1.0.16 → 1.0.18
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/__tests__/e2e.test.ts +5 -1
- package/__tests__/e2espl.test.ts +73 -0
- package/dist/config.d.ts +1 -0
- package/dist/config.js +6 -10
- package/dist/deposit.js +4 -11
- package/dist/depositSPL.d.ts +19 -0
- package/dist/depositSPL.js +433 -0
- package/dist/exportUtils.d.ts +3 -0
- package/dist/exportUtils.js +3 -0
- package/dist/getUtxos.d.ts +2 -1
- package/dist/getUtxos.js +68 -79
- package/dist/getUtxosSPL.d.ts +31 -0
- package/dist/getUtxosSPL.js +369 -0
- package/dist/index.d.ts +31 -1
- package/dist/index.js +73 -3
- package/dist/models/utxo.js +10 -1
- package/dist/utils/address_lookup_table.d.ts +1 -0
- package/dist/utils/address_lookup_table.js +23 -0
- package/dist/utils/constants.d.ts +3 -1
- package/dist/utils/constants.js +6 -3
- package/dist/utils/encryption.d.ts +1 -1
- package/dist/utils/encryption.js +5 -3
- package/dist/utils/prover.d.ts +4 -1
- package/dist/utils/prover.js +26 -2
- package/dist/utils/utils.d.ts +3 -2
- package/dist/utils/utils.js +26 -6
- package/dist/withdraw.js +3 -3
- package/dist/withdrawSPL.d.ts +22 -0
- package/dist/withdrawSPL.js +290 -0
- package/package.json +5 -3
- package/src/config.ts +7 -14
- package/src/deposit.ts +4 -11
- package/src/depositSPL.ts +555 -0
- package/src/exportUtils.ts +5 -1
- package/src/getUtxos.ts +73 -78
- package/src/getUtxosSPL.ts +495 -0
- package/src/index.ts +84 -3
- package/src/models/utxo.ts +10 -1
- package/src/utils/address_lookup_table.ts +54 -6
- package/src/utils/constants.ts +8 -3
- package/src/utils/encryption.ts +6 -3
- package/src/utils/prover.ts +36 -3
- package/src/utils/utils.ts +29 -6
- package/src/withdraw.ts +4 -4
- package/src/withdrawSPL.ts +379 -0
package/src/index.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { Connection, Keypair, LAMPORTS_PER_SOL, PublicKey, VersionedTransaction } from '@solana/web3.js';
|
|
2
2
|
import { deposit } from './deposit.js';
|
|
3
3
|
import { getBalanceFromUtxos, getUtxos, localstorageKey } from './getUtxos.js';
|
|
4
|
+
import { getBalanceFromUtxosSPL, getUtxosSPL } from './getUtxosSPL.js';
|
|
4
5
|
|
|
5
|
-
import { LSK_ENCRYPTED_OUTPUTS, LSK_FETCH_OFFSET } from './utils/constants.js';
|
|
6
|
+
import { LSK_ENCRYPTED_OUTPUTS, LSK_FETCH_OFFSET, USDC_MINT } from './utils/constants.js';
|
|
6
7
|
import { logger, type LoggerFn, setLogger } from './utils/logger.js';
|
|
7
8
|
import { EncryptionService } from './utils/encryption.js';
|
|
8
9
|
import { WasmFactory } from '@lightprotocol/hasher.rs';
|
|
@@ -10,6 +11,9 @@ import bs58 from 'bs58'
|
|
|
10
11
|
import { withdraw } from './withdraw.js';
|
|
11
12
|
import { LocalStorage } from "node-localstorage";
|
|
12
13
|
import path from 'node:path'
|
|
14
|
+
import { depositSPL } from './depositSPL.js';
|
|
15
|
+
import { withdrawSPL } from './withdrawSPL.js';
|
|
16
|
+
import { getAssociatedTokenAddress } from '@solana/spl-token';
|
|
13
17
|
|
|
14
18
|
let storage = new LocalStorage(path.join(process.cwd(), "cache"));
|
|
15
19
|
|
|
@@ -65,6 +69,16 @@ export class PrivacyCash {
|
|
|
65
69
|
}
|
|
66
70
|
storage.removeItem(LSK_FETCH_OFFSET + localstorageKey(this.publicKey))
|
|
67
71
|
storage.removeItem(LSK_ENCRYPTED_OUTPUTS + localstorageKey(this.publicKey))
|
|
72
|
+
// spl
|
|
73
|
+
let mintAddresses = [USDC_MINT]
|
|
74
|
+
for (let mintAddress of mintAddresses) {
|
|
75
|
+
let ata = await getAssociatedTokenAddress(
|
|
76
|
+
mintAddress,
|
|
77
|
+
this.publicKey
|
|
78
|
+
);
|
|
79
|
+
storage.removeItem(LSK_FETCH_OFFSET + localstorageKey(ata))
|
|
80
|
+
storage.removeItem(LSK_ENCRYPTED_OUTPUTS + localstorageKey(ata))
|
|
81
|
+
}
|
|
68
82
|
return this
|
|
69
83
|
}
|
|
70
84
|
|
|
@@ -96,6 +110,33 @@ export class PrivacyCash {
|
|
|
96
110
|
return res
|
|
97
111
|
}
|
|
98
112
|
|
|
113
|
+
/**
|
|
114
|
+
* Deposit USDC to the Privacy Cash.
|
|
115
|
+
*/
|
|
116
|
+
async depositUSDC({ base_units }: {
|
|
117
|
+
base_units: number
|
|
118
|
+
}) {
|
|
119
|
+
this.isRuning = true
|
|
120
|
+
logger.info('start depositting')
|
|
121
|
+
let lightWasm = await WasmFactory.getInstance()
|
|
122
|
+
let res = await depositSPL({
|
|
123
|
+
mintAddress: USDC_MINT,
|
|
124
|
+
lightWasm,
|
|
125
|
+
base_units: base_units,
|
|
126
|
+
connection: this.connection,
|
|
127
|
+
encryptionService: this.encryptionService,
|
|
128
|
+
publicKey: this.publicKey,
|
|
129
|
+
transactionSigner: async (tx: VersionedTransaction) => {
|
|
130
|
+
tx.sign([this.keypair])
|
|
131
|
+
return tx
|
|
132
|
+
},
|
|
133
|
+
keyBasePath: path.join(import.meta.dirname, '..', 'circuit2', 'transaction2'),
|
|
134
|
+
storage
|
|
135
|
+
})
|
|
136
|
+
this.isRuning = false
|
|
137
|
+
return res
|
|
138
|
+
}
|
|
139
|
+
|
|
99
140
|
/**
|
|
100
141
|
* Withdraw SOL from the Privacy Cash.
|
|
101
142
|
*
|
|
@@ -124,17 +165,57 @@ export class PrivacyCash {
|
|
|
124
165
|
return res
|
|
125
166
|
}
|
|
126
167
|
|
|
168
|
+
/**
|
|
169
|
+
* Withdraw USDC from the Privacy Cash.
|
|
170
|
+
*
|
|
171
|
+
* base_units is the amount of USDC in base unit. e.g. if you want to withdraw 1 USDC (1,000,000 base unit), call withdraw({ base_units: 1000000, recipientAddress: 'some_address' })
|
|
172
|
+
*/
|
|
173
|
+
async withdrawUSDC({ base_units, recipientAddress }: {
|
|
174
|
+
base_units: number,
|
|
175
|
+
recipientAddress?: string
|
|
176
|
+
}) {
|
|
177
|
+
this.isRuning = true
|
|
178
|
+
logger.info('start withdrawing')
|
|
179
|
+
let lightWasm = await WasmFactory.getInstance()
|
|
180
|
+
let recipient = recipientAddress ? new PublicKey(recipientAddress) : this.publicKey
|
|
181
|
+
let res = await withdrawSPL({
|
|
182
|
+
mintAddress: USDC_MINT,
|
|
183
|
+
lightWasm,
|
|
184
|
+
base_units,
|
|
185
|
+
connection: this.connection,
|
|
186
|
+
encryptionService: this.encryptionService,
|
|
187
|
+
publicKey: this.publicKey,
|
|
188
|
+
recipient,
|
|
189
|
+
keyBasePath: path.join(import.meta.dirname, '..', 'circuit2', 'transaction2'),
|
|
190
|
+
storage
|
|
191
|
+
})
|
|
192
|
+
console.log(`Withdraw successful. Recipient ${recipient} received ${base_units} USDC units`)
|
|
193
|
+
this.isRuning = false
|
|
194
|
+
return res
|
|
195
|
+
}
|
|
196
|
+
|
|
127
197
|
/**
|
|
128
198
|
* Returns the amount of lamports current wallet has in Privacy Cash.
|
|
129
199
|
*/
|
|
130
|
-
async getPrivateBalance() {
|
|
200
|
+
async getPrivateBalance(abortSignal?: AbortSignal) {
|
|
131
201
|
logger.info('getting private balance')
|
|
132
202
|
this.isRuning = true
|
|
133
|
-
let utxos = await getUtxos({ publicKey: this.publicKey, connection: this.connection, encryptionService: this.encryptionService, storage })
|
|
203
|
+
let utxos = await getUtxos({ publicKey: this.publicKey, connection: this.connection, encryptionService: this.encryptionService, storage, abortSignal })
|
|
134
204
|
this.isRuning = false
|
|
135
205
|
return getBalanceFromUtxos(utxos)
|
|
136
206
|
}
|
|
137
207
|
|
|
208
|
+
/**
|
|
209
|
+
* Returns the amount of lamports current wallet has in Privacy Cash.
|
|
210
|
+
*/
|
|
211
|
+
async getPrivateBalanceUSDC() {
|
|
212
|
+
logger.info('getting private balance')
|
|
213
|
+
this.isRuning = true
|
|
214
|
+
let utxos = await getUtxosSPL({ publicKey: this.publicKey, connection: this.connection, encryptionService: this.encryptionService, storage, mintAddress: USDC_MINT })
|
|
215
|
+
this.isRuning = false
|
|
216
|
+
return getBalanceFromUtxosSPL(utxos)
|
|
217
|
+
}
|
|
218
|
+
|
|
138
219
|
/**
|
|
139
220
|
* Returns true if the code is running in a browser.
|
|
140
221
|
*/
|
package/src/models/utxo.ts
CHANGED
|
@@ -9,6 +9,8 @@ import BN from 'bn.js';
|
|
|
9
9
|
import { Keypair } from './keypair.js';
|
|
10
10
|
import * as hasher from '@lightprotocol/hasher.rs';
|
|
11
11
|
import { ethers } from 'ethers';
|
|
12
|
+
import { getMintAddressField } from '../utils/utils.js';
|
|
13
|
+
import { PublicKey } from '@solana/web3.js';
|
|
12
14
|
/**
|
|
13
15
|
* Simplified Utxo class inspired by Tornado Cash Nova
|
|
14
16
|
* Based on: https://github.com/tornadocash/tornado-nova/blob/f9264eeffe48bf5e04e19d8086ee6ec58cdf0d9e/src/utxo.js
|
|
@@ -57,7 +59,14 @@ export class Utxo {
|
|
|
57
59
|
}
|
|
58
60
|
|
|
59
61
|
async getCommitment(): Promise<string> {
|
|
60
|
-
return this.lightWasm.poseidonHashString([this.amount.toString(), this.keypair.pubkey.toString(), this.blinding.toString(), this.mintAddress]);
|
|
62
|
+
// return this.lightWasm.poseidonHashString([this.amount.toString(), this.keypair.pubkey.toString(), this.blinding.toString(), this.mintAddress]);
|
|
63
|
+
const mintAddressField = getMintAddressField(new PublicKey(this.mintAddress));
|
|
64
|
+
return this.lightWasm.poseidonHashString([
|
|
65
|
+
this.amount.toString(),
|
|
66
|
+
this.keypair.pubkey.toString(),
|
|
67
|
+
this.blinding.toString(),
|
|
68
|
+
mintAddressField
|
|
69
|
+
]);
|
|
61
70
|
}
|
|
62
71
|
|
|
63
72
|
async getNullifier(): Promise<string> {
|
|
@@ -1,7 +1,17 @@
|
|
|
1
|
-
import {
|
|
2
|
-
Connection,
|
|
3
|
-
|
|
1
|
+
import {
|
|
2
|
+
Connection,
|
|
3
|
+
Keypair,
|
|
4
|
+
PublicKey,
|
|
5
|
+
SystemProgram,
|
|
6
|
+
AddressLookupTableProgram,
|
|
7
|
+
Transaction,
|
|
8
|
+
sendAndConfirmTransaction,
|
|
9
|
+
ComputeBudgetProgram,
|
|
10
|
+
VersionedTransaction,
|
|
11
|
+
TransactionMessage
|
|
4
12
|
} from '@solana/web3.js';
|
|
13
|
+
import { ASSOCIATED_TOKEN_PROGRAM_ID, TOKEN_PROGRAM_ID } from '@solana/spl-token';
|
|
14
|
+
|
|
5
15
|
|
|
6
16
|
/**
|
|
7
17
|
* Helper function to use an existing ALT (recommended for production)
|
|
@@ -14,16 +24,54 @@ export async function useExistingALT(
|
|
|
14
24
|
try {
|
|
15
25
|
console.log(`Using existing ALT: ${altAddress.toString()}`);
|
|
16
26
|
const altAccount = await connection.getAddressLookupTable(altAddress);
|
|
17
|
-
|
|
27
|
+
|
|
18
28
|
if (altAccount.value) {
|
|
19
29
|
console.log(`✅ ALT found with ${altAccount.value.state.addresses.length} addresses`);
|
|
20
30
|
} else {
|
|
21
31
|
console.log('❌ ALT not found');
|
|
22
32
|
}
|
|
23
|
-
|
|
33
|
+
|
|
24
34
|
return altAccount;
|
|
25
35
|
} catch (error) {
|
|
26
36
|
console.error('Error getting existing ALT:', error);
|
|
27
37
|
return null;
|
|
28
38
|
}
|
|
29
|
-
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
export function getProtocolAddressesWithMint(
|
|
43
|
+
programId: PublicKey,
|
|
44
|
+
authority: PublicKey,
|
|
45
|
+
treeAta: PublicKey,
|
|
46
|
+
feeRecipient: PublicKey,
|
|
47
|
+
feeRecipientAta: PublicKey
|
|
48
|
+
): PublicKey[] {
|
|
49
|
+
// Derive global config PDA
|
|
50
|
+
const [globalConfigAccount] = PublicKey.findProgramAddressSync(
|
|
51
|
+
[Buffer.from('global_config')],
|
|
52
|
+
programId
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
// Derive tree accounts
|
|
56
|
+
const [treeAccount] = PublicKey.findProgramAddressSync(
|
|
57
|
+
[Buffer.from('merkle_tree')],
|
|
58
|
+
programId
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
return [
|
|
62
|
+
// Core program accounts (constant)
|
|
63
|
+
programId,
|
|
64
|
+
treeAccount,
|
|
65
|
+
treeAta,
|
|
66
|
+
globalConfigAccount,
|
|
67
|
+
authority,
|
|
68
|
+
feeRecipient,
|
|
69
|
+
feeRecipientAta,
|
|
70
|
+
|
|
71
|
+
// System programs (constant)
|
|
72
|
+
SystemProgram.programId,
|
|
73
|
+
ComputeBudgetProgram.programId,
|
|
74
|
+
ASSOCIATED_TOKEN_PROGRAM_ID,
|
|
75
|
+
TOKEN_PROGRAM_ID,
|
|
76
|
+
];
|
|
77
|
+
}
|
package/src/utils/constants.ts
CHANGED
|
@@ -5,22 +5,27 @@ export const FIELD_SIZE = new BN('2188824287183927522224640574525727508854836440
|
|
|
5
5
|
|
|
6
6
|
export const PROGRAM_ID = new PublicKey('9fhQBbumKEFuXtMBDw8AaQyAjCorLGJQiS3skWZdQyQD');
|
|
7
7
|
|
|
8
|
-
export const DEPLOYER_ID = new PublicKey('
|
|
8
|
+
export const DEPLOYER_ID = new PublicKey('97rSMQUukMDjA7PYErccyx7ZxbHvSDaeXp2ig5BwSrTf')
|
|
9
9
|
|
|
10
|
+
//BxuZn19npE43qkrQycBSb12vgruyD3vLygxwZss7eXLU
|
|
10
11
|
export const FEE_RECIPIENT = new PublicKey('AWexibGxNFKTa1b5R5MN4PJr9HWnWRwf8EW9g8cLx3dM')
|
|
11
12
|
|
|
12
13
|
export const FETCH_UTXOS_GROUP_SIZE = 10_000
|
|
13
14
|
|
|
14
15
|
export const TRANSACT_IX_DISCRIMINATOR = Buffer.from([217, 149, 130, 143, 221, 52, 252, 119]);
|
|
15
16
|
|
|
17
|
+
export const TRANSACT_SPL_IX_DISCRIMINATOR = Buffer.from([154, 66, 244, 204, 78, 225, 163, 151]);
|
|
18
|
+
|
|
16
19
|
export const MERKLE_TREE_DEPTH = 26;
|
|
17
20
|
|
|
18
|
-
export const ALT_ADDRESS = new PublicKey('
|
|
21
|
+
export const ALT_ADDRESS = new PublicKey('HEN49U2ySJ85Vc78qprSW9y6mFDhs1NczRxyppNHjofe');
|
|
19
22
|
|
|
20
|
-
export const
|
|
23
|
+
export const RELAYER_API_URL = process.env.NEXT_PUBLIC_RELAYER_API_URL ?? 'https://api3.privacycash.org';
|
|
21
24
|
|
|
22
25
|
export const SIGN_MESSAGE = `Privacy Money account sign in`
|
|
23
26
|
|
|
24
27
|
// localStorage cache keys
|
|
25
28
|
export const LSK_FETCH_OFFSET = 'fetch_offset'
|
|
26
29
|
export const LSK_ENCRYPTED_OUTPUTS = 'encrypted_outputs'
|
|
30
|
+
|
|
31
|
+
export const USDC_MINT = new PublicKey('EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v')
|
package/src/utils/encryption.ts
CHANGED
|
@@ -5,7 +5,7 @@ import { Utxo } from '../models/utxo.js';
|
|
|
5
5
|
import { WasmFactory } from '@lightprotocol/hasher.rs';
|
|
6
6
|
import { Keypair as UtxoKeypair } from '../models/keypair.js';
|
|
7
7
|
import { keccak256 } from '@ethersproject/keccak256';
|
|
8
|
-
import { PROGRAM_ID, TRANSACT_IX_DISCRIMINATOR } from './constants.js';
|
|
8
|
+
import { PROGRAM_ID, TRANSACT_IX_DISCRIMINATOR, TRANSACT_SPL_IX_DISCRIMINATOR } from './constants.js';
|
|
9
9
|
import BN from 'bn.js';
|
|
10
10
|
|
|
11
11
|
|
|
@@ -426,16 +426,19 @@ export class EncryptionService {// Version identifier for encryption scheme (8-b
|
|
|
426
426
|
}
|
|
427
427
|
}
|
|
428
428
|
|
|
429
|
-
export function serializeProofAndExtData(proof: any, extData: any) {
|
|
429
|
+
export function serializeProofAndExtData(proof: any, extData: any, isSpl: boolean = false) {
|
|
430
430
|
// Create the ExtDataMinified object for the program call (only extAmount and fee)
|
|
431
431
|
const extDataMinified = {
|
|
432
432
|
extAmount: extData.extAmount,
|
|
433
433
|
fee: extData.fee
|
|
434
434
|
};
|
|
435
435
|
|
|
436
|
+
// Use the appropriate discriminator based on whether this is SPL or native SOL
|
|
437
|
+
const discriminator = isSpl ? TRANSACT_SPL_IX_DISCRIMINATOR : TRANSACT_IX_DISCRIMINATOR;
|
|
438
|
+
|
|
436
439
|
// Use the same serialization approach as deposit script
|
|
437
440
|
const instructionData = Buffer.concat([
|
|
438
|
-
|
|
441
|
+
discriminator,
|
|
439
442
|
// Serialize proof
|
|
440
443
|
Buffer.from(proof.proofA),
|
|
441
444
|
Buffer.from(proof.proofB),
|
package/src/utils/prover.ts
CHANGED
|
@@ -23,7 +23,14 @@ type WtnsModule = {
|
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
type Groth16Module = {
|
|
26
|
-
fullProve: (
|
|
26
|
+
fullProve: (
|
|
27
|
+
input: any,
|
|
28
|
+
wasmFile: string,
|
|
29
|
+
zkeyFile: string,
|
|
30
|
+
logger?: any,
|
|
31
|
+
wtnsCalcOptions?: { singleThread?: boolean },
|
|
32
|
+
proverOptions?: { singleThread?: boolean }
|
|
33
|
+
) => Promise<{ proof: Proof; publicSignals: string[] }>
|
|
27
34
|
verify: (vkeyData: any, publicSignals: any, proof: Proof) => Promise<boolean>
|
|
28
35
|
}
|
|
29
36
|
|
|
@@ -53,23 +60,49 @@ interface ProofResult {
|
|
|
53
60
|
|
|
54
61
|
/**
|
|
55
62
|
* Generates a ZK proof using snarkjs and formats it for use on-chain
|
|
56
|
-
*
|
|
63
|
+
*
|
|
57
64
|
* @param input The circuit inputs to generate a proof for
|
|
58
65
|
* @param keyBasePath The base path for the circuit keys (.wasm and .zkey files)
|
|
66
|
+
* @param options Optional proof generation options (e.g., singleThread for Deno/Bun)
|
|
59
67
|
* @returns A proof object with formatted proof elements and public signals
|
|
60
68
|
*/
|
|
61
|
-
async function prove(input: any, keyBasePath: string): Promise<{
|
|
69
|
+
async function prove(input: any, keyBasePath: string, options?: { singleThread?: boolean }): Promise<{
|
|
62
70
|
proof: Proof
|
|
63
71
|
publicSignals: string[];
|
|
64
72
|
}> {
|
|
73
|
+
// Detect if we should use single-threaded mode (for Deno/Bun compatibility)
|
|
74
|
+
const useSingleThread = options?.singleThread ?? shouldUseSingleThread();
|
|
75
|
+
|
|
76
|
+
// Single-thread options need to be passed to BOTH witness calculation AND proving
|
|
77
|
+
const singleThreadOpts = useSingleThread ? { singleThread: true } : undefined;
|
|
65
78
|
|
|
79
|
+
// Call fullProve with all parameters:
|
|
80
|
+
// 1. input, 2. wasmFile, 3. zkeyFile, 4. logger, 5. wtnsCalcOptions, 6. proverOptions
|
|
66
81
|
return await groth16Typed.fullProve(
|
|
67
82
|
utilsTyped.stringifyBigInts(input),
|
|
68
83
|
`${keyBasePath}.wasm`,
|
|
69
84
|
`${keyBasePath}.zkey`,
|
|
85
|
+
undefined, // logger parameter
|
|
86
|
+
singleThreadOpts, // wtnsCalcOptions (5th param) - for witness calculation
|
|
87
|
+
singleThreadOpts // proverOptions (6th param) - for proving
|
|
70
88
|
)
|
|
71
89
|
}
|
|
72
90
|
|
|
91
|
+
/**
|
|
92
|
+
* Detect if single-threaded mode should be used
|
|
93
|
+
*/
|
|
94
|
+
function shouldUseSingleThread(): boolean {
|
|
95
|
+
// @ts-ignore - Deno global
|
|
96
|
+
if (typeof Deno !== 'undefined') {
|
|
97
|
+
return true; // Deno has worker issues
|
|
98
|
+
}
|
|
99
|
+
// @ts-ignore - Bun global
|
|
100
|
+
if (typeof Bun !== 'undefined') {
|
|
101
|
+
return true; // Bun may have worker issues
|
|
102
|
+
}
|
|
103
|
+
return false;
|
|
104
|
+
}
|
|
105
|
+
|
|
73
106
|
export function parseProofToBytesArray(
|
|
74
107
|
proof: Proof,
|
|
75
108
|
compressed: boolean = false,
|
package/src/utils/utils.ts
CHANGED
|
@@ -10,7 +10,7 @@ import { Utxo } from '../models/utxo.js';
|
|
|
10
10
|
import * as borsh from 'borsh';
|
|
11
11
|
import { sha256 } from '@ethersproject/sha2';
|
|
12
12
|
import { PublicKey } from '@solana/web3.js';
|
|
13
|
-
import {
|
|
13
|
+
import { RELAYER_API_URL, PROGRAM_ID } from './constants.js';
|
|
14
14
|
import { logger } from './logger.js';
|
|
15
15
|
import { getConfig } from '../config.js';
|
|
16
16
|
|
|
@@ -115,12 +115,16 @@ export function getExtDataHash(extData: {
|
|
|
115
115
|
|
|
116
116
|
|
|
117
117
|
// Function to fetch Merkle proof from API for a given commitment
|
|
118
|
-
export async function fetchMerkleProof(commitment: string): Promise<{ pathElements: string[], pathIndices: number[] }> {
|
|
118
|
+
export async function fetchMerkleProof(commitment: string, tokenName?: string): Promise<{ pathElements: string[], pathIndices: number[] }> {
|
|
119
119
|
try {
|
|
120
120
|
logger.debug(`Fetching Merkle proof for commitment: ${commitment}`);
|
|
121
|
-
|
|
121
|
+
let url = `${RELAYER_API_URL}/merkle/proof/${commitment}`
|
|
122
|
+
if (tokenName) {
|
|
123
|
+
url += '?token=' + tokenName
|
|
124
|
+
}
|
|
125
|
+
const response = await fetch(url);
|
|
122
126
|
if (!response.ok) {
|
|
123
|
-
throw new Error(`Failed to fetch Merkle proof: ${
|
|
127
|
+
throw new Error(`Failed to fetch Merkle proof: ${url}`);
|
|
124
128
|
}
|
|
125
129
|
const data = await response.json() as { pathElements: string[], pathIndices: number[] };
|
|
126
130
|
logger.debug(`✓ Fetched Merkle proof with ${data.pathElements.length} elements`);
|
|
@@ -147,10 +151,14 @@ export function findNullifierPDAs(proof: any) {
|
|
|
147
151
|
}
|
|
148
152
|
|
|
149
153
|
// Function to query remote tree state from indexer API
|
|
150
|
-
export async function queryRemoteTreeState(): Promise<{ root: string, nextIndex: number }> {
|
|
154
|
+
export async function queryRemoteTreeState(tokenName?: string): Promise<{ root: string, nextIndex: number }> {
|
|
151
155
|
try {
|
|
152
156
|
logger.debug('Fetching Merkle root and nextIndex from API...');
|
|
153
|
-
|
|
157
|
+
let url = `${RELAYER_API_URL}/merkle/root`
|
|
158
|
+
if (tokenName) {
|
|
159
|
+
url += '?token=' + tokenName
|
|
160
|
+
}
|
|
161
|
+
const response = await fetch(url);
|
|
154
162
|
if (!response.ok) {
|
|
155
163
|
throw new Error(`Failed to fetch Merkle root and nextIndex: ${response.status} ${response.statusText}`);
|
|
156
164
|
}
|
|
@@ -196,4 +204,19 @@ export function findCrossCheckNullifierPDAs(proof: any) {
|
|
|
196
204
|
);
|
|
197
205
|
|
|
198
206
|
return { nullifier2PDA, nullifier3PDA };
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
export function getMintAddressField(mint: PublicKey): string {
|
|
210
|
+
const mintStr = mint.toString();
|
|
211
|
+
|
|
212
|
+
// Special case for SOL (system program)
|
|
213
|
+
if (mintStr === '11111111111111111111111111111112') {
|
|
214
|
+
return mintStr;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// For SPL tokens (USDC, USDT, etc): use first 31 bytes (248 bits)
|
|
218
|
+
// This provides better collision resistance than 8 bytes while still fitting in the field
|
|
219
|
+
// We will only suppport private SOL, USDC and USDT send, so there won't be any collision.
|
|
220
|
+
const mintBytes = mint.toBytes();
|
|
221
|
+
return new BN(mintBytes.slice(0, 31), 'be').toString();
|
|
199
222
|
}
|
package/src/withdraw.ts
CHANGED
|
@@ -6,7 +6,7 @@ import * as hasher from '@lightprotocol/hasher.rs';
|
|
|
6
6
|
import { Utxo } from './models/utxo.js';
|
|
7
7
|
import { parseProofToBytesArray, parseToBytesArray, prove } from './utils/prover.js';
|
|
8
8
|
|
|
9
|
-
import { ALT_ADDRESS, DEPLOYER_ID, FEE_RECIPIENT, FIELD_SIZE,
|
|
9
|
+
import { ALT_ADDRESS, DEPLOYER_ID, FEE_RECIPIENT, FIELD_SIZE, RELAYER_API_URL, MERKLE_TREE_DEPTH, PROGRAM_ID } from './utils/constants.js';
|
|
10
10
|
import { EncryptionService, serializeProofAndExtData } from './utils/encryption.js';
|
|
11
11
|
import { fetchMerkleProof, findNullifierPDAs, getExtDataHash, getProgramAccounts, queryRemoteTreeState, findCrossCheckNullifierPDAs } from './utils/utils.js';
|
|
12
12
|
|
|
@@ -20,7 +20,7 @@ import { getConfig } from './config.js';
|
|
|
20
20
|
async function submitWithdrawToIndexer(params: any): Promise<string> {
|
|
21
21
|
try {
|
|
22
22
|
|
|
23
|
-
const response = await fetch(`${
|
|
23
|
+
const response = await fetch(`${RELAYER_API_URL}/withdraw`, {
|
|
24
24
|
method: 'POST',
|
|
25
25
|
headers: {
|
|
26
26
|
'Content-Type': 'application/json',
|
|
@@ -319,7 +319,7 @@ export async function withdraw({ recipient, lightWasm, storage, publicKey, conne
|
|
|
319
319
|
console.log(`retryTimes: ${retryTimes}`)
|
|
320
320
|
await new Promise(resolve => setTimeout(resolve, itv * 1000));
|
|
321
321
|
console.log('Fetching updated tree state...');
|
|
322
|
-
let res = await fetch(
|
|
322
|
+
let res = await fetch(RELAYER_API_URL + '/utxos/check/' + encryptedOutputStr)
|
|
323
323
|
let resJson = await res.json()
|
|
324
324
|
console.log('resJson:', resJson)
|
|
325
325
|
if (resJson.exists) {
|
|
@@ -331,4 +331,4 @@ export async function withdraw({ recipient, lightWasm, storage, publicKey, conne
|
|
|
331
331
|
retryTimes++
|
|
332
332
|
}
|
|
333
333
|
|
|
334
|
-
}
|
|
334
|
+
}
|