soroban_sdk/
env.rs

1use core::convert::Infallible;
2
3#[cfg(target_family = "wasm")]
4pub mod internal {
5    use core::convert::Infallible;
6
7    pub use soroban_env_guest::*;
8    pub type EnvImpl = Guest;
9    pub type MaybeEnvImpl = Guest;
10
11    // In the Guest case, Env::Error is already Infallible so there is no work
12    // to do to "reject an error": if an error occurs in the environment, the
13    // host will trap our VM and we'll never get here at all.
14    pub(crate) fn reject_err<T>(_env: &Guest, r: Result<T, Infallible>) -> Result<T, Infallible> {
15        r
16    }
17}
18
19#[cfg(not(target_family = "wasm"))]
20pub mod internal {
21    use core::convert::Infallible;
22
23    pub use soroban_env_host::*;
24    pub type EnvImpl = Host;
25    pub type MaybeEnvImpl = Option<Host>;
26
27    // When we have `feature="testutils"` (or are in cfg(test)) we enable feature
28    // `soroban-env-{common,host}/testutils` which in turn adds the helper method
29    // `Env::escalate_error_to_panic` to the Env trait.
30    //
31    // When this is available we want to use it, because it works in concert
32    // with a _different_ part of the host that's also `testutils`-gated: the
33    // mechanism for emulating the WASM VM error-handling semantics with native
34    // contracts. In particular when a WASM contract calls a host function that
35    // fails with some error E, the host traps the VM (not returning to it at
36    // all) and propagates E to the caller of the contract. This is simulated in
37    // the native case by returning a (nontrivial) error E to us here, which we
38    // then "reject" back to the host, which stores E in a temporary cell inside
39    // any `TestContract` frame in progress and then _panics_, unwinding back to
40    // a panic-catcher it installed when invoking the `TestContract` frame, and
41    // then extracting E from the frame and returning it to its caller. This
42    // simulates the "crash, but catching the error" behaviour of the WASM case.
43    // This only works if we panic via `escalate_error_to_panic`.
44    //
45    // (The reason we don't just panic_any() here and let the panic-catcher do a
46    // type-based catch is that there might _be_ no panic-catcher around us, and
47    // we want to print out a nice error message in that case too, which
48    // panic_any() does not do us the favor of producing. This is all very
49    // subtle. See also soroban_env_host::Host::escalate_error_to_panic.)
50    #[cfg(any(test, feature = "testutils"))]
51    pub(crate) fn reject_err<T>(env: &Host, r: Result<T, HostError>) -> Result<T, Infallible> {
52        r.map_err(|e| env.escalate_error_to_panic(e))
53    }
54
55    // When we're _not_ in a cfg enabling `soroban-env-{common,host}/testutils`,
56    // there is no `Env::escalate_error_to_panic` to call, so we just panic
57    // here. But this is ok because in that case there is also no multi-contract
58    // calling machinery set up, nor probably any panic-catcher installed that
59    // we need to hide error values for the benefit of. Any panic in this case
60    // is probably going to unwind completely anyways. No special case needed.
61    #[cfg(not(any(test, feature = "testutils")))]
62    pub(crate) fn reject_err<T>(_env: &Host, r: Result<T, HostError>) -> Result<T, Infallible> {
63        r.map_err(|e| panic!("{:?}", e))
64    }
65
66    #[doc(hidden)]
67    impl<F, T> Convert<F, T> for super::Env
68    where
69        EnvImpl: Convert<F, T>,
70    {
71        type Error = <EnvImpl as Convert<F, T>>::Error;
72        fn convert(&self, f: F) -> Result<T, Self::Error> {
73            self.env_impl.convert(f)
74        }
75    }
76}
77
78pub use internal::xdr;
79pub use internal::ConversionError;
80pub use internal::EnvBase;
81pub use internal::Error;
82pub use internal::MapObject;
83pub use internal::SymbolStr;
84pub use internal::TryFromVal;
85pub use internal::TryIntoVal;
86pub use internal::Val;
87pub use internal::VecObject;
88
89pub trait IntoVal<E: internal::Env, T> {
90    fn into_val(&self, e: &E) -> T;
91}
92
93pub trait FromVal<E: internal::Env, T> {
94    fn from_val(e: &E, v: &T) -> Self;
95}
96
97impl<E: internal::Env, T, U> FromVal<E, T> for U
98where
99    U: TryFromVal<E, T>,
100{
101    fn from_val(e: &E, v: &T) -> Self {
102        U::try_from_val(e, v).unwrap_optimized()
103    }
104}
105
106impl<E: internal::Env, T, U> IntoVal<E, T> for U
107where
108    T: FromVal<E, Self>,
109{
110    fn into_val(&self, e: &E) -> T {
111        T::from_val(e, self)
112    }
113}
114
115use crate::auth::InvokerContractAuthEntry;
116use crate::unwrap::UnwrapInfallible;
117use crate::unwrap::UnwrapOptimized;
118use crate::InvokeError;
119use crate::{
120    crypto::Crypto, deploy::Deployer, events::Events, ledger::Ledger, logs::Logs, prng::Prng,
121    storage::Storage, Address, Vec,
122};
123use internal::{
124    AddressObject, Bool, BytesObject, DurationObject, I128Object, I256Object, I256Val, I64Object,
125    StorageType, StringObject, Symbol, SymbolObject, TimepointObject, U128Object, U256Object,
126    U256Val, U32Val, U64Object, U64Val, Void,
127};
128
129#[doc(hidden)]
130#[derive(Clone)]
131pub struct MaybeEnv {
132    maybe_env_impl: internal::MaybeEnvImpl,
133    #[cfg(any(test, feature = "testutils"))]
134    test_state: Option<EnvTestState>,
135}
136
137#[cfg(target_family = "wasm")]
138impl TryFrom<MaybeEnv> for Env {
139    type Error = Infallible;
140
141    fn try_from(_value: MaybeEnv) -> Result<Self, Self::Error> {
142        Ok(Env {
143            env_impl: internal::EnvImpl {},
144        })
145    }
146}
147
148impl Default for MaybeEnv {
149    fn default() -> Self {
150        Self::none()
151    }
152}
153
154#[cfg(target_family = "wasm")]
155impl MaybeEnv {
156    // separate function to be const
157    pub const fn none() -> Self {
158        Self {
159            maybe_env_impl: internal::EnvImpl {},
160        }
161    }
162}
163
164#[cfg(not(target_family = "wasm"))]
165impl MaybeEnv {
166    // separate function to be const
167    pub const fn none() -> Self {
168        Self {
169            maybe_env_impl: None,
170            #[cfg(any(test, feature = "testutils"))]
171            test_state: None,
172        }
173    }
174}
175
176#[cfg(target_family = "wasm")]
177impl From<Env> for MaybeEnv {
178    fn from(value: Env) -> Self {
179        MaybeEnv {
180            maybe_env_impl: value.env_impl,
181        }
182    }
183}
184
185#[cfg(not(target_family = "wasm"))]
186impl TryFrom<MaybeEnv> for Env {
187    type Error = ConversionError;
188
189    fn try_from(value: MaybeEnv) -> Result<Self, Self::Error> {
190        if let Some(env_impl) = value.maybe_env_impl {
191            Ok(Env {
192                env_impl,
193                #[cfg(any(test, feature = "testutils"))]
194                test_state: value.test_state.unwrap_or_default(),
195            })
196        } else {
197            Err(ConversionError)
198        }
199    }
200}
201
202#[cfg(not(target_family = "wasm"))]
203impl From<Env> for MaybeEnv {
204    fn from(value: Env) -> Self {
205        MaybeEnv {
206            maybe_env_impl: Some(value.env_impl.clone()),
207            #[cfg(any(test, feature = "testutils"))]
208            test_state: Some(value.test_state.clone()),
209        }
210    }
211}
212
213/// The [Env] type provides access to the environment the contract is executing
214/// within.
215///
216/// The [Env] provides access to information about the currently executing
217/// contract, who invoked it, contract data, functions for signing, hashing,
218/// etc.
219///
220/// Most types require access to an [Env] to be constructed or converted.
221#[derive(Clone)]
222pub struct Env {
223    env_impl: internal::EnvImpl,
224    #[cfg(any(test, feature = "testutils"))]
225    test_state: EnvTestState,
226}
227
228impl Default for Env {
229    #[cfg(not(any(test, feature = "testutils")))]
230    fn default() -> Self {
231        Self {
232            env_impl: Default::default(),
233        }
234    }
235
236    #[cfg(any(test, feature = "testutils"))]
237    fn default() -> Self {
238        Self::new_with_config(EnvTestConfig::default())
239    }
240}
241
242#[cfg(any(test, feature = "testutils"))]
243#[derive(Clone, Default)]
244struct EnvTestState {
245    config: EnvTestConfig,
246    generators: Rc<RefCell<Generators>>,
247    auth_snapshot: Rc<RefCell<AuthSnapshot>>,
248    snapshot: Option<Rc<LedgerSnapshot>>,
249}
250
251/// Config for changing the default behavior of the Env when used in tests.
252#[cfg(any(test, feature = "testutils"))]
253#[derive(Clone)]
254pub struct EnvTestConfig {
255    /// Capture a test snapshot when the Env is dropped, causing a test snapshot
256    /// JSON file to be written to disk when the Env is no longer referenced.
257    /// Defaults to true.
258    pub capture_snapshot_at_drop: bool,
259}
260
261#[cfg(any(test, feature = "testutils"))]
262impl Default for EnvTestConfig {
263    fn default() -> Self {
264        Self {
265            capture_snapshot_at_drop: true,
266        }
267    }
268}
269
270impl Env {
271    /// Panic with the given error.
272    ///
273    /// Equivalent to `panic!`, but with an error value instead of a string.
274    #[doc(hidden)]
275    #[inline(always)]
276    pub fn panic_with_error(&self, error: impl Into<internal::Error>) -> ! {
277        _ = internal::Env::fail_with_error(self, error.into());
278        #[cfg(target_family = "wasm")]
279        core::arch::wasm32::unreachable();
280        #[cfg(not(target_family = "wasm"))]
281        unreachable!();
282    }
283
284    /// Get a [Storage] for accessing and updating persistent data owned by the
285    /// currently executing contract.
286    #[inline(always)]
287    pub fn storage(&self) -> Storage {
288        Storage::new(self)
289    }
290
291    /// Get [Events] for publishing events associated with the
292    /// currently executing contract.
293    #[inline(always)]
294    pub fn events(&self) -> Events {
295        Events::new(self)
296    }
297
298    /// Get a [Ledger] for accessing the current ledger.
299    #[inline(always)]
300    pub fn ledger(&self) -> Ledger {
301        Ledger::new(self)
302    }
303
304    /// Get a deployer for deploying contracts.
305    #[inline(always)]
306    pub fn deployer(&self) -> Deployer {
307        Deployer::new(self)
308    }
309
310    /// Get a [Crypto] for accessing the current cryptographic functions.
311    #[inline(always)]
312    pub fn crypto(&self) -> Crypto {
313        Crypto::new(self)
314    }
315
316    /// # ⚠️ Hazardous Materials
317    ///
318    /// Get a [CryptoHazmat][crate::crypto::CryptoHazmat] for accessing the
319    /// cryptographic functions that are not generally recommended. Using them
320    /// incorrectly can introduce security vulnerabilities. Use [Crypto] if
321    /// possible.
322    #[cfg(any(test, feature = "hazmat"))]
323    #[cfg_attr(feature = "docs", doc(cfg(feature = "hazmat")))]
324    #[inline(always)]
325    pub fn crypto_hazmat(&self) -> crate::crypto::CryptoHazmat {
326        crate::crypto::CryptoHazmat::new(self)
327    }
328
329    /// Get a [Prng] for accessing the current functions which provide pseudo-randomness.
330    ///
331    /// # Warning
332    ///
333    /// **The pseudo-random generator returned is not suitable for
334    /// security-sensitive work.**
335    #[inline(always)]
336    pub fn prng(&self) -> Prng {
337        Prng::new(self)
338    }
339
340    /// Get the Address object corresponding to the current executing contract.
341    pub fn current_contract_address(&self) -> Address {
342        let address = internal::Env::get_current_contract_address(self).unwrap_infallible();
343        unsafe { Address::unchecked_new(self.clone(), address) }
344    }
345
346    #[doc(hidden)]
347    pub(crate) fn require_auth_for_args(&self, address: &Address, args: Vec<Val>) {
348        internal::Env::require_auth_for_args(self, address.to_object(), args.to_object())
349            .unwrap_infallible();
350    }
351
352    #[doc(hidden)]
353    pub(crate) fn require_auth(&self, address: &Address) {
354        internal::Env::require_auth(self, address.to_object()).unwrap_infallible();
355    }
356
357    /// Invokes a function of a contract that is registered in the [Env].
358    ///
359    /// # Panics
360    ///
361    /// Will panic if the `contract_id` does not match a registered contract,
362    /// `func` does not match a function of the referenced contract, or the
363    /// number of `args` do not match the argument count of the referenced
364    /// contract function.
365    ///
366    /// Will panic if the contract that is invoked fails or aborts in anyway.
367    ///
368    /// Will panic if the value returned from the contract cannot be converted
369    /// into the type `T`.
370    pub fn invoke_contract<T>(
371        &self,
372        contract_address: &Address,
373        func: &crate::Symbol,
374        args: Vec<Val>,
375    ) -> T
376    where
377        T: TryFromVal<Env, Val>,
378    {
379        let rv = internal::Env::call(
380            self,
381            contract_address.to_object(),
382            func.to_symbol_val(),
383            args.to_object(),
384        )
385        .unwrap_infallible();
386        T::try_from_val(self, &rv)
387            .map_err(|_| ConversionError)
388            .unwrap()
389    }
390
391    /// Invokes a function of a contract that is registered in the [Env],
392    /// returns an error if the invocation fails for any reason.
393    pub fn try_invoke_contract<T, E>(
394        &self,
395        contract_address: &Address,
396        func: &crate::Symbol,
397        args: Vec<Val>,
398    ) -> Result<Result<T, T::Error>, Result<E, InvokeError>>
399    where
400        T: TryFromVal<Env, Val>,
401        E: TryFrom<Error>,
402        E::Error: Into<InvokeError>,
403    {
404        let rv = internal::Env::try_call(
405            self,
406            contract_address.to_object(),
407            func.to_symbol_val(),
408            args.to_object(),
409        )
410        .unwrap_infallible();
411        match internal::Error::try_from_val(self, &rv) {
412            Ok(err) => Err(E::try_from(err).map_err(Into::into)),
413            Err(ConversionError) => Ok(T::try_from_val(self, &rv)),
414        }
415    }
416
417    /// Authorizes sub-contract calls on behalf of the current contract.
418    ///
419    /// All the direct calls that the current contract performs are always
420    /// considered to have been authorized. This is only needed to authorize
421    /// deeper calls that originate from the next contract call from the current
422    /// contract.
423    ///
424    /// For example, if the contract A calls contract B, contract
425    /// B calls contract C and contract C calls `A.require_auth()`, then an
426    /// entry corresponding to C call has to be passed in `auth_entries`. It
427    /// doesn't matter if contract B called `require_auth` or not. If contract A
428    /// calls contract B again, then `authorize_as_current_contract` has to be
429    /// called again with the respective entries.
430    ///
431    ///
432    pub fn authorize_as_current_contract(&self, auth_entries: Vec<InvokerContractAuthEntry>) {
433        internal::Env::authorize_as_curr_contract(self, auth_entries.to_object())
434            .unwrap_infallible();
435    }
436
437    /// Get the [Logs] for logging debug events.
438    #[inline(always)]
439    #[deprecated(note = "use [Env::logs]")]
440    #[doc(hidden)]
441    pub fn logger(&self) -> Logs {
442        self.logs()
443    }
444
445    /// Get the [Logs] for logging debug events.
446    #[inline(always)]
447    pub fn logs(&self) -> Logs {
448        Logs::new(self)
449    }
450}
451
452#[doc(hidden)]
453#[cfg(not(target_family = "wasm"))]
454impl Env {
455    pub(crate) fn is_same_env(&self, other: &Self) -> bool {
456        self.env_impl.check_same_env(&other.env_impl).is_ok()
457    }
458}
459
460#[cfg(any(test, feature = "testutils"))]
461use crate::testutils::cost_estimate::CostEstimate;
462#[cfg(any(test, feature = "testutils"))]
463use crate::{
464    auth,
465    testutils::{
466        budget::Budget, Address as _, AuthSnapshot, AuthorizedInvocation, ContractFunctionSet,
467        EventsSnapshot, Generators, Ledger as _, MockAuth, MockAuthContract, Register, Snapshot,
468        StellarAssetContract, StellarAssetIssuer,
469    },
470    Bytes, BytesN, ConstructorArgs,
471};
472#[cfg(any(test, feature = "testutils"))]
473use core::{cell::RefCell, cell::RefMut};
474#[cfg(any(test, feature = "testutils"))]
475use internal::ContractInvocationEvent;
476#[cfg(any(test, feature = "testutils"))]
477use soroban_ledger_snapshot::LedgerSnapshot;
478#[cfg(any(test, feature = "testutils"))]
479use std::{path::Path, rc::Rc};
480#[cfg(any(test, feature = "testutils"))]
481use xdr::{LedgerEntry, LedgerKey, LedgerKeyContractData, SorobanAuthorizationEntry};
482
483#[cfg(any(test, feature = "testutils"))]
484#[cfg_attr(feature = "docs", doc(cfg(feature = "testutils")))]
485impl Env {
486    #[doc(hidden)]
487    pub fn in_contract(&self) -> bool {
488        self.env_impl.has_frame().unwrap()
489    }
490
491    #[doc(hidden)]
492    pub fn host(&self) -> &internal::Host {
493        &self.env_impl
494    }
495
496    #[doc(hidden)]
497    pub(crate) fn with_generator<T>(&self, f: impl FnOnce(RefMut<'_, Generators>) -> T) -> T {
498        f((*self.test_state.generators).borrow_mut())
499    }
500
501    /// Create an Env with the test config.
502    pub fn new_with_config(config: EnvTestConfig) -> Env {
503        struct EmptySnapshotSource();
504
505        impl internal::storage::SnapshotSource for EmptySnapshotSource {
506            fn get(
507                &self,
508                _key: &Rc<xdr::LedgerKey>,
509            ) -> Result<Option<(Rc<xdr::LedgerEntry>, Option<u32>)>, soroban_env_host::HostError>
510            {
511                Ok(None)
512            }
513        }
514
515        let rf = Rc::new(EmptySnapshotSource());
516        let info = internal::LedgerInfo {
517            protocol_version: 22,
518            sequence_number: 0,
519            timestamp: 0,
520            network_id: [0; 32],
521            base_reserve: 0,
522            min_persistent_entry_ttl: 4096,
523            min_temp_entry_ttl: 16,
524            max_entry_ttl: 6_312_000,
525        };
526
527        Env::new_for_testutils(config, rf, None, info, None)
528    }
529
530    /// Change the test config of an Env.
531    pub fn set_config(&mut self, config: EnvTestConfig) {
532        self.test_state.config = config;
533    }
534
535    /// Used by multiple constructors to configure test environments consistently.
536    fn new_for_testutils(
537        config: EnvTestConfig,
538        recording_footprint: Rc<dyn internal::storage::SnapshotSource>,
539        generators: Option<Rc<RefCell<Generators>>>,
540        ledger_info: internal::LedgerInfo,
541        snapshot: Option<Rc<LedgerSnapshot>>,
542    ) -> Env {
543        let storage = internal::storage::Storage::with_recording_footprint(recording_footprint);
544        let budget = internal::budget::Budget::default();
545        let env_impl = internal::EnvImpl::with_storage_and_budget(storage, budget.clone());
546        env_impl
547            .set_source_account(xdr::AccountId(xdr::PublicKey::PublicKeyTypeEd25519(
548                xdr::Uint256([0; 32]),
549            )))
550            .unwrap();
551        env_impl
552            .set_diagnostic_level(internal::DiagnosticLevel::Debug)
553            .unwrap();
554        env_impl.set_base_prng_seed([0; 32]).unwrap();
555
556        let auth_snapshot = Rc::new(RefCell::new(AuthSnapshot::default()));
557        let auth_snapshot_in_hook = auth_snapshot.clone();
558        env_impl
559            .set_top_contract_invocation_hook(Some(Rc::new(move |host, event| {
560                match event {
561                    ContractInvocationEvent::Start => {}
562                    ContractInvocationEvent::Finish => {
563                        let new_auths = host
564                            .get_authenticated_authorizations()
565                            // If an error occurs getting the authenticated authorizations
566                            // it means that no auth has occurred.
567                            .unwrap();
568                        (*auth_snapshot_in_hook).borrow_mut().0.push(new_auths);
569                    }
570                }
571            })))
572            .unwrap();
573        env_impl.enable_invocation_metering();
574
575        let env = Env {
576            env_impl,
577            test_state: EnvTestState {
578                config,
579                generators: generators.unwrap_or_default(),
580                snapshot,
581                auth_snapshot,
582            },
583        };
584
585        env.ledger().set(ledger_info);
586
587        env
588    }
589
590    /// Returns the resources metered during the last top level contract
591    /// invocation.    
592    ///
593    /// In order to get non-`None` results, `enable_invocation_metering` has to
594    /// be called and at least one invocation has to happen after that.
595    ///
596    /// Take the return value with a grain of salt. The returned resources mostly
597    /// correspond only to the operations that have happened during the host
598    /// invocation, i.e. this won't try to simulate the work that happens in
599    /// production scenarios (e.g. certain XDR rountrips). This also doesn't try
600    /// to model resources related to the transaction size.
601    ///
602    /// The returned value is as useful as the preceding setup, e.g. if a test
603    /// contract is used instead of a Wasm contract, all the costs related to
604    /// VM instantiation and execution, as well as Wasm reads/rent bumps will be
605    /// missed.
606    ///
607    /// While the resource metering may be useful for contract optimization,
608    /// keep in mind that resource and fee estimation may be imprecise. Use
609    /// simulation with RPC in order to get the exact resources for submitting
610    /// the transactions to the network.    
611    pub fn cost_estimate(&self) -> CostEstimate {
612        CostEstimate::new(self.clone())
613    }
614
615    /// Register a contract with the [Env] for testing.
616    ///
617    /// Pass the contract type when the contract is defined in the current crate
618    /// and is being registered natively. Pass the contract wasm bytes when the
619    /// contract has been loaded as wasm.
620    ///
621    /// Pass the arguments for the contract's constructor, or `()` if none. For
622    /// contracts with a constructor, use the contract's generated `Args` type
623    /// to construct the arguments with the appropropriate types for invoking
624    /// the constructor during registration.
625    ///
626    /// Returns the address of the registered contract that is the same as the
627    /// contract id passed in.
628    ///
629    /// If you need to specify the address the contract should be registered at,
630    /// use [`Env::register_at`].
631    ///
632    /// ### Examples
633    /// Register a contract defined in the current crate, by specifying the type
634    /// name:
635    /// ```
636    /// use soroban_sdk::{contract, contractimpl, testutils::Address as _, Address, BytesN, Env, Symbol};
637    ///
638    /// #[contract]
639    /// pub struct Contract;
640    ///
641    /// #[contractimpl]
642    /// impl Contract {
643    ///     pub fn __constructor(_env: Env, _input: u32) {
644    ///     }
645    /// }
646    ///
647    /// #[test]
648    /// fn test() {
649    /// # }
650    /// # fn main() {
651    ///     let env = Env::default();
652    ///     let contract_id = env.register(Contract, ContractArgs::__constructor(&123,));
653    /// }
654    /// ```
655    /// Register a contract wasm, by specifying the wasm bytes:
656    /// ```
657    /// use soroban_sdk::{testutils::Address as _, Address, BytesN, Env};
658    ///
659    /// const WASM: &[u8] = include_bytes!("../doctest_fixtures/contract.wasm");
660    ///
661    /// #[test]
662    /// fn test() {
663    /// # }
664    /// # fn main() {
665    ///     let env = Env::default();
666    ///     let contract_id = env.register(WASM, ());
667    /// }
668    /// ```
669    pub fn register<'a, C, A>(&self, contract: C, constructor_args: A) -> Address
670    where
671        C: Register,
672        A: ConstructorArgs,
673    {
674        contract.register(self, None, constructor_args)
675    }
676
677    /// Register a contract with the [Env] for testing.
678    ///
679    /// Passing a contract ID for the first arguments registers the contract
680    /// with that contract ID.
681    ///
682    /// Registering a contract that is already registered replaces it.
683    /// Use re-registration with caution as it does not exist in the real
684    /// (on-chain) environment. Specifically, the new contract's constructor
685    /// will be called again during re-registration. That behavior only exists
686    /// for this test utility and is not reproducible on-chain, where contract
687    /// Wasm updates don't cause constructor to be called.
688    ///
689    /// Pass the contract type when the contract is defined in the current crate
690    /// and is being registered natively. Pass the contract wasm bytes when the
691    /// contract has been loaded as wasm.
692    ///
693    /// Returns the address of the registered contract that is the same as the
694    /// contract id passed in.
695    ///
696    /// ### Examples
697    /// Register a contract defined in the current crate, by specifying the type
698    /// name:
699    /// ```
700    /// use soroban_sdk::{contract, contractimpl, testutils::Address as _, Address, BytesN, Env, Symbol};
701    ///
702    /// #[contract]
703    /// pub struct Contract;
704    ///
705    /// #[contractimpl]
706    /// impl Contract {
707    ///     pub fn __constructor(_env: Env, _input: u32) {
708    ///     }
709    /// }
710    ///
711    /// #[test]
712    /// fn test() {
713    /// # }
714    /// # fn main() {
715    ///     let env = Env::default();
716    ///     let contract_id = Address::generate(&env);
717    ///     env.register_at(&contract_id, Contract, (123_u32,));
718    /// }
719    /// ```
720    /// Register a contract wasm, by specifying the wasm bytes:
721    /// ```
722    /// use soroban_sdk::{testutils::Address as _, Address, BytesN, Env};
723    ///
724    /// const WASM: &[u8] = include_bytes!("../doctest_fixtures/contract.wasm");
725    ///
726    /// #[test]
727    /// fn test() {
728    /// # }
729    /// # fn main() {
730    ///     let env = Env::default();
731    ///     let contract_id = Address::generate(&env);
732    ///     env.register_at(&contract_id, WASM, ());
733    /// }
734    /// ```
735    pub fn register_at<C, A>(
736        &self,
737        contract_id: &Address,
738        contract: C,
739        constructor_args: A,
740    ) -> Address
741    where
742        C: Register,
743        A: ConstructorArgs,
744    {
745        contract.register(self, contract_id, constructor_args)
746    }
747
748    /// Register a contract with the [Env] for testing.
749    ///
750    /// Passing a contract ID for the first arguments registers the contract
751    /// with that contract ID. Providing `None` causes the Env to generate a new
752    /// contract ID that is assigned to the contract.
753    ///
754    /// If a contract has a constructor defined, then it will be called with
755    /// no arguments. If a constructor takes arguments, use `register`.
756    ///
757    /// Registering a contract that is already registered replaces it.
758    /// Use re-registration with caution as it does not exist in the real
759    /// (on-chain) environment. Specifically, the new contract's constructor
760    /// will be called again during re-registration. That behavior only exists
761    /// for this test utility and is not reproducible on-chain, where contract
762    /// Wasm updates don't cause constructor to be called.
763    ///
764    /// Returns the address of the registered contract.
765    ///
766    /// ### Examples
767    /// ```
768    /// use soroban_sdk::{contract, contractimpl, BytesN, Env, Symbol};
769    ///
770    /// #[contract]
771    /// pub struct HelloContract;
772    ///
773    /// #[contractimpl]
774    /// impl HelloContract {
775    ///     pub fn hello(env: Env, recipient: Symbol) -> Symbol {
776    ///         todo!()
777    ///     }
778    /// }
779    ///
780    /// #[test]
781    /// fn test() {
782    /// # }
783    /// # fn main() {
784    ///     let env = Env::default();
785    ///     let contract_id = env.register_contract(None, HelloContract);
786    /// }
787    /// ```
788    #[deprecated(note = "use `register`")]
789    pub fn register_contract<'a, T: ContractFunctionSet + 'static>(
790        &self,
791        contract_id: impl Into<Option<&'a Address>>,
792        contract: T,
793    ) -> Address {
794        self.register_contract_with_constructor(contract_id, contract, ())
795    }
796
797    /// Register a contract with the [Env] for testing.
798    ///
799    /// This acts the in the same fashion as `register_contract`, but allows
800    /// passing arguments to the contract's constructor.
801    ///
802    /// Passing a contract ID for the first arguments registers the contract
803    /// with that contract ID. Providing `None` causes the Env to generate a new
804    /// contract ID that is assigned to the contract.
805    ///
806    /// Registering a contract that is already registered replaces it.
807    /// Use re-registration with caution as it does not exist in the real
808    /// (on-chain) environment. Specifically, the new contract's constructor
809    /// will be called again during re-registration. That behavior only exists
810    /// for this test utility and is not reproducible on-chain, where contract
811    /// Wasm updates don't cause constructor to be called.
812    ///
813    /// Returns the address of the registered contract.
814    pub(crate) fn register_contract_with_constructor<
815        'a,
816        T: ContractFunctionSet + 'static,
817        A: ConstructorArgs,
818    >(
819        &self,
820        contract_id: impl Into<Option<&'a Address>>,
821        contract: T,
822        constructor_args: A,
823    ) -> Address {
824        struct InternalContractFunctionSet<T: ContractFunctionSet>(pub(crate) T);
825        impl<T: ContractFunctionSet> internal::ContractFunctionSet for InternalContractFunctionSet<T> {
826            fn call(
827                &self,
828                func: &Symbol,
829                env_impl: &internal::EnvImpl,
830                args: &[Val],
831            ) -> Option<Val> {
832                let env = Env {
833                    env_impl: env_impl.clone(),
834                    test_state: Default::default(),
835                };
836                self.0.call(
837                    crate::Symbol::try_from_val(&env, func)
838                        .unwrap_infallible()
839                        .to_string()
840                        .as_str(),
841                    env,
842                    args,
843                )
844            }
845        }
846
847        let contract_id = if let Some(contract_id) = contract_id.into() {
848            contract_id.clone()
849        } else {
850            Address::generate(self)
851        };
852        self.env_impl
853            .register_test_contract_with_constructor(
854                contract_id.to_object(),
855                Rc::new(InternalContractFunctionSet(contract)),
856                constructor_args.into_val(self).to_object(),
857            )
858            .unwrap();
859        contract_id
860    }
861
862    /// Register a contract in a Wasm file with the [Env] for testing.
863    ///
864    /// Passing a contract ID for the first arguments registers the contract
865    /// with that contract ID. Providing `None` causes the Env to generate a new
866    /// contract ID that is assigned to the contract.
867    ///
868    /// Registering a contract that is already registered replaces it.
869    /// Use re-registration with caution as it does not exist in the real
870    /// (on-chain) environment. Specifically, the new contract's constructor
871    /// will be called again during re-registration. That behavior only exists
872    /// for this test utility and is not reproducible on-chain, where contract
873    /// Wasm updates don't cause constructor to be called.
874    ///
875    /// Returns the address of the registered contract.
876    ///
877    /// ### Examples
878    /// ```
879    /// use soroban_sdk::{BytesN, Env};
880    ///
881    /// const WASM: &[u8] = include_bytes!("../doctest_fixtures/contract.wasm");
882    ///
883    /// #[test]
884    /// fn test() {
885    /// # }
886    /// # fn main() {
887    ///     let env = Env::default();
888    ///     env.register_contract_wasm(None, WASM);
889    /// }
890    /// ```
891    #[deprecated(note = "use `register`")]
892    pub fn register_contract_wasm<'a>(
893        &self,
894        contract_id: impl Into<Option<&'a Address>>,
895        contract_wasm: impl IntoVal<Env, Bytes>,
896    ) -> Address {
897        let wasm_hash: BytesN<32> = self.deployer().upload_contract_wasm(contract_wasm);
898        self.register_contract_with_optional_contract_id_and_executable(
899            contract_id,
900            xdr::ContractExecutable::Wasm(xdr::Hash(wasm_hash.into())),
901            crate::vec![&self],
902        )
903    }
904
905    /// Register a contract in a Wasm file with the [Env] for testing.
906    ///
907    /// This acts the in the same fashion as `register_contract`, but allows
908    /// passing arguments to the contract's constructor.
909    ///
910    /// Passing a contract ID for the first arguments registers the contract
911    /// with that contract ID. Providing `None` causes the Env to generate a new
912    /// contract ID that is assigned to the contract.
913    ///
914    /// Registering a contract that is already registered replaces it.
915    /// Use re-registration with caution as it does not exist in the real
916    /// (on-chain) environment. Specifically, the new contract's constructor
917    /// will be called again during re-registration. That behavior only exists
918    /// for this test utility and is not reproducible on-chain, where contract
919    /// Wasm updates don't cause constructor to be called.
920    ///
921    /// Returns the address of the registered contract.
922    pub(crate) fn register_contract_wasm_with_constructor<'a>(
923        &self,
924        contract_id: impl Into<Option<&'a Address>>,
925        contract_wasm: impl IntoVal<Env, Bytes>,
926        constructor_args: impl ConstructorArgs,
927    ) -> Address {
928        let wasm_hash: BytesN<32> = self.deployer().upload_contract_wasm(contract_wasm);
929        self.register_contract_with_optional_contract_id_and_executable(
930            contract_id,
931            xdr::ContractExecutable::Wasm(xdr::Hash(wasm_hash.into())),
932            constructor_args.into_val(self),
933        )
934    }
935
936    /// Register the built-in Stellar Asset Contract with provided admin address.
937    ///
938    /// Returns a utility struct that contains the contract ID of the registered
939    /// token contract, as well as methods to read and update issuer flags.
940    ///
941    /// The contract will wrap a randomly-generated Stellar asset. This function
942    /// is useful for using in the tests when an arbitrary token contract
943    /// instance is needed.
944    pub fn register_stellar_asset_contract_v2(&self, admin: Address) -> StellarAssetContract {
945        let issuer_pk = self.with_generator(|mut g| g.address());
946        let issuer_id = xdr::AccountId(xdr::PublicKey::PublicKeyTypeEd25519(xdr::Uint256(
947            issuer_pk.clone(),
948        )));
949
950        self.host()
951            .with_mut_storage(|storage| {
952                let k = Rc::new(xdr::LedgerKey::Account(xdr::LedgerKeyAccount {
953                    account_id: issuer_id.clone(),
954                }));
955
956                if !storage.has(
957                    &k,
958                    soroban_env_host::budget::AsBudget::as_budget(self.host()),
959                )? {
960                    let v = Rc::new(xdr::LedgerEntry {
961                        data: xdr::LedgerEntryData::Account(xdr::AccountEntry {
962                            account_id: issuer_id.clone(),
963                            balance: 0,
964                            flags: 0,
965                            home_domain: Default::default(),
966                            inflation_dest: None,
967                            num_sub_entries: 0,
968                            seq_num: xdr::SequenceNumber(0),
969                            thresholds: xdr::Thresholds([1; 4]),
970                            signers: xdr::VecM::default(),
971                            ext: xdr::AccountEntryExt::V0,
972                        }),
973                        last_modified_ledger_seq: 0,
974                        ext: xdr::LedgerEntryExt::V0,
975                    });
976                    storage.put(
977                        &k,
978                        &v,
979                        None,
980                        soroban_env_host::budget::AsBudget::as_budget(self.host()),
981                    )?
982                }
983                Ok(())
984            })
985            .unwrap();
986
987        let asset = xdr::Asset::CreditAlphanum4(xdr::AlphaNum4 {
988            asset_code: xdr::AssetCode4([b'a', b'a', b'a', 0]),
989            issuer: issuer_id.clone(),
990        });
991        let create = xdr::HostFunction::CreateContract(xdr::CreateContractArgs {
992            contract_id_preimage: xdr::ContractIdPreimage::Asset(asset),
993            executable: xdr::ContractExecutable::StellarAsset,
994        });
995
996        let token_id: Address = self
997            .env_impl
998            .invoke_function(create)
999            .unwrap()
1000            .try_into_val(self)
1001            .unwrap();
1002
1003        let prev_auth_manager = self.env_impl.snapshot_auth_manager().unwrap();
1004        self.env_impl
1005            .switch_to_recording_auth_inherited_from_snapshot(&prev_auth_manager)
1006            .unwrap();
1007        self.invoke_contract::<()>(
1008            &token_id,
1009            &soroban_sdk_macros::internal_symbol_short!("set_admin"),
1010            (admin,).try_into_val(self).unwrap(),
1011        );
1012        self.env_impl.set_auth_manager(prev_auth_manager).unwrap();
1013
1014        let issuer = StellarAssetIssuer::new(self.clone(), issuer_id);
1015
1016        StellarAssetContract::new(token_id, issuer)
1017    }
1018
1019    /// Register the built-in Stellar Asset Contract with provided admin address.
1020    ///
1021    /// Returns the contract ID of the registered token contract.
1022    ///
1023    /// The contract will wrap a randomly-generated Stellar asset. This function
1024    /// is useful for using in the tests when an arbitrary token contract
1025    /// instance is needed.
1026    #[deprecated(note = "use [Env::register_stellar_asset_contract_v2]")]
1027    pub fn register_stellar_asset_contract(&self, admin: Address) -> Address {
1028        self.register_stellar_asset_contract_v2(admin).address()
1029    }
1030
1031    fn register_contract_with_optional_contract_id_and_executable<'a>(
1032        &self,
1033        contract_id: impl Into<Option<&'a Address>>,
1034        executable: xdr::ContractExecutable,
1035        constructor_args: Vec<Val>,
1036    ) -> Address {
1037        if let Some(contract_id) = contract_id.into() {
1038            self.register_contract_with_contract_id_and_executable(
1039                contract_id,
1040                executable,
1041                constructor_args,
1042            );
1043            contract_id.clone()
1044        } else {
1045            self.register_contract_with_source(executable, constructor_args)
1046        }
1047    }
1048
1049    fn register_contract_with_source(
1050        &self,
1051        executable: xdr::ContractExecutable,
1052        constructor_args: Vec<Val>,
1053    ) -> Address {
1054        let prev_auth_manager = self.env_impl.snapshot_auth_manager().unwrap();
1055        self.env_impl
1056            .switch_to_recording_auth_inherited_from_snapshot(&prev_auth_manager)
1057            .unwrap();
1058        let args_vec: std::vec::Vec<xdr::ScVal> =
1059            constructor_args.iter().map(|v| v.into_val(self)).collect();
1060        let contract_id: Address = self
1061            .env_impl
1062            .invoke_function(xdr::HostFunction::CreateContractV2(
1063                xdr::CreateContractArgsV2 {
1064                    contract_id_preimage: xdr::ContractIdPreimage::Address(
1065                        xdr::ContractIdPreimageFromAddress {
1066                            address: xdr::ScAddress::Contract(xdr::Hash(
1067                                self.with_generator(|mut g| g.address()),
1068                            )),
1069                            salt: xdr::Uint256([0; 32]),
1070                        },
1071                    ),
1072                    executable,
1073                    constructor_args: args_vec.try_into().unwrap(),
1074                },
1075            ))
1076            .unwrap()
1077            .try_into_val(self)
1078            .unwrap();
1079
1080        self.env_impl.set_auth_manager(prev_auth_manager).unwrap();
1081
1082        contract_id
1083    }
1084
1085    /// Set authorizations and signatures in the environment which will be
1086    /// consumed by contracts when they invoke [`Address::require_auth`] or
1087    /// [`Address::require_auth_for_args`] functions.
1088    ///
1089    /// Requires valid signatures for the authorization to be successful.
1090    ///
1091    /// This function can also be called on contract clients.
1092    ///
1093    /// To mock auth for testing, without requiring valid signatures, use
1094    /// [`mock_all_auths`][Self::mock_all_auths] or
1095    /// [`mock_auths`][Self::mock_auths]. If mocking of auths is enabled,
1096    /// calling [`set_auths`][Self::set_auths] disables any mocking.
1097    pub fn set_auths(&self, auths: &[SorobanAuthorizationEntry]) {
1098        self.env_impl
1099            .set_authorization_entries(auths.to_vec())
1100            .unwrap();
1101    }
1102
1103    /// Mock authorizations in the environment which will cause matching invokes
1104    /// of [`Address::require_auth`] and [`Address::require_auth_for_args`] to
1105    /// pass.
1106    ///
1107    /// This function can also be called on contract clients.
1108    ///
1109    /// Authorizations not matching a mocked auth will fail.
1110    ///
1111    /// To mock all auths, use [`mock_all_auths`][Self::mock_all_auths].
1112    ///
1113    /// ### Examples
1114    /// ```
1115    /// use soroban_sdk::{contract, contractimpl, Env, Address, testutils::{Address as _, MockAuth, MockAuthInvoke}, IntoVal};
1116    ///
1117    /// #[contract]
1118    /// pub struct HelloContract;
1119    ///
1120    /// #[contractimpl]
1121    /// impl HelloContract {
1122    ///     pub fn hello(env: Env, from: Address) {
1123    ///         from.require_auth();
1124    ///         // TODO
1125    ///     }
1126    /// }
1127    ///
1128    /// #[test]
1129    /// fn test() {
1130    /// # }
1131    /// # fn main() {
1132    ///     let env = Env::default();
1133    ///     let contract_id = env.register(HelloContract, ());
1134    ///
1135    ///     let client = HelloContractClient::new(&env, &contract_id);
1136    ///     let addr = Address::generate(&env);
1137    ///     client.mock_auths(&[
1138    ///         MockAuth {
1139    ///             address: &addr,
1140    ///             invoke: &MockAuthInvoke {
1141    ///                 contract: &contract_id,
1142    ///                 fn_name: "hello",
1143    ///                 args: (&addr,).into_val(&env),
1144    ///                 sub_invokes: &[],
1145    ///             },
1146    ///         },
1147    ///     ]).hello(&addr);
1148    /// }
1149    /// ```
1150    pub fn mock_auths(&self, auths: &[MockAuth]) {
1151        for a in auths {
1152            self.register_at(a.address, MockAuthContract, ());
1153        }
1154        let auths = auths
1155            .iter()
1156            .cloned()
1157            .map(Into::into)
1158            .collect::<std::vec::Vec<_>>();
1159        self.env_impl.set_authorization_entries(auths).unwrap();
1160    }
1161
1162    /// Mock all calls to the [`Address::require_auth`] and
1163    /// [`Address::require_auth_for_args`] functions in invoked contracts,
1164    /// having them succeed as if authorization was provided.
1165    ///
1166    /// When mocking is enabled, if the [`Address`] being authorized is the
1167    /// address of a contract, that contract's `__check_auth` function will not
1168    /// be called, and the contract does not need to exist or be registered in
1169    /// the test.
1170    ///
1171    /// When mocking is enabled, if the [`Address`] being authorized is the
1172    /// address of an account, the account does not need to exist.
1173    ///
1174    /// This function can also be called on contract clients.
1175    ///
1176    /// To disable mocking, see [`set_auths`][Self::set_auths].
1177    ///
1178    /// To access a list of auths that have occurred, see [`auths`][Self::auths].
1179    ///
1180    /// It is not currently possible to mock a subset of auths.
1181    ///
1182    /// ### Examples
1183    /// ```
1184    /// use soroban_sdk::{contract, contractimpl, Env, Address, testutils::Address as _};
1185    ///
1186    /// #[contract]
1187    /// pub struct HelloContract;
1188    ///
1189    /// #[contractimpl]
1190    /// impl HelloContract {
1191    ///     pub fn hello(env: Env, from: Address) {
1192    ///         from.require_auth();
1193    ///         // TODO
1194    ///     }
1195    /// }
1196    ///
1197    /// #[test]
1198    /// fn test() {
1199    /// # }
1200    /// # fn main() {
1201    ///     let env = Env::default();
1202    ///     let contract_id = env.register(HelloContract, ());
1203    ///
1204    ///     env.mock_all_auths();
1205    ///
1206    ///     let client = HelloContractClient::new(&env, &contract_id);
1207    ///     let addr = Address::generate(&env);
1208    ///     client.hello(&addr);
1209    /// }
1210    /// ```
1211    pub fn mock_all_auths(&self) {
1212        self.env_impl.switch_to_recording_auth(true).unwrap();
1213    }
1214
1215    /// A version of `mock_all_auths` that allows authorizations that are not
1216    /// present in the root invocation.
1217    ///
1218    /// Refer to `mock_all_auths` documentation for general information and
1219    /// prefer using `mock_all_auths` unless non-root authorization is required.
1220    ///
1221    /// The only difference from `mock_all_auths` is that this won't return an
1222    /// error when `require_auth` hasn't been called in the root invocation for
1223    /// any given address. This is useful to test contracts that bundle calls to
1224    /// another contract without atomicity requirements (i.e. any contract call
1225    /// can be frontrun).
1226    ///
1227    /// ### Examples
1228    /// ```
1229    /// use soroban_sdk::{contract, contractimpl, Env, Address, testutils::Address as _};
1230    ///
1231    /// #[contract]
1232    /// pub struct ContractA;
1233    ///
1234    /// #[contractimpl]
1235    /// impl ContractA {
1236    ///     pub fn do_auth(env: Env, addr: Address) {
1237    ///         addr.require_auth();
1238    ///     }
1239    /// }
1240    /// #[contract]
1241    /// pub struct ContractB;
1242    ///
1243    /// #[contractimpl]
1244    /// impl ContractB {
1245    ///     pub fn call_a(env: Env, contract_a: Address, addr: Address) {
1246    ///         // Notice there is no `require_auth` call here.
1247    ///         ContractAClient::new(&env, &contract_a).do_auth(&addr);
1248    ///     }
1249    /// }
1250    /// #[test]
1251    /// fn test() {
1252    /// # }
1253    /// # fn main() {
1254    ///     let env = Env::default();
1255    ///     let contract_a = env.register(ContractA, ());
1256    ///     let contract_b = env.register(ContractB, ());
1257    ///     // The regular `env.mock_all_auths()` would result in the call
1258    ///     // failure.
1259    ///     env.mock_all_auths_allowing_non_root_auth();
1260    ///
1261    ///     let client = ContractBClient::new(&env, &contract_b);
1262    ///     let addr = Address::generate(&env);
1263    ///     client.call_a(&contract_a, &addr);
1264    /// }
1265    /// ```
1266    pub fn mock_all_auths_allowing_non_root_auth(&self) {
1267        self.env_impl.switch_to_recording_auth(false).unwrap();
1268    }
1269
1270    /// Returns a list of authorization trees that were seen during the last
1271    /// contract or authorized host function invocation.
1272    ///
1273    /// Use this in tests to verify that the expected authorizations with the
1274    /// expected arguments are required.
1275    ///
1276    /// The return value is a vector of authorizations represented by tuples of
1277    /// `(address, AuthorizedInvocation)`. `AuthorizedInvocation` describes the
1278    /// tree of `require_auth_for_args(address, args)` from the contract
1279    /// functions (or `require_auth` with all the arguments of the function
1280    /// invocation). It also might contain the authorized host functions (
1281    /// currently CreateContract is the only such function) in case if
1282    /// corresponding host functions have been called.
1283    ///
1284    /// Refer to documentation for `AuthorizedInvocation` for detailed
1285    /// information on its contents.
1286    ///
1287    /// The order of the returned vector is defined by the order of
1288    /// [`Address::require_auth`] calls. Repeated calls to
1289    /// [`Address::require_auth`] with the same address and args in the same
1290    /// tree of contract invocations will appear only once in the vector.
1291    ///
1292    /// ### Examples
1293    /// ```
1294    /// use soroban_sdk::{contract, contractimpl, testutils::{Address as _, AuthorizedFunction, AuthorizedInvocation}, symbol_short, Address, Symbol, Env, IntoVal};
1295    ///
1296    /// #[contract]
1297    /// pub struct Contract;
1298    ///
1299    /// #[contractimpl]
1300    /// impl Contract {
1301    ///     pub fn transfer(env: Env, address: Address, amount: i128) {
1302    ///         address.require_auth();
1303    ///     }
1304    ///     pub fn transfer2(env: Env, address: Address, amount: i128) {
1305    ///         address.require_auth_for_args((amount / 2,).into_val(&env));
1306    ///     }
1307    /// }
1308    ///
1309    /// #[test]
1310    /// fn test() {
1311    /// # }
1312    /// # #[cfg(feature = "testutils")]
1313    /// # fn main() {
1314    ///     extern crate std;
1315    ///     let env = Env::default();
1316    ///     let contract_id = env.register(Contract, ());
1317    ///     let client = ContractClient::new(&env, &contract_id);
1318    ///     env.mock_all_auths();
1319    ///     let address = Address::generate(&env);
1320    ///     client.transfer(&address, &1000_i128);
1321    ///     assert_eq!(
1322    ///         env.auths(),
1323    ///         std::vec![(
1324    ///             address.clone(),
1325    ///             AuthorizedInvocation {
1326    ///                 function: AuthorizedFunction::Contract((
1327    ///                     client.address.clone(),
1328    ///                     symbol_short!("transfer"),
1329    ///                     (&address, 1000_i128,).into_val(&env)
1330    ///                 )),
1331    ///                 sub_invocations: std::vec![]
1332    ///             }
1333    ///         )]
1334    ///     );
1335    ///
1336    ///     client.transfer2(&address, &1000_i128);
1337    ///     assert_eq!(
1338    ///         env.auths(),
1339    ///        std::vec![(
1340    ///             address.clone(),
1341    ///             AuthorizedInvocation {
1342    ///                 function: AuthorizedFunction::Contract((
1343    ///                     client.address.clone(),
1344    ///                     symbol_short!("transfer2"),
1345    ///                     // `transfer2` requires auth for (amount / 2) == (1000 / 2) == 500.
1346    ///                     (500_i128,).into_val(&env)
1347    ///                 )),
1348    ///                 sub_invocations: std::vec![]
1349    ///             }
1350    ///         )]
1351    ///     );
1352    /// }
1353    /// # #[cfg(not(feature = "testutils"))]
1354    /// # fn main() { }
1355    /// ```
1356    pub fn auths(&self) -> std::vec::Vec<(Address, AuthorizedInvocation)> {
1357        (*self.test_state.auth_snapshot)
1358            .borrow()
1359            .0
1360            .last()
1361            .cloned()
1362            .unwrap_or_default()
1363            .into_iter()
1364            .map(|(sc_addr, invocation)| {
1365                (
1366                    xdr::ScVal::Address(sc_addr).try_into_val(self).unwrap(),
1367                    AuthorizedInvocation::from_xdr(self, &invocation),
1368                )
1369            })
1370            .collect()
1371    }
1372
1373    /// Invokes the special `__check_auth` function of contracts that implement
1374    /// the custom account interface.
1375    ///
1376    /// `__check_auth` can't be called outside of the host-managed `require_auth`
1377    /// calls. This test utility allows testing custom account contracts without
1378    /// the need to setup complex contract call trees and enabling the enforcing
1379    /// auth on the host side.
1380    ///
1381    /// This function requires to provide the template argument for error. Use
1382    /// `soroban_sdk::Error` if `__check_auth` doesn't return a special
1383    /// contract error and use the error with `contracterror` attribute
1384    /// otherwise.
1385    ///
1386    /// ### Examples
1387    /// ```
1388    /// use soroban_sdk::{contract, contracterror, contractimpl, testutils::{Address as _, BytesN as _}, vec, auth::Context, BytesN, Env, Vec, Val};
1389    ///
1390    /// #[contracterror]
1391    /// #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
1392    /// #[repr(u32)]
1393    /// pub enum NoopAccountError {
1394    ///     SomeError = 1,
1395    /// }
1396    /// #[contract]
1397    /// struct NoopAccountContract;
1398    /// #[contractimpl]
1399    /// impl NoopAccountContract {
1400    ///
1401    ///     #[allow(non_snake_case)]
1402    ///     pub fn __check_auth(
1403    ///         _env: Env,
1404    ///         _signature_payload: BytesN<32>,
1405    ///         signature: Val,
1406    ///         _auth_context: Vec<Context>,
1407    ///     ) -> Result<(), NoopAccountError> {
1408    ///         if signature.is_void() {
1409    ///             Err(NoopAccountError::SomeError)
1410    ///         } else {
1411    ///             Ok(())
1412    ///         }
1413    ///     }
1414    /// }
1415    /// #[test]
1416    /// fn test() {
1417    /// # }
1418    /// # fn main() {
1419    ///     let e: Env = Default::default();
1420    ///     let account_contract = NoopAccountContractClient::new(&e, &e.register(NoopAccountContract, ()));
1421    ///     // Non-succesful call of `__check_auth` with a `contracterror` error.
1422    ///     assert_eq!(
1423    ///         e.try_invoke_contract_check_auth::<NoopAccountError>(
1424    ///             &account_contract.address,
1425    ///             &BytesN::from_array(&e, &[0; 32]),
1426    ///             ().into(),
1427    ///             &vec![&e],
1428    ///         ),
1429    ///         // The inner `Result` is for conversion error and will be Ok
1430    ///         // as long as a valid error type used.
1431    ///         Err(Ok(NoopAccountError::SomeError))
1432    ///     );
1433    ///     // Successful call of `__check_auth` with a `soroban_sdk::InvokeError`
1434    ///     // error - this should be compatible with any error type.
1435    ///     assert_eq!(
1436    ///         e.try_invoke_contract_check_auth::<soroban_sdk::InvokeError>(
1437    ///             &account_contract.address,
1438    ///             &BytesN::from_array(&e, &[0; 32]),
1439    ///             0_i32.into(),
1440    ///             &vec![&e],
1441    ///         ),
1442    ///         Ok(())
1443    ///     );
1444    /// }
1445    /// ```
1446    pub fn try_invoke_contract_check_auth<E>(
1447        &self,
1448        contract: &Address,
1449        signature_payload: &BytesN<32>,
1450        signature: Val,
1451        auth_context: &Vec<auth::Context>,
1452    ) -> Result<(), Result<E, InvokeError>>
1453    where
1454        E: TryFrom<Error>,
1455        E::Error: Into<InvokeError>,
1456    {
1457        let args = Vec::from_array(
1458            self,
1459            [signature_payload.to_val(), signature, auth_context.to_val()],
1460        );
1461        let res = self
1462            .host()
1463            .call_account_contract_check_auth(contract.to_object(), args.to_object());
1464        match res {
1465            Ok(rv) => Ok(rv.into_val(self)),
1466            Err(e) => Err(e.error.try_into().map_err(Into::into)),
1467        }
1468    }
1469
1470    fn register_contract_with_contract_id_and_executable(
1471        &self,
1472        contract_address: &Address,
1473        executable: xdr::ContractExecutable,
1474        constructor_args: Vec<Val>,
1475    ) {
1476        let contract_id = contract_address.contract_id();
1477        let data_key = xdr::ScVal::LedgerKeyContractInstance;
1478        let key = Rc::new(LedgerKey::ContractData(LedgerKeyContractData {
1479            contract: xdr::ScAddress::Contract(contract_id.clone()),
1480            key: data_key.clone(),
1481            durability: xdr::ContractDataDurability::Persistent,
1482        }));
1483
1484        let instance = xdr::ScContractInstance {
1485            executable,
1486            storage: Default::default(),
1487        };
1488
1489        let entry = Rc::new(LedgerEntry {
1490            ext: xdr::LedgerEntryExt::V0,
1491            last_modified_ledger_seq: 0,
1492            data: xdr::LedgerEntryData::ContractData(xdr::ContractDataEntry {
1493                contract: xdr::ScAddress::Contract(contract_id.clone()),
1494                key: data_key,
1495                val: xdr::ScVal::ContractInstance(instance),
1496                durability: xdr::ContractDataDurability::Persistent,
1497                ext: xdr::ExtensionPoint::V0,
1498            }),
1499        });
1500        let live_until_ledger = self.ledger().sequence() + 1;
1501        self.env_impl
1502            .with_mut_storage(|storage| {
1503                storage.put(
1504                    &key,
1505                    &entry,
1506                    Some(live_until_ledger),
1507                    soroban_env_host::budget::AsBudget::as_budget(self.host()),
1508                )
1509            })
1510            .unwrap();
1511        self.env_impl
1512            .call_constructor_for_stored_contract_unsafe(&contract_id, constructor_args.to_object())
1513            .unwrap();
1514    }
1515
1516    /// Run the function as if executed by the given contract ID.
1517    ///
1518    /// Used to write or read contract data, or take other actions in tests for
1519    /// setting up tests or asserting on internal state.
1520    pub fn as_contract<T>(&self, id: &Address, f: impl FnOnce() -> T) -> T {
1521        let id: [u8; 32] = id.contract_id().into();
1522        let func = Symbol::from_small_str("");
1523        let mut t: Option<T> = None;
1524        self.env_impl
1525            .with_test_contract_frame(id.into(), func, || {
1526                t = Some(f());
1527                Ok(().into())
1528            })
1529            .unwrap();
1530        t.unwrap()
1531    }
1532
1533    /// Creates a new Env loaded with the [`Snapshot`].
1534    ///
1535    /// The ledger info and state in the snapshot are loaded into the Env.
1536    ///
1537    /// Events, as an output source only, are not loaded into the Env.
1538    pub fn from_snapshot(s: Snapshot) -> Env {
1539        Env::new_for_testutils(
1540            EnvTestConfig::default(),
1541            Rc::new(s.ledger.clone()),
1542            Some(Rc::new(RefCell::new(s.generators))),
1543            s.ledger.ledger_info(),
1544            Some(Rc::new(s.ledger.clone())),
1545        )
1546    }
1547
1548    /// Creates a new Env loaded with the ledger snapshot loaded from the file.
1549    ///
1550    /// The ledger info and state in the snapshot are loaded into the Env.
1551    ///
1552    /// Events, as an output source only, are not loaded into the Env.
1553    ///
1554    /// ### Panics
1555    ///
1556    /// If there is any error reading the file.
1557    pub fn from_snapshot_file(p: impl AsRef<Path>) -> Env {
1558        Self::from_snapshot(Snapshot::read_file(p).unwrap())
1559    }
1560
1561    /// Create a snapshot from the Env's current state.
1562    pub fn to_snapshot(&self) -> Snapshot {
1563        Snapshot {
1564            generators: (*self.test_state.generators).borrow().clone(),
1565            auth: (*self.test_state.auth_snapshot).borrow().clone(),
1566            ledger: self.to_ledger_snapshot(),
1567            events: self.to_events_snapshot(),
1568        }
1569    }
1570
1571    /// Create a snapshot file from the Env's current state.
1572    ///
1573    /// ### Panics
1574    ///
1575    /// If there is any error writing the file.
1576    pub fn to_snapshot_file(&self, p: impl AsRef<Path>) {
1577        self.to_snapshot().write_file(p).unwrap();
1578    }
1579
1580    /// Creates a new Env loaded with the [`LedgerSnapshot`].
1581    ///
1582    /// The ledger info and state in the snapshot are loaded into the Env.
1583    pub fn from_ledger_snapshot(s: LedgerSnapshot) -> Env {
1584        Env::new_for_testutils(
1585            EnvTestConfig::default(), // TODO: Allow setting the config.
1586            Rc::new(s.clone()),
1587            None,
1588            s.ledger_info(),
1589            Some(Rc::new(s.clone())),
1590        )
1591    }
1592
1593    /// Creates a new Env loaded with the ledger snapshot loaded from the file.
1594    ///
1595    /// ### Panics
1596    ///
1597    /// If there is any error reading the file.
1598    pub fn from_ledger_snapshot_file(p: impl AsRef<Path>) -> Env {
1599        Self::from_ledger_snapshot(LedgerSnapshot::read_file(p).unwrap())
1600    }
1601
1602    /// Create a snapshot from the Env's current state.
1603    pub fn to_ledger_snapshot(&self) -> LedgerSnapshot {
1604        let snapshot = self.test_state.snapshot.clone().unwrap_or_default();
1605        let mut snapshot = (*snapshot).clone();
1606        snapshot.set_ledger_info(self.ledger().get());
1607        let budget = soroban_env_host::budget::AsBudget::as_budget(&self.env_impl);
1608        let storage = self
1609            .env_impl
1610            .with_mut_storage(|s| Ok(s.map.clone()))
1611            .unwrap();
1612        snapshot.update_entries(storage.iter(budget).unwrap());
1613        snapshot
1614    }
1615
1616    /// Create a snapshot file from the Env's current state.
1617    ///
1618    /// ### Panics
1619    ///
1620    /// If there is any error writing the file.
1621    pub fn to_ledger_snapshot_file(&self, p: impl AsRef<Path>) {
1622        self.to_ledger_snapshot().write_file(p).unwrap();
1623    }
1624
1625    /// Create an events snapshot from the Env's current state.
1626    pub(crate) fn to_events_snapshot(&self) -> EventsSnapshot {
1627        EventsSnapshot(
1628            self.host()
1629                .get_events()
1630                .unwrap()
1631                .0
1632                .into_iter()
1633                .filter(|e| match e.event.type_ {
1634                    // Keep only system and contract events, because event
1635                    // snapshots are used in test snapshots, and intended to be
1636                    // stable over time because the goal is to record meaningful
1637                    // observable behaviors. Diagnostic events are observable,
1638                    // but events have no stability guarantees and are intended
1639                    // to be used by developers when debugging, tracing, and
1640                    // observing, not by systems that integrate.
1641                    xdr::ContractEventType::System | xdr::ContractEventType::Contract => true,
1642                    xdr::ContractEventType::Diagnostic => false,
1643                })
1644                .map(Into::into)
1645                .collect(),
1646        )
1647    }
1648
1649    /// Get the budget that tracks the resources consumed for the environment.
1650    #[deprecated(note = "use cost_estimate().budget()")]
1651    pub fn budget(&self) -> Budget {
1652        Budget::new(self.env_impl.budget_cloned())
1653    }
1654}
1655
1656#[cfg(any(test, feature = "testutils"))]
1657impl Drop for Env {
1658    fn drop(&mut self) {
1659        // If the env impl (Host) is finishable, that means this Env is the last
1660        // Env to hold a reference to the Host. The Env should only write a test
1661        // snapshot at that point when no other references to the host exist,
1662        // because it is only when there are no other references that the host
1663        // is being dropped.
1664        if self.env_impl.can_finish() && self.test_state.config.capture_snapshot_at_drop {
1665            self.to_test_snapshot_file();
1666        }
1667    }
1668}
1669
1670#[cfg(any(test, feature = "testutils"))]
1671#[derive(Default, Clone)]
1672struct LastTestSnapshot {
1673    name: String,
1674    number: usize,
1675}
1676
1677#[cfg(any(test, feature = "testutils"))]
1678thread_local! {
1679    static LAST_TEST_SNAPSHOT: RefCell<LastTestSnapshot> = RefCell::new(LastTestSnapshot::default());
1680}
1681
1682#[doc(hidden)]
1683#[cfg(any(test, feature = "testutils"))]
1684impl Env {
1685    /// Create a snapshot file for the currently executing test.
1686    ///
1687    /// Writes the file to the `test_snapshots/{test-name}.N.json` path where
1688    /// `N` is incremented for each unique `Env` in the test.
1689    ///
1690    /// Use to record the observable behavior of a test, and changes to that
1691    /// behavior over time. Commit the test snapshot file to version control and
1692    /// watch for changes in it on contract change, SDK upgrade, protocol
1693    /// upgrade, and other important events.
1694    ///
1695    /// No file will be created if the environment has no meaningful data such
1696    /// as stored entries or events.
1697    ///
1698    /// ### Panics
1699    ///
1700    /// If there is any error writing the file.
1701    pub(crate) fn to_test_snapshot_file(&self) {
1702        let snapshot = self.to_snapshot();
1703
1704        // Don't write a snapshot that has no data in it.
1705        if snapshot.ledger.entries().into_iter().count() == 0
1706            && snapshot.events.0.is_empty()
1707            && snapshot.auth.0.is_empty()
1708        {
1709            return;
1710        }
1711
1712        // Determine path to write test snapshots to.
1713        let thread = std::thread::current();
1714        let Some(test_name) = thread.name() else {
1715            // The stock unit test runner sets a thread name.
1716            // If there is no thread name, assume this is not running as
1717            // part of a unit test, and do nothing.
1718            return;
1719        };
1720        if test_name == "main" {
1721            // When doc tests are running they're all run with the thread name
1722            // main. There's no way to detect which doc test is being run and
1723            // there's little value in writing and overwriting a single file for
1724            // all doc tests.
1725            return;
1726        }
1727        let file_number = LAST_TEST_SNAPSHOT.with_borrow_mut(|l| {
1728            if test_name == l.name {
1729                *l = LastTestSnapshot::default();
1730                l.name = test_name.to_owned();
1731            }
1732            l.number += 1;
1733            l.number
1734        });
1735        // Break up the test name into directories, using :: as the separator.
1736        // The :: module separator cannot be written into the filename because
1737        // some operating systems (e.g. Windows) do not allow the : character in
1738        // filenames.
1739        let test_name_path = test_name
1740            .split("::")
1741            .map(|p| std::path::Path::new(p).to_path_buf())
1742            .reduce(|p0, p1| p0.join(p1))
1743            .expect("test name to not be empty");
1744        let dir = std::path::Path::new("test_snapshots");
1745        let p = dir
1746            .join(&test_name_path)
1747            .with_extension(format!("{file_number}.json"));
1748
1749        // Write test snapshots to file.
1750        eprintln!("Writing test snapshot file for test {test_name:?} to {p:?}.");
1751        snapshot.write_file(p).unwrap();
1752    }
1753}
1754
1755#[doc(hidden)]
1756impl internal::EnvBase for Env {
1757    type Error = Infallible;
1758
1759    // This exists to allow code in conversion paths to upgrade an Error to an
1760    // Env::Error with some control granted to the underlying Env (and panic
1761    // paths kept out of the host). We delegate this to our env_impl and then,
1762    // since our own Error type is Infallible, immediately throw it into either
1763    // the env_impl's Error escalation path (if testing), or just plain panic.
1764    #[cfg(not(target_family = "wasm"))]
1765    fn error_from_error_val(&self, e: crate::Error) -> Self::Error {
1766        let host_err = self.env_impl.error_from_error_val(e);
1767        #[cfg(any(test, feature = "testutils"))]
1768        self.env_impl.escalate_error_to_panic(host_err);
1769        #[cfg(not(any(test, feature = "testutils")))]
1770        panic!("{:?}", host_err);
1771    }
1772
1773    // When targeting wasm we don't even need to do that, just delegate to
1774    // the Guest's impl, which calls core::arch::wasm32::unreachable.
1775    #[cfg(target_family = "wasm")]
1776    fn error_from_error_val(&self, e: crate::Error) -> Self::Error {
1777        self.env_impl.error_from_error_val(e)
1778    }
1779
1780    fn check_protocol_version_lower_bound(&self, v: u32) -> Result<(), Self::Error> {
1781        Ok(self
1782            .env_impl
1783            .check_protocol_version_lower_bound(v)
1784            .unwrap_optimized())
1785    }
1786
1787    fn check_protocol_version_upper_bound(&self, v: u32) -> Result<(), Self::Error> {
1788        Ok(self
1789            .env_impl
1790            .check_protocol_version_upper_bound(v)
1791            .unwrap_optimized())
1792    }
1793
1794    // Note: the function `escalate_error_to_panic` only exists _on the `Env`
1795    // trait_ when the feature `soroban-env-common/testutils` is enabled. This
1796    // is because the host wants to never have this function even _compiled in_
1797    // when building for production, as it might be accidentally called (we have
1798    // mistakenly done so with conversion and comparison traits in the past).
1799    //
1800    // As a result, we only implement it here (fairly meaninglessly) when we're
1801    // in `cfg(test)` (which enables `soroban-env-host/testutils` thus
1802    // `soroban-env-common/testutils`) or when we've had our own `testutils`
1803    // feature enabled (which does the same).
1804    //
1805    // See the `internal::reject_err` functions above for more detail about what
1806    // it actually does (when implemented for real, on the host). In this
1807    // not-very-serious impl, since `Self::Error` is `Infallible`, this instance
1808    // can never actually be called and so its body is just a trivial
1809    // transformation from one empty type to another, for Type System Reasons.
1810    #[cfg(any(test, feature = "testutils"))]
1811    fn escalate_error_to_panic(&self, e: Self::Error) -> ! {
1812        match e {}
1813    }
1814
1815    fn check_same_env(&self, other: &Self) -> Result<(), Self::Error> {
1816        Ok(self
1817            .env_impl
1818            .check_same_env(&other.env_impl)
1819            .unwrap_optimized())
1820    }
1821
1822    fn bytes_copy_from_slice(
1823        &self,
1824        b: BytesObject,
1825        b_pos: U32Val,
1826        slice: &[u8],
1827    ) -> Result<BytesObject, Self::Error> {
1828        Ok(self
1829            .env_impl
1830            .bytes_copy_from_slice(b, b_pos, slice)
1831            .unwrap_optimized())
1832    }
1833
1834    fn bytes_copy_to_slice(
1835        &self,
1836        b: BytesObject,
1837        b_pos: U32Val,
1838        slice: &mut [u8],
1839    ) -> Result<(), Self::Error> {
1840        Ok(self
1841            .env_impl
1842            .bytes_copy_to_slice(b, b_pos, slice)
1843            .unwrap_optimized())
1844    }
1845
1846    fn bytes_new_from_slice(&self, slice: &[u8]) -> Result<BytesObject, Self::Error> {
1847        Ok(self.env_impl.bytes_new_from_slice(slice).unwrap_optimized())
1848    }
1849
1850    fn log_from_slice(&self, msg: &str, args: &[Val]) -> Result<Void, Self::Error> {
1851        Ok(self.env_impl.log_from_slice(msg, args).unwrap_optimized())
1852    }
1853
1854    fn string_copy_to_slice(
1855        &self,
1856        b: StringObject,
1857        b_pos: U32Val,
1858        slice: &mut [u8],
1859    ) -> Result<(), Self::Error> {
1860        Ok(self
1861            .env_impl
1862            .string_copy_to_slice(b, b_pos, slice)
1863            .unwrap_optimized())
1864    }
1865
1866    fn symbol_copy_to_slice(
1867        &self,
1868        b: SymbolObject,
1869        b_pos: U32Val,
1870        mem: &mut [u8],
1871    ) -> Result<(), Self::Error> {
1872        Ok(self
1873            .env_impl
1874            .symbol_copy_to_slice(b, b_pos, mem)
1875            .unwrap_optimized())
1876    }
1877
1878    fn string_new_from_slice(&self, slice: &[u8]) -> Result<StringObject, Self::Error> {
1879        Ok(self
1880            .env_impl
1881            .string_new_from_slice(slice)
1882            .unwrap_optimized())
1883    }
1884
1885    fn symbol_new_from_slice(&self, slice: &[u8]) -> Result<SymbolObject, Self::Error> {
1886        Ok(self
1887            .env_impl
1888            .symbol_new_from_slice(slice)
1889            .unwrap_optimized())
1890    }
1891
1892    fn map_new_from_slices(&self, keys: &[&str], vals: &[Val]) -> Result<MapObject, Self::Error> {
1893        Ok(self
1894            .env_impl
1895            .map_new_from_slices(keys, vals)
1896            .unwrap_optimized())
1897    }
1898
1899    fn map_unpack_to_slice(
1900        &self,
1901        map: MapObject,
1902        keys: &[&str],
1903        vals: &mut [Val],
1904    ) -> Result<Void, Self::Error> {
1905        Ok(self
1906            .env_impl
1907            .map_unpack_to_slice(map, keys, vals)
1908            .unwrap_optimized())
1909    }
1910
1911    fn vec_new_from_slice(&self, vals: &[Val]) -> Result<VecObject, Self::Error> {
1912        Ok(self.env_impl.vec_new_from_slice(vals).unwrap_optimized())
1913    }
1914
1915    fn vec_unpack_to_slice(&self, vec: VecObject, vals: &mut [Val]) -> Result<Void, Self::Error> {
1916        Ok(self
1917            .env_impl
1918            .vec_unpack_to_slice(vec, vals)
1919            .unwrap_optimized())
1920    }
1921
1922    fn symbol_index_in_strs(&self, key: Symbol, strs: &[&str]) -> Result<U32Val, Self::Error> {
1923        Ok(self
1924            .env_impl
1925            .symbol_index_in_strs(key, strs)
1926            .unwrap_optimized())
1927    }
1928}
1929
1930///////////////////////////////////////////////////////////////////////////////
1931/// X-macro use: impl Env for SDK's Env
1932///////////////////////////////////////////////////////////////////////////////
1933
1934// This is a helper macro used only by impl_env_for_sdk below. It consumes a
1935// token-tree of the form:
1936//
1937//  {fn $fn_id:ident $args:tt -> $ret:ty}
1938//
1939// and produces the the corresponding method definition to be used in the
1940// SDK's Env implementation of the Env (calling through to the corresponding
1941// guest or host implementation).
1942macro_rules! sdk_function_helper {
1943    {$mod_id:ident, fn $fn_id:ident($($arg:ident:$type:ty),*) -> $ret:ty}
1944    =>
1945    {
1946        fn $fn_id(&self, $($arg:$type),*) -> Result<$ret, Self::Error> {
1947            internal::reject_err(&self.env_impl, self.env_impl.$fn_id($($arg),*))
1948        }
1949    };
1950}
1951
1952// This is a callback macro that pattern-matches the token-tree passed by the
1953// x-macro (call_macro_with_all_host_functions) and produces a suite of
1954// forwarding-method definitions, which it places in the body of the declaration
1955// of the implementation of Env for the SDK's Env.
1956macro_rules! impl_env_for_sdk {
1957    {
1958        $(
1959            // This outer pattern matches a single 'mod' block of the token-tree
1960            // passed from the x-macro to this macro. It is embedded in a `$()*`
1961            // pattern-repetition matcher so that it will match all provided
1962            // 'mod' blocks provided.
1963            $(#[$mod_attr:meta])*
1964            mod $mod_id:ident $mod_str:literal
1965            {
1966                $(
1967                    // This inner pattern matches a single function description
1968                    // inside a 'mod' block in the token-tree passed from the
1969                    // x-macro to this macro. It is embedded in a `$()*`
1970                    // pattern-repetition matcher so that it will match all such
1971                    // descriptions.
1972                    $(#[$fn_attr:meta])*
1973                    { $fn_str:literal, $($min_proto:literal)?, $($max_proto:literal)?, fn $fn_id:ident $args:tt -> $ret:ty }
1974                )*
1975            }
1976        )*
1977    }
1978
1979    =>  // The part of the macro above this line is a matcher; below is its expansion.
1980
1981    {
1982        // This macro expands to a single item: the implementation of Env for
1983        // the SDK's Env struct used by client contract code running in a WASM VM.
1984        #[doc(hidden)]
1985        impl internal::Env for Env
1986        {
1987            $(
1988                $(
1989                    // This invokes the guest_function_helper! macro above
1990                    // passing only the relevant parts of the declaration
1991                    // matched by the inner pattern above. It is embedded in two
1992                    // nested `$()*` pattern-repetition expanders that
1993                    // correspond to the pattern-repetition matchers in the
1994                    // match section, but we ignore the structure of the 'mod'
1995                    // block repetition-level from the outer pattern in the
1996                    // expansion, flattening all functions from all 'mod' blocks
1997                    // into the implementation of Env for Guest.
1998                    sdk_function_helper!{$mod_id, fn $fn_id $args -> $ret}
1999                )*
2000            )*
2001        }
2002    };
2003}
2004
2005// Here we invoke the x-macro passing generate_env_trait as its callback macro.
2006internal::call_macro_with_all_host_functions! { impl_env_for_sdk }