diff --git a/programs/drift/src/instructions/admin.rs b/programs/drift/src/instructions/admin.rs index 47f7a9282..2b9ff0955 100644 --- a/programs/drift/src/instructions/admin.rs +++ b/programs/drift/src/instructions/admin.rs @@ -4504,6 +4504,8 @@ pub fn handle_initialize_pyth_lazer_oracle( feed_id: u32, ) -> Result<()> { let pubkey = ctx.accounts.lazer_oracle.to_account_info().key; + let mut account = ctx.accounts.lazer_oracle.load_init()?; + account.bump = ctx.bumps.lazer_oracle; msg!( "Lazer price feed initted {} with feed_id {}", pubkey, @@ -4512,6 +4514,20 @@ pub fn handle_initialize_pyth_lazer_oracle( Ok(()) } +pub fn handle_update_pyth_lazer_oracle_bump( + ctx: Context, + feed_id: u32, +) -> Result<()> { + let mut account = ctx.accounts.lazer_oracle.load_mut()?; + account.bump = ctx.bumps.lazer_oracle; + msg!( + "Lazer price bump updated to {} for feed id {}", + ctx.bumps.lazer_oracle, + feed_id + ); + Ok(()) +} + pub fn handle_settle_expired_market<'c: 'info, 'info>( ctx: Context<'_, '_, 'c, 'info, AdminUpdatePerpMarket<'info>>, market_index: u16, @@ -5481,6 +5497,23 @@ pub struct InitPythLazerOracle<'info> { pub system_program: Program<'info, System>, } +#[derive(Accounts)] +#[instruction(feed_id: u32)] +pub struct UpdatePythLazerOracleBump<'info> { + #[account( + mut, + constraint = admin.key() == admin_hot_wallet::id() || admin.key() == state.admin + )] + pub admin: Signer<'info>, + #[account( + mut, + seeds = [PYTH_LAZER_ORACLE_SEED, &feed_id.to_le_bytes()], + bump, + )] + pub lazer_oracle: AccountLoader<'info, PythLazerOracle>, + pub state: Box>, +} + #[derive(Accounts)] pub struct InitializeHighLeverageModeConfig<'info> { #[account(mut)] diff --git a/programs/drift/src/instructions/pyth_lazer_oracle.rs b/programs/drift/src/instructions/pyth_lazer_oracle.rs index 827ffaab1..a3b821caf 100644 --- a/programs/drift/src/instructions/pyth_lazer_oracle.rs +++ b/programs/drift/src/instructions/pyth_lazer_oracle.rs @@ -57,14 +57,21 @@ pub fn handle_update_pyth_lazer_oracle<'c: 'info, 'info>( let feed_id = payload_data.feed_id.0; // Verify the pda - let pda = Pubkey::find_program_address( - &[PYTH_LAZER_ORACLE_SEED, &feed_id.to_le_bytes()], + let pda = Pubkey::create_program_address( + &[ + PYTH_LAZER_ORACLE_SEED, + &feed_id.to_le_bytes(), + pyth_lazer_oracle.bump.to_le_bytes().as_ref(), + ], &crate::ID, - ) - .0; + ); + if pda.is_err() { + return Err(ErrorCode::OracleBadRemainingAccountPublicKey.into()); + } + let unwrapped_pda = pda.unwrap(); require_keys_eq!( *account.key, - pda, + unwrapped_pda, ErrorCode::OracleBadRemainingAccountPublicKey ); @@ -103,13 +110,6 @@ pub fn handle_update_pyth_lazer_oracle<'c: 'info, 'info>( pyth_lazer_oracle.publish_time = next_timestamp; pyth_lazer_oracle.exponent = exponent.cast::()?; pyth_lazer_oracle.conf = conf.cast::()?; - msg!("Price updated to {}", price.0.get()); - - msg!( - "Posting new lazer update. current ts {} < next ts {}", - current_timestamp, - next_timestamp - ); } else { msg!( "Skipping new lazer update. current ts {} >= next ts {}", diff --git a/programs/drift/src/lib.rs b/programs/drift/src/lib.rs index 0e9674e00..383951a83 100644 --- a/programs/drift/src/lib.rs +++ b/programs/drift/src/lib.rs @@ -1719,6 +1719,13 @@ pub mod drift { handle_initialize_pyth_lazer_oracle(ctx, feed_id) } + pub fn update_pyth_lazer_oracle_bump( + ctx: Context, + feed_id: u32, + ) -> Result<()> { + handle_update_pyth_lazer_oracle_bump(ctx, feed_id) + } + pub fn post_pyth_lazer_oracle_update<'c: 'info, 'info>( ctx: Context<'_, '_, 'c, 'info, UpdatePythLazerOracle>, pyth_message: Vec, diff --git a/programs/drift/src/macros.rs b/programs/drift/src/macros.rs index 4bd07c664..cdd200482 100644 --- a/programs/drift/src/macros.rs +++ b/programs/drift/src/macros.rs @@ -117,3 +117,15 @@ macro_rules! msg { (solana_program::msg!(&format!($($arg)*))); } } + +#[macro_export] +macro_rules! compute_fn { + ($msg:expr=> $($tt:tt)*) => { + ::solana_program::msg!(concat!($msg, " {")); + ::solana_program::log::sol_log_compute_units(); + let res = { $($tt)* }; + ::solana_program::log::sol_log_compute_units(); + ::solana_program::msg!(concat!(" } // ", $msg)); + res + }; +} diff --git a/programs/drift/src/state/pyth_lazer_oracle.rs b/programs/drift/src/state/pyth_lazer_oracle.rs index bec409a94..a5888cedd 100644 --- a/programs/drift/src/state/pyth_lazer_oracle.rs +++ b/programs/drift/src/state/pyth_lazer_oracle.rs @@ -17,6 +17,7 @@ pub struct PythLazerOracle { pub publish_time: u64, pub posted_slot: u64, pub exponent: i32, - pub _padding: [u8; 4], + pub bump: u8, + pub _padding: [u8; 3], pub conf: u64, } diff --git a/sdk/src/adminClient.ts b/sdk/src/adminClient.ts index 2347a3143..83d0c610b 100644 --- a/sdk/src/adminClient.ts +++ b/sdk/src/adminClient.ts @@ -4333,6 +4333,34 @@ export class AdminClient extends DriftClient { }); } + public async updatePythLazerOracleBump( + feedId: number + ): Promise { + const initializePythPullOracleIx = + await this.getUpdatePythLazerOracleBumpeIx(feedId); + const tx = await this.buildTransaction(initializePythPullOracleIx); + const { txSig } = await this.sendTransaction(tx, [], this.opts); + + return txSig; + } + + public async getUpdatePythLazerOracleBumpeIx( + feedId: number + ): Promise { + return await this.program.instruction.updatePythLazerOracleBump(feedId, { + accounts: { + admin: this.useHotWalletAdmin + ? this.wallet.publicKey + : this.getStateAccount().admin, + state: await this.getStatePublicKey(), + lazerOracle: getPythLazerOraclePublicKey( + this.program.programId, + feedId + ), + }, + }); + } + public async initializeHighLeverageModeConfig( maxUsers: number ): Promise { diff --git a/sdk/src/idl/drift.json b/sdk/src/idl/drift.json index 8c69dfe21..8c0da461a 100644 --- a/sdk/src/idl/drift.json +++ b/sdk/src/idl/drift.json @@ -7243,6 +7243,32 @@ } ] }, + { + "name": "updatePythLazerOracleBump", + "accounts": [ + { + "name": "admin", + "isMut": true, + "isSigner": true + }, + { + "name": "lazerOracle", + "isMut": true, + "isSigner": false + }, + { + "name": "state", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "feedId", + "type": "u32" + } + ] + }, { "name": "postPythLazerOracleUpdate", "accounts": [ @@ -8338,12 +8364,16 @@ "name": "exponent", "type": "i32" }, + { + "name": "bump", + "type": "u8" + }, { "name": "padding", "type": { "array": [ "u8", - 4 + 3 ] } }, diff --git a/test-scripts/single-anchor-test.sh b/test-scripts/single-anchor-test.sh index aa092abe8..94843f192 100755 --- a/test-scripts/single-anchor-test.sh +++ b/test-scripts/single-anchor-test.sh @@ -6,7 +6,7 @@ fi export ANCHOR_WALLET=~/.config/solana/id.json -test_files=(overwritePerpAccounts.ts) +test_files=(pythLazerBankrun.ts) for test_file in ${test_files[@]}; do ts-mocha -t 300000 ./tests/${test_file} diff --git a/tests/pythLazerBankrun.ts b/tests/pythLazerBankrun.ts index 7e1721bea..2f89310dd 100644 --- a/tests/pythLazerBankrun.ts +++ b/tests/pythLazerBankrun.ts @@ -129,8 +129,28 @@ describe('pyth pull oracles', () => { await driftClient.initializePythLazerOracle(6); }); + it('update lazer account bumps', async () => { + await driftClient.updatePythLazerOracleBump(1); + await driftClient.updatePythLazerOracleBump(2); + await driftClient.updatePythLazerOracleBump(6); + }); + it('crank single', async () => { - await driftClient.postPythLazerOracleUpdate([6], PYTH_LAZER_HEX_STRING_SOL); + const tx = await driftClient.postPythLazerOracleUpdate( + [6], + PYTH_LAZER_HEX_STRING_SOL + ); + const logs = ( + await bankrunContextWrapper.connection.getTransaction(tx, { + commitment: 'confirmed', + }) + ).meta.logMessages; + const consumedLog = logs.find((log) => log.includes('consumed')); + const cus = consumedLog.split('consumed ')[1].split(' ')[0]; + console.log(`Consumed cus: ${cus}`); + }); + + it('can update perp market feed', async () => { await driftClient.updatePerpMarketOracle( 0, getPythLazerOraclePublicKey(driftClient.program.programId, 6),