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