can submit value

This commit is contained in:
De Facto 2021-02-15 16:17:45 +08:00
parent d445491cb3
commit 39476b0aec
7 changed files with 125 additions and 133 deletions

View File

@ -81,7 +81,7 @@ Next we create a new oracle to the feed we've created previously, and set its ow
```
yarn solink add-oracle \
--feedAddress 3aTBom2uodyWkuVPiUkwCZ2HiFywdUx9tp7su7U2H4Nx \
--aggregatorAddress 3aTBom2uodyWkuVPiUkwCZ2HiFywdUx9tp7su7U2H4Nx \
--oracleName solink-test \
--oracleOwner FosLwbttPgkEDv36VJLU3wwXcBSSoUGkh7dyZPsXNtT4

View File

@ -3,6 +3,7 @@
use crate::processor::Processor;
use solana_program::{
msg,
account_info::AccountInfo, entrypoint, entrypoint::ProgramResult, pubkey::Pubkey,
};
@ -14,11 +15,12 @@ fn process_instruction<'a>(
accounts: &'a [AccountInfo<'a>],
instruction_data: &[u8],
) -> ProgramResult {
if let Err(error) = Processor::process(program_id, accounts, instruction_data) {
// catch the error so we can print it
// error.print::<Error>();
// msg!("{:?}", error);
return Err(error);
}
msg!("call aggregator yo");
// if let Err(error) = Processor::process(program_id, accounts, instruction_data) {
// // catch the error so we can print it
// // error.print::<Error>();
// // msg!("{:?}", error);
// return Err(error);
// }
Ok(())
}

View File

@ -53,7 +53,8 @@ mod tests {
#[test]
fn test_decode_instruction() -> ProgramResult {
let input = hex::decode("004254433a5553442020202020202020202020202020202020202020202020202002010c010100000000000000").map_err(|_| ProgramError::InvalidInstructionData)?;
let mut input = hex::decode("004254433a5553442020202020202020202020202020202020202020202020202002010c010100000000000000").map_err(|_| ProgramError::InvalidInstructionData)?;
let mut input = hex::decode("02534f4c494e4b2d54455354202020202020202020202020202020202020202020").map_err(|_| ProgramError::InvalidInstructionData)?;
let inx = Instruction::try_from_slice(&input)
.map_err(|_| ProgramError::InvalidInstructionData)?;

View File

@ -7,6 +7,7 @@ use crate::{
};
use solana_program::{
msg,
account_info::AccountInfo,
clock::Clock,
entrypoint::ProgramResult,
@ -112,9 +113,11 @@ impl<'a> AddOracleContext<'a> {
fn process(&self) -> ProgramResult {
// Note: there can in fact be more oracles than max_submissions
let aggregator = Aggregator::load_initialized(self.aggregator)?;
msg!("loaded aggregator");
aggregator.authorize(self.aggregator_owner)?;
let mut oracle = Oracle::init_uninitialized(self.oracle)?;
msg!("loaded oracle");
oracle.is_initialized = true;
oracle.description = self.description;
oracle.owner = self.oracle_owner.into();

View File

@ -29,6 +29,7 @@ import { decodeOracleInfo } from "./utils"
import { schema } from "./schema"
import * as encoding from "./schema"
import { deserialize, serialize } from "borsh"
import { conn } from "./context"
export const AggregatorLayout = BufferLayout.struct([])
@ -57,15 +58,11 @@ interface InitializeInstructionParams extends InitializeParams {
}
interface AddOracleParams {
owner: PublicKey
description: string
aggregator: PublicKey
// To prove you are the aggregator owner
aggregatorOwner: Account
}
interface AddOracleInstructionParams extends AddOracleParams {
oracle: PublicKey
oracleOwner: PublicKey
description: string
}
interface RemoveOracleParams {
@ -78,15 +75,17 @@ interface RemoveOracleParams {
interface RemoveOracleInstructionParams extends RemoveOracleParams {}
interface SubmitParams {
aggregator: PublicKey
oracle: PublicKey
// The oracle"s index
submission: bigint
// oracle owner
owner: Account
}
accounts: {
aggregator: { write: PublicKey }
roundSubmissions: { write: PublicKey }
answerSubmissions: { write: PublicKey }
oracle: { write: PublicKey }
oracle_owner: Account
}
interface SubmitInstructionParams extends SubmitParams {}
round_id: BigInt
value: BigInt
}
interface WithdrawParams {
aggregator: PublicKey
@ -114,8 +113,6 @@ export default class FluxAggregator extends BaseProgram {
const answer_submissions = new Account()
const round_submissions = new Account()
console.log({ config: params.config, program: this.programID.toString() })
const input = encoding.Initialize.serialize({ config: params.config })
await this.sendTx(
@ -158,6 +155,10 @@ export default class FluxAggregator extends BaseProgram {
public async addOracle(params: AddOracleParams): Promise<Account> {
const oracle = new Account()
const input = encoding.AddOracle.serialize({
description: params.description,
})
await this.sendTx(
[
await this.sys.createRentFreeAccountInstruction({
@ -165,10 +166,13 @@ export default class FluxAggregator extends BaseProgram {
space: encoding.Oracle.size,
programID: this.programID,
}),
this.addOracleInstruction({
...params,
oracle: oracle.publicKey,
}),
this.instruction(input, [
SYSVAR_RENT_PUBKEY,
params.aggregator,
params.aggregatorOwner, // signed
oracle.publicKey,
params.oracleOwner,
]),
],
[this.account, oracle, params.aggregatorOwner]
)
@ -181,32 +185,6 @@ export default class FluxAggregator extends BaseProgram {
return decodeOracleInfo(info)
}
private addOracleInstruction(
params: AddOracleInstructionParams
): TransactionInstruction {
const { oracle, owner, description, aggregator, aggregatorOwner } = params
const layout = BufferLayout.struct([
BufferLayout.u8("instruction"),
BufferLayout.blob(32, "description"),
])
return this.instructionEncode(
layout,
{
instruction: 1, // add oracle instruction
description: Buffer.from(description),
},
[
{ write: oracle },
owner,
SYSVAR_CLOCK_PUBKEY,
{ write: aggregator },
aggregatorOwner,
]
)
}
public async removeOracle(params: RemoveOracleParams): Promise<void> {
await this.sendTx(
[this.removeOracleInstruction(params)],
@ -239,29 +217,18 @@ export default class FluxAggregator extends BaseProgram {
}
public async submit(params: SubmitParams): Promise<void> {
const input = encoding.Submit.serialize(params)
let auths = [
SYSVAR_CLOCK_PUBKEY,
...Object.values(params.accounts),
]
await this.sendTx(
[this.submitInstruction(params)],
[this.account, params.owner]
)
}
private submitInstruction(
params: SubmitInstructionParams
): TransactionInstruction {
const { aggregator, oracle, submission, owner } = params
const layout = BufferLayout.struct([
BufferLayout.u8("instruction"),
uint64("submission"),
])
return this.instructionEncode(
layout,
{
instruction: 3, // submit instruction
submission: u64LEBuffer(submission),
},
[{ write: aggregator }, SYSVAR_CLOCK_PUBKEY, { write: oracle }, owner]
[
this.instruction(input, auths),
],
[this.account, params.accounts.oracle_owner]
)
}

View File

@ -18,12 +18,7 @@ import dotenv from "dotenv"
import FluxAggregator from "./FluxAggregator"
import {
decodeAggregatorInfo,
walletFromEnv,
openDeployer,
sleep,
} from "./utils"
import { decodeAggregatorInfo, sleep } from "./utils"
import * as feed from "./feed"
import { AggregatorConfig } from "./schema"
@ -39,43 +34,7 @@ const FLUX_AGGREGATOR_SO = path.resolve(
const network = (process.env.NETWORK || "local") as NetworkName
const conn = solana.connect(network)
class AppContext {
static readonly AGGREGATOR_PROGRAM = "aggregatorProgram"
static async forAdmin() {
const deployer = await openDeployer()
const admin = await walletFromEnv("ADMIN_MNEMONIC", conn)
return new AppContext(deployer, admin)
}
static async forOracle() {
const deployer = await openDeployer()
const wallet = await walletFromEnv("ORACLE_MNEMONIC", conn)
return new AppContext(deployer, wallet)
}
constructor(public deployer: Deployer, public wallet: Wallet) {}
get aggregatorProgramID() {
return this.aggregatorProgramAccount.publicKey
}
get aggregator() {
return new FluxAggregator(this.wallet, this.aggregatorProgramID)
}
get aggregatorProgramAccount() {
const program = this.deployer.account(AppContext.AGGREGATOR_PROGRAM)
if (program == null) {
throw new Error(`flux aggregator program is not yet deployed`)
}
return program
}
}
import { AppContext } from "./context"
function color(s, c = "black", b = false): string {
// 30m Black, 31m Red, 32m Green, 33m Yellow, 34m Blue, 35m Magenta, 36m Cyanic, 37m White
@ -226,7 +185,7 @@ cli
cli
.command("add-oracle")
.description("add an oracle to aggregator")
.option("--feedAddress <string>", "feed address")
.option("--aggregatorAddress <string>", "aggregator address")
.option("--oracleName <string>", "oracle name")
.option("--oracleOwner <string>", "oracle owner address")
.action(async (opts) => {
@ -236,8 +195,8 @@ cli
log("add oracle...")
const oracle = await aggregator.addOracle({
owner: new PublicKey(oracleOwner),
description: oracleName.substr(0, 32).padEnd(32),
oracleOwner: new PublicKey(oracleOwner),
description: oracleName,
aggregator: new PublicKey(feedAddress),
aggregatorOwner: wallet.account,
})

View File

@ -2,7 +2,7 @@ import { PublicKey, Account } from "solray"
import BN from "bn.js"
import { deserialize, serialize } from "borsh"
const MAX_ORACLES = 12
const MAX_ORACLES = 13
const boolMapper = {
encode: boolToInt,
@ -28,7 +28,7 @@ const pubkeyMapper = {
// support strings that can be contained in at most 32 bytes
const str32Mapper = {
encode: (str: String) => {
str = str.substr(0, 32).toUpperCase().padEnd(32)
str = str.substr(0, 32).padEnd(32)
return Buffer.from(str, "utf8").slice(0, 32) // truncate at 32 bytes
},
@ -50,7 +50,11 @@ abstract class Serialization {
}
public serialize(): Buffer {
return Buffer.from(serialize(schema, this))
let buf = Buffer.from(serialize(schema, this))
if (buf.length == 0) {
throw new Error("serialized buffer is 0. something wrong with schema")
}
return buf
}
constructor(data) {
@ -66,7 +70,7 @@ class Submission {
public static schema = {
kind: "struct",
fields: [
["time", "u64"],
["updated_at", "u64"],
["value", "u64"],
["oracle", [32], pubkeyMapper],
],
@ -104,7 +108,7 @@ export class Submissions extends Serialization {
kind: "struct",
fields: [
["isInitialized", "u8", boolMapper],
["submissions", [MAX_ORACLES, Submission]],
["submissions", [Submission, MAX_ORACLES]],
],
}
}
@ -134,7 +138,8 @@ export class Aggregator extends Serialization {
public static size = 189
public config!: AggregatorConfig
// public submissions!: Submission[]
public roundSubmissions!: PublicKey
public answerSubmissions!: PublicKey
public static schema = {
kind: "struct",
@ -143,9 +148,9 @@ export class Aggregator extends Serialization {
["isInitialized", "u8", boolMapper],
["owner", [32], pubkeyMapper],
["round", Round],
["round_submissions", [32], pubkeyMapper],
["roundSubmissions", [32], pubkeyMapper],
["answer", Answer],
["answer_submissions", [32], pubkeyMapper],
["answerSubmissions", [32], pubkeyMapper],
],
}
}
@ -170,13 +175,51 @@ export class Initialize extends InstructionSerialization {
}
}
export class Configure extends InstructionSerialization {
public static schema = {
kind: "struct",
fields: [["config", AggregatorConfig]],
}
}
export class AddOracle extends InstructionSerialization {
public static schema = {
kind: "struct",
fields: [["description", [32], str32Mapper]],
}
}
export class RemoveOracle extends InstructionSerialization {
public static schema = {
kind: "struct",
fields: [],
}
}
export class Submit extends InstructionSerialization {
public static schema = {
kind: "struct",
fields: [
["round_id", "u64"],
["value", "u64"],
],
}
}
export class Instruction extends Serialization {
public enum!: string
public static schema = {
kind: "enum",
field: "enum",
values: [[Initialize.name, Initialize]],
values: [
[Initialize.name, Initialize],
[Configure.name, Configure],
[AddOracle.name, AddOracle],
[RemoveOracle.name, RemoveOracle],
[Submit.name, Submit],
],
}
public constructor(prop: { [key: string]: any }) {
@ -215,8 +258,20 @@ function boolToInt(t: boolean) {
}
}
export class Oracle {
export class Oracle extends Serialization {
public static size = 113
public static schema = {
kind: "struct",
fields: [
["description", [32], str32Mapper],
["isInitialized", "u8", boolMapper],
["withdrawable", "u64"],
["allow_start_round", "u64"],
["aggregator", [32], pubkeyMapper],
["owner", [32], pubkeyMapper],
],
}
}
// if there is optional or variable length items, what is: borsh_utils::get_packed_len::<Submission>()?
@ -225,11 +280,16 @@ export class Oracle {
export const schema = new Map([
[Aggregator, Aggregator.schema],
[Oracle, Oracle.schema],
[Round, Round.schema],
[Answer, Answer.schema],
[AggregatorConfig, AggregatorConfig.schema],
[Submissions, Submissions.schema],
[Submission, Submission.schema],
[Initialize, Initialize.schema],
[Instruction, Instruction.schema],
[Initialize, Initialize.schema],
[AddOracle, AddOracle.schema],
[Submit, Submit.schema],
] as any) as any