diff --git a/core/bin/zksync_api/src/fee_ticker/ticker_api/coingecko.rs b/core/bin/zksync_api/src/fee_ticker/ticker_api/coingecko.rs
index 3b7b2d45b..ea7b1b3f0 100644
--- a/core/bin/zksync_api/src/fee_ticker/ticker_api/coingecko.rs
+++ b/core/bin/zksync_api/src/fee_ticker/ticker_api/coingecko.rs
@@ -6,10 +6,12 @@ use num::rational::Ratio;
use num::BigUint;
use reqwest::Url;
use serde::{Deserialize, Serialize};
-use std::collections::HashMap;
+use std::fs::File;
use std::str::FromStr;
use std::time::Instant;
-use zksync_types::{Address, Token, TokenPrice};
+use std::{collections::HashMap, path::Path};
+use zksync_types::Token;
+use zksync_types::{network::Network, Address, TokenPrice};
use zksync_utils::{remove_prefix, UnsignedRatioSerializeAsDecimal};
#[derive(Debug, Clone)]
@@ -17,10 +19,56 @@ pub struct CoinGeckoAPI {
base_url: Url,
client: reqwest::Client,
token_ids: HashMap
,
+ tnet_to_mnet_address_mapping: HashMap,
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct TokenInfo {
+ /// Address (prefixed with 0x)
+ pub address: Address,
+ /// Powers of 10 in 1.0 token (18 for default RBTC-like tokens)
+ pub decimals: u8,
+ /// Token symbol
+ pub symbol: String,
+ pub name: String,
+}
+
+impl TokenInfo {
+ pub fn from_json(reader: R) -> anyhow::Result> {
+ let tokens: Vec = serde_json::from_reader(reader)?;
+ Ok(tokens)
+ }
}
impl CoinGeckoAPI {
pub async fn new(client: reqwest::Client, base_url: Url) -> anyhow::Result {
+ // If network is testner
+ let zksync_config = zksync_config::ZkSyncConfig::from_env();
+ let network = zksync_config.chain.eth.network;
+
+ // Get tokens from etc/tokens/testnet.json and etc/tokens/mainnet.json
+ let address_mapping = if network == Network::Testnet {
+ let testnet_tokens_file = Path::new("etc/tokens/testnet.json");
+ let mainnet_tokens_file = Path::new("etc/tokens/mainnet.json");
+
+ let testnet_tokens_file = File::open(testnet_tokens_file)?;
+ let mainnet_tokens_file = File::open(mainnet_tokens_file)?;
+
+ let testnet_tokens: Vec = TokenInfo::from_json(testnet_tokens_file)?;
+ let mainnet_tokens: Vec = TokenInfo::from_json(mainnet_tokens_file)?;
+
+ let mut address_mapping = HashMap::new();
+
+ for (testnet_token, mainnet_token) in testnet_tokens.iter().zip(mainnet_tokens.iter()) {
+ address_mapping.insert(testnet_token.address, mainnet_token.address);
+ }
+
+ address_mapping
+ } else {
+ HashMap::new()
+ };
+ // create a testnet to mainnet address mapping
+
let token_list_url = base_url
.join("api/v3/coins/list?include_platform=true")
.expect("failed to join URL path");
@@ -50,6 +98,7 @@ impl CoinGeckoAPI {
base_url,
client,
token_ids,
+ tnet_to_mnet_address_mapping: address_mapping,
})
}
}
@@ -57,11 +106,25 @@ impl CoinGeckoAPI {
#[async_trait]
impl TokenPriceAPI for CoinGeckoAPI {
async fn get_price(&self, token: &Token) -> Result {
+ let token_address = {
+ let zksync_config = zksync_config::ZkSyncConfig::from_env();
+ let network = zksync_config.chain.eth.network;
+
+ if network == Network::Testnet {
+ self.tnet_to_mnet_address_mapping
+ .get(&token.address)
+ .copied()
+ .unwrap_or(token.address)
+ } else {
+ token.address
+ }
+ };
+
let start = Instant::now();
- let token_id = self.token_ids.get(&token.address).ok_or_else(|| {
+ let token_id = self.token_ids.get(&token_address).ok_or_else(|| {
PriceError::token_not_found(format!(
"Token '{}, {:?}' is not listed on CoinGecko",
- token.symbol, token.address
+ token.symbol, token_address
))
})?;
diff --git a/etc/tokens/testnet.json b/etc/tokens/testnet.json
index 6ccbcd0e9..54953060f 100644
--- a/etc/tokens/testnet.json
+++ b/etc/tokens/testnet.json
@@ -2,13 +2,13 @@
{
"address": "0x19f64674D8a5b4e652319F5e239EFd3bc969a1FE",
"decimals": 18,
- "symbol": "RIF",
+ "symbol": "TRIF",
"name": "RSK Infrastructure Framework"
},
{
"address": "0xC3De9f38581F83e281F260D0ddBAac0E102Ff9F8",
"decimals": 18,
- "symbol": "rDOC",
+ "symbol": "RDOC",
"name": "RIF Dollar on Chain"
}
]