@exponent-labs/exponent-vaults-fetcher 0.9.24 → 0.9.26

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.
@@ -0,0 +1,225 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const anchor_1 = require("@coral-xyz/anchor");
7
+ const strict_1 = __importDefault(require("node:assert/strict"));
8
+ const node_test_1 = __importDefault(require("node:test"));
9
+ const exponent_vaults_pda_1 = require("@exponent-labs/exponent-vaults-pda");
10
+ const fetcher_1 = require("./fetcher");
11
+ const EXPONENT_PRICES_DISCRIMINATOR = Buffer.from([188, 97, 196, 52, 192, 41, 211, 196]);
12
+ const PRICE_INTERFACE_ACCOUNTS_DISCRIMINATOR = Buffer.from([166, 196, 173, 204, 35, 6, 104, 230]);
13
+ const PROGRAM_ID = new anchor_1.web3.PublicKey(Uint8Array.from({ length: 32 }, (_, index) => index + 1));
14
+ const PRICE_MINT = new anchor_1.web3.PublicKey(Uint8Array.from({ length: 32 }, (_, index) => index + 33));
15
+ const MAX_PRICE_MANAGERS = 8;
16
+ const MAX_PRICES = 1024;
17
+ const PUBKEY_BYTES = 32;
18
+ const PRICE_NODE_REGISTERS_SIZE = 16;
19
+ const EXPONENT_PRICE_SIZE = 224;
20
+ const PRICE_NODE_SIZE = PRICE_NODE_REGISTERS_SIZE + EXPONENT_PRICE_SIZE;
21
+ const PRICE_NODES_OFFSET = 8 + 8 + MAX_PRICE_MANAGERS * PUBKEY_BYTES + 16;
22
+ const FIRST_PRICE_VALUE_OFFSET = PRICE_NODES_OFFSET + PRICE_NODE_REGISTERS_SIZE;
23
+ const EXPONENT_PRICES_SIZE = PRICE_NODES_OFFSET + MAX_PRICES * PRICE_NODE_SIZE + 128;
24
+ const PRICE_DECIMALS = 6;
25
+ const UNDERLYING_DECIMALS = 9;
26
+ const SY_PRICE_ID = 0x0807060504030201n;
27
+ const ZERO_PUBKEY = new anchor_1.web3.PublicKey(new Uint8Array(PUBKEY_BYTES));
28
+ function createPublicKey(seed) {
29
+ const bytes = new Uint8Array(PUBKEY_BYTES).fill(255);
30
+ new DataView(bytes.buffer).setUint32(0, seed, true);
31
+ return new anchor_1.web3.PublicKey(bytes);
32
+ }
33
+ function createExponentPricesData(priceInterfaceAccounts, reservedByte = 0) {
34
+ const data = Buffer.alloc(EXPONENT_PRICES_SIZE);
35
+ EXPONENT_PRICES_DISCRIMINATOR.copy(data);
36
+ data.writeBigUInt64LE(BigInt(priceInterfaceAccounts.length), 8 + 8 + MAX_PRICE_MANAGERS * PUBKEY_BYTES);
37
+ for (const [index, priceInterfaceAccount] of priceInterfaceAccounts.entries()) {
38
+ const valueOffset = FIRST_PRICE_VALUE_OFFSET + index * PRICE_NODE_SIZE;
39
+ PRICE_MINT.toBuffer().copy(data, valueOffset);
40
+ priceInterfaceAccount.toBuffer().copy(data, valueOffset + 128);
41
+ data.writeUInt8(PRICE_DECIMALS, valueOffset + 160);
42
+ data.writeUInt8(UNDERLYING_DECIMALS, valueOffset + 161);
43
+ data.fill(reservedByte, valueOffset + 162, valueOffset + 168);
44
+ data.writeBigUInt64LE(SY_PRICE_ID, valueOffset + 168);
45
+ data.fill(reservedByte, valueOffset + 176, valueOffset + EXPONENT_PRICE_SIZE);
46
+ }
47
+ return data;
48
+ }
49
+ function createPriceInterfaceAccountsData(interfaceAccounts, scopeConfig) {
50
+ const data = Buffer.alloc(12 + interfaceAccounts.length * PUBKEY_BYTES + (scopeConfig ? 17 : 0));
51
+ PRICE_INTERFACE_ACCOUNTS_DISCRIMINATOR.copy(data);
52
+ data.writeUInt32LE(interfaceAccounts.length, 8);
53
+ interfaceAccounts.forEach((account, index) => account.toBuffer().copy(data, 12 + index * PUBKEY_BYTES));
54
+ if (scopeConfig) {
55
+ const stateOffset = 12 + interfaceAccounts.length * PUBKEY_BYTES;
56
+ data.writeUInt8(2, stateOffset);
57
+ scopeConfig.priceChain.forEach((price, index) => data.writeUInt16LE(price, stateOffset + 1 + index * 2));
58
+ data.writeBigUInt64LE(scopeConfig.maximumAgeSeconds, stateOffset + 9);
59
+ }
60
+ return data;
61
+ }
62
+ function createConnection(registryData, options = {}) {
63
+ const registryAddress = new exponent_vaults_pda_1.ExponentVaultsPDA(PROGRAM_ID).exponentPrices()[0];
64
+ const singleAccountReads = [];
65
+ const multipleAccountReads = [];
66
+ let activeMultipleAccountReads = 0;
67
+ let maxConcurrentMultipleAccountReads = 0;
68
+ const connection = {
69
+ async getAccountInfo(address) {
70
+ singleAccountReads.push(address);
71
+ if (!address.equals(registryAddress)) {
72
+ throw new Error(`Unexpected getAccountInfo for PriceInterfaceAccounts: ${address.toBase58()}`);
73
+ }
74
+ return {
75
+ data: registryData,
76
+ executable: false,
77
+ lamports: 1,
78
+ owner: PROGRAM_ID,
79
+ rentEpoch: 0,
80
+ };
81
+ },
82
+ async getMultipleAccountsInfo(addresses) {
83
+ multipleAccountReads.push(addresses);
84
+ activeMultipleAccountReads += 1;
85
+ maxConcurrentMultipleAccountReads = Math.max(maxConcurrentMultipleAccountReads, activeMultipleAccountReads);
86
+ try {
87
+ await Promise.resolve();
88
+ if (options.rpcError)
89
+ throw options.rpcError;
90
+ const infos = addresses.map((address) => {
91
+ const fixture = options.accounts?.get(address.toBase58());
92
+ if (fixture === null || !fixture)
93
+ return null;
94
+ return {
95
+ data: fixture.data,
96
+ executable: false,
97
+ lamports: 1,
98
+ owner: fixture.owner ?? PROGRAM_ID,
99
+ rentEpoch: 0,
100
+ };
101
+ });
102
+ return options.shortResponse ? infos.slice(0, -1) : infos;
103
+ }
104
+ finally {
105
+ activeMultipleAccountReads -= 1;
106
+ }
107
+ },
108
+ };
109
+ return {
110
+ connection,
111
+ multipleAccountReads,
112
+ get maxConcurrentMultipleAccountReads() {
113
+ return maxConcurrentMultipleAccountReads;
114
+ },
115
+ registryAddress,
116
+ singleAccountReads,
117
+ };
118
+ }
119
+ function createAccountFixtures(keys) {
120
+ return new Map(keys.map((key, index) => [
121
+ key.toBase58(),
122
+ {
123
+ data: createPriceInterfaceAccountsData([createPublicKey(128 + index)], {
124
+ maximumAgeSeconds: BigInt(index + 1),
125
+ priceChain: [index + 1, index + 2, index + 3, index + 4],
126
+ }),
127
+ },
128
+ ]));
129
+ }
130
+ (0, node_test_1.default)("decodes price metadata from exact wire offsets without consuming reserved bytes", async () => {
131
+ for (const reservedByte of [0xa5, 0x5a]) {
132
+ const { connection } = createConnection(createExponentPricesData([ZERO_PUBKEY], reservedByte));
133
+ const fetcher = new fetcher_1.ExponentVaultsFetcher(connection, PROGRAM_ID);
134
+ const prices = await fetcher.fetchExponentPrices();
135
+ const price = prices.prices[1];
136
+ strict_1.default.ok(price);
137
+ strict_1.default.equal(price.priceDecimals, PRICE_DECIMALS);
138
+ strict_1.default.equal(price.underlyingDecimals, UNDERLYING_DECIMALS);
139
+ strict_1.default.equal(price.syPriceId, SY_PRICE_ID);
140
+ }
141
+ });
142
+ (0, node_test_1.default)("fetches unique price interface accounts sequentially in maximum 100-key batches", async () => {
143
+ const cases = [
144
+ { count: 0, expectedBatchSizes: [] },
145
+ { count: 1, expectedBatchSizes: [1] },
146
+ { count: 99, expectedBatchSizes: [99] },
147
+ { count: 100, expectedBatchSizes: [100] },
148
+ { count: 101, expectedBatchSizes: [100, 1] },
149
+ { count: 200, expectedBatchSizes: [100, 100] },
150
+ { count: 201, expectedBatchSizes: [100, 100, 1] },
151
+ { count: 1024, expectedBatchSizes: [100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 24] },
152
+ ];
153
+ for (const { count, expectedBatchSizes } of cases) {
154
+ const keys = Array.from({ length: count }, (_, index) => createPublicKey(index + 1));
155
+ const connectionState = createConnection(createExponentPricesData(keys), { accounts: createAccountFixtures(keys) });
156
+ const prices = await new fetcher_1.ExponentVaultsFetcher(connectionState.connection, PROGRAM_ID).fetchExponentPrices();
157
+ strict_1.default.deepEqual(connectionState.multipleAccountReads.map((batch) => batch.length), expectedBatchSizes, `count ${count}`);
158
+ strict_1.default.ok(connectionState.multipleAccountReads.every((batch) => batch.length <= 100), `count ${count}`);
159
+ strict_1.default.equal(connectionState.maxConcurrentMultipleAccountReads, count === 0 ? 0 : 1, `count ${count}`);
160
+ strict_1.default.deepEqual(connectionState.singleAccountReads.map((address) => address.toBase58()), [connectionState.registryAddress.toBase58()], `count ${count}`);
161
+ strict_1.default.deepEqual(connectionState.multipleAccountReads.flat().map((address) => address.toBase58()), keys.map((key) => key.toBase58()), `count ${count}`);
162
+ for (const [index, key] of keys.entries()) {
163
+ const price = prices.prices[index + 1];
164
+ strict_1.default.ok(price, `count ${count}, price ${index + 1}`);
165
+ strict_1.default.deepEqual(price.interfaceAccounts, [createPublicKey(128 + index)]);
166
+ strict_1.default.deepEqual(price.scopeConfig, {
167
+ maximumAgeSeconds: BigInt(index + 1),
168
+ priceChain: [index + 1, index + 2, index + 3, index + 4],
169
+ });
170
+ strict_1.default.equal(price.priceInterfaceAccounts.toBase58(), key.toBase58());
171
+ }
172
+ }
173
+ });
174
+ (0, node_test_1.default)("deduplicates nonzero price interface accounts and hydrates every matching price", async () => {
175
+ const firstKey = createPublicKey(250);
176
+ const secondKey = createPublicKey(1);
177
+ const keys = [firstKey, ZERO_PUBKEY, firstKey, secondKey];
178
+ strict_1.default.notDeepEqual([firstKey.toBase58(), secondKey.toBase58()], [firstKey.toBase58(), secondKey.toBase58()].sort());
179
+ const { connection, multipleAccountReads, registryAddress, singleAccountReads } = createConnection(createExponentPricesData(keys), { accounts: createAccountFixtures([firstKey, secondKey]) });
180
+ const prices = await new fetcher_1.ExponentVaultsFetcher(connection, PROGRAM_ID).fetchExponentPrices();
181
+ strict_1.default.deepEqual(singleAccountReads.map((address) => address.toBase58()), [registryAddress.toBase58()]);
182
+ strict_1.default.deepEqual(multipleAccountReads.map((batch) => batch.map((key) => key.toBase58())), [[firstKey.toBase58(), secondKey.toBase58()]]);
183
+ strict_1.default.deepEqual(prices.prices[1]?.interfaceAccounts, [createPublicKey(128)]);
184
+ strict_1.default.deepEqual(prices.prices[2]?.interfaceAccounts, []);
185
+ strict_1.default.deepEqual(prices.prices[3]?.interfaceAccounts, [createPublicKey(128)]);
186
+ strict_1.default.deepEqual(prices.prices[4]?.interfaceAccounts, [createPublicKey(129)]);
187
+ strict_1.default.strictEqual(prices.prices[1]?.interfaceAccounts, prices.prices[3]?.interfaceAccounts);
188
+ strict_1.default.ok(prices.prices[1]?.scopeConfig);
189
+ strict_1.default.strictEqual(prices.prices[1]?.scopeConfig, prices.prices[3]?.scopeConfig);
190
+ });
191
+ (0, node_test_1.default)("preserves PriceInterfaceAccounts validation errors and malformed RPC response failures", async () => {
192
+ const key = createPublicKey(1);
193
+ const registryData = createExponentPricesData([key]);
194
+ await strict_1.default.rejects(() => new fetcher_1.ExponentVaultsFetcher(createConnection(registryData).connection, PROGRAM_ID).fetchExponentPrices(), new Error(`PriceInterfaceAccounts account not found: ${key.toBase58()}`));
195
+ await strict_1.default.rejects(() => new fetcher_1.ExponentVaultsFetcher(createConnection(registryData, {
196
+ accounts: new Map([
197
+ [key.toBase58(), { data: createPriceInterfaceAccountsData([]), owner: createPublicKey(2) }],
198
+ ]),
199
+ }).connection, PROGRAM_ID).fetchExponentPrices(), new Error(`PriceInterfaceAccounts owner mismatch: expected ${PROGRAM_ID.toBase58()}, got ${createPublicKey(2).toBase58()}`));
200
+ await strict_1.default.rejects(() => new fetcher_1.ExponentVaultsFetcher(createConnection(registryData, { accounts: createAccountFixtures([key]), shortResponse: true }).connection, PROGRAM_ID).fetchExponentPrices(), new Error("PriceInterfaceAccounts batch size mismatch: requested 1, got 0"));
201
+ const rpcError = new Error("RPC unavailable");
202
+ await strict_1.default.rejects(() => new fetcher_1.ExponentVaultsFetcher(createConnection(registryData, { accounts: createAccountFixtures([key]), rpcError }).connection, PROGRAM_ID).fetchExponentPrices(), rpcError);
203
+ await strict_1.default.rejects(() => new fetcher_1.ExponentVaultsFetcher(createConnection(registryData, {
204
+ accounts: new Map([[key.toBase58(), { data: Buffer.alloc(1) }]]),
205
+ }).connection, PROGRAM_ID).fetchExponentPrices(), new Error("PriceInterfaceAccounts account too small: 1 bytes"));
206
+ });
207
+ (0, node_test_1.default)("reports a missing account at its indexed position in the second batch", async () => {
208
+ const keys = Array.from({ length: 102 }, (_, index) => createPublicKey(index + 1));
209
+ const accounts = createAccountFixtures(keys);
210
+ const missingKey = keys[101];
211
+ accounts.set(missingKey.toBase58(), null);
212
+ await strict_1.default.rejects(() => new fetcher_1.ExponentVaultsFetcher(createConnection(createExponentPricesData(keys), { accounts }).connection, PROGRAM_ID).fetchExponentPrices(), new Error(`PriceInterfaceAccounts account not found: ${missingKey.toBase58()}`));
213
+ });
214
+ (0, node_test_1.default)("reports an owner mismatch at its indexed position in a later batch", async () => {
215
+ const keys = Array.from({ length: 202 }, (_, index) => createPublicKey(index + 1));
216
+ const accounts = createAccountFixtures(keys);
217
+ const mismatchedKey = keys[201];
218
+ const unexpectedOwner = createPublicKey(250);
219
+ accounts.set(mismatchedKey.toBase58(), {
220
+ data: createPriceInterfaceAccountsData([]),
221
+ owner: unexpectedOwner,
222
+ });
223
+ await strict_1.default.rejects(() => new fetcher_1.ExponentVaultsFetcher(createConnection(createExponentPricesData(keys), { accounts }).connection, PROGRAM_ID).fetchExponentPrices(), new Error(`PriceInterfaceAccounts owner mismatch: expected ${PROGRAM_ID.toBase58()}, got ${unexpectedOwner.toBase58()}`));
224
+ });
225
+ //# sourceMappingURL=fetcher.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fetcher.test.js","sourceRoot":"","sources":["../src/fetcher.test.ts"],"names":[],"mappings":"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"}
package/build/types.d.ts CHANGED
@@ -235,9 +235,13 @@ export type ExponentPrice = {
235
235
  lastUpdatedAt: bigint;
236
236
  lastUpdatedSlot: bigint;
237
237
  priceType: number;
238
+ priceDecimals: number;
239
+ underlyingDecimals: number;
240
+ syPriceId: bigint;
238
241
  impliedApyBps: number | null;
239
242
  impliedApy: number | null;
240
243
  priceInterfaceAccounts: web3.PublicKey;
244
+ isInverse: boolean;
241
245
  interfaceAccounts: web3.PublicKey[];
242
246
  scopeConfig?: ScopePriceConfig | null;
243
247
  };
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":";;AA0QA,oCAAoC;AACpC,iCAAiC"}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":";;AA8QA,oCAAoC;AACpC,iCAAiC"}
package/package.json CHANGED
@@ -1,16 +1,18 @@
1
1
  {
2
2
  "name": "@exponent-labs/exponent-vaults-fetcher",
3
- "version": "0.9.24",
3
+ "version": "0.9.26",
4
4
  "main": "build/index.js",
5
5
  "types": "build/index.d.ts",
6
6
  "license": "AGPL-3.0",
7
7
  "scripts": {
8
- "build": "tsc --build"
8
+ "build": "tsc --build",
9
+ "pretest": "yarn build",
10
+ "test": "node --test build/fetcher.test.js build/priceInterfaceAccounts.test.js"
9
11
  },
10
12
  "dependencies": {
11
13
  "@coral-xyz/anchor": "0.30.1",
12
- "@exponent-labs/exponent-vaults-idl": "0.9.24",
13
- "@exponent-labs/exponent-vaults-pda": "0.9.24"
14
+ "@exponent-labs/exponent-vaults-idl": "0.9.26",
15
+ "@exponent-labs/exponent-vaults-pda": "0.9.26"
14
16
  },
15
17
  "devDependencies": {
16
18
  "@types/bn.js": "^5.1.0",
@@ -0,0 +1,346 @@
1
+ import { web3 } from "@coral-xyz/anchor"
2
+ import assert from "node:assert/strict"
3
+ import test from "node:test"
4
+
5
+ import { ExponentVaultsPDA } from "@exponent-labs/exponent-vaults-pda"
6
+
7
+ import { ExponentVaultsFetcher } from "./fetcher"
8
+
9
+ const EXPONENT_PRICES_DISCRIMINATOR = Buffer.from([188, 97, 196, 52, 192, 41, 211, 196])
10
+ const PRICE_INTERFACE_ACCOUNTS_DISCRIMINATOR = Buffer.from([166, 196, 173, 204, 35, 6, 104, 230])
11
+ const PROGRAM_ID = new web3.PublicKey(Uint8Array.from({ length: 32 }, (_, index) => index + 1))
12
+ const PRICE_MINT = new web3.PublicKey(Uint8Array.from({ length: 32 }, (_, index) => index + 33))
13
+
14
+ const MAX_PRICE_MANAGERS = 8
15
+ const MAX_PRICES = 1024
16
+ const PUBKEY_BYTES = 32
17
+ const PRICE_NODE_REGISTERS_SIZE = 16
18
+ const EXPONENT_PRICE_SIZE = 224
19
+ const PRICE_NODE_SIZE = PRICE_NODE_REGISTERS_SIZE + EXPONENT_PRICE_SIZE
20
+ const PRICE_NODES_OFFSET = 8 + 8 + MAX_PRICE_MANAGERS * PUBKEY_BYTES + 16
21
+ const FIRST_PRICE_VALUE_OFFSET = PRICE_NODES_OFFSET + PRICE_NODE_REGISTERS_SIZE
22
+ const EXPONENT_PRICES_SIZE = PRICE_NODES_OFFSET + MAX_PRICES * PRICE_NODE_SIZE + 128
23
+
24
+ const PRICE_DECIMALS = 6
25
+ const UNDERLYING_DECIMALS = 9
26
+ const SY_PRICE_ID = 0x0807060504030201n
27
+ const ZERO_PUBKEY = new web3.PublicKey(new Uint8Array(PUBKEY_BYTES))
28
+
29
+ type ScopeConfigFixture = {
30
+ maximumAgeSeconds: bigint
31
+ priceChain: readonly [number, number, number, number]
32
+ }
33
+
34
+ type AccountFixture = {
35
+ data: Buffer
36
+ owner?: web3.PublicKey
37
+ }
38
+
39
+ type ConnectionOptions = {
40
+ accounts?: ReadonlyMap<string, AccountFixture | null>
41
+ rpcError?: Error
42
+ shortResponse?: boolean
43
+ }
44
+
45
+ function createPublicKey(seed: number): web3.PublicKey {
46
+ const bytes = new Uint8Array(PUBKEY_BYTES).fill(255)
47
+ new DataView(bytes.buffer).setUint32(0, seed, true)
48
+ return new web3.PublicKey(bytes)
49
+ }
50
+
51
+ function createExponentPricesData(priceInterfaceAccounts: readonly web3.PublicKey[], reservedByte = 0): Buffer {
52
+ const data = Buffer.alloc(EXPONENT_PRICES_SIZE)
53
+ EXPONENT_PRICES_DISCRIMINATOR.copy(data)
54
+ data.writeBigUInt64LE(BigInt(priceInterfaceAccounts.length), 8 + 8 + MAX_PRICE_MANAGERS * PUBKEY_BYTES)
55
+
56
+ for (const [index, priceInterfaceAccount] of priceInterfaceAccounts.entries()) {
57
+ const valueOffset = FIRST_PRICE_VALUE_OFFSET + index * PRICE_NODE_SIZE
58
+ PRICE_MINT.toBuffer().copy(data, valueOffset)
59
+ priceInterfaceAccount.toBuffer().copy(data, valueOffset + 128)
60
+ data.writeUInt8(PRICE_DECIMALS, valueOffset + 160)
61
+ data.writeUInt8(UNDERLYING_DECIMALS, valueOffset + 161)
62
+ data.fill(reservedByte, valueOffset + 162, valueOffset + 168)
63
+ data.writeBigUInt64LE(SY_PRICE_ID, valueOffset + 168)
64
+ data.fill(reservedByte, valueOffset + 176, valueOffset + EXPONENT_PRICE_SIZE)
65
+ }
66
+
67
+ return data
68
+ }
69
+
70
+ function createPriceInterfaceAccountsData(
71
+ interfaceAccounts: readonly web3.PublicKey[],
72
+ scopeConfig?: ScopeConfigFixture,
73
+ ): Buffer {
74
+ const data = Buffer.alloc(12 + interfaceAccounts.length * PUBKEY_BYTES + (scopeConfig ? 17 : 0))
75
+ PRICE_INTERFACE_ACCOUNTS_DISCRIMINATOR.copy(data)
76
+ data.writeUInt32LE(interfaceAccounts.length, 8)
77
+ interfaceAccounts.forEach((account, index) => account.toBuffer().copy(data, 12 + index * PUBKEY_BYTES))
78
+
79
+ if (scopeConfig) {
80
+ const stateOffset = 12 + interfaceAccounts.length * PUBKEY_BYTES
81
+ data.writeUInt8(2, stateOffset)
82
+ scopeConfig.priceChain.forEach((price, index) => data.writeUInt16LE(price, stateOffset + 1 + index * 2))
83
+ data.writeBigUInt64LE(scopeConfig.maximumAgeSeconds, stateOffset + 9)
84
+ }
85
+
86
+ return data
87
+ }
88
+
89
+ function createConnection(registryData: Buffer, options: ConnectionOptions = {}) {
90
+ const registryAddress = new ExponentVaultsPDA(PROGRAM_ID).exponentPrices()[0]
91
+ const singleAccountReads: web3.PublicKey[] = []
92
+ const multipleAccountReads: web3.PublicKey[][] = []
93
+ let activeMultipleAccountReads = 0
94
+ let maxConcurrentMultipleAccountReads = 0
95
+
96
+ const connection = {
97
+ async getAccountInfo(address: web3.PublicKey) {
98
+ singleAccountReads.push(address)
99
+ if (!address.equals(registryAddress)) {
100
+ throw new Error(`Unexpected getAccountInfo for PriceInterfaceAccounts: ${address.toBase58()}`)
101
+ }
102
+ return {
103
+ data: registryData,
104
+ executable: false,
105
+ lamports: 1,
106
+ owner: PROGRAM_ID,
107
+ rentEpoch: 0,
108
+ }
109
+ },
110
+ async getMultipleAccountsInfo(addresses: web3.PublicKey[]) {
111
+ multipleAccountReads.push(addresses)
112
+ activeMultipleAccountReads += 1
113
+ maxConcurrentMultipleAccountReads = Math.max(maxConcurrentMultipleAccountReads, activeMultipleAccountReads)
114
+ try {
115
+ await Promise.resolve()
116
+ if (options.rpcError) throw options.rpcError
117
+
118
+ const infos = addresses.map((address) => {
119
+ const fixture = options.accounts?.get(address.toBase58())
120
+ if (fixture === null || !fixture) return null
121
+ return {
122
+ data: fixture.data,
123
+ executable: false,
124
+ lamports: 1,
125
+ owner: fixture.owner ?? PROGRAM_ID,
126
+ rentEpoch: 0,
127
+ }
128
+ })
129
+ return options.shortResponse ? infos.slice(0, -1) : infos
130
+ } finally {
131
+ activeMultipleAccountReads -= 1
132
+ }
133
+ },
134
+ } as unknown as web3.Connection
135
+
136
+ return {
137
+ connection,
138
+ multipleAccountReads,
139
+ get maxConcurrentMultipleAccountReads() {
140
+ return maxConcurrentMultipleAccountReads
141
+ },
142
+ registryAddress,
143
+ singleAccountReads,
144
+ }
145
+ }
146
+
147
+ function createAccountFixtures(keys: readonly web3.PublicKey[]): Map<string, AccountFixture> {
148
+ return new Map(
149
+ keys.map((key, index) => [
150
+ key.toBase58(),
151
+ {
152
+ data: createPriceInterfaceAccountsData([createPublicKey(128 + index)], {
153
+ maximumAgeSeconds: BigInt(index + 1),
154
+ priceChain: [index + 1, index + 2, index + 3, index + 4],
155
+ }),
156
+ },
157
+ ]),
158
+ )
159
+ }
160
+
161
+ test("decodes price metadata from exact wire offsets without consuming reserved bytes", async () => {
162
+ for (const reservedByte of [0xa5, 0x5a]) {
163
+ const { connection } = createConnection(createExponentPricesData([ZERO_PUBKEY], reservedByte))
164
+ const fetcher = new ExponentVaultsFetcher(connection, PROGRAM_ID)
165
+ const prices = await fetcher.fetchExponentPrices()
166
+ const price = prices.prices[1]
167
+
168
+ assert.ok(price)
169
+ assert.equal(price.priceDecimals, PRICE_DECIMALS)
170
+ assert.equal(price.underlyingDecimals, UNDERLYING_DECIMALS)
171
+ assert.equal(price.syPriceId, SY_PRICE_ID)
172
+ }
173
+ })
174
+
175
+ test("fetches unique price interface accounts sequentially in maximum 100-key batches", async () => {
176
+ const cases = [
177
+ { count: 0, expectedBatchSizes: [] },
178
+ { count: 1, expectedBatchSizes: [1] },
179
+ { count: 99, expectedBatchSizes: [99] },
180
+ { count: 100, expectedBatchSizes: [100] },
181
+ { count: 101, expectedBatchSizes: [100, 1] },
182
+ { count: 200, expectedBatchSizes: [100, 100] },
183
+ { count: 201, expectedBatchSizes: [100, 100, 1] },
184
+ { count: 1024, expectedBatchSizes: [100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 24] },
185
+ ]
186
+
187
+ for (const { count, expectedBatchSizes } of cases) {
188
+ const keys = Array.from({ length: count }, (_, index) => createPublicKey(index + 1))
189
+ const connectionState = createConnection(createExponentPricesData(keys), { accounts: createAccountFixtures(keys) })
190
+
191
+ const prices = await new ExponentVaultsFetcher(connectionState.connection, PROGRAM_ID).fetchExponentPrices()
192
+
193
+ assert.deepEqual(
194
+ connectionState.multipleAccountReads.map((batch) => batch.length),
195
+ expectedBatchSizes,
196
+ `count ${count}`,
197
+ )
198
+ assert.ok(
199
+ connectionState.multipleAccountReads.every((batch) => batch.length <= 100),
200
+ `count ${count}`,
201
+ )
202
+ assert.equal(connectionState.maxConcurrentMultipleAccountReads, count === 0 ? 0 : 1, `count ${count}`)
203
+ assert.deepEqual(
204
+ connectionState.singleAccountReads.map((address) => address.toBase58()),
205
+ [connectionState.registryAddress.toBase58()],
206
+ `count ${count}`,
207
+ )
208
+ assert.deepEqual(
209
+ connectionState.multipleAccountReads.flat().map((address) => address.toBase58()),
210
+ keys.map((key) => key.toBase58()),
211
+ `count ${count}`,
212
+ )
213
+ for (const [index, key] of keys.entries()) {
214
+ const price = prices.prices[index + 1]
215
+ assert.ok(price, `count ${count}, price ${index + 1}`)
216
+ assert.deepEqual(price.interfaceAccounts, [createPublicKey(128 + index)])
217
+ assert.deepEqual(price.scopeConfig, {
218
+ maximumAgeSeconds: BigInt(index + 1),
219
+ priceChain: [index + 1, index + 2, index + 3, index + 4],
220
+ })
221
+ assert.equal(price.priceInterfaceAccounts.toBase58(), key.toBase58())
222
+ }
223
+ }
224
+ })
225
+
226
+ test("deduplicates nonzero price interface accounts and hydrates every matching price", async () => {
227
+ const firstKey = createPublicKey(250)
228
+ const secondKey = createPublicKey(1)
229
+ const keys = [firstKey, ZERO_PUBKEY, firstKey, secondKey]
230
+ assert.notDeepEqual([firstKey.toBase58(), secondKey.toBase58()], [firstKey.toBase58(), secondKey.toBase58()].sort())
231
+ const { connection, multipleAccountReads, registryAddress, singleAccountReads } = createConnection(
232
+ createExponentPricesData(keys),
233
+ { accounts: createAccountFixtures([firstKey, secondKey]) },
234
+ )
235
+
236
+ const prices = await new ExponentVaultsFetcher(connection, PROGRAM_ID).fetchExponentPrices()
237
+
238
+ assert.deepEqual(
239
+ singleAccountReads.map((address) => address.toBase58()),
240
+ [registryAddress.toBase58()],
241
+ )
242
+ assert.deepEqual(
243
+ multipleAccountReads.map((batch) => batch.map((key) => key.toBase58())),
244
+ [[firstKey.toBase58(), secondKey.toBase58()]],
245
+ )
246
+ assert.deepEqual(prices.prices[1]?.interfaceAccounts, [createPublicKey(128)])
247
+ assert.deepEqual(prices.prices[2]?.interfaceAccounts, [])
248
+ assert.deepEqual(prices.prices[3]?.interfaceAccounts, [createPublicKey(128)])
249
+ assert.deepEqual(prices.prices[4]?.interfaceAccounts, [createPublicKey(129)])
250
+ assert.strictEqual(prices.prices[1]?.interfaceAccounts, prices.prices[3]?.interfaceAccounts)
251
+ assert.ok(prices.prices[1]?.scopeConfig)
252
+ assert.strictEqual(prices.prices[1]?.scopeConfig, prices.prices[3]?.scopeConfig)
253
+ })
254
+
255
+ test("preserves PriceInterfaceAccounts validation errors and malformed RPC response failures", async () => {
256
+ const key = createPublicKey(1)
257
+ const registryData = createExponentPricesData([key])
258
+
259
+ await assert.rejects(
260
+ () => new ExponentVaultsFetcher(createConnection(registryData).connection, PROGRAM_ID).fetchExponentPrices(),
261
+ new Error(`PriceInterfaceAccounts account not found: ${key.toBase58()}`),
262
+ )
263
+
264
+ await assert.rejects(
265
+ () =>
266
+ new ExponentVaultsFetcher(
267
+ createConnection(registryData, {
268
+ accounts: new Map([
269
+ [key.toBase58(), { data: createPriceInterfaceAccountsData([]), owner: createPublicKey(2) }],
270
+ ]),
271
+ }).connection,
272
+ PROGRAM_ID,
273
+ ).fetchExponentPrices(),
274
+ new Error(
275
+ `PriceInterfaceAccounts owner mismatch: expected ${PROGRAM_ID.toBase58()}, got ${createPublicKey(2).toBase58()}`,
276
+ ),
277
+ )
278
+
279
+ await assert.rejects(
280
+ () =>
281
+ new ExponentVaultsFetcher(
282
+ createConnection(registryData, { accounts: createAccountFixtures([key]), shortResponse: true }).connection,
283
+ PROGRAM_ID,
284
+ ).fetchExponentPrices(),
285
+ new Error("PriceInterfaceAccounts batch size mismatch: requested 1, got 0"),
286
+ )
287
+
288
+ const rpcError = new Error("RPC unavailable")
289
+ await assert.rejects(
290
+ () =>
291
+ new ExponentVaultsFetcher(
292
+ createConnection(registryData, { accounts: createAccountFixtures([key]), rpcError }).connection,
293
+ PROGRAM_ID,
294
+ ).fetchExponentPrices(),
295
+ rpcError,
296
+ )
297
+
298
+ await assert.rejects(
299
+ () =>
300
+ new ExponentVaultsFetcher(
301
+ createConnection(registryData, {
302
+ accounts: new Map([[key.toBase58(), { data: Buffer.alloc(1) }]]),
303
+ }).connection,
304
+ PROGRAM_ID,
305
+ ).fetchExponentPrices(),
306
+ new Error("PriceInterfaceAccounts account too small: 1 bytes"),
307
+ )
308
+ })
309
+
310
+ test("reports a missing account at its indexed position in the second batch", async () => {
311
+ const keys = Array.from({ length: 102 }, (_, index) => createPublicKey(index + 1))
312
+ const accounts = createAccountFixtures(keys)
313
+ const missingKey = keys[101]
314
+ accounts.set(missingKey.toBase58(), null)
315
+
316
+ await assert.rejects(
317
+ () =>
318
+ new ExponentVaultsFetcher(
319
+ createConnection(createExponentPricesData(keys), { accounts }).connection,
320
+ PROGRAM_ID,
321
+ ).fetchExponentPrices(),
322
+ new Error(`PriceInterfaceAccounts account not found: ${missingKey.toBase58()}`),
323
+ )
324
+ })
325
+
326
+ test("reports an owner mismatch at its indexed position in a later batch", async () => {
327
+ const keys = Array.from({ length: 202 }, (_, index) => createPublicKey(index + 1))
328
+ const accounts = createAccountFixtures(keys)
329
+ const mismatchedKey = keys[201]
330
+ const unexpectedOwner = createPublicKey(250)
331
+ accounts.set(mismatchedKey.toBase58(), {
332
+ data: createPriceInterfaceAccountsData([]),
333
+ owner: unexpectedOwner,
334
+ })
335
+
336
+ await assert.rejects(
337
+ () =>
338
+ new ExponentVaultsFetcher(
339
+ createConnection(createExponentPricesData(keys), { accounts }).connection,
340
+ PROGRAM_ID,
341
+ ).fetchExponentPrices(),
342
+ new Error(
343
+ `PriceInterfaceAccounts owner mismatch: expected ${PROGRAM_ID.toBase58()}, got ${unexpectedOwner.toBase58()}`,
344
+ ),
345
+ )
346
+ })