1use alloy::primitives::{U256, keccak256};
4use std::marker::PhantomData;
5
6use crate::storage::{Layout, Slot, Storable, StorableType, StorageKey};
7
8#[derive(Debug, Clone, Copy)]
43pub struct Mapping<K, V> {
44 base_slot: U256,
45 _phantom: PhantomData<(K, V)>,
46}
47
48impl<K, V> Mapping<K, V> {
49 #[inline]
53 pub const fn new(base_slot: U256) -> Self {
54 Self {
55 base_slot,
56 _phantom: PhantomData,
57 }
58 }
59
60 #[inline]
62 pub const fn slot(&self) -> U256 {
63 self.base_slot
64 }
65
66 pub fn at<const N: usize>(&self, key: K) -> Slot<V>
72 where
73 K: StorageKey,
74 V: Storable<N>,
75 {
76 Slot::new(mapping_slot(key.as_storage_bytes(), self.base_slot))
77 }
78
79 #[inline]
84 pub fn at_offset<const N: usize>(
85 struct_base_slot: U256,
86 field_offset_slots: usize,
87 key: K,
88 ) -> Slot<V>
89 where
90 K: StorageKey,
91 V: Storable<N>,
92 {
93 let field_slot = struct_base_slot + U256::from(field_offset_slots);
94 Slot::new(mapping_slot(key.as_storage_bytes(), field_slot))
95 }
96}
97
98#[derive(Debug, Clone, Copy)]
137pub struct NestedMapping<K1, K2, V> {
138 _inner: Mapping<K1, Mapping<K2, V>>,
139}
140
141impl<K1, K2, V> NestedMapping<K1, K2, V> {
142 #[inline]
146 pub const fn new(base_slot: U256) -> Self {
147 Self {
148 _inner: Mapping::new(base_slot),
149 }
150 }
151
152 #[inline]
154 pub const fn slot(&self) -> U256 {
155 self._inner.slot()
156 }
157
158 #[inline]
160 pub fn at(&self, key1: K1) -> Mapping<K2, V>
161 where
162 K1: StorageKey,
163 {
164 let intermediate_slot = mapping_slot(key1.as_storage_bytes(), self._inner.base_slot);
165 Mapping::new(intermediate_slot)
166 }
167}
168
169impl<K, V> Default for Mapping<K, V> {
170 fn default() -> Self {
171 Self::new(U256::ZERO)
172 }
173}
174
175impl<K1, K2, V> Default for NestedMapping<K1, K2, V> {
176 fn default() -> Self {
177 Self::new(U256::ZERO)
178 }
179}
180
181impl<K, V> StorableType for Mapping<K, V> {
186 const LAYOUT: Layout = Layout::Slots(1);
187}
188
189impl<K1, K2, V> StorableType for NestedMapping<K1, K2, V> {
194 const LAYOUT: Layout = Layout::Slots(1);
195}
196
197fn left_pad_to_32(data: &[u8]) -> [u8; 32] {
200 let mut buf = [0u8; 32];
201 buf[32 - data.len()..].copy_from_slice(data);
202 buf
203}
204
205#[inline]
207pub fn mapping_slot<T: AsRef<[u8]>>(key: T, mapping_slot: U256) -> U256 {
208 let mut buf = [0u8; 64];
209 buf[..32].copy_from_slice(&left_pad_to_32(key.as_ref()));
210 buf[32..].copy_from_slice(&mapping_slot.to_be_bytes::<32>());
211 U256::from_be_bytes(keccak256(buf).0)
212}
213
214#[inline]
216pub fn double_mapping_slot<T: AsRef<[u8]>, U: AsRef<[u8]>>(
217 key1: T,
218 key2: U,
219 base_slot: U256,
220) -> U256 {
221 let intermediate_slot = mapping_slot(key1, base_slot);
222 let mut buf = [0u8; 64];
223 buf[..32].copy_from_slice(&left_pad_to_32(key2.as_ref()));
224 buf[32..].copy_from_slice(&intermediate_slot.to_be_bytes::<32>());
225 U256::from_be_bytes(keccak256(buf).0)
226}
227
228#[cfg(test)]
229mod tests {
230 use super::*;
231 use crate::{
232 error::Result,
233 storage::{PrecompileStorageProvider, StorageOps, hashmap::HashMapStorageProvider},
234 };
235 use alloy::primitives::{Address, B256, address};
236 use proptest::prelude::*;
237
238 struct TestContract<'a, S> {
240 address: Address,
241 storage: &'a mut S,
242 }
243
244 impl<'a, S: PrecompileStorageProvider> StorageOps for TestContract<'a, S> {
245 fn sstore(&mut self, slot: U256, value: U256) -> Result<()> {
246 self.storage.sstore(self.address, slot, value)
247 }
248
249 fn sload(&mut self, slot: U256) -> Result<U256> {
250 self.storage.sload(self.address, slot)
251 }
252 }
253
254 fn setup_test_contract<'a>(
256 storage: &'a mut HashMapStorageProvider,
257 ) -> TestContract<'a, HashMapStorageProvider> {
258 TestContract {
259 address: Address::random(),
260 storage,
261 }
262 }
263
264 const TEST_SLOT_0: U256 = U256::ZERO;
266 const TEST_SLOT_1: U256 = U256::from_limbs([1, 0, 0, 0]);
267 const TEST_SLOT_2: U256 = U256::from_limbs([2, 0, 0, 0]);
268 const TEST_SLOT_MAX: U256 = U256::MAX;
269
270 fn arb_address() -> impl Strategy<Value = Address> {
272 any::<[u8; 20]>().prop_map(Address::from)
273 }
274
275 fn arb_u256() -> impl Strategy<Value = U256> {
276 any::<[u64; 4]>().prop_map(U256::from_limbs)
277 }
278
279 #[test]
280 fn test_mapping_slot_deterministic() {
281 let key: B256 = U256::from(123).into();
282 let slot1 = mapping_slot(key, U256::ZERO);
283 let slot2 = mapping_slot(key, U256::ZERO);
284
285 assert_eq!(slot1, slot2);
286 }
287
288 #[test]
289 fn test_different_keys_different_slots() {
290 let key1: B256 = U256::from(123).into();
291 let key2: B256 = U256::from(456).into();
292
293 let slot1 = mapping_slot(key1, U256::ZERO);
294 let slot2 = mapping_slot(key2, U256::ZERO);
295
296 assert_ne!(slot1, slot2);
297 }
298
299 #[test]
300 fn test_tip20_balance_slots() {
301 let alice = address!("0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266");
303 let bob = address!("0x70997970C51812dc3A010C7d01b50e0d17dc79C8");
304
305 let alice_balance_slot = mapping_slot(alice, U256::from(10));
306 let bob_balance_slot = mapping_slot(bob, U256::from(10));
307
308 println!("Alice balance slot: 0x{alice_balance_slot:064x}");
309 println!("Bob balance slot: 0x{bob_balance_slot:064x}");
310
311 assert_ne!(alice_balance_slot, bob_balance_slot);
313 }
314
315 #[test]
316 fn test_tip20_allowance_slots() {
317 let alice = address!("0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266");
319 let tip_fee_mgr = address!("0xfeec000000000000000000000000000000000000");
320
321 let allowances = NestedMapping::<Address, Address, U256>::new(U256::from(11));
322 let allowance_slot = allowances.at(alice).at(tip_fee_mgr).slot();
323
324 println!("Alice->TipFeeManager allowance slot: 0x{allowance_slot:064x}");
325
326 let allowance_slot2 = allowances.at(alice).at(tip_fee_mgr).slot();
328 assert_eq!(allowance_slot, allowance_slot2);
329 }
330
331 #[test]
332 fn test_double_mapping_different_keys() {
333 let alice = address!("0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266");
334 let bob = address!("0x70997970C51812dc3A010C7d01b50e0d17dc79C8");
335 let spender = address!("0xfeec000000000000000000000000000000000000");
336
337 let allowances = NestedMapping::<Address, Address, U256>::new(U256::from(11));
338 let alice_allowance = allowances.at(alice).at(spender).slot();
339 let bob_allowance = allowances.at(bob).at(spender).slot();
340
341 assert_ne!(alice_allowance, bob_allowance);
342 }
343
344 #[test]
345 fn test_left_padding_correctness() {
346 let addr = address!("0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266");
347 let bytes: &[u8] = addr.as_ref();
348 let padded = left_pad_to_32(bytes);
349
350 assert_eq!(&padded[..12], &[0u8; 12]);
352 assert_eq!(&padded[12..], bytes);
354 }
355
356 #[test]
357 fn test_mapping_slot_encoding() {
358 let key = address!("0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266");
359 let base_slot = U256::from(10);
360
361 let mut buf = [0u8; 64];
363 buf[12..32].copy_from_slice(key.as_ref());
365 buf[32..].copy_from_slice(&base_slot.to_be_bytes::<32>());
367
368 let expected = U256::from_be_bytes(keccak256(buf).0);
369 let computed = mapping_slot(key, base_slot);
370
371 assert_eq!(computed, expected, "mapping_slot encoding mismatch");
372 }
373
374 #[test]
375 fn test_double_mapping_account_role() {
376 let account = address!("0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266");
377 let role: B256 = U256::ONE.into();
378 let base_slot = U256::ONE;
379
380 let roles = NestedMapping::<Address, B256, U256>::new(base_slot);
381 let slot = roles.at(account).at(role).slot();
382
383 let slot2 = roles.at(account).at(role).slot();
385 assert_eq!(slot, slot2);
386
387 let different_role: B256 = U256::from(2).into();
389 let different_slot = roles.at(account).at(different_role).slot();
390 assert_ne!(slot, different_slot);
391 }
392
393 #[test]
394 fn test_mapping_size() {
395 assert_eq!(std::mem::size_of::<Mapping<Address, U256>>(), 32);
397 assert_eq!(std::mem::size_of::<Mapping<U256, Address>>(), 32);
398 assert_eq!(
400 std::mem::size_of::<Mapping<Address, Mapping<Address, U256>>>(),
401 32
402 );
403 }
404
405 #[test]
406 fn test_mapping_creation() {
407 let _simple: Mapping<Address, U256> = Mapping::new(U256::ZERO);
408 let _another: Mapping<U256, bool> = Mapping::new(U256::ONE);
409 }
410
411 #[test]
412 fn test_mapping_slot_extraction() {
413 assert_eq!(Mapping::<Address, U256>::new(U256::ONE).slot(), U256::ONE);
414 assert_eq!(
415 Mapping::<U256, Address>::new(U256::from(2)).slot(),
416 U256::from(2)
417 );
418
419 assert_eq!(Mapping::<Address, U256>::new(U256::MAX).slot(), U256::MAX);
421 }
422
423 #[test]
424 fn test_mapping_edge_case_zero() {
425 assert_eq!(Mapping::<Address, U256>::new(U256::ZERO).slot(), U256::ZERO);
427
428 let mut storage = HashMapStorageProvider::new(1);
429 let mut contract = setup_test_contract(&mut storage);
430 let user = Address::random();
431
432 let zero_mapping = Mapping::<Address, U256>::new(U256::ZERO);
433 let value = U256::from(1000u64);
434
435 _ = zero_mapping.at(user).write(&mut contract, value);
436 let loaded = zero_mapping.at(user).read(&mut contract).unwrap();
437 assert_eq!(loaded, value);
438 }
439
440 #[test]
441 fn test_mapping_edge_case_max() {
442 let max_mapping = Mapping::<Address, U256>::new(U256::MAX);
444 assert_eq!(max_mapping.slot(), U256::MAX);
445
446 let mut storage = HashMapStorageProvider::new(1);
447 let mut contract = setup_test_contract(&mut storage);
448 let user = Address::random();
449
450 let value = U256::from(999u64);
451 _ = max_mapping.at(user).write(&mut contract, value);
452 let loaded = max_mapping.at(user).read(&mut contract).unwrap();
453 assert_eq!(loaded, value);
454 }
455
456 #[test]
457 fn test_mapping_read_write_balances() {
458 let mut storage = HashMapStorageProvider::new(1);
459 let mut contract = setup_test_contract(&mut storage);
460 let user1 = Address::random();
461 let user2 = Address::random();
462
463 let named_mapping = Mapping::<Address, U256>::new(TEST_SLOT_1);
464
465 let balance1 = U256::from(1000u64);
466 let balance2 = U256::from(2000u64);
467
468 _ = named_mapping.at(user1).write(&mut contract, balance1);
470 _ = named_mapping.at(user2).write(&mut contract, balance2);
471
472 let loaded1 = named_mapping.at(user1).read(&mut contract).unwrap();
474 let loaded2 = named_mapping.at(user2).read(&mut contract).unwrap();
475
476 assert_eq!(loaded1, balance1);
477 assert_eq!(loaded2, balance2);
478 }
479
480 #[test]
481 fn test_mapping_read_default_is_zero() {
482 let mut storage = HashMapStorageProvider::new(1);
483 let mut contract = setup_test_contract(&mut storage);
484 let user = Address::random();
485
486 let named_mapping = Mapping::<Address, U256>::new(TEST_SLOT_1);
487
488 let balance = named_mapping.at(user).read(&mut contract).unwrap();
490 assert_eq!(balance, U256::ZERO);
491 }
492
493 #[test]
494 fn test_mapping_overwrite() {
495 let mut storage = HashMapStorageProvider::new(1);
496 let mut contract = setup_test_contract(&mut storage);
497 let user = Address::random();
498
499 let named_mapping = Mapping::<Address, U256>::new(TEST_SLOT_1);
500
501 _ = named_mapping.at(user).write(&mut contract, U256::from(100));
503 assert_eq!(
504 named_mapping.at(user).read(&mut contract),
505 Ok(U256::from(100))
506 );
507
508 _ = named_mapping.at(user).write(&mut contract, U256::from(200));
510 assert_eq!(
511 named_mapping.at(user).read(&mut contract),
512 Ok(U256::from(200))
513 );
514 }
515
516 #[test]
517 fn test_nested_mapping_read_write_allowances() {
518 let mut storage = HashMapStorageProvider::new(1);
519 let mut contract = setup_test_contract(&mut storage);
520 let owner = Address::random();
521 let spender1 = Address::random();
522 let spender2 = Address::random();
523
524 let nested_mapping = NestedMapping::<Address, Address, U256>::new(TEST_SLOT_1);
526
527 let allowance1 = U256::from(500u64);
528 let allowance2 = U256::from(1500u64);
529
530 _ = nested_mapping
532 .at(owner)
533 .at(spender1)
534 .write(&mut contract, allowance1);
535 _ = nested_mapping
536 .at(owner)
537 .at(spender2)
538 .write(&mut contract, allowance2);
539
540 let loaded1 = nested_mapping
542 .at(owner)
543 .at(spender1)
544 .read(&mut contract)
545 .unwrap();
546 let loaded2 = nested_mapping
547 .at(owner)
548 .at(spender2)
549 .read(&mut contract)
550 .unwrap();
551
552 assert_eq!(loaded1, allowance1);
553 assert_eq!(loaded2, allowance2);
554 }
555
556 #[test]
557 fn test_nested_mapping_default_is_zero() {
558 let mut storage = HashMapStorageProvider::new(1);
559 let mut contract = setup_test_contract(&mut storage);
560 let owner = Address::random();
561 let spender = Address::random();
562
563 let nested_mapping = NestedMapping::<Address, Address, U256>::new(TEST_SLOT_1);
564
565 let allowance = nested_mapping
567 .at(owner)
568 .at(spender)
569 .read(&mut contract)
570 .unwrap();
571 assert_eq!(allowance, U256::ZERO);
572 }
573
574 #[test]
575 fn test_nested_mapping_independence() {
576 let mut storage = HashMapStorageProvider::new(1);
577 let mut contract = setup_test_contract(&mut storage);
578 let owner1 = Address::random();
579 let owner2 = Address::random();
580 let spender = Address::random();
581
582 let nested_mapping = NestedMapping::<Address, Address, U256>::new(TEST_SLOT_1);
583
584 _ = nested_mapping
586 .at(owner1)
587 .at(spender)
588 .write(&mut contract, U256::from(100));
589
590 let allowance2 = nested_mapping
592 .at(owner2)
593 .at(spender)
594 .read(&mut contract)
595 .unwrap();
596 assert_eq!(allowance2, U256::ZERO);
597
598 let allowance1 = nested_mapping
600 .at(owner1)
601 .at(spender)
602 .read(&mut contract)
603 .unwrap();
604 assert_eq!(allowance1, U256::from(100));
605 }
606
607 #[test]
608 fn test_mapping_with_different_key_types() {
609 let mut storage = HashMapStorageProvider::new(1);
610 let mut contract = setup_test_contract(&mut storage);
611
612 let nonces_mapping = Mapping::<Address, U256>::new(TEST_SLOT_2);
614 let user = Address::random();
615 let nonce = U256::from(42);
616
617 _ = nonces_mapping.at(user).write(&mut contract, nonce);
618 let loaded_nonce = nonces_mapping.at(user).read(&mut contract).unwrap();
619 assert_eq!(loaded_nonce, nonce);
620
621 let flags_mapping = Mapping::<Address, bool>::new(TEST_SLOT_MAX);
623 _ = flags_mapping.at(user).write(&mut contract, true);
624 let loaded_flag = flags_mapping.at(user).read(&mut contract).unwrap();
625 assert!(loaded_flag);
626 }
627
628 proptest! {
629 #![proptest_config(ProptestConfig::with_cases(500))]
630
631 #[test]
632 fn proptest_mapping_read_write(
633 key in arb_address(),
634 value in arb_u256()
635 ) {
636 let mut storage = HashMapStorageProvider::new(1);
637 let mut contract = setup_test_contract(&mut storage);
638
639 let test_mapping = Mapping::<Address, U256>::new(TEST_SLOT_0);
641
642 test_mapping.at(key).write(&mut contract, value)?;
644 let loaded = test_mapping.at(key).read(&mut contract)?;
645 prop_assert_eq!(loaded, value, "roundtrip failed");
646
647 test_mapping.at(key).delete(&mut contract)?;
649 let after_delete = test_mapping.at(key).read(&mut contract)?;
650 prop_assert_eq!(after_delete, U256::ZERO, "not zero after delete");
651 }
652
653 #[test]
654 fn proptest_mapping_key_isolation(
655 key1 in arb_address(),
656 key2 in arb_address(),
657 value1 in arb_u256(),
658 value2 in arb_u256()
659 ) {
660 prop_assume!(key1 != key2);
662
663 let mut storage = HashMapStorageProvider::new(1);
664 let mut contract = setup_test_contract(&mut storage);
665
666 let test_mapping = Mapping::<Address, U256>::new(TEST_SLOT_0);
667
668 test_mapping.at(key1).write(&mut contract, value1)?;
670 test_mapping.at(key2).write(&mut contract, value2)?;
671
672 let loaded1 = test_mapping.at(key1).read(&mut contract)?;
674 let loaded2 = test_mapping.at(key2).read(&mut contract)?;
675
676 prop_assert_eq!(loaded1, value1, "key1 value changed");
677 prop_assert_eq!(loaded2, value2, "key2 value changed");
678
679 test_mapping.at(key1).delete(&mut contract)?;
681 let after_delete1 = test_mapping.at(key1).read(&mut contract)?;
682 let after_delete2 = test_mapping.at(key2).read(&mut contract)?;
683
684 prop_assert_eq!(after_delete1, U256::ZERO, "key1 not deleted");
685 prop_assert_eq!(after_delete2, value2, "key2 affected by key1 delete");
686 }
687
688 #[test]
689 fn proptest_nested_mapping_isolation(
690 owner1 in arb_address(),
691 owner2 in arb_address(),
692 spender in arb_address(),
693 allowance1 in arb_u256(),
694 allowance2 in arb_u256()
695 ) {
696 prop_assume!(owner1 != owner2);
698
699 let mut storage = HashMapStorageProvider::new(1);
700 let mut contract = setup_test_contract(&mut storage);
701
702 let nested_mapping = NestedMapping::<Address, Address, U256>::new(TEST_SLOT_1);
703
704 nested_mapping.at(owner1).at(spender).write(&mut contract, allowance1)?;
706 nested_mapping.at(owner2).at(spender).write(&mut contract, allowance2)?;
707
708 let loaded1 = nested_mapping.at(owner1).at(spender).read(&mut contract)?;
710 let loaded2 = nested_mapping.at(owner2).at(spender).read(&mut contract)?;
711
712 prop_assert_eq!(loaded1, allowance1, "owner1 allowance changed");
713 prop_assert_eq!(loaded2, allowance2, "owner2 allowance changed");
714
715 nested_mapping.at(owner1).at(spender).delete(&mut contract)?;
717 let after_delete1 = nested_mapping.at(owner1).at(spender).read(&mut contract)?;
718 let after_delete2 = nested_mapping.at(owner2).at(spender).read(&mut contract)?;
719
720 prop_assert_eq!(after_delete1, U256::ZERO, "owner1 allowance not deleted");
721 prop_assert_eq!(after_delete2, allowance2, "owner2 allowance affected");
722 }
723 }
724
725 #[test]
728 fn test_mapping_at_offset() -> eyre::Result<()> {
729 let mut storage = HashMapStorageProvider::new(1);
730 let mut contract = setup_test_contract(&mut storage);
731
732 let pair_key: B256 = U256::from(0x1234).into();
735 let orderbook_base_slot = mapping_slot(pair_key, TEST_SLOT_1);
736
737 let tick: i16 = 100;
739 let bid_value = U256::from(500);
740
741 Mapping::<i16, U256>::at_offset(
743 orderbook_base_slot,
744 1, tick,
746 )
747 .write(&mut contract, bid_value)?;
748
749 let read_value =
751 Mapping::<i16, U256>::at_offset(orderbook_base_slot, 1, tick).read(&mut contract)?;
752
753 assert_eq!(read_value, bid_value);
754
755 Mapping::<i16, U256>::at_offset(orderbook_base_slot, 1, tick).delete(&mut contract)?;
757
758 let deleted_value =
759 Mapping::<i16, U256>::at_offset(orderbook_base_slot, 1, tick).read(&mut contract)?;
760
761 assert_eq!(deleted_value, U256::ZERO);
762
763 Ok(())
764 }
765
766 #[test]
767 fn test_nested_mapping_at_offset() -> eyre::Result<()> {
768 let mut storage = HashMapStorageProvider::new(1);
769 let mut contract = setup_test_contract(&mut storage);
770
771 let struct_key: B256 = U256::from(0xabcd).into();
773 let struct_base_slot = mapping_slot(struct_key, TEST_SLOT_2);
774
775 let owner = Address::random();
776 let spender = Address::random();
777 let allowance = U256::from(1000);
778
779 let field_slot = struct_base_slot + U256::from(3); let nested_mapping = NestedMapping::<Address, Address, U256>::new(field_slot);
782 nested_mapping
783 .at(owner)
784 .at(spender)
785 .write(&mut contract, allowance)?;
786
787 let read_allowance = nested_mapping.at(owner).at(spender).read(&mut contract)?;
789
790 assert_eq!(read_allowance, allowance);
791
792 nested_mapping.at(owner).at(spender).delete(&mut contract)?;
794
795 let deleted = nested_mapping.at(owner).at(spender).read(&mut contract)?;
796
797 assert_eq!(deleted, U256::ZERO);
798
799 Ok(())
800 }
801
802 #[test]
803 fn test_multiple_fields_at_different_offsets() -> eyre::Result<()> {
804 let mut storage = HashMapStorageProvider::new(1);
805 let mut contract = setup_test_contract(&mut storage);
806
807 let pair_key: B256 = U256::from(0x5678).into();
809 let orderbook_base = mapping_slot(pair_key, TEST_SLOT_0);
810
811 let tick1: i16 = 50;
813 let bid1 = U256::from(100);
814 Mapping::<i16, U256>::at_offset(orderbook_base, 1, tick1).write(&mut contract, bid1)?;
815
816 let tick2: i16 = -25;
818 let ask1 = U256::from(200);
819 Mapping::<i16, U256>::at_offset(orderbook_base, 2, tick2).write(&mut contract, ask1)?;
820
821 let bitmap_key: i16 = 10;
823 let bitmap_value = U256::from(0xff);
824 Mapping::<i16, U256>::at_offset(orderbook_base, 3, bitmap_key)
825 .write(&mut contract, bitmap_value)?;
826
827 let read_bid =
829 Mapping::<i16, U256>::at_offset(orderbook_base, 1, tick1).read(&mut contract)?;
830 let read_ask =
831 Mapping::<i16, U256>::at_offset(orderbook_base, 2, tick2).read(&mut contract)?;
832 let read_bitmap =
833 Mapping::<i16, U256>::at_offset(orderbook_base, 3, bitmap_key).read(&mut contract)?;
834
835 assert_eq!(read_bid, bid1);
836 assert_eq!(read_ask, ask1);
837 assert_eq!(read_bitmap, bitmap_value);
838
839 Ok(())
840 }
841}