associate an aggregator with a particular reward faucet
This commit is contained in:
parent
8cb797235b
commit
89d4d6fbd3
|
@ -40,6 +40,9 @@ pub enum Error {
|
|||
#[error("No submitted value")]
|
||||
NoSubmission,
|
||||
|
||||
#[error("Invalid faucet")]
|
||||
InvalidFaucet,
|
||||
|
||||
#[error("Unknown error")]
|
||||
UnknownError,
|
||||
}
|
||||
|
|
|
@ -6,17 +6,8 @@ use crate::{
|
|||
state::{Aggregator, AggregatorConfig, Authority, Oracle, Round, Submissions},
|
||||
};
|
||||
|
||||
use solana_program::{
|
||||
msg,
|
||||
account_info::AccountInfo,
|
||||
clock::Clock,
|
||||
entrypoint::ProgramResult,
|
||||
program::invoke_signed,
|
||||
program_error::ProgramError,
|
||||
program_pack::IsInitialized,
|
||||
pubkey::Pubkey,
|
||||
sysvar::{rent::Rent, Sysvar},
|
||||
};
|
||||
// use spl_token::state;
|
||||
use solana_program::{account_info::AccountInfo, clock::Clock, entrypoint::ProgramResult, msg, program::invoke_signed, program_error::ProgramError, program_pack::{IsInitialized, Pack}, pubkey::Pubkey, sysvar::{rent::Rent, Sysvar}};
|
||||
|
||||
use crate::borsh_state::{BorshState, InitBorshState};
|
||||
|
||||
|
@ -300,6 +291,7 @@ impl<'a> SubmitContext<'a> {
|
|||
// Withdraw token from reward faucet to receiver account, deducting oracle's withdrawable credit.
|
||||
struct WithdrawContext<'a, 'b> {
|
||||
token_program: &'a AccountInfo<'a>,
|
||||
aggregator: &'a AccountInfo<'a>,
|
||||
faucet: &'a AccountInfo<'a>,
|
||||
faucet_owner: &'a AccountInfo<'a>, // program signed
|
||||
oracle: &'a AccountInfo<'a>,
|
||||
|
@ -311,8 +303,14 @@ struct WithdrawContext<'a, 'b> {
|
|||
|
||||
impl<'a, 'b> WithdrawContext<'a, 'b> {
|
||||
fn process(&self) -> ProgramResult {
|
||||
let aggregator = Aggregator::load_initialized(self.aggregator)?;
|
||||
let mut oracle = Oracle::load_initialized(self.oracle)?;
|
||||
oracle.authorize(&self.oracle_owner)?;
|
||||
oracle.check_aggregator(self.aggregator)?;
|
||||
|
||||
if !aggregator.config.reward_token_account.is_account(self.faucet) {
|
||||
return Err(Error::InvalidFaucet)?
|
||||
}
|
||||
|
||||
if oracle.withdrawable == 0 {
|
||||
return Err(Error::InsufficientWithdrawable)?;
|
||||
|
@ -323,6 +321,7 @@ impl<'a, 'b> WithdrawContext<'a, 'b> {
|
|||
oracle.withdrawable = 0;
|
||||
oracle.save(self.oracle)?;
|
||||
|
||||
// The SPL Token ensures that faucet and receiver are the same type of token
|
||||
let inx = spl_token::instruction::transfer(
|
||||
self.token_program.key,
|
||||
self.faucet.key,
|
||||
|
@ -407,11 +406,12 @@ impl Processor {
|
|||
// _ => 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)?,
|
||||
aggregator: accounts.get(1)?,
|
||||
faucet: accounts.get(2)?,
|
||||
faucet_owner: accounts.get(3)?,
|
||||
oracle: accounts.get(4)?,
|
||||
oracle_owner: accounts.get(5)?,
|
||||
receiver: accounts.get(6)?,
|
||||
|
||||
faucet_owner_seed: &faucet_owner_seed[..],
|
||||
}
|
||||
|
|
|
@ -15,6 +15,12 @@ use solana_program::{
|
|||
#[derive(Clone, Debug, BorshSerialize, BorshDeserialize, BorshSchema, Default, PartialEq)]
|
||||
pub struct PublicKey(pub [u8; 32]);
|
||||
|
||||
impl PublicKey {
|
||||
pub fn is_account(&self, info: &AccountInfo) -> bool {
|
||||
self.eq(&PublicKey(info.key.to_bytes()))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a AccountInfo<'a>> for PublicKey {
|
||||
fn from(info: &'a AccountInfo<'a>) -> Self {
|
||||
PublicKey(info.key.to_bytes())
|
||||
|
@ -56,6 +62,9 @@ pub struct AggregatorConfig {
|
|||
|
||||
/// amount of tokens oracles are reward per submission
|
||||
pub reward_amount: u64,
|
||||
|
||||
/// SPL token account from which to withdraw rewards
|
||||
pub reward_token_account: PublicKey,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, BorshSerialize, BorshDeserialize, BorshSchema, Default, PartialEq)]
|
||||
|
@ -210,6 +219,17 @@ pub struct Oracle {
|
|||
/// owner
|
||||
pub owner: PublicKey,
|
||||
}
|
||||
|
||||
impl Oracle {
|
||||
pub fn check_aggregator(&self, account: &AccountInfo) -> ProgramResult {
|
||||
if !self.aggregator.is_account(account) {
|
||||
return Err(Error::AggregatorMismatch)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Authority for Oracle {
|
||||
fn authority(&self) -> &PublicKey {
|
||||
&self.owner
|
||||
|
|
|
@ -111,6 +111,7 @@ export class AggregatorConfig extends Serialization {
|
|||
public rewardAmount!: number
|
||||
public maxSubmissions!: number
|
||||
public minSubmissions!: number
|
||||
public rewardTokenAccount!: PublicKey
|
||||
|
||||
public static schema = {
|
||||
kind: "struct",
|
||||
|
@ -121,6 +122,7 @@ export class AggregatorConfig extends Serialization {
|
|||
["maxSubmissions", "u8"],
|
||||
["minSubmissions", "u8"],
|
||||
["rewardAmount", "u64"],
|
||||
["rewardTokenAccount", [32], pubkeyMapper],
|
||||
],
|
||||
}
|
||||
}
|
||||
|
@ -190,7 +192,7 @@ class Answer extends Serialization {
|
|||
}
|
||||
|
||||
export class Aggregator extends Serialization {
|
||||
public static size = 197
|
||||
public static size = 229
|
||||
|
||||
public config!: AggregatorConfig
|
||||
public roundSubmissions!: PublicKey
|
||||
|
|
37
test.ts
37
test.ts
|
@ -3,7 +3,7 @@ dotenv.config()
|
|||
|
||||
import BN from "bn.js"
|
||||
|
||||
import { BPFLoader, Wallet } from "solray"
|
||||
import { BPFLoader, ProgramAccount, SPLToken, Wallet } from "solray"
|
||||
import { AppContext, conn, network } from "./src/context"
|
||||
|
||||
import fs from "fs"
|
||||
|
@ -42,6 +42,40 @@ async function main() {
|
|||
}
|
||||
)
|
||||
|
||||
const spltoken = new SPLToken(adminWallet)
|
||||
const rewardToken = await deployer.ensure("create reward token", async () => {
|
||||
return spltoken.initializeMint({
|
||||
mintAuthority: adminWallet.pubkey,
|
||||
decimals: 8,
|
||||
})
|
||||
})
|
||||
|
||||
const rewardTokenOwner = await ProgramAccount.forSeed(
|
||||
Buffer.from("solink"),
|
||||
aggregatorProgram.publicKey
|
||||
)
|
||||
|
||||
const rewardTokenAccount = await deployer.ensure(
|
||||
"initialize reward token account",
|
||||
async () => {
|
||||
const vault = await spltoken.initializeAccount({
|
||||
token: rewardToken.publicKey,
|
||||
owner: rewardTokenOwner.pubkey,
|
||||
})
|
||||
|
||||
await spltoken.mintTo({
|
||||
token: rewardToken.publicKey,
|
||||
to: vault.publicKey,
|
||||
amount: BigInt(1e6 * 1e8), // 1M
|
||||
authority: adminWallet.pubkey,
|
||||
})
|
||||
|
||||
return vault
|
||||
}
|
||||
)
|
||||
|
||||
console.log(await spltoken.mintInfo(rewardToken.publicKey))
|
||||
|
||||
const program = new FluxAggregator(adminWallet, aggregatorProgram.publicKey)
|
||||
|
||||
let aggregator = await deployer.ensure(
|
||||
|
@ -56,6 +90,7 @@ async function main() {
|
|||
maxSubmissions: 3,
|
||||
restartDelay: 0,
|
||||
rewardAmount: BigInt(10),
|
||||
rewardTokenAccount: rewardTokenAccount.publicKey,
|
||||
}),
|
||||
owner: adminWallet.account,
|
||||
})
|
||||
|
|
Loading…
Reference in New Issue