privacycash 1.1.23 → 1.2.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/__tests__/store-alias.test.ts +67 -0
- package/dist/config.d.ts +3 -1
- package/dist/config.js +10 -2
- package/dist/depositSPL.js +8 -4
- package/dist/exportUtils.d.ts +1 -1
- package/dist/exportUtils.js +1 -1
- package/dist/getUtxosSPL.js +4 -3
- package/dist/utils/constants.d.ts +8 -2
- package/dist/utils/constants.js +52 -3
- package/dist/withdrawSPL.js +7 -3
- package/package.json +5 -3
- package/src/config.ts +15 -4
- package/src/depositSPL.ts +9 -5
- package/src/exportUtils.ts +1 -1
- package/src/getUtxosSPL.ts +5 -4
- package/src/utils/constants.ts +57 -4
- package/src/withdrawSPL.ts +7 -3
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { PublicKey } from '@solana/web3.js';
|
|
2
|
+
import { describe, expect, it } from 'vitest';
|
|
3
|
+
import { depositSPL } from '../src/depositSPL';
|
|
4
|
+
import {
|
|
5
|
+
getRelayerTokenName,
|
|
6
|
+
LEGACY_STORE_MINT,
|
|
7
|
+
normalizeRelayerTokenMap,
|
|
8
|
+
resolveToken,
|
|
9
|
+
resolveTokenName,
|
|
10
|
+
STORE_MINT,
|
|
11
|
+
tokens,
|
|
12
|
+
} from '../src/utils/constants';
|
|
13
|
+
|
|
14
|
+
describe('stORE token aliases', () => {
|
|
15
|
+
it('exports latest stORE as store and old stORE as legacyStore', () => {
|
|
16
|
+
const tokenNames = tokens.map(token => token.name);
|
|
17
|
+
|
|
18
|
+
expect(tokenNames).toContain('store');
|
|
19
|
+
expect(tokenNames).toContain('legacyStore');
|
|
20
|
+
expect(tokenNames).not.toContain('newstore' as any);
|
|
21
|
+
|
|
22
|
+
expect(tokens.find(token => token.name === 'store')?.pubkey.toString()).toBe(STORE_MINT.toString());
|
|
23
|
+
expect(tokens.find(token => token.name === 'legacyStore')?.pubkey.toString()).toBe(LEGACY_STORE_MINT.toString());
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it('maps public stORE names to relayer token names', () => {
|
|
27
|
+
expect(getRelayerTokenName('store')).toBe('newstore');
|
|
28
|
+
expect(getRelayerTokenName('legacyStore')).toBe('store');
|
|
29
|
+
expect(getRelayerTokenName('usdc')).toBe('usdc');
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it('resolves CLI token aliases without exposing newstore', () => {
|
|
33
|
+
expect(resolveTokenName('store')).toBe('store');
|
|
34
|
+
expect(resolveTokenName('newstore')).toBe('store');
|
|
35
|
+
expect(resolveTokenName('legacyStore')).toBe('legacyStore');
|
|
36
|
+
expect(resolveTokenName('legacystore')).toBe('legacyStore');
|
|
37
|
+
|
|
38
|
+
expect(resolveToken('newstore')?.pubkey.toString()).toBe(STORE_MINT.toString());
|
|
39
|
+
expect(resolveToken('legacyStore')?.pubkey.toString()).toBe(LEGACY_STORE_MINT.toString());
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it('normalizes relayer config maps without exposing newstore', () => {
|
|
43
|
+
expect(normalizeRelayerTokenMap({
|
|
44
|
+
sol: 1,
|
|
45
|
+
store: 2,
|
|
46
|
+
newstore: 3,
|
|
47
|
+
})).toEqual({
|
|
48
|
+
sol: 1,
|
|
49
|
+
store: 3,
|
|
50
|
+
legacyStore: 2,
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it('rejects legacy stORE deposits before transaction work starts', async () => {
|
|
55
|
+
await expect(depositSPL({
|
|
56
|
+
mintAddress: new PublicKey(LEGACY_STORE_MINT),
|
|
57
|
+
lightWasm: {} as any,
|
|
58
|
+
storage: {} as any,
|
|
59
|
+
keyBasePath: '',
|
|
60
|
+
publicKey: PublicKey.default,
|
|
61
|
+
connection: {} as any,
|
|
62
|
+
base_units: 1,
|
|
63
|
+
encryptionService: {} as any,
|
|
64
|
+
transactionSigner: async tx => tx,
|
|
65
|
+
})).rejects.toThrow('Legacy stORE deposit has been disabled. Please use the latest stORE.');
|
|
66
|
+
});
|
|
67
|
+
});
|
package/dist/config.d.ts
CHANGED
|
@@ -3,7 +3,9 @@ type Config = {
|
|
|
3
3
|
withdraw_rent_fee: number;
|
|
4
4
|
deposit_fee_rate: number;
|
|
5
5
|
usdc_withdraw_rent_fee: number;
|
|
6
|
-
rent_fees:
|
|
6
|
+
rent_fees: Record<string, number>;
|
|
7
|
+
minimum_withdrawal: Record<string, number>;
|
|
8
|
+
prices: Record<string, number>;
|
|
7
9
|
};
|
|
8
10
|
export declare function getConfig<K extends keyof Config>(key: K): Promise<Config[K]>;
|
|
9
11
|
export {};
|
package/dist/config.js
CHANGED
|
@@ -1,12 +1,20 @@
|
|
|
1
|
-
import { RELAYER_API_URL } from "./utils/constants.js";
|
|
1
|
+
import { normalizeRelayerTokenMap, RELAYER_API_URL } from "./utils/constants.js";
|
|
2
2
|
let config;
|
|
3
3
|
export async function getConfig(key) {
|
|
4
4
|
if (!config) {
|
|
5
5
|
const res = await fetch(RELAYER_API_URL + '/config');
|
|
6
|
-
config = await res.json();
|
|
6
|
+
config = normalizeConfig(await res.json());
|
|
7
7
|
}
|
|
8
8
|
if (typeof config[key] == 'undefined') {
|
|
9
9
|
throw new Error(`can not get ${key} from ${RELAYER_API_URL}/config`);
|
|
10
10
|
}
|
|
11
11
|
return config[key];
|
|
12
12
|
}
|
|
13
|
+
function normalizeConfig(raw) {
|
|
14
|
+
return {
|
|
15
|
+
...raw,
|
|
16
|
+
rent_fees: normalizeRelayerTokenMap(raw.rent_fees) ?? {},
|
|
17
|
+
minimum_withdrawal: normalizeRelayerTokenMap(raw.minimum_withdrawal) ?? {},
|
|
18
|
+
prices: normalizeRelayerTokenMap(raw.prices) ?? {},
|
|
19
|
+
};
|
|
20
|
+
}
|
package/dist/depositSPL.js
CHANGED
|
@@ -5,7 +5,7 @@ import { getUtxosSPL } from './getUtxosSPL.js';
|
|
|
5
5
|
import { Keypair as UtxoKeypair } from './models/keypair.js';
|
|
6
6
|
import { Utxo } from './models/utxo.js';
|
|
7
7
|
import { useExistingALT } from './utils/address_lookup_table.js';
|
|
8
|
-
import { ALT_ADDRESS, FEE_RECIPIENT, FIELD_SIZE, MERKLE_TREE_DEPTH, PROGRAM_ID, RELAYER_API_URL, tokens } from './utils/constants.js';
|
|
8
|
+
import { ALT_ADDRESS, FEE_RECIPIENT, FIELD_SIZE, getRelayerTokenName, MERKLE_TREE_DEPTH, PROGRAM_ID, RELAYER_API_URL, tokens } from './utils/constants.js';
|
|
9
9
|
import { serializeProofAndExtData } from './utils/encryption.js';
|
|
10
10
|
import { logger } from './utils/logger.js';
|
|
11
11
|
import { MerkleTree } from './utils/merkle_tree.js';
|
|
@@ -61,6 +61,10 @@ export async function depositSPL({ lightWasm, storage, keyBasePath, publicKey, c
|
|
|
61
61
|
if (!token) {
|
|
62
62
|
throw new Error('token not found: ' + mintAddress.toString());
|
|
63
63
|
}
|
|
64
|
+
if (token.name === 'legacyStore') {
|
|
65
|
+
throw new Error('Legacy stORE deposit has been disabled. Please use the latest stORE.');
|
|
66
|
+
}
|
|
67
|
+
const relayerTokenName = getRelayerTokenName(token.name);
|
|
64
68
|
if (amount) {
|
|
65
69
|
base_units = amount * token.units_per_token;
|
|
66
70
|
}
|
|
@@ -125,7 +129,7 @@ export async function depositSPL({ lightWasm, storage, keyBasePath, publicKey, c
|
|
|
125
129
|
let root;
|
|
126
130
|
let nextIndex;
|
|
127
131
|
if (mintUtxos.length === 0) {
|
|
128
|
-
const treeState = await queryRemoteTreeState(
|
|
132
|
+
const treeState = await queryRemoteTreeState(relayerTokenName);
|
|
129
133
|
root = treeState.root;
|
|
130
134
|
nextIndex = treeState.nextIndex;
|
|
131
135
|
// Scenario 1: Fresh deposit with dummy inputs - add new funds to the system
|
|
@@ -193,7 +197,7 @@ export async function depositSPL({ lightWasm, storage, keyBasePath, publicKey, c
|
|
|
193
197
|
logger.debug('\nSecond UTXO to be consolidated:');
|
|
194
198
|
await secondUtxo.log();
|
|
195
199
|
}
|
|
196
|
-
let data = await fetchMerkleProof(commitmentsToFetch,
|
|
200
|
+
let data = await fetchMerkleProof(commitmentsToFetch, relayerTokenName);
|
|
197
201
|
root = data.root;
|
|
198
202
|
nextIndex = data.nextIndex;
|
|
199
203
|
let [firstUtxoMerkleProof, secondUtxoMerkleProof] = data.proofs;
|
|
@@ -425,7 +429,7 @@ export async function depositSPL({ lightWasm, storage, keyBasePath, publicKey, c
|
|
|
425
429
|
logger.debug(`retryTimes: ${retryTimes}`);
|
|
426
430
|
await new Promise(resolve => setTimeout(resolve, itv * 1000));
|
|
427
431
|
logger.debug('Fetching updated onchain state...');
|
|
428
|
-
let url = RELAYER_API_URL + '/utxos/check/' + encryptedOutputStr + '?token=' +
|
|
432
|
+
let url = RELAYER_API_URL + '/utxos/check/' + encryptedOutputStr + '?token=' + relayerTokenName;
|
|
429
433
|
let res = await fetch(url);
|
|
430
434
|
let resJson = await res.json();
|
|
431
435
|
if (resJson.exists) {
|
package/dist/exportUtils.d.ts
CHANGED
|
@@ -7,4 +7,4 @@ export { getBalanceFromUtxos, getUtxos, localstorageKey } from './getUtxos.js';
|
|
|
7
7
|
export { depositSPL } from './depositSPL.js';
|
|
8
8
|
export { withdrawSPL } from './withdrawSPL.js';
|
|
9
9
|
export { getBalanceFromUtxosSPL, getUtxosSPL } from './getUtxosSPL.js';
|
|
10
|
-
export { type TokenList, type SplList, tokens } from './utils/constants.js';
|
|
10
|
+
export { getRelayerTokenName, LEGACY_STORE_MINT, normalizeRelayerTokenMap, STORE_MINT, type TokenList, type SplList, tokens } from './utils/constants.js';
|
package/dist/exportUtils.js
CHANGED
|
@@ -7,4 +7,4 @@ export { getBalanceFromUtxos, getUtxos, localstorageKey } from './getUtxos.js';
|
|
|
7
7
|
export { depositSPL } from './depositSPL.js';
|
|
8
8
|
export { withdrawSPL } from './withdrawSPL.js';
|
|
9
9
|
export { getBalanceFromUtxosSPL, getUtxosSPL } from './getUtxosSPL.js';
|
|
10
|
-
export { tokens } from './utils/constants.js';
|
|
10
|
+
export { getRelayerTokenName, LEGACY_STORE_MINT, normalizeRelayerTokenMap, STORE_MINT, tokens } from './utils/constants.js';
|
package/dist/getUtxosSPL.js
CHANGED
|
@@ -4,7 +4,7 @@ import { Keypair as UtxoKeypair } from './models/keypair.js';
|
|
|
4
4
|
import { WasmFactory } from '@lightprotocol/hasher.rs';
|
|
5
5
|
//@ts-ignore
|
|
6
6
|
import * as ffjavascript from 'ffjavascript';
|
|
7
|
-
import { FETCH_UTXOS_GROUP_SIZE, RELAYER_API_URL, LSK_ENCRYPTED_OUTPUTS, LSK_FETCH_OFFSET, PROGRAM_ID, tokens } from './utils/constants.js';
|
|
7
|
+
import { FETCH_UTXOS_GROUP_SIZE, getRelayerTokenName, RELAYER_API_URL, LSK_ENCRYPTED_OUTPUTS, LSK_FETCH_OFFSET, PROGRAM_ID, tokens } from './utils/constants.js';
|
|
8
8
|
import { logger } from './utils/logger.js';
|
|
9
9
|
import { getAssociatedTokenAddress } from '@solana/spl-token';
|
|
10
10
|
// Use type assertion for the utility functions (same pattern as in get_verification_keys.ts)
|
|
@@ -40,6 +40,7 @@ export async function getUtxosSPL({ publicKey, connection, encryptionService, st
|
|
|
40
40
|
if (!token) {
|
|
41
41
|
throw new Error('token not found: ' + mintAddress.toString());
|
|
42
42
|
}
|
|
43
|
+
const relayerTokenName = getRelayerTokenName(token.name);
|
|
43
44
|
logger.debug('token name: ' + token.name + ', token address' + token.pubkey.toString());
|
|
44
45
|
try {
|
|
45
46
|
publicKey_ata = await getAssociatedTokenAddress(token.pubkey, publicKey);
|
|
@@ -66,8 +67,8 @@ export async function getUtxosSPL({ publicKey, connection, encryptionService, st
|
|
|
66
67
|
}
|
|
67
68
|
logger.debug(' ####fetch_utxo_offset', fetch_utxo_offset);
|
|
68
69
|
let fetch_utxo_end = fetch_utxo_offset + FETCH_UTXOS_GROUP_SIZE;
|
|
69
|
-
let fetch_utxo_url = `${RELAYER_API_URL}/utxos/range?token=${
|
|
70
|
-
let fetched = await fetchUserUtxos({ url: fetch_utxo_url, encryptionService, storage, publicKey_ata, tokenName:
|
|
70
|
+
let fetch_utxo_url = `${RELAYER_API_URL}/utxos/range?token=${relayerTokenName}&start=${fetch_utxo_offset}&end=${fetch_utxo_end}`;
|
|
71
|
+
let fetched = await fetchUserUtxos({ url: fetch_utxo_url, encryptionService, storage, publicKey_ata, tokenName: relayerTokenName });
|
|
71
72
|
let am = 0;
|
|
72
73
|
const nonZeroUtxos = [];
|
|
73
74
|
const nonZeroEncrypted = [];
|
|
@@ -13,9 +13,11 @@ export declare const SIGN_MESSAGE = "Privacy Money account sign in";
|
|
|
13
13
|
export declare const LSK_FETCH_OFFSET = "fetch_offset";
|
|
14
14
|
export declare const LSK_ENCRYPTED_OUTPUTS = "encrypted_outputs";
|
|
15
15
|
export declare const USDC_MINT: PublicKey;
|
|
16
|
-
declare const
|
|
16
|
+
export declare const STORE_MINT: PublicKey;
|
|
17
|
+
export declare const LEGACY_STORE_MINT: PublicKey;
|
|
18
|
+
declare const tokenList: readonly ["sol", "usdc", "usdt", "zec", "ore", "store", "legacyStore", "jlusdc", "jlwsol"];
|
|
17
19
|
export type TokenList = typeof tokenList[number];
|
|
18
|
-
declare const splList: readonly ["usdc", "usdt", "zec", "ore", "store", "jlusdc", "jlwsol"];
|
|
20
|
+
declare const splList: readonly ["usdc", "usdt", "zec", "ore", "store", "legacyStore", "jlusdc", "jlwsol"];
|
|
19
21
|
export type SplList = typeof splList[number];
|
|
20
22
|
export type Token = {
|
|
21
23
|
name: TokenList;
|
|
@@ -24,4 +26,8 @@ export type Token = {
|
|
|
24
26
|
pubkey: PublicKey;
|
|
25
27
|
};
|
|
26
28
|
export declare const tokens: Token[];
|
|
29
|
+
export declare function getRelayerTokenName(tokenName: string): string;
|
|
30
|
+
export declare function resolveTokenName(tokenName: string): TokenList | undefined;
|
|
31
|
+
export declare function resolveToken(tokenName: string): Token | undefined;
|
|
32
|
+
export declare function normalizeRelayerTokenMap(values?: Record<string, number>): Record<string, number> | undefined;
|
|
27
33
|
export {};
|
package/dist/utils/constants.js
CHANGED
|
@@ -14,8 +14,14 @@ 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
|
|
18
|
-
const
|
|
17
|
+
export const STORE_MINT = process.env.NEXT_PUBLIC_NEWSTORE_MINT ? new PublicKey(process.env.NEXT_PUBLIC_NEWSTORE_MINT) : new PublicKey('storenSbvkfzircixnaosc5CbzNZVrHJ6S3EKrS1yqR');
|
|
18
|
+
export const LEGACY_STORE_MINT = process.env.NEXT_PUBLIC_LEGACY_STORE_MINT
|
|
19
|
+
? new PublicKey(process.env.NEXT_PUBLIC_LEGACY_STORE_MINT)
|
|
20
|
+
: process.env.NEXT_PUBLIC_STORE_MINT
|
|
21
|
+
? new PublicKey(process.env.NEXT_PUBLIC_STORE_MINT)
|
|
22
|
+
: new PublicKey('sTorERYB6xAZ1SSbwpK3zoK2EEwbBrc7TZAzg1uCGiH');
|
|
23
|
+
const tokenList = ['sol', 'usdc', 'usdt', 'zec', 'ore', 'store', 'legacyStore', 'jlusdc', 'jlwsol'];
|
|
24
|
+
const splList = ['usdc', 'usdt', 'zec', 'ore', 'store', 'legacyStore', 'jlusdc', 'jlwsol'];
|
|
19
25
|
export const tokens = [
|
|
20
26
|
{
|
|
21
27
|
name: 'sol',
|
|
@@ -49,10 +55,16 @@ export const tokens = [
|
|
|
49
55
|
},
|
|
50
56
|
{
|
|
51
57
|
name: 'store',
|
|
52
|
-
pubkey:
|
|
58
|
+
pubkey: STORE_MINT,
|
|
53
59
|
prefix: 'store_',
|
|
54
60
|
units_per_token: 1e11
|
|
55
61
|
},
|
|
62
|
+
{
|
|
63
|
+
name: 'legacyStore',
|
|
64
|
+
pubkey: LEGACY_STORE_MINT,
|
|
65
|
+
prefix: 'legacyStore_',
|
|
66
|
+
units_per_token: 1e11
|
|
67
|
+
},
|
|
56
68
|
{
|
|
57
69
|
name: 'jlusdc',
|
|
58
70
|
pubkey: process.env.NEXT_PUBLIC_JLUSDC_MINT ? new PublicKey(process.env.NEXT_PUBLIC_JLUSDC_MINT) : new PublicKey('9BEcn9aPEmhSPbPQeFGjidRiEKki46fVQDyPpSQXPA2D'),
|
|
@@ -66,3 +78,40 @@ export const tokens = [
|
|
|
66
78
|
units_per_token: 1e9
|
|
67
79
|
}
|
|
68
80
|
];
|
|
81
|
+
export function getRelayerTokenName(tokenName) {
|
|
82
|
+
if (tokenName === 'store') {
|
|
83
|
+
return 'newstore';
|
|
84
|
+
}
|
|
85
|
+
if (tokenName === 'legacyStore') {
|
|
86
|
+
return 'store';
|
|
87
|
+
}
|
|
88
|
+
return tokenName;
|
|
89
|
+
}
|
|
90
|
+
export function resolveTokenName(tokenName) {
|
|
91
|
+
const normalized = tokenName.trim().toLowerCase();
|
|
92
|
+
if (normalized === 'newstore') {
|
|
93
|
+
return 'store';
|
|
94
|
+
}
|
|
95
|
+
if (normalized === 'legacystore') {
|
|
96
|
+
return 'legacyStore';
|
|
97
|
+
}
|
|
98
|
+
return tokens.find(token => token.name.toLowerCase() === normalized)?.name;
|
|
99
|
+
}
|
|
100
|
+
export function resolveToken(tokenName) {
|
|
101
|
+
const resolvedName = resolveTokenName(tokenName);
|
|
102
|
+
return resolvedName ? tokens.find(token => token.name === resolvedName) : undefined;
|
|
103
|
+
}
|
|
104
|
+
export function normalizeRelayerTokenMap(values) {
|
|
105
|
+
if (!values) {
|
|
106
|
+
return values;
|
|
107
|
+
}
|
|
108
|
+
const normalized = { ...values };
|
|
109
|
+
if (values.newstore !== undefined) {
|
|
110
|
+
normalized.store = values.newstore;
|
|
111
|
+
}
|
|
112
|
+
if (values.store !== undefined) {
|
|
113
|
+
normalized.legacyStore = values.store;
|
|
114
|
+
}
|
|
115
|
+
delete normalized.newstore;
|
|
116
|
+
return normalized;
|
|
117
|
+
}
|
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, PROGRAM_ID, RELAYER_API_URL, tokens } from './utils/constants.js';
|
|
7
|
+
import { ALT_ADDRESS, FEE_RECIPIENT, FIELD_SIZE, getRelayerTokenName, PROGRAM_ID, RELAYER_API_URL, tokens } from './utils/constants.js';
|
|
8
8
|
import { serializeProofAndExtData } from './utils/encryption.js';
|
|
9
9
|
import { fetchMerkleProof, findCrossCheckNullifierPDAs, findNullifierPDAs, getExtDataHash, getMintAddressField, getProgramAccounts } from './utils/utils.js';
|
|
10
10
|
import { getAssociatedTokenAddressSync, getMint } from '@solana/spl-token';
|
|
@@ -44,6 +44,7 @@ export async function withdrawSPL({ recipient, lightWasm, storage, publicKey, co
|
|
|
44
44
|
if (!token) {
|
|
45
45
|
throw new Error('token not found: ' + mintAddress.toString());
|
|
46
46
|
}
|
|
47
|
+
const relayerTokenName = getRelayerTokenName(token.name);
|
|
47
48
|
if (amount) {
|
|
48
49
|
base_units = amount * token.units_per_token;
|
|
49
50
|
}
|
|
@@ -53,6 +54,9 @@ export async function withdrawSPL({ recipient, lightWasm, storage, publicKey, co
|
|
|
53
54
|
let mintInfo = await getMint(connection, token.pubkey);
|
|
54
55
|
let units_per_token = 10 ** mintInfo.decimals;
|
|
55
56
|
let withdraw_fee_rate = await getConfig('withdraw_fee_rate');
|
|
57
|
+
if (token.name === 'legacyStore') {
|
|
58
|
+
withdraw_fee_rate = 0;
|
|
59
|
+
}
|
|
56
60
|
let withdraw_rent_fees = await getConfig('rent_fees');
|
|
57
61
|
let token_rent_fee = withdraw_rent_fees[token.name];
|
|
58
62
|
if (!token_rent_fee) {
|
|
@@ -116,7 +120,7 @@ export async function withdrawSPL({ recipient, lightWasm, storage, publicKey, co
|
|
|
116
120
|
const changeAmount = totalInputAmount.sub(new BN(base_units)).sub(new BN(fee_base_units));
|
|
117
121
|
logger.debug(`Withdrawing ${base_units} lamports with ${fee_base_units} fee, ${changeAmount.toString()} as change`);
|
|
118
122
|
let commitmentsToFetch = inputs.map(utxo => utxo.getCommitment());
|
|
119
|
-
const { root, nextIndex, proofs } = await fetchMerkleProof(commitmentsToFetch,
|
|
123
|
+
const { root, nextIndex, proofs } = await fetchMerkleProof(commitmentsToFetch, relayerTokenName);
|
|
120
124
|
// Extract path elements and indices
|
|
121
125
|
const inputMerklePathElements = proofs.map(proof => proof.pathElements);
|
|
122
126
|
const inputMerklePathIndices = inputs.map(utxo => utxo.index || 0);
|
|
@@ -278,7 +282,7 @@ export async function withdrawSPL({ recipient, lightWasm, storage, publicKey, co
|
|
|
278
282
|
logger.debug(`retryTimes: ${retryTimes}`);
|
|
279
283
|
await new Promise(resolve => setTimeout(resolve, itv * 1000));
|
|
280
284
|
logger.info('Fetching updated onchain state...');
|
|
281
|
-
let res = await fetch(RELAYER_API_URL + '/utxos/check/' + encryptedOutputStr + '?token=' +
|
|
285
|
+
let res = await fetch(RELAYER_API_URL + '/utxos/check/' + encryptedOutputStr + '?token=' + relayerTokenName);
|
|
282
286
|
let resJson = await res.json();
|
|
283
287
|
logger.debug('resJson:', resJson);
|
|
284
288
|
if (resJson.exists) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "privacycash",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"repository": "https://github.com/Privacy-Cash/privacy-cash-sdk",
|
|
@@ -12,7 +12,9 @@
|
|
|
12
12
|
"type": "module",
|
|
13
13
|
"scripts": {
|
|
14
14
|
"build": "tsc",
|
|
15
|
-
"
|
|
15
|
+
"postinstall": "cp node_modules/@lightprotocol/hasher.rs/dist/hasher_wasm_simd_bg.wasm node_modules/@lightprotocol/hasher.rs/dist/browser-fat/es/ && cp node_modules/@lightprotocol/hasher.rs/dist/light_wasm_hasher_bg.wasm node_modules/@lightprotocol/hasher.rs/dist/browser-fat/es/",
|
|
16
|
+
"prepare": "npm run build",
|
|
17
|
+
"test": "vitest run --exclude \"**/__tests__/e2e.test.ts\" --exclude \"**/__tests__/e2espl.test.ts\"",
|
|
16
18
|
"teste2e": "vitest run e2e.test.ts",
|
|
17
19
|
"teste2espl": "vitest run e2espl.test.ts"
|
|
18
20
|
},
|
|
@@ -48,4 +50,4 @@
|
|
|
48
50
|
"typescript": "^5.9.2",
|
|
49
51
|
"vitest": "^3.2.4"
|
|
50
52
|
}
|
|
51
|
-
}
|
|
53
|
+
}
|
package/src/config.ts
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
|
-
import { RELAYER_API_URL } from "./utils/constants.js";
|
|
1
|
+
import { normalizeRelayerTokenMap, RELAYER_API_URL } from "./utils/constants.js";
|
|
2
2
|
|
|
3
3
|
type Config = {
|
|
4
4
|
withdraw_fee_rate: number
|
|
5
5
|
withdraw_rent_fee: number
|
|
6
6
|
deposit_fee_rate: number
|
|
7
7
|
usdc_withdraw_rent_fee: number
|
|
8
|
-
rent_fees:
|
|
8
|
+
rent_fees: Record<string, number>
|
|
9
|
+
minimum_withdrawal: Record<string, number>
|
|
10
|
+
prices: Record<string, number>
|
|
9
11
|
}
|
|
10
12
|
|
|
11
13
|
let config: Config | undefined
|
|
@@ -13,10 +15,19 @@ let config: Config | undefined
|
|
|
13
15
|
export async function getConfig<K extends keyof Config>(key: K): Promise<Config[K]> {
|
|
14
16
|
if (!config) {
|
|
15
17
|
const res = await fetch(RELAYER_API_URL + '/config')
|
|
16
|
-
config = await res.json()
|
|
18
|
+
config = normalizeConfig(await res.json())
|
|
17
19
|
}
|
|
18
20
|
if (typeof config![key] == 'undefined') {
|
|
19
21
|
throw new Error(`can not get ${key} from ${RELAYER_API_URL}/config`)
|
|
20
22
|
}
|
|
21
23
|
return config![key]
|
|
22
|
-
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function normalizeConfig(raw: Config): Config {
|
|
27
|
+
return {
|
|
28
|
+
...raw,
|
|
29
|
+
rent_fees: normalizeRelayerTokenMap(raw.rent_fees) ?? {},
|
|
30
|
+
minimum_withdrawal: normalizeRelayerTokenMap(raw.minimum_withdrawal) ?? {},
|
|
31
|
+
prices: normalizeRelayerTokenMap(raw.prices) ?? {},
|
|
32
|
+
}
|
|
33
|
+
}
|
package/src/depositSPL.ts
CHANGED
|
@@ -6,7 +6,7 @@ import { getUtxosSPL } from './getUtxosSPL.js';
|
|
|
6
6
|
import { Keypair as UtxoKeypair } from './models/keypair.js';
|
|
7
7
|
import { Utxo } from './models/utxo.js';
|
|
8
8
|
import { useExistingALT } from './utils/address_lookup_table.js';
|
|
9
|
-
import { ALT_ADDRESS, FEE_RECIPIENT, FIELD_SIZE, MERKLE_TREE_DEPTH, PROGRAM_ID, RELAYER_API_URL, Token, tokens } from './utils/constants.js';
|
|
9
|
+
import { ALT_ADDRESS, FEE_RECIPIENT, FIELD_SIZE, getRelayerTokenName, MERKLE_TREE_DEPTH, PROGRAM_ID, RELAYER_API_URL, Token, tokens } from './utils/constants.js';
|
|
10
10
|
import { EncryptionService, serializeProofAndExtData } from './utils/encryption.js';
|
|
11
11
|
import { logger } from './utils/logger.js';
|
|
12
12
|
import { MerkleTree } from './utils/merkle_tree.js';
|
|
@@ -88,6 +88,10 @@ export async function depositSPL({ lightWasm, storage, keyBasePath, publicKey, c
|
|
|
88
88
|
if (!token) {
|
|
89
89
|
throw new Error('token not found: ' + mintAddress.toString())
|
|
90
90
|
}
|
|
91
|
+
if (token.name === 'legacyStore') {
|
|
92
|
+
throw new Error('Legacy stORE deposit has been disabled. Please use the latest stORE.')
|
|
93
|
+
}
|
|
94
|
+
const relayerTokenName = getRelayerTokenName(token.name)
|
|
91
95
|
|
|
92
96
|
if (amount) {
|
|
93
97
|
base_units = amount * token.units_per_token
|
|
@@ -185,7 +189,7 @@ export async function depositSPL({ lightWasm, storage, keyBasePath, publicKey, c
|
|
|
185
189
|
let root: string;
|
|
186
190
|
let nextIndex: number;
|
|
187
191
|
if (mintUtxos.length === 0) {
|
|
188
|
-
const treeState = await queryRemoteTreeState(
|
|
192
|
+
const treeState = await queryRemoteTreeState(relayerTokenName);
|
|
189
193
|
root = treeState.root
|
|
190
194
|
nextIndex = treeState.nextIndex
|
|
191
195
|
// Scenario 1: Fresh deposit with dummy inputs - add new funds to the system
|
|
@@ -264,7 +268,7 @@ export async function depositSPL({ lightWasm, storage, keyBasePath, publicKey, c
|
|
|
264
268
|
await secondUtxo.log();
|
|
265
269
|
}
|
|
266
270
|
|
|
267
|
-
let data = await fetchMerkleProof(commitmentsToFetch,
|
|
271
|
+
let data = await fetchMerkleProof(commitmentsToFetch, relayerTokenName)
|
|
268
272
|
root = data.root
|
|
269
273
|
nextIndex = data.nextIndex
|
|
270
274
|
let [firstUtxoMerkleProof, secondUtxoMerkleProof] = data.proofs
|
|
@@ -542,7 +546,7 @@ export async function depositSPL({ lightWasm, storage, keyBasePath, publicKey, c
|
|
|
542
546
|
logger.debug(`retryTimes: ${retryTimes}`)
|
|
543
547
|
await new Promise(resolve => setTimeout(resolve, itv * 1000));
|
|
544
548
|
logger.debug('Fetching updated onchain state...');
|
|
545
|
-
let url = RELAYER_API_URL + '/utxos/check/' + encryptedOutputStr + '?token=' +
|
|
549
|
+
let url = RELAYER_API_URL + '/utxos/check/' + encryptedOutputStr + '?token=' + relayerTokenName
|
|
546
550
|
let res = await fetch(url)
|
|
547
551
|
let resJson = await res.json()
|
|
548
552
|
if (resJson.exists) {
|
|
@@ -595,4 +599,4 @@ async function checkDepositLimit(connection: Connection, treeAccount: PublicKey,
|
|
|
595
599
|
console.log('❌ Error reading deposit limit:', error);
|
|
596
600
|
throw error
|
|
597
601
|
}
|
|
598
|
-
}
|
|
602
|
+
}
|
package/src/exportUtils.ts
CHANGED
|
@@ -9,4 +9,4 @@ export { depositSPL } from './depositSPL.js'
|
|
|
9
9
|
export { withdrawSPL } from './withdrawSPL.js'
|
|
10
10
|
export { getBalanceFromUtxosSPL, getUtxosSPL } from './getUtxosSPL.js'
|
|
11
11
|
|
|
12
|
-
export { type TokenList, type SplList, tokens } from './utils/constants.js'
|
|
12
|
+
export { getRelayerTokenName, LEGACY_STORE_MINT, normalizeRelayerTokenMap, STORE_MINT, type TokenList, type SplList, tokens } from './utils/constants.js'
|
package/src/getUtxosSPL.ts
CHANGED
|
@@ -6,7 +6,7 @@ import { EncryptionService } from './utils/encryption.js';
|
|
|
6
6
|
import { WasmFactory } from '@lightprotocol/hasher.rs';
|
|
7
7
|
//@ts-ignore
|
|
8
8
|
import * as ffjavascript from 'ffjavascript';
|
|
9
|
-
import { FETCH_UTXOS_GROUP_SIZE, RELAYER_API_URL, LSK_ENCRYPTED_OUTPUTS, LSK_FETCH_OFFSET, PROGRAM_ID,
|
|
9
|
+
import { FETCH_UTXOS_GROUP_SIZE, getRelayerTokenName, RELAYER_API_URL, LSK_ENCRYPTED_OUTPUTS, LSK_FETCH_OFFSET, PROGRAM_ID, tokens } from './utils/constants.js';
|
|
10
10
|
import { logger } from './utils/logger.js';
|
|
11
11
|
import { getAssociatedTokenAddress } from '@solana/spl-token';
|
|
12
12
|
|
|
@@ -77,6 +77,7 @@ export async function getUtxosSPL({ publicKey, connection, encryptionService, st
|
|
|
77
77
|
if (!token) {
|
|
78
78
|
throw new Error('token not found: ' + mintAddress.toString())
|
|
79
79
|
}
|
|
80
|
+
const relayerTokenName = getRelayerTokenName(token.name)
|
|
80
81
|
|
|
81
82
|
logger.debug('token name: ' + token.name + ', token address' + token.pubkey.toString())
|
|
82
83
|
|
|
@@ -107,8 +108,8 @@ export async function getUtxosSPL({ publicKey, connection, encryptionService, st
|
|
|
107
108
|
}
|
|
108
109
|
logger.debug(' ####fetch_utxo_offset', fetch_utxo_offset)
|
|
109
110
|
let fetch_utxo_end = fetch_utxo_offset + FETCH_UTXOS_GROUP_SIZE
|
|
110
|
-
let fetch_utxo_url = `${RELAYER_API_URL}/utxos/range?token=${
|
|
111
|
-
let fetched = await fetchUserUtxos({ url: fetch_utxo_url, encryptionService, storage, publicKey_ata, tokenName:
|
|
111
|
+
let fetch_utxo_url = `${RELAYER_API_URL}/utxos/range?token=${relayerTokenName}&start=${fetch_utxo_offset}&end=${fetch_utxo_end}`
|
|
112
|
+
let fetched = await fetchUserUtxos({ url: fetch_utxo_url, encryptionService, storage, publicKey_ata, tokenName: relayerTokenName })
|
|
112
113
|
let am = 0
|
|
113
114
|
|
|
114
115
|
const nonZeroUtxos: Utxo[] = [];
|
|
@@ -525,4 +526,4 @@ async function decrypt_outputs(
|
|
|
525
526
|
}
|
|
526
527
|
|
|
527
528
|
return results;
|
|
528
|
-
}
|
|
529
|
+
}
|
package/src/utils/constants.ts
CHANGED
|
@@ -26,10 +26,16 @@ export const LSK_FETCH_OFFSET = 'fetch_offset'
|
|
|
26
26
|
export const LSK_ENCRYPTED_OUTPUTS = 'encrypted_outputs'
|
|
27
27
|
|
|
28
28
|
export const USDC_MINT = process.env.NEXT_PUBLIC_USDC_MINT ? new PublicKey(process.env.NEXT_PUBLIC_USDC_MINT) : new PublicKey('EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v')
|
|
29
|
+
export const STORE_MINT = process.env.NEXT_PUBLIC_NEWSTORE_MINT ? new PublicKey(process.env.NEXT_PUBLIC_NEWSTORE_MINT) : new PublicKey('storenSbvkfzircixnaosc5CbzNZVrHJ6S3EKrS1yqR')
|
|
30
|
+
export const LEGACY_STORE_MINT = process.env.NEXT_PUBLIC_LEGACY_STORE_MINT
|
|
31
|
+
? new PublicKey(process.env.NEXT_PUBLIC_LEGACY_STORE_MINT)
|
|
32
|
+
: process.env.NEXT_PUBLIC_STORE_MINT
|
|
33
|
+
? new PublicKey(process.env.NEXT_PUBLIC_STORE_MINT)
|
|
34
|
+
: new PublicKey('sTorERYB6xAZ1SSbwpK3zoK2EEwbBrc7TZAzg1uCGiH')
|
|
29
35
|
|
|
30
|
-
const tokenList = ['sol', 'usdc', 'usdt', 'zec', 'ore', 'store', 'jlusdc', 'jlwsol'] as const;
|
|
36
|
+
const tokenList = ['sol', 'usdc', 'usdt', 'zec', 'ore', 'store', 'legacyStore', 'jlusdc', 'jlwsol'] as const;
|
|
31
37
|
export type TokenList = typeof tokenList[number];
|
|
32
|
-
const splList = ['usdc', 'usdt', 'zec', 'ore', 'store', 'jlusdc', 'jlwsol'] as const;
|
|
38
|
+
const splList = ['usdc', 'usdt', 'zec', 'ore', 'store', 'legacyStore', 'jlusdc', 'jlwsol'] as const;
|
|
33
39
|
export type SplList = typeof splList[number];
|
|
34
40
|
export type Token = {
|
|
35
41
|
name: TokenList
|
|
@@ -70,10 +76,16 @@ export const tokens: Token[] = [
|
|
|
70
76
|
},
|
|
71
77
|
{
|
|
72
78
|
name: 'store',
|
|
73
|
-
pubkey:
|
|
79
|
+
pubkey: STORE_MINT,
|
|
74
80
|
prefix: 'store_',
|
|
75
81
|
units_per_token: 1e11
|
|
76
82
|
},
|
|
83
|
+
{
|
|
84
|
+
name: 'legacyStore',
|
|
85
|
+
pubkey: LEGACY_STORE_MINT,
|
|
86
|
+
prefix: 'legacyStore_',
|
|
87
|
+
units_per_token: 1e11
|
|
88
|
+
},
|
|
77
89
|
{
|
|
78
90
|
name: 'jlusdc',
|
|
79
91
|
pubkey: process.env.NEXT_PUBLIC_JLUSDC_MINT ? new PublicKey(process.env.NEXT_PUBLIC_JLUSDC_MINT) : new PublicKey('9BEcn9aPEmhSPbPQeFGjidRiEKki46fVQDyPpSQXPA2D'),
|
|
@@ -86,4 +98,45 @@ export const tokens: Token[] = [
|
|
|
86
98
|
prefix: 'jlwsol_',
|
|
87
99
|
units_per_token: 1e9
|
|
88
100
|
}
|
|
89
|
-
]
|
|
101
|
+
]
|
|
102
|
+
|
|
103
|
+
export function getRelayerTokenName(tokenName: string) {
|
|
104
|
+
if (tokenName === 'store') {
|
|
105
|
+
return 'newstore'
|
|
106
|
+
}
|
|
107
|
+
if (tokenName === 'legacyStore') {
|
|
108
|
+
return 'store'
|
|
109
|
+
}
|
|
110
|
+
return tokenName
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export function resolveTokenName(tokenName: string): TokenList | undefined {
|
|
114
|
+
const normalized = tokenName.trim().toLowerCase()
|
|
115
|
+
if (normalized === 'newstore') {
|
|
116
|
+
return 'store'
|
|
117
|
+
}
|
|
118
|
+
if (normalized === 'legacystore') {
|
|
119
|
+
return 'legacyStore'
|
|
120
|
+
}
|
|
121
|
+
return tokens.find(token => token.name.toLowerCase() === normalized)?.name
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export function resolveToken(tokenName: string): Token | undefined {
|
|
125
|
+
const resolvedName = resolveTokenName(tokenName)
|
|
126
|
+
return resolvedName ? tokens.find(token => token.name === resolvedName) : undefined
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export function normalizeRelayerTokenMap(values?: Record<string, number>): Record<string, number> | undefined {
|
|
130
|
+
if (!values) {
|
|
131
|
+
return values
|
|
132
|
+
}
|
|
133
|
+
const normalized = { ...values }
|
|
134
|
+
if (values.newstore !== undefined) {
|
|
135
|
+
normalized.store = values.newstore
|
|
136
|
+
}
|
|
137
|
+
if (values.store !== undefined) {
|
|
138
|
+
normalized.legacyStore = values.store
|
|
139
|
+
}
|
|
140
|
+
delete normalized.newstore
|
|
141
|
+
return normalized
|
|
142
|
+
}
|
package/src/withdrawSPL.ts
CHANGED
|
@@ -6,7 +6,7 @@ import { Keypair as UtxoKeypair } from './models/keypair.js';
|
|
|
6
6
|
import { Utxo } from './models/utxo.js';
|
|
7
7
|
import { parseProofToBytesArray, parseToBytesArray, prove } from './utils/prover.js';
|
|
8
8
|
|
|
9
|
-
import { ALT_ADDRESS, FEE_RECIPIENT, FIELD_SIZE, PROGRAM_ID, RELAYER_API_URL, tokens } from './utils/constants.js';
|
|
9
|
+
import { ALT_ADDRESS, FEE_RECIPIENT, FIELD_SIZE, getRelayerTokenName, PROGRAM_ID, RELAYER_API_URL, tokens } from './utils/constants.js';
|
|
10
10
|
import { EncryptionService, serializeProofAndExtData } from './utils/encryption.js';
|
|
11
11
|
import { fetchMerkleProof, findCrossCheckNullifierPDAs, findNullifierPDAs, getExtDataHash, getMintAddressField, getProgramAccounts } from './utils/utils.js';
|
|
12
12
|
|
|
@@ -66,6 +66,7 @@ export async function withdrawSPL({ recipient, lightWasm, storage, publicKey, co
|
|
|
66
66
|
if (!token) {
|
|
67
67
|
throw new Error('token not found: ' + mintAddress.toString())
|
|
68
68
|
}
|
|
69
|
+
const relayerTokenName = getRelayerTokenName(token.name)
|
|
69
70
|
|
|
70
71
|
if (amount) {
|
|
71
72
|
base_units = amount * token.units_per_token
|
|
@@ -80,6 +81,9 @@ export async function withdrawSPL({ recipient, lightWasm, storage, publicKey, co
|
|
|
80
81
|
let units_per_token = 10 ** mintInfo.decimals
|
|
81
82
|
|
|
82
83
|
let withdraw_fee_rate = await getConfig('withdraw_fee_rate')
|
|
84
|
+
if (token.name === 'legacyStore') {
|
|
85
|
+
withdraw_fee_rate = 0
|
|
86
|
+
}
|
|
83
87
|
let withdraw_rent_fees = await getConfig('rent_fees')
|
|
84
88
|
let token_rent_fee = withdraw_rent_fees[token.name]
|
|
85
89
|
if (!token_rent_fee) {
|
|
@@ -176,7 +180,7 @@ export async function withdrawSPL({ recipient, lightWasm, storage, publicKey, co
|
|
|
176
180
|
logger.debug(`Withdrawing ${base_units} lamports with ${fee_base_units} fee, ${changeAmount.toString()} as change`);
|
|
177
181
|
|
|
178
182
|
let commitmentsToFetch = inputs.map(utxo => utxo.getCommitment());
|
|
179
|
-
const { root, nextIndex, proofs } = await fetchMerkleProof(commitmentsToFetch,
|
|
183
|
+
const { root, nextIndex, proofs } = await fetchMerkleProof(commitmentsToFetch, relayerTokenName);
|
|
180
184
|
|
|
181
185
|
// Extract path elements and indices
|
|
182
186
|
const inputMerklePathElements = proofs.map(proof => proof.pathElements);
|
|
@@ -365,7 +369,7 @@ export async function withdrawSPL({ recipient, lightWasm, storage, publicKey, co
|
|
|
365
369
|
logger.debug(`retryTimes: ${retryTimes}`)
|
|
366
370
|
await new Promise(resolve => setTimeout(resolve, itv * 1000));
|
|
367
371
|
logger.info('Fetching updated onchain state...');
|
|
368
|
-
let res = await fetch(RELAYER_API_URL + '/utxos/check/' + encryptedOutputStr + '?token=' +
|
|
372
|
+
let res = await fetch(RELAYER_API_URL + '/utxos/check/' + encryptedOutputStr + '?token=' + relayerTokenName)
|
|
369
373
|
let resJson = await res.json()
|
|
370
374
|
logger.debug('resJson:', resJson)
|
|
371
375
|
if (resJson.exists) {
|