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