Skip to main content

tempo_precompiles/storage/types/
primitives.rs

1//! `StorableType`, `FromWord`, and `StorageKey` implementations for single-word primitives.
2//!
3//! Covers Rust integers, Alloy integers, Alloy fixed bytes, `bool`, and `Address`.
4
5use alloy::primitives::{Address, U256};
6use revm::interpreter::instructions::utility::{IntoAddress, IntoU256};
7use tempo_precompiles_macros;
8
9use crate::storage::types::*;
10
11// rust integers: (u)int8, (u)int16, (u)int32, (u)int64, (u)int128
12tempo_precompiles_macros::storable_rust_ints!();
13// alloy integers: U8, I8, U16, I16, U32, I32, U64, I64, U128, I128, U256, I256
14tempo_precompiles_macros::storable_alloy_ints!();
15// alloy fixed bytes: FixedBytes<1>, FixedBytes<2>, ..., FixedBytes<32>
16tempo_precompiles_macros::storable_alloy_bytes!();
17
18// -- MANUAL STORAGE TRAIT IMPLEMENTATIONS -------------------------------------
19
20impl StorableType for bool {
21    const LAYOUT: Layout = Layout::Bytes(1);
22
23    type Handler = Slot<Self>;
24
25    fn handle(slot: U256, ctx: LayoutCtx, address: Address) -> Self::Handler {
26        Slot::new_with_ctx(slot, ctx, address)
27    }
28}
29
30impl super::sealed::OnlyPrimitives for bool {}
31impl Packable for bool {}
32impl FromWord for bool {
33    #[inline]
34    fn to_word(&self) -> U256 {
35        if *self { U256::ONE } else { U256::ZERO }
36    }
37
38    #[inline]
39    fn from_word(word: U256) -> crate::error::Result<Self> {
40        Ok(!word.is_zero())
41    }
42}
43
44impl StorageKey for bool {
45    #[inline]
46    fn as_storage_bytes(&self) -> impl AsRef<[u8]> {
47        if *self { [1u8] } else { [0u8] }
48    }
49}
50
51impl StorableType for Address {
52    const LAYOUT: Layout = Layout::Bytes(20);
53    type Handler = Slot<Self>;
54
55    fn handle(slot: U256, ctx: LayoutCtx, address: Address) -> Self::Handler {
56        Slot::new_with_ctx(slot, ctx, address)
57    }
58}
59
60impl super::sealed::OnlyPrimitives for Address {}
61impl Packable for Address {}
62impl FromWord for Address {
63    #[inline]
64    fn to_word(&self) -> U256 {
65        self.into_u256()
66    }
67
68    #[inline]
69    fn from_word(word: U256) -> crate::error::Result<Self> {
70        Ok(word.into_address())
71    }
72}
73
74impl StorageKey for Address {
75    #[inline]
76    fn as_storage_bytes(&self) -> impl AsRef<[u8]> {
77        self.as_slice()
78    }
79}
80
81#[cfg(test)]
82mod tests {
83    use super::*;
84    use crate::{
85        storage::{Handler, PrecompileStorageProvider, StorageCtx},
86        test_util::{gen_word_from, setup_storage},
87    };
88    use proptest::prelude::*;
89
90    // Strategy for generating random U256 slot values that won't overflow
91    fn arb_safe_slot() -> impl Strategy<Value = U256> {
92        any::<[u64; 4]>().prop_map(|limbs| {
93            // Ensure we don't overflow by limiting to a reasonable range
94            U256::from_limbs(limbs) % (U256::MAX - U256::from(10000))
95        })
96    }
97
98    // Strategy for generating arbitrary addresses
99    fn arb_address() -> impl Strategy<Value = Address> {
100        any::<[u8; 20]>().prop_map(Address::from)
101    }
102
103    // -- STORAGE TESTS --------------------------------------------------------
104
105    // Generate property tests for all storage types:
106    // - rust integers: (u)int8, (u)int16, (u)int32, (u)int64, (u)int128
107    // - alloy integers: U8, I8, U16, I16, U32, I32, U64, I64, U128, I128, U256, I256
108    // - alloy fixed bytes: FixedBytes<1>, FixedBytes<2>, ..., FixedBytes<32>
109    tempo_precompiles_macros::gen_storable_tests!();
110    proptest! {
111        #![proptest_config(ProptestConfig::with_cases(500))]
112
113        #[test]
114        fn test_address(addr in arb_address(), base_slot in arb_safe_slot()) {
115            let (mut storage, address) = setup_storage();
116            StorageCtx::enter(&mut storage, || {
117                let mut slot = Address::handle(base_slot, LayoutCtx::FULL, address);
118
119                // Verify store → load roundtrip
120                slot.write(addr).unwrap();
121                let loaded = slot.read().unwrap();
122                assert_eq!(addr, loaded, "Address roundtrip failed");
123
124                // Verify delete works
125                slot.delete().unwrap();
126                let after_delete = slot.read().unwrap();
127                assert_eq!(after_delete, Address::ZERO, "Address not zero after delete");
128
129                // EVM word roundtrip
130                let word = addr.to_word();
131                let recovered = <Address as FromWord>::from_word(word).unwrap();
132                assert_eq!(addr, recovered, "Address EVM word roundtrip failed");
133            });
134        }
135
136        #[test]
137        fn test_bool_values(b in any::<bool>(), base_slot in arb_safe_slot()) {
138            let (mut storage, address) = setup_storage();
139            StorageCtx::enter(&mut storage, || {
140                let mut slot = bool::handle(base_slot, LayoutCtx::FULL, address);
141
142                // Verify store → load roundtrip
143                slot.write(b).unwrap();
144                let loaded = slot.read().unwrap();
145                assert_eq!(b, loaded, "Bool roundtrip failed for value: {b}");
146
147                // Verify delete works
148                slot.delete().unwrap();
149                let after_delete = slot.read().unwrap();
150                assert!(!after_delete, "Bool not false after delete");
151
152                // EVM word roundtrip
153                let word = b.to_word();
154                let recovered = <bool as FromWord>::from_word(word).unwrap();
155                assert_eq!(b, recovered, "Bool EVM word roundtrip failed");
156            });
157        }
158    }
159
160    // -- WORD REPRESENTATION TESTS ------------------------------------------------
161
162    #[test]
163    fn test_unsigned_word_byte_representation() {
164        // u8: single byte, right-aligned
165        assert_eq!(0u8.to_word(), gen_word_from(&["0x00"]));
166        assert_eq!(1u8.to_word(), gen_word_from(&["0x01"]));
167        assert_eq!(255u8.to_word(), gen_word_from(&["0xFF"]));
168        assert!(u8::from_word(gen_word_from(&["0x0100"])).is_err()); // 256, doesn't fit in u8
169
170        // u16: 2 bytes, right-aligned
171        assert_eq!(0u16.to_word(), gen_word_from(&["0x0000"]));
172        assert_eq!(256u16.to_word(), gen_word_from(&["0x0100"]));
173        assert_eq!(u16::MAX.to_word(), gen_word_from(&["0xFFFF"]));
174        assert!(u16::from_word(gen_word_from(&["0x010000"])).is_err()); // 2**16 + 1 doesn't fit in u16
175
176        // u32: 4 bytes, right-aligned
177        assert_eq!(0u32.to_word(), gen_word_from(&["0x00000000"]));
178        assert_eq!(0x12345678u32.to_word(), gen_word_from(&["0x12345678"]));
179        assert_eq!(u32::MAX.to_word(), gen_word_from(&["0xFFFFFFFF"]));
180
181        // u64: 8 bytes, right-aligned
182        assert_eq!(0u64.to_word(), gen_word_from(&["0x0000000000000000"]));
183        assert_eq!(
184            0x123456789ABCDEFu64.to_word(),
185            gen_word_from(&["0x0123456789ABCDEF"])
186        );
187        assert_eq!(u64::MAX.to_word(), gen_word_from(&["0xFFFFFFFFFFFFFFFF"]));
188
189        // u128: 16 bytes, right-aligned
190        assert_eq!(
191            0u128.to_word(),
192            gen_word_from(&["0x00000000000000000000000000000000"])
193        );
194        assert_eq!(
195            u128::MAX.to_word(),
196            gen_word_from(&["0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"])
197        );
198    }
199
200    #[test]
201    fn test_signed_word_byte_representation() {
202        // i8: single byte, right-aligned, two's complement
203        assert_eq!(0i8.to_word(), gen_word_from(&["0x00"]));
204        assert_eq!(1i8.to_word(), gen_word_from(&["0x01"]));
205        assert_eq!((-1i8).to_word(), gen_word_from(&["0xFF"]));
206        assert_eq!((-2i8).to_word(), gen_word_from(&["0xFE"]));
207        assert_eq!(127i8.to_word(), gen_word_from(&["0x7F"])); // i8::MAX
208        assert_eq!((-128i8).to_word(), gen_word_from(&["0x80"])); // i8::MIN
209        assert!(i8::from_word(gen_word_from(&["0x0100"])).is_err()); // 256, doesn't fit in u8
210
211        // i16: 2 bytes, right-aligned, two's complement
212        assert_eq!(0i16.to_word(), gen_word_from(&["0x0000"]));
213        assert_eq!(1i16.to_word(), gen_word_from(&["0x0001"]));
214        assert_eq!((-1i16).to_word(), gen_word_from(&["0xFFFF"]));
215        assert_eq!((-2i16).to_word(), gen_word_from(&["0xFFFE"]));
216        assert_eq!(i16::MAX.to_word(), gen_word_from(&["0x7FFF"]));
217        assert_eq!(i16::MIN.to_word(), gen_word_from(&["0x8000"]));
218        assert!(i16::from_word(gen_word_from(&["0x010000"])).is_err()); // 2**16 + 1 doesn't fit in u16
219
220        // i32: 4 bytes, right-aligned, two's complement
221        assert_eq!(0i32.to_word(), gen_word_from(&["0x00000000"]));
222        assert_eq!(i32::MAX.to_word(), gen_word_from(&["0x7FFFFFFF"]));
223        assert_eq!((-1i32).to_word(), gen_word_from(&["0xFFFFFFFF"]));
224        assert_eq!(i32::MIN.to_word(), gen_word_from(&["0x80000000"]));
225
226        // i64: 8 bytes, right-aligned, two's complement
227        assert_eq!(0i64.to_word(), gen_word_from(&["0x0000000000000000"]));
228        assert_eq!(i64::MAX.to_word(), gen_word_from(&["0x7FFFFFFFFFFFFFFF"]));
229        assert_eq!((-1i64).to_word(), gen_word_from(&["0xFFFFFFFFFFFFFFFF"]));
230        assert_eq!(i64::MIN.to_word(), gen_word_from(&["0x8000000000000000"]));
231
232        // i128: 16 bytes, right-aligned, two's complement
233        assert_eq!(
234            0i128.to_word(),
235            gen_word_from(&["0x00000000000000000000000000000000"])
236        );
237        assert_eq!(
238            i128::MAX.to_word(),
239            gen_word_from(&["0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"])
240        );
241        assert_eq!(
242            (-1i128).to_word(),
243            gen_word_from(&["0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"])
244        );
245        assert_eq!(
246            i128::MIN.to_word(),
247            gen_word_from(&["0x80000000000000000000000000000000"])
248        );
249    }
250
251    // -- PRIMITIVE SLOT CONTENT VALIDATION TESTS ----------------------------------
252
253    #[test]
254    fn test_u8_at_various_offsets() {
255        let (mut storage, address) = setup_storage();
256        let base_slot = U256::from(100);
257
258        // Test u8 at offset 0
259        let val0: u8 = 0x42;
260        StorageCtx::enter(&mut storage, || {
261            let mut slot0 = u8::handle(base_slot, LayoutCtx::packed(0), address);
262            slot0.write(val0).unwrap();
263
264            // Verify with Slot read
265            let read_val = slot0.read().unwrap();
266            assert_eq!(read_val, val0);
267        });
268
269        // Verify with low-level read
270        let loaded_slot = storage.sload(address, base_slot).unwrap();
271        let expected = gen_word_from(&["0x42"]);
272        assert_eq!(loaded_slot, expected);
273
274        // Clear with low-level write
275        storage.sstore(address, base_slot, U256::ZERO).unwrap();
276
277        // Verify with Slot read
278        StorageCtx::enter(&mut storage, || {
279            let slot0 = u8::handle(base_slot, LayoutCtx::packed(0), address);
280            let cleared_val = slot0.read().unwrap();
281            assert_eq!(cleared_val, 0u8);
282        });
283
284        // Test u8 at offset 15 (middle)
285        let val15: u8 = 0xAB;
286        StorageCtx::enter(&mut storage, || {
287            let mut slot15 = u8::handle(base_slot + U256::ONE, LayoutCtx::packed(15), address);
288            slot15.write(val15).unwrap();
289
290            // Verify with Slot read
291            let read_val = slot15.read().unwrap();
292            assert_eq!(read_val, val15);
293        });
294
295        // Verify with low-level read
296        let loaded_slot = storage.sload(address, base_slot + U256::ONE).unwrap();
297        let expected = gen_word_from(&[
298            "0xAB",                             // offset 15 (1 byte)
299            "0x000000000000000000000000000000", // padding (15 bytes)
300        ]);
301        assert_eq!(loaded_slot, expected);
302
303        // Clear with low-level write
304        storage
305            .sstore(address, base_slot + U256::ONE, U256::ZERO)
306            .unwrap();
307
308        // Verify with Slot read
309        StorageCtx::enter(&mut storage, || {
310            let slot15 = u8::handle(base_slot + U256::ONE, LayoutCtx::packed(15), address);
311            let cleared_val = slot15.read().unwrap();
312            assert_eq!(cleared_val, 0u8);
313        });
314
315        // Test u8 at offset 31 (last byte)
316        let val31: u8 = 0xFF;
317        StorageCtx::enter(&mut storage, || {
318            let mut slot31 = u8::handle(base_slot + U256::from(2), LayoutCtx::packed(31), address);
319            slot31.write(val31).unwrap();
320
321            // Verify with Slot read
322            let read_val = slot31.read().unwrap();
323            assert_eq!(read_val, val31);
324        });
325
326        // Verify with low-level read
327        let loaded_slot = storage.sload(address, base_slot + U256::from(2)).unwrap();
328        let expected = gen_word_from(&[
329            "0xFF",                                                             // offset 31 (1 byte)
330            "0x00000000000000000000000000000000000000000000000000000000000000", // padding (31 bytes)
331        ]);
332        assert_eq!(loaded_slot, expected);
333
334        // Clear with low-level write
335        storage
336            .sstore(address, base_slot + U256::from(2), U256::ZERO)
337            .unwrap();
338
339        // Verify with Slot read
340        StorageCtx::enter(&mut storage, || {
341            let slot31 = u8::handle(base_slot + U256::from(2), LayoutCtx::packed(31), address);
342            let cleared_val = slot31.read().unwrap();
343            assert_eq!(cleared_val, 0u8);
344        });
345    }
346
347    #[test]
348    fn test_u16_at_various_offsets() {
349        let (mut storage, address) = setup_storage();
350        let base_slot = U256::from(200);
351
352        // Test u16 at offset 0
353        let val0: u16 = 0x1234;
354        StorageCtx::enter(&mut storage, || {
355            let mut slot0 = u16::handle(base_slot, LayoutCtx::packed(0), address);
356            slot0.write(val0).unwrap();
357
358            // Verify with Slot read
359            let read_val = slot0.read().unwrap();
360            assert_eq!(read_val, val0);
361        });
362
363        // Verify with low-level read
364        let loaded_slot = storage.sload(address, base_slot).unwrap();
365        let expected = gen_word_from(&["0x1234"]);
366        assert_eq!(loaded_slot, expected);
367
368        // Clear with low-level write
369        storage.sstore(address, base_slot, U256::ZERO).unwrap();
370
371        // Verify with Slot read
372        StorageCtx::enter(&mut storage, || {
373            let slot0 = u16::handle(base_slot, LayoutCtx::packed(0), address);
374            let cleared_val = slot0.read().unwrap();
375            assert_eq!(cleared_val, 0u16);
376        });
377
378        // Test u16 at offset 15 (middle)
379        let val15: u16 = 0xABCD;
380        StorageCtx::enter(&mut storage, || {
381            let mut slot15 = u16::handle(base_slot + U256::ONE, LayoutCtx::packed(15), address);
382            slot15.write(val15).unwrap();
383
384            // Verify with Slot read
385            let read_val = slot15.read().unwrap();
386            assert_eq!(read_val, val15);
387        });
388
389        // Verify with low-level read
390        let loaded_slot = storage.sload(address, base_slot + U256::ONE).unwrap();
391        let expected = gen_word_from(&[
392            "0xABCD",                           // offset 15 (2 bytes)
393            "0x000000000000000000000000000000", // padding (15 bytes)
394        ]);
395        assert_eq!(loaded_slot, expected);
396
397        // Clear with low-level write
398        storage
399            .sstore(address, base_slot + U256::ONE, U256::ZERO)
400            .unwrap();
401
402        // Verify with Slot read
403        StorageCtx::enter(&mut storage, || {
404            let slot15 = u16::handle(base_slot + U256::ONE, LayoutCtx::packed(15), address);
405            let cleared_val = slot15.read().unwrap();
406            assert_eq!(cleared_val, 0u16);
407        });
408
409        // Test u16 at offset 30 (last 2 bytes)
410        let val30: u16 = 0xFFEE;
411        StorageCtx::enter(&mut storage, || {
412            let mut slot30 = u16::handle(base_slot + U256::from(2), LayoutCtx::packed(30), address);
413            slot30.write(val30).unwrap();
414
415            // Verify with Slot read
416            let read_val = slot30.read().unwrap();
417            assert_eq!(read_val, val30);
418        });
419
420        // Verify with low-level read
421        let loaded_slot = storage.sload(address, base_slot + U256::from(2)).unwrap();
422        let expected = gen_word_from(&[
423            "0xFFEE",                                                         // offset 30 (2 bytes)
424            "0x000000000000000000000000000000000000000000000000000000000000", // padding (30 bytes)
425        ]);
426        assert_eq!(loaded_slot, expected);
427
428        // Clear with low-level write
429        storage
430            .sstore(address, base_slot + U256::from(2), U256::ZERO)
431            .unwrap();
432
433        // Verify with Slot read
434        StorageCtx::enter(&mut storage, || {
435            let slot30 = u16::handle(base_slot + U256::from(2), LayoutCtx::packed(30), address);
436            let cleared_val = slot30.read().unwrap();
437            assert_eq!(cleared_val, 0u16);
438        });
439    }
440
441    #[test]
442    fn test_u32_at_various_offsets() {
443        let (mut storage, address) = setup_storage();
444        let base_slot = U256::from(300);
445
446        // Test u32 at offset 0
447        let val0: u32 = 0x12345678;
448        StorageCtx::enter(&mut storage, || {
449            let mut slot0 = u32::handle(base_slot, LayoutCtx::packed(0), address);
450            slot0.write(val0).unwrap();
451
452            // Verify with Slot read
453            let read_val = slot0.read().unwrap();
454            assert_eq!(read_val, val0);
455        });
456
457        // Verify with low-level read
458        let loaded_slot = storage.sload(address, base_slot).unwrap();
459        let expected = gen_word_from(&["0x12345678"]);
460        assert_eq!(loaded_slot, expected);
461
462        // Clear with low-level write
463        storage.sstore(address, base_slot, U256::ZERO).unwrap();
464
465        // Verify with Slot read
466        StorageCtx::enter(&mut storage, || {
467            let slot0 = u32::handle(base_slot, LayoutCtx::packed(0), address);
468            let cleared_val = slot0.read().unwrap();
469            assert_eq!(cleared_val, 0u32);
470        });
471
472        // Test u32 at offset 14
473        let val14: u32 = 0xABCDEF01;
474        StorageCtx::enter(&mut storage, || {
475            let mut slot14 = u32::handle(base_slot + U256::ONE, LayoutCtx::packed(14), address);
476            slot14.write(val14).unwrap();
477
478            // Verify with Slot read
479            let read_val = slot14.read().unwrap();
480            assert_eq!(read_val, val14);
481        });
482
483        // Verify with low-level read
484        let loaded_slot = storage.sload(address, base_slot + U256::ONE).unwrap();
485        let expected = gen_word_from(&[
486            "0xABCDEF01",                     // offset 14 (4 bytes)
487            "0x0000000000000000000000000000", // padding (14 bytes)
488        ]);
489        assert_eq!(loaded_slot, expected);
490
491        // Clear with low-level write
492        storage
493            .sstore(address, base_slot + U256::ONE, U256::ZERO)
494            .unwrap();
495
496        // Verify with Slot read
497        StorageCtx::enter(&mut storage, || {
498            let slot14 = u32::handle(base_slot + U256::ONE, LayoutCtx::packed(14), address);
499            let cleared_val = slot14.read().unwrap();
500            assert_eq!(cleared_val, 0u32);
501        });
502
503        // Test u32 at offset 28 (last 4 bytes)
504        let val28: u32 = 0xFFEEDDCC;
505        StorageCtx::enter(&mut storage, || {
506            let mut slot28 = u32::handle(base_slot + U256::from(2), LayoutCtx::packed(28), address);
507            slot28.write(val28).unwrap();
508
509            // Verify with Slot read
510            let read_val = slot28.read().unwrap();
511            assert_eq!(read_val, val28);
512        });
513
514        // Verify with low-level read
515        let loaded_slot = storage.sload(address, base_slot + U256::from(2)).unwrap();
516        let expected = gen_word_from(&[
517            "0xFFEEDDCC",                                                 // offset 28 (4 bytes)
518            "0x00000000000000000000000000000000000000000000000000000000", // padding (28 bytes)
519        ]);
520        assert_eq!(loaded_slot, expected);
521
522        // Clear with low-level write
523        storage
524            .sstore(address, base_slot + U256::from(2), U256::ZERO)
525            .unwrap();
526
527        // Verify with Slot read
528        StorageCtx::enter(&mut storage, || {
529            let slot28 = u32::handle(base_slot + U256::from(2), LayoutCtx::packed(28), address);
530            let cleared_val = slot28.read().unwrap();
531            assert_eq!(cleared_val, 0u32);
532        });
533    }
534
535    #[test]
536    fn test_u64_at_various_offsets() {
537        let (mut storage, address) = setup_storage();
538        let base_slot = U256::from(400);
539
540        // Test u64 at offset 0
541        let val0: u64 = 0x123456789ABCDEF0;
542        StorageCtx::enter(&mut storage, || {
543            let mut slot0 = u64::handle(base_slot, LayoutCtx::packed(0), address);
544            slot0.write(val0).unwrap();
545
546            // Verify with Slot read
547            let read_val = slot0.read().unwrap();
548            assert_eq!(read_val, val0);
549        });
550
551        // Verify with low-level read
552        let loaded_slot = storage.sload(address, base_slot).unwrap();
553        let expected = gen_word_from(&["0x123456789ABCDEF0"]);
554        assert_eq!(loaded_slot, expected);
555
556        // Clear with low-level write
557        storage.sstore(address, base_slot, U256::ZERO).unwrap();
558
559        // Verify with Slot read
560        StorageCtx::enter(&mut storage, || {
561            let slot0 = u64::handle(base_slot, LayoutCtx::packed(0), address);
562            let cleared_val = slot0.read().unwrap();
563            assert_eq!(cleared_val, 0u64);
564        });
565
566        // Test u64 at offset 12 (middle)
567        let val12: u64 = 0xFEDCBA9876543210;
568        StorageCtx::enter(&mut storage, || {
569            let mut slot12 = u64::handle(base_slot + U256::ONE, LayoutCtx::packed(12), address);
570            slot12.write(val12).unwrap();
571
572            // Verify with Slot read
573            let read_val = slot12.read().unwrap();
574            assert_eq!(read_val, val12);
575        });
576
577        // Verify with low-level read
578        let loaded_slot = storage.sload(address, base_slot + U256::ONE).unwrap();
579        let expected = gen_word_from(&[
580            "0xFEDCBA9876543210",         // offset 12 (8 bytes)
581            "0x000000000000000000000000", // padding (12 bytes)
582        ]);
583        assert_eq!(loaded_slot, expected);
584
585        // Clear with low-level write
586        storage
587            .sstore(address, base_slot + U256::ONE, U256::ZERO)
588            .unwrap();
589
590        // Verify with Slot read
591        StorageCtx::enter(&mut storage, || {
592            let slot12 = u64::handle(base_slot + U256::ONE, LayoutCtx::packed(12), address);
593            let cleared_val = slot12.read().unwrap();
594            assert_eq!(cleared_val, 0u64);
595        });
596
597        // Test u64 at offset 24 (last 8 bytes)
598        let val24: u64 = 0xAAAABBBBCCCCDDDD;
599        StorageCtx::enter(&mut storage, || {
600            let mut slot24 = u64::handle(base_slot + U256::from(2), LayoutCtx::packed(24), address);
601            slot24.write(val24).unwrap();
602
603            // Verify with Slot read
604            let read_val = slot24.read().unwrap();
605            assert_eq!(read_val, val24);
606        });
607
608        // Verify with low-level read
609        let loaded_slot = storage.sload(address, base_slot + U256::from(2)).unwrap();
610        let expected = gen_word_from(&[
611            "0xAAAABBBBCCCCDDDD",                                 // offset 24 (8 bytes)
612            "0x000000000000000000000000000000000000000000000000", // padding (24 bytes)
613        ]);
614        assert_eq!(loaded_slot, expected);
615
616        // Clear with low-level write
617        storage
618            .sstore(address, base_slot + U256::from(2), U256::ZERO)
619            .unwrap();
620
621        // Verify with Slot read
622        StorageCtx::enter(&mut storage, || {
623            let slot24 = u64::handle(base_slot + U256::from(2), LayoutCtx::packed(24), address);
624            let cleared_val = slot24.read().unwrap();
625            assert_eq!(cleared_val, 0u64);
626        });
627    }
628
629    #[test]
630    fn test_u128_at_various_offsets() {
631        let (mut storage, address) = setup_storage();
632        let base_slot = U256::from(500);
633
634        // Test u128 at offset 0
635        let val0: u128 = 0x123456789ABCDEF0_FEDCBA9876543210;
636        StorageCtx::enter(&mut storage, || {
637            let mut slot0 = u128::handle(base_slot, LayoutCtx::packed(0), address);
638            slot0.write(val0).unwrap();
639
640            // Verify with Slot read
641            let read_val = slot0.read().unwrap();
642            assert_eq!(read_val, val0);
643        });
644
645        // Verify with low-level read
646        let loaded_slot = storage.sload(address, base_slot).unwrap();
647        let expected = gen_word_from(&["0x123456789ABCDEF0FEDCBA9876543210"]);
648        assert_eq!(loaded_slot, expected);
649
650        // Clear with low-level write
651        storage.sstore(address, base_slot, U256::ZERO).unwrap();
652
653        // Verify with Slot read
654        StorageCtx::enter(&mut storage, || {
655            let slot0 = u128::handle(base_slot, LayoutCtx::packed(0), address);
656            let cleared_val = slot0.read().unwrap();
657            assert_eq!(cleared_val, 0u128);
658        });
659
660        // Test u128 at offset 16 (second half of slot)
661        let val16: u128 = 0xAAAABBBBCCCCDDDD_1111222233334444;
662        StorageCtx::enter(&mut storage, || {
663            let mut slot16 = u128::handle(base_slot + U256::ONE, LayoutCtx::packed(16), address);
664            slot16.write(val16).unwrap();
665
666            // Verify with Slot read
667            let read_val = slot16.read().unwrap();
668            assert_eq!(read_val, val16);
669        });
670
671        // Verify with low-level read
672        let loaded_slot = storage.sload(address, base_slot + U256::ONE).unwrap();
673        let expected = gen_word_from(&[
674            "0xAAAABBBBCCCCDDDD1111222233334444", // offset 16 (16 bytes)
675            "0x00000000000000000000000000000000", // padding (16 bytes)
676        ]);
677        assert_eq!(loaded_slot, expected);
678
679        // Clear with low-level write
680        storage
681            .sstore(address, base_slot + U256::ONE, U256::ZERO)
682            .unwrap();
683
684        // Verify with Slot read
685        StorageCtx::enter(&mut storage, || {
686            let slot16 = u128::handle(base_slot + U256::ONE, LayoutCtx::packed(16), address);
687            let cleared_val = slot16.read().unwrap();
688            assert_eq!(cleared_val, 0u128);
689        });
690    }
691
692    #[test]
693    fn test_address_at_various_offsets() {
694        let (mut storage, address) = setup_storage();
695        let base_slot = U256::from(600);
696
697        // Test Address at offset 0
698        let addr0 = Address::from([0x12; 20]);
699        StorageCtx::enter(&mut storage, || {
700            let mut slot0 = Address::handle(base_slot, LayoutCtx::packed(0), address);
701            slot0.write(addr0).unwrap();
702
703            // Verify with Slot read
704            let read_val = slot0.read().unwrap();
705            assert_eq!(read_val, addr0);
706        });
707
708        // Verify with low-level read
709        let loaded_slot = storage.sload(address, base_slot).unwrap();
710        let expected = gen_word_from(&["0x1212121212121212121212121212121212121212"]);
711        assert_eq!(loaded_slot, expected);
712
713        // Clear with low-level write
714        storage.sstore(address, base_slot, U256::ZERO).unwrap();
715
716        // Verify with Slot read
717        StorageCtx::enter(&mut storage, || {
718            let slot0 = Address::handle(base_slot, LayoutCtx::packed(0), address);
719            let cleared_val = slot0.read().unwrap();
720            assert_eq!(cleared_val, Address::ZERO);
721        });
722
723        // Test Address at offset 12 (fits in one slot: 12 + 20 = 32)
724        let addr12 = Address::from([0xAB; 20]);
725        StorageCtx::enter(&mut storage, || {
726            let mut slot12 = Address::handle(base_slot + U256::ONE, LayoutCtx::packed(12), address);
727            slot12.write(addr12).unwrap();
728
729            // Verify with Slot read
730            let read_val = slot12.read().unwrap();
731            assert_eq!(read_val, addr12);
732        });
733
734        // Verify with low-level read
735        let loaded_slot = storage.sload(address, base_slot + U256::ONE).unwrap();
736        let expected = gen_word_from(&[
737            "0xABABABABABABABABABABABABABABABABABABABAB", // offset 12 (20 bytes)
738            "0x000000000000000000000000",                 // padding (12 bytes)
739        ]);
740        assert_eq!(loaded_slot, expected);
741
742        // Clear with low-level write
743        storage
744            .sstore(address, base_slot + U256::ONE, U256::ZERO)
745            .unwrap();
746
747        // Verify with Slot read
748        StorageCtx::enter(&mut storage, || {
749            let slot12 = Address::handle(base_slot + U256::ONE, LayoutCtx::packed(12), address);
750            let cleared_val = slot12.read().unwrap();
751            assert_eq!(cleared_val, Address::ZERO);
752        });
753    }
754
755    #[test]
756    fn test_bool_at_various_offsets() {
757        let (mut storage, address) = setup_storage();
758        let base_slot = U256::from(700);
759
760        // Test bool at offset 0
761        let val0 = true;
762        StorageCtx::enter(&mut storage, || {
763            let mut slot0 = bool::handle(base_slot, LayoutCtx::packed(0), address);
764            slot0.write(val0).unwrap();
765
766            // Verify with Slot read
767            let read_val = slot0.read().unwrap();
768            assert_eq!(read_val, val0);
769        });
770
771        // Verify with low-level read
772        let loaded_slot = storage.sload(address, base_slot).unwrap();
773        let expected = gen_word_from(&["0x01"]);
774        assert_eq!(loaded_slot, expected);
775
776        // Clear with low-level write
777        storage.sstore(address, base_slot, U256::ZERO).unwrap();
778
779        // Verify with Slot read
780        StorageCtx::enter(&mut storage, || {
781            let slot0 = bool::handle(base_slot, LayoutCtx::packed(0), address);
782            let cleared_val = slot0.read().unwrap();
783            assert!(!cleared_val);
784        });
785
786        // Test bool at offset 31
787        let val31 = false;
788        StorageCtx::enter(&mut storage, || {
789            let mut slot31 = bool::handle(base_slot + U256::ONE, LayoutCtx::packed(31), address);
790            slot31.write(val31).unwrap();
791
792            // Verify with Slot read
793            let read_val = slot31.read().unwrap();
794            assert_eq!(read_val, val31);
795        });
796
797        // Verify with low-level read
798        let loaded_slot = storage.sload(address, base_slot + U256::ONE).unwrap();
799        let expected = gen_word_from(&[
800            "0x00",                                                             // offset 31 (1 byte)
801            "0x00000000000000000000000000000000000000000000000000000000000000", // padding (31 bytes)
802        ]);
803        assert_eq!(loaded_slot, expected);
804
805        // Clear with low-level write
806        storage
807            .sstore(address, base_slot + U256::ONE, U256::ZERO)
808            .unwrap();
809
810        // Verify with Slot read
811        StorageCtx::enter(&mut storage, || {
812            let slot31 = bool::handle(base_slot + U256::ONE, LayoutCtx::packed(31), address);
813            let cleared_val = slot31.read().unwrap();
814            assert!(!cleared_val);
815        });
816    }
817
818    #[test]
819    fn test_u256_fills_entire_slot() {
820        let (mut storage, address) = setup_storage();
821        let base_slot = U256::from(800);
822
823        // U256 should always fill entire slot (offset must be 0)
824        let val = U256::from(0x123456789ABCDEFu64);
825        StorageCtx::enter(&mut storage, || {
826            let mut slot = Slot::<U256>::new(base_slot, address);
827            slot.write(val).unwrap();
828        });
829
830        let loaded_slot = storage.sload(address, base_slot).unwrap();
831        assert_eq!(loaded_slot, val, "U256 should match slot contents exactly");
832
833        // Verify it's stored as-is (no packing)
834        StorageCtx::enter(&mut storage, || {
835            let slot = Slot::<U256>::new(base_slot, address);
836            let recovered = slot.read().unwrap();
837            assert_eq!(recovered, val, "U256 load failed");
838        });
839    }
840
841    #[test]
842    fn test_primitive_delete_clears_slot() {
843        let (mut storage, address) = setup_storage();
844        let base_slot = U256::from(900);
845
846        // Store a u64 value
847        let val: u64 = 0x123456789ABCDEF0;
848        StorageCtx::enter(&mut storage, || {
849            let mut slot = Slot::<u64>::new(base_slot, address);
850            slot.write(val).unwrap();
851        });
852
853        // Verify slot is non-zero
854        let slot_before = storage.sload(address, base_slot).unwrap();
855        assert_ne!(
856            slot_before,
857            U256::ZERO,
858            "Slot should be non-zero before delete"
859        );
860
861        // Delete the value
862        StorageCtx::enter(&mut storage, || {
863            let mut slot = Slot::<u64>::new(base_slot, address);
864            slot.delete().unwrap();
865        });
866
867        // Verify slot is now zero
868        let slot_after = storage.sload(address, base_slot).unwrap();
869        assert_eq!(slot_after, U256::ZERO, "Slot should be zero after delete");
870
871        // Verify loading returns zero
872        StorageCtx::enter(&mut storage, || {
873            let slot = Slot::<u64>::new(base_slot, address);
874            let loaded = slot.read().unwrap();
875            assert_eq!(loaded, 0u64, "Loaded value should be 0 after delete");
876        });
877    }
878}