1use alloc::string::ToString;
2use alloc::vec::Vec;
3
4use crate::asset::{Asset, AssetVault};
5use crate::crypto::SequentialCommit;
6use crate::errors::AccountError;
7use crate::utils::serde::{
8 ByteReader,
9 ByteWriter,
10 Deserializable,
11 DeserializationError,
12 Serializable,
13};
14use crate::{Felt, Hasher, Word, ZERO};
15
16mod account_id;
17pub use account_id::{
18 AccountId,
19 AccountIdPrefix,
20 AccountIdPrefixV1,
21 AccountIdV1,
22 AccountIdVersion,
23 AccountType,
24 AssetCallbackFlag,
25};
26
27pub(crate) mod name_validation;
28
29pub mod auth;
30
31mod access;
32pub use access::RoleSymbol;
33
34mod builder;
35pub use builder::AccountBuilder;
36
37pub mod code;
38pub use code::AccountCode;
39pub use code::procedure::AccountProcedureRoot;
40
41pub mod component;
42pub use component::{AccountComponent, AccountComponentCode, AccountComponentMetadata};
43
44pub mod interface;
45pub use interface::{AccountCodeInterface, AccountComponentName};
46
47mod patch;
48pub use patch::{
49 AccountPatch,
50 AccountStoragePatch,
51 AccountUpdateDetails,
52 AccountVaultPatch,
53 StorageMapPatch,
54 StorageMapPatchEntries,
55 StoragePatchOperation,
56 StorageSlotPatch,
57 StorageValuePatch,
58};
59
60pub mod delta;
61pub use delta::{
62 AccountDelta,
63 AccountVaultDelta,
64 FungibleAssetDelta,
65 NonFungibleAssetDelta,
66 NonFungibleDeltaAction,
67};
68
69pub mod storage;
70pub use storage::{
71 AccountStorage,
72 AccountStorageHeader,
73 PartialStorage,
74 PartialStorageMap,
75 StorageMap,
76 StorageMapKey,
77 StorageMapKeyHash,
78 StorageMapWitness,
79 StorageSlot,
80 StorageSlotContent,
81 StorageSlotHeader,
82 StorageSlotId,
83 StorageSlotName,
84 StorageSlotType,
85};
86
87mod header;
88pub use header::AccountHeader;
89
90mod file;
91pub use file::AccountFile;
92
93mod partial;
94pub use partial::PartialAccount;
95
96#[derive(Debug, Clone, PartialEq, Eq)]
118pub struct Account {
119 id: AccountId,
120 vault: AssetVault,
121 storage: AccountStorage,
122 code: AccountCode,
123 nonce: Felt,
124 seed: Option<Word>,
125}
126
127impl Account {
128 pub fn new(
141 id: AccountId,
142 vault: AssetVault,
143 storage: AccountStorage,
144 code: AccountCode,
145 nonce: Felt,
146 seed: Option<Word>,
147 ) -> Result<Self, AccountError> {
148 validate_account_seed(id, code.commitment(), storage.to_commitment(), seed, nonce)?;
149
150 Ok(Self::new_unchecked(id, vault, storage, code, nonce, seed))
151 }
152
153 pub fn new_unchecked(
160 id: AccountId,
161 vault: AssetVault,
162 storage: AccountStorage,
163 code: AccountCode,
164 nonce: Felt,
165 seed: Option<Word>,
166 ) -> Self {
167 Self { id, vault, storage, code, nonce, seed }
168 }
169
170 pub(super) fn initialize_from_components(
193 components: Vec<AccountComponent>,
194 ) -> Result<(AccountCode, AccountStorage), AccountError> {
195 let code = AccountCode::from_components_unchecked(&components)?;
196 let storage = AccountStorage::from_components(components)?;
197
198 Ok((code, storage))
199 }
200
201 pub fn builder(init_seed: [u8; 32]) -> AccountBuilder {
206 AccountBuilder::new(init_seed)
207 }
208
209 pub fn to_commitment(&self) -> Word {
216 AccountHeader::from(self).to_commitment()
217 }
218
219 pub fn initial_commitment(&self) -> Word {
229 if self.is_new() {
230 Word::empty()
231 } else {
232 self.to_commitment()
233 }
234 }
235
236 pub fn id(&self) -> AccountId {
238 self.id
239 }
240
241 pub fn vault(&self) -> &AssetVault {
243 &self.vault
244 }
245
246 pub fn storage(&self) -> &AccountStorage {
248 &self.storage
249 }
250
251 pub fn code(&self) -> &AccountCode {
253 &self.code
254 }
255
256 pub fn code_interface(&self) -> AccountCodeInterface {
259 self.code.interface(self.id())
260 }
261
262 pub fn nonce(&self) -> Felt {
264 self.nonce
265 }
266
267 pub fn seed(&self) -> Option<Word> {
271 self.seed
272 }
273
274 pub fn is_public(&self) -> bool {
276 self.id().is_public()
277 }
278
279 pub fn is_private(&self) -> bool {
281 self.id().is_private()
282 }
283
284 pub fn is_new(&self) -> bool {
289 self.nonce == ZERO
290 }
291
292 pub fn into_parts(
294 self,
295 ) -> (AccountId, AssetVault, AccountStorage, AccountCode, Felt, Option<Word>) {
296 (self.id, self.vault, self.storage, self.code, self.nonce, self.seed)
297 }
298
299 pub fn apply_patch(&mut self, patch: &AccountPatch) -> Result<(), AccountError> {
316 if patch.id() != self.id {
317 return Err(AccountError::PatchAccountIdMismatch {
318 account_id: self.id,
319 patch_id: patch.id(),
320 });
321 }
322
323 if patch.is_full_state() {
324 return Err(AccountError::ApplyFullStatePatchToAccount);
325 }
326
327 self.vault
328 .apply_patch(patch.vault())
329 .map_err(AccountError::AssetVaultUpdateError)?;
330
331 self.storage.apply_patch(patch.storage())?;
332
333 if let Some(new_nonce) = patch.final_nonce() {
334 self.set_nonce(new_nonce)?;
335 }
336
337 Ok(())
338 }
339
340 pub fn increment_nonce(&mut self, nonce_delta: Felt) -> Result<(), AccountError> {
347 let new_nonce = self.nonce + nonce_delta;
348
349 self.set_nonce(new_nonce)
350 }
351
352 pub fn set_nonce(&mut self, new_nonce: Felt) -> Result<(), AccountError> {
358 if new_nonce.as_canonical_u64() < self.nonce.as_canonical_u64() {
359 return Err(AccountError::NonceMustIncrease { current: self.nonce, new: new_nonce });
360 }
361
362 self.nonce = new_nonce;
363
364 if !self.is_new() {
369 self.seed = None;
370 }
371
372 Ok(())
373 }
374
375 #[cfg(any(feature = "testing", test))]
379 pub fn vault_mut(&mut self) -> &mut AssetVault {
381 &mut self.vault
382 }
383
384 #[cfg(any(feature = "testing", test))]
385 pub fn storage_mut(&mut self) -> &mut AccountStorage {
387 &mut self.storage
388 }
389}
390
391impl TryFrom<Account> for AccountDelta {
392 type Error = AccountError;
393
394 fn try_from(account: Account) -> Result<Self, Self::Error> {
403 let Account { id, vault, storage, code, nonce, seed } = account;
404
405 if seed.is_some() {
406 return Err(AccountError::DeltaFromAccountWithSeed);
407 }
408
409 let slot_deltas = storage
410 .into_slots()
411 .into_iter()
412 .map(StorageSlot::into_parts)
413 .map(|(slot_name, slot_content)| (slot_name, StorageSlotPatch::from(slot_content)))
414 .collect();
415 let storage_patch = AccountStoragePatch::from_raw(slot_deltas)
418 .expect("number of slot patches is bounded by the account's storage slots");
419
420 let mut fungible_delta = FungibleAssetDelta::default();
421 let mut non_fungible_delta = NonFungibleAssetDelta::default();
422 for asset in vault.assets() {
423 match asset {
425 Asset::Fungible(fungible_asset) => {
426 fungible_delta
427 .add(fungible_asset)
428 .expect("delta should allow representing valid fungible assets");
429 },
430 Asset::NonFungible(non_fungible_asset) => {
431 non_fungible_delta
432 .add(non_fungible_asset)
433 .expect("delta should allow representing valid non-fungible assets");
434 },
435 }
436 }
437 let vault_delta = AccountVaultDelta::new(fungible_delta, non_fungible_delta);
438
439 let nonce_delta = nonce;
442
443 let delta = AccountDelta::new(id, storage_patch, vault_delta, Some(code), nonce_delta)
447 .expect("full state delta from account contains only create patches");
448
449 Ok(delta)
450 }
451}
452
453impl TryFrom<Account> for AccountPatch {
454 type Error = AccountError;
455
456 fn try_from(account: Account) -> Result<Self, Self::Error> {
465 let Account { id, vault, storage, code, nonce, seed } = account;
466
467 if seed.is_some() {
468 return Err(AccountError::PatchFromAccountWithSeed);
469 }
470
471 let slot_patches = storage
472 .into_slots()
473 .into_iter()
474 .map(StorageSlot::into_parts)
475 .map(|(slot_name, slot_content)| (slot_name, StorageSlotPatch::from(slot_content)))
476 .collect();
477 let storage_patch = AccountStoragePatch::from_raw(slot_patches)
480 .expect("number of slot patches is bounded by the account's storage slots");
481
482 let mut vault_patch = AccountVaultPatch::default();
483 for asset in vault.assets() {
484 vault_patch.insert_asset(asset);
485 }
486
487 let patch = AccountPatch::new(id, storage_patch, vault_patch, Some(code), Some(nonce))
492 .expect("non-seeded account should yield a valid patch");
493
494 Ok(patch)
495 }
496}
497
498impl SequentialCommit for Account {
499 type Commitment = Word;
500
501 fn to_elements(&self) -> Vec<Felt> {
502 AccountHeader::from(self).to_elements()
503 }
504
505 fn to_commitment(&self) -> Self::Commitment {
506 AccountHeader::from(self).to_commitment()
507 }
508}
509
510impl Serializable for Account {
514 fn write_into<W: ByteWriter>(&self, target: &mut W) {
515 let Account { id, vault, storage, code, nonce, seed } = self;
516
517 id.write_into(target);
518 vault.write_into(target);
519 storage.write_into(target);
520 code.write_into(target);
521 nonce.write_into(target);
522 seed.write_into(target);
523 }
524
525 fn get_size_hint(&self) -> usize {
526 self.id.get_size_hint()
527 + self.vault.get_size_hint()
528 + self.storage.get_size_hint()
529 + self.code.get_size_hint()
530 + self.nonce.get_size_hint()
531 + self.seed.get_size_hint()
532 }
533}
534
535impl Deserializable for Account {
536 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
537 let id = AccountId::read_from(source)?;
538 let vault = AssetVault::read_from(source)?;
539 let storage = AccountStorage::read_from(source)?;
540 let code = AccountCode::read_from(source)?;
541 let nonce = Felt::read_from(source)?;
542 let seed = <Option<Word>>::read_from(source)?;
543
544 Self::new(id, vault, storage, code, nonce, seed)
545 .map_err(|err| DeserializationError::InvalidValue(err.to_string()))
546 }
547}
548
549pub(super) fn validate_account_seed(
554 id: AccountId,
555 code_commitment: Word,
556 storage_commitment: Word,
557 seed: Option<Word>,
558 nonce: Felt,
559) -> Result<(), AccountError> {
560 let account_is_new = nonce == ZERO;
561
562 match (account_is_new, seed) {
563 (true, Some(seed)) => {
564 let account_id =
565 AccountId::new(seed, id.version(), code_commitment, storage_commitment)
566 .map_err(AccountError::SeedConvertsToInvalidAccountId)?;
567
568 if account_id != id {
569 return Err(AccountError::AccountIdSeedMismatch {
570 expected: id,
571 actual: account_id,
572 });
573 }
574
575 Ok(())
576 },
577 (true, None) => Err(AccountError::NewAccountMissingSeed),
578 (false, Some(_)) => Err(AccountError::ExistingAccountWithSeed),
579 (false, None) => Ok(()),
580 }
581}
582
583#[cfg(test)]
587mod tests {
588 use alloc::vec::Vec;
589
590 use assert_matches::assert_matches;
591 use miden_crypto::utils::{Deserializable, Serializable};
592 use miden_crypto::{Felt, Word};
593
594 use super::{AccountCode, AccountDelta, AccountId, AccountStorage, AccountStoragePatch};
595 use crate::account::{
596 Account,
597 AccountBuilder,
598 AccountIdVersion,
599 AccountPatch,
600 AccountType,
601 AccountVaultDelta,
602 AccountVaultPatch,
603 AssetCallbackFlag,
604 PartialAccount,
605 StorageMap,
606 StorageMapKey,
607 StorageSlot,
608 StorageSlotContent,
609 StorageSlotName,
610 };
611 use crate::asset::{Asset, AssetVault, FungibleAsset, NonFungibleAsset};
612 use crate::errors::AccountError;
613 use crate::testing::account_id::{
614 ACCOUNT_ID_REGULAR_PUBLIC_ACCOUNT_IMMUTABLE_CODE,
615 ACCOUNT_ID_REGULAR_PUBLIC_ACCOUNT_IMMUTABLE_CODE_2,
616 };
617 use crate::testing::add_component::AddComponent;
618 use crate::testing::noop_auth_component::NoopAuthComponent;
619
620 #[test]
621 fn test_serde_account() {
622 let init_nonce = Felt::from(1_u32);
623 let asset_0 = FungibleAsset::mock(99);
624 let word = Word::from([1, 2, 3, 4u32]);
625 let storage_slot = StorageSlotContent::Value(word);
626 let account = build_account(vec![asset_0], init_nonce, vec![storage_slot]);
627
628 let serialized = account.to_bytes();
629 let deserialized = Account::read_from_bytes(&serialized).unwrap();
630 assert_eq!(deserialized, account);
631 }
632
633 #[test]
634 fn test_serde_account_delta() {
635 let nonce_delta = Felt::from(2_u32);
636 let asset_0 = FungibleAsset::mock(15);
637 let asset_1 = NonFungibleAsset::mock(&[5, 5, 5]);
638 let storage_patch = AccountStoragePatch::builder()
639 .update_value(StorageSlotName::mock(0), Word::empty())
640 .update_value(StorageSlotName::mock(1), Word::from([1, 2, 3, 4u32]))
641 .build();
642 let account_delta =
643 build_account_delta(vec![asset_1], vec![asset_0], nonce_delta, storage_patch);
644
645 let serialized = account_delta.to_bytes();
646 let deserialized = AccountDelta::read_from_bytes(&serialized).unwrap();
647 assert_eq!(deserialized, account_delta);
648 }
649
650 #[test]
651 fn account_patch_is_correctly_applied() -> anyhow::Result<()> {
652 let init_nonce = Felt::from(1_u32);
653 let asset_0 = FungibleAsset::mock(100);
654 let asset_1 = NonFungibleAsset::mock(&[1, 2, 3]);
655
656 let storage_slot_value_0 = StorageSlotContent::Value(Word::from([1, 2, 3, 4u32]));
658 let storage_slot_value_1 = StorageSlotContent::Value(Word::from([5, 6, 7, 8u32]));
659 let map_key_0 = StorageMapKey::from_array([101, 102, 103, 104]);
660 let map_key_1 = StorageMapKey::from_array([105, 106, 107, 108]);
661
662 let mut storage_map = StorageMap::with_entries([
663 (map_key_0, Word::from([1, 2, 3, 4_u32])),
664 (map_key_1, Word::from([5, 6, 7, 8_u32])),
665 ])
666 .unwrap();
667 let storage_slot_map = StorageSlotContent::Map(storage_map.clone());
668
669 let initial_account = build_account(
671 vec![asset_0],
672 init_nonce,
673 vec![storage_slot_value_0, storage_slot_value_1, storage_slot_map],
674 );
675
676 let value = Word::from([9, 10, 11, 12u32]);
677 storage_map.insert(map_key_0, value).unwrap();
678
679 let final_nonce = init_nonce + Felt::ONE;
681 let storage_patch = AccountStoragePatch::builder()
682 .update_value(StorageSlotName::mock(0), Word::empty())
683 .update_value(StorageSlotName::mock(1), Word::from([1, 2, 3, 4u32]))
684 .update_map(StorageSlotName::mock(2), [(map_key_0, value)])
685 .build();
686 let account_patch =
687 build_account_patch(final_nonce, vec![asset_1], vec![asset_0], storage_patch);
688
689 let mut account_with_patched = initial_account;
691
692 account_with_patched.apply_patch(&account_patch)?;
693
694 let final_account = build_account(
695 vec![asset_1],
696 final_nonce,
697 vec![
698 StorageSlotContent::Value(Word::empty()),
699 StorageSlotContent::Value(Word::from([1, 2, 3, 4u32])),
700 StorageSlotContent::Map(storage_map),
701 ],
702 );
703
704 assert_eq!(account_with_patched, final_account);
705
706 Ok(())
707 }
708
709 #[test]
710 fn apply_patch_rejects_new_account_patch() -> anyhow::Result<()> {
711 let account_id = AccountId::try_from(ACCOUNT_ID_REGULAR_PUBLIC_ACCOUNT_IMMUTABLE_CODE)?;
712 let init_nonce = Felt::from(1_u32);
713 let mut account = build_account(vec![], init_nonce, vec![]);
714
715 let patch = AccountPatch::new(
716 account_id,
717 AccountStoragePatch::new(),
718 AccountVaultPatch::default(),
719 Some(AccountCode::mock()),
720 Some(Felt::from(2_u32)),
721 )?;
722
723 let err = account.apply_patch(&patch).unwrap_err();
724 assert_matches!(err, AccountError::ApplyFullStatePatchToAccount);
725
726 Ok(())
727 }
728
729 #[test]
730 fn apply_patch_rejects_non_increasing_nonce() -> anyhow::Result<()> {
731 let account_id = AccountId::try_from(ACCOUNT_ID_REGULAR_PUBLIC_ACCOUNT_IMMUTABLE_CODE)?;
732 let init_nonce = 5_u32;
733 let mut account = build_account(vec![], Felt::from(init_nonce), vec![]);
734
735 let patch_smaller = AccountPatch::new(
737 account_id,
738 AccountStoragePatch::new(),
739 AccountVaultPatch::default(),
740 None,
741 Some(Felt::from(init_nonce - 1)),
742 )?;
743 let err = account.apply_patch(&patch_smaller).unwrap_err();
744 assert_matches!(err, AccountError::NonceMustIncrease { .. });
745
746 Ok(())
747 }
748
749 #[test]
750 fn apply_patch_rejects_id_mismatch() -> anyhow::Result<()> {
751 let other_account_id =
752 AccountId::try_from(ACCOUNT_ID_REGULAR_PUBLIC_ACCOUNT_IMMUTABLE_CODE_2)?;
753 let init_nonce = Felt::from(1_u32);
754 let mut account = build_account(vec![], init_nonce, vec![]);
755
756 let patch = AccountPatch::new(
757 other_account_id,
758 AccountStoragePatch::default(),
759 AccountVaultPatch::default(),
760 None,
761 Some(Felt::from(2_u32)),
762 )?;
763
764 let err = account.apply_patch(&patch).unwrap_err();
765 assert_matches!(err, AccountError::PatchAccountIdMismatch { .. });
766
767 Ok(())
768 }
769
770 #[test]
771 fn apply_empty_account_patch() -> anyhow::Result<()> {
772 let nonce = Felt::from(2u8);
773 let id = AccountId::try_from(ACCOUNT_ID_REGULAR_PUBLIC_ACCOUNT_IMMUTABLE_CODE).unwrap();
774 let empty_patch = AccountPatch::new(
775 id,
776 AccountStoragePatch::default(),
777 AccountVaultPatch::default(),
778 None,
779 None,
780 )?;
781 let init_account = build_account(vec![], nonce, vec![]);
782
783 let mut account_with_patch = init_account.clone();
784 account_with_patch.apply_patch(&empty_patch)?;
785
786 assert_eq!(init_account, account_with_patch, "account should be unchanged");
787
788 Ok(())
789 }
790
791 #[test]
792 fn apply_empty_account_patch_with_incremented_nonce() -> anyhow::Result<()> {
793 let initial_nonce = Felt::from(2u8);
794 let final_nonce = initial_nonce + Felt::ONE;
795
796 let id = AccountId::try_from(ACCOUNT_ID_REGULAR_PUBLIC_ACCOUNT_IMMUTABLE_CODE).unwrap();
797 let empty_patch = AccountPatch::new(
798 id,
799 AccountStoragePatch::default(),
800 AccountVaultPatch::default(),
801 None,
802 Some(final_nonce),
803 )?;
804
805 let init_account = build_account(vec![], initial_nonce, vec![]);
806 let final_account = build_account(vec![], final_nonce, vec![]);
807
808 let mut account_with_patch = init_account.clone();
809 account_with_patch.apply_patch(&empty_patch)?;
810
811 assert_eq!(final_account, account_with_patch);
812
813 Ok(())
814 }
815
816 pub fn build_account_delta(
817 added_assets: Vec<Asset>,
818 removed_assets: Vec<Asset>,
819 nonce_delta: Felt,
820 storage_patch: AccountStoragePatch,
821 ) -> AccountDelta {
822 let id = AccountId::try_from(ACCOUNT_ID_REGULAR_PUBLIC_ACCOUNT_IMMUTABLE_CODE).unwrap();
823 let vault_delta = AccountVaultDelta::from_iters(added_assets, removed_assets);
824 AccountDelta::new(id, storage_patch, vault_delta, None, nonce_delta).unwrap()
825 }
826
827 pub fn build_account_patch(
828 final_nonce: Felt,
829 added_assets: Vec<Asset>,
830 removed_assets: Vec<Asset>,
831 storage_patch: AccountStoragePatch,
832 ) -> AccountPatch {
833 let id = AccountId::try_from(ACCOUNT_ID_REGULAR_PUBLIC_ACCOUNT_IMMUTABLE_CODE).unwrap();
834 let vault_patch = AccountVaultPatch::from_iters(added_assets, removed_assets);
835 AccountPatch::new(id, storage_patch, vault_patch, None, Some(final_nonce)).unwrap()
836 }
837
838 pub fn build_account(
839 assets: Vec<Asset>,
840 nonce: Felt,
841 slots: Vec<StorageSlotContent>,
842 ) -> Account {
843 let id = AccountId::try_from(ACCOUNT_ID_REGULAR_PUBLIC_ACCOUNT_IMMUTABLE_CODE).unwrap();
844 let code = AccountCode::mock();
845
846 let vault = AssetVault::new(&assets).unwrap();
847
848 let slots = slots
849 .into_iter()
850 .enumerate()
851 .map(|(idx, slot)| StorageSlot::new(StorageSlotName::mock(idx), slot))
852 .collect();
853
854 let storage = AccountStorage::new(slots).unwrap();
855
856 Account::new_existing(id, vault, storage, code, nonce)
857 }
858
859 #[test]
861 fn seed_validation() -> anyhow::Result<()> {
862 let account = AccountBuilder::new([5; 32])
863 .with_auth_component(NoopAuthComponent)
864 .with_component(AddComponent)
865 .build()?;
866 let (id, vault, storage, code, _nonce, seed) = account.into_parts();
867 assert!(seed.is_some());
868
869 let other_seed = AccountId::compute_account_seed(
870 [9; 32],
871 AccountType::Public,
872 AssetCallbackFlag::Disabled,
873 AccountIdVersion::Version1,
874 code.commitment(),
875 storage.to_commitment(),
876 )?;
877
878 let err = Account::new(id, vault.clone(), storage.clone(), code.clone(), Felt::ONE, seed)
880 .unwrap_err();
881 assert_matches!(err, AccountError::ExistingAccountWithSeed);
882
883 let err = Account::new(id, vault.clone(), storage.clone(), code.clone(), Felt::ZERO, None)
885 .unwrap_err();
886 assert_matches!(err, AccountError::NewAccountMissingSeed);
887
888 let err = Account::new(
891 id,
892 vault.clone(),
893 storage.clone(),
894 code.clone(),
895 Felt::ZERO,
896 Some(other_seed),
897 )
898 .unwrap_err();
899 assert_matches!(err, AccountError::AccountIdSeedMismatch { .. });
900
901 let err = Account::new(
904 id,
905 vault.clone(),
906 storage.clone(),
907 code.clone(),
908 Felt::ZERO,
909 Some(Word::from([1, 2, 3, 4u32])),
910 )
911 .unwrap_err();
912 assert_matches!(err, AccountError::SeedConvertsToInvalidAccountId(_));
913
914 Account::new(id, vault.clone(), storage.clone(), code.clone(), Felt::ONE, None)?;
917
918 Account::new(id, vault.clone(), storage.clone(), code.clone(), Felt::ZERO, seed)?;
921
922 Ok(())
923 }
924
925 #[test]
926 fn incrementing_nonce_should_remove_seed() -> anyhow::Result<()> {
927 let mut account = AccountBuilder::new([5; 32])
928 .with_auth_component(NoopAuthComponent)
929 .with_component(AddComponent)
930 .build()?;
931 account.increment_nonce(Felt::ONE)?;
932
933 assert_matches!(account.seed(), None);
934
935 let _partial_account = PartialAccount::from(&account);
938
939 Ok(())
940 }
941}