Skip to main content

tempo_precompiles/storage/types/
vec.rs

1//! Dynamic array (`Vec<T>`) implementation for the storage traits.
2//!
3//! # Storage Layout
4//!
5//! Vec uses Solidity-compatible dynamic array storage:
6//! - **Base slot**: Stores the array length (number of elements)
7//! - **Data slots**: Start at `keccak256(len_slot)`, elements packed efficiently
8//!
9//! ## Multi-Slot Support
10//!
11//! - Supports both single-slot primitives and multi-slot types (structs, arrays)
12//! - Element at index `i` starts at slot `data_start + i * T::SLOTS`
13
14use alloy::primitives::{Address, U256};
15use std::ops::{Index, IndexMut};
16
17use crate::{
18    error::{Result, TempoPrecompileError},
19    storage::{
20        Handler, Layout, LayoutCtx, Storable, StorableType, StorageOps,
21        packing::{PackedSlot, calc_element_loc, calc_packed_slot_count},
22        types::{HandlerCache, Slot},
23    },
24};
25
26impl<T> StorableType for Vec<T>
27where
28    T: Storable,
29{
30    /// Vec base slot occupies one full storage slot (stores length).
31    const LAYOUT: Layout = Layout::Slots(1);
32    const IS_DYNAMIC: bool = true;
33    type Handler = VecHandler<T>;
34
35    fn handle(slot: U256, _ctx: LayoutCtx, address: Address) -> Self::Handler {
36        VecHandler::new(slot, address)
37    }
38}
39
40impl<T> Storable for Vec<T>
41where
42    T: Storable,
43{
44    fn load<S: StorageOps>(storage: &S, len_slot: U256, ctx: LayoutCtx) -> Result<Self> {
45        debug_assert_eq!(ctx, LayoutCtx::FULL, "Dynamic arrays cannot be packed");
46
47        // Read length from base slot
48        let length_value = storage.load(len_slot)?;
49        let length = length_value.to::<usize>();
50
51        if length == 0 {
52            return Ok(Self::new());
53        }
54
55        // Pack elements if necessary. Vec elements can't be split across slots.
56        let data_start = calc_data_slot(len_slot);
57        if T::BYTES <= 16 {
58            load_packed_elements(storage, data_start, length, T::BYTES)
59        } else {
60            load_unpacked_elements(storage, data_start, length)
61        }
62    }
63
64    fn store<S: StorageOps>(&self, storage: &mut S, len_slot: U256, ctx: LayoutCtx) -> Result<()> {
65        debug_assert_eq!(ctx, LayoutCtx::FULL, "Dynamic arrays cannot be packed");
66
67        // Write length to base slot
68        storage.store(len_slot, U256::from(self.len()))?;
69
70        if self.is_empty() {
71            return Ok(());
72        }
73
74        // Pack elements if necessary. Vec elements can't be split across slots.
75        let data_start = calc_data_slot(len_slot);
76        if T::BYTES <= 16 {
77            store_packed_elements(self, storage, data_start, T::BYTES)
78        } else {
79            store_unpacked_elements(self, storage, data_start)
80        }
81    }
82
83    /// Custom delete for Vec: clears both length slot and all data slots.
84    fn delete<S: StorageOps>(storage: &mut S, len_slot: U256, ctx: LayoutCtx) -> Result<()> {
85        debug_assert_eq!(ctx, LayoutCtx::FULL, "Dynamic arrays cannot be packed");
86
87        // Read length from base slot to determine how many slots to clear
88        let length_value = storage.load(len_slot)?;
89        let length = length_value.to::<usize>();
90
91        // Clear base slot (length)
92        storage.store(len_slot, U256::ZERO)?;
93
94        if length == 0 {
95            return Ok(());
96        }
97
98        let data_start = calc_data_slot(len_slot);
99        if T::BYTES <= 16 {
100            // Clear packed element slots. Vec elements can't be split across slots.
101            let slot_count = calc_packed_slot_count(length, T::BYTES);
102            for slot_idx in 0..slot_count {
103                storage.store(data_start + U256::from(slot_idx), U256::ZERO)?;
104            }
105        } else {
106            // Clear unpacked element slots (multi-slot aware)
107            for elem_idx in 0..length {
108                let elem_slot = data_start + U256::from(elem_idx * T::SLOTS);
109                T::delete(storage, elem_slot, LayoutCtx::FULL)?;
110            }
111        }
112
113        Ok(())
114    }
115}
116
117/// Type-safe handler for accessing `Vec<T>` in storage.
118///
119/// Provides both full-vector operations (read/write/delete) and individual element access.
120/// The handler is a thin wrapper around a storage slot number and delegates full-vector
121/// operations to `Slot<Vec<T>>`.
122///
123/// # Element Access
124///
125/// Use `at(index)` to get a `Slot<T>` for individual element operations with OOB guarantees.
126/// Use `[index]` for its efficient counterpart without the check.
127/// - For packed elements (T::BYTES ≤ 16): returns a packed `Slot<T>` with byte offsets
128/// - For unpacked elements: returns a full `Slot<T>` for the element's dedicated slot
129///
130/// # Example
131///
132/// ```ignore
133/// let handler = <Vec<u8> as StorableType>::handle(len_slot, LayoutCtx::FULL);
134///
135/// // Full vector operations
136/// let vec = handler.read()?;
137/// handler.write(&mut storage, vec![1, 2, 3])?;
138///
139/// // Individual element operations
140/// if let Some(slot) = handler[0]? {
141///     let elem = slot.read()?;
142///     slot.write(42)?;
143/// }
144/// ```
145///
146/// # Capacity
147///
148/// Vectors have a maximum capacity of `u32::MAX / element_size` to prevent
149/// arithmetic overflow in storage slot calculations.
150#[derive(Debug, Clone)]
151pub struct VecHandler<T: Storable> {
152    len_slot: U256,
153    address: Address,
154    cache: HandlerCache<usize, T::Handler>,
155}
156
157impl<T> Handler<Vec<T>> for VecHandler<T>
158where
159    T: Storable,
160{
161    /// Reads the entire vector from storage.
162    #[inline]
163    fn read(&self) -> Result<Vec<T>> {
164        self.as_slot().read()
165    }
166
167    /// Writes the entire vector to storage.
168    #[inline]
169    fn write(&mut self, value: Vec<T>) -> Result<()> {
170        self.as_slot().write(value)
171    }
172
173    /// Deletes the entire vector from storage (clears length and all elements).
174    #[inline]
175    fn delete(&mut self) -> Result<()> {
176        self.as_slot().delete()
177    }
178
179    /// Reads the entire vector from transient storage.
180    #[inline]
181    fn t_read(&self) -> Result<Vec<T>> {
182        self.as_slot().t_read()
183    }
184
185    /// Writes the entire vector to transient storage.
186    #[inline]
187    fn t_write(&mut self, value: Vec<T>) -> Result<()> {
188        self.as_slot().t_write(value)
189    }
190
191    /// Deletes the entire vector from transient storage.
192    #[inline]
193    fn t_delete(&mut self) -> Result<()> {
194        self.as_slot().t_delete()
195    }
196}
197
198impl<T> VecHandler<T>
199where
200    T: Storable,
201{
202    /// Creates a new handler for the vector at the given base slot and address.
203    #[inline]
204    pub fn new(len_slot: U256, address: Address) -> Self {
205        Self {
206            len_slot,
207            address,
208            cache: HandlerCache::new(),
209        }
210    }
211
212    /// Max valid index to prevent arithmetic overflow in slot calculations.
213    const fn max_index() -> usize {
214        if T::BYTES <= 16 {
215            u32::MAX as usize / T::BYTES
216        } else {
217            u32::MAX as usize / T::SLOTS
218        }
219    }
220
221    /// Returns the slot that stores the length of the dynamic array.
222    #[inline]
223    pub fn len_slot(&self) -> ::alloy::primitives::U256 {
224        self.len_slot
225    }
226
227    /// Returns the base storage slot where this array's data is stored.
228    ///
229    /// Single-slot vectors pack all fields into this slot.
230    /// Multi-slot vectors use consecutive slots starting from this base.
231    #[inline]
232    pub fn data_slot(&self) -> ::alloy::primitives::U256 {
233        calc_data_slot(self.len_slot)
234    }
235
236    /// Returns a `Slot` accessor for full-vector operations.
237    #[inline]
238    fn as_slot(&self) -> Slot<Vec<T>> {
239        Slot::new(self.len_slot, self.address)
240    }
241
242    /// Returns the length of the vector.
243    #[inline]
244    pub fn len(&self) -> Result<usize> {
245        let slot = Slot::<U256>::new(self.len_slot, self.address);
246        Ok(slot.read()?.to::<usize>())
247    }
248
249    /// Returns whether the vector is empty.
250    #[inline]
251    pub fn is_empty(&self) -> Result<bool> {
252        Ok(self.len()? == 0)
253    }
254
255    #[inline]
256    fn compute_handler(data_start: U256, address: Address, index: usize) -> T::Handler {
257        // Pack small elements into shared slots, use T::SLOTS for multi-slot types
258        let (slot, layout_ctx) = if T::BYTES <= 16 {
259            let location = calc_element_loc(index, T::BYTES);
260            (
261                data_start + U256::from(location.offset_slots),
262                LayoutCtx::packed(location.offset_bytes),
263            )
264        } else {
265            (data_start + U256::from(index * T::SLOTS), LayoutCtx::FULL)
266        };
267
268        T::handle(slot, layout_ctx, address)
269    }
270
271    /// Returns a `Handler` for the element at the given index with bounds checking.
272    ///
273    /// The handler is computed on first access and cached for subsequent accesses.
274    ///
275    /// # Returns
276    /// - If the SLOAD to read the length fails, returns an error.
277    /// - If the index is OOB, returns `Ok(None)`.
278    /// - Otherwise, returns `Ok(Some(&T::Handler))`.
279    pub fn at(&self, index: usize) -> Result<Option<&T::Handler>> {
280        if index >= self.len()? {
281            return Ok(None);
282        }
283
284        let (data_start, address) = (self.data_slot(), self.address);
285        Ok(Some(self.cache.get_or_insert(&index, || {
286            Self::compute_handler(data_start, address, index)
287        })))
288    }
289
290    /// Pushes a new element to the end of the vector.
291    ///
292    /// Automatically increments the length and handles packing for small types.
293    ///
294    /// Returns `Err` if the vector has reached its maximum capacity.
295    #[inline]
296    pub fn push(&self, value: T) -> Result<()>
297    where
298        T: Storable,
299        T::Handler: Handler<T>,
300    {
301        // Read current length
302        let length = self.len()?;
303        if length >= Self::max_index() {
304            return Err(TempoPrecompileError::Fatal("Vec is at max capacity".into()));
305        }
306
307        // Write element at the end
308        let mut elem_slot = Self::compute_handler(self.data_slot(), self.address, length);
309        elem_slot.write(value)?;
310
311        // Increment length
312        let mut length_slot = Slot::<U256>::new(self.len_slot, self.address);
313        length_slot.write(U256::from(length + 1))
314    }
315
316    /// Pops the last element from the vector.
317    ///
318    /// Returns `None` if the vector is empty. Automatically decrements the length
319    /// and zeros out the popped element's storage slot.
320    #[inline]
321    pub fn pop(&self) -> Result<Option<T>>
322    where
323        T: Storable,
324        T::Handler: Handler<T>,
325    {
326        // Read current length
327        let length = self.len()?;
328        if length == 0 {
329            return Ok(None);
330        }
331        let last_index = length - 1;
332
333        // Read the last element
334        let mut elem_slot = Self::compute_handler(self.data_slot(), self.address, last_index);
335        let element = elem_slot.read()?;
336
337        // Zero out the element's storage
338        elem_slot.delete()?;
339
340        // Decrement length
341        let mut length_slot = Slot::<U256>::new(self.len_slot, self.address);
342        length_slot.write(U256::from(last_index))?;
343
344        Ok(Some(element))
345    }
346}
347
348impl<T> Index<usize> for VecHandler<T>
349where
350    T: Storable,
351{
352    type Output = T::Handler;
353
354    /// Returns a reference to the cached handler for the given index (unchecked).
355    ///
356    /// **WARNING:** Does not check bounds. Caller must ensure that the index is valid.
357    /// For checked access use `.at(index)` instead.
358    fn index(&self, index: usize) -> &Self::Output {
359        let (data_start, address) = (self.data_slot(), self.address);
360        self.cache
361            .get_or_insert(&index, || Self::compute_handler(data_start, address, index))
362    }
363}
364
365impl<T> IndexMut<usize> for VecHandler<T>
366where
367    T: Storable,
368{
369    /// Returns a mutable reference to the cached handler for the given index (unchecked).
370    ///
371    /// **WARNING:** Does not check bounds. Caller must ensure that the index is valid.
372    /// For checked access use `.at(index)` instead.
373    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
374        let (data_start, address) = (self.data_slot(), self.address);
375        self.cache
376            .get_or_insert_mut(&index, || Self::compute_handler(data_start, address, index))
377    }
378}
379
380/// Calculate the starting slot for dynamic array data.
381///
382/// For Solidity compatibility, dynamic array data is stored at `keccak256(len_slot)`.
383#[inline]
384pub(crate) fn calc_data_slot(len_slot: U256) -> U256 {
385    U256::from_be_bytes(alloy::primitives::keccak256(len_slot.to_be_bytes::<32>()).0)
386}
387
388/// Load packed elements from storage.
389///
390/// Used when `T::BYTES <= 16`, allowing multiple elements per slot.
391fn load_packed_elements<T, S>(
392    storage: &S,
393    data_start: U256,
394    length: usize,
395    byte_count: usize,
396) -> Result<Vec<T>>
397where
398    T: Storable,
399    S: StorageOps,
400{
401    debug_assert!(
402        T::BYTES <= 16,
403        "load_packed_elements requires T::BYTES <= 16"
404    );
405    let elements_per_slot = 32 / byte_count;
406    let slot_count = calc_packed_slot_count(length, byte_count);
407
408    let mut result = Vec::with_capacity(length);
409    let mut current_offset = 0;
410
411    for slot_idx in 0..slot_count {
412        let slot_addr = data_start + U256::from(slot_idx);
413        let slot_value = storage.load(slot_addr)?;
414        let slot_packed = PackedSlot(slot_value);
415
416        // How many elements in this slot?
417        let elements_in_this_slot = if slot_idx == slot_count - 1 {
418            // Last slot might be partially filled
419            length - (slot_idx * elements_per_slot)
420        } else {
421            elements_per_slot
422        };
423
424        // Extract each element from this slot
425        for _ in 0..elements_in_this_slot {
426            let elem = T::load(&slot_packed, slot_addr, LayoutCtx::packed(current_offset))?;
427            result.push(elem);
428
429            // Move to next element position
430            current_offset += byte_count;
431            if current_offset >= 32 {
432                current_offset = 0;
433            }
434        }
435
436        // Reset offset for next slot
437        current_offset = 0;
438    }
439
440    Ok(result)
441}
442
443/// Store packed elements to storage.
444///
445/// Packs multiple small elements into each 32-byte slot using bit manipulation.
446fn store_packed_elements<T, S>(
447    elements: &[T],
448    storage: &mut S,
449    data_start: U256,
450    byte_count: usize,
451) -> Result<()>
452where
453    T: Storable,
454    S: StorageOps,
455{
456    debug_assert!(
457        T::BYTES <= 16,
458        "store_packed_elements requires T::BYTES <= 16"
459    );
460    let elements_per_slot = 32 / byte_count;
461    let slot_count = calc_packed_slot_count(elements.len(), byte_count);
462
463    for slot_idx in 0..slot_count {
464        let slot_addr = data_start + U256::from(slot_idx);
465        let start_elem = slot_idx * elements_per_slot;
466        let end_elem = (start_elem + elements_per_slot).min(elements.len());
467
468        let slot_value = build_packed_slot(&elements[start_elem..end_elem], byte_count)?;
469        storage.store(slot_addr, slot_value)?;
470    }
471
472    Ok(())
473}
474
475/// Build a packed storage slot from multiple elements.
476///
477/// Takes a slice of elements and packs them into a single U256 word.
478fn build_packed_slot<T>(elements: &[T], byte_count: usize) -> Result<U256>
479where
480    T: Storable,
481{
482    debug_assert!(T::BYTES <= 16, "build_packed_slot requires T::BYTES <= 16");
483    let mut slot_value = PackedSlot(U256::ZERO);
484    let mut current_offset = 0;
485
486    for elem in elements {
487        elem.store(
488            &mut slot_value,
489            U256::ZERO,
490            LayoutCtx::packed(current_offset),
491        )?;
492        current_offset += byte_count;
493    }
494
495    Ok(slot_value.0)
496}
497
498/// Load unpacked elements from storage.
499///
500/// Used when elements don't pack efficiently (32 bytes or multi-slot types).
501/// Each element occupies `T::SLOTS` consecutive slots.
502fn load_unpacked_elements<T, S>(storage: &S, data_start: U256, length: usize) -> Result<Vec<T>>
503where
504    T: Storable,
505    S: StorageOps,
506{
507    let mut result = Vec::with_capacity(length);
508    for index in 0..length {
509        // Use T::SLOTS for proper multi-slot element addressing
510        let elem_slot = data_start + U256::from(index * T::SLOTS);
511        let elem = T::load(storage, elem_slot, LayoutCtx::FULL)?;
512        result.push(elem);
513    }
514    Ok(result)
515}
516
517/// Store unpacked elements to storage.
518///
519/// Each element uses `T::SLOTS` consecutive slots.
520fn store_unpacked_elements<T, S>(elements: &[T], storage: &mut S, data_start: U256) -> Result<()>
521where
522    T: Storable,
523    S: StorageOps,
524{
525    for (elem_idx, elem) in elements.iter().enumerate() {
526        // Use T::SLOTS for proper multi-slot element addressing
527        let elem_slot = data_start + U256::from(elem_idx * T::SLOTS);
528        elem.store(storage, elem_slot, LayoutCtx::FULL)?;
529    }
530
531    Ok(())
532}
533
534#[cfg(test)]
535mod tests {
536    use super::*;
537    use crate::{
538        storage::{Handler, StorageCtx},
539        test_util::{gen_word_from, setup_storage},
540    };
541    use alloy::primitives::Address;
542    use proptest::prelude::*;
543    use tempo_precompiles_macros::Storable;
544
545    // -- TEST HELPERS -------------------------------------------------------------
546
547    // Strategy for generating random U256 slot values that won't overflow
548    fn arb_safe_slot() -> impl Strategy<Value = U256> {
549        any::<[u64; 4]>().prop_map(|limbs| {
550            // Ensure we don't overflow by limiting to a reasonable range
551            U256::from_limbs(limbs) % (U256::MAX - U256::from(10000))
552        })
553    }
554
555    // Helper: Generate a single-slot struct for testing
556    #[derive(Debug, Clone, PartialEq, Eq, Storable)]
557    struct TestStruct {
558        a: u128, // 16 bytes (slot 0)
559        b: u128, // 16 bytes (slot 0)
560    }
561
562    // -- SLOT COMPUTATION TESTS ---------------------------------------------------
563    // Tests that verify handlers compute correct slots WITHOUT storage interaction
564
565    #[test]
566    fn test_vec_handler_slot_computation() {
567        let len_slot = U256::random();
568        let address = Address::random();
569        let handler = VecHandler::<u8>::new(len_slot, address);
570
571        // Verify base slot is stored correctly
572        assert_eq!(handler.len_slot, len_slot);
573
574        // Verify address is stored correctly
575        assert_eq!(*handler.address, *address);
576    }
577
578    #[test]
579    fn test_vec_data_slot_derivation() {
580        let len_slot = U256::random();
581
582        // Verify data slot matches keccak256(len_slot)
583        let data_slot = calc_data_slot(len_slot);
584        let expected =
585            U256::from_be_bytes(alloy::primitives::keccak256(len_slot.to_be_bytes::<32>()).0);
586
587        assert_eq!(
588            data_slot, expected,
589            "Data slot should be keccak256(len_slot)"
590        );
591    }
592
593    #[test]
594    fn test_vec_at_element_slot_packed() {
595        let len_slot = U256::random();
596        let address = Address::random();
597        let handler = VecHandler::<u8>::new(len_slot, address);
598
599        let data_start = calc_data_slot(len_slot);
600
601        // For packed types (u8: 1 byte), elements pack 32 per slot
602        // Element at index 5 should be in slot 0, offset 5
603        let elem_slot = &handler[5];
604        let expected_loc = calc_element_loc(5, u8::BYTES);
605        assert_eq!(
606            elem_slot.slot(),
607            data_start + U256::from(expected_loc.offset_slots)
608        );
609        assert_eq!(elem_slot.offset(), Some(expected_loc.offset_bytes));
610
611        // Element at index 35 should be in slot 1, offset 3 (35 % 32 = 3)
612        let elem_slot = &handler[35];
613        let expected_loc = calc_element_loc(35, u8::BYTES);
614        assert_eq!(
615            elem_slot.slot(),
616            data_start + U256::from(expected_loc.offset_slots)
617        );
618        assert_eq!(elem_slot.offset(), Some(expected_loc.offset_bytes));
619    }
620
621    #[test]
622    fn test_vec_at_element_slot_unpacked() {
623        let len_slot = U256::random();
624        let address = Address::random();
625        let handler = VecHandler::<U256>::new(len_slot, address);
626
627        let data_start = calc_data_slot(len_slot);
628
629        // For unpacked types (U256: 32 bytes), each element uses a full slot
630        // Element at index 0 should be at data_start + 0
631        let elem_slot = &handler[0];
632        assert_eq!(elem_slot.slot(), data_start);
633        assert_eq!(elem_slot.offset(), None); // Full slot, no offset
634
635        // Element at index 5 should be at data_start + 5
636        let elem_slot = &handler[5];
637        assert_eq!(elem_slot.slot(), data_start + U256::from(5));
638        assert_eq!(elem_slot.offset(), None);
639    }
640
641    #[test]
642    fn test_vec_at_determinism() {
643        let len_slot = U256::random();
644        let address = Address::random();
645        let handler = VecHandler::<u16>::new(len_slot, address);
646
647        // Same index should always produce same slot
648        let slot1 = &handler[10];
649        let slot2 = &handler[10];
650
651        assert_eq!(
652            slot1.slot(),
653            slot2.slot(),
654            "Same index should produce same slot"
655        );
656        assert_eq!(
657            slot1.offset(),
658            slot2.offset(),
659            "Same index should produce same offset"
660        );
661    }
662
663    #[test]
664    fn test_vec_at_different_indices() {
665        let len_slot = U256::random();
666        let address = Address::random();
667        let handler = VecHandler::<u16>::new(len_slot, address);
668
669        // Different indices should produce different slot/offset combinations
670        let slot5 = &handler[5];
671        let slot10 = &handler[10];
672
673        // u16 is 2 bytes, so 16 elements per slot
674        // Index 5 is in slot 0, offset 10
675        // Index 10 is in slot 0, offset 20
676        assert_eq!(slot5.slot(), slot10.slot(), "Both should be in same slot");
677        assert_ne!(slot5.offset(), slot10.offset(), "But different offsets");
678
679        // Index 16 should be in different slot
680        let slot16 = &handler[16];
681        assert_ne!(
682            slot5.slot(),
683            slot16.slot(),
684            "Different slot for index >= 16"
685        );
686    }
687
688    // -- STORABLE TRAIT TESTS -----------------------------------------------------
689
690    #[test]
691    fn test_vec_empty() {
692        let (mut storage, address) = setup_storage();
693
694        StorageCtx::enter(&mut storage, || {
695            let len_slot = U256::random();
696
697            let data: Vec<u8> = vec![];
698            let mut slot = Slot::<Vec<u8>>::new(len_slot, address);
699            slot.write(data.clone()).unwrap();
700
701            let loaded: Vec<u8> = slot.read().unwrap();
702            assert_eq!(loaded, data, "Empty vec roundtrip failed");
703            assert!(loaded.is_empty(), "Loaded vec should be empty");
704        });
705    }
706
707    #[test]
708    fn test_vec_nested() {
709        let (mut storage, address) = setup_storage();
710
711        StorageCtx::enter(&mut storage, || {
712            let len_slot = U256::random();
713
714            // Nested Vec<Vec<u8>>
715            let data = vec![vec![1u8, 2, 3], vec![4, 5], vec![6, 7, 8, 9]];
716            let mut slot = Slot::<Vec<Vec<u8>>>::new(len_slot, address);
717            slot.write(data.clone()).unwrap();
718
719            let loaded: Vec<Vec<u8>> = slot.read().unwrap();
720            assert_eq!(loaded, data, "Nested Vec<Vec<u8>> roundtrip failed");
721        });
722    }
723
724    #[test]
725    fn test_vec_bool_packing() {
726        let (mut storage, address) = setup_storage();
727
728        StorageCtx::enter(&mut storage, || {
729            let len_slot = U256::random();
730            let mut slot = Slot::<Vec<bool>>::new(len_slot, address);
731
732            // Test 1: Exactly 32 bools (fills exactly 1 slot: 32 * 1 byte = 32 bytes)
733            let data_exact: Vec<bool> = (0..32).map(|i| i % 2 == 0).collect();
734            slot.write(data_exact.clone()).unwrap();
735
736            // Verify length stored in base slot
737            let length_value = U256::handle(len_slot, LayoutCtx::FULL, address)
738                .read()
739                .unwrap();
740            assert_eq!(length_value, U256::from(32), "Length not stored correctly");
741
742            let loaded: Vec<bool> = slot.read().unwrap();
743            assert_eq!(
744                loaded, data_exact,
745                "Vec<bool> with 32 elements failed roundtrip"
746            );
747
748            // Test 2: 35 bools (requires 2 slots: 32 + 3)
749            let data_overflow: Vec<bool> = (0..35).map(|i| i % 3 == 0).collect();
750            slot.write(data_overflow.clone()).unwrap();
751
752            let loaded: Vec<bool> = slot.read().unwrap();
753            assert_eq!(
754                loaded, data_overflow,
755                "Vec<bool> with 35 elements failed roundtrip"
756            );
757        });
758    }
759
760    // -- SLOT-LEVEL VALIDATION TESTS ----------------------------------------------
761
762    #[test]
763    fn test_vec_u8_explicit_slot_packing() {
764        let (mut storage, address) = setup_storage();
765
766        StorageCtx::enter(&mut storage, || {
767            let len_slot = U256::from(2000);
768            let data = vec![10u8, 20, 30, 40, 50];
769
770            // Store exactly 5 u8 elements (should fit in 1 slot with 27 unused bytes)
771            <Vec<u8>>::handle(len_slot, LayoutCtx::FULL, address)
772                .write(data.clone())
773                .unwrap();
774
775            // Verify length stored in base slot
776            let length = U256::handle(len_slot, LayoutCtx::FULL, address)
777                .read()
778                .unwrap();
779            assert_eq!(
780                length,
781                U256::from(data.len()),
782                "Length not stored correctly"
783            );
784
785            let data_start = calc_data_slot(len_slot);
786            let slot_data = U256::handle(data_start, LayoutCtx::FULL, address)
787                .read()
788                .unwrap();
789
790            // Expected byte layout: 5 u8 elements packed at rightmost positions
791            let expected = gen_word_from(&[
792                "0x32", // elem[4] = 50
793                "0x28", // elem[3] = 40
794                "0x1e", // elem[2] = 30
795                "0x14", // elem[1] = 20
796                "0x0a", // elem[0] = 10
797            ]);
798            assert_eq!(
799                slot_data, expected,
800                "Slot data should match Solidity byte layout"
801            );
802
803            // Also verify each element can be extracted correctly
804            for (i, &expected) in data.iter().enumerate() {
805                let offset = i; // equivalent to: `i * u8::BYTES`
806                let actual =
807                    Slot::<u8>::new_with_ctx(data_start, LayoutCtx::packed(offset), address)
808                        .read()
809                        .unwrap();
810                assert_eq!(actual, expected, "mismatch: elem[{i}] at offset {offset}");
811            }
812        });
813    }
814
815    #[test]
816    fn test_vec_u16_slot_boundary() {
817        let (mut storage, address) = setup_storage();
818
819        StorageCtx::enter(&mut storage, || {
820            let len_slot = U256::from(2100);
821            let mut vec_slot = Slot::<Vec<u16>>::new(len_slot, address);
822
823            // Test 1: Exactly 16 u16 elements (fills exactly 1 slot: 16 * 2 bytes = 32 bytes)
824            let data_exact: Vec<u16> = (0..16).map(|i| i * 100).collect();
825            vec_slot.write(data_exact.clone()).unwrap();
826
827            let data_start = calc_data_slot(len_slot);
828            let slot0_value = U256::handle(data_start, LayoutCtx::FULL, address)
829                .read()
830                .unwrap();
831
832            let expected_slot0 = gen_word_from(&[
833                "0x05dc", // elem[15] = 1500
834                "0x0578", // elem[14] = 1400
835                "0x0514", // elem[13] = 1300
836                "0x04b0", // elem[12] = 1200
837                "0x044c", // elem[11] = 1100
838                "0x03e8", // elem[10] = 1000
839                "0x0384", // elem[9] = 900
840                "0x0320", // elem[8] = 800
841                "0x02bc", // elem[7] = 700
842                "0x0258", // elem[6] = 600
843                "0x01f4", // elem[5] = 500
844                "0x0190", // elem[4] = 400
845                "0x012c", // elem[3] = 300
846                "0x00c8", // elem[2] = 200
847                "0x0064", // elem[1] = 100
848                "0x0000", // elem[0] = 0
849            ]);
850            assert_eq!(
851                slot0_value, expected_slot0,
852                "Slot 0 should match Solidity byte layout"
853            );
854
855            // Also verify each element can be extracted
856            for (i, &expected) in data_exact.iter().enumerate() {
857                let offset = i * u16::BYTES;
858                let actual =
859                    Slot::<u16>::new_with_ctx(data_start, LayoutCtx::packed(offset), address)
860                        .read()
861                        .unwrap();
862                assert_eq!(actual, expected, "mismatch: elem[{i}] at offset {offset}");
863            }
864
865            // Test 2: 17 u16 elements (requires 2 slots)
866            let data_overflow: Vec<u16> = (0..17).map(|i| i * 100).collect();
867            vec_slot.write(data_overflow).unwrap();
868
869            // Verify slot 0 still matches (first 16 elements)
870            let slot0_value = U256::handle(data_start, LayoutCtx::FULL, address)
871                .read()
872                .unwrap();
873            assert_eq!(
874                slot0_value, expected_slot0,
875                "Slot 0 should still match after overflow"
876            );
877
878            // Verify slot 1 has the 17th element (1600 = 0x0640)
879            let slot1_addr = data_start + U256::ONE;
880            let slot1_value = U256::handle(slot1_addr, LayoutCtx::FULL, address)
881                .read()
882                .unwrap();
883
884            let expected_slot1 = gen_word_from(&[
885                "0x0640", // elem[16] = 1600
886            ]);
887            assert_eq!(
888                slot1_value, expected_slot1,
889                "Slot 1 should match Solidity byte layout"
890            );
891
892            // Also verify the 17th element can be extracted
893            let actual = Slot::<u16>::new_with_ctx(slot1_addr, LayoutCtx::packed(0), address)
894                .read()
895                .unwrap();
896            assert_eq!(actual, 1600u16, "mismatch: slot1_elem[0] at offset 0");
897        });
898    }
899
900    #[test]
901    fn test_vec_u8_partial_slot_fill() {
902        let (mut storage, address) = setup_storage();
903
904        StorageCtx::enter(&mut storage, || {
905            let len_slot = U256::from(2200);
906
907            // Store 35 u8 elements (values 1-35):
908            // - Slot 0: 32 elements (full) - elements 1-32
909            // - Slot 1: 3 elements (elements 33-35) + 29 zeros
910            let data: Vec<u8> = (0..35).map(|i| (i + 1) as u8).collect();
911            let mut vec_slot = Slot::<Vec<u8>>::new(len_slot, address);
912            vec_slot.write(data).unwrap();
913            let data_start = calc_data_slot(len_slot);
914            let slot0_value = U256::handle(data_start, LayoutCtx::FULL, address)
915                .read()
916                .unwrap();
917
918            let expected_slot0 = gen_word_from(&[
919                "0x20", // elem[31] = 32
920                "0x1f", // elem[30] = 31
921                "0x1e", // elem[29] = 30
922                "0x1d", // elem[28] = 29
923                "0x1c", // elem[27] = 28
924                "0x1b", // elem[26] = 27
925                "0x1a", // elem[25] = 26
926                "0x19", // elem[24] = 25
927                "0x18", // elem[23] = 24
928                "0x17", // elem[22] = 23
929                "0x16", // elem[21] = 22
930                "0x15", // elem[20] = 21
931                "0x14", // elem[19] = 20
932                "0x13", // elem[18] = 19
933                "0x12", // elem[17] = 18
934                "0x11", // elem[16] = 17
935                "0x10", // elem[15] = 16
936                "0x0f", // elem[14] = 15
937                "0x0e", // elem[13] = 14
938                "0x0d", // elem[12] = 13
939                "0x0c", // elem[11] = 12
940                "0x0b", // elem[10] = 11
941                "0x0a", // elem[9] = 10
942                "0x09", // elem[8] = 9
943                "0x08", // elem[7] = 8
944                "0x07", // elem[6] = 7
945                "0x06", // elem[5] = 6
946                "0x05", // elem[4] = 5
947                "0x04", // elem[3] = 4
948                "0x03", // elem[2] = 3
949                "0x02", // elem[1] = 2
950                "0x01", // elem[0] = 1
951            ]);
952            assert_eq!(
953                slot0_value, expected_slot0,
954                "Slot 0 should match Solidity byte layout"
955            );
956
957            // Verify slot 1 has exactly 3 elements at rightmost positions
958            let slot1_addr = data_start + U256::ONE;
959            let slot1_value = U256::handle(slot1_addr, LayoutCtx::FULL, address)
960                .read()
961                .unwrap();
962
963            let expected_slot1 = gen_word_from(&[
964                "0x23", // elem[2] = 35
965                "0x22", // elem[1] = 34
966                "0x21", // elem[0] = 33
967            ]);
968            assert_eq!(
969                slot1_value, expected_slot1,
970                "Slot 1 should match Solidity byte layout"
971            );
972
973            // Also verify each element in slot 1 can be extracted
974            let slot1_data = [33u8, 34u8, 35u8];
975            for (i, &expected) in slot1_data.iter().enumerate() {
976                let offset = i; // equivalent to: `i * u8::BYTES`
977                let actual =
978                    Slot::<u8>::new_with_ctx(slot1_addr, LayoutCtx::packed(offset), address)
979                        .read()
980                        .unwrap();
981                assert_eq!(
982                    actual, expected,
983                    "mismatch: slot1_elem[{i}] at offset {offset}"
984                );
985            }
986        });
987    }
988
989    #[test]
990    fn test_vec_u256_individual_slots() {
991        let (mut storage, address) = setup_storage();
992
993        StorageCtx::enter(&mut storage, || {
994            let len_slot = U256::from(2300);
995
996            // Store 3 U256 values (each should occupy its own slot)
997            let data = vec![
998                U256::from(0x1111111111111111u64),
999                U256::from(0x2222222222222222u64),
1000                U256::from(0x3333333333333333u64),
1001            ];
1002            let mut vec_slot = Slot::<Vec<U256>>::new(len_slot, address);
1003            vec_slot.write(data.clone()).unwrap();
1004
1005            let data_start = calc_data_slot(len_slot);
1006
1007            // Verify each U256 occupies its own sequential slot
1008            for (i, &expected) in data.iter().enumerate() {
1009                let stored_value =
1010                    U256::handle(data_start + U256::from(i), LayoutCtx::FULL, address)
1011                        .read()
1012                        .unwrap();
1013                assert_eq!(stored_value, expected, "incorrect U256 element {i}");
1014            }
1015
1016            // Verify there's no data in slot 3 (should be empty)
1017            let no_slot_value = U256::handle(data_start + U256::from(3), LayoutCtx::FULL, address)
1018                .read()
1019                .unwrap();
1020            assert_eq!(no_slot_value, U256::ZERO, "Slot 3 should be empty");
1021        });
1022    }
1023
1024    #[test]
1025    fn test_vec_address_unpacked_slots() {
1026        let (mut storage, address) = setup_storage();
1027
1028        StorageCtx::enter(&mut storage, || {
1029            let len_slot = U256::from(2400);
1030
1031            // Store 3 addresses (each 20 bytes, but 32 % 20 != 0, so unpacked)
1032            let data = vec![
1033                Address::repeat_byte(0xAA),
1034                Address::repeat_byte(0xBB),
1035                Address::repeat_byte(0xCC),
1036            ];
1037            let mut vec_slot = Slot::<Vec<Address>>::new(len_slot, address);
1038            vec_slot.write(data.clone()).unwrap();
1039
1040            let data_start = calc_data_slot(len_slot);
1041
1042            // Verify slot 0: Address(0xAA...) right-aligned with 12-byte padding
1043            let slot0_value = U256::handle(data_start, LayoutCtx::FULL, address)
1044                .read()
1045                .unwrap();
1046            let expected_slot0 = gen_word_from(&["0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"]);
1047            assert_eq!(
1048                slot0_value, expected_slot0,
1049                "Slot 0 should match Solidity byte layout"
1050            );
1051
1052            // Verify slot 1: Address(0xBB...) right-aligned with 12-byte padding
1053            let slot1_addr = data_start + U256::ONE;
1054            let slot1_value = U256::handle(slot1_addr, LayoutCtx::FULL, address)
1055                .read()
1056                .unwrap();
1057            let expected_slot1 = gen_word_from(&["0xBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"]);
1058            assert_eq!(
1059                slot1_value, expected_slot1,
1060                "Slot 1 should match Solidity byte layout"
1061            );
1062
1063            // Verify slot 2: Address(0xCC...) right-aligned with 12-byte padding
1064            let slot2_addr = data_start + U256::from(2);
1065            let slot2_value = U256::handle(slot2_addr, LayoutCtx::FULL, address)
1066                .read()
1067                .unwrap();
1068            let expected_slot2 = gen_word_from(&["0xCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC"]);
1069            assert_eq!(
1070                slot2_value, expected_slot2,
1071                "Slot 2 should match Solidity byte layout"
1072            );
1073
1074            // Also verify addresses can be loaded back
1075            for (i, &expected_addr) in data.iter().enumerate() {
1076                let slot_addr = data_start + U256::from(i);
1077                let stored_value = U256::handle(slot_addr, LayoutCtx::FULL, address)
1078                    .read()
1079                    .unwrap();
1080                let expected_u256 = U256::from_be_slice(expected_addr.as_slice());
1081                assert_eq!(
1082                    stored_value, expected_u256,
1083                    "Address element {i} should match"
1084                );
1085            }
1086        });
1087    }
1088
1089    #[test]
1090    fn test_vec_struct_slot_allocation() {
1091        let (mut storage, address) = setup_storage();
1092
1093        StorageCtx::enter(&mut storage, || {
1094            let len_slot = U256::from(2500);
1095
1096            // Store Vec<TestStruct> with 3 single-slot structs
1097            // Each TestStruct has two u128 fields (a, b) packed into one 32-byte slot
1098            let data = vec![
1099                TestStruct { a: 100, b: 1 },
1100                TestStruct { a: 200, b: 2 },
1101                TestStruct { a: 300, b: 3 },
1102            ];
1103            let mut vec_slot = Slot::<Vec<TestStruct>>::new(len_slot, address);
1104            vec_slot.write(data.clone()).unwrap();
1105
1106            let data_start = calc_data_slot(len_slot);
1107
1108            // Verify slot 0: TestStruct { a: 100, b: 1 }
1109            // Note: Solidity packs struct fields right-to-left (declaration order reversed in memory)
1110            // So field b (declared second) goes in bytes 0-15, field a (declared first) goes in bytes 16-31
1111            let slot0_value = U256::handle(data_start, LayoutCtx::FULL, address)
1112                .read()
1113                .unwrap();
1114            let expected_slot0 = gen_word_from(&[
1115                "0x00000000000000000000000000000001", // field b = 1
1116                "0x00000000000000000000000000000064", // field a = 100
1117            ]);
1118            assert_eq!(
1119                slot0_value, expected_slot0,
1120                "Slot 0 should match Solidity byte layout"
1121            );
1122
1123            // Verify slot 1: TestStruct { a: 200, b: 2 }
1124            let slot1_addr = data_start + U256::ONE;
1125            let slot1_value = U256::handle(slot1_addr, LayoutCtx::FULL, address)
1126                .read()
1127                .unwrap();
1128            let expected_slot1 = gen_word_from(&[
1129                "0x00000000000000000000000000000002", // field b = 2
1130                "0x000000000000000000000000000000C8", // field a = 200
1131            ]);
1132            assert_eq!(
1133                slot1_value, expected_slot1,
1134                "Slot 1 should match Solidity byte layout"
1135            );
1136
1137            // Verify slot 2: TestStruct { a: 300, b: 3 }
1138            let slot2_addr = data_start + U256::from(2);
1139            let slot2_value = U256::handle(slot2_addr, LayoutCtx::FULL, address)
1140                .read()
1141                .unwrap();
1142            let expected_slot2 = gen_word_from(&[
1143                "0x00000000000000000000000000000003", // field b = 3
1144                "0x0000000000000000000000000000012C", // field a = 300
1145            ]);
1146            assert_eq!(
1147                slot2_value, expected_slot2,
1148                "Slot 2 should match Solidity byte layout"
1149            );
1150
1151            // Verify slot 3 is empty (no 4th element)
1152            let slot3_addr = data_start + U256::from(3);
1153            let slot3_value = U256::handle(slot3_addr, LayoutCtx::FULL, address)
1154                .read()
1155                .unwrap();
1156            assert_eq!(slot3_value, U256::ZERO, "Slot 3 should be empty");
1157
1158            // Also verify each struct can be loaded back correctly
1159            for (i, expected_struct) in data.iter().enumerate() {
1160                let struct_slot_addr = data_start + U256::from(i);
1161                let struct_slot = Slot::<TestStruct>::new(struct_slot_addr, address);
1162                let loaded_struct = struct_slot.read().unwrap();
1163                assert_eq!(
1164                    loaded_struct, *expected_struct,
1165                    "TestStruct at slot {i} should match"
1166                );
1167            }
1168        });
1169    }
1170
1171    #[test]
1172    fn test_vec_small_struct_storage() {
1173        // Test that single-slot structs are stored correctly in Vec
1174        #[derive(Debug, Clone, PartialEq, Eq, Storable)]
1175        struct SmallStruct {
1176            flag1: bool, // offset 0 (1 byte)
1177            flag2: bool, // offset 1 (1 byte)
1178            value: u16,  // offset 2 (2 bytes)
1179        }
1180
1181        let (mut storage, address) = setup_storage();
1182
1183        StorageCtx::enter(&mut storage, || {
1184            let len_slot = U256::from(2550);
1185
1186            // Store 3 SmallStruct elements
1187            // Each struct uses 1 full slot (even though it only occupies 4 bytes)
1188            let data = vec![
1189                SmallStruct {
1190                    flag1: true,
1191                    flag2: false,
1192                    value: 100,
1193                },
1194                SmallStruct {
1195                    flag1: false,
1196                    flag2: true,
1197                    value: 200,
1198                },
1199                SmallStruct {
1200                    flag1: true,
1201                    flag2: true,
1202                    value: 300,
1203                },
1204            ];
1205            let mut vec_slot = Slot::<Vec<SmallStruct>>::new(len_slot, address);
1206            vec_slot.write(data.clone()).unwrap();
1207
1208            // Verify length stored in base slot
1209            let length_value = U256::handle(len_slot, LayoutCtx::FULL, address)
1210                .read()
1211                .unwrap();
1212            assert_eq!(length_value, U256::from(3), "Length not stored correctly");
1213
1214            let data_start = calc_data_slot(len_slot);
1215
1216            // Verify slot 0: first struct (fields packed within the struct)
1217            let slot0_value = U256::handle(data_start, LayoutCtx::FULL, address)
1218                .read()
1219                .unwrap();
1220            let expected_slot0 = gen_word_from(&[
1221                "0x0064", // value = 100 (offset 2-3, 2 bytes)
1222                "0x00",   // flag2 = false (offset 1, 1 byte)
1223                "0x01",   // flag1 = true (offset 0, 1 byte)
1224            ]);
1225            assert_eq!(
1226                slot0_value, expected_slot0,
1227                "Slot 0 should match Solidity layout for struct[0]"
1228            );
1229
1230            // Verify slot 1: second struct
1231            let slot1_addr = data_start + U256::ONE;
1232            let slot1_value = U256::handle(slot1_addr, LayoutCtx::FULL, address)
1233                .read()
1234                .unwrap();
1235            let expected_slot1 = gen_word_from(&[
1236                "0x00c8", // value = 200 (offset 2-3, 2 bytes)
1237                "0x01",   // flag2 = true (offset 1, 1 byte)
1238                "0x00",   // flag1 = false (offset 0, 1 byte)
1239            ]);
1240            assert_eq!(
1241                slot1_value, expected_slot1,
1242                "Slot 1 should match Solidity layout for struct[1]"
1243            );
1244
1245            // Verify slot 2: third struct
1246            let slot2_addr = data_start + U256::from(2);
1247            let slot2_value = U256::handle(slot2_addr, LayoutCtx::FULL, address)
1248                .read()
1249                .unwrap();
1250            let expected_slot2 = gen_word_from(&[
1251                "0x012c", // value = 300 (offset 2-3, 2 bytes)
1252                "0x01",   // flag2 = true (offset 1, 1 byte)
1253                "0x01",   // flag1 = true (offset 0, 1 byte)
1254            ]);
1255            assert_eq!(
1256                slot2_value, expected_slot2,
1257                "Slot 2 should match Solidity layout for struct[2]"
1258            );
1259
1260            // Verify roundtrip
1261            let loaded: Vec<SmallStruct> = vec_slot.read().unwrap();
1262            assert_eq!(loaded, data, "Vec<SmallStruct> roundtrip failed");
1263        });
1264    }
1265
1266    #[test]
1267    fn test_vec_length_slot_isolation() {
1268        let (mut storage, address) = setup_storage();
1269
1270        StorageCtx::enter(&mut storage, || {
1271            let len_slot = U256::from(2600);
1272
1273            // Store a vec with 3 u8 elements
1274            let data = vec![100u8, 200, 250];
1275            let mut vec_slot = Slot::<Vec<u8>>::new(len_slot, address);
1276            vec_slot.write(data.clone()).unwrap();
1277
1278            // Verify base slot contains length
1279            let length_value = U256::handle(len_slot, LayoutCtx::FULL, address)
1280                .read()
1281                .unwrap();
1282            assert_eq!(length_value, U256::from(3), "Length slot incorrect");
1283
1284            // Verify data starts at keccak256(len_slot), not len_slot + 1
1285            let data_start = calc_data_slot(len_slot);
1286            assert_ne!(
1287                data_start,
1288                len_slot + U256::ONE,
1289                "Data should not start immediately after base slot"
1290            );
1291
1292            // Verify data slot matches expected Solidity byte layout
1293            let data_slot_value = U256::handle(data_start, LayoutCtx::FULL, address)
1294                .read()
1295                .unwrap();
1296
1297            let expected = gen_word_from(&[
1298                "0xfa", // elem[2] = 250
1299                "0xc8", // elem[1] = 200
1300                "0x64", // elem[0] = 100
1301            ]);
1302            assert_eq!(
1303                data_slot_value, expected,
1304                "Data slot should match Solidity byte layout"
1305            );
1306
1307            // Also verify each element can be extracted
1308            for (i, &expected) in data.iter().enumerate() {
1309                let offset = i; // equivalent to: `i * u8::BYTES`
1310                let actual =
1311                    Slot::<u8>::new_with_ctx(data_start, LayoutCtx::packed(offset), address)
1312                        .read()
1313                        .unwrap();
1314                assert_eq!(actual, expected, "mismatch: elem[{i}] at offset {offset}");
1315            }
1316        });
1317    }
1318
1319    #[test]
1320    fn test_vec_overwrite_cleanup() {
1321        let (mut storage, address) = setup_storage();
1322
1323        StorageCtx::enter(&mut storage, || {
1324            let len_slot = U256::from(2700);
1325            let mut vec_slot = Slot::<Vec<u8>>::new(len_slot, address);
1326
1327            // Store a vec with 5 u8 elements (requires 1 slot)
1328            let data_long = vec![1u8, 2, 3, 4, 5];
1329            vec_slot.write(data_long).unwrap();
1330
1331            let data_start = calc_data_slot(len_slot);
1332
1333            // Verify initial storage
1334            let slot0_before = U256::handle(data_start, LayoutCtx::FULL, address)
1335                .read()
1336                .unwrap();
1337            assert_ne!(slot0_before, U256::ZERO, "Initial data should be stored");
1338
1339            // Overwrite with a shorter vec (3 elements)
1340            let data_short = vec![10u8, 20, 30];
1341            vec_slot.write(data_short.clone()).unwrap();
1342
1343            // Verify length updated
1344            let length_value = U256::handle(len_slot, LayoutCtx::FULL, address)
1345                .read()
1346                .unwrap();
1347            assert_eq!(length_value, U256::from(3), "Length should be updated");
1348
1349            // Verify new data can be extracted correctly (even though old data might remain)
1350            for (i, &expected) in data_short.iter().enumerate() {
1351                let offset = i; // equivalent to: `i * u8::BYTES`
1352                let actual =
1353                    Slot::<u8>::new_with_ctx(data_start, LayoutCtx::packed(offset), address)
1354                        .read()
1355                        .unwrap();
1356                assert_eq!(
1357                    actual, expected,
1358                    "mismatch: new_elem[{i}] at offset {offset}"
1359                );
1360            }
1361
1362            let loaded: Vec<u8> = vec_slot.read().unwrap();
1363            assert_eq!(loaded, data_short, "Loaded vec should match short version");
1364            assert_eq!(loaded.len(), 3, "Length should be 3");
1365
1366            // For full cleanup, delete first, then store
1367            vec_slot.delete().unwrap();
1368            vec_slot.write(data_short.clone()).unwrap();
1369
1370            // Verify slot matches expected Solidity byte layout after delete+store
1371            let slot0_after_delete = U256::handle(data_start, LayoutCtx::FULL, address)
1372                .read()
1373                .unwrap();
1374
1375            let expected = gen_word_from(&[
1376                "0x1e", // elem[2] = 30
1377                "0x14", // elem[1] = 20
1378                "0x0a", // elem[0] = 10
1379            ]);
1380            assert_eq!(
1381                slot0_after_delete, expected,
1382                "Slot should match Solidity byte layout after delete+store"
1383            );
1384
1385            // Also verify each element can still be extracted
1386            for (i, &expected) in data_short.iter().enumerate() {
1387                let offset = i; // equivalent to: `i * u8::BYTES`
1388                let actual =
1389                    Slot::<u8>::new_with_ctx(data_start, LayoutCtx::packed(offset), address)
1390                        .read()
1391                        .unwrap();
1392                assert_eq!(actual, expected, "mismatch: elem[{i}] at offset {offset}");
1393            }
1394        });
1395    }
1396
1397    // TODO(rusowsky): Implement and test multi-slot support
1398    // fn test_multi_slot_array() {
1399    //     #[derive(Storable)]
1400    //     struct MultiSlotStruct {
1401    //         field1: U256, // slot 0
1402    //         field2: U256, // slot 1
1403    //         field3: U256, // slot 2
1404    //     }
1405
1406    //     let (mut storage, address) = setup_storage();
1407    //     // MIGRATION TODO: This test needs to be migrated to StorageCtx::enter pattern
1408
1409    //     let len_slot = U256::from(2700);
1410
1411    //     let data: Vec<MultiSlotStruct> = vec![MultiSlotStruct {
1412    //         field1: U256::ONE,
1413    //         field2: U256::from(2),
1414    //         field3: U256::from(3),
1415    //     }];
1416
1417    //     data.store(storage, len_slot, 0).unwrap();
1418
1419    //     let data_start = calc_data_slot(len_slot);
1420    // }
1421
1422    // -- VEC HANDLER TESTS --------------------------------------------------------
1423    // Tests that verify VecHandler API methods
1424
1425    #[test]
1426    fn test_vec_handler_read_write() {
1427        let (mut storage, address) = setup_storage();
1428
1429        StorageCtx::enter(&mut storage, || {
1430            let len_slot = U256::random();
1431            let mut handler = VecHandler::<U256>::new(len_slot, address);
1432
1433            // Test write and read
1434            let data = vec![U256::random(), U256::random(), U256::random()];
1435            handler.write(data.clone()).unwrap();
1436
1437            let loaded = handler.read().unwrap();
1438            assert_eq!(loaded, data, "Vec read/write roundtrip failed");
1439        });
1440    }
1441
1442    #[test]
1443    fn test_vec_handler_delete() {
1444        let (mut storage, address) = setup_storage();
1445
1446        StorageCtx::enter(&mut storage, || {
1447            let len_slot = U256::random();
1448            let mut handler = VecHandler::<u8>::new(len_slot, address);
1449
1450            // Write some data
1451            handler.write(vec![1, 2, 3, 4, 5]).unwrap();
1452            assert_eq!(handler.read().unwrap().len(), 5);
1453
1454            // Delete
1455            handler.delete().unwrap();
1456
1457            // Verify empty
1458            let loaded = handler.read().unwrap();
1459            assert!(loaded.is_empty(), "Vec should be empty after delete");
1460
1461            // Verify length slot is cleared
1462            let length = U256::handle(len_slot, LayoutCtx::FULL, address)
1463                .read()
1464                .unwrap();
1465            assert_eq!(length, U256::ZERO, "Length slot should be zero");
1466        });
1467    }
1468
1469    #[test]
1470    fn test_vec_handler_at_read_write() {
1471        let (mut storage, address) = setup_storage();
1472
1473        StorageCtx::enter(&mut storage, || {
1474            let len_slot = U256::random();
1475            let mut handler = VecHandler::<U256>::new(len_slot, address);
1476
1477            // Write full vector first
1478            let data = vec![U256::from(10), U256::from(20), U256::from(30)];
1479            let mut vec_slot = Slot::<Vec<U256>>::new(len_slot, address);
1480            vec_slot.write(data).unwrap();
1481
1482            // Test reading individual elements via at()
1483            let elem0 = handler[0].read().unwrap();
1484            let elem1 = handler[1].read().unwrap();
1485            let elem2 = handler[2].read().unwrap();
1486
1487            assert_eq!(elem0, U256::from(10));
1488            assert_eq!(elem1, U256::from(20));
1489            assert_eq!(elem2, U256::from(30));
1490
1491            // Test writing individual elements via at()
1492            handler[1].write(U256::from(99)).unwrap();
1493
1494            // Verify via read
1495            let updated = handler.read().unwrap();
1496            assert_eq!(
1497                updated,
1498                vec![U256::from(10), U256::from(99), U256::from(30)]
1499            );
1500        });
1501    }
1502
1503    #[test]
1504    fn test_vec_handler_push_pop() {
1505        let (mut storage, address) = setup_storage();
1506
1507        StorageCtx::enter(&mut storage, || {
1508            let len_slot = U256::random();
1509            let handler = VecHandler::<U256>::new(len_slot, address);
1510
1511            let val1 = U256::random();
1512            let val2 = U256::random();
1513            let val3 = U256::random();
1514
1515            // Test push
1516            handler.push(val1).unwrap();
1517            handler.push(val2).unwrap();
1518            handler.push(val3).unwrap();
1519
1520            assert_eq!(handler.len().unwrap(), 3);
1521
1522            // Test pop
1523            assert_eq!(handler.pop().unwrap(), Some(val3));
1524            assert_eq!(handler.pop().unwrap(), Some(val2));
1525            assert_eq!(handler.pop().unwrap(), Some(val1));
1526            assert_eq!(handler.pop().unwrap(), None);
1527
1528            assert_eq!(handler.len().unwrap(), 0);
1529        });
1530    }
1531
1532    #[test]
1533    fn test_vec_handler_len() {
1534        let (mut storage, address) = setup_storage();
1535
1536        StorageCtx::enter(&mut storage, || {
1537            let len_slot = U256::random();
1538            let handler = VecHandler::<Address>::new(len_slot, address);
1539
1540            // Initial length should be 0
1541            assert_eq!(handler.len().unwrap(), 0);
1542
1543            // Push elements and verify length
1544            handler.push(Address::random()).unwrap();
1545            assert_eq!(handler.len().unwrap(), 1);
1546
1547            handler.push(Address::random()).unwrap();
1548            assert_eq!(handler.len().unwrap(), 2);
1549
1550            handler.push(Address::random()).unwrap();
1551            assert_eq!(handler.len().unwrap(), 3);
1552
1553            // Pop and verify length decreases
1554            handler.pop().unwrap();
1555            assert_eq!(handler.len().unwrap(), 2);
1556        });
1557    }
1558
1559    #[test]
1560    fn test_vec_handler_push_pop_packed_types() {
1561        let (mut storage, address) = setup_storage();
1562
1563        StorageCtx::enter(&mut storage, || {
1564            let len_slot = U256::random();
1565            let handler = VecHandler::<u8>::new(len_slot, address);
1566
1567            // Push 35 elements (crosses slot boundary: 32 in slot 0, 3 in slot 1)
1568            for i in 0..35 {
1569                handler.push(i as u8).unwrap();
1570            }
1571
1572            assert_eq!(handler.len().unwrap(), 35);
1573
1574            // Verify values
1575            for i in 0..35 {
1576                let val = handler[i].read().unwrap();
1577                assert_eq!(val, i as u8);
1578            }
1579
1580            // Pop all and verify
1581            for i in (0..35).rev() {
1582                let popped = handler.pop().unwrap();
1583                assert_eq!(popped, Some(i as u8));
1584            }
1585
1586            assert_eq!(handler.len().unwrap(), 0);
1587        });
1588    }
1589
1590    #[test]
1591    fn test_vec_handler_at_oob_check() -> eyre::Result<()> {
1592        let (mut storage, address) = setup_storage();
1593
1594        StorageCtx::enter(&mut storage, || {
1595            let len_slot = U256::random();
1596            let handler = VecHandler::<U256>::new(len_slot, address);
1597
1598            // Empty vec - any index should return None
1599            assert!(handler.at(0)?.is_none());
1600
1601            // Push 2 elements
1602            handler.push(U256::from(10))?;
1603            handler.push(U256::from(20))?;
1604
1605            // Valid indices should return Some and read the correct values
1606            assert!(handler.at(0)?.is_some());
1607            assert!(handler.at(1)?.is_some());
1608            assert_eq!(handler.at(0)?.unwrap().read()?, U256::from(10));
1609            assert_eq!(handler.at(1)?.unwrap().read()?, U256::from(20));
1610
1611            // OOB indices should return None
1612            assert!(handler.at(3)?.is_none());
1613
1614            Ok(())
1615        })
1616    }
1617
1618    #[test]
1619    fn test_vec_push_at_max_capacity() -> eyre::Result<()> {
1620        let (mut storage, address) = setup_storage();
1621
1622        StorageCtx::enter(&mut storage, || {
1623            let mut len_slot = Slot::<U256>::new(U256::ZERO, address);
1624
1625            // Test packed type
1626            let handler = VecHandler::<u32>::new(U256::ZERO, address);
1627            let max_index = u32::MAX as usize / u32::BYTES;
1628
1629            // Manually write max_index - 1 to length slot
1630            len_slot.write(U256::from(max_index - 1))?;
1631
1632            // Push should succeed once (length becomes max_index)
1633            handler.push(1)?;
1634            assert_eq!(handler.len()?, max_index);
1635
1636            // Can read element at len - 1
1637            let elem = handler.at(max_index - 1)?;
1638            assert_eq!(elem.unwrap().read()?, 1);
1639
1640            // Next push should fail
1641            let result = handler.push(1);
1642            assert!(result.is_err());
1643
1644            // Test unpacked type (U256: 32 bytes, max_index = u32::MAX / 1)
1645            let handler = VecHandler::<U256>::new(U256::ZERO, address);
1646            let max_index = u32::MAX as usize;
1647            let value = U256::random();
1648
1649            // Manually write max_index - 1 to length slot
1650            len_slot.write(U256::from(max_index - 1))?;
1651
1652            // Push should succeed once (length becomes max_index)
1653            handler.push(value)?;
1654            assert_eq!(handler.len()?, max_index);
1655
1656            // Can read element at len - 1
1657            let elem = handler.at(max_index - 1)?;
1658            assert!(elem.is_some());
1659            assert_eq!(elem.unwrap().read()?, value);
1660
1661            // Next push should fail
1662            let result = handler.push(value);
1663            assert!(result.is_err());
1664
1665            Ok(())
1666        })
1667    }
1668
1669    // -- PROPTEST STRATEGIES ------------------------------------------------------
1670
1671    prop_compose! {
1672        fn arb_u8_vec(max_len: usize) (vec in prop::collection::vec(any::<u8>(), 0..=max_len)) -> Vec<u8> {
1673            vec
1674        }
1675    }
1676
1677    prop_compose! {
1678        fn arb_u16_vec(max_len: usize) (vec in prop::collection::vec(any::<u16>(), 0..=max_len)) -> Vec<u16> {
1679            vec
1680        }
1681    }
1682
1683    prop_compose! {
1684        fn arb_u32_vec(max_len: usize) (vec in prop::collection::vec(any::<u32>(), 0..=max_len)) -> Vec<u32> {
1685            vec
1686        }
1687    }
1688
1689    prop_compose! {
1690        fn arb_u64_vec(max_len: usize) (vec in prop::collection::vec(any::<u64>(), 0..=max_len)) -> Vec<u64> {
1691            vec
1692        }
1693    }
1694
1695    prop_compose! {
1696        fn arb_u128_vec(max_len: usize) (vec in prop::collection::vec(any::<u128>(), 0..=max_len)) -> Vec<u128> {
1697            vec
1698        }
1699    }
1700
1701    prop_compose! {
1702        fn arb_u256_vec(max_len: usize) (vec in prop::collection::vec(any::<u64>(), 0..=max_len)) -> Vec<U256> {
1703            vec.into_iter().map(U256::from).collect()
1704        }
1705    }
1706
1707    prop_compose! {
1708        fn arb_address_vec(max_len: usize) (vec in prop::collection::vec(any::<[u8; 20]>(), 0..=max_len)) -> Vec<Address> {
1709            vec.into_iter().map(Address::from).collect()
1710        }
1711    }
1712
1713    prop_compose! {
1714        fn arb_test_struct() (a in any::<u64>(), b in any::<u64>()) -> TestStruct {
1715            TestStruct {
1716                a: a as u128,
1717                b: b as u128,
1718            }
1719        }
1720    }
1721
1722    prop_compose! {
1723        fn arb_test_struct_vec(max_len: usize)
1724                              (vec in prop::collection::vec(arb_test_struct(), 0..=max_len))
1725                              -> Vec<TestStruct> {
1726            vec
1727        }
1728    }
1729
1730    // -- PROPERTY TESTS -----------------------------------------------------------
1731
1732    proptest! {
1733        #![proptest_config(ProptestConfig::with_cases(500))]
1734        #[test]
1735        fn proptest_vec_u8_roundtrip(data in arb_u8_vec(100), len_slot in arb_safe_slot()) {
1736            let (mut storage, address) = setup_storage();
1737
1738            StorageCtx::enter(&mut storage, || {
1739                let data_len = data.len();
1740            let mut vec_slot = Slot::<Vec<u8>>::new(len_slot, address);
1741
1742            // Store → Load roundtrip
1743            vec_slot.write(data.clone())?;
1744            let loaded: Vec<u8> = vec_slot.read()?;
1745            prop_assert_eq!(&loaded, &data, "Vec<u8> roundtrip failed");
1746
1747            // Delete + verify cleanup
1748            vec_slot.delete()?;
1749            let after_delete: Vec<u8> = vec_slot.read()?;
1750            prop_assert!(after_delete.is_empty(), "Vec not empty after delete");
1751
1752            // Verify data slots are cleared (if length > 0)
1753            if data_len > 0 {
1754                let data_start = calc_data_slot(len_slot);
1755                let byte_count = u8::BYTES;
1756                let slot_count = calc_packed_slot_count(data_len, byte_count);
1757
1758                for i in 0..slot_count {
1759                    let slot_value = U256::handle(data_start + U256::from(i), LayoutCtx::FULL, address).read()?;
1760                    prop_assert_eq!(slot_value, U256::ZERO, "Data slot {} not cleared", i);
1761                }
1762            }
1763
1764                Ok(())
1765            }).unwrap();
1766        }
1767
1768        #[test]
1769        fn proptest_vec_u16_roundtrip(data in arb_u16_vec(100), len_slot in arb_safe_slot()) {
1770            let (mut storage, address) = setup_storage();
1771
1772            StorageCtx::enter(&mut storage, || {
1773                let data_len = data.len();
1774            let mut vec_slot = Slot::<Vec<u16>>::new(len_slot, address);
1775
1776            // Store → Load roundtrip
1777            vec_slot.write(data.clone())?;
1778            let loaded: Vec<u16> = vec_slot.read()?;
1779            prop_assert_eq!(&loaded, &data, "Vec<u16> roundtrip failed");
1780
1781            // Delete + verify cleanup
1782            vec_slot.delete()?;
1783            let after_delete: Vec<u16> = vec_slot.read()?;
1784            prop_assert!(after_delete.is_empty(), "Vec not empty after delete");
1785
1786            // Verify data slots are cleared (if length > 0)
1787            if data_len > 0 {
1788                let data_start = calc_data_slot(len_slot);
1789                let byte_count = u16::BYTES;
1790                let slot_count = calc_packed_slot_count(data_len, byte_count);
1791
1792                for i in 0..slot_count {
1793                    let slot_value = U256::handle(data_start + U256::from(i), LayoutCtx::FULL, address).read()?;
1794                    prop_assert_eq!(slot_value, U256::ZERO, "Data slot {} not cleared", i);
1795                }
1796            }
1797
1798                Ok(())
1799            }).unwrap();
1800        }
1801
1802        #[test]
1803        fn proptest_vec_u32_roundtrip(data in arb_u32_vec(100), len_slot in arb_safe_slot()) {
1804            let (mut storage, address) = setup_storage();
1805
1806            StorageCtx::enter(&mut storage, || {
1807                let data_len = data.len();
1808            let mut vec_slot = Slot::<Vec<u32>>::new(len_slot, address);
1809
1810            // Store → Load roundtrip
1811            vec_slot.write(data.clone())?;
1812            let loaded: Vec<u32> = vec_slot.read()?;
1813            prop_assert_eq!(&loaded, &data, "Vec<u32> roundtrip failed");
1814
1815            // Delete + verify cleanup
1816            vec_slot.delete()?;
1817            let after_delete: Vec<u32> = vec_slot.read()?;
1818            prop_assert!(after_delete.is_empty(), "Vec not empty after delete");
1819
1820            // Verify data slots are cleared (if length > 0)
1821            if data_len > 0 {
1822                let data_start = calc_data_slot(len_slot);
1823                let byte_count = u32::BYTES;
1824                let slot_count = calc_packed_slot_count(data_len, byte_count);
1825
1826                for i in 0..slot_count {
1827                    let slot_value = U256::handle(data_start + U256::from(i), LayoutCtx::FULL, address).read()?;
1828                    prop_assert_eq!(slot_value, U256::ZERO, "Data slot {} not cleared", i);
1829                }
1830            }
1831
1832                Ok(())
1833            }).unwrap();
1834        }
1835
1836        #[test]
1837        fn proptest_vec_u64_roundtrip(data in arb_u64_vec(100), len_slot in arb_safe_slot()) {
1838            let (mut storage, address) = setup_storage();
1839
1840            StorageCtx::enter(&mut storage, || {
1841                let data_len = data.len();
1842            let mut vec_slot = Slot::<Vec<u64>>::new(len_slot, address);
1843
1844            // Store → Load roundtrip
1845            vec_slot.write(data.clone())?;
1846            let loaded: Vec<u64> = vec_slot.read()?;
1847            prop_assert_eq!(&loaded, &data, "Vec<u64> roundtrip failed");
1848
1849            // Delete + verify cleanup
1850            vec_slot.delete()?;
1851            let after_delete: Vec<u64> = vec_slot.read()?;
1852            prop_assert!(after_delete.is_empty(), "Vec not empty after delete");
1853
1854            // Verify data slots are cleared (if length > 0)
1855            if data_len > 0 {
1856                let data_start = calc_data_slot(len_slot);
1857                let byte_count = u64::BYTES;
1858                let slot_count = calc_packed_slot_count(data_len, byte_count);
1859
1860                for i in 0..slot_count {
1861                    let slot_value = U256::handle(data_start + U256::from(i), LayoutCtx::FULL, address).read()?;
1862                    prop_assert_eq!(slot_value, U256::ZERO, "Data slot {} not cleared", i);
1863                }
1864            }
1865
1866                Ok(())
1867            }).unwrap();
1868        }
1869
1870        #[test]
1871        fn proptest_vec_u128_roundtrip(data in arb_u128_vec(50), len_slot in arb_safe_slot()) {
1872            let (mut storage, address) = setup_storage();
1873
1874            StorageCtx::enter(&mut storage, || {
1875                let data_len = data.len();
1876            let mut vec_slot = Slot::<Vec<u128>>::new(len_slot, address);
1877
1878            // Store → Load roundtrip
1879            vec_slot.write(data.clone())?;
1880            let loaded: Vec<u128> = vec_slot.read()?;
1881            prop_assert_eq!(&loaded, &data, "Vec<u128> roundtrip failed");
1882
1883            // Delete + verify cleanup
1884            vec_slot.delete()?;
1885            let after_delete: Vec<u128> = vec_slot.read()?;
1886            prop_assert!(after_delete.is_empty(), "Vec not empty after delete");
1887
1888            // Verify data slots are cleared (if length > 0)
1889            if data_len > 0 {
1890                let data_start = calc_data_slot(len_slot);
1891                let byte_count = u128::BYTES;
1892                let slot_count = calc_packed_slot_count(data_len, byte_count);
1893
1894                for i in 0..slot_count {
1895                    let slot_value = U256::handle(data_start + U256::from(i), LayoutCtx::FULL, address).read()?;
1896                    prop_assert_eq!(slot_value, U256::ZERO, "Data slot {} not cleared", i);
1897                }
1898            }
1899
1900                Ok(())
1901            }).unwrap();
1902        }
1903
1904        #[test]
1905        fn proptest_vec_u256_roundtrip(data in arb_u256_vec(50), len_slot in arb_safe_slot()) {
1906            let (mut storage, address) = setup_storage();
1907
1908            StorageCtx::enter(&mut storage, || {
1909                let data_len = data.len();
1910            let mut vec_slot = Slot::<Vec<U256>>::new(len_slot, address);
1911
1912            // Store → Load roundtrip
1913            vec_slot.write(data.clone())?;
1914            let loaded: Vec<U256> = vec_slot.read()?;
1915            prop_assert_eq!(&loaded, &data, "Vec<U256> roundtrip failed");
1916
1917            // Delete + verify cleanup
1918            vec_slot.delete()?;
1919            let after_delete: Vec<U256> = vec_slot.read()?;
1920            prop_assert!(after_delete.is_empty(), "Vec not empty after delete");
1921
1922            // Verify data slots are cleared (if length > 0)
1923            if data_len > 0 {
1924                let data_start = calc_data_slot(len_slot);
1925
1926                for i in 0..data_len {
1927                    let slot_value = U256::handle(data_start + U256::from(i), LayoutCtx::FULL, address).read()?;
1928                    prop_assert_eq!(slot_value, U256::ZERO, "Data slot {} not cleared", i);
1929                }
1930            }
1931
1932                Ok(())
1933            }).unwrap();
1934        }
1935
1936        #[test]
1937        fn proptest_vec_address_roundtrip(data in arb_address_vec(50), len_slot in arb_safe_slot()) {
1938            let (mut storage, address) = setup_storage();
1939
1940            StorageCtx::enter(&mut storage, || {
1941                let data_len = data.len();
1942            let mut vec_slot = Slot::<Vec<Address>>::new(len_slot, address);
1943
1944            // Store → Load roundtrip
1945            vec_slot.write(data.clone())?;
1946            let loaded: Vec<Address> = vec_slot.read()?;
1947            prop_assert_eq!(&loaded, &data, "Vec<Address> roundtrip failed");
1948
1949            // Delete + verify cleanup
1950            vec_slot.delete()?;
1951            let after_delete: Vec<Address> = vec_slot.read()?;
1952            prop_assert!(after_delete.is_empty(), "Vec not empty after delete");
1953
1954                // Verify data slots are cleared (if length > 0)
1955                // Address is 20 bytes, but 32 % 20 != 0, so they don't pack and each uses one slot
1956                if data_len > 0 {
1957                    let data_start = calc_data_slot(len_slot);
1958
1959                    for i in 0..data_len {
1960                        let slot_value = U256::handle(data_start + U256::from(i), LayoutCtx::FULL, address).read()?;
1961                        prop_assert_eq!(slot_value, U256::ZERO, "Data slot {} not cleared", i);
1962                    }
1963                }
1964
1965                Ok(())
1966            }).unwrap();
1967        }
1968
1969        #[test]
1970        fn proptest_vec_delete(data in arb_u8_vec(100), len_slot in arb_safe_slot()) {
1971            let (mut storage, address) = setup_storage();
1972
1973            StorageCtx::enter(&mut storage, || {
1974                let mut vec_slot = Slot::<Vec<u8>>::new(len_slot, address);
1975
1976            // Store data
1977            vec_slot.write(data.clone())?;
1978
1979            // Delete
1980            vec_slot.delete()?;
1981
1982            // Verify empty after delete
1983            let loaded: Vec<u8> = vec_slot.read()?;
1984            prop_assert!(loaded.is_empty(), "Vec not empty after delete");
1985
1986                // Verify data slots are cleared (if length > 0)
1987                if !data.is_empty() {
1988                    let data_start = calc_data_slot(len_slot);
1989                    let byte_count = u8::BYTES;
1990                    let slot_count = calc_packed_slot_count(data.len(), byte_count);
1991
1992                    for i in 0..slot_count {
1993                        let slot_value = U256::handle(data_start + U256::from(i), LayoutCtx::FULL, address).read()?;
1994                        prop_assert_eq!(slot_value, U256::ZERO, "Data slot {} not cleared", i);
1995                    }
1996                }
1997
1998                Ok(())
1999            }).unwrap();
2000        }
2001
2002        #[test]
2003        fn proptest_vec_struct_roundtrip(data in arb_test_struct_vec(50), len_slot in arb_safe_slot()) {
2004            let (mut storage, address) = setup_storage();
2005
2006            StorageCtx::enter(&mut storage, || {
2007                let data_len = data.len();
2008            let mut vec_slot = Slot::<Vec<TestStruct>>::new(len_slot, address);
2009
2010            // Store → Load roundtrip
2011            vec_slot.write(data.clone())?;
2012            let loaded: Vec<TestStruct> = vec_slot.read()?;
2013            prop_assert_eq!(&loaded, &data, "Vec<TestStruct> roundtrip failed");
2014
2015            // Delete + verify cleanup
2016            vec_slot.delete()?;
2017            let after_delete: Vec<TestStruct> = vec_slot.read()?;
2018            prop_assert!(after_delete.is_empty(), "Vec not empty after delete");
2019
2020                // Verify data slots are cleared (if length > 0)
2021                if data_len > 0 {
2022                    let data_start = calc_data_slot(len_slot);
2023
2024                    for i in 0..data_len {
2025                        let slot_value = U256::handle(data_start + U256::from(i), LayoutCtx::FULL, address).read()?;
2026                        prop_assert_eq!(slot_value, U256::ZERO, "Data slot {} not cleared", i);
2027                    }
2028                }
2029
2030                Ok(())
2031            }).unwrap();
2032        }
2033    }
2034}