2020-11-26 14:19:50 -08:00
|
|
|
//! Program state processor
|
|
|
|
|
|
|
|
use crate::{
|
|
|
|
error::Error,
|
2021-01-10 18:02:48 -08:00
|
|
|
instruction::{Instruction, PAYMENT_AMOUNT},
|
|
|
|
state::{Aggregator, Oracle},
|
2020-11-26 14:19:50 -08:00
|
|
|
};
|
2020-11-27 22:52:54 -08:00
|
|
|
|
2020-11-26 14:19:50 -08:00
|
|
|
use solana_program::{
|
|
|
|
account_info::{next_account_info, AccountInfo},
|
2021-01-08 09:39:16 -08:00
|
|
|
clock::Clock,
|
2020-11-26 14:19:50 -08:00
|
|
|
entrypoint::ProgramResult,
|
2021-01-08 09:39:16 -08:00
|
|
|
msg,
|
|
|
|
program::invoke_signed,
|
|
|
|
program_error::ProgramError,
|
|
|
|
program_pack::Pack,
|
2020-11-26 14:19:50 -08:00
|
|
|
pubkey::Pubkey,
|
|
|
|
sysvar::{rent::Rent, Sysvar},
|
|
|
|
};
|
|
|
|
|
|
|
|
/// Program state handler.
|
|
|
|
pub struct Processor {}
|
|
|
|
|
|
|
|
impl Processor {
|
|
|
|
/// Processes an [Instruction](enum.Instruction.html).
|
2020-12-01 19:42:09 -08:00
|
|
|
pub fn process(program_id: &Pubkey, accounts: &[AccountInfo], input: &[u8]) -> ProgramResult {
|
2020-12-17 22:38:28 -08:00
|
|
|
let instruction = Instruction::unpack_from_slice(input)?;
|
2020-11-26 14:19:50 -08:00
|
|
|
|
|
|
|
match instruction {
|
|
|
|
Instruction::Initialize {
|
2020-12-07 19:57:03 -08:00
|
|
|
submit_interval,
|
2020-11-26 14:19:50 -08:00
|
|
|
min_submission_value,
|
|
|
|
max_submission_value,
|
2021-01-12 02:26:59 -08:00
|
|
|
submission_decimals,
|
2020-12-02 22:45:16 -08:00
|
|
|
description,
|
2020-11-26 14:19:50 -08:00
|
|
|
} => {
|
2020-12-17 22:38:28 -08:00
|
|
|
msg!("Instruction: Initialize");
|
2020-11-26 14:19:50 -08:00
|
|
|
Self::process_initialize(
|
2021-01-08 09:39:16 -08:00
|
|
|
program_id,
|
|
|
|
accounts,
|
|
|
|
submit_interval,
|
|
|
|
min_submission_value,
|
|
|
|
max_submission_value,
|
2021-01-12 02:26:59 -08:00
|
|
|
submission_decimals,
|
2021-01-08 09:39:16 -08:00
|
|
|
description,
|
2020-11-26 14:19:50 -08:00
|
|
|
)
|
2021-01-08 09:39:16 -08:00
|
|
|
}
|
2021-01-10 18:02:48 -08:00
|
|
|
Instruction::AddOracle { description } => {
|
2020-12-17 22:38:28 -08:00
|
|
|
msg!("Instruction: AddOracle");
|
2021-01-10 18:02:48 -08:00
|
|
|
Self::process_add_oracle(accounts, description)
|
2021-01-08 09:39:16 -08:00
|
|
|
}
|
2021-01-10 18:02:48 -08:00
|
|
|
Instruction::RemoveOracle { pubkey } => {
|
2020-12-17 22:38:28 -08:00
|
|
|
msg!("Instruction: RemoveOracle");
|
2021-01-10 18:02:48 -08:00
|
|
|
Self::process_remove_oracle(accounts, pubkey)
|
2021-01-08 09:39:16 -08:00
|
|
|
}
|
|
|
|
Instruction::Submit { submission } => {
|
2020-12-17 22:38:28 -08:00
|
|
|
msg!("Instruction: Submit");
|
2021-01-08 09:39:16 -08:00
|
|
|
Self::process_submit(accounts, submission)
|
|
|
|
}
|
|
|
|
Instruction::Withdraw { amount, seed } => {
|
2020-12-17 22:38:28 -08:00
|
|
|
msg!("Instruction: Withdraw");
|
2021-01-08 09:39:16 -08:00
|
|
|
Self::process_withdraw(accounts, amount, seed)
|
|
|
|
}
|
2020-11-26 14:19:50 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Processes an [Initialize](enum.Instruction.html) instruction.
|
|
|
|
pub fn process_initialize(
|
2020-12-07 19:57:03 -08:00
|
|
|
_program_id: &Pubkey,
|
2020-11-26 14:19:50 -08:00
|
|
|
accounts: &[AccountInfo],
|
2020-12-07 19:57:03 -08:00
|
|
|
submit_interval: u32,
|
2020-11-26 14:19:50 -08:00
|
|
|
min_submission_value: u64,
|
|
|
|
max_submission_value: u64,
|
2021-01-14 04:17:25 -08:00
|
|
|
submission_decimals: u8,
|
2020-12-02 22:45:16 -08:00
|
|
|
description: [u8; 32],
|
2020-11-26 14:19:50 -08:00
|
|
|
) -> ProgramResult {
|
|
|
|
let account_info_iter = &mut accounts.iter();
|
2020-12-01 19:42:09 -08:00
|
|
|
|
2020-11-30 09:41:09 -08:00
|
|
|
let rent_info = next_account_info(account_info_iter)?;
|
2020-12-04 04:11:10 -08:00
|
|
|
let aggregator_info = next_account_info(account_info_iter)?;
|
2020-12-08 05:14:05 -08:00
|
|
|
let owner_info = next_account_info(account_info_iter)?;
|
2021-01-08 09:39:16 -08:00
|
|
|
|
2020-11-30 09:41:09 -08:00
|
|
|
// check signer
|
2020-12-08 05:14:05 -08:00
|
|
|
if !owner_info.is_signer {
|
2020-11-30 09:41:09 -08:00
|
|
|
return Err(ProgramError::MissingRequiredSignature);
|
|
|
|
}
|
2020-12-01 19:42:09 -08:00
|
|
|
|
2020-11-30 09:41:09 -08:00
|
|
|
let rent = &Rent::from_account_info(rent_info)?;
|
2021-01-19 19:17:47 -08:00
|
|
|
|
2020-11-26 14:19:50 -08:00
|
|
|
let mut aggregator = Aggregator::unpack_unchecked(&aggregator_info.data.borrow())?;
|
|
|
|
if aggregator.is_initialized {
|
|
|
|
return Err(Error::AlreadyInUse.into());
|
|
|
|
}
|
|
|
|
|
2020-11-30 09:41:09 -08:00
|
|
|
if !rent.is_exempt(aggregator_info.lamports(), aggregator_info.data_len()) {
|
2020-11-26 14:19:50 -08:00
|
|
|
return Err(Error::NotRentExempt.into());
|
|
|
|
}
|
2020-12-01 19:42:09 -08:00
|
|
|
|
2020-12-07 19:57:03 -08:00
|
|
|
aggregator.submit_interval = submit_interval;
|
2020-11-26 14:19:50 -08:00
|
|
|
aggregator.min_submission_value = min_submission_value;
|
|
|
|
aggregator.max_submission_value = max_submission_value;
|
2021-01-12 02:26:59 -08:00
|
|
|
aggregator.submission_decimals = submission_decimals;
|
2020-11-26 14:19:50 -08:00
|
|
|
aggregator.description = description;
|
|
|
|
aggregator.is_initialized = true;
|
2020-12-17 22:38:28 -08:00
|
|
|
aggregator.owner = owner_info.key.to_bytes();
|
2020-11-30 09:41:09 -08:00
|
|
|
|
2020-11-26 14:19:50 -08:00
|
|
|
Aggregator::pack(aggregator, &mut aggregator_info.data.borrow_mut())?;
|
2021-01-08 09:39:16 -08:00
|
|
|
|
2020-11-26 14:19:50 -08:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Processes an [AddOracle](enum.Instruction.html) instruction.
|
2021-01-21 15:00:16 -08:00
|
|
|
pub fn process_add_oracle(accounts: &[AccountInfo], description: [u8; 32]) -> ProgramResult {
|
2020-11-27 01:38:49 -08:00
|
|
|
let account_info_iter = &mut accounts.iter();
|
2020-12-01 02:50:31 -08:00
|
|
|
let oracle_info = next_account_info(account_info_iter)?;
|
2020-12-08 05:14:05 -08:00
|
|
|
let oracle_owner_info = next_account_info(account_info_iter)?;
|
2020-11-27 22:52:54 -08:00
|
|
|
let clock_sysvar_info = next_account_info(account_info_iter)?;
|
2020-12-01 19:42:09 -08:00
|
|
|
let aggregator_info = next_account_info(account_info_iter)?;
|
2020-12-08 05:14:05 -08:00
|
|
|
let aggregator_owner_info = next_account_info(account_info_iter)?;
|
2020-12-01 19:42:09 -08:00
|
|
|
|
2020-12-08 05:14:05 -08:00
|
|
|
if !aggregator_owner_info.is_signer {
|
2020-12-01 19:42:09 -08:00
|
|
|
return Err(ProgramError::MissingRequiredSignature);
|
|
|
|
}
|
2021-01-08 09:39:16 -08:00
|
|
|
|
2020-12-01 19:42:09 -08:00
|
|
|
let mut aggregator = Aggregator::unpack_unchecked(&aggregator_info.data.borrow())?;
|
2020-11-27 22:52:54 -08:00
|
|
|
|
2020-11-27 01:38:49 -08:00
|
|
|
if !aggregator.is_initialized {
|
|
|
|
return Err(Error::NotFoundAggregator.into());
|
|
|
|
}
|
2020-12-01 19:42:09 -08:00
|
|
|
|
2020-12-17 22:38:28 -08:00
|
|
|
if &Pubkey::new_from_array(aggregator.owner) != aggregator_owner_info.key {
|
|
|
|
return Err(Error::OwnerMismatch.into());
|
|
|
|
}
|
|
|
|
|
2020-12-04 04:11:10 -08:00
|
|
|
let mut oracle = Oracle::unpack_unchecked(&oracle_info.data.borrow())?;
|
|
|
|
if oracle.is_initialized {
|
|
|
|
return Err(Error::AlreadyInUse.into());
|
|
|
|
}
|
|
|
|
|
2020-12-07 19:57:03 -08:00
|
|
|
// sys clock
|
|
|
|
let clock = &Clock::from_account_info(clock_sysvar_info)?;
|
|
|
|
|
2021-01-10 18:02:48 -08:00
|
|
|
let mut inserted = false;
|
|
|
|
for s in aggregator.submissions.iter_mut() {
|
|
|
|
if Pubkey::new_from_array(s.oracle) == Pubkey::default() {
|
|
|
|
inserted = true;
|
|
|
|
s.oracle = oracle_info.key.to_bytes();
|
2021-01-19 05:15:34 -08:00
|
|
|
break;
|
2021-01-10 18:02:48 -08:00
|
|
|
} else if &Pubkey::new_from_array(s.oracle) == oracle_info.key {
|
|
|
|
return Err(Error::OracleExist.into());
|
|
|
|
}
|
2021-01-08 09:39:16 -08:00
|
|
|
}
|
2020-12-17 22:38:28 -08:00
|
|
|
|
2021-01-10 18:02:48 -08:00
|
|
|
if !inserted {
|
|
|
|
return Err(Error::MaxOralcesReached.into());
|
2020-12-01 02:50:31 -08:00
|
|
|
}
|
2020-11-27 01:38:49 -08:00
|
|
|
|
|
|
|
Aggregator::pack(aggregator, &mut aggregator_info.data.borrow_mut())?;
|
2020-12-01 19:42:09 -08:00
|
|
|
|
2020-12-01 02:50:31 -08:00
|
|
|
oracle.next_submit_time = clock.unix_timestamp;
|
|
|
|
oracle.description = description;
|
|
|
|
oracle.is_initialized = true;
|
|
|
|
oracle.withdrawable = 0;
|
2020-12-17 22:38:28 -08:00
|
|
|
oracle.aggregator = aggregator_info.key.to_bytes();
|
|
|
|
oracle.owner = oracle_owner_info.key.to_bytes();
|
2020-12-01 02:50:31 -08:00
|
|
|
|
|
|
|
Oracle::pack(oracle, &mut oracle_info.data.borrow_mut())?;
|
2020-11-27 01:38:49 -08:00
|
|
|
|
2020-11-26 14:19:50 -08:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Processes an [RemoveOracle](enum.Instruction.html) instruction.
|
2021-01-21 15:00:16 -08:00
|
|
|
pub fn process_remove_oracle(accounts: &[AccountInfo], pubkey: [u8; 32]) -> ProgramResult {
|
2020-11-27 22:52:54 -08:00
|
|
|
let account_info_iter = &mut accounts.iter();
|
|
|
|
let aggregator_info = next_account_info(account_info_iter)?;
|
2020-12-08 05:14:05 -08:00
|
|
|
let owner_info = next_account_info(account_info_iter)?;
|
2020-11-27 22:52:54 -08:00
|
|
|
|
2020-12-08 05:14:05 -08:00
|
|
|
if !owner_info.is_signer {
|
2020-12-01 19:42:09 -08:00
|
|
|
return Err(ProgramError::MissingRequiredSignature);
|
|
|
|
}
|
2021-01-08 09:39:16 -08:00
|
|
|
|
2020-11-27 22:52:54 -08:00
|
|
|
let mut aggregator = Aggregator::unpack_unchecked(&aggregator_info.data.borrow())?;
|
|
|
|
|
|
|
|
if !aggregator.is_initialized {
|
|
|
|
return Err(Error::NotFoundAggregator.into());
|
|
|
|
}
|
|
|
|
|
2020-12-17 22:38:28 -08:00
|
|
|
if &Pubkey::new_from_array(aggregator.owner) != owner_info.key {
|
2020-12-08 05:14:05 -08:00
|
|
|
return Err(Error::OwnerMismatch.into());
|
|
|
|
}
|
|
|
|
|
2021-01-10 18:02:48 -08:00
|
|
|
let mut found = false;
|
|
|
|
for s in aggregator.submissions.iter_mut() {
|
2021-01-21 15:00:16 -08:00
|
|
|
if s.oracle != Pubkey::default().to_bytes() && s.oracle == pubkey {
|
2021-01-10 18:02:48 -08:00
|
|
|
found = true;
|
|
|
|
s.oracle = Pubkey::default().to_bytes();
|
2021-01-19 05:15:34 -08:00
|
|
|
break;
|
2021-01-10 18:02:48 -08:00
|
|
|
}
|
|
|
|
}
|
2020-11-27 22:52:54 -08:00
|
|
|
|
2021-01-10 18:02:48 -08:00
|
|
|
if !found {
|
2020-12-04 04:11:10 -08:00
|
|
|
return Err(Error::NotFoundOracle.into());
|
|
|
|
}
|
|
|
|
|
2020-11-27 22:52:54 -08:00
|
|
|
Aggregator::pack(aggregator, &mut aggregator_info.data.borrow_mut())?;
|
|
|
|
|
2020-11-26 14:19:50 -08:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Processes an [Submit](enum.Instruction.html) instruction.
|
2021-01-08 09:39:16 -08:00
|
|
|
pub fn process_submit(accounts: &[AccountInfo], submission: u64) -> ProgramResult {
|
2020-11-27 22:52:54 -08:00
|
|
|
let account_info_iter = &mut accounts.iter();
|
|
|
|
let aggregator_info = next_account_info(account_info_iter)?;
|
|
|
|
let clock_sysvar_info = next_account_info(account_info_iter)?;
|
2020-12-01 02:50:31 -08:00
|
|
|
let oracle_info = next_account_info(account_info_iter)?;
|
2020-12-08 05:14:05 -08:00
|
|
|
let oracle_owner_info = next_account_info(account_info_iter)?;
|
2020-11-27 22:52:54 -08:00
|
|
|
|
2020-12-07 19:57:03 -08:00
|
|
|
let mut aggregator = Aggregator::unpack_unchecked(&aggregator_info.data.borrow())?;
|
2020-11-27 22:52:54 -08:00
|
|
|
if !aggregator.is_initialized {
|
|
|
|
return Err(Error::NotFoundAggregator.into());
|
|
|
|
}
|
|
|
|
|
2021-01-08 09:39:16 -08:00
|
|
|
if submission < aggregator.min_submission_value
|
|
|
|
|| submission > aggregator.max_submission_value
|
|
|
|
{
|
2020-11-27 22:52:54 -08:00
|
|
|
return Err(Error::SubmissonValueOutOfRange.into());
|
|
|
|
}
|
|
|
|
|
2020-12-08 05:14:05 -08:00
|
|
|
if !oracle_owner_info.is_signer {
|
2020-12-01 02:50:31 -08:00
|
|
|
return Err(ProgramError::MissingRequiredSignature);
|
2020-11-27 22:52:54 -08:00
|
|
|
}
|
|
|
|
|
2020-12-01 02:50:31 -08:00
|
|
|
let mut oracle = Oracle::unpack_unchecked(&oracle_info.data.borrow())?;
|
|
|
|
if !oracle.is_initialized {
|
2020-11-27 22:52:54 -08:00
|
|
|
return Err(Error::NotFoundOracle.into());
|
|
|
|
}
|
|
|
|
|
2020-12-17 22:38:28 -08:00
|
|
|
if &Pubkey::new_from_array(oracle.owner) != oracle_owner_info.key {
|
2020-12-08 05:14:05 -08:00
|
|
|
return Err(Error::OwnerMismatch.into());
|
|
|
|
}
|
|
|
|
|
2020-12-17 22:38:28 -08:00
|
|
|
if &Pubkey::new_from_array(oracle.aggregator) != aggregator_info.key {
|
2020-12-07 19:57:03 -08:00
|
|
|
return Err(Error::AggregatorKeyNotMatch.into());
|
|
|
|
}
|
|
|
|
|
2020-12-01 02:50:31 -08:00
|
|
|
let clock = &Clock::from_account_info(clock_sysvar_info)?;
|
2020-12-07 19:57:03 -08:00
|
|
|
|
|
|
|
// check whether the aggregator owned this oracle
|
|
|
|
let mut found = false;
|
2021-01-08 09:39:16 -08:00
|
|
|
for s in aggregator.submissions.iter_mut() {
|
2020-12-17 22:38:28 -08:00
|
|
|
if &Pubkey::new_from_array(s.oracle) == oracle_info.key {
|
2020-12-07 19:57:03 -08:00
|
|
|
s.value = submission;
|
|
|
|
s.time = clock.unix_timestamp;
|
|
|
|
found = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if !found {
|
|
|
|
return Err(Error::NotFoundOracle.into());
|
|
|
|
}
|
|
|
|
|
2020-12-01 02:50:31 -08:00
|
|
|
if oracle.next_submit_time > clock.unix_timestamp {
|
|
|
|
return Err(Error::SubmissonCooling.into());
|
|
|
|
}
|
|
|
|
|
|
|
|
oracle.withdrawable += PAYMENT_AMOUNT;
|
2020-12-07 19:57:03 -08:00
|
|
|
oracle.next_submit_time = clock.unix_timestamp + aggregator.submit_interval as i64;
|
2020-12-01 02:50:31 -08:00
|
|
|
|
2020-12-17 22:38:28 -08:00
|
|
|
// update aggregator
|
|
|
|
Aggregator::pack(aggregator, &mut aggregator_info.data.borrow_mut())?;
|
|
|
|
|
|
|
|
// update oracle
|
2020-12-01 02:50:31 -08:00
|
|
|
Oracle::pack(oracle, &mut oracle_info.data.borrow_mut())?;
|
|
|
|
|
2020-11-27 22:52:54 -08:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2020-11-30 09:41:09 -08:00
|
|
|
/// Processes an [Withdraw](enum.Instruction.html) instruction
|
|
|
|
pub fn process_withdraw(
|
|
|
|
accounts: &[AccountInfo],
|
|
|
|
amount: u64,
|
2020-12-17 22:38:28 -08:00
|
|
|
seed: [u8; 32],
|
2020-11-26 14:19:50 -08:00
|
|
|
) -> ProgramResult {
|
2020-11-30 09:41:09 -08:00
|
|
|
let account_info_iter = &mut accounts.iter();
|
|
|
|
let aggregator_info = next_account_info(account_info_iter)?;
|
2020-12-02 22:45:16 -08:00
|
|
|
let faucet_info = next_account_info(account_info_iter)?;
|
2021-01-08 09:39:16 -08:00
|
|
|
let receiver_info = next_account_info(account_info_iter)?;
|
2020-11-30 09:41:09 -08:00
|
|
|
|
|
|
|
let token_program_info = next_account_info(account_info_iter)?;
|
|
|
|
|
|
|
|
let faucet_owner_info = next_account_info(account_info_iter)?;
|
2020-12-01 02:50:31 -08:00
|
|
|
let oracle_info = next_account_info(account_info_iter)?;
|
2020-11-30 09:41:09 -08:00
|
|
|
|
2020-12-01 02:50:31 -08:00
|
|
|
if !oracle_info.is_signer {
|
|
|
|
return Err(ProgramError::MissingRequiredSignature);
|
|
|
|
}
|
|
|
|
|
|
|
|
let aggregator = Aggregator::unpack_unchecked(&aggregator_info.data.borrow())?;
|
2020-11-30 09:41:09 -08:00
|
|
|
if !aggregator.is_initialized {
|
|
|
|
return Err(Error::NotFoundAggregator.into());
|
|
|
|
}
|
|
|
|
|
2020-12-01 02:50:31 -08:00
|
|
|
let mut oracle = Oracle::unpack_unchecked(&oracle_info.data.borrow())?;
|
|
|
|
if !oracle.is_initialized {
|
2020-11-30 09:41:09 -08:00
|
|
|
return Err(Error::NotFoundOracle.into());
|
|
|
|
}
|
|
|
|
|
2020-12-01 02:50:31 -08:00
|
|
|
if oracle.withdrawable < amount {
|
2020-11-30 09:41:09 -08:00
|
|
|
return Err(Error::InsufficientWithdrawable.into());
|
|
|
|
}
|
2021-01-08 09:39:16 -08:00
|
|
|
|
2020-12-17 22:38:28 -08:00
|
|
|
msg!("Create transfer instruction...");
|
2020-11-30 09:41:09 -08:00
|
|
|
let instruction = spl_token::instruction::transfer(
|
|
|
|
token_program_info.key,
|
2020-12-02 22:45:16 -08:00
|
|
|
faucet_info.key,
|
2020-11-30 09:41:09 -08:00
|
|
|
receiver_info.key,
|
|
|
|
faucet_owner_info.key,
|
|
|
|
&[],
|
|
|
|
amount,
|
|
|
|
)?;
|
|
|
|
|
2020-12-17 22:38:28 -08:00
|
|
|
msg!("Invoke signed...");
|
2020-11-30 09:41:09 -08:00
|
|
|
invoke_signed(
|
2021-01-08 09:39:16 -08:00
|
|
|
&instruction,
|
2020-11-30 09:41:09 -08:00
|
|
|
&[
|
2020-12-02 22:45:16 -08:00
|
|
|
faucet_info.clone(),
|
2020-11-30 09:41:09 -08:00
|
|
|
token_program_info.clone(),
|
|
|
|
receiver_info.clone(),
|
|
|
|
faucet_owner_info.clone(),
|
|
|
|
],
|
2021-01-08 09:39:16 -08:00
|
|
|
&[&[seed.as_ref()]],
|
2020-11-30 09:41:09 -08:00
|
|
|
)?;
|
|
|
|
|
|
|
|
// update oracle
|
2020-12-01 02:50:31 -08:00
|
|
|
oracle.withdrawable -= amount;
|
|
|
|
Oracle::pack(oracle, &mut oracle_info.data.borrow_mut())?;
|
2020-11-30 09:41:09 -08:00
|
|
|
|
2020-11-26 14:19:50 -08:00
|
|
|
Ok(())
|
|
|
|
}
|
2020-11-30 09:41:09 -08:00
|
|
|
}
|
2020-11-26 14:19:50 -08:00
|
|
|
|
2020-12-17 22:38:28 -08:00
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
use super::*;
|
2021-01-10 18:02:48 -08:00
|
|
|
use crate::{instruction::*, state::Submission};
|
2021-01-08 09:39:16 -08:00
|
|
|
use solana_program::instruction::Instruction;
|
2020-12-17 22:38:28 -08:00
|
|
|
use solana_sdk::account::{
|
|
|
|
create_account, create_is_signer_account_infos, Account as SolanaAccount,
|
|
|
|
};
|
|
|
|
|
|
|
|
fn do_process_instruction(
|
|
|
|
instruction: Instruction,
|
|
|
|
accounts: Vec<&mut SolanaAccount>,
|
|
|
|
) -> ProgramResult {
|
|
|
|
let mut meta = instruction
|
|
|
|
.accounts
|
|
|
|
.iter()
|
|
|
|
.zip(accounts)
|
|
|
|
.map(|(account_meta, account)| (&account_meta.pubkey, account_meta.is_signer, account))
|
|
|
|
.collect::<Vec<_>>();
|
|
|
|
|
|
|
|
let account_infos = create_is_signer_account_infos(&mut meta);
|
|
|
|
Processor::process(&instruction.program_id, &account_infos, &instruction.data)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn rent_sysvar() -> SolanaAccount {
|
|
|
|
create_account(&Rent::default(), 42)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn clock_sysvar() -> SolanaAccount {
|
|
|
|
create_account(&Clock::default(), 42)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn aggregator_minimum_balance() -> u64 {
|
|
|
|
Rent::default().minimum_balance(Aggregator::get_packed_len())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn oracle_minimum_balance() -> u64 {
|
|
|
|
Rent::default().minimum_balance(Oracle::get_packed_len())
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_pack_unpack() {
|
|
|
|
let check = Submission {
|
|
|
|
time: 1,
|
|
|
|
value: 1,
|
|
|
|
oracle: [1; 32],
|
|
|
|
};
|
|
|
|
|
|
|
|
let mut packed = vec![0; Submission::get_packed_len() + 1];
|
2021-01-08 09:39:16 -08:00
|
|
|
|
2020-12-17 22:38:28 -08:00
|
|
|
assert_eq!(
|
|
|
|
Err(ProgramError::InvalidAccountData),
|
|
|
|
Submission::pack(check, &mut packed)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_intialize() {
|
|
|
|
let program_id = Pubkey::new_unique();
|
|
|
|
|
|
|
|
let aggregator_key = Pubkey::new_unique();
|
|
|
|
let owner_key = Pubkey::new_unique();
|
|
|
|
|
|
|
|
let mut rent_sysvar = rent_sysvar();
|
2021-01-08 09:39:16 -08:00
|
|
|
let mut aggregator_account =
|
|
|
|
SolanaAccount::new(42, Aggregator::get_packed_len(), &program_id);
|
2020-12-17 22:38:28 -08:00
|
|
|
let mut owner_account = SolanaAccount::default();
|
|
|
|
|
|
|
|
// aggregator is not rent exempt
|
|
|
|
assert_eq!(
|
|
|
|
Err(Error::NotRentExempt.into()),
|
|
|
|
do_process_instruction(
|
|
|
|
initialize(
|
2021-01-08 09:39:16 -08:00
|
|
|
&program_id,
|
|
|
|
&aggregator_key,
|
|
|
|
&owner_key,
|
2020-12-17 22:38:28 -08:00
|
|
|
6,
|
|
|
|
1,
|
2021-01-08 09:39:16 -08:00
|
|
|
9999,
|
2021-01-19 19:17:47 -08:00
|
|
|
6,
|
2020-12-17 22:38:28 -08:00
|
|
|
[1; 32]
|
2021-01-10 18:02:48 -08:00
|
|
|
),
|
2020-12-17 22:38:28 -08:00
|
|
|
vec![
|
2021-01-08 09:39:16 -08:00
|
|
|
&mut rent_sysvar,
|
|
|
|
&mut aggregator_account,
|
2020-12-17 22:38:28 -08:00
|
|
|
&mut owner_account,
|
|
|
|
]
|
|
|
|
)
|
|
|
|
);
|
2021-01-08 09:39:16 -08:00
|
|
|
|
2020-12-17 22:38:28 -08:00
|
|
|
aggregator_account.lamports = aggregator_minimum_balance();
|
|
|
|
|
|
|
|
// initialize will be successful
|
|
|
|
do_process_instruction(
|
|
|
|
initialize(
|
2021-01-08 09:39:16 -08:00
|
|
|
&program_id,
|
|
|
|
&aggregator_key,
|
|
|
|
&owner_key,
|
2020-12-17 22:38:28 -08:00
|
|
|
6,
|
|
|
|
1,
|
2021-01-08 09:39:16 -08:00
|
|
|
9999,
|
2021-01-19 19:17:47 -08:00
|
|
|
6,
|
2021-01-08 09:39:16 -08:00
|
|
|
[1; 32],
|
2021-01-10 18:02:48 -08:00
|
|
|
),
|
2020-12-17 22:38:28 -08:00
|
|
|
vec![
|
2021-01-08 09:39:16 -08:00
|
|
|
&mut rent_sysvar,
|
|
|
|
&mut aggregator_account,
|
2020-12-17 22:38:28 -08:00
|
|
|
&mut owner_account,
|
2021-01-08 09:39:16 -08:00
|
|
|
],
|
|
|
|
)
|
|
|
|
.unwrap();
|
|
|
|
|
2020-12-17 22:38:28 -08:00
|
|
|
// duplicate initialize will get failed
|
|
|
|
assert_eq!(
|
|
|
|
Err(Error::AlreadyInUse.into()),
|
|
|
|
do_process_instruction(
|
|
|
|
initialize(
|
2021-01-08 09:39:16 -08:00
|
|
|
&program_id,
|
|
|
|
&aggregator_key,
|
|
|
|
&owner_key,
|
2020-12-17 22:38:28 -08:00
|
|
|
6,
|
|
|
|
1,
|
2021-01-08 09:39:16 -08:00
|
|
|
9999,
|
2021-01-19 19:17:47 -08:00
|
|
|
6,
|
2020-12-17 22:38:28 -08:00
|
|
|
[1; 32]
|
2021-01-10 18:02:48 -08:00
|
|
|
),
|
2020-12-17 22:38:28 -08:00
|
|
|
vec![
|
2021-01-08 09:39:16 -08:00
|
|
|
&mut rent_sysvar,
|
|
|
|
&mut aggregator_account,
|
2020-12-17 22:38:28 -08:00
|
|
|
&mut owner_account,
|
|
|
|
]
|
|
|
|
)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_add_oracle() {
|
|
|
|
let program_id = Pubkey::new_unique();
|
|
|
|
|
|
|
|
let oracle_key = Pubkey::new_unique();
|
|
|
|
let oracle_owner_key = Pubkey::new_unique();
|
|
|
|
let aggregator_key = Pubkey::new_unique();
|
|
|
|
let aggregator_owner_key = Pubkey::new_unique();
|
|
|
|
|
|
|
|
let mut rent_sysvar = rent_sysvar();
|
|
|
|
let mut clock_sysvar = clock_sysvar();
|
|
|
|
|
|
|
|
let mut oracle_account = SolanaAccount::new(
|
|
|
|
oracle_minimum_balance(),
|
|
|
|
Oracle::get_packed_len(),
|
2021-01-08 09:39:16 -08:00
|
|
|
&program_id,
|
2020-12-17 22:38:28 -08:00
|
|
|
);
|
|
|
|
let mut aggregator_account = SolanaAccount::new(
|
2021-01-08 09:39:16 -08:00
|
|
|
aggregator_minimum_balance(),
|
|
|
|
Aggregator::get_packed_len(),
|
|
|
|
&program_id,
|
2020-12-17 22:38:28 -08:00
|
|
|
);
|
|
|
|
|
|
|
|
let mut oracle_owner_account = SolanaAccount::default();
|
|
|
|
let mut aggregator_owner_account = SolanaAccount::default();
|
|
|
|
|
|
|
|
// add oracle to unexist aggregator
|
|
|
|
assert_eq!(
|
|
|
|
Err(Error::NotFoundAggregator.into()),
|
|
|
|
do_process_instruction(
|
|
|
|
add_oracle(
|
2021-01-08 09:39:16 -08:00
|
|
|
&program_id,
|
2020-12-17 22:38:28 -08:00
|
|
|
&oracle_key,
|
|
|
|
&oracle_owner_key,
|
2021-01-08 09:39:16 -08:00
|
|
|
&aggregator_key,
|
|
|
|
&aggregator_owner_key,
|
2020-12-17 22:38:28 -08:00
|
|
|
[1; 32]
|
2021-01-10 18:02:48 -08:00
|
|
|
),
|
2020-12-17 22:38:28 -08:00
|
|
|
vec![
|
|
|
|
&mut oracle_account,
|
|
|
|
&mut oracle_owner_account,
|
2021-01-08 09:39:16 -08:00
|
|
|
&mut clock_sysvar,
|
|
|
|
&mut aggregator_account,
|
2020-12-17 22:38:28 -08:00
|
|
|
&mut aggregator_owner_account,
|
|
|
|
]
|
|
|
|
)
|
|
|
|
);
|
|
|
|
|
|
|
|
// initialize aggregator
|
|
|
|
do_process_instruction(
|
|
|
|
initialize(
|
2021-01-08 09:39:16 -08:00
|
|
|
&program_id,
|
|
|
|
&aggregator_key,
|
|
|
|
&aggregator_owner_key,
|
2020-12-17 22:38:28 -08:00
|
|
|
6,
|
|
|
|
1,
|
2021-01-08 09:39:16 -08:00
|
|
|
9999,
|
2021-01-19 19:17:47 -08:00
|
|
|
6,
|
2021-01-08 09:39:16 -08:00
|
|
|
[1; 32],
|
2021-01-10 18:02:48 -08:00
|
|
|
),
|
2020-12-17 22:38:28 -08:00
|
|
|
vec![
|
2021-01-08 09:39:16 -08:00
|
|
|
&mut rent_sysvar,
|
|
|
|
&mut aggregator_account,
|
2020-12-17 22:38:28 -08:00
|
|
|
&mut aggregator_owner_account,
|
2021-01-08 09:39:16 -08:00
|
|
|
],
|
|
|
|
)
|
|
|
|
.unwrap();
|
|
|
|
|
2020-12-17 22:38:28 -08:00
|
|
|
// will be successful
|
|
|
|
do_process_instruction(
|
|
|
|
add_oracle(
|
2021-01-08 09:39:16 -08:00
|
|
|
&program_id,
|
2020-12-17 22:38:28 -08:00
|
|
|
&oracle_key,
|
|
|
|
&oracle_owner_key,
|
2021-01-08 09:39:16 -08:00
|
|
|
&aggregator_key,
|
|
|
|
&aggregator_owner_key,
|
|
|
|
[1; 32],
|
2021-01-10 18:02:48 -08:00
|
|
|
),
|
2020-12-17 22:38:28 -08:00
|
|
|
vec![
|
|
|
|
&mut oracle_account,
|
|
|
|
&mut oracle_owner_account,
|
2021-01-08 09:39:16 -08:00
|
|
|
&mut clock_sysvar,
|
|
|
|
&mut aggregator_account,
|
2020-12-17 22:38:28 -08:00
|
|
|
&mut aggregator_owner_account,
|
2021-01-08 09:39:16 -08:00
|
|
|
],
|
|
|
|
)
|
|
|
|
.unwrap();
|
2020-12-17 22:38:28 -08:00
|
|
|
|
|
|
|
// duplicate oracle
|
|
|
|
assert_eq!(
|
|
|
|
Err(Error::AlreadyInUse.into()),
|
|
|
|
do_process_instruction(
|
|
|
|
add_oracle(
|
2021-01-08 09:39:16 -08:00
|
|
|
&program_id,
|
2020-12-17 22:38:28 -08:00
|
|
|
&oracle_key,
|
|
|
|
&oracle_owner_key,
|
2021-01-08 09:39:16 -08:00
|
|
|
&aggregator_key,
|
|
|
|
&aggregator_owner_key,
|
2020-12-17 22:38:28 -08:00
|
|
|
[1; 32]
|
2021-01-10 18:02:48 -08:00
|
|
|
),
|
2020-12-17 22:38:28 -08:00
|
|
|
vec![
|
|
|
|
&mut oracle_account,
|
|
|
|
&mut oracle_owner_account,
|
2021-01-08 09:39:16 -08:00
|
|
|
&mut clock_sysvar,
|
|
|
|
&mut aggregator_account,
|
2020-12-17 22:38:28 -08:00
|
|
|
&mut aggregator_owner_account,
|
|
|
|
]
|
|
|
|
)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_remove_oracle() {
|
|
|
|
let program_id = Pubkey::new_unique();
|
|
|
|
|
|
|
|
let oracle_key = Pubkey::new_unique();
|
|
|
|
let oracle_owner_key = Pubkey::new_unique();
|
|
|
|
let aggregator_key = Pubkey::new_unique();
|
|
|
|
let aggregator_owner_key = Pubkey::new_unique();
|
|
|
|
|
|
|
|
let mut rent_sysvar = rent_sysvar();
|
|
|
|
let mut clock_sysvar = clock_sysvar();
|
|
|
|
|
|
|
|
let mut oracle_account = SolanaAccount::new(
|
|
|
|
oracle_minimum_balance(),
|
|
|
|
Oracle::get_packed_len(),
|
2021-01-08 09:39:16 -08:00
|
|
|
&program_id,
|
2020-12-17 22:38:28 -08:00
|
|
|
);
|
|
|
|
let mut aggregator_account = SolanaAccount::new(
|
2021-01-08 09:39:16 -08:00
|
|
|
aggregator_minimum_balance(),
|
|
|
|
Aggregator::get_packed_len(),
|
|
|
|
&program_id,
|
2020-12-17 22:38:28 -08:00
|
|
|
);
|
|
|
|
|
|
|
|
let mut oracle_owner_account = SolanaAccount::default();
|
|
|
|
let mut aggregator_owner_account = SolanaAccount::default();
|
|
|
|
|
|
|
|
// initialize aggregator
|
|
|
|
do_process_instruction(
|
|
|
|
initialize(
|
2021-01-08 09:39:16 -08:00
|
|
|
&program_id,
|
|
|
|
&aggregator_key,
|
|
|
|
&aggregator_owner_key,
|
2020-12-17 22:38:28 -08:00
|
|
|
6,
|
|
|
|
1,
|
2021-01-08 09:39:16 -08:00
|
|
|
9999,
|
2021-01-19 19:17:47 -08:00
|
|
|
6,
|
2021-01-08 09:39:16 -08:00
|
|
|
[1; 32],
|
2021-01-10 18:02:48 -08:00
|
|
|
),
|
2020-12-17 22:38:28 -08:00
|
|
|
vec![
|
2021-01-08 09:39:16 -08:00
|
|
|
&mut rent_sysvar,
|
|
|
|
&mut aggregator_account,
|
2020-12-17 22:38:28 -08:00
|
|
|
&mut aggregator_owner_account,
|
2021-01-08 09:39:16 -08:00
|
|
|
],
|
|
|
|
)
|
|
|
|
.unwrap();
|
|
|
|
|
2021-01-10 18:02:48 -08:00
|
|
|
// add oracle
|
2020-12-17 22:38:28 -08:00
|
|
|
do_process_instruction(
|
|
|
|
add_oracle(
|
2021-01-08 09:39:16 -08:00
|
|
|
&program_id,
|
2020-12-17 22:38:28 -08:00
|
|
|
&oracle_key,
|
|
|
|
&oracle_owner_key,
|
2021-01-08 09:39:16 -08:00
|
|
|
&aggregator_key,
|
|
|
|
&aggregator_owner_key,
|
|
|
|
[1; 32],
|
2021-01-10 18:02:48 -08:00
|
|
|
),
|
2020-12-17 22:38:28 -08:00
|
|
|
vec![
|
|
|
|
&mut oracle_account,
|
|
|
|
&mut oracle_owner_account,
|
2021-01-08 09:39:16 -08:00
|
|
|
&mut clock_sysvar,
|
|
|
|
&mut aggregator_account,
|
2020-12-17 22:38:28 -08:00
|
|
|
&mut aggregator_owner_account,
|
2021-01-08 09:39:16 -08:00
|
|
|
],
|
|
|
|
)
|
|
|
|
.unwrap();
|
2020-12-17 22:38:28 -08:00
|
|
|
|
2021-01-10 18:02:48 -08:00
|
|
|
// remove an unexist oracle
|
2020-12-17 22:38:28 -08:00
|
|
|
assert_eq!(
|
|
|
|
Err(Error::NotFoundOracle.into()),
|
|
|
|
do_process_instruction(
|
2021-01-10 18:02:48 -08:00
|
|
|
remove_oracle(
|
2021-01-19 19:17:47 -08:00
|
|
|
&program_id,
|
|
|
|
&aggregator_key,
|
|
|
|
&aggregator_owner_key,
|
2021-01-10 18:02:48 -08:00
|
|
|
&Pubkey::default()
|
|
|
|
),
|
2021-01-08 09:39:16 -08:00
|
|
|
vec![&mut aggregator_account, &mut aggregator_owner_account,]
|
2020-12-17 22:38:28 -08:00
|
|
|
)
|
|
|
|
);
|
|
|
|
|
|
|
|
// will be successful
|
|
|
|
do_process_instruction(
|
2021-01-10 18:02:48 -08:00
|
|
|
remove_oracle(
|
2021-01-19 19:17:47 -08:00
|
|
|
&program_id,
|
|
|
|
&aggregator_key,
|
|
|
|
&aggregator_owner_key,
|
2021-01-21 15:00:16 -08:00
|
|
|
&oracle_key,
|
2021-01-10 18:02:48 -08:00
|
|
|
),
|
2021-01-08 09:39:16 -08:00
|
|
|
vec![&mut aggregator_account, &mut aggregator_owner_account],
|
|
|
|
)
|
|
|
|
.unwrap();
|
2020-12-17 22:38:28 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_submit() {
|
|
|
|
let program_id = Pubkey::new_unique();
|
|
|
|
|
|
|
|
let oracle_key = Pubkey::new_unique();
|
|
|
|
let oracle_owner_key = Pubkey::new_unique();
|
|
|
|
let aggregator_key = Pubkey::new_unique();
|
|
|
|
let aggregator_owner_key = Pubkey::new_unique();
|
|
|
|
|
|
|
|
let mut rent_sysvar = rent_sysvar();
|
|
|
|
let mut clock_sysvar = clock_sysvar();
|
|
|
|
|
|
|
|
let mut oracle_account = SolanaAccount::new(
|
|
|
|
oracle_minimum_balance(),
|
|
|
|
Oracle::get_packed_len(),
|
2021-01-08 09:39:16 -08:00
|
|
|
&program_id,
|
2020-12-17 22:38:28 -08:00
|
|
|
);
|
|
|
|
let mut aggregator_account = SolanaAccount::new(
|
2021-01-08 09:39:16 -08:00
|
|
|
aggregator_minimum_balance(),
|
|
|
|
Aggregator::get_packed_len(),
|
|
|
|
&program_id,
|
2020-12-17 22:38:28 -08:00
|
|
|
);
|
|
|
|
|
|
|
|
let mut oracle_owner_account = SolanaAccount::default();
|
|
|
|
let mut aggregator_owner_account = SolanaAccount::default();
|
|
|
|
|
|
|
|
// initialize aggregator
|
|
|
|
do_process_instruction(
|
|
|
|
initialize(
|
2021-01-08 09:39:16 -08:00
|
|
|
&program_id,
|
|
|
|
&aggregator_key,
|
|
|
|
&aggregator_owner_key,
|
2020-12-17 22:38:28 -08:00
|
|
|
6,
|
|
|
|
1,
|
2021-01-08 09:39:16 -08:00
|
|
|
9999,
|
2021-01-19 19:17:47 -08:00
|
|
|
6,
|
2021-01-08 09:39:16 -08:00
|
|
|
[1; 32],
|
2021-01-10 18:02:48 -08:00
|
|
|
),
|
2020-12-17 22:38:28 -08:00
|
|
|
vec![
|
2021-01-08 09:39:16 -08:00
|
|
|
&mut rent_sysvar,
|
|
|
|
&mut aggregator_account,
|
2020-12-17 22:38:28 -08:00
|
|
|
&mut aggregator_owner_account,
|
2021-01-08 09:39:16 -08:00
|
|
|
],
|
|
|
|
)
|
|
|
|
.unwrap();
|
|
|
|
|
2020-12-17 22:38:28 -08:00
|
|
|
// add oracle (index 0)
|
|
|
|
do_process_instruction(
|
|
|
|
add_oracle(
|
2021-01-08 09:39:16 -08:00
|
|
|
&program_id,
|
2020-12-17 22:38:28 -08:00
|
|
|
&oracle_key,
|
|
|
|
&oracle_owner_key,
|
2021-01-08 09:39:16 -08:00
|
|
|
&aggregator_key,
|
|
|
|
&aggregator_owner_key,
|
|
|
|
[1; 32],
|
2021-01-10 18:02:48 -08:00
|
|
|
),
|
2020-12-17 22:38:28 -08:00
|
|
|
vec![
|
|
|
|
&mut oracle_account,
|
|
|
|
&mut oracle_owner_account,
|
2021-01-08 09:39:16 -08:00
|
|
|
&mut clock_sysvar,
|
|
|
|
&mut aggregator_account,
|
2020-12-17 22:38:28 -08:00
|
|
|
&mut aggregator_owner_account,
|
2021-01-08 09:39:16 -08:00
|
|
|
],
|
|
|
|
)
|
|
|
|
.unwrap();
|
2020-12-17 22:38:28 -08:00
|
|
|
|
|
|
|
// oracle submit
|
|
|
|
do_process_instruction(
|
|
|
|
submit(
|
2021-01-08 09:39:16 -08:00
|
|
|
&program_id,
|
|
|
|
&aggregator_key,
|
|
|
|
&oracle_key,
|
|
|
|
&oracle_owner_key,
|
|
|
|
1,
|
2021-01-10 18:02:48 -08:00
|
|
|
),
|
2020-12-17 22:38:28 -08:00
|
|
|
vec![
|
2021-01-08 09:39:16 -08:00
|
|
|
&mut aggregator_account,
|
|
|
|
&mut clock_sysvar,
|
2020-12-17 22:38:28 -08:00
|
|
|
&mut oracle_account,
|
|
|
|
&mut oracle_owner_account,
|
2021-01-08 09:39:16 -08:00
|
|
|
],
|
|
|
|
)
|
|
|
|
.unwrap();
|
2020-12-17 22:38:28 -08:00
|
|
|
|
|
|
|
// submission cooling
|
|
|
|
assert_eq!(
|
|
|
|
Err(Error::SubmissonCooling.into()),
|
|
|
|
do_process_instruction(
|
|
|
|
submit(
|
2021-01-08 09:39:16 -08:00
|
|
|
&program_id,
|
|
|
|
&aggregator_key,
|
|
|
|
&oracle_key,
|
|
|
|
&oracle_owner_key,
|
2020-12-17 22:38:28 -08:00
|
|
|
1
|
2021-01-10 18:02:48 -08:00
|
|
|
),
|
2020-12-17 22:38:28 -08:00
|
|
|
vec![
|
2021-01-08 09:39:16 -08:00
|
|
|
&mut aggregator_account,
|
|
|
|
&mut clock_sysvar,
|
2020-12-17 22:38:28 -08:00
|
|
|
&mut oracle_account,
|
|
|
|
&mut oracle_owner_account,
|
|
|
|
]
|
|
|
|
)
|
|
|
|
);
|
|
|
|
}
|
2021-01-08 09:39:16 -08:00
|
|
|
}
|