tempo_precompiles/storage/types/
vec.rs

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