Skip to content

Commit

Permalink
Nour/pyth local val test (#1391)
Browse files Browse the repository at this point in the history
* fix local val tests attempt

* pyth lazer works

* fix anchor test
  • Loading branch information
NourAlharithi authored Dec 18, 2024
1 parent 40eb187 commit cdab664
Show file tree
Hide file tree
Showing 10 changed files with 75 additions and 66 deletions.
2 changes: 1 addition & 1 deletion programs/drift/src/instructions/keeper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -696,7 +696,7 @@ pub fn place_swift_taker_order<'c: 'info, 'info>(

// Set max slot for the order early so we set correct swift order id
let order_slot = taker_order_params_message.slot;
if order_slot < clock.slot - 500 {
if order_slot < clock.slot.saturating_sub(500) {
msg!(
"Swift order slot {} is too old: must be within 500 slots of current slot",
order_slot
Expand Down
2 changes: 1 addition & 1 deletion programs/drift/src/instructions/pyth_lazer_oracle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ pub fn handle_update_pyth_lazer_oracle<'c: 'info, 'info>(
&pyth_message,
ix_idx - 1,
0,
0,
12, // 8 bytes for anchor ix discriminator, 4 bytes for borsh vec len encoding
);

if verified.is_err() {
Expand Down
1 change: 1 addition & 0 deletions sdk/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
"@pythnetwork/client": "2.5.3",
"@pythnetwork/price-service-sdk": "1.7.1",
"@pythnetwork/pyth-solana-receiver": "0.7.0",
"@solana/buffer-layout": "4.0.1",
"@solana/spl-token": "0.3.7",
"@solana/web3.js": "1.92.3",
"@switchboard-xyz/on-demand": "1.2.42",
Expand Down
5 changes: 2 additions & 3 deletions sdk/src/driftClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8575,12 +8575,11 @@ export class DriftClient {
overrideIxCount?: number
): TransactionInstruction[] {
const pythMessageBytes = Buffer.from(pythMessageHex, 'hex');
const updateData = new Uint8Array(pythMessageBytes);

const verifyIx = createMinimalEd25519VerifyIx(
overrideIxCount || precedingIxs.length + 1,
0,
updateData
12,
pythMessageBytes
);

const remainingAccountsMeta = feedIds.map((feedId) => {
Expand Down
2 changes: 1 addition & 1 deletion sdk/src/idl/drift.json
Original file line number Diff line number Diff line change
Expand Up @@ -14315,7 +14315,7 @@
{
"code": 6288,
"name": "InvalidSwiftOrderParam",
"msg": "Swift only available for market/oracle perp orders"
"msg": "Invalid swift order param"
},
{
"code": 6289,
Expand Down
113 changes: 58 additions & 55 deletions sdk/src/util/pythOracleUtils.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
import {
SYSVAR_INSTRUCTIONS_PUBKEY,
TransactionInstruction,
Ed25519Program,
} from '@solana/web3.js';
import { TransactionInstruction, Ed25519Program } from '@solana/web3.js';
import * as BufferLayout from '@solana/buffer-layout';

export function trimFeedId(feedId: string): string {
if (feedId.startsWith('0x')) {
Expand All @@ -21,10 +18,14 @@ const PUBKEY_LEN = 32;
const MAGIC_LEN = 4;
const MESSAGE_SIZE_LEN = 2;

export function getEd25519ArgsFromHex(hex: string): {
export function getEd25519ArgsFromHex(
hex: string,
customInstructionIndex?: number
): {
publicKey: Uint8Array;
signature: Uint8Array;
message: Uint8Array;
instructionIndex?: number;
} {
const cleanedHex = hex.startsWith('0x') ? hex.slice(2) : hex;
const buffer = new Uint8Array(Buffer.from(cleanedHex, 'hex'));
Expand Down Expand Up @@ -58,9 +59,38 @@ export function getEd25519ArgsFromHex(hex: string): {
publicKey,
signature,
message,
instructionIndex: customInstructionIndex,
};
}

const readUint16LE = (data: Uint8Array, offset: number) => {
return data[offset] | (data[offset + 1] << 8);
};

const ED25519_INSTRUCTION_LAYOUT = BufferLayout.struct<
Readonly<{
messageDataOffset: number;
messageDataSize: number;
messageInstructionIndex: number;
numSignatures: number;
padding: number;
publicKeyInstructionIndex: number;
publicKeyOffset: number;
signatureInstructionIndex: number;
signatureOffset: number;
}>
>([
BufferLayout.u8('numSignatures'),
BufferLayout.u8('padding'),
BufferLayout.u16('signatureOffset'),
BufferLayout.u16('signatureInstructionIndex'),
BufferLayout.u16('publicKeyOffset'),
BufferLayout.u16('publicKeyInstructionIndex'),
BufferLayout.u16('messageDataOffset'),
BufferLayout.u16('messageDataSize'),
BufferLayout.u16('messageInstructionIndex'),
]);

/**
* Constructs a minimal Ed25519 verification instruction that references the data
* inside the main instruction (postPythLazerOracleUpdate).
Expand All @@ -79,58 +109,31 @@ export function createMinimalEd25519VerifyIx(
const messageDataSizeOffset = publicKeyOffset + PUBKEY_LEN;
const messageDataOffset = messageDataSizeOffset + MESSAGE_SIZE_LEN;

if (messageDataOffset > customInstructionData.length) {
throw new Error('Not enough data in main instruction to read message size');
}
const messageDataSize = readUint16LE(
customInstructionData,
messageDataSizeOffset - messageOffset
);

const messageSize =
customInstructionData[messageDataSizeOffset] |
(customInstructionData[messageDataSizeOffset + 1] << 8);

// Construct Ed25519SignatureOffsets
// struct Ed25519SignatureOffsets (14 bytes):
// u16 signature_offset
// u16 signature_instruction_index
// u16 public_key_offset
// u16 public_key_instruction_index
// u16 message_data_offset
// u16 message_data_size
// u16 message_instruction_index
const offsets = new Uint8Array(14);
const dv = new DataView(offsets.buffer);

let byteOffset = 0;
dv.setUint16(byteOffset, signatureOffset, true);
byteOffset += 2;
dv.setUint16(byteOffset, customInstructionIndex, true);
byteOffset += 2;
dv.setUint16(byteOffset, publicKeyOffset, true);
byteOffset += 2;
dv.setUint16(byteOffset, customInstructionIndex, true);
byteOffset += 2;
dv.setUint16(byteOffset, messageDataOffset, true);
byteOffset += 2;
dv.setUint16(byteOffset, messageSize, true);
byteOffset += 2;
dv.setUint16(byteOffset, customInstructionIndex, true);
byteOffset += 2;

const numSignatures = 1;
const padding = 0;
const ixData = new Uint8Array(2 + offsets.length);
ixData[0] = numSignatures;
ixData[1] = padding;
ixData.set(offsets, 2);
const instructionData = Buffer.alloc(16);

ED25519_INSTRUCTION_LAYOUT.encode(
{
numSignatures: 1,
padding: 0,
signatureOffset,
signatureInstructionIndex: customInstructionIndex,
publicKeyOffset,
publicKeyInstructionIndex: customInstructionIndex,
messageDataOffset,
messageDataSize: messageDataSize,
messageInstructionIndex: customInstructionIndex,
},
instructionData
);

return new TransactionInstruction({
keys: [
{
pubkey: SYSVAR_INSTRUCTIONS_PUBKEY,
isSigner: false,
isWritable: false,
},
],
keys: [],
programId: Ed25519Program.programId,
data: Buffer.from(ixData),
data: instructionData,
});
}
2 changes: 1 addition & 1 deletion sdk/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -493,7 +493,7 @@
bigint-buffer "^1.1.5"
bignumber.js "^9.0.1"

"@solana/buffer-layout@^4.0.0", "@solana/buffer-layout@^4.0.1":
"@solana/buffer-layout@4.0.1", "@solana/buffer-layout@^4.0.0", "@solana/buffer-layout@^4.0.1":
version "4.0.1"
resolved "https://registry.yarnpkg.com/@solana/buffer-layout/-/buffer-layout-4.0.1.tgz#b996235eaec15b1e0b5092a8ed6028df77fa6c15"
integrity sha512-E1ImOIAD1tBZFRdjeM4/pzTiTApC0AOBGwyAMS4fwIodCWArzJ3DWdoh8cKxeFM2fElkxBh2Aqts1BPC373rHA==
Expand Down
2 changes: 1 addition & 1 deletion test-scripts/run-anchor-local-validator-tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ fi
export ANCHOR_WALLET=~/.config/solana/id.json

test_files=(
pythLazer.ts
placeAndMakeSwiftPerp.ts
# pythLazer.ts
)


Expand Down
10 changes: 8 additions & 2 deletions tests/pythLazer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
} from '../sdk/src';
import {
PublicKey,
Transaction,
TransactionMessage,
VersionedTransaction,
} from '@solana/web3.js';
Expand Down Expand Up @@ -95,9 +96,10 @@ describe('pyth lazer oracles', () => {
});

it('crank', async () => {
const ixs = await driftClient.getPostPythLazerOracleUpdateIxs(
const ixs = driftClient.getPostPythLazerOracleUpdateIxs(
[1],
PYTH_LAZER_HEX_STRING_BTC
PYTH_LAZER_HEX_STRING_BTC,
[]
);

const message = new TransactionMessage({
Expand All @@ -109,6 +111,10 @@ describe('pyth lazer oracles', () => {
const simResult = await provider.connection.simulateTransaction(tx);
console.log(simResult.value.logs);
assert(simResult.value.err === null);

const normalTx = new Transaction();
normalTx.add(...ixs);
await driftClient.sendTransaction(normalTx);
});

it('crank multi', async () => {
Expand Down
2 changes: 1 addition & 1 deletion tests/pythLazerData.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
export const PYTH_STORAGE_DATA =
'0XX/ucSvRAkL/td28gTUmmjn6CkzKyvYXJOMcup4pEKu3cXcP7cvDAH2UhC+5Pz1sc7h5Tf6vP2VAQKXZTuUrwTUVPxHPpSDT+g2BnoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==';
export const PYTH_LAZER_HEX_STRING_BTC =
'b9011a82cb2701fd7ef39a113d32e1f8e5b759e1a0d41aa2f587521979d3ff10178b34b56bb9e2c0bdbc5a55fe2162ed81e90b5d0d36bd43286f9e99e49e242a00dd860ef65210bee4fcf5b1cee1e537fabcfd95010297653b94af04d454fc473e94834f1c0075d3c79340d732d48f2806000301010000000100daa8b56fe2080000';
'b9011a82c6e392a8837694bb546244b833da502497fe0b3a78b09295d5e9832d1d7b11fbb06ae6a93a78bb5988079259006fe79b32ab5983013464f358cd56ceb5a26a0df65210bee4fcf5b1cee1e537fabcfd95010297653b94af04d454fc473e94834f1c0075d3c79340b0d7837f2906000301010000000100677a0e79a6090000';

export const PYTH_LAZER_HEX_STRING_SOL =
'b9011a8286e4219d980a176145b777aff894df914947c33855028f2b993a8963b131270c9cbcccd282685eb24bdeffcb8bec8c5203f6c882ad2e8b9adb0d1ba6f89b3e09f65210bee4fcf5b1cee1e537fabcfd95010297653b94af04d454fc473e94834f1c0075d3c79340e90513da2806000301060000000100fd09283605000000';
Expand Down

0 comments on commit cdab664

Please sign in to comment.