use { common_test_utils::{ assert_treasury_balance, setup_pyth_receiver, ProgramTestFixtures, WrongSetupOption, }, program_simulator::into_transaction_error, pyth_solana_receiver::{ error::ReceiverError, instruction::{PostUpdate, ReclaimRent}, sdk::{deserialize_accumulator_update_data, get_random_treasury_id, DEFAULT_TREASURY_ID}, }, pyth_solana_receiver_sdk::price_update::{PriceUpdateV2, VerificationLevel}, pythnet_sdk::{ messages::Message, test_utils::{create_accumulator_message, create_dummy_price_feed_message}, }, solana_program::pubkey::Pubkey, solana_sdk::{rent::Rent, signature::Keypair, signer::Signer}, }; #[tokio::test] async fn test_post_update() { let feed_1 = create_dummy_price_feed_message(100); let feed_2 = create_dummy_price_feed_message(200); let message = create_accumulator_message(&[&feed_1, &feed_2], &[&feed_1, &feed_2], false, false, None); 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(); let price_update_keypair = Keypair::new(); // post one update program_simulator .process_ix_with_default_compute_limit( PostUpdate::populate( poster.pubkey(), poster.pubkey(), encoded_vaa_addresses[0], price_update_keypair.pubkey(), merkle_price_updates[0].clone(), DEFAULT_TREASURY_ID, ), &vec![&poster, &price_update_keypair], None, ) .await .unwrap(); assert_treasury_balance( &mut program_simulator, Rent::default().minimum_balance(0), DEFAULT_TREASURY_ID, ) .await; let mut price_update_account = program_simulator .get_anchor_account_data::(price_update_keypair.pubkey()) .await .unwrap(); assert_eq!(price_update_account.write_authority, poster.pubkey()); assert_eq!( price_update_account.verification_level, VerificationLevel::Full ); assert_eq!( Message::PriceFeedMessage(price_update_account.price_message), feed_1 ); assert_eq!( price_update_account.posted_slot, program_simulator.get_clock().await.unwrap().slot ); // post another update to the same account program_simulator .process_ix_with_default_compute_limit( PostUpdate::populate( poster.pubkey(), poster.pubkey(), encoded_vaa_addresses[0], price_update_keypair.pubkey(), merkle_price_updates[1].clone(), DEFAULT_TREASURY_ID, ), &vec![&poster, &price_update_keypair], None, ) .await .unwrap(); assert_treasury_balance( &mut program_simulator, Rent::default().minimum_balance(0) + 1, DEFAULT_TREASURY_ID, ) .await; price_update_account = program_simulator .get_anchor_account_data::(price_update_keypair.pubkey()) .await .unwrap(); assert_eq!(price_update_account.write_authority, poster.pubkey()); assert_eq!( price_update_account.verification_level, VerificationLevel::Full ); assert_eq!( Message::PriceFeedMessage(price_update_account.price_message), feed_2 ); assert_eq!( price_update_account.posted_slot, program_simulator.get_clock().await.unwrap().slot ); // This poster doesn't have the write authority let poster_2 = program_simulator.get_funded_keypair().await.unwrap(); assert_eq!( program_simulator .process_ix_with_default_compute_limit( ReclaimRent::populate(poster_2.pubkey(), price_update_keypair.pubkey()), &vec![&poster_2], None, ) .await .unwrap_err() .unwrap(), into_transaction_error(ReceiverError::WrongWriteAuthority) ); program_simulator .process_ix_with_default_compute_limit( ReclaimRent::populate(poster.pubkey(), price_update_keypair.pubkey()), &vec![&poster], None, ) .await .unwrap(); assert_eq!( program_simulator .get_balance(price_update_keypair.pubkey()) .await .unwrap(), 0 ); } #[tokio::test] async fn test_post_update_wrong_encoded_vaa_owner() { let feed_1 = create_dummy_price_feed_message(100); let feed_2 = create_dummy_price_feed_message(200); let message = create_accumulator_message(&[&feed_1, &feed_2], &[&feed_1, &feed_2], false, false, None); 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; let poster = program_simulator.get_funded_keypair().await.unwrap(); let price_update_keypair = Keypair::new(); assert_eq!( program_simulator .process_ix_with_default_compute_limit( PostUpdate::populate( poster.pubkey(), poster.pubkey(), Pubkey::new_unique(), // Random pubkey instead of the encoded VAA address price_update_keypair.pubkey(), merkle_price_updates[0].clone(), get_random_treasury_id() ), &vec![&poster, &price_update_keypair], None, ) .await .unwrap_err() .unwrap(), into_transaction_error(ReceiverError::WrongVaaOwner) ); } #[tokio::test] async fn test_post_update_wrong_setup() { let feed_1 = create_dummy_price_feed_message(100); let feed_2 = create_dummy_price_feed_message(200); let message = create_accumulator_message(&[&feed_1, &feed_2], &[&feed_1, &feed_2], false, false, None); 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::UnverifiedEncodedVaa, ) .await; let poster = program_simulator.get_funded_keypair().await.unwrap(); let price_update_keypair = Keypair::new(); assert_eq!( program_simulator .process_ix_with_default_compute_limit( PostUpdate::populate( poster.pubkey(), poster.pubkey(), encoded_vaa_addresses[0], price_update_keypair.pubkey(), merkle_price_updates[0].clone(), get_random_treasury_id() ), &vec![&poster, &price_update_keypair], None, ) .await .unwrap_err() .unwrap(), into_transaction_error(wormhole_core_bridge_solana::error::CoreBridgeError::UnverifiedVaa) ); }