[Solana] More tests (#1263)
* Checkpoint * Checkpoint * Cleanup * Checkpoint, debug * Go * Checkpoint * Fix * Add new error and test * Cleanup * Add another test * Keep adding errors * Another test * Add comment * More * Do it * Again * Nice (#1265) * Test governance * Fix
This commit is contained in:
parent
2ab72d994d
commit
1871ca1bf3
|
@ -8,6 +8,7 @@ use {
|
|||
messages::{
|
||||
Message,
|
||||
PriceFeedMessage,
|
||||
TwapMessage,
|
||||
},
|
||||
wire::{
|
||||
to_vec,
|
||||
|
@ -110,24 +111,61 @@ pub fn create_dummy_price_feed_message(value: i64) -> Message {
|
|||
Message::PriceFeedMessage(msg)
|
||||
}
|
||||
|
||||
pub fn create_dummy_twap_message() -> Message {
|
||||
let msg = TwapMessage {
|
||||
feed_id: [0; 32],
|
||||
cumulative_price: 0,
|
||||
cumulative_conf: 0,
|
||||
num_down_slots: 0,
|
||||
exponent: 0,
|
||||
publish_time: 0,
|
||||
prev_publish_time: 0,
|
||||
publish_slot: 0,
|
||||
};
|
||||
Message::TwapMessage(msg)
|
||||
}
|
||||
|
||||
pub fn create_accumulator_message(
|
||||
all_feeds: &[Message],
|
||||
updates: &[Message],
|
||||
corrupt_wormhole_message: bool,
|
||||
corrupt_messages: bool,
|
||||
) -> Vec<u8> {
|
||||
let all_feeds_bytes: Vec<_> = all_feeds
|
||||
let mut all_feeds_bytes: Vec<_> = all_feeds
|
||||
.iter()
|
||||
.map(|f| to_vec::<_, BigEndian>(f).unwrap())
|
||||
.collect();
|
||||
|
||||
let mut updates_bytes: Vec<_> = updates
|
||||
.iter()
|
||||
.map(|f| to_vec::<_, BigEndian>(f).unwrap())
|
||||
.collect();
|
||||
|
||||
if corrupt_messages {
|
||||
all_feeds_bytes = all_feeds_bytes
|
||||
.iter()
|
||||
.map(|f| {
|
||||
let mut f_copy = f.clone();
|
||||
f_copy[0] = 255;
|
||||
f_copy
|
||||
})
|
||||
.collect();
|
||||
updates_bytes = updates_bytes
|
||||
.iter()
|
||||
.map(|f| {
|
||||
let mut f_copy = f.clone();
|
||||
f_copy[0] = 255;
|
||||
f_copy
|
||||
})
|
||||
.collect();
|
||||
}
|
||||
let all_feeds_bytes_refs: Vec<_> = all_feeds_bytes.iter().map(|f| f.as_ref()).collect();
|
||||
let tree = MerkleTree::<Keccak160>::new(all_feeds_bytes_refs.as_slice()).unwrap();
|
||||
let mut price_updates: Vec<MerklePriceUpdate> = vec![];
|
||||
for update in updates {
|
||||
let proof = tree
|
||||
.prove(&to_vec::<_, BigEndian>(update).unwrap())
|
||||
.unwrap();
|
||||
for update in updates_bytes {
|
||||
let proof = tree.prove(&update).unwrap();
|
||||
price_updates.push(MerklePriceUpdate {
|
||||
message: PrefixedVec::from(to_vec::<_, BigEndian>(update).unwrap()),
|
||||
message: PrefixedVec::from(update),
|
||||
proof,
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1155,7 +1155,7 @@ mod test {
|
|||
let feed1 = create_dummy_price_feed_message(100);
|
||||
let feed2 = create_dummy_price_feed_message(200);
|
||||
let feed3 = create_dummy_price_feed_message(300);
|
||||
let data = create_accumulator_message(&[feed1, feed2, feed3], &[feed1], false);
|
||||
let data = create_accumulator_message(&[feed1, feed2, feed3], &[feed1], false, false);
|
||||
check_sufficient_fee(&deps.as_ref(), &[data.into()])
|
||||
}
|
||||
|
||||
|
@ -1246,13 +1246,13 @@ mod test {
|
|||
let feed2 = create_dummy_price_feed_message(200);
|
||||
let feed3 = create_dummy_price_feed_message(300);
|
||||
|
||||
let msg = create_accumulator_message(&[feed1, feed2, feed3], &[feed1, feed3], false);
|
||||
let msg = create_accumulator_message(&[feed1, feed2, feed3], &[feed1, feed3], false, false);
|
||||
assert_eq!(
|
||||
get_update_fee_amount(&deps.as_ref(), &[msg.into()]).unwrap(),
|
||||
200
|
||||
);
|
||||
|
||||
let msg = create_accumulator_message(&[feed1, feed2, feed3], &[feed1], false);
|
||||
let msg = create_accumulator_message(&[feed1, feed2, feed3], &[feed1], false, false);
|
||||
assert_eq!(
|
||||
get_update_fee_amount(&deps.as_ref(), &[msg.into()]).unwrap(),
|
||||
100
|
||||
|
@ -1262,6 +1262,7 @@ mod test {
|
|||
&[feed1, feed2, feed3],
|
||||
&[feed1, feed2, feed3, feed1, feed3],
|
||||
false,
|
||||
false,
|
||||
);
|
||||
assert_eq!(
|
||||
get_update_fee_amount(&deps.as_ref(), &[msg.into()]).unwrap(),
|
||||
|
@ -1270,7 +1271,12 @@ mod test {
|
|||
|
||||
let batch_msg =
|
||||
create_batch_price_update_msg_from_attestations(vec![PriceAttestation::default()]);
|
||||
let msg = create_accumulator_message(&[feed1, feed2, feed3], &[feed1, feed2, feed3], false);
|
||||
let msg = create_accumulator_message(
|
||||
&[feed1, feed2, feed3],
|
||||
&[feed1, feed2, feed3],
|
||||
false,
|
||||
false,
|
||||
);
|
||||
assert_eq!(
|
||||
get_update_fee_amount(&deps.as_ref(), &[msg.into(), batch_msg]).unwrap(),
|
||||
400
|
||||
|
@ -1287,7 +1293,7 @@ mod test {
|
|||
|
||||
let feed1 = create_dummy_price_feed_message(100);
|
||||
let feed2 = create_dummy_price_feed_message(200);
|
||||
let msg = create_accumulator_message(&[feed1, feed2], &[feed1], false);
|
||||
let msg = create_accumulator_message(&[feed1, feed2], &[feed1], false, false);
|
||||
let info = mock_info("123", &[]);
|
||||
let result = update_price_feeds(deps.as_mut(), env, info, &[msg.into()]);
|
||||
assert!(result.is_ok());
|
||||
|
@ -1304,7 +1310,7 @@ mod test {
|
|||
for i in 0..10000 {
|
||||
all_feeds.push(create_dummy_price_feed_message(i));
|
||||
}
|
||||
let msg = create_accumulator_message(&all_feeds, &all_feeds[100..110], false);
|
||||
let msg = create_accumulator_message(&all_feeds, &all_feeds[100..110], false, false);
|
||||
let info = mock_info("123", &[]);
|
||||
let result = update_price_feeds(deps.as_mut(), env, info, &[msg.into()]);
|
||||
assert!(result.is_ok());
|
||||
|
@ -1331,15 +1337,24 @@ mod test {
|
|||
let mut feed1 = create_dummy_price_feed_message(100);
|
||||
let mut feed2 = create_dummy_price_feed_message(200);
|
||||
let mut feed3 = create_dummy_price_feed_message(300);
|
||||
let msg = create_accumulator_message(&[feed1, feed2, feed3], &[feed1, feed2, feed3], false);
|
||||
let msg = create_accumulator_message(
|
||||
&[feed1, feed2, feed3],
|
||||
&[feed1, feed2, feed3],
|
||||
false,
|
||||
false,
|
||||
);
|
||||
as_mut_price_feed(&mut feed1).publish_time += 1;
|
||||
as_mut_price_feed(&mut feed2).publish_time += 1;
|
||||
as_mut_price_feed(&mut feed3).publish_time += 1;
|
||||
as_mut_price_feed(&mut feed1).price *= 2;
|
||||
as_mut_price_feed(&mut feed2).price *= 2;
|
||||
as_mut_price_feed(&mut feed3).price *= 2;
|
||||
let msg2 =
|
||||
create_accumulator_message(&[feed1, feed2, feed3], &[feed1, feed2, feed3], false);
|
||||
let msg2 = create_accumulator_message(
|
||||
&[feed1, feed2, feed3],
|
||||
&[feed1, feed2, feed3],
|
||||
false,
|
||||
false,
|
||||
);
|
||||
let info = mock_info("123", &[]);
|
||||
let result = update_price_feeds(deps.as_mut(), env, info, &[msg.into(), msg2.into()]);
|
||||
|
||||
|
@ -1360,7 +1375,12 @@ mod test {
|
|||
let feed3 = create_dummy_price_feed_message(300);
|
||||
as_mut_price_feed(&mut feed2).publish_time -= 1;
|
||||
as_mut_price_feed(&mut feed2).price *= 2;
|
||||
let msg = create_accumulator_message(&[feed1, feed2, feed3], &[feed1, feed2, feed3], false);
|
||||
let msg = create_accumulator_message(
|
||||
&[feed1, feed2, feed3],
|
||||
&[feed1, feed2, feed3],
|
||||
false,
|
||||
false,
|
||||
);
|
||||
let info = mock_info("123", &[]);
|
||||
let result = update_price_feeds(deps.as_mut(), env, info, &[msg.into()]);
|
||||
|
||||
|
@ -1380,9 +1400,10 @@ mod test {
|
|||
let feed3 = create_dummy_price_feed_message(300);
|
||||
as_mut_price_feed(&mut feed2).publish_time -= 1;
|
||||
as_mut_price_feed(&mut feed2).price *= 2;
|
||||
let msg = create_accumulator_message(&[feed1, feed2, feed3], &[feed1, feed3], false);
|
||||
let msg = create_accumulator_message(&[feed1, feed2, feed3], &[feed1, feed3], false, false);
|
||||
|
||||
let msg2 = create_accumulator_message(&[feed1, feed2, feed3], &[feed2, feed3], false);
|
||||
let msg2 =
|
||||
create_accumulator_message(&[feed1, feed2, feed3], &[feed2, feed3], false, false);
|
||||
let info = mock_info("123", &[]);
|
||||
let result = update_price_feeds(deps.as_mut(), env, info, &[msg.into(), msg2.into()]);
|
||||
|
||||
|
@ -1399,7 +1420,7 @@ mod test {
|
|||
.unwrap();
|
||||
|
||||
let feed1 = create_dummy_price_feed_message(100);
|
||||
let mut msg = create_accumulator_message(&[feed1], &[feed1], false);
|
||||
let mut msg = create_accumulator_message(&[feed1], &[feed1], false, false);
|
||||
msg[4] = 3; // major version
|
||||
let info = mock_info("123", &[]);
|
||||
let result = update_price_feeds(deps.as_mut(), env, info, &[msg.into()]);
|
||||
|
@ -1418,7 +1439,7 @@ mod test {
|
|||
.unwrap();
|
||||
|
||||
let feed1 = create_dummy_price_feed_message(100);
|
||||
let msg = create_accumulator_message(&[feed1], &[feed1], true);
|
||||
let msg = create_accumulator_message(&[feed1], &[feed1], true, false);
|
||||
let info = mock_info("123", &[]);
|
||||
let result = update_price_feeds(deps.as_mut(), env, info, &[msg.into()]);
|
||||
assert!(result.is_err());
|
||||
|
@ -1446,7 +1467,7 @@ mod test {
|
|||
prev_publish_time: 0,
|
||||
publish_slot: 0,
|
||||
});
|
||||
let msg = create_accumulator_message(&[feed1], &[feed1], false);
|
||||
let msg = create_accumulator_message(&[feed1], &[feed1], false, false);
|
||||
let info = mock_info("123", &[]);
|
||||
let result = update_price_feeds(deps.as_mut(), env, info, &[msg.into()]);
|
||||
assert!(result.is_err());
|
||||
|
|
|
@ -863,7 +863,7 @@ async fn test_accumulator_updates() {
|
|||
// Create a couple of test feeds.
|
||||
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], false);
|
||||
let message = create_accumulator_message(&[feed_1, feed_2], &[feed_1], false, false);
|
||||
let message = hex::encode(message);
|
||||
|
||||
// Call the usual UpdatePriceFeed function.
|
||||
|
|
|
@ -106,6 +106,11 @@ impl ProgramSimulator {
|
|||
|
||||
Ok(T::deserialize(&mut &account.data[8..])?)
|
||||
}
|
||||
|
||||
pub async fn get_balance(&mut self, pubkey: Pubkey) -> Result<u64, BanksClientError> {
|
||||
let lamports = self.banks_client.get_balance(pubkey).await.unwrap();
|
||||
Ok(lamports)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn into_transaction_error<T: Into<anchor_lang::prelude::Error>>(error: T) -> TransactionError {
|
||||
|
|
|
@ -3,18 +3,21 @@ use anchor_lang::prelude::*;
|
|||
#[error_code]
|
||||
pub enum ReceiverError {
|
||||
// Pyth payload errors
|
||||
#[msg("The tuple emitter chain, emitter doesn't match one of the valid data sources.")]
|
||||
InvalidDataSource,
|
||||
#[msg("An error occurred when deserializing the message")]
|
||||
DeserializeMessageFailed,
|
||||
#[msg("Received an invalid wormhole message")]
|
||||
InvalidWormholeMessage,
|
||||
#[msg("An error occurred when deserializing the message")]
|
||||
DeserializeMessageFailed,
|
||||
#[msg("Received an invalid price update")]
|
||||
InvalidPriceUpdate,
|
||||
#[msg("This type of message is not supported currently")]
|
||||
UnsupportedMessageType,
|
||||
#[msg("The tuple emitter chain, emitter doesn't match one of the valid data sources.")]
|
||||
InvalidDataSource,
|
||||
#[msg("Funds are insufficient to pay the receiving fee")]
|
||||
InsufficientFunds,
|
||||
// Price account permissions
|
||||
#[msg("This signer can't write to price update account")]
|
||||
WrongWriteAuthority,
|
||||
// Wormhole contract encoded vaa error (from post_updates)
|
||||
#[msg("The posted VAA account has the wrong owner.")]
|
||||
WrongVaaOwner,
|
||||
|
|
|
@ -68,8 +68,8 @@ pub mod pyth_solana_receiver {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub fn authorize_governance_authority_transfer(
|
||||
ctx: Context<AuthorizeGovernanceAuthorityTransfer>,
|
||||
pub fn accept_governance_authority_transfer(
|
||||
ctx: Context<AcceptGovernanceAuthorityTransfer>,
|
||||
) -> Result<()> {
|
||||
let config = &mut ctx.accounts.config;
|
||||
config.governance_authority = config.target_governance_authority.ok_or(error!(
|
||||
|
@ -244,13 +244,13 @@ pub struct Governance<'info> {
|
|||
}
|
||||
|
||||
#[derive(Accounts)]
|
||||
pub struct AuthorizeGovernanceAuthorityTransfer<'info> {
|
||||
pub struct AcceptGovernanceAuthorityTransfer<'info> {
|
||||
#[account(constraint =
|
||||
payer.key() == config.target_governance_authority.ok_or(error!(ReceiverError::NonexistentGovernanceAuthorityTransferRequest))? @
|
||||
ReceiverError::TargetGovernanceAuthorityMismatch
|
||||
)]
|
||||
pub payer: Signer<'info>,
|
||||
#[account(seeds = [CONFIG_SEED.as_ref()], bump)]
|
||||
#[account(mut, seeds = [CONFIG_SEED.as_ref()], bump)]
|
||||
pub config: Account<'info, Config>,
|
||||
}
|
||||
|
||||
|
@ -269,7 +269,7 @@ pub struct PostUpdates<'info> {
|
|||
pub treasury: AccountInfo<'info>,
|
||||
/// The contraint is such that either the price_update_account is uninitialized or the payer is the write_authority.
|
||||
/// Pubkey::default() is the SystemProgram on Solana and it can't sign so it's impossible that price_update_account.write_authority == Pubkey::default() once the account is initialized
|
||||
#[account(init_if_needed, constraint = price_update_account.write_authority == Pubkey::default() || price_update_account.write_authority == payer.key(), payer =payer, space = PriceUpdateV1::LEN)]
|
||||
#[account(init_if_needed, constraint = price_update_account.write_authority == Pubkey::default() || price_update_account.write_authority == payer.key() @ ReceiverError::WrongWriteAuthority , payer =payer, space = PriceUpdateV1::LEN)]
|
||||
pub price_update_account: Account<'info, PriceUpdateV1>,
|
||||
pub system_program: Program<'info, System>,
|
||||
}
|
||||
|
@ -290,7 +290,7 @@ pub struct PostUpdatesAtomic<'info> {
|
|||
pub treasury: AccountInfo<'info>,
|
||||
/// The contraint is such that either the price_update_account is uninitialized or the payer is the write_authority.
|
||||
/// Pubkey::default() is the SystemProgram on Solana and it can't sign so it's impossible that price_update_account.write_authority == Pubkey::default() once the account is initialized
|
||||
#[account(init_if_needed, constraint = price_update_account.write_authority == Pubkey::default() || price_update_account.write_authority == payer.key(), payer = payer, space = PriceUpdateV1::LEN)]
|
||||
#[account(init_if_needed, constraint = price_update_account.write_authority == Pubkey::default() || price_update_account.write_authority == payer.key() @ ReceiverError::WrongWriteAuthority, payer = payer, space = PriceUpdateV1::LEN)]
|
||||
pub price_update_account: Account<'info, PriceUpdateV1>,
|
||||
pub system_program: Program<'info, System>,
|
||||
}
|
||||
|
|
|
@ -2,7 +2,10 @@ use {
|
|||
crate::{
|
||||
accounts,
|
||||
instruction,
|
||||
state::config::Config,
|
||||
state::config::{
|
||||
Config,
|
||||
DataSource,
|
||||
},
|
||||
PostUpdatesAtomicParams,
|
||||
CONFIG_SEED,
|
||||
ID,
|
||||
|
@ -78,6 +81,13 @@ impl accounts::Governance {
|
|||
}
|
||||
}
|
||||
|
||||
impl accounts::AcceptGovernanceAuthorityTransfer {
|
||||
pub fn populate(payer: Pubkey) -> Self {
|
||||
let config = get_config_address();
|
||||
accounts::AcceptGovernanceAuthorityTransfer { payer, config }
|
||||
}
|
||||
}
|
||||
|
||||
impl instruction::Initialize {
|
||||
pub fn populate(payer: &Pubkey, initial_config: Config) -> Instruction {
|
||||
Instruction {
|
||||
|
@ -141,6 +151,85 @@ impl instruction::PostUpdatesAtomic {
|
|||
}
|
||||
|
||||
|
||||
impl instruction::SetDataSources {
|
||||
pub fn populate(payer: Pubkey, data_sources: Vec<DataSource>) -> Instruction {
|
||||
let governance_accounts = accounts::Governance::populate(payer).to_account_metas(None);
|
||||
Instruction {
|
||||
program_id: ID,
|
||||
accounts: governance_accounts,
|
||||
data: instruction::SetDataSources {
|
||||
valid_data_sources: data_sources,
|
||||
}
|
||||
.data(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl instruction::SetFee {
|
||||
pub fn populate(payer: Pubkey, fee: u64) -> Instruction {
|
||||
let governance_accounts = accounts::Governance::populate(payer).to_account_metas(None);
|
||||
Instruction {
|
||||
program_id: ID,
|
||||
accounts: governance_accounts,
|
||||
data: instruction::SetFee {
|
||||
single_update_fee_in_lamports: fee,
|
||||
}
|
||||
.data(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl instruction::SetWormholeAddress {
|
||||
pub fn populate(payer: Pubkey, wormhole: Pubkey) -> Instruction {
|
||||
let governance_accounts = accounts::Governance::populate(payer).to_account_metas(None);
|
||||
Instruction {
|
||||
program_id: ID,
|
||||
accounts: governance_accounts,
|
||||
data: instruction::SetWormholeAddress { wormhole }.data(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl instruction::SetMinimumSignatures {
|
||||
pub fn populate(payer: Pubkey, minimum_signatures: u8) -> Instruction {
|
||||
let governance_accounts = accounts::Governance::populate(payer).to_account_metas(None);
|
||||
Instruction {
|
||||
program_id: ID,
|
||||
accounts: governance_accounts,
|
||||
data: instruction::SetMinimumSignatures { minimum_signatures }.data(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl instruction::RequestGovernanceAuthorityTransfer {
|
||||
pub fn populate(payer: Pubkey, target_governance_authority: Pubkey) -> Instruction {
|
||||
let governance_accounts = accounts::Governance::populate(payer).to_account_metas(None);
|
||||
Instruction {
|
||||
program_id: ID,
|
||||
accounts: governance_accounts,
|
||||
data: instruction::RequestGovernanceAuthorityTransfer {
|
||||
target_governance_authority,
|
||||
}
|
||||
.data(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl instruction::AcceptGovernanceAuthorityTransfer {
|
||||
pub fn populate(payer: Pubkey) -> Instruction {
|
||||
let governance_accounts =
|
||||
accounts::AcceptGovernanceAuthorityTransfer::populate(payer).to_account_metas(None);
|
||||
Instruction {
|
||||
program_id: ID,
|
||||
accounts: governance_accounts,
|
||||
data: instruction::AcceptGovernanceAuthorityTransfer {}.data(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub fn get_treasury_address() -> Pubkey {
|
||||
Pubkey::find_program_address(&[TREASURY_SEED.as_ref()], &ID).0
|
||||
}
|
||||
|
|
|
@ -46,17 +46,17 @@ use {
|
|||
pub const DEFAULT_GUARDIAN_SET_INDEX: u32 = 0;
|
||||
pub const WRONG_GUARDIAN_SET_INDEX: u32 = 1;
|
||||
|
||||
pub fn default_receiver_config() -> Config {
|
||||
pub fn default_receiver_config(governance_authority: Pubkey) -> Config {
|
||||
Config {
|
||||
governance_authority: Pubkey::new_unique(),
|
||||
target_governance_authority: None,
|
||||
wormhole: BRIDGE_ID,
|
||||
valid_data_sources: vec![DataSource {
|
||||
governance_authority,
|
||||
target_governance_authority: None,
|
||||
wormhole: BRIDGE_ID,
|
||||
valid_data_sources: vec![DataSource {
|
||||
chain: DEFAULT_DATA_SOURCE.chain.into(),
|
||||
emitter: Pubkey::from(DEFAULT_DATA_SOURCE.address.0),
|
||||
}],
|
||||
single_update_fee_in_lamports: 1,
|
||||
minimum_signatures: 5,
|
||||
minimum_signatures: 5,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -64,6 +64,7 @@ pub fn default_receiver_config() -> Config {
|
|||
pub struct ProgramTestFixtures {
|
||||
pub program_simulator: ProgramSimulator,
|
||||
pub encoded_vaa_addresses: Vec<Pubkey>,
|
||||
pub governance_authority: Keypair,
|
||||
}
|
||||
|
||||
pub fn build_encoded_vaa_account_from_vaa(
|
||||
|
@ -179,8 +180,9 @@ pub async fn setup_pyth_receiver(
|
|||
|
||||
let mut program_simulator = ProgramSimulator::start_from_program_test(program_test).await;
|
||||
|
||||
let initial_config = default_receiver_config();
|
||||
let setup_keypair: Keypair = program_simulator.get_funded_keypair().await.unwrap();
|
||||
let initial_config = default_receiver_config(setup_keypair.pubkey());
|
||||
|
||||
|
||||
program_simulator
|
||||
.process_ix_with_default_compute_limit(
|
||||
|
@ -206,5 +208,21 @@ pub async fn setup_pyth_receiver(
|
|||
ProgramTestFixtures {
|
||||
program_simulator,
|
||||
encoded_vaa_addresses,
|
||||
governance_authority: setup_keypair,
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn assert_treasury_balance(
|
||||
program_simulator: &mut ProgramSimulator,
|
||||
expected_balance: u64,
|
||||
) {
|
||||
let treasury_balance = program_simulator
|
||||
.get_balance(get_treasury_address())
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
treasury_balance,
|
||||
expected_balance + Rent::default().minimum_balance(0)
|
||||
);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,406 @@
|
|||
use {
|
||||
crate::common::WrongSetupOption,
|
||||
common::{
|
||||
setup_pyth_receiver,
|
||||
ProgramTestFixtures,
|
||||
},
|
||||
program_simulator::into_transaction_error,
|
||||
pyth_solana_receiver::{
|
||||
error::ReceiverError,
|
||||
instruction::{
|
||||
AcceptGovernanceAuthorityTransfer,
|
||||
RequestGovernanceAuthorityTransfer,
|
||||
SetDataSources,
|
||||
SetFee,
|
||||
SetMinimumSignatures,
|
||||
SetWormholeAddress,
|
||||
},
|
||||
sdk::get_config_address,
|
||||
state::config::{
|
||||
Config,
|
||||
DataSource,
|
||||
},
|
||||
},
|
||||
pythnet_sdk::test_utils::SECONDARY_DATA_SOURCE,
|
||||
solana_program::{
|
||||
native_token::LAMPORTS_PER_SOL,
|
||||
pubkey::Pubkey,
|
||||
},
|
||||
solana_sdk::signer::Signer,
|
||||
};
|
||||
|
||||
mod common;
|
||||
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_governance() {
|
||||
let ProgramTestFixtures {
|
||||
mut program_simulator,
|
||||
encoded_vaa_addresses: _,
|
||||
governance_authority,
|
||||
} = setup_pyth_receiver(vec![], WrongSetupOption::None).await;
|
||||
|
||||
let new_governance_authority = program_simulator.get_funded_keypair().await.unwrap();
|
||||
|
||||
let initial_config = program_simulator
|
||||
.get_anchor_account_data::<Config>(get_config_address())
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let new_config = Config {
|
||||
governance_authority: new_governance_authority.pubkey(),
|
||||
target_governance_authority: None,
|
||||
wormhole: Pubkey::new_unique(),
|
||||
valid_data_sources: vec![DataSource {
|
||||
chain: SECONDARY_DATA_SOURCE.chain.into(),
|
||||
emitter: Pubkey::from(SECONDARY_DATA_SOURCE.address.0),
|
||||
}],
|
||||
single_update_fee_in_lamports: LAMPORTS_PER_SOL,
|
||||
minimum_signatures: 20,
|
||||
};
|
||||
|
||||
|
||||
// this authority is not allowed to do anything
|
||||
assert_eq!(
|
||||
program_simulator
|
||||
.process_ix_with_default_compute_limit(
|
||||
SetDataSources::populate(
|
||||
new_governance_authority.pubkey(),
|
||||
new_config.valid_data_sources.clone()
|
||||
),
|
||||
&vec![&new_governance_authority],
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.unwrap_err()
|
||||
.unwrap(),
|
||||
into_transaction_error(ReceiverError::GovernanceAuthorityMismatch)
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
program_simulator
|
||||
.process_ix_with_default_compute_limit(
|
||||
SetFee::populate(
|
||||
new_governance_authority.pubkey(),
|
||||
new_config.single_update_fee_in_lamports
|
||||
),
|
||||
&vec![&new_governance_authority],
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.unwrap_err()
|
||||
.unwrap(),
|
||||
into_transaction_error(ReceiverError::GovernanceAuthorityMismatch)
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
program_simulator
|
||||
.process_ix_with_default_compute_limit(
|
||||
SetWormholeAddress::populate(
|
||||
new_governance_authority.pubkey(),
|
||||
new_config.wormhole
|
||||
),
|
||||
&vec![&new_governance_authority],
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.unwrap_err()
|
||||
.unwrap(),
|
||||
into_transaction_error(ReceiverError::GovernanceAuthorityMismatch)
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
program_simulator
|
||||
.process_ix_with_default_compute_limit(
|
||||
SetMinimumSignatures::populate(
|
||||
new_governance_authority.pubkey(),
|
||||
new_config.minimum_signatures,
|
||||
),
|
||||
&vec![&new_governance_authority],
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.unwrap_err()
|
||||
.unwrap(),
|
||||
into_transaction_error(ReceiverError::GovernanceAuthorityMismatch)
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
program_simulator
|
||||
.process_ix_with_default_compute_limit(
|
||||
RequestGovernanceAuthorityTransfer::populate(
|
||||
new_governance_authority.pubkey(),
|
||||
new_config.governance_authority,
|
||||
),
|
||||
&vec![&new_governance_authority],
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.unwrap_err()
|
||||
.unwrap(),
|
||||
into_transaction_error(ReceiverError::GovernanceAuthorityMismatch)
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
program_simulator
|
||||
.get_anchor_account_data::<Config>(get_config_address())
|
||||
.await
|
||||
.unwrap(),
|
||||
initial_config
|
||||
);
|
||||
|
||||
|
||||
// Now start changing for real
|
||||
program_simulator
|
||||
.process_ix_with_default_compute_limit(
|
||||
SetDataSources::populate(
|
||||
governance_authority.pubkey(),
|
||||
new_config.valid_data_sources.clone(),
|
||||
),
|
||||
&vec![&governance_authority],
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mut current_config = program_simulator
|
||||
.get_anchor_account_data::<Config>(get_config_address())
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
current_config.governance_authority,
|
||||
initial_config.governance_authority
|
||||
);
|
||||
assert_eq!(current_config.target_governance_authority, None);
|
||||
assert_eq!(current_config.wormhole, initial_config.wormhole);
|
||||
assert_eq!(
|
||||
current_config.valid_data_sources,
|
||||
new_config.valid_data_sources
|
||||
);
|
||||
assert_eq!(
|
||||
current_config.single_update_fee_in_lamports,
|
||||
initial_config.single_update_fee_in_lamports
|
||||
);
|
||||
assert_eq!(
|
||||
current_config.minimum_signatures,
|
||||
initial_config.minimum_signatures
|
||||
);
|
||||
|
||||
program_simulator
|
||||
.process_ix_with_default_compute_limit(
|
||||
SetFee::populate(
|
||||
governance_authority.pubkey(),
|
||||
new_config.single_update_fee_in_lamports,
|
||||
),
|
||||
&vec![&governance_authority],
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
current_config = program_simulator
|
||||
.get_anchor_account_data::<Config>(get_config_address())
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
current_config.governance_authority,
|
||||
initial_config.governance_authority
|
||||
);
|
||||
assert_eq!(current_config.target_governance_authority, None);
|
||||
assert_eq!(current_config.wormhole, initial_config.wormhole);
|
||||
assert_eq!(
|
||||
current_config.valid_data_sources,
|
||||
new_config.valid_data_sources
|
||||
);
|
||||
assert_eq!(
|
||||
current_config.single_update_fee_in_lamports,
|
||||
new_config.single_update_fee_in_lamports
|
||||
);
|
||||
assert_eq!(
|
||||
current_config.minimum_signatures,
|
||||
initial_config.minimum_signatures
|
||||
);
|
||||
|
||||
program_simulator
|
||||
.process_ix_with_default_compute_limit(
|
||||
SetWormholeAddress::populate(governance_authority.pubkey(), new_config.wormhole),
|
||||
&vec![&governance_authority],
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
current_config = program_simulator
|
||||
.get_anchor_account_data::<Config>(get_config_address())
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
current_config.governance_authority,
|
||||
initial_config.governance_authority
|
||||
);
|
||||
assert_eq!(current_config.target_governance_authority, None);
|
||||
assert_eq!(current_config.wormhole, new_config.wormhole);
|
||||
assert_eq!(
|
||||
current_config.valid_data_sources,
|
||||
new_config.valid_data_sources
|
||||
);
|
||||
assert_eq!(
|
||||
current_config.single_update_fee_in_lamports,
|
||||
new_config.single_update_fee_in_lamports
|
||||
);
|
||||
assert_eq!(
|
||||
current_config.minimum_signatures,
|
||||
initial_config.minimum_signatures
|
||||
);
|
||||
|
||||
program_simulator
|
||||
.process_ix_with_default_compute_limit(
|
||||
SetMinimumSignatures::populate(
|
||||
governance_authority.pubkey(),
|
||||
new_config.minimum_signatures,
|
||||
),
|
||||
&vec![&governance_authority],
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
current_config = program_simulator
|
||||
.get_anchor_account_data::<Config>(get_config_address())
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
current_config.governance_authority,
|
||||
initial_config.governance_authority
|
||||
);
|
||||
assert_eq!(current_config.target_governance_authority, None);
|
||||
assert_eq!(current_config.wormhole, new_config.wormhole);
|
||||
assert_eq!(
|
||||
current_config.valid_data_sources,
|
||||
new_config.valid_data_sources
|
||||
);
|
||||
assert_eq!(
|
||||
current_config.single_update_fee_in_lamports,
|
||||
new_config.single_update_fee_in_lamports
|
||||
);
|
||||
assert_eq!(
|
||||
current_config.minimum_signatures,
|
||||
new_config.minimum_signatures
|
||||
);
|
||||
|
||||
// Target is not defined yet
|
||||
assert_eq!(
|
||||
program_simulator
|
||||
.process_ix_with_default_compute_limit(
|
||||
AcceptGovernanceAuthorityTransfer::populate(new_governance_authority.pubkey()),
|
||||
&vec![&new_governance_authority],
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.unwrap_err()
|
||||
.unwrap(),
|
||||
into_transaction_error(ReceiverError::NonexistentGovernanceAuthorityTransferRequest)
|
||||
);
|
||||
|
||||
// Request transfer
|
||||
program_simulator
|
||||
.process_ix_with_default_compute_limit(
|
||||
RequestGovernanceAuthorityTransfer::populate(
|
||||
governance_authority.pubkey(),
|
||||
new_governance_authority.pubkey(),
|
||||
),
|
||||
&vec![&governance_authority],
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
|
||||
current_config = program_simulator
|
||||
.get_anchor_account_data::<Config>(get_config_address())
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
current_config.governance_authority,
|
||||
initial_config.governance_authority
|
||||
);
|
||||
assert_eq!(
|
||||
current_config.target_governance_authority,
|
||||
Some(new_governance_authority.pubkey())
|
||||
);
|
||||
assert_eq!(current_config.wormhole, new_config.wormhole);
|
||||
assert_eq!(
|
||||
current_config.valid_data_sources,
|
||||
new_config.valid_data_sources
|
||||
);
|
||||
assert_eq!(
|
||||
current_config.single_update_fee_in_lamports,
|
||||
new_config.single_update_fee_in_lamports
|
||||
);
|
||||
assert_eq!(
|
||||
current_config.minimum_signatures,
|
||||
new_config.minimum_signatures
|
||||
);
|
||||
|
||||
let poster = program_simulator.get_funded_keypair().await.unwrap();
|
||||
// Random guy can't accept
|
||||
|
||||
assert_eq!(
|
||||
program_simulator
|
||||
.process_ix_with_default_compute_limit(
|
||||
AcceptGovernanceAuthorityTransfer::populate(poster.pubkey()),
|
||||
&vec![&poster],
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.unwrap_err()
|
||||
.unwrap(),
|
||||
into_transaction_error(ReceiverError::TargetGovernanceAuthorityMismatch)
|
||||
);
|
||||
|
||||
// New authority can accept
|
||||
program_simulator
|
||||
.process_ix_with_default_compute_limit(
|
||||
AcceptGovernanceAuthorityTransfer::populate(new_governance_authority.pubkey()),
|
||||
&vec![&new_governance_authority],
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
current_config = program_simulator
|
||||
.get_anchor_account_data::<Config>(get_config_address())
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(current_config, new_config);
|
||||
|
||||
// Now the new authority can do stuff
|
||||
program_simulator
|
||||
.process_ix_with_default_compute_limit(
|
||||
SetFee::populate(new_governance_authority.pubkey(), 9),
|
||||
&vec![&new_governance_authority],
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
current_config = program_simulator
|
||||
.get_anchor_account_data::<Config>(get_config_address())
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
current_config.governance_authority,
|
||||
new_config.governance_authority
|
||||
);
|
||||
assert_eq!(current_config.target_governance_authority, None);
|
||||
assert_eq!(current_config.wormhole, new_config.wormhole);
|
||||
assert_eq!(
|
||||
current_config.valid_data_sources,
|
||||
new_config.valid_data_sources
|
||||
);
|
||||
assert_eq!(current_config.single_update_fee_in_lamports, 9);
|
||||
assert_eq!(
|
||||
current_config.minimum_signatures,
|
||||
new_config.minimum_signatures
|
||||
);
|
||||
}
|
|
@ -0,0 +1,460 @@
|
|||
use {
|
||||
crate::common::{
|
||||
assert_treasury_balance,
|
||||
WrongSetupOption,
|
||||
DEFAULT_GUARDIAN_SET_INDEX,
|
||||
},
|
||||
common::{
|
||||
setup_pyth_receiver,
|
||||
ProgramTestFixtures,
|
||||
},
|
||||
program_simulator::into_transaction_error,
|
||||
pyth_solana_receiver::{
|
||||
error::ReceiverError,
|
||||
instruction::{
|
||||
PostUpdatesAtomic,
|
||||
SetDataSources,
|
||||
SetFee,
|
||||
},
|
||||
sdk::deserialize_accumulator_update_data,
|
||||
state::{
|
||||
config::DataSource,
|
||||
price_update::{
|
||||
PriceUpdateV1,
|
||||
VerificationLevel,
|
||||
},
|
||||
},
|
||||
},
|
||||
pythnet_sdk::{
|
||||
messages::Message,
|
||||
test_utils::{
|
||||
create_accumulator_message,
|
||||
create_dummy_price_feed_message,
|
||||
create_dummy_twap_message,
|
||||
DEFAULT_DATA_SOURCE,
|
||||
SECONDARY_DATA_SOURCE,
|
||||
},
|
||||
},
|
||||
solana_program::{
|
||||
native_token::LAMPORTS_PER_SOL,
|
||||
pubkey::Pubkey,
|
||||
},
|
||||
solana_sdk::{
|
||||
signature::Keypair,
|
||||
signer::Signer,
|
||||
},
|
||||
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() {
|
||||
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], true, 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;
|
||||
|
||||
let poster = program_simulator.get_funded_keypair().await.unwrap();
|
||||
let price_update_keypair = Keypair::new();
|
||||
|
||||
// corrupted wormhole message
|
||||
assert_eq!(
|
||||
program_simulator
|
||||
.process_ix_with_default_compute_limit(
|
||||
PostUpdatesAtomic::populate(
|
||||
poster.pubkey(),
|
||||
price_update_keypair.pubkey(),
|
||||
BRIDGE_ID,
|
||||
DEFAULT_GUARDIAN_SET_INDEX,
|
||||
vaa,
|
||||
merkle_price_updates[0].clone(),
|
||||
),
|
||||
&vec![&poster, &price_update_keypair],
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.unwrap_err()
|
||||
.unwrap(),
|
||||
into_transaction_error(ReceiverError::InvalidWormholeMessage)
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_invalid_update_message() {
|
||||
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, true);
|
||||
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();
|
||||
|
||||
// corrupted wormhole message
|
||||
assert_eq!(
|
||||
program_simulator
|
||||
.process_ix_with_default_compute_limit(
|
||||
PostUpdatesAtomic::populate(
|
||||
poster.pubkey(),
|
||||
price_update_keypair.pubkey(),
|
||||
BRIDGE_ID,
|
||||
DEFAULT_GUARDIAN_SET_INDEX,
|
||||
vaa,
|
||||
merkle_price_updates[0].clone(),
|
||||
),
|
||||
&vec![&poster, &price_update_keypair],
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.unwrap_err()
|
||||
.unwrap(),
|
||||
into_transaction_error(ReceiverError::DeserializeMessageFailed)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_post_price_update_from_vaa() {
|
||||
let feed_1 = create_dummy_price_feed_message(100);
|
||||
let feed_2 = create_dummy_price_feed_message(200);
|
||||
let feed_3 = create_dummy_price_feed_message(300);
|
||||
let twap_1 = create_dummy_twap_message();
|
||||
|
||||
let message = create_accumulator_message(
|
||||
&[feed_1, feed_2, twap_1],
|
||||
&[feed_1, feed_2, twap_1],
|
||||
false,
|
||||
false,
|
||||
);
|
||||
|
||||
let (vaa, merkle_price_updates) = deserialize_accumulator_update_data(message).unwrap();
|
||||
|
||||
let message2 = create_accumulator_message(&[feed_2, feed_3], &[feed_3], false, false);
|
||||
let (_, merkle_price_updates2) = deserialize_accumulator_update_data(message2).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).await;
|
||||
|
||||
let poster = program_simulator.get_funded_keypair().await.unwrap();
|
||||
let price_update_keypair = Keypair::new();
|
||||
|
||||
// this update is not in the proof
|
||||
assert_eq!(
|
||||
program_simulator
|
||||
.process_ix_with_default_compute_limit(
|
||||
PostUpdatesAtomic::populate(
|
||||
poster.pubkey(),
|
||||
price_update_keypair.pubkey(),
|
||||
BRIDGE_ID,
|
||||
DEFAULT_GUARDIAN_SET_INDEX,
|
||||
vaa.clone(),
|
||||
merkle_price_updates2[0].clone(),
|
||||
),
|
||||
&vec![&poster, &price_update_keypair],
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.unwrap_err()
|
||||
.unwrap(),
|
||||
into_transaction_error(ReceiverError::InvalidPriceUpdate)
|
||||
);
|
||||
|
||||
// this update is a twap
|
||||
assert_eq!(
|
||||
program_simulator
|
||||
.process_ix_with_default_compute_limit(
|
||||
PostUpdatesAtomic::populate(
|
||||
poster.pubkey(),
|
||||
price_update_keypair.pubkey(),
|
||||
BRIDGE_ID,
|
||||
DEFAULT_GUARDIAN_SET_INDEX,
|
||||
vaa.clone(),
|
||||
merkle_price_updates[2].clone(),
|
||||
),
|
||||
&vec![&poster, &price_update_keypair],
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.unwrap_err()
|
||||
.unwrap(),
|
||||
into_transaction_error(ReceiverError::UnsupportedMessageType)
|
||||
);
|
||||
|
||||
|
||||
// change the data source
|
||||
program_simulator
|
||||
.process_ix_with_default_compute_limit(
|
||||
SetDataSources::populate(
|
||||
governance_authority.pubkey(),
|
||||
vec![DataSource {
|
||||
chain: SECONDARY_DATA_SOURCE.chain.into(),
|
||||
emitter: Pubkey::from(DEFAULT_DATA_SOURCE.address.0),
|
||||
}],
|
||||
),
|
||||
&vec![&governance_authority],
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Now this should fail!
|
||||
assert_eq!(
|
||||
program_simulator
|
||||
.process_ix_with_default_compute_limit(
|
||||
PostUpdatesAtomic::populate(
|
||||
poster.pubkey(),
|
||||
price_update_keypair.pubkey(),
|
||||
BRIDGE_ID,
|
||||
DEFAULT_GUARDIAN_SET_INDEX,
|
||||
vaa.clone(),
|
||||
merkle_price_updates[0].clone(),
|
||||
),
|
||||
&vec![&poster, &price_update_keypair],
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.unwrap_err()
|
||||
.unwrap(),
|
||||
into_transaction_error(ReceiverError::InvalidDataSource)
|
||||
);
|
||||
|
||||
// change again, this time the emitter field
|
||||
program_simulator
|
||||
.process_ix_with_default_compute_limit(
|
||||
SetDataSources::populate(
|
||||
governance_authority.pubkey(),
|
||||
vec![DataSource {
|
||||
chain: DEFAULT_DATA_SOURCE.chain.into(),
|
||||
emitter: Pubkey::from(SECONDARY_DATA_SOURCE.address.0),
|
||||
}],
|
||||
),
|
||||
&vec![&governance_authority],
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
|
||||
assert_eq!(
|
||||
program_simulator
|
||||
.process_ix_with_default_compute_limit(
|
||||
PostUpdatesAtomic::populate(
|
||||
poster.pubkey(),
|
||||
price_update_keypair.pubkey(),
|
||||
BRIDGE_ID,
|
||||
DEFAULT_GUARDIAN_SET_INDEX,
|
||||
vaa.clone(),
|
||||
merkle_price_updates[0].clone(),
|
||||
),
|
||||
&vec![&poster, &price_update_keypair],
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.unwrap_err()
|
||||
.unwrap(),
|
||||
into_transaction_error(ReceiverError::InvalidDataSource)
|
||||
);
|
||||
|
||||
// change back
|
||||
program_simulator
|
||||
.process_ix_with_default_compute_limit(
|
||||
SetDataSources::populate(
|
||||
governance_authority.pubkey(),
|
||||
vec![DataSource {
|
||||
chain: DEFAULT_DATA_SOURCE.chain.into(),
|
||||
emitter: Pubkey::from(DEFAULT_DATA_SOURCE.address.0),
|
||||
}],
|
||||
),
|
||||
&vec![&governance_authority],
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Now it works
|
||||
program_simulator
|
||||
.process_ix_with_default_compute_limit(
|
||||
PostUpdatesAtomic::populate(
|
||||
poster.pubkey(),
|
||||
price_update_keypair.pubkey(),
|
||||
BRIDGE_ID,
|
||||
DEFAULT_GUARDIAN_SET_INDEX,
|
||||
vaa.clone(),
|
||||
merkle_price_updates[0].clone(),
|
||||
),
|
||||
&vec![&poster, &price_update_keypair],
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
assert_treasury_balance(&mut program_simulator, 1).await;
|
||||
|
||||
let mut price_update_account = program_simulator
|
||||
.get_anchor_account_data::<PriceUpdateV1>(price_update_keypair.pubkey())
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(price_update_account.write_authority, poster.pubkey());
|
||||
assert_eq!(
|
||||
price_update_account.verification_level,
|
||||
VerificationLevel::Partial(13)
|
||||
);
|
||||
assert_eq!(
|
||||
Message::PriceFeedMessage(price_update_account.price_message),
|
||||
feed_1
|
||||
);
|
||||
|
||||
|
||||
// Now change the fee!
|
||||
program_simulator
|
||||
.process_ix_with_default_compute_limit(
|
||||
SetFee::populate(governance_authority.pubkey(), LAMPORTS_PER_SOL),
|
||||
&vec![&governance_authority],
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
|
||||
assert_eq!(
|
||||
program_simulator
|
||||
.process_ix_with_default_compute_limit(
|
||||
PostUpdatesAtomic::populate(
|
||||
poster.pubkey(),
|
||||
price_update_keypair.pubkey(),
|
||||
BRIDGE_ID,
|
||||
DEFAULT_GUARDIAN_SET_INDEX,
|
||||
vaa.clone(),
|
||||
merkle_price_updates[1].clone(),
|
||||
),
|
||||
&vec![&poster, &price_update_keypair],
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.unwrap_err()
|
||||
.unwrap(),
|
||||
into_transaction_error(ReceiverError::InsufficientFunds)
|
||||
);
|
||||
|
||||
assert_treasury_balance(&mut program_simulator, 1).await;
|
||||
|
||||
price_update_account = program_simulator
|
||||
.get_anchor_account_data::<PriceUpdateV1>(price_update_keypair.pubkey())
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(price_update_account.write_authority, poster.pubkey());
|
||||
assert_eq!(
|
||||
price_update_account.verification_level,
|
||||
VerificationLevel::Partial(13)
|
||||
);
|
||||
assert_eq!(
|
||||
Message::PriceFeedMessage(price_update_account.price_message),
|
||||
feed_1
|
||||
);
|
||||
|
||||
|
||||
// Airdrop more
|
||||
program_simulator
|
||||
.airdrop(&poster.pubkey(), LAMPORTS_PER_SOL)
|
||||
.await
|
||||
.unwrap();
|
||||
program_simulator
|
||||
.process_ix_with_default_compute_limit(
|
||||
SetFee::populate(governance_authority.pubkey(), LAMPORTS_PER_SOL),
|
||||
&vec![&governance_authority],
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
program_simulator
|
||||
.process_ix_with_default_compute_limit(
|
||||
PostUpdatesAtomic::populate(
|
||||
poster.pubkey(),
|
||||
price_update_keypair.pubkey(),
|
||||
BRIDGE_ID,
|
||||
DEFAULT_GUARDIAN_SET_INDEX,
|
||||
vaa.clone(),
|
||||
merkle_price_updates[1].clone(),
|
||||
),
|
||||
&vec![&poster, &price_update_keypair],
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
assert_treasury_balance(&mut program_simulator, LAMPORTS_PER_SOL + 1).await;
|
||||
|
||||
price_update_account = program_simulator
|
||||
.get_anchor_account_data::<PriceUpdateV1>(price_update_keypair.pubkey())
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(price_update_account.write_authority, poster.pubkey());
|
||||
assert_eq!(
|
||||
price_update_account.verification_level,
|
||||
VerificationLevel::Partial(13)
|
||||
);
|
||||
assert_eq!(
|
||||
Message::PriceFeedMessage(price_update_account.price_message),
|
||||
feed_2
|
||||
);
|
||||
|
||||
|
||||
// poster_2 can't write to this price update account
|
||||
let poster_2 = program_simulator.get_funded_keypair().await.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
program_simulator
|
||||
.process_ix_with_default_compute_limit(
|
||||
PostUpdatesAtomic::populate(
|
||||
poster_2.pubkey(),
|
||||
price_update_keypair.pubkey(),
|
||||
BRIDGE_ID,
|
||||
DEFAULT_GUARDIAN_SET_INDEX,
|
||||
vaa.clone(),
|
||||
merkle_price_updates[0].clone(),
|
||||
),
|
||||
&vec![&poster_2, &price_update_keypair],
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.unwrap_err()
|
||||
.unwrap(),
|
||||
into_transaction_error(ReceiverError::WrongWriteAuthority)
|
||||
);
|
||||
}
|
|
@ -1,5 +1,8 @@
|
|||
use {
|
||||
crate::common::WrongSetupOption,
|
||||
crate::common::{
|
||||
assert_treasury_balance,
|
||||
WrongSetupOption,
|
||||
},
|
||||
common::{
|
||||
setup_pyth_receiver,
|
||||
ProgramTestFixtures,
|
||||
|
@ -35,19 +38,22 @@ mod common;
|
|||
async fn test_post_updates() {
|
||||
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);
|
||||
let message = create_accumulator_message(&[feed_1, feed_2], &[feed_1, 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).await;
|
||||
|
||||
let poster = program_simulator.get_funded_keypair().await.unwrap();
|
||||
let price_update_keypair = Keypair::new();
|
||||
|
||||
|
@ -66,6 +72,7 @@ async fn test_post_updates() {
|
|||
.await
|
||||
.unwrap();
|
||||
|
||||
assert_treasury_balance(&mut program_simulator, 1).await;
|
||||
|
||||
let mut price_update_account = program_simulator
|
||||
.get_anchor_account_data::<PriceUpdateV1>(price_update_keypair.pubkey())
|
||||
|
@ -97,6 +104,7 @@ async fn test_post_updates() {
|
|||
.await
|
||||
.unwrap();
|
||||
|
||||
assert_treasury_balance(&mut program_simulator, 2).await;
|
||||
|
||||
price_update_account = program_simulator
|
||||
.get_anchor_account_data::<PriceUpdateV1>(price_update_keypair.pubkey())
|
||||
|
@ -118,12 +126,13 @@ async fn test_post_updates() {
|
|||
async fn test_post_updates_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);
|
||||
let message = create_accumulator_message(&[feed_1, feed_2], &[feed_1, 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,
|
||||
|
@ -156,12 +165,13 @@ async fn test_post_updates_wrong_encoded_vaa_owner() {
|
|||
async fn test_post_updates_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);
|
||||
let message = create_accumulator_message(&[feed_1, feed_2], &[feed_1, 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::UnverifiedEncodedVaa,
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use {
|
||||
crate::common::{
|
||||
assert_treasury_balance,
|
||||
WrongSetupOption,
|
||||
DEFAULT_GUARDIAN_SET_INDEX,
|
||||
},
|
||||
|
@ -44,7 +45,7 @@ mod common;
|
|||
async fn test_post_updates_atomic() {
|
||||
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);
|
||||
let message = create_accumulator_message(&[feed_1, feed_2], &[feed_1, feed_2], false, false);
|
||||
let (vaa, merkle_price_updates) = deserialize_accumulator_update_data(message).unwrap();
|
||||
let vaa = serde_wormhole::to_vec(&trim_vaa_signatures(
|
||||
serde_wormhole::from_slice(&vaa).unwrap(),
|
||||
|
@ -55,11 +56,14 @@ async fn test_post_updates_atomic() {
|
|||
let ProgramTestFixtures {
|
||||
mut program_simulator,
|
||||
encoded_vaa_addresses: _,
|
||||
governance_authority: _,
|
||||
} = setup_pyth_receiver(vec![], WrongSetupOption::None).await;
|
||||
|
||||
let poster = program_simulator.get_funded_keypair().await.unwrap();
|
||||
let price_update_keypair = Keypair::new();
|
||||
|
||||
assert_treasury_balance(&mut program_simulator, 0).await;
|
||||
|
||||
// post one update atomically
|
||||
program_simulator
|
||||
.process_ix_with_default_compute_limit(
|
||||
|
@ -77,6 +81,7 @@ async fn test_post_updates_atomic() {
|
|||
.await
|
||||
.unwrap();
|
||||
|
||||
assert_treasury_balance(&mut program_simulator, 1).await;
|
||||
|
||||
let mut price_update_account = program_simulator
|
||||
.get_anchor_account_data::<PriceUpdateV1>(price_update_keypair.pubkey())
|
||||
|
@ -110,6 +115,7 @@ async fn test_post_updates_atomic() {
|
|||
.await
|
||||
.unwrap();
|
||||
|
||||
assert_treasury_balance(&mut program_simulator, 2).await;
|
||||
|
||||
price_update_account = program_simulator
|
||||
.get_anchor_account_data::<PriceUpdateV1>(price_update_keypair.pubkey())
|
||||
|
@ -131,12 +137,13 @@ async fn test_post_updates_atomic() {
|
|||
async fn test_post_updates_atomic_wrong_vaa() {
|
||||
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);
|
||||
let message = create_accumulator_message(&[feed_1, feed_2], &[feed_1, 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![], WrongSetupOption::None).await;
|
||||
|
||||
let poster = program_simulator.get_funded_keypair().await.unwrap();
|
||||
|
@ -361,13 +368,14 @@ async fn test_post_updates_atomic_wrong_vaa() {
|
|||
async fn test_post_updates_atomic_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);
|
||||
let message = create_accumulator_message(&[feed_1, feed_2], &[feed_1, feed_2], false, false);
|
||||
let (vaa, merkle_price_updates) = deserialize_accumulator_update_data(message).unwrap();
|
||||
let price_update_keypair = Keypair::new();
|
||||
|
||||
let ProgramTestFixtures {
|
||||
mut program_simulator,
|
||||
encoded_vaa_addresses: _,
|
||||
governance_authority: _,
|
||||
} = setup_pyth_receiver(vec![], WrongSetupOption::GuardianSetWrongIndex).await;
|
||||
let poster: Keypair = program_simulator.get_funded_keypair().await.unwrap();
|
||||
assert_eq!(
|
||||
|
@ -394,6 +402,7 @@ async fn test_post_updates_atomic_wrong_setup() {
|
|||
let ProgramTestFixtures {
|
||||
mut program_simulator,
|
||||
encoded_vaa_addresses: _,
|
||||
governance_authority: _,
|
||||
} = setup_pyth_receiver(vec![], WrongSetupOption::GuardianSetExpired).await;
|
||||
let poster = program_simulator.get_funded_keypair().await.unwrap();
|
||||
assert_eq!(
|
||||
|
|
Loading…
Reference in New Issue