2022-05-27 22:05:34 -07:00
|
|
|
use std::{sync::Arc, time::Duration};
|
2022-05-06 07:45:04 -07:00
|
|
|
|
2022-05-27 22:05:34 -07:00
|
|
|
use crate::MangoClient;
|
2022-08-08 04:40:33 -07:00
|
|
|
use itertools::Itertools;
|
2022-05-06 05:19:49 -07:00
|
|
|
|
2022-07-11 08:08:32 -07:00
|
|
|
use anchor_lang::{__private::bytemuck::cast_ref, solana_program};
|
2022-07-31 00:25:11 -07:00
|
|
|
use client::prettify_client_error;
|
2022-05-06 07:45:04 -07:00
|
|
|
use futures::Future;
|
2022-06-27 02:27:17 -07:00
|
|
|
use mango_v4::state::{EventQueue, EventType, FillEvent, OutEvent, PerpMarket, TokenIndex};
|
2022-05-27 22:05:34 -07:00
|
|
|
use solana_sdk::{
|
2022-08-08 07:31:59 -07:00
|
|
|
compute_budget::ComputeBudgetInstruction,
|
2022-05-27 22:05:34 -07:00
|
|
|
instruction::{AccountMeta, Instruction},
|
|
|
|
pubkey::Pubkey,
|
|
|
|
};
|
|
|
|
use tokio::time;
|
2022-05-06 05:19:49 -07:00
|
|
|
|
2022-07-31 00:25:11 -07:00
|
|
|
// TODO: move instructions into the client proper
|
|
|
|
|
2022-05-06 07:45:04 -07:00
|
|
|
pub async fn runner(
|
|
|
|
mango_client: Arc<MangoClient>,
|
|
|
|
debugging_handle: impl Future,
|
|
|
|
) -> Result<(), anyhow::Error> {
|
2022-05-27 22:05:34 -07:00
|
|
|
let handles1 = mango_client
|
2022-07-16 05:37:15 -07:00
|
|
|
.context
|
|
|
|
.tokens
|
|
|
|
.keys()
|
2022-08-08 04:40:33 -07:00
|
|
|
// TokenUpdateIndexAndRate is known to take max 71k cu
|
|
|
|
// from cargo test-bpf local tests
|
|
|
|
.chunks(15)
|
|
|
|
.into_iter()
|
|
|
|
.map(|chunk| {
|
|
|
|
loop_update_index_and_rate(
|
|
|
|
mango_client.clone(),
|
|
|
|
chunk.copied().collect::<Vec<TokenIndex>>(),
|
|
|
|
)
|
|
|
|
})
|
2022-05-06 05:19:49 -07:00
|
|
|
.collect::<Vec<_>>();
|
|
|
|
|
2022-05-27 22:05:34 -07:00
|
|
|
let handles2 = mango_client
|
2022-07-16 05:37:15 -07:00
|
|
|
.context
|
|
|
|
.perp_markets
|
2022-05-27 22:05:34 -07:00
|
|
|
.values()
|
2022-07-16 05:37:15 -07:00
|
|
|
.map(|perp| loop_consume_events(mango_client.clone(), perp.address, perp.market))
|
2022-05-06 05:19:49 -07:00
|
|
|
.collect::<Vec<_>>();
|
|
|
|
|
2022-05-27 22:05:34 -07:00
|
|
|
let handles3 = mango_client
|
2022-07-16 05:37:15 -07:00
|
|
|
.context
|
|
|
|
.perp_markets
|
2022-05-27 22:05:34 -07:00
|
|
|
.values()
|
2022-07-16 05:37:15 -07:00
|
|
|
.map(|perp| loop_update_funding(mango_client.clone(), perp.address, perp.market))
|
2022-05-17 06:59:47 -07:00
|
|
|
.collect::<Vec<_>>();
|
|
|
|
|
2022-05-06 05:19:49 -07:00
|
|
|
futures::join!(
|
|
|
|
futures::future::join_all(handles1),
|
2022-05-06 07:45:04 -07:00
|
|
|
futures::future::join_all(handles2),
|
2022-05-17 06:59:47 -07:00
|
|
|
futures::future::join_all(handles3),
|
2022-05-06 07:45:04 -07:00
|
|
|
debugging_handle
|
2022-05-06 05:19:49 -07:00
|
|
|
);
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
2022-05-27 22:05:34 -07:00
|
|
|
|
2022-08-08 04:40:33 -07:00
|
|
|
pub async fn loop_update_index_and_rate(
|
|
|
|
mango_client: Arc<MangoClient>,
|
|
|
|
token_indices: Vec<TokenIndex>,
|
|
|
|
) {
|
2022-08-09 02:20:42 -07:00
|
|
|
let mut interval = time::interval(Duration::from_secs(60));
|
2022-05-27 22:05:34 -07:00
|
|
|
loop {
|
|
|
|
interval.tick().await;
|
|
|
|
|
|
|
|
let client = mango_client.clone();
|
2022-06-27 02:27:17 -07:00
|
|
|
|
2022-08-08 04:40:33 -07:00
|
|
|
let token_indices_clone = token_indices.clone();
|
|
|
|
|
2022-05-29 00:07:15 -07:00
|
|
|
let res = tokio::task::spawn_blocking(move || -> anyhow::Result<()> {
|
2022-08-08 04:40:33 -07:00
|
|
|
let token_names = token_indices_clone
|
|
|
|
.iter()
|
|
|
|
.map(|token_index| client.context.token(*token_index).name.to_owned())
|
|
|
|
.join(", ");
|
|
|
|
|
|
|
|
let program = client.program();
|
|
|
|
let mut req = program.request();
|
2022-08-08 07:31:59 -07:00
|
|
|
req = req.instruction(ComputeBudgetInstruction::set_compute_unit_price(1));
|
2022-08-08 04:40:33 -07:00
|
|
|
for token_index in token_indices_clone.iter() {
|
|
|
|
let token = client.context.token(*token_index);
|
|
|
|
let banks_for_a_token = token.mint_info.banks();
|
|
|
|
let oracle = token.mint_info.oracle;
|
|
|
|
|
|
|
|
let mut ix = Instruction {
|
|
|
|
program_id: mango_v4::id(),
|
|
|
|
accounts: anchor_lang::ToAccountMetas::to_account_metas(
|
|
|
|
&mango_v4::accounts::TokenUpdateIndexAndRate {
|
|
|
|
group: token.mint_info.group,
|
|
|
|
mint_info: token.mint_info_address,
|
|
|
|
oracle,
|
|
|
|
instructions: solana_program::sysvar::instructions::id(),
|
|
|
|
},
|
|
|
|
None,
|
|
|
|
),
|
|
|
|
data: anchor_lang::InstructionData::data(
|
|
|
|
&mango_v4::instruction::TokenUpdateIndexAndRate {},
|
|
|
|
),
|
|
|
|
};
|
|
|
|
let mut banks = banks_for_a_token
|
|
|
|
.iter()
|
|
|
|
.map(|bank_pubkey| AccountMeta {
|
|
|
|
pubkey: *bank_pubkey,
|
|
|
|
is_signer: false,
|
|
|
|
is_writable: true,
|
|
|
|
})
|
|
|
|
.collect::<Vec<_>>();
|
|
|
|
ix.accounts.append(&mut banks);
|
|
|
|
req = req.instruction(ix);
|
|
|
|
}
|
|
|
|
let sig_result = req.send().map_err(prettify_client_error);
|
2022-06-27 02:27:17 -07:00
|
|
|
|
2022-05-27 22:05:34 -07:00
|
|
|
if let Err(e) = sig_result {
|
|
|
|
log::error!("{:?}", e)
|
|
|
|
} else {
|
2022-07-11 08:08:32 -07:00
|
|
|
log::info!(
|
|
|
|
"update_index_and_rate {} {:?}",
|
2022-08-08 04:40:33 -07:00
|
|
|
token_names,
|
2022-07-11 08:08:32 -07:00
|
|
|
sig_result.unwrap()
|
|
|
|
)
|
2022-05-27 22:05:34 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
2022-05-29 00:07:15 -07:00
|
|
|
})
|
|
|
|
.await;
|
|
|
|
|
|
|
|
match res {
|
|
|
|
Ok(inner_res) => {
|
|
|
|
if inner_res.is_err() {
|
|
|
|
log::error!("{}", inner_res.unwrap_err());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Err(join_error) => {
|
|
|
|
log::error!("{}", join_error);
|
|
|
|
}
|
|
|
|
}
|
2022-05-27 22:05:34 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn loop_consume_events(
|
|
|
|
mango_client: Arc<MangoClient>,
|
|
|
|
pk: Pubkey,
|
|
|
|
perp_market: PerpMarket,
|
|
|
|
) {
|
|
|
|
let mut interval = time::interval(Duration::from_secs(5));
|
|
|
|
loop {
|
|
|
|
interval.tick().await;
|
|
|
|
|
|
|
|
let client = mango_client.clone();
|
2022-05-29 00:07:15 -07:00
|
|
|
let res = tokio::task::spawn_blocking(move || -> anyhow::Result<()> {
|
2022-05-27 22:05:34 -07:00
|
|
|
let mut event_queue: EventQueue =
|
|
|
|
client.program().account(perp_market.event_queue).unwrap();
|
|
|
|
|
|
|
|
let mut ams_ = vec![];
|
|
|
|
|
|
|
|
// TODO: future, choose better constant of how many max events to pack
|
|
|
|
// TODO: future, choose better constant of how many max mango accounts to pack
|
|
|
|
for _ in 0..10 {
|
|
|
|
let event = match event_queue.peek_front() {
|
|
|
|
None => break,
|
|
|
|
Some(e) => e,
|
|
|
|
};
|
|
|
|
match EventType::try_from(event.event_type)? {
|
|
|
|
EventType::Fill => {
|
|
|
|
let fill: &FillEvent = cast_ref(event);
|
|
|
|
ams_.push(AccountMeta {
|
|
|
|
pubkey: fill.maker,
|
|
|
|
is_signer: false,
|
|
|
|
is_writable: true,
|
|
|
|
});
|
|
|
|
ams_.push(AccountMeta {
|
|
|
|
pubkey: fill.taker,
|
|
|
|
is_signer: false,
|
|
|
|
is_writable: true,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
EventType::Out => {
|
|
|
|
let out: &OutEvent = cast_ref(event);
|
|
|
|
ams_.push(AccountMeta {
|
|
|
|
pubkey: out.owner,
|
|
|
|
is_signer: false,
|
|
|
|
is_writable: true,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
EventType::Liquidate => {}
|
|
|
|
}
|
|
|
|
event_queue.pop_front()?;
|
|
|
|
}
|
|
|
|
|
|
|
|
let sig_result = client
|
|
|
|
.program()
|
|
|
|
.request()
|
|
|
|
.instruction(Instruction {
|
|
|
|
program_id: mango_v4::id(),
|
|
|
|
accounts: {
|
|
|
|
let mut ams = anchor_lang::ToAccountMetas::to_account_metas(
|
|
|
|
&mango_v4::accounts::PerpConsumeEvents {
|
|
|
|
group: perp_market.group,
|
|
|
|
perp_market: pk,
|
|
|
|
event_queue: perp_market.event_queue,
|
|
|
|
},
|
|
|
|
None,
|
|
|
|
);
|
|
|
|
ams.append(&mut ams_);
|
|
|
|
ams
|
|
|
|
},
|
|
|
|
data: anchor_lang::InstructionData::data(
|
|
|
|
&mango_v4::instruction::PerpConsumeEvents { limit: 10 },
|
|
|
|
),
|
|
|
|
})
|
2022-07-31 00:25:11 -07:00
|
|
|
.send()
|
|
|
|
.map_err(prettify_client_error);
|
2022-05-27 22:05:34 -07:00
|
|
|
|
|
|
|
if let Err(e) = sig_result {
|
|
|
|
log::error!("{:?}", e)
|
|
|
|
} else {
|
|
|
|
log::info!(
|
|
|
|
"consume_event {} {:?}",
|
|
|
|
perp_market.name(),
|
|
|
|
sig_result.unwrap()
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
2022-05-29 00:07:15 -07:00
|
|
|
})
|
|
|
|
.await;
|
|
|
|
|
|
|
|
match res {
|
|
|
|
Ok(inner_res) => {
|
|
|
|
if inner_res.is_err() {
|
|
|
|
log::error!("{}", inner_res.unwrap_err());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Err(join_error) => {
|
|
|
|
log::error!("{}", join_error);
|
|
|
|
}
|
|
|
|
}
|
2022-05-27 22:05:34 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn loop_update_funding(
|
|
|
|
mango_client: Arc<MangoClient>,
|
|
|
|
pk: Pubkey,
|
|
|
|
perp_market: PerpMarket,
|
|
|
|
) {
|
|
|
|
let mut interval = time::interval(Duration::from_secs(5));
|
|
|
|
loop {
|
|
|
|
interval.tick().await;
|
|
|
|
|
|
|
|
let client = mango_client.clone();
|
2022-05-29 00:07:15 -07:00
|
|
|
let res = tokio::task::spawn_blocking(move || -> anyhow::Result<()> {
|
2022-05-27 22:05:34 -07:00
|
|
|
let sig_result = client
|
|
|
|
.program()
|
|
|
|
.request()
|
|
|
|
.instruction(Instruction {
|
|
|
|
program_id: mango_v4::id(),
|
|
|
|
accounts: anchor_lang::ToAccountMetas::to_account_metas(
|
|
|
|
&mango_v4::accounts::PerpUpdateFunding {
|
2022-08-05 10:11:44 -07:00
|
|
|
group: perp_market.group,
|
2022-05-27 22:05:34 -07:00
|
|
|
perp_market: pk,
|
|
|
|
asks: perp_market.asks,
|
|
|
|
bids: perp_market.bids,
|
|
|
|
oracle: perp_market.oracle,
|
|
|
|
},
|
|
|
|
None,
|
|
|
|
),
|
|
|
|
data: anchor_lang::InstructionData::data(
|
|
|
|
&mango_v4::instruction::PerpUpdateFunding {},
|
|
|
|
),
|
|
|
|
})
|
2022-07-31 00:25:11 -07:00
|
|
|
.send()
|
|
|
|
.map_err(prettify_client_error);
|
2022-05-27 22:05:34 -07:00
|
|
|
if let Err(e) = sig_result {
|
|
|
|
log::error!("{:?}", e)
|
|
|
|
} else {
|
|
|
|
log::info!(
|
|
|
|
"update_funding {} {:?}",
|
|
|
|
perp_market.name(),
|
|
|
|
sig_result.unwrap()
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
2022-05-29 00:07:15 -07:00
|
|
|
})
|
|
|
|
.await;
|
|
|
|
|
|
|
|
match res {
|
|
|
|
Ok(inner_res) => {
|
|
|
|
if inner_res.is_err() {
|
|
|
|
log::error!("{}", inner_res.unwrap_err());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Err(join_error) => {
|
|
|
|
log::error!("{}", join_error);
|
|
|
|
}
|
|
|
|
}
|
2022-05-27 22:05:34 -07:00
|
|
|
}
|
|
|
|
}
|