123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177 |
- use crate::dex;
- use crate::dex::middleware::{Context, ErrorCode, MarketMiddleware};
- use anchor_lang::prelude::*;
- use anchor_lang::solana_program::program;
- use anchor_lang::solana_program::pubkey::Pubkey;
- use serum_dex::instruction::*;
- /// MarketProxy provides an abstraction for implementing proxy programs to the
- /// Serum orderbook, allowing one to implement a middleware for the purposes
- /// of intercepting and modifying requests before being relayed to the
- /// orderbook.
- ///
- /// The only requirement for a middleware is that, when all are done processing,
- /// a valid DEX instruction--accounts and instruction data--must be left to
- /// forward to the orderbook program.
- #[derive(Default)]
- pub struct MarketProxy<'a> {
- middlewares: Vec<&'a mut dyn MarketMiddleware>,
- }
- impl<'a> MarketProxy<'a> {
- /// Constructs a new `MarketProxy`.
- pub fn new() -> Self {
- Self {
- middlewares: Vec::new(),
- }
- }
- /// Builder method for adding a middleware to the proxy.
- pub fn middleware(mut self, mw: &'a mut dyn MarketMiddleware) -> Self {
- self.middlewares.push(mw);
- self
- }
- /// Entrypoint to the program.
- pub fn run(
- mut self,
- program_id: &Pubkey,
- accounts: &[AccountInfo],
- data: &[u8],
- ) -> ProgramResult {
- let mut ix_data = data;
- // First account is the Serum DEX executable--used for CPI.
- let dex = &accounts[0];
- require!(dex.key == &dex::ID, ErrorCode::InvalidTargetProgram);
- let acc_infos = (&accounts[1..]).to_vec();
- // Process the instruction data.
- for mw in &mut self.middlewares {
- mw.instruction(&mut ix_data)?;
- }
- // Request context.
- let mut ctx = Context::new(program_id, dex.key, acc_infos);
- // Decode instruction.
- let ix = MarketInstruction::unpack(ix_data);
- // Method dispatch.
- match ix {
- Some(MarketInstruction::InitOpenOrders) => {
- require!(ctx.accounts.len() >= 4, ErrorCode::NotEnoughAccounts);
- for mw in &self.middlewares {
- mw.init_open_orders(&mut ctx)?;
- }
- }
- Some(MarketInstruction::NewOrderV3(ix)) => {
- require!(ctx.accounts.len() >= 12, ErrorCode::NotEnoughAccounts);
- for mw in &self.middlewares {
- mw.new_order_v3(&mut ctx, &ix)?;
- }
- }
- Some(MarketInstruction::CancelOrderV2(ix)) => {
- require!(ctx.accounts.len() >= 6, ErrorCode::NotEnoughAccounts);
- for mw in &self.middlewares {
- mw.cancel_order_v2(&mut ctx, &ix)?;
- }
- }
- Some(MarketInstruction::CancelOrderByClientIdV2(ix)) => {
- require!(ctx.accounts.len() >= 6, ErrorCode::NotEnoughAccounts);
- for mw in &self.middlewares {
- mw.cancel_order_by_client_id_v2(&mut ctx, ix)?;
- }
- }
- Some(MarketInstruction::SettleFunds) => {
- require!(ctx.accounts.len() >= 10, ErrorCode::NotEnoughAccounts);
- for mw in &self.middlewares {
- mw.settle_funds(&mut ctx)?;
- }
- }
- Some(MarketInstruction::CloseOpenOrders) => {
- require!(ctx.accounts.len() >= 4, ErrorCode::NotEnoughAccounts);
- for mw in &self.middlewares {
- mw.close_open_orders(&mut ctx)?;
- }
- }
- Some(MarketInstruction::Prune(limit)) => {
- require!(ctx.accounts.len() >= 7, ErrorCode::NotEnoughAccounts);
- for mw in &self.middlewares {
- mw.prune(&mut ctx, limit)?;
- }
- }
- _ => {
- for mw in &self.middlewares {
- mw.fallback(&mut ctx)?;
- }
- return Ok(());
- }
- };
- // Extract the middleware adjusted context.
- let Context {
- seeds,
- accounts,
- pre_instructions,
- post_instructions,
- ..
- } = ctx;
- // Execute pre instructions.
- for (ix, acc_infos, seeds) in pre_instructions {
- let tmp_signers: Vec<Vec<&[u8]>> = seeds
- .iter()
- .map(|seeds| {
- let seeds: Vec<&[u8]> = seeds.iter().map(|seed| &seed[..]).collect();
- seeds
- })
- .collect();
- let signers: Vec<&[&[u8]]> = tmp_signers.iter().map(|seeds| &seeds[..]).collect();
- program::invoke_signed(&ix, &acc_infos, &signers)?;
- }
- // Execute the main dex relay.
- {
- let tmp_signers: Vec<Vec<&[u8]>> = seeds
- .iter()
- .map(|seeds| {
- let seeds: Vec<&[u8]> = seeds.iter().map(|seed| &seed[..]).collect();
- seeds
- })
- .collect();
- let signers: Vec<&[&[u8]]> = tmp_signers.iter().map(|seeds| &seeds[..]).collect();
- // CPI to the DEX.
- let dex_accounts = accounts
- .iter()
- .map(|acc| AccountMeta {
- pubkey: *acc.key,
- is_signer: acc.is_signer,
- is_writable: acc.is_writable,
- })
- .collect();
- let ix = anchor_lang::solana_program::instruction::Instruction {
- data: ix_data.to_vec(),
- accounts: dex_accounts,
- program_id: dex::ID,
- };
- program::invoke_signed(&ix, &accounts, &signers)?;
- }
- // Execute post instructions.
- for (ix, acc_infos, seeds) in post_instructions {
- let tmp_signers: Vec<Vec<&[u8]>> = seeds
- .iter()
- .map(|seeds| {
- let seeds: Vec<&[u8]> = seeds.iter().map(|seed| &seed[..]).collect();
- seeds
- })
- .collect();
- let signers: Vec<&[&[u8]]> = tmp_signers.iter().map(|seeds| &seeds[..]).collect();
- program::invoke_signed(&ix, &acc_infos, &signers)?;
- }
- Ok(())
- }
- }
|