radix_clis/resim/
cmd_call_function.rs

1use clap::Parser;
2use radix_common::prelude::*;
3use radix_transactions::builder::ManifestBuilder;
4
5use crate::resim::*;
6use crate::utils::*;
7
8/// Call a function
9#[derive(Parser, Debug)]
10pub struct CallFunction {
11    /// The package which the function belongs to
12    pub package_address: SimulatorPackageAddress,
13
14    /// The name of the blueprint which the function belongs to
15    pub blueprint_name: String,
16
17    /// The function name
18    pub function_name: String,
19
20    /// The call arguments, such as "5", "hello", "<resource_address>:<amount>" and "<resource_address>:<nf_local_id1>,<nf_local_id2>"
21    pub arguments: Vec<String>,
22
23    /// The proofs to add to the auth zone, in form of "<resource_address>:<amount>" or "<resource_address>:<nf_local_id1>,<nf_local_id2>"
24    #[clap(short, long, multiple = true)]
25    pub proofs: Option<Vec<String>>,
26
27    /// The network to use when outputting manifest, [simulator | adapanet | nebunet | mainnet]
28    #[clap(short, long)]
29    pub network: Option<String>,
30
31    /// Output a transaction manifest without execution
32    #[clap(short, long)]
33    pub manifest: Option<PathBuf>,
34
35    /// The private keys used for signing, separated by comma
36    #[clap(short, long)]
37    pub signing_keys: Option<String>,
38
39    /// Turn on tracing
40    #[clap(short, long)]
41    pub trace: bool,
42}
43
44impl CallFunction {
45    pub fn run<O: std::io::Write>(&self, out: &mut O) -> Result<(), String> {
46        let address_bech32_decoder = AddressBech32Decoder::for_simulator();
47
48        let default_account = get_default_account()?;
49        let proofs = self.proofs.clone().unwrap_or_default();
50
51        let mut builder = ManifestBuilder::new();
52        builder = builder.lock_fee_from_faucet();
53        for resource_specifier in proofs {
54            builder = create_proof_from_account(
55                builder,
56                &address_bech32_decoder,
57                default_account,
58                resource_specifier,
59            )
60            .map_err(Error::FailedToBuildArguments)?;
61        }
62        let manifest = self
63            .add_call_function_instruction_with_schema(
64                builder,
65                &address_bech32_decoder,
66                self.package_address.0,
67                self.blueprint_name.clone(),
68                self.function_name.clone(),
69                self.arguments.clone(),
70                Some(default_account),
71            )?
72            .try_deposit_entire_worktop_or_refund(default_account, None)
73            .build();
74        handle_manifest(
75            manifest.into(),
76            &self.signing_keys,
77            &self.network,
78            &self.manifest,
79            self.trace,
80            true,
81            out,
82        )
83        .map(|_| ())
84    }
85
86    /// Calls a function.
87    ///
88    /// The implementation will automatically prepare the arguments based on the
89    /// function SCHEMA, including resource buckets and proofs.
90    ///
91    /// If an Account component address is provided, resources will be withdrawn from the given account;
92    /// otherwise, they will be taken from transaction worktop.
93    pub fn add_call_function_instruction_with_schema(
94        &self,
95        builder: ManifestBuilder,
96        address_bech32_decoder: &AddressBech32Decoder,
97        package_address: PackageAddress,
98        blueprint_name: String,
99        function_name: String,
100        args: Vec<String>,
101        account: Option<ComponentAddress>,
102    ) -> Result<ManifestBuilder, Error> {
103        let bp_interface = export_blueprint_interface(package_address, &blueprint_name)?;
104
105        let function_schema = bp_interface
106            .find_function(function_name.as_str())
107            .ok_or_else(|| {
108                Error::TransactionConstructionError(BuildCallInstructionError::FunctionNotFound(
109                    function_name.clone(),
110                ))
111            })?;
112
113        let (schema, index) = match function_schema.input {
114            BlueprintPayloadDef::Static(ScopedTypeId(hash, index)) => {
115                let schema = export_schema(package_address.as_node_id(), hash)?;
116                (schema, index)
117            }
118            BlueprintPayloadDef::Generic(_instance_index) => {
119                todo!()
120            }
121        };
122
123        let (builder, built_args) = build_call_arguments(
124            builder,
125            address_bech32_decoder,
126            &schema,
127            index,
128            args,
129            account,
130        )
131        .map_err(|e| {
132            Error::TransactionConstructionError(BuildCallInstructionError::FailedToBuildArguments(
133                e,
134            ))
135        })?;
136
137        Ok(builder.call_function_raw(package_address, blueprint_name, function_name, built_args))
138    }
139}