@adelos/sdk 0.1.1 → 0.1.3

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.mjs CHANGED
@@ -1,25 +1,36 @@
1
1
  // src/index.ts
2
2
  import {
3
- Connection as Connection3,
4
- PublicKey as PublicKey5,
3
+ Connection as Connection2,
4
+ PublicKey as PublicKey4,
5
5
  SystemProgram,
6
- Transaction as Transaction2,
7
- TransactionInstruction as TransactionInstruction2
6
+ Transaction,
7
+ TransactionInstruction,
8
+ TransactionMessage,
9
+ VersionedTransaction
8
10
  } from "@solana/web3.js";
9
11
 
10
12
  // src/constants.ts
11
- import { PublicKey } from "@solana/web3.js";
12
- var PROGRAM_ID = new PublicKey(
13
- "7T1UxHJ6psKiQheKZXxANu6mhgsmgaX55eNKZZL5u4Rp"
14
- );
15
- var REGISTRY_SEED = "registry";
16
- var REGISTRY_ACCOUNT_SIZE = 8 + 32 + 32 + 1;
13
+ import { PublicKey, clusterApiUrl } from "@solana/web3.js";
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"
21
+ };
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;
17
28
 
18
29
  // src/utils.ts
19
30
  import { PublicKey as PublicKey2 } from "@solana/web3.js";
20
- function deriveRegistryPda(owner, programId = PROGRAM_ID) {
31
+ function deriveRegistryPda(owner, programId = ADELOS_CONFIG.PROGRAM_ID) {
21
32
  return PublicKey2.findProgramAddressSync(
22
- [Buffer.from(REGISTRY_SEED), owner.toBuffer()],
33
+ [Buffer.from(ADELOS_CONFIG.REGISTRY_SEED), owner.toBuffer()],
23
34
  programId
24
35
  );
25
36
  }
@@ -53,133 +64,290 @@ function getDiscriminator(instructionName) {
53
64
 
54
65
  // src/idl.ts
55
66
  var IDL = {
56
- address: "7T1UxHJ6psKiQheKZXxANu6mhgsmgaX55eNKZZL5u4Rp",
57
- metadata: {
58
- name: "adelos_registry",
59
- version: "0.1.0",
60
- spec: "0.1.0"
67
+ "address": "7T1UxHJ6psKiQheKZXxANu6mhgsmgaX55eNKZZL5u4Rp",
68
+ "metadata": {
69
+ "name": "adelos_registry",
70
+ "version": "0.1.0",
71
+ "spec": "0.1.0",
72
+ "description": "Privacy Registry for Adelos Protocol"
61
73
  },
62
- instructions: [
74
+ "instructions": [
63
75
  {
64
- name: "register_identity",
65
- discriminator: [164, 118, 227, 177, 47, 176, 187, 248],
66
- accounts: [
67
- { name: "owner", writable: true, signer: true },
68
- { name: "registry", writable: true, pda: { seeds: [{ kind: "const", value: [114, 101, 103, 105, 115, 116, 114, 121] }, { kind: "account", path: "owner" }] } },
69
- { name: "system_program", address: "11111111111111111111111111111111" }
76
+ "name": "close_registry",
77
+ "discriminator": [
78
+ 76,
79
+ 32,
80
+ 154,
81
+ 180,
82
+ 51,
83
+ 159,
84
+ 218,
85
+ 102
70
86
  ],
71
- args: [{ name: "meta_pubkey", type: { array: ["u8", 32] } }]
87
+ "accounts": [
88
+ {
89
+ "name": "owner",
90
+ "writable": true,
91
+ "signer": true,
92
+ "relations": [
93
+ "registry"
94
+ ]
95
+ },
96
+ {
97
+ "name": "registry",
98
+ "writable": true,
99
+ "pda": {
100
+ "seeds": [
101
+ {
102
+ "kind": "const",
103
+ "value": [
104
+ 114,
105
+ 101,
106
+ 103,
107
+ 105,
108
+ 115,
109
+ 116,
110
+ 114,
111
+ 121
112
+ ]
113
+ },
114
+ {
115
+ "kind": "account",
116
+ "path": "owner"
117
+ }
118
+ ]
119
+ }
120
+ }
121
+ ],
122
+ "args": []
72
123
  },
73
124
  {
74
- name: "update_identity",
75
- discriminator: [130, 54, 88, 104, 222, 124, 238, 252],
76
- accounts: [
77
- { name: "owner", signer: true },
78
- { name: "registry", writable: true }
125
+ "name": "register_identity",
126
+ "discriminator": [
127
+ 164,
128
+ 118,
129
+ 227,
130
+ 177,
131
+ 47,
132
+ 176,
133
+ 187,
134
+ 248
135
+ ],
136
+ "accounts": [
137
+ {
138
+ "name": "owner",
139
+ "writable": true,
140
+ "signer": true
141
+ },
142
+ {
143
+ "name": "registry",
144
+ "writable": true,
145
+ "pda": {
146
+ "seeds": [
147
+ {
148
+ "kind": "const",
149
+ "value": [
150
+ 114,
151
+ 101,
152
+ 103,
153
+ 105,
154
+ 115,
155
+ 116,
156
+ 114,
157
+ 121
158
+ ]
159
+ },
160
+ {
161
+ "kind": "account",
162
+ "path": "owner"
163
+ }
164
+ ]
165
+ }
166
+ },
167
+ {
168
+ "name": "system_program",
169
+ "address": "11111111111111111111111111111111"
170
+ }
79
171
  ],
80
- args: [{ name: "new_meta_pubkey", type: { array: ["u8", 32] } }]
172
+ "args": [
173
+ {
174
+ "name": "meta_pubkey",
175
+ "type": {
176
+ "array": [
177
+ "u8",
178
+ 32
179
+ ]
180
+ }
181
+ }
182
+ ]
81
183
  },
82
184
  {
83
- name: "close_registry",
84
- discriminator: [76, 32, 154, 180, 51, 159, 218, 102],
85
- accounts: [
86
- { name: "owner", writable: true, signer: true },
87
- { name: "registry", writable: true }
185
+ "name": "update_identity",
186
+ "discriminator": [
187
+ 130,
188
+ 54,
189
+ 88,
190
+ 104,
191
+ 222,
192
+ 124,
193
+ 238,
194
+ 252
195
+ ],
196
+ "accounts": [
197
+ {
198
+ "name": "owner",
199
+ "writable": true,
200
+ "signer": true,
201
+ "relations": [
202
+ "registry"
203
+ ]
204
+ },
205
+ {
206
+ "name": "registry",
207
+ "writable": true,
208
+ "pda": {
209
+ "seeds": [
210
+ {
211
+ "kind": "const",
212
+ "value": [
213
+ 114,
214
+ 101,
215
+ 103,
216
+ 105,
217
+ 115,
218
+ 116,
219
+ 114,
220
+ 121
221
+ ]
222
+ },
223
+ {
224
+ "kind": "account",
225
+ "path": "owner"
226
+ }
227
+ ]
228
+ }
229
+ },
230
+ {
231
+ "name": "system_program",
232
+ "address": "11111111111111111111111111111111"
233
+ }
88
234
  ],
89
- args: []
235
+ "args": [
236
+ {
237
+ "name": "new_meta_pubkey",
238
+ "type": {
239
+ "array": [
240
+ "u8",
241
+ 32
242
+ ]
243
+ }
244
+ }
245
+ ]
246
+ }
247
+ ],
248
+ "accounts": [
249
+ {
250
+ "name": "RegistryAccount",
251
+ "discriminator": [
252
+ 113,
253
+ 93,
254
+ 106,
255
+ 201,
256
+ 100,
257
+ 166,
258
+ 146,
259
+ 98
260
+ ]
90
261
  }
91
262
  ],
92
- accounts: [
263
+ "errors": [
264
+ {
265
+ "code": 6e3,
266
+ "name": "InvalidMetaPubkey",
267
+ "msg": "Invalid meta_pubkey"
268
+ },
93
269
  {
94
- name: "RegistryAccount",
95
- discriminator: [113, 93, 106, 201, 100, 166, 146, 98]
270
+ "code": 6001,
271
+ "name": "Unauthorized",
272
+ "msg": "Unauthorized"
96
273
  }
97
274
  ],
98
- types: [
275
+ "types": [
99
276
  {
100
- name: "RegistryAccount",
101
- type: {
102
- kind: "struct",
103
- fields: [
104
- { name: "owner", type: "pubkey" },
105
- { name: "meta_pubkey", type: { array: ["u8", 32] } },
106
- { name: "bump", type: "u8" }
277
+ "name": "RegistryAccount",
278
+ "type": {
279
+ "kind": "struct",
280
+ "fields": [
281
+ {
282
+ "name": "owner",
283
+ "type": "pubkey"
284
+ },
285
+ {
286
+ "name": "meta_pubkey",
287
+ "type": {
288
+ "array": [
289
+ "u8",
290
+ 32
291
+ ]
292
+ }
293
+ },
294
+ {
295
+ "name": "bump",
296
+ "type": "u8"
297
+ }
107
298
  ]
108
299
  }
109
300
  }
110
- ],
111
- errors: [
112
- { code: 6e3, name: "InvalidMetaPubkey", msg: "Invalid meta_pubkey" },
113
- { code: 6001, name: "Unauthorized", msg: "Unauthorized" }
114
301
  ]
115
302
  };
116
303
 
117
304
  // src/crypto.ts
118
305
  import { sha256 } from "@noble/hashes/sha256";
306
+ import { sha512 } from "@noble/hashes/sha512";
119
307
  import * as ed from "@noble/ed25519";
120
308
  ed.etc.sha512Sync = (...m) => {
121
- const h = sha256.create();
309
+ const h = sha512.create();
122
310
  m.forEach((msg) => h.update(msg));
123
311
  return h.digest();
124
312
  };
313
+ var encoder = new TextEncoder();
125
314
  function generateEphemeralKeypair() {
126
315
  const secretKey = ed.utils.randomPrivateKey();
127
- const publicKey = ed.getPublicKey(secretKey);
128
- return { secretKey, publicKey };
316
+ return { secretKey, publicKey: ed.getPublicKey(secretKey) };
129
317
  }
130
- async function computeSharedSecret(ephemeralSk, recipientMetaPubkey) {
131
- const point = ed.ExtendedPoint.fromHex(recipientMetaPubkey);
132
- const scalar = ed.etc.mod(
133
- BigInt("0x" + bytesToHex(ephemeralSk)),
134
- ed.CURVE.n
135
- );
136
- const sharedPoint = point.multiply(scalar);
137
- const sharedBytes = sharedPoint.toRawBytes();
138
- 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());
139
322
  }
140
- function deriveStealthPubkey(metaPubkey, sharedSecret) {
141
- const scalarBytes = sha256(
142
- new Uint8Array([...sharedSecret, ...Buffer.from("adelos:stealth")])
143
- );
144
- const scalar = ed.etc.mod(
145
- BigInt("0x" + bytesToHex(scalarBytes)),
146
- ed.CURVE.n
147
- );
148
- const scalarTimesG = ed.ExtendedPoint.BASE.multiply(scalar);
149
- const metaPoint = ed.ExtendedPoint.fromHex(metaPubkey);
150
- const stealthPoint = metaPoint.add(scalarTimesG);
323
+ function computeSharedSecretAsRecipient(metaSk, ephemeralPk) {
324
+ const point = ed.ExtendedPoint.fromHex(bytesToHex(ephemeralPk));
325
+ const scalar = ed.etc.mod(BigInt("0x" + bytesToHex(metaSk)), ed.CURVE.n);
326
+ return sha256(point.multiply(scalar).toRawBytes());
327
+ }
328
+ function deriveStealthPubkey(metaPk, sharedSecret) {
329
+ const domain = encoder.encode(ADELOS_CONFIG.STEALTH_DOMAIN);
330
+ const scalarBytes = sha256(new Uint8Array([...sharedSecret, ...domain]));
331
+ const scalar = ed.etc.mod(BigInt("0x" + bytesToHex(scalarBytes)), ed.CURVE.n);
332
+ const metaPoint = ed.ExtendedPoint.fromHex(bytesToHex(metaPk));
333
+ const stealthPoint = metaPoint.add(ed.ExtendedPoint.BASE.multiply(scalar));
151
334
  return stealthPoint.toRawBytes();
152
335
  }
153
336
  function recoverStealthSecretKey(metaSk, sharedSecret) {
154
- const scalarBytes = sha256(
155
- new Uint8Array([...sharedSecret, ...Buffer.from("adelos:stealth")])
156
- );
157
- const scalar = ed.etc.mod(
158
- BigInt("0x" + bytesToHex(scalarBytes)),
159
- ed.CURVE.n
160
- );
161
- const metaScalar = ed.etc.mod(
162
- BigInt("0x" + bytesToHex(metaSk)),
163
- ed.CURVE.n
164
- );
337
+ const domain = encoder.encode(ADELOS_CONFIG.STEALTH_DOMAIN);
338
+ const scalarBytes = sha256(new Uint8Array([...sharedSecret, ...domain]));
339
+ const scalar = ed.etc.mod(BigInt("0x" + bytesToHex(scalarBytes)), ed.CURVE.n);
340
+ const metaScalar = ed.etc.mod(BigInt("0x" + bytesToHex(metaSk)), ed.CURVE.n);
165
341
  const stealthScalar = ed.etc.mod(metaScalar + scalar, ed.CURVE.n);
166
342
  const hex = stealthScalar.toString(16).padStart(64, "0");
167
343
  return hexToBytes(hex);
168
344
  }
169
- async function computeSharedSecretAsRecipient(metaSk, ephemeralPubkey) {
170
- const point = ed.ExtendedPoint.fromHex(ephemeralPubkey);
171
- const scalar = ed.etc.mod(BigInt("0x" + bytesToHex(metaSk)), ed.CURVE.n);
172
- const sharedPoint = point.multiply(scalar);
173
- const sharedBytes = sharedPoint.toRawBytes();
174
- return sha256(sharedBytes);
175
- }
176
345
  function generateStealthMemo(ephemeralPubkey) {
177
- const pubkeyHex = bytesToHex(ephemeralPubkey);
178
- return `ADLSv1:${pubkeyHex}`;
346
+ return `${ADELOS_CONFIG.MEMO_PREFIX}${bytesToHex(ephemeralPubkey)}`;
179
347
  }
180
348
  function parseStealthMemo(memo) {
181
- if (!memo.startsWith("ADLSv1:")) return null;
182
- const pubkeyHex = memo.slice(7);
349
+ if (!memo.startsWith(ADELOS_CONFIG.MEMO_PREFIX)) return null;
350
+ const pubkeyHex = memo.slice(ADELOS_CONFIG.MEMO_PREFIX.length);
183
351
  if (pubkeyHex.length !== 64) return null;
184
352
  try {
185
353
  return hexToBytes(pubkeyHex);
@@ -187,600 +355,115 @@ function parseStealthMemo(memo) {
187
355
  return null;
188
356
  }
189
357
  }
190
- async function generateStealthAddress(recipientMetaPubkey) {
358
+ function generateStealthAddress(recipientMetaPk) {
191
359
  const ephemeralKeypair = generateEphemeralKeypair();
192
- const sharedSecret = await computeSharedSecret(
193
- ephemeralKeypair.secretKey,
194
- recipientMetaPubkey
195
- );
196
- const stealthPubkey = deriveStealthPubkey(recipientMetaPubkey, sharedSecret);
360
+ const sharedSecret = computeSharedSecret(ephemeralKeypair.secretKey, recipientMetaPk);
361
+ const stealthPubkey = deriveStealthPubkey(recipientMetaPk, sharedSecret);
197
362
  const memo = generateStealthMemo(ephemeralKeypair.publicKey);
198
- return {
199
- stealthPubkey,
200
- ephemeralKeypair,
201
- sharedSecret,
202
- memo
203
- };
204
- }
205
- async function isStealthTransactionForMe(metaSk, metaPubkey, ephemeralPubkey, targetAddress) {
206
- const sharedSecret = await computeSharedSecretAsRecipient(
207
- metaSk,
208
- ephemeralPubkey
209
- );
210
- const expectedStealth = deriveStealthPubkey(metaPubkey, sharedSecret);
211
- return bytesToHex(expectedStealth) === bytesToHex(targetAddress);
212
- }
213
-
214
- // src/light.ts
215
- import {
216
- Connection,
217
- PublicKey as PublicKey3,
218
- Transaction,
219
- TransactionInstruction
220
- } from "@solana/web3.js";
221
- var LIGHT_PROGRAM_IDS = {
222
- LIGHT_SYSTEM_PROGRAM: new PublicKey3(
223
- "SySTEM1eSU2p4BGQfQpimFEWWSC1XDFeun3Nqzz3rT7"
224
- ),
225
- COMPRESSED_TOKEN_PROGRAM: new PublicKey3(
226
- "cTokenmWW8bLPjZEBAUgYy3zKxQZW6VKi7bqNFEVv3m"
227
- ),
228
- ACCOUNT_COMPRESSION_PROGRAM: new PublicKey3(
229
- "compr6CUsB5m2jS4Y3831ztGSTnDpnKJTKS95d64XVq"
230
- )
231
- };
232
- var LightClient = class _LightClient {
233
- constructor(connection, config) {
234
- this.connection = connection;
235
- this.config = config;
236
- }
237
- /**
238
- * Creates a new Light Protocol client
239
- *
240
- * @param rpcUrl - Solana RPC URL with Light Protocol support
241
- * @returns LightClient instance
242
- */
243
- static create(rpcUrl) {
244
- const connection = new Connection(rpcUrl, "confirmed");
245
- return new _LightClient(connection, { rpcUrl });
246
- }
247
- /**
248
- * Gets compressed SOL balance for an address
249
- *
250
- * @param owner - Owner public key
251
- * @returns Compressed SOL balance in lamports
252
- */
253
- async getCompressedSolBalance(owner) {
254
- try {
255
- const response = await fetch(this.config.rpcUrl, {
256
- method: "POST",
257
- headers: { "Content-Type": "application/json" },
258
- body: JSON.stringify({
259
- jsonrpc: "2.0",
260
- id: 1,
261
- method: "getCompressedAccountsByOwner",
262
- params: [owner.toBase58()]
263
- })
264
- });
265
- const data = await response.json();
266
- if (data.error) {
267
- console.warn("Light RPC error:", data.error);
268
- return BigInt(0);
269
- }
270
- const accounts = data.result?.items || [];
271
- let total = BigInt(0);
272
- for (const acc of accounts) {
273
- total += BigInt(acc.lamports || 0);
274
- }
275
- return total;
276
- } catch (error) {
277
- console.warn("Failed to get compressed balance:", error);
278
- return BigInt(0);
279
- }
280
- }
281
- /**
282
- * Gets compressed token balances for an address
283
- *
284
- * @param owner - Owner public key
285
- * @param mint - Optional token mint to filter
286
- * @returns Array of compressed token balances
287
- */
288
- async getCompressedTokenBalances(owner, mint) {
289
- try {
290
- const response = await fetch(this.config.rpcUrl, {
291
- method: "POST",
292
- headers: { "Content-Type": "application/json" },
293
- body: JSON.stringify({
294
- jsonrpc: "2.0",
295
- id: 1,
296
- method: "getCompressedTokenAccountsByOwner",
297
- params: [owner.toBase58(), mint?.toBase58()]
298
- })
299
- });
300
- const data = await response.json();
301
- if (data.error) {
302
- console.warn("Light RPC error:", data.error);
303
- return [];
304
- }
305
- const balancesByMint = /* @__PURE__ */ new Map();
306
- const accounts = data.result?.items || [];
307
- for (const acc of accounts) {
308
- const mintStr = acc.mint;
309
- if (!balancesByMint.has(mintStr)) {
310
- balancesByMint.set(mintStr, {
311
- mint: new PublicKey3(mintStr),
312
- amount: BigInt(0),
313
- accounts: []
314
- });
315
- }
316
- const balance = balancesByMint.get(mintStr);
317
- balance.amount += BigInt(acc.amount || 0);
318
- balance.accounts.push({
319
- hash: acc.hash,
320
- owner: new PublicKey3(acc.owner),
321
- lamports: acc.lamports || 0,
322
- data: new Uint8Array(acc.data || []),
323
- tree: new PublicKey3(acc.tree),
324
- leafIndex: acc.leafIndex
325
- });
326
- }
327
- return Array.from(balancesByMint.values());
328
- } catch (error) {
329
- console.warn("Failed to get compressed token balances:", error);
330
- return [];
331
- }
332
- }
333
- /**
334
- * Creates a compressed SOL transfer instruction
335
- *
336
- * Note: This creates the instruction data structure.
337
- * Actual ZK proof generation requires Light Protocol SDK.
338
- *
339
- * @param from - Sender public key
340
- * @param to - Recipient public key (can be stealth address)
341
- * @param amount - Amount in lamports
342
- * @returns Transaction instruction (placeholder)
343
- */
344
- createCompressedTransferInstruction(from, to, amount) {
345
- const data = Buffer.alloc(72);
346
- data.write("compressed_transfer", 0);
347
- data.writeBigUInt64LE(amount, 32);
348
- return new TransactionInstruction({
349
- keys: [
350
- { pubkey: from, isSigner: true, isWritable: true },
351
- { pubkey: to, isSigner: false, isWritable: true },
352
- {
353
- pubkey: LIGHT_PROGRAM_IDS.LIGHT_SYSTEM_PROGRAM,
354
- isSigner: false,
355
- isWritable: false
356
- }
357
- ],
358
- programId: LIGHT_PROGRAM_IDS.LIGHT_SYSTEM_PROGRAM,
359
- data
360
- });
361
- }
362
- /**
363
- * Compresses SOL from regular account to compressed account
364
- *
365
- * @param owner - Owner public key
366
- * @param amount - Amount in lamports to compress
367
- * @returns Transaction (unsigned)
368
- */
369
- async createCompressSolTransaction(owner, amount) {
370
- const instruction = this.createCompressedTransferInstruction(
371
- owner,
372
- owner,
373
- // Compress to self
374
- amount
375
- );
376
- const transaction = new Transaction().add(instruction);
377
- transaction.recentBlockhash = (await this.connection.getLatestBlockhash()).blockhash;
378
- transaction.feePayer = owner;
379
- return transaction;
380
- }
381
- /**
382
- * Decompresses SOL from compressed account to regular account
383
- *
384
- * @param owner - Owner public key
385
- * @param amount - Amount in lamports to decompress
386
- * @returns Transaction (unsigned)
387
- */
388
- async createDecompressSolTransaction(owner, amount) {
389
- const instruction = this.createCompressedTransferInstruction(
390
- owner,
391
- owner,
392
- amount
393
- );
394
- const transaction = new Transaction().add(instruction);
395
- transaction.recentBlockhash = (await this.connection.getLatestBlockhash()).blockhash;
396
- transaction.feePayer = owner;
397
- return transaction;
398
- }
399
- /**
400
- * Creates a stealth compressed transfer
401
- * Combines stealth addressing with ZK-compression
402
- *
403
- * @param from - Sender public key
404
- * @param stealthPubkey - Derived stealth address for recipient
405
- * @param amount - Amount in lamports
406
- * @param memo - Stealth memo containing ephemeral pubkey
407
- * @returns Transaction (unsigned)
408
- */
409
- async createStealthCompressedTransfer(from, stealthPubkey, amount, memo) {
410
- const stealthAddress = new PublicKey3(stealthPubkey);
411
- const transferIx = this.createCompressedTransferInstruction(
412
- from,
413
- stealthAddress,
414
- amount
415
- );
416
- const memoIx = new TransactionInstruction({
417
- keys: [],
418
- programId: new PublicKey3("MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr"),
419
- data: Buffer.from(memo, "utf-8")
420
- });
421
- const transaction = new Transaction().add(transferIx).add(memoIx);
422
- transaction.recentBlockhash = (await this.connection.getLatestBlockhash()).blockhash;
423
- transaction.feePayer = from;
424
- return transaction;
425
- }
426
- };
427
- function createLightClient(rpcUrl) {
428
- return LightClient.create(rpcUrl);
363
+ return { stealthPubkey, ephemeralKeypair, sharedSecret, memo };
429
364
  }
430
365
 
431
366
  // src/indexer.ts
432
- import { Connection as Connection2, PublicKey as PublicKey4 } from "@solana/web3.js";
367
+ import { Connection } from "@solana/web3.js";
433
368
  var AdelosIndexer = class _AdelosIndexer {
434
369
  constructor(config) {
435
- this.isScanning = false;
436
- this.scanIntervalId = null;
437
- this.config = config;
438
- this.connection = new Connection2(config.rpcUrl, "confirmed");
370
+ this.connection = new Connection(config.rpcUrl, "confirmed");
371
+ this.heliusApiKey = config.heliusApiKey;
439
372
  }
440
- /**
441
- * Creates an indexer instance
442
- */
443
373
  static create(config) {
444
374
  return new _AdelosIndexer(config);
445
375
  }
446
- /**
447
- * Scans recent transactions for stealth transfers to a recipient
448
- *
449
- * @param metaSk - Recipient's meta secret key
450
- * @param metaPubkey - Recipient's meta public key
451
- * @param limit - Number of transactions to scan
452
- * @returns Array of stealth transactions for this recipient
453
- */
454
- async scanForStealthTransfers(metaSk, metaPubkey, limit = 100) {
455
- const results = [];
456
- try {
457
- const signatures = await this.connection.getSignaturesForAddress(
458
- new PublicKey4(metaPubkey),
459
- { limit }
460
- );
461
- for (const sigInfo of signatures) {
462
- const tx = await this.connection.getParsedTransaction(
463
- sigInfo.signature,
464
- { maxSupportedTransactionVersion: 0 }
465
- );
466
- if (!tx) continue;
467
- const stealthTx = await this.parseStealthTransaction(
468
- tx,
469
- sigInfo.signature,
470
- metaSk,
471
- metaPubkey
472
- );
473
- if (stealthTx) {
474
- results.push(stealthTx);
475
- }
476
- }
477
- } catch (error) {
478
- console.error("Error scanning transactions:", error);
479
- }
480
- return results;
481
- }
482
- /**
483
- * Scans all transactions with ADLSv1 memo prefix
484
- *
485
- * @param metaSk - Recipient's meta secret key
486
- * @param metaPubkey - Recipient's meta public key
487
- * @param since - Scan transactions after this signature
488
- * @returns Array of stealth transactions
489
- */
490
- async scanByMemoPrefix(metaSk, metaPubkey, since) {
376
+ /** Scan for stealth transfers to this recipient */
377
+ async scanForStealthTransfers(metaSk, metaPk, limit = 100) {
378
+ const sigs = await this.connection.getSignaturesForAddress(
379
+ ADELOS_CONFIG.MEMO_PROGRAM_ID,
380
+ { limit }
381
+ );
491
382
  const results = [];
492
- try {
493
- const signatures = await this.connection.getSignaturesForAddress(
494
- new PublicKey4("MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr"),
495
- { limit: 1e3, until: since }
496
- );
497
- for (const sigInfo of signatures) {
498
- const tx = await this.connection.getParsedTransaction(
499
- sigInfo.signature,
500
- { maxSupportedTransactionVersion: 0 }
501
- );
502
- if (!tx) continue;
503
- const memo = this.extractMemo(tx);
504
- if (!memo?.startsWith("ADLSv1:")) continue;
505
- const stealthTx = await this.parseStealthTransaction(
506
- tx,
507
- sigInfo.signature,
508
- metaSk,
509
- metaPubkey
510
- );
511
- if (stealthTx) {
512
- results.push(stealthTx);
513
- }
383
+ for (const s of sigs) {
384
+ const tx = await this.connection.getParsedTransaction(s.signature, {
385
+ maxSupportedTransactionVersion: 0
386
+ });
387
+ if (!tx) continue;
388
+ const memo = this.extractMemo(tx);
389
+ if (!memo?.startsWith(ADELOS_CONFIG.MEMO_PREFIX)) continue;
390
+ const detected = this.attemptDecryption(tx, metaSk, metaPk);
391
+ if (detected) {
392
+ results.push({
393
+ signature: s.signature,
394
+ blockTime: tx.blockTime ?? null,
395
+ stealthAddress: detected.stealthAddress,
396
+ amount: detected.amount
397
+ });
514
398
  }
515
- } catch (error) {
516
- console.error("Error scanning by memo:", error);
517
399
  }
518
400
  return results;
519
401
  }
520
- /**
521
- * Extracts memo from a parsed transaction
522
- */
523
- extractMemo(tx) {
524
- const memoProgram = "MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr";
525
- for (const ix of tx.transaction.message.instructions) {
526
- if ("programId" in ix && ix.programId.toBase58() === memoProgram) {
527
- if ("parsed" in ix && typeof ix.parsed === "string") {
528
- return ix.parsed;
529
- }
530
- }
531
- }
532
- if (tx.meta?.innerInstructions) {
533
- for (const inner of tx.meta.innerInstructions) {
534
- for (const ix of inner.instructions) {
535
- if ("programId" in ix && ix.programId.toBase58() === memoProgram) {
536
- if ("parsed" in ix && typeof ix.parsed === "string") {
537
- return ix.parsed;
538
- }
539
- }
540
- }
541
- }
542
- }
543
- return null;
544
- }
545
- /**
546
- * Parses a transaction to extract stealth transfer info
547
- */
548
- async parseStealthTransaction(tx, signature, metaSk, metaPubkey) {
402
+ /** Trial Decryption: Check if transaction is for this recipient */
403
+ attemptDecryption(tx, metaSk, metaPk) {
549
404
  const memo = this.extractMemo(tx);
550
- if (!memo) return null;
551
- const ephemeralPubkey = parseStealthMemo(memo);
552
- if (!ephemeralPubkey) return null;
405
+ const ephemeralPk = parseStealthMemo(memo || "");
406
+ if (!ephemeralPk) return null;
407
+ const secret = computeSharedSecretAsRecipient(metaSk, ephemeralPk);
408
+ const expectedStealthHex = bytesToHex(deriveStealthPubkey(metaPk, secret));
409
+ const accounts = tx.transaction.message.accountKeys;
410
+ const idx = accounts.findIndex(
411
+ (a) => bytesToHex(a.pubkey.toBytes()) === expectedStealthHex
412
+ );
413
+ if (idx === -1) return null;
553
414
  const preBalances = tx.meta?.preBalances || [];
554
415
  const postBalances = tx.meta?.postBalances || [];
555
- const accounts = tx.transaction.message.accountKeys;
556
- let stealthAddress = null;
557
- let amount = BigInt(0);
558
- let sender = null;
559
- for (let i = 0; i < accounts.length; i++) {
560
- const change = (postBalances[i] || 0) - (preBalances[i] || 0);
561
- if (change > 0) {
562
- stealthAddress = accounts[i].pubkey;
563
- amount = BigInt(change);
564
- } else if (change < 0 && i === 0) {
565
- sender = accounts[i].pubkey;
566
- }
567
- }
568
- if (!stealthAddress) return null;
569
- let isForMe = false;
570
- try {
571
- const sharedSecret = await computeSharedSecretAsRecipient(
572
- metaSk,
573
- ephemeralPubkey
574
- );
575
- const expectedStealth = deriveStealthPubkey(metaPubkey, sharedSecret);
576
- isForMe = bytesToHex(expectedStealth) === bytesToHex(stealthAddress.toBytes());
577
- } catch (error) {
578
- console.warn("Error checking if tx is for me:", error);
579
- }
580
- return {
581
- signature,
582
- blockTime: tx.blockTime ?? null,
583
- slot: tx.slot,
584
- sender,
585
- stealthAddress,
586
- amount,
587
- ephemeralPubkey,
588
- isForMe
589
- };
590
- }
591
- /**
592
- * Starts continuous scanning for stealth transfers
593
- *
594
- * @param metaSk - Recipient's meta secret key
595
- * @param metaPubkey - Recipient's meta public key
596
- */
597
- startScanning(metaSk, metaPubkey) {
598
- if (this.isScanning) return;
599
- this.isScanning = true;
600
- let lastSignature;
601
- const scanInterval = this.config.scanInterval || 1e4;
602
- this.scanIntervalId = setInterval(async () => {
603
- try {
604
- const txs = await this.scanByMemoPrefix(
605
- metaSk,
606
- metaPubkey,
607
- lastSignature
608
- );
609
- for (const tx of txs) {
610
- if (tx.isForMe && this.onTransaction) {
611
- this.onTransaction(tx);
612
- }
613
- }
614
- if (txs.length > 0) {
615
- lastSignature = txs[0].signature;
616
- }
617
- } catch (error) {
618
- console.error("Scan error:", error);
619
- }
620
- }, scanInterval);
621
- }
622
- /**
623
- * Stops continuous scanning
624
- */
625
- stopScanning() {
626
- this.isScanning = false;
627
- if (this.scanIntervalId) {
628
- clearInterval(this.scanIntervalId);
629
- this.scanIntervalId = null;
630
- }
631
- }
632
- /**
633
- * Processes a Helius webhook payload
634
- *
635
- * @param payload - Webhook payload from Helius
636
- * @param metaSk - Recipient's meta secret key
637
- * @param metaPubkey - Recipient's meta public key
638
- * @returns Stealth transaction if detected and for this recipient
639
- */
640
- async processWebhook(payload, metaSk, metaPubkey) {
641
- let memo = null;
642
- const memoProgram = "MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr";
643
- for (const ix of payload.instructions) {
644
- if (ix.programId === memoProgram) {
645
- memo = Buffer.from(ix.data, "base64").toString("utf-8");
646
- break;
647
- }
648
- }
649
- if (!memo?.startsWith("ADLSv1:")) return null;
650
- const ephemeralPubkey = parseStealthMemo(memo);
651
- if (!ephemeralPubkey) return null;
652
- let stealthAddress = null;
653
- let amount = BigInt(0);
654
- for (const acc of payload.accountData) {
655
- if (acc.nativeBalanceChange > 0) {
656
- stealthAddress = new PublicKey4(acc.account);
657
- amount = BigInt(acc.nativeBalanceChange);
658
- break;
659
- }
660
- }
661
- if (!stealthAddress) return null;
662
- let isForMe = false;
663
- try {
664
- const sharedSecret = await computeSharedSecretAsRecipient(
665
- metaSk,
666
- ephemeralPubkey
667
- );
668
- const expectedStealth = deriveStealthPubkey(metaPubkey, sharedSecret);
669
- isForMe = bytesToHex(expectedStealth) === bytesToHex(stealthAddress.toBytes());
670
- } catch (error) {
671
- console.warn("Error checking webhook tx:", error);
672
- }
673
- if (!isForMe) return null;
416
+ const change = (postBalances[idx] || 0) - (preBalances[idx] || 0);
674
417
  return {
675
- signature: payload.signature,
676
- blockTime: payload.timestamp,
677
- slot: payload.slot,
678
- sender: null,
679
- stealthAddress,
680
- amount,
681
- ephemeralPubkey,
682
- isForMe: true
418
+ stealthAddress: accounts[idx].pubkey,
419
+ amount: BigInt(Math.max(change, 0))
683
420
  };
684
421
  }
685
- /**
686
- * Sets up Helius webhook for real-time notifications
687
- *
688
- * @param webhookUrl - Your server's webhook endpoint
689
- * @returns Webhook ID
690
- */
691
- async setupHeliusWebhook(webhookUrl) {
692
- if (!this.config.heliusApiKey) {
693
- console.warn("Helius API key not configured");
694
- return null;
695
- }
696
- try {
697
- const response = await fetch(
698
- `https://api.helius.xyz/v0/webhooks?api-key=${this.config.heliusApiKey}`,
699
- {
700
- method: "POST",
701
- headers: { "Content-Type": "application/json" },
702
- body: JSON.stringify({
703
- webhookURL: webhookUrl,
704
- transactionTypes: ["TRANSFER"],
705
- accountAddresses: [
706
- "MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr"
707
- ],
708
- webhookType: "enhanced"
709
- })
710
- }
711
- );
712
- const data = await response.json();
713
- return data.webhookID || null;
714
- } catch (error) {
715
- console.error("Failed to setup Helius webhook:", error);
716
- return null;
717
- }
422
+ extractMemo(tx) {
423
+ const ix = tx.transaction.message.instructions.find(
424
+ (i) => i.programId.equals(ADELOS_CONFIG.MEMO_PROGRAM_ID)
425
+ );
426
+ return ix?.parsed || null;
718
427
  }
719
428
  };
720
429
  function createIndexer(config) {
721
- return AdelosIndexer.create(config);
430
+ return new AdelosIndexer(config);
722
431
  }
723
432
 
724
433
  // src/index.ts
725
434
  var AdelosSDK = class {
726
435
  constructor(options = {}) {
727
- this.program = null;
728
- const rpcUrl = options.rpcUrl ?? "https://api.devnet.solana.com";
729
- this.connection = new Connection3(rpcUrl, "confirmed");
730
- this.programId = options.programId ?? PROGRAM_ID;
436
+ const rpcUrl = options.rpcUrl ?? ADELOS_CONFIG.RPC_URL;
437
+ this.connection = new Connection2(rpcUrl, "confirmed");
438
+ this.programId = ADELOS_CONFIG.PROGRAM_ID;
731
439
  }
732
- /**
733
- * Derives the registry PDA for an owner
734
- */
440
+ // --- Registry Operations ---
735
441
  deriveRegistryAddress(owner) {
736
442
  return deriveRegistryPda(owner, this.programId);
737
443
  }
738
- /**
739
- * Fetches a registry account by owner
740
- */
741
444
  async getRegistry(owner) {
742
445
  const [address] = this.deriveRegistryAddress(owner);
743
446
  const accountInfo = await this.connection.getAccountInfo(address);
744
447
  if (!accountInfo) {
745
- return {
746
- address,
747
- exists: false,
748
- account: null
749
- };
448
+ return { address, exists: false, account: null };
750
449
  }
751
450
  const data = accountInfo.data.slice(8);
752
451
  const account = {
753
- owner: new PublicKey5(data.slice(0, 32)),
452
+ owner: new PublicKey4(data.slice(0, 32)),
754
453
  metaPubkey: new Uint8Array(data.slice(32, 64)),
755
454
  bump: data[64]
756
455
  };
757
456
  return { address, exists: true, account };
758
457
  }
759
- /**
760
- * Gets the meta pubkey for an owner
761
- * @returns The meta pubkey as Uint8Array, or null if not registered
762
- */
763
458
  async getMetaPubkey(owner) {
764
459
  const registry = await this.getRegistry(owner);
765
460
  return registry.exists ? registry.account.metaPubkey : null;
766
461
  }
767
- /**
768
- * Gets the meta pubkey as hex string
769
- */
770
- async getMetaPubkeyHex(owner) {
771
- const metaPubkey = await this.getMetaPubkey(owner);
772
- return metaPubkey ? bytesToHex(metaPubkey) : null;
773
- }
774
- /**
775
- * Checks if an owner has a registered identity
776
- */
777
462
  async isRegistered(owner) {
778
463
  const registry = await this.getRegistry(owner);
779
464
  return registry.exists;
780
465
  }
781
- /**
782
- * Creates a register identity instruction
783
- */
466
+ // --- Instruction Builders ---
784
467
  createRegisterInstruction(owner, metaPubkey) {
785
468
  if (!isValidMetaPubkey(metaPubkey)) {
786
469
  throw new Error("Invalid meta pubkey: must be 32 bytes and not all zeros");
@@ -790,7 +473,7 @@ var AdelosSDK = class {
790
473
  Buffer.from(getDiscriminator("register_identity")),
791
474
  Buffer.from(metaPubkey)
792
475
  ]);
793
- return new TransactionInstruction2({
476
+ return new TransactionInstruction({
794
477
  keys: [
795
478
  { pubkey: owner, isSigner: true, isWritable: true },
796
479
  { pubkey: registryPda, isSigner: false, isWritable: true },
@@ -800,9 +483,6 @@ var AdelosSDK = class {
800
483
  data
801
484
  });
802
485
  }
803
- /**
804
- * Creates an update identity instruction
805
- */
806
486
  createUpdateInstruction(owner, newMetaPubkey) {
807
487
  if (!isValidMetaPubkey(newMetaPubkey)) {
808
488
  throw new Error("Invalid meta pubkey: must be 32 bytes and not all zeros");
@@ -812,22 +492,20 @@ var AdelosSDK = class {
812
492
  Buffer.from(getDiscriminator("update_identity")),
813
493
  Buffer.from(newMetaPubkey)
814
494
  ]);
815
- return new TransactionInstruction2({
495
+ return new TransactionInstruction({
816
496
  keys: [
817
- { pubkey: owner, isSigner: true, isWritable: false },
818
- { pubkey: registryPda, isSigner: false, isWritable: true }
497
+ { pubkey: owner, isSigner: true, isWritable: true },
498
+ { pubkey: registryPda, isSigner: false, isWritable: true },
499
+ { pubkey: SystemProgram.programId, isSigner: false, isWritable: false }
819
500
  ],
820
501
  programId: this.programId,
821
502
  data
822
503
  });
823
504
  }
824
- /**
825
- * Creates a close registry instruction
826
- */
827
505
  createCloseInstruction(owner) {
828
506
  const [registryPda] = this.deriveRegistryAddress(owner);
829
507
  const data = Buffer.from(getDiscriminator("close_registry"));
830
- return new TransactionInstruction2({
508
+ return new TransactionInstruction({
831
509
  keys: [
832
510
  { pubkey: owner, isSigner: true, isWritable: true },
833
511
  { pubkey: registryPda, isSigner: false, isWritable: true }
@@ -836,61 +514,56 @@ var AdelosSDK = class {
836
514
  data
837
515
  });
838
516
  }
839
- /**
840
- * Creates a register transaction (unsigned)
841
- */
517
+ // --- Transaction Builders ---
518
+ async buildTransaction(payer, instructions, version = "v0") {
519
+ const { blockhash } = await this.connection.getLatestBlockhash();
520
+ if (version === "legacy") {
521
+ const tx = new Transaction().add(...instructions);
522
+ tx.recentBlockhash = blockhash;
523
+ tx.feePayer = payer;
524
+ return tx;
525
+ }
526
+ const message = new TransactionMessage({
527
+ payerKey: payer,
528
+ recentBlockhash: blockhash,
529
+ instructions
530
+ }).compileToV0Message();
531
+ return new VersionedTransaction(message);
532
+ }
842
533
  async createRegisterTransaction(owner, metaPubkey) {
843
- const instruction = this.createRegisterInstruction(owner, metaPubkey);
844
- const transaction = new Transaction2().add(instruction);
845
- transaction.recentBlockhash = (await this.connection.getLatestBlockhash()).blockhash;
846
- transaction.feePayer = owner;
847
- return transaction;
534
+ const ix = this.createRegisterInstruction(owner, metaPubkey);
535
+ return this.buildTransaction(owner, [ix], "legacy");
848
536
  }
849
- /**
850
- * Creates an update transaction (unsigned)
851
- */
852
- async createUpdateTransaction(owner, newMetaPubkey) {
853
- const instruction = this.createUpdateInstruction(owner, newMetaPubkey);
854
- const transaction = new Transaction2().add(instruction);
855
- transaction.recentBlockhash = (await this.connection.getLatestBlockhash()).blockhash;
856
- transaction.feePayer = owner;
857
- return transaction;
537
+ async createRegisterTransactionV0(owner, metaPubkey) {
538
+ const ix = this.createRegisterInstruction(owner, metaPubkey);
539
+ return this.buildTransaction(owner, [ix], "v0");
858
540
  }
859
- /**
860
- * Creates a close transaction (unsigned)
861
- */
862
- async createCloseTransaction(owner) {
863
- const instruction = this.createCloseInstruction(owner);
864
- const transaction = new Transaction2().add(instruction);
865
- transaction.recentBlockhash = (await this.connection.getLatestBlockhash()).blockhash;
866
- transaction.feePayer = owner;
867
- return transaction;
541
+ async sendAndConfirm(signedTx) {
542
+ const sig = await this.connection.sendRawTransaction(signedTx.serialize());
543
+ await this.connection.confirmTransaction(sig, "confirmed");
544
+ return sig;
868
545
  }
869
- /**
870
- * Sends a signed transaction and confirms it
871
- */
872
- async sendAndConfirm(signedTransaction) {
873
- const signature = await this.connection.sendRawTransaction(
874
- signedTransaction.serialize()
875
- );
876
- await this.connection.confirmTransaction(signature, "confirmed");
877
- return signature;
546
+ async sendAndConfirmV0(signedTx) {
547
+ const sig = await this.connection.sendRawTransaction(signedTx.serialize());
548
+ await this.connection.confirmTransaction(sig, "confirmed");
549
+ return sig;
878
550
  }
879
551
  };
880
552
  export {
553
+ ADELOS_CONFIG,
881
554
  AdelosIndexer,
882
555
  AdelosSDK,
883
556
  IDL,
884
- LIGHT_PROGRAM_IDS,
885
- LightClient,
557
+ MEMO_PREFIX,
558
+ MEMO_PROGRAM_ID,
886
559
  PROGRAM_ID,
887
- REGISTRY_ACCOUNT_SIZE,
888
560
  REGISTRY_SEED,
561
+ RPC_URL,
562
+ STEALTH_DOMAIN,
889
563
  bytesToHex,
890
564
  computeSharedSecret,
891
565
  computeSharedSecretAsRecipient,
892
566
  createIndexer,
893
- createLightClient,
894
567
  deriveRegistryPda,
895
568
  deriveStealthPubkey,
896
569
  generateEphemeralKeypair,
@@ -898,7 +571,6 @@ export {
898
571
  generateStealthMemo,
899
572
  getDiscriminator,
900
573
  hexToBytes,
901
- isStealthTransactionForMe,
902
574
  isValidMetaPubkey,
903
575
  parseStealthMemo,
904
576
  recoverStealthSecretKey