@@ -5,9 +5,13 @@ use crate::{
55 protocol:: check_protocol_version,
66 } ,
77 core:: {
8+ constants:: {
9+ ADDITIONAL_SUBMISSION_GAS_COST_PER_PROOF , CONSTANT_GAS_COST ,
10+ MAX_FEE_BATCH_PROOF_NUMBER , MAX_FEE_DEFAULT_PROOF_NUMBER ,
11+ } ,
812 errors,
913 types:: {
10- AlignedVerificationData , Network , ProvingSystemId , VerificationData ,
14+ AlignedVerificationData , Network , PriceEstimate , ProvingSystemId , VerificationData ,
1115 VerificationDataCommitment ,
1216 } ,
1317 } ,
@@ -92,6 +96,107 @@ pub async fn submit_multiple_and_wait_verification(
9296 Ok ( aligned_verification_data)
9397}
9498
99+ /// Returns the estimated `max_fee` depending on the batch inclusion preference of the user, based on the max priority gas price.
100+ /// NOTE: The `max_fee` is computed from an rpc nodes max priority gas price.
101+ /// To estimate the `max_fee` of a batch we use a compute the `max_fee` with respect to a batch of ~32 proofs present.
102+ /// The `max_fee` estimates therefore are:
103+ /// * `Min`: Specifies a `max_fee` equivalent to the cost of 1 proof in a 32 proof batch.
104+ /// This estimates the lowest possible `max_fee` the user should specify for there proof with lowest priority.
105+ /// * `Default`: Specifies a `max_fee` equivalent to the cost of 10 proofs in a 32 proof batch.
106+ /// This estimates the `max_fee` the user should specify for inclusion within the batch.
107+ /// * `Instant`: specifies a `max_fee` equivalent to the cost of all proofs within in a 32 proof batch.
108+ /// This estimates the `max_fee` the user should specify to pay for the entire batch of proofs and have there proof included instantly.
109+ /// # Arguments
110+ /// * `eth_rpc_url` - The URL of the Ethereum RPC node.
111+ /// * `estimate` - Enum specifying the type of price estimate: MIN, DEFAULT, INSTANT.
112+ /// # Returns
113+ /// The estimated `max_fee` in gas for a proof based on the users `PriceEstimate` as a `U256`.
114+ /// # Errors
115+ /// * `EthereumProviderError` if there is an error in the connection with the RPC provider.
116+ /// * `EthereumGasPriceError` if there is an error retrieving the Ethereum gas price.
117+ pub async fn estimate_fee (
118+ eth_rpc_url : & str ,
119+ estimate : PriceEstimate ,
120+ ) -> Result < U256 , errors:: MaxFeeEstimateError > {
121+ // Price of 1 proof in 32 proof batch
122+ let fee_per_proof = fee_per_proof ( eth_rpc_url, MAX_FEE_BATCH_PROOF_NUMBER ) . await ?;
123+
124+ let proof_price = match estimate {
125+ PriceEstimate :: Min => fee_per_proof,
126+ PriceEstimate :: Default => U256 :: from ( MAX_FEE_DEFAULT_PROOF_NUMBER ) * fee_per_proof,
127+ PriceEstimate :: Instant => U256 :: from ( MAX_FEE_BATCH_PROOF_NUMBER ) * fee_per_proof,
128+ } ;
129+ Ok ( proof_price)
130+ }
131+
132+ /// Returns the computed `max_fee` for a proof based on the number of proofs in a batch (`num_proofs_per_batch`) and
133+ /// number of proofs (`num_proofs`) in that batch the user would pay for i.e (`num_proofs` / `num_proofs_per_batch`).
134+ /// NOTE: The `max_fee` is computed from an rpc nodes max priority gas price.
135+ /// # Arguments
136+ /// * `eth_rpc_url` - The URL of the users Ethereum RPC node.
137+ /// * `num_proofs` - number of proofs in a batch the user would pay for.
138+ /// * `num_proofs_per_batch` - number of proofs within a batch.
139+ /// # Returns
140+ /// * The calculated `max_fee` as a `U256`.
141+ /// # Errors
142+ /// * `EthereumProviderError` if there is an error in the connection with the RPC provider.
143+ /// * `EthereumGasPriceError` if there is an error retrieving the Ethereum gas price.
144+ pub async fn compute_max_fee (
145+ eth_rpc_url : & str ,
146+ num_proofs : usize ,
147+ num_proofs_per_batch : usize ,
148+ ) -> Result < U256 , errors:: MaxFeeEstimateError > {
149+ let fee_per_proof = fee_per_proof ( eth_rpc_url, num_proofs_per_batch) . await ?;
150+ Ok ( fee_per_proof * num_proofs)
151+ }
152+
153+ /// Returns the `fee_per_proof` based on the current gas price for a batch compromised of `num_proofs_per_batch`
154+ /// i.e. (1 / `num_proofs_per_batch`).
155+ // NOTE: The `fee_per_proof` is computed from an rpc nodes max priority gas price.
156+ /// # Arguments
157+ /// * `eth_rpc_url` - The URL of the users Ethereum RPC node.
158+ /// * `num_proofs_per_batch` - number of proofs within a batch.
159+ /// # Returns
160+ /// * The fee per proof of a batch as a `U256`.
161+ /// # Errors
162+ /// * `EthereumProviderError` if there is an error in the connection with the RPC provider.
163+ /// * `EthereumGasPriceError` if there is an error retrieving the Ethereum gas price.
164+ pub async fn fee_per_proof (
165+ eth_rpc_url : & str ,
166+ num_proofs_per_batch : usize ,
167+ ) -> Result < U256 , errors:: MaxFeeEstimateError > {
168+ let eth_rpc_provider =
169+ Provider :: < Http > :: try_from ( eth_rpc_url) . map_err ( |e : url:: ParseError | {
170+ errors:: MaxFeeEstimateError :: EthereumProviderError ( e. to_string ( ) )
171+ } ) ?;
172+ let gas_price = fetch_gas_price ( & eth_rpc_provider) . await ?;
173+
174+ // Cost for estimate `num_proofs_per_batch` proofs
175+ let estimated_gas_per_proof = ( CONSTANT_GAS_COST
176+ + ADDITIONAL_SUBMISSION_GAS_COST_PER_PROOF * num_proofs_per_batch as u128 )
177+ / num_proofs_per_batch as u128 ;
178+
179+ // Price of 1 proof in 32 proof batch
180+ let fee_per_proof = U256 :: from ( estimated_gas_per_proof) * gas_price;
181+
182+ Ok ( fee_per_proof)
183+ }
184+
185+ async fn fetch_gas_price (
186+ eth_rpc_provider : & Provider < Http > ,
187+ ) -> Result < U256 , errors:: MaxFeeEstimateError > {
188+ let gas_price = match eth_rpc_provider. get_gas_price ( ) . await {
189+ Ok ( price) => price,
190+ Err ( e) => {
191+ return Err ( errors:: MaxFeeEstimateError :: EthereumGasPriceError (
192+ e. to_string ( ) ,
193+ ) )
194+ }
195+ } ;
196+
197+ Ok ( gas_price)
198+ }
199+
95200/// Submits multiple proofs to the batcher to be verified in Aligned.
96201/// # Arguments
97202/// * `batcher_url` - The url of the batcher to which the proof will be submitted.
@@ -476,3 +581,50 @@ pub async fn get_chain_id(eth_rpc_url: &str) -> Result<u64, errors::ChainIdError
476581
477582 Ok ( chain_id. as_u64 ( ) )
478583}
584+
585+ #[ cfg( test) ]
586+ mod test {
587+ //Public constants for convenience
588+ pub const HOLESKY_PUBLIC_RPC_URL : & str = "https://ethereum-holesky-rpc.publicnode.com" ;
589+ use super :: * ;
590+
591+ #[ tokio:: test]
592+ async fn computed_max_fee_for_larger_batch_is_smaller ( ) {
593+ let small_fee = compute_max_fee ( HOLESKY_PUBLIC_RPC_URL , 2 , 10 )
594+ . await
595+ . unwrap ( ) ;
596+ let large_fee = compute_max_fee ( HOLESKY_PUBLIC_RPC_URL , 5 , 10 )
597+ . await
598+ . unwrap ( ) ;
599+
600+ assert ! ( small_fee < large_fee) ;
601+ }
602+
603+ #[ tokio:: test]
604+ async fn computed_max_fee_for_more_proofs_larger_than_for_less_proofs ( ) {
605+ let small_fee = compute_max_fee ( HOLESKY_PUBLIC_RPC_URL , 5 , 20 )
606+ . await
607+ . unwrap ( ) ;
608+ let large_fee = compute_max_fee ( HOLESKY_PUBLIC_RPC_URL , 5 , 10 )
609+ . await
610+ . unwrap ( ) ;
611+
612+ assert ! ( small_fee < large_fee) ;
613+ }
614+
615+ #[ tokio:: test]
616+ async fn estimate_fee_are_larger_than_one_another ( ) {
617+ let min_fee = estimate_fee ( HOLESKY_PUBLIC_RPC_URL , PriceEstimate :: Min )
618+ . await
619+ . unwrap ( ) ;
620+ let default_fee = estimate_fee ( HOLESKY_PUBLIC_RPC_URL , PriceEstimate :: Default )
621+ . await
622+ . unwrap ( ) ;
623+ let instant_fee = estimate_fee ( HOLESKY_PUBLIC_RPC_URL , PriceEstimate :: Instant )
624+ . await
625+ . unwrap ( ) ;
626+
627+ assert ! ( min_fee < default_fee) ;
628+ assert ! ( default_fee < instant_fee) ;
629+ }
630+ }
0 commit comments