nulltrace-sdk 1.0.4 → 1.0.5
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.cjs +146 -115
- package/dist/index.mjs +27 -19
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -33,16 +33,43 @@ __export(src_exports, {
|
|
|
33
33
|
default: () => src_default
|
|
34
34
|
});
|
|
35
35
|
module.exports = __toCommonJS(src_exports);
|
|
36
|
-
var
|
|
37
|
-
var
|
|
38
|
-
var
|
|
39
|
-
var
|
|
36
|
+
var web3 = __toESM(require("@solana/web3.js"), 1);
|
|
37
|
+
var splToken = __toESM(require("@solana/spl-token"), 1);
|
|
38
|
+
var stateless = __toESM(require("@lightprotocol/stateless.js"), 1);
|
|
39
|
+
var compressedToken = __toESM(require("@lightprotocol/compressed-token"), 1);
|
|
40
40
|
var import_bs58 = __toESM(require("bs58"), 1);
|
|
41
41
|
var import_crypto = require("crypto");
|
|
42
42
|
var import_tweetnacl = __toESM(require("tweetnacl"), 1);
|
|
43
|
+
var {
|
|
44
|
+
VersionedTransaction,
|
|
45
|
+
PublicKey,
|
|
46
|
+
TransactionMessage,
|
|
47
|
+
ComputeBudgetProgram,
|
|
48
|
+
Keypair
|
|
49
|
+
} = web3;
|
|
50
|
+
var {
|
|
51
|
+
TOKEN_PROGRAM_ID,
|
|
52
|
+
TOKEN_2022_PROGRAM_ID,
|
|
53
|
+
getAssociatedTokenAddress,
|
|
54
|
+
createAssociatedTokenAccountInstruction,
|
|
55
|
+
createTransferCheckedInstruction,
|
|
56
|
+
NATIVE_MINT
|
|
57
|
+
} = splToken;
|
|
58
|
+
var {
|
|
59
|
+
createRpc,
|
|
60
|
+
bn,
|
|
61
|
+
LightSystemProgram,
|
|
62
|
+
COMPRESSED_TOKEN_PROGRAM_ID,
|
|
63
|
+
selectStateTreeInfo
|
|
64
|
+
} = stateless;
|
|
65
|
+
var {
|
|
66
|
+
getTokenPoolInfos,
|
|
67
|
+
selectTokenPoolInfosForDecompression,
|
|
68
|
+
CompressedTokenProgram
|
|
69
|
+
} = compressedToken;
|
|
43
70
|
var OPERATOR_KEY = "5STUuhrL8kJ4up9spEY39VJ6ibQCFrg8x8cRV5UeEcfv";
|
|
44
|
-
var OPERATOR_PUBLIC_KEY = new
|
|
45
|
-
var ALT_ADDRESS = new
|
|
71
|
+
var OPERATOR_PUBLIC_KEY = new PublicKey(OPERATOR_KEY);
|
|
72
|
+
var ALT_ADDRESS = new PublicKey("9NYFyEqPkyXUhkerbGHXUXkvb4qpzeEdHuGpgbgpH1NJ");
|
|
46
73
|
var REMOTE_OPERATOR_URL = "http://34.68.76.183:3333";
|
|
47
74
|
var SHARED_SECRET = "NULL_TRACE_OPERATOR_SECRET_BASE_V1";
|
|
48
75
|
var FEE_BPS = 1e-3;
|
|
@@ -78,19 +105,19 @@ function _sleep(ms) {
|
|
|
78
105
|
return new Promise((r) => setTimeout(r, ms));
|
|
79
106
|
}
|
|
80
107
|
async function _getMintInfo(connection, mintAddress) {
|
|
81
|
-
if (mintAddress ===
|
|
82
|
-
return { decimals: 9, tokenProgram:
|
|
108
|
+
if (mintAddress === NATIVE_MINT.toBase58()) {
|
|
109
|
+
return { decimals: 9, tokenProgram: TOKEN_PROGRAM_ID };
|
|
83
110
|
}
|
|
84
|
-
const mintInfo = await connection.getParsedAccountInfo(new
|
|
111
|
+
const mintInfo = await connection.getParsedAccountInfo(new PublicKey(mintAddress));
|
|
85
112
|
if (!mintInfo.value)
|
|
86
113
|
throw new Error(`Mint not found: ${mintAddress}`);
|
|
87
114
|
return {
|
|
88
115
|
decimals: mintInfo.value.data.parsed.info.decimals,
|
|
89
|
-
tokenProgram: new
|
|
116
|
+
tokenProgram: new PublicKey(mintInfo.value.owner)
|
|
90
117
|
};
|
|
91
118
|
}
|
|
92
119
|
async function _getCompressedAccounts(connection, owner, mint, isSOL) {
|
|
93
|
-
const accounts = isSOL ? await connection.getCompressedAccountsByOwner(owner) : await connection.getCompressedTokenAccountsByOwner(owner, { mint: new
|
|
120
|
+
const accounts = isSOL ? await connection.getCompressedAccountsByOwner(owner) : await connection.getCompressedTokenAccountsByOwner(owner, { mint: new PublicKey(mint) });
|
|
94
121
|
return accounts.items.sort((a, b) => {
|
|
95
122
|
const aAmt = isSOL ? a.lamports : a.parsed.amount;
|
|
96
123
|
const bAmt = isSOL ? b.lamports : b.parsed.amount;
|
|
@@ -122,15 +149,15 @@ function _batchAccounts(accounts) {
|
|
|
122
149
|
async function _packTransactions(connection, payer, instructions, adl) {
|
|
123
150
|
const { blockhash } = await connection.getLatestBlockhash();
|
|
124
151
|
const computeIxs = [
|
|
125
|
-
|
|
126
|
-
|
|
152
|
+
ComputeBudgetProgram.setComputeUnitLimit({ units: COMPUTE_UNITS }),
|
|
153
|
+
ComputeBudgetProgram.setComputeUnitPrice({ microLamports: COMPUTE_PRICE })
|
|
127
154
|
];
|
|
128
155
|
let current = [...computeIxs];
|
|
129
156
|
const messages = [];
|
|
130
157
|
for (const ix of instructions) {
|
|
131
158
|
try {
|
|
132
159
|
current.push(ix);
|
|
133
|
-
const msg = new
|
|
160
|
+
const msg = new TransactionMessage({
|
|
134
161
|
payerKey: payer,
|
|
135
162
|
recentBlockhash: blockhash,
|
|
136
163
|
instructions: current
|
|
@@ -141,7 +168,7 @@ async function _packTransactions(connection, payer, instructions, adl) {
|
|
|
141
168
|
current.pop();
|
|
142
169
|
if (current.length > computeIxs.length) {
|
|
143
170
|
messages.push(
|
|
144
|
-
new
|
|
171
|
+
new TransactionMessage({
|
|
145
172
|
payerKey: payer,
|
|
146
173
|
recentBlockhash: blockhash,
|
|
147
174
|
instructions: current
|
|
@@ -153,14 +180,14 @@ async function _packTransactions(connection, payer, instructions, adl) {
|
|
|
153
180
|
}
|
|
154
181
|
if (current.length > computeIxs.length) {
|
|
155
182
|
messages.push(
|
|
156
|
-
new
|
|
183
|
+
new TransactionMessage({
|
|
157
184
|
payerKey: payer,
|
|
158
185
|
recentBlockhash: blockhash,
|
|
159
186
|
instructions: current
|
|
160
187
|
}).compileToV0Message([adl])
|
|
161
188
|
);
|
|
162
189
|
}
|
|
163
|
-
return messages.map((m) => new
|
|
190
|
+
return messages.map((m) => new VersionedTransaction(m));
|
|
164
191
|
}
|
|
165
192
|
async function _signSendConfirm(connection, wallet, transactions) {
|
|
166
193
|
const signed = await wallet.signAllTransactions(transactions);
|
|
@@ -281,7 +308,7 @@ var NullTrace = class _NullTrace {
|
|
|
281
308
|
throw new Error("NullTrace: a wallet, Keypair, secret key, or private key string is required");
|
|
282
309
|
this.rpcUrl = rpcUrl;
|
|
283
310
|
this.wallet = _NullTrace._resolveWallet(walletOrKey);
|
|
284
|
-
this.connection =
|
|
311
|
+
this.connection = createRpc(rpcUrl, rpcUrl, rpcUrl, { commitment: "processed" });
|
|
285
312
|
this._adlCache = null;
|
|
286
313
|
this._sigCache = null;
|
|
287
314
|
}
|
|
@@ -298,14 +325,17 @@ var NullTrace = class _NullTrace {
|
|
|
298
325
|
if (!keypair?.publicKey || !keypair?.secretKey) {
|
|
299
326
|
throw new Error("NullTrace.fromKeypair: invalid Keypair");
|
|
300
327
|
}
|
|
328
|
+
const secretKeyBytes = new Uint8Array(keypair.secretKey);
|
|
329
|
+
const internalKeypair = Keypair.fromSecretKey(secretKeyBytes);
|
|
330
|
+
const pubkey = internalKeypair.publicKey;
|
|
301
331
|
return {
|
|
302
|
-
publicKey:
|
|
332
|
+
publicKey: pubkey,
|
|
303
333
|
signAllTransactions: async (txs) => {
|
|
304
334
|
for (const tx of txs)
|
|
305
|
-
tx.sign([
|
|
335
|
+
tx.sign([internalKeypair]);
|
|
306
336
|
return txs;
|
|
307
337
|
},
|
|
308
|
-
signMessage: async (msg) => import_tweetnacl.default.sign.detached(msg,
|
|
338
|
+
signMessage: async (msg) => import_tweetnacl.default.sign.detached(msg, secretKeyBytes)
|
|
309
339
|
};
|
|
310
340
|
}
|
|
311
341
|
/**
|
|
@@ -315,10 +345,10 @@ var NullTrace = class _NullTrace {
|
|
|
315
345
|
* @returns {{ publicKey: PublicKey, signAllTransactions: Function, signMessage: Function }}
|
|
316
346
|
*/
|
|
317
347
|
static fromSecretKey(secretKey) {
|
|
318
|
-
if (!
|
|
348
|
+
if (!secretKey || typeof secretKey.length !== "number" || secretKey.length !== 64) {
|
|
319
349
|
throw new Error("NullTrace.fromSecretKey: expected a 64-byte Uint8Array");
|
|
320
350
|
}
|
|
321
|
-
return _NullTrace.fromKeypair(
|
|
351
|
+
return _NullTrace.fromKeypair(Keypair.fromSecretKey(new Uint8Array(secretKey)));
|
|
322
352
|
}
|
|
323
353
|
/**
|
|
324
354
|
* Create a wallet adapter interface from a base58-encoded private key string.
|
|
@@ -331,19 +361,20 @@ var NullTrace = class _NullTrace {
|
|
|
331
361
|
throw new Error("NullTrace.fromPrivateKey: expected a base58-encoded private key string");
|
|
332
362
|
}
|
|
333
363
|
const decoded = import_bs58.default.decode(base58Key);
|
|
334
|
-
return _NullTrace.fromKeypair(
|
|
364
|
+
return _NullTrace.fromKeypair(Keypair.fromSecretKey(decoded));
|
|
335
365
|
}
|
|
336
366
|
/**
|
|
337
367
|
* @internal Resolve any supported wallet input into a wallet adapter interface.
|
|
368
|
+
* Uses duck-typing instead of instanceof to avoid cross-realm module boundary issues.
|
|
338
369
|
*/
|
|
339
370
|
static _resolveWallet(input) {
|
|
340
371
|
if (input?.publicKey && typeof input.signAllTransactions === "function") {
|
|
341
372
|
return input;
|
|
342
373
|
}
|
|
343
|
-
if (input
|
|
374
|
+
if (input?.publicKey?.toBytes && input?.secretKey?.length === 64) {
|
|
344
375
|
return _NullTrace.fromKeypair(input);
|
|
345
376
|
}
|
|
346
|
-
if (input
|
|
377
|
+
if (typeof input !== "string" && input?.length === 64 && typeof input[0] === "number") {
|
|
347
378
|
return _NullTrace.fromSecretKey(input);
|
|
348
379
|
}
|
|
349
380
|
if (typeof input === "string") {
|
|
@@ -378,22 +409,22 @@ var NullTrace = class _NullTrace {
|
|
|
378
409
|
if (!mint || !amount)
|
|
379
410
|
throw new Error("NullTrace.nullify: mint and amount are required");
|
|
380
411
|
const owner = this.wallet.publicKey;
|
|
381
|
-
const isSOL = mint ===
|
|
412
|
+
const isSOL = mint === NATIVE_MINT.toBase58();
|
|
382
413
|
const { decimals, tokenProgram } = await _getMintInfo(this.connection, mint);
|
|
383
|
-
const amountLamports =
|
|
384
|
-
const feeLamports =
|
|
414
|
+
const amountLamports = bn(Math.floor(parseFloat(amount) * 10 ** decimals).toString());
|
|
415
|
+
const feeLamports = bn(Math.floor(parseInt(amountLamports.toString()) * FEE_BPS).toString());
|
|
385
416
|
const ixs = [];
|
|
386
417
|
const activeStateTrees = await this.connection.getStateTreeInfos();
|
|
387
|
-
const tree =
|
|
418
|
+
const tree = selectStateTreeInfo(activeStateTrees);
|
|
388
419
|
if (isSOL) {
|
|
389
420
|
ixs.push(
|
|
390
|
-
await
|
|
421
|
+
await LightSystemProgram.compress({
|
|
391
422
|
payer: owner,
|
|
392
423
|
toAddress: owner,
|
|
393
424
|
lamports: amountLamports.sub(feeLamports),
|
|
394
425
|
outputStateTreeInfo: tree
|
|
395
426
|
}),
|
|
396
|
-
await
|
|
427
|
+
await LightSystemProgram.compress({
|
|
397
428
|
payer: owner,
|
|
398
429
|
toAddress: OPERATOR_PUBLIC_KEY,
|
|
399
430
|
lamports: feeLamports,
|
|
@@ -401,16 +432,16 @@ var NullTrace = class _NullTrace {
|
|
|
401
432
|
})
|
|
402
433
|
);
|
|
403
434
|
} else {
|
|
404
|
-
const mintPk = new
|
|
405
|
-
const sourceAta = await
|
|
406
|
-
const [tokenPoolPda] =
|
|
435
|
+
const mintPk = new PublicKey(mint);
|
|
436
|
+
const sourceAta = await getAssociatedTokenAddress(mintPk, owner, false, tokenProgram);
|
|
437
|
+
const [tokenPoolPda] = PublicKey.findProgramAddressSync(
|
|
407
438
|
[Buffer.from("pool"), mintPk.toBuffer()],
|
|
408
|
-
|
|
439
|
+
COMPRESSED_TOKEN_PROGRAM_ID
|
|
409
440
|
);
|
|
410
441
|
const poolInfo = await this.connection.getAccountInfo(tokenPoolPda);
|
|
411
442
|
if (!poolInfo) {
|
|
412
443
|
ixs.push(
|
|
413
|
-
await
|
|
444
|
+
await CompressedTokenProgram.createTokenPool({
|
|
414
445
|
feePayer: owner,
|
|
415
446
|
mint: mintPk,
|
|
416
447
|
tokenProgramId: tokenProgram
|
|
@@ -418,7 +449,7 @@ var NullTrace = class _NullTrace {
|
|
|
418
449
|
);
|
|
419
450
|
}
|
|
420
451
|
ixs.push(
|
|
421
|
-
await
|
|
452
|
+
await CompressedTokenProgram.compress({
|
|
422
453
|
payer: owner,
|
|
423
454
|
owner,
|
|
424
455
|
source: sourceAta,
|
|
@@ -430,7 +461,7 @@ var NullTrace = class _NullTrace {
|
|
|
430
461
|
tokenPoolPda,
|
|
431
462
|
tokenProgram,
|
|
432
463
|
isInitialized: true,
|
|
433
|
-
balance:
|
|
464
|
+
balance: bn("0"),
|
|
434
465
|
poolIndex: 0,
|
|
435
466
|
mint: mintPk
|
|
436
467
|
}
|
|
@@ -458,7 +489,7 @@ var NullTrace = class _NullTrace {
|
|
|
458
489
|
if (!mint || !amount)
|
|
459
490
|
throw new Error("NullTrace.reveal: mint and amount are required");
|
|
460
491
|
const owner = this.wallet.publicKey;
|
|
461
|
-
const isSOL = mint ===
|
|
492
|
+
const isSOL = mint === NATIVE_MINT.toBase58();
|
|
462
493
|
const { decimals, tokenProgram } = await _getMintInfo(this.connection, mint);
|
|
463
494
|
const amountLamports = Math.floor(parseFloat(amount) * 10 ** decimals);
|
|
464
495
|
const sorted = await _getCompressedAccounts(this.connection, owner, mint, isSOL);
|
|
@@ -470,12 +501,12 @@ var NullTrace = class _NullTrace {
|
|
|
470
501
|
let selectedTokenPoolInfos;
|
|
471
502
|
let destinationAta;
|
|
472
503
|
if (!isSOL) {
|
|
473
|
-
const tokenPoolInfos = await
|
|
474
|
-
selectedTokenPoolInfos =
|
|
475
|
-
destinationAta = await
|
|
504
|
+
const tokenPoolInfos = await getTokenPoolInfos(this.connection, new PublicKey(mint));
|
|
505
|
+
selectedTokenPoolInfos = selectTokenPoolInfosForDecompression(tokenPoolInfos, amountLamports);
|
|
506
|
+
destinationAta = await getAssociatedTokenAddress(new PublicKey(mint), owner, false, tokenProgram);
|
|
476
507
|
const info = await this.connection.getAccountInfo(destinationAta);
|
|
477
508
|
if (!info) {
|
|
478
|
-
ixs.push(
|
|
509
|
+
ixs.push(createAssociatedTokenAccountInstruction(owner, destinationAta, owner, new PublicKey(mint), tokenProgram));
|
|
479
510
|
}
|
|
480
511
|
}
|
|
481
512
|
let remaining = amountLamports;
|
|
@@ -489,18 +520,18 @@ var NullTrace = class _NullTrace {
|
|
|
489
520
|
);
|
|
490
521
|
const batchAmount = decimals === 0 ? 1 : Math.min(remaining, batch.reduce((s, a) => s + Number(isSOL ? a.lamports : a.parsed.amount), 0));
|
|
491
522
|
ixs.push(
|
|
492
|
-
await (isSOL ?
|
|
523
|
+
await (isSOL ? LightSystemProgram.decompress({
|
|
493
524
|
payer: owner,
|
|
494
525
|
inputCompressedAccounts: batch,
|
|
495
526
|
toAddress: owner,
|
|
496
|
-
lamports:
|
|
527
|
+
lamports: bn(batchAmount.toString()),
|
|
497
528
|
recentInputStateRootIndices: proof.rootIndices,
|
|
498
529
|
recentValidityProof: proof.compressedProof
|
|
499
|
-
}) :
|
|
530
|
+
}) : CompressedTokenProgram.decompress({
|
|
500
531
|
payer: owner,
|
|
501
532
|
inputCompressedTokenAccounts: batch,
|
|
502
533
|
toAddress: destinationAta,
|
|
503
|
-
amount:
|
|
534
|
+
amount: bn(batchAmount.toString()),
|
|
504
535
|
recentInputStateRootIndices: proof.rootIndices,
|
|
505
536
|
recentValidityProof: proof.compressedProof,
|
|
506
537
|
tokenPoolInfos: selectedTokenPoolInfos
|
|
@@ -531,8 +562,8 @@ var NullTrace = class _NullTrace {
|
|
|
531
562
|
throw new Error("NullTrace.transfer: mint, amount, and recipient are required");
|
|
532
563
|
}
|
|
533
564
|
const owner = this.wallet.publicKey;
|
|
534
|
-
const recipientPk = new
|
|
535
|
-
const isSOL = mint ===
|
|
565
|
+
const recipientPk = new PublicKey(recipient);
|
|
566
|
+
const isSOL = mint === NATIVE_MINT.toBase58();
|
|
536
567
|
const { decimals, tokenProgram } = await _getMintInfo(this.connection, mint);
|
|
537
568
|
const amountLamports = Math.floor(parseFloat(amount) * 10 ** decimals);
|
|
538
569
|
const sorted = await _getCompressedAccounts(this.connection, owner, mint, isSOL);
|
|
@@ -542,87 +573,87 @@ var NullTrace = class _NullTrace {
|
|
|
542
573
|
const preTransactions = [];
|
|
543
574
|
if (total < amountLamports) {
|
|
544
575
|
const deficit = amountLamports - total;
|
|
545
|
-
const fee =
|
|
576
|
+
const fee = bn(Math.floor(deficit * FEE_BPS).toString());
|
|
546
577
|
const trees = await this.connection.getStateTreeInfos();
|
|
547
|
-
const tree =
|
|
578
|
+
const tree = selectStateTreeInfo(trees);
|
|
548
579
|
if (isSOL) {
|
|
549
580
|
const solBal = await this.connection.getBalance(owner);
|
|
550
581
|
if (solBal < deficit + 1e5)
|
|
551
582
|
throw new Error("Insufficient balance");
|
|
552
|
-
const compressIx = await
|
|
583
|
+
const compressIx = await LightSystemProgram.compress({
|
|
553
584
|
payer: owner,
|
|
554
585
|
toAddress: recipientPk,
|
|
555
|
-
lamports:
|
|
586
|
+
lamports: bn(deficit.toString()).sub(fee),
|
|
556
587
|
outputStateTreeInfo: tree
|
|
557
588
|
});
|
|
558
|
-
const feeIx = await
|
|
589
|
+
const feeIx = await LightSystemProgram.compress({
|
|
559
590
|
payer: owner,
|
|
560
591
|
toAddress: OPERATOR_PUBLIC_KEY,
|
|
561
592
|
lamports: fee,
|
|
562
593
|
outputStateTreeInfo: tree
|
|
563
594
|
});
|
|
564
|
-
const msg = new
|
|
595
|
+
const msg = new TransactionMessage({
|
|
565
596
|
payerKey: owner,
|
|
566
597
|
recentBlockhash: blockhash,
|
|
567
598
|
instructions: [
|
|
568
|
-
|
|
569
|
-
|
|
599
|
+
ComputeBudgetProgram.setComputeUnitLimit({ units: COMPUTE_UNITS }),
|
|
600
|
+
ComputeBudgetProgram.setComputeUnitPrice({ microLamports: COMPUTE_PRICE }),
|
|
570
601
|
compressIx,
|
|
571
602
|
feeIx
|
|
572
603
|
]
|
|
573
604
|
}).compileToV0Message([adl]);
|
|
574
|
-
preTransactions.push(new
|
|
605
|
+
preTransactions.push(new VersionedTransaction(msg));
|
|
575
606
|
} else {
|
|
576
607
|
let instructions = [
|
|
577
|
-
|
|
578
|
-
|
|
608
|
+
ComputeBudgetProgram.setComputeUnitLimit({ units: COMPUTE_UNITS }),
|
|
609
|
+
ComputeBudgetProgram.setComputeUnitPrice({ microLamports: COMPUTE_PRICE })
|
|
579
610
|
];
|
|
580
|
-
const sourceAta = await
|
|
581
|
-
new
|
|
611
|
+
const sourceAta = await getAssociatedTokenAddress(
|
|
612
|
+
new PublicKey(mint),
|
|
582
613
|
owner,
|
|
583
614
|
false,
|
|
584
615
|
tokenProgram
|
|
585
616
|
);
|
|
586
617
|
const tokenAccountInfos = await this.connection.getParsedTokenAccountsByOwner(
|
|
587
618
|
owner,
|
|
588
|
-
{ programId: tokenProgram, mint: new
|
|
619
|
+
{ programId: tokenProgram, mint: new PublicKey(mint) },
|
|
589
620
|
"processed"
|
|
590
621
|
);
|
|
591
622
|
const publicBalance = tokenAccountInfos.value?.[0].account.data.parsed.info.tokenAmount.amount ?? 0;
|
|
592
623
|
if (publicBalance < deficit)
|
|
593
624
|
throw new Error("Insufficient balance");
|
|
594
|
-
const [tokenPoolPda] =
|
|
595
|
-
[Buffer.from("pool"), new
|
|
596
|
-
|
|
625
|
+
const [tokenPoolPda] = PublicKey.findProgramAddressSync(
|
|
626
|
+
[Buffer.from("pool"), new PublicKey(mint).toBuffer()],
|
|
627
|
+
COMPRESSED_TOKEN_PROGRAM_ID
|
|
597
628
|
);
|
|
598
629
|
const tokenPoolInfo = await this.connection.getAccountInfo(tokenPoolPda, "processed");
|
|
599
630
|
if (!tokenPoolInfo) {
|
|
600
|
-
const createTokenPoolIx = await
|
|
631
|
+
const createTokenPoolIx = await CompressedTokenProgram.createTokenPool({
|
|
601
632
|
feePayer: owner,
|
|
602
|
-
mint: new
|
|
633
|
+
mint: new PublicKey(mint),
|
|
603
634
|
tokenProgramId: tokenProgram
|
|
604
635
|
});
|
|
605
636
|
instructions.push(createTokenPoolIx);
|
|
606
637
|
}
|
|
607
|
-
const compressInstruction = await
|
|
638
|
+
const compressInstruction = await CompressedTokenProgram.compress({
|
|
608
639
|
payer: owner,
|
|
609
640
|
owner,
|
|
610
641
|
source: sourceAta,
|
|
611
642
|
toAddress: [recipientPk, OPERATOR_PUBLIC_KEY],
|
|
612
|
-
amount: [
|
|
613
|
-
mint: new
|
|
643
|
+
amount: [bn(deficit.toString()).sub(fee), fee],
|
|
644
|
+
mint: new PublicKey(mint),
|
|
614
645
|
outputStateTreeInfo: tree,
|
|
615
646
|
tokenPoolInfo: {
|
|
616
647
|
tokenPoolPda,
|
|
617
648
|
tokenProgram,
|
|
618
649
|
isInitialized: true,
|
|
619
|
-
balance:
|
|
650
|
+
balance: bn("0"),
|
|
620
651
|
poolIndex: 0,
|
|
621
|
-
mint: new
|
|
652
|
+
mint: new PublicKey(mint)
|
|
622
653
|
}
|
|
623
654
|
});
|
|
624
655
|
instructions.push(compressInstruction);
|
|
625
|
-
let tx = new
|
|
656
|
+
let tx = new VersionedTransaction(new TransactionMessage({
|
|
626
657
|
payerKey: owner,
|
|
627
658
|
recentBlockhash: blockhash,
|
|
628
659
|
instructions
|
|
@@ -646,18 +677,18 @@ var NullTrace = class _NullTrace {
|
|
|
646
677
|
);
|
|
647
678
|
const batchAmount = decimals === 0 ? 1 : Math.min(remaining, batch.reduce((s, a) => s + Number(isSOL ? a.lamports : a.parsed.amount), 0));
|
|
648
679
|
ixs.push(
|
|
649
|
-
await (isSOL ?
|
|
680
|
+
await (isSOL ? LightSystemProgram.transfer({
|
|
650
681
|
payer: owner,
|
|
651
682
|
inputCompressedAccounts: batch,
|
|
652
683
|
toAddress: recipientPk,
|
|
653
|
-
lamports:
|
|
684
|
+
lamports: bn(batchAmount.toString()),
|
|
654
685
|
recentInputStateRootIndices: proof.rootIndices,
|
|
655
686
|
recentValidityProof: proof.compressedProof
|
|
656
|
-
}) :
|
|
687
|
+
}) : CompressedTokenProgram.transfer({
|
|
657
688
|
payer: owner,
|
|
658
689
|
inputCompressedTokenAccounts: batch,
|
|
659
690
|
toAddress: recipientPk,
|
|
660
|
-
amount:
|
|
691
|
+
amount: bn(batchAmount.toString()),
|
|
661
692
|
recentInputStateRootIndices: proof.rootIndices,
|
|
662
693
|
recentValidityProof: proof.compressedProof
|
|
663
694
|
}))
|
|
@@ -722,7 +753,7 @@ var NullTrace = class _NullTrace {
|
|
|
722
753
|
}
|
|
723
754
|
const { onStatusChange, timeout = 12e4 } = options;
|
|
724
755
|
const owner = this.wallet.publicKey;
|
|
725
|
-
const isSOL = fromMint ===
|
|
756
|
+
const isSOL = fromMint === NATIVE_MINT.toBase58();
|
|
726
757
|
const { decimals, tokenProgram } = await _getMintInfo(this.connection, fromMint);
|
|
727
758
|
const amountLamports = Math.floor(parseFloat(amount) * 10 ** decimals);
|
|
728
759
|
const sorted = await _getCompressedAccounts(this.connection, owner, fromMint, isSOL);
|
|
@@ -732,80 +763,80 @@ var NullTrace = class _NullTrace {
|
|
|
732
763
|
const preTransactions = [];
|
|
733
764
|
if (total < amountLamports) {
|
|
734
765
|
const deficit = amountLamports - total;
|
|
735
|
-
const fee =
|
|
766
|
+
const fee = bn(Math.floor(deficit * FEE_BPS).toString());
|
|
736
767
|
const trees = await this.connection.getStateTreeInfos();
|
|
737
|
-
const tree =
|
|
768
|
+
const tree = selectStateTreeInfo(trees);
|
|
738
769
|
if (isSOL) {
|
|
739
770
|
const solBal = await this.connection.getBalance(owner);
|
|
740
771
|
if (solBal < deficit + 1e5)
|
|
741
772
|
throw new Error("Insufficient balance");
|
|
742
|
-
const compressIx = await
|
|
773
|
+
const compressIx = await LightSystemProgram.compress({
|
|
743
774
|
payer: owner,
|
|
744
775
|
toAddress: OPERATOR_PUBLIC_KEY,
|
|
745
|
-
lamports:
|
|
776
|
+
lamports: bn(deficit.toString()),
|
|
746
777
|
outputStateTreeInfo: tree
|
|
747
778
|
});
|
|
748
|
-
const msg = new
|
|
779
|
+
const msg = new TransactionMessage({
|
|
749
780
|
payerKey: owner,
|
|
750
781
|
recentBlockhash: blockhash,
|
|
751
782
|
instructions: [
|
|
752
|
-
|
|
753
|
-
|
|
783
|
+
ComputeBudgetProgram.setComputeUnitLimit({ units: COMPUTE_UNITS }),
|
|
784
|
+
ComputeBudgetProgram.setComputeUnitPrice({ microLamports: COMPUTE_PRICE }),
|
|
754
785
|
compressIx
|
|
755
786
|
]
|
|
756
787
|
}).compileToV0Message([adl]);
|
|
757
|
-
preTransactions.push(new
|
|
788
|
+
preTransactions.push(new VersionedTransaction(msg));
|
|
758
789
|
} else {
|
|
759
790
|
let instructions = [
|
|
760
|
-
|
|
761
|
-
|
|
791
|
+
ComputeBudgetProgram.setComputeUnitLimit({ units: COMPUTE_UNITS }),
|
|
792
|
+
ComputeBudgetProgram.setComputeUnitPrice({ microLamports: COMPUTE_PRICE })
|
|
762
793
|
];
|
|
763
|
-
const sourceAta = await
|
|
764
|
-
new
|
|
794
|
+
const sourceAta = await getAssociatedTokenAddress(
|
|
795
|
+
new PublicKey(fromMint),
|
|
765
796
|
owner,
|
|
766
797
|
false,
|
|
767
798
|
tokenProgram
|
|
768
799
|
);
|
|
769
800
|
const tokenAccountInfos = await this.connection.getParsedTokenAccountsByOwner(
|
|
770
801
|
owner,
|
|
771
|
-
{ programId: tokenProgram, mint: new
|
|
802
|
+
{ programId: tokenProgram, mint: new PublicKey(fromMint) },
|
|
772
803
|
"processed"
|
|
773
804
|
);
|
|
774
805
|
const publicBalance = tokenAccountInfos.value?.[0].account.data.parsed.info.tokenAmount.amount ?? 0;
|
|
775
806
|
if (publicBalance < deficit)
|
|
776
807
|
throw new Error("Insufficient balance");
|
|
777
|
-
const [tokenPoolPda] =
|
|
778
|
-
[Buffer.from("pool"), new
|
|
779
|
-
|
|
808
|
+
const [tokenPoolPda] = PublicKey.findProgramAddressSync(
|
|
809
|
+
[Buffer.from("pool"), new PublicKey(fromMint).toBuffer()],
|
|
810
|
+
COMPRESSED_TOKEN_PROGRAM_ID
|
|
780
811
|
);
|
|
781
812
|
const tokenPoolInfo = await this.connection.getAccountInfo(tokenPoolPda, "processed");
|
|
782
813
|
if (!tokenPoolInfo) {
|
|
783
|
-
const createTokenPoolIx = await
|
|
814
|
+
const createTokenPoolIx = await CompressedTokenProgram.createTokenPool({
|
|
784
815
|
feePayer: owner,
|
|
785
|
-
mint: new
|
|
816
|
+
mint: new PublicKey(fromMint),
|
|
786
817
|
tokenProgramId: tokenProgram
|
|
787
818
|
});
|
|
788
819
|
instructions.push(createTokenPoolIx);
|
|
789
820
|
}
|
|
790
|
-
const compressInstruction = await
|
|
821
|
+
const compressInstruction = await CompressedTokenProgram.compress({
|
|
791
822
|
payer: owner,
|
|
792
823
|
owner,
|
|
793
824
|
source: sourceAta,
|
|
794
825
|
toAddress: OPERATOR_PUBLIC_KEY,
|
|
795
|
-
amount:
|
|
796
|
-
mint: new
|
|
826
|
+
amount: bn(deficit.toString()),
|
|
827
|
+
mint: new PublicKey(fromMint),
|
|
797
828
|
outputStateTreeInfo: tree,
|
|
798
829
|
tokenPoolInfo: {
|
|
799
830
|
tokenPoolPda,
|
|
800
831
|
tokenProgram,
|
|
801
832
|
isInitialized: true,
|
|
802
|
-
balance:
|
|
833
|
+
balance: bn("0"),
|
|
803
834
|
poolIndex: 0,
|
|
804
|
-
mint: new
|
|
835
|
+
mint: new PublicKey(fromMint)
|
|
805
836
|
}
|
|
806
837
|
});
|
|
807
838
|
instructions.push(compressInstruction);
|
|
808
|
-
let tx = new
|
|
839
|
+
let tx = new VersionedTransaction(new TransactionMessage({
|
|
809
840
|
payerKey: owner,
|
|
810
841
|
recentBlockhash: blockhash,
|
|
811
842
|
instructions
|
|
@@ -829,18 +860,18 @@ var NullTrace = class _NullTrace {
|
|
|
829
860
|
);
|
|
830
861
|
const batchAmount = decimals === 0 ? 1 : Math.min(remaining, batch.reduce((s, a) => s + Number(isSOL ? a.lamports : a.parsed.amount), 0));
|
|
831
862
|
ixs.push(
|
|
832
|
-
await (isSOL ?
|
|
863
|
+
await (isSOL ? LightSystemProgram.transfer({
|
|
833
864
|
payer: owner,
|
|
834
865
|
inputCompressedAccounts: batch,
|
|
835
866
|
toAddress: OPERATOR_PUBLIC_KEY,
|
|
836
|
-
lamports:
|
|
867
|
+
lamports: bn(batchAmount.toString()),
|
|
837
868
|
recentInputStateRootIndices: proof.rootIndices,
|
|
838
869
|
recentValidityProof: proof.compressedProof
|
|
839
|
-
}) :
|
|
870
|
+
}) : CompressedTokenProgram.transfer({
|
|
840
871
|
payer: owner,
|
|
841
872
|
inputCompressedTokenAccounts: batch,
|
|
842
873
|
toAddress: OPERATOR_PUBLIC_KEY,
|
|
843
|
-
amount:
|
|
874
|
+
amount: bn(batchAmount.toString()),
|
|
844
875
|
recentInputStateRootIndices: proof.rootIndices,
|
|
845
876
|
recentValidityProof: proof.compressedProof
|
|
846
877
|
}))
|
|
@@ -864,7 +895,7 @@ var NullTrace = class _NullTrace {
|
|
|
864
895
|
await this.connection.confirmTransaction(sig);
|
|
865
896
|
preSigs.push(sig);
|
|
866
897
|
}
|
|
867
|
-
const swapId =
|
|
898
|
+
const swapId = import_bs58.default.encode(import_tweetnacl.default.randomBytes(32));
|
|
868
899
|
const swapData = {
|
|
869
900
|
id: swapId,
|
|
870
901
|
fromToken: fromMint,
|
|
@@ -926,12 +957,12 @@ var NullTrace = class _NullTrace {
|
|
|
926
957
|
lamports: solBal - 0.01 * 1e9,
|
|
927
958
|
decimals: 9,
|
|
928
959
|
logo: "",
|
|
929
|
-
address:
|
|
960
|
+
address: NATIVE_MINT.toString()
|
|
930
961
|
});
|
|
931
962
|
}
|
|
932
963
|
const [spl, spl22] = await Promise.all([
|
|
933
|
-
this.connection.getParsedTokenAccountsByOwner(owner, { programId:
|
|
934
|
-
this.connection.getParsedTokenAccountsByOwner(owner, { programId:
|
|
964
|
+
this.connection.getParsedTokenAccountsByOwner(owner, { programId: TOKEN_PROGRAM_ID }, "processed"),
|
|
965
|
+
this.connection.getParsedTokenAccountsByOwner(owner, { programId: TOKEN_2022_PROGRAM_ID }, "processed")
|
|
935
966
|
]);
|
|
936
967
|
for (const ta of [...spl.value, ...spl22.value]) {
|
|
937
968
|
const p = ta.account.data.parsed;
|
|
@@ -975,13 +1006,13 @@ var NullTrace = class _NullTrace {
|
|
|
975
1006
|
lamports: parseInt(compressedSol.toString()),
|
|
976
1007
|
decimals: 9,
|
|
977
1008
|
logo: "",
|
|
978
|
-
address:
|
|
1009
|
+
address: NATIVE_MINT.toString()
|
|
979
1010
|
});
|
|
980
1011
|
}
|
|
981
1012
|
const compressedTokens = await this.connection.getCompressedTokenAccountsByOwner(owner);
|
|
982
1013
|
for (const item of compressedTokens.items) {
|
|
983
1014
|
const mintAddr = item.parsed.mint.toString();
|
|
984
|
-
const amt =
|
|
1015
|
+
const amt = bn(item.parsed.amount.toString());
|
|
985
1016
|
let entry = tokenBalances.find((t) => t.address === mintAddr);
|
|
986
1017
|
if (!entry) {
|
|
987
1018
|
entry = { symbol: "", name: "", amount: "0", lamports: 0, decimals: 0, logo: "", address: mintAddr };
|
|
@@ -1025,7 +1056,7 @@ var NullTrace = class _NullTrace {
|
|
|
1025
1056
|
async getTokenMetadata(mint) {
|
|
1026
1057
|
if (!mint)
|
|
1027
1058
|
throw new Error("NullTrace.getTokenMetadata: mint is required");
|
|
1028
|
-
if (mint ===
|
|
1059
|
+
if (mint === NATIVE_MINT.toBase58()) {
|
|
1029
1060
|
return { symbol: "SOL", name: "Solana", logo: "", decimals: 9 };
|
|
1030
1061
|
}
|
|
1031
1062
|
const result = [{ address: mint, symbol: "", name: "", logo: "", decimals: 0, lamports: 0 }];
|
package/dist/index.mjs
CHANGED
|
@@ -1,34 +1,38 @@
|
|
|
1
1
|
// src/index.js
|
|
2
|
-
import
|
|
2
|
+
import * as web3 from "@solana/web3.js";
|
|
3
|
+
import * as splToken from "@solana/spl-token";
|
|
4
|
+
import * as stateless from "@lightprotocol/stateless.js";
|
|
5
|
+
import * as compressedToken from "@lightprotocol/compressed-token";
|
|
6
|
+
import bs58 from "bs58";
|
|
7
|
+
import { createHmac } from "crypto";
|
|
8
|
+
import nacl from "tweetnacl";
|
|
9
|
+
var {
|
|
3
10
|
VersionedTransaction,
|
|
4
11
|
PublicKey,
|
|
5
12
|
TransactionMessage,
|
|
6
13
|
ComputeBudgetProgram,
|
|
7
14
|
Keypair
|
|
8
|
-
}
|
|
9
|
-
|
|
15
|
+
} = web3;
|
|
16
|
+
var {
|
|
10
17
|
TOKEN_PROGRAM_ID,
|
|
11
18
|
TOKEN_2022_PROGRAM_ID,
|
|
12
19
|
getAssociatedTokenAddress,
|
|
13
20
|
createAssociatedTokenAccountInstruction,
|
|
14
21
|
createTransferCheckedInstruction,
|
|
15
22
|
NATIVE_MINT
|
|
16
|
-
}
|
|
17
|
-
|
|
23
|
+
} = splToken;
|
|
24
|
+
var {
|
|
18
25
|
createRpc,
|
|
19
26
|
bn,
|
|
20
27
|
LightSystemProgram,
|
|
21
28
|
COMPRESSED_TOKEN_PROGRAM_ID,
|
|
22
29
|
selectStateTreeInfo
|
|
23
|
-
}
|
|
24
|
-
|
|
30
|
+
} = stateless;
|
|
31
|
+
var {
|
|
25
32
|
getTokenPoolInfos,
|
|
26
33
|
selectTokenPoolInfosForDecompression,
|
|
27
34
|
CompressedTokenProgram
|
|
28
|
-
}
|
|
29
|
-
import bs58 from "bs58";
|
|
30
|
-
import { createHmac } from "crypto";
|
|
31
|
-
import nacl from "tweetnacl";
|
|
35
|
+
} = compressedToken;
|
|
32
36
|
var OPERATOR_KEY = "5STUuhrL8kJ4up9spEY39VJ6ibQCFrg8x8cRV5UeEcfv";
|
|
33
37
|
var OPERATOR_PUBLIC_KEY = new PublicKey(OPERATOR_KEY);
|
|
34
38
|
var ALT_ADDRESS = new PublicKey("9NYFyEqPkyXUhkerbGHXUXkvb4qpzeEdHuGpgbgpH1NJ");
|
|
@@ -287,14 +291,17 @@ var NullTrace = class _NullTrace {
|
|
|
287
291
|
if (!keypair?.publicKey || !keypair?.secretKey) {
|
|
288
292
|
throw new Error("NullTrace.fromKeypair: invalid Keypair");
|
|
289
293
|
}
|
|
294
|
+
const secretKeyBytes = new Uint8Array(keypair.secretKey);
|
|
295
|
+
const internalKeypair = Keypair.fromSecretKey(secretKeyBytes);
|
|
296
|
+
const pubkey = internalKeypair.publicKey;
|
|
290
297
|
return {
|
|
291
|
-
publicKey:
|
|
298
|
+
publicKey: pubkey,
|
|
292
299
|
signAllTransactions: async (txs) => {
|
|
293
300
|
for (const tx of txs)
|
|
294
|
-
tx.sign([
|
|
301
|
+
tx.sign([internalKeypair]);
|
|
295
302
|
return txs;
|
|
296
303
|
},
|
|
297
|
-
signMessage: async (msg) => nacl.sign.detached(msg,
|
|
304
|
+
signMessage: async (msg) => nacl.sign.detached(msg, secretKeyBytes)
|
|
298
305
|
};
|
|
299
306
|
}
|
|
300
307
|
/**
|
|
@@ -304,10 +311,10 @@ var NullTrace = class _NullTrace {
|
|
|
304
311
|
* @returns {{ publicKey: PublicKey, signAllTransactions: Function, signMessage: Function }}
|
|
305
312
|
*/
|
|
306
313
|
static fromSecretKey(secretKey) {
|
|
307
|
-
if (!
|
|
314
|
+
if (!secretKey || typeof secretKey.length !== "number" || secretKey.length !== 64) {
|
|
308
315
|
throw new Error("NullTrace.fromSecretKey: expected a 64-byte Uint8Array");
|
|
309
316
|
}
|
|
310
|
-
return _NullTrace.fromKeypair(Keypair.fromSecretKey(secretKey));
|
|
317
|
+
return _NullTrace.fromKeypair(Keypair.fromSecretKey(new Uint8Array(secretKey)));
|
|
311
318
|
}
|
|
312
319
|
/**
|
|
313
320
|
* Create a wallet adapter interface from a base58-encoded private key string.
|
|
@@ -324,15 +331,16 @@ var NullTrace = class _NullTrace {
|
|
|
324
331
|
}
|
|
325
332
|
/**
|
|
326
333
|
* @internal Resolve any supported wallet input into a wallet adapter interface.
|
|
334
|
+
* Uses duck-typing instead of instanceof to avoid cross-realm module boundary issues.
|
|
327
335
|
*/
|
|
328
336
|
static _resolveWallet(input) {
|
|
329
337
|
if (input?.publicKey && typeof input.signAllTransactions === "function") {
|
|
330
338
|
return input;
|
|
331
339
|
}
|
|
332
|
-
if (input
|
|
340
|
+
if (input?.publicKey?.toBytes && input?.secretKey?.length === 64) {
|
|
333
341
|
return _NullTrace.fromKeypair(input);
|
|
334
342
|
}
|
|
335
|
-
if (input
|
|
343
|
+
if (typeof input !== "string" && input?.length === 64 && typeof input[0] === "number") {
|
|
336
344
|
return _NullTrace.fromSecretKey(input);
|
|
337
345
|
}
|
|
338
346
|
if (typeof input === "string") {
|
|
@@ -853,7 +861,7 @@ var NullTrace = class _NullTrace {
|
|
|
853
861
|
await this.connection.confirmTransaction(sig);
|
|
854
862
|
preSigs.push(sig);
|
|
855
863
|
}
|
|
856
|
-
const swapId =
|
|
864
|
+
const swapId = bs58.encode(nacl.randomBytes(32));
|
|
857
865
|
const swapData = {
|
|
858
866
|
id: swapId,
|
|
859
867
|
fromToken: fromMint,
|