@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.mjs
CHANGED
|
@@ -1,25 +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
|
+
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
|
|
13
|
-
"7T1UxHJ6psKiQheKZXxANu6mhgsmgaX55eNKZZL5u4Rp"
|
|
14
|
-
)
|
|
15
|
-
|
|
16
|
-
|
|
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: "
|
|
65
|
-
discriminator: [
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
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
|
-
|
|
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: "
|
|
75
|
-
discriminator: [
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
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
|
|
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: "
|
|
84
|
-
discriminator: [
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
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
|
-
|
|
263
|
+
"errors": [
|
|
264
|
+
{
|
|
265
|
+
"code": 6e3,
|
|
266
|
+
"name": "InvalidMetaPubkey",
|
|
267
|
+
"msg": "Invalid meta_pubkey"
|
|
268
|
+
},
|
|
93
269
|
{
|
|
94
|
-
|
|
95
|
-
|
|
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
|
-
{
|
|
105
|
-
|
|
106
|
-
|
|
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 =
|
|
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
|
-
|
|
128
|
-
return { secretKey, publicKey };
|
|
316
|
+
return { secretKey, publicKey: ed.getPublicKey(secretKey) };
|
|
129
317
|
}
|
|
130
|
-
|
|
131
|
-
const point = ed.ExtendedPoint.fromHex(
|
|
132
|
-
const scalar = ed.etc.mod(
|
|
133
|
-
|
|
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
|
|
141
|
-
const
|
|
142
|
-
|
|
143
|
-
);
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
);
|
|
148
|
-
const
|
|
149
|
-
const metaPoint = ed.ExtendedPoint.fromHex(
|
|
150
|
-
const stealthPoint = metaPoint.add(
|
|
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
|
|
155
|
-
|
|
156
|
-
);
|
|
157
|
-
const
|
|
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
|
-
|
|
178
|
-
return `ADLSv1:${pubkeyHex}`;
|
|
346
|
+
return `${ADELOS_CONFIG.MEMO_PREFIX}${bytesToHex(ephemeralPubkey)}`;
|
|
179
347
|
}
|
|
180
348
|
function parseStealthMemo(memo) {
|
|
181
|
-
if (!memo.startsWith(
|
|
182
|
-
const pubkeyHex = memo.slice(
|
|
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
|
-
|
|
358
|
+
function generateStealthAddress(recipientMetaPk) {
|
|
191
359
|
const ephemeralKeypair = generateEphemeralKeypair();
|
|
192
|
-
const sharedSecret =
|
|
193
|
-
|
|
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
|
|
367
|
+
import { Connection } from "@solana/web3.js";
|
|
433
368
|
var AdelosIndexer = class _AdelosIndexer {
|
|
434
369
|
constructor(config) {
|
|
435
|
-
this.
|
|
436
|
-
this.
|
|
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
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
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
|
-
|
|
493
|
-
const
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
);
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
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
|
-
|
|
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
|
-
|
|
551
|
-
|
|
552
|
-
|
|
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
|
|
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
|
-
|
|
676
|
-
|
|
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
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
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
|
|
430
|
+
return new AdelosIndexer(config);
|
|
722
431
|
}
|
|
723
432
|
|
|
724
433
|
// src/index.ts
|
|
725
434
|
var AdelosSDK = class {
|
|
726
435
|
constructor(options = {}) {
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
this.
|
|
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
|
|
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
|
|
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
|
|
495
|
+
return new TransactionInstruction({
|
|
816
496
|
keys: [
|
|
817
|
-
{ pubkey: owner, isSigner: true, isWritable:
|
|
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
|
|
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
|
-
|
|
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
|
|
844
|
-
|
|
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
|
-
|
|
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
|
-
|
|
861
|
-
|
|
862
|
-
|
|
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
|
-
|
|
871
|
-
|
|
872
|
-
|
|
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
|
-
|
|
885
|
-
|
|
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
|