1use std::sync::Arc;
2use ethers::{
3 abi::{Token, parse_abi},
4 types::{Bytes, U256, Address, TransactionRequest, H256, H256 as Bytes32},
5 signers::Signer,
6 providers::{Middleware, Provider, Http},
7 contract::Contract,
8};
9use serde::{Deserialize, Serialize};
10use crate::{
11 client::Client,
12 error::{Result, InvalidInputsError, Transaction},
13 utils::encode_with_signature,
14};
15use ethers_middleware::SignerMiddleware;
16
17#[derive(Debug)]
18pub struct CalldataQueue {
19 pub client: Arc<Client>,
20 pub manager_address: Address,
21 pub chain_id: u64,
22 pub root: String,
23 pub calls: Vec<Call>,
24}
25
26#[derive(Debug, Serialize, Deserialize)]
27struct Call {
28 target_address: Address,
29 data: Bytes,
30 value: U256,
31 args: Vec<Token>, function_signature: String,
33 proof_data: Vec<Bytes>,
34 decoder_and_sanitizer: Address,
35}
36
37impl CalldataQueue {
38 pub async fn new(
39 chain_id: u64,
40 strategist_address: String,
41 rpc_url: String,
42 symbol: String,
43 client: Arc<Client>,
44 ) -> Result<Self> {
45 let network_string = chain_id.to_string();
47
48 let manager_address = client
50 .address_book
51 .get(&network_string)
52 .and_then(|network| network.get("nucleus"))
53 .and_then(|nucleus| nucleus.get(&symbol))
54 .and_then(|symbol_data| symbol_data.get("manager"))
55 .and_then(|addr| addr.as_str())
56 .ok_or_else(|| {
57 InvalidInputsError(format!(
58 "Could not find manager address for network '{}' and symbol '{}'. Please check the network and symbol are valid.",
59 network_string, symbol
60 ))
61 })?;
62
63 let manager_address = manager_address.parse()
65 .map_err(|_| InvalidInputsError("Invalid manager address format".to_string()))?;
66
67 let provider = Arc::new(
69 Provider::<Http>::try_from(&rpc_url)
70 .map_err(|_| InvalidInputsError(format!("Invalid RPC URL: {}", rpc_url)))?
71 );
72
73 provider.get_block_number().await
75 .map_err(|_| InvalidInputsError(format!("Could not connect to RPC URL '{}'. Please check the RPC URL is valid and accessible.", rpc_url)))?;
76
77 let strategist = strategist_address.parse::<Address>()
79 .map_err(|_| InvalidInputsError("Invalid strategist address format".to_string()))?;
80
81 let abi = parse_abi(&[
83 "function manageRoot(address strategist) view returns (bytes32)"
84 ]).expect("Failed to parse ABI");
85
86 let contract = Contract::new(
87 manager_address,
88 abi,
89 Arc::clone(&provider),
90 );
91
92 let root: Bytes32 = contract
94 .method::<_, Bytes32>("manageRoot", strategist)
95 .map_err(|e| InvalidInputsError(format!("Failed to create manageRoot method call: {}", e)))?
96 .call()
97 .await
98 .map_err(|e| InvalidInputsError(format!("Failed to call manageRoot: {}", e)))?;
99
100 let root = format!("{:?}", root);
102
103 if root == "0x0000000000000000000000000000000000000000000000000000000000000000" {
105 return Err(InvalidInputsError(format!(
106 "Could not find root for strategist '{}'. Please check the strategist address is valid.",
107 strategist_address
108 )).into());
109 }
110
111
112 Ok(Self {
113 client,
114 manager_address,
115 chain_id,
116 root,
117 calls: Vec::new(),
118 })
119 }
120
121 pub fn add_call(
123 &mut self,
124 target_address: Address,
125 function_signature: String,
126 args: Vec<Token>,
127 value: U256,
128 ) -> Result<()> {
129 let data = encode_with_signature(&function_signature, &args)
131 .map_err(|e| InvalidInputsError(format!("Failed to encode function data: {}", e)))?;
132
133 self.calls.push(Call {
135 target_address,
136 data: data.into(),
137 value,
138 args,
139 function_signature,
140 proof_data: vec![],
141 decoder_and_sanitizer: Address::zero(),
142 });
143
144 Ok(())
145 }
146
147 pub async fn get_calldata(&mut self) -> Result<Bytes> {
148 let proof_requests: Vec<ProofRequest> = self.calls.iter()
150 .filter(|call| call.proof_data.is_empty())
151 .map(|call| ProofRequest {
152 target: format!("{:?}", call.target_address),
153 calldata: format!("0x{}", hex::encode(&call.data)),
154 value: call.value.as_u64(),
155 })
156 .collect();
157
158 if !proof_requests.is_empty() {
160 let batch_response = self._get_batch_proofs_and_decoders(proof_requests).await?;
161
162 let mut proof_index = 0;
164 for call in &mut self.calls {
165 if call.proof_data.is_empty() {
166 call.proof_data = batch_response.proofs[proof_index].clone();
167 call.decoder_and_sanitizer = batch_response.decoder_and_sanitizer_addresses[proof_index];
168 proof_index += 1;
169 }
170 }
171 }
172
173 let mut proofs = Vec::new();
175 let mut decoders = Vec::new();
176 let mut targets = Vec::new();
177 let mut data = Vec::new();
178 let mut values = Vec::new();
179
180 for call in &self.calls {
181 proofs.push(Token::Array(
182 call.proof_data.iter()
183 .map(|p| Token::FixedBytes(p.to_vec()))
184 .collect()
185 ));
186 decoders.push(Token::Address(call.decoder_and_sanitizer));
187 targets.push(Token::Address(call.target_address));
188 data.push(Token::Bytes(call.data.to_vec()));
189 values.push(Token::Uint(call.value));
190 }
191
192 let function = "manageVaultWithMerkleVerification(bytes32[][],address[],address[],bytes[],uint256[])";
194
195 let args = vec![
196 Token::Array(proofs),
197 Token::Array(decoders),
198 Token::Array(targets),
199 Token::Array(data),
200 Token::Array(values),
201 ];
202
203 let encoded = encode_with_signature(function, &args)
204 .map_err(|e| InvalidInputsError(format!("Failed to encode manager function: {}", e)))?;
205
206 Ok(encoded.into())
207 }
208
209 pub async fn execute<M: Middleware, S: Signer>(
213 &mut self,
214 signer: &SignerMiddleware<M, S>
215 ) -> Result<H256> {
216 if self.calls.is_empty() {
217 return Err(InvalidInputsError("No calls to execute".to_string()).into());
218 }
219
220 let calldata = self.get_calldata().await?;
221
222 let from_address = signer.address();
224
225 let tx = TransactionRequest {
226 from: Some(from_address),
227 to: Some(self.manager_address.into()),
228 data: Some(calldata),
229 value: Some(U256::zero()),
230 ..Default::default()
231 };
232
233 let pending_tx = signer.send_transaction(tx, None)
235 .await
236 .map_err(|e| Transaction(format!("Transaction failed: {}", e)))?;
237
238 Ok(pending_tx.tx_hash())
240 }
241
242 async fn _get_batch_proofs_and_decoders(
243 &self,
244 leaves: Vec<ProofRequest>
245 ) -> Result<BatchProofResponse> {
246 let request = BatchProofRequest {
248 chain: self.chain_id,
249 calls: leaves,
250 };
251
252 let json_value = serde_json::to_value(&request)
254 .map_err(|e| InvalidInputsError(format!("Failed to serialize batch proof request: {}", e)))?;
255
256 let response: BatchProofResponse = self.client
258 .post(&format!("multiproofs/{}", self.root), Some(&json_value))
259 .await?;
260
261 if response.proofs.len() != response.decoder_and_sanitizer_addresses.len() {
263 return Err(InvalidInputsError(
264 "Mismatched lengths in proof response arrays".to_string()
265 ).into());
266 }
267
268 Ok(response)
269 }
270}
271
272#[derive(Serialize)]
273struct BatchProofRequest {
274 chain: u64, calls: Vec<ProofRequest>,
276}
277
278#[derive(Deserialize, Serialize)]
279struct BatchProofResponse {
280 proofs: Vec<Vec<Bytes>>,
281 #[serde(rename = "decoderAndSanitizerAddress")]
282 decoder_and_sanitizer_addresses: Vec<Address>,
283}
284
285#[derive(Serialize)]
286struct ProofRequest {
287 target: String,
288 calldata: String,
289 value: u64,
290}
291
292#[derive(Deserialize)]
293struct ProofResponse {
294 proof: Vec<Bytes>,
295 decoder_and_sanitizer: Address,
296}