@@ -16,9 +16,7 @@ use core::str::FromStr;
1616use crate :: {
1717 contract_address:: ContractAddress ,
1818 felt:: Felt ,
19- patricia_key:: {
20- PatriciaKey , PatriciaKeyFromFeltError , PatriciaKeyFromStrError , PATRICIA_KEY_UPPER_BOUND ,
21- } ,
19+ patricia_key:: { PatriciaKey , PatriciaKeyFromFeltError , PatriciaKeyFromStrError } ,
2220} ;
2321
2422#[ repr( transparent) ]
@@ -31,6 +29,13 @@ use crate::{
3129) ]
3230pub struct RegularContractAddress ( ContractAddress ) ;
3331
32+ impl RegularContractAddress {
33+ /// Lower inclusive bound
34+ pub const LOWER_BOUND : Self = Self :: from_hex_unchecked ( "0x4" ) ;
35+ /// Upper non-inclusive bound
36+ pub const UPPER_BOUND : Self = Self ( ContractAddress :: UPPER_BOUND ) ;
37+ }
38+
3439impl core:: fmt:: Display for RegularContractAddress {
3540 fn fmt ( & self , f : & mut core:: fmt:: Formatter < ' _ > ) -> core:: fmt:: Result {
3641 write ! ( f, "{}" , self . 0 )
@@ -167,7 +172,8 @@ impl Felt {
167172 /// https://docs.starknet.io/learn/protocol/state#special-addresses
168173 /// https://github.com/starkware-libs/sequencer/blob/ecd4779abef7bf345938a69f18ef70b6239d3a50/crates/blockifier/resources/blockifier_versioned_constants_0_15_0.json#L92-L97
169174 pub fn is_regular_contract_address ( & self ) -> bool {
170- self > & Felt :: THREE && self < & PATRICIA_KEY_UPPER_BOUND
175+ self >= & Felt :: from ( RegularContractAddress :: LOWER_BOUND )
176+ && self < & Felt :: from ( RegularContractAddress :: UPPER_BOUND )
171177 }
172178}
173179
@@ -218,9 +224,50 @@ impl FromStr for RegularContractAddress {
218224}
219225
220226impl RegularContractAddress {
227+ /// Create a new [RegularContractAddress] from an hex encoded string without checking it is a valid value.
228+ ///
229+ /// Should NEVER be used on user inputs,
230+ /// as it can cause erroneous execution if dynamically initialized with bad values.
231+ /// Should mostly be used at compilation time on hardcoded static string.
221232 pub const fn from_hex_unchecked ( s : & ' static str ) -> RegularContractAddress {
222233 let contract_address = ContractAddress :: from_hex_unchecked ( s) ;
223234
224235 RegularContractAddress ( contract_address)
225236 }
226237}
238+
239+ #[ cfg( test) ]
240+ mod test {
241+ #[ cfg( feature = "alloc" ) ]
242+ pub extern crate alloc;
243+ use proptest:: prelude:: * ;
244+
245+ use crate :: {
246+ felt:: Felt , patricia_key:: PATRICIA_KEY_UPPER_BOUND ,
247+ regular_contract_address:: RegularContractAddress ,
248+ } ;
249+
250+ #[ test]
251+ fn basic_values ( ) {
252+ assert ! ( RegularContractAddress :: try_from( Felt :: ZERO ) . is_err( ) ) ;
253+ assert ! ( RegularContractAddress :: try_from( Felt :: ONE ) . is_err( ) ) ;
254+ assert ! ( RegularContractAddress :: try_from( Felt :: TWO ) . is_err( ) ) ;
255+ assert ! ( RegularContractAddress :: try_from( Felt :: THREE ) . is_err( ) ) ;
256+ assert ! ( RegularContractAddress :: try_from( PATRICIA_KEY_UPPER_BOUND ) . is_err( ) ) ;
257+
258+ let felt = Felt :: from_hex_unwrap ( "0xcaffe" ) ;
259+ let contract_address = RegularContractAddress :: try_from ( felt) . unwrap ( ) ;
260+ assert_eq ! ( Felt :: from( contract_address) , felt) ;
261+ }
262+
263+ proptest ! {
264+ #[ test]
265+ fn is_valid_match_try_into( ref x in any:: <Felt >( ) ) {
266+ if x. is_regular_contract_address( ) {
267+ prop_assert!( RegularContractAddress :: try_from( * x) . is_ok( ) ) ;
268+ } else {
269+ prop_assert!( RegularContractAddress :: try_from( * x) . is_err( ) ) ;
270+ }
271+ }
272+ }
273+ }
0 commit comments