Explorar el Código

feat: pyth pull-based push oracle (#1370)

* feat: implement oracle instance

* Go

* Remove key

* Go

* Add instance id, fix conditional deser

* Go

* Rename

* Revert changes to cli

* Checkpoint

* Cleanup deps

* Refactor tests

* Cleanup deps

* Write test

* Fix comment

* Shard id

* ADd tests

* Extract common test utils

* Fix test

* Better name

* Cleanup

* Instance -> shard

* Update test

* Make shard id a u16
guibescos hace 1 año
padre
commit
866b6a5b4b

+ 17 - 8
pythnet/pythnet_sdk/src/test_utils/mod.rs

@@ -6,6 +6,7 @@ use {
         },
         hashers::keccak256_160::Keccak160,
         messages::{
+            FeedId,
             Message,
             PriceFeedMessage,
             TwapMessage,
@@ -95,22 +96,30 @@ pub fn dummy_guardians() -> Vec<SecretKey> {
     result
 }
 
-pub fn create_dummy_price_feed_message(value: i64) -> Message {
+pub fn create_dummy_feed_id(value: i64) -> FeedId {
     let mut dummy_id = [0; 32];
     dummy_id[0] = value as u8;
+    dummy_id
+}
+
+pub fn create_dummy_price_feed_message_with_feed_id(value: i64, feed_id: FeedId) -> Message {
     let msg = PriceFeedMessage {
-        feed_id:           dummy_id,
-        price:             value,
-        conf:              value as u64,
-        exponent:          value as i32,
-        publish_time:      value,
+        feed_id,
+        price: value,
+        conf: value as u64,
+        exponent: value as i32,
+        publish_time: value,
         prev_publish_time: value,
-        ema_price:         value,
-        ema_conf:          value as u64,
+        ema_price: value,
+        ema_conf: value as u64,
     };
     Message::PriceFeedMessage(msg)
 }
 
+pub fn create_dummy_price_feed_message(value: i64) -> Message {
+    create_dummy_price_feed_message_with_feed_id(value, create_dummy_feed_id(value))
+}
+
 pub fn create_dummy_twap_message() -> Message {
     let msg = TwapMessage {
         feed_id:           [0; 32],

+ 42 - 7
target_chains/solana/Cargo.lock

@@ -1018,6 +1018,30 @@ dependencies = [
  "unreachable",
 ]
 
+[[package]]
+name = "common-test-utils"
+version = "0.1.0"
+dependencies = [
+ "anchor-lang",
+ "bincode",
+ "lazy_static",
+ "libsecp256k1 0.7.1",
+ "program-simulator",
+ "pyth-sdk",
+ "pyth-sdk-solana",
+ "pyth-solana-receiver",
+ "pyth-solana-receiver-sdk",
+ "pythnet-sdk",
+ "rand 0.8.5",
+ "serde_wormhole",
+ "solana-program",
+ "solana-program-test",
+ "solana-sdk",
+ "tokio",
+ "wormhole-core-bridge-solana",
+ "wormhole-vaas-serde",
+]
+
 [[package]]
 name = "concurrent-queue"
 version = "2.3.0"
@@ -2990,6 +3014,23 @@ dependencies = [
  "solana-sdk",
 ]
 
+[[package]]
+name = "pyth-push-oracle"
+version = "0.1.0"
+dependencies = [
+ "anchor-lang",
+ "common-test-utils",
+ "program-simulator",
+ "pyth-solana-receiver",
+ "pyth-solana-receiver-sdk",
+ "pythnet-sdk",
+ "serde_wormhole",
+ "solana-program",
+ "solana-sdk",
+ "tokio",
+ "wormhole-vaas-serde",
+]
+
 [[package]]
 name = "pyth-sdk"
 version = "0.8.0"
@@ -3026,19 +3067,13 @@ name = "pyth-solana-receiver"
 version = "0.1.0"
 dependencies = [
  "anchor-lang",
- "bincode",
  "byteorder",
- "lazy_static",
- "libsecp256k1 0.7.1",
+ "common-test-utils",
  "program-simulator",
- "pyth-sdk",
- "pyth-sdk-solana",
  "pyth-solana-receiver-sdk",
  "pythnet-sdk",
- "rand 0.8.5",
  "serde_wormhole",
  "solana-program",
- "solana-program-test",
  "solana-sdk",
  "tokio",
  "wormhole-core-bridge-solana",

+ 2 - 1
target_chains/solana/Cargo.toml

@@ -3,7 +3,8 @@ members = [
     "programs/*",
     "cli/",
     "program_simulator/",
-    "pyth_solana_receiver_sdk/"
+    "pyth_solana_receiver_sdk/",
+    "common_test_utils"
 ]
 
 [profile.release]

+ 28 - 0
target_chains/solana/common_test_utils/Cargo.toml

@@ -0,0 +1,28 @@
+[package]
+name = "common-test-utils"
+version = "0.1.0"
+edition = "2021"
+
+[lib]
+crate-type = ["lib"]
+name = "common_test_utils"
+
+[dependencies]
+pyth-sdk = "0.8.0"
+pyth-sdk-solana = "0.8.0"
+solana-program-test = { workspace = true }
+solana-sdk = { workspace = true }
+tokio = "1.14.1"
+bincode = "1.3.3"
+libsecp256k1 = "0.7.1"
+rand = "0.8.5"
+lazy_static = "1.4.0"
+program-simulator = { path = "../program_simulator" }
+wormhole-vaas-serde = { workspace = true }
+serde_wormhole = { workspace = true }
+pythnet-sdk = { path = "../../../pythnet/pythnet_sdk", features = ["test-utils"] }
+anchor-lang = { workspace = true }
+solana-program = { workspace = true }
+pyth-solana-receiver = { path = "../programs/pyth-solana-receiver" }
+wormhole-core-bridge-solana = {workspace = true}
+pyth-solana-receiver-sdk = { path = "../pyth_solana_receiver_sdk"}

+ 7 - 3
target_chains/solana/programs/pyth-solana-receiver/tests/common/mod.rs → target_chains/solana/common_test_utils/src/lib.rs

@@ -11,9 +11,12 @@ use {
         },
         ID,
     },
-    pyth_solana_receiver_sdk::config::{
-        Config,
-        DataSource,
+    pyth_solana_receiver_sdk::{
+        config::{
+            Config,
+            DataSource,
+        },
+        PYTH_PUSH_ORACLE_ID,
     },
     pythnet_sdk::test_utils::{
         dummy_guardians,
@@ -163,6 +166,7 @@ pub async fn setup_pyth_receiver(
 ) -> ProgramTestFixtures {
     let mut program_test = ProgramTest::default();
     program_test.add_program("pyth_solana_receiver", ID, None);
+    program_test.add_program("pyth_push_oracle", PYTH_PUSH_ORACLE_ID, None);
 
     let mut encoded_vaa_addresses: Vec<Pubkey> = vec![];
     for vaa in vaas {

+ 31 - 0
target_chains/solana/programs/pyth-push-oracle/Cargo.toml

@@ -0,0 +1,31 @@
+[package]
+name = "pyth-push-oracle"
+version = "0.1.0"
+description = "Created with Anchor"
+edition = "2021"
+
+[lib]
+crate-type = ["cdylib", "lib"]
+name = "pyth_push_oracle"
+
+[features]
+no-entrypoint = []
+no-idl = []
+no-log-ix-name = []
+cpi = ["no-entrypoint"]
+test-bpf = []
+
+[dependencies]
+anchor-lang = { workspace = true }
+pythnet-sdk = { path = "../../../../pythnet/pythnet_sdk" }
+solana-program = { workspace = true }
+pyth-solana-receiver-sdk = { path = "../../pyth_solana_receiver_sdk"}
+pyth-solana-receiver = { path = "../pyth-solana-receiver", features = ["cpi"]}
+
+[dev-dependencies]
+solana-sdk = { workspace = true }
+tokio = "1.14.1"
+program-simulator = { path = "../../program_simulator" }
+wormhole-vaas-serde = { workspace = true }
+serde_wormhole = { workspace = true }
+common-test-utils = { path = "../../common_test_utils" }

+ 99 - 0
target_chains/solana/programs/pyth-push-oracle/src/lib.rs

@@ -0,0 +1,99 @@
+use {
+    anchor_lang::prelude::*,
+    pyth_solana_receiver::{
+        cpi::accounts::PostUpdate,
+        program::PythSolanaReceiver,
+        PostUpdateParams,
+    },
+    pyth_solana_receiver_sdk::{
+        price_update::PriceUpdateV2,
+        PYTH_PUSH_ORACLE_ID,
+    },
+    pythnet_sdk::messages::FeedId,
+};
+
+pub mod sdk;
+
+pub const ID: Pubkey = PYTH_PUSH_ORACLE_ID;
+
+#[error_code]
+pub enum PushOracleError {
+    #[msg("Updates must be monotonically increasing")]
+    UpdatesNotMonotonic,
+    #[msg("Trying to update price feed with the wrong feed id")]
+    PriceFeedMessageMismatch,
+}
+#[program]
+pub mod pyth_push_oracle {
+
+    use super::*;
+
+    pub fn update_price_feed(
+        ctx: Context<UpdatePriceFeed>,
+        params: PostUpdateParams,
+        shard_id: u16,
+        feed_id: FeedId,
+    ) -> Result<()> {
+        let cpi_program = ctx.accounts.pyth_solana_receiver.to_account_info().clone();
+        let cpi_accounts = PostUpdate {
+            payer:                ctx.accounts.payer.to_account_info().clone(),
+            encoded_vaa:          ctx.accounts.encoded_vaa.to_account_info().clone(),
+            config:               ctx.accounts.config.to_account_info().clone(),
+            treasury:             ctx.accounts.treasury.to_account_info().clone(),
+            price_update_account: ctx.accounts.price_feed_account.to_account_info().clone(),
+            system_program:       ctx.accounts.system_program.to_account_info().clone(),
+            write_authority:      ctx.accounts.price_feed_account.to_account_info().clone(),
+        };
+
+        let seeds = &[
+            &shard_id.to_le_bytes(),
+            feed_id.as_ref(),
+            &[*ctx.bumps.get("price_feed_account").unwrap()],
+        ];
+        let signer_seeds = &[&seeds[..]];
+        let cpi_context = CpiContext::new_with_signer(cpi_program, cpi_accounts, signer_seeds);
+
+
+        let current_timestamp = {
+            if ctx.accounts.price_feed_account.data_is_empty() {
+                0
+            } else {
+                let price_feed_account_data = ctx.accounts.price_feed_account.try_borrow_data()?;
+                let price_feed_account =
+                    PriceUpdateV2::try_deserialize(&mut &price_feed_account_data[..])?;
+                price_feed_account.price_message.publish_time
+            }
+        };
+        pyth_solana_receiver::cpi::post_update(cpi_context, params)?;
+        {
+            let price_feed_account_data = ctx.accounts.price_feed_account.try_borrow_data()?;
+            let price_feed_account =
+                PriceUpdateV2::try_deserialize(&mut &price_feed_account_data[..])?;
+
+            require!(
+                price_feed_account.price_message.publish_time > current_timestamp,
+                PushOracleError::UpdatesNotMonotonic
+            );
+            require!(
+                price_feed_account.price_message.feed_id == feed_id,
+                PushOracleError::PriceFeedMessageMismatch
+            );
+        }
+        Ok(())
+    }
+}
+
+#[derive(Accounts)]
+#[instruction(params : PostUpdateParams, shard_id : u16, feed_id : FeedId)]
+pub struct UpdatePriceFeed<'info> {
+    #[account(mut)]
+    pub payer:                Signer<'info>,
+    pub pyth_solana_receiver: Program<'info, PythSolanaReceiver>,
+    pub encoded_vaa:          AccountInfo<'info>,
+    pub config:               AccountInfo<'info>,
+    #[account(mut)]
+    pub treasury:             AccountInfo<'info>,
+    #[account(mut, seeds = [&shard_id.to_le_bytes(), &feed_id], bump)]
+    pub price_feed_account:   AccountInfo<'info>,
+    pub system_program:       Program<'info, System>,
+}

+ 74 - 0
target_chains/solana/programs/pyth-push-oracle/src/sdk.rs

@@ -0,0 +1,74 @@
+use {
+    crate::{
+        accounts,
+        instruction,
+        PostUpdateParams,
+        ID,
+    },
+    anchor_lang::{
+        prelude::*,
+        system_program,
+        InstructionData,
+    },
+    pyth_solana_receiver::sdk::{
+        get_config_address,
+        get_treasury_address,
+    },
+    pythnet_sdk::{
+        messages::FeedId,
+        wire::v1::MerklePriceUpdate,
+    },
+    solana_program::instruction::Instruction,
+};
+
+pub fn get_price_feed_address(shard_id: u16, feed_id: FeedId) -> Pubkey {
+    Pubkey::find_program_address(&[&shard_id.to_le_bytes(), feed_id.as_ref()], &ID).0
+}
+
+impl accounts::UpdatePriceFeed {
+    pub fn populate(
+        payer: Pubkey,
+        encoded_vaa: Pubkey,
+        shard_id: u16,
+        feed_id: FeedId,
+        treasury_id: u8,
+    ) -> Self {
+        accounts::UpdatePriceFeed {
+            payer,
+            encoded_vaa,
+            config: get_config_address(),
+            treasury: get_treasury_address(treasury_id),
+            price_feed_account: get_price_feed_address(shard_id, feed_id),
+            pyth_solana_receiver: pyth_solana_receiver::ID,
+            system_program: system_program::ID,
+        }
+    }
+}
+
+impl instruction::UpdatePriceFeed {
+    pub fn populate(
+        payer: Pubkey,
+        encoded_vaa: Pubkey,
+        shard_id: u16,
+        feed_id: FeedId,
+        treasury_id: u8,
+        merkle_price_update: MerklePriceUpdate,
+    ) -> Instruction {
+        let update_price_feed_accounts =
+            accounts::UpdatePriceFeed::populate(payer, encoded_vaa, shard_id, feed_id, treasury_id)
+                .to_account_metas(None);
+        Instruction {
+            program_id: ID,
+            accounts:   update_price_feed_accounts,
+            data:       instruction::UpdatePriceFeed {
+                params: PostUpdateParams {
+                    merkle_price_update,
+                    treasury_id,
+                },
+                shard_id,
+                feed_id,
+            }
+            .data(),
+        }
+    }
+}

+ 324 - 0
target_chains/solana/programs/pyth-push-oracle/tests/test_update_price_feed.rs

@@ -0,0 +1,324 @@
+use {
+    common_test_utils::{
+        assert_treasury_balance,
+        setup_pyth_receiver,
+        ProgramTestFixtures,
+        WrongSetupOption,
+    },
+    program_simulator::into_transaction_error,
+    pyth_push_oracle::{
+        instruction::UpdatePriceFeed,
+        sdk::get_price_feed_address,
+        PushOracleError,
+    },
+    pyth_solana_receiver::sdk::{
+        deserialize_accumulator_update_data,
+        DEFAULT_TREASURY_ID,
+    },
+    pyth_solana_receiver_sdk::price_update::{
+        PriceUpdateV2,
+        VerificationLevel,
+    },
+    pythnet_sdk::{
+        messages::Message,
+        test_utils::{
+            create_accumulator_message,
+            create_dummy_feed_id,
+            create_dummy_price_feed_message_with_feed_id,
+        },
+    },
+    solana_sdk::{
+        rent::Rent,
+        signer::Signer,
+    },
+};
+
+const DEFAULT_SHARD: u16 = 0;
+const SECOND_SHARD: u16 = 1;
+
+#[tokio::test]
+async fn test_update_price_feed() {
+    let feed_id: [u8; 32] = create_dummy_feed_id(100);
+    let feed_id_2: [u8; 32] = create_dummy_feed_id(200);
+
+    let feed_1_old = create_dummy_price_feed_message_with_feed_id(100, feed_id);
+    let feed_1_recent = create_dummy_price_feed_message_with_feed_id(200, feed_id);
+
+    let feed_2 = create_dummy_price_feed_message_with_feed_id(300, feed_id_2);
+
+    let message = create_accumulator_message(
+        &[feed_1_old, feed_1_recent, feed_2],
+        &[feed_1_old, feed_1_recent, feed_2],
+        false,
+        false,
+    );
+    let (vaa, merkle_price_updates) = deserialize_accumulator_update_data(message).unwrap();
+
+
+    let ProgramTestFixtures {
+        mut program_simulator,
+        encoded_vaa_addresses,
+        governance_authority: _,
+    } = setup_pyth_receiver(
+        vec![serde_wormhole::from_slice(&vaa).unwrap()],
+        WrongSetupOption::None,
+    )
+    .await;
+
+    assert_treasury_balance(&mut program_simulator, 0, DEFAULT_TREASURY_ID).await;
+
+    let poster = program_simulator.get_funded_keypair().await.unwrap();
+
+    // post one update
+    program_simulator
+        .process_ix_with_default_compute_limit(
+            UpdatePriceFeed::populate(
+                poster.pubkey(),
+                encoded_vaa_addresses[0],
+                DEFAULT_SHARD,
+                feed_id,
+                DEFAULT_TREASURY_ID,
+                merkle_price_updates[0].clone(),
+            ),
+            &vec![&poster],
+            None,
+        )
+        .await
+        .unwrap();
+
+    assert_treasury_balance(
+        &mut program_simulator,
+        Rent::default().minimum_balance(0),
+        DEFAULT_TREASURY_ID,
+    )
+    .await;
+
+    let price_feed_account = program_simulator
+        .get_anchor_account_data::<PriceUpdateV2>(get_price_feed_address(DEFAULT_SHARD, feed_id))
+        .await
+        .unwrap();
+
+    assert_eq!(
+        price_feed_account.write_authority,
+        get_price_feed_address(DEFAULT_SHARD, feed_id)
+    );
+    assert_eq!(
+        price_feed_account.verification_level,
+        VerificationLevel::Full
+    );
+    assert_eq!(
+        Message::PriceFeedMessage(price_feed_account.price_message),
+        feed_1_old
+    );
+    assert_eq!(
+        price_feed_account.posted_slot,
+        program_simulator.get_clock().await.unwrap().slot
+    );
+
+    // post another update, same price feed
+    program_simulator
+        .process_ix_with_default_compute_limit(
+            UpdatePriceFeed::populate(
+                poster.pubkey(),
+                encoded_vaa_addresses[0],
+                DEFAULT_SHARD,
+                feed_id,
+                DEFAULT_TREASURY_ID,
+                merkle_price_updates[1].clone(),
+            ),
+            &vec![&poster],
+            None,
+        )
+        .await
+        .unwrap();
+
+    assert_treasury_balance(
+        &mut program_simulator,
+        Rent::default().minimum_balance(0) + 1,
+        DEFAULT_TREASURY_ID,
+    )
+    .await;
+
+    let price_feed_account = program_simulator
+        .get_anchor_account_data::<PriceUpdateV2>(get_price_feed_address(DEFAULT_SHARD, feed_id))
+        .await
+        .unwrap();
+
+    assert_eq!(
+        price_feed_account.write_authority,
+        get_price_feed_address(DEFAULT_SHARD, feed_id)
+    );
+    assert_eq!(
+        price_feed_account.verification_level,
+        VerificationLevel::Full
+    );
+    assert_eq!(
+        Message::PriceFeedMessage(price_feed_account.price_message),
+        feed_1_recent
+    );
+    assert_eq!(
+        price_feed_account.posted_slot,
+        program_simulator.get_clock().await.unwrap().slot
+    );
+
+    // post another update, outdated
+    assert_eq!(
+        program_simulator
+            .process_ix_with_default_compute_limit(
+                UpdatePriceFeed::populate(
+                    poster.pubkey(),
+                    encoded_vaa_addresses[0],
+                    DEFAULT_SHARD,
+                    feed_id,
+                    DEFAULT_TREASURY_ID,
+                    merkle_price_updates[1].clone(),
+                ),
+                &vec![&poster],
+                None,
+            )
+            .await
+            .unwrap_err()
+            .unwrap(),
+        into_transaction_error(PushOracleError::UpdatesNotMonotonic)
+    );
+
+    assert_treasury_balance(
+        &mut program_simulator,
+        Rent::default().minimum_balance(0) + 1,
+        DEFAULT_TREASURY_ID,
+    )
+    .await;
+
+    let price_feed_account = program_simulator
+        .get_anchor_account_data::<PriceUpdateV2>(get_price_feed_address(DEFAULT_SHARD, feed_id))
+        .await
+        .unwrap();
+
+    assert_eq!(
+        price_feed_account.write_authority,
+        get_price_feed_address(DEFAULT_SHARD, feed_id)
+    );
+    assert_eq!(
+        price_feed_account.verification_level,
+        VerificationLevel::Full
+    );
+    assert_eq!(
+        Message::PriceFeedMessage(price_feed_account.price_message),
+        feed_1_recent
+    );
+    assert_eq!(
+        price_feed_account.posted_slot,
+        program_simulator.get_clock().await.unwrap().slot
+    );
+
+    // works if you change the shard
+    program_simulator
+        .process_ix_with_default_compute_limit(
+            UpdatePriceFeed::populate(
+                poster.pubkey(),
+                encoded_vaa_addresses[0],
+                SECOND_SHARD,
+                feed_id,
+                DEFAULT_TREASURY_ID,
+                merkle_price_updates[0].clone(),
+            ),
+            &vec![&poster],
+            None,
+        )
+        .await
+        .unwrap();
+
+    assert_treasury_balance(
+        &mut program_simulator,
+        Rent::default().minimum_balance(0) + 2,
+        DEFAULT_TREASURY_ID,
+    )
+    .await;
+
+    let price_feed_account = program_simulator
+        .get_anchor_account_data::<PriceUpdateV2>(get_price_feed_address(DEFAULT_SHARD, feed_id))
+        .await
+        .unwrap();
+
+    assert_eq!(
+        price_feed_account.write_authority,
+        get_price_feed_address(DEFAULT_SHARD, feed_id)
+    );
+    assert_eq!(
+        price_feed_account.verification_level,
+        VerificationLevel::Full
+    );
+    assert_eq!(
+        Message::PriceFeedMessage(price_feed_account.price_message),
+        feed_1_recent
+    );
+    assert_eq!(
+        price_feed_account.posted_slot,
+        program_simulator.get_clock().await.unwrap().slot
+    );
+
+    let price_feed_account = program_simulator
+        .get_anchor_account_data::<PriceUpdateV2>(get_price_feed_address(SECOND_SHARD, feed_id))
+        .await
+        .unwrap();
+
+    assert_eq!(
+        price_feed_account.write_authority,
+        get_price_feed_address(SECOND_SHARD, feed_id)
+    );
+    assert_eq!(
+        price_feed_account.verification_level,
+        VerificationLevel::Full
+    );
+    assert_eq!(
+        Message::PriceFeedMessage(price_feed_account.price_message),
+        feed_1_old
+    );
+    assert_eq!(
+        price_feed_account.posted_slot,
+        program_simulator.get_clock().await.unwrap().slot
+    );
+
+    // try to post the wrong price feed id
+    assert_eq!(
+        program_simulator
+            .process_ix_with_default_compute_limit(
+                UpdatePriceFeed::populate(
+                    poster.pubkey(),
+                    encoded_vaa_addresses[0],
+                    DEFAULT_SHARD,
+                    feed_id,
+                    DEFAULT_TREASURY_ID,
+                    merkle_price_updates[2].clone(),
+                ),
+                &vec![&poster],
+                None,
+            )
+            .await
+            .unwrap_err()
+            .unwrap(),
+        into_transaction_error(PushOracleError::PriceFeedMessageMismatch)
+    );
+
+    let price_feed_account = program_simulator
+        .get_anchor_account_data::<PriceUpdateV2>(get_price_feed_address(DEFAULT_SHARD, feed_id))
+        .await
+        .unwrap();
+
+    assert_eq!(
+        price_feed_account.write_authority,
+        get_price_feed_address(DEFAULT_SHARD, feed_id)
+    );
+    assert_eq!(
+        price_feed_account.verification_level,
+        VerificationLevel::Full
+    );
+    assert_eq!(
+        Message::PriceFeedMessage(price_feed_account.price_message),
+        feed_1_recent
+    );
+    assert_eq!(
+        price_feed_account.posted_slot,
+        program_simulator.get_clock().await.unwrap().slot
+    );
+}

+ 1 - 8
target_chains/solana/programs/pyth-solana-receiver/Cargo.toml

@@ -25,16 +25,9 @@ wormhole-raw-vaas = {version = "0.1.3", features = ["ruint", "on-chain"], defaul
 pyth-solana-receiver-sdk = { path = "../../pyth_solana_receiver_sdk"}
 
 [dev-dependencies]
-pyth-sdk = "0.8.0"
-pyth-sdk-solana = "0.8.0"
-solana-program-test = { workspace = true }
 solana-sdk = { workspace = true }
 tokio = "1.14.1"
-bincode = "1.3.3"
-libsecp256k1 = "0.7.1"
-rand = "0.8.5"
-lazy_static = "1.4.0"
 program-simulator = { path = "../../program_simulator" }
 wormhole-vaas-serde = { workspace = true }
 serde_wormhole = { workspace = true }
-pythnet-sdk = { path = "../../../../pythnet/pythnet_sdk", features = ["test-utils"] }
+common-test-utils = { path = "../../common_test_utils" }

+ 2 - 4
target_chains/solana/programs/pyth-solana-receiver/tests/test_governance.rs

@@ -1,8 +1,8 @@
 use {
-    crate::common::WrongSetupOption,
-    common::{
+    common_test_utils::{
         setup_pyth_receiver,
         ProgramTestFixtures,
+        WrongSetupOption,
     },
     program_simulator::into_transaction_error,
     pyth_solana_receiver::{
@@ -30,8 +30,6 @@ use {
     solana_sdk::signer::Signer,
 };
 
-mod common;
-
 
 #[tokio::test]
 async fn test_governance() {

+ 3 - 8
target_chains/solana/programs/pyth-solana-receiver/tests/test_post_price_update_from_vaa.rs

@@ -1,12 +1,10 @@
 use {
-    crate::common::{
+    common_test_utils::{
         assert_treasury_balance,
-        WrongSetupOption,
-        DEFAULT_GUARDIAN_SET_INDEX,
-    },
-    common::{
         setup_pyth_receiver,
         ProgramTestFixtures,
+        WrongSetupOption,
+        DEFAULT_GUARDIAN_SET_INDEX,
     },
     program_simulator::into_transaction_error,
     pyth_solana_receiver::{
@@ -51,9 +49,6 @@ use {
     wormhole_core_bridge_solana::ID as BRIDGE_ID,
 };
 
-mod common;
-
-
 // This file is meant to test the errors that can be thrown by post_price_update_from_vaa
 #[tokio::test]
 async fn test_invalid_wormhole_message() {

+ 2 - 6
target_chains/solana/programs/pyth-solana-receiver/tests/test_post_updates.rs

@@ -1,11 +1,9 @@
 use {
-    crate::common::{
+    common_test_utils::{
         assert_treasury_balance,
-        WrongSetupOption,
-    },
-    common::{
         setup_pyth_receiver,
         ProgramTestFixtures,
+        WrongSetupOption,
     },
     program_simulator::into_transaction_error,
     pyth_solana_receiver::{
@@ -38,8 +36,6 @@ use {
     },
 };
 
-mod common;
-
 
 #[tokio::test]
 async fn test_post_update() {

+ 3 - 7
target_chains/solana/programs/pyth-solana-receiver/tests/test_post_updates_atomic.rs

@@ -1,12 +1,10 @@
 use {
-    crate::common::{
+    common_test_utils::{
         assert_treasury_balance,
-        WrongSetupOption,
-        DEFAULT_GUARDIAN_SET_INDEX,
-    },
-    common::{
         setup_pyth_receiver,
         ProgramTestFixtures,
+        WrongSetupOption,
+        DEFAULT_GUARDIAN_SET_INDEX,
     },
     program_simulator::into_transaction_error,
     pyth_solana_receiver::{
@@ -41,8 +39,6 @@ use {
     wormhole_sdk::Vaa,
 };
 
-mod common;
-
 
 #[tokio::test]
 async fn test_post_update_atomic() {

+ 9 - 1
target_chains/solana/pyth_solana_receiver_sdk/src/lib.rs

@@ -1,7 +1,15 @@
-use anchor_lang::declare_id;
+use {
+    anchor_lang::declare_id,
+    solana_program::{
+        pubkey,
+        pubkey::Pubkey,
+    },
+};
 
 pub mod config;
 pub mod error;
 pub mod price_update;
 
 declare_id!("rec5EKMGg6MxZYaMdyBfgwp4d5rB9T1VQH5pJv5LtFJ");
+
+pub const PYTH_PUSH_ORACLE_ID: Pubkey = pubkey!("F9SP6tBXw9Af7BYauo7Y2R5Es2mpv8FP5aNCXMihp6Za");