[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::{
|
messages::{
|
||||||
Message,
|
Message,
|
||||||
PriceFeedMessage,
|
PriceFeedMessage,
|
||||||
|
TwapMessage,
|
||||||
},
|
},
|
||||||
wire::{
|
wire::{
|
||||||
to_vec,
|
to_vec,
|
||||||
|
@ -110,24 +111,61 @@ pub fn create_dummy_price_feed_message(value: i64) -> Message {
|
||||||
Message::PriceFeedMessage(msg)
|
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(
|
pub fn create_accumulator_message(
|
||||||
all_feeds: &[Message],
|
all_feeds: &[Message],
|
||||||
updates: &[Message],
|
updates: &[Message],
|
||||||
corrupt_wormhole_message: bool,
|
corrupt_wormhole_message: bool,
|
||||||
|
corrupt_messages: bool,
|
||||||
) -> Vec<u8> {
|
) -> Vec<u8> {
|
||||||
let all_feeds_bytes: Vec<_> = all_feeds
|
let mut all_feeds_bytes: Vec<_> = all_feeds
|
||||||
.iter()
|
.iter()
|
||||||
.map(|f| to_vec::<_, BigEndian>(f).unwrap())
|
.map(|f| to_vec::<_, BigEndian>(f).unwrap())
|
||||||
.collect();
|
.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 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 tree = MerkleTree::<Keccak160>::new(all_feeds_bytes_refs.as_slice()).unwrap();
|
||||||
let mut price_updates: Vec<MerklePriceUpdate> = vec![];
|
let mut price_updates: Vec<MerklePriceUpdate> = vec![];
|
||||||
for update in updates {
|
for update in updates_bytes {
|
||||||
let proof = tree
|
let proof = tree.prove(&update).unwrap();
|
||||||
.prove(&to_vec::<_, BigEndian>(update).unwrap())
|
|
||||||
.unwrap();
|
|
||||||
price_updates.push(MerklePriceUpdate {
|
price_updates.push(MerklePriceUpdate {
|
||||||
message: PrefixedVec::from(to_vec::<_, BigEndian>(update).unwrap()),
|
message: PrefixedVec::from(update),
|
||||||
proof,
|
proof,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -1155,7 +1155,7 @@ mod test {
|
||||||
let feed1 = create_dummy_price_feed_message(100);
|
let feed1 = create_dummy_price_feed_message(100);
|
||||||
let feed2 = create_dummy_price_feed_message(200);
|
let feed2 = create_dummy_price_feed_message(200);
|
||||||
let feed3 = create_dummy_price_feed_message(300);
|
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()])
|
check_sufficient_fee(&deps.as_ref(), &[data.into()])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1246,13 +1246,13 @@ mod test {
|
||||||
let feed2 = create_dummy_price_feed_message(200);
|
let feed2 = create_dummy_price_feed_message(200);
|
||||||
let feed3 = create_dummy_price_feed_message(300);
|
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!(
|
assert_eq!(
|
||||||
get_update_fee_amount(&deps.as_ref(), &[msg.into()]).unwrap(),
|
get_update_fee_amount(&deps.as_ref(), &[msg.into()]).unwrap(),
|
||||||
200
|
200
|
||||||
);
|
);
|
||||||
|
|
||||||
let msg = create_accumulator_message(&[feed1, feed2, feed3], &[feed1], false);
|
let msg = create_accumulator_message(&[feed1, feed2, feed3], &[feed1], false, false);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
get_update_fee_amount(&deps.as_ref(), &[msg.into()]).unwrap(),
|
get_update_fee_amount(&deps.as_ref(), &[msg.into()]).unwrap(),
|
||||||
100
|
100
|
||||||
|
@ -1262,6 +1262,7 @@ mod test {
|
||||||
&[feed1, feed2, feed3],
|
&[feed1, feed2, feed3],
|
||||||
&[feed1, feed2, feed3, feed1, feed3],
|
&[feed1, feed2, feed3, feed1, feed3],
|
||||||
false,
|
false,
|
||||||
|
false,
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
get_update_fee_amount(&deps.as_ref(), &[msg.into()]).unwrap(),
|
get_update_fee_amount(&deps.as_ref(), &[msg.into()]).unwrap(),
|
||||||
|
@ -1270,7 +1271,12 @@ mod test {
|
||||||
|
|
||||||
let batch_msg =
|
let batch_msg =
|
||||||
create_batch_price_update_msg_from_attestations(vec![PriceAttestation::default()]);
|
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!(
|
assert_eq!(
|
||||||
get_update_fee_amount(&deps.as_ref(), &[msg.into(), batch_msg]).unwrap(),
|
get_update_fee_amount(&deps.as_ref(), &[msg.into(), batch_msg]).unwrap(),
|
||||||
400
|
400
|
||||||
|
@ -1287,7 +1293,7 @@ mod test {
|
||||||
|
|
||||||
let feed1 = create_dummy_price_feed_message(100);
|
let feed1 = create_dummy_price_feed_message(100);
|
||||||
let feed2 = create_dummy_price_feed_message(200);
|
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 info = mock_info("123", &[]);
|
||||||
let result = update_price_feeds(deps.as_mut(), env, info, &[msg.into()]);
|
let result = update_price_feeds(deps.as_mut(), env, info, &[msg.into()]);
|
||||||
assert!(result.is_ok());
|
assert!(result.is_ok());
|
||||||
|
@ -1304,7 +1310,7 @@ mod test {
|
||||||
for i in 0..10000 {
|
for i in 0..10000 {
|
||||||
all_feeds.push(create_dummy_price_feed_message(i));
|
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 info = mock_info("123", &[]);
|
||||||
let result = update_price_feeds(deps.as_mut(), env, info, &[msg.into()]);
|
let result = update_price_feeds(deps.as_mut(), env, info, &[msg.into()]);
|
||||||
assert!(result.is_ok());
|
assert!(result.is_ok());
|
||||||
|
@ -1331,15 +1337,24 @@ mod test {
|
||||||
let mut feed1 = create_dummy_price_feed_message(100);
|
let mut feed1 = create_dummy_price_feed_message(100);
|
||||||
let mut feed2 = create_dummy_price_feed_message(200);
|
let mut feed2 = create_dummy_price_feed_message(200);
|
||||||
let mut feed3 = create_dummy_price_feed_message(300);
|
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 feed1).publish_time += 1;
|
||||||
as_mut_price_feed(&mut feed2).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 feed3).publish_time += 1;
|
||||||
as_mut_price_feed(&mut feed1).price *= 2;
|
as_mut_price_feed(&mut feed1).price *= 2;
|
||||||
as_mut_price_feed(&mut feed2).price *= 2;
|
as_mut_price_feed(&mut feed2).price *= 2;
|
||||||
as_mut_price_feed(&mut feed3).price *= 2;
|
as_mut_price_feed(&mut feed3).price *= 2;
|
||||||
let msg2 =
|
let msg2 = create_accumulator_message(
|
||||||
create_accumulator_message(&[feed1, feed2, feed3], &[feed1, feed2, feed3], false);
|
&[feed1, feed2, feed3],
|
||||||
|
&[feed1, feed2, feed3],
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
);
|
||||||
let info = mock_info("123", &[]);
|
let info = mock_info("123", &[]);
|
||||||
let result = update_price_feeds(deps.as_mut(), env, info, &[msg.into(), msg2.into()]);
|
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);
|
let feed3 = create_dummy_price_feed_message(300);
|
||||||
as_mut_price_feed(&mut feed2).publish_time -= 1;
|
as_mut_price_feed(&mut feed2).publish_time -= 1;
|
||||||
as_mut_price_feed(&mut feed2).price *= 2;
|
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 info = mock_info("123", &[]);
|
||||||
let result = update_price_feeds(deps.as_mut(), env, info, &[msg.into()]);
|
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);
|
let feed3 = create_dummy_price_feed_message(300);
|
||||||
as_mut_price_feed(&mut feed2).publish_time -= 1;
|
as_mut_price_feed(&mut feed2).publish_time -= 1;
|
||||||
as_mut_price_feed(&mut feed2).price *= 2;
|
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 info = mock_info("123", &[]);
|
||||||
let result = update_price_feeds(deps.as_mut(), env, info, &[msg.into(), msg2.into()]);
|
let result = update_price_feeds(deps.as_mut(), env, info, &[msg.into(), msg2.into()]);
|
||||||
|
|
||||||
|
@ -1399,7 +1420,7 @@ mod test {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let feed1 = create_dummy_price_feed_message(100);
|
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
|
msg[4] = 3; // major version
|
||||||
let info = mock_info("123", &[]);
|
let info = mock_info("123", &[]);
|
||||||
let result = update_price_feeds(deps.as_mut(), env, info, &[msg.into()]);
|
let result = update_price_feeds(deps.as_mut(), env, info, &[msg.into()]);
|
||||||
|
@ -1418,7 +1439,7 @@ mod test {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let feed1 = create_dummy_price_feed_message(100);
|
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 info = mock_info("123", &[]);
|
||||||
let result = update_price_feeds(deps.as_mut(), env, info, &[msg.into()]);
|
let result = update_price_feeds(deps.as_mut(), env, info, &[msg.into()]);
|
||||||
assert!(result.is_err());
|
assert!(result.is_err());
|
||||||
|
@ -1446,7 +1467,7 @@ mod test {
|
||||||
prev_publish_time: 0,
|
prev_publish_time: 0,
|
||||||
publish_slot: 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 info = mock_info("123", &[]);
|
||||||
let result = update_price_feeds(deps.as_mut(), env, info, &[msg.into()]);
|
let result = update_price_feeds(deps.as_mut(), env, info, &[msg.into()]);
|
||||||
assert!(result.is_err());
|
assert!(result.is_err());
|
||||||
|
|
|
@ -863,7 +863,7 @@ async fn test_accumulator_updates() {
|
||||||
// Create a couple of test feeds.
|
// Create a couple of test feeds.
|
||||||
let feed_1 = create_dummy_price_feed_message(100);
|
let feed_1 = create_dummy_price_feed_message(100);
|
||||||
let feed_2 = create_dummy_price_feed_message(200);
|
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);
|
let message = hex::encode(message);
|
||||||
|
|
||||||
// Call the usual UpdatePriceFeed function.
|
// Call the usual UpdatePriceFeed function.
|
||||||
|
|
|
@ -106,6 +106,11 @@ impl ProgramSimulator {
|
||||||
|
|
||||||
Ok(T::deserialize(&mut &account.data[8..])?)
|
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 {
|
pub fn into_transaction_error<T: Into<anchor_lang::prelude::Error>>(error: T) -> TransactionError {
|
||||||
|
|
|
@ -3,18 +3,21 @@ use anchor_lang::prelude::*;
|
||||||
#[error_code]
|
#[error_code]
|
||||||
pub enum ReceiverError {
|
pub enum ReceiverError {
|
||||||
// Pyth payload errors
|
// 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")]
|
#[msg("Received an invalid wormhole message")]
|
||||||
InvalidWormholeMessage,
|
InvalidWormholeMessage,
|
||||||
|
#[msg("An error occurred when deserializing the message")]
|
||||||
|
DeserializeMessageFailed,
|
||||||
#[msg("Received an invalid price update")]
|
#[msg("Received an invalid price update")]
|
||||||
InvalidPriceUpdate,
|
InvalidPriceUpdate,
|
||||||
#[msg("This type of message is not supported currently")]
|
#[msg("This type of message is not supported currently")]
|
||||||
UnsupportedMessageType,
|
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")]
|
#[msg("Funds are insufficient to pay the receiving fee")]
|
||||||
InsufficientFunds,
|
InsufficientFunds,
|
||||||
|
// Price account permissions
|
||||||
|
#[msg("This signer can't write to price update account")]
|
||||||
|
WrongWriteAuthority,
|
||||||
// Wormhole contract encoded vaa error (from post_updates)
|
// Wormhole contract encoded vaa error (from post_updates)
|
||||||
#[msg("The posted VAA account has the wrong owner.")]
|
#[msg("The posted VAA account has the wrong owner.")]
|
||||||
WrongVaaOwner,
|
WrongVaaOwner,
|
||||||
|
|
|
@ -68,8 +68,8 @@ pub mod pyth_solana_receiver {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn authorize_governance_authority_transfer(
|
pub fn accept_governance_authority_transfer(
|
||||||
ctx: Context<AuthorizeGovernanceAuthorityTransfer>,
|
ctx: Context<AcceptGovernanceAuthorityTransfer>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let config = &mut ctx.accounts.config;
|
let config = &mut ctx.accounts.config;
|
||||||
config.governance_authority = config.target_governance_authority.ok_or(error!(
|
config.governance_authority = config.target_governance_authority.ok_or(error!(
|
||||||
|
@ -244,13 +244,13 @@ pub struct Governance<'info> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Accounts)]
|
#[derive(Accounts)]
|
||||||
pub struct AuthorizeGovernanceAuthorityTransfer<'info> {
|
pub struct AcceptGovernanceAuthorityTransfer<'info> {
|
||||||
#[account(constraint =
|
#[account(constraint =
|
||||||
payer.key() == config.target_governance_authority.ok_or(error!(ReceiverError::NonexistentGovernanceAuthorityTransferRequest))? @
|
payer.key() == config.target_governance_authority.ok_or(error!(ReceiverError::NonexistentGovernanceAuthorityTransferRequest))? @
|
||||||
ReceiverError::TargetGovernanceAuthorityMismatch
|
ReceiverError::TargetGovernanceAuthorityMismatch
|
||||||
)]
|
)]
|
||||||
pub payer: Signer<'info>,
|
pub payer: Signer<'info>,
|
||||||
#[account(seeds = [CONFIG_SEED.as_ref()], bump)]
|
#[account(mut, seeds = [CONFIG_SEED.as_ref()], bump)]
|
||||||
pub config: Account<'info, Config>,
|
pub config: Account<'info, Config>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -269,7 +269,7 @@ pub struct PostUpdates<'info> {
|
||||||
pub treasury: AccountInfo<'info>,
|
pub treasury: AccountInfo<'info>,
|
||||||
/// The contraint is such that either the price_update_account is uninitialized or the payer is the write_authority.
|
/// 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
|
/// 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 price_update_account: Account<'info, PriceUpdateV1>,
|
||||||
pub system_program: Program<'info, System>,
|
pub system_program: Program<'info, System>,
|
||||||
}
|
}
|
||||||
|
@ -290,7 +290,7 @@ pub struct PostUpdatesAtomic<'info> {
|
||||||
pub treasury: AccountInfo<'info>,
|
pub treasury: AccountInfo<'info>,
|
||||||
/// The contraint is such that either the price_update_account is uninitialized or the payer is the write_authority.
|
/// 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
|
/// 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 price_update_account: Account<'info, PriceUpdateV1>,
|
||||||
pub system_program: Program<'info, System>,
|
pub system_program: Program<'info, System>,
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,10 @@ use {
|
||||||
crate::{
|
crate::{
|
||||||
accounts,
|
accounts,
|
||||||
instruction,
|
instruction,
|
||||||
state::config::Config,
|
state::config::{
|
||||||
|
Config,
|
||||||
|
DataSource,
|
||||||
|
},
|
||||||
PostUpdatesAtomicParams,
|
PostUpdatesAtomicParams,
|
||||||
CONFIG_SEED,
|
CONFIG_SEED,
|
||||||
ID,
|
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 {
|
impl instruction::Initialize {
|
||||||
pub fn populate(payer: &Pubkey, initial_config: Config) -> Instruction {
|
pub fn populate(payer: &Pubkey, initial_config: Config) -> Instruction {
|
||||||
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 {
|
pub fn get_treasury_address() -> Pubkey {
|
||||||
Pubkey::find_program_address(&[TREASURY_SEED.as_ref()], &ID).0
|
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 DEFAULT_GUARDIAN_SET_INDEX: u32 = 0;
|
||||||
pub const WRONG_GUARDIAN_SET_INDEX: u32 = 1;
|
pub const WRONG_GUARDIAN_SET_INDEX: u32 = 1;
|
||||||
|
|
||||||
pub fn default_receiver_config() -> Config {
|
pub fn default_receiver_config(governance_authority: Pubkey) -> Config {
|
||||||
Config {
|
Config {
|
||||||
governance_authority: Pubkey::new_unique(),
|
governance_authority,
|
||||||
target_governance_authority: None,
|
target_governance_authority: None,
|
||||||
wormhole: BRIDGE_ID,
|
wormhole: BRIDGE_ID,
|
||||||
valid_data_sources: vec![DataSource {
|
valid_data_sources: vec![DataSource {
|
||||||
chain: DEFAULT_DATA_SOURCE.chain.into(),
|
chain: DEFAULT_DATA_SOURCE.chain.into(),
|
||||||
emitter: Pubkey::from(DEFAULT_DATA_SOURCE.address.0),
|
emitter: Pubkey::from(DEFAULT_DATA_SOURCE.address.0),
|
||||||
}],
|
}],
|
||||||
single_update_fee_in_lamports: 1,
|
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 struct ProgramTestFixtures {
|
||||||
pub program_simulator: ProgramSimulator,
|
pub program_simulator: ProgramSimulator,
|
||||||
pub encoded_vaa_addresses: Vec<Pubkey>,
|
pub encoded_vaa_addresses: Vec<Pubkey>,
|
||||||
|
pub governance_authority: Keypair,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn build_encoded_vaa_account_from_vaa(
|
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 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 setup_keypair: Keypair = program_simulator.get_funded_keypair().await.unwrap();
|
||||||
|
let initial_config = default_receiver_config(setup_keypair.pubkey());
|
||||||
|
|
||||||
|
|
||||||
program_simulator
|
program_simulator
|
||||||
.process_ix_with_default_compute_limit(
|
.process_ix_with_default_compute_limit(
|
||||||
|
@ -206,5 +208,21 @@ pub async fn setup_pyth_receiver(
|
||||||
ProgramTestFixtures {
|
ProgramTestFixtures {
|
||||||
program_simulator,
|
program_simulator,
|
||||||
encoded_vaa_addresses,
|
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 {
|
use {
|
||||||
crate::common::WrongSetupOption,
|
crate::common::{
|
||||||
|
assert_treasury_balance,
|
||||||
|
WrongSetupOption,
|
||||||
|
},
|
||||||
common::{
|
common::{
|
||||||
setup_pyth_receiver,
|
setup_pyth_receiver,
|
||||||
ProgramTestFixtures,
|
ProgramTestFixtures,
|
||||||
|
@ -35,19 +38,22 @@ mod common;
|
||||||
async fn test_post_updates() {
|
async fn test_post_updates() {
|
||||||
let feed_1 = create_dummy_price_feed_message(100);
|
let feed_1 = create_dummy_price_feed_message(100);
|
||||||
let feed_2 = create_dummy_price_feed_message(200);
|
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, merkle_price_updates) = deserialize_accumulator_update_data(message).unwrap();
|
||||||
|
|
||||||
|
|
||||||
let ProgramTestFixtures {
|
let ProgramTestFixtures {
|
||||||
mut program_simulator,
|
mut program_simulator,
|
||||||
encoded_vaa_addresses,
|
encoded_vaa_addresses,
|
||||||
|
governance_authority: _,
|
||||||
} = setup_pyth_receiver(
|
} = setup_pyth_receiver(
|
||||||
vec![serde_wormhole::from_slice(&vaa).unwrap()],
|
vec![serde_wormhole::from_slice(&vaa).unwrap()],
|
||||||
WrongSetupOption::None,
|
WrongSetupOption::None,
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
|
assert_treasury_balance(&mut program_simulator, 0).await;
|
||||||
|
|
||||||
let poster = program_simulator.get_funded_keypair().await.unwrap();
|
let poster = program_simulator.get_funded_keypair().await.unwrap();
|
||||||
let price_update_keypair = Keypair::new();
|
let price_update_keypair = Keypair::new();
|
||||||
|
|
||||||
|
@ -66,6 +72,7 @@ async fn test_post_updates() {
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
assert_treasury_balance(&mut program_simulator, 1).await;
|
||||||
|
|
||||||
let mut price_update_account = program_simulator
|
let mut price_update_account = program_simulator
|
||||||
.get_anchor_account_data::<PriceUpdateV1>(price_update_keypair.pubkey())
|
.get_anchor_account_data::<PriceUpdateV1>(price_update_keypair.pubkey())
|
||||||
|
@ -97,6 +104,7 @@ async fn test_post_updates() {
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
assert_treasury_balance(&mut program_simulator, 2).await;
|
||||||
|
|
||||||
price_update_account = program_simulator
|
price_update_account = program_simulator
|
||||||
.get_anchor_account_data::<PriceUpdateV1>(price_update_keypair.pubkey())
|
.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() {
|
async fn test_post_updates_wrong_encoded_vaa_owner() {
|
||||||
let feed_1 = create_dummy_price_feed_message(100);
|
let feed_1 = create_dummy_price_feed_message(100);
|
||||||
let feed_2 = create_dummy_price_feed_message(200);
|
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, merkle_price_updates) = deserialize_accumulator_update_data(message).unwrap();
|
||||||
|
|
||||||
let ProgramTestFixtures {
|
let ProgramTestFixtures {
|
||||||
mut program_simulator,
|
mut program_simulator,
|
||||||
encoded_vaa_addresses: _,
|
encoded_vaa_addresses: _,
|
||||||
|
governance_authority: _,
|
||||||
} = setup_pyth_receiver(
|
} = setup_pyth_receiver(
|
||||||
vec![serde_wormhole::from_slice(&vaa).unwrap()],
|
vec![serde_wormhole::from_slice(&vaa).unwrap()],
|
||||||
WrongSetupOption::None,
|
WrongSetupOption::None,
|
||||||
|
@ -156,12 +165,13 @@ async fn test_post_updates_wrong_encoded_vaa_owner() {
|
||||||
async fn test_post_updates_wrong_setup() {
|
async fn test_post_updates_wrong_setup() {
|
||||||
let feed_1 = create_dummy_price_feed_message(100);
|
let feed_1 = create_dummy_price_feed_message(100);
|
||||||
let feed_2 = create_dummy_price_feed_message(200);
|
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, merkle_price_updates) = deserialize_accumulator_update_data(message).unwrap();
|
||||||
|
|
||||||
let ProgramTestFixtures {
|
let ProgramTestFixtures {
|
||||||
mut program_simulator,
|
mut program_simulator,
|
||||||
encoded_vaa_addresses,
|
encoded_vaa_addresses,
|
||||||
|
governance_authority: _,
|
||||||
} = setup_pyth_receiver(
|
} = setup_pyth_receiver(
|
||||||
vec![serde_wormhole::from_slice(&vaa).unwrap()],
|
vec![serde_wormhole::from_slice(&vaa).unwrap()],
|
||||||
WrongSetupOption::UnverifiedEncodedVaa,
|
WrongSetupOption::UnverifiedEncodedVaa,
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use {
|
use {
|
||||||
crate::common::{
|
crate::common::{
|
||||||
|
assert_treasury_balance,
|
||||||
WrongSetupOption,
|
WrongSetupOption,
|
||||||
DEFAULT_GUARDIAN_SET_INDEX,
|
DEFAULT_GUARDIAN_SET_INDEX,
|
||||||
},
|
},
|
||||||
|
@ -44,7 +45,7 @@ mod common;
|
||||||
async fn test_post_updates_atomic() {
|
async fn test_post_updates_atomic() {
|
||||||
let feed_1 = create_dummy_price_feed_message(100);
|
let feed_1 = create_dummy_price_feed_message(100);
|
||||||
let feed_2 = create_dummy_price_feed_message(200);
|
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, merkle_price_updates) = deserialize_accumulator_update_data(message).unwrap();
|
||||||
let vaa = serde_wormhole::to_vec(&trim_vaa_signatures(
|
let vaa = serde_wormhole::to_vec(&trim_vaa_signatures(
|
||||||
serde_wormhole::from_slice(&vaa).unwrap(),
|
serde_wormhole::from_slice(&vaa).unwrap(),
|
||||||
|
@ -55,11 +56,14 @@ async fn test_post_updates_atomic() {
|
||||||
let ProgramTestFixtures {
|
let ProgramTestFixtures {
|
||||||
mut program_simulator,
|
mut program_simulator,
|
||||||
encoded_vaa_addresses: _,
|
encoded_vaa_addresses: _,
|
||||||
|
governance_authority: _,
|
||||||
} = setup_pyth_receiver(vec![], WrongSetupOption::None).await;
|
} = setup_pyth_receiver(vec![], WrongSetupOption::None).await;
|
||||||
|
|
||||||
let poster = program_simulator.get_funded_keypair().await.unwrap();
|
let poster = program_simulator.get_funded_keypair().await.unwrap();
|
||||||
let price_update_keypair = Keypair::new();
|
let price_update_keypair = Keypair::new();
|
||||||
|
|
||||||
|
assert_treasury_balance(&mut program_simulator, 0).await;
|
||||||
|
|
||||||
// post one update atomically
|
// post one update atomically
|
||||||
program_simulator
|
program_simulator
|
||||||
.process_ix_with_default_compute_limit(
|
.process_ix_with_default_compute_limit(
|
||||||
|
@ -77,6 +81,7 @@ async fn test_post_updates_atomic() {
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
assert_treasury_balance(&mut program_simulator, 1).await;
|
||||||
|
|
||||||
let mut price_update_account = program_simulator
|
let mut price_update_account = program_simulator
|
||||||
.get_anchor_account_data::<PriceUpdateV1>(price_update_keypair.pubkey())
|
.get_anchor_account_data::<PriceUpdateV1>(price_update_keypair.pubkey())
|
||||||
|
@ -110,6 +115,7 @@ async fn test_post_updates_atomic() {
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
assert_treasury_balance(&mut program_simulator, 2).await;
|
||||||
|
|
||||||
price_update_account = program_simulator
|
price_update_account = program_simulator
|
||||||
.get_anchor_account_data::<PriceUpdateV1>(price_update_keypair.pubkey())
|
.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() {
|
async fn test_post_updates_atomic_wrong_vaa() {
|
||||||
let feed_1 = create_dummy_price_feed_message(100);
|
let feed_1 = create_dummy_price_feed_message(100);
|
||||||
let feed_2 = create_dummy_price_feed_message(200);
|
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, merkle_price_updates) = deserialize_accumulator_update_data(message).unwrap();
|
||||||
|
|
||||||
let ProgramTestFixtures {
|
let ProgramTestFixtures {
|
||||||
mut program_simulator,
|
mut program_simulator,
|
||||||
encoded_vaa_addresses: _,
|
encoded_vaa_addresses: _,
|
||||||
|
governance_authority: _,
|
||||||
} = setup_pyth_receiver(vec![], WrongSetupOption::None).await;
|
} = setup_pyth_receiver(vec![], WrongSetupOption::None).await;
|
||||||
|
|
||||||
let poster = program_simulator.get_funded_keypair().await.unwrap();
|
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() {
|
async fn test_post_updates_atomic_wrong_setup() {
|
||||||
let feed_1 = create_dummy_price_feed_message(100);
|
let feed_1 = create_dummy_price_feed_message(100);
|
||||||
let feed_2 = create_dummy_price_feed_message(200);
|
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, merkle_price_updates) = deserialize_accumulator_update_data(message).unwrap();
|
||||||
let price_update_keypair = Keypair::new();
|
let price_update_keypair = Keypair::new();
|
||||||
|
|
||||||
let ProgramTestFixtures {
|
let ProgramTestFixtures {
|
||||||
mut program_simulator,
|
mut program_simulator,
|
||||||
encoded_vaa_addresses: _,
|
encoded_vaa_addresses: _,
|
||||||
|
governance_authority: _,
|
||||||
} = setup_pyth_receiver(vec![], WrongSetupOption::GuardianSetWrongIndex).await;
|
} = setup_pyth_receiver(vec![], WrongSetupOption::GuardianSetWrongIndex).await;
|
||||||
let poster: Keypair = program_simulator.get_funded_keypair().await.unwrap();
|
let poster: Keypair = program_simulator.get_funded_keypair().await.unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -394,6 +402,7 @@ async fn test_post_updates_atomic_wrong_setup() {
|
||||||
let ProgramTestFixtures {
|
let ProgramTestFixtures {
|
||||||
mut program_simulator,
|
mut program_simulator,
|
||||||
encoded_vaa_addresses: _,
|
encoded_vaa_addresses: _,
|
||||||
|
governance_authority: _,
|
||||||
} = setup_pyth_receiver(vec![], WrongSetupOption::GuardianSetExpired).await;
|
} = setup_pyth_receiver(vec![], WrongSetupOption::GuardianSetExpired).await;
|
||||||
let poster = program_simulator.get_funded_keypair().await.unwrap();
|
let poster = program_simulator.get_funded_keypair().await.unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
|
Loading…
Reference in New Issue