implement withdraw without test

This commit is contained in:
De Facto 2021-02-04 17:35:34 +08:00
parent 7eca995088
commit 88303c8545
4 changed files with 97 additions and 52 deletions

View File

@ -14,17 +14,14 @@ pub const PAYMENT_AMOUNT: u64 = 10;
/// Instructions supported by the program
#[derive(Clone, Debug, BorshSerialize, BorshDeserialize, BorshSchema, PartialEq)]
pub enum Instruction {
/// Initializes a new Aggregator
Initialize {
config: AggregatorConfig,
},
/// Add an oracle
AddOracle {
description: [u8; 32],
},
/// Remove an oracle
RemoveOracle,
Submit {
@ -32,19 +29,8 @@ pub enum Instruction {
value: u64,
},
/// Oracle withdraw token
///
/// Accounts expected by this instruction:
/// 0. `[writable]` The aggregator (key).
/// 1. `[writable]` The faucet (which token transfer from)
/// 2. `[writable]` The recevier (which token withdraw to)
/// 3. `[]` SPL Token program id
/// 4. `[]` The faucet owner
/// 5. `[signer, writable]` The oracle's authority.
Withdraw {
/// withdraw amount
amount: u64,
/// program account nonced seed
seed: [u8; 32],
// FIXME: why 32 bytes seed? could be a vec?
faucet_owner_seed: [u8; 32],
},
}

View File

@ -2,8 +2,6 @@
//! An Flux Aggregator program for the Solana blockchain
pub mod borsh_state;
pub mod borsh_utils;
pub mod error;
@ -14,9 +12,6 @@ pub mod state;
#[cfg(not(feature = "no-entrypoint"))]
pub mod entrypoint;
/// Get median value from the aggregator account
// pub fn get_median(aggregator_info: &AccountInfo) -> Result<u64, ProgramError> {
// let aggregator = Aggregator::unpack_unchecked(&aggregator_info.data.borrow())?;

View File

@ -3,7 +3,7 @@
use crate::{
error::Error,
instruction::Instruction,
state::{Aggregator, AggregatorConfig, Oracle, Round},
state::{Aggregator, AggregatorConfig, Authority, Oracle, Round},
};
use solana_program::{
@ -77,14 +77,8 @@ struct AddOracleContext<'a> {
impl<'a> AddOracleContext<'a> {
fn process(&self) -> ProgramResult {
// Note: there can in fact be more oracles than max_submissions
if !self.aggregator_owner.is_signer {
return Err(ProgramError::MissingRequiredSignature);
}
let aggregator = Aggregator::load_initialized(self.aggregator)?;
if aggregator.owner != self.aggregator_owner.key.to_bytes() {
return Err(Error::OwnerMismatch)?;
}
aggregator.authorize(self.aggregator_owner)?;
let mut oracle = Oracle::init_uninitialized(self.oracle)?;
oracle.is_initialized = true;
@ -105,14 +99,8 @@ struct RemoveOracleContext<'a> {
impl<'a> RemoveOracleContext<'a> {
fn process(&self) -> ProgramResult {
if !self.aggregator_owner.is_signer {
return Err(ProgramError::MissingRequiredSignature);
}
let aggregator = Aggregator::load_initialized(self.aggregator)?;
if aggregator.owner != self.aggregator_owner.key.to_bytes() {
return Err(Error::OwnerMismatch)?;
}
aggregator.authorize(self.aggregator_owner)?;
let oracle = Oracle::load_initialized(self.oracle)?;
if oracle.aggregator != self.aggregator.key.to_bytes() {
@ -142,10 +130,7 @@ impl<'a> SubmitContext<'a> {
fn process(&self) -> ProgramResult {
let mut aggregator = Aggregator::load_initialized(self.aggregator)?;
let mut oracle = Oracle::load_initialized(self.oracle)?;
if !self.oracle_owner.is_signer {
return Err(ProgramError::MissingRequiredSignature);
}
oracle.authorize(self.oracle_owner)?;
if oracle.aggregator != self.aggregator.key.to_bytes() {
return Err(Error::AggregatorMismatch)?;
@ -256,15 +241,53 @@ impl<'a> SubmitContext<'a> {
}
// Withdraw token from reward faucet to receiver account, deducting oracle's withdrawable credit.
struct WithdrawContext<'a> {
token: &'a AccountInfo<'a>,
struct WithdrawContext<'a, 'b> {
token_program: &'a AccountInfo<'a>,
faucet: &'a AccountInfo<'a>,
faucet_owner: &'a AccountInfo<'a>, // program signed
oracle: &'a AccountInfo<'a>,
oracle_owner: &'a AccountInfo<'a>, // signed
receiver: &'a AccountInfo<'a>,
faucet_owner_seed: &'b [u8],
}
impl<'a, 'b> WithdrawContext<'a, 'b> {
fn process(&self) -> ProgramResult {
let mut oracle = Oracle::load_initialized(self.oracle)?;
oracle.authorize(&self.oracle_owner)?;
if oracle.withdrawable == 0 {
return Err(Error::InsufficientWithdrawable)?;
}
let amount = oracle.withdrawable;
oracle.withdrawable = 0;
oracle.save(self.oracle)?;
let inx = spl_token::instruction::transfer(
self.token_program.key,
self.faucet.key,
self.receiver.key,
self.faucet_owner.key,
&[],
amount,
)?;
invoke_signed(
&inx,
&[
self.token_program.clone(),
self.faucet.clone(),
self.faucet_owner.clone(),
self.receiver.clone(),
],
&[&[self.faucet_owner_seed]],
)?;
Ok(())
}
}
/// Program state handler.
@ -314,11 +337,18 @@ impl Processor {
value,
}
.process(),
_ => Err(ProgramError::InvalidInstructionData),
// Instruction::Withdraw { amount, seed } => {
// msg!("Instruction: Withdraw");
// Self::process_withdraw(accounts, amount, seed)
// }
// _ => Err(ProgramError::InvalidInstructionData),
Instruction::Withdraw { faucet_owner_seed } => WithdrawContext {
token_program: accounts.get(0)?,
faucet: accounts.get(1)?,
faucet_owner: accounts.get(2)?,
oracle: accounts.get(3)?,
oracle_owner: accounts.get(4)?,
receiver: accounts.get(5)?,
faucet_owner_seed: &faucet_owner_seed[..],
}
.process(),
}
}
}

View File

@ -1,10 +1,35 @@
//! State transition types
use borsh::{BorshDeserialize, BorshSchema, BorshSerialize};
use crate::borsh_state::{BorshState, InitBorshState};
use crate::instruction::MAX_ORACLES;
use crate::{
borsh_state::{BorshState, InitBorshState},
error::Error,
};
use solana_program::program_pack::IsInitialized;
use solana_program::{
account_info::AccountInfo, entrypoint::ProgramResult, program_error::ProgramError,
program_pack::IsInitialized,
};
#[derive(Clone, Debug, BorshSerialize, BorshDeserialize, BorshSchema, Default, PartialEq)]
pub struct Pubkey([u8; 32]);
pub trait Authority {
fn authority(&self) -> Pubkey;
fn authorize(&self, account: &AccountInfo) -> ProgramResult {
if !account.is_signer {
return Err(ProgramError::MissingRequiredSignature);
}
if self.authority().0 != account.key.to_bytes() {
return Err(Error::OwnerMismatch)?;
}
Ok(())
}
}
#[derive(Clone, Debug, BorshSerialize, BorshDeserialize, BorshSchema, Default, PartialEq)]
pub struct AggregatorConfig {
@ -62,12 +87,16 @@ pub struct Aggregator {
pub answer: Answer,
}
impl Authority for Aggregator {
fn authority(&self) -> Pubkey {
Pubkey(self.owner)
}
}
impl IsInitialized for Aggregator {
fn is_initialized(&self) -> bool {
self.is_initialized
}
}
impl BorshState for Aggregator {}
impl InitBorshState for Aggregator {}
@ -106,6 +135,11 @@ pub struct Oracle {
/// owner
pub owner: [u8; 32],
}
impl Authority for Oracle {
fn authority(&self) -> Pubkey {
Pubkey(self.owner)
}
}
impl BorshState for Oracle {}
impl IsInitialized for Oracle {
fn is_initialized(&self) -> bool {