aptos_network_sdk/
multicall.rs1use 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
7pub struct MultiContractCall;
9
10impl MultiContractCall {
11 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 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 let (Some(dep_field), Some(prev_result)) = (dependency, &previous_result) {
41 if let Some(dep_value) = prev_result.get(&dep_field) {
42 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 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 let condition_result =
79 crate::contract::Contract::read(Arc::clone(&client), &condition_call).await?;
80 if condition_result.success {
81 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 Ok(None)
89 }
90 }
91
92 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
103pub struct MultiCallUtils;
105
106impl MultiCallUtils {
107 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 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 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 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}