Skip to content

Commit 1a3ea40

Browse files
committed
feat: add UPPER_BOUND & LOWER_BOUND to all our new types
1 parent 7b24a2a commit 1a3ea40

File tree

3 files changed

+75
-10
lines changed

3 files changed

+75
-10
lines changed

crates/starknet-types-core/src/contract_address.rs

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,7 @@ use core::str::FromStr;
99

1010
use crate::{
1111
felt::Felt,
12-
patricia_key::{
13-
PatriciaKey, PatriciaKeyFromFeltError, PatriciaKeyFromStrError, PATRICIA_KEY_UPPER_BOUND,
14-
},
12+
patricia_key::{PatriciaKey, PatriciaKeyFromFeltError, PatriciaKeyFromStrError},
1513
};
1614

1715
#[repr(transparent)]
@@ -29,6 +27,11 @@ impl ContractAddress {
2927
pub const ONE: Self = Self::from_hex_unchecked("0x1");
3028
pub const TWO: Self = Self::from_hex_unchecked("0x2");
3129
pub const THREE: Self = Self::from_hex_unchecked("0x3");
30+
31+
/// Lower inclusive bound
32+
pub const LOWER_BOUND: Self = Self::ZERO;
33+
/// Upper non-inclusive bound
34+
pub const UPPER_BOUND: Self = Self(PatriciaKey::UPPER_BOUND);
3235
}
3336

3437
impl core::fmt::Display for ContractAddress {
@@ -78,7 +81,7 @@ impl TryFrom<Felt> for ContractAddress {
7881
impl Felt {
7982
/// Validates that a Felt value represents a valid Starknet contract address.
8083
pub fn is_valid_contract_address(&self) -> bool {
81-
self < &PATRICIA_KEY_UPPER_BOUND
84+
self < &Felt::from(ContractAddress::UPPER_BOUND)
8285
}
8386
}
8487

@@ -91,6 +94,11 @@ impl FromStr for ContractAddress {
9194
}
9295

9396
impl ContractAddress {
97+
/// Create a new [ContractAddress] from an hex encoded string without checking it is a valid value.
98+
///
99+
/// Should NEVER be used on user inputs,
100+
/// as it can cause erroneous execution if dynamically initialized with bad values.
101+
/// Should mostly be used at compilation time on hardcoded static string.
94102
pub const fn from_hex_unchecked(s: &'static str) -> ContractAddress {
95103
let patricia_key = PatriciaKey::from_hex_unchecked(s);
96104

@@ -110,8 +118,6 @@ mod test {
110118

111119
#[test]
112120
fn basic_values() {
113-
assert!(ContractAddress::try_from(Felt::ZERO).is_err());
114-
assert!(ContractAddress::try_from(Felt::ONE).is_err());
115121
assert!(ContractAddress::try_from(PATRICIA_KEY_UPPER_BOUND).is_err());
116122

117123
let felt = Felt::TWO;

crates/starknet-types-core/src/patricia_key.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,13 @@ pub const PATRICIA_KEY_UPPER_BOUND: Felt =
2525
)]
2626
pub struct PatriciaKey(Felt);
2727

28+
impl PatriciaKey {
29+
/// Lower inclusive bound
30+
pub const LOWER_BOUND: Self = Self(Felt::ZERO);
31+
/// Upper non-inclusive bound
32+
pub const UPPER_BOUND: Self = Self(PATRICIA_KEY_UPPER_BOUND);
33+
}
34+
2835
impl core::fmt::Display for PatriciaKey {
2936
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
3037
write!(f, "{}", self.0)
@@ -110,6 +117,11 @@ impl FromStr for PatriciaKey {
110117
}
111118

112119
impl PatriciaKey {
120+
/// Create a new [PatriciaKey] from an hex encoded string without checking it is a valid value.
121+
///
122+
/// Should NEVER be used on user inputs,
123+
/// as it can cause erroneous execution if dynamically initialized with bad values.
124+
/// Should mostly be used at compilation time on hardcoded static string.
113125
pub const fn from_hex_unchecked(s: &'static str) -> PatriciaKey {
114126
let felt = Felt::from_hex_unwrap(s);
115127

crates/starknet-types-core/src/regular_contract_address.rs

Lines changed: 51 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,7 @@ use core::str::FromStr;
1616
use 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
)]
3230
pub 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+
3439
impl 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

220226
impl 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

Comments
 (0)