Skip to content

Commit

Permalink
Merge branch 'dev' into vb-1153-change-pubkey-offchain-ts-test
Browse files Browse the repository at this point in the history
  • Loading branch information
vladbochok authored Dec 1, 2020
2 parents ab189bc + e732e6f commit b8610e5
Showing 16 changed files with 815 additions and 194 deletions.
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions core/bin/zksync_api/src/fee_ticker/constants.rs
Original file line number Diff line number Diff line change
@@ -24,3 +24,10 @@ pub(crate) const BASE_CHANGE_PUBKEY_OFFCHAIN_COST: u64 = CommitCost::CHANGE_PUBK
pub(crate) const BASE_CHANGE_PUBKEY_ONCHAIN_COST: u64 = CommitCost::CHANGE_PUBKEY_COST_ONCHAIN
+ zksync_types::gas_counter::VerifyCost::CHANGE_PUBKEY_COST
+ 1000 * (ChangePubKeyOp::CHUNKS as u64);

// The Subsidized cost of operations.
// Represent the cost of performing operations after recursion is introduced to mainnet.
pub(crate) const SUBSIDY_TRANSFER_COST: u64 = 550;
pub(crate) const SUBSIDY_TRANSFER_TO_NEW_COST: u64 = 550 * 3;
pub(crate) const SUBSIDY_WITHDRAW_COST: u64 = 45000;
pub(crate) const SUBSIDY_CHANGE_PUBKEY_OFFCHAIN_COST: u64 = 10000;
23 changes: 15 additions & 8 deletions core/bin/zksync_api/src/fee_ticker/fee_token_validator.rs
Original file line number Diff line number Diff line change
@@ -2,7 +2,7 @@
//! an entity which decides whether certain ERC20 token is suitable for paying fees.
// Built-in uses
use std::{collections::HashMap, str::FromStr};
use std::collections::{HashMap, HashSet};
// Workspace uses
use zksync_types::{
tokens::{Token, TokenLike},
@@ -15,12 +15,18 @@ use crate::utils::token_db_cache::TokenDBCache;
#[derive(Debug, Clone)]
pub(crate) struct FeeTokenValidator {
tokens_cache: TokenCacheWrapper,
/// List of tokens that aren't accepted to pay fees in.
disabled_tokens: HashSet<Address>,
}

impl FeeTokenValidator {
pub(crate) fn new(cache: impl Into<TokenCacheWrapper>) -> Self {
pub(crate) fn new(
cache: impl Into<TokenCacheWrapper>,
disabled_tokens: HashSet<Address>,
) -> Self {
Self {
tokens_cache: cache.into(),
disabled_tokens,
}
}

@@ -40,12 +46,8 @@ impl FeeTokenValidator {
// Later we'll check Uniswap trading volume for tokens. That's why this function is already `async` even
// though it's not really `async` at this moment.

let not_supported_tokens = &[
Address::from_str("38A2fDc11f526Ddd5a607C1F251C065f40fBF2f7").unwrap(), // PHNX (PhoenixDAO)
];

if let Some(token) = token {
let not_acceptable = not_supported_tokens.iter().any(|&t| t == token.address);
let not_acceptable = self.disabled_tokens.contains(&token.address);
Ok(!not_acceptable)
} else {
// Unknown tokens aren't suitable for our needs, obviously.
@@ -84,6 +86,8 @@ impl TokenCacheWrapper {
#[cfg(test)]
mod tests {
use super::*;
use std::collections::HashSet;
use std::str::FromStr;

#[tokio::test]
async fn check_tokens() {
@@ -98,7 +102,10 @@ mod tests {
tokens.insert(TokenLike::Address(dai_token_address), dai_token);
tokens.insert(TokenLike::Address(phnx_token_address), phnx_token);

let validator = FeeTokenValidator::new(tokens);
let mut disabled_tokens = HashSet::new();
disabled_tokens.insert(phnx_token_address);

let validator = FeeTokenValidator::new(tokens, disabled_tokens);

let dai_allowed = validator
.token_allowed(TokenLike::Address(dai_token_address))
164 changes: 122 additions & 42 deletions core/bin/zksync_api/src/fee_ticker/mod.rs
Original file line number Diff line number Diff line change
@@ -4,7 +4,7 @@
//! `( zkp cost of chunk * number of chunks + gas price of transaction) * token risk factor / cost of token is usd`
// Built-in deps
use std::collections::HashMap;
use std::collections::{HashMap, HashSet};
// External deps
use bigdecimal::BigDecimal;
use futures::{
@@ -19,10 +19,10 @@ use num::{
use serde::{Deserialize, Serialize};
use tokio::task::JoinHandle;
// Workspace deps
use zksync_config::TokenPriceSource;
use zksync_config::{FeeTickerOptions, TokenPriceSource};
use zksync_storage::ConnectionPool;
use zksync_types::{
Address, ChangePubKeyOp, TokenId, TokenLike, TransferOp, TransferToNewOp, TxFeeTypes,
Address, ChangePubKeyOp, Token, TokenId, TokenLike, TransferOp, TransferToNewOp, TxFeeTypes,
WithdrawOp,
};
use zksync_utils::ratio_to_big_decimal;
@@ -48,11 +48,101 @@ mod ticker_info;
#[cfg(test)]
mod tests;

/// Contains cost of zkSync operations in Wei.
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct GasOperationsCost {
standard_cost: HashMap<OutputFeeType, BigUint>,
subsidize_cost: HashMap<OutputFeeType, BigUint>,
}

impl GasOperationsCost {
pub fn from_constants(fast_processing_coeff: f64) -> Self {
// We increase gas price for fast withdrawals, since it will induce generating a smaller block
// size, resulting in us paying more gas than for bigger block.
let standard_fast_withdrawal_cost =
(constants::BASE_WITHDRAW_COST as f64 * fast_processing_coeff) as u32;
let subsidy_fast_withdrawal_cost =
(constants::SUBSIDY_WITHDRAW_COST as f64 * fast_processing_coeff) as u32;

let standard_cost = vec![
(
OutputFeeType::Transfer,
constants::BASE_TRANSFER_COST.into(),
),
(
OutputFeeType::TransferToNew,
constants::BASE_TRANSFER_TO_NEW_COST.into(),
),
(
OutputFeeType::Withdraw,
constants::BASE_WITHDRAW_COST.into(),
),
(
OutputFeeType::FastWithdraw,
standard_fast_withdrawal_cost.into(),
),
(
OutputFeeType::ChangePubKey {
onchain_pubkey_auth: false,
},
constants::BASE_CHANGE_PUBKEY_OFFCHAIN_COST.into(),
),
(
OutputFeeType::ChangePubKey {
onchain_pubkey_auth: true,
},
constants::BASE_CHANGE_PUBKEY_ONCHAIN_COST.into(),
),
]
.into_iter()
.collect::<HashMap<_, _>>();

let subsidize_cost = vec![
(
OutputFeeType::Transfer,
constants::SUBSIDY_TRANSFER_COST.into(),
),
(
OutputFeeType::TransferToNew,
constants::SUBSIDY_TRANSFER_TO_NEW_COST.into(),
),
(
OutputFeeType::Withdraw,
constants::SUBSIDY_WITHDRAW_COST.into(),
),
(
OutputFeeType::FastWithdraw,
subsidy_fast_withdrawal_cost.into(),
),
(
OutputFeeType::ChangePubKey {
onchain_pubkey_auth: false,
},
constants::SUBSIDY_CHANGE_PUBKEY_OFFCHAIN_COST.into(),
),
(
OutputFeeType::ChangePubKey {
onchain_pubkey_auth: true,
},
constants::BASE_CHANGE_PUBKEY_ONCHAIN_COST.into(),
),
]
.into_iter()
.collect::<HashMap<_, _>>();

Self {
standard_cost,
subsidize_cost,
}
}
}

#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct TickerConfig {
zkp_cost_chunk_usd: Ratio<BigUint>,
gas_cost_tx: HashMap<OutputFeeType, BigUint>, //wei
gas_cost_tx: GasOperationsCost,
tokens_risk_factors: HashMap<TokenId, Ratio<BigUint>>,
not_subsidized_tokens: HashSet<Address>,
}

#[derive(Debug, PartialEq, Eq)]
@@ -90,59 +180,27 @@ struct FeeTicker<API, INFO> {

#[must_use]
pub fn run_ticker_task(
token_price_source: TokenPriceSource,
fast_processing_coeff: f64,
db_pool: ConnectionPool,
tricker_requests: Receiver<TickerRequest>,
) -> JoinHandle<()> {
// We increase gas price for fast withdrawals, since it will induce generating a smaller block
// size, resulting in us paying more gas than for bigger block.
let fast_withdrawal_cost =
(constants::BASE_WITHDRAW_COST as f64 * fast_processing_coeff) as u32;
let config = FeeTickerOptions::from_env();

let ticker_config = TickerConfig {
zkp_cost_chunk_usd: Ratio::from_integer(BigUint::from(10u32).pow(3u32)).inv(),
gas_cost_tx: vec![
(
OutputFeeType::Transfer,
constants::BASE_TRANSFER_COST.into(),
),
(
OutputFeeType::TransferToNew,
constants::BASE_TRANSFER_TO_NEW_COST.into(),
),
(
OutputFeeType::Withdraw,
constants::BASE_WITHDRAW_COST.into(),
),
(OutputFeeType::FastWithdraw, fast_withdrawal_cost.into()),
(
OutputFeeType::ChangePubKey {
onchain_pubkey_auth: false,
},
constants::BASE_CHANGE_PUBKEY_OFFCHAIN_COST.into(),
),
(
OutputFeeType::ChangePubKey {
onchain_pubkey_auth: true,
},
constants::BASE_CHANGE_PUBKEY_ONCHAIN_COST.into(),
),
]
.into_iter()
.collect(),
gas_cost_tx: GasOperationsCost::from_constants(config.fast_processing_coeff),
tokens_risk_factors: HashMap::new(),
not_subsidized_tokens: config.not_subsidized_tokens,
};

let cache = TokenDBCache::new(db_pool.clone());
let validator = FeeTokenValidator::new(cache);
let validator = FeeTokenValidator::new(cache, config.disabled_tokens);

let client = reqwest::ClientBuilder::new()
.timeout(CONNECTION_TIMEOUT)
.connect_timeout(CONNECTION_TIMEOUT)
.build()
.expect("Failed to build reqwest::Client");
match token_price_source {
match config.token_price_source {
TokenPriceSource::CoinMarketCap { base_url } => {
let token_price_api = CoinMarketCapAPI::new(client, base_url);

@@ -248,6 +306,11 @@ impl<API: FeeTickerAPI, INFO: FeeTickerInfo> FeeTicker<API, INFO> {
self.info.is_account_new(address).await
}

/// Returns `true` if the token is subsidized.
async fn is_token_subsidized(&mut self, token: Token) -> bool {
!self.config.not_subsidized_tokens.contains(&token.address)
}

async fn get_fee_from_ticker_in_wei(
&mut self,
tx_type: TxFeeTypes,
@@ -284,7 +347,24 @@ impl<API: FeeTickerAPI, INFO: FeeTickerInfo> FeeTicker<API, INFO> {
};
// Convert chunks amount to `BigUint`.
let op_chunks = BigUint::from(op_chunks);
let gas_tx_amount = self.config.gas_cost_tx.get(&fee_type).cloned().unwrap();
let gas_tx_amount = {
let is_token_subsidized = self.is_token_subsidized(token.clone()).await;
if is_token_subsidized {
self.config
.gas_cost_tx
.subsidize_cost
.get(&fee_type)
.cloned()
.unwrap()
} else {
self.config
.gas_cost_tx
.standard_cost
.get(&fee_type)
.cloned()
.unwrap()
}
};
let gas_price_wei = self.api.get_gas_price_wei().await?;
let wei_price_usd = self.api.get_last_quote(TokenLike::Id(0)).await?.usd_price
/ BigUint::from(10u32).pow(18u32);
Loading

0 comments on commit b8610e5

Please sign in to comment.