@arcium-hq/reader 0.1.45
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 +126 -0
- package/build/index.cjs +200 -0
- package/build/index.d.ts +41 -0
- package/build/index.mjs +130 -0
- package/package.json +73 -0
package/README.md
ADDED
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
# Arcium Reader SDK
|
|
2
|
+
|
|
3
|
+
The Arcium Reader SDK is a TypeScript library designed for passively observing and querying the state of the Arcium program on Solana. It allows you to fetch information about Arcium accounts and track the status of computations without requiring a signer.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @arcium-hq/reader
|
|
9
|
+
|
|
10
|
+
or
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
yarn add @arcium-hq/reader
|
|
14
|
+
|
|
15
|
+
or
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
pnpm add @arcium-hq/reader
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Usage
|
|
22
|
+
|
|
23
|
+
### Getting the Read-only Program
|
|
24
|
+
|
|
25
|
+
To interact with the reader functions, you first need a read-only instance of the Arcium Anchor program. This doesn't require a wallet or signer.
|
|
26
|
+
|
|
27
|
+
```typescript
|
|
28
|
+
import * as anchor from "@coral-xyz/anchor";
|
|
29
|
+
import { getArciumProgramReadonly } from "@arcium-hq/reader";
|
|
30
|
+
|
|
31
|
+
// Assuming you have an AnchorProvider configured (e.g., from anchor.AnchorProvider.env())
|
|
32
|
+
const provider = anchor.getProvider();
|
|
33
|
+
const arciumProgram = getArciumProgramReadonly(provider as anchor.AnchorProvider);
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### Fetching Account Information
|
|
37
|
+
|
|
38
|
+
The reader SDK provides functions to fetch and deserialize various Arcium account types.
|
|
39
|
+
|
|
40
|
+
**1. Fetching MXE Accounts:**
|
|
41
|
+
|
|
42
|
+
```typescript
|
|
43
|
+
import { getMXEAccs, getMXEAccInfo } from "@arcium-hq/reader";
|
|
44
|
+
|
|
45
|
+
// Get all MXE account public keys
|
|
46
|
+
const mxeAccPubkeys = await getMXEAccs(provider.connection);
|
|
47
|
+
|
|
48
|
+
// Get detailed info for a specific MXE account
|
|
49
|
+
if (mxeAccPubkeys.length > 0) {
|
|
50
|
+
const mxeAccInfo = await getMXEAccInfo(arciumProgram, mxeAccPubkeys[0]);
|
|
51
|
+
console.log("MXE Account Info:", mxeAccInfo);
|
|
52
|
+
// Access fields like mxeAccInfo.computationDefinitions, mxeAccInfo.cluster, etc.
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
**2. Fetching Cluster Accounts:**
|
|
57
|
+
|
|
58
|
+
```typescript
|
|
59
|
+
import { getClusterAccs, getClusterAccInfo } from "@arcium-hq/reader";
|
|
60
|
+
|
|
61
|
+
// Get all Cluster account public keys
|
|
62
|
+
const clusterAccPubkeys = await getClusterAccs(provider.connection);
|
|
63
|
+
|
|
64
|
+
// Get detailed info for a specific Cluster account
|
|
65
|
+
if (clusterAccPubkeys.length > 0) {
|
|
66
|
+
const clusterInfo = await getClusterAccInfo(arciumProgram, clusterAccPubkeys[0]);
|
|
67
|
+
console.log("Cluster Account Info:", clusterInfo);
|
|
68
|
+
// Access fields like clusterInfo.mxes, clusterInfo.nodes, etc.
|
|
69
|
+
}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
**3. Fetching ArxNode Accounts:**
|
|
73
|
+
|
|
74
|
+
```typescript
|
|
75
|
+
import { getArxNodeAccs, getArxNodeAccInfo } from "@arcium-hq/reader";
|
|
76
|
+
|
|
77
|
+
// Get all ArxNode account public keys
|
|
78
|
+
const arxNodeAccPubkeys = await getArxNodeAccs(provider.connection);
|
|
79
|
+
|
|
80
|
+
// Get detailed info for a specific ArxNode account
|
|
81
|
+
if (arxNodeAccPubkeys.length > 0) {
|
|
82
|
+
const arxNodeInfo = await getArxNodeAccInfo(arciumProgram, arxNodeAccPubkeys[0]);
|
|
83
|
+
console.log("ArxNode Account Info:", arxNodeInfo);
|
|
84
|
+
// Access fields like arxNodeInfo.clusterMemberships, etc.
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Tracking Computation Status
|
|
89
|
+
|
|
90
|
+
You can subscribe to events related to a specific MXE (identified by its program ID) to track the lifecycle of computations it processes.
|
|
91
|
+
|
|
92
|
+
```typescript
|
|
93
|
+
import { subscribeComputations, unsubscribeComputations } from "@arcium-hq/reader";
|
|
94
|
+
import { PublicKey } from "@solana/web3.js";
|
|
95
|
+
|
|
96
|
+
// Assuming `mxeProgramId` is the PublicKey of the MXE program you want to monitor
|
|
97
|
+
const mxeProgramId = new PublicKey("YOUR_MXE_PROGRAM_ID");
|
|
98
|
+
|
|
99
|
+
const eventLog = [];
|
|
100
|
+
|
|
101
|
+
// Define a callback function to handle events
|
|
102
|
+
const eventCallback = (eventData: any, eventName: string) => {
|
|
103
|
+
console.log(`Received event: ${eventName}`, eventData);
|
|
104
|
+
eventLog.push({ event: eventData, name: eventName });
|
|
105
|
+
// Events typically include QueueComputationEvent, InitComputationEvent,
|
|
106
|
+
// CallbackComputationEvent, FinalizeComputationEvent
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
// Start subscribing
|
|
110
|
+
console.log(`Subscribing to computation events for ${mxeProgramId.toBase58()}`)
|
|
111
|
+
const subscriptionId = await subscribeComputations(
|
|
112
|
+
provider.connection,
|
|
113
|
+
mxeProgramId,
|
|
114
|
+
eventCallback
|
|
115
|
+
);
|
|
116
|
+
|
|
117
|
+
console.log(`Subscription active with ID: ${subscriptionId}`);
|
|
118
|
+
|
|
119
|
+
// ... later, when you want to stop listening ...
|
|
120
|
+
|
|
121
|
+
// Unsubscribe
|
|
122
|
+
await unsubscribeComputations(provider.connection, subscriptionId);
|
|
123
|
+
console.log(`Unsubscribed from computation events.`);
|
|
124
|
+
|
|
125
|
+
```
|
|
126
|
+
|
package/build/index.cjs
ADDED
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var client = require('@arcium-hq/client');
|
|
4
|
+
var anchor = require('@coral-xyz/anchor');
|
|
5
|
+
|
|
6
|
+
function _interopNamespaceDefault(e) {
|
|
7
|
+
var n = Object.create(null);
|
|
8
|
+
if (e) {
|
|
9
|
+
Object.keys(e).forEach(function (k) {
|
|
10
|
+
if (k !== 'default') {
|
|
11
|
+
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
12
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
13
|
+
enumerable: true,
|
|
14
|
+
get: function () { return e[k]; }
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
n.default = e;
|
|
20
|
+
return Object.freeze(n);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
var anchor__namespace = /*#__PURE__*/_interopNamespaceDefault(anchor);
|
|
24
|
+
|
|
25
|
+
const ARCIUM_PROGRAM_ID_STRING = 'BKck65TgoKRokMjQM3datB9oRwJ8rAj2jxPXvHXUvcL6';
|
|
26
|
+
const ARX_NODE_ACC_DISCRIMINATOR = [2, 207, 122, 223, 93, 97, 231, 199];
|
|
27
|
+
const CLUSTER_ACC_DISCRIMINATOR = [236, 225, 118, 228, 173, 106, 18, 60];
|
|
28
|
+
const MXE_ACC_DISCRIMINATOR = [32, 115, 16, 240, 209, 25, 92, 165];
|
|
29
|
+
const ARCIUM_PROGRAM_ID = new anchor__namespace.web3.PublicKey(ARCIUM_PROGRAM_ID_STRING);
|
|
30
|
+
new anchor__namespace.BorshInstructionCoder(client.ARCIUM_IDL);
|
|
31
|
+
const ARCIUM_EVENT_CODER = new anchor__namespace.EventParser(ARCIUM_PROGRAM_ID, new anchor__namespace.BorshCoder(client.ARCIUM_IDL));
|
|
32
|
+
|
|
33
|
+
// Returns all MXE accounts
|
|
34
|
+
async function getMXEAccs(conn) {
|
|
35
|
+
return getArciumAccPubkeys(conn, MXE_ACC_DISCRIMINATOR);
|
|
36
|
+
}
|
|
37
|
+
// Returns all Cluster accounts
|
|
38
|
+
async function getClusterAccs(conn) {
|
|
39
|
+
return getArciumAccPubkeys(conn, CLUSTER_ACC_DISCRIMINATOR);
|
|
40
|
+
}
|
|
41
|
+
// Returns all ArxNode accounts
|
|
42
|
+
async function getArxNodeAccs(conn) {
|
|
43
|
+
return getArciumAccPubkeys(conn, ARX_NODE_ACC_DISCRIMINATOR);
|
|
44
|
+
}
|
|
45
|
+
// Fetches and parses a given MXE account. Format:
|
|
46
|
+
async function getMXEAccInfo(arciumProgram, address, commitment) {
|
|
47
|
+
return arciumProgram.account.persistentMxeAccount.fetch(address, commitment);
|
|
48
|
+
}
|
|
49
|
+
async function getClusterAccInfo(arciumProgram, address, commitment) {
|
|
50
|
+
return arciumProgram.account.cluster.fetch(address, commitment);
|
|
51
|
+
}
|
|
52
|
+
async function getArxNodeAccInfo(arciumProgram, address, commitment) {
|
|
53
|
+
return arciumProgram.account.arxNode.fetch(address, commitment);
|
|
54
|
+
}
|
|
55
|
+
async function getComputationsInMempool(arciumProgram, address) {
|
|
56
|
+
const mempool = await client.getMempoolAccData(arciumProgram.provider, address);
|
|
57
|
+
const startIndex = mempool.inner.computations.startIndex;
|
|
58
|
+
const length = mempool.inner.computations.length;
|
|
59
|
+
const elems = mempool.inner.computations.elems;
|
|
60
|
+
function isValid(validBits, idx) {
|
|
61
|
+
const byte = idx >>> 3;
|
|
62
|
+
const bit = idx & 7;
|
|
63
|
+
if (byte >= validBits.length) {
|
|
64
|
+
// This should never happen, so we'll want to know about it
|
|
65
|
+
throw new Error(`isValid: byte ${byte} >= validBits.length ${validBits.length}`);
|
|
66
|
+
}
|
|
67
|
+
return (validBits[byte] & (1 << bit)) !== 0;
|
|
68
|
+
}
|
|
69
|
+
// Handle circular buffer wraparound
|
|
70
|
+
const refs = [];
|
|
71
|
+
for (let i = 0; i < length; i++) {
|
|
72
|
+
const idx = (startIndex + i) % elems.length;
|
|
73
|
+
// Only save non-stake computations
|
|
74
|
+
if (isValid(mempool.inner.computations.validBits, idx)) {
|
|
75
|
+
refs.push(...elems[idx].entries);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return refs.flat().filter((ref) => !isNullRef(ref));
|
|
79
|
+
}
|
|
80
|
+
async function getComputation(arciumProgram, address, commitment) {
|
|
81
|
+
return arciumProgram.account.computationAccount.fetch(address, commitment);
|
|
82
|
+
}
|
|
83
|
+
async function getArciumAccPubkeys(conn, discriminator) {
|
|
84
|
+
const accs = await conn.getProgramAccounts(ARCIUM_PROGRAM_ID, {
|
|
85
|
+
dataSlice: { offset: 0, length: 0 },
|
|
86
|
+
filters: [{
|
|
87
|
+
memcmp: {
|
|
88
|
+
offset: 0,
|
|
89
|
+
encoding: 'base64',
|
|
90
|
+
bytes: Buffer.from(discriminator).toString('base64'),
|
|
91
|
+
},
|
|
92
|
+
}],
|
|
93
|
+
});
|
|
94
|
+
return accs.map((acc) => acc.pubkey);
|
|
95
|
+
}
|
|
96
|
+
function isNullRef(ref) {
|
|
97
|
+
const bigZero = new anchor__namespace.BN(0);
|
|
98
|
+
return ref.computationDefinitionOffset === 0 && ref.computationOffset === bigZero && ref.priorityFee === bigZero;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const ArciumEventNames = [
|
|
102
|
+
'QueueComputationEvent',
|
|
103
|
+
'InitComputationEvent',
|
|
104
|
+
'CallbackComputationEvent',
|
|
105
|
+
'FinalizeComputationEvent',
|
|
106
|
+
];
|
|
107
|
+
async function subscribeComputations(conn, mxeProgramId, callback) {
|
|
108
|
+
return conn.onLogs(mxeProgramId, (logs) => {
|
|
109
|
+
const events = getComputationEventsFromLogs(logs.logs);
|
|
110
|
+
for (const event of events) {
|
|
111
|
+
callback(event.event, event.name);
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
async function unsubscribeComputations(conn, subscriptionId) {
|
|
116
|
+
conn.removeOnLogsListener(subscriptionId);
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Get the computation offset from a transaction
|
|
120
|
+
* @param tx - The transaction to get the computation offset from
|
|
121
|
+
* @returns The computation offset if one is found, otherwise null.
|
|
122
|
+
* @throws Error if multiple computation offsets are found in the transaction
|
|
123
|
+
*/
|
|
124
|
+
function getComputationOffset(tx) {
|
|
125
|
+
const events = getComputationEventsFromLogs(tx.meta?.logMessages ?? []);
|
|
126
|
+
if (events.length === 0) {
|
|
127
|
+
return undefined;
|
|
128
|
+
}
|
|
129
|
+
const computationOffsets = events.map((e) => e.event.computationOffset);
|
|
130
|
+
const computationOffset = computationOffsets[0];
|
|
131
|
+
if (computationOffsets.some((offset) => offset !== computationOffset)) {
|
|
132
|
+
throw new Error(`Multiple computation offsets found in computation: ${JSON.stringify(computationOffsets)}`);
|
|
133
|
+
}
|
|
134
|
+
return computationOffset;
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Get the events related to arcium computations from a transaction's logs
|
|
138
|
+
* @param logs - The logs to get the events from
|
|
139
|
+
* @returns The events in the logs.
|
|
140
|
+
*/
|
|
141
|
+
function getComputationEventsFromLogs(logs) {
|
|
142
|
+
return Array.from(ARCIUM_EVENT_CODER.parseLogs(logs))
|
|
143
|
+
.filter((e) => ArciumEventNames.includes(e.name))
|
|
144
|
+
.map((e) => ({
|
|
145
|
+
event: e.data,
|
|
146
|
+
name: e.name,
|
|
147
|
+
}));
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
Object.defineProperty(exports, "getArciumProgramReadonly", {
|
|
151
|
+
enumerable: true,
|
|
152
|
+
get: function () { return client.getArciumProgramReadonly; }
|
|
153
|
+
});
|
|
154
|
+
Object.defineProperty(exports, "getArxNodeAcc", {
|
|
155
|
+
enumerable: true,
|
|
156
|
+
get: function () { return client.getArxNodeAcc; }
|
|
157
|
+
});
|
|
158
|
+
Object.defineProperty(exports, "getClockAcc", {
|
|
159
|
+
enumerable: true,
|
|
160
|
+
get: function () { return client.getClockAcc; }
|
|
161
|
+
});
|
|
162
|
+
Object.defineProperty(exports, "getClusterAcc", {
|
|
163
|
+
enumerable: true,
|
|
164
|
+
get: function () { return client.getClusterAcc; }
|
|
165
|
+
});
|
|
166
|
+
Object.defineProperty(exports, "getCompDefAcc", {
|
|
167
|
+
enumerable: true,
|
|
168
|
+
get: function () { return client.getCompDefAcc; }
|
|
169
|
+
});
|
|
170
|
+
Object.defineProperty(exports, "getComputationAcc", {
|
|
171
|
+
enumerable: true,
|
|
172
|
+
get: function () { return client.getComputationAcc; }
|
|
173
|
+
});
|
|
174
|
+
Object.defineProperty(exports, "getExecutingPoolAcc", {
|
|
175
|
+
enumerable: true,
|
|
176
|
+
get: function () { return client.getExecutingPoolAcc; }
|
|
177
|
+
});
|
|
178
|
+
Object.defineProperty(exports, "getMXEAccAcc", {
|
|
179
|
+
enumerable: true,
|
|
180
|
+
get: function () { return client.getMXEAccAcc; }
|
|
181
|
+
});
|
|
182
|
+
Object.defineProperty(exports, "getMempoolAcc", {
|
|
183
|
+
enumerable: true,
|
|
184
|
+
get: function () { return client.getMempoolAcc; }
|
|
185
|
+
});
|
|
186
|
+
Object.defineProperty(exports, "getStakingPoolAcc", {
|
|
187
|
+
enumerable: true,
|
|
188
|
+
get: function () { return client.getStakingPoolAcc; }
|
|
189
|
+
});
|
|
190
|
+
exports.getArxNodeAccInfo = getArxNodeAccInfo;
|
|
191
|
+
exports.getArxNodeAccs = getArxNodeAccs;
|
|
192
|
+
exports.getClusterAccInfo = getClusterAccInfo;
|
|
193
|
+
exports.getClusterAccs = getClusterAccs;
|
|
194
|
+
exports.getComputation = getComputation;
|
|
195
|
+
exports.getComputationOffset = getComputationOffset;
|
|
196
|
+
exports.getComputationsInMempool = getComputationsInMempool;
|
|
197
|
+
exports.getMXEAccInfo = getMXEAccInfo;
|
|
198
|
+
exports.getMXEAccs = getMXEAccs;
|
|
199
|
+
exports.subscribeComputations = subscribeComputations;
|
|
200
|
+
exports.unsubscribeComputations = unsubscribeComputations;
|
package/build/index.d.ts
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { ArciumIdlType } from '@arcium-hq/client';
|
|
2
|
+
export { getArciumProgramReadonly, getArxNodeAcc, getClockAcc, getClusterAcc, getCompDefAcc, getComputationAcc, getExecutingPoolAcc, getMXEAccAcc, getMempoolAcc, getStakingPoolAcc } from '@arcium-hq/client';
|
|
3
|
+
import * as anchor from '@coral-xyz/anchor';
|
|
4
|
+
|
|
5
|
+
type PublicKey = anchor.web3.PublicKey;
|
|
6
|
+
type Connection = anchor.web3.Connection;
|
|
7
|
+
type Program<T extends anchor.Idl> = anchor.Program<T>;
|
|
8
|
+
type ArciumTypes = anchor.IdlTypes<ArciumIdlType>;
|
|
9
|
+
type ArciumEvent = anchor.IdlEvents<ArciumIdlType>;
|
|
10
|
+
type ArciumEventName = Capitalize<keyof ArciumEvent>;
|
|
11
|
+
type ArciumEventData = ArciumEvent[keyof ArciumEvent];
|
|
12
|
+
type MXEAccount = ArciumTypes['persistentMxeAccount'];
|
|
13
|
+
type ClusterAccount = ArciumTypes['cluster'];
|
|
14
|
+
type ArxNodeAccount = ArciumTypes['arxNode'];
|
|
15
|
+
type Computation = ArciumTypes['computationAccount'];
|
|
16
|
+
type ComputationReference = ArciumTypes['computationReference'];
|
|
17
|
+
type QueueComputationIx = ArciumIdlType['instructions']['37'];
|
|
18
|
+
type CallbackComputationIx = ArciumIdlType['instructions']['4'];
|
|
19
|
+
type FinalizeComputationIx = ArciumIdlType['instructions']['17'];
|
|
20
|
+
type ComputationStatus = 'queued' | 'executing' | 'executed' | 'finalized' | 'failed';
|
|
21
|
+
|
|
22
|
+
declare function getMXEAccs(conn: Connection): Promise<PublicKey[]>;
|
|
23
|
+
declare function getClusterAccs(conn: Connection): Promise<PublicKey[]>;
|
|
24
|
+
declare function getArxNodeAccs(conn: Connection): Promise<PublicKey[]>;
|
|
25
|
+
declare function getMXEAccInfo(arciumProgram: anchor.Program<ArciumIdlType>, address: PublicKey, commitment?: anchor.web3.Commitment): Promise<MXEAccount>;
|
|
26
|
+
declare function getClusterAccInfo(arciumProgram: anchor.Program<ArciumIdlType>, address: PublicKey, commitment?: anchor.web3.Commitment): Promise<ClusterAccount>;
|
|
27
|
+
declare function getArxNodeAccInfo(arciumProgram: anchor.Program<ArciumIdlType>, address: PublicKey, commitment?: anchor.web3.Commitment): Promise<ArxNodeAccount>;
|
|
28
|
+
declare function getComputationsInMempool(arciumProgram: anchor.Program<ArciumIdlType>, address: PublicKey): Promise<ComputationReference[]>;
|
|
29
|
+
declare function getComputation(arciumProgram: anchor.Program<ArciumIdlType>, address: PublicKey, commitment?: anchor.web3.Commitment): Promise<Computation>;
|
|
30
|
+
|
|
31
|
+
declare function subscribeComputations(conn: Connection, mxeProgramId: PublicKey, callback: (event: ArciumEventData, name: ArciumEventName) => void): Promise<number>;
|
|
32
|
+
declare function unsubscribeComputations(conn: Connection, subscriptionId: number): Promise<void>;
|
|
33
|
+
/**
|
|
34
|
+
* Get the computation offset from a transaction
|
|
35
|
+
* @param tx - The transaction to get the computation offset from
|
|
36
|
+
* @returns The computation offset if one is found, otherwise null.
|
|
37
|
+
* @throws Error if multiple computation offsets are found in the transaction
|
|
38
|
+
*/
|
|
39
|
+
declare function getComputationOffset(tx: anchor.web3.VersionedTransactionResponse): anchor.BN | undefined;
|
|
40
|
+
|
|
41
|
+
export { type ArciumEvent, type ArciumEventData, type ArciumEventName, type ArciumTypes, type ArxNodeAccount, type CallbackComputationIx, type ClusterAccount, type Computation, type ComputationReference, type ComputationStatus, type Connection, type FinalizeComputationIx, type MXEAccount, type Program, type PublicKey, type QueueComputationIx, getArxNodeAccInfo, getArxNodeAccs, getClusterAccInfo, getClusterAccs, getComputation, getComputationOffset, getComputationsInMempool, getMXEAccInfo, getMXEAccs, subscribeComputations, unsubscribeComputations };
|
package/build/index.mjs
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { ARCIUM_IDL, getMempoolAccData } from '@arcium-hq/client';
|
|
2
|
+
export { getArciumProgramReadonly, getArxNodeAcc, getClockAcc, getClusterAcc, getCompDefAcc, getComputationAcc, getExecutingPoolAcc, getMXEAccAcc, getMempoolAcc, getStakingPoolAcc } from '@arcium-hq/client';
|
|
3
|
+
import * as anchor from '@coral-xyz/anchor';
|
|
4
|
+
|
|
5
|
+
const ARCIUM_PROGRAM_ID_STRING = 'BKck65TgoKRokMjQM3datB9oRwJ8rAj2jxPXvHXUvcL6';
|
|
6
|
+
const ARX_NODE_ACC_DISCRIMINATOR = [2, 207, 122, 223, 93, 97, 231, 199];
|
|
7
|
+
const CLUSTER_ACC_DISCRIMINATOR = [236, 225, 118, 228, 173, 106, 18, 60];
|
|
8
|
+
const MXE_ACC_DISCRIMINATOR = [32, 115, 16, 240, 209, 25, 92, 165];
|
|
9
|
+
const ARCIUM_PROGRAM_ID = new anchor.web3.PublicKey(ARCIUM_PROGRAM_ID_STRING);
|
|
10
|
+
new anchor.BorshInstructionCoder(ARCIUM_IDL);
|
|
11
|
+
const ARCIUM_EVENT_CODER = new anchor.EventParser(ARCIUM_PROGRAM_ID, new anchor.BorshCoder(ARCIUM_IDL));
|
|
12
|
+
|
|
13
|
+
// Returns all MXE accounts
|
|
14
|
+
async function getMXEAccs(conn) {
|
|
15
|
+
return getArciumAccPubkeys(conn, MXE_ACC_DISCRIMINATOR);
|
|
16
|
+
}
|
|
17
|
+
// Returns all Cluster accounts
|
|
18
|
+
async function getClusterAccs(conn) {
|
|
19
|
+
return getArciumAccPubkeys(conn, CLUSTER_ACC_DISCRIMINATOR);
|
|
20
|
+
}
|
|
21
|
+
// Returns all ArxNode accounts
|
|
22
|
+
async function getArxNodeAccs(conn) {
|
|
23
|
+
return getArciumAccPubkeys(conn, ARX_NODE_ACC_DISCRIMINATOR);
|
|
24
|
+
}
|
|
25
|
+
// Fetches and parses a given MXE account. Format:
|
|
26
|
+
async function getMXEAccInfo(arciumProgram, address, commitment) {
|
|
27
|
+
return arciumProgram.account.persistentMxeAccount.fetch(address, commitment);
|
|
28
|
+
}
|
|
29
|
+
async function getClusterAccInfo(arciumProgram, address, commitment) {
|
|
30
|
+
return arciumProgram.account.cluster.fetch(address, commitment);
|
|
31
|
+
}
|
|
32
|
+
async function getArxNodeAccInfo(arciumProgram, address, commitment) {
|
|
33
|
+
return arciumProgram.account.arxNode.fetch(address, commitment);
|
|
34
|
+
}
|
|
35
|
+
async function getComputationsInMempool(arciumProgram, address) {
|
|
36
|
+
const mempool = await getMempoolAccData(arciumProgram.provider, address);
|
|
37
|
+
const startIndex = mempool.inner.computations.startIndex;
|
|
38
|
+
const length = mempool.inner.computations.length;
|
|
39
|
+
const elems = mempool.inner.computations.elems;
|
|
40
|
+
function isValid(validBits, idx) {
|
|
41
|
+
const byte = idx >>> 3;
|
|
42
|
+
const bit = idx & 7;
|
|
43
|
+
if (byte >= validBits.length) {
|
|
44
|
+
// This should never happen, so we'll want to know about it
|
|
45
|
+
throw new Error(`isValid: byte ${byte} >= validBits.length ${validBits.length}`);
|
|
46
|
+
}
|
|
47
|
+
return (validBits[byte] & (1 << bit)) !== 0;
|
|
48
|
+
}
|
|
49
|
+
// Handle circular buffer wraparound
|
|
50
|
+
const refs = [];
|
|
51
|
+
for (let i = 0; i < length; i++) {
|
|
52
|
+
const idx = (startIndex + i) % elems.length;
|
|
53
|
+
// Only save non-stake computations
|
|
54
|
+
if (isValid(mempool.inner.computations.validBits, idx)) {
|
|
55
|
+
refs.push(...elems[idx].entries);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return refs.flat().filter((ref) => !isNullRef(ref));
|
|
59
|
+
}
|
|
60
|
+
async function getComputation(arciumProgram, address, commitment) {
|
|
61
|
+
return arciumProgram.account.computationAccount.fetch(address, commitment);
|
|
62
|
+
}
|
|
63
|
+
async function getArciumAccPubkeys(conn, discriminator) {
|
|
64
|
+
const accs = await conn.getProgramAccounts(ARCIUM_PROGRAM_ID, {
|
|
65
|
+
dataSlice: { offset: 0, length: 0 },
|
|
66
|
+
filters: [{
|
|
67
|
+
memcmp: {
|
|
68
|
+
offset: 0,
|
|
69
|
+
encoding: 'base64',
|
|
70
|
+
bytes: Buffer.from(discriminator).toString('base64'),
|
|
71
|
+
},
|
|
72
|
+
}],
|
|
73
|
+
});
|
|
74
|
+
return accs.map((acc) => acc.pubkey);
|
|
75
|
+
}
|
|
76
|
+
function isNullRef(ref) {
|
|
77
|
+
const bigZero = new anchor.BN(0);
|
|
78
|
+
return ref.computationDefinitionOffset === 0 && ref.computationOffset === bigZero && ref.priorityFee === bigZero;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const ArciumEventNames = [
|
|
82
|
+
'QueueComputationEvent',
|
|
83
|
+
'InitComputationEvent',
|
|
84
|
+
'CallbackComputationEvent',
|
|
85
|
+
'FinalizeComputationEvent',
|
|
86
|
+
];
|
|
87
|
+
async function subscribeComputations(conn, mxeProgramId, callback) {
|
|
88
|
+
return conn.onLogs(mxeProgramId, (logs) => {
|
|
89
|
+
const events = getComputationEventsFromLogs(logs.logs);
|
|
90
|
+
for (const event of events) {
|
|
91
|
+
callback(event.event, event.name);
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
async function unsubscribeComputations(conn, subscriptionId) {
|
|
96
|
+
conn.removeOnLogsListener(subscriptionId);
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Get the computation offset from a transaction
|
|
100
|
+
* @param tx - The transaction to get the computation offset from
|
|
101
|
+
* @returns The computation offset if one is found, otherwise null.
|
|
102
|
+
* @throws Error if multiple computation offsets are found in the transaction
|
|
103
|
+
*/
|
|
104
|
+
function getComputationOffset(tx) {
|
|
105
|
+
const events = getComputationEventsFromLogs(tx.meta?.logMessages ?? []);
|
|
106
|
+
if (events.length === 0) {
|
|
107
|
+
return undefined;
|
|
108
|
+
}
|
|
109
|
+
const computationOffsets = events.map((e) => e.event.computationOffset);
|
|
110
|
+
const computationOffset = computationOffsets[0];
|
|
111
|
+
if (computationOffsets.some((offset) => offset !== computationOffset)) {
|
|
112
|
+
throw new Error(`Multiple computation offsets found in computation: ${JSON.stringify(computationOffsets)}`);
|
|
113
|
+
}
|
|
114
|
+
return computationOffset;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Get the events related to arcium computations from a transaction's logs
|
|
118
|
+
* @param logs - The logs to get the events from
|
|
119
|
+
* @returns The events in the logs.
|
|
120
|
+
*/
|
|
121
|
+
function getComputationEventsFromLogs(logs) {
|
|
122
|
+
return Array.from(ARCIUM_EVENT_CODER.parseLogs(logs))
|
|
123
|
+
.filter((e) => ArciumEventNames.includes(e.name))
|
|
124
|
+
.map((e) => ({
|
|
125
|
+
event: e.data,
|
|
126
|
+
name: e.name,
|
|
127
|
+
}));
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
export { getArxNodeAccInfo, getArxNodeAccs, getClusterAccInfo, getClusterAccs, getComputation, getComputationOffset, getComputationsInMempool, getMXEAccInfo, getMXEAccs, subscribeComputations, unsubscribeComputations };
|
package/package.json
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@arcium-hq/reader",
|
|
3
|
+
"version": "0.1.45",
|
|
4
|
+
"description": "Reader SDK for fetching onchain data for Arcium network programs",
|
|
5
|
+
"author": "Arcium",
|
|
6
|
+
"license": "GPL-3.0-only",
|
|
7
|
+
"main": "build/index.mjs",
|
|
8
|
+
"scripts": {
|
|
9
|
+
"test": "mocha test/**/*.ts --exit",
|
|
10
|
+
"lint": "eslint \"src/**/*.ts\" \"test/**/*.ts\"",
|
|
11
|
+
"lint:fix": "eslint \"src/**/*.ts\" \"test/**/*.ts\" --fix",
|
|
12
|
+
"lint:clean": "rm -rf dist/ && rm -rf build/",
|
|
13
|
+
"compile": "yarn bundle:cjs && yarn bundle:esm && yarn bundle:dts",
|
|
14
|
+
"bundle:cjs": "node ../../node_modules/rollup/dist/bin/rollup --config config/rollup.config.cjs.js",
|
|
15
|
+
"bundle:esm": "node ../../node_modules/rollup/dist/bin/rollup --config config/rollup.config.esm.js",
|
|
16
|
+
"bundle:dts": "node ../../node_modules/rollup/dist/bin/rollup --config config/rollup.config.dts.js",
|
|
17
|
+
"test-single": "mocha $1 --exit"
|
|
18
|
+
},
|
|
19
|
+
"type": "module",
|
|
20
|
+
"module": "build/index.mjs",
|
|
21
|
+
"types": "build/index.d.ts",
|
|
22
|
+
"files": [
|
|
23
|
+
"build/index.cjs",
|
|
24
|
+
"build/index.mjs",
|
|
25
|
+
"build/index.d.ts"
|
|
26
|
+
],
|
|
27
|
+
"exports": [
|
|
28
|
+
{
|
|
29
|
+
"types": "./build/index.d.ts",
|
|
30
|
+
"import": "./build/index.mjs",
|
|
31
|
+
"require": "./build/index.cjs"
|
|
32
|
+
}
|
|
33
|
+
],
|
|
34
|
+
"repository": {
|
|
35
|
+
"type": "git",
|
|
36
|
+
"url": "https://github.com/arcium-hq/arcium-tooling.git"
|
|
37
|
+
},
|
|
38
|
+
"devDependencies": {
|
|
39
|
+
"@rollup/plugin-json": "^6.1.0",
|
|
40
|
+
"@rollup/plugin-typescript": "^12.1.1",
|
|
41
|
+
"@types/bn.js": "^5.1.6",
|
|
42
|
+
"@types/chai": "^5.0.0",
|
|
43
|
+
"@types/mocha": "^10.0.9",
|
|
44
|
+
"@types/snarkjs": "^0.7.8",
|
|
45
|
+
"@typescript-eslint/eslint-plugin": "6.12.0",
|
|
46
|
+
"@typescript-eslint/parser": "6.12.0",
|
|
47
|
+
"chai": "^5.1.2",
|
|
48
|
+
"eslint": "8.54.0",
|
|
49
|
+
"eslint-config-airbnb-base": "15.0.0",
|
|
50
|
+
"eslint-plugin-import": "2.29.0",
|
|
51
|
+
"mocha": "^10.8.2",
|
|
52
|
+
"rollup": "^4.24.0",
|
|
53
|
+
"rollup-plugin-dts": "^6.1.1",
|
|
54
|
+
"ts-node": "^10.9.2",
|
|
55
|
+
"typescript": "^4.5.2"
|
|
56
|
+
},
|
|
57
|
+
"dependencies": {
|
|
58
|
+
"@coral-xyz/anchor": "^0.31.1",
|
|
59
|
+
"@noble/curves": "^1.8.1",
|
|
60
|
+
"@noble/hashes": "^1.7.1",
|
|
61
|
+
"@arcium-hq/client": "0.1.45"
|
|
62
|
+
},
|
|
63
|
+
"keywords": [
|
|
64
|
+
"Cryptography",
|
|
65
|
+
"Privacy",
|
|
66
|
+
"Multiparty Computation",
|
|
67
|
+
"Arcium",
|
|
68
|
+
"Blockchain",
|
|
69
|
+
"Solana",
|
|
70
|
+
"Confidential Computing",
|
|
71
|
+
"MPC"
|
|
72
|
+
]
|
|
73
|
+
}
|