wip
This commit is contained in:
parent
d7d2571750
commit
48e99d04a8
|
@ -13,6 +13,6 @@ tokio = "^1"
|
||||||
futures = "0.3"
|
futures = "0.3"
|
||||||
serde = "^1"
|
serde = "^1"
|
||||||
serde_json = "^1"
|
serde_json = "^1"
|
||||||
switchboard-utils = "0.5.0"
|
# switchboard-utils = "0.5.0"
|
||||||
switchboard-solana = "0.5.3"
|
# switchboard-solana = "0.5.3"
|
||||||
# switchboard-solana = { path = "../../../../rust/switchboard-solana" }
|
switchboard-solana = { path = "../../../../rust/switchboard-solana" }
|
||||||
|
|
|
@ -1,13 +1,12 @@
|
||||||
// Note: Binance API requires a non-US IP address
|
// Note: Binance API requires a non-US IP address
|
||||||
|
|
||||||
use crate::*;
|
use crate::*;
|
||||||
use bytemuck;
|
|
||||||
|
|
||||||
pub use switchboard_utils::reqwest;
|
// pub use switchboard_utils::reqwest;
|
||||||
|
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
|
||||||
const ONE: i128 = 1e9;
|
const ONE: i128 = 1000000000;
|
||||||
|
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
#[derive(Deserialize, Default, Clone, Debug)]
|
#[derive(Deserialize, Default, Clone, Debug)]
|
||||||
|
@ -62,15 +61,16 @@ impl Into<OracleData> for IndexData {
|
||||||
|
|
||||||
pub struct Binance {
|
pub struct Binance {
|
||||||
btc_usdt: IndexData,
|
btc_usdt: IndexData,
|
||||||
|
usdc_usdt: IndexData,
|
||||||
eth_usdt: IndexData,
|
eth_usdt: IndexData,
|
||||||
sol_usdt: IndexData,
|
sol_usdt: IndexData,
|
||||||
usdc_usdt: IndexData,
|
doge_usdt: IndexData,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Binance {
|
impl Binance {
|
||||||
// Fetch data from the Binance API
|
// Fetch data from the Binance API
|
||||||
pub async fn fetch() -> std::result::Result<Binance, SwitchboardClientError> {
|
pub async fn fetch() -> std::result::Result<Binance, SwitchboardClientError> {
|
||||||
let symbols = ["BTCUSDT", "ETHUSDT", "SOLUSDT", "USDCUSDT"];
|
let symbols = ["BTCUSDT", "USDCUSDT", "ETHUSDT", "SOLUSDT", "DOGEUSDT"];
|
||||||
|
|
||||||
let tickers_1hr = reqwest::get(format!(
|
let tickers_1hr = reqwest::get(format!(
|
||||||
"https://api.binance.com/api/v3/ticker?symbols=[{}]&windowSize=1h",
|
"https://api.binance.com/api/v3/ticker?symbols=[{}]&windowSize=1h",
|
||||||
|
@ -121,34 +121,38 @@ impl Binance {
|
||||||
|
|
||||||
Ok(Binance {
|
Ok(Binance {
|
||||||
btc_usdt: data.get(0).unwrap().clone(),
|
btc_usdt: data.get(0).unwrap().clone(),
|
||||||
eth_usdt: data.get(1).unwrap().clone(),
|
usdc_usdt: data.get(1).unwrap().clone(),
|
||||||
sol_usdt: data.get(2).unwrap().clone(),
|
eth_usdt: data.get(2).unwrap().clone(),
|
||||||
usdc_usdt: data.get(3).unwrap().clone(),
|
sol_usdt: data.get(3).unwrap().clone(),
|
||||||
|
doge_usdt: data.get(4).unwrap().clone(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_ixns(&self, runner: &FunctionRunner) -> Vec<Instruction> {
|
pub fn to_ixns(&self, runner: &FunctionRunner) -> Vec<Instruction> {
|
||||||
let btc_usdt: OracleData = self.btc_usdt.clone().into();
|
let rows: Vec<OracleDataWithTradingSymbol> = vec![
|
||||||
// let btc_usdc: OracleData = self.btc_usdc.clone().into();
|
OracleDataWithTradingSymbol {
|
||||||
let eth_usdt: OracleData = self.eth_usdt.clone().into();
|
symbol: TradingSymbol::BTC,
|
||||||
let sol_usdt: OracleData = self.sol_usdt.clone().into();
|
data: self.btc_usdt.clone().into(),
|
||||||
let usdc_usdt: OracleData = self.usdc_usdt.clone().into();
|
},
|
||||||
let usdt_usdc: OracleData = OracleData {
|
OracleDataWithTradingSymbol {
|
||||||
oracle_timestamp: usdc_usdt.oracle_timestamp,
|
symbol: TradingSymbol::USDC,
|
||||||
price: ONE.checked_div(usdc_usdt.price).unwrap(),
|
data: self.usdc_usdt.clone().into(),
|
||||||
volume_1hr: usdc_usdt.volume_1hr,
|
},
|
||||||
volume_24hr: usdc_usdt.volume_24hr,
|
OracleDataWithTradingSymbol {
|
||||||
twap_1hr: ONE.checked_div(usdc_usdt.twap_1hr).unwrap(),
|
symbol: TradingSymbol::ETH,
|
||||||
twap_24hr: ONE.checked_div(usdc_usdt.twap_24hr).unwrap(),
|
data: self.eth_usdt.clone().into(),
|
||||||
};
|
},
|
||||||
|
OracleDataWithTradingSymbol {
|
||||||
|
symbol: TradingSymbol::SOL,
|
||||||
|
data: self.sol_usdt.clone().into(),
|
||||||
|
},
|
||||||
|
OracleDataWithTradingSymbol {
|
||||||
|
symbol: TradingSymbol::DOGE,
|
||||||
|
data: self.doge_usdt.clone().into(),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
let params = RefreshPricesParams {
|
let params = RefreshPricesParams { rows };
|
||||||
btc: Some(btc_usdt),
|
|
||||||
eth: Some(eth_usdt),
|
|
||||||
sol: Some(sol_usdt),
|
|
||||||
usdt: Some(usdt_usdc),
|
|
||||||
usdc: Some(usdc_usdt),
|
|
||||||
};
|
|
||||||
|
|
||||||
let (program_state_pubkey, _state_bump) =
|
let (program_state_pubkey, _state_bump) =
|
||||||
Pubkey::find_program_address(&[b"BASICORACLE"], &PROGRAM_ID);
|
Pubkey::find_program_address(&[b"BASICORACLE"], &PROGRAM_ID);
|
||||||
|
|
|
@ -4,7 +4,8 @@ pub mod binance;
|
||||||
pub use binance::*;
|
pub use binance::*;
|
||||||
|
|
||||||
pub use basic_oracle::{
|
pub use basic_oracle::{
|
||||||
self, OracleData, RefreshPrices, RefreshPricesParams, SwitchboardDecimal, ID as PROGRAM_ID,
|
self, OracleData, OracleDataWithTradingSymbol, RefreshPrices, RefreshPricesParams,
|
||||||
|
SwitchboardDecimal, TradingSymbol, ID as PROGRAM_ID,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[tokio::main(worker_threads = 12)]
|
#[tokio::main(worker_threads = 12)]
|
||||||
|
|
|
@ -4,10 +4,10 @@ use crate::*;
|
||||||
pub struct RefreshPrices<'info> {
|
pub struct RefreshPrices<'info> {
|
||||||
#[account(
|
#[account(
|
||||||
seeds = [PROGRAM_SEED],
|
seeds = [PROGRAM_SEED],
|
||||||
bump = program.load()?.bump,
|
bump = program_state.load()?.bump,
|
||||||
// constraint = program.load()?.is_valid_enclave("e.load()?.mr_enclave) @ BasicOracleError::InvalidMrEnclave
|
// constraint = program.load()?.is_valid_enclave("e.load()?.mr_enclave) @ BasicOracleError::InvalidMrEnclave
|
||||||
)]
|
)]
|
||||||
pub program: AccountLoader<'info, MyProgramState>,
|
pub program_state: AccountLoader<'info, MyProgramState>,
|
||||||
|
|
||||||
#[account(
|
#[account(
|
||||||
mut,
|
mut,
|
||||||
|
@ -34,7 +34,7 @@ pub struct RefreshPrices<'info> {
|
||||||
|
|
||||||
#[derive(Clone, AnchorSerialize, AnchorDeserialize)]
|
#[derive(Clone, AnchorSerialize, AnchorDeserialize)]
|
||||||
pub struct RefreshPricesParams {
|
pub struct RefreshPricesParams {
|
||||||
pub symbols: Vec<OracleDataWithTradingSymbol>,
|
pub rows: Vec<OracleDataWithTradingSymbol>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RefreshPrices<'_> {
|
impl RefreshPrices<'_> {
|
||||||
|
@ -48,6 +48,7 @@ impl RefreshPrices<'_> {
|
||||||
|
|
||||||
pub fn actuate(ctx: &Context<Self>, params: &RefreshPricesParams) -> anchor_lang::Result<()> {
|
pub fn actuate(ctx: &Context<Self>, params: &RefreshPricesParams) -> anchor_lang::Result<()> {
|
||||||
let oracle = &mut ctx.accounts.oracle.load_mut()?;
|
let oracle = &mut ctx.accounts.oracle.load_mut()?;
|
||||||
|
oracle.save_rows(¶ms.rows)?;
|
||||||
|
|
||||||
// for data in params.data
|
// for data in params.data
|
||||||
|
|
||||||
|
|
|
@ -15,4 +15,6 @@ pub enum BasicOracleError {
|
||||||
InvalidMrEnclave,
|
InvalidMrEnclave,
|
||||||
#[msg("Switchboard QuoteAccount has an empty MrEnclave (invalid)")]
|
#[msg("Switchboard QuoteAccount has an empty MrEnclave (invalid)")]
|
||||||
EmptySwitchboardQuote,
|
EmptySwitchboardQuote,
|
||||||
|
#[msg("Failed to find a valid trading symbol for this price")]
|
||||||
|
InvalidSymbol,
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,43 +1,41 @@
|
||||||
use crate::*;
|
use crate::*;
|
||||||
use bytemuck::{Pod, Zeroable};
|
use bytemuck::{Pod, Zeroable};
|
||||||
|
|
||||||
|
#[repr(u8)]
|
||||||
#[derive(Copy, Clone, Default, Debug, Eq, PartialEq, AnchorSerialize, AnchorDeserialize)]
|
#[derive(Copy, Clone, Default, Debug, Eq, PartialEq, AnchorSerialize, AnchorDeserialize)]
|
||||||
pub enum TradingSymbol {
|
pub enum TradingSymbol {
|
||||||
#[default]
|
#[default]
|
||||||
Unknown = 0,
|
Unknown = 0,
|
||||||
BTC = 1,
|
BTC = 1,
|
||||||
USDT,
|
USDC = 2,
|
||||||
USDC,
|
ETH = 3,
|
||||||
ETH,
|
SOL = 4,
|
||||||
SOL,
|
DOGE = 5,
|
||||||
DOGE,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl Pod for TradingSymbol {}
|
unsafe impl Pod for TradingSymbol {}
|
||||||
unsafe impl Zeroable for TradingSymbol {}
|
unsafe impl Zeroable for TradingSymbol {}
|
||||||
|
|
||||||
impl From<TradingSymbol> for u32 {
|
impl From<TradingSymbol> for u8 {
|
||||||
fn from(value: TradingSymbol) -> Self {
|
fn from(value: TradingSymbol) -> Self {
|
||||||
match value {
|
match value {
|
||||||
TradingSymbol::BTC => 1,
|
TradingSymbol::BTC => 1,
|
||||||
TradingSymbol::USDT => 2,
|
TradingSymbol::USDC => 2,
|
||||||
TradingSymbol::USDC => 3,
|
TradingSymbol::ETH => 3,
|
||||||
TradingSymbol::ETH => 4,
|
TradingSymbol::SOL => 4,
|
||||||
TradingSymbol::SOL => 5,
|
TradingSymbol::DOGE => 5,
|
||||||
TradingSymbol::DOGE => 6,
|
|
||||||
_ => 0,
|
_ => 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl From<u32> for TradingSymbol {
|
impl From<u8> for TradingSymbol {
|
||||||
fn from(value: u32) -> Self {
|
fn from(value: u8) -> Self {
|
||||||
match value {
|
match value {
|
||||||
1 => TradingSymbol::BTC,
|
1 => TradingSymbol::BTC,
|
||||||
2 => TradingSymbol::USDT,
|
2 => TradingSymbol::USDC,
|
||||||
3 => TradingSymbol::USDC,
|
3 => TradingSymbol::ETH,
|
||||||
4 => TradingSymbol::ETH,
|
4 => TradingSymbol::SOL,
|
||||||
5 => TradingSymbol::SOL,
|
5 => TradingSymbol::DOGE,
|
||||||
6 => TradingSymbol::DOGE,
|
|
||||||
_ => TradingSymbol::default(),
|
_ => TradingSymbol::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -59,7 +57,6 @@ pub struct OracleData {
|
||||||
pub volume_24hr: i128,
|
pub volume_24hr: i128,
|
||||||
pub twap_1hr: i128,
|
pub twap_1hr: i128,
|
||||||
pub twap_24hr: i128,
|
pub twap_24hr: i128,
|
||||||
// pub reserved: [u8; 12], // makes 100 bytes exactly
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Default, AnchorSerialize, AnchorDeserialize)]
|
#[derive(Copy, Clone, Default, AnchorSerialize, AnchorDeserialize)]
|
||||||
|
@ -89,10 +86,9 @@ impl OracleData {
|
||||||
pub struct MyOracleState {
|
pub struct MyOracleState {
|
||||||
pub bump: u8,
|
pub bump: u8,
|
||||||
pub btc: OracleData,
|
pub btc: OracleData,
|
||||||
|
pub usdc: OracleData,
|
||||||
pub eth: OracleData,
|
pub eth: OracleData,
|
||||||
pub sol: OracleData,
|
pub sol: OracleData,
|
||||||
pub usdt: OracleData,
|
|
||||||
pub usdc: OracleData,
|
|
||||||
pub doge: OracleData,
|
pub doge: OracleData,
|
||||||
// can always re-allocate to add more
|
// can always re-allocate to add more
|
||||||
// pub reserved: [u8; 2400],
|
// pub reserved: [u8; 2400],
|
||||||
|
@ -102,3 +98,35 @@ impl Default for MyOracleState {
|
||||||
unsafe { std::mem::zeroed() }
|
unsafe { std::mem::zeroed() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl MyOracleState {
|
||||||
|
pub fn save_rows(
|
||||||
|
&mut self,
|
||||||
|
rows: &Vec<OracleDataWithTradingSymbol>,
|
||||||
|
) -> anchor_lang::Result<()> {
|
||||||
|
for row in rows.iter() {
|
||||||
|
match row.symbol {
|
||||||
|
TradingSymbol::BTC => {
|
||||||
|
self.btc = row.data;
|
||||||
|
}
|
||||||
|
TradingSymbol::USDC => {
|
||||||
|
self.usdc = row.data;
|
||||||
|
}
|
||||||
|
TradingSymbol::ETH => {
|
||||||
|
self.eth = row.data;
|
||||||
|
}
|
||||||
|
TradingSymbol::SOL => {
|
||||||
|
self.sol = row.data;
|
||||||
|
}
|
||||||
|
TradingSymbol::DOGE => {
|
||||||
|
self.doge = row.data;
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
msg!("no trading symbol found for {:?}", row.symbol);
|
||||||
|
// TODO: emit an event so we can detect and fix
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -21,7 +21,7 @@ no-entrypoint = []
|
||||||
cpi = ["no-entrypoint"]
|
cpi = ["no-entrypoint"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anchor-spl = "=0.28.0"
|
anchor-spl = "0.28.0"
|
||||||
solana-program = ">= 1.16, < 1.17"
|
solana-program = ">= 1.16, < 1.17"
|
||||||
solana-address-lookup-table-program = ">= 1.16, < 1.17"
|
solana-address-lookup-table-program = ">= 1.16, < 1.17"
|
||||||
rust_decimal = "^1"
|
rust_decimal = "^1"
|
||||||
|
@ -30,11 +30,11 @@ superslice = "1"
|
||||||
|
|
||||||
[target.'cfg(target_os = "solana")'.dependencies]
|
[target.'cfg(target_os = "solana")'.dependencies]
|
||||||
switchboard-common = { version = "0.5.3" }
|
switchboard-common = { version = "0.5.3" }
|
||||||
anchor-lang = { version = "=0.28.0" }
|
anchor-lang = { version = "0.28.0" }
|
||||||
|
|
||||||
[target.'cfg(not(target_os = "solana"))'.dependencies]
|
[target.'cfg(not(target_os = "solana"))'.dependencies]
|
||||||
switchboard-common = { version = "0.5.3", features = ["sgx"] }
|
switchboard-common = { version = "0.5.3", features = ["sgx"] }
|
||||||
anchor-client = { version = "=0.28.0" }
|
anchor-client = { version = "0.28.0" }
|
||||||
bincode = { version = "^1" }
|
bincode = { version = "^1" }
|
||||||
sgx-quote = { version = "0.1.0" }
|
sgx-quote = { version = "0.1.0" }
|
||||||
cron = { version = "0.12.0" }
|
cron = { version = "0.12.0" }
|
||||||
|
|
Loading…
Reference in New Issue