|
1 | 1 | use crate::c_oracle_header::{
|
2 | 2 | AccountHeader,
|
| 3 | + PermissionAccount, |
3 | 4 | MAX_NUM_DECIMALS,
|
| 5 | + PERMISSIONS_SEED, |
| 6 | +}; |
| 7 | +use crate::deserialize::{ |
| 8 | + load_account_as, |
| 9 | + load_checked, |
4 | 10 | };
|
5 |
| -use crate::deserialize::load_account_as; |
6 | 11 | use crate::instruction::{
|
| 12 | + CommandHeader, |
7 | 13 | OracleCommand,
|
8 | 14 | UpdPriceArgs,
|
9 | 15 | };
|
@@ -76,6 +82,34 @@ pub fn check_valid_signable_account(
|
76 | 82 | )
|
77 | 83 | }
|
78 | 84 |
|
| 85 | +/// Check that `account` is a valid signable pyth account or |
| 86 | +/// that `funding_account` is a signer and is permissioned by the `permission_account` |
| 87 | +pub fn check_valid_signable_account_or_permissioned_funding_account( |
| 88 | + program_id: &Pubkey, |
| 89 | + account: &AccountInfo, |
| 90 | + funding_account: &AccountInfo, |
| 91 | + permissions_account_option: Option<&AccountInfo>, |
| 92 | + cmd_hdr: &CommandHeader, |
| 93 | +) -> Result<(), ProgramError> { |
| 94 | + if let Some(permissions_account) = permissions_account_option { |
| 95 | + check_valid_permissions_account(program_id, permissions_account)?; |
| 96 | + let permissions_account_data = |
| 97 | + load_checked::<PermissionAccount>(permissions_account, cmd_hdr.version)?; |
| 98 | + check_valid_funding_account(funding_account)?; |
| 99 | + pyth_assert( |
| 100 | + permissions_account_data.is_authorized( |
| 101 | + funding_account.key, |
| 102 | + OracleCommand::from_i32(cmd_hdr.command) |
| 103 | + .ok_or(OracleError::UnrecognizedInstruction)?, |
| 104 | + ), |
| 105 | + OracleError::PermissionViolation.into(), |
| 106 | + )?; |
| 107 | + check_valid_writable_account(program_id, account) |
| 108 | + } else { |
| 109 | + check_valid_signable_account(program_id, account) |
| 110 | + } |
| 111 | +} |
| 112 | + |
79 | 113 | /// Returns `true` if the `account` is fresh, i.e., its data can be overwritten.
|
80 | 114 | /// Use this check to prevent accidentally overwriting accounts whose data is already populated.
|
81 | 115 | pub fn valid_fresh_account(account: &AccountInfo) -> bool {
|
@@ -141,6 +175,40 @@ pub fn check_valid_writable_account(
|
141 | 175 | )
|
142 | 176 | }
|
143 | 177 |
|
| 178 | + |
| 179 | +fn valid_readable_account( |
| 180 | + program_id: &Pubkey, |
| 181 | + account: &AccountInfo, |
| 182 | +) -> Result<bool, ProgramError> { |
| 183 | + Ok( |
| 184 | + account.owner == program_id |
| 185 | + && get_rent()?.is_exempt(account.lamports(), account.data_len()), |
| 186 | + ) |
| 187 | +} |
| 188 | + |
| 189 | +pub fn check_valid_readable_account( |
| 190 | + program_id: &Pubkey, |
| 191 | + account: &AccountInfo, |
| 192 | +) -> Result<(), ProgramError> { |
| 193 | + pyth_assert( |
| 194 | + valid_readable_account(program_id, account)?, |
| 195 | + OracleError::InvalidReadableAccount.into(), |
| 196 | + ) |
| 197 | +} |
| 198 | + |
| 199 | +pub fn check_valid_permissions_account( |
| 200 | + program_id: &Pubkey, |
| 201 | + account: &AccountInfo, |
| 202 | +) -> Result<(), ProgramError> { |
| 203 | + check_valid_readable_account(program_id, account)?; |
| 204 | + let (permission_pda_address, _) = |
| 205 | + Pubkey::find_program_address(&[PERMISSIONS_SEED.as_bytes()], program_id); |
| 206 | + pyth_assert( |
| 207 | + permission_pda_address == *account.key, |
| 208 | + OracleError::InvalidPda.into(), |
| 209 | + ) |
| 210 | +} |
| 211 | + |
144 | 212 | /// Checks whether this instruction is trying to update an individual publisher's price (`true`) or
|
145 | 213 | /// is only trying to refresh the aggregate (`false`)
|
146 | 214 | pub fn is_component_update(cmd_args: &UpdPriceArgs) -> Result<bool, OracleError> {
|
|
0 commit comments