diff --git a/batcher/Cargo.lock b/batcher/Cargo.lock index 938be6124..ce3fed794 100644 --- a/batcher/Cargo.lock +++ b/batcher/Cargo.lock @@ -302,9 +302,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.93" +version = "1.0.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c95c10ba0b00a02636238b814946408b1322d5ac4760326e6fb8ec956d85775" +checksum = "c1fd03a028ef38ba2276dce7e33fcd6369c158a1bca17946c4b1b701891c1ff7" [[package]] name = "ark-bn254" @@ -619,7 +619,7 @@ dependencies = [ "aws-sdk-sts", "aws-smithy-async", "aws-smithy-http", - "aws-smithy-json", + "aws-smithy-json 0.60.7", "aws-smithy-runtime", "aws-smithy-runtime-api", "aws-smithy-types", @@ -650,9 +650,9 @@ dependencies = [ [[package]] name = "aws-runtime" -version = "1.4.3" +version = "1.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a10d5c055aa540164d9561a0e2e74ad30f0dcf7393c3a92f6733ddf9c5762468" +checksum = "b5ac934720fbb46206292d2c75b57e67acfc56fe7dfd34fb9a02334af08409ea" dependencies = [ "aws-credential-types", "aws-sigv4", @@ -676,9 +676,9 @@ dependencies = [ [[package]] name = "aws-sdk-s3" -version = "1.64.0" +version = "1.65.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35fe5e7f71b1cc6274e905d3bcc7daf94099ac2d4cba83447ffb959b5b27b3c1" +checksum = "d3ba2c5c0f2618937ce3d4a5ad574b86775576fa24006bcb3128c6e2cbf3c34e" dependencies = [ "aws-credential-types", "aws-runtime", @@ -687,7 +687,7 @@ dependencies = [ "aws-smithy-checksums", "aws-smithy-eventstream", "aws-smithy-http", - "aws-smithy-json", + "aws-smithy-json 0.61.1", "aws-smithy-runtime", "aws-smithy-runtime-api", "aws-smithy-types", @@ -710,15 +710,15 @@ dependencies = [ [[package]] name = "aws-sdk-sso" -version = "1.49.0" +version = "1.50.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09677244a9da92172c8dc60109b4a9658597d4d298b188dd0018b6a66b410ca4" +checksum = "05ca43a4ef210894f93096039ef1d6fa4ad3edfabb3be92b80908b9f2e4b4eab" dependencies = [ "aws-credential-types", "aws-runtime", "aws-smithy-async", "aws-smithy-http", - "aws-smithy-json", + "aws-smithy-json 0.61.1", "aws-smithy-runtime", "aws-smithy-runtime-api", "aws-smithy-types", @@ -732,15 +732,15 @@ dependencies = [ [[package]] name = "aws-sdk-ssooidc" -version = "1.50.0" +version = "1.51.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81fea2f3a8bb3bd10932ae7ad59cc59f65f270fc9183a7e91f501dc5efbef7ee" +checksum = "abaf490c2e48eed0bb8e2da2fb08405647bd7f253996e0f93b981958ea0f73b0" dependencies = [ "aws-credential-types", "aws-runtime", "aws-smithy-async", "aws-smithy-http", - "aws-smithy-json", + "aws-smithy-json 0.61.1", "aws-smithy-runtime", "aws-smithy-runtime-api", "aws-smithy-types", @@ -754,15 +754,15 @@ dependencies = [ [[package]] name = "aws-sdk-sts" -version = "1.50.0" +version = "1.51.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ada54e5f26ac246dc79727def52f7f8ed38915cb47781e2a72213957dc3a7d5" +checksum = "b68fde0d69c8bfdc1060ea7da21df3e39f6014da316783336deff0a9ec28f4bf" dependencies = [ "aws-credential-types", "aws-runtime", "aws-smithy-async", "aws-smithy-http", - "aws-smithy-json", + "aws-smithy-json 0.61.1", "aws-smithy-query", "aws-smithy-runtime", "aws-smithy-runtime-api", @@ -777,9 +777,9 @@ dependencies = [ [[package]] name = "aws-sigv4" -version = "1.2.5" +version = "1.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5619742a0d8f253be760bfbb8e8e8368c69e3587e4637af5754e488a611499b1" +checksum = "7d3820e0c08d0737872ff3c7c1f21ebbb6693d832312d6152bf18ef50a5471c2" dependencies = [ "aws-credential-types", "aws-smithy-eventstream", @@ -792,7 +792,7 @@ dependencies = [ "hex", "hmac", "http 0.2.12", - "http 1.1.0", + "http 1.2.0", "once_cell", "p256", "percent-encoding", @@ -877,6 +877,15 @@ dependencies = [ "aws-smithy-types", ] +[[package]] +name = "aws-smithy-json" +version = "0.61.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee4e69cc50921eb913c6b662f8d909131bb3e6ad6cb6090d3a39b66fc5c52095" +dependencies = [ + "aws-smithy-types", +] + [[package]] name = "aws-smithy-query" version = "0.60.7" @@ -889,9 +898,9 @@ dependencies = [ [[package]] name = "aws-smithy-runtime" -version = "1.7.3" +version = "1.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be28bd063fa91fd871d131fc8b68d7cd4c5fa0869bea68daca50dcb1cbd76be2" +checksum = "9f20685047ca9d6f17b994a07f629c813f08b5bce65523e47124879e60103d45" dependencies = [ "aws-smithy-async", "aws-smithy-http", @@ -924,7 +933,7 @@ dependencies = [ "aws-smithy-types", "bytes", "http 0.2.12", - "http 1.1.0", + "http 1.2.0", "pin-project-lite", "tokio", "tracing", @@ -942,7 +951,7 @@ dependencies = [ "bytes-utils", "futures-core", "http 0.2.12", - "http 1.1.0", + "http 1.2.0", "http-body 0.4.6", "http-body 1.0.1", "http-body-util", @@ -990,7 +999,7 @@ dependencies = [ "axum-core", "bytes", "futures-util", - "http 1.1.0", + "http 1.2.0", "http-body 1.0.1", "http-body-util", "hyper 1.5.1", @@ -1023,7 +1032,7 @@ dependencies = [ "async-trait", "bytes", "futures-util", - "http 1.1.0", + "http 1.2.0", "http-body 1.0.1", "http-body-util", "mime", @@ -1489,9 +1498,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.21" +version = "4.5.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb3b4b9e5a7c7514dfa52869339ee98b3156b0bfb4e8a77c4ff4babb64b1604f" +checksum = "3135e7ec2ef7b10c6ed8950f0f792ed96ee093fa088608f1c76e569722700c84" dependencies = [ "clap_builder", "clap_derive", @@ -1499,9 +1508,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.21" +version = "4.5.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b17a95aa67cc7b5ebd32aa5370189aa0d79069ef1c64ce893bd30fb24bff20ec" +checksum = "30582fc632330df2bd26877bde0c1f4470d57c582bbc070376afcd04d8cb4838" dependencies = [ "anstream", "anstyle", @@ -1523,9 +1532,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afb84c814227b90d6895e01398aee0d8033c00e7466aca416fb6a8e0eb19d8a7" +checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" [[package]] name = "coins-bip32" @@ -3005,7 +3014,7 @@ dependencies = [ "fnv", "futures-core", "futures-sink", - "http 1.1.0", + "http 1.2.0", "indexmap", "slab", "tokio", @@ -3171,9 +3180,9 @@ dependencies = [ [[package]] name = "http" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" +checksum = "f16ca2af56261c99fba8bac40a10251ce8188205a4c448fbb745a2e4daa76fea" dependencies = [ "bytes", "fnv", @@ -3198,7 +3207,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ "bytes", - "http 1.1.0", + "http 1.2.0", ] [[package]] @@ -3209,7 +3218,7 @@ checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" dependencies = [ "bytes", "futures-util", - "http 1.1.0", + "http 1.2.0", "http-body 1.0.1", "pin-project-lite", ] @@ -3266,7 +3275,7 @@ dependencies = [ "futures-channel", "futures-util", "h2 0.4.7", - "http 1.1.0", + "http 1.2.0", "http-body 1.0.1", "httparse", "httpdate", @@ -3300,13 +3309,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08afdbb5c31130e3034af566421053ab03787c640246a446327f550d11bcb333" dependencies = [ "futures-util", - "http 1.1.0", + "http 1.2.0", "hyper 1.5.1", "hyper-util", "rustls 0.23.19", "rustls-pki-types", "tokio", - "tokio-rustls 0.26.0", + "tokio-rustls 0.26.1", "tower-service", "webpki-roots 0.26.7", ] @@ -3349,7 +3358,7 @@ dependencies = [ "bytes", "futures-channel", "futures-util", - "http 1.1.0", + "http 1.2.0", "http-body 1.0.1", "hyper 1.5.1", "pin-project-lite", @@ -5146,7 +5155,7 @@ dependencies = [ "rustc-hash 2.1.0", "rustls 0.23.19", "socket2", - "thiserror 2.0.3", + "thiserror 2.0.4", "tokio", "tracing", ] @@ -5165,7 +5174,7 @@ dependencies = [ "rustls 0.23.19", "rustls-pki-types", "slab", - "thiserror 2.0.3", + "thiserror 2.0.4", "tinyvec", "tracing", "web-time", @@ -5395,7 +5404,7 @@ dependencies = [ "futures-core", "futures-util", "h2 0.4.7", - "http 1.1.0", + "http 1.2.0", "http-body 1.0.1", "http-body-util", "hyper 1.5.1", @@ -5421,7 +5430,7 @@ dependencies = [ "system-configuration 0.6.1", "tokio", "tokio-native-tls", - "tokio-rustls 0.26.0", + "tokio-rustls 0.26.1", "tokio-util", "tower-service", "url", @@ -5441,7 +5450,7 @@ checksum = "562ceb5a604d3f7c885a792d42c199fd8af239d0a51b2fa6a78aafa092452b04" dependencies = [ "anyhow", "async-trait", - "http 1.1.0", + "http 1.2.0", "reqwest 0.12.9", "serde", "thiserror 1.0.69", @@ -7062,11 +7071,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.3" +version = "2.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c006c85c7651b3cf2ada4584faa36773bd07bac24acfb39f3c431b36d7e667aa" +checksum = "2f49a1853cf82743e3b7950f77e0f4d622ca36cf4317cba00c767838bac8d490" dependencies = [ - "thiserror-impl 2.0.3", + "thiserror-impl 2.0.4", ] [[package]] @@ -7082,9 +7091,9 @@ dependencies = [ [[package]] name = "thiserror-impl" -version = "2.0.3" +version = "2.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f077553d607adc1caf65430528a576c757a71ed73944b66ebb58ef2bbd243568" +checksum = "8381894bb3efe0c4acac3ded651301ceee58a15d47c2e34885ed1908ad667061" dependencies = [ "proc-macro2", "quote", @@ -7103,9 +7112,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.36" +version = "0.3.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" +checksum = "35e7868883861bd0e56d9ac6efcaaca0d6d5d82a2a7ec8209ff492c07cf37b21" dependencies = [ "deranged", "itoa", @@ -7126,9 +7135,9 @@ checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" [[package]] name = "time-macros" -version = "0.2.18" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" +checksum = "2834e6017e3e5e4b9834939793b282bc03b37a3336245fa820e35e233e2a85de" dependencies = [ "num-conv", "time-core", @@ -7170,9 +7179,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.41.1" +version = "1.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22cfb5bee7a6a52939ca9224d6ac897bb669134078daa8735560897f69de4d33" +checksum = "5cec9b21b0450273377fc97bd4c33a8acffc8c996c987a7c5b319a0083707551" dependencies = [ "backtrace", "bytes", @@ -7219,12 +7228,11 @@ dependencies = [ [[package]] name = "tokio-rustls" -version = "0.26.0" +version = "0.26.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" +checksum = "5f6d0975eaace0cf0fcadee4e4aaa5da15b5c079146f2cffb67c113be122bf37" dependencies = [ "rustls 0.23.19", - "rustls-pki-types", "tokio", ] @@ -7268,7 +7276,7 @@ dependencies = [ "rustls-pki-types", "tokio", "tokio-native-tls", - "tokio-rustls 0.26.0", + "tokio-rustls 0.26.1", "tungstenite 0.23.0", "webpki-roots 0.26.7", ] @@ -7286,16 +7294,16 @@ dependencies = [ "rustls-pki-types", "tokio", "tokio-native-tls", - "tokio-rustls 0.26.0", + "tokio-rustls 0.26.1", "tungstenite 0.24.0", "webpki-roots 0.26.7", ] [[package]] name = "tokio-util" -version = "0.7.12" +version = "0.7.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61e7c3654c13bcd040d4a03abee2c75b1d14a37b423cf5a813ceae1cc903ec6a" +checksum = "d7fcaa8d55a2bdd6b83ace262b016eca0d79ee02818c5c1bcdf0305114081078" dependencies = [ "bytes", "futures-core", @@ -7506,7 +7514,7 @@ dependencies = [ "byteorder", "bytes", "data-encoding", - "http 1.1.0", + "http 1.2.0", "httparse", "log", "rand", @@ -7525,7 +7533,7 @@ dependencies = [ "byteorder", "bytes", "data-encoding", - "http 1.1.0", + "http 1.2.0", "httparse", "log", "native-tls", @@ -7546,7 +7554,7 @@ dependencies = [ "byteorder", "bytes", "data-encoding", - "http 1.1.0", + "http 1.2.0", "httparse", "log", "native-tls", @@ -7567,7 +7575,7 @@ dependencies = [ "async-trait", "axum", "futures", - "http 1.1.0", + "http 1.2.0", "http-body-util", "hyper 1.5.1", "prost", diff --git a/batcher/aligned-sdk/src/core/constants.rs b/batcher/aligned-sdk/src/core/constants.rs index d45189000..0dd055ae7 100644 --- a/batcher/aligned-sdk/src/core/constants.rs +++ b/batcher/aligned-sdk/src/core/constants.rs @@ -18,13 +18,13 @@ pub const OVERRIDE_GAS_PRICE_PERCENTAGE_MULTIPLIER: u128 = 120; // gasPrice modi pub const PERCENTAGE_DIVIDER: u128 = 100; /// SDK /// -/// Number of proofs we a batch for estimation. -/// This is the number of proofs in a batch of size n, where we set n = 32. -/// i.e. the user pays for the entire batch and his proof is instantly submitted. -pub const MAX_FEE_BATCH_PROOF_NUMBER: usize = 32; -/// Estimated number of proofs for batch submission. -/// This corresponds to the number of proofs to compute for a default max_fee. -pub const MAX_FEE_DEFAULT_PROOF_NUMBER: usize = 10; +/// Constants used for `max_fee` estimation in the sdk `estimate_fee()` function. +/// The number of proofs in a batch to compute the `Instant` fee estimate for proof submission to Aligned. +/// i.e. the user pays for the entire batch and his proof is instantly submitted, therefore a batch of one proof. +pub const INSTANT_MAX_FEE_BATCH_SIZE: usize = 1; +/// The number of proofs in a batch to compute the `Default` fee estimate for proof submission to Aligned. +/// We define `16` as the `Default` setting as every 24 hours the batcher receives a batch of `16` proofs sent from Aligned to confirm the network is live. +pub const DEFAULT_MAX_FEE_BATCH_SIZE: usize = 16; /// Ethereum calls retry constants pub const ETHEREUM_CALL_MIN_RETRY_DELAY: u64 = 500; // milliseconds diff --git a/batcher/aligned-sdk/src/core/errors.rs b/batcher/aligned-sdk/src/core/errors.rs index 8712009c6..31fc3ee54 100644 --- a/batcher/aligned-sdk/src/core/errors.rs +++ b/batcher/aligned-sdk/src/core/errors.rs @@ -17,7 +17,7 @@ pub enum AlignedError { SubmitError(SubmitError), VerificationError(VerificationError), ChainIdError(ChainIdError), - MaxFeeEstimateError(MaxFeeEstimateError), + FeeEstimateError(FeeEstimateError), FileError(FileError), } @@ -39,9 +39,9 @@ impl From for AlignedError { } } -impl From for AlignedError { - fn from(e: MaxFeeEstimateError) -> Self { - AlignedError::MaxFeeEstimateError(e) +impl From for AlignedError { + fn from(e: FeeEstimateError) -> Self { + AlignedError::FeeEstimateError(e) } } @@ -57,7 +57,7 @@ impl fmt::Display for AlignedError { AlignedError::SubmitError(e) => write!(f, "Submit error: {}", e), AlignedError::VerificationError(e) => write!(f, "Verification error: {}", e), AlignedError::ChainIdError(e) => write!(f, "Chain ID error: {}", e), - AlignedError::MaxFeeEstimateError(e) => write!(f, "Max fee estimate error: {}", e), + AlignedError::FeeEstimateError(e) => write!(f, "Fee estimate error: {}", e), AlignedError::FileError(e) => write!(f, "File error: {}", e), } } @@ -266,20 +266,24 @@ impl fmt::Display for ChainIdError { } #[derive(Debug)] -pub enum MaxFeeEstimateError { +pub enum FeeEstimateError { EthereumProviderError(String), EthereumGasPriceError(String), + FeeEstimateParseError(String), } -impl fmt::Display for MaxFeeEstimateError { +impl fmt::Display for FeeEstimateError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { - MaxFeeEstimateError::EthereumProviderError(e) => { + FeeEstimateError::EthereumProviderError(e) => { write!(f, "Ethereum provider error: {}", e) } - MaxFeeEstimateError::EthereumGasPriceError(e) => { + FeeEstimateError::EthereumGasPriceError(e) => { write!(f, "Failed to retreive the current gas price: {}", e) } + FeeEstimateError::FeeEstimateParseError(e) => { + write!(f, "Error parsing PriceEstimate: {}", e) + } } } } diff --git a/batcher/aligned-sdk/src/core/types.rs b/batcher/aligned-sdk/src/core/types.rs index ba59b5d6b..17006c550 100644 --- a/batcher/aligned-sdk/src/core/types.rs +++ b/batcher/aligned-sdk/src/core/types.rs @@ -86,12 +86,12 @@ impl NoncedVerificationData { } } -// Defines an estimate price preference for the user. +// Defines an price estimate type for the user. #[derive(Debug, Serialize, Deserialize, Clone)] -pub enum PriceEstimate { - Min, +pub enum FeeEstimationType { Default, Instant, + Custom(usize), } #[derive(Debug, Serialize, Deserialize, Clone, Default)] diff --git a/batcher/aligned-sdk/src/sdk.rs b/batcher/aligned-sdk/src/sdk.rs index 6045d8411..d42ce4cdf 100644 --- a/batcher/aligned-sdk/src/sdk.rs +++ b/batcher/aligned-sdk/src/sdk.rs @@ -8,12 +8,13 @@ use crate::{ core::{ constants::{ ADDITIONAL_SUBMISSION_GAS_COST_PER_PROOF, CONSTANT_GAS_COST, - MAX_FEE_BATCH_PROOF_NUMBER, MAX_FEE_DEFAULT_PROOF_NUMBER, + DEFAULT_MAX_FEE_BATCH_SIZE, GAS_PRICE_PERCENTAGE_MULTIPLIER, + INSTANT_MAX_FEE_BATCH_SIZE, PERCENTAGE_DIVIDER, }, errors::{self, GetNonceError}, types::{ - AlignedVerificationData, ClientMessage, GetNonceResponseMessage, Network, - PriceEstimate, ProvingSystemId, VerificationData, + AlignedVerificationData, ClientMessage, FeeEstimationType, GetNonceResponseMessage, + Network, ProvingSystemId, VerificationData, }, }, eth::{ @@ -115,58 +116,38 @@ pub async fn submit_multiple_and_wait_verification( aligned_verification_data } -/// Returns the estimated `max_fee` depending on the batch inclusion preference of the user, based on the max priority gas price. +/// Returns the estimated `max_fee` depending on the batch inclusion preference of the user, computed based on the current gas price, and the number of proofs in a batch. /// NOTE: The `max_fee` is computed from an rpc nodes max priority gas price. -/// To estimate the `max_fee` of a batch we use a compute the `max_fee` with respect to a batch of ~32 proofs present. +/// To estimate the `max_fee` of a batch we compute it based on a batch size of 1 (Instant), 16 (Default), or a user supplied `number_proofs_in_batch` (Custom). /// The `max_fee` estimates therefore are: -/// * `Min`: Specifies a `max_fee` equivalent to the cost of 1 proof in a 32 proof batch. -/// This estimates the lowest possible `max_fee` the user should specify for there proof with lowest priority. -/// * `Default`: Specifies a `max_fee` equivalent to the cost of 10 proofs in a 32 proof batch. -/// This estimates the `max_fee` the user should specify for inclusion within the batch. -/// * `Instant`: specifies a `max_fee` equivalent to the cost of all proofs within in a 32 proof batch. -/// This estimates the `max_fee` the user should specify to pay for the entire batch of proofs and have there proof included instantly. +/// * `Default`: Specifies a `max_fee` equivalent to the cost of paying for one proof within a batch of 16 proofs ie. 1 / 16 proofs. +/// This estimates a default `max_fee` the user should specify for including there proof within the batch. +/// * `Instant`: Specifies a `max_fee` equivalent to the cost of paying for an entire batch ensuring the user's proof is included instantly. +/// * `Custom (number_proofs_in_batch)`: Specifies a `max_fee` equivalent to the cost of paying 1 proof / `number_proofs_in_batch` allowing the user a user to estimate the `max_fee` precisely based on the `number_proofs_in_batch`. +/// /// # Arguments /// * `eth_rpc_url` - The URL of the Ethereum RPC node. -/// * `estimate` - Enum specifying the type of price estimate: MIN, DEFAULT, INSTANT. +/// * `estimate_type` - Enum specifying the type of price estimate: Default, Instant. Custom(usize) /// # Returns -/// The estimated `max_fee` in gas for a proof based on the users `PriceEstimate` as a `U256`. +/// The estimated `max_fee` in gas for a proof based on the users `FeeEstimateType` as a `U256`. /// # Errors /// * `EthereumProviderError` if there is an error in the connection with the RPC provider. /// * `EthereumGasPriceError` if there is an error retrieving the Ethereum gas price. pub async fn estimate_fee( eth_rpc_url: &str, - estimate: PriceEstimate, -) -> Result { - // Price of 1 proof in 32 proof batch - let fee_per_proof = fee_per_proof(eth_rpc_url, MAX_FEE_BATCH_PROOF_NUMBER).await?; - - let proof_price = match estimate { - PriceEstimate::Min => fee_per_proof, - PriceEstimate::Default => U256::from(MAX_FEE_DEFAULT_PROOF_NUMBER) * fee_per_proof, - PriceEstimate::Instant => U256::from(MAX_FEE_BATCH_PROOF_NUMBER) * fee_per_proof, - }; - Ok(proof_price) -} - -/// Returns the computed `max_fee` for a proof based on the number of proofs in a batch (`num_proofs_per_batch`) and -/// number of proofs (`num_proofs`) in that batch the user would pay for i.e (`num_proofs` / `num_proofs_per_batch`). -/// NOTE: The `max_fee` is computed from an rpc nodes max priority gas price. -/// # Arguments -/// * `eth_rpc_url` - The URL of the users Ethereum RPC node. -/// * `num_proofs` - number of proofs in a batch the user would pay for. -/// * `num_proofs_per_batch` - number of proofs within a batch. -/// # Returns -/// * The calculated `max_fee` as a `U256`. -/// # Errors -/// * `EthereumProviderError` if there is an error in the connection with the RPC provider. -/// * `EthereumGasPriceError` if there is an error retrieving the Ethereum gas price. -pub async fn compute_max_fee( - eth_rpc_url: &str, - num_proofs: usize, - num_proofs_per_batch: usize, -) -> Result { - let fee_per_proof = fee_per_proof(eth_rpc_url, num_proofs_per_batch).await?; - Ok(fee_per_proof * num_proofs) + fee_estimation_type: FeeEstimationType, +) -> Result { + match fee_estimation_type { + FeeEstimationType::Default => { + calculate_fee_per_proof_for_batch_of_size(eth_rpc_url, DEFAULT_MAX_FEE_BATCH_SIZE).await + } + FeeEstimationType::Instant => { + calculate_fee_per_proof_for_batch_of_size(eth_rpc_url, INSTANT_MAX_FEE_BATCH_SIZE).await + } + FeeEstimationType::Custom(n) => { + calculate_fee_per_proof_for_batch_of_size(eth_rpc_url, n).await + } + } } /// Returns the `fee_per_proof` based on the current gas price for a batch compromised of `num_proofs_per_batch` @@ -180,34 +161,39 @@ pub async fn compute_max_fee( /// # Errors /// * `EthereumProviderError` if there is an error in the connection with the RPC provider. /// * `EthereumGasPriceError` if there is an error retrieving the Ethereum gas price. -pub async fn fee_per_proof( +pub async fn calculate_fee_per_proof_for_batch_of_size( eth_rpc_url: &str, - num_proofs_per_batch: usize, -) -> Result { + num_proofs_in_batch: usize, +) -> Result { let eth_rpc_provider = Provider::::try_from(eth_rpc_url).map_err(|e: url::ParseError| { - errors::MaxFeeEstimateError::EthereumProviderError(e.to_string()) + errors::FeeEstimateError::EthereumProviderError(e.to_string()) })?; let gas_price = fetch_gas_price(ð_rpc_provider).await?; - // Cost for estimate `num_proofs_per_batch` proofs + // Cost for estimate `num_proofs_in_batch` proofs let estimated_gas_per_proof = (CONSTANT_GAS_COST - + ADDITIONAL_SUBMISSION_GAS_COST_PER_PROOF * num_proofs_per_batch as u128) - / num_proofs_per_batch as u128; + + ADDITIONAL_SUBMISSION_GAS_COST_PER_PROOF * num_proofs_in_batch as u128) + / num_proofs_in_batch as u128; - // Price of 1 proof in 32 proof batch - let fee_per_proof = U256::from(estimated_gas_per_proof) * gas_price; + // Price of 1 proof in a batch of size `num_proofs_in_batch` i.e. (1 / `num_proofs_in_batch`). + // The computed price is adjusted with respect to the percentage multiplier from: + // https://github.com/yetanotherco/aligned_layer/blob/staging/batcher/aligned-batcher/src/lib.rs#L1401 + let fee_per_proof = (U256::from(estimated_gas_per_proof) + * gas_price + * U256::from(GAS_PRICE_PERCENTAGE_MULTIPLIER)) + / U256::from(PERCENTAGE_DIVIDER); Ok(fee_per_proof) } async fn fetch_gas_price( eth_rpc_provider: &Provider, -) -> Result { +) -> Result { let gas_price = match eth_rpc_provider.get_gas_price().await { Ok(price) => price, Err(e) => { - return Err(errors::MaxFeeEstimateError::EthereumGasPriceError( + return Err(errors::FeeEstimateError::EthereumGasPriceError( e.to_string(), )) } @@ -834,10 +820,10 @@ mod test { #[tokio::test] async fn computed_max_fee_for_larger_batch_is_smaller() { - let small_fee = compute_max_fee(HOLESKY_PUBLIC_RPC_URL, 2, 10) + let small_fee = calculate_fee_per_proof_for_batch_of_size(HOLESKY_PUBLIC_RPC_URL, 5) .await .unwrap(); - let large_fee = compute_max_fee(HOLESKY_PUBLIC_RPC_URL, 5, 10) + let large_fee = calculate_fee_per_proof_for_batch_of_size(HOLESKY_PUBLIC_RPC_URL, 2) .await .unwrap(); @@ -846,10 +832,10 @@ mod test { #[tokio::test] async fn computed_max_fee_for_more_proofs_larger_than_for_less_proofs() { - let small_fee = compute_max_fee(HOLESKY_PUBLIC_RPC_URL, 5, 20) + let small_fee = calculate_fee_per_proof_for_batch_of_size(HOLESKY_PUBLIC_RPC_URL, 20) .await .unwrap(); - let large_fee = compute_max_fee(HOLESKY_PUBLIC_RPC_URL, 5, 10) + let large_fee = calculate_fee_per_proof_for_batch_of_size(HOLESKY_PUBLIC_RPC_URL, 10) .await .unwrap(); @@ -858,13 +844,13 @@ mod test { #[tokio::test] async fn estimate_fee_are_larger_than_one_another() { - let min_fee = estimate_fee(HOLESKY_PUBLIC_RPC_URL, PriceEstimate::Min) + let min_fee = estimate_fee(HOLESKY_PUBLIC_RPC_URL, FeeEstimationType::Custom(100)) .await .unwrap(); - let default_fee = estimate_fee(HOLESKY_PUBLIC_RPC_URL, PriceEstimate::Default) + let default_fee = estimate_fee(HOLESKY_PUBLIC_RPC_URL, FeeEstimationType::Default) .await .unwrap(); - let instant_fee = estimate_fee(HOLESKY_PUBLIC_RPC_URL, PriceEstimate::Instant) + let instant_fee = estimate_fee(HOLESKY_PUBLIC_RPC_URL, FeeEstimationType::Instant) .await .unwrap(); diff --git a/batcher/aligned/src/main.rs b/batcher/aligned/src/main.rs index 1153cacbd..67d079012 100644 --- a/batcher/aligned/src/main.rs +++ b/batcher/aligned/src/main.rs @@ -6,14 +6,17 @@ use std::path::PathBuf; use std::str::FromStr; use aligned_sdk::communication::serialization::cbor_deserialize; +use aligned_sdk::core::types::FeeEstimationType; use aligned_sdk::core::{ errors::{AlignedError, SubmitError}, types::{AlignedVerificationData, Network, ProvingSystemId, VerificationData}, }; +use aligned_sdk::sdk::estimate_fee; use aligned_sdk::sdk::get_chain_id; use aligned_sdk::sdk::get_nonce_from_batcher; use aligned_sdk::sdk::{deposit_to_aligned, get_balance_in_aligned}; use aligned_sdk::sdk::{get_vk_commitment, is_proof_verified, save_response, submit_multiple}; +use clap::Args; use clap::Parser; use clap::Subcommand; use clap::ValueEnum; @@ -61,7 +64,6 @@ pub enum AlignedCommands { } #[derive(Parser, Debug)] -#[command(version, about, long_about = None)] pub struct SubmitArgs { #[arg( name = "Batcher connection address", @@ -107,12 +109,8 @@ pub struct SubmitArgs { keystore_path: Option, #[arg(name = "Private key", long = "private_key")] private_key: Option, - #[arg( - name = "Max Fee (ether)", - long = "max_fee", - default_value = "0.0013ether" // 13_000 gas per proof * 100 gwei gas price (upper bound) - )] - max_fee: String, // String because U256 expects hex + #[command(flatten)] + fee_type: FeeType, #[arg(name = "Nonce", long = "nonce")] nonce: Option, // String because U256 expects hex #[arg( @@ -120,7 +118,71 @@ pub struct SubmitArgs { long = "network", default_value = "devnet" )] - network: NetworkArg, + network: Network, +} + +#[derive(Args, Debug)] +#[group(required = false, multiple = false)] +pub struct FeeType { + #[arg( + name = "Max Fee (ether)", + long = "max_fee", + help = "Specifies the maximum fee (`max_fee`) the user is willing to pay for the submitted proof, in Ether." + )] + max_fee: Option, // String because U256 expects hex + #[arg( + name = "NUMBER_PROOFS_IN_BATCH", + long = "custom_fee_estimate", + help = "Specifies a `max_fee` equivalent to the cost of paying (1 proof / `num_proofs_in_batch`) allowing the user to estimate a `max_fee` precisely based on the `number_proofs_in_batch`." + )] + custom_fee_estimate: Option, + #[arg( + long = "instant_fee_estimate", + help = "Specifies a `max_fee` that covers the cost of paying for the entire batch, ensuring the proof is included instantly." + )] + instant_fee_estimate: bool, + #[arg( + long = "default_fee_estimate", + help = "Specifies a `max_fee`, based on the cost of one proof within a batch of 16 proofs, providing a `default` fee for batch inclusion." + )] + default_fee_estimate: bool, +} + +impl SubmitArgs { + async fn get_max_fee(&self) -> Result { + if let Some(max_fee) = &self.fee_type.max_fee { + if !max_fee.ends_with("ether") { + error!("`max_fee` should be in the format XX.XXether"); + Err(SubmitError::EthereumProviderError( + "Error while parsing `max_fee`".to_string(), + ))? + } + + let max_fee_ether = max_fee.replace("ether", ""); + return Ok(parse_ether(max_fee_ether).map_err(|e| { + SubmitError::EthereumProviderError(format!("Error while parsing `max_fee`: {}", e)) + })?); + } + + if let Some(number_proofs_in_batch) = &self.fee_type.custom_fee_estimate { + return estimate_fee( + &self.eth_rpc_url, + FeeEstimationType::Custom(*number_proofs_in_batch), + ) + .await + .map_err(AlignedError::FeeEstimateError); + } + + if self.fee_type.instant_fee_estimate { + estimate_fee(&self.eth_rpc_url, FeeEstimationType::Instant) + .await + .map_err(AlignedError::FeeEstimateError) + } else { + estimate_fee(&self.eth_rpc_url, FeeEstimationType::Default) + .await + .map_err(AlignedError::FeeEstimateError) + } + } } #[derive(Parser, Debug)] @@ -279,17 +341,12 @@ async fn main() -> Result<(), AlignedError> { SubmitError::IoError(batch_inclusion_data_directory_path.clone(), e) })?; - if !submit_args.max_fee.ends_with("ether") { - error!("`max_fee` should be in the format XX.XXether"); - return Ok(()); - } - - let max_fee_ether = submit_args.max_fee.replace("ether", ""); - - let max_fee_wei: U256 = parse_ether(&max_fee_ether).map_err(|e| { - SubmitError::EthereumProviderError(format!("Error while parsing amount: {}", e)) - })?; - + let eth_rpc_url = submit_args.eth_rpc_url.clone(); + let max_fee_wei = submit_args.get_max_fee().await?; + info!( + "Will send each proof with an estimated max_fee of: {}ether", + format_ether(max_fee_wei) + ); let repetitions = submit_args.repetitions; let connect_addr = submit_args.batcher_url.clone(); @@ -324,8 +381,6 @@ async fn main() -> Result<(), AlignedError> { } }; - let eth_rpc_url = submit_args.eth_rpc_url.clone(); - let chain_id = get_chain_id(eth_rpc_url.as_str()).await?; wallet = wallet.with_chain_id(chain_id); @@ -366,7 +421,7 @@ async fn main() -> Result<(), AlignedError> { let aligned_verification_data_vec = submit_multiple( &connect_addr, - submit_args.network.into(), + submit_args.network, &verification_data_arr, max_fee_wei, wallet.clone(), @@ -453,7 +508,7 @@ async fn main() -> Result<(), AlignedError> { } DepositToBatcher(deposit_to_batcher_args) => { if !deposit_to_batcher_args.amount.ends_with("ether") { - error!("`amount` should be in the format XX.XXether"); + error!("Amount should be in the format XX.XXether"); return Ok(()); }