2021-07-09 18:42:05 -07:00
|
|
|
// Note. This example depends on unreleased Serum DEX changes.
|
|
|
|
|
|
|
|
use anchor_lang::prelude::*;
|
|
|
|
use anchor_spl::dex;
|
2021-11-11 06:12:50 -08:00
|
|
|
use anchor_spl::dex::serum_dex::instruction::MarketInstruction;
|
|
|
|
use anchor_spl::dex::serum_dex::matching::Side;
|
|
|
|
use anchor_spl::dex::serum_dex::state::OpenOrders;
|
2021-07-09 18:42:05 -07:00
|
|
|
use solana_program::instruction::Instruction;
|
|
|
|
use solana_program::system_program;
|
2021-07-18 11:39:56 -07:00
|
|
|
use solana_program::sysvar::rent;
|
2021-07-09 18:42:05 -07:00
|
|
|
use std::mem::size_of;
|
|
|
|
|
2021-09-11 14:43:12 -07:00
|
|
|
declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS");
|
|
|
|
|
2021-07-18 11:39:56 -07:00
|
|
|
/// A low level example of permissioned markets.
|
2021-07-09 18:42:05 -07:00
|
|
|
///
|
2021-07-18 11:39:56 -07:00
|
|
|
/// It's recommended to instead study `programs/permissioned-markets-middleware`
|
|
|
|
/// in this workspace, which achieves the same functionality in a simpler, more
|
|
|
|
/// extendable fashion via a middleware abstraction. This program achieves
|
|
|
|
/// mostly the same proxy + middleware functionality, but in a much uglier way.
|
2021-07-09 18:42:05 -07:00
|
|
|
///
|
2021-07-18 11:39:56 -07:00
|
|
|
/// This example is provided as a (very) rough guide for how to might implement
|
|
|
|
/// a permissioned market in a raw program, which may be useful in the
|
2021-08-06 12:52:54 -07:00
|
|
|
/// unexpected case that the middleware abstraction does not fit one's use case.
|
2021-07-18 11:39:56 -07:00
|
|
|
///
|
|
|
|
/// Note that a fallback function is used here as the entrypoint instead of
|
|
|
|
/// higher level Anchor instruction handers. This is done to keep the example
|
|
|
|
/// consistent with `programs/permissioned-markets-middleware`. A program
|
|
|
|
/// with explicit instruction handlers would work, though then one would lose
|
2021-08-06 12:52:54 -07:00
|
|
|
/// the middleware abstraction, which may or may not be acceptable depending on
|
2021-07-18 11:39:56 -07:00
|
|
|
/// your use case.
|
2021-07-09 18:42:05 -07:00
|
|
|
#[program]
|
|
|
|
pub mod permissioned_markets {
|
|
|
|
use super::*;
|
|
|
|
|
|
|
|
#[access_control(is_serum(accounts))]
|
|
|
|
pub fn dex_instruction(
|
|
|
|
program_id: &Pubkey,
|
|
|
|
accounts: &[AccountInfo],
|
2021-07-18 11:39:56 -07:00
|
|
|
mut data: &[u8],
|
2021-07-09 18:42:05 -07:00
|
|
|
) -> ProgramResult {
|
2021-07-18 11:39:56 -07:00
|
|
|
require!(!accounts.is_empty(), NotEnoughAccounts);
|
|
|
|
|
|
|
|
// Strip instruction data.
|
|
|
|
let bumps = {
|
|
|
|
// Strip the discriminator off the data, which is provided by the client
|
|
|
|
// for prepending extra instruction data.
|
|
|
|
let disc = data[0];
|
|
|
|
data = &data[1..];
|
|
|
|
|
|
|
|
// For the init open orders instruction, bump seeds are provided.
|
|
|
|
if disc == 0 {
|
|
|
|
let bump = data[0];
|
|
|
|
let bump_init = data[1];
|
|
|
|
data = &data[2..]; // Strip bumps off.
|
|
|
|
Some((bump, bump_init))
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
};
|
2021-07-09 18:42:05 -07:00
|
|
|
|
2021-07-18 11:39:56 -07:00
|
|
|
// Strip accounts.
|
|
|
|
let (dex, mut acc_infos) = {
|
|
|
|
// First account is the dex executable--used for CPI.
|
|
|
|
let dex = &accounts[0];
|
|
|
|
|
|
|
|
// Second account is the auth token.
|
|
|
|
let auth_token = &accounts[1];
|
|
|
|
if auth_token.key != &rent::ID {
|
|
|
|
// Rent sysvar as dummy example.
|
|
|
|
return Err(ErrorCode::InvalidAuthToken.into());
|
|
|
|
}
|
|
|
|
|
|
|
|
// Strip.
|
|
|
|
let acc_infos = (&accounts[2..]).to_vec();
|
|
|
|
|
|
|
|
(dex, acc_infos)
|
|
|
|
};
|
|
|
|
|
|
|
|
let mut pre_instruction: Option<CpiInstruction> = None;
|
|
|
|
let mut post_instruction: Option<CpiInstruction> = None;
|
2021-07-09 18:42:05 -07:00
|
|
|
|
|
|
|
// Decode instruction.
|
2021-07-18 11:39:56 -07:00
|
|
|
let ix = MarketInstruction::unpack(data).ok_or(ErrorCode::CannotUnpack)?;
|
2021-07-09 18:42:05 -07:00
|
|
|
|
|
|
|
// Swap the user's account, which is in the open orders authority
|
|
|
|
// position, for the program's PDA (the real authority).
|
|
|
|
let (market, user) = match ix {
|
2021-07-18 11:39:56 -07:00
|
|
|
MarketInstruction::InitOpenOrders => {
|
|
|
|
let (market, user) = {
|
|
|
|
let market = &acc_infos[4];
|
|
|
|
let user = &acc_infos[3];
|
|
|
|
|
|
|
|
let (bump, bump_init) = bumps.as_ref().unwrap();
|
|
|
|
|
|
|
|
// Initialize PDA.
|
|
|
|
let mut accounts = &acc_infos[..];
|
|
|
|
InitAccount::try_accounts(program_id, &mut accounts, &[*bump, *bump_init])?;
|
|
|
|
|
|
|
|
(*market.key, *user.key)
|
|
|
|
};
|
|
|
|
// Chop off the first two accounts used initializing the PDA.
|
|
|
|
acc_infos = (&acc_infos[2..]).to_vec();
|
|
|
|
|
|
|
|
// Set signers.
|
|
|
|
acc_infos[1] = prepare_pda(&acc_infos[0]);
|
|
|
|
acc_infos[4].is_signer = true;
|
|
|
|
|
|
|
|
(market, user)
|
|
|
|
}
|
|
|
|
MarketInstruction::NewOrderV3(ix) => {
|
|
|
|
require!(acc_infos.len() >= 12, NotEnoughAccounts);
|
2021-07-09 18:42:05 -07:00
|
|
|
|
|
|
|
let (market, user) = {
|
|
|
|
let market = &acc_infos[0];
|
|
|
|
let user = &acc_infos[7];
|
|
|
|
|
|
|
|
if !user.is_signer {
|
|
|
|
return Err(ErrorCode::UnauthorizedUser.into());
|
|
|
|
}
|
|
|
|
|
|
|
|
(*market.key, *user.key)
|
|
|
|
};
|
|
|
|
|
2021-07-18 11:39:56 -07:00
|
|
|
// Pre-instruction to approve delegate.
|
|
|
|
{
|
|
|
|
let market = &acc_infos[0];
|
|
|
|
let user = &acc_infos[7];
|
|
|
|
let open_orders = &acc_infos[1];
|
|
|
|
let token_account_payer = &acc_infos[6];
|
|
|
|
let amount = match ix.side {
|
|
|
|
Side::Bid => ix.max_native_pc_qty_including_fees.get(),
|
|
|
|
Side::Ask => {
|
|
|
|
// +5 for padding.
|
|
|
|
let coin_lot_idx = 5 + 43 * 8;
|
|
|
|
let data = market.try_borrow_data()?;
|
|
|
|
let mut coin_lot_array = [0u8; 8];
|
|
|
|
coin_lot_array.copy_from_slice(&data[coin_lot_idx..coin_lot_idx + 8]);
|
|
|
|
let coin_lot_size = u64::from_le_bytes(coin_lot_array);
|
|
|
|
ix.max_coin_qty.get().checked_mul(coin_lot_size).unwrap()
|
|
|
|
}
|
|
|
|
};
|
|
|
|
let ix = spl_token::instruction::approve(
|
|
|
|
&spl_token::ID,
|
|
|
|
token_account_payer.key,
|
|
|
|
open_orders.key,
|
|
|
|
user.key,
|
|
|
|
&[],
|
|
|
|
amount,
|
|
|
|
)?;
|
|
|
|
let accounts = vec![
|
|
|
|
token_account_payer.clone(),
|
|
|
|
open_orders.clone(),
|
|
|
|
user.clone(),
|
|
|
|
];
|
|
|
|
pre_instruction = Some((ix, accounts, Vec::new()));
|
|
|
|
};
|
|
|
|
|
|
|
|
// Post-instruction to revoke delegate.
|
|
|
|
{
|
|
|
|
let user = &acc_infos[7];
|
|
|
|
let token_account_payer = &acc_infos[6];
|
|
|
|
let ix = spl_token::instruction::revoke(
|
|
|
|
&spl_token::ID,
|
|
|
|
token_account_payer.key,
|
|
|
|
user.key,
|
|
|
|
&[],
|
|
|
|
)?;
|
|
|
|
let accounts = vec![token_account_payer.clone(), user.clone()];
|
|
|
|
post_instruction = Some((ix, accounts, Vec::new()));
|
|
|
|
}
|
|
|
|
|
2021-07-09 18:42:05 -07:00
|
|
|
acc_infos[7] = prepare_pda(&acc_infos[1]);
|
|
|
|
|
|
|
|
(market, user)
|
|
|
|
}
|
|
|
|
MarketInstruction::CancelOrderV2(_) => {
|
2021-07-18 11:39:56 -07:00
|
|
|
require!(acc_infos.len() >= 6, NotEnoughAccounts);
|
2021-07-09 18:42:05 -07:00
|
|
|
|
|
|
|
let (market, user) = {
|
|
|
|
let market = &acc_infos[0];
|
|
|
|
let user = &acc_infos[4];
|
|
|
|
|
|
|
|
if !user.is_signer {
|
|
|
|
return Err(ErrorCode::UnauthorizedUser.into());
|
|
|
|
}
|
|
|
|
|
|
|
|
(*market.key, *user.key)
|
|
|
|
};
|
|
|
|
|
|
|
|
acc_infos[4] = prepare_pda(&acc_infos[3]);
|
|
|
|
|
|
|
|
(market, user)
|
|
|
|
}
|
|
|
|
MarketInstruction::CancelOrderByClientIdV2(_) => {
|
2021-07-18 11:39:56 -07:00
|
|
|
require!(acc_infos.len() >= 6, NotEnoughAccounts);
|
2021-07-09 18:42:05 -07:00
|
|
|
|
|
|
|
let (market, user) = {
|
|
|
|
let market = &acc_infos[0];
|
|
|
|
let user = &acc_infos[4];
|
|
|
|
|
|
|
|
if !user.is_signer {
|
|
|
|
return Err(ErrorCode::UnauthorizedUser.into());
|
|
|
|
}
|
|
|
|
|
|
|
|
(*market.key, *user.key)
|
|
|
|
};
|
|
|
|
|
|
|
|
acc_infos[4] = prepare_pda(&acc_infos[3]);
|
|
|
|
|
|
|
|
(market, user)
|
|
|
|
}
|
|
|
|
MarketInstruction::SettleFunds => {
|
2021-07-18 11:39:56 -07:00
|
|
|
require!(acc_infos.len() >= 10, NotEnoughAccounts);
|
2021-07-09 18:42:05 -07:00
|
|
|
|
|
|
|
let (market, user) = {
|
|
|
|
let market = &acc_infos[0];
|
|
|
|
let user = &acc_infos[2];
|
2021-07-18 11:39:56 -07:00
|
|
|
let referral = &acc_infos[9];
|
2021-07-09 18:42:05 -07:00
|
|
|
|
|
|
|
if !DISABLE_REFERRAL && referral.key != &referral::ID {
|
|
|
|
return Err(ErrorCode::InvalidReferral.into());
|
|
|
|
}
|
|
|
|
if !user.is_signer {
|
|
|
|
return Err(ErrorCode::UnauthorizedUser.into());
|
|
|
|
}
|
|
|
|
|
|
|
|
(*market.key, *user.key)
|
|
|
|
};
|
|
|
|
|
|
|
|
acc_infos[2] = prepare_pda(&acc_infos[1]);
|
|
|
|
|
|
|
|
(market, user)
|
|
|
|
}
|
|
|
|
MarketInstruction::CloseOpenOrders => {
|
2021-07-18 11:39:56 -07:00
|
|
|
require!(acc_infos.len() >= 4, NotEnoughAccounts);
|
2021-07-09 18:42:05 -07:00
|
|
|
|
|
|
|
let (market, user) = {
|
|
|
|
let market = &acc_infos[3];
|
|
|
|
let user = &acc_infos[1];
|
|
|
|
|
|
|
|
if !user.is_signer {
|
|
|
|
return Err(ErrorCode::UnauthorizedUser.into());
|
|
|
|
}
|
|
|
|
|
|
|
|
(*market.key, *user.key)
|
|
|
|
};
|
|
|
|
|
|
|
|
acc_infos[1] = prepare_pda(&acc_infos[0]);
|
|
|
|
|
|
|
|
(market, user)
|
|
|
|
}
|
|
|
|
_ => return Err(ErrorCode::InvalidInstruction.into()),
|
|
|
|
};
|
|
|
|
|
2021-07-18 11:39:56 -07:00
|
|
|
// Execute pre instruction.
|
|
|
|
if let Some((ix, accounts, seeds)) = pre_instruction {
|
|
|
|
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();
|
2021-09-11 14:43:12 -07:00
|
|
|
solana_program::program::invoke_signed(&ix, &accounts, &signers)?;
|
2021-07-18 11:39:56 -07:00
|
|
|
}
|
|
|
|
|
2021-07-09 18:42:05 -07:00
|
|
|
// CPI to the dex.
|
|
|
|
let dex_accounts = acc_infos
|
|
|
|
.iter()
|
|
|
|
.map(|acc| AccountMeta {
|
|
|
|
pubkey: *acc.key,
|
|
|
|
is_signer: acc.is_signer,
|
|
|
|
is_writable: acc.is_writable,
|
|
|
|
})
|
|
|
|
.collect();
|
|
|
|
let ix = Instruction {
|
|
|
|
data: data.to_vec(),
|
|
|
|
accounts: dex_accounts,
|
|
|
|
program_id: dex::ID,
|
|
|
|
};
|
|
|
|
let seeds = open_orders_authority! {
|
|
|
|
program = program_id,
|
2021-07-18 11:39:56 -07:00
|
|
|
dex_program = dex.key,
|
2021-07-09 18:42:05 -07:00
|
|
|
market = market,
|
|
|
|
authority = user
|
|
|
|
};
|
2021-07-18 11:39:56 -07:00
|
|
|
let seeds_init = open_orders_init_authority! {
|
|
|
|
program = program_id,
|
|
|
|
dex_program = dex.key,
|
|
|
|
market = market
|
|
|
|
};
|
2021-09-11 14:43:12 -07:00
|
|
|
solana_program::program::invoke_signed(&ix, &acc_infos, &[seeds, seeds_init])?;
|
2021-07-18 11:39:56 -07:00
|
|
|
|
|
|
|
// Execute post instruction.
|
|
|
|
if let Some((ix, accounts, seeds)) = post_instruction {
|
|
|
|
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();
|
2021-09-11 14:43:12 -07:00
|
|
|
solana_program::program::invoke_signed(&ix, &accounts, &signers)?;
|
2021-07-18 11:39:56 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
2021-07-09 18:42:05 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Accounts context.
|
|
|
|
|
|
|
|
#[derive(Accounts)]
|
|
|
|
#[instruction(bump: u8, bump_init: u8)]
|
|
|
|
pub struct InitAccount<'info> {
|
2021-07-18 11:39:56 -07:00
|
|
|
#[account(address = dex::ID)]
|
|
|
|
pub dex_program: AccountInfo<'info>,
|
|
|
|
#[account(address = system_program::ID)]
|
|
|
|
pub system_program: AccountInfo<'info>,
|
2021-07-09 18:42:05 -07:00
|
|
|
#[account(
|
|
|
|
init,
|
2021-07-18 11:39:56 -07:00
|
|
|
seeds = [b"open-orders", dex_program.key.as_ref(), market.key.as_ref(), authority.key.as_ref()],
|
2021-07-09 18:42:05 -07:00
|
|
|
bump = bump,
|
|
|
|
payer = authority,
|
|
|
|
owner = dex::ID,
|
|
|
|
space = size_of::<OpenOrders>() + SERUM_PADDING,
|
|
|
|
)]
|
|
|
|
pub open_orders: AccountInfo<'info>,
|
|
|
|
#[account(signer)]
|
|
|
|
pub authority: AccountInfo<'info>,
|
|
|
|
pub market: AccountInfo<'info>,
|
|
|
|
pub rent: Sysvar<'info, Rent>,
|
2021-07-18 11:39:56 -07:00
|
|
|
#[account(
|
|
|
|
seeds = [b"open-orders-init", dex_program.key.as_ref(), market.key.as_ref()],
|
|
|
|
bump = bump_init,
|
|
|
|
)]
|
|
|
|
pub open_orders_init_authority: AccountInfo<'info>,
|
2021-07-09 18:42:05 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// Access control modifiers.
|
|
|
|
|
2021-07-18 11:39:56 -07:00
|
|
|
fn is_serum(accounts: &[AccountInfo]) -> Result<()> {
|
2021-07-09 18:42:05 -07:00
|
|
|
let dex_acc_info = &accounts[0];
|
|
|
|
if dex_acc_info.key != &dex::ID {
|
|
|
|
return Err(ErrorCode::InvalidDexPid.into());
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
// Error.
|
|
|
|
|
|
|
|
#[error]
|
|
|
|
pub enum ErrorCode {
|
|
|
|
#[msg("Program ID does not match the Serum DEX")]
|
|
|
|
InvalidDexPid,
|
|
|
|
#[msg("Invalid instruction given")]
|
|
|
|
InvalidInstruction,
|
|
|
|
#[msg("Could not unpack the instruction")]
|
|
|
|
CannotUnpack,
|
|
|
|
#[msg("Invalid referral address given")]
|
|
|
|
InvalidReferral,
|
|
|
|
#[msg("The user didn't sign")]
|
|
|
|
UnauthorizedUser,
|
|
|
|
#[msg("Not enough accounts were provided")]
|
|
|
|
NotEnoughAccounts,
|
2021-07-18 11:39:56 -07:00
|
|
|
#[msg("Invalid auth token provided")]
|
|
|
|
InvalidAuthToken,
|
|
|
|
}
|
|
|
|
|
|
|
|
// Utils.
|
|
|
|
|
|
|
|
fn prepare_pda<'info>(acc_info: &AccountInfo<'info>) -> AccountInfo<'info> {
|
|
|
|
let mut acc_info = acc_info.clone();
|
|
|
|
acc_info.is_signer = true;
|
|
|
|
acc_info
|
2021-07-09 18:42:05 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// Macros.
|
|
|
|
|
2021-07-18 11:39:56 -07:00
|
|
|
/// Returns the seeds used for a user's open orders account PDA.
|
2021-07-09 18:42:05 -07:00
|
|
|
#[macro_export]
|
|
|
|
macro_rules! open_orders_authority {
|
2021-07-18 11:39:56 -07:00
|
|
|
(
|
|
|
|
program = $program:expr,
|
|
|
|
dex_program = $dex_program:expr,
|
|
|
|
market = $market:expr,
|
|
|
|
authority = $authority:expr,
|
|
|
|
bump = $bump:expr
|
|
|
|
) => {
|
2021-07-09 18:42:05 -07:00
|
|
|
&[
|
|
|
|
b"open-orders".as_ref(),
|
2021-07-18 11:39:56 -07:00
|
|
|
$dex_program.as_ref(),
|
2021-07-09 18:42:05 -07:00
|
|
|
$market.as_ref(),
|
|
|
|
$authority.as_ref(),
|
|
|
|
&[$bump],
|
|
|
|
]
|
|
|
|
};
|
2021-07-18 11:39:56 -07:00
|
|
|
(
|
|
|
|
program = $program:expr,
|
|
|
|
dex_program = $dex_program:expr,
|
|
|
|
market = $market:expr,
|
|
|
|
authority = $authority:expr
|
|
|
|
) => {
|
2021-07-09 18:42:05 -07:00
|
|
|
&[
|
|
|
|
b"open-orders".as_ref(),
|
2021-07-18 11:39:56 -07:00
|
|
|
$dex_program.as_ref(),
|
2021-07-09 18:42:05 -07:00
|
|
|
$market.as_ref(),
|
|
|
|
$authority.as_ref(),
|
|
|
|
&[Pubkey::find_program_address(
|
|
|
|
&[
|
|
|
|
b"open-orders".as_ref(),
|
2021-07-18 11:39:56 -07:00
|
|
|
$dex_program.as_ref(),
|
2021-07-09 18:42:05 -07:00
|
|
|
$market.as_ref(),
|
|
|
|
$authority.as_ref(),
|
|
|
|
],
|
|
|
|
$program,
|
|
|
|
)
|
|
|
|
.1],
|
|
|
|
]
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns the seeds used for the open orders init authority.
|
|
|
|
/// This is the account that must sign to create a new open orders account on
|
|
|
|
/// the DEX market.
|
|
|
|
#[macro_export]
|
|
|
|
macro_rules! open_orders_init_authority {
|
2021-07-18 11:39:56 -07:00
|
|
|
(
|
|
|
|
program = $program:expr,
|
|
|
|
dex_program = $dex_program:expr,
|
|
|
|
market = $market:expr,
|
|
|
|
bump = $bump:expr
|
|
|
|
) => {
|
|
|
|
&[
|
|
|
|
b"open-orders-init".as_ref(),
|
|
|
|
$dex_program.as_ref().as_ref(),
|
|
|
|
$market.as_ref().as_ref(),
|
|
|
|
&[$bump],
|
|
|
|
]
|
|
|
|
};
|
|
|
|
|
|
|
|
(program = $program:expr, dex_program = $dex_program:expr, market = $market:expr) => {
|
2021-07-09 18:42:05 -07:00
|
|
|
&[
|
|
|
|
b"open-orders-init".as_ref(),
|
2021-07-18 11:39:56 -07:00
|
|
|
$dex_program.as_ref(),
|
2021-07-09 18:42:05 -07:00
|
|
|
$market.as_ref(),
|
|
|
|
&[Pubkey::find_program_address(
|
2021-07-18 11:39:56 -07:00
|
|
|
&[
|
|
|
|
b"open-orders-init".as_ref(),
|
|
|
|
$dex_program.as_ref(),
|
|
|
|
$market.as_ref(),
|
|
|
|
],
|
2021-07-09 18:42:05 -07:00
|
|
|
$program,
|
|
|
|
)
|
|
|
|
.1],
|
|
|
|
]
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
// Constants.
|
|
|
|
|
|
|
|
// Padding added to every serum account.
|
|
|
|
//
|
|
|
|
// b"serum".len() + b"padding".len().
|
|
|
|
const SERUM_PADDING: usize = 12;
|
|
|
|
|
|
|
|
// True if we don't care about referral access control (for testing).
|
|
|
|
const DISABLE_REFERRAL: bool = true;
|
|
|
|
|
|
|
|
/// The address that will receive all fees for all markets controlled by this
|
|
|
|
/// program. Note: this is a dummy address. Do not use in production.
|
|
|
|
pub mod referral {
|
|
|
|
solana_program::declare_id!("2k1bb16Hu7ocviT2KC3wcCgETtnC8tEUuvFBH4C5xStG");
|
|
|
|
}
|
2021-07-18 11:39:56 -07:00
|
|
|
|
|
|
|
type CpiInstruction<'info> = (Instruction, Vec<AccountInfo<'info>>, Vec<Vec<Vec<u8>>>);
|