Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
308 changes: 248 additions & 60 deletions sdk/scripts/client-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,14 @@ import {
ProgramAccount,
} from '@coral-xyz/anchor';
import driftIDL from '../src/idl/drift.json';
import assert from 'assert';

const GRPC_ENDPOINT = process.env.GRPC_ENDPOINT;
const TOKEN = process.env.TOKEN;
const RPC_ENDPOINT = process.env.RPC_ENDPOINT;

async function initializeGrpcDriftClientV2VersusV1() {
const connection = new Connection('https://api.mainnet-beta.solana.com');
const connection = new Connection(RPC_ENDPOINT);
const wallet = new Wallet(new Keypair());
dotenv.config({ path: '../' });

Expand All @@ -34,49 +36,38 @@ async function initializeGrpcDriftClientV2VersusV1() {
// @ts-ignore
wallet,
{
commitment: 'confirmed',
commitment: 'processed',
}
);

const program = new Program(driftIDL as Idl, programId, provider);

const perpMarketIndexes = [4];
const spotMarketIndexes = [32];

const perpMarketProgramAccounts = (
await program.account.perpMarket.all()
).filter((a) =>
perpMarketIndexes.includes(a.account.marketIndex as number)
) as ProgramAccount<PerpMarketAccount>[];
const spotMarketProgramAccounts = (
await program.account.spotMarket.all()
).filter((a) =>
spotMarketIndexes.includes(a.account.marketIndex as number)
) as ProgramAccount<SpotMarketAccount>[];

// const perpMarketIndexes = perpMarketProgramAccounts.map(
// (a) => a.account.marketIndex
// );
// const spotMarketIndexes = spotMarketProgramAccounts.map(
// (a) => a.account.marketIndex
// );
// const oracleInfos = [
// {
// publicKey: new PublicKey('BERaNi6cpEresbq6HC1EQGaB1H1UjvEo4NGnmYSSJof4'),
// source: OracleSource.PYTH_LAZER,
// },
// {
// publicKey: new PublicKey('BERaNi6cpEresbq6HC1EQGaB1H1UjvEo4NGnmYSSJof4'),
// source: OracleSource.PYTH_LAZER_1M,
// },
// ];
const allPerpMarketProgramAccounts =
(await program.account.perpMarket.all()) as ProgramAccount<PerpMarketAccount>[];
const perpMarketProgramAccounts = allPerpMarketProgramAccounts.filter((val) =>
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15].includes(
val.account.marketIndex
)
);
const perpMarketIndexes = perpMarketProgramAccounts.map(
(val) => val.account.marketIndex
);

const allSpotMarketProgramAccounts =
(await program.account.spotMarket.all()) as ProgramAccount<SpotMarketAccount>[];
const spotMarketProgramAccounts = allSpotMarketProgramAccounts.filter((val) =>
[0, 1, 2, 3, 4, 5].includes(val.account.marketIndex)
);
const spotMarketIndexes = spotMarketProgramAccounts.map(
(val) => val.account.marketIndex
);

const seen = new Set<string>();
const oracleInfos: OracleInfo[] = [];
for (const acct of perpMarketProgramAccounts) {
const key = `${acct.account.amm.oracle.toBase58()}-${Object.keys(
acct.account.amm.oracleSource ?? {}
)?.[0]}`;
const key = `${acct.account.amm.oracle.toBase58()}-${
Object.keys(acct.account.amm.oracleSource)[0]
}`;
if (!seen.has(key)) {
seen.add(key);
oracleInfos.push({
Expand All @@ -86,9 +77,9 @@ async function initializeGrpcDriftClientV2VersusV1() {
}
}
for (const acct of spotMarketProgramAccounts) {
const key = `${acct.account.oracle.toBase58()}-${Object.keys(
acct.account.oracleSource ?? {}
)?.[0]}`;
const key = `${acct.account.oracle.toBase58()}-${
Object.keys(acct.account.oracleSource)[0]
}`;
if (!seen.has(key)) {
seen.add(key);
oracleInfos.push({
Expand All @@ -103,7 +94,7 @@ async function initializeGrpcDriftClientV2VersusV1() {
grpcConfigs: {
endpoint: GRPC_ENDPOINT,
token: TOKEN,
commitmentLevel: 'confirmed' as unknown as CommitmentLevel,
commitmentLevel: CommitmentLevel.PROCESSED,
channelOptions: {
'grpc.keepalive_time_ms': 10_000,
'grpc.keepalive_timeout_ms': 1_000,
Expand All @@ -119,7 +110,6 @@ async function initializeGrpcDriftClientV2VersusV1() {
accountSubscription: {
...baseAccountSubscription,
driftClientAccountSubscriber: grpcDriftClientAccountSubscriberV2,
logResubMessages: true,
},
perpMarketIndexes,
spotMarketIndexes,
Expand All @@ -133,7 +123,6 @@ async function initializeGrpcDriftClientV2VersusV1() {
accountSubscription: {
...baseAccountSubscription,
driftClientAccountSubscriber: grpcDriftClientAccountSubscriber,
// logResubMessages: true,
},
perpMarketIndexes,
spotMarketIndexes,
Expand All @@ -144,28 +133,227 @@ async function initializeGrpcDriftClientV2VersusV1() {
const clientV1 = new DriftClient(configV1);

await Promise.all([clientV1.subscribe(), clientV2.subscribe()]);

clientV2.eventEmitter.on('oraclePriceUpdate', (pubkey, source, data) => {
const key = pubkey.toBase58();
const src = Object.keys(source ?? {})[0];
console.log(
`v2 oracle update ${key} (${src}) price ${data.price.toString()}`
);
});
const compare = () => {
for (const idx of perpMarketIndexes) {
const p1 = clientV1.getOracleDataForPerpMarket(idx).price;
const p2 = clientV2.getOracleDataForPerpMarket(idx).price;
console.log(
`perp mkt ${idx} | v1 ${p1.toString()} | v2 ${p2.toString()}`
try {
// 1. Test getStateAccountAndSlot
const state1 = clientV1.accountSubscriber.getStateAccountAndSlot();
const state2 = clientV2.accountSubscriber.getStateAccountAndSlot();
assert.deepStrictEqual(
state1.data,
state2.data,
'State accounts should match'
);
}
for (const idx of spotMarketIndexes) {
const s1 = clientV1.getOracleDataForSpotMarket(idx).price;
const s2 = clientV2.getOracleDataForSpotMarket(idx).price;
console.log(
`spot mkt ${idx} | v1 ${s1.toString()} | v2 ${s2.toString()}`
if (
state1.slot !== undefined &&
state2.slot !== undefined &&
state2.slot < state1.slot
) {
console.error(
`State account slot regression: v2 slot ${state2.slot} < v1 slot ${state1.slot}`
);
}

// 2. Test getMarketAccountsAndSlots (all perp markets) - sorted comparison
const allPerpMarkets1 = clientV1.accountSubscriber
.getMarketAccountsAndSlots()
.sort((a, b) => a.data.marketIndex - b.data.marketIndex);
const allPerpMarkets2 = clientV2.accountSubscriber
.getMarketAccountsAndSlots()
.sort((a, b) => a.data.marketIndex - b.data.marketIndex);
assert.strictEqual(
allPerpMarkets1.length,
allPerpMarkets2.length,
'Number of perp markets should match'
);

// Compare each perp market in the sorted arrays
for (let i = 0; i < allPerpMarkets1.length; i++) {
const market1 = allPerpMarkets1[i];
const market2 = allPerpMarkets2[i];
assert.strictEqual(
market1.data.marketIndex,
market2.data.marketIndex,
`Perp market at position ${i} should have same marketIndex`
);
// assert.deepStrictEqual(
// market1.data,
// market2.data,
// `Perp market ${market1.data.marketIndex} (from getMarketAccountsAndSlots) should match`
// );
}

// 3. Test getMarketAccountAndSlot for each perp market
for (const idx of perpMarketIndexes) {
const market1 = clientV1.accountSubscriber.getMarketAccountAndSlot(idx);
const market2 = clientV2.accountSubscriber.getMarketAccountAndSlot(idx);
// assert.deepStrictEqual(
// market1?.data,
// market2?.data,
// `Perp market ${idx} data should match`
// );
// assert.strictEqual(
// market1?.slot,
// market2?.slot,
// `Perp market ${idx} slot should match`
// );
if (
market1?.slot !== undefined &&
market2?.slot !== undefined &&
market2.slot < market1.slot
) {
console.error(
`Perp market ${idx} slot regression: v2 slot ${market2.slot} < v1 slot ${market1.slot}`
);
} else if (
market1?.slot !== undefined &&
market2?.slot !== undefined &&
market2.slot > market1.slot
) {
console.info(
`Perp market ${idx} slot is FASTER! v2: ${market2.slot}, v1: ${market1.slot}`
);
}
}

// 4. Test getSpotMarketAccountsAndSlots (all spot markets) - sorted comparison
const allSpotMarkets1 = clientV1.accountSubscriber
.getSpotMarketAccountsAndSlots()
.sort((a, b) => a.data.marketIndex - b.data.marketIndex);
const allSpotMarkets2 = clientV2.accountSubscriber
.getSpotMarketAccountsAndSlots()
.sort((a, b) => a.data.marketIndex - b.data.marketIndex);
assert.strictEqual(
allSpotMarkets1.length,
allSpotMarkets2.length,
'Number of spot markets should match'
);

// Compare each spot market in the sorted arrays
for (let i = 0; i < allSpotMarkets1.length; i++) {
const market1 = allSpotMarkets1[i];
const market2 = allSpotMarkets2[i];
assert.strictEqual(
market1.data.marketIndex,
market2.data.marketIndex,
`Spot market at position ${i} should have same marketIndex`
);
// assert.deepStrictEqual(
// market1.data,
// market2.data,
// `Spot market ${market1.data.marketIndex} (from getSpotMarketAccountsAndSlots) should match`
// );
}

// 5. Test getSpotMarketAccountAndSlot for each spot market
for (const idx of spotMarketIndexes) {
const market1 =
clientV1.accountSubscriber.getSpotMarketAccountAndSlot(idx);
const market2 =
clientV2.accountSubscriber.getSpotMarketAccountAndSlot(idx);
// assert.deepStrictEqual(
// market1?.data,
// market2?.data,
// `Spot market ${idx} data should match`
// );
// assert.strictEqual(
// market1?.slot,
// market2?.slot,
// `Spot market ${idx} slot should match`
// );
if (
market1?.slot !== undefined &&
market2?.slot !== undefined &&
market2.slot < market1.slot
) {
console.error(
`Spot market ${idx} slot regression: v2 slot ${market2.slot} < v1 slot ${market1.slot}`
);
} else if (
market1?.slot !== undefined &&
market2?.slot !== undefined &&
market2.slot > market1.slot
) {
console.info(
`Spot market ${idx} slot is FASTER! v2: ${market2.slot}, v1: ${market1.slot}`
);
}
}

// 6. Test getOraclePriceDataAndSlotForPerpMarket
for (const idx of perpMarketIndexes) {
const oracle1 =
clientV1.accountSubscriber.getOraclePriceDataAndSlotForPerpMarket(
idx
);
const oracle2 =
clientV2.accountSubscriber.getOraclePriceDataAndSlotForPerpMarket(
idx
);
// assert.deepStrictEqual(
// oracle1?.data,
// oracle2?.data,
// `Perp market ${idx} oracle data should match`
// );
// Note: slots might differ slightly due to timing, so we can optionally skip this check or be lenient
// assert.strictEqual(oracle1?.slot, oracle2?.slot, `Perp market ${idx} oracle slot should match`);
if (
oracle1?.slot !== undefined &&
oracle2?.slot !== undefined &&
oracle2.slot < oracle1.slot
) {
console.error(
`Perp market ${idx} oracle slot regression: v2 slot ${oracle2.slot} < v1 slot ${oracle1.slot}`
);
} else if (
oracle1?.slot !== undefined &&
oracle2?.slot !== undefined &&
oracle2.slot > oracle1.slot
) {
console.info(
`Perp market ${idx} oracle slot is FASTER! v2: ${oracle2.slot}, v1: ${oracle1.slot}`
);
}
}

// 7. Test getOraclePriceDataAndSlotForSpotMarket
for (const idx of spotMarketIndexes) {
const oracle1 =
clientV1.accountSubscriber.getOraclePriceDataAndSlotForSpotMarket(
idx
);
const oracle2 =
clientV2.accountSubscriber.getOraclePriceDataAndSlotForSpotMarket(
idx
);
// assert.deepStrictEqual(
// oracle1?.data,
// oracle2?.data,
// `Spot market ${idx} oracle data should match`
// );
// Note: slots might differ slightly due to timing
// assert.strictEqual(oracle1?.slot, oracle2?.slot, `Spot market ${idx} oracle slot should match`);
if (
oracle1?.slot !== undefined &&
oracle2?.slot !== undefined &&
oracle2.slot < oracle1.slot
) {
console.error(
`Spot market ${idx} oracle slot regression: v2 slot ${oracle2.slot} < v1 slot ${oracle1.slot}`
);
} else if (
oracle1?.slot !== undefined &&
oracle2?.slot !== undefined &&
oracle2.slot > oracle1.slot
) {
console.info(
`Spot market ${idx} oracle slot is FASTER! v2: ${oracle2.slot}, v1: ${oracle1.slot}`
);
}
}

console.log('✓ All comparisons passed');
} catch (error) {
console.error('✗ Comparison failed:', error);
}
};

Expand Down
Loading
Loading