Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Native erc20 withdrawal integration tests #53

Merged
merged 17 commits into from
Jan 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .tool-versions
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
nodejs 18.18.0
3 changes: 3 additions & 0 deletions core/lib/web3_decl/src/namespaces/zks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,4 +121,7 @@ pub trait ZksNamespace {
keys: Vec<H256>,
l1_batch_number: L1BatchNumber,
) -> RpcResult<Proof>;

#[method(name = "getConversionRate")]
async fn get_conversion_rate(&self) -> RpcResult<U64>;
}
2 changes: 1 addition & 1 deletion core/lib/zksync_core/src/api_server/tx_sender/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -883,7 +883,7 @@ impl<G: L1GasPriceProvider> TxSender<G> {
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(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,9 @@ pub trait ZksNamespaceT {
keys: Vec<H256>,
l1_batch_number: L1BatchNumber,
) -> BoxFuture<Result<Proof>>;

#[rpc(name = "zks_getConversionRate")]
fn get_conversion_rate(&self) -> BoxFuture<Result<U64>>;
}

impl<G: L1GasPriceProvider + Send + Sync + 'static> ZksNamespaceT for ZksNamespace<G> {
Expand Down Expand Up @@ -343,4 +346,14 @@ impl<G: L1GasPriceProvider + Send + Sync + 'static> ZksNamespaceT for ZksNamespa
.map_err(into_jsrpc_error)
})
}

fn get_conversion_rate(&self) -> BoxFuture<Result<U64>> {
let self_ = self.clone();
Box::pin(async move {
self_
.get_conversion_rate_impl()
.await
.map_err(into_jsrpc_error)
})
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,9 @@ impl<G: L1GasPriceProvider + Send + Sync + 'static> EthNamespaceServer for EthNa
}

async fn gas_price(&self) -> RpcResult<U256> {
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<U256> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -174,4 +174,10 @@ impl<G: L1GasPriceProvider + Send + Sync + 'static> ZksNamespaceServer for ZksNa
.await
.map_err(into_jsrpc_error)
}

async fn get_conversion_rate(&self) -> RpcResult<U64> {
self.get_conversion_rate_impl()
.await
.map_err(into_jsrpc_error)
}
}
11 changes: 11 additions & 0 deletions core/lib/zksync_core/src/api_server/web3/namespaces/zks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -707,4 +707,15 @@ impl<G: L1GasPriceProvider> ZksNamespace<G> {
storage_proof,
})
}

#[tracing::instrument(skip_all)]
pub async fn get_conversion_rate_impl(&self) -> Result<U64, Web3Error> {
Ok(U64::from(
self.state
.tx_sender
.0
.l1_gas_price_source
.get_erc20_conversion_rate(),
))
}
}
4 changes: 2 additions & 2 deletions core/lib/zksync_core/src/eth_sender/eth_tx_aggregator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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![(
Expand All @@ -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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,7 @@ impl<G: L1GasPriceProvider> L1GasPriceProvider for BoundedGasAdjuster<G> {
}
default_gas_price
}
fn get_erc20_conversion_rate(&self) -> u64 {
self.default_gas_adjuster.get_erc20_conversion_rate()
}
}
Original file line number Diff line number Diff line change
@@ -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<String, Error> {
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::<Request>()
.await
.unwrap();
Ok(response.dai.eth.to_string())
}

fn erc20_value_from_eth_to_wei(value_in_eth: &str) -> Result<u64, String> {
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
}
23 changes: 20 additions & 3 deletions core/lib/zksync_core/src/l1_gas_price/gas_adjuster/mod.rs
Original file line number Diff line number Diff line change
@@ -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::{
Expand All @@ -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.
Expand All @@ -25,6 +26,7 @@ pub struct GasAdjuster<E> {
pub(super) statistics: GasStatistics,
pub(super) config: GasAdjusterConfig,
eth_client: E,
erc_20_value_in_wei: AtomicU64,
}

impl<E: EthInterface> GasAdjuster<E> {
Expand All @@ -44,6 +46,7 @@ impl<E: EthInterface> GasAdjuster<E> {
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),
})
}

Expand Down Expand Up @@ -78,6 +81,12 @@ impl<E: EthInterface> GasAdjuster<E> {
.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(())
}

Expand All @@ -92,7 +101,8 @@ impl<E: EthInterface> GasAdjuster<E> {
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(())
}
Expand All @@ -110,6 +120,13 @@ impl<E: EthInterface> L1GasPriceProvider for GasAdjuster<E> {

(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<E: EthInterface> L1TxParamsProvider for GasAdjuster<E> {
Expand Down
13 changes: 12 additions & 1 deletion core/lib/zksync_core/src/l1_gas_price/main_node_fetcher.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand All @@ -27,13 +27,15 @@ const SLEEP_INTERVAL: Duration = Duration::from_secs(5);
pub struct MainNodeGasPriceFetcher {
client: HttpClient,
gas_price: AtomicU64,
erc20_value_in_wei: AtomicU64,
}

impl MainNodeGasPriceFetcher {
pub fn new(main_node_url: &str) -> Self {
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),
}
}

Expand Down Expand Up @@ -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(())
}
Expand All @@ -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)
}
}
3 changes: 3 additions & 0 deletions core/lib/zksync_core/src/l1_gas_price/mod.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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
Expand Down
5 changes: 4 additions & 1 deletion core/lib/zksync_core/src/state_keeper/keeper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
Expand Down
2 changes: 1 addition & 1 deletion core/tests/ts-integration/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,6 @@
"ts-jest": "^29.0.1",
"ts-node": "^10.1.0",
"typescript": "^4.3.5",
"zksync-web3": "^0.15.5"
"zksync-web3": "../zksync2-js"
}
}
Loading
Loading