1use async_trait::async_trait;
2use ethers::{
3 abi::{HumanReadableParser, Token, Tokenize},
4 prelude::{
5 k256::{
6 ecdsa::{RecoveryId, Signature as RecoverableSignature},
7 schnorr::signature::hazmat::PrehashSigner,
8 },
9 SignerMiddleware,
10 },
11 providers::{JsonRpcClient, Middleware, Provider, ProviderError},
12 signers::{Signer, Wallet},
13 types::{
14 transaction::{eip2718::TypedTransaction, eip712::Eip712Error},
15 Address, BlockNumber, Eip1559TransactionRequest, Signature, TransactionReceipt, TxHash,
16 H256, U256, U64,
17 },
18};
19use ethers_contract::providers::PendingTransaction;
20use serde::Serialize;
21use serde_json::json;
22use std::{collections::HashMap, fmt::Debug, time::Duration};
23use tokio::time::Instant;
24
25pub mod types;
26use types::Fee;
27
28use crate::{
29 eip712::{Eip712Meta, Eip712Transaction, Eip712TransactionRequest},
30 zks_utils::{self, DEFAULT_GAS, EIP712_TX_TYPE, MAX_FEE_PER_GAS, MAX_PRIORITY_FEE_PER_GAS},
31 zks_wallet::{CallRequest, Overrides},
32};
33
34use self::types::{
35 BlockDetails, BlockRange, BridgeContracts, DebugTrace, L1BatchDetails, Proof, TokenInfo,
36 TracerConfig, Transaction, TransactionDetails,
37};
38
39#[async_trait]
42pub trait ZKSProvider {
43 type Provider: JsonRpcClient;
44 type ZKProvider: JsonRpcClient;
45
46 async fn zk_estimate_gas<T>(&self, transaction: T) -> Result<U256, ProviderError>
47 where
48 T: Debug + Serialize + Send + Sync;
49
50 async fn estimate_fee<T>(&self, transaction: T) -> Result<Fee, ProviderError>
52 where
53 T: Debug + Serialize + Send + Sync;
54
55 async fn estimate_gas_l1_to_l2<T>(&self, transaction: T) -> Result<U256, ProviderError>
57 where
58 T: Debug + Serialize + Send + Sync;
59
60 async fn get_all_account_balances(
62 &self,
63 address: Address,
64 ) -> Result<HashMap<Address, U256>, ProviderError>;
65
66 async fn get_block_details<T>(&self, block: T) -> Result<Option<BlockDetails>, ProviderError>
71 where
72 T: Into<U64> + Send + Sync + Serialize + Debug;
73
74 async fn get_bridge_contracts(&self) -> Result<BridgeContracts, ProviderError>;
76
77 async fn get_bytecode_by_hash(&self, hash: H256) -> Result<Option<Vec<u8>>, ProviderError>;
79
80 async fn get_confirmed_tokens(
86 &self,
87 from: u32,
88 limit: u8,
89 ) -> Result<Vec<TokenInfo>, ProviderError>;
90
91 async fn get_l1_batch_block_range<T>(&self, batch: T) -> Result<BlockRange, ProviderError>
95 where
96 T: Into<U64> + Send + Sync + Serialize + Debug;
97
98 async fn get_l1_batch_details<T>(&self, batch: T) -> Result<L1BatchDetails, ProviderError>
100 where
101 T: Into<U64> + Send + Sync + Serialize + Debug;
102
103 async fn get_l2_to_l1_log_proof(
109 &self,
110 tx_hash: H256,
111 l2_to_l1_log_index: Option<u64>,
112 ) -> Result<Option<Proof>, ProviderError>;
113
114 async fn get_l2_to_l1_msg_proof<T>(
118 &self,
119 block: T,
120 sender: Address,
121 msg: H256,
122 l2_log_position: Option<u64>,
123 ) -> Result<Option<Proof>, ProviderError>
124 where
125 T: Into<U64> + Send + Sync + Serialize + Debug;
126
127 async fn get_main_contract(&self) -> Result<Address, ProviderError>;
129
130 async fn get_raw_block_transactions<T>(
132 &self,
133 block: T,
134 ) -> Result<Vec<Transaction>, ProviderError>
135 where
136 T: Into<U64> + Send + Sync + Serialize + Debug;
137
138 async fn get_testnet_paymaster(&self) -> Result<Address, ProviderError>;
141
142 async fn get_token_price(&self, address: Address) -> Result<String, ProviderError>;
144
145 async fn get_transaction_details(
147 &self,
148 hash: H256,
149 ) -> Result<Option<TransactionDetails>, ProviderError>;
150
151 async fn get_l1_batch_number(&self) -> Result<U256, ProviderError>;
153
154 async fn get_l1_chain_id(&self) -> Result<U256, ProviderError>;
156
157 async fn debug_trace_block_by_hash(
159 &self,
160 hash: H256,
161 options: Option<TracerConfig>,
162 ) -> Result<DebugTrace, ProviderError>;
163
164 async fn debug_trace_block_by_number<T>(
166 &self,
167 block: T,
168 options: Option<TracerConfig>,
169 ) -> Result<DebugTrace, ProviderError>
170 where
171 T: Into<U64> + Send + Sync + Serialize + Debug;
172
173 async fn debug_trace_call<R, T>(
175 &self,
176 request: R,
177 block: Option<T>,
178 options: Option<TracerConfig>,
179 ) -> Result<DebugTrace, ProviderError>
180 where
181 R: Debug + Serialize + Send + Sync,
182 T: Into<U64> + Send + Sync + Serialize + Debug;
183
184 async fn debug_trace_transaction(
186 &self,
187 hash: H256,
188 options: Option<TracerConfig>,
189 ) -> Result<DebugTrace, ProviderError>;
190
191 async fn send_eip712<D>(
192 &self,
193 wallet: &Wallet<D>,
194 contract_address: Address,
195 function_signature: &str,
196 function_parameters: Option<Vec<String>>,
197 overrides: Option<Overrides>,
198 ) -> Result<PendingTransaction<Self::ZKProvider>, ProviderError>
199 where
200 D: PrehashSigner<(RecoverableSignature, RecoveryId)> + Send + Sync;
201
202 async fn send<D>(
203 &self,
204 wallet: &Wallet<D>,
205 contract_address: Address,
206 function_signature: &str,
207 function_parameters: Option<Vec<String>>,
208 overrides: Option<Overrides>,
209 ) -> Result<PendingTransaction<Self::Provider>, ProviderError>
210 where
211 D: PrehashSigner<(RecoverableSignature, RecoveryId)> + Send + Sync;
212
213 async fn wait_for_finalize(
214 &self,
215 transaction_receipt: TxHash,
216 polling_time_in_seconds: Option<Duration>,
217 timeout_in_seconds: Option<Duration>,
218 ) -> Result<TransactionReceipt, ProviderError>;
219
220 async fn call(&self, request: &CallRequest) -> Result<Vec<Token>, ProviderError>;
221
222 async fn send_transaction_eip712<T, D>(
223 &self,
224 wallet: &Wallet<D>,
225 transaction: T,
226 ) -> Result<PendingTransaction<Self::ZKProvider>, ProviderError>
227 where
228 T: TryInto<Eip712TransactionRequest> + Send + Sync + Debug,
229 D: PrehashSigner<(RecoverableSignature, RecoveryId)> + Send + Sync;
230}
231
232#[async_trait]
233impl<M: Middleware + ZKSProvider, S: Signer> ZKSProvider for SignerMiddleware<M, S> {
234 type Provider = <M as Middleware>::Provider;
235 type ZKProvider = <M as ZKSProvider>::ZKProvider;
236
237 async fn zk_estimate_gas<T>(&self, transaction: T) -> Result<U256, ProviderError>
238 where
239 T: Debug + Serialize + Send + Sync,
240 {
241 <M as ZKSProvider>::zk_estimate_gas(self.inner(), transaction).await
242 }
243
244 async fn estimate_fee<T>(&self, transaction: T) -> Result<Fee, ProviderError>
245 where
246 T: Debug + Serialize + Send + Sync,
247 {
248 self.inner().estimate_fee(transaction).await
249 }
250
251 async fn estimate_gas_l1_to_l2<T>(&self, transaction: T) -> Result<U256, ProviderError>
252 where
253 T: Debug + Serialize + Send + Sync,
254 {
255 self.inner().estimate_gas_l1_to_l2(transaction).await
256 }
257
258 async fn get_all_account_balances(
259 &self,
260 address: Address,
261 ) -> Result<HashMap<Address, U256>, ProviderError> {
262 self.inner().get_all_account_balances(address).await
263 }
264
265 async fn get_block_details<T>(&self, block: T) -> Result<Option<BlockDetails>, ProviderError>
266 where
267 T: Into<U64> + Send + Sync + Serialize + Debug,
268 {
269 self.inner().get_block_details(block).await
270 }
271
272 async fn get_bridge_contracts(&self) -> Result<BridgeContracts, ProviderError> {
273 self.inner().get_bridge_contracts().await
274 }
275
276 async fn get_bytecode_by_hash(&self, hash: H256) -> Result<Option<Vec<u8>>, ProviderError> {
277 self.inner().get_bytecode_by_hash(hash).await
278 }
279
280 async fn get_confirmed_tokens(
281 &self,
282 from: u32,
283 limit: u8,
284 ) -> Result<Vec<TokenInfo>, ProviderError> {
285 self.inner().get_confirmed_tokens(from, limit).await
286 }
287
288 async fn get_l1_batch_block_range<T>(&self, batch_id: T) -> Result<BlockRange, ProviderError>
289 where
290 T: Into<U64> + Send + Sync + Serialize + Debug,
291 {
292 self.inner().get_l1_batch_block_range(batch_id).await
293 }
294
295 async fn get_l1_batch_details<T>(&self, batch_id: T) -> Result<L1BatchDetails, ProviderError>
296 where
297 T: Into<U64> + Send + Sync + Serialize + Debug,
298 {
299 self.inner().get_l1_batch_details(batch_id).await
300 }
301
302 async fn get_l2_to_l1_log_proof(
303 &self,
304 tx_hash: H256,
305 l2_to_l1_log_index: Option<u64>,
306 ) -> Result<Option<Proof>, ProviderError> {
307 self.inner()
308 .get_l2_to_l1_log_proof(tx_hash, l2_to_l1_log_index)
309 .await
310 }
311
312 async fn get_l2_to_l1_msg_proof<T>(
313 &self,
314 block: T,
315 sender: Address,
316 msg: H256,
317 l2_log_position: Option<u64>,
318 ) -> Result<Option<Proof>, ProviderError>
319 where
320 T: Into<U64> + Send + Sync + Serialize + Debug,
321 {
322 self.inner()
323 .get_l2_to_l1_msg_proof(block, sender, msg, l2_log_position)
324 .await
325 }
326
327 async fn get_main_contract(&self) -> Result<Address, ProviderError> {
328 self.inner().get_main_contract().await
329 }
330
331 async fn get_raw_block_transactions<T>(
332 &self,
333 block: T,
334 ) -> Result<Vec<Transaction>, ProviderError>
335 where
336 T: Into<U64> + Send + Sync + Serialize + Debug,
337 {
338 self.inner().get_raw_block_transactions(block).await
339 }
340
341 async fn get_testnet_paymaster(&self) -> Result<Address, ProviderError> {
342 self.inner().get_testnet_paymaster().await
343 }
344
345 async fn get_token_price(&self, address: Address) -> Result<String, ProviderError> {
346 self.inner().get_token_price(address).await
347 }
348
349 async fn get_transaction_details(
350 &self,
351 hash: H256,
352 ) -> Result<Option<TransactionDetails>, ProviderError> {
353 self.inner().get_transaction_details(hash).await
354 }
355
356 async fn get_l1_batch_number(&self) -> Result<U256, ProviderError> {
357 self.inner().get_l1_batch_number().await
358 }
359
360 async fn get_l1_chain_id(&self) -> Result<U256, ProviderError> {
361 self.inner().get_l1_chain_id().await
362 }
363
364 async fn debug_trace_block_by_hash(
365 &self,
366 hash: H256,
367 options: Option<TracerConfig>,
368 ) -> Result<DebugTrace, ProviderError> {
369 ZKSProvider::debug_trace_block_by_hash(self.inner(), hash, options).await
370 }
371
372 async fn debug_trace_block_by_number<T>(
373 &self,
374 block: T,
375 options: Option<TracerConfig>,
376 ) -> Result<DebugTrace, ProviderError>
377 where
378 T: Into<U64> + Send + Sync + Serialize + Debug,
379 {
380 ZKSProvider::debug_trace_block_by_number(self.inner(), block, options).await
381 }
382
383 async fn debug_trace_call<R, T>(
384 &self,
385 request: R,
386 block: Option<T>,
387 options: Option<TracerConfig>,
388 ) -> Result<DebugTrace, ProviderError>
389 where
390 R: Debug + Serialize + Send + Sync,
391 T: Into<U64> + Send + Sync + Serialize + Debug,
392 {
393 ZKSProvider::debug_trace_call(self.inner(), request, block, options).await
394 }
395
396 async fn debug_trace_transaction(
397 &self,
398 hash: H256,
399 options: Option<TracerConfig>,
400 ) -> Result<DebugTrace, ProviderError> {
401 ZKSProvider::debug_trace_transaction(self.inner(), hash, options).await
402 }
403
404 async fn send_eip712<D>(
405 &self,
406 wallet: &Wallet<D>,
407 contract_address: Address,
408 function_signature: &str,
409 function_parameters: Option<Vec<String>>,
410 overrides: Option<Overrides>,
411 ) -> Result<PendingTransaction<Self::ZKProvider>, ProviderError>
412 where
413 D: PrehashSigner<(RecoverableSignature, RecoveryId)> + Send + Sync,
414 {
415 self.inner()
416 .send_eip712(
417 wallet,
418 contract_address,
419 function_signature,
420 function_parameters,
421 overrides,
422 )
423 .await
424 }
425
426 async fn send<D>(
427 &self,
428 wallet: &Wallet<D>,
429 contract_address: Address,
430 function_signature: &str,
431 function_parameters: Option<Vec<String>>,
432 _overrides: Option<Overrides>,
433 ) -> Result<PendingTransaction<Self::Provider>, ProviderError>
434 where
435 D: PrehashSigner<(RecoverableSignature, RecoveryId)> + Send + Sync,
436 {
437 let tx = build_send_tx(
438 self,
439 wallet,
440 contract_address,
441 function_signature,
442 function_parameters,
443 _overrides,
444 )
445 .await?;
446 self.send_transaction(tx, None)
447 .await
448 .map_err(|e| ProviderError::CustomError(format!("Error sending transaction: {e:?}")))
449 }
450
451 async fn send_transaction_eip712<T, D>(
452 &self,
453 wallet: &Wallet<D>,
454 transaction: T,
455 ) -> Result<PendingTransaction<Self::ZKProvider>, ProviderError>
456 where
457 T: TryInto<Eip712TransactionRequest> + Sync + Send + Debug,
458 D: PrehashSigner<(RecoverableSignature, RecoveryId)> + Send + Sync,
459 {
460 self.inner()
461 .send_transaction_eip712(wallet, transaction)
462 .await
463 }
464
465 async fn wait_for_finalize(
466 &self,
467 transaction_receipt: TxHash,
468 polling_time_in_seconds: Option<Duration>,
469 timeout_in_seconds: Option<Duration>,
470 ) -> Result<TransactionReceipt, ProviderError> {
471 self.inner()
472 .wait_for_finalize(
473 transaction_receipt,
474 polling_time_in_seconds,
475 timeout_in_seconds,
476 )
477 .await
478 }
479
480 async fn call(&self, request: &CallRequest) -> Result<Vec<Token>, ProviderError> {
481 ZKSProvider::call(self.inner(), request).await
482 }
483}
484
485#[async_trait]
486impl<P: JsonRpcClient> ZKSProvider for Provider<P> {
487 type Provider = P;
488 type ZKProvider = P;
489
490 async fn zk_estimate_gas<T>(&self, transaction: T) -> Result<U256, ProviderError>
491 where
492 T: Debug + Serialize + Send + Sync,
493 {
494 self.request("eth_estimateGas", [transaction]).await
495 }
496
497 async fn estimate_fee<T>(&self, transaction: T) -> Result<Fee, ProviderError>
498 where
499 T: Debug + Serialize + Send + Sync,
500 {
501 self.request("zks_estimateFee", [transaction]).await
502 }
503
504 async fn estimate_gas_l1_to_l2<T>(&self, transaction: T) -> Result<U256, ProviderError>
505 where
506 T: Debug + Serialize + Send + Sync,
507 {
508 self.request("zks_estimateGasL1ToL2", [transaction]).await
509 }
510
511 async fn get_all_account_balances(
512 &self,
513 address: Address,
514 ) -> Result<HashMap<Address, U256>, ProviderError> {
515 self.request("zks_getAllAccountBalances", [address]).await
516 }
517
518 async fn get_block_details<T>(&self, block: T) -> Result<Option<BlockDetails>, ProviderError>
519 where
520 T: Into<U64> + Send + Sync + Serialize + Debug,
521 {
522 self.request("zks_getBlockDetails", [block]).await
523 }
524
525 async fn get_bridge_contracts(&self) -> Result<BridgeContracts, ProviderError> {
526 self.request("zks_getBridgeContracts", ()).await
527 }
528
529 async fn get_bytecode_by_hash(&self, hash: H256) -> Result<Option<Vec<u8>>, ProviderError> {
530 self.request("zks_getBytecodeByHash", [hash]).await
531 }
532
533 async fn get_confirmed_tokens(
534 &self,
535 from: u32,
536 limit: u8,
537 ) -> Result<Vec<TokenInfo>, ProviderError> {
538 self.request("zks_getConfirmedTokens", [from, limit.into()])
539 .await
540 }
541
542 async fn get_l1_batch_block_range<T>(&self, batch: T) -> Result<BlockRange, ProviderError>
543 where
544 T: Into<U64> + Send + Sync + Serialize + Debug,
545 {
546 self.request("zks_getL1BatchBlockRange", [batch]).await
547 }
548
549 async fn get_l1_batch_details<T>(&self, batch: T) -> Result<L1BatchDetails, ProviderError>
550 where
551 T: Into<U64> + Send + Sync + Serialize + Debug,
552 {
553 self.request("zks_getL1BatchDetails", [batch]).await
554 }
555
556 async fn get_l2_to_l1_log_proof(
557 &self,
558 tx_hash: H256,
559 l2_to_l1_log_index: Option<u64>,
560 ) -> Result<Option<Proof>, ProviderError> {
561 self.request(
562 "zks_getL2ToL1LogProof",
563 json!([tx_hash, l2_to_l1_log_index]),
564 )
565 .await
566 }
567
568 async fn get_l2_to_l1_msg_proof<T>(
569 &self,
570 block: T,
571 sender: Address,
572 msg: H256,
573 l2_log_position: Option<u64>,
574 ) -> Result<Option<Proof>, ProviderError>
575 where
576 T: Into<U64> + Send + Sync + Serialize + Debug,
577 {
578 self.request(
579 "zks_getL2ToL1MsgProof",
580 json!([block, sender, msg, l2_log_position]),
581 )
582 .await
583 }
584
585 async fn get_main_contract(&self) -> Result<Address, ProviderError> {
586 self.request("zks_getMainContract", ()).await
587 }
588
589 async fn get_raw_block_transactions<T>(
590 &self,
591 block: T,
592 ) -> Result<Vec<Transaction>, ProviderError>
593 where
594 T: Into<U64> + Send + Sync + Serialize + Debug,
595 {
596 self.request("zks_getRawBlockTransactions", [block]).await
597 }
598
599 async fn get_testnet_paymaster(&self) -> Result<Address, ProviderError> {
600 self.request("zks_getTestnetPaymaster", ()).await
601 }
602
603 async fn get_token_price(&self, address: Address) -> Result<String, ProviderError> {
604 self.request("zks_getTokenPrice", [address]).await
605 }
606
607 async fn get_transaction_details(
608 &self,
609 hash: H256,
610 ) -> Result<Option<TransactionDetails>, ProviderError> {
611 self.request("zks_getTransactionDetails", [hash]).await
612 }
613
614 async fn get_l1_batch_number(&self) -> Result<U256, ProviderError> {
615 self.request("zks_L1BatchNumber", ()).await
616 }
617
618 async fn get_l1_chain_id(&self) -> Result<U256, ProviderError> {
619 self.request("zks_L1ChainId", ()).await
620 }
621
622 async fn debug_trace_block_by_hash(
623 &self,
624 hash: H256,
625 options: Option<TracerConfig>,
626 ) -> Result<DebugTrace, ProviderError> {
627 let processable_response = self
628 .request::<serde_json::Value, serde_json::Value>(
629 "debug_traceBlockByHash",
630 json!([hash, options]),
631 )
632 .await?
633 .get(0)
634 .ok_or(ProviderError::CustomError(
635 "error on debug_trace_block_by_hash".to_owned(),
636 ))?
637 .get("result")
638 .ok_or(ProviderError::CustomError(
639 "error on debug_trace_block_by_hash".to_owned(),
640 ))?
641 .clone();
642 serde_json::from_value(processable_response).map_err(ProviderError::SerdeJson)
643 }
644
645 async fn debug_trace_block_by_number<T>(
646 &self,
647 block: T,
648 options: Option<TracerConfig>,
649 ) -> Result<DebugTrace, ProviderError>
650 where
651 T: Into<U64> + Send + Sync + Serialize + Debug,
652 {
653 let processable_response = self
654 .request::<serde_json::Value, serde_json::Value>(
655 "debug_traceBlockByNumber",
656 json!([block, options]),
657 )
658 .await?
659 .get(0)
660 .ok_or(ProviderError::CustomError(
661 "error on debug_trace_block_by_hash".to_owned(),
662 ))?
663 .get("result")
664 .ok_or(ProviderError::CustomError(
665 "error on debug_trace_block_by_hash".to_owned(),
666 ))?
667 .clone();
668 serde_json::from_value(processable_response).map_err(ProviderError::SerdeJson)
669 }
670
671 async fn debug_trace_call<R, T>(
672 &self,
673 request: R,
674 block: Option<T>,
675 options: Option<TracerConfig>,
676 ) -> Result<DebugTrace, ProviderError>
677 where
678 R: Debug + Serialize + Send + Sync,
679 T: Into<U64> + Send + Sync + Serialize + Debug,
680 {
681 self.request("debug_traceCall", json!([request, block, options]))
682 .await
683 }
684
685 async fn debug_trace_transaction(
686 &self,
687 hash: H256,
688 options: Option<TracerConfig>,
689 ) -> Result<DebugTrace, ProviderError> {
690 self.request("debug_traceTransaction", json!([hash, options]))
691 .await
692 }
693
694 async fn send_transaction_eip712<T, D>(
695 &self,
696 wallet: &Wallet<D>,
697 transaction: T,
698 ) -> Result<PendingTransaction<Self::ZKProvider>, ProviderError>
699 where
700 T: TryInto<Eip712TransactionRequest> + Sync + Send + Debug,
701 D: PrehashSigner<(RecoverableSignature, RecoveryId)> + Send + Sync,
702 {
703 let mut request: Eip712TransactionRequest = transaction.try_into().map_err(|_e| {
704 ProviderError::CustomError("error on send_transaction_eip712".to_owned())
705 })?;
706
707 let gas_price = self.get_gas_price().await?;
708 request = request
709 .from(wallet.address())
710 .chain_id(wallet.chain_id())
711 .nonce(self.get_transaction_count(wallet.address(), None).await?)
712 .gas_price(gas_price)
713 .max_fee_per_gas(gas_price);
714
715 let custom_data = request.clone().custom_data;
716 let fee = self.estimate_fee(request.clone()).await?;
717 request = request
718 .max_priority_fee_per_gas(fee.max_priority_fee_per_gas)
719 .max_fee_per_gas(fee.max_fee_per_gas)
720 .gas_limit(fee.gas_limit);
721 let signable_data: Eip712Transaction = request
722 .clone()
723 .try_into()
724 .map_err(|e: Eip712Error| ProviderError::CustomError(e.to_string()))?;
725 let signature: Signature = wallet
726 .sign_typed_data(&signable_data)
727 .await
728 .map_err(|e| ProviderError::CustomError(format!("error signing transaction: {e}")))?;
729 request = request.custom_data(custom_data.custom_signature(signature.to_vec()));
730 let encoded_rlp = &*request
731 .rlp_signed(signature)
732 .map_err(|e| ProviderError::CustomError(format!("Error in the rlp encoding {e}")))?;
733
734 self.send_raw_transaction([&[EIP712_TX_TYPE], encoded_rlp].concat().into())
735 .await
736 }
737
738 async fn send_eip712<D>(
739 &self,
740 wallet: &Wallet<D>,
741 contract_address: Address,
742 function_signature: &str,
743 function_parameters: Option<Vec<String>>,
744 overrides: Option<Overrides>,
745 ) -> Result<PendingTransaction<Self::ZKProvider>, ProviderError>
746 where
747 D: PrehashSigner<(RecoverableSignature, RecoveryId)> + Send + Sync,
748 {
749 let function = HumanReadableParser::parse_function(function_signature)
752 .map_err(|e| ProviderError::CustomError(e.to_string()))?;
753
754 let mut send_request = if let Some(overrides) = overrides {
755 Eip712TransactionRequest::from_overrides(overrides)
756 } else {
757 Eip712TransactionRequest::new()
758 };
759
760 let function_args = if let Some(function_args) = function_parameters {
761 function
762 .decode_input(
763 &zks_utils::encode_args(&function, &function_args)
764 .map_err(|e| ProviderError::CustomError(e.to_string()))?,
765 )
766 .map_err(|e| ProviderError::CustomError(e.to_string()))?
767 } else {
768 vec![]
769 };
770
771 send_request = send_request
772 .r#type(EIP712_TX_TYPE)
773 .from(wallet.address())
774 .to(contract_address)
775 .chain_id(wallet.chain_id())
776 .nonce(self.get_transaction_count(wallet.address(), None).await?)
777 .gas_price(self.get_gas_price().await?)
778 .max_fee_per_gas(self.get_gas_price().await?)
779 .data(if !function_args.is_empty() {
780 function
781 .encode_input(&function_args)
782 .map_err(|e| ProviderError::CustomError(e.to_string()))?
783 } else {
784 function.short_signature().into()
785 });
786
787 let fee = self.estimate_fee(send_request.clone()).await?;
788 send_request = send_request
789 .max_priority_fee_per_gas(fee.max_priority_fee_per_gas)
790 .max_fee_per_gas(fee.max_fee_per_gas)
791 .gas_limit(fee.gas_limit);
792
793 let signable_data: Eip712Transaction = send_request
794 .clone()
795 .try_into()
796 .map_err(|e: Eip712Error| ProviderError::CustomError(e.to_string()))?;
797 let signature: Signature = wallet
798 .sign_typed_data(&signable_data)
799 .await
800 .map_err(|e| ProviderError::CustomError(format!("error signing transaction: {e}")))?;
801 send_request =
802 send_request.custom_data(Eip712Meta::new().custom_signature(signature.to_vec()));
803
804 let encoded_rlp = &*send_request
805 .rlp_signed(signature)
806 .map_err(|e| ProviderError::CustomError(format!("error encoding transaction: {e}")))?;
807 self.send_raw_transaction([&[EIP712_TX_TYPE], encoded_rlp].concat().into())
808 .await
809 }
810
811 async fn send<D>(
812 &self,
813 wallet: &Wallet<D>,
814 contract_address: Address,
815 function_signature: &str,
816 function_parameters: Option<Vec<String>>,
817 _overrides: Option<Overrides>,
818 ) -> Result<PendingTransaction<Self::Provider>, ProviderError>
819 where
820 D: PrehashSigner<(RecoverableSignature, RecoveryId)> + Send + Sync,
821 {
822 let tx = build_send_tx(
823 self,
824 wallet,
825 contract_address,
826 function_signature,
827 function_parameters,
828 _overrides,
829 )
830 .await?;
831 self.send_transaction(tx, None).await
832 }
833
834 async fn wait_for_finalize(
835 &self,
836 tx_hash: TxHash,
837 polling_time_in_seconds: Option<Duration>,
838 timeout_in_seconds: Option<Duration>,
839 ) -> Result<TransactionReceipt, ProviderError> {
840 let polling_time_in_seconds = polling_time_in_seconds.unwrap_or(Duration::from_secs(2));
841 let mut timer = tokio::time::interval(polling_time_in_seconds);
842 let start = Instant::now();
843
844 let transaction_receipt =
845 self.get_transaction_receipt(tx_hash)
846 .await?
847 .ok_or(ProviderError::CustomError(
848 "No transaction receipt".to_owned(),
849 ))?;
850
851 loop {
852 timer.tick().await;
853
854 if let Some(timeout) = timeout_in_seconds {
855 if start.elapsed() >= timeout {
856 return Err(ProviderError::CustomError(
857 "Error waiting for transaction to be included into the finalized block"
858 .to_owned(),
859 ));
860 }
861 }
862
863 let latest_block =
865 self.get_block(BlockNumber::Finalized)
866 .await?
867 .ok_or(ProviderError::CustomError(
868 "Error getting finalized block".to_owned(),
869 ))?;
870
871 if transaction_receipt.block_number <= latest_block.number {
872 return Ok(transaction_receipt);
873 }
874 }
875 }
876
877 async fn call(&self, request: &CallRequest) -> Result<Vec<Token>, ProviderError> {
878 let function = request
879 .get_parsed_function()
880 .map_err(|e| ProviderError::CustomError(format!("Failed to parse function: {e}")))?;
881 let request: Eip1559TransactionRequest = request
882 .clone()
883 .try_into()
884 .map_err(|e| ProviderError::CustomError(format!("Failed to convert request: {e}")))?;
885 let transaction: TypedTransaction = request.into();
886
887 let encoded_output = Middleware::call(self, &transaction, None).await?;
888 let decoded_output = function.decode_output(&encoded_output).map_err(|e| {
889 ProviderError::CustomError(format!("failed to decode output: {e}\n{encoded_output}"))
890 })?;
891
892 Ok(if decoded_output.is_empty() {
893 encoded_output.into_tokens()
894 } else {
895 decoded_output
896 })
897 }
898}
899
900async fn build_send_tx<D>(
901 provider: &impl Middleware,
902 wallet: &Wallet<D>,
903 contract_address: Address,
904 function_signature: &str,
905 function_parameters: Option<Vec<String>>,
906 _overrides: Option<Overrides>,
907) -> Result<TypedTransaction, ProviderError>
908where
909 D: PrehashSigner<(RecoverableSignature, RecoveryId)> + Send + Sync,
910{
911 let function = HumanReadableParser::parse_function(function_signature)
912 .map_err(|e| ProviderError::CustomError(e.to_string()))?;
913
914 let function_args = if let Some(function_args) = function_parameters {
915 function
916 .decode_input(
917 &zks_utils::encode_args(&function, &function_args)
918 .map_err(|e| ProviderError::CustomError(e.to_string()))?,
919 )
920 .map_err(|e| ProviderError::CustomError(e.to_string()))?
921 } else {
922 vec![]
923 };
924
925 let send_request = Eip1559TransactionRequest::new()
927 .from(wallet.address())
928 .to(contract_address)
929 .chain_id(wallet.chain_id())
930 .nonce(
931 provider
932 .get_transaction_count(wallet.address(), None)
933 .await
934 .map_err(|e| ProviderError::CustomError(e.to_string()))?,
935 )
936 .data(if !function_args.is_empty() {
937 function
938 .encode_input(&function_args)
939 .map_err(|e| ProviderError::CustomError(e.to_string()))?
940 } else {
941 function.short_signature().into()
942 })
943 .value(0_u8)
944 .gas(DEFAULT_GAS)
946 .max_fee_per_gas(MAX_FEE_PER_GAS)
947 .max_priority_fee_per_gas(MAX_PRIORITY_FEE_PER_GAS);
948
949 Ok(send_request.into())
950}