Update
This commit is contained in:
parent
95d86e8c0e
commit
3f0b330113
|
@ -8,6 +8,7 @@ edition = "2018"
|
|||
|
||||
[dependencies]
|
||||
solana-program = "1.4.8"
|
||||
spl-token = { version = "3.0.0", features = [ "no-entrypoint" ] }
|
||||
byteorder = "1.3"
|
||||
thiserror = "1.0"
|
||||
num-derive = "0.3"
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
[230,199,10,234,118,135,80,179,41,207,6,148,213,115,124,131,231,98,111,94,230,60,157,233,181,137,107,192,74,90,146,137,195,104,18,142,51,221,206,67,34,125,1,169,105,243,210,182,239,4,85,132,189,79,155,159,50,7,195,53,144,151,128,232]
|
|
@ -37,6 +37,9 @@ pub enum Error {
|
|||
/// Submit cooling
|
||||
#[error("Submission cooling")]
|
||||
SubmissonCooling,
|
||||
/// InsufficientWithdrawable
|
||||
#[error("Insufficient withdrawable")]
|
||||
InsufficientWithdrawable,
|
||||
}
|
||||
|
||||
impl From<Error> for ProgramError {
|
||||
|
|
|
@ -9,10 +9,14 @@ use solana_program::{
|
|||
|
||||
use std::convert::TryInto;
|
||||
|
||||
/// Maximum number of aggregators in this program
|
||||
pub const MAX_AGGREGATORS: usize = 32;
|
||||
/// Maximum number of oracles
|
||||
pub const MAX_ORACLES: usize = 18;
|
||||
/// The interval(seconds) of an oracle's each submission
|
||||
pub const SUBMIT_INTERVAL: i64 = 6;
|
||||
/// The amount paid of TOKEN paid to each oracle per submission, in lamports (10e-10 SOL)
|
||||
pub const PAYMENT_AMOUNT: u64 = 10;
|
||||
|
||||
/// Instructions supported by the program.
|
||||
#[repr(C)]
|
||||
|
@ -20,14 +24,14 @@ pub const SUBMIT_INTERVAL: i64 = 6;
|
|||
pub enum Instruction {
|
||||
/// Initializes a new Aggregator
|
||||
Initialize {
|
||||
/// The aggregator authority
|
||||
authority: Pubkey,
|
||||
/// A short description of what is being reported
|
||||
description: [u8; 32],
|
||||
/// min submission value
|
||||
min_submission_value: u64,
|
||||
/// max submission value
|
||||
max_submission_value: u64,
|
||||
/// The payment token program
|
||||
payment_token: Pubkey,
|
||||
},
|
||||
|
||||
/// Add an oracle
|
||||
|
@ -38,6 +42,8 @@ pub enum Instruction {
|
|||
AddOracle {
|
||||
/// The oracle authority
|
||||
authority: Pubkey,
|
||||
/// Is usually the oracle name
|
||||
description: [u8; 32],
|
||||
/// The oracle's index
|
||||
seat: u8,
|
||||
},
|
||||
|
@ -53,6 +59,12 @@ pub enum Instruction {
|
|||
/// submission is the updated data that the oracle is submitting
|
||||
submission: u64,
|
||||
},
|
||||
|
||||
/// Oracle withdraw token
|
||||
Withdraw {
|
||||
/// withdraw amount
|
||||
amount: u64,
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -64,8 +76,7 @@ impl Instruction {
|
|||
let (&tag, rest) = input.split_first().ok_or(InvalidInstruction)?;
|
||||
Ok(match tag {
|
||||
0 => {
|
||||
let (authority, rest) = Self::unpack_pubkey(rest)?;
|
||||
|
||||
|
||||
let (description, rest) = rest.split_at(32);
|
||||
let description = description
|
||||
.try_into()
|
||||
|
@ -79,25 +90,34 @@ impl Instruction {
|
|||
.map(u64::from_le_bytes)
|
||||
.ok_or(InvalidInstruction)?;
|
||||
|
||||
let (max_submission_value, _rest) = rest.split_at(8);
|
||||
let (max_submission_value, rest) = rest.split_at(8);
|
||||
let max_submission_value = max_submission_value
|
||||
.try_into()
|
||||
.ok()
|
||||
.map(u64::from_le_bytes)
|
||||
.ok_or(InvalidInstruction)?;
|
||||
|
||||
let (payment_token, _rest) = Self::unpack_pubkey(rest)?;
|
||||
|
||||
Self::Initialize {
|
||||
authority,
|
||||
description,
|
||||
min_submission_value,
|
||||
max_submission_value,
|
||||
payment_token,
|
||||
}
|
||||
},
|
||||
1 => {
|
||||
let (authority, rest) = Self::unpack_pubkey(rest)?;
|
||||
let (seat, _rest) = rest.split_first().ok_or(InvalidInstruction)?;
|
||||
let (seat, rest) = rest.split_first().ok_or(InvalidInstruction)?;
|
||||
let (description, _rest) = rest.split_at(32);
|
||||
let description = description
|
||||
.try_into()
|
||||
.ok()
|
||||
.ok_or(InvalidInstruction)?;
|
||||
|
||||
Self::AddOracle {
|
||||
authority,
|
||||
description,
|
||||
seat: *seat,
|
||||
}
|
||||
},
|
||||
|
@ -118,7 +138,19 @@ impl Instruction {
|
|||
Self::Submit {
|
||||
submission,
|
||||
}
|
||||
}
|
||||
},
|
||||
4 => {
|
||||
let (amount, _rest) = rest.split_at(8);
|
||||
let amount = amount
|
||||
.try_into()
|
||||
.ok()
|
||||
.map(u64::from_le_bytes)
|
||||
.ok_or(InvalidInstruction)?;
|
||||
|
||||
Self::Withdraw {
|
||||
amount,
|
||||
}
|
||||
},
|
||||
_ => return Err(Error::InvalidInstruction.into()),
|
||||
})
|
||||
}
|
||||
|
|
194
src/processor.rs
194
src/processor.rs
|
@ -2,7 +2,7 @@
|
|||
|
||||
use crate::{
|
||||
error::Error,
|
||||
instruction::{Instruction, SUBMIT_INTERVAL},
|
||||
instruction::{Instruction, SUBMIT_INTERVAL, PAYMENT_AMOUNT},
|
||||
state::{Aggregator, Oracle},
|
||||
};
|
||||
|
||||
|
@ -14,6 +14,7 @@ use solana_program::{
|
|||
entrypoint::ProgramResult,
|
||||
info,
|
||||
program_pack::{Pack},
|
||||
program::{invoke_signed},
|
||||
program_error::{PrintProgramError, ProgramError},
|
||||
pubkey::Pubkey,
|
||||
sysvar::{rent::Rent, Sysvar},
|
||||
|
@ -29,23 +30,25 @@ impl Processor {
|
|||
|
||||
match instruction {
|
||||
Instruction::Initialize {
|
||||
authority,
|
||||
description,
|
||||
min_submission_value,
|
||||
max_submission_value,
|
||||
payment_token,
|
||||
} => {
|
||||
info!("Instruction: Initialize");
|
||||
Self::process_initialize(
|
||||
accounts, authority, description, min_submission_value, max_submission_value
|
||||
accounts, description, min_submission_value,
|
||||
max_submission_value, payment_token,
|
||||
)
|
||||
},
|
||||
Instruction::AddOracle {
|
||||
authority,
|
||||
description,
|
||||
seat,
|
||||
} => {
|
||||
info!("Instruction: AddOracle");
|
||||
Self::process_add_oracle(
|
||||
accounts, authority, seat,
|
||||
accounts, authority, description, seat,
|
||||
)
|
||||
},
|
||||
Instruction::RemoveOracle {
|
||||
|
@ -64,42 +67,83 @@ impl Processor {
|
|||
accounts, submission,
|
||||
)
|
||||
},
|
||||
Instruction::Withdraw {
|
||||
amount,
|
||||
} => {
|
||||
info!("Instruction: Withdraw");
|
||||
Self::process_withdraw(
|
||||
accounts, amount,
|
||||
)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// Processes an [Initialize](enum.Instruction.html) instruction.
|
||||
///
|
||||
/// Accounts expected by this instruction:
|
||||
///
|
||||
/// 0. `[writable]` The aggregator(key).
|
||||
/// 1. `[writable]` The program id
|
||||
/// 1. `[]` Sysvar rent
|
||||
/// 2. `[signer]` The aggregator's authority.
|
||||
pub fn process_initialize(
|
||||
accounts: &[AccountInfo],
|
||||
authority: Pubkey,
|
||||
description: [u8; 32],
|
||||
min_submission_value: u64,
|
||||
max_submission_value: u64,
|
||||
payment_token: Pubkey,
|
||||
) -> ProgramResult {
|
||||
|
||||
let account_info_iter = &mut accounts.iter();
|
||||
let aggregator_info = next_account_info(account_info_iter)?;
|
||||
let _aggregator_data_len = aggregator_info.data_len();
|
||||
|
||||
let rent = &Rent::from_account_info(next_account_info(account_info_iter)?)?;
|
||||
let program_info = next_account_info(account_info_iter)?;
|
||||
let rent_info = next_account_info(account_info_iter)?;
|
||||
|
||||
let owner_info = next_account_info(account_info_iter)?;
|
||||
|
||||
// check signer
|
||||
if !owner_info.is_signer {
|
||||
return Err(ProgramError::MissingRequiredSignature);
|
||||
}
|
||||
|
||||
let rent = &Rent::from_account_info(rent_info)?;
|
||||
|
||||
let mut aggregator = Aggregator::unpack_unchecked(&aggregator_info.data.borrow())?;
|
||||
if aggregator.is_initialized {
|
||||
return Err(Error::AlreadyInUse.into());
|
||||
}
|
||||
|
||||
if !rent.is_exempt(aggregator_info.lamports(), _aggregator_data_len) {
|
||||
if !rent.is_exempt(aggregator_info.lamports(), aggregator_info.data_len()) {
|
||||
return Err(Error::NotRentExempt.into());
|
||||
}
|
||||
|
||||
let (faucet_owner, faucet_bump_seed) = find_authority_bump_seed(
|
||||
program_info.key,
|
||||
aggregator_info.key,
|
||||
b"faucet",
|
||||
);
|
||||
|
||||
aggregator.min_submission_value = min_submission_value;
|
||||
aggregator.max_submission_value = max_submission_value;
|
||||
aggregator.description = description;
|
||||
aggregator.is_initialized = true;
|
||||
|
||||
aggregator.authority = authority;
|
||||
|
||||
aggregator.payment_token = payment_token;
|
||||
|
||||
aggregator.faucet_owner = faucet_owner;
|
||||
aggregator.faucet_bump_seed = faucet_bump_seed;
|
||||
|
||||
aggregator.authority = *owner_info.key;
|
||||
|
||||
Aggregator::pack(aggregator, &mut aggregator_info.data.borrow_mut())?;
|
||||
|
||||
// let mut program = Program::unpack_unchecked(&program_info.data.borrow())?;
|
||||
// for p in program.aggregators.iter_mut() {
|
||||
// if p == &Pubkey::default() {
|
||||
// *p = *aggregator_info.key;
|
||||
// }
|
||||
// }
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -116,6 +160,7 @@ impl Processor {
|
|||
pub fn process_add_oracle(
|
||||
accounts: &[AccountInfo],
|
||||
authority: Pubkey,
|
||||
description: [u8; 32],
|
||||
seat: u8,
|
||||
) -> ProgramResult {
|
||||
let account_info_iter = &mut accounts.iter();
|
||||
|
@ -125,7 +170,7 @@ impl Processor {
|
|||
|
||||
// Check aggregator authority
|
||||
let owner_info = next_account_info(account_info_iter)?;
|
||||
Self::validate_owner(&aggregator.authority, owner_info)?;
|
||||
validate_owner(&aggregator.authority, owner_info)?;
|
||||
|
||||
if !aggregator.is_initialized {
|
||||
return Err(Error::NotFoundAggregator.into());
|
||||
|
@ -143,6 +188,7 @@ impl Processor {
|
|||
submission: 0,
|
||||
next_submit_time: clock.unix_timestamp,
|
||||
authority,
|
||||
description,
|
||||
withdrawable: 0,
|
||||
};
|
||||
|
||||
|
@ -171,7 +217,7 @@ impl Processor {
|
|||
|
||||
// Check aggregator authority
|
||||
let owner_info = next_account_info(account_info_iter)?;
|
||||
Self::validate_owner(&aggregator.authority, owner_info)?;
|
||||
validate_owner(&aggregator.authority, owner_info)?;
|
||||
|
||||
if !aggregator.is_initialized {
|
||||
return Err(Error::NotFoundAggregator.into());
|
||||
|
@ -227,6 +273,9 @@ impl Processor {
|
|||
}
|
||||
found_oracle = true;
|
||||
oracle.submission = submission;
|
||||
|
||||
// pay oracle
|
||||
oracle.withdrawable += PAYMENT_AMOUNT;
|
||||
|
||||
oracle.next_submit_time = clock.unix_timestamp + SUBMIT_INTERVAL;
|
||||
}
|
||||
|
@ -242,21 +291,125 @@ impl Processor {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// Validate aggregator owner
|
||||
pub fn validate_owner(
|
||||
expected_owner: &Pubkey,
|
||||
owner_account_info: &AccountInfo,
|
||||
/// Processes an [Withdraw](enum.Instruction.html) instruction
|
||||
/// Can only be called by the oracle admin
|
||||
///
|
||||
/// @to: the address to send the token to
|
||||
/// @amount: the amount of token to send
|
||||
///
|
||||
/// Accounts expected by this instruction:
|
||||
///
|
||||
/// 0. `[writable]` The aggregator(key).
|
||||
/// 1. `[writable]` The token transfer from
|
||||
/// 2. `[writable]` The token withdraw to
|
||||
/// 3. `[]` SPL Token program id
|
||||
/// 4. `[]` The faucet owner
|
||||
/// 5. `[signer]` The oracle's authority.
|
||||
pub fn process_withdraw(
|
||||
accounts: &[AccountInfo],
|
||||
amount: u64,
|
||||
) -> ProgramResult {
|
||||
if expected_owner != owner_account_info.key {
|
||||
return Err(Error::OwnerMismatch.into());
|
||||
let account_info_iter = &mut accounts.iter();
|
||||
let aggregator_info = next_account_info(account_info_iter)?;
|
||||
let token_account_info = next_account_info(account_info_iter)?;
|
||||
let receiver_info = next_account_info(account_info_iter)?;
|
||||
|
||||
let token_program_info = next_account_info(account_info_iter)?;
|
||||
|
||||
let faucet_owner_info = next_account_info(account_info_iter)?;
|
||||
let oracle_owner_info = next_account_info(account_info_iter)?;
|
||||
|
||||
let mut aggregator = Aggregator::unpack_unchecked(&aggregator_info.data.borrow())?;
|
||||
if !aggregator.is_initialized {
|
||||
return Err(Error::NotFoundAggregator.into());
|
||||
}
|
||||
if !owner_account_info.is_signer {
|
||||
|
||||
let mut oracles = aggregator.oracles;
|
||||
let mut oracle_idx: i8 = -1;
|
||||
|
||||
// find oracle
|
||||
for (idx, oracle) in oracles.iter().enumerate() {
|
||||
if &oracle.authority == oracle_owner_info.key {
|
||||
oracle_idx = idx as i8;
|
||||
}
|
||||
}
|
||||
if oracle_idx < 0 {
|
||||
return Err(Error::NotFoundOracle.into());
|
||||
}
|
||||
|
||||
// must be signer
|
||||
if !oracle_owner_info.is_signer {
|
||||
return Err(ProgramError::MissingRequiredSignature);
|
||||
}
|
||||
|
||||
if oracles[oracle_idx as usize].withdrawable < amount {
|
||||
return Err(Error::InsufficientWithdrawable.into());
|
||||
}
|
||||
|
||||
let authority_signature_seeds = [
|
||||
&aggregator_info.key.to_bytes()[..32],
|
||||
b"faucet",
|
||||
&[aggregator.faucet_bump_seed]
|
||||
];
|
||||
|
||||
let signers = &[&authority_signature_seeds[..]];
|
||||
|
||||
info!("Create transfer transaction...");
|
||||
let instruction = spl_token::instruction::transfer(
|
||||
token_program_info.key,
|
||||
token_account_info.key,
|
||||
receiver_info.key,
|
||||
faucet_owner_info.key,
|
||||
&[],
|
||||
amount,
|
||||
)?;
|
||||
|
||||
info!("Invoke signed...");
|
||||
invoke_signed(
|
||||
&instruction,
|
||||
&[
|
||||
token_account_info.clone(),
|
||||
token_program_info.clone(),
|
||||
receiver_info.clone(),
|
||||
faucet_owner_info.clone(),
|
||||
],
|
||||
signers
|
||||
)?;
|
||||
|
||||
// update oracle
|
||||
oracles[oracle_idx as usize].withdrawable -= amount;
|
||||
aggregator.oracles = oracles;
|
||||
|
||||
Aggregator::pack(aggregator, &mut aggregator_info.data.borrow_mut())?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
// Helpers
|
||||
|
||||
/// Validate aggregator owner
|
||||
fn validate_owner(
|
||||
expected_owner: &Pubkey,
|
||||
owner_account_info: &AccountInfo,
|
||||
) -> ProgramResult {
|
||||
if expected_owner != owner_account_info.key {
|
||||
return Err(Error::OwnerMismatch.into());
|
||||
}
|
||||
if !owner_account_info.is_signer {
|
||||
return Err(ProgramError::MissingRequiredSignature);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Generates seed bump for stake pool authorities
|
||||
pub fn find_authority_bump_seed(
|
||||
program_id: &Pubkey,
|
||||
my_info: &Pubkey,
|
||||
authority_type: &[u8],
|
||||
) -> (Pubkey, u8) {
|
||||
Pubkey::find_program_address(&[&my_info.to_bytes()[..32], authority_type], program_id)
|
||||
}
|
||||
|
||||
impl PrintProgramError for Error {
|
||||
fn print<E>(&self)
|
||||
|
@ -274,6 +427,7 @@ impl PrintProgramError for Error {
|
|||
Error::NotFoundOracle => info!("Error: Not found oracle"),
|
||||
Error::SubmissonValueOutOfRange => info!("Error: Submisson value out of range"),
|
||||
Error::SubmissonCooling => info!("Submission cooling"),
|
||||
Error::InsufficientWithdrawable => info!("Insufficient withdrawable"),
|
||||
}
|
||||
}
|
||||
}
|
101
src/state.rs
101
src/state.rs
|
@ -1,6 +1,6 @@
|
|||
//! State transition types
|
||||
|
||||
use crate::instruction::MAX_ORACLES;
|
||||
use crate::instruction::{MAX_ORACLES, MAX_AGGREGATORS};
|
||||
use arrayref::{array_mut_ref, array_ref, array_refs, mut_array_refs};
|
||||
|
||||
use solana_program::{
|
||||
|
@ -10,6 +10,37 @@ use solana_program::{
|
|||
clock::{UnixTimestamp}
|
||||
};
|
||||
|
||||
/// Program data
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Debug, Copy, PartialEq)]
|
||||
pub struct Program {
|
||||
/// All aggregators
|
||||
pub aggregators: [Pubkey; MAX_AGGREGATORS],
|
||||
}
|
||||
|
||||
impl Sealed for Program {}
|
||||
impl Pack for Program {
|
||||
const LEN: usize = MAX_AGGREGATORS*32;
|
||||
fn unpack_from_slice(src: &[u8]) -> Result<Self, ProgramError> {
|
||||
let src = array_ref![src, 0, MAX_AGGREGATORS*32];
|
||||
|
||||
Ok(Program {
|
||||
aggregators: unpack_aggregators(src),
|
||||
})
|
||||
}
|
||||
|
||||
fn pack_into_slice(&self, dst: &mut [u8]) {
|
||||
let dst = array_mut_ref![dst, 0, MAX_AGGREGATORS*32];
|
||||
let (aggregators_dst, _) = mut_array_refs![dst, 0;..;];
|
||||
|
||||
let &Program {
|
||||
ref aggregators,
|
||||
} = self;
|
||||
|
||||
pack_aggregators(aggregators, aggregators_dst);
|
||||
}
|
||||
}
|
||||
|
||||
/// Aggregator data.
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Debug, Copy, Default, PartialEq)]
|
||||
|
@ -24,6 +55,12 @@ pub struct Aggregator {
|
|||
pub is_initialized: bool,
|
||||
/// authority
|
||||
pub authority: Pubkey,
|
||||
/// the payment token program
|
||||
pub payment_token: Pubkey,
|
||||
/// faucet owner (program derived address)
|
||||
pub faucet_owner: Pubkey,
|
||||
/// faucet bump seed
|
||||
pub faucet_bump_seed: u8,
|
||||
/// submissions
|
||||
pub oracles: [Oracle; MAX_ORACLES],
|
||||
}
|
||||
|
@ -36,13 +73,13 @@ impl IsInitialized for Aggregator {
|
|||
|
||||
impl Sealed for Aggregator {}
|
||||
impl Pack for Aggregator {
|
||||
const LEN: usize = 81 + MAX_ORACLES*56;
|
||||
const LEN: usize = 146 + MAX_ORACLES*88;
|
||||
fn unpack_from_slice(src: &[u8]) -> Result<Self, ProgramError> {
|
||||
let src = array_ref![src, 0, 81 + MAX_ORACLES*56];
|
||||
let src = array_ref![src, 0, 146 + MAX_ORACLES*88];
|
||||
let (
|
||||
min_submission_value, max_submission_value,
|
||||
description, is_initialized, authority, rem,
|
||||
) = array_refs![src, 8, 8, 32, 1, 32; ..;];
|
||||
min_submission_value, max_submission_value, description, is_initialized,
|
||||
authority, payment_token, faucet_owner, faucet_bump_seed, rem,
|
||||
) = array_refs![src, 8, 8, 32, 1, 32, 32, 32, 1; ..;];
|
||||
|
||||
let is_initialized = match is_initialized {
|
||||
[0] => false,
|
||||
|
@ -57,19 +94,25 @@ impl Pack for Aggregator {
|
|||
is_initialized,
|
||||
authority: Pubkey::new_from_array(*authority),
|
||||
oracles: unpack_oracles(rem),
|
||||
payment_token: Pubkey::new_from_array(*payment_token),
|
||||
faucet_owner: Pubkey::new_from_array(*faucet_owner),
|
||||
faucet_bump_seed: faucet_bump_seed[0],
|
||||
})
|
||||
}
|
||||
|
||||
fn pack_into_slice(&self, dst: &mut [u8]) {
|
||||
let dst = array_mut_ref![dst, 0, 81 + MAX_ORACLES*56];
|
||||
let dst = array_mut_ref![dst, 0, 146 + MAX_ORACLES*88];
|
||||
let (
|
||||
min_submission_value_dst,
|
||||
max_submission_value_dst,
|
||||
description_dst,
|
||||
is_initialized_dst,
|
||||
authority_dst,
|
||||
payment_token_dst,
|
||||
faucet_owner_dst,
|
||||
faucet_bump_seed_dst,
|
||||
rem,
|
||||
) = mut_array_refs![dst, 8, 8, 32, 1, 32; ..;];
|
||||
) = mut_array_refs![dst, 8, 8, 32, 1, 32, 32, 32, 1; ..;];
|
||||
|
||||
let &Aggregator {
|
||||
min_submission_value,
|
||||
|
@ -77,6 +120,9 @@ impl Pack for Aggregator {
|
|||
description,
|
||||
is_initialized,
|
||||
ref authority,
|
||||
ref payment_token,
|
||||
ref faucet_owner,
|
||||
faucet_bump_seed,
|
||||
ref oracles,
|
||||
} = self;
|
||||
|
||||
|
@ -85,6 +131,9 @@ impl Pack for Aggregator {
|
|||
*description_dst = description;
|
||||
is_initialized_dst[0] = is_initialized as u8;
|
||||
authority_dst.copy_from_slice(authority.as_ref());
|
||||
payment_token_dst.copy_from_slice(payment_token.as_ref());
|
||||
faucet_owner_dst.copy_from_slice(faucet_owner.as_ref());
|
||||
faucet_bump_seed_dst[0] = faucet_bump_seed as u8;
|
||||
|
||||
pack_oracles(oracles, rem);
|
||||
}
|
||||
|
@ -100,6 +149,8 @@ pub struct Oracle {
|
|||
pub next_submit_time: UnixTimestamp,
|
||||
/// oracle authority
|
||||
pub authority: Pubkey,
|
||||
/// is usually the oracle name
|
||||
pub description: [u8; 32],
|
||||
/// withdrawable
|
||||
pub withdrawable: u64,
|
||||
}
|
||||
|
@ -112,14 +163,16 @@ fn unpack_oracles(mut dst: &[u8]) -> [Oracle; MAX_ORACLES] {
|
|||
submission,
|
||||
next_submit_time,
|
||||
authority,
|
||||
description,
|
||||
withdrawable,
|
||||
rem,
|
||||
) = array_refs![dst, 8, 8, 32, 8; ..;];
|
||||
) = array_refs![dst, 8, 8, 32, 32, 8; ..;];
|
||||
|
||||
arr[i] = Oracle {
|
||||
submission: u64::from_le_bytes(*submission),
|
||||
next_submit_time: i64::from_le_bytes(*next_submit_time),
|
||||
authority: Pubkey::new_from_array(*authority),
|
||||
description: *description,
|
||||
withdrawable: u64::from_le_bytes(*withdrawable),
|
||||
};
|
||||
|
||||
|
@ -130,27 +183,53 @@ fn unpack_oracles(mut dst: &[u8]) -> [Oracle; MAX_ORACLES] {
|
|||
|
||||
fn pack_oracles(src: &[Oracle; MAX_ORACLES], mut dst: &mut [u8]) {
|
||||
for i in 0 .. MAX_ORACLES {
|
||||
let (s, rem) = mut_array_refs![dst, 56; ..;];
|
||||
let (s, rem) = mut_array_refs![dst, 88; ..;];
|
||||
|
||||
let (
|
||||
submission_dst,
|
||||
next_submit_time_dst,
|
||||
authority_dst,
|
||||
description_dst,
|
||||
withdrawable_dst,
|
||||
) = mut_array_refs![&mut *s, 8, 8, 32, 8];
|
||||
) = mut_array_refs![&mut *s, 8, 8, 32, 32, 8];
|
||||
|
||||
let &Oracle {
|
||||
submission,
|
||||
next_submit_time,
|
||||
authority,
|
||||
description,
|
||||
withdrawable,
|
||||
} = &src[i];
|
||||
|
||||
*submission_dst = submission.to_le_bytes();
|
||||
*next_submit_time_dst = next_submit_time.to_le_bytes();
|
||||
*description_dst = description;
|
||||
|
||||
authority_dst.copy_from_slice(authority.as_ref());
|
||||
*withdrawable_dst = withdrawable.to_le_bytes();
|
||||
|
||||
dst = rem;
|
||||
}
|
||||
}
|
||||
|
||||
fn unpack_aggregators(mut dst: &[u8]) -> [Pubkey; MAX_AGGREGATORS] {
|
||||
let mut arr = [Pubkey::default(); MAX_AGGREGATORS];
|
||||
for i in 0 .. MAX_AGGREGATORS {
|
||||
let ( pubkey, rem ) = array_refs![dst, 32; ..;];
|
||||
arr[i] = Pubkey::new_from_array(*pubkey);
|
||||
|
||||
dst = rem;
|
||||
}
|
||||
arr
|
||||
}
|
||||
|
||||
fn pack_aggregators(src: &[Pubkey; MAX_AGGREGATORS], mut dst: &mut [u8]) {
|
||||
for i in 0 .. MAX_AGGREGATORS {
|
||||
let (s, rem) = mut_array_refs![dst, 32; ..;];
|
||||
|
||||
let &pubkey = &src[i];
|
||||
s.copy_from_slice(pubkey.as_ref());
|
||||
|
||||
dst = rem;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue