1use crate::{
8 error::TempoPrecompileError,
9 stablecoin_exchange::{IStablecoinExchange, error::OrderError},
10 storage::{Slot, StorageOps, slots::mapping_slot},
11};
12use alloy::primitives::{Address, B256};
13use tempo_precompiles_macros::Storable;
14
15#[derive(Debug, Clone, PartialEq, Eq, Storable)]
40pub struct Order {
41 pub order_id: u128,
43 pub maker: Address,
45 pub book_key: B256,
47 pub is_bid: bool,
49 pub tick: i16,
51 pub amount: u128,
53 pub remaining: u128,
55 pub prev: u128,
57 pub next: u128,
59 pub is_flip: bool,
61 pub flip_tick: i16,
65}
66
67type OrderId = Slot<u128>;
69type OrderAmount = Slot<u128>;
71
72impl Order {
73 #[allow(clippy::too_many_arguments)]
75 pub fn new(
76 order_id: u128,
77 maker: Address,
78 book_key: B256,
79 amount: u128,
80 tick: i16,
81 is_bid: bool,
82 is_flip: bool,
83 flip_tick: i16,
84 ) -> Self {
85 Self {
86 order_id,
87 maker,
88 book_key,
89 is_bid,
90 tick,
91 amount,
92 remaining: amount,
93 prev: 0,
94 next: 0,
95 is_flip,
96 flip_tick,
97 }
98 }
99
100 pub fn new_bid(
102 order_id: u128,
103 maker: Address,
104 book_key: B256,
105 amount: u128,
106 tick: i16,
107 ) -> Self {
108 Self::new(order_id, maker, book_key, amount, tick, true, false, 0)
109 }
110
111 pub fn new_ask(
113 order_id: u128,
114 maker: Address,
115 book_key: B256,
116 amount: u128,
117 tick: i16,
118 ) -> Self {
119 Self::new(order_id, maker, book_key, amount, tick, false, false, 0)
120 }
121
122 pub fn new_flip(
132 order_id: u128,
133 maker: Address,
134 book_key: B256,
135 amount: u128,
136 tick: i16,
137 is_bid: bool,
138 flip_tick: i16,
139 ) -> Result<Self, OrderError> {
140 if is_bid {
142 if flip_tick <= tick {
143 return Err(OrderError::InvalidBidFlipTick { tick, flip_tick });
144 }
145 } else if flip_tick >= tick {
146 return Err(OrderError::InvalidAskFlipTick { tick, flip_tick });
147 }
148
149 Ok(Self::new(
150 order_id, maker, book_key, amount, tick, is_bid, true, flip_tick,
151 ))
152 }
153
154 pub fn update_remaining<S: StorageOps>(
156 storage: &mut S,
157 order_id: u128,
158 new_remaining: u128,
159 ) -> Result<(), TempoPrecompileError> {
160 let order_base_slot = mapping_slot(order_id.to_be_bytes(), super::slots::ORDERS);
161 OrderAmount::new_at_loc(order_base_slot, __packing_order::REMAINING_LOC)
162 .write(storage, new_remaining)?;
163 Ok(())
164 }
165
166 pub fn update_next_order<S: StorageOps>(
167 storage: &mut S,
168 order_id: u128,
169 new_next: u128,
170 ) -> Result<(), TempoPrecompileError> {
171 let order_base_slot = mapping_slot(order_id.to_be_bytes(), super::slots::ORDERS);
172 OrderId::new_at_loc(order_base_slot, __packing_order::NEXT_LOC).write(storage, new_next)?;
173 Ok(())
174 }
175
176 pub fn update_prev_order<S: StorageOps>(
177 storage: &mut S,
178 order_id: u128,
179 new_prev: u128,
180 ) -> Result<(), TempoPrecompileError> {
181 let order_base_slot = mapping_slot(order_id.to_be_bytes(), super::slots::ORDERS);
182 OrderId::new_at_loc(order_base_slot, __packing_order::PREV_LOC).write(storage, new_prev)?;
183 Ok(())
184 }
185
186 pub fn order_id(&self) -> u128 {
188 self.order_id
189 }
190
191 pub fn maker(&self) -> Address {
193 self.maker
194 }
195
196 pub fn book_key(&self) -> B256 {
198 self.book_key
199 }
200
201 pub fn is_bid(&self) -> bool {
203 self.is_bid
204 }
205
206 pub fn amount(&self) -> u128 {
208 self.amount
209 }
210
211 pub fn remaining(&self) -> u128 {
213 self.remaining
214 }
215
216 fn remaining_mut(&mut self) -> &mut u128 {
218 &mut self.remaining
219 }
220
221 pub fn tick(&self) -> i16 {
223 self.tick
224 }
225
226 pub fn is_ask(&self) -> bool {
228 !self.is_bid
229 }
230
231 pub fn is_flip(&self) -> bool {
233 self.is_flip
234 }
235
236 pub fn flip_tick(&self) -> i16 {
241 self.flip_tick
242 }
243
244 pub fn prev(&self) -> u128 {
246 self.prev
247 }
248
249 pub fn next(&self) -> u128 {
251 self.next
252 }
253
254 pub fn set_prev(&mut self, prev_id: u128) {
256 self.prev = prev_id;
257 }
258
259 pub fn set_next(&mut self, next_id: u128) {
261 self.next = next_id;
262 }
263
264 pub fn is_fully_filled(&self) -> bool {
266 self.remaining == 0
267 }
268
269 pub fn fill(&mut self, fill_amount: u128) -> Result<(), OrderError> {
274 if fill_amount > self.remaining {
275 return Err(OrderError::FillAmountExceedsRemaining {
276 requested: fill_amount,
277 available: self.remaining,
278 });
279 }
280 *self.remaining_mut() = self.remaining.saturating_sub(fill_amount);
281 Ok(())
282 }
283
284 pub fn create_flipped_order(&self, new_order_id: u128) -> Result<Self, OrderError> {
296 if !self.is_flip {
298 return Err(OrderError::NotAFlipOrder);
299 }
300
301 if self.remaining != 0 {
303 return Err(OrderError::OrderNotFullyFilled {
304 remaining: self.remaining,
305 });
306 }
307
308 Ok(Self {
310 order_id: new_order_id,
311 maker: self.maker,
312 book_key: self.book_key,
313 is_bid: !self.is_bid, tick: self.flip_tick, amount: self.amount, remaining: self.amount, prev: 0, next: 0,
319 is_flip: true, flip_tick: self.tick, })
322 }
323}
324
325impl From<Order> for IStablecoinExchange::Order {
326 fn from(value: Order) -> Self {
327 Self {
328 orderId: value.order_id,
329 maker: value.maker,
330 bookKey: value.book_key,
331 isBid: value.is_bid,
332 tick: value.tick,
333 amount: value.amount,
334 remaining: value.remaining,
335 prev: value.prev,
336 next: value.next,
337 isFlip: value.is_flip,
338 flipTick: value.flip_tick,
339 }
340 }
341}
342
343#[cfg(test)]
344mod tests {
345 use crate::{
346 stablecoin_exchange::StablecoinExchange, storage::hashmap::HashMapStorageProvider,
347 };
348
349 use super::*;
350 use alloy::primitives::{address, b256};
351
352 const TEST_MAKER: Address = address!("0x1111111111111111111111111111111111111111");
353 const TEST_BOOK_KEY: B256 =
354 b256!("0x0000000000000000000000000000000000000000000000000000000000000001");
355
356 #[test]
357 fn test_new_bid_order() {
358 let order = Order::new_bid(1, TEST_MAKER, TEST_BOOK_KEY, 1000, 5);
359
360 assert_eq!(order.order_id(), 1);
361 assert_eq!(order.maker(), TEST_MAKER);
362 assert_eq!(order.book_key(), TEST_BOOK_KEY);
363 assert!(order.is_bid());
364 assert_eq!(order.amount(), 1000);
365 assert_eq!(order.remaining(), 1000);
366 assert!(order.is_bid());
367 assert!(!order.is_ask());
368 assert_eq!(order.tick(), 5);
369 assert!(!order.is_flip());
370 assert_eq!(order.flip_tick(), 0);
371 }
372
373 #[test]
374 fn test_new_ask_order() {
375 let order = Order::new_ask(1, TEST_MAKER, TEST_BOOK_KEY, 1000, 5);
376
377 assert_eq!(order.order_id(), 1);
378 assert!(!order.is_bid());
379 assert!(!order.is_bid());
380 assert!(order.is_ask());
381 assert!(!order.is_flip());
382 }
383
384 #[test]
385 fn test_new_flip_order_bid() {
386 let order = Order::new_flip(1, TEST_MAKER, TEST_BOOK_KEY, 1000, 5, true, 10).unwrap();
387
388 assert!(order.is_flip());
389 assert_eq!(order.flip_tick(), 10);
390 assert_eq!(order.tick(), 5);
391 assert!(order.is_bid());
392 }
393
394 #[test]
395 fn test_new_flip_order_ask() {
396 let order = Order::new_flip(1, TEST_MAKER, TEST_BOOK_KEY, 1000, 5, false, 2).unwrap();
397
398 assert!(order.is_flip());
399 assert_eq!(order.flip_tick(), 2);
400 assert_eq!(order.tick(), 5);
401 assert!(!order.is_bid());
402 assert!(order.is_ask());
403 }
404
405 #[test]
406 fn test_new_flip_order_bid_invalid_flip_tick() {
407 let result = Order::new_flip(1, TEST_MAKER, TEST_BOOK_KEY, 1000, 5, true, 3);
408
409 assert!(matches!(result, Err(OrderError::InvalidBidFlipTick { .. })));
410 }
411
412 #[test]
413 fn test_new_flip_order_ask_invalid_flip_tick() {
414 let result = Order::new_flip(1, TEST_MAKER, TEST_BOOK_KEY, 1000, 5, false, 7);
415
416 assert!(matches!(result, Err(OrderError::InvalidAskFlipTick { .. })));
417 }
418
419 #[test]
420 fn test_fill_bid_order_partial() {
421 let mut order = Order::new_bid(1, TEST_MAKER, TEST_BOOK_KEY, 1000, 5);
422
423 assert!(!order.is_fully_filled());
424
425 order.fill(400).unwrap();
426
427 assert_eq!(order.remaining(), 600);
428 assert_eq!(order.amount(), 1000);
429 assert!(!order.is_fully_filled());
430 }
431
432 #[test]
433 fn test_fill_ask_order_complete() {
434 let mut order = Order::new_ask(1, TEST_MAKER, TEST_BOOK_KEY, 1000, 5);
435
436 order.fill(1000).unwrap();
437
438 assert_eq!(order.remaining(), 0);
439 assert_eq!(order.amount(), 1000);
440 assert!(order.is_fully_filled());
441 }
442
443 #[test]
444 fn test_fill_order_overfill() {
445 let mut order = Order::new_bid(1, TEST_MAKER, TEST_BOOK_KEY, 1000, 5);
446
447 let result = order.fill(1001);
448 assert!(matches!(
449 result,
450 Err(OrderError::FillAmountExceedsRemaining { .. })
451 ));
452 }
453
454 #[test]
455 fn test_create_flipped_order_bid_to_ask() {
456 let mut order = Order::new_flip(1, TEST_MAKER, TEST_BOOK_KEY, 1000, 5, true, 10).unwrap();
457
458 order.fill(1000).unwrap();
460 assert!(order.is_fully_filled());
461
462 let flipped = order.create_flipped_order(2).unwrap();
464
465 assert_eq!(flipped.order_id(), 2);
466 assert_eq!(flipped.maker(), order.maker());
467 assert_eq!(flipped.book_key(), order.book_key());
468 assert_eq!(flipped.amount(), 1000); assert_eq!(flipped.remaining(), 1000); assert!(!flipped.is_bid()); assert!(flipped.is_ask());
472 assert_eq!(flipped.tick(), 10); assert_eq!(flipped.flip_tick(), 5); assert!(flipped.is_flip());
475 }
476
477 #[test]
478 fn test_create_flipped_order_ask_to_bid() {
479 let mut order = Order::new_flip(1, TEST_MAKER, TEST_BOOK_KEY, 1000, 10, false, 5).unwrap();
480
481 order.fill(1000).unwrap();
482 let flipped = order.create_flipped_order(2).unwrap();
483
484 assert!(flipped.is_bid()); assert!(!flipped.is_ask());
486 assert_eq!(flipped.tick(), 5); assert_eq!(flipped.flip_tick(), 10); }
489
490 #[test]
491 fn test_create_flipped_order_non_flip() {
492 let mut order = Order::new_bid(1, TEST_MAKER, TEST_BOOK_KEY, 1000, 5);
493
494 order.fill(1000).unwrap();
495 let result = order.create_flipped_order(2);
496 assert!(matches!(result, Err(OrderError::NotAFlipOrder)));
497 }
498
499 #[test]
500 fn test_create_flipped_order_not_filled() {
501 let order = Order::new_flip(1, TEST_MAKER, TEST_BOOK_KEY, 1000, 5, true, 10).unwrap();
502
503 let result = order.create_flipped_order(2);
504 assert!(matches!(
505 result,
506 Err(OrderError::OrderNotFullyFilled { .. })
507 ));
508 }
509
510 #[test]
511 fn test_multiple_fills() {
512 let mut order = Order::new_bid(1, TEST_MAKER, TEST_BOOK_KEY, 1000, 5);
513
514 order.fill(300).unwrap();
516 assert_eq!(order.remaining(), 700);
517
518 order.fill(200).unwrap();
519 assert_eq!(order.remaining(), 500);
520
521 order.fill(500).unwrap();
522 assert_eq!(order.remaining(), 0);
523 assert!(order.is_fully_filled());
524 }
525
526 #[test]
527 fn test_multiple_flips() {
528 let mut order = Order::new_flip(1, TEST_MAKER, TEST_BOOK_KEY, 1000, 5, true, 10).unwrap();
530
531 order.fill(1000).unwrap();
533 let mut flipped1 = order.create_flipped_order(2).unwrap();
534
535 assert!(!flipped1.is_bid());
536 assert!(flipped1.is_ask());
537 assert_eq!(flipped1.tick(), 10);
538 assert_eq!(flipped1.flip_tick(), 5);
539
540 flipped1.fill(1000).unwrap();
542 let flipped2 = flipped1.create_flipped_order(3).unwrap();
543
544 assert!(flipped2.is_bid());
545 assert!(!flipped2.is_ask());
546 assert_eq!(flipped2.tick(), 5);
547 assert_eq!(flipped2.flip_tick(), 10);
548 }
549
550 #[test]
551 fn test_tick_price_encoding() {
552 let order_above = Order::new_bid(1, TEST_MAKER, TEST_BOOK_KEY, 1000, 2);
555 assert_eq!(order_above.tick(), 2);
556
557 let order_below = Order::new_ask(2, TEST_MAKER, TEST_BOOK_KEY, 1000, -2);
558 assert_eq!(order_below.tick(), -2);
559
560 let order_par = Order::new_bid(3, TEST_MAKER, TEST_BOOK_KEY, 1000, 0);
561 assert_eq!(order_par.tick(), 0);
562 }
563
564 #[test]
565 fn test_linked_list_pointers_initialization() {
566 let order = Order::new_bid(1, TEST_MAKER, TEST_BOOK_KEY, 1000, 5);
567 assert_eq!(order.prev(), 0);
569 assert_eq!(order.next(), 0);
570 }
571
572 #[test]
573 fn test_set_linked_list_pointers() {
574 let mut order = Order::new_bid(1, TEST_MAKER, TEST_BOOK_KEY, 1000, 5);
575
576 order.set_prev(42);
578 order.set_next(43);
579
580 assert_eq!(order.prev(), 42);
581 assert_eq!(order.next(), 43);
582 }
583
584 #[test]
585 fn test_flipped_order_resets_linked_list_pointers() {
586 let mut order = Order::new_flip(1, TEST_MAKER, TEST_BOOK_KEY, 1000, 5, true, 10).unwrap();
587
588 order.set_prev(100);
590 order.set_next(200);
591
592 order.fill(1000).unwrap();
594
595 let flipped = order.create_flipped_order(2).unwrap();
597
598 assert_eq!(flipped.prev(), 0);
600 assert_eq!(flipped.next(), 0);
601 }
602
603 #[test]
604 fn test_store_order() -> eyre::Result<()> {
605 let mut storage = HashMapStorageProvider::new(1);
606 let mut exchange = StablecoinExchange::new(&mut storage);
607
608 let id = 42;
609 let order = Order::new_flip(id, TEST_MAKER, TEST_BOOK_KEY, 1000, 5, true, 10).unwrap();
610 exchange.sstore_orders(id, order)?;
611
612 let loaded_order = exchange.sload_orders(id)?;
613 assert_eq!(loaded_order.order_id(), 42);
614 assert_eq!(loaded_order.maker(), TEST_MAKER);
615 assert_eq!(loaded_order.book_key(), TEST_BOOK_KEY);
616 assert_eq!(loaded_order.amount(), 1000);
617 assert_eq!(loaded_order.remaining(), 1000);
618 assert_eq!(loaded_order.tick(), 5);
619 assert!(loaded_order.is_bid());
620 assert!(loaded_order.is_flip());
621 assert_eq!(loaded_order.flip_tick(), 10);
622 assert_eq!(loaded_order.prev(), 0);
623 assert_eq!(loaded_order.next(), 0);
624
625 Ok(())
626 }
627
628 #[test]
629 fn test_delete_order() -> eyre::Result<()> {
630 let mut storage = HashMapStorageProvider::new(1);
631 let mut exchange = StablecoinExchange::new(&mut storage);
632
633 let id = 42;
634 let order = Order::new_flip(id, TEST_MAKER, TEST_BOOK_KEY, 1000, 5, true, 10).unwrap();
635 exchange.sstore_orders(id, order)?;
636 exchange.clear_orders(id)?;
637
638 let deleted_order = exchange.sload_orders(id)?;
639 assert_eq!(deleted_order.order_id(), 0);
640 assert_eq!(deleted_order.maker(), Address::ZERO);
641 assert_eq!(deleted_order.book_key(), B256::ZERO);
642 assert_eq!(deleted_order.amount(), 0);
643 assert_eq!(deleted_order.remaining(), 0);
644 assert_eq!(deleted_order.tick(), 0);
645 assert!(!deleted_order.is_bid());
646 assert!(!deleted_order.is_flip());
647 assert_eq!(deleted_order.flip_tick(), 0);
648 assert_eq!(deleted_order.prev(), 0);
649 assert_eq!(deleted_order.next(), 0);
650
651 Ok(())
652 }
653}