Skip to main content

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