1extern crate alloc;
2
3use miden_field_repr::{FromFeltRepr, ToFeltRepr};
4use miden_stdlib_sys::{Felt, Word, felt};
5
6pub fn padded_word_from_felt(value: Felt) -> Word {
8 Word::new([value, felt!(0), felt!(0), felt!(0)])
9}
10
11pub fn felt_from_padded_word(value: Word) -> Result<Felt, &'static str> {
13 if value[1] != felt!(0) || value[2] != felt!(0) || value[3] != felt!(0) {
14 return Err("expected zero padding in the trailing three felts");
15 }
16
17 Ok(value[0])
18}
19
20#[derive(Copy, Clone, Debug, PartialEq, Eq, FromFeltRepr, ToFeltRepr)]
22pub struct AccountId {
23 pub prefix: Felt,
24 pub suffix: Felt,
25}
26
27impl AccountId {
28 pub fn new(prefix: Felt, suffix: Felt) -> Self {
30 Self { prefix, suffix }
31 }
32}
33
34#[derive(Copy, Clone)]
37#[repr(C)]
38pub(crate) struct RawAccountId {
39 pub suffix: Felt,
40 pub prefix: Felt,
41}
42
43impl RawAccountId {
44 pub(crate) fn into_account_id(self) -> AccountId {
46 AccountId::new(self.prefix, self.suffix)
47 }
48}
49
50impl From<AccountId> for Word {
51 #[inline]
52 fn from(value: AccountId) -> Self {
53 Word::from([felt!(0), felt!(0), value.suffix, value.prefix])
54 }
55}
56
57impl TryFrom<Word> for AccountId {
58 type Error = &'static str;
59
60 #[inline]
61 fn try_from(value: Word) -> Result<Self, Self::Error> {
62 if value[0] != felt!(0) || value[1] != felt!(0) {
63 return Err("expected zero padding in the upper two felts");
64 }
65
66 Ok(Self {
67 prefix: value[3],
68 suffix: value[2],
69 })
70 }
71}
72
73#[derive(Copy, Clone, Debug, PartialEq, Eq, FromFeltRepr, ToFeltRepr)]
78#[repr(C)]
79pub struct Asset {
80 pub id: AssetId,
82 pub value: Word,
84}
85
86impl Asset {
87 pub fn new(id: impl Into<AssetId>, value: impl Into<Word>) -> Self {
89 Self {
90 id: id.into(),
91 value: value.into(),
92 }
93 }
94
95 #[inline]
97 pub fn id(&self) -> AssetId {
98 self.id
99 }
100
101 pub fn amount(&self) -> AssetAmount {
111 assert!(self.is_fungible(), "asset is not fungible");
112 let amount = self.value[0];
113 assert!(
114 amount <= AssetAmount::max_inner(),
115 "asset amount exceeds the maximum allowed amount"
116 );
117 AssetAmount { inner: amount }
118 }
119
120 #[inline]
129 pub fn is_fungible(&self) -> bool {
130 self.id.composition() == AssetComposition::Fungible
131 }
132}
133
134impl From<Asset> for (Word, Word) {
135 fn from(val: Asset) -> Self {
136 (val.id.inner, val.value)
137 }
138}
139
140#[derive(Copy, Clone, Debug, PartialEq, Eq, FromFeltRepr, ToFeltRepr)]
146#[repr(transparent)]
147pub struct AssetId {
148 pub inner: Word,
150}
151
152impl From<Word> for AssetId {
153 #[inline]
154 fn from(value: Word) -> Self {
155 Self { inner: value }
156 }
157}
158
159impl From<[Felt; 4]> for AssetId {
160 #[inline]
161 fn from(value: [Felt; 4]) -> Self {
162 Self {
163 inner: Word::from(value),
164 }
165 }
166}
167
168impl From<AssetId> for Word {
169 #[inline]
170 fn from(value: AssetId) -> Self {
171 value.inner
172 }
173}
174
175#[derive(Copy, Clone, Debug, PartialEq, Eq, FromFeltRepr, ToFeltRepr)]
180pub struct AssetClass {
181 pub prefix: Felt,
183 pub suffix: Felt,
185}
186
187impl AssetClass {
188 pub fn new(prefix: Felt, suffix: Felt) -> Self {
190 Self { prefix, suffix }
191 }
192}
193
194#[derive(Copy, Clone)]
197#[repr(C)]
198pub(crate) struct RawAssetClass {
199 pub suffix: Felt,
201 pub prefix: Felt,
203}
204
205impl RawAssetClass {
206 pub(crate) fn into_asset_class(self) -> AssetClass {
208 AssetClass::new(self.prefix, self.suffix)
209 }
210}
211
212#[derive(Copy, Clone, Debug, PartialEq, Eq)]
214pub enum AssetComposition {
215 None,
217 Fungible,
219 Custom,
221}
222
223impl TryFrom<Felt> for AssetComposition {
224 type Error = &'static str;
225
226 #[inline]
227 fn try_from(value: Felt) -> Result<Self, Self::Error> {
228 match value.as_canonical_u64() {
229 0 => Ok(Self::None),
230 1 => Ok(Self::Fungible),
231 2 => Ok(Self::Custom),
232 _ => Err("unrecognized asset composition"),
233 }
234 }
235}
236
237#[derive(Copy, Clone, Debug, PartialEq, Eq)]
239pub enum AssetAmountError {
240 AmountTooBig(u64),
242}
243
244impl core::fmt::Display for AssetAmountError {
245 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
246 match self {
247 Self::AmountTooBig(amount) => {
248 write!(f, "asset amount {amount} exceeds the maximum {}", AssetAmount::MAX_U64)
249 }
250 }
251 }
252}
253
254impl core::error::Error for AssetAmountError {}
255
256#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
270#[repr(transparent)]
271pub struct AssetAmount {
272 #[doc(hidden)]
278 pub inner: Felt,
279}
280
281impl AssetAmount {
282 pub const MAX_U64: u64 = (1u64 << 63) - (1u64 << 31);
289 pub const ZERO: Self = Self { inner: Felt::ZERO };
291
292 #[inline]
294 pub fn max() -> Self {
295 Self {
296 inner: Self::max_inner(),
297 }
298 }
299
300 pub fn new(amount: u64) -> Result<Self, AssetAmountError> {
306 if amount > Self::MAX_U64 {
307 return Err(AssetAmountError::AmountTooBig(amount));
308 }
309 Ok(Self {
311 inner: Felt::new_unchecked(amount),
312 })
313 }
314
315 #[inline]
317 pub fn as_u64(&self) -> u64 {
318 self.inner.as_canonical_u64()
319 }
320
321 #[inline]
323 pub fn as_felt(&self) -> Felt {
324 self.inner
325 }
326
327 #[inline(always)]
329 fn max_inner() -> Felt {
330 Felt::new_unchecked(Self::MAX_U64)
332 }
333
334 #[inline]
336 fn amount_too_big(value: Felt) -> AssetAmountError {
337 AssetAmountError::AmountTooBig(value.as_canonical_u64())
339 }
340}
341
342const _: () = assert!(AssetAmount::MAX_U64 * 2 == Felt::ORDER - 1);
345
346impl core::ops::Add for AssetAmount {
347 type Output = Self;
348
349 fn add(self, other: Self) -> Self {
355 let max = Self::max_inner();
356 assert!(self.inner <= max, "asset amount exceeds the maximum allowed amount");
359 let headroom = max - self.inner;
364 assert!(other.inner <= headroom, "asset amount addition overflow");
365 Self {
366 inner: self.inner + other.inner,
367 }
368 }
369}
370
371impl core::ops::Sub for AssetAmount {
372 type Output = Self;
373
374 fn sub(self, other: Self) -> Self {
381 let max = Self::max_inner();
382 assert!(self.inner <= max, "asset amount exceeds the maximum allowed amount");
385 assert!(other.inner <= self.inner, "asset amount subtraction underflow");
388 Self {
389 inner: self.inner - other.inner,
390 }
391 }
392}
393
394impl Default for AssetAmount {
395 fn default() -> Self {
396 Self::ZERO
397 }
398}
399
400impl From<u8> for AssetAmount {
401 fn from(value: u8) -> Self {
402 Self {
403 inner: Felt::from(value),
404 }
405 }
406}
407
408impl From<u16> for AssetAmount {
409 fn from(value: u16) -> Self {
410 Self {
411 inner: Felt::from(value),
412 }
413 }
414}
415
416impl From<u32> for AssetAmount {
417 fn from(value: u32) -> Self {
418 Self {
420 inner: Felt::from_u32(value),
421 }
422 }
423}
424
425impl TryFrom<u64> for AssetAmount {
426 type Error = AssetAmountError;
427
428 fn try_from(value: u64) -> Result<Self, Self::Error> {
429 Self::new(value)
430 }
431}
432
433impl TryFrom<Felt> for AssetAmount {
434 type Error = AssetAmountError;
435
436 fn try_from(value: Felt) -> Result<Self, Self::Error> {
437 if value > Self::max_inner() {
438 return Err(Self::amount_too_big(value));
439 }
440 Ok(Self { inner: value })
441 }
442}
443
444impl From<AssetAmount> for u64 {
445 fn from(amount: AssetAmount) -> Self {
446 amount.as_u64()
447 }
448}
449
450impl From<AssetAmount> for Felt {
451 fn from(amount: AssetAmount) -> Self {
452 amount.inner
453 }
454}
455
456impl core::fmt::Display for AssetAmount {
457 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
458 write!(f, "{}", self.as_u64())
459 }
460}
461
462#[derive(Clone, Debug, PartialEq, Eq, FromFeltRepr, ToFeltRepr)]
464#[repr(transparent)]
465pub struct Recipient {
466 pub inner: Word,
467}
468
469#[derive(Copy, Clone, Debug, PartialEq, Eq, FromFeltRepr, ToFeltRepr)]
472#[repr(transparent)]
473pub struct NoteId {
474 pub inner: Word,
476}
477
478impl From<Word> for NoteId {
479 #[inline]
480 fn from(value: Word) -> Self {
481 Self { inner: value }
482 }
483}
484
485impl From<NoteId> for Word {
486 #[inline]
487 fn from(value: NoteId) -> Self {
488 value.inner
489 }
490}
491
492#[derive(Copy, Clone)]
497#[repr(C)]
498pub(crate) struct RawCommitmentWithCount {
499 pub commitment: Word,
501 pub count: Felt,
503}
504
505impl RawCommitmentWithCount {
506 pub(crate) fn num_items(&self) -> u32 {
508 self.count.as_canonical_u64() as u32
510 }
511}
512
513#[derive(Copy, Clone, Debug, PartialEq, Eq)]
519#[repr(C)]
520pub struct NoteMetadata {
521 pub header: Word,
523}
524
525impl NoteMetadata {
526 pub fn new(header: Word) -> Self {
528 Self { header }
529 }
530}
531
532#[derive(Copy, Clone)]
536#[repr(C)]
537pub(crate) struct RawFoundIndex {
538 pub is_found: Felt,
540 pub index: Felt,
542}
543
544impl RawFoundIndex {
545 fn index(self) -> Option<Felt> {
547 (self.is_found != Felt::ZERO).then_some(self.index)
548 }
549
550 pub(crate) fn into_attachment_index(self) -> Option<u32> {
552 self.index().map(|index| index.as_canonical_u64() as u32)
554 }
555
556 pub(crate) fn into_note_index(self) -> Option<NoteIdx> {
558 self.index().map(|index| NoteIdx { inner: index })
559 }
560}
561
562impl From<[Felt; 4]> for Recipient {
563 fn from(value: [Felt; 4]) -> Self {
564 Recipient {
565 inner: Word::from(value),
566 }
567 }
568}
569
570impl From<Word> for Recipient {
571 fn from(value: Word) -> Self {
572 Recipient { inner: value }
573 }
574}
575
576impl From<Recipient> for Word {
577 #[inline]
578 fn from(value: Recipient) -> Self {
579 value.inner
580 }
581}
582
583#[derive(Clone, Copy, Debug, PartialEq, Eq, FromFeltRepr, ToFeltRepr)]
584#[repr(transparent)]
585pub struct Tag {
586 pub inner: Felt,
587}
588
589impl From<Felt> for Tag {
590 fn from(value: Felt) -> Self {
591 Tag { inner: value }
592 }
593}
594
595impl From<Tag> for Word {
596 #[inline]
597 fn from(value: Tag) -> Self {
598 padded_word_from_felt(value.inner)
599 }
600}
601
602impl TryFrom<Word> for Tag {
603 type Error = &'static str;
604
605 #[inline]
606 fn try_from(value: Word) -> Result<Self, Self::Error> {
607 Ok(Tag {
608 inner: felt_from_padded_word(value)?,
609 })
610 }
611}
612
613#[derive(Clone, Copy, Debug, PartialEq, Eq)]
614#[repr(transparent)]
615pub struct NoteIdx {
616 pub inner: Felt,
617}
618
619impl From<NoteIdx> for Word {
620 #[inline]
621 fn from(value: NoteIdx) -> Self {
622 padded_word_from_felt(value.inner)
623 }
624}
625
626impl TryFrom<Word> for NoteIdx {
627 type Error = &'static str;
628
629 #[inline]
630 fn try_from(value: Word) -> Result<Self, Self::Error> {
631 Ok(NoteIdx {
632 inner: felt_from_padded_word(value)?,
633 })
634 }
635}
636
637#[derive(Clone, Copy, Debug, PartialEq, Eq, FromFeltRepr, ToFeltRepr)]
638#[repr(transparent)]
639pub struct NoteType {
640 pub inner: Felt,
641}
642
643impl From<Felt> for NoteType {
644 fn from(value: Felt) -> Self {
645 NoteType { inner: value }
646 }
647}
648
649impl From<NoteType> for Word {
650 #[inline]
651 fn from(value: NoteType) -> Self {
652 padded_word_from_felt(value.inner)
653 }
654}
655
656impl TryFrom<Word> for NoteType {
657 type Error = &'static str;
658
659 #[inline]
660 fn try_from(value: Word) -> Result<Self, Self::Error> {
661 Ok(NoteType {
662 inner: felt_from_padded_word(value)?,
663 })
664 }
665}
666
667#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
673#[repr(transparent)]
674pub struct Nonce {
675 #[doc(hidden)]
678 pub inner: Felt,
679}
680
681impl Nonce {
682 #[inline]
684 pub fn as_u64(&self) -> u64 {
685 self.inner.as_canonical_u64()
686 }
687
688 #[inline]
690 pub fn as_felt(&self) -> Felt {
691 self.inner
692 }
693}
694
695impl From<Nonce> for Felt {
696 #[inline]
697 fn from(value: Nonce) -> Self {
698 value.inner
699 }
700}
701
702#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
708#[repr(transparent)]
709pub struct BlockNumber {
710 #[doc(hidden)]
713 pub inner: Felt,
714}
715
716impl BlockNumber {
717 #[inline]
724 pub fn as_u32(&self) -> u32 {
725 assert!(
728 self.inner <= Felt::from_u32(u32::MAX),
729 "block number exceeds the maximum block height"
730 );
731 self.inner.as_canonical_u64() as u32
732 }
733
734 #[inline]
736 pub fn as_felt(&self) -> Felt {
737 self.inner
738 }
739}
740
741impl From<u32> for BlockNumber {
742 fn from(value: u32) -> Self {
743 Self {
744 inner: Felt::from_u32(value),
745 }
746 }
747}
748
749impl TryFrom<Felt> for BlockNumber {
750 type Error = &'static str;
751
752 fn try_from(value: Felt) -> Result<Self, Self::Error> {
753 if value.as_canonical_u64() > u32::MAX as u64 {
754 return Err("block number exceeds the maximum block height");
755 }
756 Ok(Self { inner: value })
757 }
758}
759
760impl From<BlockNumber> for Felt {
761 #[inline]
762 fn from(value: BlockNumber) -> Self {
763 value.inner
764 }
765}
766
767#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
774pub struct StorageSlotId {
775 suffix: Felt,
776 prefix: Felt,
777}
778
779impl StorageSlotId {
780 pub fn new(suffix: Felt, prefix: Felt) -> Self {
785 Self { suffix, prefix }
786 }
787
788 pub fn from_prefix_suffix(prefix: Felt, suffix: Felt) -> Self {
792 Self { suffix, prefix }
793 }
794
795 pub fn to_prefix_suffix(&self) -> (Felt, Felt) {
797 (self.prefix, self.suffix)
798 }
799
800 pub fn to_suffix_prefix(&self) -> (Felt, Felt) {
802 (self.suffix, self.prefix)
803 }
804
805 pub fn suffix(&self) -> Felt {
807 self.suffix
808 }
809
810 pub fn prefix(&self) -> Felt {
812 self.prefix
813 }
814}
815
816#[cfg(test)]
817mod tests {
818 use miden_stdlib_sys::{Felt, Word, felt};
819
820 use super::{
821 AssetAmount, AssetAmountError, BlockNumber, felt_from_padded_word, padded_word_from_felt,
822 };
823
824 #[test]
826 fn padded_word_from_felt_zero_pads_trailing_limbs() {
827 assert_eq!(
828 padded_word_from_felt(felt!(7)),
829 Word::new([felt!(7), felt!(0), felt!(0), felt!(0)])
830 );
831 }
832
833 #[test]
835 fn felt_from_padded_word_rejects_non_zero_padding() {
836 let err =
837 felt_from_padded_word(Word::new([felt!(7), felt!(1), felt!(0), felt!(0)])).unwrap_err();
838
839 assert_eq!(err, "expected zero padding in the trailing three felts");
840 }
841
842 #[test]
844 fn felt_padding_helpers_roundtrip() {
845 let value = felt!(42);
846
847 assert_eq!(felt_from_padded_word(padded_word_from_felt(value)), Ok(value));
848 }
849
850 #[test]
852 fn asset_amount_valid_amounts() {
853 assert_eq!(AssetAmount::new(0).unwrap().as_u64(), 0);
854 assert_eq!(AssetAmount::new(1000).unwrap().as_u64(), 1000);
855 assert_eq!(AssetAmount::new(AssetAmount::MAX_U64).unwrap(), AssetAmount::max());
856 }
857
858 #[test]
860 fn asset_amount_exceeds_max() {
861 assert_eq!(
862 AssetAmount::new(AssetAmount::MAX_U64 + 1),
863 Err(AssetAmountError::AmountTooBig(AssetAmount::MAX_U64 + 1))
864 );
865 assert_eq!(AssetAmount::new(u64::MAX), Err(AssetAmountError::AmountTooBig(u64::MAX)));
866 }
867
868 #[test]
870 fn asset_amount_max_value() {
871 assert_eq!(AssetAmount::MAX_U64, 2u64.pow(63) - 2u64.pow(31));
872 assert_eq!(AssetAmount::max().as_u64(), AssetAmount::MAX_U64);
873 }
874
875 #[test]
877 fn asset_amount_from_small_types() {
878 assert_eq!(AssetAmount::from(42u8).as_u64(), 42);
879 assert_eq!(AssetAmount::from(1000u16).as_u64(), 1000);
880 assert_eq!(AssetAmount::from(u32::MAX).as_u64(), u32::MAX as u64);
881 }
882
883 #[test]
885 fn asset_amount_try_from() {
886 assert!(AssetAmount::try_from(AssetAmount::MAX_U64).is_ok());
887 assert!(AssetAmount::try_from(AssetAmount::MAX_U64 + 1).is_err());
888 assert!(AssetAmount::try_from(Felt::new(AssetAmount::MAX_U64).unwrap()).is_ok());
889 assert!(AssetAmount::try_from(Felt::new(AssetAmount::MAX_U64 + 1).unwrap()).is_err());
890 assert_eq!(
892 AssetAmount::try_from(Felt::new(Felt::ORDER - 1).unwrap()),
893 Err(AssetAmountError::AmountTooBig(Felt::ORDER - 1))
894 );
895 }
896
897 #[test]
899 fn asset_amount_add() {
900 let a = AssetAmount::new(100).unwrap();
901 let b = AssetAmount::new(200).unwrap();
902
903 assert_eq!((a + b).as_u64(), 300);
904 assert_eq!(AssetAmount::ZERO + AssetAmount::ZERO, AssetAmount::ZERO);
905 assert_eq!(AssetAmount::max() + AssetAmount::ZERO, AssetAmount::max());
906 }
907
908 #[test]
910 #[should_panic(expected = "asset amount addition overflow")]
911 fn asset_amount_add_panics_on_overflow() {
912 let _ = AssetAmount::max() + AssetAmount::new(1).unwrap();
913 }
914
915 #[test]
919 #[should_panic(expected = "asset amount exceeds the maximum allowed amount")]
920 fn asset_amount_add_panics_on_forged_lhs() {
921 let wrapping = AssetAmount {
922 inner: Felt::new(Felt::ORDER - 1).unwrap(),
923 };
924
925 let _ = wrapping + AssetAmount::new(1).unwrap();
926 }
927
928 #[test]
931 #[should_panic(expected = "asset amount addition overflow")]
932 fn asset_amount_add_panics_on_forged_rhs() {
933 let forged = AssetAmount {
934 inner: Felt::new(AssetAmount::MAX_U64 + 1).unwrap(),
935 };
936
937 let _ = AssetAmount::new(1).unwrap() + forged;
938 }
939
940 #[test]
942 fn asset_amount_sub() {
943 let a = AssetAmount::new(300).unwrap();
944 let b = AssetAmount::new(100).unwrap();
945
946 assert_eq!((a - b).as_u64(), 200);
947 assert_eq!(AssetAmount::ZERO - AssetAmount::ZERO, AssetAmount::ZERO);
948 assert_eq!(AssetAmount::max() - AssetAmount::max(), AssetAmount::ZERO);
949 }
950
951 #[test]
953 #[should_panic(expected = "asset amount subtraction underflow")]
954 fn asset_amount_sub_panics_on_underflow() {
955 let _ = AssetAmount::ZERO - AssetAmount::new(1).unwrap();
956 }
957
958 #[test]
961 #[should_panic(expected = "asset amount exceeds the maximum allowed amount")]
962 fn asset_amount_sub_panics_on_forged_minuend() {
963 let forged = AssetAmount {
964 inner: Felt::new(AssetAmount::MAX_U64 + 1).unwrap(),
965 };
966
967 let _ = forged - AssetAmount::new(1).unwrap();
968 }
969
970 #[test]
973 fn asset_amount_differential_vs_protocol() {
974 use miden_protocol::asset::AssetAmount as ProtocolAmount;
975
976 let values = [
977 0u64,
978 1,
979 2,
980 31,
981 u32::MAX as u64,
982 1 << 40,
983 AssetAmount::MAX_U64 / 2,
984 AssetAmount::MAX_U64 - 1,
985 AssetAmount::MAX_U64,
986 ];
987 for &a in &values {
988 for &b in &values {
989 let ours = (AssetAmount::new(a).unwrap(), AssetAmount::new(b).unwrap());
990 let theirs = (ProtocolAmount::new(a).unwrap(), ProtocolAmount::new(b).unwrap());
991
992 if let Ok(sum) = theirs.0 + theirs.1 {
993 assert_eq!(
994 (ours.0 + ours.1).as_u64(),
995 sum.as_u64(),
996 "sum mismatch for {a} + {b}"
997 );
998 }
999
1000 if let Ok(difference) = theirs.0 - theirs.1 {
1001 assert_eq!(
1002 (ours.0 - ours.1).as_u64(),
1003 difference.as_u64(),
1004 "difference mismatch for {a} - {b}"
1005 );
1006 }
1007 }
1008 }
1009 }
1010
1011 #[test]
1013 fn asset_amount_ordering() {
1014 assert!(AssetAmount::new(1).unwrap() < AssetAmount::new(2).unwrap());
1015 assert!(AssetAmount::max() > AssetAmount::ZERO);
1016 assert_eq!(AssetAmount::default(), AssetAmount::ZERO);
1017 }
1018
1019 #[test]
1021 fn asset_amount_display() {
1022 extern crate alloc;
1023 use alloc::string::ToString;
1024
1025 assert_eq!(AssetAmount::new(12345).unwrap().to_string(), "12345");
1026 }
1027
1028 #[test]
1030 fn asset_amount_felt_roundtrip() {
1031 let amount = AssetAmount::new(500).unwrap();
1032
1033 assert_eq!(amount.as_felt(), felt!(500));
1034 assert_eq!(Felt::from(amount), felt!(500));
1035 assert_eq!(u64::from(amount), 500);
1036 }
1037
1038 #[test]
1040 fn block_number_try_from_felt_bounds() {
1041 let max = Felt::new(u32::MAX as u64).unwrap();
1042
1043 assert_eq!(BlockNumber::try_from(max).unwrap().as_u32(), u32::MAX);
1044 assert!(BlockNumber::try_from(Felt::new(u32::MAX as u64 + 1).unwrap()).is_err());
1045 }
1046
1047 #[test]
1050 #[should_panic(expected = "block number exceeds the maximum block height")]
1051 fn block_number_as_u32_panics_on_out_of_range_felt() {
1052 let forged = BlockNumber {
1053 inner: Felt::new(u32::MAX as u64 + 1).unwrap(),
1054 };
1055
1056 let _ = forged.as_u32();
1057 }
1058}