aptos_network_sdk/
multicall.rs

1use crate::{trade::BatchTradeHandle, types::ContractCall, wallet::Wallet, Aptos};
2use futures::future::join_all;
3use serde_json::{Value, json};
4use std::{collections::HashMap, sync::Arc};
5use tokio::sync::Semaphore;
6
7/// Multi-contract call manager
8pub struct MultiContractCall;
9
10impl MultiContractCall {
11    /// execute multiple read-only calls
12    pub async fn aggregate_read(
13        client: Arc<Aptos>,
14        calls: Vec<ContractCall>,
15    ) -> Result<Vec<Value>, String> {
16        let mut results = Vec::new();
17        for call in calls {
18            match crate::contract::Contract::read(Arc::clone(&client), &call).await {
19                Ok(result) => results.push(json!(result)),
20                Err(e) => results.push(json!({
21                    "success": false,
22                    "error": e
23                })),
24            }
25        }
26        Ok(results)
27    }
28
29    /// Contract call sequence with dependencies
30    pub async fn execute_sequence(
31        client: Arc<Aptos>,
32        wallet: Arc<Wallet>,
33        calls: Vec<(ContractCall, Option<String>)>,
34    ) -> Result<Vec<Value>, String> {
35        let mut results = Vec::new();
36        let mut previous_result: Option<Value> = None;
37        for (call, dependency) in calls {
38            let mut final_call = call;
39            // If there is a dependency, extract data from the previous result
40            if let (Some(dep_field), Some(prev_result)) = (dependency, &previous_result) {
41                if let Some(dep_value) = prev_result.get(&dep_field) {
42                    // Adding dependent values ​​to parameters
43                    final_call.arguments.push(dep_value.clone());
44                }
45            }
46            match crate::contract::Contract::write(
47                Arc::clone(&client),
48                Arc::clone(&wallet),
49                final_call,
50            )
51            .await
52            {
53                Ok(result) => {
54                    let result_value = json!(result);
55                    previous_result = Some(result_value.clone());
56                    results.push(result_value);
57                }
58                Err(e) => {
59                    results.push(json!({
60                        "success": false,
61                        "error": e
62                    }));
63                    break;
64                }
65            }
66        }
67        Ok(results)
68    }
69
70    /// Conditional execution execute the call only if a condition is met
71    pub async fn conditional_execute(
72        client: Arc<Aptos>,
73        wallet: Arc<Wallet>,
74        condition_call: ContractCall,
75        execute_call: ContractCall,
76    ) -> Result<Option<Value>, String> {
77        // First check the conditions
78        let condition_result =
79            crate::contract::Contract::read(Arc::clone(&client), &condition_call).await?;
80        if condition_result.success {
81            // If the conditions are met, execute the call
82            crate::contract::Contract::write(client, wallet, execute_call)
83                .await
84                .map(|result| Some(json!(result)))
85                .map_err(|e| e.to_string())
86        } else {
87            // If the condition is not met
88            Ok(None)
89        }
90    }
91
92    /// Execute multiple write calls in parallel (no dependencies)
93    pub async fn parallel_execute(
94        client: Arc<Aptos>,
95        wallet: Arc<Wallet>,
96        calls: Vec<ContractCall>,
97        max_concurrency: usize,
98    ) -> Result<Vec<Value>, String> {
99        BatchTradeHandle::process_batch(client, wallet, calls, max_concurrency).await
100    }
101}
102
103/// Multiple call tool functions
104pub struct MultiCallUtils;
105
106impl MultiCallUtils {
107    /// Creating standard multi-call parameters
108    pub fn create_multicall_calls(
109        base_calls: Vec<ContractCall>,
110        common_args: Vec<Value>,
111    ) -> Vec<ContractCall> {
112        base_calls
113            .into_iter()
114            .map(|mut call| {
115                call.arguments.extend(common_args.clone());
116                call
117            })
118            .collect()
119    }
120
121    /// Analyzing multiple call results
122    pub fn analyze_multicall_results(results: &[Value]) -> HashMap<String, usize> {
123        let mut analysis = HashMap::new();
124        let mut success_count = 0;
125        let mut failure_count = 0;
126        for result in results {
127            if let Some(success) = result.get("success").and_then(|s| s.as_bool()) {
128                if success {
129                    success_count += 1;
130                } else {
131                    failure_count += 1;
132                }
133            }
134        }
135        analysis.insert("total".to_string(), results.len());
136        analysis.insert("success".to_string(), success_count);
137        analysis.insert("failed".to_string(), failure_count);
138        analysis
139    }
140
141    /// Filter successful call results
142    pub fn filter_successful_results(results: Vec<Value>) -> Vec<Value> {
143        results
144            .into_iter()
145            .filter(|result| {
146                result
147                    .get("success")
148                    .and_then(|s| s.as_bool())
149                    .unwrap_or(false)
150            })
151            .collect()
152    }
153
154    /// Extract all transaction hashes
155    pub fn extract_transaction_hashes(results: &[Value]) -> Vec<String> {
156        results
157            .iter()
158            .filter_map(|result| {
159                if result
160                    .get("success")
161                    .and_then(|s| s.as_bool())
162                    .unwrap_or(false)
163                {
164                    result
165                        .get("transaction_hash")
166                        .and_then(|h| h.as_str())
167                        .map(|s| s.to_string())
168                } else {
169                    None
170                }
171            })
172            .collect()
173    }
174}