@arcium-hq/reader 0.3.0 → 0.5.0
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 +5 -5
- package/build/index.cjs +82 -57
- package/build/index.d.ts +44 -13
- package/build/index.mjs +73 -55
- package/package.json +4 -7
package/README.md
CHANGED
|
@@ -18,12 +18,12 @@ pnpm add @arcium-hq/reader
|
|
|
18
18
|
|
|
19
19
|
```typescript
|
|
20
20
|
import * as anchor from "@coral-xyz/anchor";
|
|
21
|
-
import {
|
|
21
|
+
import { getArciumProgram } from "@arcium-hq/reader";
|
|
22
22
|
|
|
23
23
|
// Setup connection (no wallet required)
|
|
24
24
|
const connection = new anchor.web3.Connection("https://api.mainnet-beta.solana.com");
|
|
25
25
|
const provider = new anchor.AnchorProvider(connection, null, {});
|
|
26
|
-
const arciumProgram =
|
|
26
|
+
const arciumProgram = getArciumProgram(provider);
|
|
27
27
|
```
|
|
28
28
|
|
|
29
29
|
### 2. Query Account Information
|
|
@@ -288,6 +288,6 @@ if (tx) {
|
|
|
288
288
|
|
|
289
289
|
## API Reference
|
|
290
290
|
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
291
|
+
- **[API Reference](https://ts.arcium.com/api)** - Complete API documentation
|
|
292
|
+
- **[Developer Docs](https://docs.arcium.com/developers/js-client-library)** - Guides and tutorials
|
|
293
|
+
- **[Examples](https://github.com/arcium-hq/examples)** - Code examples
|
package/build/index.cjs
CHANGED
|
@@ -22,7 +22,26 @@ function _interopNamespaceDefault(e) {
|
|
|
22
22
|
|
|
23
23
|
var anchor__namespace = /*#__PURE__*/_interopNamespaceDefault(anchor);
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
/**
|
|
26
|
+
* Prefix for program data logs in Solana transaction logs.
|
|
27
|
+
* @constant {string}
|
|
28
|
+
*/
|
|
29
|
+
const PROGRAM_DATA_PREFIX = 'Program data: ';
|
|
30
|
+
/**
|
|
31
|
+
* Prefix for program log messages in Solana transaction logs.
|
|
32
|
+
* @constant {string}
|
|
33
|
+
*/
|
|
34
|
+
const PROGRAM_LOG_PREFIX = 'Program log: ';
|
|
35
|
+
/**
|
|
36
|
+
* Valid Arcium event names for computation lifecycle tracking.
|
|
37
|
+
* @constant {ArciumEventName[]}
|
|
38
|
+
*/
|
|
39
|
+
const ARCIUM_EVENT_NAMES = [
|
|
40
|
+
'QueueComputationEvent',
|
|
41
|
+
'InitComputationEvent',
|
|
42
|
+
'CallbackComputationEvent',
|
|
43
|
+
'FinalizeComputationEvent',
|
|
44
|
+
];
|
|
26
45
|
/**
|
|
27
46
|
* Discriminator for the ArxNode account type. Used to filter and identify ArxNode accounts on-chain.
|
|
28
47
|
*/
|
|
@@ -38,7 +57,7 @@ const MXE_ACC_DISCRIMINATOR = [103, 26, 85, 250, 179, 159, 17, 117];
|
|
|
38
57
|
/**
|
|
39
58
|
* The public key of the deployed Arcium program on Solana.
|
|
40
59
|
*/
|
|
41
|
-
const ARCIUM_PROGRAM_ID = new anchor__namespace.web3.PublicKey(
|
|
60
|
+
const ARCIUM_PROGRAM_ID = new anchor__namespace.web3.PublicKey(client.ARCIUM_ADDR);
|
|
42
61
|
/**
|
|
43
62
|
* Anchor coder for encoding and decoding Arcium program instructions.
|
|
44
63
|
*/
|
|
@@ -46,7 +65,12 @@ new anchor__namespace.BorshInstructionCoder(client.ARCIUM_IDL);
|
|
|
46
65
|
/**
|
|
47
66
|
* Anchor event parser for parsing Arcium program events from transaction logs.
|
|
48
67
|
*/
|
|
49
|
-
|
|
68
|
+
new anchor__namespace.EventParser(ARCIUM_PROGRAM_ID, new anchor__namespace.BorshCoder(client.ARCIUM_IDL));
|
|
69
|
+
/**
|
|
70
|
+
* BorshCoder instance for decoding Arcium events.
|
|
71
|
+
* Used directly instead of accessing EventParser's private coder property.
|
|
72
|
+
*/
|
|
73
|
+
const ARCIUM_BORSH_CODER = new anchor__namespace.BorshCoder(client.ARCIUM_IDL);
|
|
50
74
|
|
|
51
75
|
/**
|
|
52
76
|
* Returns all MXE account addresses.
|
|
@@ -112,40 +136,6 @@ async function getArxNodeAccInfo(arciumProgram, address, commitment) {
|
|
|
112
136
|
async function getCompDefAccInfo(arciumProgram, address, commitment) {
|
|
113
137
|
return arciumProgram.account.computationDefinitionAccount.fetch(address, commitment);
|
|
114
138
|
}
|
|
115
|
-
/**
|
|
116
|
-
* Returns all computation references in the mempool for a given account.
|
|
117
|
-
* Only non-stake computations are included.
|
|
118
|
-
* @param arciumProgram - The Anchor program instance.
|
|
119
|
-
* @param address - The public key of the mempool account.
|
|
120
|
-
* @returns Array of ComputationReference objects.
|
|
121
|
-
*/
|
|
122
|
-
async function getComputationsInMempool(arciumProgram, address) {
|
|
123
|
-
const mempool = await client.getMempoolAccData(arciumProgram.provider, address);
|
|
124
|
-
const startIndex = mempool.inner.computations.startIndex;
|
|
125
|
-
const length = mempool.inner.computations.length;
|
|
126
|
-
const elems = mempool.inner.computations.elems;
|
|
127
|
-
function isValid(validBits, idx) {
|
|
128
|
-
const byte = idx >>> 3;
|
|
129
|
-
const bit = idx & 7;
|
|
130
|
-
if (byte >= validBits.length) {
|
|
131
|
-
// This should never happen, so we'll want to know about it
|
|
132
|
-
throw new Error(`isValid: byte ${byte} >= validBits.length ${validBits.length}`);
|
|
133
|
-
}
|
|
134
|
-
return (validBits[byte] & (1 << bit)) !== 0;
|
|
135
|
-
}
|
|
136
|
-
// Handle circular buffer wraparound
|
|
137
|
-
const refs = [];
|
|
138
|
-
for (let i = 0; i < length; i++) {
|
|
139
|
-
const idx = (startIndex + i) % elems.length;
|
|
140
|
-
// Only save non-stake computations
|
|
141
|
-
if (isValid(mempool.inner.computations.validBits, idx)) {
|
|
142
|
-
refs.push(...elems[idx].entries);
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
return refs
|
|
146
|
-
.flat()
|
|
147
|
-
.filter((ref) => !isNullRef(ref));
|
|
148
|
-
}
|
|
149
139
|
/**
|
|
150
140
|
* Fetches and parses a given Computation account.
|
|
151
141
|
* @param arciumProgram - The Anchor program instance.
|
|
@@ -171,19 +161,7 @@ async function getArciumAccPubkeys(conn, discriminator) {
|
|
|
171
161
|
});
|
|
172
162
|
return accs.map((acc) => acc.pubkey);
|
|
173
163
|
}
|
|
174
|
-
function isNullRef(ref) {
|
|
175
|
-
const bigZero = new anchor__namespace.BN(0);
|
|
176
|
-
return (ref.computationDefinitionOffset === 0
|
|
177
|
-
&& ref.computationOffset === bigZero
|
|
178
|
-
&& ref.priorityFee === bigZero);
|
|
179
|
-
}
|
|
180
164
|
|
|
181
|
-
const ArciumEventNames = [
|
|
182
|
-
'QueueComputationEvent',
|
|
183
|
-
'InitComputationEvent',
|
|
184
|
-
'CallbackComputationEvent',
|
|
185
|
-
'FinalizeComputationEvent',
|
|
186
|
-
];
|
|
187
165
|
/**
|
|
188
166
|
* Subscribes to computation-related events for a given MXE program ID.
|
|
189
167
|
* @param conn - The Solana connection object.
|
|
@@ -227,13 +205,53 @@ function getComputationOffset(tx) {
|
|
|
227
205
|
}
|
|
228
206
|
/**
|
|
229
207
|
* Get the events related to arcium computations from a transaction's logs
|
|
208
|
+
*
|
|
209
|
+
* Note: This implements a direct decode approach instead of using Anchor's EventParser.parseLogs().
|
|
210
|
+
*
|
|
211
|
+
* BREAKING CHANGE IN ANCHOR v0.32.0 (PR #3657, commit 34b6d19):
|
|
212
|
+
* EventParser.parseLogs was hardened to prevent malicious log injection attacks. It now:
|
|
213
|
+
* 1. Requires the first log to match "Program X invoke [1]" (root invocation)
|
|
214
|
+
* 2. Pre-seeds the execution stack with program X from the first log
|
|
215
|
+
* 3. Only parses events when execution.program() === EventParser.programId
|
|
216
|
+
*
|
|
217
|
+
* This breaks our use case:
|
|
218
|
+
* - We subscribe to MXE program logs (line 29) via conn.onLogs(mxeProgramId, ...)
|
|
219
|
+
* - But we need to parse Arcium events emitted during MXE→Arcium CPI calls
|
|
220
|
+
* - When MXE is the root program, execution.program() = MXE_PROGRAM_ID
|
|
221
|
+
* - EventParser expects execution.program() = ARCIUM_PROGRAM_ID
|
|
222
|
+
* - Result: All Arcium events are silently skipped
|
|
223
|
+
*
|
|
224
|
+
* Our discriminator-based approach:
|
|
225
|
+
* - Scans all logs for "Program data:" and "Program log:" prefixes
|
|
226
|
+
* - Uses event discriminators to identify valid Arcium events (no program context check)
|
|
227
|
+
* - Works regardless of which program is root or subscription target
|
|
228
|
+
* - Handles both MXE→Arcium and Arcium→MXE CPI patterns
|
|
229
|
+
*
|
|
230
230
|
* @param logs - The logs to get the events from
|
|
231
231
|
* @returns The events in the logs.
|
|
232
232
|
*/
|
|
233
233
|
function getComputationEventsFromLogs(logs) {
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
234
|
+
const events = [];
|
|
235
|
+
// Scan all event logs and rely on discriminators to identify valid Arcium events.
|
|
236
|
+
// This works for both MXE→Arcium CPI and Arcium→MXE CPI transactions.
|
|
237
|
+
for (const log of logs) {
|
|
238
|
+
if (log.startsWith(PROGRAM_DATA_PREFIX)) {
|
|
239
|
+
const eventData = log.slice(PROGRAM_DATA_PREFIX.length);
|
|
240
|
+
const decoded = ARCIUM_BORSH_CODER.events.decode(eventData);
|
|
241
|
+
if (decoded && ARCIUM_EVENT_NAMES.includes(decoded.name)) {
|
|
242
|
+
events.push(decoded);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
else if (log.startsWith(PROGRAM_LOG_PREFIX)) {
|
|
246
|
+
const eventData = log.slice(PROGRAM_LOG_PREFIX.length);
|
|
247
|
+
const decoded = ARCIUM_BORSH_CODER.events.decode(eventData);
|
|
248
|
+
if (decoded && ARCIUM_EVENT_NAMES.includes(decoded.name)) {
|
|
249
|
+
events.push(decoded);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
// Map to existing return format
|
|
254
|
+
return events.map((e) => {
|
|
237
255
|
const eventData = {
|
|
238
256
|
computationOffset: e.data.computation_offset,
|
|
239
257
|
...e.data,
|
|
@@ -248,9 +266,9 @@ function getComputationEventsFromLogs(logs) {
|
|
|
248
266
|
});
|
|
249
267
|
}
|
|
250
268
|
|
|
251
|
-
Object.defineProperty(exports, "
|
|
269
|
+
Object.defineProperty(exports, "getArciumProgram", {
|
|
252
270
|
enumerable: true,
|
|
253
|
-
get: function () { return client.
|
|
271
|
+
get: function () { return client.getArciumProgram; }
|
|
254
272
|
});
|
|
255
273
|
Object.defineProperty(exports, "getArxNodeAccAddress", {
|
|
256
274
|
enumerable: true,
|
|
@@ -272,10 +290,18 @@ Object.defineProperty(exports, "getComputationAccAddress", {
|
|
|
272
290
|
enumerable: true,
|
|
273
291
|
get: function () { return client.getComputationAccAddress; }
|
|
274
292
|
});
|
|
293
|
+
Object.defineProperty(exports, "getComputationsInMempool", {
|
|
294
|
+
enumerable: true,
|
|
295
|
+
get: function () { return client.getComputationsInMempool; }
|
|
296
|
+
});
|
|
275
297
|
Object.defineProperty(exports, "getExecutingPoolAccAddress", {
|
|
276
298
|
enumerable: true,
|
|
277
299
|
get: function () { return client.getExecutingPoolAccAddress; }
|
|
278
300
|
});
|
|
301
|
+
Object.defineProperty(exports, "getFeePoolAccAddress", {
|
|
302
|
+
enumerable: true,
|
|
303
|
+
get: function () { return client.getFeePoolAccAddress; }
|
|
304
|
+
});
|
|
279
305
|
Object.defineProperty(exports, "getMXEAccAddress", {
|
|
280
306
|
enumerable: true,
|
|
281
307
|
get: function () { return client.getMXEAccAddress; }
|
|
@@ -284,9 +310,9 @@ Object.defineProperty(exports, "getMempoolAccAddress", {
|
|
|
284
310
|
enumerable: true,
|
|
285
311
|
get: function () { return client.getMempoolAccAddress; }
|
|
286
312
|
});
|
|
287
|
-
Object.defineProperty(exports, "
|
|
313
|
+
Object.defineProperty(exports, "getMempoolPriorityFeeStats", {
|
|
288
314
|
enumerable: true,
|
|
289
|
-
get: function () { return client.
|
|
315
|
+
get: function () { return client.getMempoolPriorityFeeStats; }
|
|
290
316
|
});
|
|
291
317
|
exports.getArxNodeAccAddresses = getArxNodeAccAddresses;
|
|
292
318
|
exports.getArxNodeAccInfo = getArxNodeAccInfo;
|
|
@@ -295,7 +321,6 @@ exports.getClusterAccInfo = getClusterAccInfo;
|
|
|
295
321
|
exports.getCompDefAccInfo = getCompDefAccInfo;
|
|
296
322
|
exports.getComputationAccInfo = getComputationAccInfo;
|
|
297
323
|
exports.getComputationOffset = getComputationOffset;
|
|
298
|
-
exports.getComputationsInMempool = getComputationsInMempool;
|
|
299
324
|
exports.getMXEAccAddresses = getMXEAccAddresses;
|
|
300
325
|
exports.getMXEAccInfo = getMXEAccInfo;
|
|
301
326
|
exports.subscribeComputations = subscribeComputations;
|
package/build/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ArciumIdlType } from '@arcium-hq/client';
|
|
2
|
-
export {
|
|
2
|
+
export { getArciumProgram, getArxNodeAccAddress, getClockAccAddress, getClusterAccAddress, getCompDefAccAddress, getComputationAccAddress, getComputationsInMempool, getExecutingPoolAccAddress, getFeePoolAccAddress, getMXEAccAddress, getMempoolAccAddress, getMempoolPriorityFeeStats } from '@arcium-hq/client';
|
|
3
3
|
import * as anchor from '@coral-xyz/anchor';
|
|
4
4
|
|
|
5
5
|
/**
|
|
@@ -7,9 +7,21 @@ import * as anchor from '@coral-xyz/anchor';
|
|
|
7
7
|
* Many types are derived from the Anchor-generated IDL and are used throughout the reader package.
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
+
/**
|
|
11
|
+
* Solana PublicKey type alias for convenience.
|
|
12
|
+
*/
|
|
10
13
|
type PublicKey = anchor.web3.PublicKey;
|
|
14
|
+
/**
|
|
15
|
+
* Solana Connection type alias for convenience.
|
|
16
|
+
*/
|
|
11
17
|
type Connection = anchor.web3.Connection;
|
|
18
|
+
/**
|
|
19
|
+
* Anchor Program type alias with generic IDL support.
|
|
20
|
+
*/
|
|
12
21
|
type Program<T extends anchor.Idl> = anchor.Program<T>;
|
|
22
|
+
/**
|
|
23
|
+
* Arcium IDL types derived from the Arcium program interface.
|
|
24
|
+
*/
|
|
13
25
|
type ArciumTypes = anchor.IdlTypes<ArciumIdlType>;
|
|
14
26
|
/**
|
|
15
27
|
* All events emitted by the Arcium program, keyed by event name.
|
|
@@ -23,15 +35,42 @@ type ArciumEventName = Capitalize<keyof ArciumEvent>;
|
|
|
23
35
|
* Data structure for any Arcium event, as parsed from logs.
|
|
24
36
|
*/
|
|
25
37
|
type ArciumEventData = ArciumEvent[keyof ArciumEvent];
|
|
38
|
+
/**
|
|
39
|
+
* MXE (Multi-party eXecution Environment) account data structure.
|
|
40
|
+
*/
|
|
26
41
|
type MXEAccount = ArciumTypes['mxeAccount'];
|
|
42
|
+
/**
|
|
43
|
+
* Cluster account data structure containing node information.
|
|
44
|
+
*/
|
|
27
45
|
type ClusterAccount = ArciumTypes['cluster'];
|
|
46
|
+
/**
|
|
47
|
+
* ArxNode account data structure for individual computation nodes.
|
|
48
|
+
*/
|
|
28
49
|
type ArxNodeAccount = ArciumTypes['arxNode'];
|
|
50
|
+
/**
|
|
51
|
+
* Computation account data structure tracking computation state.
|
|
52
|
+
*/
|
|
29
53
|
type ComputationAccount = ArciumTypes['computationAccount'];
|
|
54
|
+
/**
|
|
55
|
+
* Reference to a computation in a mempool or executing pool.
|
|
56
|
+
*/
|
|
30
57
|
type ComputationReference = ArciumTypes['computationReference'];
|
|
58
|
+
/**
|
|
59
|
+
* Computation definition account containing circuit configuration.
|
|
60
|
+
*/
|
|
31
61
|
type ComputationDefinitionAccount = ArciumTypes['computationDefinitionAccount'];
|
|
32
|
-
|
|
62
|
+
/**
|
|
63
|
+
* Queue computation instruction type from the Arcium IDL.
|
|
64
|
+
*/
|
|
65
|
+
type QueueComputationIx = ArciumIdlType['instructions']['26'];
|
|
66
|
+
/**
|
|
67
|
+
* Callback computation instruction type from the Arcium IDL.
|
|
68
|
+
*/
|
|
33
69
|
type CallbackComputationIx = ArciumIdlType['instructions']['3'];
|
|
34
|
-
|
|
70
|
+
/**
|
|
71
|
+
* Valid instruction names from the Arcium IDL.
|
|
72
|
+
*/
|
|
73
|
+
type ArciumInstructionName = ArciumIdlType['instructions'][number]['name'];
|
|
35
74
|
/**
|
|
36
75
|
* Status values for a computation, as defined by the Arcium protocol.
|
|
37
76
|
*/
|
|
@@ -87,14 +126,6 @@ declare function getArxNodeAccInfo(arciumProgram: anchor.Program<ArciumIdlType>,
|
|
|
87
126
|
* @returns The ComputationDefinitionAccount object.
|
|
88
127
|
*/
|
|
89
128
|
declare function getCompDefAccInfo(arciumProgram: anchor.Program<ArciumIdlType>, address: PublicKey, commitment?: anchor.web3.Commitment): Promise<ComputationDefinitionAccount>;
|
|
90
|
-
/**
|
|
91
|
-
* Returns all computation references in the mempool for a given account.
|
|
92
|
-
* Only non-stake computations are included.
|
|
93
|
-
* @param arciumProgram - The Anchor program instance.
|
|
94
|
-
* @param address - The public key of the mempool account.
|
|
95
|
-
* @returns Array of ComputationReference objects.
|
|
96
|
-
*/
|
|
97
|
-
declare function getComputationsInMempool(arciumProgram: anchor.Program<ArciumIdlType>, address: PublicKey): Promise<ComputationReference[]>;
|
|
98
129
|
/**
|
|
99
130
|
* Fetches and parses a given Computation account.
|
|
100
131
|
* @param arciumProgram - The Anchor program instance.
|
|
@@ -126,5 +157,5 @@ declare function unsubscribeComputations(conn: Connection, subscriptionId: numbe
|
|
|
126
157
|
*/
|
|
127
158
|
declare function getComputationOffset(tx: anchor.web3.VersionedTransactionResponse): anchor.BN | undefined;
|
|
128
159
|
|
|
129
|
-
export { getArxNodeAccAddresses, getArxNodeAccInfo, getClusterAccAddresses, getClusterAccInfo, getCompDefAccInfo, getComputationAccInfo, getComputationOffset,
|
|
130
|
-
export type { ArciumEvent, ArciumEventData, ArciumEventName, ArciumTypes, ArxNodeAccount, CallbackComputationIx, ClusterAccount, ComputationAccount, ComputationDefinitionAccount, ComputationReference, ComputationStatus, Connection,
|
|
160
|
+
export { getArxNodeAccAddresses, getArxNodeAccInfo, getClusterAccAddresses, getClusterAccInfo, getCompDefAccInfo, getComputationAccInfo, getComputationOffset, getMXEAccAddresses, getMXEAccInfo, subscribeComputations, unsubscribeComputations };
|
|
161
|
+
export type { ArciumEvent, ArciumEventData, ArciumEventName, ArciumInstructionName, ArciumTypes, ArxNodeAccount, CallbackComputationIx, ClusterAccount, ComputationAccount, ComputationDefinitionAccount, ComputationReference, ComputationStatus, Connection, MXEAccount, Program, PublicKey, QueueComputationIx };
|
package/build/index.mjs
CHANGED
|
@@ -1,8 +1,27 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export {
|
|
1
|
+
import { ARCIUM_ADDR, ARCIUM_IDL } from '@arcium-hq/client';
|
|
2
|
+
export { getArciumProgram, getArxNodeAccAddress, getClockAccAddress, getClusterAccAddress, getCompDefAccAddress, getComputationAccAddress, getComputationsInMempool, getExecutingPoolAccAddress, getFeePoolAccAddress, getMXEAccAddress, getMempoolAccAddress, getMempoolPriorityFeeStats } from '@arcium-hq/client';
|
|
3
3
|
import * as anchor from '@coral-xyz/anchor';
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
/**
|
|
6
|
+
* Prefix for program data logs in Solana transaction logs.
|
|
7
|
+
* @constant {string}
|
|
8
|
+
*/
|
|
9
|
+
const PROGRAM_DATA_PREFIX = 'Program data: ';
|
|
10
|
+
/**
|
|
11
|
+
* Prefix for program log messages in Solana transaction logs.
|
|
12
|
+
* @constant {string}
|
|
13
|
+
*/
|
|
14
|
+
const PROGRAM_LOG_PREFIX = 'Program log: ';
|
|
15
|
+
/**
|
|
16
|
+
* Valid Arcium event names for computation lifecycle tracking.
|
|
17
|
+
* @constant {ArciumEventName[]}
|
|
18
|
+
*/
|
|
19
|
+
const ARCIUM_EVENT_NAMES = [
|
|
20
|
+
'QueueComputationEvent',
|
|
21
|
+
'InitComputationEvent',
|
|
22
|
+
'CallbackComputationEvent',
|
|
23
|
+
'FinalizeComputationEvent',
|
|
24
|
+
];
|
|
6
25
|
/**
|
|
7
26
|
* Discriminator for the ArxNode account type. Used to filter and identify ArxNode accounts on-chain.
|
|
8
27
|
*/
|
|
@@ -18,7 +37,7 @@ const MXE_ACC_DISCRIMINATOR = [103, 26, 85, 250, 179, 159, 17, 117];
|
|
|
18
37
|
/**
|
|
19
38
|
* The public key of the deployed Arcium program on Solana.
|
|
20
39
|
*/
|
|
21
|
-
const ARCIUM_PROGRAM_ID = new anchor.web3.PublicKey(
|
|
40
|
+
const ARCIUM_PROGRAM_ID = new anchor.web3.PublicKey(ARCIUM_ADDR);
|
|
22
41
|
/**
|
|
23
42
|
* Anchor coder for encoding and decoding Arcium program instructions.
|
|
24
43
|
*/
|
|
@@ -26,7 +45,12 @@ new anchor.BorshInstructionCoder(ARCIUM_IDL);
|
|
|
26
45
|
/**
|
|
27
46
|
* Anchor event parser for parsing Arcium program events from transaction logs.
|
|
28
47
|
*/
|
|
29
|
-
|
|
48
|
+
new anchor.EventParser(ARCIUM_PROGRAM_ID, new anchor.BorshCoder(ARCIUM_IDL));
|
|
49
|
+
/**
|
|
50
|
+
* BorshCoder instance for decoding Arcium events.
|
|
51
|
+
* Used directly instead of accessing EventParser's private coder property.
|
|
52
|
+
*/
|
|
53
|
+
const ARCIUM_BORSH_CODER = new anchor.BorshCoder(ARCIUM_IDL);
|
|
30
54
|
|
|
31
55
|
/**
|
|
32
56
|
* Returns all MXE account addresses.
|
|
@@ -92,40 +116,6 @@ async function getArxNodeAccInfo(arciumProgram, address, commitment) {
|
|
|
92
116
|
async function getCompDefAccInfo(arciumProgram, address, commitment) {
|
|
93
117
|
return arciumProgram.account.computationDefinitionAccount.fetch(address, commitment);
|
|
94
118
|
}
|
|
95
|
-
/**
|
|
96
|
-
* Returns all computation references in the mempool for a given account.
|
|
97
|
-
* Only non-stake computations are included.
|
|
98
|
-
* @param arciumProgram - The Anchor program instance.
|
|
99
|
-
* @param address - The public key of the mempool account.
|
|
100
|
-
* @returns Array of ComputationReference objects.
|
|
101
|
-
*/
|
|
102
|
-
async function getComputationsInMempool(arciumProgram, address) {
|
|
103
|
-
const mempool = await getMempoolAccData(arciumProgram.provider, address);
|
|
104
|
-
const startIndex = mempool.inner.computations.startIndex;
|
|
105
|
-
const length = mempool.inner.computations.length;
|
|
106
|
-
const elems = mempool.inner.computations.elems;
|
|
107
|
-
function isValid(validBits, idx) {
|
|
108
|
-
const byte = idx >>> 3;
|
|
109
|
-
const bit = idx & 7;
|
|
110
|
-
if (byte >= validBits.length) {
|
|
111
|
-
// This should never happen, so we'll want to know about it
|
|
112
|
-
throw new Error(`isValid: byte ${byte} >= validBits.length ${validBits.length}`);
|
|
113
|
-
}
|
|
114
|
-
return (validBits[byte] & (1 << bit)) !== 0;
|
|
115
|
-
}
|
|
116
|
-
// Handle circular buffer wraparound
|
|
117
|
-
const refs = [];
|
|
118
|
-
for (let i = 0; i < length; i++) {
|
|
119
|
-
const idx = (startIndex + i) % elems.length;
|
|
120
|
-
// Only save non-stake computations
|
|
121
|
-
if (isValid(mempool.inner.computations.validBits, idx)) {
|
|
122
|
-
refs.push(...elems[idx].entries);
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
return refs
|
|
126
|
-
.flat()
|
|
127
|
-
.filter((ref) => !isNullRef(ref));
|
|
128
|
-
}
|
|
129
119
|
/**
|
|
130
120
|
* Fetches and parses a given Computation account.
|
|
131
121
|
* @param arciumProgram - The Anchor program instance.
|
|
@@ -151,19 +141,7 @@ async function getArciumAccPubkeys(conn, discriminator) {
|
|
|
151
141
|
});
|
|
152
142
|
return accs.map((acc) => acc.pubkey);
|
|
153
143
|
}
|
|
154
|
-
function isNullRef(ref) {
|
|
155
|
-
const bigZero = new anchor.BN(0);
|
|
156
|
-
return (ref.computationDefinitionOffset === 0
|
|
157
|
-
&& ref.computationOffset === bigZero
|
|
158
|
-
&& ref.priorityFee === bigZero);
|
|
159
|
-
}
|
|
160
144
|
|
|
161
|
-
const ArciumEventNames = [
|
|
162
|
-
'QueueComputationEvent',
|
|
163
|
-
'InitComputationEvent',
|
|
164
|
-
'CallbackComputationEvent',
|
|
165
|
-
'FinalizeComputationEvent',
|
|
166
|
-
];
|
|
167
145
|
/**
|
|
168
146
|
* Subscribes to computation-related events for a given MXE program ID.
|
|
169
147
|
* @param conn - The Solana connection object.
|
|
@@ -207,13 +185,53 @@ function getComputationOffset(tx) {
|
|
|
207
185
|
}
|
|
208
186
|
/**
|
|
209
187
|
* Get the events related to arcium computations from a transaction's logs
|
|
188
|
+
*
|
|
189
|
+
* Note: This implements a direct decode approach instead of using Anchor's EventParser.parseLogs().
|
|
190
|
+
*
|
|
191
|
+
* BREAKING CHANGE IN ANCHOR v0.32.0 (PR #3657, commit 34b6d19):
|
|
192
|
+
* EventParser.parseLogs was hardened to prevent malicious log injection attacks. It now:
|
|
193
|
+
* 1. Requires the first log to match "Program X invoke [1]" (root invocation)
|
|
194
|
+
* 2. Pre-seeds the execution stack with program X from the first log
|
|
195
|
+
* 3. Only parses events when execution.program() === EventParser.programId
|
|
196
|
+
*
|
|
197
|
+
* This breaks our use case:
|
|
198
|
+
* - We subscribe to MXE program logs (line 29) via conn.onLogs(mxeProgramId, ...)
|
|
199
|
+
* - But we need to parse Arcium events emitted during MXE→Arcium CPI calls
|
|
200
|
+
* - When MXE is the root program, execution.program() = MXE_PROGRAM_ID
|
|
201
|
+
* - EventParser expects execution.program() = ARCIUM_PROGRAM_ID
|
|
202
|
+
* - Result: All Arcium events are silently skipped
|
|
203
|
+
*
|
|
204
|
+
* Our discriminator-based approach:
|
|
205
|
+
* - Scans all logs for "Program data:" and "Program log:" prefixes
|
|
206
|
+
* - Uses event discriminators to identify valid Arcium events (no program context check)
|
|
207
|
+
* - Works regardless of which program is root or subscription target
|
|
208
|
+
* - Handles both MXE→Arcium and Arcium→MXE CPI patterns
|
|
209
|
+
*
|
|
210
210
|
* @param logs - The logs to get the events from
|
|
211
211
|
* @returns The events in the logs.
|
|
212
212
|
*/
|
|
213
213
|
function getComputationEventsFromLogs(logs) {
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
214
|
+
const events = [];
|
|
215
|
+
// Scan all event logs and rely on discriminators to identify valid Arcium events.
|
|
216
|
+
// This works for both MXE→Arcium CPI and Arcium→MXE CPI transactions.
|
|
217
|
+
for (const log of logs) {
|
|
218
|
+
if (log.startsWith(PROGRAM_DATA_PREFIX)) {
|
|
219
|
+
const eventData = log.slice(PROGRAM_DATA_PREFIX.length);
|
|
220
|
+
const decoded = ARCIUM_BORSH_CODER.events.decode(eventData);
|
|
221
|
+
if (decoded && ARCIUM_EVENT_NAMES.includes(decoded.name)) {
|
|
222
|
+
events.push(decoded);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
else if (log.startsWith(PROGRAM_LOG_PREFIX)) {
|
|
226
|
+
const eventData = log.slice(PROGRAM_LOG_PREFIX.length);
|
|
227
|
+
const decoded = ARCIUM_BORSH_CODER.events.decode(eventData);
|
|
228
|
+
if (decoded && ARCIUM_EVENT_NAMES.includes(decoded.name)) {
|
|
229
|
+
events.push(decoded);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
// Map to existing return format
|
|
234
|
+
return events.map((e) => {
|
|
217
235
|
const eventData = {
|
|
218
236
|
computationOffset: e.data.computation_offset,
|
|
219
237
|
...e.data,
|
|
@@ -228,4 +246,4 @@ function getComputationEventsFromLogs(logs) {
|
|
|
228
246
|
});
|
|
229
247
|
}
|
|
230
248
|
|
|
231
|
-
export { getArxNodeAccAddresses, getArxNodeAccInfo, getClusterAccAddresses, getClusterAccInfo, getCompDefAccInfo, getComputationAccInfo, getComputationOffset,
|
|
249
|
+
export { getArxNodeAccAddresses, getArxNodeAccInfo, getClusterAccAddresses, getClusterAccInfo, getCompDefAccInfo, getComputationAccInfo, getComputationOffset, getMXEAccAddresses, getMXEAccInfo, subscribeComputations, unsubscribeComputations };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@arcium-hq/reader",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "Reader SDK for fetching onchain data for Arcium network programs",
|
|
5
5
|
"author": "Arcium",
|
|
6
6
|
"license": "GPL-3.0-only",
|
|
@@ -31,10 +31,7 @@
|
|
|
31
31
|
"require": "./build/index.cjs"
|
|
32
32
|
}
|
|
33
33
|
],
|
|
34
|
-
"
|
|
35
|
-
"type": "git",
|
|
36
|
-
"url": "https://github.com/arcium-hq/arcium-tooling.git"
|
|
37
|
-
},
|
|
34
|
+
"homepage": "https://ts.arcium.com",
|
|
38
35
|
"devDependencies": {
|
|
39
36
|
"@rollup/plugin-json": "^6.1.0",
|
|
40
37
|
"@rollup/plugin-typescript": "^12.1.1",
|
|
@@ -57,10 +54,10 @@
|
|
|
57
54
|
"typescript-eslint": "^8.15.0"
|
|
58
55
|
},
|
|
59
56
|
"dependencies": {
|
|
60
|
-
"@coral-xyz/anchor": "^0.
|
|
57
|
+
"@coral-xyz/anchor": "^0.32.1",
|
|
61
58
|
"@noble/curves": "^1.9.5",
|
|
62
59
|
"@noble/hashes": "^1.7.1",
|
|
63
|
-
"@arcium-hq/client": "0.
|
|
60
|
+
"@arcium-hq/client": "0.5.0"
|
|
64
61
|
},
|
|
65
62
|
"keywords": [
|
|
66
63
|
"Cryptography",
|