@adelos/sdk 0.1.2 → 0.1.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.d.mts +42 -470
- package/dist/index.d.ts +42 -470
- package/dist/index.js +138 -725
- package/dist/index.mjs +138 -725
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -1,41 +1,36 @@
|
|
|
1
1
|
// src/index.ts
|
|
2
2
|
import {
|
|
3
|
-
Connection as
|
|
4
|
-
PublicKey as
|
|
3
|
+
Connection as Connection2,
|
|
4
|
+
PublicKey as PublicKey4,
|
|
5
5
|
SystemProgram,
|
|
6
|
-
Transaction
|
|
7
|
-
TransactionInstruction
|
|
6
|
+
Transaction,
|
|
7
|
+
TransactionInstruction,
|
|
8
8
|
TransactionMessage,
|
|
9
9
|
VersionedTransaction
|
|
10
10
|
} from "@solana/web3.js";
|
|
11
11
|
|
|
12
12
|
// src/constants.ts
|
|
13
13
|
import { PublicKey, clusterApiUrl } from "@solana/web3.js";
|
|
14
|
-
var
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
devnet: clusterApiUrl("devnet"),
|
|
22
|
-
"mainnet-beta": clusterApiUrl("mainnet-beta"),
|
|
23
|
-
localnet: "http://localhost:8899"
|
|
14
|
+
var ADELOS_CONFIG = {
|
|
15
|
+
PROGRAM_ID: new PublicKey("7T1UxHJ6psKiQheKZXxANu6mhgsmgaX55eNKZZL5u4Rp"),
|
|
16
|
+
RPC_URL: clusterApiUrl("devnet"),
|
|
17
|
+
MEMO_PROGRAM_ID: new PublicKey("MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr"),
|
|
18
|
+
REGISTRY_SEED: "registry",
|
|
19
|
+
MEMO_PREFIX: "ADLSv1:",
|
|
20
|
+
STEALTH_DOMAIN: "adelos:stealth:v1"
|
|
24
21
|
};
|
|
25
|
-
var PROGRAM_ID =
|
|
26
|
-
var
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
var
|
|
30
|
-
var
|
|
31
|
-
var MEMO_PREFIX = "ADLSv1:";
|
|
32
|
-
var STEALTH_DOMAIN = "adelos:stealth:v1";
|
|
22
|
+
var PROGRAM_ID = ADELOS_CONFIG.PROGRAM_ID;
|
|
23
|
+
var RPC_URL = ADELOS_CONFIG.RPC_URL;
|
|
24
|
+
var MEMO_PROGRAM_ID = ADELOS_CONFIG.MEMO_PROGRAM_ID;
|
|
25
|
+
var REGISTRY_SEED = ADELOS_CONFIG.REGISTRY_SEED;
|
|
26
|
+
var MEMO_PREFIX = ADELOS_CONFIG.MEMO_PREFIX;
|
|
27
|
+
var STEALTH_DOMAIN = ADELOS_CONFIG.STEALTH_DOMAIN;
|
|
33
28
|
|
|
34
29
|
// src/utils.ts
|
|
35
30
|
import { PublicKey as PublicKey2 } from "@solana/web3.js";
|
|
36
|
-
function deriveRegistryPda(owner, programId = PROGRAM_ID) {
|
|
31
|
+
function deriveRegistryPda(owner, programId = ADELOS_CONFIG.PROGRAM_ID) {
|
|
37
32
|
return PublicKey2.findProgramAddressSync(
|
|
38
|
-
[Buffer.from(REGISTRY_SEED), owner.toBuffer()],
|
|
33
|
+
[Buffer.from(ADELOS_CONFIG.REGISTRY_SEED), owner.toBuffer()],
|
|
39
34
|
programId
|
|
40
35
|
);
|
|
41
36
|
}
|
|
@@ -308,65 +303,52 @@ var IDL = {
|
|
|
308
303
|
|
|
309
304
|
// src/crypto.ts
|
|
310
305
|
import { sha256 } from "@noble/hashes/sha256";
|
|
306
|
+
import { sha512 } from "@noble/hashes/sha512";
|
|
311
307
|
import * as ed from "@noble/ed25519";
|
|
308
|
+
ed.etc.sha512Sync = (...m) => {
|
|
309
|
+
const h = sha512.create();
|
|
310
|
+
m.forEach((msg) => h.update(msg));
|
|
311
|
+
return h.digest();
|
|
312
|
+
};
|
|
313
|
+
var encoder = new TextEncoder();
|
|
312
314
|
function generateEphemeralKeypair() {
|
|
313
315
|
const secretKey = ed.utils.randomPrivateKey();
|
|
314
|
-
|
|
315
|
-
return { secretKey, publicKey };
|
|
316
|
+
return { secretKey, publicKey: ed.getPublicKey(secretKey) };
|
|
316
317
|
}
|
|
317
|
-
|
|
318
|
-
const point = ed.ExtendedPoint.fromHex(
|
|
319
|
-
const scalar = ed.etc.mod(
|
|
320
|
-
|
|
321
|
-
ed.CURVE.n
|
|
322
|
-
);
|
|
323
|
-
const sharedPoint = point.multiply(scalar);
|
|
324
|
-
const sharedBytes = sharedPoint.toRawBytes();
|
|
325
|
-
return sha256(sharedBytes);
|
|
318
|
+
function computeSharedSecret(ephemeralSk, recipientMetaPk) {
|
|
319
|
+
const point = ed.ExtendedPoint.fromHex(bytesToHex(recipientMetaPk));
|
|
320
|
+
const scalar = ed.etc.mod(BigInt("0x" + bytesToHex(ephemeralSk)), ed.CURVE.n);
|
|
321
|
+
return sha256(point.multiply(scalar).toRawBytes());
|
|
326
322
|
}
|
|
327
|
-
function
|
|
328
|
-
const
|
|
329
|
-
|
|
330
|
-
);
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
);
|
|
335
|
-
const
|
|
336
|
-
const
|
|
337
|
-
const
|
|
323
|
+
function computeSharedSecretAsRecipient(metaSk, ephemeralPk) {
|
|
324
|
+
const secretKey = metaSk.length === 64 ? metaSk.slice(0, 32) : metaSk;
|
|
325
|
+
const point = ed.ExtendedPoint.fromHex(bytesToHex(ephemeralPk));
|
|
326
|
+
const scalar = ed.etc.mod(BigInt("0x" + bytesToHex(secretKey)), ed.CURVE.n);
|
|
327
|
+
return sha256(point.multiply(scalar).toRawBytes());
|
|
328
|
+
}
|
|
329
|
+
function deriveStealthPubkey(metaPk, sharedSecret) {
|
|
330
|
+
const domain = encoder.encode(ADELOS_CONFIG.STEALTH_DOMAIN);
|
|
331
|
+
const scalarBytes = sha256(new Uint8Array([...sharedSecret, ...domain]));
|
|
332
|
+
const scalar = ed.etc.mod(BigInt("0x" + bytesToHex(scalarBytes)), ed.CURVE.n);
|
|
333
|
+
const metaPoint = ed.ExtendedPoint.fromHex(bytesToHex(metaPk));
|
|
334
|
+
const stealthPoint = metaPoint.add(ed.ExtendedPoint.BASE.multiply(scalar));
|
|
338
335
|
return stealthPoint.toRawBytes();
|
|
339
336
|
}
|
|
340
337
|
function recoverStealthSecretKey(metaSk, sharedSecret) {
|
|
341
|
-
const
|
|
342
|
-
|
|
343
|
-
);
|
|
344
|
-
const
|
|
345
|
-
BigInt("0x" + bytesToHex(scalarBytes)),
|
|
346
|
-
ed.CURVE.n
|
|
347
|
-
);
|
|
348
|
-
const metaScalar = ed.etc.mod(
|
|
349
|
-
BigInt("0x" + bytesToHex(metaSk)),
|
|
350
|
-
ed.CURVE.n
|
|
351
|
-
);
|
|
338
|
+
const domain = encoder.encode(ADELOS_CONFIG.STEALTH_DOMAIN);
|
|
339
|
+
const scalarBytes = sha256(new Uint8Array([...sharedSecret, ...domain]));
|
|
340
|
+
const scalar = ed.etc.mod(BigInt("0x" + bytesToHex(scalarBytes)), ed.CURVE.n);
|
|
341
|
+
const metaScalar = ed.etc.mod(BigInt("0x" + bytesToHex(metaSk)), ed.CURVE.n);
|
|
352
342
|
const stealthScalar = ed.etc.mod(metaScalar + scalar, ed.CURVE.n);
|
|
353
343
|
const hex = stealthScalar.toString(16).padStart(64, "0");
|
|
354
344
|
return hexToBytes(hex);
|
|
355
345
|
}
|
|
356
|
-
async function computeSharedSecretAsRecipient(metaSk, ephemeralPubkey) {
|
|
357
|
-
const point = ed.ExtendedPoint.fromHex(ephemeralPubkey);
|
|
358
|
-
const scalar = ed.etc.mod(BigInt("0x" + bytesToHex(metaSk)), ed.CURVE.n);
|
|
359
|
-
const sharedPoint = point.multiply(scalar);
|
|
360
|
-
const sharedBytes = sharedPoint.toRawBytes();
|
|
361
|
-
return sha256(sharedBytes);
|
|
362
|
-
}
|
|
363
346
|
function generateStealthMemo(ephemeralPubkey) {
|
|
364
|
-
|
|
365
|
-
return `${MEMO_PREFIX}${pubkeyHex}`;
|
|
347
|
+
return `${ADELOS_CONFIG.MEMO_PREFIX}${bytesToHex(ephemeralPubkey)}`;
|
|
366
348
|
}
|
|
367
349
|
function parseStealthMemo(memo) {
|
|
368
|
-
if (!memo.startsWith(MEMO_PREFIX)) return null;
|
|
369
|
-
const pubkeyHex = memo.slice(MEMO_PREFIX.length);
|
|
350
|
+
if (!memo.startsWith(ADELOS_CONFIG.MEMO_PREFIX)) return null;
|
|
351
|
+
const pubkeyHex = memo.slice(ADELOS_CONFIG.MEMO_PREFIX.length);
|
|
370
352
|
if (pubkeyHex.length !== 64) return null;
|
|
371
353
|
try {
|
|
372
354
|
return hexToBytes(pubkeyHex);
|
|
@@ -374,618 +356,115 @@ function parseStealthMemo(memo) {
|
|
|
374
356
|
return null;
|
|
375
357
|
}
|
|
376
358
|
}
|
|
377
|
-
|
|
359
|
+
function generateStealthAddress(recipientMetaPk) {
|
|
378
360
|
const ephemeralKeypair = generateEphemeralKeypair();
|
|
379
|
-
const sharedSecret =
|
|
380
|
-
|
|
381
|
-
recipientMetaPubkey
|
|
382
|
-
);
|
|
383
|
-
const stealthPubkey = deriveStealthPubkey(recipientMetaPubkey, sharedSecret);
|
|
361
|
+
const sharedSecret = computeSharedSecret(ephemeralKeypair.secretKey, recipientMetaPk);
|
|
362
|
+
const stealthPubkey = deriveStealthPubkey(recipientMetaPk, sharedSecret);
|
|
384
363
|
const memo = generateStealthMemo(ephemeralKeypair.publicKey);
|
|
385
|
-
return {
|
|
386
|
-
stealthPubkey,
|
|
387
|
-
ephemeralKeypair,
|
|
388
|
-
sharedSecret,
|
|
389
|
-
memo
|
|
390
|
-
};
|
|
391
|
-
}
|
|
392
|
-
async function isStealthTransactionForMe(metaSk, metaPubkey, ephemeralPubkey, targetAddress) {
|
|
393
|
-
const sharedSecret = await computeSharedSecretAsRecipient(
|
|
394
|
-
metaSk,
|
|
395
|
-
ephemeralPubkey
|
|
396
|
-
);
|
|
397
|
-
const expectedStealth = deriveStealthPubkey(metaPubkey, sharedSecret);
|
|
398
|
-
return bytesToHex(expectedStealth) === bytesToHex(targetAddress);
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
// src/light.ts
|
|
402
|
-
import {
|
|
403
|
-
Connection,
|
|
404
|
-
PublicKey as PublicKey3,
|
|
405
|
-
Transaction,
|
|
406
|
-
TransactionInstruction
|
|
407
|
-
} from "@solana/web3.js";
|
|
408
|
-
var LIGHT_PROGRAM_IDS = {
|
|
409
|
-
LIGHT_SYSTEM_PROGRAM: new PublicKey3(
|
|
410
|
-
"SySTEM1eSU2p4BGQfQpimFEWWSC1XDFeun3Nqzz3rT7"
|
|
411
|
-
),
|
|
412
|
-
COMPRESSED_TOKEN_PROGRAM: new PublicKey3(
|
|
413
|
-
"cTokenmWW8bLPjZEBAUgYy3zKxQZW6VKi7bqNFEVv3m"
|
|
414
|
-
),
|
|
415
|
-
ACCOUNT_COMPRESSION_PROGRAM: new PublicKey3(
|
|
416
|
-
"compr6CUsB5m2jS4Y3831ztGSTnDpnKJTKS95d64XVq"
|
|
417
|
-
)
|
|
418
|
-
};
|
|
419
|
-
var LightClient = class _LightClient {
|
|
420
|
-
constructor(connection, config) {
|
|
421
|
-
this.connection = connection;
|
|
422
|
-
this.config = config;
|
|
423
|
-
}
|
|
424
|
-
/**
|
|
425
|
-
* Creates a new Light Protocol client
|
|
426
|
-
*
|
|
427
|
-
* @param rpcUrl - Solana RPC URL with Light Protocol support
|
|
428
|
-
* @returns LightClient instance
|
|
429
|
-
*/
|
|
430
|
-
static create(rpcUrl) {
|
|
431
|
-
const connection = new Connection(rpcUrl, "confirmed");
|
|
432
|
-
return new _LightClient(connection, { rpcUrl });
|
|
433
|
-
}
|
|
434
|
-
/**
|
|
435
|
-
* Gets compressed SOL balance for an address
|
|
436
|
-
*
|
|
437
|
-
* @param owner - Owner public key
|
|
438
|
-
* @returns Compressed SOL balance in lamports
|
|
439
|
-
*/
|
|
440
|
-
async getCompressedSolBalance(owner) {
|
|
441
|
-
try {
|
|
442
|
-
const response = await fetch(this.config.rpcUrl, {
|
|
443
|
-
method: "POST",
|
|
444
|
-
headers: { "Content-Type": "application/json" },
|
|
445
|
-
body: JSON.stringify({
|
|
446
|
-
jsonrpc: "2.0",
|
|
447
|
-
id: 1,
|
|
448
|
-
method: "getCompressedAccountsByOwner",
|
|
449
|
-
params: [owner.toBase58()]
|
|
450
|
-
})
|
|
451
|
-
});
|
|
452
|
-
const data = await response.json();
|
|
453
|
-
if (data.error) {
|
|
454
|
-
console.warn("Light RPC error:", data.error);
|
|
455
|
-
return BigInt(0);
|
|
456
|
-
}
|
|
457
|
-
const accounts = data.result?.items || [];
|
|
458
|
-
let total = BigInt(0);
|
|
459
|
-
for (const acc of accounts) {
|
|
460
|
-
total += BigInt(acc.lamports || 0);
|
|
461
|
-
}
|
|
462
|
-
return total;
|
|
463
|
-
} catch (error) {
|
|
464
|
-
console.warn("Failed to get compressed balance:", error);
|
|
465
|
-
return BigInt(0);
|
|
466
|
-
}
|
|
467
|
-
}
|
|
468
|
-
/**
|
|
469
|
-
* Gets compressed token balances for an address
|
|
470
|
-
*
|
|
471
|
-
* @param owner - Owner public key
|
|
472
|
-
* @param mint - Optional token mint to filter
|
|
473
|
-
* @returns Array of compressed token balances
|
|
474
|
-
*/
|
|
475
|
-
async getCompressedTokenBalances(owner, mint) {
|
|
476
|
-
try {
|
|
477
|
-
const response = await fetch(this.config.rpcUrl, {
|
|
478
|
-
method: "POST",
|
|
479
|
-
headers: { "Content-Type": "application/json" },
|
|
480
|
-
body: JSON.stringify({
|
|
481
|
-
jsonrpc: "2.0",
|
|
482
|
-
id: 1,
|
|
483
|
-
method: "getCompressedTokenAccountsByOwner",
|
|
484
|
-
params: [owner.toBase58(), mint?.toBase58()]
|
|
485
|
-
})
|
|
486
|
-
});
|
|
487
|
-
const data = await response.json();
|
|
488
|
-
if (data.error) {
|
|
489
|
-
console.warn("Light RPC error:", data.error);
|
|
490
|
-
return [];
|
|
491
|
-
}
|
|
492
|
-
const balancesByMint = /* @__PURE__ */ new Map();
|
|
493
|
-
const accounts = data.result?.items || [];
|
|
494
|
-
for (const acc of accounts) {
|
|
495
|
-
const mintStr = acc.mint;
|
|
496
|
-
if (!balancesByMint.has(mintStr)) {
|
|
497
|
-
balancesByMint.set(mintStr, {
|
|
498
|
-
mint: new PublicKey3(mintStr),
|
|
499
|
-
amount: BigInt(0),
|
|
500
|
-
accounts: []
|
|
501
|
-
});
|
|
502
|
-
}
|
|
503
|
-
const balance = balancesByMint.get(mintStr);
|
|
504
|
-
balance.amount += BigInt(acc.amount || 0);
|
|
505
|
-
balance.accounts.push({
|
|
506
|
-
hash: acc.hash,
|
|
507
|
-
owner: new PublicKey3(acc.owner),
|
|
508
|
-
lamports: acc.lamports || 0,
|
|
509
|
-
data: new Uint8Array(acc.data || []),
|
|
510
|
-
tree: new PublicKey3(acc.tree),
|
|
511
|
-
leafIndex: acc.leafIndex
|
|
512
|
-
});
|
|
513
|
-
}
|
|
514
|
-
return Array.from(balancesByMint.values());
|
|
515
|
-
} catch (error) {
|
|
516
|
-
console.warn("Failed to get compressed token balances:", error);
|
|
517
|
-
return [];
|
|
518
|
-
}
|
|
519
|
-
}
|
|
520
|
-
/**
|
|
521
|
-
* Creates a compressed SOL transfer instruction
|
|
522
|
-
*
|
|
523
|
-
* Note: This creates the instruction data structure.
|
|
524
|
-
* Actual ZK proof generation requires Light Protocol SDK.
|
|
525
|
-
*
|
|
526
|
-
* @param from - Sender public key
|
|
527
|
-
* @param to - Recipient public key (can be stealth address)
|
|
528
|
-
* @param amount - Amount in lamports
|
|
529
|
-
* @returns Transaction instruction (placeholder)
|
|
530
|
-
*/
|
|
531
|
-
createCompressedTransferInstruction(from, to, amount) {
|
|
532
|
-
const data = Buffer.alloc(72);
|
|
533
|
-
data.write("compressed_transfer", 0);
|
|
534
|
-
data.writeBigUInt64LE(amount, 32);
|
|
535
|
-
return new TransactionInstruction({
|
|
536
|
-
keys: [
|
|
537
|
-
{ pubkey: from, isSigner: true, isWritable: true },
|
|
538
|
-
{ pubkey: to, isSigner: false, isWritable: true },
|
|
539
|
-
{
|
|
540
|
-
pubkey: LIGHT_PROGRAM_IDS.LIGHT_SYSTEM_PROGRAM,
|
|
541
|
-
isSigner: false,
|
|
542
|
-
isWritable: false
|
|
543
|
-
}
|
|
544
|
-
],
|
|
545
|
-
programId: LIGHT_PROGRAM_IDS.LIGHT_SYSTEM_PROGRAM,
|
|
546
|
-
data
|
|
547
|
-
});
|
|
548
|
-
}
|
|
549
|
-
/**
|
|
550
|
-
* Compresses SOL from regular account to compressed account
|
|
551
|
-
*
|
|
552
|
-
* @param owner - Owner public key
|
|
553
|
-
* @param amount - Amount in lamports to compress
|
|
554
|
-
* @returns Transaction (unsigned)
|
|
555
|
-
*/
|
|
556
|
-
async createCompressSolTransaction(owner, amount) {
|
|
557
|
-
const instruction = this.createCompressedTransferInstruction(
|
|
558
|
-
owner,
|
|
559
|
-
owner,
|
|
560
|
-
// Compress to self
|
|
561
|
-
amount
|
|
562
|
-
);
|
|
563
|
-
const transaction = new Transaction().add(instruction);
|
|
564
|
-
transaction.recentBlockhash = (await this.connection.getLatestBlockhash()).blockhash;
|
|
565
|
-
transaction.feePayer = owner;
|
|
566
|
-
return transaction;
|
|
567
|
-
}
|
|
568
|
-
/**
|
|
569
|
-
* Decompresses SOL from compressed account to regular account
|
|
570
|
-
*
|
|
571
|
-
* @param owner - Owner public key
|
|
572
|
-
* @param amount - Amount in lamports to decompress
|
|
573
|
-
* @returns Transaction (unsigned)
|
|
574
|
-
*/
|
|
575
|
-
async createDecompressSolTransaction(owner, amount) {
|
|
576
|
-
const instruction = this.createCompressedTransferInstruction(
|
|
577
|
-
owner,
|
|
578
|
-
owner,
|
|
579
|
-
amount
|
|
580
|
-
);
|
|
581
|
-
const transaction = new Transaction().add(instruction);
|
|
582
|
-
transaction.recentBlockhash = (await this.connection.getLatestBlockhash()).blockhash;
|
|
583
|
-
transaction.feePayer = owner;
|
|
584
|
-
return transaction;
|
|
585
|
-
}
|
|
586
|
-
/**
|
|
587
|
-
* Creates a stealth compressed transfer
|
|
588
|
-
* Combines stealth addressing with ZK-compression
|
|
589
|
-
*
|
|
590
|
-
* @param from - Sender public key
|
|
591
|
-
* @param stealthPubkey - Derived stealth address for recipient
|
|
592
|
-
* @param amount - Amount in lamports
|
|
593
|
-
* @param memo - Stealth memo containing ephemeral pubkey
|
|
594
|
-
* @returns Transaction (unsigned)
|
|
595
|
-
*/
|
|
596
|
-
async createStealthCompressedTransfer(from, stealthPubkey, amount, memo) {
|
|
597
|
-
const stealthAddress = new PublicKey3(stealthPubkey);
|
|
598
|
-
const transferIx = this.createCompressedTransferInstruction(
|
|
599
|
-
from,
|
|
600
|
-
stealthAddress,
|
|
601
|
-
amount
|
|
602
|
-
);
|
|
603
|
-
const memoIx = new TransactionInstruction({
|
|
604
|
-
keys: [],
|
|
605
|
-
programId: MEMO_PROGRAM_ID,
|
|
606
|
-
data: Buffer.from(memo, "utf-8")
|
|
607
|
-
});
|
|
608
|
-
const transaction = new Transaction().add(transferIx).add(memoIx);
|
|
609
|
-
transaction.recentBlockhash = (await this.connection.getLatestBlockhash()).blockhash;
|
|
610
|
-
transaction.feePayer = from;
|
|
611
|
-
return transaction;
|
|
612
|
-
}
|
|
613
|
-
};
|
|
614
|
-
function createLightClient(rpcUrl) {
|
|
615
|
-
return LightClient.create(rpcUrl);
|
|
364
|
+
return { stealthPubkey, ephemeralKeypair, sharedSecret, memo };
|
|
616
365
|
}
|
|
617
366
|
|
|
618
367
|
// src/indexer.ts
|
|
619
|
-
import { Connection
|
|
368
|
+
import { Connection } from "@solana/web3.js";
|
|
620
369
|
var AdelosIndexer = class _AdelosIndexer {
|
|
621
370
|
constructor(config) {
|
|
622
|
-
this.
|
|
623
|
-
this.
|
|
624
|
-
this.config = config;
|
|
625
|
-
this.connection = new Connection2(config.rpcUrl, "confirmed");
|
|
371
|
+
this.connection = new Connection(config.rpcUrl, "confirmed");
|
|
372
|
+
this.heliusApiKey = config.heliusApiKey;
|
|
626
373
|
}
|
|
627
|
-
/**
|
|
628
|
-
* Creates an indexer instance
|
|
629
|
-
*/
|
|
630
374
|
static create(config) {
|
|
631
375
|
return new _AdelosIndexer(config);
|
|
632
376
|
}
|
|
633
|
-
/**
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
*
|
|
640
|
-
* @param metaSk - Recipient's meta secret key
|
|
641
|
-
* @param metaPubkey - Recipient's meta public key
|
|
642
|
-
* @param limit - Number of transactions to scan
|
|
643
|
-
* @returns Array of stealth transactions for this recipient
|
|
644
|
-
*/
|
|
645
|
-
async scanForStealthTransfers(metaSk, metaPubkey, limit = 100) {
|
|
646
|
-
const results = [];
|
|
647
|
-
try {
|
|
648
|
-
const signatures = await this.connection.getSignaturesForAddress(
|
|
649
|
-
MEMO_PROGRAM_ID,
|
|
650
|
-
{ limit }
|
|
651
|
-
);
|
|
652
|
-
for (const sigInfo of signatures) {
|
|
653
|
-
const tx = await this.connection.getParsedTransaction(
|
|
654
|
-
sigInfo.signature,
|
|
655
|
-
{ maxSupportedTransactionVersion: 0 }
|
|
656
|
-
);
|
|
657
|
-
if (!tx) continue;
|
|
658
|
-
const memo = this.extractMemo(tx);
|
|
659
|
-
if (!memo?.startsWith(MEMO_PREFIX)) continue;
|
|
660
|
-
const stealthTx = await this.parseStealthTransaction(
|
|
661
|
-
tx,
|
|
662
|
-
sigInfo.signature,
|
|
663
|
-
metaSk,
|
|
664
|
-
metaPubkey
|
|
665
|
-
);
|
|
666
|
-
if (stealthTx) {
|
|
667
|
-
results.push(stealthTx);
|
|
668
|
-
}
|
|
669
|
-
}
|
|
670
|
-
} catch (error) {
|
|
671
|
-
console.error("Error scanning transactions:", error);
|
|
672
|
-
}
|
|
673
|
-
return results;
|
|
674
|
-
}
|
|
675
|
-
/**
|
|
676
|
-
* Scans all transactions with ADLSv1 memo prefix
|
|
677
|
-
*
|
|
678
|
-
* @param metaSk - Recipient's meta secret key
|
|
679
|
-
* @param metaPubkey - Recipient's meta public key
|
|
680
|
-
* @param since - Scan transactions after this signature
|
|
681
|
-
* @returns Array of stealth transactions
|
|
682
|
-
*/
|
|
683
|
-
async scanByMemoPrefix(metaSk, metaPubkey, since) {
|
|
377
|
+
/** Scan for stealth transfers to this recipient */
|
|
378
|
+
async scanForStealthTransfers(metaSk, metaPk, limit = 100) {
|
|
379
|
+
const sigs = await this.connection.getSignaturesForAddress(
|
|
380
|
+
ADELOS_CONFIG.MEMO_PROGRAM_ID,
|
|
381
|
+
{ limit }
|
|
382
|
+
);
|
|
684
383
|
const results = [];
|
|
685
|
-
|
|
686
|
-
const
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
);
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
sigInfo.signature,
|
|
701
|
-
metaSk,
|
|
702
|
-
metaPubkey
|
|
703
|
-
);
|
|
704
|
-
if (stealthTx) {
|
|
705
|
-
results.push(stealthTx);
|
|
706
|
-
}
|
|
384
|
+
for (const s of sigs) {
|
|
385
|
+
const tx = await this.connection.getParsedTransaction(s.signature, {
|
|
386
|
+
maxSupportedTransactionVersion: 0
|
|
387
|
+
});
|
|
388
|
+
if (!tx) continue;
|
|
389
|
+
const memo = this.extractMemo(tx);
|
|
390
|
+
if (!memo?.startsWith(ADELOS_CONFIG.MEMO_PREFIX)) continue;
|
|
391
|
+
const detected = this.attemptDecryption(tx, metaSk, metaPk);
|
|
392
|
+
if (detected) {
|
|
393
|
+
results.push({
|
|
394
|
+
signature: s.signature,
|
|
395
|
+
blockTime: tx.blockTime ?? null,
|
|
396
|
+
stealthAddress: detected.stealthAddress,
|
|
397
|
+
amount: detected.amount
|
|
398
|
+
});
|
|
707
399
|
}
|
|
708
|
-
} catch (error) {
|
|
709
|
-
console.error("Error scanning by memo:", error);
|
|
710
400
|
}
|
|
711
401
|
return results;
|
|
712
402
|
}
|
|
713
|
-
/**
|
|
714
|
-
|
|
715
|
-
*/
|
|
716
|
-
extractMemo(tx) {
|
|
717
|
-
const memoProgram = "MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr";
|
|
718
|
-
for (const ix of tx.transaction.message.instructions) {
|
|
719
|
-
if ("programId" in ix && ix.programId.toBase58() === memoProgram) {
|
|
720
|
-
if ("parsed" in ix && typeof ix.parsed === "string") {
|
|
721
|
-
return ix.parsed;
|
|
722
|
-
}
|
|
723
|
-
}
|
|
724
|
-
}
|
|
725
|
-
if (tx.meta?.innerInstructions) {
|
|
726
|
-
for (const inner of tx.meta.innerInstructions) {
|
|
727
|
-
for (const ix of inner.instructions) {
|
|
728
|
-
if ("programId" in ix && ix.programId.toBase58() === memoProgram) {
|
|
729
|
-
if ("parsed" in ix && typeof ix.parsed === "string") {
|
|
730
|
-
return ix.parsed;
|
|
731
|
-
}
|
|
732
|
-
}
|
|
733
|
-
}
|
|
734
|
-
}
|
|
735
|
-
}
|
|
736
|
-
return null;
|
|
737
|
-
}
|
|
738
|
-
/**
|
|
739
|
-
* Parses a transaction to extract stealth transfer info using Trial Decryption
|
|
740
|
-
*
|
|
741
|
-
* Trial Decryption: First compute expected stealth address, then find if it exists in tx accounts
|
|
742
|
-
*/
|
|
743
|
-
async parseStealthTransaction(tx, signature, metaSk, metaPubkey) {
|
|
403
|
+
/** Trial Decryption: Check if transaction is for this recipient */
|
|
404
|
+
attemptDecryption(tx, metaSk, metaPk) {
|
|
744
405
|
const memo = this.extractMemo(tx);
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
try {
|
|
750
|
-
const sharedSecret = await computeSharedSecretAsRecipient(
|
|
751
|
-
metaSk,
|
|
752
|
-
ephemeralPubkey
|
|
753
|
-
);
|
|
754
|
-
const expectedStealth = deriveStealthPubkey(metaPubkey, sharedSecret);
|
|
755
|
-
expectedStealthHex = bytesToHex(expectedStealth);
|
|
756
|
-
} catch (error) {
|
|
757
|
-
console.warn("Error computing expected stealth:", error);
|
|
758
|
-
return null;
|
|
759
|
-
}
|
|
406
|
+
const ephemeralPk = parseStealthMemo(memo || "");
|
|
407
|
+
if (!ephemeralPk) return null;
|
|
408
|
+
const secret = computeSharedSecretAsRecipient(metaSk, ephemeralPk);
|
|
409
|
+
const expectedStealthHex = bytesToHex(deriveStealthPubkey(metaPk, secret));
|
|
760
410
|
const accounts = tx.transaction.message.accountKeys;
|
|
411
|
+
const idx = accounts.findIndex(
|
|
412
|
+
(a) => bytesToHex(a.pubkey.toBytes()) === expectedStealthHex
|
|
413
|
+
);
|
|
414
|
+
if (idx === -1) return null;
|
|
761
415
|
const preBalances = tx.meta?.preBalances || [];
|
|
762
416
|
const postBalances = tx.meta?.postBalances || [];
|
|
763
|
-
|
|
764
|
-
for (let i = 0; i < accounts.length; i++) {
|
|
765
|
-
const accountHex = bytesToHex(accounts[i].pubkey.toBytes());
|
|
766
|
-
if (accountHex === expectedStealthHex) {
|
|
767
|
-
stealthIndex = i;
|
|
768
|
-
break;
|
|
769
|
-
}
|
|
770
|
-
}
|
|
771
|
-
if (stealthIndex === -1) return null;
|
|
772
|
-
const stealthAddress = accounts[stealthIndex].pubkey;
|
|
773
|
-
const change = (postBalances[stealthIndex] || 0) - (preBalances[stealthIndex] || 0);
|
|
774
|
-
const amount = BigInt(Math.max(change, 0));
|
|
775
|
-
let sender = null;
|
|
776
|
-
for (let i = 0; i < accounts.length; i++) {
|
|
777
|
-
const accChange = (postBalances[i] || 0) - (preBalances[i] || 0);
|
|
778
|
-
if (accChange < 0) {
|
|
779
|
-
sender = accounts[i].pubkey;
|
|
780
|
-
break;
|
|
781
|
-
}
|
|
782
|
-
}
|
|
783
|
-
return {
|
|
784
|
-
signature,
|
|
785
|
-
blockTime: tx.blockTime ?? null,
|
|
786
|
-
slot: tx.slot,
|
|
787
|
-
sender,
|
|
788
|
-
stealthAddress,
|
|
789
|
-
amount,
|
|
790
|
-
ephemeralPubkey,
|
|
791
|
-
isForMe: true
|
|
792
|
-
// If we reach here, it's definitely for us
|
|
793
|
-
};
|
|
794
|
-
}
|
|
795
|
-
/**
|
|
796
|
-
* Starts continuous scanning for stealth transfers
|
|
797
|
-
*
|
|
798
|
-
* @param metaSk - Recipient's meta secret key
|
|
799
|
-
* @param metaPubkey - Recipient's meta public key
|
|
800
|
-
*/
|
|
801
|
-
startScanning(metaSk, metaPubkey) {
|
|
802
|
-
if (this.isScanning) return;
|
|
803
|
-
this.isScanning = true;
|
|
804
|
-
let lastSignature;
|
|
805
|
-
const scanInterval = this.config.scanInterval || 1e4;
|
|
806
|
-
this.scanIntervalId = setInterval(async () => {
|
|
807
|
-
try {
|
|
808
|
-
const txs = await this.scanByMemoPrefix(
|
|
809
|
-
metaSk,
|
|
810
|
-
metaPubkey,
|
|
811
|
-
lastSignature
|
|
812
|
-
);
|
|
813
|
-
for (const tx of txs) {
|
|
814
|
-
if (tx.isForMe && this.onTransaction) {
|
|
815
|
-
this.onTransaction(tx);
|
|
816
|
-
}
|
|
817
|
-
}
|
|
818
|
-
if (txs.length > 0) {
|
|
819
|
-
lastSignature = txs[0].signature;
|
|
820
|
-
}
|
|
821
|
-
} catch (error) {
|
|
822
|
-
console.error("Scan error:", error);
|
|
823
|
-
}
|
|
824
|
-
}, scanInterval);
|
|
825
|
-
}
|
|
826
|
-
/**
|
|
827
|
-
* Stops continuous scanning
|
|
828
|
-
*/
|
|
829
|
-
stopScanning() {
|
|
830
|
-
this.isScanning = false;
|
|
831
|
-
if (this.scanIntervalId) {
|
|
832
|
-
clearInterval(this.scanIntervalId);
|
|
833
|
-
this.scanIntervalId = null;
|
|
834
|
-
}
|
|
835
|
-
}
|
|
836
|
-
/**
|
|
837
|
-
* Processes a Helius webhook payload
|
|
838
|
-
*
|
|
839
|
-
* @param payload - Webhook payload from Helius
|
|
840
|
-
* @param metaSk - Recipient's meta secret key
|
|
841
|
-
* @param metaPubkey - Recipient's meta public key
|
|
842
|
-
* @returns Stealth transaction if detected and for this recipient
|
|
843
|
-
*/
|
|
844
|
-
async processWebhook(payload, metaSk, metaPubkey) {
|
|
845
|
-
let memo = null;
|
|
846
|
-
const memoProgramStr = MEMO_PROGRAM_ID.toBase58();
|
|
847
|
-
for (const ix of payload.instructions) {
|
|
848
|
-
if (ix.programId === memoProgramStr) {
|
|
849
|
-
memo = Buffer.from(ix.data, "base64").toString("utf-8");
|
|
850
|
-
break;
|
|
851
|
-
}
|
|
852
|
-
}
|
|
853
|
-
if (!memo?.startsWith(MEMO_PREFIX)) return null;
|
|
854
|
-
const ephemeralPubkey = parseStealthMemo(memo);
|
|
855
|
-
if (!ephemeralPubkey) return null;
|
|
856
|
-
let stealthAddress = null;
|
|
857
|
-
let amount = BigInt(0);
|
|
858
|
-
for (const acc of payload.accountData) {
|
|
859
|
-
if (acc.nativeBalanceChange > 0) {
|
|
860
|
-
stealthAddress = new PublicKey4(acc.account);
|
|
861
|
-
amount = BigInt(acc.nativeBalanceChange);
|
|
862
|
-
break;
|
|
863
|
-
}
|
|
864
|
-
}
|
|
865
|
-
if (!stealthAddress) return null;
|
|
866
|
-
let isForMe = false;
|
|
867
|
-
try {
|
|
868
|
-
const sharedSecret = await computeSharedSecretAsRecipient(
|
|
869
|
-
metaSk,
|
|
870
|
-
ephemeralPubkey
|
|
871
|
-
);
|
|
872
|
-
const expectedStealth = deriveStealthPubkey(metaPubkey, sharedSecret);
|
|
873
|
-
isForMe = bytesToHex(expectedStealth) === bytesToHex(stealthAddress.toBytes());
|
|
874
|
-
} catch (error) {
|
|
875
|
-
console.warn("Error checking webhook tx:", error);
|
|
876
|
-
}
|
|
877
|
-
if (!isForMe) return null;
|
|
417
|
+
const change = (postBalances[idx] || 0) - (preBalances[idx] || 0);
|
|
878
418
|
return {
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
slot: payload.slot,
|
|
882
|
-
sender: null,
|
|
883
|
-
stealthAddress,
|
|
884
|
-
amount,
|
|
885
|
-
ephemeralPubkey,
|
|
886
|
-
isForMe: true
|
|
419
|
+
stealthAddress: accounts[idx].pubkey,
|
|
420
|
+
amount: BigInt(Math.max(change, 0))
|
|
887
421
|
};
|
|
888
422
|
}
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
*/
|
|
895
|
-
async setupHeliusWebhook(webhookUrl) {
|
|
896
|
-
if (!this.config.heliusApiKey) {
|
|
897
|
-
console.warn("Helius API key not configured");
|
|
898
|
-
return null;
|
|
899
|
-
}
|
|
900
|
-
try {
|
|
901
|
-
const response = await fetch(
|
|
902
|
-
`https://api.helius.xyz/v0/webhooks?api-key=${this.config.heliusApiKey}`,
|
|
903
|
-
{
|
|
904
|
-
method: "POST",
|
|
905
|
-
headers: { "Content-Type": "application/json" },
|
|
906
|
-
body: JSON.stringify({
|
|
907
|
-
webhookURL: webhookUrl,
|
|
908
|
-
transactionTypes: ["TRANSFER"],
|
|
909
|
-
accountAddresses: [
|
|
910
|
-
MEMO_PROGRAM_ID.toBase58()
|
|
911
|
-
],
|
|
912
|
-
webhookType: "enhanced"
|
|
913
|
-
})
|
|
914
|
-
}
|
|
915
|
-
);
|
|
916
|
-
const data = await response.json();
|
|
917
|
-
return data.webhookID || null;
|
|
918
|
-
} catch (error) {
|
|
919
|
-
console.error("Failed to setup Helius webhook:", error);
|
|
920
|
-
return null;
|
|
921
|
-
}
|
|
423
|
+
extractMemo(tx) {
|
|
424
|
+
const ix = tx.transaction.message.instructions.find(
|
|
425
|
+
(i) => i.programId.equals(ADELOS_CONFIG.MEMO_PROGRAM_ID)
|
|
426
|
+
);
|
|
427
|
+
return ix?.parsed || null;
|
|
922
428
|
}
|
|
923
429
|
};
|
|
924
430
|
function createIndexer(config) {
|
|
925
|
-
return AdelosIndexer
|
|
431
|
+
return new AdelosIndexer(config);
|
|
926
432
|
}
|
|
927
433
|
|
|
928
434
|
// src/index.ts
|
|
929
435
|
var AdelosSDK = class {
|
|
930
436
|
constructor(options = {}) {
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
this.
|
|
934
|
-
this.programId = PROGRAM_IDS[this.cluster];
|
|
935
|
-
this.heliusApiKey = options.heliusApiKey;
|
|
437
|
+
const rpcUrl = options.rpcUrl ?? ADELOS_CONFIG.RPC_URL;
|
|
438
|
+
this.connection = new Connection2(rpcUrl, "confirmed");
|
|
439
|
+
this.programId = ADELOS_CONFIG.PROGRAM_ID;
|
|
936
440
|
}
|
|
937
|
-
|
|
938
|
-
* Derives the registry PDA for an owner
|
|
939
|
-
*/
|
|
441
|
+
// --- Registry Operations ---
|
|
940
442
|
deriveRegistryAddress(owner) {
|
|
941
443
|
return deriveRegistryPda(owner, this.programId);
|
|
942
444
|
}
|
|
943
|
-
/**
|
|
944
|
-
* Fetches a registry account by owner
|
|
945
|
-
*/
|
|
946
445
|
async getRegistry(owner) {
|
|
947
446
|
const [address] = this.deriveRegistryAddress(owner);
|
|
948
447
|
const accountInfo = await this.connection.getAccountInfo(address);
|
|
949
448
|
if (!accountInfo) {
|
|
950
|
-
return {
|
|
951
|
-
address,
|
|
952
|
-
exists: false,
|
|
953
|
-
account: null
|
|
954
|
-
};
|
|
449
|
+
return { address, exists: false, account: null };
|
|
955
450
|
}
|
|
956
451
|
const data = accountInfo.data.slice(8);
|
|
957
452
|
const account = {
|
|
958
|
-
owner: new
|
|
453
|
+
owner: new PublicKey4(data.slice(0, 32)),
|
|
959
454
|
metaPubkey: new Uint8Array(data.slice(32, 64)),
|
|
960
455
|
bump: data[64]
|
|
961
456
|
};
|
|
962
457
|
return { address, exists: true, account };
|
|
963
458
|
}
|
|
964
|
-
/**
|
|
965
|
-
* Gets the meta pubkey for an owner
|
|
966
|
-
* @returns The meta pubkey as Uint8Array, or null if not registered
|
|
967
|
-
*/
|
|
968
459
|
async getMetaPubkey(owner) {
|
|
969
460
|
const registry = await this.getRegistry(owner);
|
|
970
461
|
return registry.exists ? registry.account.metaPubkey : null;
|
|
971
462
|
}
|
|
972
|
-
/**
|
|
973
|
-
* Gets the meta pubkey as hex string
|
|
974
|
-
*/
|
|
975
|
-
async getMetaPubkeyHex(owner) {
|
|
976
|
-
const metaPubkey = await this.getMetaPubkey(owner);
|
|
977
|
-
return metaPubkey ? bytesToHex(metaPubkey) : null;
|
|
978
|
-
}
|
|
979
|
-
/**
|
|
980
|
-
* Checks if an owner has a registered identity
|
|
981
|
-
*/
|
|
982
463
|
async isRegistered(owner) {
|
|
983
464
|
const registry = await this.getRegistry(owner);
|
|
984
465
|
return registry.exists;
|
|
985
466
|
}
|
|
986
|
-
|
|
987
|
-
* Creates a register identity instruction
|
|
988
|
-
*/
|
|
467
|
+
// --- Instruction Builders ---
|
|
989
468
|
createRegisterInstruction(owner, metaPubkey) {
|
|
990
469
|
if (!isValidMetaPubkey(metaPubkey)) {
|
|
991
470
|
throw new Error("Invalid meta pubkey: must be 32 bytes and not all zeros");
|
|
@@ -995,7 +474,7 @@ var AdelosSDK = class {
|
|
|
995
474
|
Buffer.from(getDiscriminator("register_identity")),
|
|
996
475
|
Buffer.from(metaPubkey)
|
|
997
476
|
]);
|
|
998
|
-
return new
|
|
477
|
+
return new TransactionInstruction({
|
|
999
478
|
keys: [
|
|
1000
479
|
{ pubkey: owner, isSigner: true, isWritable: true },
|
|
1001
480
|
{ pubkey: registryPda, isSigner: false, isWritable: true },
|
|
@@ -1005,9 +484,6 @@ var AdelosSDK = class {
|
|
|
1005
484
|
data
|
|
1006
485
|
});
|
|
1007
486
|
}
|
|
1008
|
-
/**
|
|
1009
|
-
* Creates an update identity instruction
|
|
1010
|
-
*/
|
|
1011
487
|
createUpdateInstruction(owner, newMetaPubkey) {
|
|
1012
488
|
if (!isValidMetaPubkey(newMetaPubkey)) {
|
|
1013
489
|
throw new Error("Invalid meta pubkey: must be 32 bytes and not all zeros");
|
|
@@ -1017,22 +493,20 @@ var AdelosSDK = class {
|
|
|
1017
493
|
Buffer.from(getDiscriminator("update_identity")),
|
|
1018
494
|
Buffer.from(newMetaPubkey)
|
|
1019
495
|
]);
|
|
1020
|
-
return new
|
|
496
|
+
return new TransactionInstruction({
|
|
1021
497
|
keys: [
|
|
1022
|
-
{ pubkey: owner, isSigner: true, isWritable:
|
|
1023
|
-
{ pubkey: registryPda, isSigner: false, isWritable: true }
|
|
498
|
+
{ pubkey: owner, isSigner: true, isWritable: true },
|
|
499
|
+
{ pubkey: registryPda, isSigner: false, isWritable: true },
|
|
500
|
+
{ pubkey: SystemProgram.programId, isSigner: false, isWritable: false }
|
|
1024
501
|
],
|
|
1025
502
|
programId: this.programId,
|
|
1026
503
|
data
|
|
1027
504
|
});
|
|
1028
505
|
}
|
|
1029
|
-
/**
|
|
1030
|
-
* Creates a close registry instruction
|
|
1031
|
-
*/
|
|
1032
506
|
createCloseInstruction(owner) {
|
|
1033
507
|
const [registryPda] = this.deriveRegistryAddress(owner);
|
|
1034
508
|
const data = Buffer.from(getDiscriminator("close_registry"));
|
|
1035
|
-
return new
|
|
509
|
+
return new TransactionInstruction({
|
|
1036
510
|
keys: [
|
|
1037
511
|
{ pubkey: owner, isSigner: true, isWritable: true },
|
|
1038
512
|
{ pubkey: registryPda, isSigner: false, isWritable: true }
|
|
@@ -1041,116 +515,56 @@ var AdelosSDK = class {
|
|
|
1041
515
|
data
|
|
1042
516
|
});
|
|
1043
517
|
}
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
*/
|
|
1047
|
-
async createRegisterTransaction(owner, metaPubkey) {
|
|
1048
|
-
const instruction = this.createRegisterInstruction(owner, metaPubkey);
|
|
1049
|
-
const transaction = new Transaction2().add(instruction);
|
|
1050
|
-
transaction.recentBlockhash = (await this.connection.getLatestBlockhash()).blockhash;
|
|
1051
|
-
transaction.feePayer = owner;
|
|
1052
|
-
return transaction;
|
|
1053
|
-
}
|
|
1054
|
-
/**
|
|
1055
|
-
* Creates a register transaction (unsigned) - Versioned format (v0)
|
|
1056
|
-
* Recommended for modern Solana applications
|
|
1057
|
-
*/
|
|
1058
|
-
async createRegisterTransactionV0(owner, metaPubkey) {
|
|
1059
|
-
const instruction = this.createRegisterInstruction(owner, metaPubkey);
|
|
1060
|
-
const { blockhash } = await this.connection.getLatestBlockhash();
|
|
1061
|
-
const messageV0 = new TransactionMessage({
|
|
1062
|
-
payerKey: owner,
|
|
1063
|
-
recentBlockhash: blockhash,
|
|
1064
|
-
instructions: [instruction]
|
|
1065
|
-
}).compileToV0Message();
|
|
1066
|
-
return new VersionedTransaction(messageV0);
|
|
1067
|
-
}
|
|
1068
|
-
/**
|
|
1069
|
-
* Creates an update transaction (unsigned) - Legacy format
|
|
1070
|
-
*/
|
|
1071
|
-
async createUpdateTransaction(owner, newMetaPubkey) {
|
|
1072
|
-
const instruction = this.createUpdateInstruction(owner, newMetaPubkey);
|
|
1073
|
-
const transaction = new Transaction2().add(instruction);
|
|
1074
|
-
transaction.recentBlockhash = (await this.connection.getLatestBlockhash()).blockhash;
|
|
1075
|
-
transaction.feePayer = owner;
|
|
1076
|
-
return transaction;
|
|
1077
|
-
}
|
|
1078
|
-
/**
|
|
1079
|
-
* Creates an update transaction (unsigned) - Versioned format (v0)
|
|
1080
|
-
*/
|
|
1081
|
-
async createUpdateTransactionV0(owner, newMetaPubkey) {
|
|
1082
|
-
const instruction = this.createUpdateInstruction(owner, newMetaPubkey);
|
|
518
|
+
// --- Transaction Builders ---
|
|
519
|
+
async buildTransaction(payer, instructions, version = "v0") {
|
|
1083
520
|
const { blockhash } = await this.connection.getLatestBlockhash();
|
|
1084
|
-
|
|
1085
|
-
|
|
521
|
+
if (version === "legacy") {
|
|
522
|
+
const tx = new Transaction().add(...instructions);
|
|
523
|
+
tx.recentBlockhash = blockhash;
|
|
524
|
+
tx.feePayer = payer;
|
|
525
|
+
return tx;
|
|
526
|
+
}
|
|
527
|
+
const message = new TransactionMessage({
|
|
528
|
+
payerKey: payer,
|
|
1086
529
|
recentBlockhash: blockhash,
|
|
1087
|
-
instructions
|
|
530
|
+
instructions
|
|
1088
531
|
}).compileToV0Message();
|
|
1089
|
-
return new VersionedTransaction(
|
|
532
|
+
return new VersionedTransaction(message);
|
|
1090
533
|
}
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
async createCloseTransaction(owner) {
|
|
1095
|
-
const instruction = this.createCloseInstruction(owner);
|
|
1096
|
-
const transaction = new Transaction2().add(instruction);
|
|
1097
|
-
transaction.recentBlockhash = (await this.connection.getLatestBlockhash()).blockhash;
|
|
1098
|
-
transaction.feePayer = owner;
|
|
1099
|
-
return transaction;
|
|
534
|
+
async createRegisterTransaction(owner, metaPubkey) {
|
|
535
|
+
const ix = this.createRegisterInstruction(owner, metaPubkey);
|
|
536
|
+
return this.buildTransaction(owner, [ix], "legacy");
|
|
1100
537
|
}
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
async createCloseTransactionV0(owner) {
|
|
1105
|
-
const instruction = this.createCloseInstruction(owner);
|
|
1106
|
-
const { blockhash } = await this.connection.getLatestBlockhash();
|
|
1107
|
-
const messageV0 = new TransactionMessage({
|
|
1108
|
-
payerKey: owner,
|
|
1109
|
-
recentBlockhash: blockhash,
|
|
1110
|
-
instructions: [instruction]
|
|
1111
|
-
}).compileToV0Message();
|
|
1112
|
-
return new VersionedTransaction(messageV0);
|
|
538
|
+
async createRegisterTransactionV0(owner, metaPubkey) {
|
|
539
|
+
const ix = this.createRegisterInstruction(owner, metaPubkey);
|
|
540
|
+
return this.buildTransaction(owner, [ix], "v0");
|
|
1113
541
|
}
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
const signature = await this.connection.sendRawTransaction(
|
|
1119
|
-
signedTransaction.serialize()
|
|
1120
|
-
);
|
|
1121
|
-
await this.connection.confirmTransaction(signature, "confirmed");
|
|
1122
|
-
return signature;
|
|
542
|
+
async sendAndConfirm(signedTx) {
|
|
543
|
+
const sig = await this.connection.sendRawTransaction(signedTx.serialize());
|
|
544
|
+
await this.connection.confirmTransaction(sig, "confirmed");
|
|
545
|
+
return sig;
|
|
1123
546
|
}
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
const signature = await this.connection.sendRawTransaction(
|
|
1129
|
-
signedTransaction.serialize()
|
|
1130
|
-
);
|
|
1131
|
-
await this.connection.confirmTransaction(signature, "confirmed");
|
|
1132
|
-
return signature;
|
|
547
|
+
async sendAndConfirmV0(signedTx) {
|
|
548
|
+
const sig = await this.connection.sendRawTransaction(signedTx.serialize());
|
|
549
|
+
await this.connection.confirmTransaction(sig, "confirmed");
|
|
550
|
+
return sig;
|
|
1133
551
|
}
|
|
1134
552
|
};
|
|
1135
553
|
export {
|
|
554
|
+
ADELOS_CONFIG,
|
|
1136
555
|
AdelosIndexer,
|
|
1137
556
|
AdelosSDK,
|
|
1138
557
|
IDL,
|
|
1139
|
-
LIGHT_PROGRAM_IDS,
|
|
1140
|
-
LightClient,
|
|
1141
558
|
MEMO_PREFIX,
|
|
1142
559
|
MEMO_PROGRAM_ID,
|
|
1143
560
|
PROGRAM_ID,
|
|
1144
|
-
PROGRAM_IDS,
|
|
1145
|
-
REGISTRY_ACCOUNT_SIZE,
|
|
1146
561
|
REGISTRY_SEED,
|
|
1147
|
-
|
|
562
|
+
RPC_URL,
|
|
1148
563
|
STEALTH_DOMAIN,
|
|
1149
564
|
bytesToHex,
|
|
1150
565
|
computeSharedSecret,
|
|
1151
566
|
computeSharedSecretAsRecipient,
|
|
1152
567
|
createIndexer,
|
|
1153
|
-
createLightClient,
|
|
1154
568
|
deriveRegistryPda,
|
|
1155
569
|
deriveStealthPubkey,
|
|
1156
570
|
generateEphemeralKeypair,
|
|
@@ -1158,7 +572,6 @@ export {
|
|
|
1158
572
|
generateStealthMemo,
|
|
1159
573
|
getDiscriminator,
|
|
1160
574
|
hexToBytes,
|
|
1161
|
-
isStealthTransactionForMe,
|
|
1162
575
|
isValidMetaPubkey,
|
|
1163
576
|
parseStealthMemo,
|
|
1164
577
|
recoverStealthSecretKey
|