privacycash 1.0.21 → 1.1.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/config.d.ts +1 -0
- package/dist/config.js +1 -1
- package/dist/deposit.js +1 -1
- package/dist/depositSPL.d.ts +4 -3
- package/dist/depositSPL.js +57 -49
- package/dist/exportUtils.d.ts +1 -0
- package/dist/exportUtils.js +1 -0
- package/dist/getUtxosSPL.d.ts +3 -2
- package/dist/getUtxosSPL.js +37 -12
- package/dist/index.d.ts +35 -1
- package/dist/index.js +68 -5
- package/dist/utils/constants.d.ts +12 -0
- package/dist/utils/constants.js +34 -0
- package/dist/withdrawSPL.d.ts +4 -3
- package/dist/withdrawSPL.js +38 -21
- package/package.json +1 -1
- package/src/config.ts +2 -1
- package/src/deposit.ts +2 -1
- package/src/depositSPL.ts +63 -53
- package/src/exportUtils.ts +3 -1
- package/src/getUtxosSPL.ts +44 -15
- package/src/index.ts +83 -5
- package/src/utils/constants.ts +45 -1
- package/src/withdrawSPL.ts +46 -26
package/dist/utils/constants.js
CHANGED
|
@@ -14,3 +14,37 @@ export const SIGN_MESSAGE = `Privacy Money account sign in`;
|
|
|
14
14
|
export const LSK_FETCH_OFFSET = 'fetch_offset';
|
|
15
15
|
export const LSK_ENCRYPTED_OUTPUTS = 'encrypted_outputs';
|
|
16
16
|
export const USDC_MINT = process.env.NEXT_PUBLIC_USDC_MINT ? new PublicKey(process.env.NEXT_PUBLIC_USDC_MINT) : new PublicKey('EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v');
|
|
17
|
+
const tokenList = ['sol', 'usdc', 'usdt', 'zec', 'ore'];
|
|
18
|
+
const splList = ['usdc', 'usdt', 'ore'];
|
|
19
|
+
export const tokens = [
|
|
20
|
+
{
|
|
21
|
+
name: 'sol',
|
|
22
|
+
pubkey: new PublicKey('So11111111111111111111111111111111111111112'),
|
|
23
|
+
prefix: '',
|
|
24
|
+
units_per_token: 1e9
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
name: 'usdc',
|
|
28
|
+
pubkey: process.env.NEXT_PUBLIC_USDC_MINT ? new PublicKey(process.env.NEXT_PUBLIC_USDC_MINT) : new PublicKey('EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v'),
|
|
29
|
+
prefix: 'usdc_',
|
|
30
|
+
units_per_token: 1e6
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
name: 'usdt',
|
|
34
|
+
pubkey: process.env.NEXT_PUBLIC_USDT_MINT ? new PublicKey(process.env.NEXT_PUBLIC_USDT_MINT) : new PublicKey('Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB'),
|
|
35
|
+
prefix: 'usdt_',
|
|
36
|
+
units_per_token: 1e6
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
name: 'zec',
|
|
40
|
+
pubkey: process.env.NEXT_PUBLIC_ZEC_MINT ? new PublicKey(process.env.NEXT_PUBLIC_ZEC_MINT) : new PublicKey('A7bdiYdS5GjqGFtxf17ppRHtDKPkkRqbKtR27dxvQXaS'),
|
|
41
|
+
prefix: 'zec_',
|
|
42
|
+
units_per_token: 1e8
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
name: 'ore',
|
|
46
|
+
pubkey: process.env.NEXT_PUBLIC_ORE_MINT ? new PublicKey(process.env.NEXT_PUBLIC_ORE_MINT) : new PublicKey('oreoU2P8bN6jkk3jbaiVxYnG1dCXcYxwhwyK9jSybcp'),
|
|
47
|
+
prefix: 'ore_',
|
|
48
|
+
units_per_token: 1e11
|
|
49
|
+
}
|
|
50
|
+
];
|
package/dist/withdrawSPL.d.ts
CHANGED
|
@@ -4,15 +4,16 @@ import { EncryptionService } from './utils/encryption.js';
|
|
|
4
4
|
type WithdrawParams = {
|
|
5
5
|
publicKey: PublicKey;
|
|
6
6
|
connection: Connection;
|
|
7
|
-
base_units
|
|
7
|
+
base_units?: number;
|
|
8
|
+
amount?: number;
|
|
8
9
|
keyBasePath: string;
|
|
9
10
|
encryptionService: EncryptionService;
|
|
10
11
|
lightWasm: hasher.LightWasm;
|
|
11
12
|
recipient: PublicKey;
|
|
12
|
-
mintAddress: PublicKey;
|
|
13
|
+
mintAddress: PublicKey | string;
|
|
13
14
|
storage: Storage;
|
|
14
15
|
};
|
|
15
|
-
export declare function withdrawSPL({ recipient, lightWasm, storage, publicKey, connection, base_units, encryptionService, keyBasePath, mintAddress }: WithdrawParams): Promise<{
|
|
16
|
+
export declare function withdrawSPL({ recipient, lightWasm, storage, publicKey, connection, base_units, amount, encryptionService, keyBasePath, mintAddress }: WithdrawParams): Promise<{
|
|
16
17
|
isPartial: boolean;
|
|
17
18
|
tx: string;
|
|
18
19
|
recipient: string;
|
package/dist/withdrawSPL.js
CHANGED
|
@@ -4,7 +4,7 @@ import { Buffer } from 'buffer';
|
|
|
4
4
|
import { Keypair as UtxoKeypair } from './models/keypair.js';
|
|
5
5
|
import { Utxo } from './models/utxo.js';
|
|
6
6
|
import { parseProofToBytesArray, parseToBytesArray, prove } from './utils/prover.js';
|
|
7
|
-
import { ALT_ADDRESS, FEE_RECIPIENT, FIELD_SIZE, RELAYER_API_URL, MERKLE_TREE_DEPTH, PROGRAM_ID } from './utils/constants.js';
|
|
7
|
+
import { ALT_ADDRESS, FEE_RECIPIENT, FIELD_SIZE, RELAYER_API_URL, MERKLE_TREE_DEPTH, PROGRAM_ID, tokens } from './utils/constants.js';
|
|
8
8
|
import { serializeProofAndExtData } from './utils/encryption.js';
|
|
9
9
|
import { fetchMerkleProof, findNullifierPDAs, getProgramAccounts, queryRemoteTreeState, findCrossCheckNullifierPDAs, getMintAddressField, getExtDataHash } from './utils/utils.js';
|
|
10
10
|
import { getUtxosSPL } from './getUtxosSPL.js';
|
|
@@ -36,26 +36,43 @@ async function submitWithdrawToIndexer(params) {
|
|
|
36
36
|
throw error;
|
|
37
37
|
}
|
|
38
38
|
}
|
|
39
|
-
export async function withdrawSPL({ recipient, lightWasm, storage, publicKey, connection, base_units, encryptionService, keyBasePath, mintAddress }) {
|
|
40
|
-
|
|
39
|
+
export async function withdrawSPL({ recipient, lightWasm, storage, publicKey, connection, base_units, amount, encryptionService, keyBasePath, mintAddress }) {
|
|
40
|
+
if (typeof mintAddress == 'string') {
|
|
41
|
+
mintAddress = new PublicKey(mintAddress);
|
|
42
|
+
}
|
|
43
|
+
let token = tokens.find(t => t.pubkey.toString() == mintAddress.toString());
|
|
44
|
+
if (!token) {
|
|
45
|
+
throw new Error('token not found: ' + mintAddress.toString());
|
|
46
|
+
}
|
|
47
|
+
if (amount) {
|
|
48
|
+
base_units = amount * token.units_per_token;
|
|
49
|
+
}
|
|
50
|
+
if (!base_units) {
|
|
51
|
+
throw new Error('You must input at leaset one of "base_units" or "amount"');
|
|
52
|
+
}
|
|
53
|
+
let mintInfo = await getMint(connection, token.pubkey);
|
|
41
54
|
let units_per_token = 10 ** mintInfo.decimals;
|
|
42
55
|
let withdraw_fee_rate = await getConfig('withdraw_fee_rate');
|
|
43
|
-
let
|
|
44
|
-
let
|
|
56
|
+
let withdraw_rent_fees = await getConfig('rent_fees');
|
|
57
|
+
let token_rent_fee = withdraw_rent_fees[token.name];
|
|
58
|
+
if (!token_rent_fee) {
|
|
59
|
+
throw new Error('can not find token_rent_fee for ' + token.name);
|
|
60
|
+
}
|
|
61
|
+
let fee_base_units = Math.floor(base_units * withdraw_fee_rate + units_per_token * token_rent_fee);
|
|
45
62
|
base_units -= fee_base_units;
|
|
46
63
|
if (base_units <= 0) {
|
|
47
|
-
throw new Error('withdraw amount too low');
|
|
64
|
+
throw new Error('withdraw amount too low, at least ' + fee_base_units / token_rent_fee);
|
|
48
65
|
}
|
|
49
66
|
let isPartial = false;
|
|
50
|
-
let recipient_ata = getAssociatedTokenAddressSync(
|
|
51
|
-
let feeRecipientTokenAccount = getAssociatedTokenAddressSync(
|
|
52
|
-
let signerTokenAccount = getAssociatedTokenAddressSync(
|
|
67
|
+
let recipient_ata = getAssociatedTokenAddressSync(token.pubkey, recipient, true);
|
|
68
|
+
let feeRecipientTokenAccount = getAssociatedTokenAddressSync(token.pubkey, FEE_RECIPIENT, true);
|
|
69
|
+
let signerTokenAccount = getAssociatedTokenAddressSync(token.pubkey, publicKey);
|
|
53
70
|
logger.debug('Encryption key generated from user keypair');
|
|
54
71
|
// Derive tree account PDA with mint address for SPL (different from SOL version)
|
|
55
|
-
const [treeAccount] = PublicKey.findProgramAddressSync([Buffer.from('merkle_tree'),
|
|
72
|
+
const [treeAccount] = PublicKey.findProgramAddressSync([Buffer.from('merkle_tree'), token.pubkey.toBuffer()], PROGRAM_ID);
|
|
56
73
|
const { globalConfigAccount, treeTokenAccount } = getProgramAccounts();
|
|
57
74
|
// Get current tree state
|
|
58
|
-
const { root, nextIndex: currentNextIndex } = await queryRemoteTreeState(
|
|
75
|
+
const { root, nextIndex: currentNextIndex } = await queryRemoteTreeState(token.name);
|
|
59
76
|
logger.debug(`Using tree root: ${root}`);
|
|
60
77
|
logger.debug(`New UTXOs will be inserted at indices: ${currentNextIndex} and ${currentNextIndex + 1}`);
|
|
61
78
|
// Generate a deterministic private key derived from the wallet keypair
|
|
@@ -69,7 +86,7 @@ export async function withdrawSPL({ recipient, lightWasm, storage, publicKey, co
|
|
|
69
86
|
// Fetch existing UTXOs for this user
|
|
70
87
|
logger.debug('\nFetching existing UTXOs...');
|
|
71
88
|
const mintUtxos = await getUtxosSPL({ connection, publicKey, encryptionService, storage, mintAddress });
|
|
72
|
-
logger.debug(`Found ${mintUtxos.length} total UTXOs`);
|
|
89
|
+
logger.debug(`Found ${mintUtxos.length} total UTXOs for ${token.name}`);
|
|
73
90
|
// Calculate and log total unspent UTXO balance
|
|
74
91
|
const totalUnspentBalance = mintUtxos.reduce((sum, utxo) => sum.add(utxo.amount), new BN(0));
|
|
75
92
|
logger.debug(`Total unspent UTXO balance before: ${totalUnspentBalance.toString()} lamports (${totalUnspentBalance.toNumber() / 1e9} SOL)`);
|
|
@@ -84,7 +101,7 @@ export async function withdrawSPL({ recipient, lightWasm, storage, publicKey, co
|
|
|
84
101
|
lightWasm,
|
|
85
102
|
keypair: utxoKeypair,
|
|
86
103
|
amount: '0',
|
|
87
|
-
mintAddress:
|
|
104
|
+
mintAddress: token.pubkey.toString()
|
|
88
105
|
});
|
|
89
106
|
const inputs = [firstInput, secondInput];
|
|
90
107
|
logger.debug(`firstInput index: ${firstInput.index}, commitment: ${firstInput.getCommitment()}`);
|
|
@@ -113,7 +130,7 @@ export async function withdrawSPL({ recipient, lightWasm, storage, publicKey, co
|
|
|
113
130
|
}
|
|
114
131
|
// For real UTXOs, fetch the proof from API
|
|
115
132
|
const commitment = await utxo.getCommitment();
|
|
116
|
-
return fetchMerkleProof(commitment,
|
|
133
|
+
return fetchMerkleProof(commitment, token.name);
|
|
117
134
|
}));
|
|
118
135
|
// Extract path elements and indices
|
|
119
136
|
const inputMerklePathElements = inputMerkleProofs.map(proof => proof.pathElements);
|
|
@@ -125,14 +142,14 @@ export async function withdrawSPL({ recipient, lightWasm, storage, publicKey, co
|
|
|
125
142
|
amount: changeAmount.toString(),
|
|
126
143
|
keypair: utxoKeypairV2,
|
|
127
144
|
index: currentNextIndex,
|
|
128
|
-
mintAddress:
|
|
145
|
+
mintAddress: token.pubkey.toString()
|
|
129
146
|
}), // Change output
|
|
130
147
|
new Utxo({
|
|
131
148
|
lightWasm,
|
|
132
149
|
amount: '0',
|
|
133
150
|
keypair: utxoKeypairV2,
|
|
134
151
|
index: currentNextIndex + 1,
|
|
135
|
-
mintAddress:
|
|
152
|
+
mintAddress: token.pubkey.toString()
|
|
136
153
|
}) // Empty UTXO
|
|
137
154
|
];
|
|
138
155
|
// For withdrawals, extAmount is negative (funds leaving the system)
|
|
@@ -185,7 +202,7 @@ export async function withdrawSPL({ recipient, lightWasm, storage, publicKey, co
|
|
|
185
202
|
encryptedOutput2: encryptedOutput2,
|
|
186
203
|
fee: new BN(fee_base_units),
|
|
187
204
|
feeRecipient: feeRecipientTokenAccount,
|
|
188
|
-
mintAddress:
|
|
205
|
+
mintAddress: token.pubkey.toString()
|
|
189
206
|
};
|
|
190
207
|
// Calculate the extDataHash with the encrypted outputs
|
|
191
208
|
const calculatedExtDataHash = getExtDataHash(extData);
|
|
@@ -193,7 +210,7 @@ export async function withdrawSPL({ recipient, lightWasm, storage, publicKey, co
|
|
|
193
210
|
const input = {
|
|
194
211
|
// Common transaction data
|
|
195
212
|
root: root,
|
|
196
|
-
mintAddress: getMintAddressField(
|
|
213
|
+
mintAddress: getMintAddressField(token.pubkey), // new mint address
|
|
197
214
|
publicAmount: publicAmountForCircuit.toString(), // Use proper field arithmetic result
|
|
198
215
|
extDataHash: calculatedExtDataHash,
|
|
199
216
|
// Input UTXO data (UTXOs being spent) - ensure all values are in decimal format
|
|
@@ -239,7 +256,7 @@ export async function withdrawSPL({ recipient, lightWasm, storage, publicKey, co
|
|
|
239
256
|
const serializedProof = serializeProofAndExtData(proofToSubmit, extData, true);
|
|
240
257
|
logger.debug(`Total instruction data size: ${serializedProof.length} bytes`);
|
|
241
258
|
const [globalConfigPda, globalConfigPdaBump] = await PublicKey.findProgramAddressSync([Buffer.from("global_config")], PROGRAM_ID);
|
|
242
|
-
const treeAta = getAssociatedTokenAddressSync(
|
|
259
|
+
const treeAta = getAssociatedTokenAddressSync(token.pubkey, globalConfigPda, true);
|
|
243
260
|
// Prepare withdraw parameters for indexer backend
|
|
244
261
|
const withdrawParams = {
|
|
245
262
|
serializedProof: serializedProof.toString('base64'),
|
|
@@ -258,7 +275,7 @@ export async function withdrawSPL({ recipient, lightWasm, storage, publicKey, co
|
|
|
258
275
|
senderAddress: publicKey.toString(),
|
|
259
276
|
treeAta: treeAta.toString(),
|
|
260
277
|
recipientAta: recipient_ata.toString(),
|
|
261
|
-
mintAddress:
|
|
278
|
+
mintAddress: token.pubkey.toString(),
|
|
262
279
|
feeRecipientTokenAccount: feeRecipientTokenAccount.toString()
|
|
263
280
|
};
|
|
264
281
|
logger.debug('Prepared withdraw parameters for indexer backend');
|
|
@@ -275,7 +292,7 @@ export async function withdrawSPL({ recipient, lightWasm, storage, publicKey, co
|
|
|
275
292
|
console.log(`retryTimes: ${retryTimes}`);
|
|
276
293
|
await new Promise(resolve => setTimeout(resolve, itv * 1000));
|
|
277
294
|
console.log('Fetching updated tree state...');
|
|
278
|
-
let res = await fetch(RELAYER_API_URL + '/utxos/check/' + encryptedOutputStr + '?token=
|
|
295
|
+
let res = await fetch(RELAYER_API_URL + '/utxos/check/' + encryptedOutputStr + '?token=' + token.name);
|
|
279
296
|
let resJson = await res.json();
|
|
280
297
|
console.log('resJson:', resJson);
|
|
281
298
|
if (resJson.exists) {
|
package/package.json
CHANGED
package/src/config.ts
CHANGED
|
@@ -5,6 +5,7 @@ type Config = {
|
|
|
5
5
|
withdraw_rent_fee: number
|
|
6
6
|
deposit_fee_rate: number
|
|
7
7
|
usdc_withdraw_rent_fee: number
|
|
8
|
+
rent_fees: any
|
|
8
9
|
}
|
|
9
10
|
|
|
10
11
|
let config: Config | undefined
|
|
@@ -14,7 +15,7 @@ export async function getConfig<K extends keyof Config>(key: K): Promise<Config[
|
|
|
14
15
|
const res = await fetch(RELAYER_API_URL + '/config')
|
|
15
16
|
config = await res.json()
|
|
16
17
|
}
|
|
17
|
-
if (typeof config![key]
|
|
18
|
+
if (typeof config![key] == 'undefined') {
|
|
18
19
|
throw new Error(`can not get ${key} from ${RELAYER_API_URL}/config`)
|
|
19
20
|
}
|
|
20
21
|
return config![key]
|
package/src/deposit.ts
CHANGED
|
@@ -67,6 +67,7 @@ type DepositParams = {
|
|
|
67
67
|
export async function deposit({ lightWasm, storage, keyBasePath, publicKey, connection, amount_in_lamports, encryptionService, transactionSigner, referrer }: DepositParams) {
|
|
68
68
|
// check limit
|
|
69
69
|
let limitAmount = await checkDepositLimit(connection)
|
|
70
|
+
|
|
70
71
|
if (limitAmount && amount_in_lamports > limitAmount * LAMPORTS_PER_SOL) {
|
|
71
72
|
throw new Error(`Don't deposit more than ${limitAmount} SOL`)
|
|
72
73
|
}
|
|
@@ -451,7 +452,7 @@ async function checkDepositLimit(connection: Connection) {
|
|
|
451
452
|
const accountInfo = await connection.getAccountInfo(treeAccount);
|
|
452
453
|
|
|
453
454
|
if (!accountInfo) {
|
|
454
|
-
console.error('❌ Tree account not found. Make sure the program is initialized.');
|
|
455
|
+
console.error('❌ Tree account not found. Make sure the program is initialized.' + PROGRAM_ID);
|
|
455
456
|
return;
|
|
456
457
|
}
|
|
457
458
|
|
package/src/depositSPL.ts
CHANGED
|
@@ -8,7 +8,7 @@ import { MerkleTree } from './utils/merkle_tree.js';
|
|
|
8
8
|
import { EncryptionService, serializeProofAndExtData } from './utils/encryption.js';
|
|
9
9
|
import { Keypair as UtxoKeypair } from './models/keypair.js';
|
|
10
10
|
import { getUtxosSPL, isUtxoSpent } from './getUtxosSPL.js';
|
|
11
|
-
import { FIELD_SIZE, FEE_RECIPIENT, MERKLE_TREE_DEPTH, RELAYER_API_URL, PROGRAM_ID, ALT_ADDRESS } from './utils/constants.js';
|
|
11
|
+
import { FIELD_SIZE, FEE_RECIPIENT, MERKLE_TREE_DEPTH, RELAYER_API_URL, PROGRAM_ID, ALT_ADDRESS, tokens, SplList, Token } from './utils/constants.js';
|
|
12
12
|
import { getProtocolAddressesWithMint, useExistingALT } from './utils/address_lookup_table.js';
|
|
13
13
|
import { logger } from './utils/logger.js';
|
|
14
14
|
import { getAssociatedTokenAddress, ASSOCIATED_TOKEN_PROGRAM_ID, TOKEN_PROGRAM_ID, getAssociatedTokenAddressSync, getMint, getAccount } from '@solana/spl-token';
|
|
@@ -34,7 +34,7 @@ async function relayDepositToIndexer({ signedTransaction, publicKey, referrer, m
|
|
|
34
34
|
if (referrer) {
|
|
35
35
|
params.referralWalletAddress = referrer
|
|
36
36
|
}
|
|
37
|
-
params.mintAddress = mintAddress
|
|
37
|
+
params.mintAddress = mintAddress
|
|
38
38
|
|
|
39
39
|
const response = await fetch(`${RELAYER_API_URL}/deposit/spl`, {
|
|
40
40
|
method: 'POST',
|
|
@@ -63,10 +63,11 @@ async function relayDepositToIndexer({ signedTransaction, publicKey, referrer, m
|
|
|
63
63
|
}
|
|
64
64
|
|
|
65
65
|
type DepositParams = {
|
|
66
|
-
mintAddress: PublicKey,
|
|
66
|
+
mintAddress: PublicKey | string,
|
|
67
67
|
publicKey: PublicKey,
|
|
68
68
|
connection: Connection,
|
|
69
|
-
base_units
|
|
69
|
+
base_units?: number,
|
|
70
|
+
amount?: number,
|
|
70
71
|
storage: Storage,
|
|
71
72
|
encryptionService: EncryptionService,
|
|
72
73
|
keyBasePath: string,
|
|
@@ -74,61 +75,70 @@ type DepositParams = {
|
|
|
74
75
|
referrer?: string,
|
|
75
76
|
transactionSigner: (tx: VersionedTransaction) => Promise<VersionedTransaction>
|
|
76
77
|
}
|
|
77
|
-
export async function depositSPL({ lightWasm, storage, keyBasePath, publicKey, connection, base_units, encryptionService, transactionSigner, referrer, mintAddress }: DepositParams) {
|
|
78
|
-
|
|
79
|
-
|
|
78
|
+
export async function depositSPL({ lightWasm, storage, keyBasePath, publicKey, connection, base_units, amount, encryptionService, transactionSigner, referrer, mintAddress }: DepositParams) {
|
|
79
|
+
if (typeof mintAddress == 'string') {
|
|
80
|
+
mintAddress = new PublicKey(mintAddress)
|
|
81
|
+
}
|
|
82
|
+
let token = tokens.find(t => t.pubkey.toString() == mintAddress.toString())
|
|
83
|
+
if (!token) {
|
|
84
|
+
throw new Error('token not found: ' + mintAddress.toString())
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (amount) {
|
|
88
|
+
base_units = amount * token.units_per_token
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (!base_units) {
|
|
92
|
+
throw new Error('You must input at least one of "base_units" or "amount"')
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
// let mintInfo = await getMint(connection, token.pubkey)
|
|
97
|
+
// let units_per_token = 10 ** mintInfo.decimals
|
|
80
98
|
|
|
81
99
|
let recipient = new PublicKey('AWexibGxNFKTa1b5R5MN4PJr9HWnWRwf8EW9g8cLx3dM')
|
|
82
100
|
let recipient_ata = getAssociatedTokenAddressSync(
|
|
83
|
-
|
|
101
|
+
token.pubkey,
|
|
84
102
|
recipient,
|
|
85
103
|
true
|
|
86
104
|
);
|
|
87
105
|
let feeRecipientTokenAccount = getAssociatedTokenAddressSync(
|
|
88
|
-
|
|
106
|
+
token.pubkey,
|
|
89
107
|
FEE_RECIPIENT,
|
|
90
108
|
true
|
|
91
109
|
);
|
|
92
110
|
let signerTokenAccount = getAssociatedTokenAddressSync(
|
|
93
|
-
|
|
111
|
+
token.pubkey,
|
|
94
112
|
publicKey
|
|
95
113
|
);
|
|
96
114
|
|
|
97
|
-
// Derive tree account PDA with mint address for SPL
|
|
115
|
+
// Derive tree account PDA with mint address for SPL
|
|
98
116
|
const [treeAccount] = PublicKey.findProgramAddressSync(
|
|
99
|
-
[Buffer.from('merkle_tree'),
|
|
117
|
+
[Buffer.from('merkle_tree'), token.pubkey.toBuffer()],
|
|
100
118
|
PROGRAM_ID
|
|
101
119
|
);
|
|
102
120
|
|
|
103
|
-
let limitAmount = await checkDepositLimit(connection, treeAccount)
|
|
104
|
-
if (limitAmount && base_units > limitAmount *
|
|
105
|
-
throw new Error(`Don't deposit more than ${limitAmount}
|
|
121
|
+
let limitAmount = await checkDepositLimit(connection, treeAccount, token)
|
|
122
|
+
if (limitAmount && base_units > limitAmount * token.units_per_token) {
|
|
123
|
+
throw new Error(`Don't deposit more than ${limitAmount} ${token.name.toUpperCase()}`)
|
|
106
124
|
}
|
|
107
125
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
// check limit
|
|
111
|
-
// let limitAmount = await checkDepositLimit(connection)
|
|
112
|
-
// if (limitAmount && base_units > limitAmount * units_per_token) {
|
|
113
|
-
// throw new Error(`Don't deposit more than ${limitAmount} SOL`)
|
|
114
|
-
// }
|
|
115
|
-
|
|
116
126
|
// const base_units = amount_in_sol * units_per_token
|
|
117
127
|
const fee_base_units = 0
|
|
118
128
|
logger.debug('Encryption key generated from user keypair');
|
|
119
129
|
logger.debug(`User wallet: ${publicKey.toString()}`);
|
|
120
|
-
logger.debug(`Deposit amount: ${base_units} base_units (${base_units / units_per_token}
|
|
121
|
-
logger.debug(`Calculated fee: ${fee_base_units} base_units (${fee_base_units / units_per_token}
|
|
130
|
+
logger.debug(`Deposit amount: ${base_units} base_units (${base_units / token.units_per_token} ${token.name.toUpperCase()})`);
|
|
131
|
+
logger.debug(`Calculated fee: ${fee_base_units} base_units (${fee_base_units / token.units_per_token} ${token.name.toUpperCase()})`);
|
|
122
132
|
|
|
123
133
|
// Check SPL balance
|
|
124
134
|
const accountInfo = await getAccount(connection, signerTokenAccount)
|
|
125
135
|
let balance = Number(accountInfo.amount)
|
|
126
|
-
logger.debug(`
|
|
136
|
+
logger.debug(`wallet balance: ${balance / token.units_per_token} ${token.name.toUpperCase()}`);
|
|
127
137
|
console.log('balance', balance)
|
|
128
138
|
console.log('base_units + fee_base_units', base_units + fee_base_units)
|
|
129
139
|
|
|
130
140
|
if (balance < (base_units + fee_base_units)) {
|
|
131
|
-
throw new Error(`Insufficient balance. Need at least ${(base_units + fee_base_units) / units_per_token}
|
|
141
|
+
throw new Error(`Insufficient balance. Need at least ${(base_units + fee_base_units) / token.units_per_token} ${token.name.toUpperCase()}.`);
|
|
132
142
|
}
|
|
133
143
|
|
|
134
144
|
// Check SOL balance
|
|
@@ -145,7 +155,7 @@ export async function depositSPL({ lightWasm, storage, keyBasePath, publicKey, c
|
|
|
145
155
|
const tree = new MerkleTree(MERKLE_TREE_DEPTH, lightWasm);
|
|
146
156
|
|
|
147
157
|
// Initialize root and nextIndex variables
|
|
148
|
-
const { root, nextIndex: currentNextIndex } = await queryRemoteTreeState(
|
|
158
|
+
const { root, nextIndex: currentNextIndex } = await queryRemoteTreeState(token.name);
|
|
149
159
|
|
|
150
160
|
logger.debug(`Using tree root: ${root}`);
|
|
151
161
|
logger.debug(`New UTXOs will be inserted at indices: ${currentNextIndex} and ${currentNextIndex + 1}`);
|
|
@@ -185,12 +195,12 @@ export async function depositSPL({ lightWasm, storage, keyBasePath, publicKey, c
|
|
|
185
195
|
new Utxo({
|
|
186
196
|
lightWasm,
|
|
187
197
|
keypair: utxoKeypair,
|
|
188
|
-
mintAddress:
|
|
198
|
+
mintAddress: token.pubkey.toString()
|
|
189
199
|
}),
|
|
190
200
|
new Utxo({
|
|
191
201
|
lightWasm,
|
|
192
202
|
keypair: utxoKeypair,
|
|
193
|
-
mintAddress:
|
|
203
|
+
mintAddress: token.pubkey.toString()
|
|
194
204
|
})
|
|
195
205
|
];
|
|
196
206
|
|
|
@@ -227,7 +237,7 @@ export async function depositSPL({ lightWasm, storage, keyBasePath, publicKey, c
|
|
|
227
237
|
lightWasm,
|
|
228
238
|
keypair: utxoKeypair,
|
|
229
239
|
amount: '0', // This UTXO will be inserted at currentNextIndex
|
|
230
|
-
mintAddress:
|
|
240
|
+
mintAddress: token.pubkey.toString()
|
|
231
241
|
});
|
|
232
242
|
|
|
233
243
|
inputs = [
|
|
@@ -237,13 +247,13 @@ export async function depositSPL({ lightWasm, storage, keyBasePath, publicKey, c
|
|
|
237
247
|
|
|
238
248
|
// Fetch Merkle proofs for real UTXOs
|
|
239
249
|
const firstUtxoCommitment = await firstUtxo.getCommitment();
|
|
240
|
-
const firstUtxoMerkleProof = await fetchMerkleProof(firstUtxoCommitment,
|
|
250
|
+
const firstUtxoMerkleProof = await fetchMerkleProof(firstUtxoCommitment, token.name);
|
|
241
251
|
|
|
242
252
|
let secondUtxoMerkleProof;
|
|
243
253
|
if (secondUtxo.amount.gt(new BN(0))) {
|
|
244
254
|
// Second UTXO is real, fetch its proof
|
|
245
255
|
const secondUtxoCommitment = await secondUtxo.getCommitment();
|
|
246
|
-
secondUtxoMerkleProof = await fetchMerkleProof(secondUtxoCommitment,
|
|
256
|
+
secondUtxoMerkleProof = await fetchMerkleProof(secondUtxoCommitment, token.name);
|
|
247
257
|
logger.debug('\nSecond UTXO to be consolidated:');
|
|
248
258
|
await secondUtxo.log();
|
|
249
259
|
}
|
|
@@ -278,14 +288,14 @@ export async function depositSPL({ lightWasm, storage, keyBasePath, publicKey, c
|
|
|
278
288
|
amount: outputAmount,
|
|
279
289
|
keypair: utxoKeypair,
|
|
280
290
|
index: currentNextIndex, // This UTXO will be inserted at currentNextIndex
|
|
281
|
-
mintAddress:
|
|
291
|
+
mintAddress: token.pubkey.toString()
|
|
282
292
|
}), // Output with value (either deposit amount minus fee, or input amount minus fee)
|
|
283
293
|
new Utxo({
|
|
284
294
|
lightWasm,
|
|
285
295
|
amount: '0',
|
|
286
296
|
keypair: utxoKeypair,
|
|
287
297
|
index: currentNextIndex + 1, // This UTXO will be inserted at currentNextIndex
|
|
288
|
-
mintAddress:
|
|
298
|
+
mintAddress: token.pubkey.toString()
|
|
289
299
|
}) // Empty UTXO
|
|
290
300
|
];
|
|
291
301
|
|
|
@@ -341,7 +351,7 @@ export async function depositSPL({ lightWasm, storage, keyBasePath, publicKey, c
|
|
|
341
351
|
encryptedOutput2: encryptedOutput2,
|
|
342
352
|
fee: new BN(fee_base_units),
|
|
343
353
|
feeRecipient: feeRecipientTokenAccount,
|
|
344
|
-
mintAddress:
|
|
354
|
+
mintAddress: token.pubkey.toString()
|
|
345
355
|
};
|
|
346
356
|
// Calculate the extDataHash with the encrypted outputs (now includes mintAddress for security)
|
|
347
357
|
const calculatedExtDataHash = getExtDataHash(extData);
|
|
@@ -350,7 +360,7 @@ export async function depositSPL({ lightWasm, storage, keyBasePath, publicKey, c
|
|
|
350
360
|
const input = {
|
|
351
361
|
// Common transaction data
|
|
352
362
|
root: root,
|
|
353
|
-
mintAddress: getMintAddressField(
|
|
363
|
+
mintAddress: getMintAddressField(token.pubkey),// new mint address
|
|
354
364
|
publicAmount: publicAmountForCircuit.toString(), // Use proper field arithmetic result
|
|
355
365
|
extDataHash: calculatedExtDataHash,
|
|
356
366
|
|
|
@@ -403,7 +413,7 @@ export async function depositSPL({ lightWasm, storage, keyBasePath, publicKey, c
|
|
|
403
413
|
[Buffer.from("global_config")],
|
|
404
414
|
PROGRAM_ID
|
|
405
415
|
);
|
|
406
|
-
const treeAta = getAssociatedTokenAddressSync(
|
|
416
|
+
const treeAta = getAssociatedTokenAddressSync(token.pubkey, globalConfigPda, true);
|
|
407
417
|
|
|
408
418
|
const lookupTableAccount = await useExistingALT(connection, ALT_ADDRESS);
|
|
409
419
|
|
|
@@ -428,7 +438,7 @@ export async function depositSPL({ lightWasm, storage, keyBasePath, publicKey, c
|
|
|
428
438
|
// signer
|
|
429
439
|
{ pubkey: publicKey, isSigner: true, isWritable: true },
|
|
430
440
|
// SPL token mint
|
|
431
|
-
{ pubkey:
|
|
441
|
+
{ pubkey: token.pubkey, isSigner: false, isWritable: false },
|
|
432
442
|
// signer's token account
|
|
433
443
|
{ pubkey: signerTokenAccount, isSigner: false, isWritable: true },
|
|
434
444
|
// recipient (placeholder)
|
|
@@ -482,7 +492,7 @@ export async function depositSPL({ lightWasm, storage, keyBasePath, publicKey, c
|
|
|
482
492
|
// Relay the pre-signed transaction to indexer backend
|
|
483
493
|
logger.info('submitting transaction to relayer...')
|
|
484
494
|
const signature = await relayDepositToIndexer({
|
|
485
|
-
mintAddress:
|
|
495
|
+
mintAddress: token.pubkey.toString(),
|
|
486
496
|
publicKey,
|
|
487
497
|
signedTransaction: serializedTransaction,
|
|
488
498
|
referrer
|
|
@@ -500,7 +510,7 @@ export async function depositSPL({ lightWasm, storage, keyBasePath, publicKey, c
|
|
|
500
510
|
logger.debug(`retryTimes: ${retryTimes}`)
|
|
501
511
|
await new Promise(resolve => setTimeout(resolve, itv * 1000));
|
|
502
512
|
logger.debug('Fetching updated tree state...');
|
|
503
|
-
let url = RELAYER_API_URL + '/utxos/check/' + encryptedOutputStr + '?token=
|
|
513
|
+
let url = RELAYER_API_URL + '/utxos/check/' + encryptedOutputStr + '?token=' + token.name
|
|
504
514
|
let res = await fetch(url)
|
|
505
515
|
let resJson = await res.json()
|
|
506
516
|
if (resJson.exists) {
|
|
@@ -516,7 +526,7 @@ export async function depositSPL({ lightWasm, storage, keyBasePath, publicKey, c
|
|
|
516
526
|
}
|
|
517
527
|
|
|
518
528
|
|
|
519
|
-
async function checkDepositLimit(connection: Connection, treeAccount: PublicKey) {
|
|
529
|
+
async function checkDepositLimit(connection: Connection, treeAccount: PublicKey, token: Token) {
|
|
520
530
|
try {
|
|
521
531
|
|
|
522
532
|
// Fetch the account data
|
|
@@ -533,21 +543,21 @@ async function checkDepositLimit(connection: Connection, treeAccount: PublicKey)
|
|
|
533
543
|
const maxDepositAmount = new BN(accountInfo.data.slice(4120, 4128), 'le');
|
|
534
544
|
const bump = accountInfo.data[4128];
|
|
535
545
|
|
|
536
|
-
// Convert to
|
|
537
|
-
const
|
|
538
|
-
const
|
|
539
|
-
const remainder = maxDepositAmount.mod(
|
|
546
|
+
// Convert to SPL using BN division to handle large numbers
|
|
547
|
+
const unitesPerToken = new BN(token.units_per_token);
|
|
548
|
+
const maxDepositSpl = maxDepositAmount.div(unitesPerToken);
|
|
549
|
+
const remainder = maxDepositAmount.mod(unitesPerToken);
|
|
540
550
|
|
|
541
|
-
// Format the
|
|
542
|
-
let
|
|
551
|
+
// Format the SPL amount with decimals
|
|
552
|
+
let amountFormatted = '1';
|
|
543
553
|
if (remainder.eq(new BN(0))) {
|
|
544
|
-
|
|
554
|
+
amountFormatted = maxDepositSpl.toString();
|
|
545
555
|
} else {
|
|
546
|
-
// Handle fractional
|
|
547
|
-
const fractional = remainder.toNumber() /
|
|
548
|
-
|
|
556
|
+
// Handle fractional SPL by converting remainder to decimal
|
|
557
|
+
const fractional = remainder.toNumber() / token.units_per_token;
|
|
558
|
+
amountFormatted = `${maxDepositSpl.toString()}${fractional.toFixed(Math.log10(token.units_per_token)).substring(1)}`;
|
|
549
559
|
}
|
|
550
|
-
return Number(
|
|
560
|
+
return Number(amountFormatted)
|
|
551
561
|
|
|
552
562
|
} catch (error) {
|
|
553
563
|
console.log('❌ Error reading deposit limit:', error);
|
package/src/exportUtils.ts
CHANGED
|
@@ -7,4 +7,6 @@ export { getBalanceFromUtxos, getUtxos, localstorageKey } from './getUtxos.js'
|
|
|
7
7
|
|
|
8
8
|
export { depositSPL } from './depositSPL.js'
|
|
9
9
|
export { withdrawSPL } from './withdrawSPL.js'
|
|
10
|
-
export { getBalanceFromUtxosSPL, getUtxosSPL } from './getUtxosSPL.js'
|
|
10
|
+
export { getBalanceFromUtxosSPL, getUtxosSPL } from './getUtxosSPL.js'
|
|
11
|
+
|
|
12
|
+
export { type TokenList, type SplList, tokens } from './utils/constants.js'
|