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

Fee: Gas fee conversion to the native ERC20. #19

Draft
wants to merge 12 commits into
base: native_erc20
Choose a base branch
from
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 @@ -118,4 +118,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 @@ -119,6 +119,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 @@ -331,4 +334,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 @@ -169,4 +169,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)
}
}
13 changes: 12 additions & 1 deletion core/lib/zksync_core/src/api_server/web3/namespaces/zks.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -679,4 +679,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 etc/tokens/native_erc20.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"address": "0x714FE7588649B69Fb58317e986a16676526772Ff",
"address": "0x601f6d7BE97C1B55ff1F65CE777a2701F16e07E4",
"name": "lambdacoin",
"symbol": "LBC",
"decimals": "18"
Expand Down
2 changes: 1 addition & 1 deletion infrastructure/zk/src/init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down
6 changes: 3 additions & 3 deletions infrastructure/zk/src/run/run.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
Loading