1use std::collections::HashMap;
2use std::sync::{Arc, Mutex};
3
4use async_trait::async_trait;
5use serde::{Deserialize, Serialize};
6
7use crate::abi::{AbiType, ContractArtifact, EventSelector};
8use crate::error::Error;
9use crate::fee::{Gas, GasSettings};
10use crate::node::LogId;
11use crate::tx::{AuthWitness, Capsule, ExecutionPayload, FunctionCall, TxHash};
12use crate::types::{AztecAddress, ContractInstanceWithAddress, Fr};
13
14pub use aztec_core::hash::{ChainInfo, MessageHashOrIntent};
17
18#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
24#[serde(rename_all = "camelCase")]
25pub struct Aliased<T> {
26 pub alias: String,
28 pub item: T,
30}
31
32#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
34#[serde(rename_all = "camelCase")]
35pub struct ContractMetadata {
36 pub instance: Option<ContractInstanceWithAddress>,
38 pub is_contract_initialized: bool,
40 pub is_contract_published: bool,
42 pub is_contract_updated: bool,
44 pub updated_contract_class_id: Option<Fr>,
46}
47
48#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
50#[serde(rename_all = "camelCase")]
51pub struct ContractClassMetadata {
52 pub is_artifact_registered: bool,
54 pub is_contract_class_publicly_registered: bool,
56}
57
58#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
60#[serde(rename_all = "camelCase")]
61pub struct SimulateOptions {
62 pub from: AztecAddress,
64 #[serde(default)]
66 pub skip_validation: bool,
67 #[serde(default = "default_skip_fee_enforcement")]
69 pub skip_fee_enforcement: bool,
70 #[serde(default)]
72 pub auth_witnesses: Vec<AuthWitness>,
73 #[serde(default)]
75 pub capsules: Vec<Capsule>,
76 #[serde(default)]
78 pub additional_scopes: Vec<AztecAddress>,
79 pub gas_settings: Option<GasSettings>,
81 #[serde(default, skip_serializing_if = "Option::is_none")]
83 pub fee_execution_payload: Option<ExecutionPayload>,
84 #[serde(default)]
86 pub estimate_gas: bool,
87 #[serde(default, skip_serializing_if = "Option::is_none")]
89 pub estimated_gas_padding: Option<f64>,
90}
91
92#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
94#[serde(rename_all = "camelCase")]
95pub struct SendOptions {
96 pub from: AztecAddress,
98 #[serde(default)]
100 pub auth_witnesses: Vec<AuthWitness>,
101 #[serde(default)]
103 pub capsules: Vec<Capsule>,
104 #[serde(default)]
106 pub additional_scopes: Vec<AztecAddress>,
107 pub gas_settings: Option<GasSettings>,
109 #[serde(default, skip_serializing_if = "Option::is_none")]
111 pub fee_execution_payload: Option<ExecutionPayload>,
112}
113
114#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
116#[serde(rename_all = "kebab-case")]
117pub enum ProfileMode {
118 Gates,
120 ExecutionSteps,
122 Full,
124}
125
126#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
128#[serde(rename_all = "camelCase")]
129pub struct ProfileOptions {
130 pub from: AztecAddress,
132 #[serde(default)]
134 pub auth_witnesses: Vec<AuthWitness>,
135 #[serde(default)]
137 pub capsules: Vec<Capsule>,
138 #[serde(default)]
140 pub additional_scopes: Vec<AztecAddress>,
141 pub profile_mode: Option<ProfileMode>,
143 #[serde(default = "default_skip_proof_generation")]
145 pub skip_proof_generation: bool,
146 pub gas_settings: Option<GasSettings>,
148 #[serde(default, skip_serializing_if = "Option::is_none")]
150 pub fee_execution_payload: Option<ExecutionPayload>,
151}
152
153#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
155#[serde(rename_all = "camelCase")]
156pub struct ExecuteUtilityOptions {
157 pub scope: AztecAddress,
159 #[serde(default)]
161 pub auth_witnesses: Vec<AuthWitness>,
162}
163
164#[derive(Clone, Debug, Serialize, Deserialize)]
166pub struct TxSimulationResult {
167 pub return_values: serde_json::Value,
169 pub gas_used: Option<Gas>,
171}
172
173#[derive(Clone, Debug, Serialize, Deserialize)]
175pub struct TxProfileResult {
176 pub return_values: serde_json::Value,
178 pub gas_used: Option<Gas>,
180 pub profile_data: serde_json::Value,
182}
183
184#[derive(Clone, Debug, Serialize, Deserialize)]
186pub struct UtilityExecutionResult {
187 pub result: serde_json::Value,
189 #[serde(default, skip_serializing_if = "Option::is_none")]
191 pub stats: Option<serde_json::Value>,
192}
193
194#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
196pub struct SendResult {
197 pub tx_hash: TxHash,
199}
200
201#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
203#[serde(rename_all = "camelCase")]
204pub struct EventMetadataDefinition {
205 pub event_selector: EventSelector,
207 pub abi_type: AbiType,
209 pub field_names: Vec<String>,
211}
212
213#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
215#[serde(rename_all = "camelCase")]
216pub struct PrivateEventFilter {
217 pub contract_address: AztecAddress,
219 #[serde(default)]
221 pub scopes: Vec<AztecAddress>,
222 pub tx_hash: Option<TxHash>,
224 pub from_block: Option<u64>,
226 pub to_block: Option<u64>,
228 pub after_log: Option<LogId>,
230}
231
232#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
234#[serde(rename_all = "camelCase")]
235pub struct PrivateEventMetadata {
236 pub tx_hash: TxHash,
238 pub block_number: Option<u64>,
240 pub log_index: Option<u64>,
242}
243
244#[derive(Clone, Debug, Serialize, Deserialize)]
249#[serde(rename_all = "camelCase")]
250pub struct PrivateEvent {
251 pub event: serde_json::Value,
253 pub metadata: PrivateEventMetadata,
255}
256
257impl Default for SimulateOptions {
258 fn default() -> Self {
259 Self {
260 from: AztecAddress(Fr::zero()),
261 skip_validation: false,
262 skip_fee_enforcement: default_skip_fee_enforcement(),
263 auth_witnesses: vec![],
264 capsules: vec![],
265 additional_scopes: vec![],
266 gas_settings: None,
267 fee_execution_payload: None,
268 estimate_gas: false,
269 estimated_gas_padding: None,
270 }
271 }
272}
273
274impl Default for SendOptions {
275 fn default() -> Self {
276 Self {
277 from: AztecAddress(Fr::zero()),
278 auth_witnesses: vec![],
279 capsules: vec![],
280 additional_scopes: vec![],
281 gas_settings: None,
282 fee_execution_payload: None,
283 }
284 }
285}
286
287impl Default for ProfileOptions {
288 fn default() -> Self {
289 Self {
290 from: AztecAddress(Fr::zero()),
291 auth_witnesses: vec![],
292 capsules: vec![],
293 additional_scopes: vec![],
294 profile_mode: None,
295 skip_proof_generation: default_skip_proof_generation(),
296 gas_settings: None,
297 fee_execution_payload: None,
298 }
299 }
300}
301
302impl Default for ExecuteUtilityOptions {
303 fn default() -> Self {
304 Self {
305 scope: AztecAddress(Fr::zero()),
306 auth_witnesses: vec![],
307 }
308 }
309}
310
311const fn default_skip_fee_enforcement() -> bool {
312 true
313}
314
315const fn default_skip_proof_generation() -> bool {
316 true
317}
318
319#[async_trait]
329pub trait Wallet: Send + Sync {
330 async fn get_chain_info(&self) -> Result<ChainInfo, Error>;
332
333 async fn get_accounts(&self) -> Result<Vec<Aliased<AztecAddress>>, Error>;
335
336 async fn get_address_book(&self) -> Result<Vec<Aliased<AztecAddress>>, Error>;
338
339 async fn register_sender(
341 &self,
342 address: AztecAddress,
343 alias: Option<String>,
344 ) -> Result<AztecAddress, Error>;
345
346 async fn get_contract_metadata(&self, address: AztecAddress)
348 -> Result<ContractMetadata, Error>;
349
350 async fn get_contract_class_metadata(
352 &self,
353 class_id: Fr,
354 ) -> Result<ContractClassMetadata, Error>;
355
356 async fn register_contract(
358 &self,
359 instance: ContractInstanceWithAddress,
360 artifact: Option<ContractArtifact>,
361 secret_key: Option<Fr>,
362 ) -> Result<ContractInstanceWithAddress, Error>;
363
364 async fn get_private_events(
366 &self,
367 event_metadata: &EventMetadataDefinition,
368 filter: PrivateEventFilter,
369 ) -> Result<Vec<PrivateEvent>, Error>;
370
371 async fn simulate_tx(
373 &self,
374 exec: ExecutionPayload,
375 opts: SimulateOptions,
376 ) -> Result<TxSimulationResult, Error>;
377
378 async fn execute_utility(
380 &self,
381 call: FunctionCall,
382 opts: ExecuteUtilityOptions,
383 ) -> Result<UtilityExecutionResult, Error>;
384
385 async fn profile_tx(
387 &self,
388 exec: ExecutionPayload,
389 opts: ProfileOptions,
390 ) -> Result<TxProfileResult, Error>;
391
392 async fn send_tx(&self, exec: ExecutionPayload, opts: SendOptions)
394 -> Result<SendResult, Error>;
395
396 async fn wait_for_contract(&self, address: AztecAddress) -> Result<(), Error>;
398
399 async fn wait_for_tx_proven(&self, tx_hash: TxHash) -> Result<(), Error>;
401
402 async fn create_auth_wit(
404 &self,
405 from: AztecAddress,
406 message_hash_or_intent: MessageHashOrIntent,
407 ) -> Result<AuthWitness, Error>;
408
409 async fn get_public_storage_at(&self, contract: &AztecAddress, slot: &Fr) -> Result<Fr, Error>;
411}
412
413#[async_trait]
418impl<W: Wallet> Wallet for Arc<W> {
419 async fn get_chain_info(&self) -> Result<ChainInfo, Error> {
420 (**self).get_chain_info().await
421 }
422 async fn get_accounts(&self) -> Result<Vec<Aliased<AztecAddress>>, Error> {
423 (**self).get_accounts().await
424 }
425 async fn get_address_book(&self) -> Result<Vec<Aliased<AztecAddress>>, Error> {
426 (**self).get_address_book().await
427 }
428 async fn register_sender(
429 &self,
430 address: AztecAddress,
431 alias: Option<String>,
432 ) -> Result<AztecAddress, Error> {
433 (**self).register_sender(address, alias).await
434 }
435 async fn get_contract_metadata(
436 &self,
437 address: AztecAddress,
438 ) -> Result<ContractMetadata, Error> {
439 (**self).get_contract_metadata(address).await
440 }
441 async fn get_contract_class_metadata(
442 &self,
443 class_id: Fr,
444 ) -> Result<ContractClassMetadata, Error> {
445 (**self).get_contract_class_metadata(class_id).await
446 }
447 async fn register_contract(
448 &self,
449 instance: ContractInstanceWithAddress,
450 artifact: Option<ContractArtifact>,
451 secret_key: Option<Fr>,
452 ) -> Result<ContractInstanceWithAddress, Error> {
453 (**self)
454 .register_contract(instance, artifact, secret_key)
455 .await
456 }
457 async fn get_private_events(
458 &self,
459 event_metadata: &EventMetadataDefinition,
460 filter: PrivateEventFilter,
461 ) -> Result<Vec<PrivateEvent>, Error> {
462 (**self).get_private_events(event_metadata, filter).await
463 }
464 async fn simulate_tx(
465 &self,
466 exec: ExecutionPayload,
467 opts: SimulateOptions,
468 ) -> Result<TxSimulationResult, Error> {
469 (**self).simulate_tx(exec, opts).await
470 }
471 async fn execute_utility(
472 &self,
473 call: FunctionCall,
474 opts: ExecuteUtilityOptions,
475 ) -> Result<UtilityExecutionResult, Error> {
476 (**self).execute_utility(call, opts).await
477 }
478 async fn profile_tx(
479 &self,
480 exec: ExecutionPayload,
481 opts: ProfileOptions,
482 ) -> Result<TxProfileResult, Error> {
483 (**self).profile_tx(exec, opts).await
484 }
485 async fn send_tx(
486 &self,
487 exec: ExecutionPayload,
488 opts: SendOptions,
489 ) -> Result<SendResult, Error> {
490 (**self).send_tx(exec, opts).await
491 }
492 async fn wait_for_contract(&self, address: AztecAddress) -> Result<(), Error> {
493 (**self).wait_for_contract(address).await
494 }
495 async fn wait_for_tx_proven(&self, tx_hash: TxHash) -> Result<(), Error> {
496 (**self).wait_for_tx_proven(tx_hash).await
497 }
498 async fn create_auth_wit(
499 &self,
500 from: AztecAddress,
501 message_hash_or_intent: MessageHashOrIntent,
502 ) -> Result<AuthWitness, Error> {
503 (**self).create_auth_wit(from, message_hash_or_intent).await
504 }
505 async fn get_public_storage_at(&self, contract: &AztecAddress, slot: &Fr) -> Result<Fr, Error> {
506 (**self).get_public_storage_at(contract, slot).await
507 }
508}
509
510fn lock_mutex<T>(mutex: &Mutex<T>) -> Result<std::sync::MutexGuard<'_, T>, Error> {
515 mutex
516 .lock()
517 .map_err(|e| Error::InvalidData(format!("mutex poisoned: {e}")))
518}
519
520pub struct MockWallet {
526 chain_info: ChainInfo,
527 accounts: Mutex<Vec<Aliased<AztecAddress>>>,
528 address_book: Mutex<Vec<Aliased<AztecAddress>>>,
529 contracts: Mutex<HashMap<AztecAddress, ContractMetadata>>,
530 contract_classes: Mutex<HashMap<Fr, ContractClassMetadata>>,
531 simulate_result: TxSimulationResult,
532 send_result: SendResult,
533}
534
535impl MockWallet {
536 pub fn new(chain_info: ChainInfo) -> Self {
538 Self {
539 chain_info,
540 accounts: Mutex::new(vec![]),
541 address_book: Mutex::new(vec![]),
542 contracts: Mutex::new(HashMap::new()),
543 contract_classes: Mutex::new(HashMap::new()),
544 simulate_result: TxSimulationResult {
545 return_values: serde_json::Value::Null,
546 gas_used: None,
547 },
548 send_result: SendResult {
549 tx_hash: TxHash::zero(),
550 },
551 }
552 }
553
554 #[must_use]
556 pub fn with_simulate_result(mut self, result: TxSimulationResult) -> Self {
557 self.simulate_result = result;
558 self
559 }
560
561 #[must_use]
563 #[allow(clippy::missing_const_for_fn)]
564 pub fn with_send_result(mut self, result: SendResult) -> Self {
565 self.send_result = result;
566 self
567 }
568
569 pub fn add_account(&self, address: AztecAddress, alias: Option<String>) -> Result<(), Error> {
571 lock_mutex(&self.accounts)?.push(Aliased {
572 alias: alias.unwrap_or_default(),
573 item: address,
574 });
575 Ok(())
576 }
577
578 pub fn register_contract_class(
580 &self,
581 class_id: Fr,
582 metadata: ContractClassMetadata,
583 ) -> Result<(), Error> {
584 lock_mutex(&self.contract_classes)?.insert(class_id, metadata);
585 Ok(())
586 }
587}
588
589#[async_trait]
590impl Wallet for MockWallet {
591 async fn get_chain_info(&self) -> Result<ChainInfo, Error> {
592 Ok(self.chain_info.clone())
593 }
594
595 async fn get_accounts(&self) -> Result<Vec<Aliased<AztecAddress>>, Error> {
596 Ok(lock_mutex(&self.accounts)?.clone())
597 }
598
599 async fn get_address_book(&self) -> Result<Vec<Aliased<AztecAddress>>, Error> {
600 Ok(lock_mutex(&self.address_book)?.clone())
601 }
602
603 async fn register_sender(
604 &self,
605 address: AztecAddress,
606 alias: Option<String>,
607 ) -> Result<AztecAddress, Error> {
608 lock_mutex(&self.address_book)?.push(Aliased {
609 alias: alias.unwrap_or_default(),
610 item: address,
611 });
612 Ok(address)
613 }
614
615 async fn get_contract_metadata(
616 &self,
617 address: AztecAddress,
618 ) -> Result<ContractMetadata, Error> {
619 lock_mutex(&self.contracts)?
620 .get(&address)
621 .cloned()
622 .ok_or_else(|| Error::InvalidData(format!("contract not registered: {address}")))
623 }
624
625 async fn get_contract_class_metadata(
626 &self,
627 class_id: Fr,
628 ) -> Result<ContractClassMetadata, Error> {
629 lock_mutex(&self.contract_classes)?
630 .get(&class_id)
631 .cloned()
632 .ok_or_else(|| Error::InvalidData(format!("contract class not registered: {class_id}")))
633 }
634
635 async fn register_contract(
636 &self,
637 instance: ContractInstanceWithAddress,
638 artifact: Option<ContractArtifact>,
639 _secret_key: Option<Fr>,
640 ) -> Result<ContractInstanceWithAddress, Error> {
641 let metadata = ContractMetadata {
642 instance: Some(instance.clone()),
643 is_contract_initialized: false,
644 is_contract_published: false,
645 is_contract_updated: false,
646 updated_contract_class_id: None,
647 };
648 lock_mutex(&self.contracts)?.insert(instance.address, metadata);
649
650 if artifact.is_some() {
651 lock_mutex(&self.contract_classes)?
652 .entry(instance.inner.current_contract_class_id)
653 .or_insert(ContractClassMetadata {
654 is_artifact_registered: true,
655 is_contract_class_publicly_registered: false,
656 });
657 }
658
659 Ok(instance)
660 }
661
662 async fn get_private_events(
663 &self,
664 _event_metadata: &EventMetadataDefinition,
665 _filter: PrivateEventFilter,
666 ) -> Result<Vec<PrivateEvent>, Error> {
667 Ok(vec![])
668 }
669
670 async fn simulate_tx(
671 &self,
672 _exec: ExecutionPayload,
673 _opts: SimulateOptions,
674 ) -> Result<TxSimulationResult, Error> {
675 Ok(self.simulate_result.clone())
676 }
677
678 async fn execute_utility(
679 &self,
680 _call: FunctionCall,
681 _opts: ExecuteUtilityOptions,
682 ) -> Result<UtilityExecutionResult, Error> {
683 Ok(UtilityExecutionResult {
684 result: serde_json::Value::Null,
685 stats: None,
686 })
687 }
688
689 async fn profile_tx(
690 &self,
691 _exec: ExecutionPayload,
692 _opts: ProfileOptions,
693 ) -> Result<TxProfileResult, Error> {
694 Ok(TxProfileResult {
695 return_values: serde_json::Value::Null,
696 gas_used: None,
697 profile_data: serde_json::Value::Null,
698 })
699 }
700
701 async fn send_tx(
702 &self,
703 _exec: ExecutionPayload,
704 _opts: SendOptions,
705 ) -> Result<SendResult, Error> {
706 Ok(self.send_result.clone())
707 }
708
709 async fn wait_for_contract(&self, _address: AztecAddress) -> Result<(), Error> {
710 Ok(())
711 }
712
713 async fn wait_for_tx_proven(&self, _tx_hash: TxHash) -> Result<(), Error> {
714 Ok(())
715 }
716
717 async fn create_auth_wit(
718 &self,
719 _from: AztecAddress,
720 _message_hash_or_intent: MessageHashOrIntent,
721 ) -> Result<AuthWitness, Error> {
722 Ok(AuthWitness::default())
723 }
724
725 async fn get_public_storage_at(
726 &self,
727 _contract: &AztecAddress,
728 _slot: &Fr,
729 ) -> Result<Fr, Error> {
730 Ok(Fr::zero())
731 }
732}
733
734#[cfg(test)]
739#[allow(clippy::unwrap_used, clippy::expect_used)]
740mod tests {
741 use super::*;
742 use crate::abi::{AbiParameter, FunctionSelector, FunctionType};
743 use crate::types::{ContractInstance, PublicKeys};
744
745 fn sample_chain_info() -> ChainInfo {
746 ChainInfo {
747 chain_id: Fr::from(31337u64),
748 version: Fr::from(1u64),
749 }
750 }
751
752 fn sample_instance() -> ContractInstanceWithAddress {
753 ContractInstanceWithAddress {
754 address: AztecAddress(Fr::from(1u64)),
755 inner: ContractInstance {
756 version: 1,
757 salt: Fr::from(42u64),
758 deployer: AztecAddress(Fr::from(2u64)),
759 current_contract_class_id: Fr::from(100u64),
760 original_contract_class_id: Fr::from(100u64),
761 initialization_hash: Fr::from(0u64),
762 public_keys: PublicKeys::default(),
763 },
764 }
765 }
766
767 #[test]
770 fn wallet_is_object_safe() {
771 fn _assert_object_safe(_: &dyn Wallet) {}
772 }
773
774 #[test]
777 fn mock_wallet_is_send_sync() {
778 fn assert_send_sync<T: Send + Sync>() {}
779 assert_send_sync::<MockWallet>();
780 }
781
782 #[test]
785 fn chain_info_roundtrip() {
786 let info = sample_chain_info();
787 let json = serde_json::to_string(&info).expect("serialize ChainInfo");
788 let decoded: ChainInfo = serde_json::from_str(&json).expect("deserialize ChainInfo");
789 assert_eq!(decoded, info);
790 }
791
792 #[test]
793 fn aliased_with_alias_roundtrip() {
794 let aliased = Aliased {
795 alias: "alice".to_owned(),
796 item: AztecAddress(Fr::from(1u64)),
797 };
798 let json = serde_json::to_string(&aliased).expect("serialize");
799 let decoded: Aliased<AztecAddress> = serde_json::from_str(&json).expect("deserialize");
800 assert_eq!(decoded, aliased);
801 }
802
803 #[test]
804 fn aliased_without_alias_roundtrip() {
805 let aliased: Aliased<AztecAddress> = Aliased {
806 alias: String::new(),
807 item: AztecAddress(Fr::from(1u64)),
808 };
809 let json = serde_json::to_string(&aliased).expect("serialize");
810 let decoded: Aliased<AztecAddress> = serde_json::from_str(&json).expect("deserialize");
811 assert_eq!(decoded, aliased);
812 }
813
814 #[test]
815 fn simulate_options_default() {
816 let opts = SimulateOptions::default();
817 assert_eq!(opts.from, AztecAddress(Fr::zero()));
818 assert!(!opts.skip_validation);
819 assert!(opts.skip_fee_enforcement);
820 assert!(opts.gas_settings.is_none());
821 assert!(opts.auth_witnesses.is_empty());
822 assert!(opts.capsules.is_empty());
823 assert!(opts.additional_scopes.is_empty());
824 }
825
826 #[test]
827 fn send_options_default() {
828 let opts = SendOptions::default();
829 assert_eq!(opts.from, AztecAddress(Fr::zero()));
830 assert!(opts.gas_settings.is_none());
831 assert!(opts.auth_witnesses.is_empty());
832 assert!(opts.capsules.is_empty());
833 assert!(opts.additional_scopes.is_empty());
834 }
835
836 #[test]
837 fn profile_options_default() {
838 let opts = ProfileOptions::default();
839 assert_eq!(opts.from, AztecAddress(Fr::zero()));
840 assert!(opts.profile_mode.is_none());
841 assert!(opts.skip_proof_generation);
842 assert!(opts.gas_settings.is_none());
843 }
844
845 #[test]
846 fn execute_utility_options_default() {
847 let opts = ExecuteUtilityOptions::default();
848 assert_eq!(opts.scope, AztecAddress(Fr::zero()));
849 assert!(opts.auth_witnesses.is_empty());
850 }
851
852 #[test]
853 fn send_result_roundtrip() {
854 let result = SendResult {
855 tx_hash: TxHash::zero(),
856 };
857 let json = serde_json::to_string(&result).expect("serialize");
858 let decoded: SendResult = serde_json::from_str(&json).expect("deserialize");
859 assert_eq!(decoded, result);
860 }
861
862 #[test]
863 fn private_event_filter_default() {
864 let filter = PrivateEventFilter::default();
865 assert_eq!(filter.contract_address, AztecAddress(Fr::zero()));
866 assert!(filter.scopes.is_empty());
867 assert!(filter.tx_hash.is_none());
868 assert!(filter.from_block.is_none());
869 assert!(filter.to_block.is_none());
870 assert!(filter.after_log.is_none());
871 }
872
873 #[test]
874 fn message_hash_roundtrip() {
875 let msg = MessageHashOrIntent::Hash {
876 hash: Fr::from(42u64),
877 };
878 let json = serde_json::to_string(&msg).expect("serialize");
879 let decoded: MessageHashOrIntent = serde_json::from_str(&json).expect("deserialize");
880 assert_eq!(decoded, msg);
881 }
882
883 #[test]
884 fn message_intent_roundtrip() {
885 let msg = MessageHashOrIntent::Intent {
886 caller: AztecAddress(Fr::from(1u64)),
887 call: FunctionCall {
888 to: AztecAddress(Fr::from(2u64)),
889 selector: FunctionSelector::from_hex("0xaabbccdd").expect("valid selector"),
890 args: vec![],
891 function_type: FunctionType::Private,
892 is_static: false,
893 hide_msg_sender: false,
894 },
895 };
896 let json = serde_json::to_string(&msg).expect("serialize");
897 let decoded: MessageHashOrIntent = serde_json::from_str(&json).expect("deserialize");
898 assert_eq!(decoded, msg);
899 }
900
901 #[test]
902 fn contract_metadata_roundtrip() {
903 let meta = ContractMetadata {
904 instance: Some(sample_instance()),
905 is_contract_initialized: false,
906 is_contract_published: false,
907 is_contract_updated: false,
908 updated_contract_class_id: None,
909 };
910 let json = serde_json::to_string(&meta).expect("serialize");
911 let decoded: ContractMetadata = serde_json::from_str(&json).expect("deserialize");
912 assert_eq!(decoded, meta);
913 }
914
915 #[test]
916 fn contract_class_metadata_roundtrip() {
917 let meta = ContractClassMetadata {
918 is_artifact_registered: true,
919 is_contract_class_publicly_registered: true,
920 };
921 let json = serde_json::to_string(&meta).expect("serialize");
922 let decoded: ContractClassMetadata = serde_json::from_str(&json).expect("deserialize");
923 assert_eq!(decoded, meta);
924 }
925
926 #[test]
927 fn event_metadata_definition_roundtrip() {
928 let def = EventMetadataDefinition {
929 event_selector: EventSelector(Fr::from(1u64)),
930 abi_type: AbiType::Struct {
931 name: "Transfer".to_owned(),
932 fields: vec![
933 AbiParameter {
934 name: "amount".to_owned(),
935 typ: AbiType::Field,
936 visibility: None,
937 },
938 AbiParameter {
939 name: "sender".to_owned(),
940 typ: AbiType::Field,
941 visibility: None,
942 },
943 ],
944 },
945 field_names: vec!["amount".to_owned(), "sender".to_owned()],
946 };
947 let json = serde_json::to_string(&def).expect("serialize");
948 let decoded: EventMetadataDefinition = serde_json::from_str(&json).expect("deserialize");
949 assert_eq!(decoded, def);
950 }
951
952 #[tokio::test]
955 async fn mock_wallet_get_chain_info() {
956 let wallet = MockWallet::new(sample_chain_info());
957 let info = wallet.get_chain_info().await.expect("get chain info");
958 assert_eq!(info.chain_id, Fr::from(31337u64));
959 assert_eq!(info.version, Fr::from(1u64));
960 }
961
962 #[tokio::test]
965 async fn mock_wallet_accounts_initially_empty() {
966 let wallet = MockWallet::new(sample_chain_info());
967 let accounts = wallet.get_accounts().await.expect("get accounts");
968 assert!(accounts.is_empty());
969 }
970
971 #[tokio::test]
972 async fn mock_wallet_add_and_get_accounts() {
973 let wallet = MockWallet::new(sample_chain_info());
974 wallet
975 .add_account(AztecAddress(Fr::from(1u64)), Some("alice".into()))
976 .expect("add account");
977 wallet
978 .add_account(AztecAddress(Fr::from(2u64)), None)
979 .expect("add account");
980
981 let accounts = wallet.get_accounts().await.expect("get accounts");
982 assert_eq!(accounts.len(), 2);
983 assert_eq!(accounts[0].alias, "alice");
984 assert!(accounts[1].alias.is_empty());
985 }
986
987 #[tokio::test]
990 async fn mock_wallet_register_sender() {
991 let wallet = MockWallet::new(sample_chain_info());
992 let addr = AztecAddress(Fr::from(99u64));
993 let result = wallet
994 .register_sender(addr, Some("bob".into()))
995 .await
996 .expect("register sender");
997 assert_eq!(result, addr);
998
999 let book = wallet.get_address_book().await.expect("get address book");
1000 assert_eq!(book.len(), 1);
1001 assert_eq!(book[0].item, addr);
1002 assert_eq!(book[0].alias, "bob");
1003 }
1004
1005 #[tokio::test]
1008 async fn mock_wallet_register_and_get_contract() {
1009 let wallet = MockWallet::new(sample_chain_info());
1010 let instance = sample_instance();
1011
1012 let registered = wallet
1013 .register_contract(instance.clone(), None, None)
1014 .await
1015 .expect("register contract");
1016 assert_eq!(registered.address, instance.address);
1017
1018 let metadata = wallet
1019 .get_contract_metadata(instance.address)
1020 .await
1021 .expect("get contract metadata");
1022 assert_eq!(
1023 metadata.instance.expect("registered instance").address,
1024 instance.address
1025 );
1026 assert!(!metadata.is_contract_initialized);
1027 assert!(!metadata.is_contract_published);
1028 assert!(!metadata.is_contract_updated);
1029 assert!(metadata.updated_contract_class_id.is_none());
1030 }
1031
1032 #[tokio::test]
1033 async fn mock_wallet_unregistered_contract_fails() {
1034 let wallet = MockWallet::new(sample_chain_info());
1035 let result = wallet
1036 .get_contract_metadata(AztecAddress(Fr::from(999u64)))
1037 .await;
1038 assert!(result.is_err());
1039 }
1040
1041 #[tokio::test]
1044 async fn mock_wallet_contract_class_metadata() {
1045 let wallet = MockWallet::new(sample_chain_info());
1046 let class_id = Fr::from(100u64);
1047
1048 wallet
1049 .register_contract_class(
1050 class_id,
1051 ContractClassMetadata {
1052 is_artifact_registered: true,
1053 is_contract_class_publicly_registered: true,
1054 },
1055 )
1056 .expect("register class");
1057
1058 let meta = wallet
1059 .get_contract_class_metadata(class_id)
1060 .await
1061 .expect("get class metadata");
1062 assert!(meta.is_artifact_registered);
1063 assert!(meta.is_contract_class_publicly_registered);
1064 }
1065
1066 #[tokio::test]
1067 async fn mock_wallet_unregistered_class_fails() {
1068 let wallet = MockWallet::new(sample_chain_info());
1069 let result = wallet.get_contract_class_metadata(Fr::from(999u64)).await;
1070 assert!(result.is_err());
1071 }
1072
1073 #[tokio::test]
1076 async fn mock_wallet_simulate_default() {
1077 let wallet = MockWallet::new(sample_chain_info());
1078 let result = wallet
1079 .simulate_tx(ExecutionPayload::default(), SimulateOptions::default())
1080 .await
1081 .expect("simulate tx");
1082 assert_eq!(result.return_values, serde_json::Value::Null);
1083 assert!(result.gas_used.is_none());
1084 }
1085
1086 #[tokio::test]
1087 async fn mock_wallet_simulate_custom_result() {
1088 let wallet =
1089 MockWallet::new(sample_chain_info()).with_simulate_result(TxSimulationResult {
1090 return_values: serde_json::json!([42]),
1091 gas_used: Some(Gas {
1092 da_gas: 100,
1093 l2_gas: 200,
1094 }),
1095 });
1096
1097 let result = wallet
1098 .simulate_tx(ExecutionPayload::default(), SimulateOptions::default())
1099 .await
1100 .expect("simulate tx");
1101 assert_eq!(result.return_values, serde_json::json!([42]));
1102 assert_eq!(result.gas_used.as_ref().map(|g| g.l2_gas), Some(200));
1103 }
1104
1105 #[tokio::test]
1108 async fn mock_wallet_send_default() {
1109 let wallet = MockWallet::new(sample_chain_info());
1110 let result = wallet
1111 .send_tx(ExecutionPayload::default(), SendOptions::default())
1112 .await
1113 .expect("send tx");
1114 assert_eq!(result.tx_hash, TxHash::zero());
1115 }
1116
1117 #[tokio::test]
1118 async fn mock_wallet_send_custom_result() {
1119 let tx_hash =
1120 TxHash::from_hex("0x00000000000000000000000000000000000000000000000000000000deadbeef")
1121 .expect("valid hex");
1122 let wallet = MockWallet::new(sample_chain_info()).with_send_result(SendResult { tx_hash });
1123
1124 let result = wallet
1125 .send_tx(ExecutionPayload::default(), SendOptions::default())
1126 .await
1127 .expect("send tx");
1128 assert_eq!(result.tx_hash, tx_hash);
1129 }
1130
1131 #[tokio::test]
1134 async fn mock_wallet_execute_utility() {
1135 let wallet = MockWallet::new(sample_chain_info());
1136 let call = FunctionCall {
1137 to: AztecAddress(Fr::from(1u64)),
1138 selector: FunctionSelector::from_hex("0xaabbccdd").expect("valid selector"),
1139 args: vec![],
1140 function_type: FunctionType::Utility,
1141 is_static: true,
1142 hide_msg_sender: false,
1143 };
1144 let result = wallet
1145 .execute_utility(call, ExecuteUtilityOptions::default())
1146 .await
1147 .expect("execute utility");
1148 assert_eq!(result.result, serde_json::Value::Null);
1149 assert!(result.stats.is_none());
1150 }
1151
1152 #[tokio::test]
1155 async fn mock_wallet_profile_tx() {
1156 let wallet = MockWallet::new(sample_chain_info());
1157 let result = wallet
1158 .profile_tx(ExecutionPayload::default(), ProfileOptions::default())
1159 .await
1160 .expect("profile tx");
1161 assert_eq!(result.return_values, serde_json::Value::Null);
1162 assert!(result.gas_used.is_none());
1163 }
1164
1165 #[tokio::test]
1168 async fn mock_wallet_private_events_empty() {
1169 let wallet = MockWallet::new(sample_chain_info());
1170 let events = wallet
1171 .get_private_events(
1172 &EventMetadataDefinition {
1173 event_selector: EventSelector(Fr::from(1u64)),
1174 abi_type: AbiType::Struct {
1175 name: "AmountOnly".to_owned(),
1176 fields: vec![AbiParameter {
1177 name: "amount".to_owned(),
1178 typ: AbiType::Field,
1179 visibility: None,
1180 }],
1181 },
1182 field_names: vec!["amount".to_owned()],
1183 },
1184 PrivateEventFilter {
1185 contract_address: AztecAddress(Fr::from(1u64)),
1186 scopes: vec![AztecAddress(Fr::from(2u64))],
1187 ..PrivateEventFilter::default()
1188 },
1189 )
1190 .await
1191 .expect("get private events");
1192 assert!(events.is_empty());
1193 }
1194
1195 #[tokio::test]
1198 async fn mock_wallet_create_auth_wit() {
1199 let wallet = MockWallet::new(sample_chain_info());
1200 let wit = wallet
1201 .create_auth_wit(
1202 AztecAddress(Fr::from(1u64)),
1203 MessageHashOrIntent::Hash {
1204 hash: Fr::from(42u64),
1205 },
1206 )
1207 .await
1208 .expect("create auth wit");
1209 assert!(wit.fields.is_empty());
1210 }
1211
1212 #[test]
1215 fn profile_mode_serialization() {
1216 for mode in [
1217 ProfileMode::Gates,
1218 ProfileMode::ExecutionSteps,
1219 ProfileMode::Full,
1220 ] {
1221 let json = serde_json::to_string(&mode).expect("serialize");
1222 let decoded: ProfileMode = serde_json::from_str(&json).expect("deserialize");
1223 assert_eq!(decoded, mode);
1224 }
1225 assert_eq!(
1226 serde_json::to_string(&ProfileMode::Gates).unwrap(),
1227 "\"gates\""
1228 );
1229 assert_eq!(
1230 serde_json::to_string(&ProfileMode::ExecutionSteps).unwrap(),
1231 "\"execution-steps\""
1232 );
1233 assert_eq!(
1234 serde_json::to_string(&ProfileMode::Full).unwrap(),
1235 "\"full\""
1236 );
1237 }
1238}