-
Notifications
You must be signed in to change notification settings - Fork 0
[ENG-164] Add BatchReplace instruction to the dropset program
#70
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: ENG-182
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,49 @@ | ||
| use client::e2e_helpers::{ | ||
| E2e, | ||
| Trader, | ||
| }; | ||
| use dropset_interface::instructions::{ | ||
| BatchReplaceInstructionData, | ||
| Orders, | ||
| }; | ||
| use price::OrderInfoArgs; | ||
| use solana_sdk::{ | ||
| signature::Keypair, | ||
| signer::Signer, | ||
| }; | ||
|
|
||
| #[tokio::main] | ||
| async fn main() -> anyhow::Result<()> { | ||
| let trader = Keypair::new(); | ||
| let e2e = E2e::new_traders_and_market(None, [Trader::new(&trader, 0, 0)]).await?; | ||
|
|
||
| let res = e2e | ||
| .market | ||
| .batch_replace( | ||
| trader.pubkey(), | ||
| BatchReplaceInstructionData::new( | ||
| 0, | ||
| Orders::new([OrderInfoArgs::new_unscaled(11_000_000, 1)]), | ||
| Orders::new([ | ||
| OrderInfoArgs::new_unscaled(12_000_000, 1), | ||
| OrderInfoArgs::new_unscaled(13_000_000, 2), | ||
| OrderInfoArgs::new_unscaled(14_000_000, 3), | ||
| OrderInfoArgs::new_unscaled(15_000_000, 4), | ||
| OrderInfoArgs::new_unscaled(16_000_000, 5), | ||
| ]), | ||
| ), | ||
| ) | ||
| .send_single_signer(&e2e.rpc, &trader) | ||
| .await?; | ||
|
|
||
| for msg in res.parsed_transaction.log_messages { | ||
| println!("{msg}"); | ||
| } | ||
|
|
||
| println!( | ||
| "Transaction signature: {}", | ||
| e2e.register_market_txn.parsed_transaction.signature | ||
| ); | ||
|
|
||
| Ok(()) | ||
| } |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,181 @@ | ||||||||||||||||||||||||
| use core::mem::MaybeUninit; | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| use instruction_macros::{ | ||||||||||||||||||||||||
| Pack, | ||||||||||||||||||||||||
| Unpack, | ||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||
| use price::OrderInfoArgs; | ||||||||||||||||||||||||
| use solana_program_error::ProgramError; | ||||||||||||||||||||||||
| use static_assertions::const_assert_eq; | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| use crate::{ | ||||||||||||||||||||||||
| instructions::orders::private::UpToFive, | ||||||||||||||||||||||||
| state::user_order_sectors::{ | ||||||||||||||||||||||||
| MAX_ORDERS, | ||||||||||||||||||||||||
| MAX_ORDERS_USIZE, | ||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| #[repr(C)] | ||||||||||||||||||||||||
| #[derive(Debug, Clone, Pack, Unpack, PartialEq, Eq)] | ||||||||||||||||||||||||
| pub struct Orders { | ||||||||||||||||||||||||
| /// The number of elements representing real order arguments in [`Orders::order_args`]. | ||||||||||||||||||||||||
| /// This value will always be less than or equal to the max number of orders [`MAX_ORDERS`]. | ||||||||||||||||||||||||
| /// The remaining elements will be zero-initialized but cannot be accessed through the | ||||||||||||||||||||||||
| /// public [`Orders`] interface. | ||||||||||||||||||||||||
| num_orders: u8, | ||||||||||||||||||||||||
| /// Instruction data that isn't read is free, so it's simpler to always use [`MAX_ORDERS`] | ||||||||||||||||||||||||
| /// elements in the array and simply ignore elements with an index >= [`Orders::num_orders`] | ||||||||||||||||||||||||
| /// than to use a slice with a dynamic length. | ||||||||||||||||||||||||
| order_args: OrdersArray, | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| impl Orders { | ||||||||||||||||||||||||
| #[inline(always)] | ||||||||||||||||||||||||
| pub fn new<const N: usize>(orders: [OrderInfoArgs; N]) -> Self | ||||||||||||||||||||||||
| where | ||||||||||||||||||||||||
| [OrderInfoArgs; N]: UpToFive<N>, | ||||||||||||||||||||||||
| { | ||||||||||||||||||||||||
| let mut res: [MaybeUninit<OrderInfoArgs>; MAX_ORDERS_USIZE] = | ||||||||||||||||||||||||
| [const { MaybeUninit::uninit() }; MAX_ORDERS_USIZE]; | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| unsafe { | ||||||||||||||||||||||||
| // Copy the orders passed in. This initializes `res[0..N]`. | ||||||||||||||||||||||||
| // | ||||||||||||||||||||||||
| // Safety: | ||||||||||||||||||||||||
| // - `orders` is valid for `N` reads. | ||||||||||||||||||||||||
| // - `res` is valid for `MAX_ORDERS` writes, and `MAX_ORDERS` >= `N`. | ||||||||||||||||||||||||
| // - Both pointers are aligned and do not overlap. | ||||||||||||||||||||||||
| core::ptr::copy_nonoverlapping( | ||||||||||||||||||||||||
| orders.as_ptr(), | ||||||||||||||||||||||||
| res.as_mut_ptr() as *mut OrderInfoArgs, | ||||||||||||||||||||||||
| N, | ||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| // Write zeros to the remaining elements. This initializes `res[N..MAX_ORDERS]`. | ||||||||||||||||||||||||
| // | ||||||||||||||||||||||||
| // Safety: | ||||||||||||||||||||||||
| // - `res.as_mut_ptr().add(N)` is valid for up to `MAX_ORDERS - N` writes and `N` is | ||||||||||||||||||||||||
| // guaranteed to be <= `MAX_ORDERS`. | ||||||||||||||||||||||||
| // - Zero is a valid value for all field types. | ||||||||||||||||||||||||
| core::ptr::write_bytes( | ||||||||||||||||||||||||
| (res.as_mut_ptr() as *mut OrderInfoArgs).add(N), | ||||||||||||||||||||||||
| 0u8, | ||||||||||||||||||||||||
| MAX_ORDERS_USIZE - N, | ||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| Self { | ||||||||||||||||||||||||
| num_orders: N as u8, | ||||||||||||||||||||||||
| // Safety: The array has been fully initialized with `MAX_ORDERS` elements. | ||||||||||||||||||||||||
| order_args: OrdersArray(unsafe { | ||||||||||||||||||||||||
| core::mem::transmute::< | ||||||||||||||||||||||||
| [MaybeUninit<OrderInfoArgs>; MAX_ORDERS_USIZE], | ||||||||||||||||||||||||
| [OrderInfoArgs; MAX_ORDERS_USIZE], | ||||||||||||||||||||||||
| >(res) | ||||||||||||||||||||||||
| }), | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| /// Exposes the order args elements as an owned iterator for indices 0..[`Self::num_orders`]`. | ||||||||||||||||||||||||
| #[inline(always)] | ||||||||||||||||||||||||
| pub fn into_order_args_iter(self) -> impl Iterator<Item = OrderInfoArgs> { | ||||||||||||||||||||||||
| let n = self.num_orders as usize; | ||||||||||||||||||||||||
| self.order_args.0.into_iter().take(n) | ||||||||||||||||||||||||
|
Comment on lines
+82
to
+84
|
||||||||||||||||||||||||
| pub fn into_order_args_iter(self) -> impl Iterator<Item = OrderInfoArgs> { | |
| let n = self.num_orders as usize; | |
| self.order_args.0.into_iter().take(n) | |
| pub fn into_order_args_iter( | |
| self, | |
| ) -> Result<impl Iterator<Item = OrderInfoArgs>, ProgramError> { | |
| let n = self.num_orders as usize; | |
| if n > MAX_ORDERS_USIZE { | |
| return Err(ProgramError::InvalidInstructionData); | |
| } | |
| Ok(self.order_args.0.into_iter().take(n)) |
Uh oh!
There was an error while loading. Please reload this page.