soroban_sdk/testutils/
mock_auth.rs

1#![cfg(any(test, feature = "testutils"))]
2
3use crate::{contract, contractimpl, xdr, Address, Env, Symbol, TryFromVal, Val, Vec};
4
5#[doc(hidden)]
6#[contract(crate_path = "crate")]
7pub struct MockAuthContract;
8
9#[contractimpl(crate_path = "crate")]
10impl MockAuthContract {
11    #[allow(non_snake_case)]
12    pub fn __check_auth(_signature_payload: Val, _signatures: Val, _auth_context: Val) {}
13}
14
15#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
16pub struct MockAuth<'a> {
17    pub address: &'a Address,
18    pub invoke: &'a MockAuthInvoke<'a>,
19}
20
21#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
22pub struct MockAuthInvoke<'a> {
23    pub contract: &'a Address,
24    pub fn_name: &'a str,
25    pub args: Vec<Val>,
26    pub sub_invokes: &'a [MockAuthInvoke<'a>],
27}
28
29impl<'a> From<&MockAuth<'a>> for xdr::SorobanAuthorizationEntry {
30    fn from(value: &MockAuth) -> Self {
31        let env = value.address.env();
32        let curr_ledger = env.ledger().sequence();
33        let max_entry_ttl = env.storage().max_ttl();
34        Self {
35            root_invocation: value.invoke.into(),
36            credentials: xdr::SorobanCredentials::Address(xdr::SorobanAddressCredentials {
37                address: value.address.try_into().unwrap(),
38                nonce: env.with_generator(|mut g| g.nonce()),
39                signature_expiration_ledger: curr_ledger + max_entry_ttl,
40                signature: xdr::ScVal::Void,
41            }),
42        }
43    }
44}
45
46impl<'a> From<MockAuth<'a>> for xdr::SorobanAuthorizationEntry {
47    fn from(value: MockAuth<'a>) -> Self {
48        (&value).into()
49    }
50}
51
52impl<'a> From<&MockAuthInvoke<'a>> for xdr::SorobanAuthorizedInvocation {
53    fn from(value: &MockAuthInvoke<'a>) -> Self {
54        Self {
55            function: xdr::SorobanAuthorizedFunction::ContractFn(xdr::InvokeContractArgs {
56                contract_address: xdr::ScAddress::Contract(value.contract.contract_id()),
57                function_name: value.fn_name.try_into().unwrap(),
58                args: value.args.clone().try_into().unwrap(),
59            }),
60            sub_invocations: value
61                .sub_invokes
62                .iter()
63                .map(Into::<_>::into)
64                .collect::<std::vec::Vec<_>>()
65                .try_into()
66                .unwrap(),
67        }
68    }
69}
70
71impl<'a> From<MockAuthInvoke<'a>> for xdr::SorobanAuthorizedInvocation {
72    fn from(value: MockAuthInvoke<'a>) -> Self {
73        (&value).into()
74    }
75}
76
77/// Describes an authorized invocation tree from the perspective of a single
78/// address.
79///
80/// The authorized invocation tree for a given address is different from a
81/// regular call tree: it only has nodes for the contract calls that called
82/// `require_auth[_for_args]` for that address.
83#[derive(Clone, Eq, PartialEq, Debug)]
84pub struct AuthorizedInvocation {
85    /// Function that has called `require_auth`.
86    pub function: AuthorizedFunction,
87    /// Authorized invocations originating from `function`.
88    pub sub_invocations: std::vec::Vec<AuthorizedInvocation>,
89}
90
91/// A single node in `AuthorizedInvocation` tree.
92#[derive(Clone, Eq, PartialEq, Debug)]
93pub enum AuthorizedFunction {
94    /// Contract function defined by the contract address, function name and
95    /// `require_auth[_for_args]` arguments (these don't necessarily need to
96    /// match the actual invocation arguments).
97    Contract((Address, Symbol, Vec<Val>)),
98    /// Create contract host function with arguments specified as the respective
99    /// XDR.
100    CreateContractHostFn(xdr::CreateContractArgs),
101    /// Create contract host function with arguments specified as the respective
102    /// XDR. Supports passing constructor arguments.
103    CreateContractV2HostFn(xdr::CreateContractArgsV2),
104}
105
106impl AuthorizedFunction {
107    pub fn from_xdr(env: &Env, v: &xdr::SorobanAuthorizedFunction) -> Self {
108        match v {
109            xdr::SorobanAuthorizedFunction::ContractFn(contract_fn) => {
110                let mut args = Vec::new(env);
111                for v in contract_fn.args.iter() {
112                    args.push_back(Val::try_from_val(env, v).unwrap());
113                }
114                Self::Contract((
115                    Address::try_from_val(
116                        env,
117                        &xdr::ScVal::Address(contract_fn.contract_address.clone()),
118                    )
119                    .unwrap(),
120                    Symbol::try_from_val(env, &contract_fn.function_name).unwrap(),
121                    args,
122                ))
123            }
124            xdr::SorobanAuthorizedFunction::CreateContractHostFn(create_contract) => {
125                Self::CreateContractHostFn(create_contract.clone())
126            }
127            xdr::SorobanAuthorizedFunction::CreateContractV2HostFn(create_contract) => {
128                Self::CreateContractV2HostFn(create_contract.clone())
129            }
130        }
131    }
132}
133
134impl AuthorizedInvocation {
135    pub fn from_xdr(env: &Env, v: &xdr::SorobanAuthorizedInvocation) -> Self {
136        Self {
137            function: AuthorizedFunction::from_xdr(env, &v.function),
138            sub_invocations: v
139                .sub_invocations
140                .iter()
141                .map(|si| AuthorizedInvocation::from_xdr(env, si))
142                .collect(),
143        }
144    }
145}