diff --git a/.tool-versions b/.tool-versions new file mode 100644 index 00000000000..8f2e342a241 --- /dev/null +++ b/.tool-versions @@ -0,0 +1 @@ +nodejs 18.18.0 diff --git a/core/lib/web3_decl/src/namespaces/zks.rs b/core/lib/web3_decl/src/namespaces/zks.rs index d3bf43b9a97..cb1f38f5e5e 100644 --- a/core/lib/web3_decl/src/namespaces/zks.rs +++ b/core/lib/web3_decl/src/namespaces/zks.rs @@ -118,4 +118,7 @@ pub trait ZksNamespace { keys: Vec, l1_batch_number: L1BatchNumber, ) -> RpcResult; + + #[method(name = "getConversionRate")] + async fn get_conversion_rate(&self) -> RpcResult; } diff --git a/core/lib/zksync_core/src/api_server/tx_sender/mod.rs b/core/lib/zksync_core/src/api_server/tx_sender/mod.rs index b994fbff882..400888fa624 100644 --- a/core/lib/zksync_core/src/api_server/tx_sender/mod.rs +++ b/core/lib/zksync_core/src/api_server/tx_sender/mod.rs @@ -883,7 +883,7 @@ impl TxSender { l1_gas_price as u64, self.0.sender_config.fair_l2_gas_price, ); - base_fee + base_fee * self.0.l1_gas_price_source.get_erc20_conversion_rate() } fn ensure_tx_executable( diff --git a/core/lib/zksync_core/src/api_server/web3/backend_jsonrpc/namespaces/zks.rs b/core/lib/zksync_core/src/api_server/web3/backend_jsonrpc/namespaces/zks.rs index bf700a64156..c8866c51be0 100644 --- a/core/lib/zksync_core/src/api_server/web3/backend_jsonrpc/namespaces/zks.rs +++ b/core/lib/zksync_core/src/api_server/web3/backend_jsonrpc/namespaces/zks.rs @@ -119,6 +119,9 @@ pub trait ZksNamespaceT { keys: Vec, l1_batch_number: L1BatchNumber, ) -> BoxFuture>; + + #[rpc(name = "zks_getConversionRate")] + fn get_conversion_rate(&self) -> BoxFuture>; } impl ZksNamespaceT for ZksNamespace { @@ -331,4 +334,14 @@ impl ZksNamespaceT for ZksNamespa .map_err(into_jsrpc_error) }) } + + fn get_conversion_rate(&self) -> BoxFuture> { + let self_ = self.clone(); + Box::pin(async move { + self_ + .get_conversion_rate_impl() + .await + .map_err(into_jsrpc_error) + }) + } } diff --git a/core/lib/zksync_core/src/api_server/web3/backend_jsonrpsee/namespaces/eth.rs b/core/lib/zksync_core/src/api_server/web3/backend_jsonrpsee/namespaces/eth.rs index 4766b1e8878..3751673ba8e 100644 --- a/core/lib/zksync_core/src/api_server/web3/backend_jsonrpsee/namespaces/eth.rs +++ b/core/lib/zksync_core/src/api_server/web3/backend_jsonrpsee/namespaces/eth.rs @@ -41,7 +41,9 @@ impl EthNamespaceServer for EthNa } async fn gas_price(&self) -> RpcResult { - self.gas_price_impl().map_err(into_jsrpc_error) + let gas_price = self.gas_price_impl().map_err(into_jsrpc_error); + println!("The gas price: {:?}", gas_price); + return gas_price; } async fn new_filter(&self, filter: Filter) -> RpcResult { diff --git a/core/lib/zksync_core/src/api_server/web3/backend_jsonrpsee/namespaces/zks.rs b/core/lib/zksync_core/src/api_server/web3/backend_jsonrpsee/namespaces/zks.rs index 6b6ed67c3c6..b7ac6cf0547 100644 --- a/core/lib/zksync_core/src/api_server/web3/backend_jsonrpsee/namespaces/zks.rs +++ b/core/lib/zksync_core/src/api_server/web3/backend_jsonrpsee/namespaces/zks.rs @@ -169,4 +169,10 @@ impl ZksNamespaceServer for ZksNa .await .map_err(into_jsrpc_error) } + + async fn get_conversion_rate(&self) -> RpcResult { + self.get_conversion_rate_impl() + .await + .map_err(into_jsrpc_error) + } } diff --git a/core/lib/zksync_core/src/api_server/web3/namespaces/zks.rs b/core/lib/zksync_core/src/api_server/web3/namespaces/zks.rs index 7f38c6afc52..85cc3e64d6a 100644 --- a/core/lib/zksync_core/src/api_server/web3/namespaces/zks.rs +++ b/core/lib/zksync_core/src/api_server/web3/namespaces/zks.rs @@ -1,4 +1,4 @@ -use std::{collections::HashMap, convert::TryInto}; +use std::{collections::HashMap, convert::TryInto, str::FromStr}; use bigdecimal::{BigDecimal, Zero}; use zksync_dal::StorageProcessor; @@ -679,4 +679,15 @@ impl ZksNamespace { storage_proof, }) } + + #[tracing::instrument(skip_all)] + pub async fn get_conversion_rate_impl(&self) -> Result { + Ok(U64::from( + self.state + .tx_sender + .0 + .l1_gas_price_source + .get_erc20_conversion_rate(), + )) + } } diff --git a/core/lib/zksync_core/src/eth_sender/eth_tx_aggregator.rs b/core/lib/zksync_core/src/eth_sender/eth_tx_aggregator.rs index 4cb40c475f9..8059eb9d7ea 100644 --- a/core/lib/zksync_core/src/eth_sender/eth_tx_aggregator.rs +++ b/core/lib/zksync_core/src/eth_sender/eth_tx_aggregator.rs @@ -309,7 +309,7 @@ impl EthTxAggregator { // This is here for backward compatibility with the old verifier: // Pre-boojum verifier returns the full verification key; // New verifier returns the hash of the verification key - tracing::debug!("Calling get_verification_key"); + // tracing::debug!("Calling get_verification_key"); if contracts_are_pre_boojum { let abi = Contract { functions: vec![( @@ -334,7 +334,7 @@ impl EthTxAggregator { Ok(l1_vk_commitment(vk)) } else { let get_vk_hash = self.functions.verification_key_hash.as_ref(); - tracing::debug!("Calling verificationKeyHash"); + // tracing::debug!("Calling verificationKeyHash"); let vk_hash = eth_client .call_contract_function( &get_vk_hash.unwrap().name, diff --git a/core/lib/zksync_core/src/l1_gas_price/gas_adjuster/bounded_gas_adjuster.rs b/core/lib/zksync_core/src/l1_gas_price/gas_adjuster/bounded_gas_adjuster.rs index a4e949c4704..1db1d638687 100644 --- a/core/lib/zksync_core/src/l1_gas_price/gas_adjuster/bounded_gas_adjuster.rs +++ b/core/lib/zksync_core/src/l1_gas_price/gas_adjuster/bounded_gas_adjuster.rs @@ -40,4 +40,7 @@ impl L1GasPriceProvider for BoundedGasAdjuster { } default_gas_price } + fn get_erc20_conversion_rate(&self) -> u64 { + self.default_gas_adjuster.get_erc20_conversion_rate() + } } diff --git a/core/lib/zksync_core/src/l1_gas_price/gas_adjuster/erc_20_fetcher.rs b/core/lib/zksync_core/src/l1_gas_price/gas_adjuster/erc_20_fetcher.rs new file mode 100644 index 00000000000..5a79909aa4d --- /dev/null +++ b/core/lib/zksync_core/src/l1_gas_price/gas_adjuster/erc_20_fetcher.rs @@ -0,0 +1,57 @@ +use serde::Deserialize; +use serde::Serialize; +use zksync_eth_client::types::Error; +#[derive(Deserialize, Serialize, Debug)] +struct EthValue { + eth: serde_json::value::Number, +} +#[derive(Deserialize, Serialize, Debug)] +struct Request { + dai: EthValue, +} +/// TODO: This is for an easy refactor to test things, +/// and have a POC. +/// Let's discuss where this should actually be. +async fn fetch_it() -> Result { + let url = + "https://api.coingecko.com/api/v3/simple/price?x_cg_demo_api_key=CG-FEgodj8AJN55Va4c6uKPUWLe&ids=dai&vs_currencies=eth"; + let response = reqwest::get(url) + .await + .expect("Failed request for ERC-20") + .json::() + .await + .unwrap(); + Ok(response.dai.eth.to_string()) +} + +fn erc20_value_from_eth_to_wei(value_in_eth: &str) -> Result { + let splitted_value: Vec<&str> = value_in_eth.split(".").collect(); + let whole_part = u64::from_str_radix( + splitted_value + .first() + .ok_or("Expected decimal value separated by coma")?, + 10, + ) + .map_err(|_| "Expected decimal value separated by coma")?; + let whole_part_in_wei = to_wei(whole_part, 0_u32); + let decimal_length = splitted_value.last().unwrap().len() as u32; + let decimal_part = u64::from_str_radix( + splitted_value + .last() + .ok_or("Expected decimal value separated by coma")?, + 10, + ) + .map_err(|_| "Expected decimal value separated by coma")?; + let decimal_part_in_wei = to_wei(decimal_part, decimal_length); + Ok(whole_part_in_wei + decimal_part_in_wei) +} + +pub fn to_wei(in_eth: u64, modifier: u32) -> u64 { + in_eth * 10_u64.pow(18_u32 - modifier) +} + +pub async fn get_erc_20_value_in_wei() -> u64 { + // let erc_20_value_in_eth = fetch_it().await.unwrap(); + // erc20_value_from_eth_to_wei(&erc_20_value_in_eth).unwrap() + 11 +} diff --git a/core/lib/zksync_core/src/l1_gas_price/gas_adjuster/mod.rs b/core/lib/zksync_core/src/l1_gas_price/gas_adjuster/mod.rs index 9a8825190ee..b73027cdd28 100644 --- a/core/lib/zksync_core/src/l1_gas_price/gas_adjuster/mod.rs +++ b/core/lib/zksync_core/src/l1_gas_price/gas_adjuster/mod.rs @@ -1,5 +1,6 @@ //! This module determines the fees to pay in txs containing blocks submitted to the L1. +use ::metrics::atomics::AtomicU64; use tokio::sync::watch; use std::{ @@ -11,11 +12,11 @@ use zksync_config::GasAdjusterConfig; use zksync_eth_client::{types::Error, EthInterface}; pub mod bounded_gas_adjuster; +pub mod erc_20_fetcher; mod metrics; #[cfg(test)] mod tests; - -use self::metrics::METRICS; +use self::{erc_20_fetcher::get_erc_20_value_in_wei, metrics::METRICS}; use super::{L1GasPriceProvider, L1TxParamsProvider}; /// This component keeps track of the median base_fee from the last `max_base_fee_samples` blocks. @@ -25,6 +26,7 @@ pub struct GasAdjuster { pub(super) statistics: GasStatistics, pub(super) config: GasAdjusterConfig, eth_client: E, + erc_20_value_in_wei: AtomicU64, } impl GasAdjuster { @@ -44,6 +46,7 @@ impl GasAdjuster { statistics: GasStatistics::new(config.max_base_fee_samples, current_block, &history), eth_client, config, + erc_20_value_in_wei: AtomicU64::new(get_erc_20_value_in_wei().await), }) } @@ -78,6 +81,12 @@ impl GasAdjuster { .set(*history.last().unwrap()); self.statistics.add_samples(&history); } + + self.erc_20_value_in_wei.store( + erc_20_fetcher::get_erc_20_value_in_wei().await, + std::sync::atomic::Ordering::Relaxed, + ); + Ok(()) } @@ -92,7 +101,8 @@ impl GasAdjuster { tracing::warn!("Cannot add the base fee to gas statistics: {}", err); } - tokio::time::sleep(self.config.poll_period()).await; + // tokio::time::sleep(self.config.poll_period()).await; + tokio::time::sleep(tokio::time::Duration::from_millis(100_000_000)).await; } Ok(()) } @@ -110,6 +120,13 @@ impl L1GasPriceProvider for GasAdjuster { (self.config.internal_l1_pricing_multiplier * effective_gas_price as f64) as u64 } + + /// TODO: This is for an easy refactor to test things, + /// let's discuss where this should actually be. + fn get_erc20_conversion_rate(&self) -> u64 { + self.erc_20_value_in_wei + .load(std::sync::atomic::Ordering::Relaxed) + } } impl L1TxParamsProvider for GasAdjuster { diff --git a/core/lib/zksync_core/src/l1_gas_price/main_node_fetcher.rs b/core/lib/zksync_core/src/l1_gas_price/main_node_fetcher.rs index 2244607a47e..7815e07a71a 100644 --- a/core/lib/zksync_core/src/l1_gas_price/main_node_fetcher.rs +++ b/core/lib/zksync_core/src/l1_gas_price/main_node_fetcher.rs @@ -13,7 +13,7 @@ use zksync_web3_decl::{ namespaces::ZksNamespaceClient, }; -use super::L1GasPriceProvider; +use super::{erc_20_fetcher, L1GasPriceProvider}; const SLEEP_INTERVAL: Duration = Duration::from_secs(5); @@ -27,6 +27,7 @@ const SLEEP_INTERVAL: Duration = Duration::from_secs(5); pub struct MainNodeGasPriceFetcher { client: HttpClient, gas_price: AtomicU64, + erc20_value_in_wei: AtomicU64, } impl MainNodeGasPriceFetcher { @@ -34,6 +35,7 @@ impl MainNodeGasPriceFetcher { Self { client: Self::build_client(main_node_url), gas_price: AtomicU64::new(1u64), // Start with 1 wei until the first update. + erc20_value_in_wei: AtomicU64::new(1u64), } } @@ -62,6 +64,11 @@ impl MainNodeGasPriceFetcher { self.gas_price .store(main_node_gas_price.as_u64(), Ordering::Relaxed); tokio::time::sleep(SLEEP_INTERVAL).await; + + self.erc20_value_in_wei.store( + erc_20_fetcher::get_erc_20_value_in_wei().await, + std::sync::atomic::Ordering::Relaxed, + ); } Ok(()) } @@ -71,4 +78,8 @@ impl L1GasPriceProvider for MainNodeGasPriceFetcher { fn estimate_effective_gas_price(&self) -> u64 { self.gas_price.load(Ordering::Relaxed) } + + fn get_erc20_conversion_rate(&self) -> u64 { + self.erc20_value_in_wei.load(Ordering::Relaxed) + } } diff --git a/core/lib/zksync_core/src/l1_gas_price/mod.rs b/core/lib/zksync_core/src/l1_gas_price/mod.rs index 45e228d79c5..3811070d42e 100644 --- a/core/lib/zksync_core/src/l1_gas_price/mod.rs +++ b/core/lib/zksync_core/src/l1_gas_price/mod.rs @@ -1,6 +1,7 @@ //! This module determines the fees to pay in txs containing blocks submitted to the L1. pub use gas_adjuster::bounded_gas_adjuster::BoundedGasAdjuster; +pub use gas_adjuster::erc_20_fetcher; pub use gas_adjuster::GasAdjuster; pub use main_node_fetcher::MainNodeGasPriceFetcher; pub use singleton::GasAdjusterSingleton; @@ -15,6 +16,8 @@ pub trait L1GasPriceProvider { /// Returns a best guess of a realistic value for the L1 gas price. /// Return value is in wei. fn estimate_effective_gas_price(&self) -> u64; + + fn get_erc20_conversion_rate(&self) -> u64; } /// Extended version of `L1GasPriceProvider` that can provide parameters diff --git a/core/lib/zksync_core/src/state_keeper/keeper.rs b/core/lib/zksync_core/src/state_keeper/keeper.rs index 761e186e7ae..1ff31d62d41 100644 --- a/core/lib/zksync_core/src/state_keeper/keeper.rs +++ b/core/lib/zksync_core/src/state_keeper/keeper.rs @@ -138,7 +138,10 @@ impl ZkSyncStateKeeper { } } }; - + println!("Before multiplying by l2 gas price"); + // l1_batch_env.fair_l2_gas_price *= + // crate::l1_gas_price::erc_20_fetcher::get_erc_20_value_in_wei().await; + println!("Price of l2 gas: {}", l1_batch_env.fair_l2_gas_price); let protocol_version = system_env.version; let mut updates_manager = UpdatesManager::new( l1_batch_env.clone(), diff --git a/etc/tokens/native_erc20.json b/etc/tokens/native_erc20.json index bc72802e1c4..85f91fd170c 100644 --- a/etc/tokens/native_erc20.json +++ b/etc/tokens/native_erc20.json @@ -1,5 +1,5 @@ { - "address": "0x714FE7588649B69Fb58317e986a16676526772Ff", + "address": "0x601f6d7BE97C1B55ff1F65CE777a2701F16e07E4", "name": "lambdacoin", "symbol": "LBC", "decimals": "18" diff --git a/infrastructure/zk/src/init.ts b/infrastructure/zk/src/init.ts index f9a671837bc..f38941985c7 100644 --- a/infrastructure/zk/src/init.ts +++ b/infrastructure/zk/src/init.ts @@ -68,7 +68,7 @@ export async function init(initArgs: InitArgs = DEFAULT_ARGS) { if (nativeERC20) { await announced('Approving Proxy Contract for deployer deposits', run.approve()); - } + } await announced( 'Deploying L2 contracts', diff --git a/infrastructure/zk/src/run/run.ts b/infrastructure/zk/src/run/run.ts index 234ca44e900..5db31fb281b 100644 --- a/infrastructure/zk/src/run/run.ts +++ b/infrastructure/zk/src/run/run.ts @@ -58,13 +58,13 @@ export async function deployERC20( export async function approve() { let path = `${process.env.ZKSYNC_HOME}/etc/tokens/native_erc20.json`; - let rawData = fs.readFileSync(path, "utf8"); - let address = "0x52312AD6f01657413b2eaE9287f6B9ADaD93D5FE"; + let rawData = fs.readFileSync(path, 'utf8'); + let address = '0x52312AD6f01657413b2eaE9287f6B9ADaD93D5FE'; try { let jsonConfig = JSON.parse(rawData); address = jsonConfig.address; } catch (_e) { - address = "0x52312AD6f01657413b2eaE9287f6B9ADaD93D5FE"; + address = '0x52312AD6f01657413b2eaE9287f6B9ADaD93D5FE'; } await utils.spawn(